Android release v6.7_preview1
[xcsoar.git] / src / Dialogs / Settings / Panels / PolarConfigPanel.cpp
blob491888959677fbbd1fc5cb4175efcc4fec43d7df
1 /*
2 Copyright_License {
4 XCSoar Glide Computer - http://www.xcsoar.org/
5 Copyright (C) 2000-2013 The XCSoar Project
6 A detailed list of copyright holders can be found in the file "AUTHORS".
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include "PolarConfigPanel.hpp"
25 #include "Dialogs/Plane/PolarShapeEditWidget.hpp"
26 #include "ConfigPanel.hpp"
27 #include "Widget/XMLWidget.hpp"
28 #include "Widget/DockWindow.hpp"
29 #include "Form/DataField/Enum.hpp"
30 #include "Form/DataField/Float.hpp"
31 #include "Form/DataField/ComboList.hpp"
32 #include "Form/DataField/FileReader.hpp"
33 #include "Form/Button.hpp"
34 #include "Form/Edit.hpp"
35 #include "Form/Util.hpp"
36 #include "Form/Frame.hpp"
37 #include "Form/Form.hpp"
38 #include "Dialogs/ComboPicker.hpp"
39 #include "Dialogs/TextEntry.hpp"
40 #include "Dialogs/CallBackTable.hpp"
41 #include "Screen/SingleWindow.hpp"
42 #include "Screen/Layout.hpp"
43 #include "Polar/PolarStore.hpp"
44 #include "Polar/PolarFileGlue.hpp"
45 #include "Polar/PolarGlue.hpp"
46 #include "Polar/Polar.hpp"
47 #include "Engine/GlideSolvers/PolarCoefficients.hpp"
48 #include "GlideSolvers/GlidePolar.hpp"
49 #include "Profile/ProfileKeys.hpp"
50 #include "Profile/Profile.hpp"
51 #include "Interface.hpp"
52 #include "LocalPath.hpp"
53 #include "Task/ProtectedTaskManager.hpp"
54 #include "Components.hpp"
55 #include "OS/FileUtil.hpp"
56 #include "Language/Language.hpp"
57 #include "Plane/PlaneGlue.hpp"
58 #include "Units/Units.hpp"
60 #include <cstdio>
61 #include <windef.h> /* for MAX_PATH */
63 class PolarConfigPanel final : public XMLWidget {
64 bool loading;
65 WndButton *buttonList, *buttonImport, *buttonExport;
67 void UpdatePolarTitle();
68 void UpdatePolarInvalidLabel();
69 void SetVisible(bool active);
71 public:
72 void LoadInternal();
73 void LoadFromFile();
74 void Export();
75 void DataChanged();
77 virtual void Prepare(ContainerWindow &parent, const PixelRect &rc) override;
78 virtual bool Save(bool &changed) override;
79 virtual void Show(const PixelRect &rc) override;
80 virtual void Hide() override;
83 /** XXX this hack is needed because the form callbacks don't get a
84 context pointer - please refactor! */
85 static PolarConfigPanel *instance;
87 static PolarShapeEditWidget &
88 GetShapeEditor(SubForm &form)
90 DockWindow &dock = *(DockWindow *)form.FindByName(_T("shape"));
91 return *(PolarShapeEditWidget *)dock.GetWidget();
94 static void
95 LoadPolarShape(SubForm &form, const PolarShape &shape)
97 GetShapeEditor(form).SetPolarShape(shape);
100 void
101 PolarConfigPanel::UpdatePolarTitle()
103 StaticString<100> caption(_("Polar"));
104 caption += _T(": ");
105 caption += CommonInterface::GetComputerSettings().plane.polar_name;
107 ((WndFrame *)form.FindByName(_T("lblPolar")))->SetCaption(caption);
110 static bool
111 SavePolarShape(SubForm &form, PolarShape &shape)
113 PolarShapeEditWidget &widget = GetShapeEditor(form);
114 bool changed = false;
115 if (!widget.Save(changed))
116 return false;
118 shape = widget.GetPolarShape();
119 return true;
122 static bool
123 SaveFormToPolar(SubForm &form, PolarInfo &polar)
125 bool changed = SavePolarShape(form, polar.shape);
127 changed |= SaveFormProperty(form, _T("prpPolarReferenceMass"), polar.reference_mass);
128 changed |= SaveFormProperty(form, _T("prpPolarMaxBallast"), polar.max_ballast);
130 changed |= SaveFormProperty(form, _T("prpPolarWingArea"), polar.wing_area);
131 changed |= SaveFormProperty(form, _T("prpMaxManoeuveringSpeed"),
132 UnitGroup::HORIZONTAL_SPEED, polar.v_no);
134 return changed;
137 void
138 PolarConfigPanel::UpdatePolarInvalidLabel()
140 PolarShape shape;
141 bool valid = SavePolarShape(form, shape) && shape.IsValid();
142 ((WndFrame *)form.FindByName(_T("lblPolarInvalid")))->SetVisible(!valid);
145 void
146 PolarConfigPanel::LoadInternal()
148 ComboList list;
149 unsigned len = PolarStore::Count();
150 for (unsigned i = 0; i < len; i++)
151 list.Append(i, PolarStore::GetItem(i).name);
153 list.Sort();
155 /* let the user select */
157 int result = ComboPicker(_("Load Polar"), list, NULL);
158 if (result >= 0) {
159 const PolarStore::Item &item = PolarStore::GetItem(list[result].DataFieldIndex);
161 LoadPolarShape(form, item.ToPolarShape());
163 LoadFormProperty(form, _T("prpPolarReferenceMass"), fixed(item.reference_mass));
164 LoadFormProperty(form, _T("prpPolarDryMass"), fixed(item.reference_mass));
165 LoadFormProperty(form, _T("prpPolarMaxBallast"), fixed(item.max_ballast));
167 if (item.wing_area > 0.0)
168 LoadFormProperty(form, _T("prpPolarWingArea"), fixed(item.wing_area));
170 if (item.v_no > 0.0)
171 LoadFormProperty(form, _T("prpMaxManoeuveringSpeed"), UnitGroup::HORIZONTAL_SPEED,
172 fixed(item.v_no));
174 if (item.contest_handicap > 0)
175 LoadFormProperty(form, _T("prpHandicap"), item.contest_handicap);
177 CommonInterface::SetComputerSettings().plane.polar_name = item.name;
178 UpdatePolarTitle();
179 UpdatePolarInvalidLabel();
183 static void
184 OnLoadInternal()
186 instance->LoadInternal();
189 class PolarFileVisitor: public File::Visitor
191 private:
192 ComboList &list;
194 public:
195 PolarFileVisitor(ComboList &_list): list(_list) {}
197 void Visit(const TCHAR* path, const TCHAR* filename) {
198 list.Append(0, path, filename);
202 void
203 PolarConfigPanel::LoadFromFile()
205 ComboList list;
206 PolarFileVisitor fv(list);
208 // Fill list
209 VisitDataFiles(_T("*.plr"), fv);
211 // Sort list
212 list.Sort();
214 // Show selection dialog
215 int result = ComboPicker(_("Load Polar From File"), list, NULL);
216 if (result >= 0) {
217 const TCHAR* path = list[result].StringValue;
218 PolarInfo polar;
219 PolarGlue::LoadFromFile(polar, path);
221 LoadPolarShape(form, polar.shape);
223 LoadFormProperty(form, _T("prpPolarReferenceMass"), polar.reference_mass);
224 LoadFormProperty(form, _T("prpPolarDryMass"), polar.reference_mass);
225 LoadFormProperty(form, _T("prpPolarMaxBallast"), polar.max_ballast);
227 if (positive(polar.wing_area))
228 LoadFormProperty(form, _T("prpPolarWingArea"), polar.wing_area);
230 if (positive(polar.v_no))
231 LoadFormProperty(form, _T("prpMaxManoeuveringSpeed"), UnitGroup::HORIZONTAL_SPEED,
232 polar.v_no);
234 CommonInterface::SetComputerSettings().plane.polar_name =
235 list[result].StringValueFormatted;
236 UpdatePolarTitle();
237 UpdatePolarInvalidLabel();
241 static void
242 OnLoadFromFile()
244 instance->LoadFromFile();
247 void
248 PolarConfigPanel::Export()
250 TCHAR filename[69] = _T("");
251 if (!TextEntryDialog(filename, 64, _("Polar name")))
252 return;
254 TCHAR path[MAX_PATH];
255 _tcscat(filename, _T(".plr"));
256 LocalPath(path, filename);
258 PolarInfo polar;
259 SaveFormToPolar(form, polar);
260 if (PolarGlue::SaveToFile(polar, path)) {
261 CommonInterface::SetComputerSettings().plane.polar_name = filename;
262 UpdatePolarTitle();
266 static void
267 OnExport()
269 instance->Export();
272 void
273 PolarConfigPanel::DataChanged()
275 if (!loading)
276 CommonInterface::SetComputerSettings().plane.polar_name = _T("Custom");
278 UpdatePolarTitle();
279 UpdatePolarInvalidLabel();
282 static void
283 OnFieldData(DataField *Sender, DataField::DataAccessMode Mode)
285 if (Mode == DataField::daChange)
286 instance->DataChanged();
289 void
290 PolarConfigPanel::SetVisible(bool active)
292 if (buttonList != NULL)
293 buttonList->SetVisible(active);
295 if (buttonImport != NULL)
296 buttonImport->SetVisible(active);
298 if (buttonExport != NULL)
299 buttonExport->SetVisible(active);
302 void
303 PolarConfigPanel::Show(const PixelRect &rc)
305 PolarConfigPanel::SetVisible(true);
306 XMLWidget::Show(rc);
309 void
310 PolarConfigPanel::Hide()
312 XMLWidget::Hide();
313 PolarConfigPanel::SetVisible(false);
316 static constexpr CallBackTableEntry polar_callbacks[] = {
317 DeclareCallBackEntry(OnFieldData),
318 DeclareCallBackEntry(NULL)
321 void
322 PolarConfigPanel::Prepare(ContainerWindow &parent, const PixelRect &rc)
324 instance = this;
325 loading = true;
327 LoadWindow(polar_callbacks, parent,
328 Layout::landscape
329 ? _T("IDR_XML_POLARCONFIGPANEL_L")
330 : _T("IDR_XML_POLARCONFIGPANEL"));
332 buttonList = (WndButton *)ConfigPanel::GetForm()
333 .FindByName(_T("cmdLoadInternalPolar"));
334 assert(buttonList != NULL);
335 buttonList->SetOnClickNotify(OnLoadInternal);
337 buttonImport = (WndButton *)ConfigPanel::GetForm()
338 .FindByName(_T("cmdLoadPolarFile"));
339 assert(buttonImport != NULL);
340 buttonImport->SetOnClickNotify(OnLoadFromFile);
342 buttonExport = (WndButton *)ConfigPanel::GetForm()
343 .FindByName(_T("cmdSavePolarFile"));
344 assert(buttonExport != NULL);
345 buttonExport->SetOnClickNotify(OnExport);
347 const ComputerSettings &settings = CommonInterface::GetComputerSettings();
349 DockWindow &dock = *(DockWindow *)form.FindByName(_T("shape"));
350 PolarShapeEditWidget *shape_editor =
351 new PolarShapeEditWidget(settings.plane.polar_shape);
352 dock.SetWidget(shape_editor);
353 shape_editor->SetDataAccessCallback(OnFieldData);
355 LoadFormProperty(form, _T("prpPolarReferenceMass"),
356 settings.plane.reference_mass);
357 LoadFormProperty(form, _T("prpPolarDryMass"), settings.plane.dry_mass);
358 LoadFormProperty(form, _T("prpPolarMaxBallast"), settings.plane.max_ballast);
360 LoadFormProperty(form, _T("prpPolarWingArea"), settings.plane.wing_area);
361 LoadFormProperty(form, _T("prpMaxManoeuveringSpeed"), UnitGroup::HORIZONTAL_SPEED,
362 settings.plane.max_speed);
364 UpdatePolarTitle();
365 UpdatePolarInvalidLabel();
367 const ComputerSettings &settings_computer = CommonInterface::GetComputerSettings();
369 LoadFormProperty(form, _T("prpHandicap"),
370 settings_computer.plane.handicap);
372 LoadFormProperty(form, _T("prpBallastSecsToEmpty"),
373 settings_computer.plane.dump_time);
375 loading = false;
378 bool
379 PolarConfigPanel::Save(bool &_changed)
381 bool changed = false;
383 ComputerSettings &settings_computer = CommonInterface::SetComputerSettings();
385 changed |= SavePolarShape(form, settings_computer.plane.polar_shape);
387 changed |= SaveFormProperty(form, _T("prpPolarReferenceMass"),
388 settings_computer.plane.reference_mass);
390 changed |= SaveFormProperty(form, _T("prpPolarDryMass"),
391 settings_computer.plane.dry_mass);
393 changed |= SaveFormProperty(form, _T("prpPolarMaxBallast"),
394 settings_computer.plane.max_ballast);
396 changed |= SaveFormProperty(form, _T("prpPolarWingArea"),
397 settings_computer.plane.wing_area);
399 changed |= SaveFormProperty(form, _T("prpMaxManoeuveringSpeed"),
400 UnitGroup::HORIZONTAL_SPEED,
401 settings_computer.plane.max_speed);
403 changed |= SaveFormProperty(form, _T("prpHandicap"),
404 settings_computer.plane.handicap);
406 changed |= SaveFormProperty(form, _T("prpBallastSecsToEmpty"),
407 settings_computer.plane.dump_time);
409 if (changed) {
410 PlaneGlue::DetachFromPlaneFile();
411 PlaneGlue::ToProfile(settings_computer.plane);
412 PlaneGlue::Synchronize(settings_computer.plane, settings_computer,
413 settings_computer.polar.glide_polar_task);
415 if (protected_task_manager != NULL)
416 protected_task_manager->SetGlidePolar(settings_computer.polar.glide_polar_task);
419 _changed |= changed;
420 return true;
423 Widget *
424 CreatePolarConfigPanel()
426 return new PolarConfigPanel();