home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 19 / AACD19.BIN / AACD / System / SnoopDos / SnoopDos_Src / SnoopDos_Source / subwin.c < prev    next >
C/C++ Source or Header  |  2001-02-04  |  185KB  |  3,853 lines

  1. /*
  2.  *              SUBWIN.C                                                                                        vi:ts=4
  3.  *
  4.  *      Copyright (c) Eddy Carroll, September 1994.
  5.  *
  6.  *              This module handles all the windows other than the main window.
  7.  *              That is, the functions window, settings window and format
  8.  *              window.
  9.  */             
  10.  
  11. #include "system.h"
  12. #include "snoopdos.h"
  13. #include "gui.h"
  14.  
  15. #if 0
  16. #define DB(s)   KPrintF(s)
  17. #else
  18. #define DB(s)
  19. #endif
  20.  
  21. /*
  22.  *              These are used by all the requesters to decide what options to do
  23.  *              when leaving a requester (make current settings permanent or
  24.  *              restore the old settings)
  25.  */
  26. #define SEL_NONE                0               /* User didn't select an option yet             */
  27. #define SEL_USE                 1               /* User selected USE in a requester             */
  28. #define SEL_CANCEL              2               /* User selected CANCEL in a requester  */
  29.  
  30. /*
  31.  *              These control which items are displayed in the System and DOS
  32.  *              columns in the function window.
  33.  */
  34. #define COL_SELECTED    0               /* Column shows selected items                  */
  35. #define COL_ALL                 1               /* Column shows all items                               */
  36. #define COL_NONE                2               /* Column shows no items                                */
  37.  
  38. #define SETBUTTON_FILE  0               /* Little image of a file folder                */
  39. #define SETBUTTON_FONT  1               /* Little image of a font folder                */
  40. #define SETBUTTON_MAX   2               /* Anything above this is a string ID   */
  41.  
  42. /*
  43.  *              These two are imported from SNOOPDOS.C
  44.  */
  45. extern char     SnoopDosTitle[];
  46.  
  47. /*
  48.  *              Variables for the format editor
  49.  */
  50. int FBoxA_Left;                         /* X pos of left box in format window   */
  51. int FBoxA_Top;                          /* Y pos of left box in format window   */
  52. int FBoxA_Width;                        /* Width of left box in format window   */
  53. int FBoxA_Height;                       /* Height of left box in format window  */
  54. int FBoxA_NumChars;                     /* No. of characters across left box    */
  55. int FBoxA_CurLines;                     /* No. of lines currently in left box   */
  56.  
  57. int FBoxB_Left;                         /* X pos of right box in format window  */
  58. int FBoxB_Top;                          /* Y pos of right box in format window  */
  59. int FBoxB_Width;                        /* Hidth of right box in format window  */
  60. int FBoxB_Height;                       /* Weight of right box in format window */
  61. int FBoxB_NumChars;                     /* No. of characters across right box   */
  62. int FBoxB_CurLines;                     /* No. of lines currently in right box  */
  63.  
  64. int FBoxSpacing;                        /* Distance between box text baselines  */
  65. int FBoxSelected;                       /* Line number of right box selection   */
  66.                                                         /* (or FBOX_NOSELECT / FBOX_SELECTLEFT) */
  67.  
  68. int FBoxDeltaX;                         /* Offset from mouse to corner of drag  */
  69. int FBoxDeltaY;                         /* Offset from mouse to corner of drag  */
  70. int FBoxDragSelect;                     /* Currently selected drag drop area    */
  71. int FormatCurLMB;                       /* Current state of left mouse button   */
  72. int FormatMovingField;          /* If true, currently dragging field    */
  73. int FormatDragBox;                      /* Box we're dragging from                              */
  74. int FormatDragLine;                     /* Line we're dragging from                             */
  75.  
  76. char FBoxA_FormString[20];      /* sprintf format string for left box   */
  77. char FBoxB_FormString[20];      /* sprintf format string for right box  */
  78.  
  79. char FormatSaveFormat[MAX_FORM_LEN];    /* Save area for format ed      */
  80.  
  81. /*
  82.  *              These next two arrays are indices into the FieldTypes[] array
  83.  *              of format initialisers.
  84.  */
  85. typedef struct {
  86.         int     type;                                                   /* Type of this entry           */
  87.         int width;                                                      /* Width of this entry          */
  88. } EditEvent;
  89.         
  90. extern FieldInit FieldTypes[];                  /* Pulled in from BUFFER.C      */
  91.  
  92. EditEvent CurrentFields[EF_COUNT+1];    /* Fields in current format     */
  93. EditEvent AvailableFields[EF_COUNT+1];  /* Fields still available       */
  94.  
  95. Settings                        SavedFuncSets;          /* Saved function settings      */
  96. Settings                        SavedSetupSets;         /* Saved setup settings         */
  97.  
  98. struct Gadget           *SetGadList;            /* Settings window gadgets      */
  99. struct Gadget           *FuncGadList;           /* Function window gadgets      */
  100. struct Gadget           *FormGadList;           /* Format window gadgets        */
  101. struct Image            *FileButtonImage;       /* Image of a file button       */
  102. struct Image            *FontButtonImage;       /* Image of a font button       */
  103.  
  104. struct TextFont         *FormBufFont;           /* Format window listview       */
  105. struct TextFont         *FormGadFont;           /* Format window gadgets        */
  106.  
  107. /*
  108.  *              We don't usually free the Function window gadgets when we close
  109.  *              the window (since it takes a long time to generate them). However,
  110.  *              if we change window font, then we need a way to be able to change
  111.  *              them. This variable shows you how.
  112.  */
  113. int             FuncSystemCol;          /* Mode of system column (all/none/sel) */
  114. int             FuncDOSCol;                     /* Mode of DOS column (all/none/select) */
  115.  
  116. UBYTE   SavedCols[GID_NUMFUNCSETS];     /* Currently selected settings  */
  117. UBYTE   TempCols[GID_NUMFUNCSETS];      /* Currently selected settings  */
  118.  
  119. UBYTE   SetKeyboard[KB_SHORTCUT_SIZE];  /* For keyboard equivs          */
  120. UBYTE   FuncKeyboard[KB_SHORTCUT_SIZE]; /* For keyboard equivs          */
  121. UBYTE   FormKeyboard[KB_SHORTCUT_SIZE]; /* For keyboard equivs          */
  122.  
  123. /*
  124.  *              Now our font structures.
  125.  *
  126.  *              We do everything in terms of FontAttr structures, and whenever a
  127.  *              window needs a font, it OpenFont's it itself. This has several
  128.  *              advantages: it allows each window to dynamically select the
  129.  *              best-fitting font, and it also ensures no problems if we have a
  130.  *              window open with one font and the user than changes the font
  131.  *              to something else -- the first window will still have a valid
  132.  *              lock on the old font.
  133.  */
  134. extern struct TextAttr TopazFontAttr;
  135. extern struct TextAttr SystemFontAttr;
  136. extern struct TextAttr WindowFontAttr;
  137. extern struct TextAttr BufferFontAttr;
  138.  
  139. extern struct {
  140.         struct TextAttr *gadgetfa;
  141.         struct TextAttr *bufferfa;
  142. } MainWindowFontList[];                         /* Imported from MAINWIN.C */
  143.  
  144. struct TextAttr *SubWindowFontList[] = {
  145.         &WindowFontAttr,
  146.         &SystemFontAttr,
  147.         &TopazFontAttr,
  148.         NULL
  149. };
  150.  
  151. /*
  152.  *              Next, all our gadget structures -- these are used to build the
  153.  *              font-sensitive gadget windows at runtime.
  154.  */
  155. struct FuncGadgets {
  156.         ULONG   gadgid;                 /* Gadget ID                                    */
  157.         UWORD   stringid;               /* Name of checkmark gadget     */
  158.         UBYTE   col;                    /* Column (0, 1 or 2)                   */
  159.         UBYTE   row;                    /* Row (0 -- 13)                                */
  160. };
  161.  
  162. struct FuncGadgets FuncGadgs[] = {
  163.         /*
  164.          *              General controls
  165.          */
  166.         GID_ONLYFAILS,          MSG_SHOWFAILS_GAD,              0, 0,
  167.         GID_SHOWCLINUM,         MSG_SHOWCLI_GAD,                0, 1,
  168.         GID_SHOWPATHS,          MSG_SHOWFULLPATHS_GAD,  0, 2,
  169.         GID_USEDEVNAMES,        MSG_USEDEVNAMES_GAD,    0, 3,
  170.         GID_MONPACKETS,         MSG_MONPACKETS_GAD,             0, 4,
  171.         GID_MONALLPACKETS,      MSG_MONALLPACKETS_GAD,  0, 5,
  172.         GID_MONROMCALLS,        MSG_MONROMCALLS_GAD,    0, 6,
  173.         GID_IGNOREWB,           MSG_IGNOREWB_GAD,               0, 7,
  174.         /*
  175.          *              System functions
  176.          */
  177.         GID_FINDPORT,           MSG_FINDPORT_GAD,               1, 0,
  178.         GID_FINDRESIDENT,       MSG_FINDRESIDENT_GAD,   1, 1,
  179.         GID_FINDSEMAPHORE,      MSG_FINDSEMAPHORE_GAD,  1, 2,
  180.         GID_FINDTASK,           MSG_FINDTASK_GAD,               1, 3,
  181.         GID_LOCKSCREEN,         MSG_LOCKSCREEN_GAD,             1, 4,
  182.         GID_OPENDEVICE,         MSG_OPENDEVICE_GAD,             1, 5,
  183.         GID_OPENFONT,           MSG_OPENFONT_GAD,               1, 6,
  184.         GID_OPENLIBRARY,        MSG_OPENLIBRARY_GAD,    1, 7,
  185.         GID_OPENRESOURCE,       MSG_OPENRESOURCE_GAD,   1, 8,
  186.         GID_READTOOLTYPES,      MSG_READTOOLTYPES_GAD,  1, 9,
  187.         GID_SENDREXX,           MSG_SENDREXX_GAD,               1, 10,
  188.  
  189.         /*
  190.          *              AmigaDOS Functions
  191.          */
  192.         GID_CHANGEDIR,          MSG_CHANGEDIR_GAD,              2, 0,
  193.         GID_DELETE,                     MSG_DELETE_GAD,                 2, 1,
  194.         GID_EXECUTE,            MSG_EXECUTE_GAD,                2, 2,
  195.         GID_GETVAR,                     MSG_GETVAR_GAD,                 2, 3,
  196.         GID_LOADSEG,            MSG_LOADSEG_GAD,                2, 4,
  197.         GID_LOCKFILE,           MSG_LOCKFILE_GAD,               2, 5,
  198.         GID_MAKEDIR,            MSG_MAKEDIR_GAD,                2, 6,
  199.         GID_MAKELINK,           MSG_MAKELINK_GAD,               2, 7,
  200.         GID_OPENFILE,           MSG_OPENFILE_GAD,               2, 8,
  201.         GID_RENAME,                     MSG_RENAME_GAD,                 2, 9,
  202.         GID_RUNCOMMAND,         MSG_RUNCOMMAND_GAD,             2, 10,
  203.         GID_SETVAR,                     MSG_SETVAR_GAD,                 2, 11,
  204.         GID_SYSTEM,                     MSG_SYSTEM_GAD,                 2, 12,
  205.  
  206.         0,                                      0,                                              0, 0
  207. };
  208.  
  209. /*
  210.  *              This structure defines the gadgets in the settings window. There
  211.  *              are three basic types of gadgets supported: cycle, string and
  212.  *              display. For cycle gadgets, data1 is the index of the current
  213.  *              selection, data2 is a 0-terminated array of message IDs that
  214.  *              will hold the possible ListView choices, and data3 is a pointer
  215.  *              to an array of string pointers of the same size (including
  216.  *              terminating NULL) that will be filled in by the code with actual
  217.  *              pointers to those strings.
  218.  *              
  219.  *              For string and display gadgets, data2 is a pointer to the string
  220.  *              to be displayed inside the gadget and data1/data3 are unused.
  221.  *              However, if promptid is specified, then data1 is the message
  222.  *              number of the prompt to be used in the button instead of defaulting
  223.  *              to a question mark (the width is automatically adjusted).
  224.  */             
  225. struct SetGadgets {
  226.         UWORD   gadgid;                 /* Gadget ID                                                            */
  227.         UWORD   stringid;               /* ID of label name                                     */
  228.         ULONG   gtype;                  /* Gadget type (cycle, string, or display)      */
  229.         UWORD   promptid;               /* If non-zero, ID of optional "?" button       */
  230.         ULONG   data1;                  /* See above                                                            */
  231.         void    *data2;                 /* See above                                                            */
  232.         void    *data3;                 /* See above                                                            */
  233.         UBYTE   col;                    /* Start col (0 or 1)                                           */
  234.         UBYTE   cwidth;                 /* Column width (0, 1 or 2)                                     */
  235.         UBYTE   row;                    /* Row (0 to 6)                                                         */
  236. };
  237.  
  238. int SetCylHide[] = {
  239.         MSG_CYL_HIDE_GAD, MSG_CYL_ICONIFY_GAD, MSG_CYL_TOOLSMENU_GAD,
  240.         MSG_CYL_NONE_GAD, 0
  241. };
  242.  
  243. int SetCylOpenOn[] = {
  244.         MSG_CYL_DEFSCREEN_GAD, MSG_CYL_FRONTSCREEN_GAD, MSG_CYL_NAMEDSCREEN_GAD, 0
  245. };
  246.  
  247. int SetCylLogMode[] = {
  248.         MSG_CYL_PROMPT_USER_GAD, MSG_CYL_APPEND_GAD, MSG_CYL_OVERWRITE_GAD,
  249.         MSG_CYL_SERIALPORT_GAD, 0
  250. };
  251.  
  252. int SetCylFileIO[] = {
  253.         MSG_CYL_AUTOMATIC_GAD, MSG_CYL_IMMEDIATE_GAD, MSG_CYL_BUFFERED_GAD, 0
  254. };
  255.  
  256. char *SetCylHideText[HIDE_MAX+1];
  257. char *SetCylOpenOnText[SCREEN_MAX+1];
  258. char *SetCylLogModeText[LOGMODE_MAX+1];
  259. char *SetCylFileIOText[FILE_MAX+1];
  260.  
  261.  
  262. /*
  263.  *              If you re-arrange the order of these gadget definitions,
  264.  *              make sure you re-order the enum's that follow below as well.
  265.  */
  266. struct SetGadgets SetGadgs[] = {
  267.         GID_BUFFORMAT,  MSG_BUFFORMAT_GAD,      STRING_KIND,    GID_FORMATEDIT, 
  268.                                                                                                                 MSG_FORMATEDIT_GAD,
  269.                                         NULL,                           0,                                      0,      2,      5,
  270.  
  271.         GID_LOGFORMAT,  MSG_LOGFORMAT_GAD,      STRING_KIND,    GID_FORMATCOPY,
  272.                                                                                                                 MSG_FORMATCOPYF_GAD,
  273.                                         NULL,                           0,                                      0,      2,      6,
  274.         
  275.         GID_HIDEMETHOD, MSG_HIDEMETHOD_GAD,     CYCLE_KIND,             0,      0,
  276.                                         SetCylHide,                     SetCylHideText,         0,      0,      0,
  277.         
  278.         GID_OPENON,             MSG_OPENON_GAD,         CYCLE_KIND,             0,      0,
  279.                                         SetCylOpenOn,           SetCylOpenOnText,       0,      0,      1,
  280.  
  281.         GID_LOGMODE,    MSG_LOGMODE_GAD,        CYCLE_KIND,             0,      0,
  282.                                         SetCylLogMode,          SetCylLogModeText,      0,      0,      2,
  283.  
  284.         GID_FILEIO,             MSG_FILEIO_GAD,         CYCLE_KIND,             0,      0,
  285.                                         SetCylFileIO,           SetCylFileIOText,       0,      0,      3,
  286.         
  287.         GID_HOTKEY,             MSG_HOTKEY_GAD,         STRING_KIND,    0,      0,
  288.                                         NULL,                           0,                                      1,      1,      0,
  289.         
  290.         GID_SCREENNAME, MSG_SCREENNAME_GAD,     STRING_KIND,    0,      0,
  291.                                         NULL,                           0,                                      1,      1,      1,
  292.         
  293.         GID_LOGFILE,    MSG_LOGFILE_GAD,        STRING_KIND,    GID_FILEPROMPT,
  294.                                                                                                                 SETBUTTON_FILE,
  295.                                         NULL,                           0,                                      1,      1,      2,
  296.  
  297.         GID_WINDOWFONT, MSG_WINDOWFONT_GAD,     TEXT_KIND,              GID_WFONTPROMPT,
  298.                                                                                                                 SETBUTTON_FONT,
  299.                                         NULL,                           0,                                      1,      1,      3,
  300.         
  301.         GID_BUFFERFONT, MSG_BUFFERFONT_GAD,     TEXT_KIND,              GID_BFONTPROMPT,
  302.                                                                                                                 SETBUTTON_FONT,
  303.                                         NULL,                           0,                                      1,      1,      4,
  304.  
  305.         0
  306. };
  307.  
  308. /*
  309.  *              The following gadgets should match the _order_ that the above
  310.  *              gadgets are laid out in, since they are used as indices into the
  311.  *              above array.
  312.  */
  313. typedef enum {
  314.         SG_BufferFormat,
  315.         SG_LogfileFormat,
  316.         SG_HideMethod,
  317.         SG_ScreenType,
  318.         SG_LogMode,
  319.         SG_FileIOType,
  320.         SG_HotKey,
  321.         SG_ScreenName,
  322.         SG_LogFile,
  323.         SG_WindowFont,
  324.         SG_BufferFont,
  325. } SetGadgetEnums;
  326.  
  327. /*
  328.  *              Arrays of gadget names for calculating minimum width
  329.  */
  330.  
  331. /*
  332.  *              Miscellaneous gadgets in functions window
  333.  */
  334. int MiscColNames[] = {
  335.         MSG_SHOWFAILS_GAD,
  336.         MSG_SHOWCLI_GAD,
  337.         MSG_SHOWFULLPATHS_GAD,
  338.         MSG_USEDEVNAMES_GAD,
  339.         MSG_MONPACKETS_GAD,
  340.         MSG_MONALLPACKETS_GAD,
  341.         MSG_IGNOREWB_GAD,
  342.         0
  343. };
  344.  
  345. /*
  346.  *              System gadgets in functions window
  347.  */
  348. int SysColNames[] = {
  349.         MSG_FINDPORT_GAD,     
  350.         MSG_FINDRESIDENT_GAD, 
  351.         MSG_FINDSEMAPHORE_GAD,
  352.         MSG_FINDTASK_GAD,     
  353.         MSG_LOCKSCREEN_GAD,   
  354.         MSG_OPENDEVICE_GAD,   
  355.         MSG_OPENFONT_GAD,     
  356.         MSG_OPENLIBRARY_GAD,  
  357.         MSG_OPENRESOURCE_GAD, 
  358.         MSG_READTOOLTYPES_GAD,
  359.         MSG_SENDREXX_GAD, 
  360.         0
  361. };
  362.  
  363. /*
  364.  *              AmigaDOS gadgets in functions window
  365.  */
  366. int DOSColNames[] = {
  367.         MSG_CHANGEDIR_GAD, 
  368.         MSG_DELETE_GAD,    
  369.         MSG_EXECUTE_GAD,   
  370.         MSG_GETVAR_GAD,    
  371.         MSG_LOADSEG_GAD,   
  372.         MSG_LOCKFILE_GAD,  
  373.         MSG_MAKEDIR_GAD,   
  374.         MSG_MAKELINK_GAD,  
  375.         MSG_OPENFILE_GAD,  
  376.         MSG_RENAME_GAD,    
  377.         MSG_RUNCOMMAND_GAD,
  378.         MSG_SETVAR_GAD,    
  379.         MSG_SYSTEM_GAD,
  380.         0
  381. };
  382.  
  383. /*
  384.  *              Aditional gadgets in function window
  385.  */
  386. int FuncCycleText[]             = { MSG_ALL_GAD, MSG_NONE_GAD, MSG_SELECTED_GAD, 0 };
  387. int FuncCycleName[]             = { MSG_SELSYSTEM_GAD, MSG_SELDOS_GAD, 0 };
  388. int UseCancelUndoText[] = { MSG_USE_GAD, MSG_CANCEL_GAD, MSG_UNDO_GAD, 0 };
  389.  
  390. /*
  391.  *              Left column gadgets names in settings window
  392.  */
  393. int SettingsLeftNames[] = {
  394.         MSG_HIDEMETHOD_GAD,
  395.         MSG_OPENON_GAD,
  396.         MSG_LOGMODE_GAD,
  397.         MSG_FILEIO_GAD,
  398.         MSG_BUFFORMAT_GAD,
  399.         MSG_LOGFORMAT_GAD,
  400.         0
  401. };
  402.  
  403. /*
  404.  *              Right column gadget names in settings window
  405.  */
  406. int SettingsRightNames[] = {
  407.         MSG_HOTKEY_GAD,
  408.         MSG_SCREENNAME_GAD,
  409.         MSG_LOGFILE_GAD,
  410.         MSG_WINDOWFONT_GAD,
  411.         MSG_BUFFERFONT_GAD,
  412.         0
  413. };
  414.  
  415. /*
  416.  *              Two mini buttons attached to format gadgets in settings window
  417.  *              Note that we have two types of possibility: one for fixed point
  418.  *              fonts and one for proportional fonts. This is so that we can
  419.  *              arrange for the two strings "Edit..." and "Copy" to always
  420.  *              look properly aligned, regardless of font type. If we didn't do
  421.  *              this, then with fixed point fonts, "Copy" looks mis-aligned
  422.  *              with respect to "Edit..." because they are different lengths.
  423.  */
  424. int SetMiniButtonsP[] = {
  425.         MSG_FORMATCOPYP_GAD,
  426.         MSG_FORMATEDIT_GAD,
  427.         0
  428. };
  429.  
  430. int SetMiniButtonsF[] = {
  431.         MSG_FORMATCOPYF_GAD,
  432.         MSG_FORMATEDIT_GAD,
  433.         0
  434. };
  435.  
  436. /*
  437.  *              Left column gadget contents in settings
  438.  */
  439. int SettingsLeftContents[] = {
  440.         MSG_CYL_HIDE_GAD,
  441.         MSG_CYL_ICONIFY_GAD,
  442.         MSG_CYL_TOOLSMENU_GAD,
  443.         MSG_CYL_DEFSCREEN_GAD,
  444.         MSG_CYL_FRONTSCREEN_GAD,
  445.         MSG_CYL_NAMEDSCREEN_GAD,
  446.         MSG_CYL_PROMPT_USER_GAD,
  447.         MSG_CYL_APPEND_GAD,
  448.         MSG_CYL_OVERWRITE_GAD,
  449.         MSG_CYL_AUTOMATIC_GAD,
  450.         MSG_CYL_IMMEDIATE_GAD,
  451.         MSG_CYL_BUFFERED_GAD,
  452.         0
  453. };
  454.  
  455. /*
  456.  *              Mega struct that collects all the data needed to create useful BOBs.
  457.  */
  458. typedef struct MyGel {
  459.         struct GelsInfo  gelinfo;                       /* GelInfo for entire structure */
  460.         WORD                     nextline[8];           /* Nextline data                                */ 
  461.         WORD                     *lastcolor[8];         /* Last colour data                             */
  462.         struct RastPort  *mainrast;                     /* Rastport bob is displayed in */
  463.         struct collTable colltable;                     /* Collision table                              */
  464.         struct VSprite   vshead;                        /* Head sprite anchor                   */
  465.         struct VSprite   vstail;                        /* Tail sprite anchor                   */
  466.         struct VSprite   bobvsprite;            /* Vsprite used for bob                 */
  467.         struct Bob               bob;                           /* Data for a single bob                */
  468.         struct RastPort  rastport;                      /* Rastport for our BOB                 */
  469.         struct BitMap    bitmap;                        /* Bitmap for our BOB                   */
  470.         ULONG                    planesize;                     /* Size of one plane in bob             */
  471.         UBYTE                   *planedata;                     /* Pointer to first plane               */
  472.         UBYTE                   *chipdata;                      /* Pointer to all CHIP RAM data */
  473.         ULONG                    chipsize;                      /* Total size of allocated CHIP */
  474. } MyGel;
  475.  
  476. MyGel   *TextBob;                                               /* Info about GEL/BOBs                  */
  477.  
  478. /*
  479.  *              Some prototypes private to this file
  480.  */
  481. MyGel *CreateBob(struct RastPort *rport, int width, int height, int transp);
  482. void FreeBob(MyGel *mygel);
  483. void UpdateBob(int x, int y);
  484. int  PickupBob(int hit, int x, int y);
  485. void DropBob(void);
  486.  
  487. /*****************************************************************************
  488.  *
  489.  *              Start of functions!
  490.  *
  491.  *****************************************************************************/
  492.  
  493. /*
  494.  *              CleanupSubWindows()
  495.  *
  496.  *              Frees any resources associated with this module
  497.  */
  498. void CleanupSubWindows(void)
  499. {
  500.         PurgeFuncGadgets = 1;
  501.         CloseFunctionWindow();
  502.         CloseSettingsWindow();
  503.         CloseFormatWindow();
  504. }
  505.  
  506. /*
  507.  *              GetFuncName(gadgetid)
  508.  *
  509.  *              Returns a pointer to a string describing the function name which
  510.  *              matches the gadget ID passed in. This is used by PATCHES.C when
  511.  *              it is unpatching the patched functions at exit time to identify
  512.  *              which function can't be unpatched in the event of a problem.
  513.  */
  514. char *GetFuncName(int gadgetid)
  515. {
  516.         struct FuncGadgets *fg = FuncGadgs;
  517.  
  518.         if (gadgetid == GID_SENDREXX)   /* Special-case this multi-function one */
  519.                 return MSG(MSG_PACKET_NAME);
  520.  
  521.         for (fg = &FuncGadgs[0]; fg->gadgid; fg++) {
  522.                 if (fg->gadgid == gadgetid)
  523.                         return MSG(fg->stringid);
  524.         }
  525.         return ("<Unknown Function>");
  526. }
  527.  
  528. /*
  529.  *              CreateFunctionGadgets(fontattr, getsize, &width, &height)
  530.  *
  531.  *              Creates all the gadgets for the function window. If getsize
  532.  *              is true, then the width and height values are filled in with
  533.  *              the dimensions of the window needed to hold the gadgets. In
  534.  *              this case, NULL is returned if the window would be too big to
  535.  *              fit on the current screen, or non-NULL if width and height
  536.  *              were successfully initialised.
  537.  *
  538.  *              If getsize is zero, then the actual gadgets are created and
  539.  *              a pointer to the gadget list is returned, or NULL if an
  540.  *              error occurred (typically, out of memory).
  541.  */
  542. struct Gadget *CreateFunctionGadgets(struct TextAttr *fontattr,
  543.                                                                          int getsize, int *pwidth, int *pheight)
  544. {
  545.         static char *cyltext[4];
  546.         struct TextFont *font;
  547.         struct FuncGadgets *fg;
  548.         struct NewGadget ng;
  549.         struct Gadget *gadlist;
  550.         struct Gadget *gad;
  551.         UWORD spacing[3];
  552.         UWORD yoffset[3]; 
  553.         UWORD colpos[3];
  554.         int heightadjust = 0;
  555.         int width;
  556.         int height;
  557.         int gwidth;
  558.         int gheight;
  559.         int fonty;
  560.         int colspace = 30;
  561.         int topline;
  562.         int w1, w2;
  563.  
  564.         if (!FuncVI) {
  565.                 FuncVI = GetVisualInfoA(SnoopScreen, NULL);
  566.                 if (!FuncVI)
  567.                         return (NULL);
  568.         }
  569.         font = MyOpenFont(fontattr);
  570.         if (!font)
  571.                 return (NULL);
  572.  
  573.         fonty           = font->tf_YSize;
  574.         gheight         = fonty   + 3;
  575.         gwidth          = gheight + 15;
  576.         
  577.         spacing[0]  = fonty + 4;
  578.         spacing[1]  = fonty + 4;
  579.         spacing[2]  = fonty + 4;
  580.         yoffset[1]      = TitlebarHeight + fonty/2;
  581.         yoffset[2]      = yoffset[1];
  582.         yoffset[0]      = yoffset[1] + 10 * spacing[1] - 7 * spacing[0];
  583.  
  584.         colpos[0]       = BorderLeft + FUNC_MARGIN;
  585.         colpos[1]       = colpos[0]  + MaxTextLen(font, MiscColNames)
  586.                                   + gwidth + colspace;
  587.         w1                      = MaxTextLen(font, SysColNames) + gwidth;
  588.         w2                      = GetTextLen(font, MSG(MSG_SYSFUNCS_GAD));
  589.         colpos[2]       = colpos[1]  + MAX(w1, w2) + colspace;
  590.         w1                      = MaxTextLen(font, DOSColNames) + gwidth;
  591.         w2                      = GetTextLen(font, MSG(MSG_DOSFUNCS_GAD));
  592.         width           = colpos[2]  + MAX(w1, w2) + FUNC_MARGIN + BorderRight + 8;
  593.         height      = yoffset[2] + spacing[2] * 15 + BorderBottom;
  594.  
  595.         topline = yoffset[2];
  596.         if (ScreenHeight < 256 && height > ScreenHeight) {
  597.                 /*
  598.                  *              For medium and low resolution screens, shave another
  599.                  *              few pixels from the height. Our aim is to be able to
  600.                  *              open on a 640 x 200 screen with a 15 point screen font.
  601.                  */
  602.                 heightadjust = -2;
  603.                 height      += heightadjust * 2;
  604.         }
  605.         if ((height + spacing[2] * 2) <= ScreenHeight) {
  606.                 int disp = (spacing[2] * 3) / 2;
  607.  
  608.                 yoffset[0] += disp;
  609.                 yoffset[1] += disp;
  610.                 yoffset[2] += disp;
  611.                 height     += disp;
  612.         }
  613.  
  614.         if (width > ScreenWidth || height > ScreenHeight) {
  615.                 CloseFont(font);
  616.                 return (NULL);
  617.         }
  618.         if (getsize) {
  619.                 CloseFont(font);
  620.                 *pwidth  = width;
  621.                 *pheight = height;
  622.                 return (struct Gadget *)(-1);
  623.         }
  624.  
  625.         /*
  626.          *              Now create our new gadgets
  627.          */     
  628.         ng.ng_Height            = gheight; 
  629.         ng.ng_Width                     = gwidth;  
  630.         ng.ng_TextAttr          = fontattr;
  631.         ng.ng_VisualInfo        = FuncVI;
  632.         ng.ng_Flags         = PLACETEXT_RIGHT;
  633.  
  634.         gadlist = NULL;
  635.         gad = CreateContext(&gadlist);
  636.         if (!gad)
  637.                 goto fgad_failed;
  638.  
  639.         for (fg = &FuncGadgs[0]; fg->gadgid; fg++) {
  640.                 int col = fg->col;
  641.  
  642.                 ng.ng_LeftEdge          = colpos[col];
  643.                 ng.ng_TopEdge           = fg->row * spacing[col] + yoffset[col];
  644.                 ng.ng_GadgetText        = MSG(fg->stringid);
  645.                 ng.ng_GadgetID          = fg->gadgid;
  646.  
  647.                 gad = CreateGadget(CHECKBOX_KIND, gad, &ng,
  648.                                                    GT_Underscore,       '_',
  649.                                                    GTCB_Scaled,     TRUE,
  650.                                                    TAG_DONE);
  651.                 if (!gad)
  652.                         goto fgad_failed;
  653.                 Gadget[fg->gadgid] = gad;
  654.                 AddKeyShortcut(FuncKeyboard, fg->gadgid, fg->stringid);
  655.         }
  656.  
  657.         /*
  658.          *              Now create the remaining window gadgets
  659.          */
  660.         ng.ng_LeftEdge          = colpos[0]
  661.                                                   + GetTextLen(font, MSG(MSG_MATCHNAME_GAD)) + 10;
  662.         ng.ng_TopEdge           = yoffset[1] + (23 * spacing[1]) / 2;
  663.         ng.ng_GadgetText        = MSG(MSG_MATCHNAME_GAD);
  664.         ng.ng_GadgetID          = GID_MATCHNAME;
  665.         ng.ng_Width         = colpos[2] - ng.ng_LeftEdge - colspace + 8;
  666.         ng.ng_Height            = gheight + 3;
  667.         ng.ng_Flags         = PLACETEXT_LEFT;
  668.  
  669.         gad = CreateGadget(STRING_KIND,         gad, &ng,
  670.                                            GT_Underscore,       '_',
  671.                                            GTST_MaxChars,       MAX_STR_LEN,
  672.                                            GTST_String,         CurSettings.Func.Pattern,
  673.                                            TAG_DONE);
  674.         if (!gad)
  675.                 goto fgad_failed;
  676.         Gadget[GID_MATCHNAME] = gad;
  677.         AddKeyShortcut(FuncKeyboard, GID_MATCHNAME, MSG_MATCHNAME_GAD);
  678.  
  679.         ng.ng_GadgetText        = MSG(MSG_SELSYSTEM_GAD);
  680.         ng.ng_GadgetID          = GID_SELSYSTEM;
  681.         ng.ng_Height            = gheight + 3;
  682.         ng.ng_Width                     = MaxTextLen(font, FuncCycleText) + 40;
  683.         ng.ng_LeftEdge          = colpos[0] + MaxTextLen(font, FuncCycleName) + 10;
  684.         ng.ng_TopEdge           = yoffset[1];
  685.         cyltext[0]                      = MSG(MSG_SELECTED_GAD);
  686.         cyltext[1]                      = MSG(MSG_ALL_GAD);
  687.         cyltext[2]                      = MSG(MSG_NONE_GAD);
  688.         cyltext[3]                      = NULL;
  689.  
  690.         gad = CreateGadget(CYCLE_KIND,          gad, &ng,
  691.                                            GT_Underscore,       '_',
  692.                                            GTCY_Labels,         cyltext,
  693.                                            GTCY_Active,         COL_SELECTED,
  694.                                            TAG_DONE);
  695.         if (!gad)
  696.                 goto fgad_failed;
  697.         Gadget[GID_SELSYSTEM] = gad;
  698.         AddKeyShortcut(FuncKeyboard, GID_SELSYSTEM, MSG_SELSYSTEM_GAD);
  699.  
  700.         ng.ng_GadgetText        = MSG(MSG_SELDOS_GAD);
  701.         ng.ng_GadgetID          = GID_SELDOS;
  702.         ng.ng_TopEdge           = (yoffset[0] + yoffset[1]) / 2;
  703.  
  704.         gad = CreateGadget(CYCLE_KIND,          gad, &ng,
  705.                                            GT_Underscore,       '_',
  706.                                            GTCY_Labels,         cyltext,
  707.                                            GTCY_Active,         COL_SELECTED,
  708.                                            TAG_DONE);
  709.         if (!gad)
  710.                 goto fgad_failed;
  711.         Gadget[GID_SELDOS] = gad;
  712.         AddKeyShortcut(FuncKeyboard, GID_SELDOS, MSG_SELDOS_GAD);
  713.  
  714.         ng.ng_Width                     = MaxTextLen(font, UseCancelUndoText) + 32;
  715.         ng.ng_Height            = fonty + GadgetHeight;
  716.         ng.ng_GadgetText        = MSG(MSG_USE_GAD);
  717.         ng.ng_GadgetID          = GID_FUNCUSE;
  718.         ng.ng_LeftEdge          = colpos[0];
  719.         ng.ng_TopEdge           = yoffset[2] + heightadjust + (27 * spacing[2]) / 2;
  720.         ng.ng_Flags                     = PLACETEXT_IN;
  721.  
  722.         gad = CreateGadget(BUTTON_KIND,         gad, &ng,
  723.                                            GT_Underscore,       '_',
  724.                                            TAG_DONE);
  725.         if (!gad)
  726.                 goto fgad_failed;
  727.         Gadget[GID_FUNCUSE] = gad;
  728.         AddKeyShortcut(FuncKeyboard, GID_FUNCUSE, MSG_USE_GAD);
  729.         
  730.         ng.ng_LeftEdge          = width - BorderRight - FUNC_MARGIN - ng.ng_Width;
  731.         ng.ng_GadgetText        = MSG(MSG_CANCEL_GAD);
  732.         ng.ng_GadgetID          = GID_FUNCCANCEL;
  733.  
  734.         gad = CreateGadget(BUTTON_KIND,         gad, &ng,
  735.                                            GT_Underscore,       '_',
  736.                                            TAG_DONE);
  737.         if (!gad)
  738.                 goto fgad_failed;
  739.         Gadget[GID_FUNCCANCEL] = gad;
  740.         AddKeyShortcut(FuncKeyboard, GID_FUNCCANCEL, MSG_CANCEL_GAD);
  741.  
  742.         ng.ng_LeftEdge          = (ng.ng_LeftEdge + BorderLeft + FUNC_MARGIN) / 2;
  743.         ng.ng_GadgetText        = MSG(MSG_UNDO_GAD);
  744.         ng.ng_GadgetID          = GID_FUNCUNDO;
  745.  
  746.         gad = CreateGadget(BUTTON_KIND,         gad, &ng,
  747.                                            GT_Underscore,       '_',
  748.                                            TAG_DONE);
  749.         if (!gad)
  750.                 goto fgad_failed;
  751.         Gadget[GID_FUNCUNDO] = gad;
  752.         AddKeyShortcut(FuncKeyboard, GID_FUNCUNDO, MSG_UNDO_GAD);
  753.         
  754.         if (topline != yoffset[2]) {
  755.                 /*
  756.                  *              If there's room at the top of the window, create two text
  757.                  *              gadgets with the column headings for the System and DOS cols.
  758.                  */
  759.                 ng.ng_TopEdge           = topline;
  760.                 ng.ng_LeftEdge          = colpos[1];
  761.                 ng.ng_GadgetText        = "";
  762.                 ng.ng_GadgetID          = 0;
  763.  
  764.                 gad = CreateGadget(TEXT_KIND,   gad, &ng,
  765.                                                    GTTX_Text,   MSG(MSG_SYSFUNCS_GAD),
  766.                                                    TAG_DONE);
  767.                 if (!gad)
  768.                         goto fgad_failed;
  769.  
  770.                 ng.ng_LeftEdge          = colpos[2];
  771.                 gad = CreateGadget(TEXT_KIND,   gad, &ng,
  772.                                                    GTTX_Text,   MSG(MSG_DOSFUNCS_GAD),
  773.                                                    TAG_DONE);
  774.                 if (!gad)
  775.                         goto fgad_failed;
  776.         }
  777.         PurgeFuncGadgets = 0;   /* No need to purge now */
  778.         CloseFont(font);
  779.         return (gadlist);
  780.  
  781. fgad_failed:
  782.         if (gadlist)
  783.                 FreeGadgets(gadlist);
  784.         CloseFont(font);
  785.         return (NULL);
  786. }
  787.  
  788. /*
  789.  *              OpenFunctionWindow()
  790.  *
  791.  *              Opens the functions window with all the functions gadgets.
  792.  *              Returns TRUE for success, FALSE for failure.
  793.  *              The window will contain all necessary gadgets.
  794.  *
  795.  *              As with the Settings window, we try a variety of fonts until we
  796.  *              find one that fits onto the screen.
  797.  */
  798. int OpenFunctionWindow(void)
  799. {
  800.         static struct TextAttr funcfontattr =
  801.                 { "empty-storage-for-func-fonts...", 0, FS_NORMAL, FPB_DISKFONT};
  802.  
  803.         static int width;               /* Maintained from call to call */
  804.         static int height;
  805.  
  806.         int left = CurSettings.FuncWinLeft;
  807.         int top  = CurSettings.FuncWinTop;
  808.         struct TextAttr *fontattr = NULL;
  809.         struct Window *win;
  810.         int i;
  811.  
  812.         CheckSegTracker();
  813.         if (FuncWindow) {
  814.                 WindowToFront(FuncWindow);
  815.                 ActivateWindow(FuncWindow);
  816.                 return (TRUE);
  817.         }
  818.         if (!CheckForScreen())
  819.                 return (FALSE);
  820.  
  821.         SavedFuncSets = CurSettings;            /* Save so we can restore later */
  822.  
  823.         if (!FuncGadList) {
  824.                 /*
  825.                  *              Find out what dimensions our new window should be; to do
  826.                  *              this, we calculate the size with a variety of fonts until
  827.                  *              we find one that works.
  828.                  */
  829.                 int i;
  830.  
  831.                 for (i = 0; fontattr = SubWindowFontList[i]; i++) {
  832.                         if (CreateFunctionGadgets(fontattr, TRUE, &width, &height))
  833.                                 break;
  834.                 }
  835.                 if (!fontattr) {
  836.                         ShowError(MSG(MSG_ERROR_OPENFUNC));
  837.                         return (FALSE);
  838.                 }
  839.                 /*
  840.                  *              We need to make a copy of the fontattr now so that if
  841.                  *              the user changes the font, all our gadgets don't suddenly
  842.                  *              inherit the new font (at least until the window has been
  843.                  *              closed and re-opened!)
  844.                  */
  845.                 strcpy(funcfontattr.ta_Name, fontattr->ta_Name);
  846.                 funcfontattr.ta_YSize = fontattr->ta_YSize;
  847.                 fontattr = &funcfontattr;
  848.         }
  849.         if (left == -1)  left = (ScreenWidth  - width)  / 2;
  850.         if (top  == -1)  top  = (ScreenHeight - height) / 2;
  851.  
  852.         win = OpenWindowTags(NULL,
  853.                                                  WA_Title,                      MSG(MSG_FUNCTION_TITLE),
  854.                                                  WA_IDCMP,                      IDCMP_CLOSEWINDOW        |
  855.                                                                                         IDCMP_REFRESHWINDOW      |
  856.                                                                                         IDCMP_NEWSIZE            |
  857.                                                                                         IDCMP_INACTIVEWINDOW |
  858.                                                                                         IDCMP_RAWKEY             |
  859.                                                                                         BUTTONIDCMP,
  860.                                                  WA_Left,                       left,
  861.                                                  WA_Top,                        top,
  862.                                                  WA_Width,                      width,
  863.                                                  WA_Height,                     height,
  864.                                                  WA_Flags,                      WFLG_DRAGBAR             |
  865.                                                                                         WFLG_DEPTHGADGET         |
  866.                                                                                         WFLG_ACTIVATE            |
  867.                                                                                         WFLG_RMBTRAP             |
  868.                                                                                         WFLG_NEWLOOKMENUS,
  869.                                                  RefreshTag,            TRUE,
  870.                                                  WA_NoCareRefresh,      NoCareRefreshBool,
  871.                                                  WA_PubScreen,          SnoopScreen,
  872.                                                  TAG_DONE);
  873.         if (!win) {
  874.                 ShowError(MSG(MSG_ERROR_OPENFUNC));
  875.                 return (FALSE);
  876.         }
  877.  
  878.         if (!FuncGadList) {
  879.                 FuncGadList = CreateFunctionGadgets(fontattr, 0, 0, 0);
  880.                 if (!FuncGadList) {
  881.                         CloseWindow(win);
  882.                         ShowError(MSG(MSG_ERROR_OPENFUNC));
  883.                         return (FALSE);
  884.                 }
  885.         }
  886.  
  887.         /*
  888.          *              Now update function gadgets to reflect current settings
  889.          *              for AmigaDOS functions. Under V39+, we can do this before
  890.          *              adding them to the window. Under V37, we have to do it
  891.          *              after adding them to the window.
  892.          */
  893.         if (GadToolsBase->lib_Version < 39) {
  894.                 AddGList(win, FuncGadList, -1, -1, NULL);
  895.                 RefreshGList(FuncGadList, win, NULL, -1);
  896.                 GT_RefreshWindow(win, NULL);
  897.                 for (i = FIRST_BOOL_GADGET; i <= LAST_BOOL_GADGET; i++) {
  898.                         if (Gadget[i]) {
  899.                                 GT_SetGadgetAttrs(Gadget[i], win, NULL,
  900.                                                                   GTCB_Checked, CurSettings.Func.Opts[i],
  901.                                                                   TAG_DONE);
  902.                         }
  903.                 }
  904.         } else { /* GadToolsBase->lib_Version >= 39 */
  905.                 for (i = FIRST_BOOL_GADGET; i <= LAST_BOOL_GADGET; i++) {
  906.                         if (Gadget[i]) {
  907.                                 GT_SetGadgetAttrs(Gadget[i], NULL, NULL,
  908.                                                                   GTCB_Checked, CurSettings.Func.Opts[i],
  909.                                                                   TAG_DONE);
  910.                         }
  911.                 }
  912.                 AddGList(win, FuncGadList, -1, -1, NULL);
  913.                 RefreshGList(FuncGadList, win, NULL, -1);
  914.                 GT_RefreshWindow(win, NULL);
  915.         }
  916.  
  917.         /*
  918.          *              All done, so initialise some globals and return
  919.          */
  920.         FuncWindow              = win;
  921.         FuncWindowPort  = win->UserPort;
  922.         FuncWindowMask  = 1 << FuncWindowPort->mp_SigBit;
  923.         FuncSystemCol   = COL_SELECTED;
  924.         FuncDOSCol              = COL_SELECTED;
  925.         if (DisableNestCount)
  926.                 DisableWindow(FuncWindow, &FuncRequester);
  927.         return (TRUE);
  928. }
  929.  
  930. /*
  931.  *              CreateSettingsGadgets(fontattr, getsize, &pwidth, &pheight)
  932.  *
  933.  *              Creates the gadgets list for the settings window using the specified
  934.  *              window font. If the window would be to big for the current screen
  935.  *              using this font, or if there is a problem creating the gadgets,
  936.  *              returns NULL.
  937.  *
  938.  *              The returned gadget list should be passed to FreeGadgets() when
  939.  *              it is no longer required.
  940.  *
  941.  *              If getsize is true, then pwidth and pheight are filled in with the
  942.  *              dimensions of the window size needed to hold the gadgets, but
  943.  *              no actual gadget creation is carried out. In this case, NULL is
  944.  *              returned for a failure (couldn't open font, or window size would
  945.  *              exceed current screen size) and non-NULL for success.
  946.  */
  947. struct Gadget *CreateSettingsGadgets(struct TextAttr *fontattr,
  948.                                                                          int getsize, int *pwidth, int *pheight)
  949. {
  950.         struct SetGadgets *sg;
  951.         struct NewGadget ng;
  952.         struct NewGadget ngbut;
  953.         struct TextFont *font;
  954.         struct Gadget *gadlist;
  955.         struct Gadget *gad;
  956.         UWORD spacing;
  957.         UWORD yoffset;
  958.         UWORD colpos[2];
  959.         UWORD colwidth[3];
  960.         int miniwidth;
  961.         int width;
  962.         int height;
  963.         int gheight;
  964.         int fonty;
  965.         int fontx;
  966.  
  967.         if (!SetVI) {
  968.                 SetVI = GetVisualInfoA(SnoopScreen, NULL);
  969.                 if (!SetVI)
  970.                         return (NULL);
  971.         }
  972.         font = MyOpenFont(fontattr);
  973.         if (!font)
  974.                 return (NULL);
  975.         
  976.         fonty           = font->tf_YSize;
  977.         fontx           = font->tf_XSize;
  978.  
  979.         gheight         = fonty + GadgetHeight;
  980.         spacing     = fonty + GadgetSpacing;
  981.         yoffset         = TitlebarHeight + fonty/2;
  982.         colpos[0]       = BorderLeft + SET_MARGIN
  983.                                   + MaxTextLen(font, SettingsLeftNames) + 7;
  984.         colwidth[0] = MaxTextLen(font, SettingsLeftContents) + 40;
  985.         colpos[1]       = colpos[0] + colwidth[0] + SET_MARGIN*2
  986.                                                           + MaxTextLen(font, SettingsRightNames);
  987.         colwidth[1] = fontx * 24; /* Room for about 24 chars in string gadgets */
  988.         colwidth[2] = colwidth[1] + colpos[1] - colpos[0];      /* Dual width */
  989.  
  990.         /*
  991.          *              See SetMiniButtons[] definitions for explanation of this bit
  992.          */
  993.         if (font->tf_Flags & FPF_PROPORTIONAL) {
  994.                 miniwidth = MaxTextLen(font, SetMiniButtonsP) + 20;
  995.                 SetGadgs[1].data1 = MSG_FORMATCOPYP_GAD;
  996.         } else {
  997.                 miniwidth = MaxTextLen(font, SetMiniButtonsF) + 20;
  998.                 SetGadgs[1].data1 = MSG_FORMATCOPYF_GAD;
  999.         }
  1000.  
  1001.         width           = colpos[1] + colwidth[1] + SET_MARGIN + BorderRight;
  1002.         height      = yoffset + spacing * 8 + BorderBottom;
  1003.  
  1004.         if (width > ScreenWidth || height >ScreenHeight) {
  1005.                 CloseFont(font);
  1006.                 return (NULL);
  1007.         }
  1008.         if (getsize) {
  1009.                 *pwidth  = width;
  1010.                 *pheight = height;
  1011.                 CloseFont(font);
  1012.                 return (struct Gadget *)(-1);
  1013.         }
  1014.  
  1015.         /*
  1016.          *              Okay, looks like our size is okay so now prime our gadget
  1017.          *              table with the current settings values to use when the
  1018.          *              gadget is created.
  1019.          *
  1020.          */
  1021. #define DEF_CYCLE(x)    SetGadgs[SG_##x].data1
  1022. #define DEF_STRING(x)   SetGadgs[SG_##x].data2
  1023.  
  1024.         DEF_CYCLE(HideMethod)     = CurSettings.Setup.HideMethod;
  1025.         DEF_CYCLE(ScreenType)     = CurSettings.Setup.ScreenType;
  1026.         DEF_CYCLE(LogMode)                = CurSettings.Setup.LogMode;
  1027.         DEF_CYCLE(FileIOType)     = CurSettings.Setup.FileIOType;
  1028.         DEF_STRING(HotKey)                = CurSettings.Setup.HotKey;
  1029.         DEF_STRING(ScreenName)    = CurSettings.Setup.ScreenName;
  1030.         DEF_STRING(LogFile)               = CurSettings.Setup.LogFile;
  1031.         DEF_STRING(WindowFont)    = GetFontDesc(WindowFontDesc,
  1032.                                                                                     WindowFontName, WindowFontSize);
  1033.         DEF_STRING(BufferFont)    = GetFontDesc(BufferFontDesc,
  1034.                                                                                 BufferFontName, BufferFontSize);
  1035.         DEF_STRING(BufferFormat)  = BufFormat;
  1036.         DEF_STRING(LogfileFormat) = LogFormat;
  1037.  
  1038.         /*
  1039.          *              Next, onto the gadget creation itself
  1040.          */
  1041.         ng.ng_Height            = gheight; 
  1042.         ng.ng_TextAttr          = fontattr;
  1043.         ng.ng_VisualInfo        = SetVI;
  1044.         ng.ng_Flags         = PLACETEXT_LEFT;
  1045.  
  1046.         ngbut.ng_Height         = gheight; 
  1047.         ngbut.ng_TextAttr       = fontattr;
  1048.         ngbut.ng_VisualInfo     = SetVI;
  1049.         ngbut.ng_Flags          = PLACETEXT_IN;
  1050.  
  1051.         FileButtonImage = CreateCustomImage(IMAGE_FILE, gheight+2-2*SquareAspect);
  1052.         FontButtonImage = CreateCustomImage(IMAGE_FONT, gheight);
  1053.         if (!FileButtonImage || !FontButtonImage) {
  1054.                 CloseFont(font);
  1055.                 return (NULL);
  1056.         }
  1057.         gadlist = NULL;
  1058.         gad = CreateContext(&gadlist);
  1059.         if (!gad) {
  1060.                 CloseFont(font);
  1061.                 return (NULL);
  1062.         }
  1063.  
  1064.         for (sg = &SetGadgs[0]; sg->gadgid; sg++) {
  1065.                 ng.ng_LeftEdge          = colpos[sg->col];
  1066.                 ng.ng_Width                     = colwidth[sg->cwidth];
  1067.                 ng.ng_TopEdge           = yoffset + sg->row * spacing;
  1068.                 ng.ng_GadgetText        = MSG(sg->stringid);
  1069.                 ng.ng_GadgetID          = sg->gadgid;
  1070.                 ng.ng_Height            = gheight;
  1071.  
  1072.                 if (sg->promptid) {
  1073.                         /*
  1074.                          *              Create optional mini gadget to right of main gadget.
  1075.                          *              If data1 == 0 or data1 == 1 then use a file or font
  1076.                          *              BOOPSI gadget image, else use a Gadtools text button
  1077.                          *              containing the label corresponding to MSG(data1) else
  1078.                          *              use string ID indicated by data1
  1079.                          */
  1080.                         ngbut.ng_GadgetID  = sg->promptid;
  1081.                         ngbut.ng_TopEdge   = ng.ng_TopEdge;
  1082.                         ngbut.ng_Height    = gheight;
  1083.                         if (sg->gtype == STRING_KIND && !SquareAspect) {
  1084.                                 ngbut.ng_Height  += 2;
  1085.                                 ngbut.ng_TopEdge -= 1;
  1086.                         }
  1087.                         if (sg->data1 > SETBUTTON_MAX) {
  1088.                                 /*
  1089.                                  *              Creating a text gadget
  1090.                                  */
  1091.                                 ngbut.ng_LeftEdge   = ng.ng_LeftEdge + ng.ng_Width - miniwidth;
  1092.                                 ngbut.ng_Width          = miniwidth;
  1093.                                 ngbut.ng_GadgetText = MSG(sg->data1);
  1094.                                 gad = CreateGadget(BUTTON_KIND, gad, &ngbut,
  1095.                                                                    GT_Underscore, '_',
  1096.                                                                    TAG_DONE);
  1097.                                 if (!gad)
  1098.                                         goto sgad_failed;
  1099.                                 AddKeyShortcut(SetKeyboard, sg->promptid, sg->data1);
  1100.                         } else {
  1101.                                 /*
  1102.                                  *              Creating an image gadget
  1103.                                  */
  1104.                                 struct Image *img = FileButtonImage;
  1105.  
  1106.                                 if (sg->data1 == SETBUTTON_FONT)
  1107.                                         img = FontButtonImage;
  1108.  
  1109.                                 ngbut.ng_Width          = img->Width;
  1110.                                 ngbut.ng_GadgetText = NULL;
  1111.                                 ngbut.ng_LeftEdge   = ng.ng_LeftEdge + ng.ng_Width -img->Width;
  1112.                                 gad = CreateGadget(GENERIC_KIND, gad, &ngbut, TAG_DONE);
  1113.                                 if (!gad)
  1114.                                         goto sgad_failed;
  1115.  
  1116.                                 /*
  1117.                                  *              Now fill in the details of our gadget
  1118.                                  */
  1119.                                 gad->Flags                      |= GFLG_GADGIMAGE | GFLG_GADGHIMAGE;
  1120.                                 gad->Activation         |= GACT_IMMEDIATE | GACT_RELVERIFY;
  1121.                                 gad->GadgetType         |= GTYP_BOOLGADGET;
  1122.                                 gad->GadgetRender       = img;
  1123.                                 gad->SelectRender       = img + 1;
  1124.                         }
  1125.                         Gadget[sg->promptid] = gad;
  1126.                         ng.ng_Width     -= ngbut.ng_Width + 2;
  1127.                 }
  1128.                 switch (sg->gtype) {
  1129.                         case STRING_KIND:
  1130.                                 if (!SquareAspect) {
  1131.                                         ng.ng_Height  += 2;
  1132.                                         ng.ng_TopEdge -= 1;
  1133.                                 }
  1134.                                 gad = CreateGadget(STRING_KIND, gad, &ng,
  1135.                                                                    GT_Underscore,       '_',
  1136.                                                                    GTST_String,         sg->data2,
  1137.                                                                    GTST_MaxChars,       MAX_STR_LEN,
  1138.                                                                    TAG_DONE);
  1139.                                 break;
  1140.  
  1141.                         case TEXT_KIND:
  1142.                                 ng.ng_Width-= 2;
  1143.                                 ng.ng_LeftEdge++;
  1144.                                 gad = CreateGadget(TEXT_KIND, gad, &ng,
  1145.                                                                    GT_Underscore,       '_',
  1146.                                                                    GTTX_Text,           sg->data2,
  1147.                                                                    GTTX_Border,         TRUE,
  1148.                                                                    TAG_DONE);
  1149.                                 break;
  1150.  
  1151.                         case CYCLE_KIND:
  1152.                         {
  1153.                                 int *msgid = sg->data2;
  1154.                                 char **msg = sg->data3;
  1155.                                 int i;
  1156.  
  1157.                                 for (i = 0; msgid[i]; i++)
  1158.                                         msg[i] = MSG(msgid[i]);
  1159.                                 msg[i] = NULL;
  1160.                                 gad = CreateGadget(CYCLE_KIND, gad, &ng,
  1161.                                                                    GT_Underscore,       '_',
  1162.                                                                    GTCY_Active,         sg->data1,
  1163.                                                                    GTCY_Labels,         msg,
  1164.                                                                    TAG_DONE);
  1165.                                 break;
  1166.                         }
  1167.                 }
  1168.                 if (!gad)
  1169.                         goto sgad_failed;
  1170.                 Gadget[sg->gadgid] = gad;
  1171.                 AddKeyShortcut(SetKeyboard, sg->gadgid, sg->stringid);
  1172.         }
  1173.  
  1174.         ng.ng_GadgetText        = MSG(MSG_BUFFERSIZE_GAD);
  1175.         ng.ng_GadgetID          = GID_BUFFERSIZE;
  1176.         ng.ng_TopEdge           = yoffset + spacing * 4 + (1 - SquareAspect);
  1177.         ng.ng_Height            = gheight + (2 - 2 * SquareAspect);
  1178.         ng.ng_Width                     = GetTextLen(font, "10000") + 14;
  1179.         ng.ng_LeftEdge          = colpos[0] + colwidth[0] - ng.ng_Width;
  1180.  
  1181.         gad = CreateGadget(INTEGER_KIND,        gad, &ng,
  1182.                                            GT_Underscore,       '_',
  1183.                                            GTIN_Number,         CurSettings.Setup.BufferSize,
  1184.                                            TAG_DONE);
  1185.         if (!gad)
  1186.                 goto sgad_failed;
  1187.         Gadget[GID_BUFFERSIZE] = gad;
  1188.         AddKeyShortcut(SetKeyboard, GID_BUFFERSIZE, MSG_BUFFERSIZE_GAD);
  1189.  
  1190.         ng.ng_Width                     = MaxTextLen(font, UseCancelUndoText) + 32;
  1191.         ng.ng_Height            = fonty + GadgetHeight;
  1192.         ng.ng_GadgetText        = MSG(MSG_USE_GAD);
  1193.         ng.ng_GadgetID          = GID_SETUSE;
  1194.         ng.ng_LeftEdge          = BorderLeft + SET_MARGIN;
  1195.         ng.ng_TopEdge           = yoffset + 7 * spacing;
  1196.         ng.ng_Flags                     = PLACETEXT_IN;
  1197.  
  1198.         gad = CreateGadget(BUTTON_KIND,         gad, &ng,
  1199.                                            GT_Underscore,       '_',
  1200.                                            TAG_DONE);
  1201.         if (!gad)
  1202.                 goto sgad_failed;
  1203.         Gadget[GID_SETUSE] = gad;
  1204.         AddKeyShortcut(SetKeyboard, GID_SETUSE, MSG_USE_GAD);
  1205.         
  1206.         ng.ng_LeftEdge          = width - BorderRight - SET_MARGIN - ng.ng_Width;
  1207.         ng.ng_GadgetText        = MSG(MSG_CANCEL_GAD);
  1208.         ng.ng_GadgetID          = GID_SETCANCEL;
  1209.  
  1210.         gad = CreateGadget(BUTTON_KIND,         gad, &ng,
  1211.                                            GT_Underscore,       '_',
  1212.                                            TAG_DONE);
  1213.         if (!gad)
  1214.                 goto sgad_failed;
  1215.         Gadget[GID_SETCANCEL] = gad;
  1216.         AddKeyShortcut(SetKeyboard, GID_SETCANCEL, MSG_CANCEL_GAD);
  1217.         
  1218.         ng.ng_LeftEdge          = (ng.ng_LeftEdge + BorderLeft + SET_MARGIN) / 2;
  1219.         ng.ng_GadgetText        = MSG(MSG_UNDO_GAD);
  1220.         ng.ng_GadgetID          = GID_SETUNDO;
  1221.  
  1222.         gad = CreateGadget(BUTTON_KIND,         gad, &ng,
  1223.                                            GT_Underscore,       '_',
  1224.                                            TAG_DONE);
  1225.         if (!gad)
  1226.                 goto sgad_failed;
  1227.         Gadget[GID_SETUNDO] = gad;
  1228.         AddKeyShortcut(SetKeyboard, GID_SETUNDO, MSG_UNDO_GAD);
  1229.  
  1230.         CloseFont(font);
  1231.         return (gadlist);
  1232.  
  1233. sgad_failed:
  1234.         if (gadlist)
  1235.                 FreeGadgets(gadlist);
  1236.         CloseFont(font);
  1237.         return (FALSE);
  1238. }
  1239.  
  1240. /*
  1241.  *              OpenSettingsWindow()
  1242.  *
  1243.  *              Opens the settings window with all the settings gadgets.
  1244.  *              The window will contain all necessary gadgets. Note that
  1245.  *              since gadgets can take some time to create on 68000 systems,
  1246.  *              we cache the gadget list so that on subsequent re-opens of
  1247.  *              the window, we don't need to recreate them all.
  1248.  *
  1249.  *              Returns TRUE for success, false for failure.
  1250.  */
  1251. int OpenSettingsWindow(void)
  1252. {
  1253.         static struct TextAttr setfontattr =
  1254.                 { "empty-storage-for-setup-fonts..", 0, FS_NORMAL, FPB_DISKFONT};
  1255.  
  1256.         static int width;               /* Maintained from call to call */
  1257.         static int height;
  1258.  
  1259.         int left = CurSettings.SetupWinLeft;
  1260.         int top  = CurSettings.SetupWinTop;
  1261.         struct TextAttr *fontattr = NULL;
  1262.         struct Window *win;
  1263.  
  1264.         CheckSegTracker();
  1265.         if (SetWindow) {
  1266.                 WindowToFront(SetWindow);
  1267.                 ActivateWindow(SetWindow);
  1268.                 return (TRUE);
  1269.         }
  1270.         if (!CheckForScreen())
  1271.                 return (FALSE);
  1272.  
  1273.         SavedSetupSets = CurSettings;           /* Save so we can restore later */
  1274.  
  1275.         if (!SetGadList) {
  1276.                 /*
  1277.                  *              Find out what dimensions our new window should be; to do
  1278.                  *              this, we calculate the size with a variety of fonts until
  1279.                  *              we find one that works.
  1280.                  */
  1281.                 int i;
  1282.  
  1283.                 for (i = 0; fontattr = SubWindowFontList[i]; i++) {
  1284.                         if (CreateSettingsGadgets(fontattr, TRUE, &width, &height))
  1285.                                 break;
  1286.                 }
  1287.                 if (!fontattr) {
  1288.                         ShowError(MSG(MSG_ERROR_OPENSET));
  1289.                         return (FALSE);
  1290.                 }
  1291.                 /*
  1292.                  *              We need to make a copy of the fontattr now so that if
  1293.                  *              the user changes the font, all our gadgets don't suddenly
  1294.                  *              inherit the new font (at least until the window has been
  1295.                  *              closed and re-opened!)
  1296.                  */
  1297.                 strcpy(setfontattr.ta_Name, fontattr->ta_Name);
  1298.                 setfontattr.ta_YSize = fontattr->ta_YSize;
  1299.                 fontattr = &setfontattr;
  1300.         }
  1301.         if (left == -1)  left = (ScreenWidth  - width)  / 2;
  1302.         if (top  == -1)  top  = (ScreenHeight - height) / 2;
  1303.  
  1304.         win = OpenWindowTags(NULL,
  1305.                                                  WA_Title,                      MSG(MSG_SETTINGS_TITLE),
  1306.                                                  WA_IDCMP,                      IDCMP_CLOSEWINDOW        |
  1307.                                                                                         IDCMP_REFRESHWINDOW      |
  1308.                                                                                         IDCMP_NEWSIZE            |
  1309.                                                                                         IDCMP_RAWKEY             |
  1310.                                                                                         IDCMP_INACTIVEWINDOW |
  1311.                                                                                         BUTTONIDCMP,
  1312.                                                  WA_Left,                       left,
  1313.                                                  WA_Top,                        top,
  1314.                                                  WA_Width,                      width,
  1315.                                                  WA_Height,                     height,
  1316.                                                  WA_Flags,                      WFLG_DRAGBAR             |
  1317.                                                                                         WFLG_DEPTHGADGET         |
  1318.                                                                                         WFLG_ACTIVATE            |
  1319.                                                                                         WFLG_RMBTRAP             |
  1320.                                                                                         WFLG_NEWLOOKMENUS,
  1321.                                                  RefreshTag,            TRUE,
  1322.                                                  WA_NoCareRefresh,      NoCareRefreshBool,
  1323.                                                  WA_PubScreen,          SnoopScreen,
  1324.                                                  TAG_DONE);
  1325.         if (!win) {
  1326.                 ShowError(MSG(MSG_ERROR_OPENSET));
  1327.                 return (FALSE);
  1328.         }
  1329.         if (!SetGadList) {
  1330.                 SetGadList = CreateSettingsGadgets(fontattr, 0, 0, 0);
  1331.                 if (!SetGadList) {
  1332.                         CloseWindow(win);
  1333.                         ShowError(MSG(MSG_ERROR_OPENSET));
  1334.                         return (FALSE);
  1335.                 }
  1336.         }
  1337.         AddGList(win, SetGadList, -1, -1, NULL);
  1338.         RefreshGList(SetGadList, win, NULL, -1);
  1339.         GT_RefreshWindow(win, NULL);
  1340.  
  1341.         SetWindow               = win;
  1342.         SetWindowPort   = win->UserPort;
  1343.         SetWindowMask   = 1 << SetWindowPort->mp_SigBit;
  1344.         if (DisableNestCount)
  1345.                 DisableWindow(SetWindow, &SetRequester);
  1346.         return (TRUE);
  1347. }
  1348.  
  1349. /*
  1350.  *              CloseFunctionWindow(void)
  1351.  *
  1352.  *              Closes the functions window. Note that we do NOT free the gadget
  1353.  *              list in this case; since it takes so long to build, we leave it
  1354.  *              alone for the benefit of future opens.
  1355.  */
  1356. void CloseFunctionWindow(void)
  1357. {
  1358.         if (FuncWindow) {
  1359.                 RecordWindowSizes();
  1360.                 CloseWindow(FuncWindow);
  1361.                 FuncWindow     = NULL;
  1362.                 FuncWindowMask = 0;
  1363.         }
  1364.         if (PurgeFuncGadgets && FuncGadList) {
  1365.                 FreeGadgets(FuncGadList);
  1366.                 FuncGadList        = NULL;
  1367.         }
  1368.         if (PurgeFuncGadgets && FuncVI) {
  1369.                 FreeVisualInfo(FuncVI);
  1370.                 FuncVI = NULL;
  1371.         }
  1372.         PurgeFuncGadgets = 0;
  1373. }
  1374.  
  1375. /*
  1376.  *              CloseSettingsWindow(void)
  1377.  *
  1378.  *              Closes the settings window, and free gadgets associated with window.
  1379.  */
  1380. void CloseSettingsWindow(void)
  1381. {
  1382.         if (SetWindow) {
  1383.                 RecordWindowSizes();
  1384.                 CloseWindow(SetWindow);
  1385.                 SetWindow     = NULL;
  1386.                 SetWindowMask = 0;
  1387.         }
  1388.         if (SetGadList) {
  1389.                 FreeGadgets(SetGadList);
  1390.                 SetGadList = NULL;
  1391.         }
  1392.         if (FileButtonImage) {
  1393.                 FreeCustomImage(FileButtonImage);
  1394.                 FileButtonImage = NULL;
  1395.         }
  1396.         if (FontButtonImage) {
  1397.                 FreeCustomImage(FontButtonImage);
  1398.                 FontButtonImage = NULL;
  1399.         }
  1400.         if (SetVI) {
  1401.                 FreeVisualInfo(SetVI);
  1402.                 SetVI = NULL;
  1403.         }
  1404. }
  1405.  
  1406. /*
  1407.  *              HandleSettingsMsgs()
  1408.  *
  1409.  *              Processes all outstanding messages associated with the Settings
  1410.  *              gadget window. To be called whenever we get a settings event.
  1411.  */
  1412.  
  1413. #define STRVAL(gid)     (((struct StringInfo *)(Gadget[gid]->SpecialInfo))->Buffer)
  1414.  
  1415. void HandleSettingsMsgs(void)
  1416. {
  1417.         static int activegad;                   /* Non-zero if gadget is depressed   */
  1418.         static int activekey;                   /* Keycode shortcut of activegad     */
  1419.  
  1420.         struct IntuiMessage *imsg;
  1421.         int doneset = SEL_NONE;
  1422.         char *str;
  1423.         int val;
  1424.  
  1425.         if (!SetWindow)
  1426.                 return;
  1427.  
  1428.         while ((imsg = GT_GetIMsg(SetWindowPort)) != NULL) {
  1429.                 struct Gadget *gad;
  1430.                 int gadid;
  1431.                 int shift  = (imsg->Qualifier & IE_SHIFT);
  1432.                 int newval;
  1433.  
  1434.                 switch (imsg->Class) {
  1435.                         
  1436.                         case IDCMP_CLOSEWINDOW:
  1437.                                 doneset = SEL_USE;
  1438.                                 break;
  1439.  
  1440.                         case IDCMP_REFRESHWINDOW:
  1441.                                 GT_BeginRefresh(SetWindow);
  1442.                                 GT_EndRefresh(SetWindow, TRUE);
  1443.                                 break;
  1444.  
  1445.                         case IDCMP_MOUSEMOVE: 
  1446.                         case IDCMP_GADGETDOWN:
  1447.                         case IDCMP_GADGETUP:
  1448.                                 gad    = (struct Gadget *)imsg->IAddress;
  1449.                                 gadid  = gad->GadgetID;
  1450.                                 newval = imsg->Code;
  1451.  
  1452. handle_set_gads:
  1453.                                 switch (gadid) {
  1454.  
  1455.                                         case GID_FILEPROMPT:
  1456.                                         {
  1457.                                                 char *defname = "";
  1458.  
  1459.                                                 /*
  1460.                                                  *              Choose a default name for the logfile
  1461.                                                  */
  1462.                                                 if (IsFileSystem(DefaultLogName))
  1463.                                                         defname = DefaultLogName;
  1464.  
  1465.                                                 if (SelectFile(DefaultLogName, defname, SetWindow,
  1466.                                                                            FILESEL_DEFLOGNAME))
  1467.                                                 {
  1468.                                                         /*
  1469.                                                          *              Got a new default filename, so update
  1470.                                                          *              the logfile gadget accordingly
  1471.                                                          */
  1472.                                                         GT_SetGadgetAttrs(Gadget[GID_LOGFILE],
  1473.                                                                                           SetWindow, NULL,
  1474.                                                                                           GTST_String, DefaultLogName,
  1475.                                                                                           TAG_DONE);
  1476.                                                 }
  1477.                                                 break;
  1478.                                         }
  1479.  
  1480.                                         case GID_WFONTPROMPT:
  1481.                                                 /*
  1482.                                                  *              Choose a new gadget (window) font
  1483.                                                  */
  1484.                                                 if (SelectFont(SetWindow, FONTSEL_WINDOW)) {
  1485.                                                         strcpy(WindowFontName, WindowFR->fo_Attr.ta_Name);
  1486.                                                         WindowFontSize = WindowFR->fo_Attr.ta_YSize;
  1487.                                                         WindowFontAttr.ta_YSize = WindowFontSize;
  1488.  
  1489.                                                         GT_SetGadgetAttrs(
  1490.                                                                 Gadget[GID_WINDOWFONT], SetWindow, NULL,
  1491.                                                                 GTTX_Text, GetFontDesc(WindowFontDesc,
  1492.                                                                                                            WindowFontName,
  1493.                                                                                                            WindowFontSize),
  1494.                                                                 TAG_DONE);
  1495.                                                         ReOpenMainWindow();
  1496.                                                         WindowToFront(SetWindow);
  1497.                                                         /*
  1498.                                                          *              Since we allow the function gadgets
  1499.                                                          *              to hang around even when the function
  1500.                                                          *              window closes, we need to free the
  1501.                                                          *              gadgets when we change fonts to force
  1502.                                                          *              them to be regenerated in the new
  1503.                                                          *              font.
  1504.                                                          */             
  1505.                                                         if (!FuncWindow) {
  1506.                                                                 FreeGadgets(FuncGadList);
  1507.                                                                 FuncGadList              = NULL;
  1508.                                                         } else {
  1509.                                                                 PurgeFuncGadgets = TRUE;
  1510.                                                         }
  1511.                                                 }
  1512.                                                 break;
  1513.  
  1514.                                         case GID_BFONTPROMPT:
  1515.                                                 /*
  1516.                                                  *              Choose a new buffer font
  1517.                                                  */
  1518.                                                 if (SelectFont(SetWindow, FONTSEL_BUFFER)) {
  1519.                                                         strcpy(BufferFontName, BufferFR->fo_Attr.ta_Name);
  1520.                                                         BufferFontSize = BufferFR->fo_Attr.ta_YSize;
  1521.                                                         BufferFontAttr.ta_YSize = BufferFontSize;
  1522.  
  1523.                                                         GT_SetGadgetAttrs(
  1524.                                                                 Gadget[GID_BUFFERFONT],
  1525.                                                                 SetWindow, NULL,
  1526.                                                                 GTTX_Text, GetFontDesc(BufferFontDesc,
  1527.                                                                                                            BufferFontName,
  1528.                                                                                                            BufferFontSize),
  1529.                                                                 TAG_DONE);
  1530.                                                         ReOpenMainWindow();
  1531.                                                         WindowToFront(SetWindow);
  1532.                                                 }
  1533.                                                 break;
  1534.  
  1535.                                         case GID_FORMATEDIT:
  1536.                                                 OpenFormatWindow();
  1537.                                                 break;
  1538.  
  1539.                                         case GID_FORMATCOPY:
  1540.                                                 if (shift)
  1541.                                                         *LogFormat = '\0';
  1542.                                                 else
  1543.                                                         strcpy(LogFormat, BufFormat);
  1544.                                                 GT_SetGadgetAttrs(Gadget[GID_LOGFORMAT],
  1545.                                                                                   SetWindow, NULL,
  1546.                                                                                   GTST_String, LogFormat,
  1547.                                                                                   TAG_DONE);
  1548.                                                 break;
  1549.  
  1550.                                         case GID_FILEIO:
  1551.                                                 CurSettings.Setup.FileIOType = newval;
  1552.                                                 break;
  1553.  
  1554.                                         case GID_OPENON:
  1555.                                                 CurSettings.Setup.ScreenType = newval;
  1556.                                                 break;
  1557.  
  1558.                                         case GID_LOGMODE:
  1559.                                                 CurSettings.Setup.LogMode        = newval;
  1560.                                                 SetLogGadget(newval, LG_REFRESH);
  1561.                                                 break;
  1562.  
  1563.                                         case GID_HIDEMETHOD:
  1564.                                                 if (!CxBase)
  1565.                                                         newval = 0;
  1566.  
  1567.                                                 if (newval != CurSettings.Setup.HideMethod) {
  1568.                                                         int oldval = CurSettings.Setup.HideMethod;
  1569.  
  1570.                                                         CurSettings.Setup.HideMethod = newval;
  1571.                                                         if (newval == HIDE_NONE)
  1572.                                                                 CleanupHotKey();
  1573.                                                         else if (oldval == HIDE_NONE) {
  1574.                                                                 /*
  1575.                                                                  *              Switching out of hide state so
  1576.                                                                  *              re-activate hotkey
  1577.                                                                  */
  1578.                                                                 InstallHotKey(CurSettings.Setup.HotKey);
  1579.                                                         }
  1580.                                                         SetMainHideState(newval);
  1581.                                                 }
  1582.                                                 break;
  1583.  
  1584.                                         case GID_HOTKEY:
  1585.                                         {
  1586.                                                 char *msg = CurSettings.Setup.HotKey;
  1587.  
  1588.                                                 strcpy(msg, STRVAL(GID_HOTKEY));
  1589.                                                 InstallHotKey(msg);
  1590.                                                 SetMainHideState(CurSettings.Setup.HideMethod);
  1591.                                                 break;
  1592.                                         }
  1593.  
  1594.                                         case GID_SCREENNAME:
  1595.                                                 strcpy(CurSettings.Setup.ScreenName,
  1596.                                                            STRVAL(GID_SCREENNAME));
  1597.                                                 break;
  1598.  
  1599.                                         case GID_LOGFILE:
  1600.                                                 strcpy(CurSettings.Setup.LogFile, STRVAL(GID_LOGFILE));
  1601.                                                 break;
  1602.  
  1603.                                         case GID_LOGFORMAT:
  1604.                                                 strcpy(CurSettings.Setup.LogfileFormat,
  1605.                                                            STRVAL(GID_LOGFORMAT));
  1606.                                                 break;
  1607.  
  1608.                                         case GID_BUFFORMAT:
  1609.                                                 str = STRVAL(GID_BUFFORMAT);
  1610.                                                 if (strcmp(BufFormat, str) != 0) {
  1611.                                                         strcpy(BufFormat, str);
  1612.                                                         InstallNewFormat(NEW_STRING);
  1613.                                                 }
  1614.                                                 break;
  1615.  
  1616.                                         case GID_BUFFERSIZE:
  1617.                                                 /*
  1618.                                                  *              We don't do anything here at all ... instead,
  1619.                                                  *              the update is handled when the user clicks
  1620.                                                  *              on USE.
  1621.                                                  */
  1622.                                                 break;
  1623.  
  1624.                                         case GID_SETUSE:
  1625.                                                 doneset = SEL_USE;
  1626.                                                 break;
  1627.  
  1628.                                         case GID_SETCANCEL:
  1629.                                                 doneset = SEL_CANCEL;
  1630.                                                 break;
  1631.  
  1632.                                         case GID_SETUNDO:
  1633.                                                 /*
  1634.                                                  *              Major bummer -- we need to manually update
  1635.                                                  *              ALL the string gadgets, since if the user
  1636.                                                  *              modified one of them and didn't press RETURN
  1637.                                                  *              we won't have picked it up and so we won't
  1638.                                                  *              know to undo it :-(
  1639.                                                  */
  1640.                                                 InstallSettings(&SavedSetupSets, SET_SETUP);
  1641.  
  1642. #define UndoSet SavedSetupSets.Setup
  1643.  
  1644.                                                 GT_SetGadgetAttrs(Gadget[GID_HOTKEY],
  1645.                                                                                   SetWindow, NULL,
  1646.                                                                                   GTST_String, UndoSet.HotKey,
  1647.                                                                                   TAG_DONE);
  1648.                                                 GT_SetGadgetAttrs(Gadget[GID_SCREENNAME],
  1649.                                                                                   SetWindow, NULL,
  1650.                                                                                   GTST_String, UndoSet.ScreenName,
  1651.                                                                                   TAG_DONE);
  1652.                                                 GT_SetGadgetAttrs(Gadget[GID_LOGFILE],
  1653.                                                                                   SetWindow, NULL,
  1654.                                                                                   GTST_String, UndoSet.LogFile,
  1655.                                                                                   TAG_DONE);
  1656.                                                 GT_SetGadgetAttrs(Gadget[GID_BUFFORMAT],
  1657.                                                                                   SetWindow, NULL,
  1658.                                                                                   GTST_String, UndoSet.BufferFormat,
  1659.                                                                                   TAG_DONE);
  1660.                                                 GT_SetGadgetAttrs(Gadget[GID_LOGFORMAT],
  1661.                                                                                   SetWindow, NULL,
  1662.                                                                                   GTST_String, UndoSet.LogfileFormat,
  1663.                                                                                   TAG_DONE);
  1664.                                                 GT_SetGadgetAttrs(Gadget[GID_BUFFERSIZE],
  1665.                                                                                   SetWindow, NULL,
  1666.                                                                                   GTIN_Number, UndoSet.BufferSize,
  1667.                                                                                   TAG_DONE);
  1668.                                                 break;
  1669.                                 }
  1670.                                 break;
  1671.  
  1672.                         case IDCMP_INACTIVEWINDOW:
  1673.                                 if (activegad) {
  1674.                                         ShowGadget(SetWindow, Gadget[activegad], GADGET_UP);
  1675.                                         activegad = 0;
  1676.                                 }
  1677.                                 break;
  1678.  
  1679.                         case IDCMP_RAWKEY:
  1680.                         {
  1681.                                 int upstroke = imsg->Code & 0x80;
  1682.                                 int keypress = ConvertIMsgToChar(imsg);
  1683.  
  1684.                                 gadid  = SetKeyboard[keypress];
  1685.                                 if (activegad) {
  1686.                                         /*
  1687.                                          *              We're releasing a gadget that was pressed
  1688.                                          *              earlier, so handle it now
  1689.                                          */
  1690.                                         int samekey = (imsg->Code & 0x7f) == activekey;
  1691.  
  1692.                                         if (samekey && !upstroke)       /* Ignore repeated keys */
  1693.                                                 break;
  1694.  
  1695.                                         ShowGadget(SetWindow, Gadget[activegad], GADGET_UP);
  1696.                                         if (samekey) {
  1697.                                                 /*
  1698.                                                  *              Just released the key that was originally
  1699.                                                  *              pressed for this gadget, so now go and
  1700.                                                  *              handle the gadget action.
  1701.                                                  */
  1702.                                                 gadid     = activegad;
  1703.                                                 gad       = Gadget[gadid];
  1704.                                                 activegad = 0;
  1705.                                                 goto handle_set_gads;
  1706.                                         }
  1707.  
  1708.                                         /*
  1709.                                          *              If the above check didn't kick in, it means
  1710.                                          *              we got a downpress of a different key, so
  1711.                                          *              disable the gadget for this key and continue
  1712.                                          *              to press the other key.
  1713.                                          */
  1714.                                         activegad = 0;
  1715.                                 }
  1716.  
  1717.                                 if (imsg->Code == HELPKEY) {
  1718.                                         ShowAGuide(MSG(MSG_LINK_SETUPWIN));
  1719.                                         break;
  1720.                                 }
  1721.  
  1722.                                 /*
  1723.                                  *              Handle keyboard equivalent keypresses for gadgets
  1724.                                  */
  1725.                                 if (gadid) {
  1726.                                         int numopts;
  1727.  
  1728.                                         gad = Gadget[gadid];
  1729.  
  1730.                                         switch (gadid) {
  1731.                                                 case GID_HIDEMETHOD:
  1732.                                                         newval  = CurSettings.Setup.HideMethod;
  1733.                                                         numopts = HIDE_MAX;
  1734.                                                         goto handle_set_cycle;
  1735.  
  1736.                                                 case GID_OPENON:
  1737.                                                         newval  = CurSettings.Setup.ScreenType;
  1738.                                                         numopts = SCREEN_MAX;
  1739.                                                         goto handle_set_cycle;
  1740.  
  1741.                                                 case GID_LOGMODE:
  1742.                                                         newval  = CurSettings.Setup.LogMode;
  1743.                                                         numopts = LOGMODE_MAX;
  1744.                                                         goto handle_set_cycle;
  1745.  
  1746.                                                 case GID_FILEIO:
  1747.                                                         newval  = CurSettings.Setup.FileIOType;
  1748.                                                         numopts = FILE_MAX;
  1749. handle_set_cycle:
  1750.                                                         newval++;
  1751.                                                         if (shift)
  1752.                                                                 newval -= 2;
  1753.                                                         if (newval < 0)                 newval += numopts;
  1754.                                                         if (newval >= numopts)  newval -= numopts;
  1755.                                                         GT_SetGadgetAttrs(gad, SetWindow, NULL,
  1756.                                                                                           GTCY_Active, newval,
  1757.                                                                                           TAG_DONE);
  1758.                                                         goto handle_set_gads;
  1759.  
  1760.                                                 case GID_BUFFERSIZE:
  1761.                                                 case GID_BUFFORMAT:
  1762.                                                 case GID_LOGFORMAT:
  1763.                                                 case GID_HOTKEY:
  1764.                                                 case GID_SCREENNAME:
  1765.                                                 case GID_LOGFILE:
  1766.                                                         if (gadid != GID_LOGFILE || !shift) {
  1767.                                                                 ActivateGadget(gad, SetWindow, NULL);
  1768.                                                                 break;
  1769.                                                         }
  1770.                                                         /*
  1771.                                                          *              User pressed GID_LOGFILE with SHIFT
  1772.                                                          *              pressed, so change gadget type to
  1773.                                                          *              GID_FILEPROMPT and fall through to
  1774.                                                          *              button code.
  1775.                                                          */
  1776.                                                         gadid = GID_FILEPROMPT;
  1777.                                                         /* Fall through */
  1778.  
  1779.                                                 case GID_SETUSE:
  1780.                                                 case GID_SETUNDO:
  1781.                                                 case GID_SETCANCEL:
  1782.                                                 case GID_FORMATCOPY:
  1783.                                                 case GID_FORMATEDIT:
  1784.                                                 case GID_WINDOWFONT:
  1785.                                                 case GID_BUFFERFONT:
  1786.                                                 case GID_WFONTPROMPT:
  1787.                                                 case GID_BFONTPROMPT:
  1788.                                                         if (gadid == GID_WINDOWFONT)
  1789.                                                                 gadid = GID_WFONTPROMPT;
  1790.                                                         if (gadid == GID_BUFFERFONT)
  1791.                                                                 gadid = GID_BFONTPROMPT;
  1792.                                                         gad = Gadget[gadid];
  1793.                                                         ShowGadget(SetWindow, gad, GADGET_DOWN);
  1794.                                                         activegad = gadid;
  1795.                                                         activekey = imsg->Code;
  1796.                                                         break;
  1797.                                         }
  1798.                                 }
  1799.                                 break;
  1800.                         }
  1801.                 }
  1802.                 GT_ReplyIMsg(imsg);
  1803.         }
  1804.         /*
  1805.          *              Handled all messages. Now check for possible USE/CANCEL
  1806.          */
  1807.         if (doneset == SEL_USE) {
  1808.                 /*
  1809.                  *              Use the current settings. To be safe, we update all
  1810.                  *              our string gadgets in case they were modified but
  1811.                  *              we didn't catch the modification (i.e. user didn't press
  1812.                  *              Return).
  1813.                  */
  1814.                 str = STRVAL(GID_BUFFORMAT);
  1815.                 if (strcmp(BufFormat, str) != 0) {
  1816.                         strcpy(BufFormat, str);
  1817.                         InstallNewFormat(NEW_STRING);
  1818.                 }
  1819.                 strcpy(CurSettings.Setup.LogFile,                STRVAL(GID_LOGFILE));
  1820.                 strcpy(CurSettings.Setup.ScreenName,     STRVAL(GID_SCREENNAME));
  1821.                 strcpy(CurSettings.Setup.HotKey,                 STRVAL(GID_HOTKEY));
  1822.                 strcpy(CurSettings.Setup.LogfileFormat,  STRVAL(GID_LOGFORMAT));
  1823.                 strcpy(CurSettings.Setup.LogfileFormat,  STRVAL(GID_LOGFORMAT));
  1824.                 val = atoi(STRVAL(GID_BUFFERSIZE));
  1825.                 CloseSettingsWindow();
  1826.                 /*
  1827.                  *              Now check if we've got a new buffer size --
  1828.                  *              if so, install it.
  1829.                  */
  1830.                 if (val < 1)
  1831.                         val = 1;
  1832.  
  1833.                 if (val != SavedSetupSets.Setup.BufferSize) {
  1834.                         CurSettings.Setup.BufferSize = val;
  1835.                         ClearWindowBuffer();
  1836.                         if (!SetTotalBufferSize(val * 1024, SETBUF_FORCENEW)) {
  1837.                                 ShowError(MSG(MSG_ERROR_NOBUFMEM), val);
  1838.                                 Cleanup(20);
  1839.                         }
  1840.                 }
  1841.         } else if (doneset == SEL_CANCEL) {
  1842.                 /*
  1843.                  *              Cancel the current settings, and restore those that
  1844.                  *              were in effect before we started this. We close
  1845.                  *              the settings window first in case the main window
  1846.                  *              needs to close and re-open (change of font) since
  1847.                  *              this looks cleaner.
  1848.                  *
  1849.                  *              Note that even though we saved the entire set of settings,
  1850.                  *              we only restore the SETUP settings, not all of them.
  1851.                  */
  1852.                 CloseSettingsWindow();
  1853.                 InstallSettings(&SavedSetupSets, SET_SETUP);
  1854.         }
  1855. }
  1856.  
  1857. /*
  1858.  *              ShowFuncOpts(options, firstid, lastid)
  1859.  *
  1860.  *              Updates the function window gadgets to reflect the new values
  1861.  *              in the specified options array.
  1862.  *
  1863.  *              The new options are compared with the existing options to see
  1864.  *              if they've changed, so you should make sure to call this function
  1865.  *              _before_ copying the new options onto the current settings.
  1866.  *
  1867.  *              Only gadgets from the first to the last ID given are affected.
  1868.  */
  1869. void ShowFuncOpts(UBYTE newopts[], int firstid, int lastid)
  1870. {
  1871.         int i;
  1872.  
  1873.         for (i = firstid; i <= lastid; i++) {
  1874.                 if (Gadget[i] != NULL && newopts[i] != CurSettings.Func.Opts[i]) {
  1875.                         GT_SetGadgetAttrs(Gadget[i], FuncWindow, NULL,
  1876.                                                           GTCB_Checked, newopts[i],
  1877.                                                           TAG_DONE);
  1878.                 }
  1879.         }
  1880. }
  1881.  
  1882. /*
  1883.  *              ResetFuncToSelected()
  1884.  *
  1885.  *              Changes the two cycle gadgets in the function window back to the
  1886.  *              SELECTED state, and updates the variables accordingly. Note
  1887.  *              that doesn't change the actual boolean settings themselves; in
  1888.  *              effect, it makes the current settings permanent by stopping you
  1889.  *              switching back to the SELECTED state to restore an older set
  1890.  *              by clicking on the cycle gadget yourself.
  1891.  */
  1892. void ResetFuncToSelected(void)
  1893. {
  1894.         if (FuncSystemCol != COL_SELECTED) {
  1895.                 GT_SetGadgetAttrs(Gadget[GID_SELSYSTEM],
  1896.                                                   FuncWindow, NULL,
  1897.                                                   GTCY_Active, COL_SELECTED,
  1898.                                                   TAG_DONE);
  1899.         }
  1900.         if (FuncDOSCol != COL_SELECTED) {
  1901.                 GT_SetGadgetAttrs(Gadget[GID_SELDOS],
  1902.                                                   FuncWindow, NULL,
  1903.                                                   GTCY_Active, COL_SELECTED,
  1904.                                                   TAG_DONE);
  1905.         }
  1906.         FuncSystemCol = COL_SELECTED;
  1907.         FuncDOSCol    = COL_SELECTED;
  1908. }
  1909.  
  1910. /*
  1911.  *              HandleFuncMsgs()
  1912.  *
  1913.  *              Processes all outstanding messages associated with the Functions
  1914.  *              gadget window. To be called whenever we get a functions event.
  1915.  *
  1916.  *              The only slightly complicated bit here concerns the two cycle
  1917.  *              gadgets which can be used to select all or none of either of
  1918.  *              the DOS and System columns, or to restore a previous setting
  1919.  *              installed before.
  1920.  */
  1921. void HandleFuncMsgs(void)
  1922. {
  1923.         static int activegad;                   /* Non-zero if gadget is depressed   */
  1924.         static int activekey;                   /* Keycode shortcut of activegad     */
  1925.  
  1926.         struct IntuiMessage *imsg;
  1927.         int donefunc = SEL_NONE;
  1928.  
  1929.         if (!FuncWindow)
  1930.                 return;
  1931.  
  1932.         while ((imsg = GT_GetIMsg(FuncWindowPort)) != NULL) {
  1933.                 struct Gadget *gad;
  1934.                 int shift = (imsg->Qualifier & IE_SHIFT);
  1935.                 LONG gadid;
  1936.                 int newval;
  1937.  
  1938.                 switch (imsg->Class) {
  1939.                         
  1940.                         case IDCMP_REFRESHWINDOW:
  1941.                                 GT_BeginRefresh(FuncWindow);
  1942.                                 GT_EndRefresh(FuncWindow, TRUE);
  1943.                                 break;
  1944.  
  1945.                         case IDCMP_CLOSEWINDOW:
  1946.                                 donefunc = SEL_USE;
  1947.                                 break;
  1948.  
  1949.                         case IDCMP_MOUSEMOVE: 
  1950.                         case IDCMP_GADGETDOWN:
  1951.                         case IDCMP_GADGETUP:
  1952.                                 gad    = (struct Gadget *)imsg->IAddress;
  1953.                                 gadid  = gad->GadgetID;
  1954.                                 newval = imsg->Code;
  1955.  
  1956. handle_func_gads:
  1957.  
  1958.                                 switch (gadid) {
  1959.  
  1960.                                         case GID_MATCHNAME:
  1961.                                                 strcpy(MatchName, STRVAL(GID_MATCHNAME));
  1962.                                                 SetPattern(MatchName, IgnoreWBShell);
  1963.                                                 break;
  1964.  
  1965.                                         case GID_SELSYSTEM:
  1966.                                         case GID_SELDOS:
  1967.                                                 /*
  1968.                                                  *              Changing system column cycle gadget.
  1969.                                                  *              Update to show ALL, NONE or SELECTED
  1970.                                                  *              system gadgets.
  1971.                                                  */
  1972.                                         {
  1973.                                                 int first    = FIRST_SYS_GADGET;
  1974.                                                 int last     = LAST_SYS_GADGET;
  1975.                                                 int numgads  = NUM_SYS_GADGETS;
  1976.                                                 int *pcurval = &FuncSystemCol;
  1977.  
  1978.                                                 if (gadid == GID_SELDOS) {
  1979.                                                         /*
  1980.                                                          *              Override above defaults with new
  1981.                                                          *              defaults for DOS cycle gadget
  1982.                                                          */
  1983.                                                         first    = FIRST_DOS_GADGET;
  1984.                                                         last     = LAST_DOS_GADGET;
  1985.                                                         numgads  = NUM_DOS_GADGETS;
  1986.                                                         pcurval  = &FuncDOSCol;
  1987.                                                 }
  1988.                                                 if (newval == *pcurval)
  1989.                                                         break;          /* Ignore no-op events */
  1990.  
  1991.                                                 if (newval == COL_SELECTED) {
  1992.                                                         /*
  1993.                                                          *              Restore previously saved system col values
  1994.                                                          */
  1995.                                                         ShowFuncOpts(SavedCols, first, last);
  1996.                                                         memcpy(&CurSettings.Func.Opts[first],
  1997.                                                                    &SavedCols[first], numgads);
  1998.                                                 } else {
  1999.                                                         /*
  2000.                                                          *              Select either ALL or NONE of the settings
  2001.                                                          *              in the system column.
  2002.                                                          */
  2003.                                                         int fillval = (newval == COL_ALL);
  2004.  
  2005.                                                         memset(&TempCols[first], fillval, numgads);
  2006.                                                         ShowFuncOpts(TempCols, first, last);
  2007.                                                                         
  2008.                                                         if (*pcurval == COL_SELECTED) {
  2009.                                                            /*
  2010.                                                             *           If we are moving out of the
  2011.                                                                 *               selected state, then save the
  2012.                                                                 *               existing settings for later.
  2013.                                                                 */
  2014.                                                            memcpy(&SavedCols[first],
  2015.                                                                           &CurSettings.Func.Opts[first], numgads);
  2016.                                                         }
  2017.                                                         memset(&CurSettings.Func.Opts[first],
  2018.                                                                    fillval, numgads);
  2019.                                                 }
  2020.                                                 LoadFuncSettings(&CurSettings.Func);
  2021.                                                 *pcurval = newval;
  2022.                                                 break;
  2023.                                         }
  2024.  
  2025.                                         case GID_FUNCUSE:
  2026.                                                 /*
  2027.                                                  *              Retain existing settings, and exit
  2028.                                                  */
  2029.                                                 donefunc = SEL_USE;
  2030.                                                 break;
  2031.  
  2032.                                         case GID_FUNCCANCEL:
  2033.                                                 /*
  2034.                                                  *              Restore original settings and exit
  2035.                                                  */
  2036.                                                 donefunc = SEL_CANCEL;
  2037.                                                 break;
  2038.  
  2039.                                         case GID_FUNCUNDO:
  2040.                                                 /*
  2041.                                                  *              Restore original settings but don't exit
  2042.                                                  */
  2043.                                                 InstallSettings(&SavedFuncSets, SET_FUNC);
  2044.                                                 break;
  2045.  
  2046.                                         default:
  2047.                                                 if (gadid >= FIRST_BOOL_GADGET &&
  2048.                                                                                                 gadid <= LAST_BOOL_GADGET) {
  2049.                                                         /*
  2050.                                                          *              Getting a new boolean gadget so update
  2051.                                                          *              CurSettings to reflect this.
  2052.                                                          */
  2053.                                                         CurSettings.Func.Opts[gadid] =
  2054.                                                                                 (gad->Flags & GFLG_SELECTED) != 0;
  2055.                                                         LoadFuncSettings(&CurSettings.Func);
  2056.                                                         /*
  2057.                                                          *              Now check to see if we need to put
  2058.                                                          *              either column back into the selected
  2059.                                                          *              state again.
  2060.                                                          */
  2061.                                                         if (FuncSystemCol != COL_SELECTED &&
  2062.                                                                 gadid >= FIRST_SYS_GADGET         &&
  2063.                                                             gadid <= LAST_SYS_GADGET)
  2064.                                                         {
  2065.                                                                 FuncSystemCol = COL_SELECTED;
  2066.                                                                 GT_SetGadgetAttrs(Gadget[GID_SELSYSTEM],
  2067.                                                                                                   FuncWindow, NULL,
  2068.                                                                                                   GTCY_Active, COL_SELECTED,
  2069.                                                                                                   TAG_DONE);
  2070.                                                         }
  2071.                                                         if (FuncDOSCol != COL_SELECTED  &&
  2072.                                                                 gadid >= FIRST_DOS_GADGET       &&
  2073.                                                             gadid <= LAST_DOS_GADGET)
  2074.                                                         {
  2075.                                                                 FuncDOSCol = COL_SELECTED;
  2076.                                                                 GT_SetGadgetAttrs(Gadget[GID_SELDOS],
  2077.                                                                                                   FuncWindow, NULL,
  2078.                                                                                                   GTCY_Active, COL_SELECTED,
  2079.                                                                                                   TAG_DONE);
  2080.                                                         }
  2081.                                                 }
  2082.                                                 break;
  2083.                                 }
  2084.                                 break;
  2085.  
  2086.                         case IDCMP_INACTIVEWINDOW:
  2087.                                 if (activegad) {
  2088.                                         ShowGadget(FuncWindow, Gadget[activegad], GADGET_UP);
  2089.                                         activegad = 0;
  2090.                                 }
  2091.                                 break;
  2092.  
  2093.                         case IDCMP_RAWKEY:
  2094.                         {
  2095.                                 int upstroke = imsg->Code & 0x80;
  2096.                                 int keypress = ConvertIMsgToChar(imsg);
  2097.  
  2098.                                 gadid  = FuncKeyboard[keypress];
  2099.                                 if (activegad) {
  2100.                                         /*
  2101.                                          *              We're releasing a gadget that was pressed
  2102.                                          *              earlier, so handle it now
  2103.                                          */
  2104.                                         int samekey = (imsg->Code & 0x7f) == activekey;
  2105.  
  2106.                                         if (samekey && !upstroke)       /* Ignore repeated keys */
  2107.                                                 break;
  2108.  
  2109.                                         ShowGadget(FuncWindow, Gadget[activegad], GADGET_UP);
  2110.                                         if (samekey) {
  2111.                                                 /*
  2112.                                                  *              Just released the key that was originally
  2113.                                                  *              pressed for this gadget, so now go and
  2114.                                                  *              handle the gadget action.
  2115.                                                  */
  2116.                                                 gadid     = activegad;
  2117.                                                 gad       = Gadget[gadid];
  2118.                                                 activegad = 0;
  2119.                                                 goto handle_func_gads;
  2120.                                         }
  2121.                                         /*
  2122.                                          *              If the above check didn't kick in, it means
  2123.                                          *              we got a downpress of a different key, so
  2124.                                          *              disable the gadget for this key and continue
  2125.                                          *              to press the other key.
  2126.                                          */
  2127.                                         activegad = 0;
  2128.                                 }
  2129.  
  2130.                                 if (imsg->Code == HELPKEY) {
  2131.                                         ShowAGuide(MSG(MSG_LINK_FUNCWIN));
  2132.                                         break;
  2133.                                 }
  2134.  
  2135.                                 /*
  2136.                                  *              Handle keyboard equivalents for gadgets
  2137.                                  */
  2138.                                 gadid = FuncKeyboard[keypress];
  2139.                                 if (gadid) {
  2140.                                         gad = Gadget[gadid];
  2141.  
  2142.                                         if (gadid >= FIRST_BOOL_GADGET &&
  2143.                                                                                 gadid <= LAST_BOOL_GADGET) {
  2144.                                                 /*
  2145.                                                  *              It's a boolean gadget so just invert its
  2146.                                                  *              current setting
  2147.                                                  */
  2148.                                                 newval = !CurSettings.Func.Opts[gadid];
  2149.                                                 GT_SetGadgetAttrs(Gadget[gadid], FuncWindow, NULL,
  2150.                                                                                   GTCB_Checked, newval, TAG_DONE);
  2151.                                                 goto handle_func_gads;
  2152.                                         } else if (gadid == GID_SELSYSTEM || gadid == GID_SELDOS) {
  2153.                                                 /*
  2154.                                                  *              One of the two cycle gadgets. Cycle forward
  2155.                                                  *              if the unshifted key was pressed or back
  2156.                                                  *              if the shifted version was pressed
  2157.                                                  */
  2158.                                                 newval = FuncSystemCol;
  2159.                                                 if (gadid == GID_SELDOS)
  2160.                                                         newval = FuncDOSCol;
  2161.                                                 newval++;
  2162.                                                 if (shift)
  2163.                                                         newval -= 2;
  2164.                                                 if (newval < 0) newval = 2;
  2165.                                                 if (newval > 2) newval = 0;
  2166.                                                 GT_SetGadgetAttrs(gad, FuncWindow, NULL,
  2167.                                                                                   GTCY_Active, newval, TAG_DONE);
  2168.                                                 goto handle_func_gads;
  2169.                                         } else if (gadid == GID_MATCHNAME) {
  2170.                                                 /* 
  2171.                                                  *              The string gadget, so simply activate it
  2172.                                                  */
  2173.                                                 ActivateGadget(gad, FuncWindow, NULL);
  2174.                                         } else {
  2175.                                                 /*
  2176.                                                  *              It must be a button gadget so show it
  2177.                                                  *              selected first before processing it
  2178.                                                  */
  2179.                                                 ShowGadget(FuncWindow, gad, GADGET_DOWN);
  2180.                                                 activegad = gadid;
  2181.                                                 activekey = imsg->Code;
  2182.                                         }
  2183.                                 }
  2184.                                 break;
  2185.                         }
  2186.                 }
  2187.                 GT_ReplyIMsg(imsg);
  2188.         }
  2189.         if (donefunc != SEL_NONE) {
  2190.                 /*
  2191.                  *              Since we cache the function gadgets between window opens,
  2192.                  *              we need to ensure the two cycle gadgets are reset to
  2193.                  *              SELECTED mode ready for the next time we open the window.
  2194.                  *              (Ideally, we would remember the cycle state and use the
  2195.                  *              same state next time, but that's too much work!)
  2196.                  */
  2197.                 ResetFuncToSelected();
  2198.         }
  2199.         if (donefunc == SEL_USE) {
  2200.                 strcpy(MatchName, STRVAL(GID_MATCHNAME));
  2201.                 SetPattern(MatchName, IgnoreWBShell);
  2202.                 CloseFunctionWindow();
  2203.         } else if (donefunc == SEL_CANCEL) {
  2204.                 CloseFunctionWindow();
  2205.                 /*
  2206.                  *              Note that though we saved all the settings, we only
  2207.                  *              re-install the original function settings, not all
  2208.                  *              of them.
  2209.                  */
  2210.                 InstallSettings(&SavedFuncSets, SET_FUNC);
  2211.         }
  2212. }
  2213.  
  2214. /*
  2215.  *              CreateFormatGadgets(gadgetfa, bufferfa, getsize, &width, &height)
  2216.  *
  2217.  *              Creates all the gadgets for the format window. If getsize
  2218.  *              is true, then the width and height values are filled in with
  2219.  *              the dimensions of the window needed to hold the gadgets. In
  2220.  *              this case, NULL is returned if the window would be too big to
  2221.  *              fit on the current screen, or non-NULL if width and height
  2222.  *              were successfully initialised.
  2223.  *
  2224.  *              gadgetfa gives the gadget font to use, bufferfa gives the buffer
  2225.  *              font (for the format listings).
  2226.  *
  2227.  *              If getsize is zero, then the actual gadgets are created and
  2228.  *              a pointer to the gadget list is returned, or NULL if an
  2229.  *              error occurred (typically, out of memory).
  2230.  */
  2231. struct Gadget *CreateFormatGadgets(struct TextAttr *gadgetfa,
  2232.                                                                    struct TextAttr *bufferfa,
  2233.                                                                    int getsize, int *pwidth, int *pheight)
  2234. {
  2235.         struct TextFont *gfont;
  2236.         struct TextFont *bfont;
  2237.         struct NewGadget ng;
  2238.         struct Gadget *gadlist;
  2239.         struct Gadget *gad;
  2240.         FieldInit *fi;
  2241.         int width;
  2242.         int height;
  2243.         int gwidth;
  2244.         int gheight;
  2245.         int gfonty;
  2246.         int bfontx;
  2247.         int bfonty;
  2248.         int topline;
  2249.         int maxtitlelen;
  2250.         int buttonwidth;
  2251.         int buttonspace;
  2252.         int headingspace;
  2253.         int outmargin;
  2254.  
  2255.         if (!FormVI) {
  2256.                 FormVI = GetVisualInfoA(SnoopScreen, NULL);
  2257.                 if (!FormVI)
  2258.                         return (NULL);
  2259.         }
  2260.         gfont = MyOpenFont(gadgetfa);
  2261.         if (!gfont)
  2262.                 return (NULL);
  2263.  
  2264.         bfont = MyOpenFont(bufferfa);
  2265.         if (!bfont) {
  2266.                 CloseFont(gfont);
  2267.                 return (NULL);
  2268.         }
  2269.         if (bfont->tf_Flags & FPF_PROPORTIONAL) {
  2270.                 CloseFont(bfont);
  2271.                 CloseFont(gfont);
  2272.                 return (NULL);
  2273.         }
  2274.         bfontx          = bfont->tf_XSize;
  2275.         bfonty          = bfont->tf_YSize;
  2276.         gfonty          = gfont->tf_YSize;
  2277.         gheight         = gfonty  + 3;
  2278.         gwidth          = gheight + 15;
  2279.         topline     = TitlebarHeight + gfonty/2;
  2280.  
  2281.         /*
  2282.          *              Now calculate the width of the window boxes which will contain
  2283.          *              the format sequences being displayed. The defaults box must be
  2284.          *              wide enough to hold "titlemsg..  %x" whereas the current format
  2285.          *              box must be wide enough to hold "titlemsg..  %20x".
  2286.          *
  2287.          *              Since the message titles may be localised, we calculate the
  2288.          *              longest string and work from that.
  2289.          */
  2290.         maxtitlelen = 0;
  2291.         for (fi = FieldTypes; fi->type != EF_END; fi++) {
  2292.                 int len = strlen(MSG(fi->titlemsgid));
  2293.  
  2294.                 if (len > maxtitlelen)
  2295.                         maxtitlelen = len;
  2296.         }
  2297.         /*
  2298.          *              The next two vars give the number of characters that will fit
  2299.          *              across each box. These is used when producing output.
  2300.          *
  2301.          *              For the left box, this is the length of the longest heading title,
  2302.          *              plus 2 for spacing after the heading name, another 2 for the
  2303.          *              format ID (%x) and a final 2 for the spacing on either side.
  2304.          *
  2305.          *              The right box is similar, but uses an additional 2 characters to
  2306.          *              display the field width of the selected item.
  2307.          */
  2308.         FBoxA_NumChars  = maxtitlelen   + 6;
  2309.         FBoxB_NumChars  = FBoxA_NumChars + 2;
  2310.         FBoxA_Width     = FBoxA_NumChars * bfontx + 4;
  2311.         FBoxB_Width     = FBoxB_NumChars * bfontx + 4;
  2312.  
  2313.         /*
  2314.          *              Create format strings for sprintf formatting later on. These
  2315.          *              look like this:
  2316.          *
  2317.          *                      FBoxA_FormString:       " %-??s  %%%lc "                (2 parameters)
  2318.          *                      FBoxB_FormString:       " %-??s  %%%02ld%lc "   (3 parameters)
  2319.          *
  2320.          *              and when strings are output using these templates, they look like:
  2321.          *
  2322.          *                      FBoxA_FormString:       " PaddedTitleName....  %x "
  2323.          *                      FBoxB_FormString:   " PaddedTitleName....  %12x "
  2324.          */
  2325.         mysprintf(FBoxA_FormString, " %%-%lds  %%%%%%lc ",               maxtitlelen);
  2326.         mysprintf(FBoxB_FormString, " %%-%lds  %%%%%%02ld%%lc ", maxtitlelen);
  2327.  
  2328.         /*
  2329.          *              Make sure we never have overlapping button gadgets (this might
  2330.          *              happen if we had a big gadget font and small buffer font).
  2331.          */
  2332.         buttonwidth = MaxTextLen(gfont, UseCancelUndoText) + 32;
  2333.         buttonspace = buttonwidth * 3 + FORM_MARGIN * 4 + BorderLeft + BorderRight;
  2334.  
  2335.         width = FBoxA_Width + FBoxB_Width + FORM_MARGIN * 4 +
  2336.                                                   BorderLeft  + BorderRight;
  2337.  
  2338.         outmargin = FORM_MARGIN;
  2339.         if (buttonspace > width)
  2340.                 width = buttonspace;
  2341.  
  2342.         headingspace =  GetTextLen(gfont, MSG(MSG_AVAILABLE_GAD)) +
  2343.                                         GetTextLen(gfont, MSG(MSG_CURFORMAT_GAD)) +
  2344.                                         BorderLeft + BorderRight + FORM_MARGIN*3;
  2345.  
  2346.         if (headingspace > width)
  2347.                 width = headingspace;
  2348.  
  2349.         /*
  2350.          *              Now calculate the dimensions of our two windows boxes. The left
  2351.          *              box displays the available format headings, and the right box
  2352.          *              displays the currently selected format headings.
  2353.          */
  2354.         FBoxSpacing             = bfonty + 2;
  2355.         FBoxA_Top               = topline + gfonty + 4;
  2356.         FBoxA_Height    = EF_COUNT * FBoxSpacing + 4;
  2357.         FBoxA_Left      = BorderLeft + outmargin;
  2358.  
  2359.         FBoxB_Top               = FBoxA_Top;
  2360.         FBoxB_Height    = FBoxA_Height;
  2361.         FBoxB_Left      = width - BorderRight - outmargin - FBoxB_Width;
  2362.          
  2363.         height = FBoxA_Top + FBoxA_Height + BorderBottom +
  2364.                          (gfonty + GadgetHeight) * 3;
  2365.  
  2366.         if (width > ScreenWidth || height > ScreenHeight) {
  2367.                 CloseFont(gfont);
  2368.                 CloseFont(bfont);
  2369.                 return (NULL);
  2370.         }
  2371.         if (getsize) {
  2372.                 CloseFont(gfont);
  2373.                 CloseFont(bfont);
  2374.                 *pwidth  = width;
  2375.                 *pheight = height;
  2376.                 return (struct Gadget *)(-1);
  2377.         }
  2378.  
  2379.         /*
  2380.          *              Now create our window gadgets. We have a total of 4 -- the
  2381.          *              Use, Undo, Cancel buttons, and the field width slider.
  2382.          */     
  2383.         gadlist = NULL;
  2384.         gad = CreateContext(&gadlist);
  2385.         if (!gad)
  2386.                 goto fogad_failed;
  2387.  
  2388.         ng.ng_TextAttr          = gadgetfa;
  2389.         ng.ng_VisualInfo        = FormVI;
  2390.         ng.ng_Flags                     = PLACETEXT_IN;
  2391.         ng.ng_TopEdge           = height - BorderBottom - (gfonty+GadgetHeight) * 3/2;
  2392.         ng.ng_Height            = gfonty + GadgetHeight;
  2393.         ng.ng_Width                     = buttonwidth;
  2394.  
  2395.         ng.ng_LeftEdge          = FORM_MARGIN + BorderLeft;
  2396.         ng.ng_GadgetText        = MSG(MSG_USE_GAD);
  2397.         ng.ng_GadgetID          = GID_FORMUSE;
  2398.  
  2399.         gad = CreateGadget(BUTTON_KIND,         gad, &ng,
  2400.                                            GT_Underscore,       '_',
  2401.                                            TAG_DONE);
  2402.         if (!gad)
  2403.                 goto fogad_failed;
  2404.         Gadget[GID_FORMUSE] = gad;
  2405.         AddKeyShortcut(FormKeyboard, GID_FORMUSE, MSG_USE_GAD);
  2406.         
  2407.         ng.ng_LeftEdge          = width - BorderRight - FORM_MARGIN - ng.ng_Width;
  2408.         ng.ng_GadgetText        = MSG(MSG_CANCEL_GAD);
  2409.         ng.ng_GadgetID          = GID_FORMCANCEL;
  2410.  
  2411.         gad = CreateGadget(BUTTON_KIND,         gad, &ng,
  2412.                                            GT_Underscore,       '_',
  2413.                                            TAG_DONE);
  2414.         if (!gad)
  2415.                 goto fogad_failed;
  2416.         Gadget[GID_FORMCANCEL] = gad;
  2417.         AddKeyShortcut(FormKeyboard, GID_FORMCANCEL, MSG_CANCEL_GAD);
  2418.         
  2419.         ng.ng_LeftEdge          = (ng.ng_LeftEdge + BorderLeft + FORM_MARGIN) / 2;
  2420.         ng.ng_GadgetText        = MSG(MSG_UNDO_GAD);
  2421.         ng.ng_GadgetID          = GID_FORMUNDO;
  2422.  
  2423.         gad = CreateGadget(BUTTON_KIND,         gad, &ng,
  2424.                                            GT_Underscore,       '_',
  2425.                                            TAG_DONE);
  2426.         if (!gad)
  2427.                 goto fogad_failed;
  2428.         Gadget[GID_FORMUNDO] = gad;
  2429.         AddKeyShortcut(FormKeyboard, GID_FORMUNDO, MSG_UNDO_GAD);
  2430.  
  2431.         /*
  2432.          *              Create the slider gadget. We need to leave room on the left for
  2433.          *              the title, and on the right for the current value.
  2434.          */
  2435.         ng.ng_LeftEdge          = FORM_MARGIN + BorderLeft + 8 +
  2436.                                                   GetTextLen(gfont, MSG(MSG_FIELDWIDTH_GAD));
  2437.         ng.ng_Width                     = width - FORM_MARGIN - ng.ng_LeftEdge -
  2438.                                                   BorderLeft - BorderRight - GetTextLen(gfont, "99 ");
  2439.         ng.ng_Height            = gfonty + 3;
  2440.         ng.ng_TopEdge           = (ng.ng_TopEdge + FBoxA_Top + FBoxA_Height -
  2441.                                                    ng.ng_Height) / 2;
  2442.         ng.ng_GadgetText        = MSG(MSG_FIELDWIDTH_GAD);
  2443.         ng.ng_GadgetID          = GID_FORMWIDTH;
  2444.         ng.ng_Flags                     = PLACETEXT_LEFT;
  2445.  
  2446.         gad = CreateGadget(SLIDER_KIND,                 gad, &ng,
  2447.                                            GTSL_LevelFormat,    "%2ld ",
  2448.                                            GTSL_LevelPlace,             PLACETEXT_RIGHT,
  2449.                                            GTSL_Level,                  1,
  2450.                                            GTSL_Min,                    1,
  2451.                                            GTSL_Max,                    MAX_FIELD_LEN,
  2452.                                            GTSL_MaxLevelLen,    2,
  2453.                                            GT_Underscore,               '_',
  2454.                                            GA_Disabled,                 TRUE,
  2455.                                            GA_RelVerify,                TRUE,
  2456.                                            TAG_DONE);
  2457.         if (!gad)
  2458.                 goto fogad_failed;
  2459.         Gadget[GID_FORMWIDTH] = gad;
  2460.         AddKeyShortcut(FormKeyboard, GID_FORMWIDTH, MSG_FIELDWIDTH_GAD);
  2461.  
  2462.         FormGadFont = gfont;
  2463.         FormBufFont = bfont;
  2464.         return (gadlist);
  2465.  
  2466. fogad_failed:
  2467.         if (gadlist)
  2468.                 FreeGadgets(gadlist);
  2469.         CloseFont(gfont);
  2470.         CloseFont(bfont);
  2471.         return (NULL);
  2472. }
  2473.  
  2474. /*
  2475.  *              ShowFormatLine(line, select)
  2476.  *
  2477.  *              Outputs the numbered line of text in the right-hand box. If the
  2478.  *              number given is too high, then a blank line is output instead.
  2479.  *              The text will be of the form "HeadingName.... %02x" according
  2480.  *              to the current contents of the line.
  2481.  *
  2482.  *              If select is FORMAT_SELECTED, the line will be highlighted, else
  2483.  *              it will be output normally.
  2484.  */
  2485. void ShowFormatLine(int line, int select)
  2486. {
  2487.         int bfontbaseline          = FormBufFont->tf_Baseline;
  2488.         int boxwidth               = FormBufFont->tf_XSize * FBoxB_NumChars;
  2489.         struct RastPort *rport = FormWindow->RPort;
  2490.         char viewbuf[60];
  2491.         int fillpen = 0;
  2492.         int textpen = 1;
  2493.         int textrow;
  2494.         
  2495.         if (select == FORMAT_SELECTED) {
  2496.                 fillpen = ScreenDI->dri_Pens[FILLPEN];
  2497.                 textpen = ScreenDI->dri_Pens[FILLTEXTPEN];
  2498.         }
  2499.         SetFont(rport, FormBufFont);
  2500.         SetAPen(rport, textpen);
  2501.         SetBPen(rport, fillpen);
  2502.         SetDrMd(rport, JAM2);
  2503.  
  2504.         if (line < 0 || line >= EF_COUNT)
  2505.                 return;
  2506.  
  2507.         if (line < FBoxB_CurLines) {
  2508.                 FieldInit *fi = &FieldTypes[CurrentFields[line].type];
  2509.  
  2510.                 mysprintf(viewbuf, FBoxB_FormString, MSG(fi->titlemsgid),
  2511.                                                    CurrentFields[line].width, fi->idchar);
  2512.         } else {
  2513.                 memset(viewbuf, ' ', FBoxB_NumChars);
  2514.         }
  2515.         textrow = FBoxB_Top + line*FBoxSpacing + 3;
  2516.         Move(rport, FBoxB_Left + 2, textrow + bfontbaseline);
  2517.         Text(rport, viewbuf, FBoxB_NumChars);
  2518.  
  2519.         /*
  2520.          *              Now draw highlight on top and bottom of selected line
  2521.          *              (or erase, as the case may be). This fills out the
  2522.          *              selection area and makes it look much better.
  2523.          */
  2524.         SetAPen(rport, fillpen);
  2525.         Move(rport, FBoxB_Left + 2, textrow - 1);
  2526.         Draw(rport, FBoxB_Left + 1 + boxwidth, textrow - 1);
  2527.         Move(rport, FBoxB_Left + 2, textrow + FormBufFont->tf_YSize);
  2528.         Draw(rport, FBoxB_Left + 1 + boxwidth, textrow + FormBufFont->tf_YSize);
  2529. }
  2530.  
  2531. /*
  2532.  *              ShowDragSelect(pos, select)
  2533.  *
  2534.  *              Highlights the specified region to indicate where the currently
  2535.  *              dragged field will end up if it is released here.
  2536.  *
  2537.  *              If pos is FBOX_NOSELECT, no drop area is active and no output is
  2538.  *              produced. If pos is FBOX_SELECTLEFT, then the left box is active
  2539.  *              and it is given an inverse highlight around the interior of the
  2540.  *              box giving a bezel effect.
  2541.  *
  2542.  *              If pos is in the range 0 ... EF_COUNT, then it corresponds to an
  2543.  *              insertion point between two lines in the right-most box. This is
  2544.  *              show by a two-pixel high highlight line drawn between those two
  2545.  *              lines.
  2546.  *
  2547.  *              If select is FORMAT_SELECTED, the feature is drawn; if select is
  2548.  *              FORMAT_UNSELECTED, the feature is instead erased. Note that after
  2549.  *              calling this function, it may be necessary to redisplay any
  2550.  *              current highlight bar in the right box (see ShowFormatLine) since
  2551.  *              there is a one-pixel overlap between the highlight bar and the
  2552.  *              rendering done here.
  2553.  */
  2554. void ShowDragSelect(int pos, int select)
  2555. {
  2556.         struct RastPort *rport = FormWindow->RPort;
  2557.         int black = 1;
  2558.         int white = 2; 
  2559.  
  2560.         if (pos == FBOX_NOSELECT)
  2561.                 return;
  2562.         
  2563.         if (select == FORMAT_UNSELECTED) {
  2564.                 black = 0;
  2565.                 white = 0;
  2566.         }
  2567.         SetDrMd(rport, JAM2);
  2568.         if (pos == FBOX_SELECTLEFT) {
  2569.                 /*
  2570.                  *              Draw bezel inside left box
  2571.                  */
  2572.                 int boxleft  = FBoxA_Left + 2;
  2573.                 int boxtop       = FBoxA_Top  + 1;
  2574.                 int boxright = FBoxA_Left + FBoxA_Width  - 3;
  2575.                 int boxbot   = FBoxA_Top  + FBoxA_Height - 2;
  2576.  
  2577.                 SetAPen(rport, black);
  2578.                 Move(rport, boxleft,    boxbot);
  2579.                 Draw(rport, boxleft,    boxtop);
  2580.                 Move(rport, boxleft+1,  boxbot-1);
  2581.                 Draw(rport, boxleft+1,  boxtop);
  2582.                 Draw(rport, boxright-1, boxtop);
  2583.  
  2584.                 SetAPen(rport, white);
  2585.                 Move(rport, boxright,   boxtop);
  2586.                 Draw(rport, boxright,   boxbot);
  2587.                 Move(rport, boxright-1, boxtop);
  2588.                 Draw(rport, boxright-1, boxbot);
  2589.                 Draw(rport, boxleft-1,  boxbot);
  2590.         } else if (pos >= 0 && pos <= EF_COUNT) {
  2591.                 /*
  2592.                  *              Draw thin selection line in right box
  2593.                  */
  2594.                 int line = FBoxB_Top + 1 + pos * FBoxSpacing;
  2595.  
  2596.                 SetAPen(rport, white);
  2597.                 Move(rport, FBoxB_Left+2,                               line);
  2598.                 Draw(rport, FBoxB_Left+FBoxB_Width-3,   line);
  2599.                 SetAPen(rport, black);
  2600.                 Move(rport, FBoxB_Left+2,                               line+1);
  2601.                 Draw(rport, FBoxB_Left+FBoxB_Width-3,   line+1);
  2602.         }
  2603. }
  2604.  
  2605. /*
  2606.  *              RedrawFormatWindow()
  2607.  *
  2608.  *              Redraws all the parts of the format window that are generated by
  2609.  *              hand: this includes the two bevelled boxes containing the available
  2610.  *              format fields, the headings for those boxes, and the current contens
  2611.  *              of those boxes, including highlighting where appropriate.
  2612.  */
  2613. void RedrawFormatWindow(void)
  2614. {
  2615.         char viewbuf[60];
  2616.         struct RastPort *rport = FormWindow->RPort;
  2617.         int gfonty                = FormGadFont->tf_YSize;
  2618.         int gfontbaseline = FormGadFont->tf_Baseline;
  2619.         int bfontbaseline = FormBufFont->tf_Baseline;
  2620.         int line;
  2621.         int headpos;
  2622.         EditEvent *ee;
  2623.  
  2624.         DrawBevelBox(rport, FBoxA_Left, FBoxA_Top, FBoxA_Width, FBoxA_Height,
  2625.                                                 GT_VisualInfo, FormVI,
  2626.                                                 TAG_DONE);
  2627.  
  2628.         DrawBevelBox(rport, FBoxB_Left, FBoxB_Top, FBoxB_Width, FBoxB_Height,
  2629.                                                 GT_VisualInfo, FormVI,
  2630.                                                 TAG_DONE);
  2631.  
  2632.         SetAPen(rport, 1);
  2633.         SetBPen(rport, 0);
  2634.         SetDrMd(rport, JAM2);
  2635.         SetFont(rport, FormGadFont);
  2636.  
  2637.         /*
  2638.          *              When outputting the box headings, we adjust the centering
  2639.          *              to ensure that headings wider than the boxes don't get
  2640.          *              pushed into the window borders.
  2641.          */
  2642. #define CENTRE(left,width,msgid)        \
  2643.                 ((width - GetTextLen(FormGadFont, MSG(msgid)))/2 + left)
  2644.  
  2645.         headpos = CENTRE(FBoxA_Left, FBoxA_Width, MSG_AVAILABLE_GAD);
  2646.         if (headpos < (BorderLeft + 4))
  2647.                 headpos = FBoxA_Left; /* was: BorderLeft + 4; */
  2648.  
  2649.         Move(rport, headpos, FBoxA_Top - gfonty + gfontbaseline - 4);
  2650.         Text(rport, MSG(MSG_AVAILABLE_GAD), strlen(MSG(MSG_AVAILABLE_GAD)));
  2651.  
  2652.         headpos = CENTRE(FBoxB_Left, FBoxB_Width, MSG_CURFORMAT_GAD);
  2653.         if (headpos < (FBoxB_Left - 4))
  2654.                 headpos = FBoxB_Left + FBoxB_Width -
  2655.                                                            GetTextLen(FormGadFont, MSG(MSG_CURFORMAT_GAD));
  2656.  
  2657.         Move(rport, headpos, FBoxB_Top - gfonty + gfontbaseline - 4);
  2658.         Text(rport, MSG(MSG_CURFORMAT_GAD), strlen(MSG(MSG_CURFORMAT_GAD)));
  2659.  
  2660.         /*
  2661.          *              Now redraw the text inside the left box (available headings)
  2662.          */
  2663.         SetFont(rport, FormBufFont);
  2664.         ee = &AvailableFields[0];
  2665.         for (line = 0; line < (FBoxB_Height - 4); line += FBoxSpacing) {
  2666.                 if (ee->type != END_EDITLIST) {
  2667.                         FieldInit *fi = &FieldTypes[ee->type];
  2668.                         mysprintf(viewbuf, FBoxA_FormString, MSG(fi->titlemsgid),
  2669.                                                                                                  fi->idchar);
  2670.                         ee++;
  2671.                 } else {
  2672.                         memset(viewbuf, ' ', FBoxA_NumChars);
  2673.                 }
  2674.                 Move(rport, FBoxA_Left + 2, FBoxA_Top + line + bfontbaseline + 3);
  2675.                 Text(rport, viewbuf, FBoxA_NumChars);
  2676.         }
  2677.  
  2678.         /*
  2679.          *              Redraw the text inside the right box (currently selected headings)
  2680.          */
  2681.         ee = &CurrentFields[0];
  2682.         for (line = 0; line < EF_COUNT; line++) {
  2683.                 if (line == FBoxSelected)
  2684.                         ShowFormatLine(line, FORMAT_SELECTED);
  2685.                 else
  2686.                         ShowFormatLine(line, FORMAT_UNSELECTED);
  2687.         }
  2688. }
  2689.  
  2690. /*
  2691.  *              ConvertListToFormat(list, format)
  2692.  *
  2693.  *              Converts the passed in EditList to a format list which can be
  2694.  *              used for updating the main SnoopDos display. Returns the
  2695.  *              total width (in characters) occupied by the format.
  2696.  */
  2697. int ConvertListToFormat(EditEvent *ee, EventFormat *evformat)
  2698. {
  2699.         int width = 0;
  2700.  
  2701.         while (ee->type != END_EDITLIST) {
  2702.                 width               += ee->width + 1; /* Include space between cols */
  2703.                 evformat->type           = FieldTypes[ee->type].type;
  2704.                 evformat->width          = ee->width;
  2705.                 evformat->titlemsgid = FieldTypes[ee->type].titlemsgid;
  2706.                 evformat++;
  2707.                 ee++;
  2708.         }
  2709.         evformat->type = EF_END;
  2710.         if (width)
  2711.                 width--;                /* Don't count extra space at end */
  2712.         return (width);
  2713. }
  2714.  
  2715. /*
  2716.  *              CreateFormatLists(format)
  2717.  *
  2718.  *              Parses the passed-in format string and creates the two lists
  2719.  *              used by the format editor window to allow the user to re-arrange
  2720.  *              the format.
  2721.  *
  2722.  *              Should be called before RedrawFormatWindow() is called for the
  2723.  *              first time.
  2724.  *
  2725.  *              Also initialises some format globals related to the list boxes.
  2726.  */
  2727. void CreateFormatLists(EventFormat *evformat)
  2728. {
  2729.         EditEvent *ee;
  2730.         FieldInit *fi;
  2731.         EventFormat *ef;
  2732.  
  2733.         /*
  2734.          *              Now build the lists for the two boxes. The right box contains
  2735.          *              all items in the format string (and in the same order that they
  2736.          *              appear in the format string). The left box contains all the
  2737.          *              items that are NOT in the format string, in the presorted
  2738.          *              order that they appear in the FieldTypes[] initialiser array.
  2739.          *
  2740.          *              Note that the two edit lists contain indexes directly into
  2741.          *              the FieldTypes array, rather than specific event types.
  2742.          *              Thus, we store the offset into the array when we find a match
  2743.          *              rather than fi->type.
  2744.          */
  2745.         ee = &CurrentFields[0];
  2746.         for (ef = evformat; ef->type != EF_END; ef++) {
  2747.                 for (fi = FieldTypes; fi->type != ef->type && fi->type != EF_END; fi++)
  2748.                         ;
  2749.                 ee->type  = fi - FieldTypes;
  2750.                 ee->width = ef->width;
  2751.                 ee++;
  2752.         }
  2753.         ee->type = END_EDITLIST;
  2754.         FBoxB_CurLines = ee - &CurrentFields[0];
  2755.  
  2756.         ee = &AvailableFields[0];
  2757.         for (fi = FieldTypes; fi->type != EF_END; fi++) {
  2758.                 for (ef = BufferEFormat; ef->type != fi->type && ef->type != EF_END;
  2759.                                                                 ef++)
  2760.                         ;
  2761.                 if (ef->type != fi->type) {     /* Not in current format so add it here */
  2762.                         ee->type = fi - &FieldTypes[0];
  2763.                         ee++;
  2764.                 }
  2765.         }
  2766.         ee->type = END_EDITLIST;
  2767.  
  2768.         FBoxA_CurLines          = ee - &AvailableFields[0];
  2769.         FBoxSelected            = FBOX_NOSELECT;
  2770.         FBoxDragSelect          = FBOX_NOSELECT;
  2771.         FormatCurLMB            = 0;    /* Left mouse button not selected at start */
  2772.         FormatMovingField       = 0;
  2773.         /*
  2774.          *              Ensure slider gadget is disabled (it might have been left
  2775.          *              enabled from an earlier time, which can be confusing).
  2776.          */
  2777.         if (FormWindow) {
  2778.                 GT_SetGadgetAttrs(Gadget[GID_FORMWIDTH], FormWindow,  NULL,
  2779.                                                   GA_Disabled, TRUE,
  2780.                                                   TAG_DONE);
  2781.         }
  2782. }
  2783.  
  2784. /*
  2785.  *              OpenFormatWindow()
  2786.  *
  2787.  *              Opens the format editor window with all the format gadgets.
  2788.  *              Returns TRUE for success, FALSE for failure.
  2789.  *              The window will contain all necessary gadgets.
  2790.  *
  2791.  *              As with the Settings window, we try a variety of fonts until we
  2792.  *              find one that fits onto the screen.
  2793.  */
  2794. int OpenFormatWindow(void)
  2795. {
  2796.         static struct TextAttr formgfontattr =
  2797.                 { "empty-storage-for-format1-fonts", 0, FS_NORMAL, FPB_DISKFONT};
  2798.         static struct TextAttr formbfontattr =
  2799.                 { "empty-storage-for-format2-fonts", 0, FS_NORMAL, FPB_DISKFONT};
  2800.  
  2801.         static int width;               /* Maintained from call to call */
  2802.         static int height;
  2803.  
  2804.         int left = CurSettings.FormWinLeft;
  2805.         int top  = CurSettings.FormWinTop;
  2806.         struct TextAttr *gadgetfa;
  2807.         struct TextAttr *bufferfa;
  2808.         struct Window *win;
  2809.         int i;
  2810.  
  2811.         CheckSegTracker();
  2812.         if (FormWindow) {
  2813.                 WindowToFront(FormWindow);
  2814.                 ActivateWindow(FormWindow);
  2815.                 return (TRUE);
  2816.         }
  2817.         if (!CheckForScreen())
  2818.                 return (FALSE);
  2819.  
  2820.         strcpy(FormatSaveFormat, BufFormat);    /* Save for possible Undo */
  2821.  
  2822.         /*
  2823.          *              Now try all combinations of gadget and buffer font until we
  2824.          *              find a font combination that fits on our screen
  2825.          */
  2826.         for (i = 0; gadgetfa = MainWindowFontList[i].gadgetfa; i++) {
  2827.                 bufferfa = MainWindowFontList[i].bufferfa;
  2828.                 if (CreateFormatGadgets(gadgetfa, bufferfa, TRUE, &width, &height))
  2829.                         break;
  2830.         }
  2831.         if (!gadgetfa) {
  2832.                 ShowError(MSG(MSG_ERROR_OPENFORMAT));
  2833.                 return (FALSE);
  2834.         }
  2835.         /*
  2836.          *              Now copy our font attributes so that our gadgets won't strangely
  2837.          *              get changed behind the scenes if we update our fonts
  2838.          */
  2839.         strcpy(formgfontattr.ta_Name, gadgetfa->ta_Name);
  2840.         formgfontattr.ta_YSize = gadgetfa->ta_YSize;
  2841.         gadgetfa = &formgfontattr;
  2842.  
  2843.         strcpy(formbfontattr.ta_Name, bufferfa->ta_Name);
  2844.         formbfontattr.ta_YSize = bufferfa->ta_YSize;
  2845.         bufferfa = &formbfontattr;
  2846.  
  2847.         if (left == -1)  left = (ScreenWidth  - width)  / 2;
  2848.         if (top  == -1)  top  = (ScreenHeight - height) / 2;
  2849.  
  2850.         win = OpenWindowTags(NULL,
  2851.                                                  WA_Title,                      MSG(MSG_FORMAT_TITLE),
  2852.                                                  WA_IDCMP,                      IDCMP_CLOSEWINDOW        |
  2853.                                                                                         IDCMP_REFRESHWINDOW      |
  2854.                                                                                         IDCMP_NEWSIZE            |
  2855.                                                                                         IDCMP_RAWKEY             |
  2856.                                                                                         IDCMP_MOUSEBUTTONS       |
  2857.                                                                                         IDCMP_INACTIVEWINDOW |
  2858.                                                                                         BUTTONIDCMP                      |
  2859.                                                                                         SLIDERIDCMP,
  2860.                                                  WA_Left,                       left,
  2861.                                                  WA_Top,                        top,
  2862.                                                  WA_Width,                      width,
  2863.                                                  WA_Height,                     height,
  2864.                                                  WA_Flags,                      WFLG_DRAGBAR             |
  2865.                                                                                         WFLG_DEPTHGADGET         |
  2866.                                                                                         WFLG_ACTIVATE            |
  2867.                                                                                         WFLG_RMBTRAP             |
  2868.                                                                                         WFLG_NEWLOOKMENUS,
  2869.                                                  RefreshTag,            TRUE,
  2870.                                                  WA_NoCareRefresh,      NoCareRefreshBool,
  2871.                                                  WA_PubScreen,          SnoopScreen,
  2872.                                                  TAG_DONE);
  2873.         if (!win) {
  2874.                 ShowError(MSG(MSG_ERROR_OPENFORMAT));
  2875.                 return (FALSE);
  2876.         }
  2877.  
  2878.         if (!FormGadList) {
  2879.                 FormGadList = CreateFormatGadgets(gadgetfa, bufferfa, 0, 0, 0);
  2880.                 if (!FormGadList) {
  2881.                         CloseWindow(win);
  2882.                         ShowError(MSG(MSG_ERROR_OPENFORMAT));
  2883.                         return (FALSE);
  2884.                 }
  2885.         }
  2886.  
  2887.         /*
  2888.          *              Now try and create our BOBs for the window
  2889.          */
  2890.         TextBob = CreateBob(win->RPort, FBoxB_Width + 8,
  2891.                                                                     FormBufFont->tf_YSize + 4, 1);
  2892.         if (!TextBob) {
  2893.                 ShowError(MSG(MSG_ERROR_OPENFORMAT));
  2894.                 FreeGadgets(FormGadList);
  2895.                 FormGadList     = NULL;
  2896.                 CloseWindow(win);
  2897.                 return (FALSE);
  2898.         }
  2899.         AddBob(&TextBob->bob, win->RPort);
  2900.  
  2901.         /*
  2902.          *              Now add gadgets to screen window, and then setup the current
  2903.          *              format string for editing.
  2904.          */
  2905.         AddGList(win, FormGadList, -1, -1, NULL);
  2906.         RefreshGList(FormGadList, win, NULL, -1);
  2907.         GT_RefreshWindow(win, NULL);
  2908.  
  2909.         /*
  2910.          *              All done, so initialise some globals and return
  2911.          */
  2912.         FormWindow              = win;
  2913.         FormWindowPort  = win->UserPort;
  2914.         FormWindowMask  = 1 << FormWindowPort->mp_SigBit;
  2915.  
  2916.         CreateFormatLists(BufferEFormat);
  2917.         /*
  2918.          *              Finally, draw our window to reflect this
  2919.          */
  2920.         RedrawFormatWindow();
  2921.         if (DisableNestCount)
  2922.                 DisableWindow(FormWindow, &FormRequester);
  2923.         return (TRUE);
  2924. }
  2925.  
  2926. /*
  2927.  *              CloseFormatWindow(void)
  2928.  *
  2929.  *              Close the format window and free gadgets associated with the window.
  2930.  */
  2931. void CloseFormatWindow(void)
  2932. {
  2933.         if (FormWindow) {
  2934.                 if (TextBob) {
  2935.                         FreeBob(TextBob);
  2936.                         TextBob = NULL;
  2937.                 }
  2938.                 RecordWindowSizes();
  2939.                 CloseWindow(FormWindow);
  2940.                 CloseFont(FormGadFont);
  2941.                 CloseFont(FormBufFont);
  2942.                 FormWindow     = NULL;
  2943.                 FormWindowMask = 0;
  2944.                 FormGadFont        = NULL;
  2945.                 FormBufFont        = NULL;
  2946.         }
  2947.         if (FormGadList) {
  2948.                 FreeGadgets(FormGadList);
  2949.                 FormGadList = NULL;
  2950.         }
  2951.         if (FormVI) {
  2952.                 FreeVisualInfo(FormVI);
  2953.                 FormVI = NULL;
  2954.         }
  2955. }
  2956.  
  2957. /*
  2958.  *              FormatHitDetect(x, y)
  2959.  *
  2960.  *              Does a bounds check for the specified X/Y co-ordinates against the
  2961.  *              format editor window. A return value in the range 0..EF_COUNT-1
  2962.  *              indicates that line number in the right hand window was hit.
  2963.  *
  2964.  *              A return of FBOX_SELECTLEFT indicates that the left box was selected
  2965.  *              (not sure which line; doesn't really matter).
  2966.  *
  2967.  *              A return of FBOX_NOSELECT indicates neither box was selected.
  2968.  */
  2969. int FormatHitDetect(int x, int y)
  2970. {
  2971.         if (x >= FBoxA_Left && x <= (FBoxA_Left + FBoxA_Width  - 1) &&
  2972.                 y >= FBoxA_Top  && y <= (FBoxA_Top  + FBoxA_Height - 1))
  2973.         {
  2974.                 return (FBOX_SELECTLEFT);
  2975.         }
  2976.         
  2977.         if (x >= FBoxB_Left && x <= (FBoxB_Left + FBoxB_Width  - 1) &&
  2978.                 y >= FBoxB_Top  && y <= (FBoxB_Top  + FBoxB_Height - 1))
  2979.         {
  2980.                 if (y <= FBoxB_Top + FBoxSpacing + 2)
  2981.                         return (0);
  2982.                 else
  2983.                         return (y - FBoxB_Top - 2) / FBoxSpacing;
  2984.         }
  2985.         return (FBOX_NOSELECT);
  2986. }
  2987.  
  2988. /*
  2989.  *              InstallNewFormat(type)
  2990.  *
  2991.  *              Installs the currently defined format into the main window for
  2992.  *              the user to see immediately.
  2993.  *
  2994.  *              If type is NEW_LISTVIEW, then the new format is assumed to be
  2995.  *              from the format editor window's CurrentFields list. The
  2996.  *              setup window, if open, will have its own format string updated
  2997.  *              accordingly.
  2998.  *
  2999.  *              If type is NEW_STRING, then the new format is assumed to be
  3000.  *              stored in the BufFormat string. The format window, if open,
  3001.  *              will have its own format listview updated accordingly.
  3002.  *
  3003.  *              If the buffer string is completely invalid (i.e. evaluates to
  3004.  *              an empty format) then it will be replaced with an empty string.
  3005.  */
  3006. void InstallNewFormat(int type)
  3007. {
  3008.         if (type == NEW_LISTVIEW) {
  3009.                 BufferWidth = ConvertListToFormat(CurrentFields, BufferEFormat);
  3010.         } else /* type == NEW_STRING */ {
  3011.                 BufferWidth = ParseFormatString(BufFormat, BufferEFormat,
  3012.                                                                                                    MAX_FORM_LEN);
  3013.                 if (BufferWidth == 0) {
  3014.                         BufferWidth = ParseFormatString(DefaultSettings.Setup.BufferFormat,
  3015.                                                                                         BufferEFormat, MAX_FORM_LEN);
  3016.                 }
  3017.                 if (FormWindow) {
  3018.                         CreateFormatLists(BufferEFormat);
  3019.                         RedrawFormatWindow();
  3020.                 }
  3021.         }
  3022.         BuildFormatString(BufferEFormat, BufFormat, MAX_FORM_LEN);
  3023.         if (SetWindow) {
  3024.                 GT_SetGadgetAttrs(Gadget[GID_BUFFORMAT], SetWindow, NULL,
  3025.                                                   GTST_String,  BufFormat,
  3026.                                                   TAG_DONE);
  3027.         }
  3028.         ClearMainRHS = 1;
  3029.         InitMainMargins();
  3030.         UpdateMainHScroll();
  3031.         RedrawMainWindow();
  3032. }
  3033.  
  3034. /*
  3035.  *              HandleFormatMsgs()
  3036.  *
  3037.  *              Processes all outstanding messages associated with the Format
  3038.  *              editor gadget window. To be called whenever we get a format event.
  3039.  */
  3040. void HandleFormatMsgs(void)
  3041. {
  3042.         static int activegad;                   /* Non-zero if gadget is depressed   */
  3043.         static int activekey;                   /* Keycode shortcut of activegad     */
  3044.  
  3045.         struct IntuiMessage *imsg;
  3046.         int doneform = SEL_NONE;
  3047.         int hit;
  3048.         int lmb;
  3049.         int rmb;
  3050.  
  3051.         if (!FormWindow)
  3052.                 return;
  3053.  
  3054.         while ((imsg = GT_GetIMsg(FormWindowPort)) != NULL) {
  3055.                 struct Gadget *gad;
  3056.                 int dxwidth = 0;                                /* Amount to adjust width by */
  3057.                 int newrow  = FBoxSelected;             /* Currently selected row        */
  3058.                 int gadid;
  3059.  
  3060.                 switch (imsg->Class) {
  3061.                         
  3062.                         case IDCMP_CLOSEWINDOW:
  3063.                                 doneform = SEL_USE;
  3064.                                 break;
  3065.  
  3066.                         case IDCMP_REFRESHWINDOW:
  3067.                                 GT_BeginRefresh(FormWindow);
  3068.                                 RedrawFormatWindow();
  3069.                                 GT_EndRefresh(FormWindow, TRUE);
  3070.                                 break;
  3071.  
  3072.                         case IDCMP_MOUSEBUTTONS:
  3073.                                 lmb = imsg->Qualifier & IEQUALIFIER_LEFTBUTTON;
  3074.                                 rmb = imsg->Qualifier & IEQUALIFIER_RBUTTON;
  3075.                                 /*
  3076.                                  *              If we're already dragging something, then the
  3077.                                  *              right mouse button allows it to be cancelled.
  3078.                                  */
  3079.                                 if (FormatMovingField && rmb)
  3080.                                         goto cancel_moving_field;
  3081.  
  3082.                                 if (lmb == FormatCurLMB)        /* Ignore spurious events */
  3083.                                         break;
  3084.  
  3085.                                 hit = FormatHitDetect(imsg->MouseX, imsg->MouseY);
  3086.                                 if (lmb) {
  3087.                                         /*
  3088.                                          *              User is trying to select or pick-up a new
  3089.                                          *              event.
  3090.                                          */
  3091.                                         if (hit >= 0 && hit < FBoxB_CurLines &&
  3092.                                                                                                 hit != FBoxSelected) {
  3093.                                                 if (FBoxSelected >= 0 && FBoxSelected < FBoxB_CurLines)
  3094.                                                         ShowFormatLine(FBoxSelected, FORMAT_UNSELECTED);
  3095.                                                 FBoxSelected = hit;
  3096.                                                 ShowFormatLine(hit, FORMAT_SELECTED);
  3097.                                                 GT_SetGadgetAttrs(Gadget[GID_FORMWIDTH],
  3098.                                                                                   FormWindow,  NULL,
  3099.                                                                                   GA_Disabled, FALSE,
  3100.                                                                                   GTSL_Level, CurrentFields[hit].width,
  3101.                                                                                   TAG_DONE);
  3102.                                         }
  3103.                                         if (hit != FBOX_NOSELECT) {
  3104.                                                 /*
  3105.                                                  *              Pick-up the icon under mouse
  3106.                                                  */
  3107.                                                 if (PickupBob(hit, imsg->MouseX, imsg->MouseY)) {
  3108.                                                         FormatMovingField = 1;
  3109.                                                         ReportMouse(1, FormWindow);     /* Enable mouse moves */
  3110.                                                 }
  3111.                                         }
  3112.                                 } else {
  3113.                                         /*
  3114.                                          *              We might be finished doing a drag of a field
  3115.                                          *              from one position to another -- if so, drop the
  3116.                                          *              field in it's new place.
  3117.                                          */
  3118.                                         if (FormatMovingField) {
  3119.                                                 int curdragselect = FBoxDragSelect;
  3120.  
  3121.                                                 FormatMovingField = 0;
  3122.                                                 ReportMouse(0, FormWindow);     /* Disable mouse moves  */
  3123.                                                 DropBob();
  3124.                                                 if (curdragselect != FBOX_NOSELECT)
  3125.                                                         InstallNewFormat(NEW_LISTVIEW);
  3126.                                         }
  3127.                                 }
  3128.                                 FormatCurLMB = lmb;
  3129.                                 break;
  3130.                                                 
  3131.                         case IDCMP_MOUSEMOVE: 
  3132.                                 if (FormatMovingField) {
  3133.                                         UpdateBob(imsg->MouseX, imsg->MouseY);
  3134.                                         break;
  3135.                                 }
  3136.  
  3137.                                 /*
  3138.                                  *              Fall through to handle MOUSEMOVE for slider gadget
  3139.                                  */
  3140.  
  3141.                         case IDCMP_GADGETDOWN:
  3142.                         case IDCMP_GADGETUP:
  3143.                                 gad   = (struct Gadget *)imsg->IAddress;
  3144.                                 gadid = gad->GadgetID;
  3145.  
  3146. handle_form_gads:
  3147.                                 switch (gadid) {
  3148.  
  3149.                                         case GID_FORMUSE:
  3150.                                                 doneform = SEL_USE;
  3151.                                                 break;
  3152.  
  3153.                                         case GID_FORMCANCEL:
  3154.                                                 doneform = SEL_CANCEL;
  3155.                                                 break;
  3156.  
  3157.                                         case GID_FORMUNDO:
  3158.                                                 strcpy(BufFormat, FormatSaveFormat);
  3159.                                                 InstallNewFormat(NEW_STRING);
  3160.                                                 break;
  3161.  
  3162.                                         case GID_FORMWIDTH:
  3163.                                                 /*
  3164.                                                  *              The slider has been moved, so update the
  3165.                                                  *              currently selected item accordingly.
  3166.                                                  */
  3167.                                                 if (FBoxSelected >= 0 &&
  3168.                                                                                         FBoxSelected < FBoxB_CurLines) {
  3169.                                                         CurrentFields[FBoxSelected].width = imsg->Code;
  3170.                                                         ShowFormatLine(FBoxSelected, FORMAT_SELECTED);
  3171.                                                         if (imsg->Class == IDCMP_GADGETUP)
  3172.                                                                 InstallNewFormat(NEW_LISTVIEW);
  3173.                                                 }
  3174.                                                 break;
  3175.                                 }
  3176.                                 break;
  3177.  
  3178.                         case IDCMP_INACTIVEWINDOW:
  3179.                                 /*
  3180.                                  *              Cancel any currently pressed button
  3181.                                  */
  3182.                                 if (activegad) {
  3183.                                         ShowGadget(FormWindow, Gadget[activegad], GADGET_UP);
  3184.                                         activegad = 0;
  3185.                                 }
  3186.                                 /*
  3187.                                  *              If we're dragging something and the window
  3188.                                  *              goes inactive, drop it. Otherwise, when the
  3189.                                  *              window is reactivated, it will still be attached
  3190.                                  *              to the mouse pointer!
  3191.                                  */
  3192.                                 if (FormatMovingField) {
  3193.                                         FormatCurLMB      = 0;
  3194. cancel_moving_field:
  3195.                                         ReportMouse(0, FormWindow);
  3196.                                         UpdateBob(0, -9999);            /* Make position invalid */
  3197.                                         DropBob();
  3198.                                         FormatMovingField = 0;
  3199.                                         if (imsg->Class == IDCMP_INACTIVEWINDOW) {
  3200.                                                 /*
  3201.                                                  *              If we went inactive, then the act of
  3202.                                                  *              erasing the BOB has probably resulted
  3203.                                                  *              in a portion of the window frame being
  3204.                                                  *              restored in its active colours, even
  3205.                                                  *              though the window is now inactive -- so
  3206.                                                  *              we refresh it to get around this.
  3207.                                                  */
  3208.                                                 RefreshWindowFrame(FormWindow);
  3209.                                         }
  3210.                                 }
  3211.                                 break;
  3212.                                         
  3213.                         case IDCMP_RAWKEY:
  3214.                         {
  3215.                                 int shift    = imsg->Qualifier & IE_SHIFT;
  3216.                                 int altctrl  = imsg->Qualifier & (IE_ALT | IE_CTRL);
  3217.                                 int upstroke = imsg->Code & 0x80;
  3218.                                 int keypress = ConvertIMsgToChar(imsg);
  3219.  
  3220.                                 /*
  3221.                                  *              Handle keyboard shortcuts
  3222.                                  */
  3223.                                 if (FormatMovingField && keypress == '\033') {
  3224.                                         /*
  3225.                                          *              ESC cancels any drag currently in operation
  3226.                                          */
  3227.                                         goto cancel_moving_field;
  3228.                                 }
  3229.  
  3230.                                 gadid  = FormKeyboard[keypress];
  3231.                                 if (activegad) {
  3232.                                         /*
  3233.                                          *              We're releasing a gadget that was pressed
  3234.                                          *              earlier, so handle it now
  3235.                                          */
  3236.                                         int samekey = (imsg->Code & 0x7f) == activekey;
  3237.  
  3238.                                         if (samekey && !upstroke)       /* Ignore repeated keys */
  3239.                                                 break;
  3240.  
  3241.                                         ShowGadget(FormWindow, Gadget[activegad], GADGET_UP);
  3242.                                         if (samekey) {
  3243.                                                 /*
  3244.                                                  *              Just released the key that was originally
  3245.                                                  *              pressed for this gadget, so now go and
  3246.                                                  *              handle the gadget action.
  3247.                                                  */
  3248.                                                 gadid     = activegad;
  3249.                                                 gad       = Gadget[gadid];
  3250.                                                 activegad = 0;
  3251.                                                 goto handle_form_gads;
  3252.                                         }
  3253.  
  3254.                                         /*
  3255.                                          *              If the above check didn't kick in, it means
  3256.                                          *              we got a downpress of a different key, so
  3257.                                          *              disable the gadget for this key and continue
  3258.                                          *              to press the other key.
  3259.                                          */
  3260.                                         activegad = 0;
  3261.                                 }
  3262.  
  3263.                                 /*
  3264.                                  *              Check for normal gadget keyboard shortcuts
  3265.                                  */
  3266.                                 if (gadid) {
  3267.                                         gad = Gadget[gadid];
  3268.                                         if (gadid == GID_FORMWIDTH) {
  3269.                                                 /*
  3270.                                                  *              Got a slider adjustment request
  3271.                                                  */
  3272.                                                 if (imsg->Qualifier & IE_SHIFT)
  3273.                                                         dxwidth = -1;
  3274.                                                 else
  3275.                                                         dxwidth = 1;
  3276.  
  3277.                                                 if (newrow == FBOX_NOSELECT)
  3278.                                                         newrow = 0;     /* If no row active, pick first row */
  3279.  
  3280.                                                 if (FBoxB_CurLines == 0)  /* Ignore if box is empty */
  3281.                                                         break;
  3282.  
  3283.                                                 goto format_move_slider;
  3284.                                         }
  3285.                                         /*
  3286.                                          *              Must be a simple button press so highlight
  3287.                                          *              the button and handle accordingly
  3288.                                          */
  3289.                                         ShowGadget(FormWindow, gad, GADGET_DOWN);
  3290.                                         activegad = gadid;
  3291.                                         activekey = imsg->Code;
  3292.                                         break;
  3293.                                 }
  3294.  
  3295.                                 /*
  3296.                                  *              Handle cursor movement. This lets us choose a
  3297.                                  *              new item in the format box, or adjust the width
  3298.                                  *              of an existing item.
  3299.                                  */
  3300.                                 if (!FBoxB_CurLines)    /* A format must exist */
  3301.                                         break;
  3302.                                 
  3303.                                 if (newrow == FBOX_NOSELECT)
  3304.                                         newrow = -1;    /* Ensure cursor down selects item 0 */
  3305.  
  3306.                                 switch (imsg->Code) {
  3307.                                         case CURSORUP:
  3308.                                                 if (newrow > 0 && !(shift | altctrl))
  3309.                                                         newrow--;
  3310.                                                 else
  3311.                                                         newrow = 0;
  3312.                                                 break;
  3313.  
  3314.                                         case CURSORDOWN:
  3315.                                                 if (shift | altctrl)
  3316.                                                         newrow = FBoxB_CurLines - 1;
  3317.                                                 else if (newrow < (FBoxB_CurLines-1))
  3318.                                                         newrow++;
  3319.                                                 break;
  3320.  
  3321.                                         case CURSORLEFT:
  3322.                                                 dxwidth = -1;
  3323.                                                 if (shift)   dxwidth  = -5;
  3324.                                                 if (altctrl) dxwidth  = -MAX_FIELD_LEN;
  3325.                                                 break;
  3326.  
  3327.                                         case CURSORRIGHT:
  3328.                                                 dxwidth = 1;
  3329.                                                 if (shift)   dxwidth = 5;
  3330.                                                 if (altctrl) dxwidth = MAX_FIELD_LEN;
  3331.                                                 break;
  3332.  
  3333.                                         case HELPKEY:
  3334.                                                 ShowAGuide(MSG(MSG_LINK_FORMATWIN));
  3335.                                                 goto done_keys;
  3336.  
  3337.                                         default:
  3338.                                                 goto done_keys;         /* Ignore all other keys */
  3339.                                 }
  3340.  
  3341. format_move_slider:
  3342.                                 /*
  3343.                                  *              First check if the row has changed. (As well as
  3344.                                  *              changing via cursor up/down, this can also happen
  3345.                                  *              with left/right if there was no item selected to
  3346.                                  *              begin with
  3347.                                  */
  3348.                                 if (newrow < 0)
  3349.                                         newrow = 0;
  3350.  
  3351.                                 if (newrow != FBoxSelected && FBoxB_CurLines > 0) {
  3352.                                         /*
  3353.                                          *              Unactivate old row, activate a new row
  3354.                                          */
  3355.                                         if (FBoxSelected >= 0 && FBoxSelected < FBoxB_CurLines)
  3356.                                                 ShowFormatLine(FBoxSelected, FORMAT_UNSELECTED);
  3357.                                         FBoxSelected = newrow;
  3358.                                         ShowFormatLine(newrow, FORMAT_SELECTED);
  3359.                                         GT_SetGadgetAttrs(Gadget[GID_FORMWIDTH],
  3360.                                                                           FormWindow,  NULL,
  3361.                                                                           GA_Disabled, FALSE,
  3362.                                                                           GTSL_Level, CurrentFields[newrow].width,
  3363.                                                                           TAG_DONE);
  3364.                                 }
  3365.  
  3366.                                 /*
  3367.                                  *              Now check if the horizontal position of the
  3368.                                  *              slider has changed.
  3369.                                  */
  3370.                                 if (dxwidth) {
  3371.                                         int newwidth = CurrentFields[FBoxSelected].width + dxwidth;
  3372.  
  3373.                                         if (newwidth < 1)                               newwidth = 1;
  3374.                                         if (newwidth > MAX_FIELD_LEN)   newwidth = MAX_FIELD_LEN;
  3375.                                         if (FBoxSelected != FBOX_NOSELECT) {
  3376.                                                 if (newwidth != CurrentFields[FBoxSelected].width) {
  3377.                                                         GT_SetGadgetAttrs(Gadget[GID_FORMWIDTH],
  3378.                                                                                           FormWindow,  NULL,
  3379.                                                                                           GTSL_Level,  newwidth,
  3380.                                                                                           TAG_DONE);
  3381.                                                         CurrentFields[FBoxSelected].width = newwidth;
  3382.                                                         ShowFormatLine(FBoxSelected, FORMAT_SELECTED);
  3383.                                                         InstallNewFormat(NEW_LISTVIEW);
  3384.                                                 }
  3385.                                         }
  3386.                                 }
  3387. done_keys:
  3388.                                 break;
  3389.                         }
  3390.                 }
  3391.                 GT_ReplyIMsg(imsg);
  3392.         }
  3393.         if (doneform != SEL_NONE) {
  3394.                 CloseFormatWindow();
  3395.                 if (doneform == SEL_CANCEL) {
  3396.                         strcpy(BufFormat, FormatSaveFormat);
  3397.                         InstallNewFormat(NEW_STRING);
  3398.                 }
  3399.         }
  3400. }
  3401.  
  3402. /*
  3403.  *              -----------------------------------------------------------------------
  3404.  *              Now our BOB/GEL routines for the drag-and-drop format editor.
  3405.  *              These should really be in their own module, but they're being
  3406.  *              put here for now for convenience.
  3407.  *              -----------------------------------------------------------------------
  3408.  */
  3409.  
  3410. /*
  3411.  *              InitGel(rastport, width, height, transp)
  3412.  *
  3413.  *              This function does all the initialisation necessary to allow us
  3414.  *              to use a single BOB in the given rastport. A new bitmap is allocated
  3415.  *              of dimensions width x height into which data can be rendered.
  3416.  *
  3417.  *              If successful, this function returns a pointer to a MyGel structure
  3418.  *              which contains, among other things, the rastport and bob structure
  3419.  *              you will use when calling system routines to manipulate the bob.
  3420.  *
  3421.  *              Note that the bob must be removed from the Gel list before rendering
  3422.  *              into it.
  3423.  *
  3424.  *              If transp is true, then the BOB will be transparent on colour zero.
  3425.  *              In this case, you must call InitMasks(mygel->vsprite) whenever
  3426.  *              you make a change to the image, to recalculate the mask.
  3427.  */
  3428. MyGel *CreateBob(struct RastPort *rport, int width, int height, int transp)
  3429. {
  3430.         struct GelsInfo *gInfo;
  3431.         struct Bob              *bob;
  3432.         struct VSprite  *vsprite;
  3433.         MyGel                   *mygel;
  3434.         ULONG                   linesize;
  3435.         ULONG                   planesize;
  3436.         ULONG                   imagesize;
  3437.         ULONG                   chipsize;
  3438.         UBYTE                   *chipdata;
  3439.         int                             wordwidth;
  3440.         int                             depth;
  3441.         int                             i;
  3442.  
  3443.         wordwidth       = (width + 15) >> 4;
  3444.         depth           = rport->BitMap->Depth;
  3445.  
  3446.         mygel = (MyGel *)AllocMem(sizeof(MyGel), MEMF_CLEAR);
  3447.         if (!mygel)
  3448.                 return (NULL);
  3449.                 
  3450.         mygel->mainrast         = rport;
  3451.         gInfo                           = &mygel->gelinfo;
  3452.         gInfo->nextLine         = mygel->nextline;
  3453.         gInfo->lastColor        = mygel->lastcolor;
  3454.         gInfo->collHandler      = &mygel->colltable;
  3455.         gInfo->sprRsrvd         = 0x03;
  3456.  
  3457.         /*
  3458.          *              Set left-most and top-most to 1 to better keep items
  3459.          *              inside the display boundaries.
  3460.          */
  3461.         gInfo->leftmost   = 1;
  3462.         gInfo->topmost    = 1;
  3463.         gInfo->rightmost  = (rport->BitMap->BytesPerRow << 3) - 1;
  3464.         gInfo->bottommost = rport->BitMap->Rows - 1;
  3465.         rport->GelsInfo   = gInfo;
  3466.         InitGels(&mygel->vshead, &mygel->vstail, gInfo);
  3467.  
  3468.         /*
  3469.          *              Now allocate a new BOB to be linked into this structure.
  3470.          *              We also allocate a bitmap associated with the bob, and
  3471.          *              give it its own RastPort so that we can render into it.
  3472.          */
  3473.         linesize        = sizeof(WORD)  * wordwidth;
  3474.         planesize       = linesize      * height;
  3475.         imagesize       = planesize             * depth;
  3476.         chipsize        = imagesize*2 + linesize + planesize;
  3477.         bob                     = &mygel->bob;
  3478.         vsprite         = &mygel->bobvsprite;
  3479.  
  3480.         if (!(chipdata = AllocMem(chipsize, MEMF_CHIP | MEMF_CLEAR))) {
  3481.                 rport->GelsInfo = NULL;
  3482.                 FreeMem(mygel, sizeof(MyGel));
  3483.                 return (NULL);
  3484.         }
  3485.         mygel->chipdata         = (void *)(chipdata);
  3486.         mygel->chipsize         = chipsize;
  3487.  
  3488.         mygel->planedata        = (void *)(chipdata);
  3489.         bob->SaveBuffer         = (void *)(chipdata + imagesize);
  3490.         vsprite->BorderLine = (void *)(chipdata + imagesize*2);
  3491.         vsprite->CollMask       = (void *)(chipdata + imagesize*2 + linesize);
  3492.  
  3493.         vsprite->Y                      = -9999;
  3494.         vsprite->X                      = -9999;
  3495.         vsprite->Flags      = SAVEBACK | (transp ? OVERLAY : 0);
  3496.         vsprite->Width      = wordwidth;
  3497.         vsprite->Depth      = depth;
  3498.         vsprite->Height     = height;
  3499.         vsprite->MeMask     = 0;
  3500.         vsprite->HitMask    = 0;
  3501.         vsprite->ImageData  = (void *)mygel->planedata;
  3502.         vsprite->SprColors  = NULL;
  3503.         vsprite->PlanePick  = -1;
  3504.         vsprite->PlaneOnOff = 0x00;
  3505.         InitMasks(vsprite);
  3506.  
  3507.         vsprite->VSBob      = bob;
  3508.         bob->BobVSprite     = vsprite;
  3509.         bob->ImageShadow    = vsprite->CollMask;
  3510.         bob->Flags          = 0;
  3511.         bob->Before         = NULL;
  3512.         bob->After          = NULL;
  3513.         bob->BobComp        = NULL;
  3514.         bob->DBuffer            = NULL;
  3515.  
  3516.         /*
  3517.          *              Now setup the Rastport and Bitmap so we can render into the BOB
  3518.          */
  3519.         InitRastPort(&mygel->rastport);
  3520.         InitBitMap(&mygel->bitmap, depth, width, height);
  3521.         mygel->rastport.BitMap = &mygel->bitmap;
  3522.  
  3523.         for (i = 0; i < depth; i++)
  3524.                 mygel->bitmap.Planes[i] = mygel->planedata + i * planesize;
  3525.  
  3526.         return (mygel);
  3527. }
  3528.  
  3529. /*
  3530.  *              FreeBob(mygel)
  3531.  *
  3532.  *              Frees the bob allocated earlier, along with all other associated info 
  3533.  *              Also removes all GELs from the system rastport.
  3534.  */
  3535. void FreeBob(MyGel *mygel)
  3536. {
  3537.         mygel->mainrast->GelsInfo = NULL;
  3538.         FreeMem(mygel->chipdata, mygel->chipsize);
  3539.         FreeMem(mygel, sizeof(MyGel));
  3540. }
  3541.  
  3542. /*
  3543.  *              PickupBob(hit, x, y)
  3544.  *
  3545.  *              Picks up the line and copies it into our bob's bitmap, then adds
  3546.  *              the bob to the screen at the current mouse location so the
  3547.  *              user can drag it around.
  3548.  *
  3549.  *              If the hit is correct, we can ignore Y since the field being
  3550.  *              dragged is in the right box and we already know which line.
  3551.  *              Otherwise, Y is a pixel co-ordinate that we use to calculate
  3552.  *              the line of the box that's being chosen.
  3553.  *
  3554.  *              If hit is FBOX_SELECTLEFT, then we need to calculate which line
  3555.  *              we are dealing with.
  3556.  *
  3557.  *              We also record the start line we use.
  3558.  *
  3559.  *              Returns true for success, false if we didn't have a hit after all.
  3560.  */
  3561. int PickupBob(int hit, int x, int y)
  3562. {
  3563.         struct RastPort *rport    = FormWindow->RPort;
  3564.         struct RastPort *bobrport = &TextBob->rastport;
  3565.         char viewbuf[50];
  3566.         int line;
  3567.         int box;
  3568.         int xpos;
  3569.         int ypos;
  3570.         int len;
  3571.  
  3572.         if (hit == FBOX_NOSELECT) {
  3573.                 return (FALSE);
  3574.         } else if (hit == FBOX_SELECTLEFT) {
  3575.                 box  = FORMAT_LEFTBOX;
  3576.                 line = (y - FBoxA_Top - 2);
  3577.                 if (line < FBoxSpacing)
  3578.                         line = 0;
  3579.                 else
  3580.                         line /= FBoxSpacing;
  3581.                 if (line >= FBoxA_CurLines)
  3582.                         return (FALSE);
  3583.         } else {
  3584.                 /* Right box */
  3585.                 box  = FORMAT_RIGHTBOX;
  3586.                 line = hit;
  3587.                 if (line >= FBoxB_CurLines)
  3588.                         return (FALSE);
  3589.         }
  3590.  
  3591.         /*
  3592.          *              Okay, got a definite hit so go ahead and start the drag
  3593.          */
  3594.         FormatDragBox   = box;
  3595.         FormatDragLine  = line;
  3596.         
  3597.         SetRast(bobrport, 0);                           /* Erase rast bitmap    */
  3598.         SetAPen(bobrport, 2);                           /* White foreground             */
  3599.         SetBPen(bobrport, 1);                           /* Black background             */
  3600.         SetDrMd(bobrport, JAM2);                        /* Solid text                   */
  3601.         SetFont(bobrport, FormBufFont);
  3602.  
  3603.         if (box == FORMAT_LEFTBOX) {
  3604.                 FieldInit *fi = &FieldTypes[AvailableFields[line].type];
  3605.  
  3606.                 mysprintf(viewbuf, FBoxA_FormString, MSG(fi->titlemsgid), fi->idchar);
  3607.                 len  = FBoxA_NumChars;
  3608.                 xpos = FBoxA_Left + 2;
  3609.                 ypos = FBoxA_Top  + 2 + line * FBoxSpacing;
  3610.         } else {
  3611.                 FieldInit *fi = &FieldTypes[CurrentFields[line].type];
  3612.  
  3613.                 mysprintf(viewbuf, FBoxB_FormString, MSG(fi->titlemsgid),
  3614.                                                    CurrentFields[line].width, fi->idchar);
  3615.                 len  = FBoxB_NumChars;
  3616.                 xpos = FBoxB_Left + 2;
  3617.                 ypos = FBoxB_Top  + 2 + line * FBoxSpacing;
  3618.         }
  3619.         TextBob->bob.BobVSprite->X = xpos;
  3620.         TextBob->bob.BobVSprite->Y = ypos;
  3621.         FBoxDeltaX = xpos - x;
  3622.         FBoxDeltaY = ypos - y;
  3623.  
  3624.         Move(bobrport, 0, FormBufFont->tf_Baseline+1);
  3625.         Text(bobrport, viewbuf, len);
  3626.  
  3627.         /*
  3628.          *              Now draw highlight above and below the text
  3629.          */
  3630.         SetAPen(bobrport, 1);
  3631.         Move(bobrport, 0, 0);
  3632.         Draw(bobrport, len * FormBufFont->tf_XSize - 1, 0);
  3633.         Move(bobrport, 0, FormBufFont->tf_YSize + 1);
  3634.         Draw(bobrport, len * FormBufFont->tf_XSize - 1, FormBufFont->tf_YSize + 1);
  3635.  
  3636.         InitMasks(TextBob->bob.BobVSprite);
  3637.         SortGList(rport);
  3638.         DrawGList(rport, ViewPortAddress(FormWindow));
  3639.         return (1);
  3640. }
  3641.  
  3642. /*
  3643.  *              DropBob()
  3644.  *
  3645.  *              Releases the current bob at the target, and updates the two
  3646.  *              lists/displays accordingly.
  3647.  */
  3648. void DropBob(void)
  3649. {
  3650.         EditEvent savedev;
  3651.         EditEvent *ee;
  3652.         int destpos;
  3653.         int seltype;
  3654.  
  3655.         destpos = FBoxDragSelect;                       /* Save destination drop selection      */
  3656.         UpdateBob(0, -9999);                            /* Kill any highlighted region          */
  3657.  
  3658.         /*
  3659.          *              Now re-arrange the edit lists to reflect the new position of
  3660.          *              the dragged field. There are three cases to consider:
  3661.          *
  3662.          *                      Left box        -> Right box
  3663.          *                      Right box       -> Right box
  3664.          *                      Right box       -> Left box
  3665.          */
  3666.         if (destpos == FBOX_NOSELECT)
  3667.                 return;
  3668.         
  3669.         ShowFormatLine(FBoxSelected, FORMAT_UNSELECTED);
  3670.         if (FBoxSelected >= 0 && FBoxSelected < EF_COUNT)
  3671.                 seltype = CurrentFields[FBoxSelected].type;
  3672.         else
  3673.                 seltype = -1;
  3674.  
  3675.         /*
  3676.          *              First, delete item from its current list
  3677.          */
  3678.         if (FormatDragBox == FORMAT_LEFTBOX) {
  3679.                 /*
  3680.                  *              Deleting from left box
  3681.                  */
  3682.                 ee              = &AvailableFields[FormatDragLine];
  3683.                 savedev.type  = ee->type;
  3684.                 savedev.width = FieldTypes[ee->type].defwidth;
  3685.  
  3686.                 while (ee->type != END_EDITLIST) {
  3687.                         ee[0] = ee[1];
  3688.                         ee++;
  3689.                 }
  3690.                 FBoxA_CurLines--;
  3691.                 seltype = savedev.type; /* New selection is item we just dragged */
  3692.         } else {
  3693.                 /*
  3694.                  *              Deleting from right box. If the drop position is after
  3695.                  *              the point where we're deleting, we adjust it to reflect
  3696.                  *              the deleted line.
  3697.                  */
  3698.  
  3699.                 if (destpos > FormatDragLine && destpos <= EF_COUNT)
  3700.                         destpos--;
  3701.  
  3702.                 ee              = &CurrentFields[FormatDragLine];
  3703.                 savedev = *ee;
  3704.                 while (ee->type != END_EDITLIST) {
  3705.                         ee[0] = ee[1];
  3706.                         ee++;
  3707.                 }
  3708.                 FBoxB_CurLines--;
  3709.         }
  3710.         /*
  3711.          *              Now add the item (savedev) to the new list in the appropriate
  3712.          *              place
  3713.          */
  3714.         if (destpos == FBOX_SELECTLEFT) {
  3715.                 /*
  3716.                  *              Search the existing left box list looking for the best place
  3717.                  *              to insert the item -- we do this in strict alphabetical
  3718.                  *              order (based on the % identifer)
  3719.                  */
  3720.                 int newid = FieldTypes[savedev.type].idchar;
  3721.                 EditEvent tempev;
  3722.  
  3723.                 for (ee = &AvailableFields[0]; ee->type != END_EDITLIST; ee++)
  3724.                         if (FieldTypes[ee->type].idchar > newid)
  3725.                                 break;
  3726.  
  3727.                 do {
  3728.                         tempev  = *ee;
  3729.                         *ee     = savedev;
  3730.                         savedev = tempev;
  3731.                         ee++;
  3732.                 } while (ee[-1].type != END_EDITLIST);
  3733.                 FBoxA_CurLines++;
  3734.         } else {
  3735.                 /* 
  3736.                  *              Adding line to the right box. Simply insert it at the
  3737.                  *              specified location.
  3738.                  */
  3739.                 EditEvent tempev;
  3740.  
  3741.                 ee = &CurrentFields[destpos];
  3742.                 do {
  3743.                         tempev  = *ee;
  3744.                         *ee     = savedev;
  3745.                         savedev = tempev;
  3746.                         ee++;
  3747.                 } while (ee[-1].type != END_EDITLIST);
  3748.                 FBoxB_CurLines++;
  3749.         }
  3750.         /*
  3751.          *              Now search our right box list to see can we match the item
  3752.          *              that was currently highlighted when we entered this routine.
  3753.          */
  3754.         FBoxSelected = 0;
  3755.         for (ee = &CurrentFields[0]; ee->type != END_EDITLIST; ee++) {
  3756.                 if (ee->type == seltype)
  3757.                         break;
  3758.                 FBoxSelected++;
  3759.         }
  3760.         if (ee->type == END_EDITLIST) {
  3761.                 FBoxSelected = FBOX_NOSELECT;
  3762.                 GT_SetGadgetAttrs(Gadget[GID_FORMWIDTH], FormWindow,  NULL,
  3763.                                                   GA_Disabled, TRUE,
  3764.                                                   TAG_DONE);
  3765.         } else {
  3766.                 GT_SetGadgetAttrs(Gadget[GID_FORMWIDTH], FormWindow,  NULL,
  3767.                                                   GA_Disabled, FALSE,
  3768.                                                   GTSL_Level,  ee->width,
  3769.                                                   TAG_DONE);
  3770.         }
  3771.  
  3772.         /*
  3773.          *              Now, finally, update our window to show the new arrangement.
  3774.          */
  3775.         RedrawFormatWindow();
  3776. }
  3777.  
  3778. /*
  3779.  *              UpdateBob(x, y)
  3780.  *
  3781.  *              Updates the current position of the bob on the screen, and
  3782.  *              draws any highlights etc. that are deemed necessary.
  3783.  */
  3784. void UpdateBob(int x, int y)
  3785. {
  3786.         int bfonty = FormBufFont->tf_YSize;
  3787.         int pos;
  3788.  
  3789.         /*
  3790.          *              Now see if we are overlapping any of the drop regions, and if
  3791.          *              so, highlight the region appropriately.
  3792.          *
  3793.          *              When dragging into the left box, we highlight the entire box
  3794.          *              since the order of items is pre-determined and it doesn't
  3795.          *              make any sense to drop a field into one particular place.
  3796.          *
  3797.          *              When dragging into the right box, we highlight a line in
  3798.          *              between two other lines, which shows where the item will
  3799.          *              be inserted.
  3800.          *
  3801.          *              For neatness, we don't show highlighting which would have
  3802.          *              no effect on the current settings (i.e. moving a field to
  3803.          *              the same position it's already in).
  3804.          */
  3805.         pos = FBOX_NOSELECT;
  3806.         if (x >= FBoxA_Left && x <= (FBoxA_Left + FBoxA_Width  - 1) &&
  3807.             y >= FBoxA_Top  && y <= (FBoxA_Top  + FBoxA_Height - 1) &&
  3808.                 FormatDragBox != FORMAT_LEFTBOX) {
  3809.                 /*
  3810.                  *              Got a hit in left-hand box
  3811.                  */
  3812.                 pos = FBOX_SELECTLEFT;
  3813.         } else if (x >= FBoxB_Left && x <= (FBoxB_Left + FBoxB_Width - 1) &&
  3814.                            y >= (FBoxB_Top - 10) && y <= (FBoxB_Top + FBoxB_Height + 10)) {
  3815.                 /*
  3816.                  *              Got a hit in the right-hand box, so now calculate which line
  3817.                  */
  3818.                 pos = (y - FBoxB_Top - 2 + bfonty/2) / FBoxSpacing;
  3819.  
  3820.                 if (pos < 0)                            pos = 0;
  3821.                 if (pos > FBoxB_CurLines)       pos = FBoxB_CurLines;
  3822.                 if (FormatDragBox == FORMAT_RIGHTBOX &&
  3823.                                                 (pos == FormatDragLine || pos == (FormatDragLine+1))) {
  3824.                         pos = FBOX_NOSELECT;    /* Don't highlight line we dragged from */
  3825.                 }
  3826.         }
  3827.  
  3828.         if (pos != FBoxDragSelect) {
  3829.                 /*
  3830.                  *              Currently selected item has changed, so erase current one,
  3831.                  *              then draw new one. We also refresh the currently selected
  3832.                  *              line, in case it got trashed by the highlighting.
  3833.                  *
  3834.                  *              Note that we must first move the bob off-screen while we
  3835.                  *              render the changes, otherwise it gets confused and tends
  3836.                  *              to obscure the output.
  3837.                  */
  3838.                 TextBob->bob.BobVSprite->X = 0;
  3839.                 TextBob->bob.BobVSprite->Y = -9999;
  3840.                 SortGList(FormWindow->RPort);
  3841.                 DrawGList(FormWindow->RPort, ViewPortAddress(FormWindow));
  3842.                 ShowDragSelect(FBoxDragSelect, FORMAT_UNSELECTED);
  3843.                 ShowFormatLine(FBoxSelected, FORMAT_SELECTED);
  3844.                 ShowDragSelect(pos, FORMAT_SELECTED);
  3845.                 FBoxDragSelect = pos;
  3846.         }
  3847.  
  3848.         TextBob->bob.BobVSprite->X = x + FBoxDeltaX;
  3849.         TextBob->bob.BobVSprite->Y = y + FBoxDeltaY;
  3850.         SortGList(FormWindow->RPort);
  3851.         DrawGList(FormWindow->RPort, ViewPortAddress(FormWindow));
  3852. }
  3853.