1 /*****************************************************************************/
2 /* */
3 /* MENUITEM.CC */
4 /* */
5 /* (C) 1993-96 Ullrich von Bassewitz */
6 /* Wacholderweg 14 */
7 /* D-70597 Stuttgart */
8 /* EMail: uz@ibb.schwaben.com */
9 /* */
10 /*****************************************************************************/
11
12
13
14 // $Id$
15 //
16 // $Log$
17 //
18 //
19
20
21
22 #include "menuitem.h"
23 #include "winattr.h"
24 #include "menuedit.h"
25 #include "progutil.h"
26 #include "streamid.h"
27 #include "strcvt.h"
28 #include "msgid.h"
29
30
31
32 // Register the classes
33 LINK (MenueLine, ID_MenueLine);
34 LINK (LongItem, ID_LongItem);
35 LINK (HexItem, ID_HexItem);
36 LINK (StringItem, ID_StringItem);
37 LINK (ToggleItem, ID_ToggleItem);
38 LINK (OffOnItem, ID_OffOnItem);
39 LINK (NoYesItem, ID_NoYesItem);
40 LINK (FloatItem, ID_FloatItem);
41 LINK (TimeItem, ID_TimeItem);
42 LINK (DateItem, ID_DateItem);
43 LINK (RStringItem, ID_RStringItem);
44
45
46
47 /*****************************************************************************/
48 /* Message constants */
49 /*****************************************************************************/
50
51
52
53 static const u16 msOffOn = MSGBASE_MENUITEM + 0;
54 static const u16 msNoYes = MSGBASE_MENUITEM + 1;
55
56
57
58 /*****************************************************************************/
59 /* class MenueLine */
60 /*****************************************************************************/
61
62
63
MenueLine(i16 aID,WindowItem * NextItem)64 MenueLine::MenueLine (i16 aID, WindowItem *NextItem) :
65 MenueItem ("", aID, NextItem)
66 {
67 // Menuelines are inactive objects
68 Flags |= ifInactive;
69 }
70
71
72
StreamableID() const73 u16 MenueLine::StreamableID () const
74 {
75 return ID_MenueLine;
76 }
77
78
79
Build()80 Streamable* MenueLine::Build ()
81 {
82 return new MenueLine (Empty);
83 }
84
85
86
BuildEntry(const String &)87 void MenueLine::BuildEntry (const String&)
88 // Rebuild Entry when the length has changed. The given String is
89 // ignored.
90 {
91 // Cut the entry string if it is longer than the new width
92 Entry.Trunc (ItemWidth);
93
94 // Construct a new display string
95 Entry.Set (0, ItemWidth, InactiveFrame [fcHorizontal]);
96
97 // Optimize memory
98 Entry.Settle ();
99 }
100
101
102
MinWidth()103 u16 MenueLine::MinWidth ()
104 {
105 // A line has min width zero
106 return 0;
107 }
108
109
110
111 /*****************************************************************************/
112 /* class EditMenueItem */
113 /*****************************************************************************/
114
115
116
EditMenueItem(const String & aItemText,i16 aID,i16 EditID,ItemWindow * EditWin,WindowItem * NextItem)117 EditMenueItem::EditMenueItem (const String& aItemText, i16 aID, i16 EditID,
118 ItemWindow* EditWin, WindowItem* NextItem) :
119 MenueItem (aItemText, aID, NextItem),
120 EditWindow (EditWin), EditItemID (EditID)
121 {
122 }
123
124
125
~EditMenueItem()126 EditMenueItem::~EditMenueItem ()
127 {
128 delete EditWindow;
129 }
130
131
132
Store(Stream & S) const133 void EditMenueItem::Store (Stream &S) const
134 // Store the object data into a stream
135 {
136 // Store parental data
137 MenueItem::Store (S);
138
139 // Store instance data
140 S << EditItemID;
141 S.Put (EditWindow);
142 }
143
144
145
Load(Stream & S)146 void EditMenueItem::Load (Stream &S)
147 // Load the object data from a stream
148 {
149 // Load parental data
150 MenueItem::Load (S);
151
152 // Load instance data
153 S >> EditItemID;
154 EditWindow = (ItemWindow *) S.Get ();
155 }
156
157
158
PlaceEditWindow()159 void EditMenueItem::PlaceEditWindow ()
160 // Place the edit window below this entry if EditWindow has no position
161 // (== has position 0/0).
162 {
163 if (EditWindow) {
164
165 // Get the coords of the edit window
166 Rect Bounds (EditWindow->OuterBounds ());
167
168 if (Bounds.A == Point (0, 0)) {
169
170 // The edit window has no position. Get the coords of the
171 // item and make them absolute
172 Point P (ItemX, ItemY);
173 Owner->Absolute (P);
174
175 // Now place the edit window below the entry
176 P.Y++;
177 EditWindow->MoveRel (P);
178 }
179 }
180 }
181
182
183
ItemWithID(i16 aID)184 WindowItem* EditMenueItem::ItemWithID (i16 aID)
185 // Search for the item with the given ID. The editwindow (if one exists)
186 // is also searched.
187 {
188 if (ID == aID) {
189 return this;
190 } else {
191 return EditWindow ? EditWindow->ItemWithID (aID) : (WindowItem*) NULL;
192 }
193 }
194
195
196
SetEditWindow(ItemWindow * Win,i16 EditID)197 void EditMenueItem::SetEditWindow (ItemWindow *Win, i16 EditID)
198 // Set the edit window. Beware: An already existing edit window is not
199 // deleted!
200 {
201 // Check the given parameters
202 PRECONDITION (Win == NULL || EditID != 0);
203
204 // Store them
205 EditWindow = Win;
206 EditItemID = EditID;
207 }
208
209
210
211 /*****************************************************************************/
212 /* class LongItem */
213 /*****************************************************************************/
214
215
216
LongItem(const String & aItemText,i16 aID,u16 aDigits,i16 EditID,i32 Min,i32 Max,WindowItem * NextItem)217 LongItem::LongItem (const String& aItemText, i16 aID, u16 aDigits, i16 EditID,
218 i32 Min, i32 Max, WindowItem* NextItem) :
219 EditMenueItem (aItemText, aID, EditID, NULL, NextItem),
220 LValue (Min),
221 Digits (aDigits),
222 LMin (Min),
223 LMax (Max)
224 {
225 }
226
227
228
LongItem(const String & aItemText,i16 aID,u16 aDigits,WindowItem * NextItem)229 LongItem::LongItem (const String& aItemText, i16 aID, u16 aDigits,
230 WindowItem* NextItem) :
231 EditMenueItem (aItemText, aID, 0, NULL, NextItem),
232 LValue (0),
233 Digits (aDigits),
234 LMin (0x80000000),
235 LMax (0x7FFFFFFF)
236 {
237 }
238
239
240
Load(Stream & S)241 void LongItem::Load (Stream &S)
242 // Load the object data from a stream
243 {
244 // Load parental data
245 EditMenueItem::Load (S);
246
247 // Load instance data
248 S >> LValue >> Digits >> LMin >> LMax;
249 }
250
251
252
Store(Stream & S) const253 void LongItem::Store (Stream &S) const
254 // Store the object data into a stream
255 {
256 // Store parental data
257 EditMenueItem::Store (S);
258
259 // Store instance data
260 S << LValue << Digits << LMin << LMax;
261 }
262
263
264
StreamableID() const265 u16 LongItem::StreamableID () const
266 {
267 return ID_LongItem;
268 }
269
270
271
Build()272 Streamable* LongItem::Build ()
273 {
274 return new LongItem (Empty);
275 }
276
277
278
SetWidth(u16 NewWidth)279 void LongItem::SetWidth (u16 NewWidth)
280 {
281 // Check against the minimum width needed
282 if (NewWidth < MinWidth ()) {
283 // Ignore the request
284 return;
285 }
286
287 // Store the new width
288 ItemWidth = NewWidth;
289
290 // Convert the number to string
291 String S (I32Str (LValue));
292 S.ForceLen (Digits, String::Left);
293 S.Ins (0, ' ');
294 BuildEntry (S);
295 }
296
297
298
MinWidth()299 u16 LongItem::MinWidth ()
300 {
301 u16 Len = ItemText.Len ();
302 u16 Width = Len + Digits + 2; // One space to the left and right
303 if (Len) {
304 Width += 2; // Space between text and number
305 }
306 return Width;
307 }
308
309
310
Choose()311 i16 LongItem::Choose ()
312 // Choose the entry. If an edit window is defined (EditWindow != NULL),
313 // the entry with id EditItemID in EditWindow is called. If there was
314 // no abort (or EditWindow is not defined), the id of this item is
315 // returned.
316 {
317 LongEdit *P;
318 int Abort;
319 i16 Result;
320
321 // If the edit id is zero, return the own id
322 if (EditItemID == 0) {
323 return ID;
324 }
325
326 // Check if a predefined window exists
327 if (EditWindow) {
328
329 // Move the window to the correct position
330 PlaceEditWindow ();
331
332 // Allow editing the value
333 P = (LongEdit *) EditWindow->ForcedItemWithID (EditItemID);
334 P->SetValue (LValue);
335 P->Edit (Abort);
336
337 // if no abort, set the value and return the id
338 if (Abort) {
339 Result = 0;
340 } else {
341 SetValue (P->GetValue ());
342 Result = ID;
343 }
344
345 } else {
346
347 // No item defined, we have to create one
348 P = new LongEdit ("", EditItemID, Digits, NULL);
349
350 // Insert the item into the owner window
351 Owner->AddItem (P);
352
353 // Set the position of the newly created item
354 P->SetPos (ItemX + ItemWidth - P->GetWidth (), ItemY);
355
356 // Deselect "this"
357 Deselect ();
358
359 // Transfer the values from "this" to the new item. Calling
360 // SetValue will also draw the edit item
361 P->SetMinMax (LMin, LMax);
362 P->SetValue (LValue);
363
364 // allow editing
365 P->Edit (Abort);
366
367 // Get the edited value if the editing was not aborted
368 if (Abort) {
369 Result = 0;
370 } else {
371 SetValue (P->GetValue ());
372 Result = ID;
373 }
374
375 // Delete the edit item from the owners list
376 Owner->DeleteItem (P);
377
378 // Select "this". This redraws the item and clears the edit field
379 Select ();
380
381 }
382
383 // Return the result
384 return Result;
385
386 }
387
388
389
SetValue(i32 Val)390 void LongItem::SetValue (i32 Val)
391 {
392 // Store the new value
393 LValue = Val;
394
395 // Build the new display text. As the number of digits is fixed,
396 // the length cannot change.
397 // Use SetWidth with the current width to do that
398 SetWidth (ItemWidth);
399
400 // Now redraw the item
401 Draw ();
402 }
403
404
405
SetMinMax(i32 Min,i32 Max)406 void LongItem::SetMinMax (i32 Min, i32 Max)
407 {
408 // Check parameters
409 PRECONDITION (Min <= Max);
410
411 LMin = Min;
412 LMax = Max;
413 }
414
415
416
417 /*****************************************************************************/
418 /* class HexItem */
419 /*****************************************************************************/
420
421
422
StreamableID() const423 u16 HexItem::StreamableID () const
424 {
425 return ID_LongItem;
426 }
427
428
429
Build()430 Streamable* HexItem::Build ()
431 {
432 return new HexItem (Empty);
433 }
434
435
436
SetWidth(u16 NewWidth)437 void HexItem::SetWidth (u16 NewWidth)
438 {
439 // Check against the minimum width needed
440 if (NewWidth < MinWidth ()) {
441 // Ignore the request
442 return;
443 }
444
445 // Store the new width
446 ItemWidth = NewWidth;
447
448 // Convert the number to string
449 String S (U32Str (LValue, 16));
450 S.ForceLen (Digits, String::Left);
451 S.Ins (0, ' ');
452 BuildEntry (S);
453 }
454
455
456
Choose()457 i16 HexItem::Choose ()
458 // Choose the entry. If an edit window is defined (EditWindow != NULL),
459 // the entry with id EditItemID in EditWindow is called. If there was
460 // no abort (or EditWindow is not defined), the id of this item is
461 // returned.
462 {
463 HexEdit *P;
464 int Abort;
465 i16 Result;
466
467 // If the edit id is zero, return the own id
468 if (EditItemID == 0) {
469 return ID;
470 }
471
472 // Check if a predefined window exists
473 if (EditWindow) {
474
475 // Move the window to the correct position
476 PlaceEditWindow ();
477
478 // Allow editing the value
479 P = (HexEdit *) EditWindow->ForcedItemWithID (EditItemID);
480 P->SetValue (LValue);
481 P->Edit (Abort);
482
483 // if no abort, set the value and return the id
484 if (Abort) {
485 Result = 0;
486 } else {
487 SetValue (P->GetValue ());
488 Result = ID;
489 }
490
491 } else {
492
493 // No item defined, we have to create one
494 P = new HexEdit ("", EditItemID, Digits, NULL);
495
496 // Insert the item into the owner window
497 Owner->AddItem (P);
498
499 // Set the position of the newly created item
500 P->SetPos (ItemX + ItemWidth - P->GetWidth (), ItemY);
501
502 // Deselect "this"
503 Deselect ();
504
505 // Transfer the values from "this" to the new item. Calling
506 // SetValue will also draw the edit item
507 P->SetMinMax (LMin, LMax);
508 P->SetValue (LValue);
509
510 // allow editing
511 P->Edit (Abort);
512
513 // Get the edited value if the editing was not aborted
514 if (Abort) {
515 Result = 0;
516 } else {
517 SetValue (P->GetValue ());
518 Result = ID;
519 }
520
521 // Delete the edit item from the owners list
522 Owner->DeleteItem (P);
523
524 // Select "this". This redraws the item and clears the edit field
525 Select ();
526
527 }
528
529 // Return the result
530 return Result;
531
532 }
533
534
535
536 /*****************************************************************************/
537 /* class StringItem */
538 /*****************************************************************************/
539
540
541
StringItem(const String & aItemText,i16 aID,i16 EditID,WindowItem * NextItem)542 StringItem::StringItem (const String& aItemText, i16 aID, i16 EditID,
543 WindowItem* NextItem) :
544 EditMenueItem (aItemText, aID, EditID, NULL, NextItem)
545 {
546 // Allow all input chars
547 AllowedChars.SetAll ();
548 }
549
550
551
StringItem(StreamableInit)552 StringItem::StringItem (StreamableInit) :
553 EditMenueItem (Empty),
554 SValue (Empty)
555 {
556 // Allow all chars
557 AllowedChars.SetAll ();
558 }
559
560
561
Load(Stream & S)562 void StringItem::Load (Stream &S)
563 // Load the object data from a stream
564 {
565 // Load parental data
566 EditMenueItem::Load (S);
567
568 // Load instance data
569 S >> SValue;
570 }
571
572
573
Store(Stream & S) const574 void StringItem::Store (Stream &S) const
575 // Store the object data into a stream
576 {
577 // Store parental data
578 EditMenueItem::Store (S);
579
580 // Store instance data
581 S << SValue;
582 }
583
584
585
StreamableID() const586 u16 StringItem::StreamableID () const
587 {
588 return ID_StringItem;
589 }
590
591
592
Build()593 Streamable* StringItem::Build ()
594 {
595 return new StringItem (Empty);
596 }
597
598
599
SetWidth(u16 NewWidth)600 void StringItem::SetWidth (u16 NewWidth)
601 {
602 // Check against the minimum width needed
603 u16 MinW = MinWidth ();
604 if (NewWidth < MinW) {
605 // Ignore the request
606 return;
607 }
608
609 // Store the new width
610 ItemWidth = NewWidth;
611
612 // Get a copy of the value string, pad it left to the length needed
613 String S (SValue);
614 S.Pad (String::Left, ItemWidth - MinW);
615
616 // Build the new entry
617 S.Ins (0, ' ');
618 BuildEntry (S);
619 }
620
621
622
MinWidth()623 u16 StringItem::MinWidth ()
624 {
625 u16 Len = ItemText.Len ();
626 u16 Width = Len + 2; // One space to the left and right
627 if (Len > 0) {
628 Width += 2; // Add two spaces between text and string
629 }
630 return Width;
631 }
632
633
634
Choose()635 i16 StringItem::Choose ()
636 // Choose the entry. If an edit window is defined (EditWindow != NULL),
637 // the entry with id EditItemID in EditWindow is called. If there was
638 // no abort (or EditWindow is not defined), the id of this item is
639 // returned.
640 {
641 int Abort;
642 i16 Result;
643
644 // If the edit id is zero, return the own id
645 if (EditItemID == 0) {
646 return ID;
647 }
648
649 // Check if a predefined window exists
650 if (EditWindow) {
651
652 // Move the window to the correct position
653 PlaceEditWindow ();
654
655 // Allow editing the value
656 TextEdit* P = (TextEdit*) EditWindow->ForcedItemWithID (EditItemID);
657 P->SetValue (SValue);
658 P->Edit (Abort);
659
660 // if no abort, set the value and return the id
661 if (Abort) {
662 Result = 0;
663 } else {
664 SetValue (P->GetValue ());
665 Result = ID;
666 }
667
668 } else {
669
670 // No item defined, we have to create one
671 u16 Len = ItemWidth - MinWidth () - 1;
672 TextEdit* P = new TextEdit ("", EditItemID, Len-1, Len, NULL);
673
674 // Set the allowed characters for input
675 P->SetAllowedChars (AllowedChars);
676
677 // Insert the item into the owner window
678 Owner->AddItem (P);
679
680 // Set the position of the newly created item
681 P->SetPos (ItemX + ItemWidth - P->GetWidth (), ItemY);
682
683 // Deselect "this"
684 Deselect ();
685
686 // Transfer the values from "this" to the new item. Calling
687 // SetValue will also draw the edit item
688 P->SetValue (SValue);
689
690 // allow editing
691 P->Edit (Abort);
692
693 // Get the edited value if the editing was not aborted
694 if (Abort) {
695 Result = 0;
696 } else {
697 SetValue (P->GetValue ());
698 Result = ID;
699 }
700
701 // Delete the edit item from the owners list
702 Owner->DeleteItem (P);
703
704 // Select "this". This redraws the item and clears the edit field
705 Select ();
706
707 }
708
709 // Return the result
710 return Result;
711
712 }
713
714
715
SetValue(const String & NewVal)716 void StringItem::SetValue (const String& NewVal)
717 {
718 // Store the new value
719 SValue = NewVal;
720 SValue.Settle ();
721
722 // Build the new display text. As the number of digits is fixed,
723 // the length cannot change.
724 // Use SetWidth with the current width to do that
725 SetWidth (ItemWidth);
726
727 // Now redraw the item
728 Draw ();
729 }
730
731
732
GetAllowedChars() const733 const CharSet& StringItem::GetAllowedChars () const
734 // Get the set of allowed input chars
735 {
736 return AllowedChars;
737 }
738
739
740
SetAllowedChars(const CharSet & CS)741 void StringItem::SetAllowedChars (const CharSet& CS)
742 // Set the allowed input chars
743 {
744 AllowedChars = CS;
745 }
746
747
748
AllowEmptyInput()749 void StringItem::AllowEmptyInput ()
750 // Allow an empty input
751 {
752 AllowedChars += '\0';
753 }
754
755
756
DisallowEmptyInput()757 void StringItem::DisallowEmptyInput ()
758 // Disallow an empty input line
759 {
760 AllowedChars -= '\0';
761 }
762
763
764
765 /*****************************************************************************/
766 /* class ToggleItem */
767 /*****************************************************************************/
768
769
770
ToggleItem(const String & aItemText,i16 aID,const String & ToggleList,unsigned ToggleCount,WindowItem * NextItem)771 ToggleItem::ToggleItem (const String& aItemText, i16 aID,
772 const String& ToggleList, unsigned ToggleCount,
773 WindowItem* NextItem) :
774 StringItem (aItemText, aID, 0, NextItem),
775 TValue (0),
776 TCount (ToggleCount),
777 TList (ToggleList)
778 {
779 // Get the length of the value list
780 u16 Len = TList.Len ();
781
782 // Check the parameters
783 PRECONDITION (Len != 0 && TCount != 0 && (Len % TCount) == 0);
784
785 // Initialize variables
786 ItemWidth = MinWidth ();
787 TLen = Len / TCount;
788 SValue = TList.Cut (0, TLen);
789 }
790
791
792
Load(Stream & S)793 void ToggleItem::Load (Stream& S)
794 // Load an object from a stream
795 {
796 // Load parental data
797 StringItem::Load (S);
798
799 // Load new data
800 S >> TValue >> TCount >> TLen >> TList;
801 }
802
803
804
Store(Stream & S) const805 void ToggleItem::Store (Stream& S) const
806 // Store an object into a stream
807 {
808 // Store parental data
809 StringItem::Store (S);
810
811 // Store new data
812 S << TValue << TCount << TLen << TList;
813 }
814
815
816
StreamableID() const817 u16 ToggleItem::StreamableID () const
818 {
819 return ID_ToggleItem;
820 }
821
822
823
Build()824 Streamable* ToggleItem::Build ()
825 {
826 return new ToggleItem (Empty);
827 }
828
829
830
SetValue(u16 NewVal)831 void ToggleItem::SetValue (u16 NewVal)
832 // Set the new value of the toggle item
833 {
834 // Check the new value
835 PRECONDITION (NewVal < TCount);
836
837 // Remember the new value
838 TValue = NewVal;
839
840 // Use the inherited function to set the actual value
841 StringItem::SetValue (TList.Cut (TValue * TLen, TLen));
842 }
843
844
845
Toggle()846 void ToggleItem::Toggle ()
847 // Toggle the value
848 {
849 // Select the next value
850 if (++TValue >= TCount) {
851 TValue = 0;
852 }
853 SetValue (TValue);
854 }
855
856
857
SetWidth(u16 NewWidth)858 void ToggleItem::SetWidth (u16 NewWidth)
859 // Set the new entry width
860 {
861 // Check if the new width is acceptable
862 u16 WMin = MinWidth ();
863 if (NewWidth < WMin) {
864 // Ignore the request
865 return;
866 }
867
868 // Remember the new value
869 ItemWidth = NewWidth;
870
871 // Build the new entry
872 if (SValue.Len () == 0) {
873 BuildEntry (" ");
874 } else {
875 String S;
876 S.Set (0, ItemWidth - WMin);
877
878 // One space between value and itemtext
879 if (ItemText.Len () != 0) {
880 S += ' ';
881 }
882
883 BuildEntry (S + SValue);
884 }
885
886 }
887
888
889
MinWidth()890 u16 ToggleItem::MinWidth ()
891 // return the width needed
892 {
893 u16 Len = ItemText.Len ();
894 return Len ? Len + TLen + 4 : Len + TLen + 2;
895 }
896
897
898
ItemWithID(i16 aID)899 WindowItem * ToggleItem::ItemWithID (i16 aID)
900 // Return a pointer to this if the given ID is the ID of the object.
901 // A ToggleItem uses all IDs from ID to ID + ToggleCount - 1
902 {
903 if (aID >= ID && aID < (ID + TCount)) {
904 return this;
905 } else {
906 return NULL;
907 }
908 }
909
910
911
GetID()912 i16 ToggleItem::GetID ()
913 // Return the ID of the entry. The returned ID is the ID of the item plus
914 // the current toggle value
915 {
916 return ID + TValue;
917 }
918
919
920
Choose()921 i16 ToggleItem::Choose ()
922 // Choose this entry. This implementation toggles to the next value and
923 // returns the corresponding ID
924 {
925 // No chance if the item is inactive
926 if (!IsActive ()) {
927 return 0;
928 }
929
930 // Select and show the next toggle value
931 Toggle ();
932
933 // Now return the ID
934 return GetID ();
935 }
936
937
938
939 /*****************************************************************************/
940 /* class OffOnItem */
941 /*****************************************************************************/
942
943
944
OffOnItem(const String & aItemText,i16 aID,WindowItem * NextItem)945 OffOnItem::OffOnItem (const String& aItemText, i16 aID, WindowItem* NextItem) :
946 ToggleItem (aItemText, aID, LoadMsg (msOffOn), 2, NextItem)
947 {
948 }
949
950
951
StreamableID() const952 u16 OffOnItem::StreamableID () const
953 {
954 return ID_OffOnItem;
955 }
956
957
958
Load(Stream & S)959 void OffOnItem::Load (Stream& S)
960 {
961 // Load data from ToggleItem
962 ToggleItem::Load (S);
963
964 // Now override the toggle text (loading this instance in a new language
965 // environment should show the new language when loaded)
966 TList = LoadMsg (msOffOn);
967 TLen = TList.Len () / 2;
968 SValue = TList.Cut (TValue * TLen, TLen);
969 }
970
971
972
Build()973 Streamable* OffOnItem::Build ()
974 {
975 return new OffOnItem (Empty);
976 }
977
978
979
980 /*****************************************************************************/
981 /* class NoYesItem */
982 /*****************************************************************************/
983
984
985
NoYesItem(const String & aItemText,i16 aID,WindowItem * NextItem)986 NoYesItem::NoYesItem (const String& aItemText, i16 aID, WindowItem* NextItem) :
987 ToggleItem (aItemText, aID, LoadMsg (msNoYes), 2, NextItem)
988 {
989 }
990
991
992
StreamableID() const993 u16 NoYesItem::StreamableID () const
994 {
995 return ID_NoYesItem;
996 }
997
998
999
Load(Stream & S)1000 void NoYesItem::Load (Stream& S)
1001 {
1002 // Load data from ToggleItem
1003 ToggleItem::Load (S);
1004
1005 // Now override the toggle text (loading this instance in a new language
1006 // environment should show the new language when loaded)
1007 TList = LoadMsg (msNoYes);
1008 TLen = TList.Len () / 2;
1009 SValue = TList.Cut (TValue * TLen, TLen);
1010 }
1011
1012
1013
Build()1014 Streamable* NoYesItem::Build ()
1015 {
1016 return new NoYesItem (Empty);
1017 }
1018
1019
1020
1021 /*****************************************************************************/
1022 /* class FloatItem */
1023 /*****************************************************************************/
1024
1025
1026
FloatItem(const String & aItemText,i16 aID,u16 aLD,u16 aTD,u16 EditID,double Min,double Max,WindowItem * NextItem)1027 FloatItem::FloatItem (const String& aItemText, i16 aID, u16 aLD, u16 aTD,
1028 u16 EditID, double Min, double Max, WindowItem* NextItem) :
1029 EditMenueItem (aItemText, aID, EditID, NULL, NextItem),
1030 FValue (Min),
1031 LD (aLD),
1032 TD (aTD),
1033 FMin (Min),
1034 FMax (Max)
1035 {
1036 }
1037
1038
1039
FloatItem(const String & aItemText,i16 aID,u16 aLD,u16 aTD,WindowItem * NextItem)1040 FloatItem::FloatItem (const String& aItemText, i16 aID, u16 aLD, u16 aTD,
1041 WindowItem* NextItem) :
1042 EditMenueItem (aItemText, aID, 0, NULL, NextItem),
1043 FValue (0),
1044 LD (aLD),
1045 TD (aTD),
1046 FMin (-100000),
1047 FMax (+100000)
1048 {
1049 }
1050
1051
1052
Load(Stream & S)1053 void FloatItem::Load (Stream &S)
1054 // Load the instance from a stream
1055 {
1056 EditMenueItem::Load (S);
1057 S >> FValue >> LD >> TD >> FMin >> FMax;
1058 }
1059
1060
1061
Store(Stream & S) const1062 void FloatItem::Store (Stream &S) const
1063 // Store the instance into a stream
1064 {
1065 EditMenueItem::Store (S);
1066 S << FValue << LD << TD << FMin << FMax;
1067 }
1068
1069
1070
StreamableID() const1071 u16 FloatItem::StreamableID () const
1072 {
1073 return ID_FloatItem;
1074 }
1075
1076
1077
Build()1078 Streamable* FloatItem::Build ()
1079 {
1080 return new FloatItem (Empty);
1081 }
1082
1083
1084
SetValue(double Val)1085 void FloatItem::SetValue (double Val)
1086 // Set the new value of the float item
1087 {
1088 // Store the new value
1089 FValue = Val;
1090
1091 // Build the new display text. As the number of digits is fixed,
1092 // the length cannot change.
1093 // Use SetWidth with the current width to do that
1094 SetWidth (ItemWidth);
1095
1096 // Now redraw the item
1097 Draw ();
1098 }
1099
1100
1101
SetMinMax(double Min,double Max)1102 void FloatItem::SetMinMax (double Min, double Max)
1103 // Set the values for FMin/FMax
1104 {
1105 FMin = Min;
1106 FMax = Max;
1107 }
1108
1109
1110
SetWidth(u16 NewWidth)1111 void FloatItem::SetWidth (u16 NewWidth)
1112 // Set the new entry width
1113 {
1114 // Check against the minimum width needed
1115 if (NewWidth < MinWidth ()) {
1116 // Ignore the request
1117 return;
1118 }
1119
1120 // Store the new width
1121 ItemWidth = NewWidth;
1122
1123 // Build the new entry
1124 String S (FloatStr (FValue, LD, TD));
1125 S.ForceLen (TD ? LD + TD + 1 : LD, String::Left);
1126 BuildEntry (S);
1127 }
1128
1129
1130
MinWidth()1131 u16 FloatItem::MinWidth ()
1132 // return the width needed
1133 {
1134 u16 Len = ItemText.Len ();
1135 u16 Width = Len + 2 + LD + TD; // one space left and right
1136 if (TD > 0) {
1137 Width++; // Decimal point
1138 }
1139 if (Len > 0) {
1140 Width += 2; // Space between float and text
1141 }
1142 return Width;
1143 }
1144
1145
1146
Choose()1147 i16 FloatItem::Choose ()
1148 // Choose the entry. If an edit window is defined (EditWindow != NULL),
1149 // the entry with id EditItemID in EditWindow is called. If there was
1150 // no abort (or EditWindow is not defined), the id of this item is
1151 // returned.
1152 {
1153 FloatEdit *P;
1154 int Abort;
1155 i16 Result;
1156
1157 // If the edit id is zero, return the own id
1158 if (EditItemID == 0) {
1159 return ID;
1160 }
1161
1162 // Check if a predefined window exists
1163 if (EditWindow) {
1164
1165 // Move the window to the correct position
1166 PlaceEditWindow ();
1167
1168 // Allow editing the value
1169 P = (FloatEdit *) EditWindow->ForcedItemWithID (EditItemID);
1170 P->SetValue (FValue);
1171 P->Edit (Abort);
1172
1173 // if no abort, set the value and return the id
1174 if (Abort) {
1175 Result = 0;
1176 } else {
1177 SetValue (P->GetValue ());
1178 Result = ID;
1179 }
1180
1181 } else {
1182
1183 // No item defined, we have to create one
1184 P = new FloatEdit ("", EditItemID, LD, TD, NULL);
1185
1186 // Insert the item into the owner window
1187 Owner->AddItem (P);
1188
1189 // Set the position of the newly created item
1190 P->SetPos (ItemX + ItemWidth - P->GetWidth (), ItemY);
1191
1192 // Deselect "this"
1193 Deselect ();
1194
1195 // Transfer the values from "this" to the new item. Calling
1196 // SetValue will also draw the edit item
1197 P->SetMinMax (FMin, FMax);
1198 P->SetValue (FValue);
1199
1200 // allow editing
1201 P->Edit (Abort);
1202
1203 // Get the edited value if the editing was not aborted
1204 if (Abort) {
1205 Result = 0;
1206 } else {
1207 SetValue (P->GetValue ());
1208 Result = ID;
1209 }
1210
1211 // Delete the edit item from the owners list
1212 Owner->DeleteItem (P);
1213
1214 // Select "this". This redraws the item and clears the edit field
1215 Select ();
1216
1217 }
1218
1219 // Return the result
1220 return Result;
1221
1222 }
1223
1224
1225
1226 /*****************************************************************************/
1227 /* class TimeItem */
1228 /*****************************************************************************/
1229
1230
1231
TimeItem(const String & aItemText,i16 aID,i16 EditID,WindowItem * NextItem)1232 TimeItem::TimeItem (const String& aItemText, i16 aID, i16 EditID,
1233 WindowItem* NextItem) :
1234 EditMenueItem (aItemText, aID, EditID, NULL, NextItem)
1235 {
1236 }
1237
1238
1239
TimeItem(const String & aItemText,i16 aID,WindowItem * NextItem)1240 TimeItem::TimeItem (const String& aItemText, i16 aID, WindowItem* NextItem) :
1241 EditMenueItem (aItemText, aID, 0, NULL, NextItem)
1242 {
1243 }
1244
1245
1246
Load(Stream & S)1247 void TimeItem::Load (Stream &S)
1248 {
1249 EditMenueItem::Load (S);
1250 S >> TimeVal;
1251 }
1252
1253
1254
Store(Stream & S) const1255 void TimeItem::Store (Stream &S) const
1256 {
1257 EditMenueItem::Store (S);
1258 S << TimeVal;
1259 }
1260
1261
1262
StreamableID() const1263 u16 TimeItem::StreamableID () const
1264 {
1265 return ID_TimeItem;
1266 }
1267
1268
1269
Build()1270 Streamable* TimeItem::Build ()
1271 {
1272 return new TimeItem (Empty);
1273 }
1274
1275
1276
SetWidth(u16 NewWidth)1277 void TimeItem::SetWidth (u16 NewWidth)
1278 {
1279 // Check against the minimum width needed
1280 if (NewWidth < MinWidth ()) {
1281 // Ignore the request
1282 return;
1283 }
1284
1285 // Store the new width
1286 ItemWidth = NewWidth;
1287
1288 // Build the new entry
1289 BuildEntry (TimeVal.TimeStr ());
1290 }
1291
1292
1293
MinWidth()1294 u16 TimeItem::MinWidth ()
1295 {
1296 u16 Len = ItemText.Len ();
1297 u16 Width = Len + TimeVal.TimeStr().Len() + 2;
1298 if (Len) {
1299 Width += 2;
1300 }
1301 return Width;
1302 }
1303
1304
1305
Choose()1306 i16 TimeItem::Choose ()
1307 // Choose the entry. If an edit window is defined (EditWindow != NULL),
1308 // the entry with id EditItemID in EditWindow is called. If there was
1309 // no abort (or EditWindow is not defined), the id of this item is
1310 // returned.
1311 {
1312 TimeEdit *P;
1313 int Abort;
1314 i16 Result;
1315
1316 // If the edit id is zero, return the own id
1317 if (EditItemID == 0) {
1318 return ID;
1319 }
1320
1321 // Check if a predefined window exists
1322 if (EditWindow) {
1323
1324 // Move the window to the correct position
1325 PlaceEditWindow ();
1326
1327 // Allow editing the value
1328 P = (TimeEdit *) EditWindow->ForcedItemWithID (EditItemID);
1329 P->SetValue (TimeVal);
1330 P->Edit (Abort);
1331
1332 // if no abort, set the value and return the id
1333 if (Abort) {
1334 Result = 0;
1335 } else {
1336 SetValue (P->GetValue ());
1337 Result = ID;
1338 }
1339
1340 } else {
1341
1342 // No item defined, we have to create one
1343 P = new TimeEdit ("", EditItemID, NULL);
1344
1345 // Insert the item into the owner window
1346 Owner->AddItem (P);
1347
1348 // Set the position of the newly created item
1349 P->SetPos (ItemX + ItemWidth - P->GetWidth (), ItemY);
1350
1351 // Deselect "this"
1352 Deselect ();
1353
1354 // Transfer the values from "this" to the new item. Calling
1355 // SetValue will also draw the edit item
1356 P->SetValue (TimeVal);
1357
1358 // allow editing
1359 P->Edit (Abort);
1360
1361 // Get the edited value if the editing was not aborted
1362 if (Abort) {
1363 Result = 0;
1364 } else {
1365 SetValue (P->GetValue ());
1366 Result = ID;
1367 }
1368
1369 // Delete the edit item from the owners list
1370 Owner->DeleteItem (P);
1371
1372 // Select "this". This redraws the item and clears the edit field
1373 Select ();
1374
1375 }
1376
1377 // Return the result
1378 return Result;
1379
1380 }
1381
1382
1383
SetValue(unsigned Hour,unsigned Minute,unsigned Second)1384 void TimeItem::SetValue (unsigned Hour, unsigned Minute, unsigned Second)
1385 {
1386 // Set the new value
1387 TimeVal.SetTime (Hour, Minute, Second);
1388
1389 // Build the new display text.
1390 // Use SetWidth with the current width to do that
1391 SetWidth (ItemWidth);
1392
1393 // Now redraw the item
1394 Draw ();
1395 }
1396
1397
1398
SetValue(u32 Seconds)1399 void TimeItem::SetValue (u32 Seconds)
1400 {
1401 unsigned Sec = Seconds % 60;
1402 Seconds /= 60;
1403 unsigned Min = Seconds % 60;
1404 unsigned Hour = Seconds / 60;
1405 CHECK (Hour < 24);
1406
1407 // Set the new value
1408 SetValue (Hour, Min, Sec);
1409 }
1410
1411
1412
SetValue(const Time & Val)1413 void TimeItem::SetValue (const Time& Val)
1414 {
1415 // Set the new value
1416 TimeVal = Val;
1417
1418 // Build the new display text.
1419 // Use SetWidth with the current width to do that
1420 SetWidth (ItemWidth);
1421
1422 // Now redraw the item
1423 Draw ();
1424 }
1425
1426
1427
1428 /*****************************************************************************/
1429 /* class DateItem */
1430 /*****************************************************************************/
1431
1432
1433
1434
DateItem(const String & aItemText,i16 aID,i16 EditID,WindowItem * NextItem)1435 DateItem::DateItem (const String& aItemText, i16 aID, i16 EditID,
1436 WindowItem* NextItem) :
1437 EditMenueItem (aItemText, aID, EditID, NULL, NextItem)
1438 {
1439 }
1440
1441
1442
DateItem(const String & aItemText,i16 aID,WindowItem * NextItem)1443 DateItem::DateItem (const String& aItemText, i16 aID, WindowItem* NextItem) :
1444 EditMenueItem (aItemText, aID, 0, NULL, NextItem)
1445 {
1446 }
1447
1448
1449
Load(Stream & S)1450 void DateItem::Load (Stream &S)
1451 {
1452 EditMenueItem::Load (S);
1453 S >> TimeVal;
1454 }
1455
1456
1457
Store(Stream & S) const1458 void DateItem::Store (Stream &S) const
1459 {
1460 EditMenueItem::Store (S);
1461 S << TimeVal;
1462 }
1463
1464
1465
StreamableID() const1466 u16 DateItem::StreamableID () const
1467 {
1468 return ID_DateItem;
1469 }
1470
1471
1472
Build()1473 Streamable* DateItem::Build ()
1474 {
1475 return new DateItem (Empty);
1476 }
1477
1478
1479
SetWidth(u16 NewWidth)1480 void DateItem::SetWidth (u16 NewWidth)
1481 {
1482 // Check against the minimum width needed
1483 if (NewWidth < MinWidth ()) {
1484 // Ignore the request
1485 return;
1486 }
1487
1488 // Store the new width
1489 ItemWidth = NewWidth;
1490
1491 // Build the new entry
1492 BuildEntry (TimeVal.DateStr ());
1493 }
1494
1495
1496
MinWidth()1497 u16 DateItem::MinWidth ()
1498 {
1499 u16 Len = ItemText.Len ();
1500 u16 Width = Len + TimeVal.DateStr().Len() + 2;
1501 if (Len) {
1502 Width += 2;
1503 }
1504 return Width;
1505 }
1506
1507
1508
Choose()1509 i16 DateItem::Choose ()
1510 // Choose the entry. If an edit window is defined (EditWindow != NULL),
1511 // the entry with id EditItemID in EditWindow is called. If there was
1512 // no abort (or EditWindow is not defined), the id of this item is
1513 // returned.
1514 {
1515 DateEdit *P;
1516 int Abort;
1517 i16 Result;
1518
1519 // If the edit id is zero, return the own id
1520 if (EditItemID == 0) {
1521 return ID;
1522 }
1523
1524 // Check if a predefined window exists
1525 if (EditWindow) {
1526
1527 // Move the window to the correct position
1528 PlaceEditWindow ();
1529
1530 // Allow editing the value
1531 P = (DateEdit *) EditWindow->ForcedItemWithID (EditItemID);
1532 P->SetValue (TimeVal);
1533 P->Edit (Abort);
1534
1535 // if no abort, set the value and return the id
1536 if (Abort) {
1537 Result = 0;
1538 } else {
1539 SetValue (P->GetValue ());
1540 Result = ID;
1541 }
1542
1543 } else {
1544
1545 // No item defined, we have to create one
1546 P = new DateEdit ("", EditItemID, NULL);
1547
1548 // Insert the item into the owner window
1549 Owner->AddItem (P);
1550
1551 // Set the position of the newly created item
1552 P->SetPos (ItemX + ItemWidth - P->GetWidth (), ItemY);
1553
1554 // Deselect "this"
1555 Deselect ();
1556
1557 // Transfer the values from "this" to the new item. Calling
1558 // SetValue will also draw the edit item
1559 P->SetValue (TimeVal);
1560
1561 // allow editing
1562 P->Edit (Abort);
1563
1564 // Get the edited value if the editing was not aborted
1565 if (Abort) {
1566 Result = 0;
1567 } else {
1568 SetValue (P->GetValue ());
1569 Result = ID;
1570 }
1571
1572 // Delete the edit item from the owners list
1573 Owner->DeleteItem (P);
1574
1575 // Select "this". This redraws the item and clears the edit field
1576 Select ();
1577
1578 }
1579
1580 // Return the result
1581 return Result;
1582
1583 }
1584
1585
1586
SetValue(unsigned Year,unsigned Month,unsigned Day)1587 void DateItem::SetValue (unsigned Year, unsigned Month, unsigned Day)
1588 {
1589 // Set the new value
1590 TimeVal.SetDate (Year, Month, Day);
1591
1592 // Build the new display text.
1593 // Use SetWidth with the current width to do that
1594 SetWidth (ItemWidth);
1595
1596 // Now redraw the item
1597 Draw ();
1598 }
1599
1600
1601
SetValue(const Time & Val)1602 void DateItem::SetValue (const Time& Val)
1603 {
1604 // Set the new value
1605 TimeVal = Val;
1606
1607 // Build the new display text.
1608 // Use SetWidth with the current width to do that
1609 SetWidth (ItemWidth);
1610
1611 // Now redraw the item
1612 Draw ();
1613 }
1614
1615
1616
1617 /*****************************************************************************/
1618 /* class RStringItem */
1619 /*****************************************************************************/
1620
1621
1622
1623 // Class RStringItem has the same functionality as class StringItem with one
1624 // exception: The set of allowed input characters is written out on a Store
1625 // and reloaded when calling Load. This has been a compatibility decision:
1626 // The complete functionality to restrict input has been added to class
1627 // StringItem (without changing the default behavior), but writing out the
1628 // additional class would have made existing resources unusable - so there
1629 // is a new class for that.
1630
1631
1632
RStringItem(StreamableInit)1633 RStringItem::RStringItem (StreamableInit):
1634 StringItem (Empty)
1635 // Build constructor
1636 {
1637 }
1638
1639
1640
RStringItem(const String & aItemText,i16 aID,i16 EditID,u16 aInputLength,WindowItem * NextItem)1641 RStringItem::RStringItem (const String& aItemText, i16 aID, i16 EditID,
1642 u16 aInputLength, WindowItem* NextItem):
1643 StringItem (aItemText, aID, EditID, NextItem),
1644 InputLength (aInputLength)
1645 {
1646 }
1647
1648
1649
Load(Stream & S)1650 void RStringItem::Load (Stream& S)
1651 {
1652 StringItem::Load (S);
1653 S >> AllowedChars >> InputLength;
1654 }
1655
1656
1657
Store(Stream & S) const1658 void RStringItem::Store (Stream& S) const
1659 {
1660 StringItem::Store (S);
1661 S << AllowedChars << InputLength;
1662 }
1663
1664
1665
StreamableID() const1666 u16 RStringItem::StreamableID () const
1667 {
1668 return ID_RStringItem;
1669 }
1670
1671
1672
Build()1673 Streamable* RStringItem::Build ()
1674 {
1675 return new RStringItem (Empty);
1676 }
1677
1678
1679
Choose()1680 i16 RStringItem::Choose ()
1681 // Choose the entry. If an edit window is defined (EditWindow != NULL),
1682 // the entry with id EditItemID in EditWindow is called. If there was
1683 // no abort (or EditWindow is not defined), the id of this item is
1684 // returned.
1685 {
1686 int Abort;
1687 i16 Result;
1688
1689 // If the edit id is zero, return the own id
1690 if (EditItemID == 0) {
1691 return ID;
1692 }
1693
1694 // Check if a predefined window exists
1695 if (EditWindow) {
1696
1697 // Move the window to the correct position
1698 PlaceEditWindow ();
1699
1700 // Allow editing the value
1701 TextEdit* P = (TextEdit*) EditWindow->ForcedItemWithID (EditItemID);
1702 P->SetValue (SValue);
1703 P->Edit (Abort);
1704
1705 // if no abort, set the value and return the id
1706 if (Abort) {
1707 Result = 0;
1708 } else {
1709 SetValue (P->GetValue ());
1710 Result = ID;
1711 }
1712
1713 } else {
1714
1715 // No item defined, we have to create one
1716 u16 Len = ItemWidth - MinWidth () - 1;
1717 if (Len > InputLength + 1) {
1718 Len = InputLength + 1;
1719 }
1720 TextEdit* P = new TextEdit ("", EditItemID, InputLength, Len, NULL);
1721
1722 // Set the allowed characters for input
1723 P->SetAllowedChars (AllowedChars);
1724
1725 // Insert the item into the owner window
1726 Owner->AddItem (P);
1727
1728 // Set the position of the newly created item
1729 P->SetPos (ItemX + ItemWidth - P->GetWidth (), ItemY);
1730
1731 // Deselect "this"
1732 Deselect ();
1733
1734 // Transfer the values from "this" to the new item. Calling
1735 // SetValue will also draw the edit item
1736 P->SetValue (SValue);
1737
1738 // allow editing
1739 P->Edit (Abort);
1740
1741 // Get the edited value if the editing was not aborted
1742 if (Abort) {
1743 Result = 0;
1744 } else {
1745 SetValue (P->GetValue ());
1746 Result = ID;
1747 }
1748
1749 // Delete the edit item from the owners list
1750 Owner->DeleteItem (P);
1751
1752 // Select "this". This redraws the item and clears the edit field
1753 Select ();
1754
1755 }
1756
1757 // Return the result
1758 return Result;
1759
1760 }
1761
1762
1763
1764