/* ** Gui.c ** ** Copyright (C) 1993,94,95,96,97 Bernardo Innocenti ** ** Graphic User Interface handling routines. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "XModulePriv.h" #include "Gui.h" #include "CustomClasses.h" XDEF struct Screen *Scr = NULL; XDEF struct ScrInfo ScrInfo = {0}; XDEF APTR VisualInfo = NULL; XDEF struct DrawInfo *DrawInfo = NULL; XDEF struct TextAttr TopazAttr = { "topaz.font", 8, FS_NORMAL, FPF_ROMFONT }, ScreenAttr = { 0 }, WindowAttr = { 0 }, ListAttr = { 0 }, EditorAttr = { 0 }; XDEF struct TextFont *TopazFont = NULL, *WindowFont = NULL, *ListFont = NULL; /* Window borders layout information */ XDEF UWORD OffX, OffY; /* X and Y offsets for window rendering */ XDEF WORD SizeWidth = 18, /* Dimensions of the window size gadget */ SizeHeight = 10; /* IDCMP windows support */ XDEF ULONG IDCMPSig = 0; /* Signal for above mentioned port */ XDEF ULONG Signals = SIGBREAKFLAGS; /* Signals for Wait() in main loop */ XDEF struct IntuiMessage IntuiMsg; /* A copy of the last received IntuiMsg */ XDEF struct List WindowList; /* Linked list of all open windows */ static UBYTE ActiveKey = 0; /* These three are used to handle */ static struct Gadget *ActiveGad = NULL; /* selection of button gadgets */ static struct Window *ActiveWin = NULL; /* with keyboard shortcuts. */ static struct Window *OldPrWindowPtr = (struct Window *)1L; XDEF LONG LastErr = 0; XDEF ULONG UniqueID; /* An ID got from GetUniqueID() */ XDEF UWORD WinLockCount = 0; /* Allow nesting of window locking */ XDEF BOOL Quit = FALSE; XDEF BOOL DoNextSelect = TRUE; /* Menu selection, see menu handling code */ XDEF BOOL ShowRequesters = TRUE; XDEF BOOL OwnScreen = FALSE; /* Are we owners or visitors? */ XDEF BOOL ScreenReopening = FALSE; /* Set to TRUE while reopening windows */ XDEF BOOL ScreenShutdown = FALSE; /* Set to TRUE while shutting down screen */ XDEF Class *ScrollButtonClass = NULL; /* Shared IDCMP port for all windows */ static struct MsgPort *WinPort = NULL; static Class *VImageClass = NULL; static ULONG VImageUseCount = 0; static struct Image *ButtonFrame = NULL; static WORD ButtonFrameWidth = 0; static WORD ButtonFrameHeight = 0; XDEF struct WDescr WDescr[WID_COUNT] = { { NULL, 0, 0, (struct TagItem *)ToolBoxWinTags }, { NULL, 0, 0, (struct TagItem *)PrefsWinTags }, { NULL, 0, 0, (struct TagItem *)SongInfoWinTags }, { NULL, 0, 0, (struct TagItem *)InstrumentsWinTags }, { NULL, 0, 0, (struct TagItem *)SequenceWinTags }, { NULL, 0, 0, (struct TagItem *)PatternWinTags }, { NULL, 0, 0, (struct TagItem *)PlayWinTags }, { NULL, 0, 0, (struct TagItem *)SampleWinTags }, { NULL, 0, 0, (struct TagItem *)OptimizationWinTags }, { NULL, 0, 0, (struct TagItem *)SaversWinTags }, { NULL, 0, 0, (struct TagItem *)PattPrefsWinTags }, { NULL, 0, 0, (struct TagItem *)PattSizeWinTags }, { NULL, 0, 0, (struct TagItem *)ClearWinTags }, { NULL, 0, 0, (struct TagItem *)LogWinTags }, { NULL, 0, 0, (struct TagItem *)ProgressWinTags } }; XDEF struct GuiSwitches GuiSwitches = { TRUE, /* SaveIcons */ TRUE, /* AskOverwrite */ TRUE, /* AskExit */ TRUE, /* ShowAppIcon */ FALSE, /* UseReqTools */ TRUE, /* SmartRefresh */ TRUE, /* UseDataTypes */ TRUE, /* InstrSaveIcons */ TRUE, /* AskAutosave */ FALSE, /* DoBackups */ FALSE, /* LogToFile */ INST_8SVX, /* InstrSaveMode */ 1, /* SampDrawMode */ XMDMF_NOTE+1, /* LogLevel */ 0, /* AutosaveTime */ 3, /* BackupVersions */ "*,#", /* BackupTemplate */ "CON:////XModule Log/AUTO/CLOSE/INACTIVE/SCREEN XMODULE" /* LogFile */ }; #ifndef OS30_ONLY /* Wait pointer image data */ static __chip UWORD WaitPointer[] = { 0x0000, 0x0000, 0x0400, 0x07c0, 0x0000, 0x07c0, 0x0100, 0x0380, 0x0000, 0x07e0, 0x07c0, 0x1ff8, 0x1ff0, 0x3fec, 0x3ff8, 0x7fde, 0x3ff8, 0x7fbe, 0x7ffc, 0xff7f, 0x7efc, 0xffff, 0x7ffc, 0xffff, 0x3ff8, 0x7ffe, 0x3ff8, 0x7ffe, 0x1ff0, 0x3ffc, 0x07c0, 0x1ff8, 0x0000, 0x07e0, 0x0000, 0x0000 }; #endif /* OS30_ONLY */ /* Martin Taillefer's block pointer */ /* static UWORD __chip BlockPointer[] = { 0x0000, 0x0000, 0x0000, 0x0100, 0x0100, 0x0280, 0x0380, 0x0440, 0x0100, 0x0280, 0x0100, 0x0ee0, 0x0000, 0x2828, 0x2008, 0x5834, 0x783c, 0x8002, 0x2008, 0x5834, 0x0000, 0x2828, 0x0100, 0x0ee0, 0x0100, 0x0280, 0x0380, 0x0440, 0x0100, 0x0280, 0x0000, 0x0100, 0x0000, 0x0000, 0x0000, 0x0000 }; */ /* Local function prototypes */ static void HandleKey (void); static void SelectButton (struct Window *win, struct Gadget *gad); static void DeselectButton (void); static void RenderWindowBorders(struct WinUserData *wud); static struct WindowBorder *CreateWindowBorder (struct WinUserData *wud, UWORD left, UWORD top, UWORD width, UWORD height, ULONG bordertype); static struct Gadget *CreateVImageButton (struct TagItem *tags, struct NewGadget *ng); static void DeleteVImageButton (struct Gadget *g); static struct Gadget *CreateGadgets (struct LayoutGadgetsArgs *lga, UWORD mode, UWORD left, UWORD top, UWORD width, UWORD height); static void LayoutGadgets (struct LayoutGadgetsArgs *lga, UWORD mode); static void DeleteGadgets (struct WinUserData *wud); static void DeleteWUD (struct WinUserData *wud); static struct WinUserData *CreateLayoutInfo (struct WinUserData *wud); GLOBALCALL LONG HandleGui (void) /* Handle XModule GUI - Main event handling loop */ { ULONG recsig; /* Received Signals */ LONG rc = 0; /* Return Code */ /* This is the main event handling loop */ while (!Quit) { recsig = Wait (Signals); if (recsig & IDCMPSig) HandleIDCMP(); if (recsig & AudioSig) HandleAudio(); if (recsig & PubPortSig) HandleRexxMsg(); if (recsig & AppSig) HandleAppMessage(); if (recsig & FileReqSig) HandleFileRequest(); if (recsig & CxSig) HandleCx(); if (recsig & AmigaGuideSig) HandleAmigaGuide(); /* Check break signals */ if (recsig & SIGBREAKFLAGS) { if (recsig & SIGBREAKF_CTRL_C) { Quit = TRUE; GuiSwitches.AskExit = FALSE; rc = ERROR_BREAK; } if (recsig & SIGBREAKF_CTRL_D) if (MyBroker) ActivateCxObj (MyBroker, FALSE); if (recsig & SIGBREAKF_CTRL_E) if (MyBroker) ActivateCxObj (MyBroker, TRUE); if (recsig & SIGBREAKF_CTRL_F) DeIconify(); } if (LastErr) { switch (LastErr) { case ERROR_NO_FREE_STORE: ShowMessage (MSG_NO_FREE_STORE); break; case ERROR_BREAK: ShowMessage (MSG_BREAK); break; default: break; } DisplayBeep (Scr); LastErr = 0; } if (Quit && GuiSwitches.AskExit) if (!ShowRequestArgs (MSG_REALLY_QUIT_XMODULE, MSG_YES_OR_NO, NULL)) { Quit = FALSE; rc = 0; } } /* End main loop */ return rc; } /* Intuition Event Handler. Based on GadToolsBox's HandleIDCMP() */ GLOBALCALL void HandleIDCMP (void) { struct IntuiMessage *m; struct MenuItem *n; struct Window *win; struct WinUserData *wud; while (m = GT_GetIMsg (WinPort)) { IntuiMsg = *m; /* Make a local copy and return message immediately */ GT_ReplyIMsg (m); win = IntuiMsg.IDCMPWindow; wud = (struct WinUserData *)win->UserData; switch (IntuiMsg.Class) { case IDCMP_REFRESHWINDOW: /* TODO: Handle multiple IDCMP_REFRESHWINDOW * messages sent at the same time. */ /* Lock Layer in sizeable windows so its size * won't change until we are finished rendering * on it. * * Newsflash: **DON'T!** Layers BeginUpdate() will already * lock the window layer for us, so doing it again we would * risk a complete GUI deadlock in some particular conditions... */ /* if (win->Flags & WFLG_SIZEGADGET) * LockLayer (NULL, win->WLayer); */ if (wud->WUDFlags & WUDF_JUSTRESIZED) { // RefreshGadgets (wud->GList, win, NULL); GT_RefreshWindow (win, NULL); RefreshWindowFrame (win); if (wud->Borders) RenderWindowBorders (wud); wud->WUDFlags &= ~WUDF_JUSTRESIZED; } else { GT_BeginRefresh (win); if (wud->Borders) RenderWindowBorders (wud); GT_EndRefresh (win, TRUE); } /* if (win->Flags & WFLG_SIZEGADGET) * UnlockLayer (win->WLayer); */ break; case IDCMP_RAWKEY: HandleKey (); break; case IDCMP_NEWSIZE: { struct Gadget *g; struct LayoutGadgetsArgs lga; struct RastPort rp; ULONG SpecialTags[20]; UWORD newwidth, newheight; /* TODO: Handle multiple IDCMP_NEWSIZE * messages sent at the same time. */ // LockLayer (NULL, win->WLayer); newwidth = win->Width - win->BorderLeft - win->BorderRight; newheight = win->Height - win->BorderTop - win->BorderBottom; if ((wud->WindowSize.Width == newwidth) && (wud->WindowSize.Height == newheight)) { // UnlockLayer (win->WLayer); break; } if (!(wud->WUDFlags & WUDF_CUSTOMLAYOUT)) { /* Detatch and free old gadgets */ RemoveGList (win, wud->GList, -1); DeleteGadgets (wud); /* Clear old window region (or what remains of it) */ SetAPen (win->RPort, 0); SetDrMd (win->RPort, JAM1); RectFill (win->RPort, win->BorderLeft, win->BorderTop, min (wud->WindowSize.Width, newwidth) + win->BorderLeft - 1, min (wud->WindowSize.Height, newheight) + win->BorderTop - 1); wud->WindowSize.Width = newwidth; wud->WindowSize.Height = newheight; /* Layout phase 2 */ InitRastPort (&rp); SetFont (&rp, wud->Font); if (!CreateContext (&wud->GList)) { // UnlockLayer (win->WLayer); DeleteWUD (wud); break; } lga.Args = wud->LayoutArgs; lga.VInfo = VisualInfo; lga.PrevGad = wud->GList; lga.GInfo = wud->GInfo; lga.Wud = wud; lga.DummyRast = &rp; lga.Count = 0; lga.SpecialTags = SpecialTags; SpecialTags[0] = GT_Underscore; SpecialTags[1] = (ULONG) '_'; g = CreateGadgets (&lga, LAYOUTMODE_V, OffX + lga.GInfo[0].LabelWidth + HSPACING, OffY + VSPACING, wud->WindowSize.Width - lga.GInfo[0].LabelWidth - HSPACING * 2, wud->WindowSize.Height - VSPACING * 2); if (!g) { // UnlockLayer (win->WLayer); DeleteWUD (wud); break; } AddGList (win, wud->GList, -1, -1, NULL); wud->WUDFlags |= WUDF_JUSTRESIZED; } if (wud->IDCMPFunc) wud->IDCMPFunc (wud); // UnlockLayer (win->WLayer); break; } case IDCMP_CLOSEWINDOW: if (wud->WindowID == WID_TOOLBOX) Quit = 1; else MyCloseWindow (wud); break; case IDCMP_GADGETUP: case IDCMP_GADGETDOWN: { struct Gadget *gad = (struct Gadget *)IntuiMsg.IAddress; /* Toggle switch */ if (wud->GInfo[gad->GadgetID].GKind == CHECKBOX_KIND) { UWORD *check; if (check = (WORD *)(wud->GInfo[gad->GadgetID].SpecialStorage)) *check ^= 1; } /* Execute function */ if (((struct Gadget *)IntuiMsg.IAddress)->UserData) ((void (*)(struct WinUserData *)) gad->UserData) (wud); break; } case IDCMP_MENUPICK: while (IntuiMsg.Code != MENUNULL) { n = ItemAddress (win->MenuStrip, IntuiMsg.Code); ((void (*)(struct WinUserData *))(GTMENUITEM_USERDATA(n))) (wud); /* Some window operations invalidate the menu * we are working on. For istance, Re-opening a * window causes the old MenuStrip to be killed. * The DoNextSelect flag provides a way to stop * this loop and avoid a nasty crash. */ if (!DoNextSelect) { DoNextSelect = TRUE; break; } IntuiMsg.Code = n->NextSelect; } break; case IDCMP_INACTIVEWINDOW: DeselectButton(); if (wud->IDCMPFunc) wud->IDCMPFunc (wud); break; case IDCMP_MENUHELP: case IDCMP_GADGETHELP: HandleHelp (&IntuiMsg); break; default: if (wud->IDCMPFunc) wud->IDCMPFunc (wud); break; } /* End switch (IntuiMsg.Class) */ if (!WinPort) break; } /* End while (GT_GetIMsg ()) */ } static void HandleKey (void) { struct Window *win = IntuiMsg.IDCMPWindow; struct WinUserData *wud = (struct WinUserData *)win->UserData; UWORD i; UBYTE keycode; /* Handle key up for buttons */ if (IntuiMsg.Code & IECODE_UP_PREFIX) { struct Gadget *gad = ActiveGad; DeselectButton(); if (gad && (ActiveKey == (IntuiMsg.Code & ~IECODE_UP_PREFIX))) ((void (*)(struct WinUserData *)) gad->UserData) (wud); return; } switch (IntuiMsg.Code) { case 0x5F: /* HELP */ HandleHelp (&IntuiMsg); return; case CURSORUP: case CURSORDOWN: if (wud->GInfo) for (i = 0; i < wud->GCount; i++) if (wud->GInfo[i].GKind == LISTVIEW_KIND) { struct Gadget *g = wud->Gadgets[i]; LONG selected, oldselected, top = ~0; #ifndef OS30_ONLY if (GadToolsBase->lib_Version < 39) selected = (LONG)(*(UWORD *)(((char *)g)+sizeof(struct Gadget)+48)); /* top = *(short *)(((char *)gad) + sizeof(struct Gadget) + 6); +4 ? */ else #endif /* !OS30_ONLY */ GT_GetGadgetAttrs (g, win, NULL, GTLV_Selected, &selected, GTLV_Top, &top, TAG_DONE); selected = (LONG)((WORD) selected); /* Extend to long */ oldselected = selected; /* Make a backup of it */ if (selected == ~0) selected = top; /* Scroll Top */ else top = ~0; if (IntuiMsg.Code == CURSORUP) { if (IntuiMsg.Qualifier & IEQUALIFIER_SHIFT) selected -= 5; else if (IntuiMsg.Qualifier & IEQUALIFIER_ALT) selected = 0; else selected--; } else /* CURSORDOWN */ { if (IntuiMsg.Qualifier & IEQUALIFIER_SHIFT) selected += 5; else if (IntuiMsg.Qualifier & IEQUALIFIER_ALT) selected = 65535; else selected++; } if (selected < 0) selected = 0; GT_SetGadgetAttrs (g, win, NULL, (top == ~0) ? GTLV_Selected : GTLV_Top, selected, (top == ~0) ? GTLV_MakeVisible : TAG_IGNORE, selected, TAG_DONE); #ifndef OS30_ONLY if (GadToolsBase->lib_Version < 39) selected = (LONG)(*(UWORD *)(((char *)g)+sizeof(struct Gadget)+48)); else #endif /* !OS30_ONLY */ GT_GetGadgetAttrs (g, win, NULL, GTLV_Selected, &selected, TAG_DONE); if (selected != oldselected) { IntuiMsg.Code = selected; if (g->UserData) ((void (*)(struct WinUserData *)) g->UserData) (wud); break; /* Stop for() loop */ } } /* End for */ return; case 0x42: /* TAB */ if (IntuiMsg.Qualifier & IEQUALIFIER_ALT) { struct WinUserData *nextwud; if (IntuiMsg.Qualifier & IEQUALIFIER_SHIFT) { /* ALT+SHIFT+TAB: Cycle windows backwards */ nextwud = (struct WinUserData *)wud->Link.mln_Pred; if (!(nextwud->Link.mln_Pred)) /* List head? */ nextwud = (struct WinUserData *)WindowList.lh_TailPred; } else { /* ALT+TAB: Cycle windows */ nextwud = (struct WinUserData *)wud->Link.mln_Succ; if (!(nextwud->Link.mln_Succ)) /* List tail? */ nextwud = (struct WinUserData *)WindowList.lh_Head; } RevealWindow (nextwud); return; } default: break; } /* End switch (IntuiMsg.Code) */ /* Convert the IDCMP_RAWKEY IntuiMessage to the single * character representation it corresponds to. If this isn't * possible (e.g. a HELP key or cursor key) then abort. */ { static struct InputEvent ie; ie.ie_NextEvent = NULL; ie.ie_Class = IECLASS_RAWKEY; ie.ie_SubClass = 0; ie.ie_Code = IntuiMsg.Code; ie.ie_Qualifier = IntuiMsg.Qualifier & IEQUALIFIER_CONTROL; /* Filter qualifiers. */ ie.ie_EventAddress = (APTR *) *((ULONG *)IntuiMsg.IAddress); if (MapRawKey (&ie, &keycode, 1, NULL) != 1) return; } /* Handle IDCMP_VANILLAKEY */ /* Check special keys */ switch (keycode) { case 0x03: /* CTRL-C */ Signal ((struct Task *)ThisTask, SIGBREAKF_CTRL_C); return; case 0x09: /* TAB */ case 0x0D: /* RETURN */ if (wud->GInfo) for (i = 0; i < wud->GCount; i++) if (wud->GInfo[i].GKind == STRING_KIND || wud->GInfo[i].GKind == INTEGER_KIND) ActivateGadget (wud->Gadgets[i],win, NULL); return; case 0x1B: /* ESC */ if (wud->WindowID != WID_TOOLBOX) MyCloseWindow (wud); return; default: break; } /* Look for gadget shortcuts */ if (wud->GInfo) for (i = 0; i < wud->GCount; i++) { if (wud->Keys[i] == keycode) /* Case insensitive compare */ { struct Gadget *g = wud->Gadgets[i]; LONG disabled = FALSE; /* Check disabled */ #ifndef OS30_ONLY if (GadToolsBase->lib_Version < 39) disabled = g->Flags & GFLG_DISABLED; else #endif /* !OS30_ONLY */ GT_GetGadgetAttrs (g, win, NULL, GA_Disabled, &disabled, TAG_DONE); if (disabled) break; /* Stop for() loop */ switch (wud->GInfo[i].GKind) { case BUTTON_KIND: if (!(IntuiMsg.Qualifier & IEQUALIFIER_REPEAT)) SelectButton (win, g); break; case CHECKBOX_KIND: /* Toggle switch */ if (wud->GInfo[i].SpecialStorage) *((UWORD *)wud->GInfo[i].SpecialStorage) ^= 1; GT_SetGadgetAttrs (g, win, NULL, GTCB_Checked, !(g->Flags & GFLG_SELECTED), TAG_DONE); if (g->UserData) ((void (*)(struct WinUserData *)) g->UserData) (wud); break; case INTEGER_KIND: case STRING_KIND: ActivateGadget (g, win, NULL); break; case CYCLE_KIND: #ifndef OS30_ONLY if (GadToolsBase->lib_Version >= 39) #endif /* !OS30_ONLY */ { LONG act, max; UBYTE **lab; /* ON V37: active = *(short *)(((char *)gad) + sizeof(struct Gadget) + 6); */ GT_GetGadgetAttrs (g, win, NULL, GTCY_Active, &act, GTCY_Labels, &lab, TAG_DONE); act = (LONG)((UWORD)act); /* Extend to LONG */ if (IntuiMsg.Qualifier & IEQUALIFIER_SHIFT) act--; else act++; for (max = 0; lab[max]; max++); /* Count labels */ if (act >= max) act = 0; else if (act < 0) act = max - 1; GT_SetGadgetAttrs (g, win, NULL, GTCY_Active, act, TAG_DONE); if (g->UserData) { IntuiMsg.Code = act; ((void (*)(struct WinUserData *)) g->UserData) (wud); } } break; case MX_KIND: { LONG act; #ifndef OS30_ONLY if (GadToolsBase->lib_Version < 39) act = (LONG)(*(UWORD *)(((char *)g)+sizeof(struct Gadget)+24)); /* 38? */ else #endif /* !OS30_ONLY */ { GT_GetGadgetAttrs (g, win, NULL, GTMX_Active, &act, TAG_DONE); act = (LONG)((UWORD)act); /* Extend to LONG */ } if (IntuiMsg.Qualifier & IEQUALIFIER_SHIFT) act--; else act++; GT_SetGadgetAttrs (g, win, NULL, GTMX_Active, act, TAG_DONE); #ifndef OS30_ONLY if (GadToolsBase->lib_Version < 39) act = (LONG)(*(UWORD *)(((char *)g)+sizeof(struct Gadget)+24)); else #endif /* !OS30_ONLY */ { GT_GetGadgetAttrs (g, win, NULL, GTMX_Active, &act, TAG_DONE); act = (LONG)((UWORD)act); /* Extend to LONG */ } if (g->UserData) { IntuiMsg.Code = act; ((void (*)(struct WinUserData *)) g->UserData) (wud); } break; } case SLIDER_KIND: #ifndef OS30_ONLY if (GadToolsBase->lib_Version >= 39) #endif /* !OS30_ONLY */ { LONG min, max, level; GT_GetGadgetAttrs (g, win, NULL, GTSL_Min, &min, GTSL_Max, &max, GTSL_Level, &level, TAG_DONE); /* Extend to LONG */ min = (LONG)((WORD)min); max = (LONG)((WORD)max); level = (LONG)((WORD)level); if (IntuiMsg.Qualifier & IEQUALIFIER_SHIFT) { if (IntuiMsg.Qualifier & IEQUALIFIER_ALT) level = min; else level--; } else { if (IntuiMsg.Qualifier & IEQUALIFIER_ALT) level = max; else level++; } if (level > max) level = max; if (level < min) level = min; GT_SetGadgetAttrs (g, win, NULL, GTSL_Level, level, TAG_DONE); if (g->UserData) { IntuiMsg.Code = level; ((void (*)(struct WinUserData *)) g->UserData) (wud); } } break; default: break; } return; /* Stop for() loop */ } } /* End for() */ /* There is no apparent use for this key event, * let's pass the IntuiMessage to user's IDCMPFunc()... */ if (wud->IDCMPFunc) ((void (*)(void)) wud->IDCMPFunc) (); } static void SelectButton (struct Window *win, struct Gadget *gad) /* Selects the button gadget . This operation is illegal with * GadTools gadgets, but many programs do it anyway, so this trick * will probably be supported in future OS releases :-). */ { UWORD gadpos; if (ActiveGad) DeselectButton(); gadpos = RemoveGadget (win, gad); gad->Flags |= GFLG_SELECTED; AddGadget (win, gad, gadpos); RefreshGList (gad, win, NULL, 1); ActiveKey = IntuiMsg.Code; ActiveGad = gad; ActiveWin = win; } static void DeselectButton (void) /* Deselects the button previously selected with SelectButton() */ { if (ActiveGad) { UWORD gadpos = RemoveGadget (ActiveWin, ActiveGad); ActiveGad->Flags &= ~GFLG_SELECTED; AddGadget (ActiveWin, ActiveGad, gadpos); RefreshGList (ActiveGad, ActiveWin, NULL, 1); ActiveGad = NULL; } } GLOBALCALL void LockWindows (void) /* Disable user input in all windows */ { struct WinUserData *wud; struct Window *win; struct WindowLock *lock; /* Are the windows already locked? */ WinLockCount++; if (WinLockCount > 1) return; for (wud = (struct WinUserData *) WindowList.lh_Head; wud->Link.mln_Succ; wud = (struct WinUserData *)wud->Link.mln_Succ) { if (!(win = wud->Win)) continue; /* Set wait pointer */ #ifndef OS30_ONLY if (IntuitionBase->LibNode.lib_Version < 39) SetPointer (win, WaitPointer, 16, 16, -6, 0); else #endif /* !OS30_ONLY */ SetWindowPointer (win, WA_BusyPointer, TRUE, TAG_DONE); /* Do not block input in Progress window */ if (wud->WindowID == WID_PROGRESS) continue; /* Set an invisible Requester in window to block user input. * We allocate 4 more bytes after the requester structure to store * the IDCMP flags before modifying them. MEMF_PUBLIC is used * because intuition is going to process the Requester structure. */ if (!(lock = AllocPooled (Pool, sizeof (struct WindowLock)))) continue; InitRequester (&lock->Req); lock->Req.Flags = SIMPLEREQ | NOREQBACKFILL; /* Disable window resizing */ if (win->Flags & WFLG_SIZEGADGET) { lock->OldMinWidth = win->MinWidth; lock->OldMinHeight = win->MinHeight; lock->OldMaxWidth = win->MaxWidth; lock->OldMaxHeight = win->MaxHeight; WindowLimits (win, win->Width, win->Height, win->Width, win->Height); } /* Disable IDCMP messages except IDCMP_REFRESHWINDOW events. * WARNING: ModifyIDCMP (win, 0) would free the shared port!! */ lock->OldIDCMPFlags = win->IDCMPFlags; ModifyIDCMP (win, IDCMP_REFRESHWINDOW); Request (&lock->Req, win); } } GLOBALCALL void UnlockWindows (void) /* Restore user input in all windows. */ { struct WinUserData *wud; struct Window *win; struct WindowLock *lock; /* Make sure windows arn't unlocked already */ if (WinLockCount) return; /* Check lock nesting */ WinLockCount--; if (WinLockCount) return; for (wud = (struct WinUserData *) WindowList.lh_Head; wud->Link.mln_Succ; wud = (struct WinUserData *)wud->Link.mln_Succ) { if (!(win = wud->Win)) continue; if (lock = (struct WindowLock *) win->FirstRequest) { /* Restore old window IDCMP */ ModifyIDCMP (win, lock->OldIDCMPFlags); /* Re-enable window sizing and restore old window limits */ if (win->Flags & WFLG_SIZEGADGET) WindowLimits (win, lock->OldMinWidth, lock->OldMinHeight, lock->OldMaxWidth, lock->OldMaxHeight); EndRequest (&lock->Req, wud->Win); FreePooled (Pool, lock, sizeof (struct WindowLock)); } /* Restore standard pointer */ #ifndef OS30_ONLY if (IntuitionBase->LibNode.lib_Version < 39) ClearPointer (win); else #endif /* !OS30_ONLY */ SetWindowPointer (win, TAG_DONE); } } GLOBALCALL void RevealWindow (struct WinUserData *wud) { WindowToFront (wud->Win); ActivateWindow (wud->Win); /* Make the window visible on the screen */ #ifndef OS30_ONLY if (IntuitionBase->LibNode.lib_Version >= 39) #endif /* OS30_ONLY */ ScreenPosition (Scr, SPOS_MAKEVISIBLE, wud->Win->LeftEdge, wud->Win->TopEdge, wud->Win->LeftEdge + wud->Win->Width - 1, wud->Win->TopEdge + wud->Win->Height - 1); } GLOBALCALL void SetGadgets (struct WinUserData *wud, LONG arg, ...) /* Update status of gadgets in the window associated to . * is the first of a -1 terminated array of commands. * Each command is represented by a pair of LONGs, where the * first LONG is the gadget number, and the second is the value * to set for that gadget, depending on the gadget type. */ { LONG *cmd = &arg; static ULONG actions[] = { TAG_IGNORE, /* GENERIC_KIND */ TAG_IGNORE, /* BUTTON_KIND */ GTCB_Checked, /* CHECKBOX_KIND */ GTIN_Number, /* INTEGER_KIND */ GTLV_Selected, /* LISTVIEW_KIND */ GTMX_Active, /* MX_KIND */ GTNM_Number, /* NUMBER_KIND */ GTCY_Active, /* CYCLE_KIND */ GTPA_Color, /* PALETTE_KIND */ TAG_IGNORE, /* SCROLLER_KIND */ TAG_IGNORE, /* -- reserved -- */ GTSL_Level, /* SLIDER_KIND */ GTST_String, /* STRING_KIND */ GTTX_Text /* TEXT_KIND */ }; while (*cmd != -1) { GT_SetGadgetAttrs (wud->Gadgets[*cmd], wud->Win, NULL, actions[wud->GInfo[*cmd].GKind], *(cmd+1), TAG_DONE); cmd += 2; } } GLOBALCALL LONG AddListViewNode (struct List *lv, CONST_STRPTR label, ...) /* Var-args stub for AddListViewNodeA */ { return AddListViewNodeA (lv, label, (LONG *) (&label)+1); } GLOBALCALL LONG AddListViewNodeA (struct List *lv, CONST_STRPTR label, LONG *args) /* Allocate and add a new node to a ListView list. The label * is printf()-formatted and copied to a buffer just after the * node structure. Call RemListViewNode() to deallocate the node. * * RETURNS * 0 for failure (no memory), any other value for success. */ { struct Node *n; UBYTE buf[256]; if (args) { VSPrintf (buf, label, args); label = buf; } if (!(n = AllocVecPooled (Pool, sizeof (struct Node) + strlen (label) + 1))) return FALSE; n->ln_Name = ((UBYTE *)n) + sizeof (struct Node); strcpy (n->ln_Name, label); n->ln_Pri = 0; /* Selected */ ADDTAIL (lv, n); return TRUE; } GLOBALCALL void RemListViewNode (struct Node *n) { REMOVE (n); FreeVecPooled (Pool, n); } GLOBALCALL struct Image *NewImageObject (ULONG which) /* Creates a sysiclass object. */ { return ((struct Image *)NewObject (NULL, SYSICLASS, SYSIA_DrawInfo, DrawInfo, SYSIA_Which, which, SYSIA_Size, Scr->Flags & SCREENHIRES ? SYSISIZE_MEDRES : SYSISIZE_LOWRES, TAG_DONE)); /* NB: SYSISIZE_HIRES not yet supported. */ } static struct Gadget *CreateVImageButton (struct TagItem *tags, struct NewGadget *ng) /* This routine is called by the layout engine to create an IMAGEBUTTON_KIND gadget. */ { struct Gadget *VButton; struct Image *VImage; if (!VImageClass) { if (VImageClass = InitVImageClass ()) { if (ButtonFrame = NewObject (NULL, FRAMEICLASS, IA_FrameType, FRAME_BUTTON, IA_EdgesOnly, TRUE, TAG_DONE)) { struct IBox FrameBox, ContentsBox = { 0, 0, 0, 0 }; DoMethod ((Object *)ButtonFrame, IM_FRAMEBOX, &ContentsBox, &FrameBox, DrawInfo, 0); ButtonFrameWidth = FrameBox.Width; ButtonFrameHeight = FrameBox.Height; } else { FreeVImageClass (VImageClass); VImageClass = NULL; return NULL; } } else return NULL; } if (!(VImage = (struct Image *)NewObject (VImageClass, NULL, IA_Width, ng->ng_Width - ButtonFrameWidth, IA_Height, ng->ng_Height - ButtonFrameHeight, SYSIA_Which, ng->ng_Flags, TAG_DONE))) return NULL; if (!(VButton = (struct Gadget *)NewObject (NULL, FRBUTTONCLASS, GA_ID, ng->ng_GadgetID, GA_UserData, ng->ng_UserData, GA_Left, ng->ng_LeftEdge, GA_Top, ng->ng_TopEdge, GA_Image, ButtonFrame, GA_LabelImage, VImage, GA_RelVerify, TRUE, TAG_DONE))) DisposeObject (VImage); else VImageUseCount++; return VButton; } static void DeleteVImageButton (struct Gadget *g) { if (g) { DisposeObject (g->GadgetText); DisposeObject (g); VImageUseCount--; if (!VImageUseCount) { if (ButtonFrame) { DisposeObject (ButtonFrame); ButtonFrame = NULL; } if (VImageClass) { FreeVImageClass (VImageClass); VImageClass = NULL; } } } } /* Gadget definition format: * * VGROUP_KIND, BorderType, * HGROUP_KIND, BorderType, * IMAGEBUTTON_KIND, ClickedFunction, ImageType, Tag1, ..., * CHECKBOX_KIND, ClickedFunction, Label, Storage (UWORD *), Tag1, ..., * BUTTON_KIND, ClickedFunction, Label, Tag1, ..., * INTEGER_KIND, ClickedFunction, Label, MaxDigits, Tag1, ..., * STRING_KIND, ClickedFunction, Label, MaxChars, Tag1, ..., * TEXT_KIND, Label, NumChars, Tag1, ..., * NUMBER_KIND, Label, MaxDigits, Tag1, ..., * LISTVIEW_KIND, ClickedFunction, Label, Labels (struct List *), Tag1, ..., * MX_KIND, ClickedFunction, Label, Labels (ULONG *), Tag1, ..., * CYCLE_KIND, ClickedFunction, Label, Labels (ULONG *), Tag1, ..., * SLIDER_KIND, ClickedFunction, Label, Min, Max, LevelFormat (UBYTE *), MaxLevelLen (ULONG), Tag1, ..., * PALETTE_KIND, ClickedFunction, Label, Tags, * ENDGROUP_KIND, */ static void LayoutGadgets (struct LayoutGadgetsArgs *lga, UWORD mode) { struct GInfo *ginfo, *myginfo = &lga->GInfo[lga->Count]; STRPTR label; /* Skip this group */ lga->Count++; if (mode == LAYOUTMODE_V) myginfo->Flags |= GIF_FIXEDWIDTH; else myginfo->Flags |= GIF_FIXEDHEIGHT; while (*lga->Args != ENDGROUP_KIND) { ginfo = &lga->GInfo[lga->Count]; label = NULL; switch (ginfo->GKind = *lga->Args++) { case HGROUP_KIND: case VGROUP_KIND: if (*lga->Args++) /* Border? */ { LayoutGadgets (lga, (ginfo->GKind == HGROUP_KIND) ? LAYOUTMODE_H : LAYOUTMODE_V); /* Add border dimensions to group size */ ginfo->MinWidth += HSPACING * 8; ginfo->Fixed.Width += HSPACING * 8; ginfo->MinHeight += VSPACING * 8; ginfo->Fixed.Height += VSPACING * 8; ginfo->Flags |= GIF_HASBORDER; } else LayoutGadgets (lga, (ginfo->GKind == HGROUP_KIND) ? LAYOUTMODE_H : LAYOUTMODE_V); break; case IMAGEBUTTON_KIND: lga->Args++; /* Skip Clicked function */ lga->Args++; /* Skip Image */ ginfo->MinWidth = lga->Wud->Font->tf_XSize * 3 + 2; ginfo->MinHeight = lga->Wud->Font->tf_YSize + 4; ginfo->Flags |= GIF_FIXEDWIDTH | GIF_FIXEDHEIGHT; break; case CHECKBOX_KIND: lga->Args++; /* Skip Clicked function */ label = STR(*lga->Args++); ginfo->SpecialStorage = (void *)*lga->Args++; /* Record storage */ ginfo->MinWidth = lga->Wud->Font->tf_XSize * 2 + 8; ginfo->MinHeight = lga->Wud->Font->tf_YSize + 4; ginfo->LabelWidth = TextLength (lga->DummyRast, label, strlen (label)) + LABELSPACING; ginfo->Flags = GIF_FIXEDWIDTH | GIF_FIXEDHEIGHT; break; case BUTTON_KIND: lga->Args++; /* Skip Clicked function */ label = STR(*lga->Args++); ginfo->MinWidth = TextLength (lga->DummyRast, label, strlen (label)) + LABELSPACING; ginfo->MinHeight = lga->Wud->Font->tf_YSize + 4; ginfo->Flags = GIF_FIXEDHEIGHT; break; case INTEGER_KIND: case STRING_KIND: { UWORD maxchars; lga->Args++; /* Skip Clicked function */ if (label = STR (*lga->Args++)) ginfo->LabelWidth = TextLength (lga->DummyRast, label, strlen (label)) + LABELSPACING; maxchars = *lga->Args++; ginfo->MinWidth = lga->Wud->Font->tf_XSize * min (maxchars + 1, 8) + 12; ginfo->MinHeight = lga->Wud->Font->tf_YSize + 6; ginfo->Flags = GIF_FIXEDHEIGHT; break; } case LISTVIEW_KIND: lga->Args++; /* Skip Clicked function */ ginfo->MinWidth = lga->Wud->Font->tf_XSize * 16 + 16; ginfo->MinHeight = lga->Wud->Font->tf_YSize * 4 + 4; if (label = STR (*lga->Args++)) ginfo->LabelWidth = TextLength (lga->DummyRast, label, strlen (label)) + LABELSPACING; ginfo->SpecialStorage = (void *)*lga->Args++; /* Record List pointer */ break; case MX_KIND: case CYCLE_KIND: { ULONG *labels, cnt = 0; STRPTR str; lga->Args++; /* Skip Clicked function */ if (label = STR(*lga->Args++)) ginfo->LabelWidth = TextLength (lga->DummyRast, label, strlen (label)) + LABELSPACING; ginfo->MinWidth = ginfo->MinHeight = 0; /* Count labels */ labels = (ULONG *) *lga->Args++; while (labels[cnt]) cnt++; /* Allocate and fill-in MX/Cycle labels array */ if (!ginfo->SpecialStorage) ginfo->SpecialStorage = AllocVecPooled (Pool, (cnt + 1) * sizeof (STRPTR)); if (ginfo->SpecialStorage) { ULONG i; for (i = 0; i < cnt; i++) { /* Store localized label */ ((STRPTR *)(ginfo->SpecialStorage))[i] = str = STR (labels[i]); /* Calculate maximum width */ ginfo->MinWidth = max (ginfo->MinWidth, TextLength (lga->DummyRast, str, strlen (str)) + LABELSPACING); if (ginfo->GKind == MX_KIND) ginfo->MinHeight += lga->Wud->Font->tf_YSize + 2; } /* Terminate labels array */ ((STRPTR *)(ginfo->SpecialStorage))[i] = NULL; } /* add width of radio button (or cycle image) */ ginfo->MinWidth += lga->Wud->Font->tf_XSize * 2 + 4; if (ginfo->GKind == MX_KIND) ginfo->Flags = GIF_FIXEDWIDTH | GIF_FIXEDHEIGHT; else { ginfo->Flags = GIF_FIXEDHEIGHT; ginfo->MinHeight += lga->Wud->Font->tf_YSize + 4; } break; } case NUMBER_KIND: case TEXT_KIND: if (label = STR (*lga->Args++)) ginfo->LabelWidth = TextLength (lga->DummyRast, label, strlen (label)) + LABELSPACING; ginfo->MinWidth = lga->Wud->Font->tf_XSize * (*lga->Args++) + 8; ginfo->MinHeight = lga->Wud->Font->tf_YSize + 4; ginfo->Flags = GIF_FIXEDHEIGHT; break; case SLIDER_KIND: lga->Args++; /* Skip Clicked function */ if (label = STR (*lga->Args++)) ginfo->LabelWidth = TextLength (lga->DummyRast, label, strlen (label)) + LABELSPACING; lga->Args += 3; /* Skip Min, Max and LevelFormat */ if (ginfo->SpecialStorage = (APTR)((*lga->Args++) * lga->Wud->Font->tf_XSize)) ginfo->SpecialStorage = (APTR) ((ULONG)ginfo->SpecialStorage + 4); ginfo->MinWidth = lga->Wud->Font->tf_XSize * 8 + 8 + (ULONG)ginfo->SpecialStorage; ginfo->MinHeight = lga->Wud->Font->tf_YSize; ginfo->Flags = GIF_FIXEDHEIGHT; break; case PALETTE_KIND: lga->Args++; /* Skip Clicked function */ if (label = STR (*lga->Args++)) ginfo->LabelWidth = TextLength (lga->DummyRast, label, strlen (label)) + LABELSPACING; ginfo->MinWidth = lga->Wud->Font->tf_XSize * 6 + 8; ginfo->MinHeight = lga->Wud->Font->tf_YSize * 3 + 4; break; } if ((ginfo->GKind != HGROUP_KIND) && (ginfo->GKind != VGROUP_KIND)) { UBYTE *c; /* Go to next gadget (ie: skip tags until TAG_END) */ while (*lga->Args) lga->Args += 2; lga->Args++; /* Look for the key equivalent of this gadget. */ if (c = label) for ( ; *c ; c++) if (*c == '_') { /* Found! Now store in the key array */ lga->Wud->Keys[lga->Count] = *(++c) | (1<<5); /* Lower case */ break; } } if (mode == LAYOUTMODE_V) { myginfo->MinHeight += ginfo->MinHeight + VSPACING; if (ginfo->Flags & GIF_HASBORDER) myginfo->MinWidth = max (myginfo->MinWidth, ginfo->MinWidth + ginfo->LabelWidth); else { myginfo->MinWidth = max (myginfo->MinWidth, ginfo->MinWidth); myginfo->LabelWidth = max (myginfo->LabelWidth, ginfo->LabelWidth); } myginfo->Fixed.Height += VSPACING; if (ginfo->Flags & GIF_FIXEDHEIGHT) myginfo->Fixed.Height += ginfo->MinHeight; if (!(ginfo->Flags & GIF_FIXEDWIDTH)) myginfo->Flags &= ~GIF_FIXEDWIDTH; } else /* LAYOUTMODE_H */ { myginfo->MinWidth += ginfo->MinWidth + ginfo->LabelWidth + HSPACING; myginfo->MinHeight = max (myginfo->MinHeight, ginfo->MinHeight); myginfo->Fixed.Width += ginfo->LabelWidth + HSPACING; if (ginfo->Flags & GIF_FIXEDWIDTH) myginfo->Fixed.Width += ginfo->MinWidth; if (!(ginfo->Flags & GIF_FIXEDHEIGHT)) myginfo->Flags &= ~GIF_FIXEDHEIGHT; } lga->Count++; } /* End while (*lga->Args != ENDGROUP_KIND) */ if (mode == LAYOUTMODE_H) { /* Remove extra HSPACING after last child */ myginfo->MinWidth -= HSPACING; myginfo->Fixed.Width -= HSPACING; if (!(myginfo->Flags & GIF_HASBORDER)) { /* Align first child of HGROUP_KIND with other * gadgets in our parent group */ myginfo->LabelWidth = (myginfo+1)->LabelWidth; (myginfo+1)->LabelWidth = 0; myginfo->MinWidth -= myginfo->LabelWidth; myginfo->Fixed.Width -= myginfo->LabelWidth; } } else /* LAYOUTMODE_V */ { /* Remove extra VSPACING after last child */ myginfo->MinHeight -= VSPACING; myginfo->Fixed.Height -= VSPACING; } if (myginfo->MinWidth <= myginfo->Fixed.Width) myginfo->Flags |= GIF_FIXEDWIDTH; if (myginfo->MinHeight <= myginfo->Fixed.Height) myginfo->Flags |= GIF_FIXEDHEIGHT; lga->Args++; /* Skip ENDGROUP_KIND */ lga->Count--; /* Take back one position */ } static struct Gadget *CreateGadgets (struct LayoutGadgetsArgs *lga, UWORD mode, UWORD left, UWORD top, UWORD width, UWORD height) { struct GInfo *ginfo, *myginfo = &lga->GInfo[lga->Count]; struct TagItem *Tags, *tmp; ULONG stc; struct NewGadget ng; BOOL boopsi; /* Skip this group */ lga->Count++; while (*lga->Args != ENDGROUP_KIND) { ginfo = &lga->GInfo[lga->Count]; Tags = (struct TagItem *)lga->SpecialTags; stc = 2; boopsi = FALSE; ng.ng_TextAttr = lga->Wud->Attr; ng.ng_GadgetID = lga->Count; ng.ng_VisualInfo = lga->VInfo; ng.ng_Flags = PLACETEXT_LEFT; if (mode == LAYOUTMODE_V) { if (ginfo->Flags & GIF_FIXEDWIDTH) ng.ng_Width = ginfo->MinWidth; else ng.ng_Width = width - ((ginfo->Flags & GIF_HASBORDER) ? ginfo->LabelWidth : 0); if (ginfo->Flags & GIF_FIXEDHEIGHT) ng.ng_Height = ginfo->MinHeight; else ng.ng_Height = (((ULONG)(height - myginfo->Fixed.Height)) * ((ULONG)ginfo->MinHeight)) / ((ULONG)(myginfo->MinHeight - myginfo->Fixed.Height)); ng.ng_LeftEdge = left + ((ginfo->Flags & GIF_HASBORDER) ? ginfo->LabelWidth : 0); ng.ng_TopEdge = top; top = ng.ng_TopEdge + ng.ng_Height + VSPACING; } else /* mode == LAYOUTMODE_H */ { if (ginfo->Flags & GIF_FIXEDWIDTH) ng.ng_Width = ginfo->MinWidth; else ng.ng_Width = (((ULONG)(width - myginfo->Fixed.Width)) * ((ULONG)ginfo->MinWidth)) / ((ULONG)(myginfo->MinWidth - myginfo->Fixed.Width)); if (ginfo->Flags & GIF_FIXEDHEIGHT) { /* Vertical center */ ng.ng_Height = ginfo->MinHeight; ng.ng_TopEdge = top + (height - ng.ng_Height) / 2; } else { /* Vertical stretch */ ng.ng_Height = height; ng.ng_TopEdge = top; } ng.ng_LeftEdge = left + ginfo->LabelWidth; left = ng.ng_LeftEdge + ng.ng_Width + HSPACING; } switch (ginfo->GKind = *lga->Args++) { case BOOPSI_KIND: ng.ng_UserData = (void *)(*lga->Args++); lga->SpecialTags[stc++] = XMGAD_SetupFunc; lga->SpecialTags[stc++] = (*lga->Args++); boopsi = TRUE; break; case IMAGEBUTTON_KIND: ng.ng_UserData = (void *)(*lga->Args++); ng.ng_Flags = (*lga->Args++); ng.ng_GadgetText = NULL; lga->SpecialTags[stc++] = XMGAD_SetupFunc; lga->SpecialTags[stc++] = (ULONG)CreateVImageButton; boopsi = TRUE; break; case VGROUP_KIND: case HGROUP_KIND: { ULONG bordertype; if (bordertype = *lga->Args++) { if (!CreateWindowBorder (lga->Wud, ng.ng_LeftEdge - ginfo->LabelWidth, ng.ng_TopEdge, ng.ng_Width + ginfo->LabelWidth, ng.ng_Height, bordertype)) return NULL; if (!CreateGadgets (lga, (ginfo->GKind == VGROUP_KIND) ? LAYOUTMODE_V : LAYOUTMODE_H, ng.ng_LeftEdge + HSPACING*4, ng.ng_TopEdge + VSPACING*4, ng.ng_Width - HSPACING*8, ng.ng_Height - VSPACING*8)) return NULL; } else if (!CreateGadgets (lga, (ginfo->GKind == VGROUP_KIND) ? LAYOUTMODE_V : LAYOUTMODE_H, ng.ng_LeftEdge, ng.ng_TopEdge, ng.ng_Width, ng.ng_Height)) return NULL; break; } case BUTTON_KIND: ng.ng_UserData = (void *)(*lga->Args++); ng.ng_GadgetText = STR(*lga->Args++); ng.ng_Flags = PLACETEXT_IN; break; case CHECKBOX_KIND: ng.ng_UserData = (void *)(*lga->Args++); ng.ng_GadgetText = STR(*lga->Args++); lga->Args++; /* Skip storage */ lga->SpecialTags[stc++] = GTCB_Checked; lga->SpecialTags[stc++] = (ginfo->SpecialStorage ? (*((UWORD *)ginfo->SpecialStorage)) : NULL); lga->SpecialTags[stc++] = GTCB_Scaled; lga->SpecialTags[stc++] = TRUE; break; case INTEGER_KIND: ng.ng_UserData = (void *)(*lga->Args++); ng.ng_GadgetText = STR(*lga->Args++); /* Editing in right-justified integer gadgets * is very uncomfortable!! * * lga->SpecialTags[stc++] = STRINGA_Justification; * lga->SpecialTags[stc++] = GACT_STRINGRIGHT; */ lga->SpecialTags[stc++] = GTIN_MaxChars; lga->SpecialTags[stc++] = *lga->Args++; lga->SpecialTags[stc++] = STRINGA_ExitHelp; lga->SpecialTags[stc++] = TRUE; break; case LISTVIEW_KIND: { struct List *l; ng.ng_UserData = (void *)*lga->Args++; ng.ng_GadgetText = STR(*lga->Args++); lga->SpecialTags[stc++] = GTLV_ShowSelected; lga->SpecialTags[stc++] = NULL; if (l = (struct List *)*lga->Args++) { lga->SpecialTags[stc++] = GTLV_Labels; lga->SpecialTags[stc++] = (ULONG)l; // l->lh_Type = 0; /* Selected Item */ // l->l_pad = 0; /* Item Count */ } #ifndef OS30_ONLY if (GadToolsBase->lib_Version < 39) ng.ng_Height -= 4; #endif /* !OS30_ONLY */ break; } case MX_KIND: case CYCLE_KIND: { ng.ng_UserData = (void *)(*lga->Args++); ng.ng_GadgetText = STR(*lga->Args++); /* Skip labels */ lga->Args++; if (ginfo->GKind == MX_KIND) { /* Special kludge: MX gadgets width and height refer to * one button instead of the whole gadget. */ ng.ng_Width = lga->Wud->Font->tf_XSize * 2; ng.ng_Height = lga->Wud->Font->tf_YSize; ng.ng_Flags = PLACETEXT_RIGHT; lga->SpecialTags[stc++] = GTMX_Labels; lga->SpecialTags[stc++] = (ULONG)ginfo->SpecialStorage; lga->SpecialTags[stc++] = GTMX_Scaled; lga->SpecialTags[stc++] = TRUE; lga->SpecialTags[stc++] = GTMX_Spacing; lga->SpecialTags[stc++] = 2; } else { lga->SpecialTags[stc++] = GTCY_Labels; lga->SpecialTags[stc++] = (ULONG)ginfo->SpecialStorage; } break; } case NUMBER_KIND: ng.ng_UserData = NULL; ng.ng_GadgetText = STR(*lga->Args++); lga->Args++; /* Skip NumDigits */ lga->SpecialTags[stc++] = GTNM_Border; lga->SpecialTags[stc++] = TRUE; /* Under V39 and below, GTJ_RIGHT does not work properly. */ if (GadToolsBase->lib_Version > 39) { lga->SpecialTags[stc++] = GTNM_Justification; lga->SpecialTags[stc++] = GTJ_RIGHT; } break; case TEXT_KIND: ng.ng_UserData = NULL; ng.ng_GadgetText = STR(*lga->Args++); lga->Args++; /* Skip NumDigits */ break; case PALETTE_KIND: ng.ng_UserData = (void *)(*lga->Args++); ng.ng_GadgetText = STR(*lga->Args++); lga->SpecialTags[stc++] = GTPA_IndicatorWidth; lga->SpecialTags[stc++] = ng.ng_Width / 8; break; case SCROLLER_KIND: ng.ng_UserData = (void *)(*lga->Args++); ng.ng_GadgetText = STR(*lga->Args++); lga->SpecialTags[stc++] = GTSC_Arrows; lga->SpecialTags[stc++] = lga->Wud->Font->tf_XSize + 4; break; case STRING_KIND: /* ClassId = STRGCLASS; lga->SpecialTags[stc++] = GA_UserData; lga->SpecialTags[stc++] = *lga->Args++; lga->SpecialTags[stc++] = GA_LabelImage; lga->SpecialTags[stc++] = *lga->Args++; lga->SpecialTags[stc++] = STRINGA_MaxChars; lga->SpecialTags[stc++] = *lga->Args++; lga->SpecialTags[stc++] = GA_Border; lga->SpecialTags[stc++] = StringFrame; lga->SpecialTags[stc++] = STRINGA_ExitHelp; lga->SpecialTags[stc++] = TRUE; */ ng.ng_UserData = (void *)(*lga->Args++); ng.ng_GadgetText = STR(*lga->Args++); lga->SpecialTags[stc++] = GTST_MaxChars; lga->SpecialTags[stc++] = *lga->Args++; lga->SpecialTags[stc++] = STRINGA_ExitHelp; lga->SpecialTags[stc++] = TRUE; break; case SLIDER_KIND: ng.ng_UserData = (void *)(*lga->Args++); ng.ng_GadgetText = STR(*lga->Args++); lga->SpecialTags[stc++] = GTSL_Min; lga->SpecialTags[stc++] = *lga->Args++; lga->SpecialTags[stc++] = GTSL_Max; lga->SpecialTags[stc++] = *lga->Args++; lga->SpecialTags[stc++] = GTSL_LevelFormat; lga->SpecialTags[stc++] = *lga->Args++; lga->SpecialTags[stc++] = GTSL_MaxLevelLen; lga->SpecialTags[stc++] = *lga->Args++; lga->SpecialTags[stc++] = GTSL_LevelPlace; lga->SpecialTags[stc++] = PLACETEXT_RIGHT; lga->SpecialTags[stc++] = GTSL_Justification; lga->SpecialTags[stc++] = GTJ_RIGHT; lga->SpecialTags[stc++] = GA_RelVerify; lga->SpecialTags[stc++] = TRUE; ng.ng_Width -= (ULONG)ginfo->SpecialStorage; break; } if ((ginfo->GKind != HGROUP_KIND) && (ginfo->GKind != VGROUP_KIND)) { if (*lga->Args != TAG_DONE) { /* Add user Tags */ lga->SpecialTags[stc++] = TAG_MORE; lga->SpecialTags[stc] = (ULONG) lga->Args; } else lga->SpecialTags[stc] = TAG_DONE; /* Go to next gadget (ie: skip tags until TAG_END) */ while (*lga->Args) lga->Args += 2; lga->Args++; if (boopsi) { /* BOOPSI Gadget. Let SetupFunc() allocate the gadget for us */ if (tmp = FindTagItem (XMGAD_SetupFunc, Tags)) { if (lga->PrevGad->NextGadget = ((struct Gadget * (*)(struct TagItem *, struct NewGadget *)) (tmp->ti_Data)) (Tags, &ng)) /* Record it into the list */ lga->Wud->Gadgets[lga->Count] = lga->PrevGad->NextGadget; else return NULL; } else return NULL; } else { /* Normal GadTools gadget */ if (!(lga->Wud->Gadgets[lga->Count] = CreateGadgetA (ginfo->GKind, lga->PrevGad, &ng, Tags))) return NULL; } lga->PrevGad = lga->Wud->Gadgets[lga->Count]; } /* End if (GKind != ?GROUP_KIND */ lga->Count++; /* Go to next gadget */ } lga->Args++; /* Skip ENDGROUP_KIND */ lga->Count--; /* Take back one position */ return (lga->Wud->GList); } static void RenderWindowBorders (struct WinUserData *wud) { struct WindowBorder *border = wud->Borders; while (border) { DrawBevelBox (wud->Win->RPort, border->Size.Left, border->Size.Top, border->Size.Width, border->Size.Height, GT_VisualInfo, VisualInfo, GTBB_Recessed, TRUE, GTBB_FrameType, border->Type, TAG_DONE); border = border->NextBorder; } } static struct WindowBorder *CreateWindowBorder (struct WinUserData *wud, UWORD left, UWORD top, UWORD width, UWORD height, ULONG bordertype) /* Creates new WindowBorder structure and links it to the WUD passed. * Will return NULL in case of failure. */ { struct WindowBorder *border; if (!(border = AllocPooled (Pool, sizeof (struct WindowBorder)))) return NULL; /* Link this border struct in WUD */ border->NextBorder = wud->Borders; wud->Borders = border; /* Fill in WindowBorder structure */ border->Type = bordertype; border->Size.Left = left; border->Size.Top = top; border->Size.Width = width; border->Size.Height = height; return border; } static void DeleteGadgets (struct WinUserData *wud) { FreeGadgets (wud->GList); wud->GList = NULL; if (wud->GInfo) { ULONG i; for (i = 0; i < wud->GCount; i++) { if (wud->Gadgets[i]) { switch (wud->GInfo[i].GKind) { case IMAGEBUTTON_KIND: DeleteVImageButton (wud->Gadgets[i]); break; default: break; } } } } if (wud->Borders) { struct WindowBorder *border = wud->Borders, *nextborder; do { nextborder = border->NextBorder; FreePooled (Pool, border, sizeof (struct WindowBorder)); } while (border = nextborder); wud->Borders = NULL; } } struct WinUserData *CreateWUD (ULONG id) { struct WinUserData *wud; struct WDescr *wdescr = &WDescr[id]; /* Create a new WUD structure for this window */ if (wud = CAllocPooled (Pool, sizeof (struct WinUserData))) { wdescr->Wud = wud; wdescr->UseCnt++; wud->WindowID = id; wud->IDCMPFlags = IDCMP_RAWKEY | IDCMP_MENUHELP | IDCMP_GADGETHELP | IDCMP_INACTIVEWINDOW; wud->Flags = WFLG_DRAGBAR | WFLG_DEPTHGADGET; wud->Title = PrgName; /* Link WUD to windows list */ ADDHEAD (&WindowList, (struct Node *)wud); if (wdescr->CreationTags) { struct TagItem *tstate = wdescr->CreationTags, *tag; /* Read taglist arguments */ while (tag = NextTagItem (&tstate)) switch (tag->ti_Tag) { case XMWIN_NewMenu: wud->NewMenu = (struct NewMenu *)tag->ti_Data; break; case XMWIN_LayoutArgs: wud->LayoutArgs = (ULONG *)tag->ti_Data; break; case XMWIN_GCount: wud->GCount = tag->ti_Data; break; case XMWIN_Title: wud->Title = STR(tag->ti_Data); break; case XMWIN_WindowFlags: wud->Flags |= tag->ti_Data; break; case XMWIN_IDCMPFlags: wud->IDCMPFlags |= tag->ti_Data; break; case XMWIN_IDCMPFunc: wud->IDCMPFunc = (void (*)()) tag->ti_Data; break; case XMWIN_DropIconFunc: wud->DropIcon = (void (*)()) tag->ti_Data; break; case XMWIN_LayoutFunc: wud->LayoutArgs = (ULONG *)tag->ti_Data; wud->WUDFlags |= WUDF_CUSTOMLAYOUT; break; case XMWIN_PreOpenFunc: wud->PreOpenFunc = (LONG (*)()) tag->ti_Data; break; case XMWIN_PostOpenFunc: wud->PostOpenFunc = (void (*)()) tag->ti_Data; break; case XMWIN_PreCloseFunc: wud->PreCloseFunc = (LONG (*)()) tag->ti_Data; break; case XMWIN_PostCloseFunc: wud->PostCloseFunc = (void (*)()) tag->ti_Data; break; case XMWIN_HelpNode: wud->HelpNode = (STRPTR) tag->ti_Data; break; case XMWIN_UserData: wud->UserData = (APTR) tag->ti_Data; break; case XMWIN_LayoutCleanup: wud->LayoutCleanupFunc = (void (*)()) tag->ti_Data; break; default: break; } } if (!CreateLayoutInfo (wud)) { DeleteWUD (wud); wud = NULL; } } return wud; } static void DeleteWUD (struct WinUserData *wud) { if (wud) { MyCloseWindow (wud); REMOVE ((struct Node *) wud); { struct WDescr *wdescr = &WDescr[wud->WindowID]; wdescr->Wud = NULL; if (--wdescr->UseCnt) { struct WinUserData *otherwud; /* Search for another wud with same ID and set it in WDescr... */ for (otherwud = (struct WinUserData *)WindowList.lh_Head; otherwud->Link.mln_Succ; otherwud = (struct WinUserData *)otherwud->Link.mln_Succ) if (otherwud->WindowID == wud->WindowID) { wdescr->Wud = otherwud; break; } } } DeleteLayoutInfo (wud); FreePooled (Pool, wud, sizeof (struct WinUserData)); } } static struct WinUserData *CreateLayoutInfo (struct WinUserData *wud) { struct WDescr *wdescr = &WDescr[wud->WindowID]; /* Compute font */ if (wud->Font = WindowFont) wud->Attr = &WindowAttr; else { wud->Font = TopazFont; wud->Attr = &TopazAttr; } if (wud->LayoutArgs) { if (!wud->Gadgets) { /* Allocate Gadgets array */ if (!(wud->Gadgets = CAllocPooled (Pool, wud->GCount * sizeof (struct Gadget *)))) return NULL; } if (wud->WUDFlags & WUDF_CUSTOMLAYOUT) { if (!(wud->GList = ((struct Gadget * (*)(struct WinUserData *)) wud->LayoutArgs) (wud) )) return NULL; } else /* Use standard layout engine */ { struct LayoutGadgetsArgs lga; lga.Wud = wud; /* Layout Phase 1 */ if (!wud->GInfo) { struct RastPort rp; InitRastPort (&rp); SetFont (&rp, wud->Font); lga.DummyRast = &rp; lga.Args = wud->LayoutArgs; lga.Count = 0; /* Allocate Key shortcuts array */ if (!(wud->Keys = CAllocPooled (Pool, wud->GCount))) return NULL; /* Allocate GInfo array */ if (!(wud->GInfo = lga.GInfo = CAllocPooled (Pool, sizeof (struct GInfo) * wud->GCount))) return NULL; LayoutGadgets (&lga, LAYOUTMODE_V); if ((lga.GInfo[0].Flags & (GIF_FIXEDWIDTH | GIF_FIXEDHEIGHT)) != (GIF_FIXEDWIDTH | GIF_FIXEDHEIGHT)) { wud->Flags |= (WFLG_SIZEGADGET | WFLG_SIZEBBOTTOM); wud->IDCMPFlags |= IDCMP_NEWSIZE; } /* Force minimum size */ wud->WindowSize.Width = max (wud->WindowSize.Width, lga.GInfo[0].MinWidth + lga.GInfo[0].LabelWidth + HSPACING * 2); wud->WindowSize.Height = max (wud->WindowSize.Height, lga.GInfo[0].MinHeight + VSPACING * 2); } else /* Reuse previous GInfo array */ lga.GInfo = wud->GInfo; /* Layout Phase 2 */ { ULONG SpecialTags[20]; SpecialTags[0] = GT_Underscore; SpecialTags[1] = (ULONG) '_'; if (!CreateContext (&wud->GList)) return NULL; lga.Args = wud->LayoutArgs; lga.VInfo = VisualInfo; lga.PrevGad = wud->GList; lga.Count = 0; lga.SpecialTags = SpecialTags; if (!CreateGadgets (&lga, LAYOUTMODE_V, OffX + lga.GInfo[0].LabelWidth + HSPACING, OffY + VSPACING, wud->WindowSize.Width - lga.GInfo[0].LabelWidth - HSPACING * 2, wud->WindowSize.Height - VSPACING * 2)) return NULL; } } } if (!(wdescr->Flags & XMWINF_LOCALEDONE)) { if (wud->NewMenu) { /* Localize the MenuStrip */ struct NewMenu *nm = wud->NewMenu; while (nm->nm_Type != NM_END) { if (nm->nm_Label != (STRPTR)NM_BARLABEL) nm->nm_Label = STR ((ULONG)nm->nm_Label); nm++; } } wdescr->Flags |= XMWINF_LOCALEDONE; } if (wud->NewMenu && (!wud->MenuStrip)) { if (!(wud->MenuStrip = CreateMenusA (wud->NewMenu, NULL))) return NULL; if (!(LayoutMenus (wud->MenuStrip, VisualInfo, GTMN_NewLookMenus, TRUE, TAG_DONE))) return NULL; } /* Setup zoom size */ if (wud->Flags & WFLG_SIZEGADGET) { wud->WindowZoom.Left = 0; wud->WindowZoom.Top = 1; wud->WindowZoom.Width = Scr->Width; wud->WindowZoom.Height = Scr->Height; } else { wud->WindowZoom.Left = wud->WindowSize.Left; wud->WindowZoom.Top = wud->WindowSize.Top; if (wud->Title) wud->WindowZoom.Width = TextLength (&Scr->RastPort, wud->Title, strlen (wud->Title)) + 80; else wud->WindowZoom.Width = 80; wud->WindowZoom.Height = Scr->WBorTop + Scr->RastPort.TxHeight + 1; /* TODO: Under V39 specifying ~0,~0 as Zoom X,Y, intuition * will only size-zoom the window. Consider implementing it... */ } return wud; } GLOBALCALL void DeleteLayoutInfo (struct WinUserData *wud) { if (!wud) return; DeleteGadgets (wud); if (wud->LayoutCleanupFunc) wud->LayoutCleanupFunc (wud); if (wud->Keys) { FreePooled (Pool, wud->Keys, wud->GCount); wud->Keys = NULL; } if (wud->Gadgets) { if (wud->GInfo) { ULONG i; /* Free gadget associated resources */ for (i = 0; i < wud->GCount; i++) { if (wud->Gadgets[i]) { switch (wud->GInfo[i].GKind) { case MX_KIND: case CYCLE_KIND: FreeVecPooled (Pool, wud->GInfo[i].SpecialStorage); default: break; } } } } FreePooled (Pool, wud->Gadgets, wud->GCount * sizeof (struct Gadget *)); wud->Gadgets = NULL; } if (wud->GInfo) { FreePooled (Pool, wud->GInfo, wud->GCount * sizeof (struct GInfo)); wud->GInfo = NULL; } if (wud->MenuStrip) { FreeMenus (wud->MenuStrip); wud->MenuStrip = NULL; } } GLOBALCALL struct Window *NewWindow (ULONG id) /* Create a new window using the given Window ID. */ { struct WDescr *wdescr = &WDescr[id]; struct WinUserData *wud; if (!Scr) return NULL; /* Some windows can not be opened multiple times */ if (!(wud = wdescr->Wud) || (wdescr->Flags & XMWINF_OPENMULTI)) { if (!(wud = CreateWUD (id))) return NULL; } return MyOpenWindow (wud); } GLOBALCALL struct Window *MyOpenWindow (struct WinUserData *wud) /* Open & setup a window using the given WinUserData structure. */ /* This function is now OBSOLETE and should be merged with NewWindow() */ { if (!Scr) return NULL; if (wud->PreOpenFunc) if (wud->PreOpenFunc (wud)) { if (wud->PreCloseFunc) wud->PreCloseFunc (wud); return NULL; } if (wud->Win) { RevealWindow (wud); return wud->Win; } if (!wud->Gadgets && wud->LayoutArgs) if (!CreateLayoutInfo (wud)) return NULL; /* Open the Window */ if (wud->Win = OpenWindowTags (NULL, WA_Left, wud->WindowSize.Left, WA_Top, wud->WindowSize.Top, WA_InnerWidth, wud->WindowSize.Width, WA_InnerHeight, wud->WindowSize.Height, WA_Gadgets, wud->GList, WA_Title, wud->Title, WA_Flags, wud->Flags, WA_Zoom, &(wud->WindowZoom), WA_PubScreen, Scr, WA_HelpGroup, UniqueID, /* Set user preferred refresh method unless this window * requests simple refresh explicitly. */ GuiSwitches.SmartRefresh ? WA_SmartRefresh : WA_SimpleRefresh, TRUE, WA_Activate, !ScreenReopening, /* Set minimum and maximum size according to the main gadget group * properties. */ (wud->Flags & WFLG_SIZEGADGET) ? WA_MinWidth : TAG_IGNORE, wud->GInfo ? (wud->GInfo[0].MinWidth + Scr->WBorLeft + Scr->WBorRight) : wud->WindowSize.Width, (wud->Flags & WFLG_SIZEGADGET) ? WA_MinHeight : TAG_IGNORE, wud->GInfo ? (wud->GInfo[0].MinHeight + Scr->WBorTop + Scr->WBorBottom + Scr->Font->ta_YSize + SizeHeight + 1) : wud->WindowSize.Height, /**/ (wud->Flags & WFLG_SIZEGADGET) ? WA_MaxWidth : TAG_IGNORE, wud->GInfo ? (wud->GInfo[0].Flags & GIF_FIXEDWIDTH ? 0 : -1) : -1, (wud->Flags & WFLG_SIZEGADGET) ? WA_MaxHeight : TAG_IGNORE, wud->GInfo ? (wud->GInfo[0].Flags & GIF_FIXEDHEIGHT ? wud->GInfo[0].MinHeight : -1) : -1, /* Constant tags */ WA_ScreenTitle, (ULONG)Version+6, WA_AutoAdjust, TRUE, WA_MenuHelp, TRUE, // WA_MouseQueue, 2, // WA_RptQueue, 2, WA_NewLookMenus, TRUE, /* Add user tags */ WDescr[wud->WindowID].CreationTags ? TAG_MORE : TAG_DONE, WDescr[wud->WindowID].CreationTags )) { wud->Win->UserData = (BYTE *) wud; wud->Win->UserPort = WinPort; if (ModifyIDCMP (wud->Win, wud->IDCMPFlags)) { /* Set default font for this window */ if (wud->Font) SetFont (wud->Win->RPort, wud->Font); if (wud->MenuStrip) SetMenuStrip (wud->Win, wud->MenuStrip); /* Do initial refresh */ GT_RefreshWindow (wud->Win, NULL); RenderWindowBorders (wud); /* Make the window visible on the screen */ if (!ScreenReopening #ifndef OS30_ONLY && (IntuitionBase->LibNode.lib_Version >= 39) #endif /* !OS30_ONLY */ ) ScreenPosition (Scr, SPOS_MAKEVISIBLE, wud->Win->LeftEdge, wud->Win->TopEdge, wud->Win->LeftEdge + wud->Win->Width - 1, wud->Win->TopEdge + wud->Win->Height - 1); /* Make it an AppWindow if it is requested */ if (wud->DropIcon) AddAppWin (wud); if (wud->PostOpenFunc) wud->PostOpenFunc (wud); wud->WUDFlags &= ~WUDF_REOPENME; return wud->Win; } /* ClearMenuStrip() -- no need to call it... */ CloseWindow (wud->Win); wud->Win = NULL; } return NULL; } /* Close a window and all related resources */ GLOBALCALL void MyCloseWindow (struct WinUserData *wud) { struct Window *win = wud->Win; struct Requester *req; if (win) { DeselectButton(); if (wud->PreCloseFunc) if (wud->PreCloseFunc (wud)) return; /* Cleanup locked window */ if (req = win->FirstRequest) { EndRequest (req, win); FreePooled (Pool, req, sizeof (struct WindowLock)); } /* Remove AppWindow */ if (wud->AppWin) RemAppWin (wud); /* Free MenuStrip */ if (win->MenuStrip) { ClearMenuStrip (win); DoNextSelect = 0; /* Do not loop any more on this window's MenuStrip */ } /* Now remove any pending message from the shared IDCMP port */ Forbid(); { struct Node *succ; struct Message *msg = (struct Message *) win->UserPort->mp_MsgList.lh_Head; while (succ = msg->mn_Node.ln_Succ) { if (((struct IntuiMessage *)msg)->IDCMPWindow == win) { REMOVE ((struct Node *)msg); ReplyMsg (msg); } msg = (struct Message *) succ; } win->UserPort = NULL; /* Keep intuition from freeing our port... */ ModifyIDCMP (win, 0L); /* ...and from sending us any more messages. */ } Permit(); /* Save Window position and clear window pointer */ wud->WindowSize.Left = win->LeftEdge; wud->WindowSize.Top = win->TopEdge; if (win->Flags & WFLG_SIZEGADGET) { wud->WindowSize.Width = win->Width - win->BorderLeft - win->BorderRight; wud->WindowSize.Height = win->Height - win->BorderTop - win->BorderBottom; } CloseWindow (win); wud->Win = NULL; if (wud->PostCloseFunc) wud->PostCloseFunc (wud); } if (wud->Font) { CloseFont (wud->Font); wud->Font = NULL; } if ((WDescr[wud->WindowID].Flags & XMWINF_OPENMULTI) && (WDescr[wud->WindowID].UseCnt > 1)) DeleteWUD (wud); } GLOBALCALL void ReopenWindows (void) /* Reopen windows that were previously open */ { struct WinUserData *wud; ScreenReopening = TRUE; /* Find window */ for (wud = (struct WinUserData *)WindowList.lh_Head; wud->Link.mln_Succ; wud = (struct WinUserData *)wud->Link.mln_Succ) { if (wud->WUDFlags & WUDF_REOPENME) MyOpenWindow (wud); } ScreenReopening = FALSE; } GLOBALCALL LONG SetupScreen (void) { struct Screen *DefScr; struct DrawInfo *DefDri; static LONG ExtraScreenTags[] = { SA_SysFont, 1, SA_FullPalette, TRUE, SA_SharePens, TRUE, /* These three Tags are valid only under SA_LikeWorkbench, TRUE, * V39 and are properly ignored by V37. SA_MinimizeISG, TRUE, */ SA_Interleaved, TRUE, TAG_DONE }; if (Scr) { /* If screen is already open, pop it to front and activate * the main window. */ ScreenToFront (Scr); if (ThisTask->pr_WindowPtr) RevealWindow ((struct WinUserData *)(((struct Window *)(ThisTask->pr_WindowPtr))->UserData)); return RETURN_OK; } if (!(ScrollButtonClass = InitScrollButtonClass())) return ERROR_NO_FREE_STORE; /* Try the user selected Public Screen */ if (!(Scr = LockPubScreen (ScrInfo.PubScreenName[0] ? ScrInfo.PubScreenName : NULL))) { /* Try to open own screen */ if (ScrInfo.DisplayID) { static UWORD PensArray[1] = {(UWORD)~0}; ULONG *ColorTable = NULL; #ifndef OS30_ONLY struct ColorSpec *ColorSpec = NULL; #endif /* !OS30_ONLY */ ULONG i; /* Color map translation */ if (ScrInfo.OwnPalette) { #ifndef OS30_ONLY if (IntuitionBase->LibNode.lib_Version >= 39) { #endif /* !OS30_ONLY */ if (ColorTable = AllocPooled (Pool, ((32 * 3) + 2) * sizeof (LONG))) { ULONG *col = ColorTable, tmp; *col++ = 32 << 16; for (i = 0; i < 32; i++) { tmp = (ScrInfo.Colors[i] >> 16); /* Red */ tmp |= tmp << 8 | tmp << 16 | tmp << 24; *col++ = tmp; tmp = (ScrInfo.Colors[i] >> 8) & 0xFF; /* Green */ tmp |= tmp << 8 | tmp << 16 | tmp << 24; *col++ = tmp; tmp = ScrInfo.Colors[i] & 0xFF; /* Blue */ tmp |= tmp << 8 | tmp << 16 | tmp << 24; *col++ = tmp; } *col = 0; } } #ifndef OS30_ONLY else /* V37 */ { if (ColorSpec = AllocPooled (Pool, 33 * sizeof (struct ColorSpec))) { for (i = 0; i < 32; i++) { ColorSpec[i].ColorIndex = i; ColorSpec[i].Red = ScrInfo.Colors[i] >> 20; ColorSpec[i].Green = ScrInfo.Colors[i] >> 12 & 0xF; ColorSpec[i].Blue = ScrInfo.Colors[i] >> 4 & 0xF; } ColorSpec[i].ColorIndex = -1; } } } #endif /* !OS30_ONLY */ /* Use user requested attributes for screen */ Scr = OpenScreenTags (NULL, SA_Width, ScrInfo.Width, SA_Height, ScrInfo.Height, SA_Depth, ScrInfo.Depth, SA_DisplayID, ScrInfo.DisplayID, SA_Overscan, ScrInfo.OverscanType, SA_AutoScroll, ScrInfo.AutoScroll, SA_Title, ScrInfo.PubScreenName, SA_PubName, ScrInfo.PubScreenName, SA_Font, ScreenAttr.ta_Name ? &ScreenAttr : NULL, SA_Pens, PensArray, ScrInfo.OwnPalette ? #ifndef OS30_ONLY ((IntuitionBase->LibNode.lib_Version >= 39) ? SA_Colors32 : SA_Colors) : TAG_IGNORE, (IntuitionBase->LibNode.lib_Version >= 39) ? (ULONG)ColorTable : (ULONG)ColorSpec, #else SA_Colors32 : TAG_IGNORE, ColorTable, #endif /* !OS30_ONLY */ TAG_MORE, ExtraScreenTags); if (ColorTable) FreePooled (Pool, ColorTable, ((32 * 3) + 2) * sizeof (LONG)); #ifndef OS30_ONLY if (ColorSpec) FreePooled (Pool, ColorSpec, 33 * sizeof (struct ColorSpec)); #endif /* !OS30_ONLY */ if (Scr) OwnScreen = TRUE; } if (!Scr) { /* Try to clone the Default (Workbench) Screen */ if (!(DefScr = LockPubScreen (NULL))) { CloseDownScreen(); return ERROR_OBJECT_NOT_FOUND; } DefDri = GetScreenDrawInfo (DefScr); if (Scr = OpenScreenTags (NULL, SA_Depth, DefDri->dri_Depth, SA_DisplayID, GetVPModeID (&DefScr->ViewPort), SA_Overscan, OSCAN_TEXT, SA_AutoScroll, TRUE, SA_Title, ScrInfo.PubScreenName, SA_PubName, ScrInfo.PubScreenName, SA_Pens, DefDri->dri_Pens, TAG_MORE, ExtraScreenTags)) { UnlockPubScreen (NULL, DefScr); OwnScreen = TRUE; } else Scr = DefScr; FreeScreenDrawInfo (DefScr, DefDri); } /* Make our screen really public */ if (OwnScreen) PubScreenStatus (Scr, 0); } if (!(VisualInfo = GetVisualInfoA (Scr, NULL))) { CloseDownScreen(); return ERROR_NO_FREE_STORE; } DrawInfo = GetScreenDrawInfo (Scr); OffX = Scr->WBorLeft; OffY = Scr->RastPort.TxHeight + Scr->WBorTop + 1; /* Setup fonts */ if (!WindowAttr.ta_Name) CopyTextAttrPooled (Pool, Scr->Font, &WindowAttr); if (!ListAttr.ta_Name) CopyTextAttrPooled (Pool, Scr->Font, &ListAttr); if (!EditorAttr.ta_Name) CopyTextAttrPooled (Pool, &TopazAttr, &EditorAttr); if (!(TopazFont = OpenFont (&TopazAttr))) { CantOpenLib (TopazAttr.ta_Name, 0); CloseDownScreen(); return ERROR_NO_FREE_STORE; } if (DiskfontBase) { if (!(WindowFont = OpenDiskFont (&WindowAttr))) CantOpenLib (WindowAttr.ta_Name, 0); if (!(ListFont = OpenDiskFont (&WindowAttr))) CantOpenLib (ListAttr.ta_Name, 0); } /* Setup windows shared Message Port */ if (!(WinPort = CreateMsgPort())) { CloseDownScreen(); return ERROR_NO_FREE_STORE; } IDCMPSig = 1 << WinPort->mp_SigBit; Signals |= IDCMPSig; /* Create a SIZEIMAGE to get the correct size * and position for the slider and arrow buttons. */ { struct Image *sizeimage; if (sizeimage = NewImageObject (SIZEIMAGE)) { SizeWidth = sizeimage->Width; SizeHeight = sizeimage->Height; DisposeObject (sizeimage); } } if (!NewWindow (WID_TOOLBOX)) { CloseDownScreen(); return ERROR_NO_FREE_STORE; } /* Set Process Window pointer for DOS requesters */ OldPrWindowPtr = ThisTask->pr_WindowPtr; ThisTask->pr_WindowPtr = WDescr[WID_TOOLBOX].Wud->Win; ReopenWindows(); /* Bring screen to front in case it was hidden */ ScreenToFront (Scr); return RETURN_OK; } GLOBALCALL void CloseDownScreen (void) /* Free screen and all associated resources */ { struct WinUserData *wud; if (!Scr) return; ScreenShutdown = TRUE; /* Close AmigaGuide help window */ CleanupHelp(); if (Quit) { /* Destroy all windows */ while (!IsListEmpty (&WindowList)) DeleteWUD ((struct WinUserData *)WindowList.lh_Head); } else { /* Close all windows */ for (wud = (struct WinUserData *)WindowList.lh_Head; wud->Link.mln_Succ; wud = (struct WinUserData *)wud->Link.mln_Succ) { MyCloseWindow (wud); DeleteLayoutInfo (wud); wud->WUDFlags |= WUDF_REOPENME; } } if (WinPort) { Signals &= ~IDCMPSig; IDCMPSig = 0; DeleteMsgPort (WinPort); WinPort = NULL; } FreeScreenDrawInfo (Scr, DrawInfo); DrawInfo = NULL; FreeVisualInfo (VisualInfo); VisualInfo = NULL; if (OwnScreen) { /* TODO: Use BuildEasyRequest()/SysReqHandler() with SA_PubSig like IPrefs */ while (!CloseScreen (Scr)) ShowRequestArgs (MSG_CLOSE_ALL_WINDOWS, MSG_CONTINUE, NULL); } else UnlockPubScreen (NULL, Scr); if (OldPrWindowPtr != (struct Window *)1L) { ThisTask->pr_WindowPtr = OldPrWindowPtr; OldPrWindowPtr = (struct Window *)1L; } if (WindowFont) { CloseFont (WindowFont); WindowFont = NULL; } if (ListFont) { CloseFont (ListFont); ListFont = NULL; } if (TopazFont) { CloseFont (TopazFont); TopazFont = NULL; } if (ScrollButtonClass) { FreeScrollButtonClass (ScrollButtonClass); ScrollButtonClass = NULL; } Scr = NULL; OwnScreen = FALSE; ScreenShutdown = FALSE; }