home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Emulation / BasiliskII / src / AmigaOS / prefs_editor_amiga.cpp < prev    next >
C/C++ Source or Header  |  1999-11-01  |  41KB  |  1,643 lines

  1. /*
  2.  *  prefs_editor_amiga.cpp - Preferences editor, AmigaOS implementation (using gtlayout.library)
  3.  *
  4.  *  Basilisk II (C) 1997-1999 Christian Bauer
  5.  *
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published by
  8.  *  the Free Software Foundation; either version 2 of the License, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; if not, write to the Free Software
  18.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  */
  20.  
  21. #include <exec/types.h>
  22. #include <exec/memory.h>
  23. #include <dos/dos.h>
  24. #include <dos/dosextens.h>
  25. #include <dos/filehandler.h>
  26. #include <intuition/intuition.h>
  27. #include <libraries/asl.h>
  28. #include <libraries/gtlayout.h>
  29. #include <libraries/Picasso96.h>
  30. #include <graphics/displayinfo.h>
  31. #include <devices/ahi.h>
  32. #include <proto/exec.h>
  33. #include <proto/dos.h>
  34. #include <proto/intuition.h>
  35. #include <proto/gadtools.h>
  36. #include <proto/gtlayout.h>
  37. #include <proto/graphics.h>
  38. #include <proto/asl.h>
  39. #include <proto/Picasso96.h>
  40. #include <proto/ahi.h>
  41.  
  42. #include "sysdeps.h"
  43. #include "main.h"
  44. #include "xpram.h"
  45. #include "cdrom.h"
  46. #include "user_strings.h"
  47. #include "version.h"
  48. #include "prefs.h"
  49. #include "prefs_editor.h"
  50.  
  51.  
  52. // Gadget/menu IDs
  53. const int MSG_OK = 0x0100;                    // "Start" button
  54. const int MSG_CANCEL = 0x0101;                // "Quit" button
  55. const int MSG_ABOUT = 0x0102;                // "About..." menu item
  56. const int MSG_ZAP_PRAM = 0x0103;            // "Zap PRAM" menu item
  57.  
  58. const int GAD_PAGEGROUP = 0x0200;
  59.  
  60. const int GAD_DISK_LIST = 0x0300;            // "Volumes" pane
  61. const int GAD_ADD_VOLUME = 0x0301;
  62. const int GAD_EDIT_VOLUME = 0x0302;
  63. const int GAD_REMOVE_VOLUME = 0x0303;
  64. const int GAD_CDROM_DEVICE = 0x0304;
  65. const int GAD_CDROM_UNIT = 0x0305;
  66. const int GAD_BOOTDRIVER = 0x0306;
  67. const int GAD_NOCDROM = 0x0307;
  68. const int GAD_EXTFS = 0x0308;
  69.  
  70. const int GAD_VOLUME_READONLY = 0x0310;        // "Add/Edit Volume" window
  71. const int GAD_VOLUME_TYPE = 0x0311;
  72. const int GAD_VOLUME_FILE = 0x0312;
  73. const int GAD_VOLUME_DEVICE = 0x0313;
  74. const int GAD_VOLUME_UNIT = 0x0314;
  75. const int GAD_VOLUME_OPENFLAGS = 0x0315;
  76. const int GAD_VOLUME_STARTBLOCK = 0x0316;
  77. const int GAD_VOLUME_SIZE = 0x0317;
  78. const int GAD_VOLUME_BLOCKSIZE = 0x0318;
  79. const int GAD_VOLUME_PAGEGROUP = 0x0319;
  80.  
  81. const int GAD_SCSI0_DEVICE = 0x0400;        // "SCSI" pane
  82. const int GAD_SCSI1_DEVICE = 0x0401;
  83. const int GAD_SCSI2_DEVICE = 0x0402;
  84. const int GAD_SCSI3_DEVICE = 0x0403;
  85. const int GAD_SCSI4_DEVICE = 0x0404;
  86. const int GAD_SCSI5_DEVICE = 0x0405;
  87. const int GAD_SCSI6_DEVICE = 0x0406;
  88. const int GAD_SCSI0_UNIT = 0x0410;
  89. const int GAD_SCSI1_UNIT = 0x0411;
  90. const int GAD_SCSI2_UNIT = 0x0412;
  91. const int GAD_SCSI3_UNIT = 0x0413;
  92. const int GAD_SCSI4_UNIT = 0x0414;
  93. const int GAD_SCSI5_UNIT = 0x0415;
  94. const int GAD_SCSI6_UNIT = 0x0416;
  95.  
  96. const int GAD_VIDEO_TYPE = 0x0500;            // "Graphics/Sound" pane
  97. const int GAD_DISPLAY_X = 0x0501;
  98. const int GAD_DISPLAY_Y = 0x0502;
  99. const int GAD_FRAMESKIP = 0x0503;
  100. const int GAD_SCREEN_MODE = 0x0504;
  101. const int GAD_AHI_MODE = 0x0505;
  102. const int GAD_NOSOUND = 0x0506;
  103.  
  104. const int GAD_SERIALA_DEVICE = 0x0600;        // "Serial/Network" pane
  105. const int GAD_SERIALA_UNIT = 0x0601;
  106. const int GAD_SERIALA_ISPAR = 0x0602;
  107. const int GAD_SERIALB_DEVICE = 0x0603;
  108. const int GAD_SERIALB_UNIT = 0x0604;
  109. const int GAD_SERIALB_ISPAR = 0x0605;
  110. const int GAD_ETHER_DEVICE = 0x0606;
  111. const int GAD_ETHER_UNIT = 0x00607;
  112.  
  113. const int GAD_RAMSIZE = 0x0700;                // "Memory/Misc" pane
  114. const int GAD_MODELID = 0x0701;
  115. const int GAD_ROM_FILE = 0x0702;
  116.  
  117.  
  118. // Global variables
  119. struct Library *GTLayoutBase = NULL;
  120. static struct FileRequester *dev_request = NULL, *file_request = NULL;
  121.  
  122. // gtlayout.library macros
  123. #define VGROUP LT_New(h, LA_Type, VERTICAL_KIND, TAG_END)
  124. #define HGROUP LT_New(h, LA_Type, HORIZONTAL_KIND, TAG_END)
  125. #define ENDGROUP LT_EndGroup(h)
  126.  
  127. // Prototypes
  128. static void create_volumes_pane(struct LayoutHandle *h);
  129. static void create_scsi_pane(struct LayoutHandle *h);
  130. static void create_graphics_pane(struct LayoutHandle *h);
  131. static void create_serial_pane(struct LayoutHandle *h);
  132. static void create_memory_pane(struct LayoutHandle *h);
  133. static void add_edit_volume(struct LayoutHandle *h, bool adding);
  134. static void remove_volume(struct LayoutHandle *h);
  135. static void ghost_volumes_gadgets(struct LayoutHandle *h);
  136. static void ghost_graphics_gadgets(struct LayoutHandle *h);
  137. static void screen_mode_req(struct Window *win, struct LayoutHandle *h);
  138. static void ahi_mode_req(struct Window *win, struct LayoutHandle *h);
  139. static void read_settings(struct LayoutHandle *h);
  140.  
  141.  
  142. /*
  143.  *  Locale hook - returns string for given ID
  144.  */
  145.  
  146. static __saveds __attribute__((regparm(3))) const char *locale_hook_func(struct Hook *hook /*a0*/, void *id /*a1*/, struct LayoutHandle *h /*a2*/)
  147. {
  148.     return GetString((uint32)id);
  149. }
  150.  
  151. struct Hook locale_hook = {{NULL, NULL}, (HOOKFUNC)locale_hook_func, NULL, NULL};
  152.  
  153.  
  154. /*
  155.  *  Show preferences editor
  156.  *  Returns true when user clicked on "Start", false otherwise
  157.  */
  158.  
  159. bool PrefsEditor(void)
  160. {
  161.     bool retval = true, done = false;
  162.     struct LayoutHandle *h = NULL;
  163.     struct Window *win = NULL;
  164.     struct Menu *menu = NULL;
  165.  
  166.     // Pane tabs
  167.     static const LONG labels[] = {
  168.         STR_VOLUMES_PANE_TITLE,
  169.         STR_SCSI_PANE_TITLE,
  170.         STR_GRAPHICS_SOUND_PANE_TITLE,
  171.         STR_SERIAL_NETWORK_PANE_TITLE,
  172.         STR_MEMORY_MISC_PANE_TITLE,
  173.         -1
  174.     };
  175.  
  176.     // Open gtlayout.library
  177.     GTLayoutBase = (struct Library *)OpenLibrary((UBYTE *)"gtlayout.library", 39);
  178.     if (GTLayoutBase == NULL) {
  179.         WarningAlert(GetString(STR_NO_GTLAYOUT_LIB_WARN));
  180.         return true;
  181.     }
  182.  
  183.     // Create layout handle
  184.     h = LT_CreateHandleTags(NULL,
  185.         LAHN_AutoActivate, FALSE,
  186.         LAHN_LocaleHook, (ULONG)&locale_hook,
  187.         TAG_END
  188.     );
  189.     if (h == NULL)
  190.         goto quit;
  191.  
  192.     // Create menus
  193.     menu = LT_NewMenuTags(
  194.         LAMN_LayoutHandle, (ULONG)h,
  195.         LAMN_TitleID, STR_PREFS_MENU,
  196.         LAMN_ItemID, STR_PREFS_ITEM_ABOUT,
  197.         LAMN_UserData, MSG_ABOUT,
  198.         LAMN_ItemText, (ULONG)NM_BARLABEL,
  199.         LAMN_ItemID, STR_PREFS_ITEM_START,
  200.         LAMN_UserData, MSG_OK,
  201.         LAMN_ItemID, STR_PREFS_ITEM_ZAP_PRAM,
  202.         LAMN_UserData, MSG_ZAP_PRAM,
  203.         LAMN_ItemText, (ULONG)NM_BARLABEL,
  204.         LAMN_ItemID, STR_PREFS_ITEM_QUIT,
  205.         LAMN_UserData, MSG_CANCEL,
  206.         LAMN_KeyText, (ULONG)"Q",
  207.         TAG_END
  208.     );
  209.  
  210.     // Create window contents
  211.     VGROUP;
  212.         VGROUP;
  213.             LT_New(h, LA_Type, TAB_KIND,
  214.                 LATB_LabelTable, (ULONG)labels,
  215.                 LATB_AutoPageID, GAD_PAGEGROUP,
  216.                 LATB_FullWidth, TRUE,
  217.                 TAG_END
  218.             );
  219.         ENDGROUP;
  220.  
  221.         // Panes
  222.         LT_New(h, LA_Type, VERTICAL_KIND,
  223.             LA_ID, GAD_PAGEGROUP,
  224.             LAGR_ActivePage, 0,
  225.             TAG_END
  226.         );
  227.             create_volumes_pane(h);
  228.             create_scsi_pane(h);
  229.             create_graphics_pane(h);
  230.             create_serial_pane(h);
  231.             create_memory_pane(h);
  232.         ENDGROUP;
  233.  
  234.         // Separator between tabs and buttons
  235.         VGROUP;
  236.             LT_New(h, LA_Type, XBAR_KIND,
  237.                 LAXB_FullSize, TRUE,
  238.                 TAG_END
  239.             );
  240.         ENDGROUP;
  241.  
  242.         // "Start" and "Quit" buttons
  243.         LT_New(h, LA_Type, HORIZONTAL_KIND,
  244.             LAGR_SameSize, TRUE,
  245.             LAGR_Spread, TRUE,
  246.             TAG_END
  247.         );
  248.             LT_New(h, LA_Type, BUTTON_KIND,
  249.                 LA_LabelID, STR_START_BUTTON,
  250.                 LA_ID, MSG_OK,
  251.                 LABT_ReturnKey, TRUE,
  252.                 TAG_END
  253.             );
  254.             LT_New(h, LA_Type, BUTTON_KIND,
  255.                 LA_LabelID, STR_QUIT_BUTTON,
  256.                 LA_ID, MSG_CANCEL,
  257.                 LABT_EscKey, TRUE,
  258.                 TAG_END
  259.             );
  260.         ENDGROUP;
  261.     ENDGROUP;
  262.  
  263.     // Open window
  264.     win = LT_Build(h,
  265.         LAWN_TitleID, STR_PREFS_TITLE,
  266.         LAWN_Menu, (ULONG)menu,
  267.         LAWN_IDCMP, IDCMP_CLOSEWINDOW,
  268.         LAWN_BelowMouse, TRUE,
  269.         LAWN_SmartZoom, TRUE,
  270.         WA_SimpleRefresh, TRUE,
  271.         WA_Activate, TRUE,
  272.         WA_CloseGadget, TRUE,
  273.         WA_DepthGadget, TRUE,
  274.         WA_DragBar, TRUE,
  275.         TAG_END
  276.     );
  277.     if (win == NULL)
  278.         goto quit;
  279.  
  280.     // Create file requesters
  281.     dev_request = (struct FileRequester *)AllocAslRequestTags(ASL_FileRequest,
  282.         ASLFR_DoPatterns, TRUE,
  283.         ASLFR_RejectIcons, TRUE,
  284.         ASLFR_InitialDrawer, (ULONG)"DEVS:",
  285.         ASLFR_InitialPattern, (ULONG)"#?.device",
  286.         TAG_END
  287.     );
  288.     file_request = (struct FileRequester *)AllocAslRequestTags(ASL_FileRequest,
  289.         ASLFR_DoPatterns, TRUE,
  290.         ASLFR_RejectIcons, TRUE,
  291.         ASLFR_InitialPattern, (ULONG)"#?",
  292.         TAG_END
  293.     );
  294.  
  295.     // Event loop
  296.     do {
  297.         struct IntuiMessage *msg;
  298.  
  299.         // Wait for message
  300.         WaitPort(win->UserPort);
  301.  
  302.         // Get pending messages
  303.         while (msg = LT_GetIMsg(h)) {
  304.  
  305.             // Get data from message and reply
  306.             ULONG cl = msg->Class;
  307.             UWORD code = msg->Code;
  308.             struct Gadget *gad = (struct Gadget *)msg->IAddress;
  309.             LT_ReplyIMsg(msg);
  310.  
  311.             // Handle message according to class
  312.             switch (cl) {
  313.                 case IDCMP_CLOSEWINDOW:
  314.                     retval = false;
  315.                     done = true;
  316.                     break;
  317.  
  318.                 case IDCMP_GADGETUP:
  319.                     switch (gad->GadgetID) {
  320.                         case MSG_OK:
  321.                             read_settings(h);
  322.                             SavePrefs();
  323.                             retval = true;
  324.                             done = true;
  325.                             break;
  326.  
  327.                         case MSG_CANCEL:
  328.                             retval = false;
  329.                             done = true;
  330.                             break;
  331.  
  332.                         case GAD_DISK_LIST:
  333.                             ghost_volumes_gadgets(h);
  334.                             break;
  335.  
  336.                         case GAD_ADD_VOLUME:
  337.                             LT_LockWindow(win);
  338.                             add_edit_volume(h, true);
  339.                             LT_UnlockWindow(win);
  340.                             break;
  341.  
  342.                         case GAD_EDIT_VOLUME:
  343.                             LT_LockWindow(win);
  344.                             add_edit_volume(h, false);
  345.                             LT_UnlockWindow(win);
  346.                             break;
  347.  
  348.                         case GAD_REMOVE_VOLUME:
  349.                             remove_volume(h);
  350.                             break;
  351.  
  352.                         case GAD_BOOTDRIVER:
  353.                             switch (code) {
  354.                                 case 0:
  355.                                     PrefsReplaceInt16("bootdriver", 0);
  356.                                     break;
  357.                                 case 1:
  358.                                     PrefsReplaceInt16("bootdriver", CDROMRefNum);
  359.                                     break;
  360.                             }
  361.                             break;
  362.  
  363.                         case GAD_VIDEO_TYPE:
  364.                             ghost_graphics_gadgets(h);
  365.                             break;
  366.  
  367.                         case GAD_FRAMESKIP:
  368.                             switch (code) {
  369.                                 case 0:
  370.                                     PrefsReplaceInt32("frameskip", 12);
  371.                                     break;
  372.                                 case 1:
  373.                                     PrefsReplaceInt32("frameskip", 8);
  374.                                     break;
  375.                                 case 2:
  376.                                     PrefsReplaceInt32("frameskip", 6);
  377.                                     break;
  378.                                 case 3:
  379.                                     PrefsReplaceInt32("frameskip", 4);
  380.                                     break;
  381.                                 case 4:
  382.                                     PrefsReplaceInt32("frameskip", 2);
  383.                                     break;
  384.                                 case 5:
  385.                                     PrefsReplaceInt32("frameskip", 1);
  386.                                     break;
  387.                             }
  388.                             break;
  389.  
  390.                         case GAD_MODELID:
  391.                             switch (code) {
  392.                                 case 0:
  393.                                     PrefsReplaceInt32("modelid", 5);
  394.                                     break;
  395.                                 case 1:
  396.                                     PrefsReplaceInt32("modelid", 14);
  397.                                     break;
  398.                             }
  399.                             break;
  400.                     }
  401.                     break;
  402.  
  403.                 case IDCMP_IDCMPUPDATE:
  404.                     switch (gad->GadgetID) {
  405.                         case GAD_DISK_LIST:    // Double-click on volumes list = edit volume
  406.                             LT_LockWindow(win);
  407.                             add_edit_volume(h, false);
  408.                             LT_UnlockWindow(win);
  409.                             break;
  410.  
  411.                         case GAD_SCREEN_MODE:
  412.                             screen_mode_req(win, h);
  413.                             break;
  414.  
  415.                         case GAD_AHI_MODE:
  416.                             ahi_mode_req(win, h);
  417.                             break;
  418.  
  419.                         case GAD_CDROM_DEVICE:
  420.                         case GAD_SCSI0_DEVICE:
  421.                         case GAD_SCSI1_DEVICE:
  422.                         case GAD_SCSI2_DEVICE:
  423.                         case GAD_SCSI3_DEVICE:
  424.                         case GAD_SCSI4_DEVICE:
  425.                         case GAD_SCSI5_DEVICE:
  426.                         case GAD_SCSI6_DEVICE:
  427.                         case GAD_SERIALA_DEVICE:
  428.                         case GAD_SERIALB_DEVICE:
  429.                         case GAD_ETHER_DEVICE:
  430.                             if (dev_request) {
  431.                                 LT_LockWindow(win);
  432.                                 BOOL result = AslRequestTags(dev_request, ASLFR_Window, (ULONG)win, TAG_END);
  433.                                 LT_UnlockWindow(win);
  434.                                 if (result) {
  435.                                     char *str;
  436.                                     GT_GetGadgetAttrs(gad, win, NULL, GTST_String, (ULONG)&str, TAG_END);
  437.                                     strncpy(str, dev_request->rf_File, 255);    // Don't copy the directory part. This is usually "DEVS:" and we don't need that.
  438.                                     str[255] = 0;
  439.                                     LT_SetAttributes(h, gad->GadgetID, GTST_String, (ULONG)str, TAG_END);
  440.                                 }
  441.                             }
  442.                             break;
  443.  
  444.                         case GAD_ROM_FILE:
  445.                             if (file_request) {
  446.                                 LT_LockWindow(win);
  447.                                 BOOL result = AslRequestTags(file_request, ASLFR_Window, (ULONG)win, TAG_END);
  448.                                 LT_UnlockWindow(win);
  449.                                 if (result) {
  450.                                     char *str;
  451.                                     GT_GetGadgetAttrs(gad, win, NULL, GTST_String, (ULONG)&str, TAG_END);
  452.                                     strncpy(str, file_request->rf_Dir, 255);
  453.                                     str[255] = 0;
  454.                                     AddPart(str, file_request->rf_File, 255);
  455.                                     LT_SetAttributes(h, gad->GadgetID, GTST_String, (ULONG)str, TAG_END);
  456.                                 }
  457.                             }
  458.                             break;
  459.                     }
  460.                     break;
  461.  
  462.                 case IDCMP_MENUPICK:
  463.                     while (code != MENUNULL) {
  464.                         struct MenuItem *item = ItemAddress(menu, code);
  465.                         if (item == NULL)
  466.                             break;
  467.                         switch ((ULONG)GTMENUITEM_USERDATA(item)) {
  468.                             case MSG_OK:
  469.                                 read_settings(h);
  470.                                 SavePrefs();
  471.                                 retval = true;
  472.                                 done = true;
  473.                                 break;
  474.  
  475.                             case MSG_CANCEL:
  476.                                 retval = false;
  477.                                 done = true;
  478.                                 break;
  479.  
  480.                             case MSG_ABOUT: {
  481.                                 char str[256];
  482.                                 sprintf(str, GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR);
  483.                                 strncat(str, "\n", 255);
  484.                                 strncat(str, GetString(STR_ABOUT_TEXT2), 255);
  485.  
  486.                                 EasyStruct req;
  487.                                 req.es_StructSize = sizeof(EasyStruct);
  488.                                 req.es_Flags = 0;
  489.                                 req.es_Title = (UBYTE *)GetString(STR_ABOUT_TITLE);
  490.                                 req.es_TextFormat = (UBYTE *)str;
  491.                                 req.es_GadgetFormat = (UBYTE *)GetString(STR_OK_BUTTON);
  492.                                 LT_LockWindow(win);
  493.                                 EasyRequest(win, &req, NULL);
  494.                                 LT_UnlockWindow(win);
  495.                                 break;
  496.                             }
  497.  
  498.                             case MSG_ZAP_PRAM:
  499.                                 ZapPRAM();
  500.                                 break;
  501.                         }
  502.                         code = item->NextSelect;
  503.                     }
  504.                     break;
  505.             }
  506.         }
  507.     } while (!done);
  508.  
  509. quit:
  510.     // Free requesters
  511.     FreeAslRequest(dev_request);
  512.     FreeAslRequest(file_request);
  513.  
  514.     // Delete handle
  515.     LT_DeleteHandle(h);
  516.  
  517.     // Close gtlayout.library
  518.     CloseLibrary(GTLayoutBase);
  519.     return retval;
  520. }
  521.  
  522.  
  523. /*
  524.  *  "Volumes" pane
  525.  */
  526.  
  527. static struct List disk_list;
  528. static char cdrom_name[256], extfs_name[256];
  529. static ULONG cdrom_unit, cdrom_flags, cdrom_start, cdrom_size, cdrom_bsize;
  530. static BYTE bootdriver_num, nocdrom;
  531.  
  532. // Read volumes preferences
  533. static void parse_volumes_prefs(void)
  534. {
  535.     NewList(&disk_list);
  536.     const char *str;
  537.     for (int i=0; (str = PrefsFindString("disk", i)) != NULL; i++) {
  538.         struct Node *item = (struct Node *)AllocMem(sizeof(struct Node), MEMF_CLEAR);
  539.         item->ln_Name = (char *)str;
  540.         AddTail(&disk_list, item);
  541.     }
  542.  
  543.     cdrom_name[0] = 0;
  544.     cdrom_unit = 0; cdrom_flags = 0; cdrom_start = 0; cdrom_size = 0; cdrom_bsize = 2048;
  545.  
  546.     str = PrefsFindString("cdrom");
  547.     if (str)
  548.         sscanf(str, "/dev/%[^/]/%ld/%ld/%ld/%ld/%ld", cdrom_name, &cdrom_unit, &cdrom_flags, &cdrom_start, &cdrom_size, &cdrom_bsize);
  549.  
  550.     bootdriver_num = 0;
  551.  
  552.     int bootdriver = PrefsFindInt16("bootdriver");
  553.     switch (bootdriver) {
  554.         case 0:
  555.             bootdriver_num = 0;
  556.             break;
  557.         case CDROMRefNum:
  558.             bootdriver_num = 1;
  559.             break;
  560.     }
  561.  
  562.     nocdrom = PrefsFindBool("nocdrom");
  563.  
  564.     extfs_name[0] = 0;
  565.     str = PrefsFindString("extfs");
  566.     if (str)
  567.         strncpy(extfs_name, str, sizeof(extfs_name) - 1);
  568. }
  569.  
  570. // Ghost/unghost "Edit" and "Remove" buttons
  571. static void ghost_volumes_gadgets(struct LayoutHandle *h)
  572. {
  573.     UWORD sel = LT_GetAttributes(h, GAD_DISK_LIST, TAG_END);
  574.     if (sel == 0xffff) {
  575.         LT_SetAttributes(h, GAD_EDIT_VOLUME, GA_Disabled, TRUE, TAG_END);
  576.         LT_SetAttributes(h, GAD_REMOVE_VOLUME, GA_Disabled, TRUE, TAG_END);
  577.     } else {
  578.         LT_SetAttributes(h, GAD_EDIT_VOLUME, GA_Disabled, FALSE, TAG_END);
  579.         LT_SetAttributes(h, GAD_REMOVE_VOLUME, GA_Disabled, FALSE, TAG_END);
  580.     }
  581. }
  582.  
  583. // Get device data from partition name
  584. static void analyze_partition(const char *part, char *dev_name, ULONG &dev_unit, ULONG &dev_flags, ULONG &dev_start, ULONG &dev_size, ULONG &dev_bsize)
  585. {
  586.     // Remove everything after and including the ':'
  587.     char str[256];
  588.     strncpy(str, part, sizeof(str) - 1);
  589.     str[sizeof(str) - 1] = 0;
  590.     char *colon = strchr(str, ':');
  591.     if (colon)
  592.         *colon = 0;
  593.  
  594.     // Look for partition
  595.     struct DosList *dl = LockDosList(LDF_DEVICES | LDF_READ);
  596.     dl = FindDosEntry(dl, str, LDF_DEVICES);
  597.     if (dl) {
  598.         // Get File System Startup Message
  599.         struct FileSysStartupMsg *fssm = (struct FileSysStartupMsg *)(dl->dol_misc.dol_handler.dol_Startup << 2);
  600.         if (fssm) {
  601.             // Get DOS environment vector
  602.             struct DosEnvec *de = (struct DosEnvec *)(fssm->fssm_Environ << 2);
  603.             if (de && de->de_TableSize >= DE_UPPERCYL) {
  604.                 // Read settings from FSSM and Envec
  605.                 strncpy(dev_name, (char *)(fssm->fssm_Device << 2) + 1, 255);
  606.                 dev_name[255] = 0;
  607.                 dev_unit = fssm->fssm_Unit;
  608.                 dev_flags = fssm->fssm_Flags;
  609.                 dev_start = de->de_BlocksPerTrack * de->de_Surfaces * de->de_LowCyl;
  610.                 dev_size = de->de_BlocksPerTrack * de->de_Surfaces * (de->de_HighCyl - de->de_LowCyl + 1);
  611.                 dev_bsize = de->de_SizeBlock << 2;
  612.             }
  613.         }
  614.     }
  615.     UnLockDosList(LDF_DEVICES | LDF_READ);
  616. }
  617.  
  618. // Display and handle "Add/Edit Volume" window
  619. static void add_edit_volume(struct LayoutHandle *h2, bool adding)
  620. {
  621.     bool ok_clicked = false;
  622.  
  623.     UWORD sel = LT_GetAttributes(h2, GAD_DISK_LIST, TAG_END);
  624.     if ((sel == 0xffff) && !adding)
  625.         return;
  626.  
  627.     char dev_name[256] = "";
  628.     char file_name[256] = "";
  629.     ULONG dev_unit = 0, dev_flags = 0, dev_start = 0, dev_size = 0, dev_bsize = 512;
  630.     BYTE read_only = false, is_device = false;
  631.  
  632.     if (!adding) {
  633.         const char *str = PrefsFindString("disk", sel);
  634.         if (str == NULL)
  635.             return;
  636.         if (str[0] == '*') {
  637.             read_only = true;
  638.             str++;
  639.         }
  640.         if (strstr(str, "/dev/") == str) {
  641.             is_device = true;
  642.             sscanf(str, "/dev/%[^/]/%ld/%ld/%ld/%ld/%ld", dev_name, &dev_unit, &dev_flags, &dev_start, &dev_size, &dev_bsize);
  643.         } else {
  644.             strncpy(file_name, str, sizeof(file_name) - 1);
  645.             file_name[sizeof(file_name) - 1] = 0;
  646.         }
  647.     }
  648.  
  649.     // Create layout handle
  650.     struct LayoutHandle *h = NULL;
  651.     struct Window *win = NULL;
  652.     h = LT_CreateHandleTags(NULL,
  653.         LAHN_AutoActivate, FALSE,
  654.         LAHN_LocaleHook, (ULONG)&locale_hook,
  655.         TAG_END
  656.     );
  657.     if (h == NULL)
  658.         return;
  659.  
  660.     // Create window contents
  661.     VGROUP;
  662.         // Volume gadgets
  663.         VGROUP;
  664.             LT_New(h, LA_Type, CHECKBOX_KIND,
  665.                 LA_LabelID, STR_VOL_READONLY_CTRL,
  666.                 LA_ID, GAD_VOLUME_READONLY,
  667.                 LA_BYTE, (ULONG)&read_only,
  668.                 TAG_END
  669.             );
  670.             LT_New(h, LA_Type, CYCLE_KIND,
  671.                 LA_LabelID, STR_VOL_TYPE_CTRL,
  672.                 LA_ID, GAD_VOLUME_TYPE,
  673.                 LACY_AutoPageID, GAD_VOLUME_PAGEGROUP,
  674.                 LACY_FirstLabel, STR_VOL_FILE_LAB,
  675.                 LACY_LastLabel, STR_VOL_DEVICE_LAB,
  676.                 LA_BYTE, (ULONG)&is_device,
  677.                 TAG_END
  678.             );
  679.         ENDGROUP;
  680.         LT_New(h, LA_Type, VERTICAL_KIND,
  681.             LA_ID, GAD_VOLUME_PAGEGROUP,
  682.             LAGR_ActivePage, is_device,
  683.             TAG_END
  684.         );
  685.             VGROUP;
  686.                 LT_New(h, LA_Type, STRING_KIND,
  687.                     LA_LabelID, STR_VOL_FILE_CTRL,
  688.                     LA_ID, GAD_VOLUME_FILE,
  689.                     LA_Chars, 20,
  690.                     LA_STRPTR, (ULONG)file_name,
  691.                     GTST_MaxChars, sizeof(file_name) - 1,
  692.                     LAST_Picker, TRUE,
  693.                     TAG_END
  694.                 );
  695.             ENDGROUP;
  696.             VGROUP;
  697.                 LT_New(h, LA_Type, STRING_KIND,
  698.                     LA_LabelID, STR_DEVICE_CTRL,
  699.                     LA_ID, GAD_VOLUME_DEVICE,
  700.                     LA_Chars, 20,
  701.                     LA_STRPTR, (ULONG)dev_name,
  702.                     GTST_MaxChars, sizeof(dev_name) - 1,
  703.                     LAST_Picker, TRUE,
  704.                     TAG_END
  705.                 );
  706.                 LT_New(h, LA_Type, INTEGER_KIND,
  707.                     LA_LabelID, STR_UNIT_CTRL,
  708.                     LA_ID, GAD_VOLUME_UNIT,
  709.                     LA_LONG, (ULONG)&dev_unit,
  710.                     LAIN_UseIncrementers, TRUE,
  711.                     GTIN_MaxChars, 8,
  712.                     TAG_END
  713.                 );
  714.                 LT_New(h, LA_Type, INTEGER_KIND,
  715.                     LA_LabelID, STR_VOL_OPENFLAGS_CTRL,
  716.                     LA_ID, GAD_VOLUME_OPENFLAGS,
  717.                     LA_LONG, (ULONG)&dev_flags,
  718.                     LAIN_UseIncrementers, TRUE,
  719.                     GTIN_MaxChars, 8,
  720.                     TAG_END
  721.                 );
  722.                 LT_New(h, LA_Type, INTEGER_KIND,
  723.                     LA_LabelID, STR_VOL_STARTBLOCK_CTRL,
  724.                     LA_ID, GAD_VOLUME_STARTBLOCK,
  725.                     LA_LONG, (ULONG)&dev_start,
  726.                     LAIN_UseIncrementers, TRUE,
  727.                     GTIN_MaxChars, 8,
  728.                     TAG_END
  729.                 );
  730.                 LT_New(h, LA_Type, INTEGER_KIND,
  731.                     LA_LabelID, STR_VOL_SIZE_CTRL,
  732.                     LA_ID, GAD_VOLUME_SIZE,
  733.                     LA_LONG, (ULONG)&dev_size,
  734.                     LAIN_UseIncrementers, TRUE,
  735.                     GTIN_MaxChars, 8,
  736.                     TAG_END
  737.                 );
  738.                 LT_New(h, LA_Type, INTEGER_KIND,
  739.                     LA_LabelID, STR_VOL_BLOCKSIZE_CTRL,
  740.                     LA_ID, GAD_VOLUME_BLOCKSIZE,
  741.                     LA_LONG, (ULONG)&dev_bsize,
  742.                     LAIN_UseIncrementers, TRUE,
  743.                     GTIN_MaxChars, 8,
  744.                     TAG_END
  745.                 );
  746.             ENDGROUP;
  747.         ENDGROUP;
  748.  
  749.         // Separator between gadgets and buttons
  750.         VGROUP;
  751.             LT_New(h, LA_Type, XBAR_KIND,
  752.                 LAXB_FullSize, TRUE,
  753.                 TAG_END
  754.             );
  755.         ENDGROUP;
  756.  
  757.         // "OK" and "Cancel" buttons
  758.         LT_New(h, LA_Type, HORIZONTAL_KIND,
  759.             LAGR_SameSize, TRUE,
  760.             LAGR_Spread, TRUE,
  761.             TAG_END
  762.         );
  763.             LT_New(h, LA_Type, BUTTON_KIND,
  764.                 LA_LabelID, STR_OK_BUTTON,
  765.                 LA_ID, MSG_OK,
  766.                 LABT_ReturnKey, TRUE,
  767.                 TAG_END
  768.             );
  769.             LT_New(h, LA_Type, BUTTON_KIND,
  770.                 LA_LabelID, STR_CANCEL_BUTTON,
  771.                 LA_ID, MSG_CANCEL,
  772.                 LABT_EscKey, TRUE,
  773.                 TAG_END
  774.             );
  775.         ENDGROUP;
  776.     ENDGROUP;
  777.  
  778.     // Open window
  779.     win = LT_Build(h,
  780.         LAWN_TitleID, adding ? STR_ADD_VOLUME_TITLE : STR_EDIT_VOLUME_TITLE,
  781.         LAWN_IDCMP, IDCMP_CLOSEWINDOW,
  782.         LAWN_BelowMouse, TRUE,
  783.         LAWN_SmartZoom, TRUE,
  784.         WA_SimpleRefresh, TRUE,
  785.         WA_Activate, TRUE,
  786.         WA_CloseGadget, TRUE,
  787.         WA_DepthGadget, TRUE,
  788.         WA_DragBar, TRUE,
  789.         TAG_END
  790.     );
  791.     if (win == NULL) {
  792.         LT_DeleteHandle(h);
  793.         return;
  794.     }
  795.  
  796.     // Event loop
  797.     bool done = false;
  798.     do {
  799.         struct IntuiMessage *msg;
  800.  
  801.         // Wait for message
  802.         WaitPort(win->UserPort);
  803.  
  804.         // Get pending messages
  805.         while (msg = LT_GetIMsg(h)) {
  806.  
  807.             // Get data from message and reply
  808.             ULONG cl = msg->Class;
  809.             UWORD code = msg->Code;
  810.             struct Gadget *gad = (struct Gadget *)msg->IAddress;
  811.             LT_ReplyIMsg(msg);
  812.  
  813.             // Handle message according to class
  814.             switch (cl) {
  815.                 case IDCMP_CLOSEWINDOW:
  816.                     done = true;
  817.                     break;
  818.  
  819.                 case IDCMP_GADGETUP:
  820.                     switch (gad->GadgetID) {
  821.                         case MSG_OK:
  822.                             ok_clicked = true;
  823.                             done = true;
  824.                             break;
  825.                         case MSG_CANCEL:
  826.                             done = true;
  827.                             break;
  828.                     }
  829.                     break;
  830.  
  831.                 case IDCMP_IDCMPUPDATE: {
  832.                     struct FileRequester *req = NULL;
  833.                     switch (gad->GadgetID) {
  834.                         case GAD_VOLUME_FILE:
  835.                             req = file_request;
  836.                             goto do_req;
  837.                         case GAD_VOLUME_DEVICE:
  838.                             req = dev_request;
  839. do_req:                        if (req) {
  840.                                 LT_LockWindow(win);
  841.                                 BOOL result = AslRequestTags(req, ASLFR_Window, (ULONG)win, TAG_END);
  842.                                 LT_UnlockWindow(win);
  843.                                 if (result) {
  844.                                     char *str;
  845.                                     GT_GetGadgetAttrs(gad, win, NULL, GTST_String, (ULONG)&str, TAG_END);
  846.                                     if (gad->GadgetID == GAD_VOLUME_FILE) {
  847.                                         strncpy(str, req->rf_Dir, 255);
  848.                                         str[255] = 0;
  849.                                         AddPart(str, req->rf_File, 255);
  850.                                     } else {
  851.                                         if (strlen(req->rf_File)) {
  852.                                             strncpy(str, req->rf_File, 255);    // Don't copy the directory part. This is usually "DEVS:" and we don't need that.
  853.                                             str[255] = 0;
  854.                                         } else if (strlen(req->rf_Dir) && req->rf_Dir[strlen(req->rf_Dir) - 1] == ':') {
  855.                                             analyze_partition(req->rf_Dir, str, dev_unit, dev_flags, dev_start, dev_size, dev_bsize);
  856.                                             LT_SetAttributes(h, GAD_VOLUME_UNIT, GTIN_Number, dev_unit, TAG_END);
  857.                                             LT_SetAttributes(h, GAD_VOLUME_OPENFLAGS, GTIN_Number, dev_flags, TAG_END);
  858.                                             LT_SetAttributes(h, GAD_VOLUME_STARTBLOCK, GTIN_Number, dev_start, TAG_END);
  859.                                             LT_SetAttributes(h, GAD_VOLUME_SIZE, GTIN_Number, dev_size, TAG_END);
  860.                                             LT_SetAttributes(h, GAD_VOLUME_BLOCKSIZE, GTIN_Number, dev_bsize, TAG_END);
  861.                                         }
  862.                                     }
  863.                                     LT_SetAttributes(h, gad->GadgetID, GTST_String, (ULONG)str, TAG_END);
  864.                                 }
  865.                             }
  866.                             break;
  867.                     }
  868.                     break;
  869.                 }
  870.             }
  871.         }
  872.     } while (!done);
  873.  
  874.     // Delete handle
  875.     LT_DeleteHandle(h);
  876.  
  877.     // Update preferences and list view
  878.     if (ok_clicked) {
  879.         char str[256];
  880.         LT_UpdateStrings(h);
  881.  
  882.         if (is_device)
  883.             sprintf(str, "%s/dev/%s/%ld/%ld/%ld/%ld/%ld", read_only ? "*" : "", dev_name, dev_unit, dev_flags, dev_start, dev_size, dev_bsize);
  884.         else
  885.             sprintf(str, "%s%s", read_only ? "*" : "", file_name);
  886.         LT_SetAttributes(h2, GAD_DISK_LIST, GTLV_Labels, ~0, TAG_END);
  887.  
  888.         if (adding) {
  889.  
  890.             // Add new item
  891.             int i;
  892.             PrefsAddString("disk", str);
  893.             struct Node *item = (struct Node *)AllocMem(sizeof(struct Node), MEMF_CLEAR);
  894.             for (i=0; PrefsFindString("disk", i); i++) ;
  895.             item->ln_Name = (char *)PrefsFindString("disk", i - 1);
  896.             AddTail(&disk_list, item);
  897.  
  898.         } else {
  899.  
  900.             // Replace existing item
  901.             PrefsReplaceString("disk", str, sel);
  902.             struct Node *item = disk_list.lh_Head;
  903.             for (int i=0; item->ln_Succ; i++) {
  904.                 if (i == sel) {
  905.                     item->ln_Name = (char *)PrefsFindString("disk", sel);
  906.                     break;
  907.                 }
  908.                 item = item->ln_Succ;
  909.             }
  910.         }
  911.         LT_SetAttributes(h2, GAD_DISK_LIST, GTLV_Labels, (ULONG)&disk_list, TAG_END);
  912.         ghost_volumes_gadgets(h2);
  913.     }
  914. }
  915.  
  916. // Remove volume from list
  917. static void remove_volume(struct LayoutHandle *h)
  918. {
  919.     UWORD sel = LT_GetAttributes(h, GAD_DISK_LIST, TAG_END);
  920.     if (sel != 0xffff) {
  921.  
  922.         // Remove item from preferences and list view
  923.         LT_SetAttributes(h, GAD_DISK_LIST, GTLV_Labels, ~0, TAG_END);
  924.         PrefsRemoveItem("disk", sel);
  925.         struct Node *item = disk_list.lh_Head;
  926.         for (int i=0; item->ln_Succ; i++) {
  927.             struct Node *next = item->ln_Succ;
  928.             if (i == sel) {
  929.                 Remove(item);
  930.                 FreeMem(item, sizeof(struct Node));
  931.                 break;
  932.             }
  933.             item = next;
  934.         }
  935.         LT_SetAttributes(h, GAD_DISK_LIST, GTLV_Labels, (ULONG)&disk_list, GTLV_Selected, 0xffff, TAG_END);
  936.         ghost_volumes_gadgets(h);
  937.     }
  938. }
  939.  
  940. // Read settings from gadgets and set preferences
  941. static void read_volumes_settings(void)
  942. {
  943.     struct Node *item = disk_list.lh_Head;
  944.     while (item->ln_Succ) {
  945.         struct Node *next = item->ln_Succ;
  946.         Remove(item);
  947.         FreeMem(item, sizeof(struct Node));
  948.         item = next;
  949.     }
  950.  
  951.     if (strlen(cdrom_name)) {
  952.         char str[256];
  953.         sprintf(str, "/dev/%s/%ld/%ld/%ld/%ld/%ld", cdrom_name, cdrom_unit, cdrom_flags, cdrom_start, cdrom_size, cdrom_bsize);
  954.         PrefsReplaceString("cdrom", str);
  955.     } else
  956.         PrefsRemoveItem("cdrom");
  957.  
  958.     PrefsReplaceBool("nocdrom", nocdrom);
  959.  
  960.     if (strlen(extfs_name))
  961.         PrefsReplaceString("extfs", extfs_name);
  962. }
  963.  
  964. // Create "Volumes" pane
  965. static void create_volumes_pane(struct LayoutHandle *h)
  966. {
  967.     parse_volumes_prefs();
  968.  
  969.     VGROUP;
  970.         LT_New(h, LA_Type, VERTICAL_KIND,
  971.             LA_LabelID, STR_VOLUMES_CTRL,
  972.             TAG_END
  973.         );
  974.             VGROUP;
  975.                 LT_New(h, LA_Type, LISTVIEW_KIND,
  976.                     LA_ID, GAD_DISK_LIST,
  977.                     LA_Chars, 20,
  978.                     GTLV_Labels, (ULONG)&disk_list,
  979.                     LALV_Lines, 6,
  980.                     LALV_Link, (ULONG)NIL_LINK,
  981.                     LALV_ResizeX, TRUE,
  982.                     LALV_ResizeY, TRUE,
  983.                     LALV_Selected, 0,
  984.                     TAG_END
  985.                 );
  986.             ENDGROUP;
  987.             LT_New(h, LA_Type, HORIZONTAL_KIND,
  988.                 LAGR_SameSize, TRUE,
  989.                 LAGR_Spread, TRUE,
  990.                 TAG_END
  991.             );
  992.                 LT_New(h, LA_Type, BUTTON_KIND,
  993.                     LA_LabelID, STR_ADD_VOLUME_BUTTON,
  994.                     LA_ID, GAD_ADD_VOLUME,
  995.                     TAG_END
  996.                 );
  997.                 LT_New(h, LA_Type, BUTTON_KIND,
  998.                     LA_LabelID, STR_EDIT_VOLUME_BUTTON,
  999.                     LA_ID, GAD_EDIT_VOLUME,
  1000.                     TAG_END
  1001.                 );
  1002.                 LT_New(h, LA_Type, BUTTON_KIND,
  1003.                     LA_LabelID, STR_REMOVE_VOLUME_BUTTON,
  1004.                     LA_ID, GAD_REMOVE_VOLUME,
  1005.                     TAG_END
  1006.                 );
  1007.             ENDGROUP;
  1008.         ENDGROUP;
  1009.         LT_New(h, LA_Type, VERTICAL_KIND,
  1010.             LA_LabelID, STR_CDROM_DRIVE_CTRL,
  1011.             TAG_END
  1012.         );
  1013.             LT_New(h, LA_Type, STRING_KIND,
  1014.                 LA_LabelID, STR_DEVICE_CTRL,
  1015.                 LA_ID, GAD_CDROM_DEVICE,
  1016.                 LA_Chars, 20,
  1017.                 LA_STRPTR, (ULONG)cdrom_name,
  1018.                 GTST_MaxChars, sizeof(cdrom_name) - 1,
  1019.                 LAST_Picker, TRUE,
  1020.                 TAG_END
  1021.             );
  1022.             LT_New(h, LA_Type, INTEGER_KIND,
  1023.                 LA_LabelID, STR_UNIT_CTRL,
  1024.                 LA_ID, GAD_CDROM_UNIT,
  1025.                 LA_LONG, (ULONG)&cdrom_unit,
  1026.                 LAIN_UseIncrementers, TRUE,
  1027.                 GTIN_MaxChars, 8,
  1028.                 TAG_END
  1029.             );
  1030.             LT_New(h, LA_Type, CYCLE_KIND,
  1031.                 LA_LabelID, STR_BOOTDRIVER_CTRL,
  1032.                 LA_ID, GAD_BOOTDRIVER,
  1033.                 LACY_FirstLabel, STR_BOOT_ANY_LAB,
  1034.                 LACY_LastLabel, STR_BOOT_CDROM_LAB,
  1035.                 LA_BYTE, (ULONG)&bootdriver_num,
  1036.                 TAG_END
  1037.             );
  1038.             LT_New(h, LA_Type, CHECKBOX_KIND,
  1039.                 LA_LabelID, STR_NOCDROM_CTRL,
  1040.                 LA_ID, GAD_NOCDROM,
  1041.                 LA_BYTE, (ULONG)&nocdrom,
  1042.                 TAG_END
  1043.             );
  1044.         ENDGROUP;
  1045.         VGROUP;
  1046.             LT_New(h, LA_Type, STRING_KIND,
  1047.                 LA_LabelID, STR_EXTFS_CTRL,
  1048.                 LA_ID, GAD_EXTFS,
  1049.                 LA_Chars, 20,
  1050.                 LA_STRPTR, (ULONG)extfs_name,
  1051.                 GTST_MaxChars, sizeof(extfs_name) - 1,
  1052.                 TAG_END
  1053.             );
  1054.         ENDGROUP;
  1055.     ENDGROUP;
  1056. }
  1057.  
  1058.  
  1059. /*
  1060.  *  "SCSI" pane
  1061.  */
  1062.  
  1063. static char scsi_dev[6][256];
  1064. static LONG scsi_unit[6];
  1065.  
  1066. // Read SCSI preferences
  1067. static void parse_scsi_prefs(void)
  1068. {
  1069.     for (int i=0; i<7; i++) {
  1070.         scsi_dev[i][0] = 0;
  1071.         scsi_unit[i] = 0;
  1072.  
  1073.         char prefs_name[16];
  1074.         sprintf(prefs_name, "scsi%d", i);
  1075.         const char *str = PrefsFindString(prefs_name);
  1076.         if (str)
  1077.             sscanf(str, "%[^/]/%ld", scsi_dev[i], &scsi_unit[i]);
  1078.     }
  1079. }
  1080.  
  1081. // Read settings from gadgets and set preferences
  1082. static void read_scsi_settings(void)
  1083. {
  1084.     for (int i=0; i<7; i++) {
  1085.         char prefs_name[16];
  1086.         sprintf(prefs_name, "scsi%d", i);
  1087.  
  1088.         if (strlen(scsi_dev[i])) {
  1089.             char str[256];
  1090.             sprintf(str, "%s/%ld", scsi_dev[i], scsi_unit[i]);
  1091.             PrefsReplaceString(prefs_name, str);
  1092.         } else
  1093.             PrefsRemoveItem(prefs_name);
  1094.     }
  1095. }
  1096.  
  1097. // Create "SCSI" pane
  1098. static void create_scsi_pane(struct LayoutHandle *h)
  1099. {
  1100.     parse_scsi_prefs();
  1101.  
  1102.     VGROUP;
  1103.         for (int i=0; i<7; i++) {
  1104.             HGROUP;
  1105.                 LT_New(h, LA_Type, TEXT_KIND,
  1106.                     LA_LabelID, STR_SCSI_ID_0 + i,
  1107.                     TAG_END
  1108.                 );
  1109.                 LT_New(h, LA_Type, STRING_KIND,
  1110.                     LA_LabelID, STR_DEVICE_CTRL,
  1111.                     LA_ID, GAD_SCSI0_DEVICE + i,
  1112.                     LA_Chars, 20,
  1113.                     LA_STRPTR, (ULONG)scsi_dev[i],
  1114.                     GTST_MaxChars, sizeof(scsi_dev[i]) - 1,
  1115.                     LAST_Picker, TRUE,
  1116.                     TAG_END
  1117.                 );
  1118.                 LT_New(h, LA_Type, INTEGER_KIND,
  1119.                     LA_LabelID, STR_UNIT_CTRL,
  1120.                     LA_ID, GAD_SCSI0_UNIT + i,
  1121.                     LA_Chars, 4,
  1122.                     LA_LONG, (ULONG)&scsi_unit[i],
  1123.                     LAIN_UseIncrementers, TRUE,
  1124.                     GTIN_MaxChars, 8,
  1125.                     TAG_END
  1126.                 );
  1127.             ENDGROUP;
  1128.         }
  1129.     ENDGROUP;
  1130. }
  1131.  
  1132.  
  1133. /*
  1134.  *  "Graphics/Sound" pane
  1135.  */
  1136.  
  1137. // Display types
  1138. enum {
  1139.     DISPLAY_WINDOW,
  1140.     DISPLAY_PIP,
  1141.     DISPLAY_SCREEN
  1142. };
  1143.  
  1144. static BYTE display_type;
  1145. static LONG dis_width, dis_height;
  1146. static ULONG mode_id;
  1147. static BYTE frameskip_num;
  1148. static struct NameInfo mode_name;
  1149. static ULONG ahi_id;
  1150. static char ahi_mode_name[256];
  1151. static BYTE nosound;
  1152.  
  1153. // Read graphics preferences
  1154. static void parse_graphics_prefs(void)
  1155. {
  1156.     display_type = DISPLAY_WINDOW;
  1157.     dis_width = 512;
  1158.     dis_height = 384;
  1159.     mode_id = 0;
  1160.     ahi_id = AHI_DEFAULT_ID;
  1161.     ahi_mode_name[0] = 0;
  1162.  
  1163.     frameskip_num = 0;
  1164.     int frameskip = PrefsFindInt32("frameskip");
  1165.     switch (frameskip) {
  1166.         case 12:
  1167.             frameskip_num = 0;
  1168.             break;
  1169.         case 8:
  1170.             frameskip_num = 1;
  1171.             break;
  1172.         case 6:
  1173.             frameskip_num = 2;
  1174.             break;
  1175.         case 4:
  1176.             frameskip_num = 3;
  1177.             break;
  1178.         case 2:
  1179.             frameskip_num = 4;
  1180.             break;
  1181.         case 1:
  1182.             frameskip_num = 5;
  1183.             break;
  1184.     }
  1185.  
  1186.     const char *str = PrefsFindString("screen");
  1187.     if (str) {
  1188.         if (sscanf(str, "win/%d/%d", &dis_width, &dis_height) == 2)
  1189.             display_type = DISPLAY_WINDOW;
  1190.         else if (sscanf(str, "pip/%d/%d", &dis_width, &dis_height) == 2)
  1191.             display_type = DISPLAY_PIP;
  1192.         else if (sscanf(str, "scr/%08lx", &mode_id) == 1)
  1193.             display_type = DISPLAY_SCREEN;
  1194.     }
  1195.  
  1196.     GetDisplayInfoData(NULL, (UBYTE *)&mode_name, sizeof(mode_name), DTAG_NAME, mode_id);
  1197.  
  1198.     str = PrefsFindString("sound");
  1199.     if (str) {
  1200.         if (sscanf(str, "ahi/%08lx", &ahi_id) == 1 && AHIBase) {
  1201.             AHI_GetAudioAttrs(ahi_id, NULL,
  1202.                 AHIDB_Name, (ULONG)ahi_mode_name,
  1203.                 AHIDB_BufferLen, sizeof(ahi_mode_name) - 1,
  1204.                 TAG_END
  1205.             );
  1206.         }
  1207.     }
  1208.     nosound = PrefsFindBool("nosound");
  1209. }
  1210.  
  1211. // Ghost/unghost graphics gadgets, depending on display type
  1212. static void ghost_graphics_gadgets(struct LayoutHandle *h)
  1213. {
  1214.     bool dis_xy, dis_skip, dis_mode;
  1215.     switch (display_type) {
  1216.         case DISPLAY_WINDOW:
  1217.             dis_xy = false;
  1218.             dis_skip = false;
  1219.             dis_mode = true;
  1220.             break;
  1221.         case DISPLAY_PIP:
  1222.             dis_xy = false;
  1223.             dis_skip = true;
  1224.             dis_mode = true;
  1225.             break;
  1226.         case DISPLAY_SCREEN:
  1227.             dis_xy = true;
  1228.             dis_skip = true;
  1229.             dis_mode = false;
  1230.             break;
  1231.     }
  1232.     LT_SetAttributes(h, GAD_DISPLAY_X, GA_Disabled, dis_xy, TAG_END);
  1233.     LT_SetAttributes(h, GAD_DISPLAY_Y, GA_Disabled, dis_xy, TAG_END);
  1234.     LT_SetAttributes(h, GAD_FRAMESKIP, GA_Disabled, dis_skip, TAG_END);
  1235.     LT_SetAttributes(h, GAD_SCREEN_MODE, GA_Disabled, dis_mode, TAG_END);
  1236.     LT_SetAttributes(h, GAD_AHI_MODE, GA_Disabled, AHIBase == NULL, TAG_END);
  1237. }
  1238.  
  1239. // Show screen mode requester
  1240. static void screen_mode_req(struct Window *win, struct LayoutHandle *h)
  1241. {
  1242.     if (P96Base == NULL)
  1243.         return;
  1244.  
  1245.     LT_LockWindow(win);
  1246.     ULONG id = p96RequestModeIDTags(
  1247.         P96MA_MinDepth, 8,
  1248.         P96MA_FormatsAllowed, RGBFF_CLUT | RGBFF_R5G5B5 | RGBFF_A8R8G8B8,
  1249.         TAG_END
  1250.     );
  1251.     LT_UnlockWindow(win);
  1252.  
  1253.     if (id != INVALID_ID) {
  1254.         mode_id = id;
  1255.         GetDisplayInfoData(NULL, (UBYTE *)&mode_name, sizeof(mode_name), DTAG_NAME, mode_id);
  1256.         LT_SetAttributes(h, GAD_SCREEN_MODE, GTTX_Text, (ULONG)mode_name.Name, TAG_END);
  1257.     }
  1258. }
  1259.  
  1260. // Show AHI mode requester
  1261. static void ahi_mode_req(struct Window *win, struct LayoutHandle *h)
  1262. {
  1263.     if (AHIBase == NULL)
  1264.         return;
  1265.  
  1266.     struct AHIAudioModeRequester *req = AHI_AllocAudioRequest(
  1267.         AHIR_Window, (ULONG)win,
  1268.         TAG_END
  1269.     );
  1270.     if (req == NULL)
  1271.         return;
  1272.  
  1273.     LT_LockWindow(win);
  1274.     BOOL ok = AHI_AudioRequest(req,
  1275.         AHIR_InitialAudioID, ahi_id,
  1276.         TAG_END
  1277.     );
  1278.     LT_UnlockWindow(win);
  1279.  
  1280.     if (ok) {
  1281.         ahi_id = req->ahiam_AudioID;
  1282.         AHI_GetAudioAttrs(ahi_id, NULL,
  1283.             AHIDB_Name, (ULONG)ahi_mode_name,
  1284.             AHIDB_BufferLen, sizeof(ahi_mode_name) - 1,
  1285.             TAG_END
  1286.         );
  1287.         LT_SetAttributes(h, GAD_AHI_MODE, GTTX_Text, (ULONG)ahi_mode_name, TAG_END);
  1288.     }
  1289.     AHI_FreeAudioRequest(req);
  1290. }
  1291.  
  1292. // Read settings from gadgets and set preferences
  1293. static void read_graphics_settings(void)
  1294. {
  1295.     char str[256];
  1296.     switch (display_type) {
  1297.         case DISPLAY_WINDOW:
  1298.             sprintf(str, "win/%ld/%ld", dis_width, dis_height);
  1299.             break;
  1300.         case DISPLAY_PIP:
  1301.             sprintf(str, "pip/%ld/%ld", dis_width, dis_height);
  1302.             break;
  1303.         case DISPLAY_SCREEN:
  1304.             sprintf(str, "scr/%08lx", mode_id);
  1305.             break;
  1306.         default:
  1307.             PrefsRemoveItem("screen");
  1308.             return;
  1309.     }
  1310.     PrefsReplaceString("screen", str);
  1311.  
  1312.     sprintf(str, "ahi/%08lx", ahi_id);
  1313.     PrefsReplaceString("sound", str);
  1314.  
  1315.     PrefsReplaceBool("nosound", nosound);
  1316. }
  1317.  
  1318. // Create "Graphics/Sound" pane
  1319. static void create_graphics_pane(struct LayoutHandle *h)
  1320. {
  1321.     parse_graphics_prefs();
  1322.  
  1323.     VGROUP;
  1324.         LT_New(h, LA_Type, VERTICAL_KIND,
  1325.             LA_LabelID, STR_GRAPHICS_CTRL,
  1326.             TAG_END
  1327.         );
  1328.             static const LONG labels[] = {STR_WINDOW_LAB, STR_PIP_LAB, STR_FULLSCREEN_LAB, -1};
  1329.             LT_New(h, LA_Type, CYCLE_KIND,
  1330.                 LA_LabelID, STR_VIDEO_TYPE_CTRL,
  1331.                 LA_ID, GAD_VIDEO_TYPE,
  1332.                 LACY_LabelTable, (ULONG)labels,
  1333.                 LA_BYTE, (ULONG)&display_type,
  1334.                 TAG_END
  1335.             );
  1336.             LT_New(h, LA_Type, INTEGER_KIND,
  1337.                 LA_LabelID, STR_DISPLAY_X_CTRL,
  1338.                 LA_ID, GAD_DISPLAY_X,
  1339.                 LA_LONG, (ULONG)&dis_width,
  1340.                 GTIN_MaxChars, 8,
  1341.                 TAG_END
  1342.             );
  1343.             LT_New(h, LA_Type, INTEGER_KIND,
  1344.                 LA_LabelID, STR_DISPLAY_Y_CTRL,
  1345.                 LA_ID, GAD_DISPLAY_Y,
  1346.                 LA_LONG, (ULONG)&dis_height,
  1347.                 GTIN_MaxChars, 8,
  1348.                 TAG_END
  1349.             );
  1350.             LT_New(h, LA_Type, POPUP_KIND,
  1351.                 LA_LabelID, STR_FRAMESKIP_CTRL,
  1352.                 LA_ID, GAD_FRAMESKIP,
  1353.                 LAPU_FirstLabel, STR_REF_5HZ_LAB,
  1354.                 LAPU_LastLabel, STR_REF_60HZ_LAB,
  1355.                 LA_BYTE, (ULONG)&frameskip_num,
  1356.                 TAG_END
  1357.             );
  1358.             LT_New(h, LA_Type, TEXT_KIND,
  1359.                 LA_LabelID, STR_SCREEN_MODE_CTRL,
  1360.                 LA_ID, GAD_SCREEN_MODE,
  1361.                 LA_Chars, DISPLAYNAMELEN,
  1362.                 LATX_Picker, TRUE,
  1363.                 GTTX_Text, (ULONG)mode_name.Name,
  1364.                 GTTX_Border, TRUE,
  1365.                 TAG_END
  1366.             );
  1367.         ENDGROUP;
  1368.         LT_New(h, LA_Type, VERTICAL_KIND,
  1369.             LA_LabelID, STR_SOUND_CTRL,
  1370.             TAG_END
  1371.         );
  1372.             LT_New(h, LA_Type, TEXT_KIND,
  1373.                 LA_LabelID, STR_AHI_MODE_CTRL,
  1374.                 LA_ID, GAD_AHI_MODE,
  1375.                 LA_Chars, DISPLAYNAMELEN,
  1376.                 LATX_Picker, TRUE,
  1377.                 GTTX_Text, (ULONG)ahi_mode_name,
  1378.                 GTTX_Border, TRUE,
  1379.                 TAG_END
  1380.             );
  1381.             LT_New(h, LA_Type, CHECKBOX_KIND,
  1382.                 LA_LabelID, STR_NOSOUND_CTRL,
  1383.                 LA_ID, GAD_NOSOUND,
  1384.                 LA_BYTE, (ULONG)&nosound,
  1385.                 TAG_END
  1386.             );
  1387.         ENDGROUP;
  1388.     ENDGROUP;
  1389.  
  1390.     ghost_graphics_gadgets(h);
  1391. }
  1392.  
  1393.  
  1394. /*
  1395.  *  "Serial/Network" pane
  1396.  */
  1397.  
  1398. static char seriala_dev[256], serialb_dev[256];
  1399. static LONG seriala_unit, serialb_unit;
  1400. static BYTE seriala_ispar, serialb_ispar;
  1401.  
  1402. static char ether_dev[256];
  1403. static ULONG ether_unit;
  1404.  
  1405. // Read serial/network preferences
  1406. static void parse_ser_prefs(const char *prefs, char *dev, LONG &unit, BYTE &ispar)
  1407. {
  1408.     dev[0] = 0;
  1409.     unit = 0;
  1410.     ispar = false;
  1411.  
  1412.     const char *str = PrefsFindString(prefs);
  1413.     if (str) {
  1414.         if (str[0] == '*') {
  1415.             ispar = true;
  1416.             str++;
  1417.         }
  1418.         sscanf(str, "%[^/]/%ld", dev, &unit);
  1419.     }
  1420. }
  1421.  
  1422. static void parse_serial_prefs(void)
  1423. {
  1424.     parse_ser_prefs("seriala", seriala_dev, seriala_unit, seriala_ispar);
  1425.     parse_ser_prefs("serialb", serialb_dev, serialb_unit, serialb_ispar);
  1426.  
  1427.     ether_dev[0] = 0;
  1428.     ether_unit = 0;
  1429.  
  1430.     const char *str = PrefsFindString("ether");
  1431.     if (str)
  1432.         sscanf(str, "%[^/]/%ld", ether_dev, ðer_unit);
  1433. }
  1434.  
  1435. // Set serial preference item
  1436. static void make_serial_prefs(const char *prefs, const char *dev, LONG unit, BYTE ispar)
  1437. {
  1438.     if (strlen(dev)) {
  1439.         char str[256];
  1440.         sprintf(str, "%s%s/%ld", ispar ? "*" : "", dev, unit);
  1441.         PrefsReplaceString(prefs, str);
  1442.     } else
  1443.         PrefsRemoveItem(prefs);
  1444. }
  1445.  
  1446. // Read settings from gadgets and set preferences
  1447. static void read_serial_settings(void)
  1448. {
  1449.     make_serial_prefs("seriala", seriala_dev, seriala_unit, seriala_ispar);
  1450.     make_serial_prefs("serialb", serialb_dev, serialb_unit, serialb_ispar);
  1451.  
  1452.     if (strlen(ether_dev)) {
  1453.         char str[256];
  1454.         sprintf(str, "%s/%ld", ether_dev, ether_unit);
  1455.         PrefsReplaceString("ether", str);
  1456.     } else
  1457.         PrefsRemoveItem("ether");
  1458. }
  1459.  
  1460. // Create "Serial/Network" pane
  1461. static void create_serial_pane(struct LayoutHandle *h)
  1462. {
  1463.     parse_serial_prefs();
  1464.  
  1465.     VGROUP;
  1466.         LT_New(h, LA_Type, VERTICAL_KIND,
  1467.             LA_LabelID, STR_SERIALA_CTRL,
  1468.             TAG_END
  1469.         );
  1470.             LT_New(h, LA_Type, STRING_KIND,
  1471.                 LA_LabelID, STR_DEVICE_CTRL,
  1472.                 LA_ID, GAD_SERIALA_DEVICE,
  1473.                 LA_Chars, 20,
  1474.                 LA_STRPTR, (ULONG)seriala_dev,
  1475.                 GTST_MaxChars, sizeof(seriala_dev) - 1,
  1476.                 LAST_Picker, TRUE,
  1477.                 TAG_END
  1478.             );
  1479.             LT_New(h, LA_Type, INTEGER_KIND,
  1480.                 LA_LabelID, STR_UNIT_CTRL,
  1481.                 LA_ID, GAD_SERIALA_UNIT,
  1482.                 LA_LONG, (ULONG)&seriala_unit,
  1483.                 LAIN_UseIncrementers, TRUE,
  1484.                 GTIN_MaxChars, 8,
  1485.                 TAG_END
  1486.             );
  1487.             LT_New(h, LA_Type, CHECKBOX_KIND,
  1488.                 LA_LabelID, STR_ISPAR_CTRL,
  1489.                 LA_ID, GAD_SERIALA_ISPAR,
  1490.                 LA_BYTE, (ULONG)&seriala_ispar,
  1491.                 TAG_END
  1492.             );
  1493.         ENDGROUP;
  1494.  
  1495.         LT_New(h, LA_Type, VERTICAL_KIND,
  1496.             LA_LabelID, STR_SERIALB_CTRL,
  1497.             TAG_END
  1498.         );
  1499.             LT_New(h, LA_Type, STRING_KIND,
  1500.                 LA_LabelID, STR_DEVICE_CTRL,
  1501.                 LA_ID, GAD_SERIALB_DEVICE,
  1502.                 LA_Chars, 20,
  1503.                 LA_STRPTR, (ULONG)serialb_dev,
  1504.                 GTST_MaxChars, sizeof(serialb_dev) - 1,
  1505.                 LAST_Picker, TRUE,
  1506.                 TAG_END
  1507.             );
  1508.             LT_New(h, LA_Type, INTEGER_KIND,
  1509.                 LA_LabelID, STR_UNIT_CTRL,
  1510.                 LA_ID, GAD_SERIALB_UNIT,
  1511.                 LA_LONG, (ULONG)&serialb_unit,
  1512.                 LAIN_UseIncrementers, TRUE,
  1513.                 GTIN_MaxChars, 8,
  1514.                 TAG_END
  1515.             );
  1516.             LT_New(h, LA_Type, CHECKBOX_KIND,
  1517.                 LA_LabelID, STR_ISPAR_CTRL,
  1518.                 LA_ID, GAD_SERIALB_ISPAR,
  1519.                 LA_BYTE, (ULONG)&serialb_ispar,
  1520.                 TAG_END
  1521.             );
  1522.         ENDGROUP;
  1523.  
  1524.         LT_New(h, LA_Type, VERTICAL_KIND,
  1525.             LA_LabelID, STR_ETHERNET_IF_CTRL,
  1526.             TAG_END
  1527.         );
  1528.             LT_New(h, LA_Type, STRING_KIND,
  1529.                 LA_LabelID, STR_DEVICE_CTRL,
  1530.                 LA_ID, GAD_ETHER_DEVICE,
  1531.                 LA_Chars, 20,
  1532.                 LA_STRPTR, (ULONG)ether_dev,
  1533.                 GTST_MaxChars, sizeof(ether_dev) - 1,
  1534.                 LAST_Picker, TRUE,
  1535.                 TAG_END
  1536.             );
  1537.             LT_New(h, LA_Type, INTEGER_KIND,
  1538.                 LA_LabelID, STR_UNIT_CTRL,
  1539.                 LA_ID, GAD_ETHER_UNIT,
  1540.                 LA_LONG, (ULONG)ðer_unit,
  1541.                 LAIN_UseIncrementers, TRUE,
  1542.                 GTIN_MaxChars, 8,
  1543.                 TAG_END
  1544.             );
  1545.         ENDGROUP;
  1546.     ENDGROUP;
  1547. }
  1548.  
  1549.  
  1550. /*
  1551.  *  "Memory/Misc" pane
  1552.  */
  1553.  
  1554. static ULONG ramsize_mb;
  1555. static BYTE model_num;
  1556. static char rom_file[256];
  1557.  
  1558. // Read memory/misc preferences
  1559. static void parse_memory_prefs(void)
  1560. {
  1561.     ramsize_mb = PrefsFindInt32("ramsize") >> 20;
  1562.  
  1563.     model_num = 0;
  1564.     int id = PrefsFindInt32("modelid");
  1565.     switch (id) {
  1566.         case 5:
  1567.             model_num = 0;
  1568.             break;
  1569.         case 14:
  1570.             model_num = 1;
  1571.             break;
  1572.     }
  1573.  
  1574.     rom_file[0] = 0;
  1575.     const char *str = PrefsFindString("rom");
  1576.     if (str) {
  1577.         strncpy(rom_file, str, sizeof(rom_file) - 1);
  1578.         rom_file[sizeof(rom_file) - 1] = 0;
  1579.     }
  1580. }
  1581.  
  1582. // Read settings from gadgets and set preferences
  1583. static void read_memory_settings(void)
  1584. {
  1585.     PrefsReplaceInt32("ramsize", ramsize_mb << 20);
  1586.  
  1587.     if (strlen(rom_file))
  1588.         PrefsReplaceString("rom", rom_file);
  1589.     else
  1590.         PrefsRemoveItem("rom");
  1591. }
  1592.  
  1593. // Create "Memory/Misc" pane
  1594. static void create_memory_pane(struct LayoutHandle *h)
  1595. {
  1596.     parse_memory_prefs();
  1597.  
  1598.     VGROUP;
  1599.         LT_New(h, LA_Type, LEVEL_KIND,
  1600.             LA_LabelID, STR_RAMSIZE_SLIDER,
  1601.             LA_ID, GAD_RAMSIZE,
  1602.             LA_Chars, 20,
  1603.             LA_LONG, (ULONG)&ramsize_mb,
  1604.             GTSL_LevelFormat, (ULONG)GetString(STR_RAMSIZE_FMT),
  1605.             GTSL_Min, 1,
  1606.             GTSL_Max, AvailMem(MEMF_LARGEST) >> 20,
  1607.             TAG_END
  1608.         );
  1609.         LT_New(h, LA_Type, CYCLE_KIND,
  1610.             LA_LabelID, STR_MODELID_CTRL,
  1611.             LA_ID, GAD_MODELID,
  1612.             LACY_FirstLabel, STR_MODELID_5_LAB,
  1613.             LACY_LastLabel, STR_MODELID_14_LAB,
  1614.             LA_BYTE, (ULONG)&model_num,
  1615.             TAG_END
  1616.         );
  1617.         LT_New(h, LA_Type, STRING_KIND,
  1618.             LA_LabelID, STR_ROM_FILE_CTRL,
  1619.             LA_ID, GAD_ROM_FILE,
  1620.             LA_Chars, 20,
  1621.             LA_STRPTR, (ULONG)rom_file,
  1622.             GTST_MaxChars, sizeof(rom_file) - 1,
  1623.             LAST_Picker, TRUE,
  1624.             TAG_END
  1625.         );
  1626.     ENDGROUP;
  1627. }
  1628.  
  1629.  
  1630. /*
  1631.  *  Read settings from gadgets and set preferences
  1632.  */
  1633.  
  1634. static void read_settings(struct LayoutHandle *h)
  1635. {
  1636.     LT_UpdateStrings(h);
  1637.     read_volumes_settings();
  1638.     read_scsi_settings();
  1639.     read_graphics_settings();
  1640.     read_serial_settings();
  1641.     read_memory_settings();
  1642. }
  1643.