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"
61 #include <windef.h> /* for MAX_PATH */
63 class PolarConfigPanel final
: public XMLWidget
{
65 WndButton
*buttonList
, *buttonImport
, *buttonExport
;
67 void UpdatePolarTitle();
68 void UpdatePolarInvalidLabel();
69 void SetVisible(bool active
);
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();
95 LoadPolarShape(SubForm
&form
, const PolarShape
&shape
)
97 GetShapeEditor(form
).SetPolarShape(shape
);
101 PolarConfigPanel::UpdatePolarTitle()
103 StaticString
<100> caption(_("Polar"));
105 caption
+= CommonInterface::GetComputerSettings().plane
.polar_name
;
107 ((WndFrame
*)form
.FindByName(_T("lblPolar")))->SetCaption(caption
);
111 SavePolarShape(SubForm
&form
, PolarShape
&shape
)
113 PolarShapeEditWidget
&widget
= GetShapeEditor(form
);
114 bool changed
= false;
115 if (!widget
.Save(changed
))
118 shape
= widget
.GetPolarShape();
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
);
138 PolarConfigPanel::UpdatePolarInvalidLabel()
141 bool valid
= SavePolarShape(form
, shape
) && shape
.IsValid();
142 ((WndFrame
*)form
.FindByName(_T("lblPolarInvalid")))->SetVisible(!valid
);
146 PolarConfigPanel::LoadInternal()
149 unsigned len
= PolarStore::Count();
150 for (unsigned i
= 0; i
< len
; i
++)
151 list
.Append(i
, PolarStore::GetItem(i
).name
);
155 /* let the user select */
157 int result
= ComboPicker(_("Load Polar"), list
, NULL
);
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
));
171 LoadFormProperty(form
, _T("prpMaxManoeuveringSpeed"), UnitGroup::HORIZONTAL_SPEED
,
174 if (item
.contest_handicap
> 0)
175 LoadFormProperty(form
, _T("prpHandicap"), item
.contest_handicap
);
177 CommonInterface::SetComputerSettings().plane
.polar_name
= item
.name
;
179 UpdatePolarInvalidLabel();
186 instance
->LoadInternal();
189 class PolarFileVisitor
: public File::Visitor
195 PolarFileVisitor(ComboList
&_list
): list(_list
) {}
197 void Visit(const TCHAR
* path
, const TCHAR
* filename
) {
198 list
.Append(0, path
, filename
);
203 PolarConfigPanel::LoadFromFile()
206 PolarFileVisitor
fv(list
);
209 VisitDataFiles(_T("*.plr"), fv
);
214 // Show selection dialog
215 int result
= ComboPicker(_("Load Polar From File"), list
, NULL
);
217 const TCHAR
* path
= list
[result
].StringValue
;
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
,
234 CommonInterface::SetComputerSettings().plane
.polar_name
=
235 list
[result
].StringValueFormatted
;
237 UpdatePolarInvalidLabel();
244 instance
->LoadFromFile();
248 PolarConfigPanel::Export()
250 TCHAR filename
[69] = _T("");
251 if (!TextEntryDialog(filename
, 64, _("Polar name")))
254 TCHAR path
[MAX_PATH
];
255 _tcscat(filename
, _T(".plr"));
256 LocalPath(path
, filename
);
259 SaveFormToPolar(form
, polar
);
260 if (PolarGlue::SaveToFile(polar
, path
)) {
261 CommonInterface::SetComputerSettings().plane
.polar_name
= filename
;
273 PolarConfigPanel::DataChanged()
276 CommonInterface::SetComputerSettings().plane
.polar_name
= _T("Custom");
279 UpdatePolarInvalidLabel();
283 OnFieldData(DataField
*Sender
, DataField::DataAccessMode Mode
)
285 if (Mode
== DataField::daChange
)
286 instance
->DataChanged();
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
);
303 PolarConfigPanel::Show(const PixelRect
&rc
)
305 PolarConfigPanel::SetVisible(true);
310 PolarConfigPanel::Hide()
313 PolarConfigPanel::SetVisible(false);
316 static constexpr CallBackTableEntry polar_callbacks
[] = {
317 DeclareCallBackEntry(OnFieldData
),
318 DeclareCallBackEntry(NULL
)
322 PolarConfigPanel::Prepare(ContainerWindow
&parent
, const PixelRect
&rc
)
327 LoadWindow(polar_callbacks
, parent
,
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
);
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
);
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
);
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
);
424 CreatePolarConfigPanel()
426 return new PolarConfigPanel();