1 /*****************************************************************************/
2 /* */
3 /* ITEMWIN.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 "itemwin.h"
23 #include "national.h"
24 #include "streamid.h"
25 #include "thread.h"
26 #include "program.h"
27 #include "progutil.h"
28
29
30
31 // Register class WindowItem and ItemWindow
32 LINK(ItemWindow, ID_ItemWindow);
33 LINK(WindowItem, ID_WindowItem);
34
35
36
37 /*****************************************************************************/
38 /* Explicit template instantiation */
39 /*****************************************************************************/
40
41
42
43 #ifdef EXPLICIT_TEMPLATES
44 template class ListNode<WindowItem>;
45 #endif
46
47
48
49 /*****************************************************************************/
50 /* class WindowItem */
51 /*****************************************************************************/
52
53
54
WindowItem(const String & aItemText,i16 aID,WindowItem * NextItem)55 WindowItem::WindowItem (const String &aItemText, i16 aID, WindowItem *NextItem) :
56 INode (this), ItemX (0), ItemY (0), ID (aID), Flags (0),
57 AccelKey (kbNoKey), ItemText (aItemText)
58 {
59 // Check the given parameters
60 PRECONDITION (aID <= MaxUserID && aID > 0);
61
62 // Check the item text for a hot key
63 HotPos = (i16) ItemText.Pos ('@');
64 if (HotPos >= 0) {
65 // There is a hot key, delete the marker and grab it
66 ItemText.Del (HotPos);
67 HotKey = (Key) NLSUpCase (ItemText [HotPos]);
68 } else {
69 // No hotkey
70 HotKey = kbNoKey;
71 }
72
73 // Init some other stuff
74 AccelKey = kbNoKey;
75 SetPos (0, 0);
76 ItemWidth = MinWidth ();
77
78 // If the next item is given, make up the list
79 if (NextItem) {
80 INode.InsertBefore (&NextItem->INode);
81 }
82
83 }
84
85
86
StreamableID() const87 u16 WindowItem::StreamableID () const
88 {
89 return ID_WindowItem;
90 }
91
92
93
Build()94 Streamable* WindowItem::Build ()
95 {
96 return new WindowItem (Empty);
97 }
98
99
100
Store(Stream & S) const101 void WindowItem::Store (Stream& S) const
102 // Write instance data to the stream
103 {
104 S << ItemX << ItemY << ItemWidth << ID << Flags << HotKey << HotPos
105 << AccelKey << ItemText << HelpKey;
106 }
107
108
109
Load(Stream & S)110 void WindowItem::Load (Stream &S)
111 // Load instance data from the stream
112 {
113 S >> ItemX >> ItemY >> ItemWidth >> ID >> Flags >> HotKey >> HotPos
114 >> AccelKey >> ItemText >> HelpKey;
115 }
116
117
118
RegisterKey()119 void WindowItem::RegisterKey ()
120 // If the item is active and has an accel key: Register the key at the
121 // current thread.
122 {
123 if (IsActive () && AccelKey != kbNoKey) {
124 CurThread () -> RegisterKey (AccelKey);
125 }
126 }
127
128
129
UnregisterKey()130 void WindowItem::UnregisterKey ()
131 // If the item is active and has an accel key: Unregister the key at the
132 // current thread.
133 {
134 if (IsActive () && AccelKey != kbNoKey) {
135 CurThread () -> UnregisterKey (AccelKey);
136 }
137 }
138
139
140
SetPos(u16 X,u16 Y)141 void WindowItem::SetPos (u16 X, u16 Y)
142 {
143 ItemX = X;
144 ItemY = Y;
145 }
146
147
148
SetWidth(u16 NewWidth)149 void WindowItem::SetWidth (u16 NewWidth)
150 {
151 ItemWidth = NewWidth;
152 }
153
154
155
GetRootWindow()156 ItemWindow* WindowItem::GetRootWindow ()
157 // Get the root of all windows in the current chain
158 {
159 ItemWindow *Win = Owner;
160 while (Win->GetOwner ()) {
161 Win = Win->GetOwner () -> GetOwner ();
162 }
163 CHECK (Win != NULL);
164
165 return Win;
166 }
167
168
169
SelectNew(WindowItem * NewItem)170 void WindowItem::SelectNew (WindowItem* NewItem)
171 // Deselect the selected item and set NewItem as newly selected item.
172 // Checks if this == NewItem and ignores a request in this case
173 {
174 // This item must be selected !
175 PRECONDITION (IsSelected ());
176
177 // No action if the new item and this item are the same
178 if (NewItem != this) {
179 Deselect (); // Deselect this item
180 NewItem->Select (); // Select other item
181 }
182 }
183
184
185
186
SelectNext()187 WindowItem* WindowItem::SelectNext ()
188 // Select the next item in the list. Return the item that is selected
189 // after the operation has been performed.
190 {
191 // Get a pointer to the node of the item list
192 ListNode<WindowItem>* Node = &INode;
193 WindowItem* Item;
194
195 // Search the item list forward for the next matching item
196 do {
197 Node = Node->Next ();
198 Item = Node->Contents ();
199 } while (!Item->IsActive ());
200
201 // Select the new item, deselect current
202 SelectNew (Item);
203
204 // Return the new selected item
205 return Item;
206 }
207
208
209
SelectPrev()210 WindowItem* WindowItem::SelectPrev ()
211 // Select the previous item in the list. Return the item that is selected
212 // after the operation has been performed.
213 {
214 // Get a pointer to the node of the item list
215 ListNode<WindowItem>* Node = &INode;
216 WindowItem* Item;
217
218 // Search the item list forward for the next matching item
219 do {
220 Node = Node->Prev ();
221 Item = Node->Contents ();
222 } while (!Item->IsActive ());
223
224 // Select the new item, deselect current
225 SelectNew (Item);
226
227 // Return the new selected item
228 return Item;
229 }
230
231
232
GetWidth() const233 u16 WindowItem::GetWidth () const
234 {
235 return ItemWidth;
236 }
237
238
239
MinWidth()240 u16 WindowItem::MinWidth ()
241 // Return the minimal needed width of the item
242 {
243 return ItemText.Len ();
244 }
245
246
247
GetID()248 i16 WindowItem::GetID ()
249 // Return the item id
250 {
251 return ID;
252 }
253
254
255
SetItemText(const String & aItemText)256 void WindowItem::SetItemText (const String& aItemText)
257 {
258 // Set new string
259 ItemText = aItemText;
260
261 // Adjust memory needed for the string
262 ItemText.Settle ();
263
264 // Reset width
265 SetWidth (GetWidth ());
266
267 // Redraw the item
268 Draw ();
269 }
270
271
272
Draw()273 void WindowItem::Draw ()
274 {
275 unsigned TextAttr; // Attribute for normal text
276 unsigned HotAttr; // Attribute for hot key
277
278 // If the item text is empty, bail out early
279 if (ItemText.IsEmpty ()) {
280 // Nothing to do
281 return;
282 }
283
284 // Set up attributes
285 if (IsActive ()) {
286 HotAttr = atTextHigh;
287 TextAttr = IsSelected () ? atTextSelected : atTextNormal;
288 } else {
289 if (IsGrayed ()) {
290 HotAttr = atTextGrayed;
291 TextAttr = atTextGrayed;
292 } else {
293 HotAttr = atTextNormal;
294 TextAttr = atTextNormal;
295 }
296 }
297
298 // Lock the owner window
299 Owner->Lock ();
300
301 // Write out the item text
302 Owner->Write (ItemX, ItemY, ItemText, TextAttr);
303
304 // If there is a hotkey, show it
305 if (HotPos >= 0) {
306 Owner->Write (ItemX + HotPos, ItemY, ItemText [HotPos], HotAttr);
307 }
308
309 // Unlock the owner window
310 Owner->Unlock ();
311
312 }
313
314
315
Clear()316 void WindowItem::Clear ()
317 {
318 if (ItemWidth) {
319 String S (ItemWidth);
320 S.Set (0, ItemWidth, ' ');
321 Owner->Write (ItemX, ItemY, S);
322 }
323 }
324
325
326
DrawItemText()327 void WindowItem::DrawItemText ()
328 {
329 WindowItem::Draw ();
330 }
331
332
333
ClearItemText()334 void WindowItem::ClearItemText ()
335 {
336 unsigned Len = ItemText.Len ();
337 if (Len) {
338 String S (Len);
339 S.Set (0, Len, ' ');
340 Owner->Write (ItemX, ItemY, S);
341 }
342 }
343
344
345
Activate()346 void WindowItem::Activate ()
347 {
348 // Clear the gray and inactive attributes
349 Flags &= ~(ifGrayed | ifInactive);
350
351 // Redraw the item
352 DrawItemText ();
353 }
354
355
356
Deactivate()357 void WindowItem::Deactivate ()
358 {
359 // Set new state
360 Flags |= ifInactive;
361 Flags &= ~ifSelected;
362
363 // Redraw the item
364 DrawItemText ();
365 }
366
367
368
Gray()369 void WindowItem::Gray ()
370 {
371 // Set new state
372 Flags |= ifGrayed | ifInactive;
373 Flags &= ~ifSelected;
374
375 // Redraw the item
376 DrawItemText ();
377 }
378
379
380
Select()381 void WindowItem::Select ()
382 {
383 // Set new state
384 Flags |= ifSelected;
385
386 // Redraw the item
387 DrawItemText ();
388 }
389
390
391
Deselect()392 void WindowItem::Deselect ()
393 {
394 // Set new state
395 Flags &= ~ifSelected;
396
397 // Redraw the item
398 DrawItemText ();
399 }
400
401
402
CallHelp()403 void WindowItem::CallHelp ()
404 // Call the help function with the help key of this item
405 {
406 if (HasHelp ()) {
407 App->CallHelp (HelpKey);
408 }
409 }
410
411
412
Choose()413 i16 WindowItem::Choose ()
414 // Choose an entry
415 {
416 // Item must be active
417 PRECONDITION (IsActive ());
418
419 // Return entry id
420 return ID;
421 }
422
423
424
ItemWithID(i16 aID)425 WindowItem* WindowItem::ItemWithID (i16 aID)
426 //
427 {
428 return (aID == ID) ? this : (WindowItem*) NULL;
429 }
430
431
432
ItemWithHotKey(Key aHotKey)433 WindowItem* WindowItem::ItemWithHotKey (Key aHotKey)
434 {
435 return (IsActive () && aHotKey == HotKey) ? this : (WindowItem*) NULL;
436 }
437
438
439
ItemWithAccelKey(Key aAccelKey)440 WindowItem* WindowItem::ItemWithAccelKey (Key aAccelKey)
441 {
442 return (IsActive () && aAccelKey == AccelKey) ? this : (WindowItem*) NULL;
443 }
444
445
446
447 /*****************************************************************************/
448 /* class ItemWindow */
449 /*****************************************************************************/
450
451
452
ItemWindow(const Rect & Bounds,u16 aState,WindowItem * ItemList)453 ItemWindow::ItemWindow (const Rect& Bounds, u16 aState, WindowItem* ItemList):
454 Window (Bounds, aState, paGray, 0, 1),
455 Owner (NULL),
456 SelectedItem (NULL),
457 FirstItem (ItemList)
458 // Internal constructor, used by GenericMenue
459 {
460 // Set up the item count
461 ItemCount = (u16) (FirstItem ? FirstItem->INode.NodeCount () : 0);
462
463 // Set this as the owner of all items in ItemList
464 SetItemListOwner ();
465 }
466
467
468
ItemWindow(const Rect & Bounds,u16 aState,unsigned aPalette,unsigned Number,WindowItem * ItemList)469 ItemWindow::ItemWindow (const Rect& Bounds, u16 aState, unsigned aPalette,
470 unsigned Number, WindowItem* ItemList):
471 Window (Bounds, aState, aPalette, Number, 1),
472 Owner (NULL),
473 SelectedItem (NULL),
474 FirstItem (ItemList)
475 {
476 // Set up the item count
477 ItemCount = FirstItem ? FirstItem->INode.NodeCount () : 0;
478
479 // Set this as the owner of all items in ItemList
480 SetItemListOwner ();
481
482 // Set the positions of the items
483 SetPos ();
484
485 // Choose a selected item
486 ValidateSelectedItem ();
487
488 // Draw all items
489 DrawItems ();
490
491 // The parent class has been called with LockCount == 1, so we
492 // have to unlock the screen output here
493 Unlock ();
494 }
495
496
497
~ItemWindow()498 ItemWindow::~ItemWindow ()
499 // Destructor of class ItemWindow
500 {
501 // Delete the list of items
502 if (FirstItem) {
503
504 ListNode<WindowItem>* N = &FirstItem->INode;
505 ListNode<WindowItem>* P;
506
507 while (!N->IsEmpty ()) {
508 P = N->Next ();
509 P->Unlink ();
510 delete P->Contents ();
511 }
512 delete N->Contents ();
513
514 }
515 }
516
517
518
StreamableID() const519 u16 ItemWindow::StreamableID () const
520 {
521 return ID_ItemWindow;
522 }
523
524
525
Build()526 Streamable* ItemWindow::Build ()
527 {
528 return new ItemWindow (Empty);
529 }
530
531
532
StoreOneItem(ListNode<WindowItem> * N,void * S)533 int ItemWindow::StoreOneItem (ListNode<WindowItem>* N, void* S)
534 // Helper function to store a WindowItem into the stream S
535 {
536 // Get a casted pointer to the stream
537 Stream *Str = (Stream *) S;
538
539 // Store the WindowItem
540 Str->Put (N->Contents ());
541
542 // keep on traversing...
543 return 0;
544 }
545
546
547
Store(Stream & S) const548 void ItemWindow::Store (Stream& S) const
549 // Store the object into a stream
550 {
551 // Store parental data
552 Window::Store (S);
553
554 // Store the node number of the selected item. Note: If FirstItem is
555 // NULL, SelectedItem cannot be != NULL
556 i16 Selected;
557 if (SelectedItem) {
558 CHECK (FirstItem != NULL);
559 Selected = (i16) FirstItem->INode.NumberOfNode (&SelectedItem->INode);
560 } else {
561 Selected = -1;
562 }
563
564 // Store the item count and each item
565 S << Selected << ItemCount;
566 Traverse (StoreOneItem, &S);
567 }
568
569
570
SetOneItemWidth(ListNode<WindowItem> * N,void *)571 int ItemWindow::SetOneItemWidth (ListNode<WindowItem>* N, void*)
572 // Reset the width of one item
573 {
574 // Get a pointer to the item
575 WindowItem* W = N->Contents ();
576
577 // Reset the width
578 W->SetWidth (W->GetWidth ());
579
580 // keep on traversing...
581 return 0;
582 }
583
584
585
Load(Stream & S)586 void ItemWindow::Load (Stream& S)
587 // Load the window from the stream
588 {
589 i16 Selected;
590
591 // Clear ItemCount and most of the pointers before calling the parental
592 // Load function. This is because Window::Load is calling Redraw, which
593 // tries to draw not existing items if the data is not initialized.
594 ItemCount = 0;
595 Owner = NULL;
596 FirstItem = NULL;
597 SelectedItem = NULL;
598
599 // Now load the window data
600 Window::Load (S);
601
602 // Read the number of the selected item and the item count
603 S >> Selected >> ItemCount;
604
605 // Read in all items and put them into the linked list
606 WindowItem *P;
607 for (int I = 0; I < ItemCount; I++) {
608 // Load the item from the stream
609 P = (WindowItem *) S.Get ();
610
611 // Insert the item into the item list
612 if (FirstItem) {
613 P->INode.InsertBefore (&FirstItem->INode);
614 } else {
615 FirstItem = P;
616 }
617 }
618
619 // Set "this" as the owner of all the items in the list
620 SetItemListOwner ();
621
622 // Set the pointer to the selected item
623 if (Selected == -1) {
624 // No selected item
625 SelectedItem = NULL;
626 } else {
627 CHECK (FirstItem != NULL);
628 SelectedItem = FirstItem->INode.NodeWithNumber ((u16) Selected)->Contents ();
629 }
630
631 // Before redrawing the items, adjust for a changed size of the window and
632 // changed language. Reset the width of all items.
633 Traverse (SetOneItemWidth);
634
635 // We have to redraw the items because Window::Redraw has not done this.
636 // DrawItems is doing a lock, so we don't have to do this here
637 DrawItems ();
638
639 }
640
641
642
DrawInterior()643 void ItemWindow::DrawInterior ()
644 // Redraw the inner part of the window
645 {
646 // Clear the inner window, the redraw the items
647 Lock ();
648 Clear ();
649 DrawItems ();
650 Unlock ();
651 }
652
653
654
Activate()655 void ItemWindow::Activate ()
656 // Activate the window. This overrides Window::Activate and highlights
657 // the selected item
658 {
659 // Activate the window
660 Window::Activate ();
661
662 // If there is a selected item, highlight it
663 if (SelectedItem) {
664 SelectedItem->Select ();
665 }
666 }
667
668
669
Deactivate()670 void ItemWindow::Deactivate ()
671 // Activate the window. This overrides Window::Activate and deselects
672 // the selected item
673 {
674 // Deactivate the window
675 Window::Deactivate ();
676
677 // If there is a selected item, deselect it
678 if (SelectedItem) {
679 SelectedItem->Deselect ();
680 }
681 }
682
683
684
Browse()685 Key ItemWindow::Browse ()
686 // Make the window active and display the window contents in a suitable
687 // manner. This function should be overridden for special derived
688 // windows. It returns the key that ended the browse state.
689 {
690 // Remember the state of the window and the cursor form
691 u16 OldState = GetState ();
692 CursorType Cursor = GetCursor ();
693
694 // new StatusLine
695 PushStatusLine (CreateStatusLine (GetStatusFlags ()));
696
697 // Activate the window
698 Activate ();
699
700 // Get all keys until abort or a registered key is read
701 Key K;
702 int Done = 0;
703 while (!Done) {
704
705 // Get a key
706 K = KbdGet ();
707
708 // Handle the key
709 HandleKey (K);
710
711 // Check for some other keys...
712 switch (K) {
713
714 case vkAbort:
715 Done = 1;
716 break;
717
718 default:
719 if (KeyIsRegistered (K)) {
720 Done = 1;
721 }
722 break;
723 }
724
725 }
726
727 // Restore the old status line
728 PopStatusLine ();
729
730 // Reset window to old state, then deselect the selected item. Do it
731 // in this order, because often the menue is hidden after SetState,
732 // so the call to Deselect will cause no additional screen output.
733 SetState (OldState);
734 if (SelectedItem) {
735 SelectedItem->Deselect ();
736 }
737
738 // Set the old cursor
739 SetCursor (Cursor);
740
741 // Return the abort key
742 return K;
743 }
744
745
746
GetStatusFlags()747 u32 ItemWindow::GetStatusFlags ()
748 // Returns the flags that are used to build the status line in Browse
749 {
750 u32 Flags = siEnd;
751 if (CanMove () || CanResize ()) {
752 Flags |= siResize;
753 }
754 return Flags;
755 }
756
757
758
HandleKey(Key & K)759 void ItemWindow::HandleKey (Key& K)
760 // Key dispatcher used in Browse
761 {
762 // Handle some known keys
763 switch (K) {
764
765 case vkResize:
766 MoveResize ();
767 K = kbNoKey;
768 break;
769
770 }
771 }
772
773
774
AddItem(WindowItem * Item)775 void ItemWindow::AddItem (WindowItem* Item)
776 // Add the given item to the item list of the window. After that, the
777 // item is owned by the window and destroyed if the window destructor
778 // is called. The given WindowItem is unlinked from the list it is
779 // linked in before it is added to the windows item list.
780 {
781 // unlink the item from the list it is currently in
782 Item->INode.Unlink ();
783
784 // Insert the item into the list managed by the window
785 if (FirstItem) {
786 Item->INode.InsertBefore (&FirstItem->INode);
787 } else {
788 FirstItem = Item;
789 }
790
791 // Set the owner of the item
792 Item->SetOwner (this);
793
794 // Track the count of items in the list
795 ItemCount++;
796
797 // Validate the selected item
798 ValidateSelectedItem ();
799 }
800
801
802
DeleteItem(WindowItem * Item)803 void ItemWindow::DeleteItem (WindowItem* Item)
804 // Take the item from the item list and delete it. If Item is the
805 // selected item, a new selected item is choosen. After deleting
806 // Item, the window is redrawn.
807 {
808 ListNode<WindowItem> *N;
809
810 if (FirstItem) {
811 // List is not empty
812 N = &FirstItem->INode;
813
814 do {
815 if (N->Contents () == Item) {
816
817 // Found the item, clear, then unlink it. Be carefull:
818 // Item could be the item, FirstItem is pointing to!
819 N->Contents () -> Clear ();
820 if (Item == FirstItem) {
821 // Take the next item if possible
822 if (ItemCount > 1) {
823 FirstItem = N->Next () -> Contents ();
824 } else {
825 // This is the last item, the list is empty
826 FirstItem = NULL;
827 }
828 }
829 N->Unlink ();
830
831 // Keep track of the item count
832 ItemCount--;
833
834 // If Item was selected, choose a new selected item
835 if (Item == SelectedItem) {
836 SelectedItem = NULL; // Invalidate item
837 ValidateSelectedItem (); // Choose a new one
838 }
839
840 // Now delete the item and exit
841 delete Item;
842 return;
843
844 } else {
845
846 // Not this item, try the next
847 N = N->Next ();
848
849 }
850
851 // until the first item is reached again
852 } while (Item != FirstItem);
853
854 }
855
856 // OOPS! There is no such item in the item list.
857 FAIL ("ItemWindow::DeleteItem: Item not found");
858
859 }
860
861
862
SetOneOwner(ListNode<WindowItem> * N,void * P)863 int ItemWindow::SetOneOwner (ListNode<WindowItem>* N, void* P)
864 // Helper function for ItemWindow::SetItemListOwner. Sets the owner window
865 // for all items in the list
866 {
867 N->Contents () -> SetOwner ((ItemWindow *) P);
868 return 0;
869 }
870
871
872
SetItemListOwner()873 void ItemWindow::SetItemListOwner ()
874 // Traverse through all items and tell them their owner
875 {
876 Traverse (SetOneOwner, (void*) this);
877 }
878
879
880
SetOnePos(ListNode<WindowItem> * N,void * P)881 int ItemWindow::SetOnePos (ListNode<WindowItem>* N, void* P)
882 // Helper function for ItemWindow::SetPos, sets the position of one item
883 {
884 // Get a casted pointer to the given Y position
885 u16* Pos = (u16*) P;
886
887 // Set the position for one item
888 N->Contents () -> SetPos (0, *Pos);
889
890 // Increment the Y position
891 (*Pos)++;
892
893 // Keep on traversing
894 return 0;
895 }
896
897
898
SetPos()899 void ItemWindow::SetPos ()
900 // Sets the positions of all window items. The items are lined up
901 // vertically at the left window border. To change this behaviour,
902 // overload this function.
903 {
904 // Position of first item is 0/0
905 u16 Y = 0;
906
907 Traverse (SetOnePos, &Y);
908 }
909
910
911
DrawOneItem(ListNode<WindowItem> * N,void *)912 int ItemWindow::DrawOneItem (ListNode<WindowItem>* N, void*)
913 // Helper function for DrawItems, draw on item
914 {
915 // Draw the given item
916 N->Contents () -> Draw ();
917
918 // Keep on traversing
919 return 0;
920 }
921
922
923
DrawItems()924 void ItemWindow::DrawItems ()
925 // Draw all items
926 {
927 if (FirstItem) {
928 // Use Lock/Unlock to speed up display processing
929 Lock ();
930 Traverse (DrawOneItem);
931 Unlock ();
932 }
933 }
934
935
936
CheckSelectedItem(ListNode<WindowItem> * N,void *)937 int ItemWindow::CheckSelectedItem (ListNode<WindowItem>* N, void*)
938 // Helper function for ValidateSelectedItem, find active item
939 {
940 return N->Contents () -> IsActive ();
941 }
942
943
944
ValidateSelectedItem()945 void ItemWindow::ValidateSelectedItem ()
946 // Check if the item pointed to by SelectedItem is still active. If
947 // not, a new item is choosen.
948 {
949 if (FirstItem == NULL) {
950 // No items
951 SelectedItem = NULL;
952 return;
953 }
954
955 if (SelectedItem == NULL || SelectedItem->IsActive () == 0) {
956 // Selected item is invalid, choose a new one
957 SelectedItem = Traverse (CheckSelectedItem);
958 }
959
960 // If a selected item exists and the window is active, show the new state
961 if (SelectedItem && IsActive ()) {
962 SelectedItem->Select ();
963 }
964 }
965
966
967
SelectNextItem()968 void ItemWindow::SelectNextItem ()
969 // Choose the next item in the item list as selected
970 {
971 if (SelectedItem) {
972 SelectedItem = SelectedItem->SelectNext ();
973 }
974 }
975
976
977
SelectPrevItem()978 void ItemWindow::SelectPrevItem ()
979 // Choose the previous item in the item list as selected
980 {
981 if (SelectedItem) {
982 SelectedItem = SelectedItem->SelectPrev ();
983 }
984 }
985
986
987
SelectNewItem(WindowItem * NewItem)988 void ItemWindow::SelectNewItem (WindowItem* NewItem)
989 // Select the new item, update SelectedItem
990 {
991 if (SelectedItem) {
992 SelectedItem->SelectNew (NewItem);
993 } else {
994 NewItem->Select ();
995 }
996 SelectedItem = NewItem;
997 }
998
999
1000
SelectNewItem(i16 NewID)1001 void ItemWindow::SelectNewItem (i16 NewID)
1002 // Select the new item, update SelectedItem
1003 {
1004 SelectNewItem (ForcedItemWithID (NewID));
1005 }
1006
1007
1008
Traverse(int (* F)(ListNode<WindowItem> *,void *),void * Data) const1009 WindowItem* ItemWindow::Traverse (int (*F) (ListNode<WindowItem>*, void*),
1010 void* Data) const
1011 // Use ListNode::Traverse to traverse through all window items starting
1012 // at FirstItem. Return value corresponds to ListNode::Traverse
1013 {
1014 ListNode<WindowItem> *Node;
1015
1016 if (FirstItem) {
1017 Node = FirstItem->INode.Traverse (1, F, Data);
1018 } else {
1019 Node = NULL;
1020 }
1021
1022 // if Node is not NULL, return the item that Node contains
1023 return Node ? Node->Contents () : (WindowItem*) NULL;
1024 }
1025
1026
1027
PlaceNear(const Point & Pos)1028 void ItemWindow::PlaceNear (const Point& Pos)
1029 // Place the window near the given absolute position. If there is not enough
1030 // room to place the window below the given item, the window is placed above.
1031 {
1032 // Get the coords of the window and the screen
1033 Rect WinBounds (OuterBounds ());
1034 Rect ScreenBounds (Background->OuterBounds ());
1035
1036 // Now move the window bounds so that the window is positioned
1037 // below the given item.
1038 WinBounds.Move (-WinBounds.A.X, -WinBounds.A.Y); // Move to 0/0
1039 WinBounds.Move (Pos.X, Pos.Y+1);
1040
1041 // Check if the Y position is inside the screen area
1042 if (WinBounds.B.Y > ScreenBounds.B.Y) {
1043 // This did not work. Parts of the window are outside the
1044 // screen area. Move the window to a position above the item
1045 WinBounds.Move (0, -WinBounds.A.Y); // Move to X/0
1046 WinBounds.Move (0, Pos.Y-WinBounds.YSize ());
1047 }
1048
1049 // Check if the X position is correct. If the left border of the window
1050 // is outside the screen, correct that
1051 if (WinBounds.B.X > ScreenBounds.B.X) {
1052
1053 WinBounds.Move (ScreenBounds.B.X-WinBounds.B.X, 0);
1054
1055 }
1056
1057 // Assume that the position is valid and move the window
1058 MoveAbs (WinBounds.A);
1059 }
1060
1061
1062
PlaceNear(WindowItem * Item)1063 void ItemWindow::PlaceNear (WindowItem* Item)
1064 // Place the window below the given Item. Item must not be an item
1065 // owned by this window. If there is not enough room to place the
1066 // window below the given item, the window is placed above.
1067 {
1068 // Get the item position in absolute coords
1069 Point ItemPos (Item->ItemX, Item->ItemY);
1070 Item->Owner->Absolute (ItemPos);
1071
1072 // Place the window near this position
1073 PlaceNear (ItemPos);
1074 }
1075
1076
1077
FindAccelKey(ListNode<WindowItem> * N,void * I)1078 int ItemWindow::FindAccelKey (ListNode<WindowItem>* N, void* I)
1079 // Helper function for ItemWithAccelKey
1080 {
1081 // Cast the pointer
1082 FindStruc2 *P = (FindStruc2 *) I;
1083
1084 P->Item = N->Contents () -> ItemWithAccelKey (P->K);
1085 return (P->Item != NULL);
1086 }
1087
1088
1089
ItemWithAccelKey(Key aAccelKey)1090 WindowItem* ItemWindow::ItemWithAccelKey (Key aAccelKey)
1091 // Try to find an item with the given accelerator key in the tree
1092 // below this window. If one is found, a pointer to the item is
1093 // returned, otherwise the function returns NULL.
1094 {
1095 FindStruc2 F;
1096
1097 // Search the given ID
1098 F.Item = NULL;
1099 F.K = aAccelKey;
1100 Traverse (FindAccelKey, &F);
1101 return F.Item;
1102 }
1103
1104
1105
FindHotKey(ListNode<WindowItem> * N,void * P)1106 int ItemWindow::FindHotKey (ListNode<WindowItem>* N, void* P)
1107 // Helper function for ItemWithHotKey
1108 {
1109 return (N->Contents () -> ItemWithHotKey (*(Key*)P) != NULL);
1110 }
1111
1112
1113
ItemWithHotKey(Key aHotKey)1114 WindowItem* ItemWindow::ItemWithHotKey (Key aHotKey)
1115 // Try to find an item with the given hot key in the tree
1116 // below this window. If one is found, a pointer to the item is
1117 // returned, otherwise the function returns NULL.
1118 {
1119 // Searching for a null hotkey does not make sense
1120 PRECONDITION (aHotKey != kbNoKey);
1121 return Traverse (FindHotKey, &aHotKey);
1122 }
1123
1124
1125
FindID(ListNode<WindowItem> * N,void * I)1126 int ItemWindow::FindID (ListNode<WindowItem>* N, void* I)
1127 // Helper function for ItemWithID
1128 {
1129 // Cast the pointer
1130 FindStruc1* P = (FindStruc1*) I;
1131
1132 P->Item = N->Contents () -> ItemWithID (P->ID);
1133 return (P->Item != NULL);
1134 }
1135
1136
1137
ItemWithID(i16 aID)1138 WindowItem* ItemWindow::ItemWithID (i16 aID)
1139 // Try to find an item with the given ID in the tree below this
1140 // window. If one is found, a pointer to the item is returned,
1141 // otherwise the function returns NULL.
1142 {
1143 FindStruc1 F;
1144
1145 // Check the given parameter
1146 PRECONDITION (aID > 0 && aID <= MaxUserID);
1147
1148 // Search the given ID
1149 F.Item = NULL;
1150 F.ID = aID;
1151 Traverse (FindID, &F);
1152 return F.Item;
1153 }
1154
1155
1156
ForcedItemWithID(i16 aID)1157 WindowItem* ItemWindow::ForcedItemWithID (i16 aID)
1158 // Acts like ItemWithID but treats the case different, when no
1159 // matching ID is found: This is considered as a fatal error.
1160 {
1161 // Search for the ID
1162 WindowItem* Item = ItemWithID (aID);
1163
1164 // Check if a item was found
1165 CHECK (Item != NULL);
1166
1167 // Return the result
1168 return Item;
1169 }
1170
1171
1172
SetAccelKey(i16 aID,Key aAccelKey)1173 void ItemWindow::SetAccelKey (i16 aID, Key aAccelKey)
1174 // Sets the accelerator key for the item with the given ID. If no
1175 // item with this ID is found, this is considered as a fatal error.
1176 {
1177 ForcedItemWithID (aID) -> SetAccelKey (aAccelKey);
1178 }
1179
1180
1181
GetHotKey(i16 aID)1182 Key ItemWindow::GetHotKey (i16 aID)
1183 // Return the hot key of the item with the given ID. If no such item
1184 // is found, this is considered as a fatal error.
1185 {
1186 return ForcedItemWithID (aID) -> GetHotKey ();
1187 }
1188
1189
1190
GetAccelKey(i16 aID)1191 Key ItemWindow::GetAccelKey (i16 aID)
1192 // Return the accelerator key of the item with the given ID. If no
1193 // such item is found, this is considered as a fatal error.
1194 {
1195 return ForcedItemWithID (aID) -> GetAccelKey ();
1196 }
1197
1198
1199
SetHelpKey(i16 aID,const String & aHelpKey)1200 void ItemWindow::SetHelpKey (i16 aID, const String &aHelpKey)
1201 // Set the key for the help function for the item with the given ID.
1202 // If no item with that ID is found, this is handled as a fatal error.
1203 {
1204 ForcedItemWithID (aID) -> SetHelpKey (aHelpKey);
1205 }
1206
1207
1208
DrawItem(i16 aID)1209 void ItemWindow::DrawItem (i16 aID)
1210 // Redraw the item with the given ID.
1211 {
1212 ForcedItemWithID (aID) -> Draw ();
1213 }
1214
1215
1216
ActivateItem(i16 aID)1217 void ItemWindow::ActivateItem (i16 aID)
1218 // Activate the item with the given ID
1219 {
1220 // Get a pointer to the item
1221 WindowItem* Item = ForcedItemWithID (aID);
1222
1223 // Activate the item
1224 Item->Activate ();
1225
1226 // If there has been no selected item before, choose this one
1227 ValidateSelectedItem ();
1228 }
1229
1230
1231
DeactivateItem(i16 aID)1232 void ItemWindow::DeactivateItem (i16 aID)
1233 // Deactivate the item with the given ID
1234 {
1235 // Get a pointer to the item
1236 WindowItem* Item = ForcedItemWithID (aID);
1237
1238 // Deactivate the item
1239 Item->Deactivate ();
1240
1241 // If the inactive item is the selected item, choose another selected item
1242 ValidateSelectedItem ();
1243 }
1244
1245
1246
GrayItem(i16 aID)1247 void ItemWindow::GrayItem (i16 aID)
1248 // Gray the item with the given ID
1249 {
1250 // Get a pointer to the item
1251 WindowItem* Item = ForcedItemWithID (aID);
1252
1253 // Gray the item
1254 Item->Gray ();
1255
1256 // If the grayed item is the selected item, choose another selected item
1257 ValidateSelectedItem ();
1258 }
1259
1260
1261
RegisterOneItemKey(ListNode<WindowItem> * N,void *)1262 int ItemWindow::RegisterOneItemKey (ListNode<WindowItem> *N, void *)
1263 // Register the accel key of one item
1264 {
1265 N->Contents () -> RegisterKey ();
1266 return 0;
1267 }
1268
1269
1270
UnregisterOneItemKey(ListNode<WindowItem> * N,void *)1271 int ItemWindow::UnregisterOneItemKey (ListNode<WindowItem> *N, void *)
1272 // Unregister the accel key of one item
1273 {
1274 N->Contents () -> UnregisterKey ();
1275 return 0;
1276 }
1277
1278
1279
RegisterItemKeys()1280 void ItemWindow::RegisterItemKeys ()
1281 // Register the accel keys of all active items
1282 {
1283 Traverse (RegisterOneItemKey);
1284 }
1285
1286
1287
UnregisterItemKeys()1288 void ItemWindow::UnregisterItemKeys ()
1289 // Unregister the accel keys of all active items
1290 {
1291 Traverse (UnregisterOneItemKey);
1292 }
1293
1294
1295
CanClose()1296 int ItemWindow::CanClose ()
1297 // Return true if the window is allowed to close. This function is a hook
1298 // for derived windows, it returns always true.
1299 {
1300 // Simple ItemWindows are allways allowed to close
1301 return 1;
1302 }
1303
1304
1305
Zoom()1306 void ItemWindow::Zoom ()
1307 // Interface function for derived classes. This function is a no op and
1308 // must be overloaded
1309 {
1310 }
1311
1312
1313
1314