Power System Platform  2026w34a-beta
Loading...
Searching...
No Matches
GeneralPropertiesForm.cpp
1/*
2 * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
19#include <wx/fontenum.h>
20#include <wx/font.h>
21#include <wx/stdpaths.h>
22#include <wx/app.h>
23#include <wx/tokenzr.h>
24#include <wx/imaglist.h>
25#include <wx/dcmemory.h>
26#include <algorithm>
27#include "../utils/PropertiesData.h"
28
29
30static bool ParseVoltageDouble(const wxString& str, double& value)
31{
32 wxString s = str;
33 s.Trim().Trim(false);
34 if (s.IsEmpty()) return false;
35
36 // 1. Try standard ToDouble (respects current locale, e.g. "230,00" in pt_BR)
37 if (s.ToDouble(&value)) return true;
38
39 // 2. Try converting comma to dot via ToCDouble (e.g. "230.00" or "230,00" -> "230.00")
40 wxString sDot = s;
41 sDot.Replace(wxT(","), wxT("."));
42 if (sDot.ToCDouble(&value)) return true;
43
44 // 3. Try converting dot to comma via ToDouble (e.g. "230.00" -> "230,00" in pt_BR)
45 wxString sComma = s;
46 sComma.Replace(wxT("."), wxT(","));
47 if (sComma.ToDouble(&value)) return true;
48
49 return false;
50}
51
52GeneralPropertiesForm::GeneralPropertiesForm(wxWindow* parent, PropertiesData* properties)
53 : GeneralPropertiesFormBase(parent)
54{
55 m_properties = properties;
56 auto data = m_properties->GetGeneralPropertiesData();
57
58 // Clear the choices and rebuild to set the correct translations.
59 m_choiceLanguage->Clear();
60 m_choiceLanguage->Insert(_("English"), 0);
61 m_choiceLanguage->Insert(_("Portuguese"), 1);
62 m_choiceTheme->Clear();
63 m_choiceTheme->Insert(_("Light"), 0);
64 m_choiceTheme->Insert(_("Dark"), 1);
65 //m_choiceRender->Clear();
66 //m_choiceRender->Insert(_("OpenGL"), 0);
67 //m_choiceRender->Insert(_("Device Context"), 0);
68 m_choicePlotLib->Clear();
69 m_choicePlotLib->Insert(_("Chart Director"), 0);
70 m_choicePlotLib->Insert(_("wxMathPlot"), 1);
71
72 switch (data.language) {
73 case wxLANGUAGE_ENGLISH: {
74 m_choiceLanguage->SetSelection(0);
75 } break;
76 case wxLANGUAGE_PORTUGUESE_BRAZILIAN: {
77 m_choiceLanguage->SetSelection(1);
78 } break;
79 default: {
80 m_choiceLanguage->SetSelection(wxNOT_FOUND);
81 } break;
82 }
83 switch (data.plotLib) {
84 case PlotLib::wxCHART_DIR: {
85 m_choicePlotLib->SetSelection(0);
86 } break;
87 case PlotLib::wxMATH_PLOT: {
88 m_choicePlotLib->SetSelection(1);
89 } break;
90 }
91 switch (data.theme) {
92 case THEME_LIGHT: {
93 m_choiceTheme->SetSelection(0);
94 } break;
95 case THEME_DARK: {
96 m_choiceTheme->SetSelection(1);
97 } break;
98 }
99 //if (data.useOpenGL) m_choiceRender->SetSelection(0);
100 //else m_choiceRender->SetSelection(1);
101 m_filePickerATPFolder->SetPath(data.atpPath.GetFullPath());
102 m_choiceElementToolbar->SetSelection(data.elementsToolbar);
103
104 wxFont currentFont(data.labelFontSize, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, data.labelFont);
105 m_fontPickerText->SetSelectedFont(currentFont);
106
107 // Buses colour tab setup
108 m_checkBoxUseBusColours->SetValue(data.useBusVoltageColours);
109 EnableBusColoursControls(data.useBusVoltageColours);
110 m_voltageLevels = data.voltageLevels;
111 if (m_voltageLevels.empty()) {
112 m_voltageLevels = PropertiesData::GetDefaultVoltageLevels();
113 }
114
115 m_listCtrlVoltages->InsertColumn(0, wxEmptyString, wxLIST_FORMAT_LEFT, 110);
116 m_listCtrlVoltages->InsertColumn(1, wxEmptyString, wxLIST_FORMAT_LEFT, 110);
117
118 PopulateVoltageList();
119
120 if (GetSizer()) {
121 GetSizer()->Fit(this);
122 }
123 Layout();
124 SetMinSize(wxSize(480, 380));
125 Fit();
126 Centre();
127}
128
129GeneralPropertiesForm::~GeneralPropertiesForm()
130{
131}
132void GeneralPropertiesForm::OnButtonOKClick(wxCommandEvent& event)
133{
134 if (ValidateData()) EndModal(wxID_OK);
135}
136
137bool GeneralPropertiesForm::ValidateData()
138{
139 auto data = m_properties->GetGeneralPropertiesData();
140 auto checkData = m_properties->GetGeneralPropertiesData();
141 bool needRestart = false;
142 data.atpPath = wxFileName(m_filePickerATPFolder->GetPath());
143 wxFont slectedFont = m_fontPickerText->GetSelectedFont();
144 data.labelFont = slectedFont.GetFaceName();
145 data.labelFontSize = slectedFont.GetPointSize();
146
147 switch (m_choiceLanguage->GetSelection()) {
148 case 0: {
149 data.language = wxLANGUAGE_ENGLISH;
150 } break;
151 case 1: {
152 data.language = wxLANGUAGE_PORTUGUESE_BRAZILIAN;
153 } break;
154 }
155 if (data.language != checkData.language) needRestart = true;
156
157 switch (m_choicePlotLib->GetSelection()) {
158 case 0: {
159 data.plotLib = PlotLib::wxCHART_DIR;
160 } break;
161 case 1: {
162 data.plotLib = PlotLib::wxMATH_PLOT;
163 } break;
164 }
165
166 switch (m_choiceTheme->GetSelection()) {
167 case 0: {
168 data.theme = THEME_LIGHT;
169 wxTheApp->SetAppearance(wxApp::Appearance::Light);
170 } break;
171 case 1: {
172 data.theme = THEME_DARK;
173 wxTheApp->SetAppearance(wxApp::Appearance::Dark);
174 } break;
175 }
176 if (data.theme != checkData.theme) needRestart = true;
177
178 data.elementsToolbar = static_cast<ElementsToolbar>(m_choiceElementToolbar->GetSelection());
179
180 data.useBusVoltageColours = m_checkBoxUseBusColours->GetValue();
181 data.voltageLevels = m_voltageLevels;
182
183 if (!PropertiesData::SaveConfigFile(data)) {
184 wxMessageDialog msgDialog(this,
185 _("It was not possible to access the init file.\nThe settings won't be applied."),
186 _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
187 msgDialog.ShowModal();
188 }
189
190 if (needRestart) {
191 wxMessageDialog msgDialog(this, _("The application must be restarted to settings changes be applied."),
192 _("Info"), wxOK | wxCENTRE | wxICON_INFORMATION);
193 msgDialog.ShowModal();
194 }
195 m_properties->SetGeneralPropertiesData(data);
196 return true;
197}
198
199void GeneralPropertiesForm::OnThemeSelected(wxCommandEvent& event)
200{
201 switch (event.GetSelection())
202 {
203 case 0:
204 wxTheApp->SetAppearance(wxApp::Appearance::Light);
205 break;
206 case 1:
207 wxTheApp->SetAppearance(wxApp::Appearance::Dark);
208 break;
209 }
210}
211
212void GeneralPropertiesForm::PopulateVoltageList()
213{
214 m_listCtrlVoltages->DeleteAllItems();
215
216 wxImageList* imgList = new wxImageList(16, 16, true);
217
218 for (size_t i = 0; i < m_voltageLevels.size(); ++i) {
219 const auto& lvl = m_voltageLevels[i];
220
221 wxBitmap bmp(16, 16);
222 wxMemoryDC memDC(bmp);
223 memDC.SetPen(*wxTRANSPARENT_PEN);
224 memDC.SetBrush(wxBrush(lvl.colour));
225 memDC.DrawRectangle(0, 0, 16, 16);
226
227 memDC.SetPen(wxPen(wxColour(120, 120, 120), 1));
228 memDC.SetBrush(*wxTRANSPARENT_BRUSH);
229 memDC.DrawRectangle(0, 0, 16, 16);
230 memDC.SelectObject(wxNullBitmap);
231
232 int imgIdx = imgList->Add(bmp);
233
234 long itemIndex = m_listCtrlVoltages->InsertItem(static_cast<long>(i), wxString::Format(wxT("%.2f"), lvl.voltage));
235 m_listCtrlVoltages->SetItem(itemIndex, 1, lvl.colour.GetAsString(wxC2S_HTML_SYNTAX), imgIdx);
236 }
237
238 m_listCtrlVoltages->AssignImageList(imgList, wxIMAGE_LIST_SMALL);
239}
240
241void GeneralPropertiesForm::EnableBusColoursControls(bool enable)
242{
243 m_listCtrlVoltages->Enable(enable);
244 m_textCtrlVoltage->Enable(enable);
245 m_colourPickerBus->Enable(enable);
246 m_buttonAddVoltage->Enable(enable);
247 m_buttonRemoveVoltage->Enable(enable);
248 m_buttonDefaultVoltages->Enable(enable);
249}
250
251void GeneralPropertiesForm::OnVoltageItemSelected(wxListEvent& event)
252{
253 long itemIndex = event.GetIndex();
254 if (itemIndex >= 0 && static_cast<size_t>(itemIndex) < m_voltageLevels.size()) {
255 const auto& lvl = m_voltageLevels[itemIndex];
256 m_textCtrlVoltage->SetValue(wxString::Format(wxT("%.2f"), lvl.voltage));
257 m_colourPickerBus->SetColour(lvl.colour);
258 }
259}
260
261void GeneralPropertiesForm::OnButtonAddVoltage(wxCommandEvent& event)
262{
263 wxString vStr = m_textCtrlVoltage->GetValue();
264 double v = 0.0;
265
266 if (!ParseVoltageDouble(vStr, v) || v <= 0.0) {
267 wxMessageDialog msgDialog(this, _("Please enter a valid voltage value in kV."), _("Warning"), wxOK | wxICON_WARNING);
268 msgDialog.ShowModal();
269 return;
270 }
271
272 wxColour col = m_colourPickerBus->GetColour();
273
274 bool found = false;
275 for (auto& lvl : m_voltageLevels) {
276 if (std::abs(lvl.voltage - v) < 0.001) {
277 lvl.colour = col;
278 found = true;
279 break;
280 }
281 }
282
283 if (!found) {
284 m_voltageLevels.push_back({ v, col });
285 }
286
287 std::sort(m_voltageLevels.begin(), m_voltageLevels.end(), [](const VoltageLevelColour& a, const VoltageLevelColour& b) {
288 return a.voltage > b.voltage;
289 });
290
291 PopulateVoltageList();
292
293 for (size_t i = 0; i < m_voltageLevels.size(); ++i) {
294 if (std::abs(m_voltageLevels[i].voltage - v) < 0.001) {
295 m_listCtrlVoltages->SetItemState(static_cast<long>(i), wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED);
296 m_listCtrlVoltages->EnsureVisible(static_cast<long>(i));
297 break;
298 }
299 }
300}
301
302void GeneralPropertiesForm::OnButtonRemoveVoltage(wxCommandEvent& event)
303{
304 long itemIndex = m_listCtrlVoltages->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
305 if (itemIndex >= 0 && static_cast<size_t>(itemIndex) < m_voltageLevels.size()) {
306 m_voltageLevels.erase(m_voltageLevels.begin() + itemIndex);
307 PopulateVoltageList();
308 m_textCtrlVoltage->Clear();
309 }
310 else {
311 wxMessageDialog msgDialog(this, _("Select a voltage level from the list to remove."), _("Warning"), wxOK | wxICON_WARNING);
312 msgDialog.ShowModal();
313 }
314}
315
316void GeneralPropertiesForm::OnButtonDefaultVoltages(wxCommandEvent& event)
317{
318 m_voltageLevels = PropertiesData::GetDefaultVoltageLevels();
319 PopulateVoltageList();
320 m_textCtrlVoltage->Clear();
321}
322
323void GeneralPropertiesForm::OnUseBusColoursClick(wxCommandEvent& event)
324{
325 EnableBusColoursControls(event.GetSelection());
326 event.Skip();
327}
General and simulation data manager.