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 "RowFormWidget.hpp"
25 #include "Form/Edit.hpp"
26 #include "Form/Panel.hpp"
27 #include "Form/Button.hpp"
28 #include "Form/HLine.hpp"
29 #include "Look/DialogLook.hpp"
30 #include "Dialogs/DialogSettings.hpp"
31 #include "UIGlobals.hpp"
32 #include "Screen/Layout.hpp"
33 #include "Screen/LargeTextWindow.hpp"
34 #include "Screen/Font.hpp"
35 #include "Form/DataField/Boolean.hpp"
36 #include "Form/DataField/Integer.hpp"
37 #include "Form/DataField/Float.hpp"
38 #include "Form/DataField/Angle.hpp"
39 #include "Form/DataField/Enum.hpp"
40 #include "Form/DataField/String.hpp"
41 #include "Form/DataField/Password.hpp"
42 #include "Form/DataField/FileReader.hpp"
43 #include "Form/DataField/Time.hpp"
44 #include "Form/DataField/RoughTime.hpp"
45 #include "Time/RoughTime.hpp"
46 #include "Language/Language.hpp"
47 #include "Profile/Profile.hpp"
48 #include "Units/Units.hpp"
49 #include "Units/Descriptor.hpp"
50 #include "LocalPath.hpp"
51 #include "Math/Angle.hpp"
52 #include "Util/ConvertString.hpp"
59 RowFormWidget::Row::GetMinimumHeight(bool vertical
) const
66 return widget
->GetMinimumSize().cy
;
72 if (vertical
&& GetControl().HasCaption())
73 return 2 * Layout::GetMinimumControlHeight();
78 return Layout::GetMinimumControlHeight();
80 case Type::MULTI_LINE
:
81 return Layout::GetMinimumControlHeight();
84 return Layout::GetMinimumControlHeight();
87 return window
->GetHeight();
91 RowFormWidget::Row::GetMaximumHeight(bool vertical
) const
98 return widget
->GetMaximumSize().cy
;
104 if (vertical
&& GetControl().HasCaption())
105 return 2 * Layout::GetMinimumControlHeight();
107 return GetControl().IsReadOnly()
108 /* rows that are not clickable don't need to be extra-large */
109 ? Layout::GetMinimumControlHeight()
110 : Layout::GetMaximumControlHeight();
113 return Layout::GetMaximumControlHeight();
115 case Type::MULTI_LINE
:
116 return Layout::GetMinimumControlHeight() * 3;
118 case Type::REMAINING
:
122 return window
->GetHeight();
125 RowFormWidget::RowFormWidget(const DialogLook
&_look
, bool _vertical
)
126 :look(_look
), vertical(_vertical
)
130 RowFormWidget::~RowFormWidget()
133 PanelControl
*panel
= (PanelControl
*)GetWindow();
137 /* destroy all rows */
143 RowFormWidget::SetRowAvailable(unsigned i
, bool available
)
146 if (available
== row
.available
)
149 row
.available
= available
;
154 RowFormWidget::SetRowVisible(unsigned i
, bool visible
)
157 if (visible
== row
.visible
)
160 row
.visible
= visible
;
162 row
.GetWindow().Hide();
163 else if (row
.IsAvailable(UIGlobals::GetDialogSettings().expert
))
164 row
.GetWindow().Show();
168 RowFormWidget::SetExpertRow(unsigned i
)
176 RowFormWidget::Add(Row::Type type
, Window
*window
)
180 assert(window
->GetParent() == GetWindow());
182 assert(window
->IsVisible());
183 /* cannot append rows after a REMAINING row */
184 assert(rows
.empty() || rows
.back().type
!= Row::Type::REMAINING
);
186 rows
.push_back(Row(type
, window
));
190 RowFormWidget::CreateEdit(const TCHAR
*label
, const TCHAR
*help
,
195 const PixelRect edit_rc
=
196 InitialControlRect(Layout::GetMinimumControlHeight());
202 PanelControl
&panel
= *(PanelControl
*)GetWindow();
204 new WndProperty(panel
, look
, label
,
205 edit_rc
, (*label
== '\0') ? 0 : 100,
207 edit
->SetReadOnly(read_only
);
210 edit
->SetHelpText(help
);
216 RowFormWidget::Add(const TCHAR
*label
, const TCHAR
*help
, bool read_only
)
218 WndProperty
*edit
= CreateEdit(label
, help
, read_only
);
219 Add(Row::Type::EDIT
, edit
);
224 RowFormWidget::AddReadOnly(const TCHAR
*label
, const TCHAR
*help
,
227 WndProperty
*control
= Add(label
, help
, true);
229 control
->SetText(text
);
233 RowFormWidget::AddReadOnly(const TCHAR
*label
, const TCHAR
*help
,
234 const TCHAR
*display_format
,
237 WndProperty
*edit
= Add(label
, help
, true);
238 DataFieldFloat
*df
= new DataFieldFloat(display_format
, display_format
,
240 value
, fixed(1), false, NULL
);
241 edit
->SetDataField(df
);
245 RowFormWidget::AddReadOnly(const TCHAR
*label
, const TCHAR
*help
,
246 const TCHAR
*display_format
,
247 UnitGroup unit_group
, fixed value
)
249 WndProperty
*edit
= Add(label
, help
, true);
250 const Unit unit
= Units::GetUserUnitByGroup(unit_group
);
251 value
= Units::ToUserUnit(value
, unit
);
252 DataFieldFloat
*df
= new DataFieldFloat(display_format
, display_format
,
254 value
, fixed(1), false, NULL
);
255 df
->SetUnits(Units::GetUnitName(unit
));
256 edit
->SetDataField(df
);
260 RowFormWidget::AddReadOnly(const TCHAR
*label
, const TCHAR
*help
,
263 WndProperty
*edit
= Add(label
, help
, true);
264 DataFieldBoolean
*df
= new DataFieldBoolean(value
, _("On"), _("Off"),
266 edit
->SetDataField(df
);
270 RowFormWidget::AddFloat(const TCHAR
*label
, const TCHAR
*help
,
271 const TCHAR
*display_format
,
272 const TCHAR
*edit_format
,
273 fixed min_value
, fixed max_value
,
274 fixed step
, bool fine
,
275 UnitGroup unit_group
, fixed value
,
276 DataField::DataAccessCallback callback
)
278 WndProperty
*edit
= Add(label
, help
);
279 const Unit unit
= Units::GetUserUnitByGroup(unit_group
);
280 value
= Units::ToUserUnit(value
, unit
);
281 DataFieldFloat
*df
= new DataFieldFloat(edit_format
, display_format
,
282 min_value
, max_value
,
283 value
, step
, fine
, callback
);
284 df
->SetUnits(Units::GetUnitName(unit
));
285 edit
->SetDataField(df
);
290 RowFormWidget::Add(const TCHAR
*label
, const TCHAR
*help
,
293 WndProperty
*edit
= Add(label
, help
);
294 edit
->SetDataField(df
);
299 RowFormWidget::AddBoolean(const TCHAR
*label
, const TCHAR
*help
,
301 DataField::DataAccessCallback callback
)
303 WndProperty
*edit
= Add(label
, help
);
304 DataFieldBoolean
*df
= new DataFieldBoolean(value
, _("On"), _("Off"),
306 edit
->SetDataField(df
);
311 RowFormWidget::AddInteger(const TCHAR
*label
, const TCHAR
*help
,
312 const TCHAR
*display_format
,
313 const TCHAR
*edit_format
,
314 int min_value
, int max_value
, int step
, int value
,
315 DataField::DataAccessCallback callback
)
317 WndProperty
*edit
= Add(label
, help
);
318 DataFieldInteger
*df
= new DataFieldInteger(edit_format
, display_format
,
319 min_value
, max_value
,
320 value
, step
, callback
);
321 edit
->SetDataField(df
);
326 RowFormWidget::AddFloat(const TCHAR
*label
, const TCHAR
*help
,
327 const TCHAR
*display_format
,
328 const TCHAR
*edit_format
,
329 fixed min_value
, fixed max_value
,
330 fixed step
, bool fine
,
332 DataField::DataAccessCallback callback
)
334 WndProperty
*edit
= Add(label
, help
);
335 DataFieldFloat
*df
= new DataFieldFloat(edit_format
, display_format
,
336 min_value
, max_value
,
337 value
, step
, fine
, callback
);
338 edit
->SetDataField(df
);
343 RowFormWidget::AddAngle(const TCHAR
*label
, const TCHAR
*help
,
344 Angle value
, unsigned step
, bool fine
,
345 DataFieldListener
*listener
)
347 WndProperty
*edit
= Add(label
, help
);
348 AngleDataField
*df
= new AngleDataField(value
, step
, fine
, listener
);
349 edit
->SetDataField(df
);
354 RowFormWidget::AddEnum(const TCHAR
*label
, const TCHAR
*help
,
355 const StaticEnumChoice
*list
, unsigned value
,
356 DataField::DataAccessCallback callback
)
358 assert(list
!= NULL
);
360 WndProperty
*edit
= Add(label
, help
);
361 DataFieldEnum
*df
= new DataFieldEnum(callback
);
363 if (list
[0].help
!= NULL
)
364 df
->EnableItemHelp(true);
366 df
->AddChoices(list
);
369 edit
->SetDataField(df
);
374 RowFormWidget::AddEnum(const TCHAR
*label
, const TCHAR
*help
,
375 DataField::DataAccessCallback callback
)
377 WndProperty
*edit
= Add(label
, help
);
378 DataFieldEnum
*df
= new DataFieldEnum(callback
);
380 edit
->SetDataField(df
);
385 RowFormWidget::AddText(const TCHAR
*label
, const TCHAR
*help
,
386 const TCHAR
*content
)
388 WndProperty
*edit
= Add(label
, help
);
389 DataFieldString
*df
= new DataFieldString(content
, NULL
);
391 edit
->SetDataField(df
);
396 RowFormWidget::AddPassword(const TCHAR
*label
, const TCHAR
*help
,
397 const TCHAR
*content
)
399 WndProperty
*edit
= Add(label
, help
);
400 PasswordDataField
*df
= new PasswordDataField(content
);
402 edit
->SetDataField(df
);
407 RowFormWidget::AddTime(const TCHAR
*label
, const TCHAR
*help
,
408 int min_value
, int max_value
, unsigned step
,
409 int value
, unsigned max_tokens
,
410 DataField::DataAccessCallback callback
)
412 WndProperty
*edit
= Add(label
, help
);
413 DataFieldTime
*df
= new DataFieldTime(min_value
, max_value
, value
,
415 df
->SetMaxTokenNumber(max_tokens
);
416 edit
->SetDataField(df
);
421 RowFormWidget::AddRoughTime(const TCHAR
*label
, const TCHAR
*help
,
422 RoughTime value
, RoughTimeDelta time_zone
,
423 DataFieldListener
*listener
)
425 WndProperty
*edit
= Add(label
, help
);
426 RoughTimeDataField
*df
= new RoughTimeDataField(value
, time_zone
, listener
);
427 edit
->SetDataField(df
);
432 RowFormWidget::AddSpacer()
436 HLine
*window
= new HLine(GetLook());
437 ContainerWindow
&panel
= *(ContainerWindow
*)GetWindow();
438 const PixelRect rc
= InitialControlRect(Layout::Scale(3));
439 window
->Create(panel
, rc
);
444 RowFormWidget::AddFileReader(const TCHAR
*label
, const TCHAR
*help
,
445 const char *registry_key
, const TCHAR
*filters
,
448 WndProperty
*edit
= Add(label
, help
);
449 DataFieldFileReader
*df
= new DataFieldFileReader(NULL
);
450 edit
->SetDataField(df
);
455 df
->ScanMultiplePatterns(filters
);
457 if (registry_key
!= nullptr) {
458 TCHAR path
[MAX_PATH
];
459 if (Profile::GetPath(registry_key
, path
))
463 edit
->RefreshDisplay();
469 RowFormWidget::AddMultiLine(const TCHAR
*text
)
474 InitialControlRect(Layout::GetMinimumControlHeight());
476 LargeTextWindowStyle style
;
477 if (IsEmbedded() || Layout::scale_1024
< 2048)
478 /* sunken edge doesn't fit well on the tiny screen of an embedded
484 PanelControl
&panel
= *(PanelControl
*)GetWindow();
485 LargeTextWindow
*ltw
= new LargeTextWindow();
486 ltw
->Create(panel
, rc
, style
);
487 ltw
->SetFont(*look
.text_font
);
492 Add(Row::Type::MULTI_LINE
, ltw
);
496 RowFormWidget::AddButton(const TCHAR
*label
, ActionListener
&listener
, int id
)
500 const PixelRect button_rc
=
501 InitialControlRect(Layout::GetMinimumControlHeight());
503 ButtonWindowStyle button_style
;
504 button_style
.TabStop();
505 button_style
.multiline();
507 ContainerWindow
&panel
= *(ContainerWindow
*)GetWindow();
509 WndButton
*button
= new WndButton(panel
, look
, label
, button_rc
, button_style
, listener
, id
);
511 Add(Row::Type::BUTTON
, button
);
515 RowFormWidget::SetMultiLineText(unsigned i
, const TCHAR
*text
)
517 assert(text
!= nullptr);
518 assert(rows
[i
].type
== Row::Type::MULTI_LINE
);
520 LargeTextWindow
<w
= *(LargeTextWindow
*)rows
[i
].window
;
525 RowFormWidget::LoadValue(unsigned i
, int value
)
527 WndProperty
&control
= GetControl(i
);
528 DataFieldInteger
&df
= *(DataFieldInteger
*)control
.GetDataField();
529 assert(df
.GetType() == DataField::Type::INTEGER
);
531 control
.RefreshDisplay();
535 RowFormWidget::LoadValue(unsigned i
, bool value
)
537 WndProperty
&control
= GetControl(i
);
538 DataFieldBoolean
&df
= *(DataFieldBoolean
*)control
.GetDataField();
539 assert(df
.GetType() == DataField::Type::BOOLEAN
);
541 control
.RefreshDisplay();
545 RowFormWidget::LoadValueEnum(unsigned i
, unsigned value
)
547 WndProperty
&control
= GetControl(i
);
548 DataFieldEnum
&df
= *(DataFieldEnum
*)control
.GetDataField();
549 assert(df
.GetType() == DataField::Type::ENUM
);
551 control
.RefreshDisplay();
555 RowFormWidget::LoadValue(unsigned i
, fixed value
)
557 WndProperty
&control
= GetControl(i
);
558 DataFieldFloat
&df
= *(DataFieldFloat
*)control
.GetDataField();
559 assert(df
.GetType() == DataField::Type::REAL
);
561 control
.RefreshDisplay();
565 RowFormWidget::LoadValue(unsigned i
, Angle value
)
567 WndProperty
&control
= GetControl(i
);
568 AngleDataField
&df
= *(AngleDataField
*)control
.GetDataField();
569 assert(df
.GetType() == DataField::Type::ANGLE
);
571 control
.RefreshDisplay();
575 RowFormWidget::LoadValue(unsigned i
, fixed value
, UnitGroup unit_group
)
577 const Unit unit
= Units::GetUserUnitByGroup(unit_group
);
578 WndProperty
&control
= GetControl(i
);
579 DataFieldFloat
&df
= *(DataFieldFloat
*)control
.GetDataField();
580 assert(df
.GetType() == DataField::Type::REAL
);
581 df
.Set(Units::ToUserUnit(value
, unit
));
582 df
.SetUnits(Units::GetUnitName(unit
));
583 control
.RefreshDisplay();
587 RowFormWidget::LoadValue(unsigned i
, RoughTime value
)
589 WndProperty
&control
= GetControl(i
);
590 RoughTimeDataField
&df
= *(RoughTimeDataField
*)control
.GetDataField();
592 control
.RefreshDisplay();
596 RowFormWidget::LoadValueTime(unsigned i
, int value
)
598 WndProperty
&control
= GetControl(i
);
599 DataFieldTime
&df
= *(DataFieldTime
*)control
.GetDataField();
600 assert(df
.GetType() == DataField::Type::TIME
);
602 control
.RefreshDisplay();
606 RowFormWidget::GetValueBoolean(unsigned i
) const
608 const DataFieldBoolean
&df
=
609 (const DataFieldBoolean
&)GetDataField(i
);
610 assert(df
.GetType() == DataField::Type::BOOLEAN
);
611 return df
.GetAsBoolean();
615 RowFormWidget::GetValueInteger(unsigned i
) const
617 return GetDataField(i
).GetAsInteger();
621 RowFormWidget::GetValueFloat(unsigned i
) const
623 const DataFieldFloat
&df
=
624 (const DataFieldFloat
&)GetDataField(i
);
625 assert(df
.GetType() == DataField::Type::REAL
);
626 return df
.GetAsFixed();
630 RowFormWidget::GetValueAngle(unsigned i
) const
632 const AngleDataField
&df
=
633 (const AngleDataField
&)GetDataField(i
);
634 assert(df
.GetType() == DataField::Type::ANGLE
);
635 return df
.GetValue();
639 RowFormWidget::GetValueIntegerAngle(unsigned i
) const
641 const AngleDataField
&df
=
642 (const AngleDataField
&)GetDataField(i
);
643 assert(df
.GetType() == DataField::Type::ANGLE
);
644 return df
.GetIntegerValue();
648 RowFormWidget::GetValueRoughTime(unsigned i
) const
650 const RoughTimeDataField
&df
=
651 (const RoughTimeDataField
&)GetDataField(i
);
652 assert(df
.GetType() == DataField::Type::ROUGH_TIME
);
653 return df
.GetValue();
657 RowFormWidget::SaveValue(unsigned i
, bool &value
, bool negated
) const
659 bool new_value
= GetValueBoolean(i
);
661 new_value
= !new_value
;
662 if (new_value
== value
)
670 RowFormWidget::SaveValue(unsigned i
, int &value
) const
672 int new_value
= GetValueInteger(i
);
673 if (new_value
== value
)
681 RowFormWidget::SaveValue(unsigned i
, uint8_t &value
) const
683 int new_value
= GetValueInteger(i
);
684 if (new_value
== value
|| new_value
< 0)
687 value
= (uint8_t)new_value
;
692 RowFormWidget::SaveValue(unsigned i
, uint16_t &value
) const
694 int new_value
= GetValueInteger(i
);
695 if (new_value
== value
|| new_value
< 0)
698 value
= (uint16_t)new_value
;
703 RowFormWidget::SaveValue(unsigned i
, fixed
&value
) const
705 fixed new_value
= GetValueFloat(i
);
706 if (new_value
== value
)
714 RowFormWidget::SaveValue(unsigned i
, Angle
&value_r
) const
716 unsigned old_value
= AngleDataField::Import(value_r
);
717 unsigned new_value
= GetValueIntegerAngle(i
);
718 if (new_value
== old_value
)
721 value_r
= GetValueAngle(i
);
726 RowFormWidget::SaveValue(unsigned i
, RoughTime
&value_r
) const
728 const auto new_value
= GetValueRoughTime(i
);
729 if (new_value
== value_r
)
737 RowFormWidget::SaveValue(unsigned i
, TCHAR
*string
, size_t max_size
) const
739 const TCHAR
*new_value
= GetDataField(i
).GetAsString();
740 assert(new_value
!= NULL
);
742 if (_tcscmp(string
, new_value
) == 0)
745 CopyString(string
, new_value
, max_size
);
750 RowFormWidget::SaveValue(unsigned i
, const char *registry_key
,
751 TCHAR
*string
, size_t max_size
) const
753 if (!SaveValue(i
, string
, max_size
))
756 Profile::Set(registry_key
, string
);
761 RowFormWidget::SaveValue(unsigned i
, const char *registry_key
,
762 bool &value
, bool negated
) const
764 if (!SaveValue(i
, value
, negated
))
767 Profile::Set(registry_key
, value
);
772 RowFormWidget::SaveValue(unsigned i
, const char *registry_key
,
775 if (!SaveValue(i
, value
))
778 Profile::Set(registry_key
, value
);
783 RowFormWidget::SaveValue(unsigned i
, const char *registry_key
,
784 uint8_t &value
) const
786 if (!SaveValue(i
, value
))
789 Profile::Set(registry_key
, value
);
794 RowFormWidget::SaveValue(unsigned i
, const char *registry_key
,
795 uint16_t &value
) const
797 if (!SaveValue(i
, value
))
800 Profile::Set(registry_key
, value
);
805 RowFormWidget::SaveValue(unsigned i
, const char *registry_key
,
808 if (!SaveValue(i
, value
))
811 Profile::Set(registry_key
, value
);
816 RowFormWidget::SaveValue(unsigned i
, UnitGroup unit_group
, fixed
&value
) const
818 const DataFieldFloat
&df
=
819 (const DataFieldFloat
&)GetDataField(i
);
820 assert(df
.GetType() == DataField::Type::REAL
);
822 fixed new_value
= df
.GetAsFixed();
823 const Unit unit
= Units::GetUserUnitByGroup(unit_group
);
824 new_value
= Units::ToSysUnit(new_value
, unit
);
825 if (new_value
> value
- df
.GetStep() / 2 &&
826 new_value
< value
+ df
.GetStep() / 2)
834 RowFormWidget::SaveValue(unsigned i
, UnitGroup unit_group
,
835 const char *registry_key
, fixed
&value
) const
837 const DataFieldFloat
&df
=
838 (const DataFieldFloat
&)GetDataField(i
);
839 assert(df
.GetType() == DataField::Type::REAL
);
841 fixed new_value
= df
.GetAsFixed();
842 const Unit unit
= Units::GetUserUnitByGroup(unit_group
);
843 new_value
= Units::ToSysUnit(new_value
, unit
);
844 if (new_value
> value
- df
.GetStep() / 2 &&
845 new_value
< value
+ df
.GetStep() / 2)
849 Profile::Set(registry_key
, new_value
);
854 RowFormWidget::SaveValue(unsigned i
, UnitGroup unit_group
,
855 const char *registry_key
, unsigned int &value
) const
857 const DataFieldFloat
&df
=
858 (const DataFieldFloat
&)GetDataField(i
);
859 assert(df
.GetType() == DataField::Type::INTEGER
||
860 df
.GetType() == DataField::Type::REAL
);
862 fixed new_value
= df
.GetAsFixed();
863 const Unit unit
= Units::GetUserUnitByGroup(unit_group
);
864 new_value
= Units::ToSysUnit(new_value
, unit
);
865 if ((unsigned int)(new_value
) > value
- iround(df
.GetStep()) / 2 &&
866 (unsigned int)(new_value
) < value
+ iround(df
.GetStep()) / 2)
869 value
= iround(new_value
);
870 Profile::Set(registry_key
, value
);
875 RowFormWidget::SaveValueFileReader(unsigned i
, const char *registry_key
)
877 const DataFieldFileReader
*dfe
=
878 (const DataFieldFileReader
*)GetControl(i
).GetDataField();
879 TCHAR new_value
[MAX_PATH
];
880 _tcscpy(new_value
, dfe
->GetPathFile());
881 ContractLocalPath(new_value
);
883 const WideToUTF8Converter
new_value2(new_value
);
884 if (!new_value2
.IsValid())
887 const char *old_value
= Profile::Get(registry_key
, "");
888 if (StringIsEqual(old_value
, new_value2
))
891 Profile::Set(registry_key
, new_value2
);
896 RowFormWidget::GetRecommendedCaptionWidth() const
898 const bool expert
= UIGlobals::GetDialogSettings().expert
;
901 for (const auto &i
: rows
) {
902 if (!i
.IsAvailable(expert
))
905 if (i
.type
== Row::Type::EDIT
) {
906 unsigned x
= i
.GetControl().GetRecommendedCaptionWidth();
916 RowFormWidget::UpdateLayout()
918 PixelRect current_rect
= GetWindow()->GetClientRect();
919 const unsigned total_width
= current_rect
.right
- current_rect
.left
;
920 const unsigned total_height
= current_rect
.bottom
- current_rect
.top
;
921 current_rect
.bottom
= current_rect
.top
;
923 const bool expert
= UIGlobals::GetDialogSettings().expert
;
925 /* first row traversal: count the number of "elastic" rows and
926 determine the minimum total height */
927 unsigned min_height
= 0;
928 unsigned n_elastic
= 0;
929 unsigned caption_width
= 0;
931 for (const auto &i
: rows
) {
932 if (!i
.IsAvailable(expert
))
935 min_height
+= i
.GetMinimumHeight(vertical
);
936 if (i
.IsElastic(vertical
))
939 if (!vertical
&& i
.type
== Row::Type::EDIT
) {
940 unsigned cw
= i
.GetControl().GetRecommendedCaptionWidth();
941 if (cw
> caption_width
)
946 if (!vertical
&& caption_width
* 3 > total_width
* 2)
947 caption_width
= total_width
* 2 / 3;
949 /* how much excess height in addition to the minimum height? */
950 unsigned excess_height
= min_height
< total_height
951 ? total_height
- min_height
954 /* second row traversal: now move and resize the rows */
955 for (auto &i
: rows
) {
956 if (!i
.IsAvailable(expert
)) {
957 if (i
.type
== Row::Type::WIDGET
)
958 i
.GetWidget().Hide();
959 else if (i
.type
!= Row::Type::DUMMY
)
960 i
.GetWindow().Hide();
965 /* determine this row's height */
966 UPixelScalar height
= i
.GetMinimumHeight(vertical
);
967 if (excess_height
> 0 && i
.IsElastic(vertical
)) {
968 assert(n_elastic
> 0);
970 /* distribute excess height among all elastic rows */
971 unsigned grow_height
= excess_height
/ n_elastic
;
972 if (grow_height
> 0) {
973 height
+= grow_height
;
974 const UPixelScalar max_height
= i
.GetMaximumHeight(vertical
);
975 if (height
> max_height
) {
976 /* never grow beyond declared maximum height */
978 grow_height
= max_height
- height
;
981 excess_height
-= grow_height
;
987 if (i
.type
== Row::Type::WIDGET
) {
988 Widget
&widget
= i
.GetWidget();
990 /* TODO: visible check - hard to implement without remembering
991 the control position, because Widget::Show() wants a
992 PixelRect parameter */
994 NextControlRect(current_rect
, height
);
996 if (!i
.initialised
) {
997 i
.initialised
= true;
998 widget
.Initialise(*(ContainerWindow
*)GetWindow(), current_rect
);
1003 widget
.Prepare(*(ContainerWindow
*)GetWindow(), current_rect
);
1006 widget
.Show(current_rect
);
1010 Window
&window
= i
.GetWindow();
1015 if (i
.type
== Row::Type::EDIT
&&
1016 i
.GetControl().HasCaption()) {
1018 i
.GetControl().SetCaptionWidth(-1);
1019 else if (caption_width
> 0)
1020 i
.GetControl().SetCaptionWidth(caption_width
);
1023 /* finally move and resize */
1024 NextControlRect(current_rect
, height
);
1025 window
.Move(current_rect
);
1028 assert(excess_height
== 0 || n_elastic
== 0);
1032 RowFormWidget::GetMinimumSize() const
1034 const unsigned value_width
=
1035 look
.text_font
->TextSize(_T("Foo Bar Foo Bar")).cx
;
1037 const bool expert
= UIGlobals::GetDialogSettings().expert
;
1039 const unsigned edit_width
= vertical
1040 ? std::max(GetRecommendedCaptionWidth(), value_width
)
1041 : (GetRecommendedCaptionWidth() + value_width
);
1043 PixelSize
size(edit_width
, 0u);
1044 for (const auto &i
: rows
)
1045 if (i
.IsAvailable(expert
))
1046 size
.cy
+= i
.GetMinimumHeight(vertical
);
1052 RowFormWidget::GetMaximumSize() const
1054 const unsigned value_width
=
1055 look
.text_font
->TextSize(_T("Foo Bar Foo Bar")).cx
* 2;
1057 const unsigned edit_width
= vertical
1058 ? std::max(GetRecommendedCaptionWidth(), value_width
)
1059 : (GetRecommendedCaptionWidth() + value_width
);
1061 PixelSize
size(edit_width
, 0u);
1062 for (const auto &i
: rows
)
1063 size
.cy
+= i
.GetMaximumHeight(vertical
);
1069 RowFormWidget::Initialise(ContainerWindow
&parent
, const PixelRect
&rc
)
1071 assert(!IsDefined());
1072 assert(rows
.empty());
1076 style
.ControlParent();
1078 SetWindow(new PanelControl(parent
, look
, rc
, style
));
1082 RowFormWidget::Show(const PixelRect
&rc
)
1084 PanelControl
&panel
= *(PanelControl
*)GetWindow();
1093 RowFormWidget::Move(const PixelRect
&rc
)
1095 PanelControl
&panel
= *(PanelControl
*)GetWindow();
1102 RowFormWidget::SetFocus()
1107 PanelControl
&panel
= *(PanelControl
*)GetWindow();
1108 return panel
.FocusFirstControl();