home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #3 / amigamamagazinepolishissue1998.iso / bazy / db3.4 / dbgui.c < prev    next >
C/C++ Source or Header  |  1997-03-16  |  34KB  |  1,109 lines

  1. /*
  2.  *  GUI Designed by : David Ekholm, Datadosen
  3.  */
  4.  
  5. #include <stdlib.h>    /* atoi() */
  6. #include <exec/types.h>
  7. #include <exec/memory.h>
  8. #include <intuition/intuition.h>
  9. #include <intuition/intuitionbase.h>
  10. #include <intuition/screens.h>    /* DrawInfo */
  11. #include <intuition/classes.h>
  12. #include <intuition/classusr.h>
  13. #include <intuition/imageclass.h>
  14. #include <intuition/gadgetclass.h>
  15. #include <gadgets/textfield.h>
  16.  
  17. #include <intuition/sghooks.h> /* struct SGWork here */
  18. #include <workbench/workbench.h>    /* For AppWindow */
  19. #include <libraries/gadtools.h>
  20. #include <libraries/commodities.h> /* This has a nice qualifier #define */
  21. #include <libraries/iffparse.h>
  22.  
  23. #include <graphics/displayinfo.h>
  24. #include <graphics/gfxbase.h>
  25. #include <graphics/text.h>        /* For my TextAttr struct */
  26. #include <graphics/rastport.h>
  27. #include <utility/hooks.h>        /* For my stringhook */
  28.  
  29. #include <proto/wb.h>                /* For AppWindow */
  30. #include <clib/exec_protos.h>
  31. #include <clib/intuition_protos.h>
  32. #include <clib/gadtools_protos.h>
  33. #include <clib/graphics_protos.h>
  34. #include <clib/utility_protos.h>
  35. #include <string.h>
  36. #include <pragmas/exec_pragmas.h>
  37. #include <pragmas/intuition_pragmas.h>
  38. #include <pragmas/gadtools_pragmas.h>
  39. #include <pragmas/graphics_pragmas.h>
  40. #include <pragmas/utility_pragmas.h>
  41. #include <proto/textfield.h>
  42.  
  43. #include "dbGUI.h"
  44. #include "db.h"
  45. #include "dbparser.h"
  46. #include "Version.h"
  47.  
  48.  
  49. #define TOGGLE_LED *(UBYTE *)0xbfe001 ^= 2
  50.  
  51. extern Class *TextFieldClass;
  52. extern struct IFFHandle *Iff0;
  53.  
  54. struct Screen         *Scr = NULL;
  55. struct DrawInfo *DrInfo = NULL;
  56. UWORD *Pens;
  57. APTR                   VisualInfo = NULL;
  58. struct IntuiMessage    DB_Msg;
  59. UWORD                  DB_Zoom[4];
  60. struct Gadget          *LastGad = NULL;
  61. struct Hook                    MyStrHook;
  62. struct TextAttr       *Font, Attr;
  63. UWORD                  FontX, FontY;
  64. UWORD                  OffX, OffY;
  65. UWORD                  DragKnobWidth, DragKnobHeight;
  66.  
  67. WORD LastLeftEdge=-1;
  68. WORD LastTopEdge=-1;                    /* For nice layoutswitching */
  69.  
  70. /*For gadgetlayout */
  71. UWORD TabSize;
  72.  
  73. /* For MyStrHookFunc() */
  74. BOOL ReactivateGad = FALSE;
  75. BOOL GadDoubleClicked = FALSE;
  76. struct Gadget *NextGad = NULL;
  77.  
  78. struct TextAttr UserTextAttr =
  79. {
  80.     NULL, 0, FS_NORMAL, FPF_DISKFONT
  81. };
  82.  
  83.  
  84. struct NewMenu DB_NewMenu[] = {
  85.     NM_TITLE, (STRPTR)MSG_PROJECT_MENU, NULL, 0, NULL, NULL,
  86.     NM_ITEM, (STRPTR)MSG_PROJECT_NEW, NULL, 0, 0L, (APTR)DB_NEW,
  87.     NM_ITEM, (STRPTR)MSG_PROJECT_OPEN, NULL, 0, 0L, (APTR)DB_OPEN,
  88.     NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
  89.     NM_ITEM, (STRPTR)MSG_PROJECT_SAVE, NULL, 0, 0L, (APTR)DB_SAVE,
  90.     NM_ITEM, (STRPTR)MSG_PROJECT_SAVE_AS, NULL, 0, 0L, (APTR)DB_SAVEAS,
  91.     NM_ITEM, (STRPTR)MSG_PROJECT_OUTPUT, NULL, 0, NULL, NULL,
  92.     NM_SUB, (STRPTR)MSG_PROJECT_OUTPUT_VIEW, NULL, 0, 0L, (APTR)DB_OUTPUT_VIEW,
  93.     NM_SUB, (STRPTR)MSG_PROJECT_OUTPUT_VIEW_WN, NULL, 0, 0L, (APTR)DB_OUTPUT_VIEW_WN,
  94.     NM_SUB, (STRPTR)MSG_PROJECT_OUTPUT_TAB_ASCII, NULL, 0, 0L, (APTR)DB_OUTPUT_TAB_ASCII,
  95.     NM_SUB, (STRPTR)MSG_PROJECT_OUTPUT_COMMA_ASCII, NULL, 0, 0L, (APTR)DB_OUTPUT_COMMA_ASCII,
  96.     NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
  97.     NM_ITEM, (STRPTR)MSG_PROJECT_ABOUT, NULL, 0, 0L, (APTR)DB_ABOUT,
  98.     NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
  99.     NM_ITEM, (STRPTR)MSG_PROJECT_QUIT, NULL, 0, 0L, (APTR)DB_QUIT,
  100.     NM_TITLE, (STRPTR)MSG_EDIT_MENU, NULL, 0, NULL, NULL,
  101.     NM_ITEM, (STRPTR)MSG_EDIT_CUT, NULL, 0, 0L, (APTR)DB_CUT,
  102.     NM_ITEM, (STRPTR)MSG_EDIT_COPY, NULL, 0, 0L, (APTR)DB_COPY,
  103.     NM_ITEM, (STRPTR)MSG_EDIT_PASTE, NULL, 0, 0L, (APTR)DB_PASTE,
  104.     NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
  105.     NM_ITEM, (STRPTR)MSG_EDIT_ADD, NULL, 0, 0L, (APTR)DB_ADD,
  106.     NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
  107.     NM_ITEM, (STRPTR)MSG_EDIT_KILL, NULL, 0, 0L, (APTR)DB_KILL,
  108.     NM_TITLE, (STRPTR)MSG_VIEW_MENU, NULL, 0, NULL, NULL,
  109.     NM_TITLE, (STRPTR)MSG_ACTION_MENU, NULL, 0, NULL, NULL,
  110.     NM_ITEM, (STRPTR)MSG_ACTION_FIND, NULL, 0, 0L, (APTR)DB_FIND,
  111.     NM_ITEM, (STRPTR)MSG_ACTION_FIND_NEXT, NULL, 0, 0L, (APTR)DB_FINDNEXT,
  112.     NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
  113.     NM_ITEM, (STRPTR)MSG_ACTION_SORT, NULL, 0, 0L, (APTR)DB_SORT,
  114.     NM_ITEM, (STRPTR)MSG_ACTION_DIAL, NULL, 0, 0L, (APTR)DB_DIAL,
  115.     NM_ITEM, (STRPTR)MSG_ACTION_BROWSE, NULL, 0, 0L, (APTR)DB_BROWSE,
  116.     NM_TITLE, (STRPTR)MSG_SETTINGS_MENU, NULL, 0, NULL, NULL,
  117.     NM_ITEM, (STRPTR)MSG_SETTINGS_WARNINGS, NULL, CHECKIT|CHECKED|MENUTOGGLE, 0L, (APTR)DB_WARNINGS,
  118.     NM_ITEM, (STRPTR)MSG_SETTINGS_SORTDIR, NULL, 0, NULL, NULL,
  119.     NM_SUB, (STRPTR)MSG_SETTINGS_SORTDIR_AZ, NULL, CHECKIT|CHECKED, 2L, (APTR)DB_AZ,
  120.     NM_SUB, (STRPTR)MSG_SETTINGS_SORTDIR_ZA, NULL, CHECKIT, 1L, (APTR)DB_ZA,
  121.     NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
  122.     NM_ITEM, (STRPTR)MSG_SETTINGS_FIELD_DEFINITION, NULL, NM_ITEMDISABLED, 0L, (APTR)DB_FIELD_DEFINITION,
  123.     NM_ITEM, (STRPTR)MSG_SETTINGS_VIEW_DESIGN, NULL, 0L, 0L, (APTR)DB_VIEW_DESIGN,
  124.     NM_TITLE, (STRPTR)MSG_AREXX_MENU, NULL, 0, NULL, NULL,
  125.     NM_ITEM, (STRPTR)MSG_AREXX_EXECUTE, NULL, 0, 0L, (APTR)DB_EXECUTE_AREXX,
  126.     NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
  127.     NM_END, NULL, NULL, 0, 0L, NULL };
  128.  
  129.  
  130. void LocalizeMenu(struct NewMenu *nm)
  131. {
  132.     /* Replaces the string-indexes in the NewMenu array with localized text */
  133.     /* Gets called once from SetupScreen() */
  134.     UWORD    i=0;
  135.  
  136.     while (nm[i].nm_Type != NM_END) {
  137.         if (nm[i].nm_Label != NM_BARLABEL) {
  138.             nm[i].nm_CommKey = GetAppStr((LONG)nm[i].nm_Label);
  139.  
  140.             nm[i].nm_Label = nm[i].nm_CommKey+2;
  141.             if (nm[i].nm_CommKey[0] == ' ') nm[i].nm_CommKey = NULL;
  142.         }
  143.     ++i;
  144.     }
  145. }
  146. /**/
  147. __inline BOOL OkStrGad(struct Gadget *g)
  148. {
  149.     return (BOOL)(g->Flags & GFLG_TABCYCLE && !(g->Flags & GFLG_DISABLED));
  150. }
  151.  
  152. struct Gadget *PrevStrGad(struct Gadget *Gad, struct Gadget *glist)
  153. {
  154.     /* Returns the previous stringgadget, or NULL if Gad is the first one */
  155.  
  156.     struct Gadget *strgad = NULL, *g = glist;
  157.  
  158.     if (g == Gad) return NULL;
  159.     for (; g; g = g->NextGadget) {
  160.         if (OkStrGad(g)) strgad = g;    /* Only return stringgads */
  161.         if (g->NextGadget == Gad) break;
  162.     }
  163.     return strgad;
  164. }
  165.  
  166. struct Gadget *EndGad(struct Gadget *g)
  167. {
  168.     while (g->NextGadget) g = g->NextGadget;
  169.     return g;
  170. }
  171.  
  172. struct Gadget *ActivateThisGad(ULONG actions, struct Gadget *current,
  173.  struct Gadget *glist)
  174. {
  175.     /* Takes over the job of deciding which (if any) gadget should be reactivated
  176.      * based upon the SGWork->Actionfield.
  177.      * Without this function, it is impossible to activate other stringgadgets
  178.      * (as responce to an ARexx command) as Intiuition otherwize will have
  179.      * activated some other gadget first if the user cyclesteps thru a gadgetlist.
  180.     */
  181.     struct Gadget *g = NULL;
  182.  
  183.     if (actions & SGA_NEXTACTIVE) {
  184.         for (g = current->NextGadget;; g = g->NextGadget) {
  185.             if (!g) g = glist;
  186.             if (OkStrGad(g)) break;
  187.         }
  188.     }
  189.     else if (actions & SGA_PREVACTIVE) {
  190.         for (g = PrevStrGad(current, glist);; g = PrevStrGad(g, glist)) {
  191.             if (!g) g = EndGad(glist);
  192.             if (OkStrGad(g)) break;
  193.         }
  194.     }
  195.     return g;
  196. }
  197.  
  198.  
  199. /* Stuff for my stringHook */
  200.  
  201. ULONG __saveds __asm MyStrHookFunc(register __a0 struct Hook *hook,
  202.                                               register __a2 struct SGWork *sgw,
  203.                                               register __a1 ULONG *msg)
  204. {
  205.     /* This hook does the following modifications to a gadtool stringgadet:
  206.      * Pressing ESC will terminate the gadget without leaving the ESC char.
  207.      * Pressing R-Amiga+Key will terminate the gadget leaving the keycode in
  208.      * the Code field of the GadgetUp IDCMP event that will follow. It will
  209.     * also reuse the inputevent, making Intition select the corresponding menu.
  210.      * Pressing up, down, shift-up or shift-down will navigate between records.
  211.      * It also responds to the keys F1 to F10.
  212.      * Doubleclicking into a stringgadget will invoke a special function
  213.      */
  214.  
  215.     static ULONG StartSecs=0, StartMicros=0;
  216.     ULONG CurrentSecs, CurrentMicros;
  217.     ULONG return_code = ~0;
  218.  
  219.     if (*msg == SGH_KEY) {    /* Process some key event */
  220.         if ((sgw->EditOp == EO_REPLACECHAR) || (sgw->EditOp == EO_INSERTCHAR)) {
  221.             /* sgw->Code is VANILLAKEY, sgw->IEvent->ie_Code is RAWKEY */
  222.  
  223.             if (sgw->IEvent->ie_Code == RAW_ESC)    {    /* ESC pressed */
  224.                 sgw->Actions &= ~SGA_USE;    /* ~SGA_BEEP will not prevent beep :-( */
  225.                 sgw->Actions |=  SGA_END;    /* NewEdit does this */
  226.             }
  227.             else if (sgw->IEvent->ie_Qualifier &
  228.              (IEQUALIFIER_RCOMMAND | IEQUALIFIER_LCOMMAND)) {
  229.                 sgw->Actions &= ~SGA_USE;
  230.                 sgw->Actions |=  SGA_END | SGA_REUSE;
  231. /**/            ReactivateGad = TRUE;
  232.             }
  233.         }
  234.         else if (sgw->EditOp == EO_ENTER && sgw->Code != RAW_HELP) {
  235.             if (!(MyArgArray[NORETURNSTEP] ||
  236.              sgw->IEvent->ie_Qualifier & IXSYM_ALTMASK)) {
  237.                 if (sgw->IEvent->ie_Qualifier & IXSYM_SHIFTMASK) 
  238.                     sgw->Actions |= SGA_PREVACTIVE;
  239.                 else sgw->Actions |= SGA_NEXTACTIVE;
  240.             }
  241.         }
  242.         else if (sgw->EditOp == EO_NOOP) {
  243.             if (sgw->IEvent->ie_Code == RAW_DOWN || sgw->IEvent->ie_Code == RAW_UP)    {
  244.                 /* Down or up key pressed */
  245.                 sgw->Actions &= ~SGA_USE;
  246.                 sgw->Actions |=  SGA_END | SGA_REUSE;
  247.                 ReactivateGad = TRUE;
  248.             }
  249.             else if (sgw->IEvent->ie_Code == RAW_ESC)    {    /* ESC pressed */
  250.                 sgw->Actions &= ~SGA_USE;    /* ~SGA_BEEP will not prevent beep :-( */
  251.                 sgw->Actions |=  SGA_END;    /* NewEdit does this */
  252.             }
  253.             else if (sgw->IEvent->ie_Code >= RAW_F1 && sgw->IEvent->ie_Code <= RAW_F10) {
  254.                 sgw->Actions &= ~SGA_USE;
  255.                 sgw->Actions |=  SGA_END | SGA_REUSE;
  256.             }
  257.         }
  258.         if (sgw->Actions & SGA_END) {
  259.             if (NextGad = ActivateThisGad(sgw->Actions, sgw->Gadget,
  260.              sgw->GadgetInfo->gi_Window->FirstGadget))
  261.                 sgw->Actions &= ~(SGA_PREVACTIVE | SGA_NEXTACTIVE);
  262.         }
  263.     }
  264.     else if (*msg == SGH_CLICK) {                    /* Process mouse click */
  265.         CurrentSecs = sgw->IEvent->ie_TimeStamp.tv_secs;
  266.         CurrentMicros = sgw->IEvent->ie_TimeStamp.tv_micro;
  267.         
  268.         if (DoubleClick(StartSecs, StartMicros, CurrentSecs, CurrentMicros)
  269.          && sgw->BufferPos == sgw->StringInfo->BufferPos) {
  270.             /* Only allow doubleclick if user doubleclicks at the same character */
  271.             /* to avoid accidental doubleclick if user only wants to position */
  272.             /* cursor exactly */
  273.             GadDoubleClicked = TRUE;
  274.  
  275.             StartSecs = StartMicros = 0;    /* Prevent "triple clicks" */
  276.         }
  277.         else {
  278.             StartSecs = CurrentSecs;
  279.             StartMicros = CurrentMicros;
  280.         }
  281.     }
  282.     else return_code = 0;
  283.  
  284.     return return_code;
  285. }
  286.  
  287.  
  288. void InitHook(struct Hook *hook)
  289. {
  290.     hook->h_Entry = (HOOKFUNC)MyStrHookFunc;
  291.     hook->h_SubEntry = NULL;
  292.     hook->h_Data = 0;
  293. }
  294.  
  295.  
  296. int SetupScreen( void )
  297. {
  298. /*
  299.     struct Screen *s;
  300.     if (!Stricmp(MyArgArray[PUBSCREEN] "frontmost")) {
  301.         for (s = IntuitionBase->FirstScreen; s; s = s->NextScreen)
  302.             if (s->Flags & PUBLICSCREEN) 
  303.     }
  304.     else {
  305. */
  306.         if (!(Scr = LockPubScreen((STRPTR)MyArgArray[PUBSCREEN])))
  307.             if (!(Scr = LockPubScreen(NULL)))    /* Workbench */
  308.                 return( 1L );
  309. /*    } */
  310.  
  311.     if ( ! ( VisualInfo = GetVisualInfo( Scr, TAG_DONE )))
  312.         return( 2L );
  313.  
  314.     if ( ! (DrInfo = GetScreenDrawInfo(Scr)))
  315.         return 3L;
  316.     Pens = DrInfo->dri_Pens;
  317.  
  318.  
  319.     LocalizeMenu(DB_NewMenu);
  320.  
  321.     InitHook(&MyStrHook);
  322.  
  323.     return( 0L );
  324. }
  325.  
  326. void CloseDownScreen( void )
  327. {
  328.     if (DrInfo) FreeScreenDrawInfo(Scr, DrInfo);
  329.     if ( VisualInfo ) {
  330.         FreeVisualInfo( VisualInfo );
  331.         VisualInfo = NULL;
  332.     }
  333.  
  334.     if ( Scr        ) {
  335.         UnlockPubScreen( NULL, Scr );
  336.         Scr = NULL;
  337.     }
  338. }
  339.  
  340.  
  341. int HandleDB_IDCMP(struct Layout *Lay)
  342. {
  343.     struct IntuiMessage    *m;
  344.     struct MenuItem        *n;
  345.     int            (*func)(void);
  346.     struct Window *Win = Lay->Window;
  347.     struct VisFldInfo *vf;
  348.  
  349.     BOOL running = TRUE;
  350.  
  351.     while( m = GT_GetIMsg( Win->UserPort )) {
  352.  
  353.         CopyMem(( char * )m, ( char * )&DB_Msg, (long)sizeof( struct IntuiMessage ));
  354.  
  355.         GT_ReplyIMsg( m );
  356.         
  357.         switch ( DB_Msg.Class ) {
  358.         
  359.             case IDCMP_INTUITICKS:
  360.                 if (GadDoubleClicked) {
  361.                     running = DB_SpecialAction(TRUE);
  362.                     GadDoubleClicked = FALSE;
  363.                 }
  364.                 break;
  365.  
  366.             case    IDCMP_REFRESHWINDOW:
  367.                 GT_BeginRefresh(Win);
  368.                 GT_EndRefresh(Win, TRUE );
  369.                 break;
  370.  
  371.             case    IDCMP_CLOSEWINDOW:
  372.                 running = DB_CloseWindow();
  373.                 break;
  374.  
  375.             case    IDCMP_MENUHELP:
  376.                 running = DB_MenuHelp();
  377.                 break;
  378.  
  379.             case    IDCMP_NEWSIZE:
  380.                 running = DB_NewSize();
  381.                 break;
  382.  
  383.             case    IDCMP_VANILLAKEY:
  384.                 if (!(NextGad && (NextGad->Flags & GFLG_SELECTED)))
  385.                     running = DB_VanillaKey();
  386.                 break;
  387.  
  388.             case    IDCMP_RAWKEY:
  389.                 if (!(NextGad && (NextGad->Flags & GFLG_SELECTED)))
  390.                     running = DB_RawKey();
  391.                     if (running) return running;    /* The window has been closed! */
  392.                 break;
  393.  
  394.             case    IDCMP_GADGETUP:
  395.                 {
  396.                     struct Gadget *gad = (struct Gadget *)DB_Msg.IAddress;
  397.                     if (gad->GadgetID == SCROLLER_KIND) DragGadgetSelected();
  398.                     else {
  399.                         if ((gad->GadgetID == CHECKBOX_KIND) ||
  400.                              (gad->GadgetID == CYCLE_KIND)) {
  401.                             LastGad = gad;
  402.                             VisFldSelected(gad);
  403.                             vf = GetVisFldInfo(Lay, gad);
  404.                             vf->Code = DB_Msg.Code;
  405.                         }
  406.                         if (!ReactivateGad)
  407.                             running = DB_SpecialAction(FALSE);
  408.                         if (NextGad) ActivateGadget(NextGad, Win, NULL);
  409.                     }
  410.                 }
  411.                 break;
  412.  
  413.             case    IDCMP_GADGETDOWN:
  414.                 {
  415.                     struct Gadget *gad = (struct Gadget *)DB_Msg.IAddress;
  416.  
  417.                     if (gad->GadgetID == STRING_KIND || gad->GadgetID == TEXTFIELD_KIND) {
  418.                         LastGad = gad;
  419.                         VisFldSelected(gad);
  420.                     }
  421.                     else if (gad->GadgetID == SCROLLER_KIND) DragGadgetSelected();
  422.                 }
  423.                 break;
  424.  
  425.             case    IDCMP_MENUPICK:
  426.                 while( DB_Msg.Code != MENUNULL ) {
  427.                     n = ItemAddress( Win->MenuStrip, DB_Msg.Code );
  428.                     func = (int (*)(void))(GTMENUITEM_USERDATA( n ));
  429.                     running = func();
  430.                     if (running) return running;    /* The window has been closed! */
  431.                     DB_Msg.Code = n->NextSelect;
  432.                 }
  433.                 break;
  434.  
  435.             /* Added by me as GadToolBox won't do that */
  436.             case    IDCMP_MOUSEMOVE:
  437.                 DB_MouseMove();
  438.                 break;
  439.         }
  440.     }
  441.     if (ReactivateGad) ReactivateGad = FALSE;
  442.     return( running );
  443. }
  444.  
  445. void DeleteSoftMenu(struct SoftMenu *sm)
  446. {
  447.     if (sm->Items) FreeMenus((struct Menu *)sm->Items);
  448.     sm->Items = NULL;
  449.     if (sm->NewItems) FreeMem(sm->NewItems, sm->NewItemsNum * sizeof(struct NewMenu));
  450.     sm->NewItems = NULL;
  451.     sm->NewItemsNum = 0;
  452. }
  453.  
  454. void CloseMenu(struct Pro *Pr)
  455. {
  456.     /* Frees all memory allocated by OpenMenu() */
  457.  
  458.     if (Pr->Menu) FreeMenus(Pr->Menu);
  459.     Pr->Menu = NULL;
  460.     DeleteSoftMenu(&Pr->ViewMenu);
  461.     DeleteSoftMenu(&Pr->ARexxMenu);
  462. }
  463.  
  464. int AddViewMenu(struct Pro *Pr)
  465. {
  466.     int n;
  467.     struct Layout *Lay;
  468.  
  469.     /* Count how many layouts there are */
  470.     for (n=0, Lay=Pr->FirstLayout; Lay; Lay=Lay->NextLayout, n++);
  471.     if (!n) return 0;    /* No layouts at all. Extra safety */
  472.  
  473.     Pr->ViewMenu.NewItemsNum = n+1;    /* One extra array-closing item */
  474.     /* Allocate memory for the NewMenu structs */
  475.     if (!(Pr->ViewMenu.NewItems =
  476.      AllocMem(Pr->ViewMenu.NewItemsNum * sizeof(struct NewMenu), MEMF_CLEAR))) return MEM_ERR;
  477.  
  478.     /* Fill in the NewMenu structs */
  479.     for (n=0, Lay=Pr->FirstLayout; Lay; Lay=Lay->NextLayout, n++) {
  480.         Pr->ViewMenu.NewItems[n].nm_Type = NM_ITEM;
  481.         Pr->ViewMenu.NewItems[n].nm_Label = (STRPTR)Lay->Name;
  482.         Pr->ViewMenu.NewItems[n].nm_Flags = CHECKIT;
  483.         Pr->ViewMenu.NewItems[n].nm_MutualExclude = ~(1<<n);
  484.         Pr->ViewMenu.NewItems[n].nm_UserData = (APTR)DB_VIEW;
  485.     }
  486.     Pr->ViewMenu.NewItems[n].nm_Type = NM_END;
  487.     Pr->ViewMenu.NewItems[0].nm_Flags |= CHECKED;
  488.  
  489.     if (!(Pr->ViewMenu.Items = (struct MenuItem *)CreateMenus(Pr->ViewMenu.NewItems, TAG_DONE))) return MENU_ERR;
  490.     Pr->Menu->NextMenu->NextMenu->FirstItem = Pr->ViewMenu.Items;    /* Link in */
  491.     return 0;    /* ok */
  492. }
  493.  
  494. int AddARexxMenu(struct Pro *Pr)
  495. {
  496.     int n;
  497.     struct RxInfo *ri;
  498.     struct RFFTag *tag;
  499.     char *label;
  500.  
  501.     /* Count how many ARexx items there are */
  502.     for (n=0, ri=Pr->FirstRxInfo; ri; ri=ri->Next, n++);
  503.     if (n < 2) return 0;    /* No ARexx menu items at all (The global RFF data is in the first node). */
  504.  
  505.     Pr->ARexxMenu.NewItemsNum = n;    /* One extra array-closing item */
  506.     /* Allocate memory for the NewMenu structs */
  507.     if (!(Pr->ARexxMenu.NewItems =
  508.      AllocMem(Pr->ARexxMenu.NewItemsNum * sizeof(struct NewMenu), MEMF_CLEAR))) return MEM_ERR;
  509.  
  510.     /* Fill in the NewMenu structs */
  511.     for (n=0, ri=Pr->FirstRxInfo->Next; ri; ri=ri->Next, n++) {
  512.         Pr->ARexxMenu.NewItems[n].nm_Type = NM_ITEM;
  513.         if (!(tag = FindTag(&ri->RxTags, NAME)) && !(tag = FindTag(&ri->RxTags, RXFILE)))
  514.             label = "« error »";
  515.         else label = tag->Data;
  516.         Pr->ARexxMenu.NewItems[n].nm_Label = (STRPTR)label;
  517.         Pr->ARexxMenu.NewItems[n].nm_UserData = (APTR)DB_AREXX;
  518.     }
  519.     Pr->ARexxMenu.NewItems[n].nm_Type = NM_END;
  520.  
  521.     if (!(Pr->ARexxMenu.Items = (struct MenuItem *)CreateMenus(Pr->ARexxMenu.NewItems, TAG_DONE))) return MENU_ERR;
  522.     Pr->Menu->NextMenu->NextMenu->NextMenu->NextMenu->NextMenu->
  523.     FirstItem->NextItem->NextItem = Pr->ARexxMenu.Items;    /* Link in */
  524.     return 0;    /* ok */
  525. }
  526.  
  527. int OpenMenu(struct Pro *Pr)
  528. {
  529.     /* Builds a complete menu including the variable View menu */
  530.     int err;
  531.  
  532.     if (!(Pr->Menu = CreateMenus(DB_NewMenu, TAG_DONE))) return MENU_ERR;
  533.  
  534.     if (err = AddViewMenu(Pr)) {
  535.         CloseMenu(Pr);
  536.         return err;
  537.     }
  538.     if (err = AddARexxMenu(Pr)) {
  539.         CloseMenu(Pr);
  540.         return err;
  541.     }
  542.     LayoutMenus(Pr->Menu, VisualInfo, GTMN_NewLookMenus, TRUE, TAG_DONE );
  543.     return 0;
  544. }
  545.  
  546. void GadSpace(struct VisFldInfo *vf, struct RastPort *rp)
  547. {
  548.     /* Calculate the offset and size of a vf info vf->Pos. */
  549.    /* Take space for the gadgets name into account */
  550.     /* If rp is NULL then topaz 8 is assumed */
  551.  
  552.     int len;
  553.     char *buffer, *bufp, *namep;
  554.     int diff, rows;
  555.     struct RFFTag *tag;
  556.  
  557.     vf->Pos.YOffset = vf->Pos.XOffset = 0;
  558.     vf->Label.LeftEdge = vf->Label.TopEdge = 0;    /* textfield gadget */
  559.     
  560.     tag = SearchTag(CurrentPro, vf, NULL, PLACE);
  561.     if (tag && !Stricmp(tag->Data, "above")) {        /* Title is above gadget */
  562.         vf->Pos.YOffset = FontY + (FontY >> 1);    /* Seems to look nice */
  563.         vf->Label.TopEdge = -vf->Pos.YOffset;        /* textfield gadget */
  564.     }
  565.     else {    /* Title is to the left of gadget */
  566.         /* gadgetname size */
  567.         len = strlen(vf->Name);
  568.         if (!(buffer = AllocMem(len+1,0))) return;    /* mem fail */
  569.  
  570.         /* Strip underscore _ in gadetname for correct length */
  571.         for (bufp = buffer, namep = vf->Name;; namep++) {
  572.             if (*namep != '_') *bufp++ = *namep;
  573.             if (!(*namep)) break;    /* Also copy the \0 char */
  574.         }
  575.         if (rp) vf->Pos.XOffset = TextLength(rp,buffer,strlen(buffer));
  576.         else vf->Pos.XOffset = FontX * strlen(buffer);    /* Topaz 8 */
  577.         FreeMem(buffer, len+1);
  578.         if (vf->Pos.XOffset) vf->Pos.XOffset += FontX;            /* If vf->name, add extra space */
  579.         vf->Label.LeftEdge = -vf->Pos.XOffset;    /* textfield gadget */
  580.     }
  581.  
  582.     vf->Pos.Width = FontX * (vf->VisLen + 2);
  583.     diff = vf->Pos.XOffset % FontX;
  584.     if (diff) vf->Pos.XOffset += FontX - diff;        /* Snap to next FontX tick */
  585.  
  586.     tag = SearchTag(CurrentPro, vf, NULL, ROWS);
  587.     if (tag && (rows = atoi(tag->Data))) {
  588.         vf->Pos.Height = FontY * rows + STRGADFRAMESHEIGHT;
  589.     }
  590.     else vf->Pos.Height = FontY + STRGADFRAMESHEIGHT;
  591. }
  592.  
  593.  
  594. __inline WORD LineOffset(struct VisFldInfo *vf)
  595. {
  596.     /* Return the maximum Y offset needed for a line of visual fields */
  597.     WORD oldmax = 0;
  598.     
  599.     for (; vf; vf = vf->Next) {
  600.         if (vf->Pos.YOffset > oldmax) oldmax = vf->Pos.YOffset;
  601.         if (vf->VisSep == '\n' || vf->VisSep == '\f') break;
  602.     }
  603.     return oldmax;
  604. }
  605.  
  606. __inline BOOL EndOfLine(struct VisFldInfo *vf)
  607. {
  608.     return (BOOL)(vf->VisSep == '\n' || vf->VisSep == '\f' || !vf->Next);
  609. }
  610.  
  611. BOOL CalcPos(struct Layout *Lay, struct Space *GLim, WORD *ww, WORD *wh,
  612.  struct RastPort *rp)
  613. {
  614.     struct VisFldInfo *vf;
  615.     WORD curX = 0, curY = 0;
  616.     BOOL firstCol = TRUE;
  617.     int stepsize = 0;
  618.     WORD maxheight = 0;
  619.     
  620.     GLim->XOffset = GLim->Width = GLim->YOffset = GLim->Height = 0;
  621.  
  622.     /* First set each vf's local offset and size */
  623.     for (vf = Lay->FirstVisFldInfo; vf; vf = vf->Next)
  624.         GadSpace(vf, rp);
  625.  
  626.     /* Now adjust all vf's according to one another */
  627.     for (vf = Lay->FirstVisFldInfo; vf; vf = vf->Next) {
  628.  
  629.         if (firstCol) {
  630.             curY += LineOffset(vf);    /* This line's max Y offset */
  631.             if (vf->Pos.XOffset > GLim->XOffset) GLim->XOffset = vf->Pos.XOffset;
  632.             vf->Pos.XOffset = 0;        /* It will be added later */
  633.         }
  634.         vf->Pos.XOffset += curX;
  635.         vf->Pos.YOffset = curY;
  636.  
  637.         if (stepsize) {
  638.             vf->Pos.XOffset += stepsize - vf->Pos.XOffset % stepsize;
  639.             stepsize = 0;
  640.         }
  641.  
  642.         if (vf->Pos.XOffset + vf->Pos.Width > GLim->Width)
  643.             GLim->Width = vf->Pos.XOffset + vf->Pos.Width;
  644.         
  645.         if (vf->Pos.Height > maxheight) maxheight = vf->Pos.Height;
  646.  
  647.         if (EndOfLine(vf)) {
  648.             firstCol = TRUE;
  649.             curX = 0;
  650.             curY += maxheight;
  651.             GLim->Height = curY;
  652.             maxheight = 0;    
  653.         }
  654.         switch (vf->VisSep) {
  655.             case ' ':
  656.                 curX = vf->Pos.XOffset + vf->Pos.Width + FontX;
  657.                 firstCol = FALSE;
  658.                 stepsize = 0;
  659.                 break;
  660.             case '\t':
  661.                 curX = vf->Pos.XOffset + vf->Pos.Width + FontX;
  662.                 stepsize = TabSize * FontX;
  663.                 firstCol = FALSE;
  664.                 break;
  665.             case '\f':
  666.                 curY += (FontY * 3 >> 1);    /* Looks nice */
  667.                 break;
  668.             case '\n':
  669.             default:
  670.                 curY += (FontY * 3 >> 3); /* Looks nice */
  671.                 break;
  672.         }
  673.     }
  674.     GLim->Width += GLim->XOffset;
  675.     *ww = OffX + (FontX << 1) + GLim->Width + Scr->WBorRight;
  676.     *wh = OffY + FontY + GLim->Height + Scr->WBorBottom;
  677.     if (MyArgArray[HORIZBAR]) *wh += DragKnobHeight;
  678.     else *ww += DragKnobWidth;
  679.  
  680.     return TRUE;
  681. }
  682.  
  683. void DeleteAllGadgets(struct Layout *Lay, char mode)
  684. {
  685.     struct VisFldInfo *vf;
  686.     struct Gadget *g;
  687.  
  688.     /* Relink the gadgetborders we deleted for sake of speed */
  689.     if (mode == USE_MODE && Lay->FirstSR) SpeedRenderOff(Lay);    /* FirstSR will be cleared */
  690.  
  691.     if (Lay->GList) {
  692.         if (mode == USE_MODE && Lay->Window) RemoveGList(Lay->Window, Lay->GList, -1);
  693.  
  694.         /* Remove objects first */
  695.         for (g = Lay->GList; g && g->NextGadget; g = g->NextGadget) {
  696.             if (g->NextGadget->GadgetID == TEXTFIELD_KIND) {
  697.                 DisposeObject(g->NextGadget);
  698.                 g->NextGadget = g->NextGadget->NextGadget;    /* Objects shall not be freed by FreeGadgets */
  699.             }
  700.         }
  701.         FreeGadgets(Lay->GList);
  702.         Lay->GList = NULL;
  703.     }
  704.     for (vf = Lay->FirstVisFldInfo; vf; vf = vf->Next) {
  705.         vf->Gadget = NULL;
  706.         vf->Code = 0;
  707.     }
  708.     LastGad = NULL;
  709. }
  710.  
  711. void CloseLayWin(struct Pro *Pr, struct Layout *Lay)
  712. {
  713.     CloseSelect(CurrentPro->CurrentLayout->Browser);
  714.     RemoveAllStrings(CurrentPro->CurrentLayout->Browser);
  715.  
  716.     DeleteAllGadgets(Lay, USE_MODE);
  717.     if (Lay->Window) {
  718.         /* Remember old window pos */
  719.         LastLeftEdge = Lay->Window->LeftEdge;
  720.         LastTopEdge = Lay->Window->TopEdge;
  721.         /* AppWindow specifics */
  722.         if (Lay->AppWin) RemoveAppWindow(Lay->AppWin);
  723.         Lay->AppWin = NULL;
  724.         ClearMenuStrip(Lay->Window);
  725.         CloseWindow(Lay->Window);
  726.         Lay->Window = NULL;
  727.     }
  728. }
  729.  
  730. void AdjustVars(struct RastPort *rp)
  731. {
  732.     /* Supportfunction to simplify OpenLayWin */
  733.     if (rp) {
  734.         Font->ta_Name = (STRPTR)rp->Font->tf_Message.mn_Node.ln_Name;
  735.         Font->ta_YSize = FontY = rp->Font->tf_YSize;
  736.         FontX = rp->Font->tf_XSize;
  737.     }
  738.     else {
  739.         Font->ta_Name = (STRPTR)"topaz.font";
  740.         FontX = FontY = Font->ta_YSize = 8;
  741.     }
  742.     DragKnobHeight = FontY;
  743.     if (DragKnobHeight < 12) DragKnobHeight = 12;
  744.     DragKnobWidth = (DragKnobHeight * 5) >> 2;
  745. }
  746.  
  747. int CalcAllPos(struct Pro *Pr, struct Layout *Lay, WORD *ww, WORD *wh)
  748. {
  749.     /* Calculate the position of all gadgets and put the final windowsize in ww and wh */
  750.     struct RastPort *rp = &Scr->RastPort, *myrp=NULL;
  751.     struct RFFTag *tag;
  752.     struct Space GLim;    /* "rectangle" that gadgets are to be drawn within */
  753.     struct VisFldInfo *vf;
  754.  
  755.     if (UserTextFont) {
  756.         /* Alloc and init a dummy RastPort for TextLength() with custom fonts */
  757.         if (!(myrp = AllocMem(sizeof(struct RastPort),0))) return MEM_ERR;
  758.         InitRastPort(myrp);
  759.         SetFont(myrp,UserTextFont);
  760.         rp = myrp;
  761.     }
  762.  
  763.     Font = &Attr;
  764.     OffX = Scr->WBorLeft;
  765.     OffY = Scr->RastPort.TxHeight + Scr->WBorTop + 1;
  766.  
  767.     /* Get the tabsize from the taglist */
  768.     if (tag = FindTag(&Lay->LayTags, TABSIZE))
  769.         TabSize = atoi(tag->Data);
  770.     else TabSize = DEFTABSIZE;
  771.  
  772.     AdjustVars(rp);
  773.     CalcPos(Lay, &GLim, ww, wh, rp); 
  774.     if (myrp) FreeMem(myrp, sizeof(struct RastPort));
  775.  
  776.     if ((*ww>Scr->Width || *wh>Scr->Height) && UserTextFont) { /* Try screen font */
  777.         rp = &Scr->RastPort;
  778.         AdjustVars(rp);
  779.         CalcPos(Lay, &GLim, ww, wh, rp);
  780.     }
  781.         
  782.     if (*ww > Scr->Width || *wh > Scr->Height) {    /* Try Topaz 8 */
  783.         AdjustVars(NULL);
  784.         CalcPos(Lay, &GLim, ww, wh, NULL); 
  785.         if (*ww > Scr->Width || *wh > Scr->Height) return WINSIZE_ERR;
  786.     }
  787.     
  788.     /* Finally add GLim's offsets to all gadgets */
  789.     for (vf = Lay->FirstVisFldInfo; vf; vf = vf->Next) {
  790.         vf->Pos.XOffset += OffX + FontX + GLim.XOffset;
  791.         vf->Pos.YOffset += OffY + (FontY >> 1) + GLim.YOffset;
  792.     }
  793.  
  794.     /* Window specifics */
  795.     DB_Zoom[0] = 0;
  796.     DB_Zoom[1] = OffY;
  797.     DB_Zoom[2] =
  798.      TextLength( &Scr->RastPort, (UBYTE *)Pr->Name, strlen((char *)Pr->Name))
  799.      + TextLength( &Scr->RastPort, (UBYTE *)Lay->Name, strlen((char *)Lay->Name))
  800.      + FontX + 80;
  801.     DB_Zoom[3] = Scr->WBorTop + Scr->RastPort.TxHeight + 1;
  802.     
  803.     /* Make sure window is not too small */
  804.     if (*ww < (DB_Zoom[2] + 8 * FontX)) *ww = DB_Zoom[2] + 8 * FontX;
  805.     if (*wh < DragKnobHeight * 5) {
  806.         if (!Lay->FirstVisFldInfo) *wh = 10 * DragKnobHeight;
  807.         else *wh = 5 * DragKnobHeight;
  808.     }
  809.     return 0;
  810. }
  811.  
  812. int CreateAllGadgets(struct Pro *Pr, struct Layout *Lay, WORD ww, WORD wh, char mode)
  813. {
  814.     /* Create all gadgets with sizes, and positions fixed by CalcAllPos() */
  815.     struct FldInfo *f;
  816.     struct VisFldInfo *vf;
  817.     struct Gadget *g;
  818.     struct NewGadget ng;
  819.     struct RFFTag *tag;
  820.     struct RFFTag *sfmt; /* String format (left, right, center etc) */
  821.     LONG justification;    /* String format (left, right, center etc) */
  822.  
  823.     if (!(g = CreateContext(&Lay->GList))) return GAD_ERR;
  824.  
  825.     ng.ng_TextAttr = Font;
  826.     ng.ng_VisualInfo = VisualInfo;
  827.     ng.ng_UserData = 0;
  828.  
  829.     /* The drag gadget. (No dragbar in design mode) */
  830.     if (mode == USE_MODE) {
  831.         ng.ng_GadgetText = NULL;
  832.         ng.ng_GadgetID = SCROLLER_KIND;    /* For our information, from gadtools.h */
  833.         ng.ng_Flags = 0;
  834.  
  835.         if (MyArgArray[HORIZBAR]) {
  836.             ng.ng_LeftEdge = Scr->WBorLeft;
  837.             ng.ng_TopEdge = wh - Scr->WBorBottom - DragKnobHeight;
  838.             ng.ng_Width = ww - (Scr->WBorLeft + Scr->WBorRight);
  839.             ng.ng_Height = DragKnobHeight;
  840.  
  841.             Lay->DragGad = g = CreateGadget(SCROLLER_KIND, g, &ng,
  842.                 GTSC_Total, 1,
  843.                 GTSC_Arrows, DragKnobWidth,
  844.                 PGA_Freedom, LORIENT_HORIZ,
  845.                 GA_Immediate, TRUE,
  846.                 GA_RelVerify, TRUE,
  847.                 TAG_DONE
  848.             );
  849.         }
  850.         else {
  851.             ng.ng_LeftEdge = ww - Scr->WBorRight - DragKnobWidth;
  852.             ng.ng_TopEdge = OffY;
  853.             ng.ng_Width = DragKnobWidth;
  854.             ng.ng_Height = wh - OffY - Scr->WBorBottom;
  855.  
  856.             Lay->DragGad = g = CreateGadget(SCROLLER_KIND, g, &ng,
  857.                 GTSC_Total, 1,
  858.                 GTSC_Arrows, DragKnobHeight,
  859.                 PGA_Freedom, LORIENT_VERT,
  860.                 GA_Immediate, TRUE,
  861.                 GA_RelVerify, TRUE,
  862.                 TAG_DONE
  863.             );
  864.         }
  865.     } /* end-if RUN-MODE */
  866.  
  867.     /* The other gadgets */
  868.     for (vf = Lay->FirstVisFldInfo; vf; vf = vf->Next) {
  869.  
  870.         if (!(f = GetFldInfo(Pr, vf->Offset))) return RFF_ERR;
  871.  
  872.         ng.ng_LeftEdge = vf->Pos.XOffset;
  873.         ng.ng_TopEdge = vf->Pos.YOffset;
  874.         ng.ng_Width = vf->Pos.Width;
  875.         ng.ng_Height = vf->Pos.Height;
  876.         ng.ng_GadgetText = vf->Name;
  877.  
  878.         tag = SearchTag(CurrentPro, vf, NULL, PLACE);
  879.         if (tag && !Stricmp(tag->Data, "above")) /* Title is above gadget */
  880.             ng.ng_Flags = PLACETEXT_ABOVE;
  881.         else ng.ng_Flags = PLACETEXT_LEFT;
  882.  
  883.         if (MyArgArray[HIGHLABEL]) ng.ng_Flags |= NG_HIGHLABEL;
  884.  
  885.         tag = SearchTag(CurrentPro, vf, NULL, FTYP);
  886.  
  887.         if (tag && !Stricmp(tag->Data, "checkbox"))
  888.         {
  889.             Lay->ComplexGadgets = TRUE;    /* For UpdateGadgets() */
  890.             ng.ng_Width = (ng.ng_Height * 3) >> 1;
  891.             ng.ng_GadgetID = CHECKBOX_KIND;    /* For our information, from gadtools.h */
  892.             vf->Gadget = g = CreateGadget(CHECKBOX_KIND, g, &ng,
  893.                 GT_Underscore, '_',
  894.                 GTCB_Scaled, TRUE,
  895.                 TAG_DONE
  896.             );
  897.         }
  898.         else if (tag && !Stricmp(tag->Data, "cycle"))
  899.         {
  900.             Lay->ComplexGadgets = TRUE;    /* For UpdateGadgets() */
  901.             ng.ng_GadgetID = CYCLE_KIND;    /* For our information, from gadtools.h */
  902.             vf->Gadget = g = CreateGadget(CYCLE_KIND, g, &ng,
  903.                 GT_Underscore, '_',
  904.                 GTCY_Labels, vf->CEnt,
  905.                 TAG_DONE
  906.             );
  907.         }
  908.         else if (tag && !Stricmp(tag->Data, "text"))
  909.         {
  910.             Lay->ComplexGadgets = TRUE;    /* For UpdateGadgets() */
  911.             ng.ng_GadgetID = TEXT_KIND;    /* For our information, from gadtools.h */
  912.             justification = GTJ_LEFT;
  913.             if (sfmt = SearchTag(CurrentPro, vf, NULL, SFMT)) {
  914.                 if (!Stricmp(sfmt->Data, "right")) justification = GTJ_RIGHT;
  915.                 else if (!Stricmp(sfmt->Data, "center")) justification = GTJ_CENTER;
  916.             }
  917.             vf->Gadget = g = CreateGadget(TEXT_KIND, g, &ng,
  918.                 GTTX_Justification, justification,
  919.                 GT_Underscore, '_',
  920.                 GTTX_Clipped, TRUE,
  921.                 GTTX_Border, TRUE,
  922.                 GTTX_CopyText, TRUE,
  923.                 TAG_DONE
  924.             );
  925.         }
  926.         else if (tag && !Stricmp(tag->Data, "textfield") && TextFieldClass) {
  927.             long bordertype = TEXTFIELD_BORDER_DOUBLEBEVEL;
  928.  
  929.             vf->Label.FrontPen = MyArgArray[HIGHLABEL] ? Pens[HIGHLIGHTTEXTPEN] : Pens[TEXTPEN];
  930.  
  931.             Lay->ComplexGadgets = TRUE;    /* For UpdateGadgets() */
  932.             if (MyArgArray[NOBORDER]) bordertype = TEXTFIELD_BORDER_NONE;
  933.             justification = TEXTFIELD_ALIGN_LEFT;
  934.             if (sfmt = SearchTag(CurrentPro, vf, NULL, SFMT)) {
  935.                 if (!Stricmp(sfmt->Data, "right")) justification = TEXTFIELD_ALIGN_RIGHT;
  936.                 else if (!Stricmp(sfmt->Data, "center")) justification = TEXTFIELD_ALIGN_CENTER;
  937.             }
  938.             vf->Gadget = g = NewObject(TextFieldClass, NULL,
  939.                                     GA_ID,                TEXTFIELD_KIND,
  940.                                     GA_Left,                ng.ng_LeftEdge,
  941.                                     GA_Top,                ng.ng_TopEdge,
  942.                                     GA_Width,            ng.ng_Width,
  943.                                     GA_Height,            ng.ng_Height,
  944.                                     GA_Previous,        g,
  945.                                     GA_TabCycle,        TRUE,
  946.                                     GA_IntuiText,        &vf->Label,
  947.                                     TEXTFIELD_ClipStream,    Iff0->iff_Stream,
  948.                                     TEXTFIELD_Border,            bordertype,
  949.                                     TEXTFIELD_Alignment,        justification,
  950.                                     TEXTFIELD_MaxSize,        f->Len,
  951.                                     TEXTFIELD_TextAttr,        (ULONG)Font,
  952.                                     TEXTFIELD_BlockCursor,    TRUE,
  953.                                     TEXTFIELD_PassCommand,    TRUE,
  954.                                     TAG_END);
  955.             vf->Gadget->Activation |= GACT_IMMEDIATE; /* To get gadgetdown events */
  956.         }
  957.         else {            /* Assume string type as default */
  958.             ng.ng_GadgetID = STRING_KIND;    /* For our information, from gadtools.h */
  959.  
  960.             /* Handle string formatting */
  961.             justification = STRINGLEFT;
  962.             if (sfmt = SearchTag(CurrentPro, vf, NULL, SFMT)) {
  963.                 if (!Stricmp(sfmt->Data, "right")) justification = STRINGRIGHT;
  964.                 else if (!Stricmp(sfmt->Data, "center")) justification = STRINGCENTER;
  965.             }
  966.             
  967.             vf->Gadget = g = CreateGadget(STRING_KIND, g, &ng,
  968.                 STRINGA_ExitHelp, TRUE,
  969.                 GTST_MaxChars, f->Len,
  970.                 STRINGA_Justification, justification,
  971.                 GT_Underscore, '_',
  972.                 GTST_EditHook, &MyStrHook,
  973.                 TAG_DONE
  974.             );
  975.             vf->Gadget->Activation |= GACT_IMMEDIATE; /* To get gadgetdown events */
  976.         }                                                            /* GA_Immediate tag is v39  */
  977.     }
  978.  
  979.     if (Lay->FirstVisFldInfo) LastGad = Lay->FirstVisFldInfo->Gadget;
  980.     else LastGad = NULL;
  981.  
  982.     return 0;
  983. }
  984.  
  985. int AttachAllGadgets(struct Layout *Lay, WORD ww, WORD wh, char mode)
  986. {
  987.     /* Attach all gadgets to an already opened window, and size the window accordingly */
  988.     /* Use DoOpenLayWindow() instead if window is closed */
  989.  
  990.     struct IntuiMessage    *m;
  991.     ULONG class;
  992.     WORD clearw, clearh;    // Just so we don't clear more than neccesary.
  993.  
  994.     clearw = (Lay->Window->Width < ww) ? Lay->Window->Width : ww;
  995.     clearh = (Lay->Window->Height < wh) ? Lay->Window->Height : wh;
  996.  
  997.     /* Resize (and maybe move) window */
  998. //    Lay->Window->Flags |= WFLG_SIMPLE_REFRESH;    /* Speed */
  999.     {
  1000.         WORD x = (Lay->XPos >= 0) ? Lay->XPos : Lay->Window->LeftEdge;
  1001.         WORD y = (Lay->YPos >= 0) ? Lay->YPos : Lay->Window->TopEdge;
  1002.         ChangeWindowBox(Lay->Window, x, y, ww, wh);
  1003.     }
  1004.     /* The action is delayed until I get a IDCMP_NEWSIZE message. Ugly! */
  1005.     for (;;) {
  1006.         WaitPort(Lay->Window->UserPort);
  1007.         while( m = GT_GetIMsg( Lay->Window->UserPort )) {
  1008.             class = m->Class;
  1009.             GT_ReplyIMsg(m);
  1010.             if (class == IDCMP_NEWSIZE) goto SIZEOK;
  1011.         }
  1012.     }
  1013.     SIZEOK:
  1014. //    Lay->Window->Flags &= ~WFLG_SIMPLE_REFRESH;    /* Speed */
  1015.  
  1016.     if (mode == USE_MODE && MyArgArray[NOBORDER]) {
  1017.         MyArgArray[NOSPEEDRENDER] = FALSE;
  1018.         if (!SpeedRenderOn(Lay)) ByeBye();
  1019.     }
  1020.  
  1021.     AddGList(Lay->Window, Lay->GList, -1, -1, NULL);
  1022.  
  1023.     /* Clear old gadget imagery */
  1024.     EraseRect(Lay->Window->RPort, Lay->Window->BorderLeft, Lay->Window->BorderTop,
  1025.      clearw - Lay->Window->BorderRight-1, clearh - Lay->Window->BorderBottom-1);
  1026.  
  1027. //    RefreshWindowFrame(Lay->Window);
  1028.     RefreshGList(Lay->GList, Lay->Window, NULL, -1);
  1029.     GT_RefreshWindow( Lay->Window, NULL ); /* Must also be called. Works fine without however */
  1030.  
  1031.     if (mode == DESIGN_MODE)
  1032.         RemoveGList(Lay->Window, Lay->GList, -1);
  1033.  
  1034.     else if (!MyArgArray[NOBORDER])
  1035.         if (!SpeedRenderOn(Lay)) ByeBye();
  1036.  
  1037.     return 0;
  1038. }
  1039.  
  1040.  
  1041. int DoOpenLayWindow(struct Pro *Pr, struct Layout *Lay, WORD ww, WORD wh)
  1042. {
  1043.     /* Does the actual opening (in USE_MODE) */
  1044.     WORD leftedge, topedge;
  1045.  
  1046.     if (MyArgArray[NOBORDER]) {
  1047.         MyArgArray[NOSPEEDRENDER] = FALSE;
  1048.         if (!SpeedRenderOn(Lay)) ByeBye();
  1049.     }
  1050.  
  1051.     /* Position window nicely */
  1052.     if (LastLeftEdge == -1) {    /* No previous window to use */
  1053.         leftedge = (Scr->Width - ww) >> 1;    /* Middle */
  1054.         topedge = (Scr->Height - wh) >> 1;    /* Middle */
  1055.     }
  1056.     else {
  1057.         leftedge = LastLeftEdge;
  1058.         topedge = LastTopEdge;
  1059.     }
  1060.     if (Lay->XPos != -1) leftedge = Lay->XPos;
  1061.     if (Lay->YPos != -1)    topedge = Lay->YPos;
  1062.  
  1063.     if ( ! ( Lay->Window = OpenWindowTags( NULL,
  1064.                 WA_Left,       leftedge,
  1065.                 WA_Top,        topedge,
  1066.                 WA_Width,    ww,
  1067.                 WA_Height,    wh,
  1068.                 WA_IDCMP,    STRINGIDCMP|SCROLLERIDCMP|ARROWIDCMP|IDCMP_NEWSIZE|IDCMP_MENUPICK|IDCMP_CLOSEWINDOW|IDCMP_RAWKEY|IDCMP_VANILLAKEY|IDCMP_MENUHELP|IDCMP_REFRESHWINDOW,
  1069.                 WA_Flags,    WFLG_NEWLOOKMENUS|WFLG_DRAGBAR|WFLG_DEPTHGADGET|WFLG_CLOSEGADGET|WFLG_SMART_REFRESH|WFLG_ACTIVATE,
  1070.                 WA_Gadgets,    Lay->GList,
  1071.                 WA_Title,    Lay->Title,
  1072.                 WA_ScreenTitle,    "db v" VERSION_NUMBER "  ©1997 David Ekholm, Datadosen",
  1073.                 WA_PubScreen,    Scr,
  1074.                 WA_Zoom,    DB_Zoom,
  1075.                 WA_MenuHelp, TRUE,
  1076.                 TAG_DONE )))
  1077.     return WIN_ERR;
  1078.  
  1079.     if (!Pr->Menu) OpenMenu(Pr);
  1080.     SetMenuStrip(Lay->Window, Pr->Menu);
  1081.  
  1082.     GT_RefreshWindow( Lay->Window, NULL);
  1083.     /* AppWindow specifics */
  1084.     Lay->AppWin = AddAppWindow(1, 1, Lay->Window, AWPort, NULL);
  1085.     /* End of AppWindow specifics */
  1086.  
  1087.     /* We delete the reference to the gadget borders to double the update speed */
  1088.     /* We relink the information before windowclosing so that memory is freed */
  1089.     if (!MyArgArray[NOBORDER])
  1090.         if (!SpeedRenderOn(Lay)) ByeBye();
  1091.  
  1092.     /* For IDCMP handling used in this file and in main() */
  1093.     WinSig = 1L << Lay->Window->UserPort->mp_SigBit;
  1094.  
  1095.     return 0;
  1096. }
  1097.  
  1098.  
  1099. int OpenLayWin(struct Pro *Pr, struct Layout *Lay)
  1100. {
  1101.     /* Frontend function for the old db code */
  1102.     int ret;
  1103.     WORD ww, wh; /* Final window width and height */
  1104.     
  1105.     if ((ret = CalcAllPos(Pr, Lay, &ww, &wh)) < 0) return ret;
  1106.     if ((ret = CreateAllGadgets(Pr, Lay, ww, wh, USE_MODE)) < 0) return ret;
  1107.     if ((ret = DoOpenLayWindow(Pr, Lay, ww, wh)) < 0) return ret;
  1108.     return 0;
  1109. }