Initial commit.
[amiga/xmodule.git] / Gui.c
1 /*
2 **      Gui.c
3 **
4 **      Copyright (C) 1993,94,95,96,97 Bernardo Innocenti
5 **
6 **      Graphic User Interface handling routines.
7 */
8
9 #include <exec/nodes.h>
10 #include <exec/memory.h>
11 #include <intuition/intuition.h>
12 #include <intuition/intuitionbase.h>
13 #include <intuition/gadgetclass.h>
14 #include <intuition/imageclass.h>
15 #include <utility/tagitem.h>
16 #include <graphics/rpattr.h>
17
18 #include <proto/exec.h>
19 #include <proto/dos.h>
20 #include <proto/intuition.h>
21 #include <proto/gadtools.h>
22 #include <proto/graphics.h>
23 #include <proto/layers.h>
24 #include <proto/keymap.h>
25 #include <proto/utility.h>
26 #include <proto/commodities.h>
27 #include <proto/diskfont.h>
28
29 #include "XModulePriv.h"
30 #include "Gui.h"
31 #include "CustomClasses.h"
32
33
34
35 XDEF struct Screen              *Scr            = NULL;
36 XDEF struct ScrInfo              ScrInfo        = {0};
37 XDEF APTR                                VisualInfo     = NULL;
38 XDEF struct DrawInfo    *DrawInfo       = NULL;
39
40
41 XDEF struct TextAttr
42         TopazAttr       = { "topaz.font", 8, FS_NORMAL, FPF_ROMFONT },
43         ScreenAttr      = { 0 },
44         WindowAttr      = { 0 },
45         ListAttr        = { 0 },
46         EditorAttr      = { 0 };
47
48 XDEF struct TextFont
49         *TopazFont      = NULL,
50         *WindowFont     = NULL,
51         *ListFont       = NULL;
52
53
54 /* Window borders layout information */
55 XDEF UWORD                               OffX, OffY;                            /* X and Y offsets for window rendering */
56 XDEF WORD                                SizeWidth = 18,                        /* Dimensions of the window size gadget */
57                                                  SizeHeight = 10;
58
59 /* IDCMP windows support */
60 XDEF ULONG                               IDCMPSig = 0;                          /* Signal for above mentioned port              */
61 XDEF ULONG                               Signals = SIGBREAKFLAGS;       /* Signals for Wait() in main loop              */
62 XDEF struct IntuiMessage IntuiMsg;                                      /* A copy of the last received IntuiMsg */
63 XDEF struct List                 WindowList;                            /* Linked list of all open windows              */
64
65 static UBYTE                     ActiveKey      = 0;                    /* These three are used to handle               */
66 static struct Gadget    *ActiveGad      = NULL;                 /*              selection of button gadgets             */
67 static struct Window    *ActiveWin      = NULL;                 /*              with keyboard shortcuts.                */
68 static struct Window *OldPrWindowPtr = (struct Window *)1L;
69
70 XDEF LONG       LastErr                         = 0;
71 XDEF ULONG      UniqueID;                                               /* An ID got from GetUniqueID()                         */
72 XDEF UWORD      WinLockCount            = 0;            /* Allow nesting of window locking                      */
73 XDEF BOOL       Quit                            = FALSE;
74 XDEF BOOL       DoNextSelect            = TRUE;         /* Menu selection, see menu handling code       */
75 XDEF BOOL       ShowRequesters          = TRUE;
76 XDEF BOOL       OwnScreen                       = FALSE;        /* Are we owners or visitors?                           */
77 XDEF BOOL       ScreenReopening         = FALSE;        /* Set to TRUE while reopening windows          */
78 XDEF BOOL       ScreenShutdown          = FALSE;        /* Set to TRUE while shutting down screen       */
79 XDEF Class *ScrollButtonClass   = NULL;
80
81 /* Shared IDCMP port for all windows */
82 static struct MsgPort   *WinPort                        = NULL;
83 static Class                    *VImageClass            = NULL;
84 static ULONG                     VImageUseCount         = 0;
85 static struct Image             *ButtonFrame            = NULL;
86 static WORD                              ButtonFrameWidth       = 0;
87 static WORD                              ButtonFrameHeight      = 0;
88
89
90 XDEF struct WDescr WDescr[WID_COUNT] =
91 {
92         { NULL, 0, 0, (struct TagItem *)ToolBoxWinTags          },
93         { NULL, 0, 0, (struct TagItem *)PrefsWinTags            },
94         { NULL, 0, 0, (struct TagItem *)SongInfoWinTags         },
95         { NULL, 0, 0, (struct TagItem *)InstrumentsWinTags      },
96         { NULL, 0, 0, (struct TagItem *)SequenceWinTags         },
97         { NULL, 0, 0, (struct TagItem *)PatternWinTags          },
98         { NULL, 0, 0, (struct TagItem *)PlayWinTags                     },
99         { NULL, 0, 0, (struct TagItem *)SampleWinTags           },
100         { NULL, 0, 0, (struct TagItem *)OptimizationWinTags     },
101         { NULL, 0, 0, (struct TagItem *)SaversWinTags           },
102         { NULL, 0, 0, (struct TagItem *)PattPrefsWinTags        },
103         { NULL, 0, 0, (struct TagItem *)PattSizeWinTags         },
104         { NULL, 0, 0, (struct TagItem *)ClearWinTags            },
105         { NULL, 0, 0, (struct TagItem *)LogWinTags                      },
106         { NULL, 0, 0, (struct TagItem *)ProgressWinTags         }
107 };
108
109
110
111 XDEF struct GuiSwitches GuiSwitches =
112 {
113         TRUE,                   /* SaveIcons            */
114         TRUE,                   /* AskOverwrite         */
115         TRUE,                   /* AskExit                      */
116         TRUE,                   /* ShowAppIcon          */
117         FALSE,                  /* UseReqTools          */
118         TRUE,                   /* SmartRefresh         */
119         TRUE,                   /* UseDataTypes         */
120         TRUE,                   /* InstrSaveIcons       */
121         TRUE,                   /* AskAutosave          */
122         FALSE,                  /* DoBackups            */
123         FALSE,                  /* LogToFile            */
124         INST_8SVX,              /* InstrSaveMode        */
125         1,                              /* SampDrawMode         */
126         XMDMF_NOTE+1,   /* LogLevel                     */
127         0,                              /* AutosaveTime         */
128         3,                              /* BackupVersions       */
129         "*,#",                  /* BackupTemplate       */
130         "CON:////XModule Log/AUTO/CLOSE/INACTIVE/SCREEN XMODULE"        /* LogFile */
131 };
132
133
134
135 #ifndef OS30_ONLY
136
137 /* Wait pointer image data */
138
139 static __chip UWORD WaitPointer[] =
140 {
141         0x0000, 0x0000,
142
143         0x0400, 0x07c0,
144         0x0000, 0x07c0,
145         0x0100, 0x0380,
146         0x0000, 0x07e0,
147         0x07c0, 0x1ff8,
148         0x1ff0, 0x3fec,
149         0x3ff8, 0x7fde,
150         0x3ff8, 0x7fbe,
151         0x7ffc, 0xff7f,
152         0x7efc, 0xffff,
153         0x7ffc, 0xffff,
154         0x3ff8, 0x7ffe,
155         0x3ff8, 0x7ffe,
156         0x1ff0, 0x3ffc,
157         0x07c0, 0x1ff8,
158         0x0000, 0x07e0,
159
160         0x0000, 0x0000
161 };
162
163 #endif /* OS30_ONLY */
164
165
166 /* Martin Taillefer's block pointer */
167 /*
168 static UWORD __chip BlockPointer[] =
169 {
170         0x0000, 0x0000,
171
172         0x0000, 0x0100,
173         0x0100, 0x0280,
174         0x0380, 0x0440,
175         0x0100, 0x0280,
176         0x0100, 0x0ee0,
177         0x0000, 0x2828,
178         0x2008, 0x5834,
179         0x783c, 0x8002,
180         0x2008, 0x5834,
181         0x0000, 0x2828,
182         0x0100, 0x0ee0,
183         0x0100, 0x0280,
184         0x0380, 0x0440,
185         0x0100, 0x0280,
186         0x0000, 0x0100,
187         0x0000, 0x0000,
188
189         0x0000, 0x0000
190 };
191 */
192
193
194 /* Local function prototypes */
195
196 static void                                      HandleKey                      (void);
197 static void                                      SelectButton           (struct Window *win, struct Gadget *gad);
198 static void                                      DeselectButton         (void);
199 static void                              RenderWindowBorders(struct WinUserData *wud);
200 static struct WindowBorder      *CreateWindowBorder (struct WinUserData *wud, UWORD left, UWORD top, UWORD width, UWORD height, ULONG bordertype);
201 static struct Gadget            *CreateVImageButton (struct TagItem *tags, struct NewGadget *ng);
202 static void                                      DeleteVImageButton     (struct Gadget *g);
203 static struct Gadget            *CreateGadgets          (struct LayoutGadgetsArgs *lga, UWORD mode, UWORD left, UWORD top, UWORD width, UWORD height);
204 static void                                      LayoutGadgets          (struct LayoutGadgetsArgs *lga, UWORD mode);
205 static void                                      DeleteGadgets          (struct WinUserData *wud);
206
207 static void                                      DeleteWUD                      (struct WinUserData *wud);
208 static struct WinUserData       *CreateLayoutInfo       (struct WinUserData *wud);
209
210
211
212 GLOBALCALL LONG HandleGui (void)
213
214 /* Handle XModule GUI - Main event handling loop */
215 {
216         ULONG recsig;   /* Received Signals     */
217         LONG rc = 0;    /* Return Code          */
218
219
220         /* This is the main event handling loop */
221
222         while (!Quit)
223         {
224                 recsig = Wait (Signals);
225
226                 if (recsig & IDCMPSig)
227                         HandleIDCMP();
228
229                 if (recsig & AudioSig)
230                         HandleAudio();
231
232                 if (recsig & PubPortSig)
233                         HandleRexxMsg();
234
235                 if (recsig & AppSig)
236                         HandleAppMessage();
237
238                 if (recsig & FileReqSig)
239                         HandleFileRequest();
240
241                 if (recsig & CxSig)
242                         HandleCx();
243
244                 if (recsig & AmigaGuideSig)
245                         HandleAmigaGuide();
246
247                 /* Check break signals */
248                 if (recsig & SIGBREAKFLAGS)
249                 {
250                         if (recsig & SIGBREAKF_CTRL_C)
251                         {
252                                 Quit = TRUE;
253                                 GuiSwitches.AskExit = FALSE;
254                                 rc = ERROR_BREAK;
255                         }
256
257                         if (recsig & SIGBREAKF_CTRL_D)
258                                 if (MyBroker) ActivateCxObj (MyBroker, FALSE);
259
260                         if (recsig & SIGBREAKF_CTRL_E)
261                                 if (MyBroker) ActivateCxObj (MyBroker, TRUE);
262
263                         if (recsig & SIGBREAKF_CTRL_F)
264                                 DeIconify();
265                 }
266
267
268                 if (LastErr)
269                 {
270                         switch (LastErr)
271                         {
272                                 case ERROR_NO_FREE_STORE:
273                                         ShowMessage (MSG_NO_FREE_STORE);
274                                         break;
275
276                                 case ERROR_BREAK:
277                                         ShowMessage (MSG_BREAK);
278                                         break;
279
280                                 default:
281                                         break;
282                         }
283
284                         DisplayBeep (Scr);
285                         LastErr = 0;
286                 }
287
288                 if (Quit && GuiSwitches.AskExit)
289                         if (!ShowRequestArgs (MSG_REALLY_QUIT_XMODULE, MSG_YES_OR_NO, NULL))
290                         {
291                                 Quit = FALSE;
292                                 rc = 0;
293                         }
294
295         }       /* End main loop */
296
297         return rc;
298 }
299
300
301
302 /* Intuition Event Handler.  Based on GadToolsBox's HandleIDCMP() */
303 GLOBALCALL void HandleIDCMP (void)
304 {
305         struct IntuiMessage     *m;
306         struct MenuItem         *n;
307         struct Window           *win;
308         struct WinUserData      *wud;
309
310         while (m = GT_GetIMsg (WinPort))
311         {
312                 IntuiMsg = *m;  /* Make a local copy and return message immediately */
313
314                 GT_ReplyIMsg (m);
315
316                 win = IntuiMsg.IDCMPWindow;
317                 wud = (struct WinUserData *)win->UserData;
318
319                 switch (IntuiMsg.Class)
320                 {
321                         case IDCMP_REFRESHWINDOW:
322
323                                 /* TODO: Handle multiple IDCMP_REFRESHWINDOW
324                                  * messages sent at the same time.
325                                  */
326
327                                 /* Lock Layer in sizeable windows so its size
328                                  * won't change until we are finished rendering
329                                  * on it.
330                                  *
331                                  * Newsflash: **DON'T!**  Layers BeginUpdate() will already
332                                  * lock the window layer for us, so doing it again we would
333                                  * risk a complete GUI deadlock in some particular conditions...
334                                  */
335                                 /* if (win->Flags & WFLG_SIZEGADGET)
336                                  *      LockLayer (NULL, win->WLayer);
337                                  */
338
339                                 if (wud->WUDFlags & WUDF_JUSTRESIZED)
340                                 {
341                                         // RefreshGadgets (wud->GList, win, NULL);
342                                         GT_RefreshWindow (win, NULL);
343                                         RefreshWindowFrame (win);
344
345                                         if (wud->Borders)
346                                                 RenderWindowBorders (wud);
347
348                                         wud->WUDFlags &= ~WUDF_JUSTRESIZED;
349                                 }
350                                 else
351                                 {
352                                         GT_BeginRefresh (win);
353
354                                         if (wud->Borders)
355                                                 RenderWindowBorders (wud);
356
357                                         GT_EndRefresh (win, TRUE);
358                                 }
359
360                                 /* if (win->Flags & WFLG_SIZEGADGET)
361                                  *      UnlockLayer (win->WLayer);
362                                  */
363                                 break;
364
365                         case IDCMP_RAWKEY:
366                                 HandleKey ();
367                                 break;
368
369                         case IDCMP_NEWSIZE:
370                         {
371                                 struct Gadget *g;
372                                 struct LayoutGadgetsArgs lga;
373                                 struct RastPort rp;
374                                 ULONG SpecialTags[20];
375                                 UWORD newwidth, newheight;
376
377                                 /* TODO: Handle multiple IDCMP_NEWSIZE
378                                  * messages sent at the same time.
379                                  */
380
381 //                              LockLayer (NULL, win->WLayer);
382
383                                 newwidth        = win->Width - win->BorderLeft - win->BorderRight;
384                                 newheight       = win->Height - win->BorderTop - win->BorderBottom;
385
386                                 if ((wud->WindowSize.Width == newwidth) &&
387                                         (wud->WindowSize.Height == newheight))
388                                 {
389 //                                      UnlockLayer (win->WLayer);
390                                         break;
391                                 }
392
393                                 if (!(wud->WUDFlags & WUDF_CUSTOMLAYOUT))
394                                 {
395                                         /* Detatch and free old gadgets */
396                                         RemoveGList (win, wud->GList, -1);
397                                         DeleteGadgets (wud);
398
399                                         /* Clear old window region (or what remains of it) */
400                                         SetAPen (win->RPort, 0);
401                                         SetDrMd (win->RPort, JAM1);
402                                         RectFill (win->RPort, win->BorderLeft, win->BorderTop,
403                                                 min (wud->WindowSize.Width, newwidth) + win->BorderLeft - 1,
404                                                 min (wud->WindowSize.Height, newheight) + win->BorderTop - 1);
405
406                                         wud->WindowSize.Width = newwidth;
407                                         wud->WindowSize.Height = newheight;
408
409
410                                         /* Layout phase 2 */
411
412                                         InitRastPort (&rp);
413                                         SetFont (&rp, wud->Font);
414
415                                         if (!CreateContext (&wud->GList))
416                                         {
417 //                                              UnlockLayer (win->WLayer);
418                                                 DeleteWUD (wud);
419                                                 break;
420                                         }
421
422                                         lga.Args                = wud->LayoutArgs;
423                                         lga.VInfo               = VisualInfo;
424                                         lga.PrevGad             = wud->GList;
425                                         lga.GInfo               = wud->GInfo;
426                                         lga.Wud                 = wud;
427                                         lga.DummyRast   = &rp;
428                                         lga.Count               = 0;
429                                         lga.SpecialTags = SpecialTags;
430
431                                         SpecialTags[0] = GT_Underscore;
432                                         SpecialTags[1] = (ULONG) '_';
433
434                                         g = CreateGadgets (&lga, LAYOUTMODE_V, OffX + lga.GInfo[0].LabelWidth + HSPACING, OffY + VSPACING,
435                                                 wud->WindowSize.Width - lga.GInfo[0].LabelWidth - HSPACING * 2,
436                                                 wud->WindowSize.Height - VSPACING * 2);
437
438                                         if (!g)
439                                         {
440 //                                              UnlockLayer (win->WLayer);
441                                                 DeleteWUD (wud);
442                                                 break;
443                                         }
444
445                                         AddGList (win, wud->GList, -1, -1, NULL);
446                                         wud->WUDFlags |= WUDF_JUSTRESIZED;
447                                 }
448
449                                 if (wud->IDCMPFunc) wud->IDCMPFunc (wud);
450
451 //                              UnlockLayer (win->WLayer);
452                                 break;
453                         }
454
455                         case IDCMP_CLOSEWINDOW:
456                                 if (wud->WindowID == WID_TOOLBOX)
457                                         Quit = 1;
458                                 else
459                                         MyCloseWindow (wud);
460
461                                 break;
462
463                         case IDCMP_GADGETUP:
464                         case IDCMP_GADGETDOWN:
465                         {
466                                 struct Gadget *gad = (struct Gadget *)IntuiMsg.IAddress;
467
468                                 /* Toggle switch */
469                                 if (wud->GInfo[gad->GadgetID].GKind == CHECKBOX_KIND)
470                                 {
471                                         UWORD *check;
472
473                                         if (check = (WORD *)(wud->GInfo[gad->GadgetID].SpecialStorage))
474                                                 *check ^= 1;
475                                 }
476
477                                 /* Execute function */
478                                 if (((struct Gadget *)IntuiMsg.IAddress)->UserData)
479                                         ((void (*)(struct WinUserData *)) gad->UserData) (wud);
480
481                                 break;
482                         }
483
484                         case IDCMP_MENUPICK:
485                                 while (IntuiMsg.Code != MENUNULL)
486                                 {
487                                         n = ItemAddress (win->MenuStrip, IntuiMsg.Code);
488                                         ((void (*)(struct WinUserData *))(GTMENUITEM_USERDATA(n))) (wud);
489
490                                         /* Some window operations invalidate the menu
491                                          * we are working on.  For istance, Re-opening a
492                                          * window causes the old MenuStrip to be killed.
493                                          * The DoNextSelect flag provides a way to stop
494                                          * this loop and avoid a nasty crash.
495                                          */
496                                         if (!DoNextSelect)
497                                         {
498                                                 DoNextSelect = TRUE;
499                                                 break;
500                                         }
501                                         IntuiMsg.Code = n->NextSelect;
502                                 }
503                                 break;
504
505                         case IDCMP_INACTIVEWINDOW:
506                                 DeselectButton();
507                                 if (wud->IDCMPFunc) wud->IDCMPFunc (wud);
508                                 break;
509
510                         case IDCMP_MENUHELP:
511                         case IDCMP_GADGETHELP:
512                                 HandleHelp (&IntuiMsg);
513                                 break;
514
515                         default:
516                                 if (wud->IDCMPFunc) wud->IDCMPFunc (wud);
517                                 break;
518
519                 }       /* End switch (IntuiMsg.Class) */
520
521                 if (!WinPort) break;
522
523         }       /* End while (GT_GetIMsg ()) */
524 }
525
526
527
528 static void HandleKey (void)
529 {
530         struct Window           *win = IntuiMsg.IDCMPWindow;
531         struct WinUserData      *wud = (struct WinUserData *)win->UserData;
532         UWORD i;
533         UBYTE keycode;
534
535
536         /* Handle key up for buttons */
537
538         if (IntuiMsg.Code & IECODE_UP_PREFIX)
539         {
540                 struct Gadget *gad = ActiveGad;
541
542                 DeselectButton();
543                 if (gad && (ActiveKey == (IntuiMsg.Code & ~IECODE_UP_PREFIX)))
544                         ((void (*)(struct WinUserData *)) gad->UserData) (wud);
545
546                 return;
547         }
548
549         switch (IntuiMsg.Code)
550         {
551                 case 0x5F:      /* HELP */
552                         HandleHelp (&IntuiMsg);
553                         return;
554
555                 case CURSORUP:
556                 case CURSORDOWN:
557
558                         if (wud->GInfo)
559                                 for (i = 0; i < wud->GCount; i++)
560                                         if (wud->GInfo[i].GKind == LISTVIEW_KIND)
561                                         {
562                                                 struct Gadget *g = wud->Gadgets[i];
563                                                 LONG selected, oldselected, top = ~0;
564
565 #ifndef OS30_ONLY
566                                                 if (GadToolsBase->lib_Version < 39)
567                                                         selected = (LONG)(*(UWORD *)(((char *)g)+sizeof(struct Gadget)+48));
568                                                         /* top = *(short *)(((char *)gad) + sizeof(struct Gadget) + 6); +4 ? */
569                                                 else
570 #endif /* !OS30_ONLY */
571                                                         GT_GetGadgetAttrs (g, win, NULL,
572                                                                 GTLV_Selected,  &selected,
573                                                                 GTLV_Top,               &top,
574                                                                 TAG_DONE);
575
576                                                 selected = (LONG)((WORD) selected);     /* Extend to long */
577                                                 oldselected = selected; /* Make a backup of it */
578
579                                                 if (selected == ~0)
580                                                         selected = top; /* Scroll Top */
581                                                 else
582                                                         top = ~0;
583
584                                                 if (IntuiMsg.Code == CURSORUP)
585                                                 {
586                                                         if (IntuiMsg.Qualifier & IEQUALIFIER_SHIFT)
587                                                                 selected -= 5;
588                                                         else if (IntuiMsg.Qualifier & IEQUALIFIER_ALT)
589                                                                 selected = 0;
590                                                         else
591                                                                 selected--;
592                                                 }
593                                                 else /* CURSORDOWN */
594                                                 {
595                                                         if (IntuiMsg.Qualifier & IEQUALIFIER_SHIFT)
596                                                                 selected += 5;
597                                                         else if (IntuiMsg.Qualifier & IEQUALIFIER_ALT)
598                                                                 selected = 65535;
599                                                         else
600                                                                 selected++;
601                                                 }
602
603                                                 if (selected < 0) selected = 0;
604
605                                                 GT_SetGadgetAttrs (g, win, NULL,
606                                                         (top == ~0) ? GTLV_Selected : GTLV_Top,                 selected,
607                                                         (top == ~0) ? GTLV_MakeVisible : TAG_IGNORE,    selected,
608                                                         TAG_DONE);
609
610 #ifndef OS30_ONLY
611                                                 if (GadToolsBase->lib_Version < 39)
612                                                         selected = (LONG)(*(UWORD *)(((char *)g)+sizeof(struct Gadget)+48));
613                                                 else
614 #endif /* !OS30_ONLY */
615                                                         GT_GetGadgetAttrs (g, win, NULL,
616                                                                 GTLV_Selected,  &selected,
617                                                                 TAG_DONE);
618
619                                                 if (selected != oldselected)
620                                                 {
621                                                         IntuiMsg.Code = selected;
622                                                         if (g->UserData)
623                                                                 ((void (*)(struct WinUserData *)) g->UserData) (wud);
624                                                         break; /* Stop for() loop */
625                                                 }
626                                         }       /* End for */
627                         return;
628
629                 case 0x42:      /* TAB */
630                         if (IntuiMsg.Qualifier & IEQUALIFIER_ALT)
631                         {
632                                 struct WinUserData *nextwud;
633
634                                 if (IntuiMsg.Qualifier & IEQUALIFIER_SHIFT)
635                                 {
636                                         /* ALT+SHIFT+TAB: Cycle windows backwards */
637
638                                         nextwud = (struct WinUserData *)wud->Link.mln_Pred;
639
640                                         if (!(nextwud->Link.mln_Pred))  /* List head? */
641                                                 nextwud = (struct WinUserData *)WindowList.lh_TailPred;
642                                 }
643                                 else
644                                 {
645                                         /* ALT+TAB: Cycle windows */
646
647                                         nextwud = (struct WinUserData *)wud->Link.mln_Succ;
648
649                                         if (!(nextwud->Link.mln_Succ))  /* List tail? */
650                                                 nextwud = (struct WinUserData *)WindowList.lh_Head;
651                                 }
652
653                                 RevealWindow (nextwud);
654                                 return;
655                         }
656
657                 default:
658                         break;
659
660         } /* End switch (IntuiMsg.Code) */
661
662
663         /*      Convert the IDCMP_RAWKEY IntuiMessage to the single
664          *      character representation it corresponds to. If this isn't
665          *      possible (e.g. a HELP key or cursor key) then abort.
666          */
667         {
668                 static struct InputEvent ie;
669
670                 ie.ie_NextEvent         = NULL;
671                 ie.ie_Class                     = IECLASS_RAWKEY;
672                 ie.ie_SubClass          = 0;
673                 ie.ie_Code                      = IntuiMsg.Code;
674                 ie.ie_Qualifier         = IntuiMsg.Qualifier & IEQUALIFIER_CONTROL;     /* Filter qualifiers. */
675                 ie.ie_EventAddress      = (APTR *) *((ULONG *)IntuiMsg.IAddress);
676                 if (MapRawKey (&ie, &keycode, 1, NULL) != 1)
677                         return;
678         }
679
680
681         /* Handle IDCMP_VANILLAKEY */
682
683         /* Check special keys */
684         switch (keycode)
685         {
686                 case 0x03:      /* CTRL-C */
687                         Signal ((struct Task *)ThisTask, SIGBREAKF_CTRL_C);
688                         return;
689
690                 case 0x09:      /* TAB */
691                 case 0x0D:      /* RETURN */
692                         if (wud->GInfo)
693                                 for (i = 0; i < wud->GCount; i++)
694                                         if (wud->GInfo[i].GKind == STRING_KIND || wud->GInfo[i].GKind == INTEGER_KIND)
695                                                 ActivateGadget (wud->Gadgets[i],win, NULL);
696                         return;
697
698                 case 0x1B:      /* ESC */
699                         if (wud->WindowID != WID_TOOLBOX)
700                                 MyCloseWindow (wud);
701                         return;
702
703                 default:
704                         break;
705         }
706
707
708         /* Look for gadget shortcuts */
709
710         if (wud->GInfo)
711                 for (i = 0; i < wud->GCount; i++)
712                 {
713                         if (wud->Keys[i] == keycode)    /* Case insensitive compare */
714                         {
715                                 struct Gadget *g = wud->Gadgets[i];
716                                 LONG disabled = FALSE;
717
718                                 /* Check disabled */
719
720 #ifndef OS30_ONLY
721                                 if (GadToolsBase->lib_Version < 39)
722                                         disabled = g->Flags & GFLG_DISABLED;
723                                 else
724 #endif /* !OS30_ONLY */
725                                         GT_GetGadgetAttrs (g, win, NULL,
726                                                 GA_Disabled, &disabled,
727                                                 TAG_DONE);
728
729                                 if (disabled) break;    /* Stop for() loop */
730
731                                 switch (wud->GInfo[i].GKind)
732                                 {
733                                         case BUTTON_KIND:
734                                                 if (!(IntuiMsg.Qualifier & IEQUALIFIER_REPEAT))
735                                                         SelectButton (win, g);
736                                                 break;
737
738                                         case CHECKBOX_KIND:
739
740                                                 /* Toggle switch */
741                                                 if (wud->GInfo[i].SpecialStorage)
742                                                         *((UWORD *)wud->GInfo[i].SpecialStorage) ^= 1;
743
744                                                 GT_SetGadgetAttrs (g, win, NULL,
745                                                         GTCB_Checked, !(g->Flags & GFLG_SELECTED),
746                                                         TAG_DONE);
747
748                                                 if (g->UserData)
749                                                         ((void (*)(struct WinUserData *)) g->UserData) (wud);
750                                                 break;
751
752                                         case INTEGER_KIND:
753                                         case STRING_KIND:
754                                                 ActivateGadget (g, win, NULL);
755                                                 break;
756
757                                         case CYCLE_KIND:
758 #ifndef OS30_ONLY
759                                                 if (GadToolsBase->lib_Version >= 39)
760 #endif /* !OS30_ONLY */
761                                                 {
762                                                         LONG act, max;
763                                                         UBYTE **lab;
764
765                                                         /* ON V37: active = *(short *)(((char *)gad) + sizeof(struct Gadget) + 6); */
766
767                                                         GT_GetGadgetAttrs (g, win, NULL,
768                                                                 GTCY_Active, &act,
769                                                                 GTCY_Labels, &lab,
770                                                                 TAG_DONE);
771
772                                                         act = (LONG)((UWORD)act);       /* Extend to LONG */
773
774                                                         if (IntuiMsg.Qualifier & IEQUALIFIER_SHIFT)
775                                                                 act--;
776                                                         else
777                                                                 act++;
778
779                                                         for (max = 0; lab[max]; max++); /* Count labels */
780
781                                                         if (act >= max) act = 0;
782                                                         else if (act < 0) act = max - 1;
783
784                                                         GT_SetGadgetAttrs (g, win, NULL,
785                                                                 GTCY_Active, act,
786                                                                 TAG_DONE);
787
788                                                         if (g->UserData)
789                                                         {
790                                                                 IntuiMsg.Code = act;
791                                                                 ((void (*)(struct WinUserData *)) g->UserData) (wud);
792                                                         }
793                                                 }
794                                                 break;
795
796                                         case MX_KIND:
797                                         {
798                                                 LONG act;
799
800 #ifndef OS30_ONLY
801                                                 if (GadToolsBase->lib_Version < 39)
802                                                         act = (LONG)(*(UWORD *)(((char *)g)+sizeof(struct Gadget)+24)); /* 38? */
803                                                 else
804 #endif /* !OS30_ONLY */
805                                                 {
806                                                         GT_GetGadgetAttrs (g, win, NULL,
807                                                                 GTMX_Active, &act,
808                                                                 TAG_DONE);
809                                                         act = (LONG)((UWORD)act);       /* Extend to LONG */
810                                                 }
811
812                                                 if (IntuiMsg.Qualifier & IEQUALIFIER_SHIFT)
813                                                         act--;
814                                                 else
815                                                         act++;
816
817                                                 GT_SetGadgetAttrs (g, win, NULL,
818                                                         GTMX_Active, act,
819                                                         TAG_DONE);
820
821 #ifndef OS30_ONLY
822                                                 if (GadToolsBase->lib_Version < 39)
823                                                         act = (LONG)(*(UWORD *)(((char *)g)+sizeof(struct Gadget)+24));
824                                                 else
825 #endif /* !OS30_ONLY */
826                                                 {
827                                                         GT_GetGadgetAttrs (g, win, NULL,
828                                                                 GTMX_Active, &act,
829                                                                 TAG_DONE);
830                                                         act = (LONG)((UWORD)act);       /* Extend to LONG */
831                                                 }
832
833                                                 if (g->UserData)
834                                                 {
835                                                         IntuiMsg.Code = act;
836                                                         ((void (*)(struct WinUserData *)) g->UserData) (wud);
837                                                 }
838
839                                                 break;
840                                         }
841
842                                         case SLIDER_KIND:
843 #ifndef OS30_ONLY
844                                                 if (GadToolsBase->lib_Version >= 39)
845 #endif /* !OS30_ONLY */
846                                                 {
847                                                         LONG min, max, level;
848
849                                                         GT_GetGadgetAttrs (g, win, NULL,
850                                                                 GTSL_Min, &min,
851                                                                 GTSL_Max, &max,
852                                                                 GTSL_Level, &level,
853                                                                 TAG_DONE);
854
855                                                         /* Extend to LONG */
856                                                         min = (LONG)((WORD)min);
857                                                         max = (LONG)((WORD)max);
858                                                         level = (LONG)((WORD)level);
859
860                                                         if (IntuiMsg.Qualifier & IEQUALIFIER_SHIFT)
861                                                         {
862                                                                 if (IntuiMsg.Qualifier & IEQUALIFIER_ALT)
863                                                                         level = min;
864                                                                 else level--;
865                                                         }
866                                                         else
867                                                         {
868                                                                 if (IntuiMsg.Qualifier & IEQUALIFIER_ALT)
869                                                                         level = max;
870                                                                 else level++;
871                                                         }
872
873                                                         if (level > max) level = max;
874                                                         if (level < min) level = min;
875
876                                                         GT_SetGadgetAttrs (g, win, NULL,
877                                                                 GTSL_Level, level,
878                                                                 TAG_DONE);
879
880                                                         if (g->UserData)
881                                                         {
882                                                                 IntuiMsg.Code = level;
883                                                                 ((void (*)(struct WinUserData *)) g->UserData) (wud);
884                                                         }
885                                                 }
886                                                 break;
887
888                                         default:
889                                                 break;
890                                 }
891
892                                 return; /* Stop for() loop */
893                         }
894                 }       /* End for() */
895
896
897         /* There is no apparent use for this key event,
898          * let's pass the IntuiMessage to user's IDCMPFunc()...
899          */
900         if (wud->IDCMPFunc) ((void (*)(void)) wud->IDCMPFunc) ();
901 }
902
903
904
905 static void SelectButton (struct Window *win, struct Gadget *gad)
906
907 /* Selects the button gadget <gad>.  This operation is illegal with
908  * GadTools gadgets, but many programs do it anyway, so this trick
909  * will probably be supported in future OS releases :-).
910  */
911 {
912         UWORD gadpos;
913
914         if (ActiveGad) DeselectButton();
915
916         gadpos = RemoveGadget (win, gad);
917
918         gad->Flags |= GFLG_SELECTED;
919         AddGadget (win, gad, gadpos);
920         RefreshGList (gad, win, NULL, 1);
921
922         ActiveKey = IntuiMsg.Code;
923         ActiveGad = gad;
924         ActiveWin = win;
925 }
926
927
928
929 static void DeselectButton (void)
930
931 /* Deselects the button previously selected with SelectButton() */
932 {
933         if      (ActiveGad)
934         {
935                 UWORD gadpos = RemoveGadget (ActiveWin, ActiveGad);
936
937                 ActiveGad->Flags &= ~GFLG_SELECTED;
938                 AddGadget (ActiveWin, ActiveGad, gadpos);
939                 RefreshGList (ActiveGad, ActiveWin, NULL, 1);
940
941                 ActiveGad = NULL;
942         }
943 }
944
945
946
947 GLOBALCALL void LockWindows (void)
948
949 /* Disable user input in all windows */
950 {
951         struct WinUserData      *wud;
952         struct Window           *win;
953         struct WindowLock       *lock;
954
955
956         /* Are the windows already locked? */
957         WinLockCount++;
958         if (WinLockCount > 1) return;
959
960         for (wud = (struct WinUserData *) WindowList.lh_Head;
961                 wud->Link.mln_Succ;
962                 wud = (struct WinUserData *)wud->Link.mln_Succ)
963         {
964                 if (!(win = wud->Win)) continue;
965
966                 /* Set wait pointer */
967 #ifndef OS30_ONLY
968                 if (IntuitionBase->LibNode.lib_Version < 39)
969                         SetPointer (win, WaitPointer, 16, 16, -6, 0);
970                 else
971 #endif /* !OS30_ONLY */
972                         SetWindowPointer (win, WA_BusyPointer, TRUE, TAG_DONE);
973
974                 /* Do not block input in Progress window */
975                 if (wud->WindowID == WID_PROGRESS) continue;
976
977                 /* Set an invisible Requester in window to block user input.
978                  * We allocate 4 more bytes after the requester structure to store
979                  * the IDCMP flags before modifying them.  MEMF_PUBLIC is used
980                  * because intuition is going to process the Requester structure.
981                  */
982
983                 if (!(lock = AllocPooled (Pool, sizeof (struct WindowLock))))
984                         continue;
985
986                 InitRequester (&lock->Req);
987                 lock->Req.Flags = SIMPLEREQ | NOREQBACKFILL;
988
989                 /* Disable window resizing */
990                 if (win->Flags & WFLG_SIZEGADGET)
991                 {
992                         lock->OldMinWidth       = win->MinWidth;
993                         lock->OldMinHeight      = win->MinHeight;
994                         lock->OldMaxWidth       = win->MaxWidth;
995                         lock->OldMaxHeight      = win->MaxHeight;
996                         WindowLimits (win, win->Width, win->Height,
997                                 win->Width, win->Height);
998                 }
999
1000                 /* Disable IDCMP messages except IDCMP_REFRESHWINDOW events.
1001                  * WARNING: ModifyIDCMP (win, 0) would free the shared port!!
1002                  */
1003                 lock->OldIDCMPFlags = win->IDCMPFlags;
1004                 ModifyIDCMP (win, IDCMP_REFRESHWINDOW);
1005
1006                 Request (&lock->Req, win);
1007         }
1008 }
1009
1010
1011
1012 GLOBALCALL void UnlockWindows (void)
1013
1014 /* Restore user input in all windows. */
1015 {
1016         struct WinUserData      *wud;
1017         struct Window           *win;
1018         struct WindowLock       *lock;
1019
1020         /* Make sure windows arn't unlocked already */
1021         if (WinLockCount) return;
1022
1023         /* Check lock nesting */
1024         WinLockCount--;
1025         if (WinLockCount) return;
1026
1027         for (wud = (struct WinUserData *) WindowList.lh_Head;
1028                 wud->Link.mln_Succ;
1029                 wud = (struct WinUserData *)wud->Link.mln_Succ)
1030         {
1031                 if (!(win = wud->Win)) continue;
1032
1033                 if (lock = (struct WindowLock *) win->FirstRequest)
1034                 {
1035                         /* Restore old window IDCMP */
1036                         ModifyIDCMP (win, lock->OldIDCMPFlags);
1037
1038                         /* Re-enable window sizing and restore old window limits */
1039                         if (win->Flags & WFLG_SIZEGADGET)
1040                                 WindowLimits (win, lock->OldMinWidth, lock->OldMinHeight,
1041                                         lock->OldMaxWidth, lock->OldMaxHeight);
1042
1043                         EndRequest (&lock->Req, wud->Win);
1044                         FreePooled (Pool, lock, sizeof (struct WindowLock));
1045                 }
1046
1047                 /* Restore standard pointer */
1048 #ifndef OS30_ONLY
1049                 if (IntuitionBase->LibNode.lib_Version < 39)
1050                         ClearPointer (win);
1051                 else
1052 #endif /* !OS30_ONLY */
1053                         SetWindowPointer (win, TAG_DONE);
1054         }
1055 }
1056
1057
1058
1059 GLOBALCALL void RevealWindow (struct WinUserData *wud)
1060 {
1061         WindowToFront (wud->Win);
1062         ActivateWindow (wud->Win);
1063
1064         /* Make the window visible on the screen */
1065
1066 #ifndef OS30_ONLY
1067         if (IntuitionBase->LibNode.lib_Version >= 39)
1068 #endif /* OS30_ONLY */
1069                 ScreenPosition (Scr, SPOS_MAKEVISIBLE,
1070                         wud->Win->LeftEdge, wud->Win->TopEdge,
1071                         wud->Win->LeftEdge + wud->Win->Width - 1,
1072                         wud->Win->TopEdge + wud->Win->Height - 1);
1073 }
1074
1075
1076
1077 GLOBALCALL void SetGadgets (struct WinUserData *wud, LONG arg, ...)
1078
1079 /* Update status of gadgets in the window associated to <wud>.
1080  * <arg> is the first of a -1 terminated array of commands.
1081  * Each command is represented by a pair of LONGs, where the
1082  * first LONG is the gadget number, and the second is the value
1083  * to set for that gadget, depending on the gadget type.
1084  */
1085 {
1086         LONG *cmd = &arg;
1087
1088         static ULONG actions[] =
1089         {
1090                 TAG_IGNORE,             /* GENERIC_KIND         */
1091                 TAG_IGNORE,             /* BUTTON_KIND          */
1092                 GTCB_Checked,   /* CHECKBOX_KIND        */
1093                 GTIN_Number,    /* INTEGER_KIND         */
1094                 GTLV_Selected,  /* LISTVIEW_KIND        */
1095                 GTMX_Active,    /* MX_KIND                      */
1096                 GTNM_Number,    /* NUMBER_KIND          */
1097                 GTCY_Active,    /* CYCLE_KIND           */
1098                 GTPA_Color,             /* PALETTE_KIND         */
1099                 TAG_IGNORE,             /* SCROLLER_KIND        */
1100                 TAG_IGNORE,             /* -- reserved --       */
1101                 GTSL_Level,             /* SLIDER_KIND          */
1102                 GTST_String,    /* STRING_KIND          */
1103                 GTTX_Text               /* TEXT_KIND            */
1104         };
1105
1106         while (*cmd != -1)
1107         {
1108                 GT_SetGadgetAttrs (wud->Gadgets[*cmd], wud->Win, NULL,
1109                         actions[wud->GInfo[*cmd].GKind], *(cmd+1),
1110                         TAG_DONE);
1111
1112                 cmd += 2;
1113         }
1114 }
1115
1116
1117
1118 GLOBALCALL LONG AddListViewNode (struct List *lv, CONST_STRPTR label, ...)
1119
1120 /* Var-args stub for AddListViewNodeA */
1121 {
1122         return AddListViewNodeA (lv, label, (LONG *) (&label)+1);
1123 }
1124
1125
1126
1127 GLOBALCALL LONG AddListViewNodeA (struct List *lv, CONST_STRPTR label, LONG *args)
1128
1129 /* Allocate and add a new node to a ListView list.  The label
1130  * is printf()-formatted and copied to a buffer just after the
1131  * node structure.  Call RemListViewNode() to deallocate the node.
1132  *
1133  * RETURNS
1134  *   0 for failure (no memory), any other value for success.
1135  */
1136 {
1137         struct Node *n;
1138         UBYTE buf[256];
1139
1140         if (args)
1141         {
1142                 VSPrintf (buf, label, args);
1143                 label = buf;
1144         }
1145
1146         if (!(n = AllocVecPooled (Pool, sizeof (struct Node) + strlen (label) + 1)))
1147                 return FALSE;
1148
1149         n->ln_Name = ((UBYTE *)n) + sizeof (struct Node);
1150
1151         strcpy (n->ln_Name, label);
1152         n->ln_Pri = 0;  /* Selected */
1153
1154         ADDTAIL (lv, n);
1155
1156         return TRUE;
1157 }
1158
1159
1160
1161 GLOBALCALL void RemListViewNode (struct Node *n)
1162 {
1163         REMOVE (n);
1164         FreeVecPooled (Pool, n);
1165 }
1166
1167
1168
1169
1170 GLOBALCALL struct Image *NewImageObject (ULONG which)
1171
1172 /* Creates a sysiclass object. */
1173 {
1174         return ((struct Image *)NewObject (NULL, SYSICLASS,
1175                 SYSIA_DrawInfo, DrawInfo,
1176                 SYSIA_Which,    which,
1177                 SYSIA_Size,             Scr->Flags & SCREENHIRES ? SYSISIZE_MEDRES : SYSISIZE_LOWRES,
1178                 TAG_DONE));
1179
1180         /* NB: SYSISIZE_HIRES not yet supported. */
1181 }
1182
1183
1184
1185 static struct Gadget *CreateVImageButton (struct TagItem *tags, struct NewGadget *ng)
1186
1187 /* This routine is called by the layout engine to create an IMAGEBUTTON_KIND gadget. */
1188 {
1189         struct Gadget   *VButton;
1190         struct Image    *VImage;
1191
1192         if (!VImageClass)
1193         {
1194                 if (VImageClass = InitVImageClass ())
1195                 {
1196                         if (ButtonFrame = NewObject (NULL, FRAMEICLASS,
1197                                 IA_FrameType,   FRAME_BUTTON,
1198                                 IA_EdgesOnly,   TRUE,
1199                                 TAG_DONE))
1200                         {
1201                                 struct IBox FrameBox, ContentsBox = { 0, 0, 0, 0 };
1202
1203                                 DoMethod ((Object *)ButtonFrame, IM_FRAMEBOX, &ContentsBox, &FrameBox, DrawInfo, 0);
1204
1205                                 ButtonFrameWidth = FrameBox.Width;
1206                                 ButtonFrameHeight = FrameBox.Height;
1207                         }
1208                         else
1209                         {
1210                                 FreeVImageClass (VImageClass);
1211                                 VImageClass = NULL;
1212                                 return NULL;
1213                         }
1214                 }
1215                 else return NULL;
1216         }
1217
1218         if (!(VImage = (struct Image *)NewObject (VImageClass, NULL,
1219                 IA_Width,               ng->ng_Width - ButtonFrameWidth,
1220                 IA_Height,              ng->ng_Height - ButtonFrameHeight,
1221                 SYSIA_Which,    ng->ng_Flags,
1222                 TAG_DONE)))
1223                 return NULL;
1224
1225         if (!(VButton = (struct Gadget *)NewObject (NULL, FRBUTTONCLASS,
1226                 GA_ID,                  ng->ng_GadgetID,
1227                 GA_UserData,    ng->ng_UserData,
1228                 GA_Left,                ng->ng_LeftEdge,
1229                 GA_Top,                 ng->ng_TopEdge,
1230                 GA_Image,               ButtonFrame,
1231                 GA_LabelImage,  VImage,
1232                 GA_RelVerify,   TRUE,
1233                 TAG_DONE)))
1234                 DisposeObject (VImage);
1235         else
1236                 VImageUseCount++;
1237
1238         return VButton;
1239 }
1240
1241
1242
1243 static void DeleteVImageButton (struct Gadget *g)
1244 {
1245         if (g)
1246         {
1247                 DisposeObject (g->GadgetText);
1248                 DisposeObject (g);
1249
1250                 VImageUseCount--;
1251
1252                 if (!VImageUseCount)
1253                 {
1254                         if (ButtonFrame)
1255                         {
1256                                 DisposeObject (ButtonFrame);
1257                                 ButtonFrame = NULL;
1258                         }
1259
1260                         if (VImageClass)
1261                         {
1262                                 FreeVImageClass (VImageClass);
1263                                 VImageClass = NULL;
1264                         }
1265                 }
1266         }
1267 }
1268
1269
1270
1271 /* Gadget definition format:
1272  *
1273  * VGROUP_KIND,                 BorderType,
1274  * HGROUP_KIND,                 BorderType,
1275  * IMAGEBUTTON_KIND,    ClickedFunction, ImageType, Tag1, ...,
1276  * CHECKBOX_KIND,               ClickedFunction, Label, Storage (UWORD *), Tag1, ...,
1277  * BUTTON_KIND,                 ClickedFunction, Label, Tag1, ...,
1278  * INTEGER_KIND,                ClickedFunction, Label, MaxDigits, Tag1, ...,
1279  * STRING_KIND,                 ClickedFunction, Label, MaxChars, Tag1, ...,
1280  * TEXT_KIND,                   Label, NumChars, Tag1, ...,
1281  * NUMBER_KIND,                 Label, MaxDigits, Tag1, ...,
1282  * LISTVIEW_KIND,               ClickedFunction, Label, Labels (struct List *), Tag1, ...,
1283  * MX_KIND,                             ClickedFunction, Label, Labels (ULONG *), Tag1, ...,
1284  * CYCLE_KIND,                  ClickedFunction, Label, Labels (ULONG *), Tag1, ...,
1285  * SLIDER_KIND,                 ClickedFunction, Label, Min, Max, LevelFormat (UBYTE *), MaxLevelLen (ULONG), Tag1, ...,
1286  * PALETTE_KIND,                ClickedFunction, Label, Tags,
1287  * ENDGROUP_KIND,
1288  */
1289
1290
1291 static void LayoutGadgets (struct LayoutGadgetsArgs *lga, UWORD mode)
1292 {
1293         struct GInfo            *ginfo,
1294                                                 *myginfo = &lga->GInfo[lga->Count];
1295         STRPTR label;
1296
1297
1298         /* Skip this group */
1299         lga->Count++;
1300
1301         if (mode == LAYOUTMODE_V)
1302                 myginfo->Flags |= GIF_FIXEDWIDTH;
1303         else
1304                 myginfo->Flags |= GIF_FIXEDHEIGHT;
1305
1306         while (*lga->Args != ENDGROUP_KIND)
1307         {
1308                 ginfo = &lga->GInfo[lga->Count];
1309                 label = NULL;
1310
1311                 switch (ginfo->GKind = *lga->Args++)
1312                 {
1313                         case HGROUP_KIND:
1314                         case VGROUP_KIND:
1315                                 if (*lga->Args++) /* Border? */
1316                                 {
1317                                         LayoutGadgets (lga, (ginfo->GKind == HGROUP_KIND) ? LAYOUTMODE_H : LAYOUTMODE_V);
1318
1319                                         /* Add border dimensions to group size */
1320                                         ginfo->MinWidth += HSPACING * 8;
1321                                         ginfo->Fixed.Width += HSPACING * 8;
1322                                         ginfo->MinHeight += VSPACING * 8;
1323                                         ginfo->Fixed.Height += VSPACING * 8;
1324                                         ginfo->Flags |= GIF_HASBORDER;
1325                                 }
1326                                 else LayoutGadgets (lga, (ginfo->GKind == HGROUP_KIND) ? LAYOUTMODE_H : LAYOUTMODE_V);
1327                                 break;
1328
1329                         case IMAGEBUTTON_KIND:
1330                                 lga->Args++;    /* Skip Clicked function */
1331                                 lga->Args++;    /* Skip Image */
1332                                 ginfo->MinWidth         = lga->Wud->Font->tf_XSize * 3 + 2;
1333                                 ginfo->MinHeight        = lga->Wud->Font->tf_YSize + 4;
1334                                 ginfo->Flags |= GIF_FIXEDWIDTH | GIF_FIXEDHEIGHT;
1335                                 break;
1336
1337                         case CHECKBOX_KIND:
1338                                 lga->Args++;    /* Skip Clicked function */
1339                                 label = STR(*lga->Args++);
1340                                 ginfo->SpecialStorage = (void *)*lga->Args++;   /* Record storage */
1341                                 ginfo->MinWidth         = lga->Wud->Font->tf_XSize * 2 + 8;
1342                                 ginfo->MinHeight        = lga->Wud->Font->tf_YSize + 4;
1343                                 ginfo->LabelWidth       = TextLength (lga->DummyRast, label, strlen (label)) + LABELSPACING;
1344                                 ginfo->Flags            = GIF_FIXEDWIDTH | GIF_FIXEDHEIGHT;
1345                                 break;
1346
1347                         case BUTTON_KIND:
1348                                 lga->Args++;    /* Skip Clicked function */
1349                                 label = STR(*lga->Args++);
1350                                 ginfo->MinWidth         = TextLength (lga->DummyRast, label, strlen (label)) + LABELSPACING;
1351                                 ginfo->MinHeight        = lga->Wud->Font->tf_YSize + 4;
1352                                 ginfo->Flags            = GIF_FIXEDHEIGHT;
1353                                 break;
1354
1355                         case INTEGER_KIND:
1356                         case STRING_KIND:
1357                         {
1358                                 UWORD maxchars;
1359
1360                                 lga->Args++;    /* Skip Clicked function */
1361                                 if (label = STR (*lga->Args++))
1362                                         ginfo->LabelWidth       = TextLength (lga->DummyRast, label, strlen (label)) + LABELSPACING;
1363
1364                                 maxchars = *lga->Args++;
1365
1366                                 ginfo->MinWidth         = lga->Wud->Font->tf_XSize * min (maxchars + 1, 8) + 12;
1367                                 ginfo->MinHeight        = lga->Wud->Font->tf_YSize + 6;
1368                                 ginfo->Flags            = GIF_FIXEDHEIGHT;
1369
1370                                 break;
1371                         }
1372
1373                         case LISTVIEW_KIND:
1374                                 lga->Args++;    /* Skip Clicked function */
1375                                 ginfo->MinWidth         = lga->Wud->Font->tf_XSize * 16 + 16;
1376                                 ginfo->MinHeight        = lga->Wud->Font->tf_YSize * 4 + 4;
1377                                 if (label = STR (*lga->Args++))
1378                                         ginfo->LabelWidth       = TextLength (lga->DummyRast, label, strlen (label)) + LABELSPACING;
1379                                 ginfo->SpecialStorage = (void *)*lga->Args++;   /* Record List pointer */
1380                                 break;
1381
1382                         case MX_KIND:
1383                         case CYCLE_KIND:
1384                         {
1385                                 ULONG   *labels, cnt = 0;
1386                                 STRPTR  str;
1387
1388                                 lga->Args++;    /* Skip Clicked function */
1389
1390                                 if (label = STR(*lga->Args++))
1391                                         ginfo->LabelWidth       = TextLength (lga->DummyRast, label, strlen (label)) + LABELSPACING;
1392
1393                                 ginfo->MinWidth = ginfo->MinHeight = 0;
1394
1395
1396                                 /* Count labels */
1397
1398                                 labels = (ULONG *) *lga->Args++;
1399                                 while (labels[cnt]) cnt++;
1400
1401
1402                                 /* Allocate and fill-in MX/Cycle labels array */
1403
1404                                 if (!ginfo->SpecialStorage)
1405                                          ginfo->SpecialStorage = AllocVecPooled (Pool, (cnt + 1) * sizeof (STRPTR));
1406
1407                                 if (ginfo->SpecialStorage)
1408                                 {
1409                                         ULONG i;
1410
1411                                         for (i = 0; i < cnt; i++)
1412                                         {
1413                                                 /* Store localized label */
1414                                                 ((STRPTR *)(ginfo->SpecialStorage))[i] = str = STR (labels[i]);
1415
1416                                                 /* Calculate maximum width */
1417                                                 ginfo->MinWidth = max (ginfo->MinWidth, TextLength (lga->DummyRast, str, strlen (str)) + LABELSPACING);
1418
1419                                                 if (ginfo->GKind == MX_KIND)
1420                                                         ginfo->MinHeight += lga->Wud->Font->tf_YSize + 2;
1421                                         }
1422
1423                                         /* Terminate labels array */
1424                                         ((STRPTR *)(ginfo->SpecialStorage))[i] = NULL;
1425                                 }
1426
1427                                 /* add width of radio button (or cycle image) */
1428                                 ginfo->MinWidth += lga->Wud->Font->tf_XSize * 2 + 4;
1429
1430                                 if (ginfo->GKind == MX_KIND)
1431                                         ginfo->Flags = GIF_FIXEDWIDTH | GIF_FIXEDHEIGHT;
1432                                 else
1433                                 {
1434                                         ginfo->Flags = GIF_FIXEDHEIGHT;
1435                                         ginfo->MinHeight += lga->Wud->Font->tf_YSize + 4;
1436                                 }
1437
1438                                 break;
1439                         }
1440
1441                         case NUMBER_KIND:
1442                         case TEXT_KIND:
1443
1444                                 if (label = STR (*lga->Args++))
1445                                         ginfo->LabelWidth       = TextLength (lga->DummyRast, label, strlen (label)) + LABELSPACING;
1446
1447                                 ginfo->MinWidth         = lga->Wud->Font->tf_XSize * (*lga->Args++) + 8;
1448                                 ginfo->MinHeight        = lga->Wud->Font->tf_YSize + 4;
1449                                 ginfo->Flags            = GIF_FIXEDHEIGHT;
1450                                 break;
1451
1452                         case SLIDER_KIND:
1453                                 lga->Args++;    /* Skip Clicked function */
1454
1455                                 if (label = STR (*lga->Args++))
1456                                         ginfo->LabelWidth       = TextLength (lga->DummyRast, label, strlen (label)) + LABELSPACING;
1457
1458                                 lga->Args += 3; /* Skip Min, Max and LevelFormat */
1459
1460                                 if (ginfo->SpecialStorage = (APTR)((*lga->Args++) * lga->Wud->Font->tf_XSize))
1461                                         ginfo->SpecialStorage = (APTR) ((ULONG)ginfo->SpecialStorage + 4);
1462
1463                                 ginfo->MinWidth         = lga->Wud->Font->tf_XSize * 8 + 8 + (ULONG)ginfo->SpecialStorage;
1464                                 ginfo->MinHeight        = lga->Wud->Font->tf_YSize;
1465                                 ginfo->Flags            = GIF_FIXEDHEIGHT;
1466                                 break;
1467
1468                         case PALETTE_KIND:
1469                                 lga->Args++;    /* Skip Clicked function */
1470
1471                                 if (label = STR (*lga->Args++))
1472                                         ginfo->LabelWidth       = TextLength (lga->DummyRast, label, strlen (label)) + LABELSPACING;
1473
1474                                 ginfo->MinWidth         = lga->Wud->Font->tf_XSize * 6 + 8;
1475                                 ginfo->MinHeight        = lga->Wud->Font->tf_YSize * 3 + 4;
1476                                 break;
1477                 }
1478
1479                 if ((ginfo->GKind != HGROUP_KIND) && (ginfo->GKind != VGROUP_KIND))
1480                 {
1481                         UBYTE *c;
1482
1483                         /* Go to next gadget (ie: skip tags until TAG_END) */
1484                         while (*lga->Args) lga->Args += 2;
1485                         lga->Args++;
1486
1487                         /* Look for the key equivalent of this gadget. */
1488                         if (c = label)
1489                                 for ( ; *c ; c++)
1490                                         if (*c == '_')
1491                                         {
1492                                                 /* Found! Now store in the key array */
1493                                                 lga->Wud->Keys[lga->Count] = *(++c) | (1<<5);   /* Lower case */
1494                                                 break;
1495                                         }
1496                 }
1497
1498                 if (mode == LAYOUTMODE_V)
1499                 {
1500                         myginfo->MinHeight += ginfo->MinHeight + VSPACING;
1501                         if (ginfo->Flags & GIF_HASBORDER)
1502                                 myginfo->MinWidth       = max (myginfo->MinWidth, ginfo->MinWidth + ginfo->LabelWidth);
1503                         else
1504                         {
1505                                 myginfo->MinWidth       = max (myginfo->MinWidth, ginfo->MinWidth);
1506                                 myginfo->LabelWidth     = max (myginfo->LabelWidth, ginfo->LabelWidth);
1507                         }
1508
1509                         myginfo->Fixed.Height += VSPACING;
1510                         if (ginfo->Flags & GIF_FIXEDHEIGHT)
1511                                 myginfo->Fixed.Height += ginfo->MinHeight;
1512                         if (!(ginfo->Flags & GIF_FIXEDWIDTH))
1513                                 myginfo->Flags &= ~GIF_FIXEDWIDTH;
1514                 }
1515                 else    /* LAYOUTMODE_H */
1516                 {
1517                         myginfo->MinWidth       += ginfo->MinWidth + ginfo->LabelWidth + HSPACING;
1518                         myginfo->MinHeight      = max (myginfo->MinHeight, ginfo->MinHeight);
1519                         myginfo->Fixed.Width += ginfo->LabelWidth + HSPACING;
1520                         if (ginfo->Flags & GIF_FIXEDWIDTH)
1521                                 myginfo->Fixed.Width += ginfo->MinWidth;
1522                         if (!(ginfo->Flags & GIF_FIXEDHEIGHT))
1523                                 myginfo->Flags &= ~GIF_FIXEDHEIGHT;
1524                 }
1525
1526                 lga->Count++;
1527
1528         }       /* End while (*lga->Args != ENDGROUP_KIND) */
1529
1530
1531         if (mode == LAYOUTMODE_H)
1532         {
1533                 /* Remove extra HSPACING after last child */
1534                 myginfo->MinWidth               -= HSPACING;
1535                 myginfo->Fixed.Width    -= HSPACING;
1536
1537                 if (!(myginfo->Flags & GIF_HASBORDER))
1538                 {
1539                         /* Align first child of HGROUP_KIND with other
1540                          * gadgets in our parent group
1541                          */
1542                         myginfo->LabelWidth             = (myginfo+1)->LabelWidth;
1543                         (myginfo+1)->LabelWidth = 0;
1544                         myginfo->MinWidth               -= myginfo->LabelWidth;
1545                         myginfo->Fixed.Width    -= myginfo->LabelWidth;
1546                 }
1547         }
1548         else /* LAYOUTMODE_V */
1549         {
1550                 /* Remove extra VSPACING after last child */
1551                 myginfo->MinHeight              -= VSPACING;
1552                 myginfo->Fixed.Height   -= VSPACING;
1553         }
1554
1555         if (myginfo->MinWidth <= myginfo->Fixed.Width)
1556                 myginfo->Flags |= GIF_FIXEDWIDTH;
1557         if (myginfo->MinHeight <= myginfo->Fixed.Height)
1558                 myginfo->Flags |= GIF_FIXEDHEIGHT;
1559
1560         lga->Args++;    /* Skip ENDGROUP_KIND           */
1561         lga->Count--;   /* Take back one position       */
1562 }
1563
1564
1565
1566 static struct Gadget *CreateGadgets (struct LayoutGadgetsArgs *lga, UWORD mode, UWORD left, UWORD top, UWORD width, UWORD height)
1567 {
1568         struct GInfo            *ginfo,
1569                                                 *myginfo        = &lga->GInfo[lga->Count];
1570         struct TagItem          *Tags, *tmp;
1571         ULONG                            stc;
1572         struct NewGadget         ng;
1573         BOOL                             boopsi;
1574
1575
1576         /* Skip this group */
1577         lga->Count++;
1578
1579
1580         while (*lga->Args != ENDGROUP_KIND)
1581         {
1582                 ginfo = &lga->GInfo[lga->Count];
1583                 Tags = (struct TagItem *)lga->SpecialTags;
1584                 stc = 2;
1585                 boopsi = FALSE;
1586
1587                 ng.ng_TextAttr          = lga->Wud->Attr;
1588                 ng.ng_GadgetID          = lga->Count;
1589                 ng.ng_VisualInfo        = lga->VInfo;
1590                 ng.ng_Flags                     = PLACETEXT_LEFT;
1591
1592                 if (mode == LAYOUTMODE_V)
1593                 {
1594                         if (ginfo->Flags & GIF_FIXEDWIDTH)
1595                                 ng.ng_Width = ginfo->MinWidth;
1596                         else
1597                                 ng.ng_Width = width - ((ginfo->Flags & GIF_HASBORDER) ? ginfo->LabelWidth : 0);
1598
1599                         if (ginfo->Flags & GIF_FIXEDHEIGHT)
1600                                 ng.ng_Height = ginfo->MinHeight;
1601                         else
1602                                 ng.ng_Height = (((ULONG)(height - myginfo->Fixed.Height)) * ((ULONG)ginfo->MinHeight)) / ((ULONG)(myginfo->MinHeight - myginfo->Fixed.Height));
1603
1604                         ng.ng_LeftEdge  = left + ((ginfo->Flags & GIF_HASBORDER) ? ginfo->LabelWidth : 0);
1605                         ng.ng_TopEdge   = top;
1606                         top = ng.ng_TopEdge + ng.ng_Height + VSPACING;
1607                 }
1608                 else    /* mode == LAYOUTMODE_H */
1609                 {
1610                         if (ginfo->Flags & GIF_FIXEDWIDTH)
1611                                 ng.ng_Width = ginfo->MinWidth;
1612                         else
1613                                 ng.ng_Width = (((ULONG)(width - myginfo->Fixed.Width)) * ((ULONG)ginfo->MinWidth)) / ((ULONG)(myginfo->MinWidth - myginfo->Fixed.Width));
1614
1615                         if (ginfo->Flags & GIF_FIXEDHEIGHT)
1616                         {
1617                                 /* Vertical center */
1618                                 ng.ng_Height    = ginfo->MinHeight;
1619                                 ng.ng_TopEdge   = top + (height - ng.ng_Height) / 2;
1620                         }
1621                         else
1622                         {
1623                                 /* Vertical stretch */
1624                                 ng.ng_Height    = height;
1625                                 ng.ng_TopEdge   = top;
1626                         }
1627
1628                         ng.ng_LeftEdge  = left + ginfo->LabelWidth;
1629
1630                         left = ng.ng_LeftEdge + ng.ng_Width + HSPACING;
1631                 }
1632
1633                 switch (ginfo->GKind = *lga->Args++)
1634                 {
1635                         case BOOPSI_KIND:
1636                                 ng.ng_UserData = (void *)(*lga->Args++);
1637                                 lga->SpecialTags[stc++] = XMGAD_SetupFunc;
1638                                 lga->SpecialTags[stc++] = (*lga->Args++);
1639                                 boopsi = TRUE;
1640                                 break;
1641
1642                         case IMAGEBUTTON_KIND:
1643                                 ng.ng_UserData          = (void *)(*lga->Args++);
1644                                 ng.ng_Flags                     = (*lga->Args++);
1645                                 ng.ng_GadgetText        = NULL;
1646                                 lga->SpecialTags[stc++] = XMGAD_SetupFunc;
1647                                 lga->SpecialTags[stc++] = (ULONG)CreateVImageButton;
1648                                 boopsi = TRUE;
1649                                 break;
1650
1651                         case VGROUP_KIND:
1652                         case HGROUP_KIND:
1653                         {
1654                                 ULONG bordertype;
1655
1656                                 if (bordertype = *lga->Args++)
1657                                 {
1658                                         if (!CreateWindowBorder (lga->Wud, ng.ng_LeftEdge - ginfo->LabelWidth, ng.ng_TopEdge,
1659                                                 ng.ng_Width + ginfo->LabelWidth, ng.ng_Height, bordertype))
1660                                                 return NULL;
1661                                         if (!CreateGadgets (lga, (ginfo->GKind == VGROUP_KIND) ? LAYOUTMODE_V : LAYOUTMODE_H,
1662                                                 ng.ng_LeftEdge + HSPACING*4, ng.ng_TopEdge + VSPACING*4,
1663                                                 ng.ng_Width - HSPACING*8, ng.ng_Height - VSPACING*8))
1664                                                 return NULL;
1665                                 }
1666                                 else if (!CreateGadgets (lga, (ginfo->GKind == VGROUP_KIND) ? LAYOUTMODE_V : LAYOUTMODE_H,
1667                                         ng.ng_LeftEdge, ng.ng_TopEdge, ng.ng_Width, ng.ng_Height))
1668                                         return NULL;
1669
1670
1671                                 break;
1672                         }
1673
1674                         case BUTTON_KIND:
1675                                 ng.ng_UserData          = (void *)(*lga->Args++);
1676                                 ng.ng_GadgetText        = STR(*lga->Args++);
1677                                 ng.ng_Flags                     = PLACETEXT_IN;
1678                                 break;
1679
1680                         case CHECKBOX_KIND:
1681                                 ng.ng_UserData = (void *)(*lga->Args++);
1682                                 ng.ng_GadgetText = STR(*lga->Args++);
1683                                 lga->Args++;    /* Skip storage */
1684
1685                                 lga->SpecialTags[stc++] = GTCB_Checked;
1686                                 lga->SpecialTags[stc++] = (ginfo->SpecialStorage ? (*((UWORD *)ginfo->SpecialStorage)) : NULL);
1687                                 lga->SpecialTags[stc++] = GTCB_Scaled;
1688                                 lga->SpecialTags[stc++] = TRUE;
1689                                 break;
1690
1691                         case INTEGER_KIND:
1692                                 ng.ng_UserData = (void *)(*lga->Args++);
1693                                 ng.ng_GadgetText = STR(*lga->Args++);
1694
1695                                 /* Editing in right-justified integer gadgets
1696                                  * is very uncomfortable!!
1697                                  *
1698                                  * lga->SpecialTags[stc++] = STRINGA_Justification;
1699                                  * lga->SpecialTags[stc++] = GACT_STRINGRIGHT;
1700                                  */
1701                                 lga->SpecialTags[stc++] = GTIN_MaxChars;
1702                                 lga->SpecialTags[stc++] = *lga->Args++;
1703                                 lga->SpecialTags[stc++] = STRINGA_ExitHelp;
1704                                 lga->SpecialTags[stc++] = TRUE;
1705                                 break;
1706
1707                         case LISTVIEW_KIND:
1708                         {
1709                                 struct List *l;
1710
1711                                 ng.ng_UserData          = (void *)*lga->Args++;
1712                                 ng.ng_GadgetText        = STR(*lga->Args++);
1713
1714                                 lga->SpecialTags[stc++] = GTLV_ShowSelected;
1715                                 lga->SpecialTags[stc++] = NULL;
1716
1717                                 if (l = (struct List *)*lga->Args++)
1718                                 {
1719                                         lga->SpecialTags[stc++] = GTLV_Labels;
1720                                         lga->SpecialTags[stc++] = (ULONG)l;
1721
1722                                         // l->lh_Type = 0;      /* Selected Item        */
1723                                         // l->l_pad = 0;        /* Item Count           */
1724                                 }
1725
1726 #ifndef OS30_ONLY
1727                                 if (GadToolsBase->lib_Version < 39)
1728                                         ng.ng_Height -= 4;
1729 #endif /* !OS30_ONLY */
1730
1731                                 break;
1732                         }
1733
1734                         case MX_KIND:
1735                         case CYCLE_KIND:
1736                         {
1737                                 ng.ng_UserData          = (void *)(*lga->Args++);
1738                                 ng.ng_GadgetText        = STR(*lga->Args++);
1739
1740                                 /* Skip labels */
1741                                 lga->Args++;
1742
1743                                 if (ginfo->GKind == MX_KIND)
1744                                 {
1745                                         /* Special kludge: MX gadgets width and height refer to
1746                                          * one button instead of the whole gadget.
1747                                          */
1748                                         ng.ng_Width = lga->Wud->Font->tf_XSize * 2;
1749                                         ng.ng_Height = lga->Wud->Font->tf_YSize;
1750
1751                                         ng.ng_Flags = PLACETEXT_RIGHT;
1752
1753                                         lga->SpecialTags[stc++] = GTMX_Labels;
1754                                         lga->SpecialTags[stc++] = (ULONG)ginfo->SpecialStorage;
1755                                         lga->SpecialTags[stc++] = GTMX_Scaled;
1756                                         lga->SpecialTags[stc++] = TRUE;
1757                                         lga->SpecialTags[stc++] = GTMX_Spacing;
1758                                         lga->SpecialTags[stc++] = 2;
1759                                 }
1760                                 else
1761                                 {
1762                                         lga->SpecialTags[stc++] = GTCY_Labels;
1763                                         lga->SpecialTags[stc++] = (ULONG)ginfo->SpecialStorage;
1764                                 }
1765
1766                                 break;
1767                         }
1768
1769                         case NUMBER_KIND:
1770                                 ng.ng_UserData = NULL;
1771                                 ng.ng_GadgetText = STR(*lga->Args++);
1772
1773                                 lga->Args++;    /* Skip NumDigits */
1774
1775                                 lga->SpecialTags[stc++] = GTNM_Border;
1776                                 lga->SpecialTags[stc++] = TRUE;
1777
1778                                 /* Under V39 and below, GTJ_RIGHT does not work properly. */
1779                                 if (GadToolsBase->lib_Version > 39)
1780                                 {
1781                                         lga->SpecialTags[stc++] = GTNM_Justification;
1782                                         lga->SpecialTags[stc++] = GTJ_RIGHT;
1783                                 }
1784                                 break;
1785
1786                         case TEXT_KIND:
1787                                 ng.ng_UserData = NULL;
1788                                 ng.ng_GadgetText = STR(*lga->Args++);
1789
1790                                 lga->Args++;    /* Skip NumDigits */
1791                                 break;
1792
1793                         case PALETTE_KIND:
1794                                 ng.ng_UserData = (void *)(*lga->Args++);
1795                                 ng.ng_GadgetText = STR(*lga->Args++);
1796
1797                                 lga->SpecialTags[stc++] = GTPA_IndicatorWidth;
1798                                 lga->SpecialTags[stc++] = ng.ng_Width / 8;
1799                                 break;
1800
1801                         case SCROLLER_KIND:
1802                                 ng.ng_UserData = (void *)(*lga->Args++);
1803                                 ng.ng_GadgetText = STR(*lga->Args++);
1804
1805                                 lga->SpecialTags[stc++] = GTSC_Arrows;
1806                                 lga->SpecialTags[stc++] = lga->Wud->Font->tf_XSize + 4;
1807                                 break;
1808
1809                         case STRING_KIND:
1810 /*                              ClassId = STRGCLASS;
1811                                 lga->SpecialTags[stc++] = GA_UserData;
1812                                 lga->SpecialTags[stc++] = *lga->Args++;
1813                                 lga->SpecialTags[stc++] = GA_LabelImage;
1814                                 lga->SpecialTags[stc++] = *lga->Args++;
1815                                 lga->SpecialTags[stc++] = STRINGA_MaxChars;
1816                                 lga->SpecialTags[stc++] = *lga->Args++;
1817                                 lga->SpecialTags[stc++] = GA_Border;
1818                                 lga->SpecialTags[stc++] = StringFrame;
1819                                 lga->SpecialTags[stc++] = STRINGA_ExitHelp;
1820                                 lga->SpecialTags[stc++] = TRUE;
1821 */
1822                                 ng.ng_UserData = (void *)(*lga->Args++);
1823                                 ng.ng_GadgetText = STR(*lga->Args++);
1824
1825                                 lga->SpecialTags[stc++] = GTST_MaxChars;
1826                                 lga->SpecialTags[stc++] = *lga->Args++;
1827                                 lga->SpecialTags[stc++] = STRINGA_ExitHelp;
1828                                 lga->SpecialTags[stc++] = TRUE;
1829                                 break;
1830
1831                         case SLIDER_KIND:
1832                                 ng.ng_UserData = (void *)(*lga->Args++);
1833                                 ng.ng_GadgetText = STR(*lga->Args++);
1834
1835                                 lga->SpecialTags[stc++] = GTSL_Min;
1836                                 lga->SpecialTags[stc++] = *lga->Args++;
1837                                 lga->SpecialTags[stc++] = GTSL_Max;
1838                                 lga->SpecialTags[stc++] = *lga->Args++;
1839                                 lga->SpecialTags[stc++] = GTSL_LevelFormat;
1840                                 lga->SpecialTags[stc++] = *lga->Args++;
1841                                 lga->SpecialTags[stc++] = GTSL_MaxLevelLen;
1842                                 lga->SpecialTags[stc++] = *lga->Args++;
1843                                 lga->SpecialTags[stc++] = GTSL_LevelPlace;
1844                                 lga->SpecialTags[stc++] = PLACETEXT_RIGHT;
1845                                 lga->SpecialTags[stc++] = GTSL_Justification;
1846                                 lga->SpecialTags[stc++] = GTJ_RIGHT;
1847                                 lga->SpecialTags[stc++] = GA_RelVerify;
1848                                 lga->SpecialTags[stc++] = TRUE;
1849
1850                                 ng.ng_Width -= (ULONG)ginfo->SpecialStorage;
1851                                 break;
1852                 }
1853
1854                 if ((ginfo->GKind != HGROUP_KIND) && (ginfo->GKind != VGROUP_KIND))
1855                 {
1856                         if (*lga->Args != TAG_DONE)
1857                         {
1858                                 /* Add user Tags */
1859                                 lga->SpecialTags[stc++] = TAG_MORE;
1860                                 lga->SpecialTags[stc] = (ULONG) lga->Args;
1861                         }
1862                         else lga->SpecialTags[stc] = TAG_DONE;
1863
1864
1865                         /* Go to next gadget (ie: skip tags until TAG_END) */
1866                         while (*lga->Args) lga->Args += 2;
1867                         lga->Args++;
1868
1869                         if (boopsi)
1870                         {
1871                                 /* BOOPSI Gadget. Let SetupFunc() allocate the gadget for us */
1872
1873                                 if (tmp = FindTagItem (XMGAD_SetupFunc, Tags))
1874                                 {
1875                                         if (lga->PrevGad->NextGadget = ((struct Gadget * (*)(struct TagItem *, struct NewGadget *)) (tmp->ti_Data)) (Tags, &ng))
1876                                                 /* Record it into the list */
1877                                                 lga->Wud->Gadgets[lga->Count] = lga->PrevGad->NextGadget;
1878                                         else
1879                                                 return NULL;
1880                                 }
1881                                 else
1882                                         return NULL;
1883                         }
1884                         else
1885                         {
1886                                 /* Normal GadTools gadget */
1887
1888                                 if (!(lga->Wud->Gadgets[lga->Count] = CreateGadgetA (ginfo->GKind, lga->PrevGad, &ng, Tags)))
1889                                         return NULL;
1890                         }
1891
1892                         lga->PrevGad = lga->Wud->Gadgets[lga->Count];
1893
1894                 } /* End if (GKind != ?GROUP_KIND */
1895
1896                 lga->Count++;   /* Go to next gadget    */
1897         }
1898
1899         lga->Args++;    /* Skip ENDGROUP_KIND           */
1900         lga->Count--;   /* Take back one position       */
1901
1902         return (lga->Wud->GList);
1903 }
1904
1905
1906
1907 static void RenderWindowBorders (struct WinUserData *wud)
1908 {
1909         struct WindowBorder *border = wud->Borders;
1910
1911         while (border)
1912         {
1913                 DrawBevelBox (wud->Win->RPort,
1914                         border->Size.Left, border->Size.Top,
1915                         border->Size.Width, border->Size.Height,
1916                         GT_VisualInfo,  VisualInfo,
1917                         GTBB_Recessed,  TRUE,
1918                         GTBB_FrameType, border->Type,
1919                         TAG_DONE);
1920
1921                 border = border->NextBorder;
1922         }
1923 }
1924
1925
1926
1927 static struct WindowBorder *CreateWindowBorder (struct WinUserData *wud,
1928         UWORD left, UWORD top, UWORD width, UWORD height, ULONG bordertype)
1929
1930 /* Creates new WindowBorder structure and links it to the WUD passed.
1931  * Will return NULL in case of failure.
1932  */
1933 {
1934         struct WindowBorder *border;
1935
1936         if (!(border = AllocPooled (Pool, sizeof (struct WindowBorder))))
1937                 return NULL;
1938
1939         /* Link this border struct in WUD */
1940         border->NextBorder = wud->Borders;
1941         wud->Borders = border;
1942
1943         /* Fill in WindowBorder structure */
1944         border->Type            = bordertype;
1945         border->Size.Left       = left;
1946         border->Size.Top        = top;
1947         border->Size.Width      = width;
1948         border->Size.Height     = height;
1949
1950         return border;
1951 }
1952
1953
1954
1955 static void DeleteGadgets (struct WinUserData *wud)
1956 {
1957         FreeGadgets (wud->GList);       wud->GList = NULL;
1958
1959         if (wud->GInfo)
1960         {
1961                 ULONG i;
1962
1963                 for (i = 0; i < wud->GCount; i++)
1964                 {
1965                         if (wud->Gadgets[i])
1966                         {
1967                                 switch (wud->GInfo[i].GKind)
1968                                 {
1969                                         case IMAGEBUTTON_KIND:
1970                                                 DeleteVImageButton (wud->Gadgets[i]);
1971                                                 break;
1972
1973                                         default:
1974                                                 break;
1975                                 }
1976                         }
1977                 }
1978         }
1979
1980         if (wud->Borders)
1981         {
1982                 struct WindowBorder *border = wud->Borders, *nextborder;
1983
1984                 do
1985                 {
1986                         nextborder = border->NextBorder;
1987                         FreePooled (Pool, border, sizeof (struct WindowBorder));
1988                 }
1989                 while (border = nextborder);
1990
1991                 wud->Borders = NULL;
1992         }
1993 }
1994
1995
1996
1997 struct WinUserData *CreateWUD (ULONG id)
1998 {
1999         struct WinUserData *wud;
2000         struct WDescr *wdescr = &WDescr[id];
2001
2002
2003         /* Create a new WUD structure for this window */
2004         if (wud = CAllocPooled (Pool, sizeof (struct WinUserData)))
2005         {
2006                 wdescr->Wud = wud;
2007                 wdescr->UseCnt++;
2008                 wud->WindowID = id;
2009                 wud->IDCMPFlags =       IDCMP_RAWKEY | IDCMP_MENUHELP |
2010                                                         IDCMP_GADGETHELP | IDCMP_INACTIVEWINDOW;
2011                 wud->Flags = WFLG_DRAGBAR | WFLG_DEPTHGADGET;
2012                 wud->Title = PrgName;
2013
2014                 /* Link WUD to windows list */
2015                 ADDHEAD (&WindowList, (struct Node *)wud);
2016
2017                 if (wdescr->CreationTags)
2018                 {
2019                         struct TagItem  *tstate = wdescr->CreationTags,
2020                                                         *tag;
2021
2022                         /* Read taglist arguments */
2023
2024                         while (tag = NextTagItem (&tstate))
2025                                 switch (tag->ti_Tag)
2026                                 {
2027                                         case XMWIN_NewMenu:
2028                                                 wud->NewMenu = (struct NewMenu *)tag->ti_Data;
2029                                                 break;
2030
2031                                         case XMWIN_LayoutArgs:
2032                                                 wud->LayoutArgs = (ULONG *)tag->ti_Data;
2033                                                 break;
2034
2035                                         case XMWIN_GCount:
2036                                                 wud->GCount = tag->ti_Data;
2037                                                 break;
2038
2039                                         case XMWIN_Title:
2040                                                 wud->Title = STR(tag->ti_Data);
2041                                                 break;
2042
2043                                         case XMWIN_WindowFlags:
2044                                                 wud->Flags |= tag->ti_Data;
2045                                                 break;
2046
2047                                         case XMWIN_IDCMPFlags:
2048                                                 wud->IDCMPFlags |= tag->ti_Data;
2049                                                 break;
2050
2051                                         case XMWIN_IDCMPFunc:
2052                                                 wud->IDCMPFunc = (void (*)()) tag->ti_Data;
2053                                                 break;
2054
2055                                         case XMWIN_DropIconFunc:
2056                                                 wud->DropIcon = (void (*)()) tag->ti_Data;
2057                                                 break;
2058
2059                                         case XMWIN_LayoutFunc:
2060                                                 wud->LayoutArgs = (ULONG *)tag->ti_Data;
2061                                                 wud->WUDFlags |= WUDF_CUSTOMLAYOUT;
2062                                                 break;
2063
2064                                         case XMWIN_PreOpenFunc:
2065                                                 wud->PreOpenFunc = (LONG (*)()) tag->ti_Data;
2066                                                 break;
2067
2068                                         case XMWIN_PostOpenFunc:
2069                                                 wud->PostOpenFunc = (void (*)()) tag->ti_Data;
2070                                                 break;
2071
2072                                         case XMWIN_PreCloseFunc:
2073                                                 wud->PreCloseFunc = (LONG (*)()) tag->ti_Data;
2074                                                 break;
2075
2076                                         case XMWIN_PostCloseFunc:
2077                                                 wud->PostCloseFunc = (void (*)()) tag->ti_Data;
2078                                                 break;
2079
2080                                         case XMWIN_HelpNode:
2081                                                 wud->HelpNode = (STRPTR) tag->ti_Data;
2082                                                 break;
2083
2084                                         case XMWIN_UserData:
2085                                                 wud->UserData = (APTR) tag->ti_Data;
2086                                                 break;
2087
2088                                         case XMWIN_LayoutCleanup:
2089                                                 wud->LayoutCleanupFunc = (void (*)()) tag->ti_Data;
2090                                                 break;
2091
2092                                         default:
2093                                                 break;
2094                                 }
2095                 }
2096
2097                 if (!CreateLayoutInfo (wud))
2098                 {
2099                         DeleteWUD (wud);
2100                         wud = NULL;
2101                 }
2102         }
2103
2104         return wud;
2105 }
2106
2107
2108
2109 static void DeleteWUD (struct WinUserData *wud)
2110 {
2111         if (wud)
2112         {
2113                 MyCloseWindow (wud);
2114
2115                 REMOVE ((struct Node *) wud);
2116
2117                 {
2118                         struct WDescr *wdescr = &WDescr[wud->WindowID];
2119
2120                         wdescr->Wud = NULL;
2121
2122                         if (--wdescr->UseCnt)
2123                         {
2124                                 struct WinUserData *otherwud;
2125
2126                                 /* Search for another wud with same ID and set it in WDescr... */
2127
2128                                 for (otherwud = (struct WinUserData *)WindowList.lh_Head;
2129                                                 otherwud->Link.mln_Succ;
2130                                                 otherwud = (struct WinUserData *)otherwud->Link.mln_Succ)
2131                                         if (otherwud->WindowID == wud->WindowID)
2132                                         {
2133                                                 wdescr->Wud = otherwud;
2134                                                 break;
2135                                         }
2136                         }
2137                 }
2138
2139                 DeleteLayoutInfo (wud);
2140
2141                 FreePooled (Pool, wud, sizeof (struct WinUserData));
2142         }
2143 }
2144
2145
2146
2147 static struct WinUserData *CreateLayoutInfo (struct WinUserData *wud)
2148 {
2149         struct WDescr *wdescr = &WDescr[wud->WindowID];
2150
2151         /* Compute font */
2152
2153         if (wud->Font = WindowFont)
2154                 wud->Attr = &WindowAttr;
2155         else
2156         {
2157                 wud->Font = TopazFont;
2158                 wud->Attr = &TopazAttr;
2159         }
2160
2161
2162         if (wud->LayoutArgs)
2163         {
2164                 if (!wud->Gadgets)
2165                 {
2166                         /* Allocate Gadgets array */
2167                         if (!(wud->Gadgets = CAllocPooled (Pool,
2168                                 wud->GCount * sizeof (struct Gadget *))))
2169                                 return NULL;
2170                 }
2171
2172                 if (wud->WUDFlags & WUDF_CUSTOMLAYOUT)
2173                 {
2174                         if (!(wud->GList = ((struct Gadget * (*)(struct WinUserData *))
2175                                 wud->LayoutArgs) (wud) ))
2176                                         return NULL;
2177                 }
2178                 else    /* Use standard layout engine */
2179                 {
2180                         struct LayoutGadgetsArgs lga;
2181
2182                         lga.Wud = wud;
2183
2184                         /* Layout Phase 1 */
2185
2186                         if (!wud->GInfo)
2187                         {
2188                                 struct RastPort rp;
2189                                 InitRastPort (&rp);
2190                                 SetFont (&rp, wud->Font);
2191
2192                                 lga.DummyRast   = &rp;
2193                                 lga.Args                = wud->LayoutArgs;
2194                                 lga.Count               = 0;
2195
2196
2197                                 /* Allocate Key shortcuts array */
2198                                 if (!(wud->Keys = CAllocPooled (Pool, wud->GCount)))
2199                                         return NULL;
2200
2201                                 /* Allocate GInfo array */
2202                                 if (!(wud->GInfo = lga.GInfo = CAllocPooled (Pool, sizeof (struct GInfo) * wud->GCount)))
2203                                         return NULL;
2204
2205                                 LayoutGadgets (&lga, LAYOUTMODE_V);
2206
2207                                 if ((lga.GInfo[0].Flags & (GIF_FIXEDWIDTH | GIF_FIXEDHEIGHT)) != (GIF_FIXEDWIDTH | GIF_FIXEDHEIGHT))
2208                                 {
2209                                         wud->Flags |= (WFLG_SIZEGADGET | WFLG_SIZEBBOTTOM);
2210                                         wud->IDCMPFlags |= IDCMP_NEWSIZE;
2211                                 }
2212
2213                                 /* Force minimum size */
2214                                 wud->WindowSize.Width = max (wud->WindowSize.Width, lga.GInfo[0].MinWidth + lga.GInfo[0].LabelWidth + HSPACING * 2);
2215                                 wud->WindowSize.Height = max (wud->WindowSize.Height, lga.GInfo[0].MinHeight + VSPACING * 2);
2216                         }
2217                         else
2218                                 /* Reuse previous GInfo array */
2219                                 lga.GInfo = wud->GInfo;
2220
2221
2222                         /* Layout Phase 2 */
2223                         {
2224                                 ULONG SpecialTags[20];
2225
2226                                 SpecialTags[0] = GT_Underscore;
2227                                 SpecialTags[1] = (ULONG) '_';
2228
2229                                 if (!CreateContext (&wud->GList))
2230                                         return NULL;
2231
2232                                 lga.Args                = wud->LayoutArgs;
2233                                 lga.VInfo               = VisualInfo;
2234                                 lga.PrevGad             = wud->GList;
2235                                 lga.Count               = 0;
2236                                 lga.SpecialTags = SpecialTags;
2237
2238                                 if (!CreateGadgets (&lga, LAYOUTMODE_V, OffX + lga.GInfo[0].LabelWidth + HSPACING, OffY + VSPACING,
2239                                         wud->WindowSize.Width - lga.GInfo[0].LabelWidth - HSPACING * 2,
2240                                         wud->WindowSize.Height - VSPACING * 2))
2241                                         return NULL;
2242                         }
2243                 }
2244         }
2245
2246         if (!(wdescr->Flags & XMWINF_LOCALEDONE))
2247         {
2248                 if (wud->NewMenu)
2249                 {
2250                         /* Localize the MenuStrip */
2251                         struct NewMenu *nm = wud->NewMenu;
2252
2253                         while (nm->nm_Type != NM_END)
2254                         {
2255                                 if (nm->nm_Label != (STRPTR)NM_BARLABEL)
2256                                         nm->nm_Label = STR ((ULONG)nm->nm_Label);
2257
2258                                 nm++;
2259                         }
2260                 }
2261
2262                 wdescr->Flags |= XMWINF_LOCALEDONE;
2263         }
2264
2265
2266         if (wud->NewMenu && (!wud->MenuStrip))
2267         {
2268                 if (!(wud->MenuStrip = CreateMenusA (wud->NewMenu, NULL)))
2269                         return NULL;
2270
2271                 if (!(LayoutMenus (wud->MenuStrip, VisualInfo,
2272                         GTMN_NewLookMenus, TRUE,
2273                         TAG_DONE)))
2274                         return NULL;
2275         }
2276
2277
2278         /* Setup zoom size */
2279
2280         if (wud->Flags & WFLG_SIZEGADGET)
2281         {
2282                 wud->WindowZoom.Left = 0;
2283                 wud->WindowZoom.Top = 1;
2284                 wud->WindowZoom.Width = Scr->Width;
2285                 wud->WindowZoom.Height = Scr->Height;
2286         }
2287         else
2288         {
2289                 wud->WindowZoom.Left = wud->WindowSize.Left;
2290                 wud->WindowZoom.Top = wud->WindowSize.Top;
2291                 if (wud->Title)
2292                         wud->WindowZoom.Width = TextLength (&Scr->RastPort, wud->Title,
2293                                 strlen (wud->Title)) + 80;
2294                 else
2295                         wud->WindowZoom.Width = 80;
2296                 wud->WindowZoom.Height = Scr->WBorTop + Scr->RastPort.TxHeight + 1;
2297
2298                 /* TODO: Under V39 specifying ~0,~0 as Zoom X,Y, intuition
2299                  * will only size-zoom the window.  Consider implementing it...
2300                  */
2301         }
2302
2303         return wud;
2304 }
2305
2306
2307
2308 GLOBALCALL void DeleteLayoutInfo (struct WinUserData *wud)
2309 {
2310         if (!wud) return;
2311
2312         DeleteGadgets (wud);
2313
2314         if (wud->LayoutCleanupFunc)
2315                 wud->LayoutCleanupFunc (wud);
2316
2317         if (wud->Keys)
2318         {
2319                 FreePooled (Pool, wud->Keys, wud->GCount);
2320                 wud->Keys = NULL;
2321         }
2322
2323         if (wud->Gadgets)
2324         {
2325                 if (wud->GInfo)
2326                 {
2327                         ULONG i;
2328
2329                         /* Free gadget associated resources */
2330
2331                         for (i = 0; i < wud->GCount; i++)
2332                         {
2333                                 if (wud->Gadgets[i])
2334                                 {
2335                                         switch (wud->GInfo[i].GKind)
2336                                         {
2337                                                 case MX_KIND:
2338                                                 case CYCLE_KIND:
2339                                                         FreeVecPooled (Pool, wud->GInfo[i].SpecialStorage);
2340
2341                                                 default:
2342                                                         break;
2343                                         }
2344                                 }
2345                         }
2346                 }
2347
2348                 FreePooled (Pool, wud->Gadgets, wud->GCount * sizeof (struct Gadget *));
2349                 wud->Gadgets = NULL;
2350         }
2351
2352         if (wud->GInfo)
2353         {
2354                 FreePooled (Pool, wud->GInfo, wud->GCount * sizeof (struct GInfo));
2355                 wud->GInfo = NULL;
2356         }
2357
2358         if (wud->MenuStrip)
2359         {
2360                 FreeMenus (wud->MenuStrip);
2361                 wud->MenuStrip = NULL;
2362         }
2363 }
2364
2365
2366
2367 GLOBALCALL struct Window *NewWindow (ULONG id)
2368
2369 /* Create a new window using the given Window ID. */
2370 {
2371         struct WDescr           *wdescr         = &WDescr[id];
2372         struct WinUserData      *wud;
2373
2374         if (!Scr) return NULL;
2375
2376         /* Some windows can not be opened multiple times */
2377
2378         if (!(wud = wdescr->Wud) || (wdescr->Flags & XMWINF_OPENMULTI))
2379         {
2380                 if (!(wud = CreateWUD (id)))
2381                         return NULL;
2382         }
2383
2384         return MyOpenWindow (wud);
2385 }
2386
2387
2388
2389 GLOBALCALL struct Window *MyOpenWindow (struct WinUserData *wud)
2390
2391 /* Open & setup a window using the given WinUserData structure. */
2392 /* This function is now OBSOLETE and should be merged with NewWindow() */
2393 {
2394         if (!Scr) return NULL;
2395
2396         if (wud->PreOpenFunc)
2397                 if (wud->PreOpenFunc (wud))
2398                 {
2399                         if (wud->PreCloseFunc) wud->PreCloseFunc (wud);
2400                         return NULL;
2401                 }
2402
2403         if (wud->Win)
2404         {
2405                 RevealWindow (wud);
2406                 return wud->Win;
2407         }
2408
2409         if (!wud->Gadgets && wud->LayoutArgs)
2410                 if (!CreateLayoutInfo (wud))
2411                         return NULL;
2412
2413
2414         /* Open the Window */
2415
2416         if (wud->Win = OpenWindowTags (NULL,
2417                 WA_Left,                        wud->WindowSize.Left,
2418                 WA_Top,                         wud->WindowSize.Top,
2419                 WA_InnerWidth,          wud->WindowSize.Width,
2420                 WA_InnerHeight,         wud->WindowSize.Height,
2421                 WA_Gadgets,                     wud->GList,
2422                 WA_Title,                       wud->Title,
2423                 WA_Flags,                       wud->Flags,
2424                 WA_Zoom,                        &(wud->WindowZoom),
2425                 WA_PubScreen,           Scr,
2426                 WA_HelpGroup,           UniqueID,
2427                 /* Set user preferred refresh method unless this window
2428                  * requests simple refresh explicitly.
2429                  */
2430                 GuiSwitches.SmartRefresh ? WA_SmartRefresh : WA_SimpleRefresh, TRUE,
2431                 WA_Activate,            !ScreenReopening,
2432
2433                 /* Set minimum and maximum size according to the main gadget group
2434                  * properties.
2435                  */
2436                 (wud->Flags & WFLG_SIZEGADGET) ? WA_MinWidth : TAG_IGNORE,
2437                         wud->GInfo ? (wud->GInfo[0].MinWidth + Scr->WBorLeft + Scr->WBorRight) : wud->WindowSize.Width,
2438                 (wud->Flags & WFLG_SIZEGADGET) ? WA_MinHeight : TAG_IGNORE,
2439                         wud->GInfo ? (wud->GInfo[0].MinHeight + Scr->WBorTop + Scr->WBorBottom + Scr->Font->ta_YSize + SizeHeight + 1) : wud->WindowSize.Height,
2440 /**/    (wud->Flags & WFLG_SIZEGADGET) ? WA_MaxWidth : TAG_IGNORE,
2441                         wud->GInfo ? (wud->GInfo[0].Flags & GIF_FIXEDWIDTH ? 0 : -1) : -1,
2442                 (wud->Flags & WFLG_SIZEGADGET) ? WA_MaxHeight : TAG_IGNORE,
2443                         wud->GInfo ? (wud->GInfo[0].Flags & GIF_FIXEDHEIGHT ? wud->GInfo[0].MinHeight : -1) : -1,
2444
2445                 /* Constant tags */
2446                 WA_ScreenTitle,         (ULONG)Version+6,
2447                 WA_AutoAdjust,          TRUE,
2448                 WA_MenuHelp,            TRUE,
2449         //      WA_MouseQueue,          2,
2450         //      WA_RptQueue,            2,
2451                 WA_NewLookMenus,        TRUE,
2452
2453                 /* Add user tags */
2454                 WDescr[wud->WindowID].CreationTags ? TAG_MORE : TAG_DONE, WDescr[wud->WindowID].CreationTags
2455                 ))
2456         {
2457                 wud->Win->UserData = (BYTE *) wud;
2458                 wud->Win->UserPort = WinPort;
2459
2460                 if (ModifyIDCMP (wud->Win, wud->IDCMPFlags))
2461                 {
2462                         /* Set default font for this window */
2463                         if (wud->Font) SetFont (wud->Win->RPort, wud->Font);
2464
2465                         if (wud->MenuStrip) SetMenuStrip (wud->Win, wud->MenuStrip);
2466
2467                         /* Do initial refresh */
2468                         GT_RefreshWindow (wud->Win, NULL);
2469                         RenderWindowBorders (wud);
2470
2471                         /* Make the window visible on the screen */
2472                         if (!ScreenReopening
2473 #ifndef OS30_ONLY
2474                                 && (IntuitionBase->LibNode.lib_Version >= 39)
2475 #endif /* !OS30_ONLY */
2476                                 )
2477                             ScreenPosition (Scr, SPOS_MAKEVISIBLE,
2478                                         wud->Win->LeftEdge, wud->Win->TopEdge,
2479                                         wud->Win->LeftEdge + wud->Win->Width - 1,
2480                                         wud->Win->TopEdge + wud->Win->Height - 1);
2481
2482                         /* Make it an AppWindow if it is requested */
2483                         if (wud->DropIcon) AddAppWin (wud);
2484
2485                         if (wud->PostOpenFunc)
2486                                 wud->PostOpenFunc (wud);
2487
2488                         wud->WUDFlags &= ~WUDF_REOPENME;
2489
2490                         return wud->Win;
2491                 }
2492
2493                 /* ClearMenuStrip() -- no need to call it... */
2494                 CloseWindow (wud->Win); wud->Win = NULL;
2495         }
2496
2497         return NULL;
2498 }
2499
2500
2501
2502 /* Close a window and all related resources */
2503 GLOBALCALL void MyCloseWindow (struct WinUserData *wud)
2504 {
2505         struct Window *win = wud->Win;
2506         struct Requester *req;
2507
2508         if (win)
2509         {
2510                 DeselectButton();
2511
2512                 if (wud->PreCloseFunc)
2513                         if (wud->PreCloseFunc (wud))
2514                                 return;
2515
2516                 /* Cleanup locked window */
2517                 if (req = win->FirstRequest)
2518                 {
2519                         EndRequest (req, win);
2520                         FreePooled (Pool, req, sizeof (struct WindowLock));
2521                 }
2522
2523                 /* Remove AppWindow */
2524                 if (wud->AppWin) RemAppWin (wud);
2525
2526
2527                 /* Free MenuStrip */
2528                 if (win->MenuStrip)
2529                 {
2530                         ClearMenuStrip (win);
2531                         DoNextSelect = 0;       /* Do not loop any more on this window's MenuStrip */
2532                 }
2533
2534                 /* Now remove any pending message from the shared IDCMP port */
2535
2536                 Forbid();
2537                 {
2538                         struct Node *succ;
2539                         struct Message *msg = (struct Message *) win->UserPort->mp_MsgList.lh_Head;
2540
2541                         while (succ = msg->mn_Node.ln_Succ)
2542                         {
2543                                 if (((struct IntuiMessage *)msg)->IDCMPWindow ==  win)
2544                                 {
2545                                         REMOVE ((struct Node *)msg);
2546                                         ReplyMsg (msg);
2547                                 }
2548                                 msg = (struct Message *) succ;
2549                         }
2550
2551                         win->UserPort = NULL;   /* Keep intuition from freeing our port... */
2552                         ModifyIDCMP (win, 0L);  /* ...and from sending us any more messages. */
2553                 }
2554                 Permit();
2555
2556
2557                 /* Save Window position and clear window pointer */
2558
2559                 wud->WindowSize.Left    = win->LeftEdge;
2560                 wud->WindowSize.Top             = win->TopEdge;
2561
2562                 if (win->Flags & WFLG_SIZEGADGET)
2563                 {
2564                         wud->WindowSize.Width   = win->Width - win->BorderLeft - win->BorderRight;
2565                         wud->WindowSize.Height  = win->Height - win->BorderTop - win->BorderBottom;
2566                 }
2567
2568                 CloseWindow (win);      wud->Win = NULL;
2569
2570                 if (wud->PostCloseFunc)
2571                         wud->PostCloseFunc (wud);
2572         }
2573
2574         if (wud->Font)
2575                 { CloseFont (wud->Font); wud->Font = NULL; }
2576
2577         if ((WDescr[wud->WindowID].Flags & XMWINF_OPENMULTI)
2578                 && (WDescr[wud->WindowID].UseCnt > 1))
2579                 DeleteWUD (wud);
2580 }
2581
2582
2583
2584 GLOBALCALL void ReopenWindows (void)
2585
2586 /* Reopen windows that were previously open */
2587 {
2588         struct WinUserData *wud;
2589
2590         ScreenReopening = TRUE;
2591
2592         /* Find window */
2593         for (wud = (struct WinUserData *)WindowList.lh_Head; wud->Link.mln_Succ;
2594                 wud = (struct WinUserData *)wud->Link.mln_Succ)
2595         {
2596                 if (wud->WUDFlags & WUDF_REOPENME)
2597                         MyOpenWindow (wud);
2598         }
2599
2600         ScreenReopening = FALSE;
2601 }
2602
2603
2604
2605 GLOBALCALL LONG SetupScreen (void)
2606 {
2607         struct Screen *DefScr;
2608         struct DrawInfo *DefDri;
2609
2610         static LONG ExtraScreenTags[] =
2611         {
2612                 SA_SysFont,                     1,
2613                 SA_FullPalette,         TRUE,
2614                 SA_SharePens,           TRUE,   /* These three Tags are valid only under
2615                 SA_LikeWorkbench,       TRUE,    * V39 and are properly ignored by V37.
2616                 SA_MinimizeISG,         TRUE,    */
2617                 SA_Interleaved,         TRUE,
2618                 TAG_DONE
2619         };
2620
2621         if (Scr)
2622         {
2623                 /* If screen is already open, pop it to front and activate
2624                  * the main window.
2625                  */
2626                 ScreenToFront (Scr);
2627                 if (ThisTask->pr_WindowPtr)
2628                         RevealWindow ((struct WinUserData *)(((struct Window *)(ThisTask->pr_WindowPtr))->UserData));
2629
2630                 return RETURN_OK;
2631         }
2632
2633
2634         if (!(ScrollButtonClass = InitScrollButtonClass()))
2635                 return ERROR_NO_FREE_STORE;
2636
2637
2638         /* Try the user selected Public Screen */
2639
2640         if (!(Scr = LockPubScreen (ScrInfo.PubScreenName[0] ? ScrInfo.PubScreenName : NULL)))
2641         {
2642                 /* Try to open own screen */
2643
2644                 if (ScrInfo.DisplayID)
2645                 {
2646                         static UWORD             PensArray[1] = {(UWORD)~0};
2647                         ULONG                           *ColorTable     = NULL;
2648 #ifndef OS30_ONLY
2649                         struct ColorSpec        *ColorSpec      = NULL;
2650 #endif /* !OS30_ONLY */
2651                         ULONG                            i;
2652
2653                         /* Color map translation */
2654
2655                         if (ScrInfo.OwnPalette)
2656                         {
2657 #ifndef OS30_ONLY
2658                                 if (IntuitionBase->LibNode.lib_Version >= 39)
2659                                 {
2660 #endif /* !OS30_ONLY */
2661                                         if (ColorTable = AllocPooled (Pool, ((32 * 3) + 2) * sizeof (LONG)))
2662                                         {
2663                                                 ULONG   *col = ColorTable,
2664                                                                  tmp;
2665
2666                                                 *col++ = 32 << 16;
2667
2668                                                 for (i = 0; i < 32; i++)
2669                                                 {
2670                                                         tmp = (ScrInfo.Colors[i] >> 16);                        /* Red */
2671                                                         tmp |= tmp << 8 | tmp << 16 | tmp << 24;
2672                                                         *col++ = tmp;
2673
2674                                                         tmp = (ScrInfo.Colors[i] >> 8) & 0xFF;          /* Green */
2675                                                         tmp |= tmp << 8 | tmp << 16 | tmp << 24;
2676                                                         *col++ = tmp;
2677
2678                                                         tmp = ScrInfo.Colors[i] & 0xFF;                         /* Blue */
2679                                                         tmp |= tmp << 8 | tmp << 16 | tmp << 24;
2680                                                         *col++ = tmp;
2681                                                 }
2682
2683                                                 *col = 0;
2684                                         }
2685                                 }
2686 #ifndef OS30_ONLY
2687                                 else    /* V37 */
2688                                 {
2689                                         if (ColorSpec = AllocPooled (Pool, 33 * sizeof (struct ColorSpec)))
2690                                         {
2691                                                 for (i = 0; i < 32; i++)
2692                                                 {
2693                                                         ColorSpec[i].ColorIndex = i;
2694                                                         ColorSpec[i].Red        = ScrInfo.Colors[i] >> 20;
2695                                                         ColorSpec[i].Green      = ScrInfo.Colors[i] >> 12 & 0xF;
2696                                                         ColorSpec[i].Blue       = ScrInfo.Colors[i] >>  4 & 0xF;
2697                                                 }
2698
2699                                                 ColorSpec[i].ColorIndex = -1;
2700                                         }
2701                                 }
2702                         }
2703 #endif /* !OS30_ONLY */
2704
2705
2706                         /* Use user requested attributes for screen */
2707
2708                         Scr = OpenScreenTags (NULL,
2709                                 SA_Width,                       ScrInfo.Width,
2710                                 SA_Height,                      ScrInfo.Height,
2711                                 SA_Depth,                       ScrInfo.Depth,
2712                                 SA_DisplayID,           ScrInfo.DisplayID,
2713                                 SA_Overscan,            ScrInfo.OverscanType,
2714                                 SA_AutoScroll,          ScrInfo.AutoScroll,
2715                                 SA_Title,                       ScrInfo.PubScreenName,
2716                                 SA_PubName,                     ScrInfo.PubScreenName,
2717                                 SA_Font,                        ScreenAttr.ta_Name ? &ScreenAttr : NULL,
2718                                 SA_Pens,                        PensArray,
2719                                 ScrInfo.OwnPalette ?
2720 #ifndef OS30_ONLY
2721                                         ((IntuitionBase->LibNode.lib_Version >= 39) ?
2722                                                 SA_Colors32 : SA_Colors) : TAG_IGNORE,
2723                                         (IntuitionBase->LibNode.lib_Version >= 39) ?
2724                                                 (ULONG)ColorTable : (ULONG)ColorSpec,
2725 #else
2726                                         SA_Colors32 : TAG_IGNORE,       ColorTable,
2727 #endif /* !OS30_ONLY */
2728
2729                                 TAG_MORE,                       ExtraScreenTags);
2730
2731                         if (ColorTable) FreePooled (Pool, ColorTable, ((32 * 3) + 2) * sizeof (LONG));
2732 #ifndef OS30_ONLY
2733                         if (ColorSpec)  FreePooled (Pool, ColorSpec, 33 * sizeof (struct ColorSpec));
2734 #endif /* !OS30_ONLY */
2735                         if (Scr) OwnScreen = TRUE;
2736                 }
2737
2738                 if (!Scr)
2739                 {
2740                         /* Try to clone the Default (Workbench) Screen */
2741
2742                         if (!(DefScr = LockPubScreen (NULL)))
2743                         {
2744                                 CloseDownScreen();
2745                                 return ERROR_OBJECT_NOT_FOUND;
2746                         }
2747
2748                         DefDri = GetScreenDrawInfo (DefScr);
2749
2750                         if (Scr = OpenScreenTags (NULL,
2751                                 SA_Depth,                       DefDri->dri_Depth,
2752                                 SA_DisplayID,           GetVPModeID (&DefScr->ViewPort),
2753                                 SA_Overscan,            OSCAN_TEXT,
2754                                 SA_AutoScroll,          TRUE,
2755                                 SA_Title,                       ScrInfo.PubScreenName,
2756                                 SA_PubName,                     ScrInfo.PubScreenName,
2757                                 SA_Pens,                        DefDri->dri_Pens,
2758                                 TAG_MORE,                       ExtraScreenTags))
2759                         {
2760                                 UnlockPubScreen (NULL, DefScr);
2761                                 OwnScreen = TRUE;
2762                         }
2763                         else
2764                                 Scr = DefScr;
2765
2766                         FreeScreenDrawInfo (DefScr, DefDri);
2767                 }
2768
2769                 /* Make our screen really public */
2770                 if (OwnScreen) PubScreenStatus (Scr, 0);
2771         }
2772
2773         if (!(VisualInfo = GetVisualInfoA (Scr, NULL)))
2774         {
2775                 CloseDownScreen();
2776                 return ERROR_NO_FREE_STORE;
2777         }
2778
2779         DrawInfo = GetScreenDrawInfo (Scr);
2780
2781         OffX = Scr->WBorLeft;
2782         OffY = Scr->RastPort.TxHeight + Scr->WBorTop + 1;
2783
2784         /* Setup fonts */
2785         if (!WindowAttr.ta_Name)        CopyTextAttrPooled (Pool, Scr->Font, &WindowAttr);
2786         if (!ListAttr.ta_Name)          CopyTextAttrPooled (Pool, Scr->Font, &ListAttr);
2787         if (!EditorAttr.ta_Name)        CopyTextAttrPooled (Pool, &TopazAttr, &EditorAttr);
2788
2789         if (!(TopazFont = OpenFont (&TopazAttr)))
2790         {
2791                 CantOpenLib (TopazAttr.ta_Name, 0);
2792                 CloseDownScreen();
2793                 return ERROR_NO_FREE_STORE;
2794         }
2795
2796         if (DiskfontBase)
2797         {
2798                 if (!(WindowFont = OpenDiskFont (&WindowAttr)))
2799                         CantOpenLib (WindowAttr.ta_Name, 0);
2800                 if (!(ListFont = OpenDiskFont (&WindowAttr)))
2801                         CantOpenLib (ListAttr.ta_Name, 0);
2802         }
2803
2804         /* Setup windows shared Message Port */
2805         if (!(WinPort = CreateMsgPort()))
2806         {
2807                 CloseDownScreen();
2808                 return ERROR_NO_FREE_STORE;
2809         }
2810         IDCMPSig = 1 << WinPort->mp_SigBit;
2811         Signals |= IDCMPSig;
2812
2813
2814         /* Create a SIZEIMAGE to get the correct size
2815          * and position for the slider and arrow buttons.
2816          */
2817         {
2818                 struct Image *sizeimage;
2819
2820                 if (sizeimage = NewImageObject (SIZEIMAGE))
2821                 {
2822                         SizeWidth       = sizeimage->Width;
2823                         SizeHeight      = sizeimage->Height;
2824                         DisposeObject (sizeimage);
2825                 }
2826         }
2827
2828
2829         if (!NewWindow (WID_TOOLBOX))
2830         {
2831                 CloseDownScreen();
2832                 return ERROR_NO_FREE_STORE;
2833         }
2834
2835         /* Set Process Window pointer for DOS requesters */
2836         OldPrWindowPtr = ThisTask->pr_WindowPtr;
2837         ThisTask->pr_WindowPtr = WDescr[WID_TOOLBOX].Wud->Win;
2838
2839         ReopenWindows();
2840
2841         /* Bring screen to front in case it was hidden */
2842         ScreenToFront (Scr);
2843
2844         return RETURN_OK;
2845 }
2846
2847
2848
2849 GLOBALCALL void CloseDownScreen (void)
2850
2851 /* Free screen and all associated resources */
2852 {
2853         struct WinUserData *wud;
2854
2855         if (!Scr) return;
2856
2857         ScreenShutdown = TRUE;
2858
2859         /* Close AmigaGuide help window */
2860         CleanupHelp();
2861
2862
2863         if (Quit)
2864         {
2865                 /* Destroy all windows */
2866                 while (!IsListEmpty (&WindowList))
2867                         DeleteWUD ((struct WinUserData *)WindowList.lh_Head);
2868         }
2869         else
2870         {
2871                 /* Close all windows */
2872                 for (wud = (struct WinUserData *)WindowList.lh_Head; wud->Link.mln_Succ;
2873                                 wud = (struct WinUserData *)wud->Link.mln_Succ)
2874                 {
2875                         MyCloseWindow (wud);
2876                         DeleteLayoutInfo (wud);
2877                         wud->WUDFlags |= WUDF_REOPENME;
2878                 }
2879         }
2880
2881
2882         if (WinPort)
2883         {
2884                 Signals &= ~IDCMPSig;
2885                 IDCMPSig = 0;
2886                 DeleteMsgPort (WinPort); WinPort = NULL;
2887         }
2888
2889         FreeScreenDrawInfo (Scr, DrawInfo);     DrawInfo = NULL;
2890         FreeVisualInfo (VisualInfo);            VisualInfo = NULL;
2891
2892         if (OwnScreen)
2893         {
2894                 /* TODO: Use BuildEasyRequest()/SysReqHandler() with SA_PubSig like IPrefs */
2895
2896                 while (!CloseScreen (Scr))
2897                         ShowRequestArgs (MSG_CLOSE_ALL_WINDOWS, MSG_CONTINUE, NULL);
2898         }
2899         else UnlockPubScreen (NULL, Scr);
2900
2901         if (OldPrWindowPtr != (struct Window *)1L)
2902         {
2903                 ThisTask->pr_WindowPtr = OldPrWindowPtr;
2904                 OldPrWindowPtr = (struct Window *)1L;
2905         }
2906
2907         if (WindowFont)
2908         {
2909                 CloseFont (WindowFont);
2910                 WindowFont = NULL;
2911         }
2912
2913         if (ListFont)
2914         {
2915                 CloseFont (ListFont);
2916                 ListFont = NULL;
2917         }
2918
2919         if (TopazFont)
2920         {
2921                 CloseFont (TopazFont);
2922                 TopazFont = NULL;
2923         }
2924
2925         if (ScrollButtonClass)
2926         {
2927                 FreeScrollButtonClass (ScrollButtonClass);
2928                 ScrollButtonClass = NULL;
2929         }
2930
2931         Scr = NULL;
2932         OwnScreen = FALSE;
2933         ScreenShutdown = FALSE;
2934 }