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