home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 113 / EnigmaAmiga113CD.iso / software / sviluppo / easygui_os12 / source / tools / easygui_os12.e < prev   
Encoding:
Text File  |  2000-06-11  |  62.2 KB  |  2,127 lines

  1. /* EasyGui constructs fast nononsense font sensitive resizable gui's.
  2.  
  3.    This is based on the original EasyGUI code version 3.3b4, released to the
  4.    public by Copyright (c) 1994-6, Wouter van Oortmerssen and Jason R. Hulance..
  5.  
  6.    EasyGui_OS12.m is a customized version of EasyGUI, tweaked to work with
  7.    gadtools13.library under any Amiga-OS above and including V1.2 (V33)
  8.    (see "RST" and "EASY_OS12" occurences). This is V0.9 of the OS12 "port".
  9.  
  10.    Please do not redistribute modified versions of this code. If you have
  11.    any ideas how to make things better contact me at metamonk@yahoo.com.
  12.  
  13.    All changes are Copyright (c) 2000, Ralf 'hippie2000' Steines,
  14.    and inherit the legal state from the original EasyGUI disctribution.
  15.    (Reuse there is welcome :) */
  16.  
  17. OPT MODULE, PREPROCESS -> RST: OSVERSION below
  18.  
  19. -> Let only one of the following be defined:
  20.  
  21. ->#define EASYGUI_LITE
  22. #define EASYGUI_FULL
  23. ->#define EASYGUI_DEBUG
  24.  
  25. -> This "switch" applies to all versions of EasyGUI
  26.  
  27. #define EASY_OS12
  28.  
  29. -> This selects various components based on above choice.
  30. #ifndef EASY_OS12
  31. OPT OSVERSION=37 ->RST: now optional
  32. #endif
  33. #ifndef EASYGUI_LITE
  34. #define EASY_KEYBOARD
  35. #ifdef EASYGUI_DEBUG
  36. #ifndef EASYGUI_FULL
  37. #define EASYGUI_FULL
  38. #endif
  39. #endif
  40. #ifdef EASYGUI_FULL
  41. #define EASY_APPWINDOW
  42. #define EASY_EXTRAS
  43. #endif
  44. #endif
  45.  
  46. -> This enables a descriptive message before an exception is raised.
  47. #ifdef EASYGUI_DEBUG
  48. #define RaiseX(x,l,s) myraise(x,l,s)
  49. MODULE 'tools/exceptions'
  50. #endif
  51. #ifndef EASYGUI_DEBUG
  52. #define RaiseX(x,l,s) Raise(x)
  53. #endif
  54.  
  55. -> EASY_OS12 support defines
  56. #ifdef EASY_OS12
  57.   CONST SIZERY=10 -> size gadget y size for getrealbot()
  58.   MODULE 'hybrid/ports','hybrid/tagdata','hybrid/version','hybrid/openwin'
  59.   #define OpenWindowTagList openWindowTagList
  60.   #define GetTagData getTagData
  61.   #define CreateMsgPort createMsgPort
  62.   #define DeleteMsgPort deleteMsgPort
  63.   #define SCREENPOINTER IF (intuiVersion(36)=FALSE) AND (gh.is_wb=TRUE) THEN NIL ELSE gh.scr
  64. #endif
  65. #ifndef EASY_OS12
  66.   #define SCREENPOINTER gh.scr
  67. #endif
  68.  
  69. MODULE 'gadtools',
  70.        'exec/libraries', 'exec/lists', 'exec/nodes', 'exec/ports',
  71.        'graphics/rastport', 'graphics/text',
  72.        'graphics/gfx', 'graphics/videocontrol', 'graphics/view',
  73.        'intuition/gadgetclass', 'intuition/imageclass', 'intuition/intuition',
  74.        'intuition/screens',
  75.        'libraries/gadtools',
  76.        'tools/textlen', 'amigalib/lists',
  77.        'utility/tagitem',
  78.        'utility'
  79.  
  80. #ifdef EASY_APPWINDOW
  81. MODULE 'wb', 'workbench/workbench'
  82. #endif
  83.  
  84. #ifdef EASY_KEYBOARD
  85. MODULE 'tools/ctype'
  86. #endif
  87.  
  88. DEF utilitybase  -> Redefine for privateness
  89.  
  90.  
  91. #ifdef EASY_EXTRAS
  92. /************ multihandle ************/
  93. EXPORT OBJECT multihandle
  94.   sig
  95.   opencount
  96. PRIVATE
  97. #ifdef EASY_APPWINDOW
  98.   awport:PTR TO mp
  99. #endif
  100.   wndport:PTR TO mp
  101.   guis:lh
  102. ENDOBJECT
  103. #endif
  104.  
  105. -> The offset of the `link' node in a guihandle.  Used for getting
  106. -> back to the guihandle from the node in the list.
  107. CONST GH_LINK_OFFSET=16
  108.  
  109. /************ guihandle ************/
  110. EXPORT OBJECT guihandle
  111.   -> Window, Signal Mask (not Bit), Info
  112.   wnd:PTR TO window,sig,info
  113. #ifdef EASY_EXTRAS
  114.   -> Multi-Window Handle
  115.   mh:PTR TO multihandle
  116. #endif
  117. PRIVATE
  118. #ifdef EASY_EXTRAS
  119.   -> Node for Linking GUIs in Multi-Window GUIs
  120.   link:ln
  121. #endif
  122.   -> Private Window Pointer (so that wnd is a flag for GUI validity, too)
  123.   pwnd:PTR TO window
  124.   -> Last Gadget, VisualInfo, Font, Font_uses_screen, GT_lib_is_open
  125.   gl:PTR TO gadget,visual,tattr:PTR TO textattr,ta_scr,gt_isopen
  126.   -> Gadget desc, Gadget list, Screen, Screen_is_WB
  127.   base:PTR TO g,glist,scr:PTR TO screen,is_wb
  128.   -> Min Width and Height, X and Y Offset Past Window Borders
  129.   xsize,ysize,xoff,yoff
  130.   -> Menus, Plugins
  131.   menus, plugins:PTR TO plugin
  132. #ifndef EASY_KEYBOARD
  133.   -> First String Gadget
  134.   firststr
  135. #endif
  136. #ifdef EASY_KEYBOARD
  137.   -> Map of Key to Gadget
  138.   keys[26]:ARRAY OF LONG
  139. #endif
  140. #ifdef EASY_APPWINDOW
  141.   -> AppWindow Port, AppWindow, WB_lib_is_open
  142.   awport:PTR TO mp,appwin,wb_isopen
  143. #endif
  144. #ifdef EASY_EXTRAS
  145.   -> Requester used for Blocking
  146.   req:PTR TO requester
  147. #endif
  148.   -> GUI X and Y, GUI Desc, Window Title, Menu Desc
  149.   x,y,gui,wtitle,awproc,newmenus
  150.   -> Window Port, OnClose Proc, Window Type, OnClean Proc
  151.   wndport:PTR TO mp,onclose,wtype,onclean
  152.   -> Hack to make menu selections safe
  153.   menuitem:PTR TO LONG
  154. #ifdef EASY_EXTRAS
  155.   -> Count of blockwin() calls
  156.   blockcnt
  157. #endif
  158. ENDOBJECT
  159.  
  160. -> Flag set for resizing constants.
  161. SET CRSZ_X, CRSZ_Y, UNCOND_X, UNCOND_Y
  162.  
  163. EXPORT CONST COND_RESIZEX=CRSZ_X, COND_RESIZEY=CRSZ_Y
  164. EXPORT CONST RESIZEX=COND_RESIZEX OR UNCOND_X, RESIZEY=COND_RESIZEY OR UNCOND_Y
  165.  
  166. CONST RESIZEXANDY=RESIZEX OR RESIZEY
  167.  
  168. -> Resize testing macros.
  169. #define DoesXResize(flag) ((flag) AND COND_RESIZEX)
  170. #define DoesYResize(flag) ((flag) AND COND_RESIZEY)
  171. #define DoesXUncond(flag) ((flag) AND RESIZEX=RESIZEX)
  172. #define DoesYUncond(flag) ((flag) AND RESIZEY=RESIZEY)
  173.  
  174. -> Gadget type constants.
  175. ->          0    1      2    3      4     5
  176. EXPORT ENUM ROWS,EQROWS,COLS,EQCOLS,BEVEL,BEVELR,
  177. ->       6      7     8       9     10 11    12      13     14    15  16   17
  178.          BUTTON,CHECK,INTEGER,LISTV,MX,CYCLE,PALETTE,SCROLL,SLIDE,STR,TEXT,NUM,
  179. ->       18      19     20  21     22    23     24      25
  180.          SBUTTON,PLUGIN,BAR,SPACEH,SPACE,SPACEV,RBUTTON,MAXGUI
  181.  
  182. -> ROWS...      BUTTON...   PALETTE...      SBUTTON...     RBUTTON...
  183. -> Mapping of gadget type to GT KIND.
  184. #define KINDTAB \
  185.   [0,0,0,0,0,0, 1,2,3,4,5,7,8,9,11,12,13,6, 1, 0, 0,0,0,0, 1,12]:CHAR
  186. -> Mapping of gadget type to number of required arguments.
  187. #define MINARGS \
  188.   [2,2,2,2,2,2, 3,5,5,9,6,4,7,7, 9, 6, 5,5, 3, 3, 1,1,1,1, 3,6]:CHAR
  189.  
  190. -> Constants to index gadget desc lists.
  191. EXPORT ENUM BEV_GUI=1,
  192.   BUT_ACT=1, BUT_TXT,  BUT_DATA, BUT_KEY,  BUT_APPW, BUT_DIS,
  193.   CHK_ACT=1, CHK_TXT,  CHK_VAL,  CHK_LEFT, CHK_DATA, CHK_KEY,  CHK_DIS,
  194.   INT_ACT=1, INT_TXT,  INT_VAL,  INT_REL,  INT_DATA, INT_KEY,  INT_DIS,
  195.   LST_ACT=1, LST_TXT,  LST_RELX, LST_RELY, LST_LIST, LST_RO,   LST_SHOW,
  196.              LST_CURR, LST_DATA, LST_KEY,  LST_APPW, LST_DIS,
  197.    MX_ACT=1,  MX_TXT,   MX_LIST,  MX_LEFT,  MX_CURR,  MX_DATA,  MX_KEY,
  198.               MX_DIS,
  199.   CYC_ACT=1, CYC_TXT,  CYC_LIST, CYC_CURR, CYC_DATA, CYC_KEY,  CYC_DIS,
  200.   PAL_ACT=1, PAL_TXT,  PAL_DEP,  PAL_RELX, PAL_RELY, PAL_CURR, PAL_DATA,
  201.              PAL_KEY,  PAL_DIS,
  202.   SCR_ACT=1, SCR_VERT, SCR_TOTL, SCR_TOP,  SCR_VIS,  SCR_REL,  SCR_DATA,
  203.              SCR_KEY,  SCR_DIS,
  204.   SLI_ACT=1, SLI_TXT,  SLI_VERT, SLI_MIN,  SLI_MAX,  SLI_CURR, SLI_REL,
  205.              SLI_FMT,  SLI_DATA, SLI_KEY,  SLI_DIS,
  206.   STR_ACT=1, STR_TXT,  STR_STR,  STR_MAX,  STR_REL,  STR_OVR,  STR_DATA,
  207.              STR_KEY,  STR_APPW, STR_DIS,
  208.   TXT_VAL=1, TXT_TXT,  TXT_BORD, TXT_REL,
  209.   NUM_VAL=1, NUM_TXT,  NUM_BORD, NUM_REL,
  210.   PLG_ACT=1, PLG_OBJ,  PLG_GT,   PLG_APPW
  211.  
  212. ENUM EG_TYPE=0, EG_ACT, EG_TXT
  213.  
  214. -> Test group type macros.
  215. #define IsRow(type)        ((type)<=EQROWS)
  216. #define IsCol(type)        ((type)>EQROWS)
  217. #define IsRowOrCol(type)   ((type)<BEVEL)
  218. #define IsBevel(type)      ((type)<BUTTON)
  219. #define IsGroup(type)      IsBevel(type)
  220. #define IsEqualGroup(type) (((type)=EQROWS) OR ((type)=EQCOLS))
  221.  
  222. -> Test space sizing macros.
  223. #define HasHSpace(type)    ((type)<=SPACE)
  224. #define HasVSpace(type)    ((type)>=SPACE)
  225. #define HSpace(type)       (IF HasHSpace(type) THEN RESIZEX ELSE 0)
  226. #define VSpace(type)       (IF HasVSpace(type) THEN RESIZEY ELSE 0)
  227. #define SpaceFlags(type)   (HSpace(type) OR VSpace(type))
  228.  
  229. -> Test button sizing macros.
  230. #define HasHButtSp(type)   ((type)>=SBUTTON)
  231. #define HasVButtSp(type)   ((type)=RBUTTON)
  232. #define HButtSp(type)      (IF HasHButtSp(type) THEN RESIZEX ELSE 0)
  233. #define VButtSp(type)      (IF HasVButtSp(type) THEN RESIZEY ELSE 0)
  234. #define ButtSpFlags(type)  (HButtSp(type) OR VButtSp(type))
  235.  
  236. CONST SP=2,YSP=3            -> very basic spacing (Y=nonsense!?!)
  237. CONST XSPACING=YSP,YSPACING=SP,   -> basic spacing between gadgets
  238.       SIDESPACE=YSP,TOPSPACE=SP,  -> spacing to window border
  239.       BUTXSPACE=16,BUTYSPACE=6,   -> space around text in button (min)
  240.       BEVELXSPACE=4,BEVELYSPACE=3,  -> between bevelbox and inner gadgets
  241.       MXSPACE=2,CHECKSPACE=2        -> between two mx and check gads
  242.  
  243. EXPORT ENUM WTYPE_NOBORDER, WTYPE_BASIC, WTYPE_NOSIZE, WTYPE_SIZE
  244.  
  245. -> Window flags.
  246. CONST WIN_FBASIC=WFLG_ACTIVATE OR WFLG_NEWLOOKMENUS
  247. CONST WIN_FNOBORD=WFLG_BORDERLESS OR WIN_FBASIC
  248. CONST WIN_FNOSIZE=WIN_FBASIC OR WFLG_DRAGBAR OR WFLG_DEPTHGADGET OR
  249.                   WFLG_CLOSEGADGET
  250. CONST WIN_FSIZE=WIN_FNOSIZE OR WFLG_SIZEBBOTTOM OR WFLG_SIZEGADGET
  251.  
  252. -> Gadget click IDCMP.
  253. CONST GAD_IDCMP=IDCMP_GADGETDOWN OR IDCMP_GADGETUP OR IDCMP_MOUSEMOVE
  254.  
  255. -> Window IDMCP (without NEWSIZE).
  256. CONST WIN_IDCMP_NS=GAD_IDCMP OR IDCMP_REFRESHWINDOW OR IDCMP_MOUSEBUTTONS OR
  257.                    IDCMP_MENUPICK OR IDCMP_CLOSEWINDOW OR IDCMP_RAWKEY OR
  258.                    IDCMP_ACTIVEWINDOW OR IDCMP_INACTIVEWINDOW OR
  259.                    IDCMP_INTUITICKS OR IDCMP_CHANGEWINDOW OR IDCMP_VANILLAKEY
  260.  
  261. -> Window IDMCP (with NEWSIZE).
  262. CONST WIN_IDCMP=IDCMP_NEWSIZE OR WIN_IDCMP_NS
  263.  
  264. -> Message loop constants.
  265. CONST GUI_CONT=-1, GUI_QUIT=0
  266.  
  267. -> Action function test macro.
  268. #define IsActionFun(ret) (((ret)<0) OR ((ret)>1000))
  269.  
  270. -> Convert to unsigned INT.
  271. #define Unsigned(x) ((x) AND $FFFF)
  272.  
  273. -> System gadget aspect ratio macro.
  274. #define SysISize(flags) \
  275.         (IF (flags) AND SCREENHIRES THEN SYSISIZE_MEDRES ELSE SYSISIZE_LOWRES)
  276.  
  277. -> Gadget information extraction macros.
  278. #define GadLongInt(gad) (gad.specialinfo::stringinfo.longint)
  279. #define GadString(gad)  (gad.specialinfo::stringinfo.buffer)
  280. #define IsChecked(gad)  ((gad.flags AND GFLG_SELECTED)<>0)
  281.  
  282. -> Constant to mark gadget has no mid-point.
  283. CONST NO_MID=-1
  284.  
  285. -> Gadget data (intermediate level).
  286. OBJECT g
  287.   -> Link, X, Y, Width, Height
  288.   next,x,y,xs,ys
  289.   -> Gadget Type, Gadget Desc, Flags, Mid-Point
  290.   type,list:PTR TO LONG,flags,mid
  291. ENDOBJECT
  292.  
  293. /************ plugin ************/
  294. EXPORT OBJECT plugin PRIVATE
  295.   -> Gadget Data, Link
  296.   base:PTR TO g, next:PTR TO plugin
  297. PUBLIC
  298.   -> X, Y, Width, Height
  299.   x:INT,y:INT,xs:INT,ys:INT
  300.   -> guihandle
  301.   gh:PTR TO guihandle
  302. ENDOBJECT
  303.  
  304. PROC min_size(ta,fontheight) OF plugin IS fontheight,fontheight
  305. PROC will_resize() OF plugin IS RESIZEXANDY
  306. PROC message_test(imsg:PTR TO intuimessage,win:PTR TO window) OF plugin IS FALSE
  307. PROC message_action(class,qual,code,win:PTR TO window) OF plugin IS FALSE
  308. PROC clear_render(win:PTR TO window) OF plugin IS EMPTY
  309.  
  310. PROC render(ta:PTR TO textattr,x,y,xs,ys,win:PTR TO window) OF plugin
  311.   fillbox(win.rport,1,x,y,x+xs-1,y+ys-1)
  312. ENDPROC
  313.  
  314. PROC appmessage(amsg,win:PTR TO window) OF plugin IS FALSE
  315. PROC gtrender(gl,vis,ta,x,y,xs,ys,win) OF plugin IS gl
  316. /************ plugin end ************/
  317.  
  318. -> Magic idenitifier for AppWindow gadgets.
  319. CONST EG_MAGIC=$EA51EA51
  320.  
  321. -> Tag list constants
  322. CONST EG_TAGBASE=TAG_USER+$4000
  323.  
  324. EXPORT ENUM EG_TITLE=EG_TAGBASE, EG_GUI,  EG_INFO, EG_SCRN, EG_FONT, EG_MENU,
  325.             EG_GHVAR, EG_AWPROC, EG_LEFT, EG_TOP,  EG_MAXW, EG_MAXH, EG_WTYPE,
  326.             EG_CLOSE, EG_CLEAN,  EG_HIDE
  327.  
  328. -> Gadget list attribute selection.
  329. #define ATTR(gui,n)        gui[(n)]
  330. #define HasATTR(list,n)    (ListLen((list))>n)
  331. #define OptATTR(list,n)    optattr(list,n)
  332. #define OptDefATTR(list,n) optdefattr(list,n)
  333.  
  334. PROC optattr(list:PTR TO LONG,n) IS IF HasATTR(list,n) THEN ATTR(list,n) ELSE 0
  335.  
  336. PROC optdefattr(list:PTR TO LONG,n)
  337.   DEF res=-1
  338.   IF HasATTR(list,n) THEN res:=ATTR(list,n)
  339. ENDPROC IF res<>-1 THEN res ELSE list
  340.  
  341. PROC indexdata(type)
  342.   DEF index, but=FALSE, val=0
  343.   SELECT MAXGUI OF type
  344.   CASE BUTTON,SBUTTON,RBUTTON;  index:=BUT_DATA; but:=TRUE
  345.   CASE CHECK;    index:=CHK_DATA; val:=CHK_VAL
  346.   CASE LISTV;    index:=LST_DATA
  347.   CASE MX;       index:= MX_DATA
  348.   CASE STR;      index:=STR_DATA; val:=STR_STR
  349.   CASE INTEGER;  index:=INT_DATA; val:=INT_VAL
  350.   CASE CYCLE;    index:=CYC_DATA
  351.   CASE PALETTE;  index:=PAL_DATA
  352.   CASE SCROLL;   index:=SCR_DATA
  353.   CASE SLIDE;    index:=SLI_DATA
  354.   ENDSELECT
  355. ENDPROC index, but, val
  356.  
  357. #ifndef EASY_KEYBOARD
  358. #ifndef EASY_EXTRAS
  359. #define EASY_NOKEYBEXTRA
  360. #endif
  361. #endif
  362.  
  363. #ifndef EASY_NOKEYBEXTRA
  364. -> Optional value based on index.
  365. PROC optindex(i:PTR TO LONG,index) IS IF index THEN OptATTR(i,index) ELSE 0
  366. #endif
  367.  
  368. #ifdef EASY_KEYBOARD
  369. #define optkey(t,i) optindex(i,indexkey(t))
  370. PROC indexkey(type)
  371.   DEF index
  372.   SELECT MAXGUI OF type
  373.   CASE BUTTON,SBUTTON,RBUTTON;  index:=BUT_KEY
  374.   CASE CHECK;    index:=CHK_KEY
  375.   CASE LISTV;    index:=LST_KEY
  376.   CASE MX;       index:= MX_KEY
  377.   CASE STR;      index:=STR_KEY
  378.   CASE INTEGER;  index:=INT_KEY
  379.   CASE CYCLE;    index:=CYC_KEY
  380.   CASE PALETTE;  index:=PAL_KEY
  381.   CASE SCROLL;   index:=SCR_KEY
  382.   CASE SLIDE;    index:=SLI_KEY
  383.   ENDSELECT
  384. ENDPROC index
  385. #endif
  386.  
  387. #ifndef EASY_EXTRAS
  388. #define optdis(t,i) 0
  389. #endif
  390. #ifdef EASY_EXTRAS
  391. #define optdis(t,i) optindex(i,indexdis(t))
  392. PROC indexdis(type)
  393.   DEF index=0
  394.   SELECT MAXGUI OF type
  395.   CASE BUTTON,SBUTTON,RBUTTON;  index:=BUT_DIS
  396.   CASE CHECK;    index:=CHK_DIS
  397.   CASE LISTV;    index:=LST_DIS
  398.   CASE MX;       index:= MX_DIS
  399.   CASE STR;      index:=STR_DIS
  400.   CASE INTEGER;  index:=INT_DIS
  401.   CASE CYCLE;    index:=CYC_DIS
  402.   CASE PALETTE;  index:=PAL_DIS
  403.   CASE SCROLL;   index:=SCR_DIS
  404.   CASE SLIDE;    index:=SLI_DIS
  405.   ENDSELECT
  406. ENDPROC index
  407.  
  408. /********** setdisabled **********/
  409. EXPORT PROC setdisabled(gh,gad:PTR TO LONG,disabled=TRUE)
  410.   DEF index
  411.   index:=indexdis(ATTR(gad,EG_TYPE))
  412.   IF HasATTR(gad,index) THEN setattr(gh,gad,disabled,GA_DISABLED,index)
  413. ENDPROC
  414. #endif
  415.  
  416. -> Clear window contents and redraw frame.
  417. PROC clearwindow(w:PTR TO window)
  418.   fillbox(w.rport,0,w.borderleft,w.bordertop,
  419.           w.width-w.borderright-1, w.height-w.borderbottom-1)
  420.   RefreshWindowFrame(w)
  421. ENDPROC
  422.  
  423. PROC fillbox(rport,pen,x,y,x2,y2)
  424.   SetAPen(rport,pen)
  425.   RectFill(rport,x,y,x2,y2)
  426. ENDPROC
  427.  
  428. -> Create new gadget data.
  429. PROC newg(xs,ys,type,list,flags=0,mid=NO_MID) IS NEW [0,0,0,xs,ys,type,list,flags,mid]:g
  430.  
  431. -> Access functions for gadget type mapping lists.
  432. PROC minARGS() IS MINARGS
  433. PROC kindTAB() IS KINDTAB
  434.  
  435. #ifdef EASYGUI_DEBUG
  436. -> In debug version this will be called instead of raising an exception.
  437. PROC myraise(x,l,s)
  438.   exception:=x;  exceptioninfo:=0
  439.   WriteF('Just about to raise exception:\n')
  440.   report_exception()
  441.   IF (l>0) AND (l<2000)
  442.     WriteF(' Error ref \d: \s\n',l,s)
  443.   ELSE
  444.     WriteF(' \s (Gadget list $\h)\n',s,l)
  445.   ENDIF
  446.   Raise(x)
  447. ENDPROC
  448. #endif
  449.  
  450. /********** easyguiA() **********/
  451. EXPORT PROC easyguiA(title,gui,tags=NIL) HANDLE
  452.   DEF gh=NIL:PTR TO guihandle,res=-1
  453.   gh:=guiinitA(title,gui,tags)
  454.   WHILE res<0
  455.     Wait(gh.sig)
  456.     res:=guimessage(gh)
  457.   ENDWHILE
  458. EXCEPT DO
  459.   cleangui(gh)
  460.   ReThrow()
  461. ENDPROC res
  462.  
  463. /********** easygui_fallbackA() **********/
  464. EXPORT PROC easygui_fallbackA(title,gui,tags=NIL) HANDLE
  465.   RETURN easyguiA(title,gui,tags)
  466. EXCEPT
  467.   IF exception="bigg"
  468.     RETURN easyguiA(title,gui,[EG_FONT,['topaz.font',8,0,0]:textattr,
  469.                                TAG_MORE,tags])
  470.   ENDIF
  471.   ReThrow()
  472. ENDPROC
  473.  
  474. -> Init font.
  475. PROC initfont(gh:PTR TO guihandle,tattr)
  476.   gh.tattr:=tattr
  477.   gh.ta_scr:=(tattr=NIL)
  478. ENDPROC
  479.  
  480. -> Init screen.
  481. PROC initscr(gh:PTR TO guihandle,scr)
  482.   gh.scr:=scr
  483.   gh.is_wb:=(scr=NIL)
  484. ENDPROC
  485.  
  486. -> Set up menus.
  487. PROC setmenus(gh:PTR TO guihandle)
  488.   -> setup menus
  489.   IF gh.newmenus
  490.     gh.menus:=CreateMenusA(gh.newmenus,NIL)
  491.     IF gh.menus=NIL THEN RaiseX("GUI",431,'Could not create menus. Bad menu description? Or out of memory?')
  492.     IF LayoutMenusA(gh.menus,gh.visual,[GTMN_NEWLOOKMENUS,TRUE,NIL])=FALSE THEN RaiseX("GUI",432,'Could not layout menus. Out of memory?')
  493.     IF SetMenuStrip(gh.pwnd,gh.menus)=FALSE THEN RaiseX("GUI",433,'Could not set menu strip. Should never happen!')
  494.   ENDIF
  495. ENDPROC
  496.  
  497. PROC win_off(n,s:PTR TO screen)
  498.   DEF y
  499.   IF n=WTYPE_NOBORDER THEN RETURN 1,1
  500.   y:=s.wbortop+TOPSPACE
  501.   IF n>WTYPE_BASIC THEN y:=y+s.rastport.txheight+1
  502. ENDPROC s.wborleft+SIDESPACE,y
  503.  
  504. PROC win_pad(n,s:PTR TO screen)
  505.   DEF y=TOPSPACE
  506.   IF n=WTYPE_NOBORDER THEN RETURN 1,1
  507.   y:=y+IF n=WTYPE_SIZE THEN getrealbot(s) ELSE s.wborbottom
  508. ENDPROC s.wborright+SIDESPACE,y
  509.  
  510. -> Set up GUI.
  511. PROC setgui(gh:PTR TO guihandle)
  512.   DEF base:PTR TO g,s:PTR TO screen,w:PTR TO window,xsize,ysize,
  513.       cm,h=NIL:PTR TO LONG,vpe=NIL:PTR TO viewportextra,x,y
  514.   s:=gh.scr
  515.   w:=gh.pwnd
  516.  
  517.   -> Get gadget data and calculate minimum GUI size.
  518.   gh.base:=base:=minsize(gh.gui,gh)
  519.   IF w=NIL
  520.     -> Calculate offset of borders in window.
  521.     x,y:=win_off(gh.wtype,s)
  522.     gh.xoff:=x
  523.     gh.yoff:=y
  524.   ENDIF
  525.   -> Calculate minimum width and height of window.
  526.   x,y:=win_pad(gh.wtype,s)
  527.   xsize:=x+gh.xoff+base.xs
  528.   ysize:=y+gh.yoff+base.ys
  529.  
  530.   IF (xsize>s.width) OR (ysize>s.height) THEN RaiseX("bigg",455,'Size is too big for the screen.')
  531.  
  532. #ifdef EASY_EXTRAS
  533.   -> If window open then adjust sizing.
  534.   IF w
  535.     -> Calculate X size and pos delta if needed.
  536.     cm:=IF (w.width>=xsize) AND DoesXResize(base.flags) THEN w.width ELSE xsize
  537.     x:=IF cm+w.leftedge>s.width THEN s.width-cm ELSE w.leftedge
  538.     -> Calculate Y size and pos delta if needed.
  539.     h:=IF (w.height>=ysize) AND DoesYResize(base.flags) THEN w.height ELSE ysize
  540.     y:=IF h+w.topedge>s.height THEN s.height-h ELSE w.topedge
  541.     -> Disallow window sizing.
  542.     ModifyIDCMP(w, WIN_IDCMP_NS)
  543.     -> Temporarily allow window to grow as large and small as possible.
  544.     WindowLimits(w,8,8,-1,-1)
  545. #ifdef EASY_OS12
  546.     IF intuiVersion(36)
  547. #endif
  548.       -> Move and size window.
  549.       ChangeWindowBox(w,x,y,cm,h) -> RST:V36
  550. #ifdef EASY_OS12
  551.     ELSE
  552.       IF (x<>w.leftedge) OR (y<>w.topedge) THEN MoveWindow(w,x-w.leftedge,y-w.topedge)
  553.       IF (cm<>w.width) OR (h<>w.height) THEN SizeWindow(w,cm-w.width,h-w.height)
  554.     ENDIF
  555. #endif
  556.     -> Set window to proper limits.
  557.     setwinlimits(w,xsize,ysize,
  558.                    IF DoesXResize(base.flags) THEN -1 ELSE xsize,
  559.                    IF DoesYResize(base.flags) THEN -1 ELSE ysize)
  560.     -> Remove mess.
  561.     clearwindow(w)
  562.     -> Allow resizing (maybe) again.
  563.     ModifyIDCMP(w, WIN_IDCMP)
  564.   ELSE
  565. #endif
  566.   -> Window not open so create it.
  567.     -> get visual infos
  568.     gh.visual:=GetVisualInfoA(gh.scr,NIL)
  569.     IF gh.visual=NIL THEN RaiseX("GUI",482,'Could not get visual info. Out of memory?')
  570.  
  571.     x:=s.width-xsize/2
  572.     y:=s.height-ysize/2
  573. #ifdef EASY_OS12
  574.     IF intuiVersion(36)
  575. #endif
  576.       -> calc window position (centre of visible part of screen)
  577.       h:=VTAG_VIEWPORTEXTRA_GET  -> Ack! VideoControl changes tag!
  578.       IF IF cm:=s.viewport.colormap THEN VideoControl(cm, h:=[h,NIL,NIL]) BUT vpe:=h[1] ELSE vpe:=NIL
  579.         x:=Min(vpe.displayclip.maxx-vpe.displayclip.minx+1,s.width)-xsize/2-s.viewport.dxoffset
  580.         y:=Min(vpe.displayclip.maxy-vpe.displayclip.miny+1,s.height)-ysize/2-s.viewport.dyoffset
  581.       ENDIF
  582. #ifdef EASY_OS12
  583.     ENDIF
  584. #endif
  585.     w:=s.width
  586.     h:=s.height
  587.     -> If position stored use that, else centred.  And adjust max size.
  588.     IF gh.x<>-1
  589.       x:=gh.x
  590.       -> Offset the maximum
  591.       w:=Bounds(w-x,xsize,w)
  592.     ENDIF
  593.     IF gh.y<>-1
  594.       y:=gh.y
  595.       h:=Bounds(h-y,ysize,h)
  596.     ENDIF
  597.     -> Use minimum or stored size (default is maximum).
  598.     IF gh.xsize=0
  599.       w:=xsize
  600.     ELSEIF DoesXResize(base.flags)=FALSE
  601.       w:=xsize
  602.     ELSEIF gh.xsize<>-1
  603.       w:=Bounds(gh.xsize,xsize,s.width)
  604.     ENDIF
  605.     IF gh.ysize=0
  606.       h:=ysize
  607.     ELSEIF DoesYResize(base.flags)=FALSE
  608.       h:=ysize
  609.     ELSEIF gh.ysize<>-1
  610.       h:=Bounds(gh.ysize,ysize,s.height)
  611.     ENDIF
  612.  
  613.     -> open the window
  614.     gh.pwnd:=w:=OpenWindowTagList(NIL,  -> RST:V36
  615.                [WA_LEFT,       Bounds(x,0,s.width-w),
  616.                 WA_TOP,        Bounds(y,0,s.height-h),
  617.                 WA_WIDTH,      w,
  618.                 WA_HEIGHT,     h,
  619.                 WA_IDCMP,      0, -> Was WIN_IDCMP: now ports are shared.
  620.                 WA_FLAGS,      ListItem([WIN_FNOBORD,WIN_FBASIC,
  621.                                          WIN_FNOSIZE,WIN_FSIZE], gh.wtype),
  622.                 WA_TITLE,      IF gh.wtype>WTYPE_BASIC THEN gh.wtitle ELSE NIL,
  623.                 WA_CUSTOMSCREEN, SCREENPOINTER, -> RST: new, see defines at the beginning
  624.                 WA_MINWIDTH,   xsize,
  625.                 WA_MINHEIGHT,  ysize,
  626.                 WA_MAXWIDTH,   IF DoesXResize(base.flags) THEN -1 ELSE xsize,
  627.                 WA_MAXHEIGHT,  IF DoesYResize(base.flags) THEN -1 ELSE ysize,
  628.                 ->WA_AUTOADJUST,1,
  629.                 NIL])
  630.     IF w=NIL THEN RaiseX("GUI",537,'Could not open window. Too many layers?')
  631.     w.userdata:=gh
  632.     -> Set up window IDCMP port.
  633.     w.userport:=gh.wndport
  634.     ModifyIDCMP(w,WIN_IDCMP)
  635.  
  636. #ifdef EASY_APPWINDOW
  637.     IF gh.awproc THEN gh.appwin:=AddAppWindowA(gh,gh.awproc,gh.pwnd,gh.awport,NIL) -> RST:V36
  638. #endif
  639.     stdrast:=w.rport
  640. #ifdef EASY_EXTRAS
  641.   ENDIF
  642. #endif
  643.   -> Remember minimum window size.
  644.   gh.xsize:=xsize
  645.   gh.ysize:=ysize
  646.   -> Now render the gadgets.
  647.   gh.glist:=rendergui(gh)
  648. ENDPROC
  649.  
  650. /********** guiinitA() **********/
  651. #ifdef EASY_EXTRAS
  652. EXPORT PROC guiinitA(title,gui,tags=NIL) IS addmultiA(NIL,title,gui,tags)
  653. #endif
  654. #ifndef EASY_EXTRAS
  655. EXPORT PROC guiinitA(title,gui,tags=NIL) HANDLE
  656.   DEF gh=NIL:PTR TO guihandle
  657.   gh:=makehandle(title,gui,NIL,tags)
  658. EXCEPT
  659.   -> Stop the user cleanup in this case.
  660.   gh.onclean:=NIL
  661.   cleangui(gh)
  662.   ReThrow()
  663. ENDPROC gh
  664. #endif
  665.  
  666. #ifdef EASY_OS12
  667. PROC openlibrary(s,v) -> RST: added v=version num
  668.   DEF lib
  669.   IF (lib:=OpenLibrary(s,v))=NIL THEN RaiseX("LIB",613,s)
  670. ENDPROC lib
  671. #endif
  672. #ifndef EASY_OS12
  673. PROC openlibrary(s)
  674.   DEF lib
  675.   IF (lib:=OpenLibrary(s,37))=NIL THEN RaiseX("LIB",613,s)
  676. ENDPROC lib
  677. #endif
  678.  
  679. -> Make a handle and initialise from the tags.
  680. PROC makehandle(title,gui,mh,tags) HANDLE
  681.   DEF gh=NIL:PTR TO guihandle, temp:PTR TO LONG,isopen=FALSE
  682.   NEW gh
  683. #ifdef EASY_OS12
  684.   utilitybase:=OpenLibrary('utility.library',36)  -> RST: new, safe to fail!
  685.   isopen:=(utilitybase<>NIL)
  686. #endif
  687. #ifndef EASY_OS12
  688.   utilitybase:=openlibrary('utility.library')
  689.   isopen:=TRUE
  690. #endif
  691.   IF temp:=GetTagData(EG_GHVAR,NIL,tags) THEN temp[]:=gh
  692.   gh.wtype:=GetTagData(EG_WTYPE,WTYPE_SIZE,tags)
  693.   gh.wtitle:=title
  694.   gh.gui:=gui
  695.   gh.info:=IF -1<>(temp:=GetTagData(EG_INFO,-1,tags)) THEN temp ELSE gh
  696.   initscr(gh,GetTagData(EG_SCRN,NIL,tags))
  697.   initfont(gh,GetTagData(EG_FONT,NIL,tags))
  698.   gh.newmenus:=GetTagData(EG_MENU,NIL,tags)
  699.   gh.awproc:=GetTagData(EG_AWPROC,NIL,tags)
  700.   gh.x:=GetTagData(EG_LEFT,-1,tags)
  701.   gh.y:=GetTagData(EG_TOP,-1,tags)
  702.   gh.onclose:=GetTagData(EG_CLOSE,NIL,tags)
  703.   gh.onclean:=GetTagData(EG_CLEAN,NIL,tags)
  704.   IF GetTagData(EG_MAXW,FALSE,tags) THEN gh.xsize:=-1
  705.   IF GetTagData(EG_MAXH,FALSE,tags) THEN gh.ysize:=-1
  706. #ifdef EASY_EXTRAS
  707.   gh.mh:=mh
  708. #endif
  709.   setinit(gh)
  710. EXCEPT DO
  711.   IF exception
  712.     END gh
  713.     ReThrow()
  714.   ELSE
  715.     IF GetTagData(EG_HIDE,FALSE,tags)=FALSE THEN openwin(gh)
  716.   ENDIF
  717.   IF isopen THEN CloseLibrary(utilitybase)
  718. ENDPROC gh
  719.  
  720. -> Initialisation stuff.
  721. PROC setinit(gh:PTR TO guihandle) HANDLE
  722.   -> Open library safely.
  723. #ifdef EASY_OS12
  724.   IF (gadtoolsbase:=OpenLibrary('gadtools.library',36))=NIL -> RST: new, safe to fail.
  725.     gadtoolsbase:=openlibrary('gadtools13.library',34)      -> RST: exception on failure
  726.   ENDIF
  727. #endif
  728. #ifndef EASY_OS12
  729.     gadtoolsbase:=openlibrary('gadtools.library')
  730. #endif
  731.   gh.gt_isopen:=TRUE
  732. #ifdef EASY_EXTRAS
  733.   -> Window IDCMP port.
  734.   IF gh.mh
  735.     -> If multi-window then share port.
  736.     gh.wndport:=gh.mh.wndport
  737.     -> Also, share the *complete* signal mask.
  738.     -> (This ensures that guimessage() works...)
  739.     gh.sig:=gh.mh.sig
  740.   ELSE
  741. #endif
  742.     gh.wndport:=makeport()
  743.     gh.sig:=Shl(1,gh.wndport.sigbit)
  744. #ifdef EASY_EXTRAS
  745.   ENDIF
  746. #endif
  747. #ifdef EASY_APPWINDOW
  748.   -> Open library safely.
  749. #ifdef EASY_OS12
  750.   workbenchbase:=OpenLibrary('workbench.library',36) -> RST: new, safe to fail.
  751.   gh.wb_isopen:=(workbenchbase<>NIL)
  752.   IF workbenchbase=NIL THEN gh.awproc:=NIL
  753. #endif
  754. #ifndef EASY_OS12
  755.   workbenchbase:=openlibrary('workbench.library')
  756.   gh.wb_isopen:=TRUE
  757. #endif
  758. #ifdef EASY_EXTRAS
  759.   -> AppWindow port
  760.   IF gh.mh
  761.     -> If multi-window then share port (even if no awproc)
  762.     -> (This ensures that guimessage() works...)
  763.     gh.awport:=gh.mh.awport
  764.   ELSEIF gh.awproc
  765. #endif
  766. #ifndef EASY_EXTRAS
  767.   IF gh.awproc
  768. #endif
  769.     gh.awport:=makeport()
  770.     gh.sig:=gh.sig OR Shl(1,gh.awport.sigbit)
  771.   ELSE
  772.     gh.awport:=NIL
  773.   ENDIF
  774. #endif
  775. EXCEPT
  776.   cleaninit(gh)
  777.   ReThrow()
  778. ENDPROC
  779.  
  780. /********** openwin() **********/
  781. EXPORT PROC openwin(gh:PTR TO guihandle)
  782.   IF gh.pwnd=NIL
  783.     -> Set up screen.
  784.     IF gh.is_wb
  785. #ifdef EASY_OS12
  786.       IF intuiVersion(36)
  787. #endif
  788.         IF gh.scr=NIL THEN gh.scr:=LockPubScreen(NIL)   -> RST:V36
  789.         IF gh.scr=NIL THEN RaiseX("GUI",417,'Could not lock default public screen (Workbench?). Is it open?')
  790. #ifdef EASY_OS12
  791.       ELSE
  792.         NEW gh.scr
  793.         GetScreenData(gh.scr,SIZEOF screen,WBENCHSCREEN,NIL)
  794.       ENDIF
  795. #endif
  796.     ENDIF
  797.     -> Set up font.
  798.     IF gh.ta_scr THEN gh.tattr:=gh.scr.font
  799.     -> Set up window and GUI.
  800.     setgui(gh)
  801.     -> Set up menus.
  802.     setmenus(gh)
  803. #ifdef EASY_EXTRAS
  804.     -> If multi then bump count of open windows.
  805.     IF gh.mh THEN gh.mh.opencount:=gh.mh.opencount+1
  806. #endif
  807.   ENDIF
  808. ENDPROC gh
  809.  
  810. #ifdef EASY_EXTRAS
  811. /********** changescreen() **********/
  812. EXPORT PROC changescreen(gh:PTR TO guihandle,scr=NIL)
  813.   IF gh.wnd=NIL THEN initscr(gh,scr)
  814. ENDPROC
  815.  
  816. /********** changefont() **********/
  817. EXPORT PROC changefont(gh:PTR TO guihandle,tattr=NIL)
  818.   IF gh.wnd=NIL THEN initfont(gh,tattr)
  819. ENDPROC
  820.  
  821. /********** changewintype() **********/
  822. EXPORT PROC changewintype(gh:PTR TO guihandle,wintype=WTYPE_SIZE)
  823.   IF gh.wnd=NIL THEN gh.wtype:=wintype
  824. ENDPROC
  825.  
  826. /********** changeinfo() **********/
  827. EXPORT PROC changeinfo(gh:PTR TO guihandle,info=-1)
  828.   gh.info:=IF info<>-1 THEN info ELSE gh
  829. ENDPROC
  830.  
  831. /********** changetitle() **********/
  832. EXPORT PROC changetitle(gh:PTR TO guihandle,windowtitle=NIL)
  833.   IF gh.wnd
  834.     IF (windowtitle=NIL) OR (gh.wtype>WTYPE_BASIC)
  835.       SetWindowTitles(gh.wnd, windowtitle, -1)
  836.     ENDIF
  837.   ENDIF
  838.   gh.wtitle:=windowtitle
  839. ENDPROC
  840.  
  841. /********** changemenus() **********/
  842. EXPORT PROC changemenus(gh:PTR TO guihandle,newmenus=NIL) HANDLE
  843.   IF gh.wnd THEN removemenus(gh)
  844.   gh.newmenus:=newmenus
  845.   IF gh.wnd THEN setmenus(gh)
  846. EXCEPT
  847.   removemenus(gh)
  848.   ReThrow()
  849. ENDPROC
  850.  
  851. /********** changegui() **********/
  852. EXPORT PROC changegui(gh:PTR TO guihandle,gui)
  853.   IF gui
  854.     IF gh.pwnd THEN removegui(gh)
  855.     gh.gui:=gui
  856.     IF gh.pwnd THEN setgui(gh)
  857.   ENDIF
  858. ENDPROC
  859.  
  860. /********** movewin() **********/
  861. EXPORT PROC movewin(gh:PTR TO guihandle,x=-1,y=-1)
  862.   DEF w:PTR TO window
  863.   IF w:=gh.wnd
  864. #ifdef EASY_OS12
  865.     -> this clipping avoids crashes on intuition 1.x when moving out of the screen
  866.     x:=Bounds(x,-1,w.wscreen.width-w.width)
  867.     y:=Bounds(y,-1,w.wscreen.height-w.height)
  868. #endif
  869.     MoveWindow(w, IF x=-1 THEN 0 ELSE (x-w.leftedge),
  870.                   IF y=-1 THEN 0 ELSE (y-w.topedge))
  871.   ENDIF
  872. ENDPROC
  873.  
  874. /********** sizewin() **********/
  875. EXPORT PROC sizewin(gh:PTR TO guihandle,xs=-1,ys=-1)
  876.   DEF w:PTR TO window
  877.   IF w:=gh.wnd
  878. #ifdef EASY_OS12
  879.     -> this clipping avoids crashes on intuition 1.x when sizing out of the screen and cares of the winlimits since intui 1.x does not
  880.     IF xs<>-1 THEN xs:=Bounds(xs,w.minwidth,Min(IF w.maxwidth>0 THEN w.maxwidth ELSE xs,w.wscreen.width-w.leftedge))
  881.     IF ys<>-1 THEN ys:=Bounds(ys,w.minheight,Min(IF w.maxheight>0 THEN w.maxheight ELSE ys,w.wscreen.height-w.topedge))
  882. #endif
  883.     SizeWindow(w, IF xs=-1 THEN 0 ELSE (xs-w.width),
  884.                   IF ys=-1 THEN 0 ELSE (ys-w.height))
  885.   ENDIF
  886. ENDPROC
  887.  
  888. -> Try setting window limits a few times.
  889. PROC setwinlimits(w,minx,miny,maxx,maxy)
  890.   DEF i
  891.   FOR i:=0 TO 3
  892.   EXIT WindowLimits(w,minx,miny,maxx,maxy)
  893.     Delay(1)
  894.   ENDFOR
  895. ENDPROC
  896.  
  897. /********** blockwin() **********/
  898. EXPORT PROC blockwin(gh:PTR TO guihandle)
  899.   DEF lib:PTR TO lib,c,w:PTR TO window
  900.   gh.blockcnt:=(c:=gh.blockcnt)+1
  901.   IF c=0
  902.     -> Only works if window open and not already blocked.
  903.     IF (w:=gh.wnd) AND (gh.req=NIL)
  904.       -> Only allow window refresh messages.
  905.       ModifyIDCMP(w, IDCMP_REFRESHWINDOW)
  906.       -> Stop window sizing.
  907.       setwinlimits(w,w.width,w.height,w.width,w.height)
  908.       NEW gh.req
  909.       -> Block window with requester.
  910.       InitRequester(gh.req)
  911.       Request(gh.req, w)
  912.       lib:=intuitionbase
  913.       IF lib.version>=39 THEN SetWindowPointerA(w,[WA_BUSYPOINTER,TRUE,
  914.                                                    WA_POINTERDELAY,TRUE,NIL])
  915.     ENDIF
  916.   ENDIF
  917. ENDPROC
  918.  
  919. /********** unblockwin() **********/
  920. EXPORT PROC unblockwin(gh:PTR TO guihandle)
  921.   DEF lib:PTR TO lib,c,w:PTR TO window
  922.   IF (c:=gh.blockcnt)>0
  923.     gh.blockcnt:=c-1
  924.     IF c=1
  925.       -> Only works if window open and blocked.
  926.       IF (w:=gh.wnd) AND (gh.req<>NIL)
  927.         -> Remove requester.
  928.         EndRequest(gh.req, w)
  929.         -> Reset window limits.
  930.         setwinlimits(w,gh.xsize,gh.ysize,
  931.                        IF DoesXResize(gh.base.flags) THEN -1 ELSE gh.xsize,
  932.                        IF DoesYResize(gh.base.flags) THEN -1 ELSE gh.ysize)
  933.         -> Reset IDCMP.
  934.         ModifyIDCMP(w, WIN_IDCMP)
  935.         END gh.req
  936.         lib:=intuitionbase
  937.         IF lib.version>=39 THEN SetWindowPointerA(w,[WA_BUSYPOINTER,FALSE,NIL])
  938.       ENDIF
  939.     ENDIF
  940.   ENDIF
  941. ENDPROC
  942. #endif
  943.  
  944. #ifdef EASY_APPWINDOW
  945. -> Handle AppWindow messages.
  946. PROC appwmessage(port) HANDLE
  947.   DEF ret,data,list:PTR TO LONG,amsg=NIL:PTR TO appmessage,gh:PTR TO guihandle,
  948.       pl:PTR TO plugin
  949.   IF port
  950.     WHILE amsg:=GetMsg(port)
  951.       -> Get guihandle from message ID.
  952.       gh:=amsg.id
  953.       -> See if any PLUGIN wants it.
  954.       pl:=gh.plugins
  955.       WHILE pl
  956.         IF OptATTR(pl.base.list,PLG_APPW)=NIL THEN JUMP plugin_appw_skip
  957.       EXIT pl.appmessage(amsg,gh.pwnd)
  958. plugin_appw_skip:
  959.         pl:=pl.next
  960.       ENDWHILE
  961.       ret:=NIL
  962.       data:=NIL
  963.       -> Get awproc (in ret) and data.
  964.       IF pl
  965.         ret:=OptATTR(pl.base.list,PLG_APPW)
  966.         data:=pl
  967.       ELSE
  968.         IF list:=findxy(gh,amsg.mousex,amsg.mousey)
  969.           SELECT MAXGUI OF ATTR(list,EG_TYPE)
  970.           CASE BUTTON, SBUTTON, RBUTTON
  971.             ret:=OptATTR(list,BUT_APPW)
  972.             data:=OptDefATTR(list,BUT_DATA)
  973.           CASE LISTV
  974.             ret:=OptATTR(list,LST_APPW)
  975.             data:=OptDefATTR(list,LST_DATA)
  976.           CASE STR
  977.             ret:=OptATTR(list,STR_APPW)
  978.             data:=OptDefATTR(list,STR_DATA)
  979.           ENDSELECT
  980.         ENDIF
  981.       ENDIF
  982.       -> If no gadget awproc then use window one.
  983.       IF ret=NIL
  984.         ret:=amsg.userdata
  985.         data:=NIL
  986.       ENDIF
  987.       -> Call the awproc.
  988.       IF ret THEN ret(data,gh.info,amsg)
  989.       -> Now we can reply to the message.
  990.       ReplyMsg(amsg)
  991.       amsg:=NIL
  992.     ENDWHILE
  993.   ENDIF
  994. EXCEPT
  995.   -> Still need to reply if exception happened at a bad point
  996.   IF amsg THEN ReplyMsg(amsg)
  997.   ReThrow()
  998. ENDPROC
  999. #endif
  1000.  
  1001. -> Handle menu messages.
  1002. PROC menumessage(gh:PTR TO guihandle,code) HANDLE
  1003.   DEF ret=GUI_CONT,menunum,item:PTR TO menuitem
  1004.   menunum:=Unsigned(code)
  1005.   -> Stop if the window's gone away.
  1006.   WHILE (menunum<>MENUNULL) AND gh.pwnd
  1007.     item:=ItemAddress(gh.menus,menunum)
  1008.     -> Get action value/function.
  1009.     ret:=GTMENUITEM_USERDATA(item)
  1010.   -> Stop if action value.
  1011.   EXIT IsActionFun(ret)=FALSE
  1012.     gh.menuitem:={item}
  1013.     -> Call action function.
  1014.     ret(NIL,NIL,gh.info)
  1015.     ret:=GUI_CONT
  1016.   EXIT item=NIL
  1017.     menunum:=Unsigned(item.nextselect)
  1018.   ENDWHILE
  1019. EXCEPT DO
  1020.   gh.menuitem:=NIL
  1021.   ReThrow()
  1022. ENDPROC ret
  1023.  
  1024. -> Handle GadTools/window messages.
  1025. PROC gtmessage(port) HANDLE
  1026.   DEF ret=GUI_CONT,mes=NIL:PTR TO intuimessage,type,gh:PTR TO guihandle,
  1027.       gs:PTR TO gadget,list:PTR TO LONG,code,pl:PTR TO plugin,qual
  1028.   WHILE mes:=Gt_GetIMsg(port)
  1029.     -> Get guihandle from window userdata.
  1030.     gh:=mes.idcmpwindow.userdata
  1031.     -> See if any PLUGIN wants it.
  1032.     pl:=gh.plugins
  1033.     WHILE pl
  1034.     EXIT pl.message_test(mes,gh.pwnd)
  1035.       pl:=pl.next
  1036.     ENDWHILE
  1037.     -> Copy important bits of the message.
  1038.     type:=mes.class
  1039.     code:=mes.code
  1040.     gs:=mes.iaddress
  1041.     qual:=Unsigned(mes.qualifier)
  1042.     -> Now we can reply to the message.
  1043.     Gt_ReplyIMsg(mes)
  1044.     mes:=NIL
  1045.     IF pl
  1046.       -> Call the PLUGIN's action function if necessary.
  1047.       IF pl.message_action(type,qual,code,gh.pwnd)
  1048.         ret:=ATTR(pl.base.list,PLG_ACT)
  1049.         IF IsActionFun(ret)
  1050.           ret(gh.info,pl)
  1051.           ret:=GUI_CONT
  1052.         ENDIF
  1053.       ENDIF
  1054.     ELSE
  1055.       -> Gadget click.
  1056.       IF type AND GAD_IDCMP
  1057. ->WriteF('type=$\h, code=$\h, gad=$\h\n', type, code, gs)
  1058.         -> Protect from stray IDCMP_MOUSEMOVE.
  1059.         IF gs AND (gs<>gh.pwnd)
  1060.           -> Get gadget description list.
  1061.           list:=gs.userdata
  1062.           -> Set new attribute.
  1063.           performset(gs,code,list)
  1064.           -> Get action value/function.
  1065.           ret:=ATTR(list,EG_ACT)
  1066.           IF IsActionFun(ret)
  1067.             performaction(ret,gs,gh.info,code,list,qual)
  1068.             ret:=GUI_CONT
  1069.           ENDIF
  1070.         ENDIF
  1071. #ifdef EASY_KEYBOARD
  1072.       -> Key press.
  1073.       ELSEIF type=IDCMP_VANILLAKEY
  1074.         ret:=performkey(gh,code)
  1075. #endif
  1076.       -> Window refresh.
  1077.       ELSEIF type=IDCMP_REFRESHWINDOW
  1078.         Gt_BeginRefresh(gh.pwnd)
  1079.         Gt_EndRefresh(gh.pwnd,TRUE)
  1080.       -> Window size change.
  1081.       ELSEIF type=IDCMP_NEWSIZE
  1082.         -> Remove the gadgets, clear and recreate.
  1083.         removegads(gh)
  1084.         clearwindow(gh.pwnd)
  1085.         gh.glist:=rendergui(gh)
  1086.       -> Close gadget click.
  1087.       ELSEIF type=IDCMP_CLOSEWINDOW
  1088.         -> Find action value/function.
  1089.         ret:=gh.onclose
  1090.         IF IsActionFun(ret)
  1091. #ifdef EASY_EXTRAS
  1092.           ret(gh.mh,gh.info)
  1093. #endif
  1094. #ifndef EASY_EXTRAS
  1095.           ret(NIL,gh.info)
  1096. #endif
  1097.           ret:=GUI_CONT
  1098.         ENDIF
  1099.       -> Menu choice(s).
  1100.       ELSEIF type=IDCMP_MENUPICK
  1101.         ret:=menumessage(gh,code)
  1102.       ENDIF
  1103.     ENDIF
  1104.   EXIT ret<>GUI_CONT
  1105.   ENDWHILE
  1106. #ifdef EASY_EXTRAS
  1107.   IF ret<>GUI_CONT THEN IF gh.mh THEN cleangui(gh)
  1108. #endif
  1109. EXCEPT
  1110.   -> Still need to reply if exception happened in PLUGIN message_test().
  1111.   IF mes THEN Gt_ReplyIMsg(mes)
  1112.   ReThrow()
  1113. ENDPROC ret
  1114.  
  1115. #ifdef EASY_EXTRAS
  1116. /********** multiinit() **********/
  1117. EXPORT PROC multiinit() HANDLE
  1118.   DEF mh=NIL:PTR TO multihandle
  1119.   NEW mh
  1120.   newList(mh.guis)
  1121.   mh.wndport:=makeport()
  1122.   mh.sig:=Shl(1,mh.wndport.sigbit)
  1123. #ifdef EASY_APPWINDOW
  1124.   mh.awport:=makeport()
  1125.   mh.sig:=mh.sig OR Shl(1,mh.awport.sigbit)
  1126. #endif
  1127. EXCEPT
  1128.   cleanmulti(mh)
  1129.   ReThrow()
  1130. ENDPROC mh
  1131.  
  1132. /********** addmultiA() **********/
  1133. EXPORT PROC addmultiA(mh:PTR TO multihandle,title,gui,tags=NIL) HANDLE
  1134.   DEF gh=NIL:PTR TO guihandle
  1135.   gh:=makehandle(title,gui,mh,tags)
  1136.   IF mh THEN AddHead(mh.guis,gh.link)
  1137. EXCEPT
  1138.   -> Stop the user cleanup in this case.
  1139.   gh.onclean:=NIL
  1140.   cleangui(gh)
  1141.   ReThrow()
  1142. ENDPROC gh
  1143.  
  1144. /********** multiforall() **********/
  1145. EXPORT PROC multiforall(varaddr:PTR TO LONG,mh:PTR TO multihandle,expr) IS
  1146.   multieval(varaddr,mh,expr,FALSE)
  1147.  
  1148. /********** multiexists() **********/
  1149. EXPORT PROC multiexists(varaddr:PTR TO LONG,mh:PTR TO multihandle,expr) IS
  1150.   multieval(varaddr,mh,expr,TRUE)
  1151.  
  1152. -> Evaluate and maybe stop...
  1153. PROC multieval(varaddr:PTR TO LONG,mh:PTR TO multihandle,expr,exists)
  1154.   DEF node:PTR TO ln, next, this, res
  1155.   -> If empty then TRUE for forall, but FALSE for exists
  1156.   res:=(exists=FALSE)
  1157.   IF mh
  1158.     node:=mh.guis.head
  1159.     WHILE next:=node.succ
  1160.       varaddr[]:=node-GH_LINK_OFFSET
  1161.       IF this:=Eval(expr)
  1162.         -> If exists then we've found a match.
  1163.         IF exists THEN RETURN this
  1164.       ELSE
  1165.         -> Forall is FALSE.  Exists is still FALSE.
  1166.         res:=FALSE
  1167.       ENDIF
  1168.       node:=next
  1169.     ENDWHILE
  1170.   ENDIF
  1171.   -> Invalidate for case where exists fails.
  1172.   varaddr[]:=NIL
  1173. ENDPROC res
  1174.  
  1175. /********** multiempty() **********/
  1176. EXPORT PROC multiempty(mh:PTR TO multihandle) IS mh.guis.tailpred=mh.guis
  1177.  
  1178. /********** multiloop() **********/
  1179. EXPORT PROC multiloop(mh:PTR TO multihandle)
  1180.   DEF res=-1
  1181.   WHILE res<0
  1182.   EXIT mh.opencount=0
  1183.     Wait(mh.sig)
  1184.     res:=multimessage(mh)
  1185.   ENDWHILE
  1186. ENDPROC res
  1187.  
  1188. /********** cleanmulti() **********/
  1189. EXPORT PROC cleanmulti(mh:PTR TO multihandle)
  1190.   IF mh
  1191.     -> Clean up any remaining guihandles.
  1192.     WHILE multiempty(mh)=FALSE DO cleangui(mh.guis.head-GH_LINK_OFFSET)
  1193. #ifdef EASY_APPWINDOW
  1194.     IF mh.awport
  1195.       DeleteMsgPort(mh.awport) -> RST:V36
  1196.       mh.awport:=NIL
  1197.     ENDIF
  1198. #endif
  1199.     IF mh.wndport
  1200.       DeleteMsgPort(mh.wndport)  -> RST:V36
  1201.       mh.wndport:=NIL
  1202.     ENDIF
  1203.     END mh
  1204.   ENDIF
  1205. ENDPROC
  1206.  
  1207. /********** checkmulti() **********/
  1208. EXPORT PROC checkmulti(mh:PTR TO multihandle)
  1209.   DEF ret
  1210.   -> Check if there a message waiting on our ports.
  1211.   IF SetSignal(0,0) AND mh.sig
  1212.     IF (ret:=multimessage(mh))>=0 THEN quitgui(ret)
  1213.   ENDIF
  1214. ENDPROC
  1215. #endif
  1216.  
  1217. -> Note: as long as gh is valid, guimessage() can be used in place of
  1218. -> multimessage() for multi-window GUIs.  But remember that gh could
  1219. -> be invalidated by an action function when guimessage() is called.
  1220.  
  1221. /********** guimessage() **********/
  1222. /********** multimessage() **********/
  1223. #ifdef EASY_APPWINDOW
  1224. EXPORT PROC guimessage(gh:PTR TO guihandle)     IS message(gh.wndport,gh.awport)
  1225. #ifdef EASY_EXTRAS
  1226. EXPORT PROC multimessage(mh:PTR TO multihandle) IS message(mh.wndport,mh.awport)
  1227. #endif
  1228. #endif
  1229. #ifndef EASY_APPWINDOW
  1230. EXPORT PROC guimessage(gh:PTR TO guihandle)     IS message(gh.wndport,NIL)
  1231. #ifdef EASY_EXTRAS
  1232. EXPORT PROC multimessage(mh:PTR TO multihandle) IS message(mh.wndport,NIL)
  1233. #endif
  1234. #endif
  1235.  
  1236. -> Handle messages from the ports.
  1237. PROC message(wndport,awport) HANDLE
  1238.   DEF ret=-1
  1239. #ifdef EASY_APPWINDOW
  1240.   appwmessage(awport)
  1241. #endif
  1242.   ret:=gtmessage(wndport)
  1243. EXCEPT
  1244.   -> If we got "QUIT" then return value is in exceptioninfo.
  1245.   IF exception="QUIT"
  1246.     ret:=exceptioninfo
  1247.   ELSE
  1248.     ReThrow()
  1249.   ENDIF
  1250. ENDPROC ret
  1251.  
  1252. /********** quitgui() **********/
  1253. EXPORT PROC quitgui(ret=0) IS Throw("QUIT",ret)
  1254.  
  1255. -> Note: as above, checkgui() is safe for multi-window GUIs as long as
  1256. -> gh is valid.
  1257.  
  1258. /********** checkgui() **********/
  1259. EXPORT PROC checkgui(gh:PTR TO guihandle)
  1260.   DEF ret
  1261.   -> Check if there a message waiting on our ports.
  1262.   IF SetSignal(0,0) AND gh.sig
  1263.     IF (ret:=guimessage(gh))>=0 THEN quitgui(ret)
  1264.   ENDIF
  1265. ENDPROC
  1266.  
  1267. -> Remove menus and reset handle.
  1268. PROC removemenus(gh:PTR TO guihandle)
  1269.   IF gh.menus
  1270.     -> Hack to prevent the item.nextselect if closed from menu action function.
  1271.     IF gh.menuitem THEN gh.menuitem[]:=NIL
  1272.     IF gh.pwnd THEN ClearMenuStrip(gh.pwnd)
  1273.     FreeMenus(gh.menus)
  1274.     gh.menus:=NIL
  1275.   ENDIF
  1276. ENDPROC
  1277.  
  1278. -> Remove GUI and reset handle.
  1279. PROC removegui(gh:PTR TO guihandle)
  1280.   clean(gh.base)
  1281.   gh.base:=NIL
  1282.   removegads(gh)
  1283.   gh.glist:=NIL
  1284.   gh.plugins:=NIL
  1285. ENDPROC
  1286.  
  1287. -> Check if is this an IDCMP message for the window.
  1288. PROC testintuimsg(msg:PTR TO intuimessage,data) IS msg.idcmpwindow=data
  1289.  
  1290. #ifdef EASY_APPWINDOW
  1291. -> Check if is this an appmessage for the AppWindow.
  1292. PROC testappwmsg(msg:PTR TO appmessage,data) IS msg.id=data
  1293. #endif
  1294.  
  1295. -> Selectively remove messages from the port.
  1296. PROC clearmsgs(mp:PTR TO mp,f,data)
  1297.   DEF msg:PTR TO mn, succ
  1298.   -> Must be in Forbid()/Permit() brackets...
  1299.   Forbid()
  1300.   msg:=mp.msglist.head
  1301.   WHILE succ:=msg.ln.succ
  1302.     IF f(msg,data)
  1303.       Remove(msg)
  1304.       ReplyMsg(msg)
  1305.     ENDIF
  1306.     msg:=succ
  1307.   ENDWHILE
  1308.   Permit()
  1309. ENDPROC
  1310.  
  1311. -> Create a new message port.
  1312. PROC makeport()
  1313.   DEF port:PTR TO mp
  1314.   IF (port:=CreateMsgPort())=NIL THEN RaiseX("GUI",1065,'Could not create message port. Run out of signal bits?') -> RST:V36
  1315. ENDPROC port
  1316.  
  1317. -> Clean initialisation stuff and reset handle.
  1318. PROC cleaninit(gh:PTR TO guihandle)
  1319.   -> Clean ports.
  1320. #ifdef EASY_APPWINDOW
  1321. #ifdef EASY_EXTRAS
  1322.   IF (gh.mh=NIL) AND gh.awport THEN DeleteMsgPort(gh.awport) -> RST:V36
  1323. #endif
  1324. #ifndef EASY_EXTRAS
  1325.   IF gh.awport THEN DeleteMsgPort(gh.awport) -> RST:V36
  1326. #endif
  1327.   gh.awport:=NIL
  1328.   IF gh.wb_isopen
  1329.     CloseLibrary(workbenchbase)
  1330.     gh.wb_isopen:=FALSE
  1331.   ENDIF
  1332. #endif
  1333. #ifdef EASY_EXTRAS
  1334.   IF (gh.mh=NIL) AND gh.wndport THEN DeleteMsgPort(gh.wndport) -> RST:V36
  1335. #endif
  1336. #ifndef EASY_EXTRAS
  1337.   IF gh.wndport THEN DeleteMsgPort(gh.wndport) -> RST:V36
  1338. #endif
  1339.   gh.wndport:=NIL
  1340.   IF gh.gt_isopen
  1341.     CloseLibrary(gadtoolsbase)
  1342.     gh.gt_isopen:=FALSE
  1343.   ENDIF
  1344. ENDPROC
  1345.  
  1346. /********** cleangui() **********/
  1347. EXPORT PROC cleangui(gh:PTR TO guihandle)
  1348.   DEF f
  1349.   IF gh
  1350.     -> Close window if necessary.
  1351.     closewin(gh)
  1352.     IF f:=gh.onclean THEN f(gh.info)
  1353.     cleaninit(gh)
  1354. #ifdef EASY_EXTRAS
  1355.     IF gh.mh
  1356.       -> Unlink from multi-window list.
  1357.       Remove(gh.link)
  1358.       gh.mh:=NIL
  1359.     ENDIF
  1360. #endif
  1361.     END gh
  1362.   ENDIF
  1363. ENDPROC
  1364.  
  1365. /********** closewin() **********/
  1366. EXPORT PROC closewin(gh:PTR TO guihandle)
  1367.   DEF w:PTR TO window
  1368.   IF w:=gh.wnd
  1369.     -> Remember window size and position.
  1370.     gh.x:=w.leftedge
  1371.     gh.y:=w.topedge
  1372.     gh.xsize:=w.width
  1373.     gh.ysize:=w.height
  1374. #ifdef EASY_EXTRAS
  1375.     gh.blockcnt:=1  -> Force unblock, if necessary.
  1376.     unblockwin(gh)  -> Just in case!
  1377. #endif
  1378.     removegui(gh)
  1379.     removemenus(gh)
  1380. #ifdef EASY_APPWINDOW
  1381.     IF gh.appwin
  1382.       RemoveAppWindow(gh.appwin) -> RST:V36
  1383.       gh.appwin:=NIL
  1384.     ENDIF
  1385.     -> Remove any last minute messages safely.
  1386.     IF gh.awport THEN clearmsgs(gh.awport,{testappwmsg},gh)
  1387. #endif
  1388.     IF w
  1389.       -> Must be in Forbid()/Permit() brackets.
  1390.       Forbid()
  1391.       -> Remove any last minute messages safely.
  1392.       clearmsgs(gh.wndport,{testintuimsg},w)
  1393.       -> Make sure no more messages get sent.
  1394.       w.userport:=NIL
  1395.       ModifyIDCMP(w,0)
  1396.       Permit()
  1397.       -> Now the window can be closed safely.
  1398.       CloseWindow(w)
  1399.       gh.pwnd:=NIL
  1400.     ENDIF
  1401.     stdrast:=NIL
  1402.     IF gh.visual
  1403.       FreeVisualInfo(gh.visual)
  1404.       gh.visual:=NIL
  1405.     ENDIF
  1406. #ifdef EASY_EXTRAS
  1407.     -> If multi then decrement count of open windows.
  1408.     IF gh.mh THEN gh.mh.opencount:=gh.mh.opencount-1
  1409. #endif
  1410.     IF gh.is_wb
  1411. #ifdef EASY_OS12
  1412.       IF intuiVersion(36)
  1413. #endif
  1414.         IF gh.scr THEN UnlockPubScreen(NIL,gh.scr) -> RST:V36
  1415. #ifdef EASY_OS12
  1416.       ELSE
  1417.         END gh.scr
  1418.       ENDIF
  1419. #endif
  1420.       gh.scr:=NIL
  1421.     ENDIF
  1422.     -> If the font is linked to the screen, it's no longer valid.
  1423.     IF gh.ta_scr THEN gh.tattr:=NIL
  1424.   ENDIF
  1425. ENDPROC
  1426.  
  1427. -> Render the gadgets on the window.
  1428. PROC rendergui(gh:PTR TO guihandle)
  1429.   DEF glist=0,w:PTR TO window,base:PTR TO g
  1430.   w:=gh.pwnd
  1431.   base:=gh.base
  1432.   gh.gl:=CreateContext({glist})
  1433.   IF gh.gl=NIL THEN RaiseX("GUI",1183,'Could not create gadget context. Out of memory?')
  1434.   stdrast:=w.rport
  1435.   -> Adjust intermediate gadgets to be real gadgets fitting in window.
  1436.   adjust(base, gh.xoff,gh.yoff,
  1437.          w.width-gh.xsize+base.xs,w.height-gh.ysize+base.ys, gh)
  1438.   AddGList(w,glist,-1,-1,NIL)
  1439. #ifndef EASY_KEYBOARD
  1440.   -> If no keyboard support, activate first sting gadget.
  1441.   IF gh.firststr THEN ActivateGadget(gh.firststr,w,NIL)
  1442. #endif
  1443.   RefreshGList(glist,w,NIL,-1)
  1444.   Gt_RefreshWindow(w,NIL)
  1445.   -> Set public pointer, as a flag to say it's OK to play with the GUI, now.
  1446.   gh.wnd:=w
  1447. ENDPROC glist
  1448.  
  1449. -> Remove PLUGINs and gadgets from window.
  1450. PROC removegads(gh:PTR TO guihandle)
  1451.   DEF pl:PTR TO plugin
  1452.   -> Set public pointer to NIL, to say it's no longer safe to play with the GUI.
  1453.   gh.wnd:=NIL
  1454.   pl:=gh.plugins
  1455.   WHILE pl
  1456.     pl.clear_render(gh.pwnd)
  1457.     pl:=pl.next
  1458.   ENDWHILE
  1459.   IF gh.glist
  1460.     RemoveGList(gh.pwnd,gh.glist,-1)
  1461.     FreeGadgets(gh.glist)
  1462.   ENDIF
  1463. ENDPROC
  1464.  
  1465. -> Decide what the real screen bottom is by getting size gadget height.
  1466. PROC getrealbot(s:PTR TO screen)
  1467.   DEF dri,bot,im:PTR TO image
  1468. #ifdef EASY_OS12
  1469.   IF intuiVersion(36)
  1470. #endif
  1471.     bot:=s.wborbottom
  1472.     IF dri:=GetScreenDrawInfo(s) -> RST:V36
  1473.       IF im:=NewObjectA(NIL,'sysiclass', -> RST:V36
  1474.                        [SYSIA_DRAWINFO,dri, SYSIA_WHICH,SIZEIMAGE,
  1475.                         SYSIA_SIZE,SysISize(s.flags), NIL])
  1476.         bot:=im.height
  1477.         DisposeObject(im) -> RST:V36
  1478.       ENDIF
  1479.       FreeScreenDrawInfo(s,dri) -> RST:V36
  1480.     ENDIF
  1481. #ifdef EASY_OS12
  1482.   ELSE
  1483.     bot:=SIZERY
  1484.   ENDIF
  1485. #endif
  1486. ENDPROC bot
  1487.  
  1488. #ifdef EASY_KEYBOARD
  1489. -> Fiddled so actually one less than length...
  1490. PROC execlistlen(list:PTR TO mlh)
  1491.   DEF len=-1, node:PTR TO mln
  1492.   -> Catch the case where the LISTV is being cleanly updated.
  1493.   IF list<>-1
  1494.     IF list
  1495.       node:=list.head
  1496.       WHILE node:=node.succ DO len++
  1497.     ENDIF
  1498.   ENDIF
  1499. ENDPROC len
  1500.  
  1501. -> Do action appropriate to key press.
  1502. PROC performkey(gh:PTR TO guihandle,code)
  1503.   DEF list:PTR TO LONG,ret,val,tag,index,data,gad=NIL:PTR TO gadget,inc
  1504.   -> Look up gadget in key index.
  1505.   IF islower(code)      -> Positive action
  1506.     gad:=gh.keys[code-"a"]
  1507.     inc:=TRUE
  1508.   ELSEIF isupper(code)  -> Negative action
  1509.     gad:=gh.keys[code-"A"]
  1510.     inc:=FALSE
  1511.   ENDIF
  1512.   IF gad=NIL THEN RETURN GUI_CONT
  1513. /* Ack! Doesn't work under OS2.0...
  1514. #ifdef EASY_EXTRAS
  1515.   Gt_GetGadgetAttrsA(gad,gh.pwnd,NIL,[GA_DISABLED,{ret},NIL])
  1516.   IF ret THEN RETURN GUI_CONT
  1517. #endif
  1518. */
  1519.   list:=gad.userdata
  1520.   ret:=ATTR(list,EG_ACT)
  1521. #ifdef EASY_EXTRAS
  1522.   -> If disabled then don't react.
  1523.   IF optdis(gad.gadgetid,list) THEN RETURN GUI_CONT
  1524. #endif
  1525.   -> Tag is TRUE if a button.
  1526.   data,tag:=indexdata(gad.gadgetid)
  1527.   data:=OptDefATTR(list,data)
  1528.   SELECT MAXGUI OF gad.gadgetid
  1529.   -> Just press button.
  1530.   -> CASE BUTTON,SBUTTON,RBUTTON
  1531.   CASE STR,INTEGER
  1532.     -> Activate string and integer gadgets.
  1533.     ActivateGadget(gad,gh.pwnd,NIL)
  1534.   CASE CHECK
  1535.     -> Toggle check gadgets.
  1536.     tag:=GTCB_CHECKED
  1537.     index:=CHK_VAL
  1538.     val:=(IsChecked(gad)=FALSE)
  1539.   CASE MX
  1540.     -> Next/prev item, wrapping.
  1541.     tag:=GTMX_ACTIVE
  1542.     index:=ListLen(ATTR(list,MX_LIST))-2
  1543.     val:=ATTR(list,MX_CURR)
  1544.     IF inc
  1545.       IF val++>=index THEN val:=0
  1546.     ELSE
  1547.       IF val--<0 THEN val:=index
  1548.     ENDIF
  1549.     index:=MX_CURR
  1550.   CASE CYCLE
  1551.     -> Next/prev item, wrapping.
  1552.     tag:=GTCY_ACTIVE
  1553.     index:=ListLen(ATTR(list,CYC_LIST))-2
  1554.     val:=ATTR(list,CYC_CURR)
  1555.     IF inc
  1556.       IF val++>=index THEN val:=0
  1557.     ELSE
  1558.       IF val--<0 THEN val:=index
  1559.     ENDIF
  1560.     index:=CYC_CURR
  1561.   CASE SCROLL
  1562.     -> Inc/dec, stopping at ends.
  1563.     tag:=GTSC_TOP
  1564.     val:=ATTR(list,SCR_TOP)
  1565.     IF inc
  1566.       IF val++>=(ATTR(list,SCR_TOTL)-ATTR(list,SCR_VIS)) THEN tag:=0
  1567.     ELSE
  1568.       IF val--<0 THEN tag:=0
  1569.     ENDIF
  1570.     index:=SCR_TOP
  1571.   CASE SLIDE
  1572.     -> Inc/dec, stopping at ends.
  1573.     tag:=GTSL_LEVEL
  1574.     val:=ATTR(list,SLI_CURR)
  1575.     IF inc
  1576.       IF val++>=ATTR(list,SLI_MAX) THEN tag:=0
  1577.     ELSE
  1578.       IF val--<ATTR(list,SLI_MIN) THEN tag:=0
  1579.     ENDIF
  1580.     index:=SLI_CURR
  1581.   CASE LISTV
  1582.     -> Next/prev, stopping at ends.
  1583.     tag:=GTLV_SELECTED
  1584.     val:=ATTR(list,LST_CURR)
  1585.     IF inc
  1586.       IF val++>=execlistlen(ATTR(list,LST_LIST)) THEN tag:=0
  1587.     ELSE
  1588.       IF val--<0 THEN tag:=0
  1589.     ENDIF
  1590.     index:=LST_CURR
  1591.   CASE PALETTE
  1592.     -> Next/prev, wrapping.
  1593.     tag:=GTPA_COLOR
  1594.     val:=ATTR(list,PAL_CURR)
  1595.     index:=Shl(1,ATTR(list,PAL_DEP))-1
  1596.     IF inc
  1597.       IF val++>=index THEN val:=0
  1598.     ELSE
  1599.       IF val--<0 THEN val:=index
  1600.     ENDIF
  1601.     index:=PAL_CURR
  1602.   ENDSELECT
  1603.   -> Perform change if required.
  1604.   IF tag
  1605.     IF tag<>TRUE  -> If not a button (non-zero is tag value).
  1606.       setgadattr(gad,gh.pwnd,list,val,tag,index)
  1607.       IF gad.gadgetid=LISTV THEN setgadattr(gad,gh.pwnd,list,val,GTLV_MAKEVISIBLE)
  1608.     ENDIF
  1609.     -> Do action.
  1610.     IF IsActionFun(ret)
  1611.       -> If button (non-zero is tag value).
  1612.       IF tag=TRUE THEN ret(0,data,gh.info) ELSE ret(0,data,gh.info,val)
  1613.       ret:=GUI_CONT
  1614.     ENDIF
  1615.   ELSE
  1616.     ret:=GUI_CONT
  1617.   ENDIF
  1618. ENDPROC ret
  1619. #endif
  1620.  
  1621. -> Call action function based on new code.
  1622. PROC performaction(fun,gad:PTR TO gadget,info,code,l:PTR TO LONG,qual)
  1623.   DEF data,but,val
  1624.   data,but,val:=indexdata(gad.gadgetid)
  1625.   data:=OptDefATTR(l,data)
  1626. ENDPROC (IF but THEN fun(qual,data,info) ELSE
  1627.                      fun(qual,data,info,IF val THEN ATTR(l,val) ELSE code))
  1628.  
  1629. /********** getstr **********/
  1630. EXPORT PROC getstr(gh,g) IS gadstr(g,findgadget(gh,g))
  1631.  
  1632. /********** getinteger **********/
  1633. EXPORT PROC getinteger(gh,g) IS gadinteger(g,findgadget(gh,g))
  1634.  
  1635. -> Copy buffer string to gadget E-string.
  1636. PROC gadstr(l:PTR TO LONG, gad:PTR TO gadget) IS
  1637.   IF gad THEN StrCopy(ATTR(l,STR_STR),GadString(gad)) ELSE 0
  1638.  
  1639. -> Copy buffer integer to gadget integer.
  1640. PROC gadinteger(l:PTR TO LONG, gad:PTR TO gadget)
  1641.   DEF x=0
  1642.   IF gad THEN ATTR(l,INT_VAL):=x:=GadLongInt(gad)
  1643. ENDPROC x
  1644.  
  1645. -> Record new gadget value.
  1646. PROC performset(gad:PTR TO gadget,code,l:PTR TO LONG)
  1647.   SELECT MAXGUI OF gad.gadgetid
  1648.   CASE STR;     gadstr(l,gad)
  1649.   CASE INTEGER; gadinteger(l,gad)
  1650.   CASE CHECK;   ATTR(l,CHK_VAL):=IsChecked(gad)
  1651.   CASE MX;      ATTR(l,MX_CURR):=code
  1652.   CASE CYCLE;   ATTR(l,CYC_CURR):=code
  1653.   CASE SCROLL;  ATTR(l,SCR_TOP):=code
  1654.   CASE SLIDE;   ATTR(l,SLI_CURR):=code
  1655.   CASE LISTV;   ATTR(l,LST_CURR):=code
  1656.   CASE PALETTE; ATTR(l,PAL_CURR):=code
  1657.   ENDSELECT
  1658. ENDPROC
  1659.  
  1660. -> Clean gadget description objects.
  1661. PROC clean(base:PTR TO g)
  1662.   DEF i:PTR TO g,j
  1663.   IF base
  1664.     IF IsRowOrCol(base.type)
  1665.       i:=base.list
  1666.       WHILE i
  1667.         j:=i
  1668.         i:=i.next
  1669.         clean(j)
  1670.       ENDWHILE
  1671.     ELSEIF IsBevel(base.type)
  1672.       clean(base.list)
  1673.     ENDIF
  1674.     END base
  1675.   ENDIF
  1676. ENDPROC
  1677.  
  1678. -> Length of text, ignoring a "_" if present.
  1679. #ifdef EASY_KEYBOARD
  1680. #define textlenkey(s,g,k) textlen_key(s,g,k)
  1681. #endif
  1682. #ifndef EASY_KEYBOARD
  1683. #define textlenkey(s,g,k) textlen(s,g)
  1684. #endif
  1685.  
  1686. -> Calculate minimum size for a PALETTE gadget showing depth d
  1687. -> Ack! Fiddled to compensate for OS2.0 indicator
  1688. PROC min_pal(x,y,d)
  1689.   DEF dy
  1690.   IF (x+y)=0 THEN RETURN RaiseX("Egui",1441,'Bad PALETTE gadget sizes.')
  1691.   dy:=Div(Mul(y,d),x+y)
  1692. ENDPROC Max(Mul(Shl(1,d-dy),7)+21,x), Max(Shl(4,dy)+3,y)
  1693.  
  1694. -> Calculate minimum size of GUI.
  1695. PROC minsize(gui:PTR TO LONG,gh:PTR TO guihandle,isinrows=TRUE,eql=FALSE)
  1696.   DEF p:PTR TO g,h,minargs,a,b:PTR TO LONG,c,pl:PTR TO plugin,type,
  1697.       ta:PTR TO textattr
  1698.   minargs:=minARGS()
  1699.   ta:=gh.tattr
  1700.   h:=ta.ysize
  1701.   type:=ATTR(gui,EG_TYPE)
  1702.   IF (type<0) OR (type>=MAXGUI) THEN RaiseX("Egui",gui,'Bad gadget type.')
  1703.   IF (ListLen(gui)<minargs[type]) THEN RaiseX("Egui",gui,'Too few arguments for gadget.')
  1704. #ifdef EASY_KEYBOARD
  1705.   a:=optkey(type,gui)
  1706. #endif
  1707. #ifndef EASY_KEYBOARD
  1708.   a:=0
  1709. #endif
  1710.   SELECT MAXGUI OF type
  1711.   CASE ROWS,EQROWS,COLS,EQCOLS
  1712.     p:=foreach(gui,type,gh,IsRow(type),IsEqualGroup(type))
  1713.   CASE BEVEL,BEVELR
  1714.     p:=minsize(ATTR(gui,BEV_GUI),gh)
  1715.     p:=newg(BEVELXSPACE*2+p.xs,BEVELYSPACE*2+p.ys,type,p,p.flags)
  1716.   CASE BUTTON,SBUTTON,RBUTTON
  1717.     p:=newg(textlenkey(ATTR(gui,BUT_TXT),ta,a)+BUTXSPACE,
  1718.             h+BUTYSPACE,type,gui,ButtSpFlags(type))
  1719.   CASE CHECK
  1720.     a:=textlenkey(ATTR(gui,CHK_TXT),ta,a)+8
  1721.     p:=newg(11+a+BUTXSPACE,h+CHECKSPACE,CHECK,gui,
  1722.             IF eql THEN COND_RESIZEX ELSE 0,IF ATTR(gui,CHK_LEFT) THEN a ELSE 0)
  1723.   CASE INTEGER
  1724.     a:=textlenkey(ATTR(gui,INT_TXT),ta,a)+8
  1725.     p:=newg(ATTR(gui,INT_REL)*textlen('5',ta)+a,h+BUTYSPACE,INTEGER,gui,
  1726.             RESIZEX,a)
  1727.   CASE LISTV
  1728.     a:=textlen(ATTR(gui,LST_TXT),ta)
  1729.     p:=newg(Max(a,ATTR(gui,LST_RELX)*h+4),
  1730.             ATTR(gui,LST_RELY)*h+(IF a THEN (h+10) ELSE 4),LISTV,gui,
  1731.             RESIZEXANDY)
  1732.   CASE MX
  1733.     c:=textlenkey(ATTR(gui,MX_TXT),ta,a)+8
  1734.     a:=0
  1735.     b:=ATTR(gui,MX_LIST)
  1736.     WHILE b[] DO a:=Max(a,textlen(b[]++,ta))
  1737.     p:=newg(8+a+c+BUTXSPACE,ListLen(ATTR(gui,MX_LIST))-1*(h+MXSPACE)-1,MX,gui,
  1738.             IF eql THEN COND_RESIZEX ELSE 0,IF ATTR(gui,MX_LEFT) THEN c ELSE 0)
  1739.   CASE CYCLE
  1740.     c:=textlenkey(ATTR(gui,CYC_TXT),ta,a)+8
  1741.     a:=0
  1742.     b:=ATTR(gui,CYC_LIST)
  1743.     WHILE b[] DO a:=Max(a,textlen(b[]++,ta))
  1744.     p:=newg(h*2+a+c+BUTXSPACE,h+BUTYSPACE,CYCLE,gui,RESIZEX,c)
  1745.   CASE PALETTE
  1746.     a:=textlenkey(ATTR(gui,PAL_TXT),ta,a)+8
  1747.     b,c:=min_pal(ATTR(gui,PAL_RELX)*h,ATTR(gui,PAL_RELY)*h,ATTR(gui,PAL_DEP))
  1748.     p:=newg(b+a,c,PALETTE,gui,RESIZEXANDY,a)
  1749.   CASE SCROLL
  1750.     a:=ATTR(gui,SCR_REL)*h
  1751.     b:=h+BUTYSPACE
  1752.     p:=newg(IF ATTR(gui,SCR_VERT) THEN b ELSE a,
  1753.             IF ATTR(gui,SCR_VERT) THEN a ELSE b,SCROLL,gui,
  1754.             IF ATTR(gui,SCR_VERT) THEN RESIZEY ELSE RESIZEX)
  1755.   CASE SLIDE
  1756.     a:=textlenkey(ATTR(gui,SLI_TXT),ta,a)+8
  1757.     b:=ATTR(gui,SLI_REL)*h
  1758.     c:=h+BUTYSPACE
  1759.     p:=newg(a+IF ATTR(gui,SLI_VERT) THEN c ELSE b,
  1760.             IF ATTR(gui,SLI_VERT) THEN b ELSE c,SLIDE,gui,
  1761.             IF ATTR(gui,SLI_VERT) THEN RESIZEY ELSE RESIZEX,a)
  1762.   CASE STR
  1763.     a:=textlenkey(ATTR(gui,STR_TXT),ta,a)+8
  1764.     p:=newg(ATTR(gui,STR_REL)*h+a,h+BUTYSPACE,STR,gui,RESIZEX,a)
  1765.   CASE TEXT,NUM
  1766.     a:=textlen(ATTR(gui,TXT_TXT),ta)+8
  1767.     b:=(IF type=NUM THEN Max(ATTR(gui,NUM_REL),2)*textlen('5',ta)
  1768.         ELSE Max(textlen(ATTR(gui,TXT_VAL),ta),ATTR(gui,TXT_REL)*h))
  1769.     p:=newg(a+b,h+IF ATTR(gui,TXT_BORD) THEN BUTYSPACE ELSE YSP,type,gui,
  1770.             RESIZEX,a)
  1771.   CASE BAR
  1772.     p:=newg(2,4,BAR,gui,IF isinrows THEN COND_RESIZEX ELSE COND_RESIZEY)
  1773.   CASE SPACEH,SPACE,SPACEV
  1774.     p:=newg(0,0,SPACE,gui,SpaceFlags(type))
  1775.   CASE PLUGIN
  1776.     IF (pl:=ATTR(gui,PLG_OBJ))=NIL THEN RaiseX("Egui",gui,'PLUGIN object is NIL.')
  1777.     a,b:=pl.min_size(ta,h)
  1778.     p:=newg(a,b,PLUGIN,gui,pl.will_resize())
  1779.     pl.next:=gh.plugins; gh.plugins:=pl
  1780.     pl.base:=p
  1781.     pl.gh:=gh
  1782.   ENDSELECT
  1783. ENDPROC p
  1784.  
  1785. -> Calculate minimum size of group.
  1786. PROC foreach(guilist:PTR TO LONG,type,gh:PTR TO guihandle,row,eq)
  1787.   DEF l,x=0,y=0,z=0,zmid=NO_MID,zother=0,a,p:PTR TO g,list=NIL,
  1788.       last:PTR TO g,resize=0,xs,t
  1789.   last:={list}
  1790.   l:=ListLen(guilist)-1
  1791.   FOR a:=1 TO l
  1792.     p:=minsize(guilist[a],gh,row,eq)
  1793.     resize:=resize OR p.flags
  1794.     xs:=p.xs
  1795.     IF row
  1796.       x:=Max(xs,x)
  1797.       y:=y+p.ys+IF y THEN YSPACING ELSE 0
  1798.     ELSE
  1799.       y:=Max(p.ys,y)
  1800.       x:=x+xs+IF x THEN XSPACING ELSE 0
  1801.     ENDIF
  1802.     z:=Max(z,xs)        -> for EQ(ROWS/COLS)
  1803.     t:=p.mid
  1804.     zmid:=Max(zmid,t)
  1805.     zother:=Max(zother,IF t<>NO_MID THEN (xs-t) ELSE xs)
  1806.     last.next:=p
  1807.     last:=p
  1808.   ENDFOR
  1809.   IF eq
  1810.     last:=list
  1811.     z:=IF zmid<>NO_MID THEN (zmid+zother) ELSE zother
  1812.     WHILE last
  1813.       last.xs:=z
  1814.       last.mid:=IF last.mid<>NO_MID THEN zmid ELSE 0
  1815.       last:=last.next
  1816.     ENDWHILE
  1817.     x:=IF row THEN z ELSE (z+XSPACING*l-XSPACING)
  1818.   ENDIF
  1819.   resize:=(IF DoesXUncond(resize) THEN RESIZEX ELSE 0) OR
  1820.           (IF DoesYUncond(resize) THEN RESIZEY ELSE 0)
  1821. ENDPROC newg(x,y,type,list,resize)
  1822.  
  1823. -> Calculate real positions and sizes, and create real gadgets.
  1824. PROC adjust(base:PTR TO g,x,y,xs,ys,gh:PTR TO guihandle,isinrow=TRUE)
  1825.   DEF pl:PTR TO plugin
  1826.   IF DoesXResize(base.flags)=FALSE THEN (x:=xs-base.xs/2+x) BUT xs:=base.xs
  1827.   IF DoesYResize(base.flags)=FALSE THEN (y:=ys-base.ys/2+y) BUT ys:=base.ys
  1828.   SELECT MAXGUI OF base.type
  1829.   CASE ROWS,EQROWS,COLS,EQCOLS
  1830.     adjustall(base,x,y,xs,ys,gh)
  1831.   CASE BEVEL,BEVELR
  1832.     adjust(base.list,BEVELXSPACE+x,BEVELYSPACE+y,
  1833.            xs-(BEVELXSPACE*2),ys-(BEVELYSPACE*2),gh)
  1834.     DrawBevelBoxA(gh.pwnd.rport,x,y,xs,ys,
  1835.                  [GT_VISUALINFO,gh.visual,GTBB_FRAMETYPE,BBFT_BUTTON,
  1836.                   IF base.type=BEVELR THEN GTBB_RECESSED ELSE TAG_IGNORE,0,NIL])
  1837.   CASE BAR
  1838.     IF isinrow
  1839.       Line(x,y+1,x+xs-1,y+1,1)
  1840.       Line(x,y+2,x+xs-1,y+2,2)
  1841.     ELSE
  1842.       Line(x+1,y,x+1,y+ys-1,1)
  1843.       Line(x+2,y,x+2,y+ys-1,2)
  1844.     ENDIF
  1845.   CASE PLUGIN
  1846.     pl:=ATTR(base.list,PLG_OBJ)
  1847.     pl.x:=x; pl.y:=y; pl.xs:=xs; pl.ys:=ys
  1848.     IF OptATTR(base.list,PLG_GT)
  1849.       gh.gl:=pl.gtrender(gh.gl,gh.visual,gh.tattr,x,y,xs,ys,gh.pwnd)
  1850.     ELSE
  1851.       pl.render(gh.tattr,x,y,xs,ys,gh.pwnd)
  1852.     ENDIF
  1853.   DEFAULT
  1854.     base.x:=x; base.y:=y
  1855.     creategadget(base,xs,ys,gh)
  1856.   ENDSELECT
  1857. ENDPROC x+xs+XSPACING,y+ys+YSPACING
  1858.  
  1859. -> adjust over column and row groups.
  1860. PROC adjustall(base:PTR TO g,x,y,xs,ys,gh)
  1861.   DEF p:PTR TO g,rs=0,fs=0,sp=0,ds=0,t,rg=0,u,row
  1862.   -> fs is fixed-width total, rs is resize total
  1863.   -> ds is gad count, sp is space gad count
  1864.   p:=base.list
  1865.   row:=IsRow(base.type)
  1866.   WHILE p
  1867.     t:=IF row THEN p.ys ELSE p.xs
  1868.     IF (row AND DoesYResize(p.flags)) OR (row=FALSE AND DoesXResize(p.flags))
  1869.       IF t<=0 THEN sp++ ELSE ((rs:=rs+t) BUT rg++)
  1870.     ELSE
  1871.       fs:=fs+t
  1872.     ENDIF
  1873.     p:=p.next
  1874.     ds++
  1875.   ENDWHILE
  1876.   p:=base.list
  1877.   ds:=(IF row THEN ys ELSE xs)-rs-fs-(ds-1*IF row THEN YSPACING ELSE XSPACING)
  1878.   -> ds is now difference in space reqts
  1879.   WHILE p
  1880.     t:=IF row THEN p.ys ELSE p.xs
  1881.     IF (row AND DoesYResize(p.flags)) OR (row=FALSE AND DoesXResize(p.flags))
  1882.       IF t<=0
  1883.         IF rg
  1884.           IF row THEN ys:=0 ELSE xs:=0
  1885.         ELSE  -> If only space gads can resize...
  1886.           fs:=((sp-1)/2+ds)/sp  -> Share space completely and fairly
  1887.           ds:=ds-fs
  1888.           sp--
  1889.           IF row THEN ys:=fs ELSE xs:=fs
  1890.         ENDIF
  1891.       ELSE
  1892.         fs:=((t*ds)+((rs-1)/2))/rs  -> Share space completely and fairly
  1893.         ds:=ds-fs
  1894.         rs:=rs-t
  1895.         IF row THEN ys:=t+fs ELSE xs:=t+fs
  1896.       ENDIF
  1897.     ELSE
  1898.       IF row THEN ys:=t ELSE xs:=t
  1899.     ENDIF
  1900.     t,u:=adjust(p,x,y,xs,ys,gh,row)
  1901.     IF row THEN y:=u ELSE x:=t
  1902.     p:=p.next
  1903.   ENDWHILE
  1904. ENDPROC
  1905.  
  1906. -> Create real gadget.
  1907. PROC creategadget(base:PTR TO g,lxs,lys,gh:PTR TO guihandle)
  1908.   DEF tl,i:PTR TO LONG,minargs,text,flags=0,kindtab,h,textl,x,y,xs,ys,
  1909.       mid,domid=FALSE,key=0,appw=0
  1910.   minargs:=minARGS()
  1911.   -> Args at least two, so not SPACE* (never called for other possibilities)
  1912.   IF minargs[base.type]>=2
  1913.     i:=base.list
  1914.     h:=gh.tattr.ysize
  1915.     flags:=PLACETEXT_RIGHT
  1916.     x:=base.x
  1917.     y:=base.y
  1918.     xs:=base.xs
  1919.     ys:=base.ys
  1920.     mid:=IF (base.mid<>NO_MID) AND base.mid THEN (base.mid) ELSE 0
  1921.     text:=ATTR(i,EG_TXT)  -> speculative
  1922.     IF text=NIL THEN text:=''
  1923.     SELECT MAXGUI OF base.type
  1924.     CASE BUTTON,SBUTTON,RBUTTON
  1925.       tl:=[NIL]
  1926.       flags:=PLACETEXT_IN
  1927.       IF HasHButtSp(base.type) THEN xs:=lxs
  1928.       IF HasVButtSp(base.type) THEN ys:=lys
  1929. #ifdef EASY_APPWINDOW
  1930.       appw:=OptATTR(i,BUT_APPW)
  1931. #endif
  1932.     CASE CHECK
  1933.       tl:=[GTCB_CHECKED,IF ATTR(i,CHK_VAL) THEN 1 ELSE 0, GTCB_SCALED,TRUE, NIL]
  1934.       textl:=IF StrLen(text) THEN mid ELSE 0
  1935.       x:=x+textl
  1936.       IF ATTR(i,CHK_LEFT) THEN flags:=PLACETEXT_LEFT
  1937.       xs:=h*2+2
  1938.       ys:=h+1
  1939.     CASE LISTV
  1940.       xs:=ATTR(i,LST_CURR)
  1941.       tl:=[GTLV_LABELS,ATTR(i,LST_LIST), GTLV_SELECTED,xs,
  1942.            IF ATTR(i,LST_SHOW)>=1 THEN GTLV_SHOWSELECTED ELSE TAG_IGNORE,NIL,
  1943.            -> GTLV_SCROLLWIDTH,h*2,
  1944.            GTLV_READONLY,ATTR(i,LST_RO),
  1945. ->           IF xs<>-1 THEN GTLV_TOP ELSE TAG_IGNORE, xs,
  1946.            IF xs<>-1 THEN GTLV_MAKEVISIBLE ELSE TAG_IGNORE, xs, NIL]
  1947.       flags:=PLACETEXT_ABOVE
  1948.       xs:=lxs
  1949.       IF StrLen(text)
  1950.         ys:=lys-h-6
  1951.         y:=y+h+6
  1952.       ELSE
  1953.         ys:=lys
  1954.       ENDIF
  1955. #ifdef EASY_APPWINDOW
  1956.       appw:=OptATTR(i,LST_APPW)
  1957. #endif
  1958.     CASE MX
  1959.       tl:=[GTMX_LABELS,ATTR(i,MX_LIST), GTMX_ACTIVE,ATTR(i,MX_CURR),
  1960.            GTMX_TITLEPLACE,IF ATTR(i,MX_LEFT) THEN PLACETEXT_LEFT ELSE PLACETEXT_RIGHT,
  1961.            GTMX_SPACING,MXSPACE, GTMX_SCALED,TRUE, NIL]
  1962.       textl:=IF StrLen(text) THEN mid ELSE 0
  1963.       x:=x+textl
  1964.       IF ATTR(i,MX_LEFT)=FALSE THEN flags:=PLACETEXT_RIGHT
  1965.       xs:=h
  1966.       ys:=h
  1967.     CASE STR
  1968.       tl:=[GTST_STRING,ATTR(i,STR_STR), STRINGA_REPLACEMODE,OptATTR(i,STR_OVR),
  1969.            GTST_MAXCHARS,Min(StrMax(ATTR(i,STR_STR)),ATTR(i,STR_MAX)), NIL]
  1970.       domid:=TRUE
  1971. #ifdef EASY_APPWINDOW
  1972.       appw:=OptATTR(i,STR_APPW)
  1973. #endif
  1974.     CASE INTEGER
  1975.       tl:=[GTIN_NUMBER,ATTR(i,INT_VAL), GTIN_MAXCHARS,15, NIL]
  1976.       domid:=TRUE
  1977.       lxs--
  1978.     CASE CYCLE
  1979.       tl:=[GTCY_LABELS,ATTR(i,CYC_LIST), GTCY_ACTIVE,ATTR(i,CYC_CURR), NIL]
  1980.       domid:=TRUE
  1981.     CASE PALETTE
  1982.       -> Ack!  Indicator width is large for OS2.0 compatibility
  1983.       tl:=[GTPA_DEPTH,ATTR(i,PAL_DEP), GTPA_INDICATORWIDTH,16,
  1984.            GTPA_COLOR,ATTR(i,PAL_CURR), NIL]
  1985.       domid:=TRUE
  1986.     CASE SCROLL
  1987.       tl:=[GTSC_TOP,ATTR(i,SCR_TOP), GTSC_TOTAL,ATTR(i,SCR_TOTL),
  1988.            PGA_FREEDOM,IF ATTR(i,SCR_VERT) THEN LORIENT_VERT ELSE LORIENT_HORIZ,
  1989.            GTSC_VISIBLE,ATTR(i,SCR_VIS), GTSC_ARROWS,12, NIL]
  1990.       xs:=lxs
  1991.       ys:=lys
  1992.       text:=''
  1993.     CASE SLIDE
  1994.       tl:=[GTSL_MIN,ATTR(i,SLI_MIN), GTSL_MAX,ATTR(i,SLI_MAX),
  1995.            GTSL_LEVEL,ATTR(i,SLI_CURR), GTSL_LEVELFORMAT,ATTR(i,SLI_FMT),
  1996.            PGA_FREEDOM,IF ATTR(i,SLI_VERT) THEN LORIENT_VERT ELSE LORIENT_HORIZ,
  1997.            GTSL_MAXLEVELLEN,3, NIL]
  1998.       domid:=TRUE
  1999.     CASE TEXT
  2000.       tl:=[GTTX_TEXT,ATTR(i,TXT_VAL), GTTX_BORDER,ATTR(i,TXT_BORD), NIL]
  2001.       domid:=TRUE
  2002.     CASE NUM
  2003.       tl:=[GTNM_NUMBER,ATTR(i,NUM_VAL), GTNM_BORDER,ATTR(i,NUM_BORD), NIL]
  2004.       domid:=TRUE
  2005.     ENDSELECT
  2006.     IF domid
  2007.       flags:=PLACETEXT_LEFT
  2008.       textl:=IF StrLen(text) THEN mid ELSE 0
  2009. ->      textl:=IF mid<>NO_MID THEN mid ELSE 0
  2010.       x:=x+textl
  2011.       xs:=lxs-textl
  2012.       ys:=lys
  2013.     ENDIF
  2014. #ifdef EASY_KEYBOARD
  2015.     key:=optkey(base.type,i)
  2016. #endif
  2017.     kindtab:=kindTAB()
  2018.     gh.gl:=CreateGadgetA(kindtab[base.type],gh.gl,
  2019.         [x,y,xs,ys,text,gh.tattr,base.type,flags,gh.visual,NIL]:newgadget,
  2020.         [IF key THEN GT_UNDERSCORE ELSE TAG_IGNORE,"_",
  2021.          IF optdis(base.type,i) THEN GA_DISABLED ELSE TAG_IGNORE,TRUE,
  2022.          TAG_MORE,tl])
  2023.     IF gh.gl=NIL THEN RaiseX("GUI",i,'Could not create gadget. Out of memory?')
  2024.     gh.gl.userdata:=i
  2025. #ifdef EASY_APPWINDOW
  2026. #ifdef EASY_OS12
  2027.     IF gh.wb_isopen
  2028. #endif
  2029.       IF appw THEN gh.gl.mutualexclude:=EG_MAGIC -> AppW magic identifier.
  2030. #ifdef EASY_OS12
  2031.     ENDIF
  2032. #endif
  2033. #endif
  2034. #ifndef EASY_KEYBOARD
  2035.     IF base.type=STR THEN IF gh.firststr=NIL THEN gh.firststr:=gh.gl
  2036. #endif
  2037. #ifdef EASY_KEYBOARD
  2038.     -> Remember gadget in key index.  Key must be lowercase.
  2039.     IF islower(key) THEN gh.keys[key-"a"]:=gh.gl
  2040. #endif
  2041.   ENDIF
  2042. ENDPROC
  2043.  
  2044. /********** findgadget **********/
  2045. EXPORT PROC findgadget(gh:PTR TO guihandle,list)
  2046.   DEF gad:PTR TO gadget
  2047.   IF gh.wnd
  2048.     gad:=gh.glist
  2049.     WHILE gad
  2050.       IF gad.userdata=list THEN RETURN gad
  2051.       gad:=gad.nextgadget
  2052.     ENDWHILE
  2053.   ENDIF
  2054. ENDPROC NIL
  2055.  
  2056. #ifdef EASY_APPWINDOW
  2057. -> Search for gadget desc list based on mouse position.
  2058. PROC findxy(gh:PTR TO guihandle,x,y)
  2059.   DEF gad:PTR TO gadget,offx=0,offy=0
  2060.   gad:=gh.glist
  2061.   WHILE gad
  2062.     IF gad.mutualexclude=EG_MAGIC  -> Then it's an EasyGUI AppW gadget...
  2063.       -> The only gadgets (so far) have a label on the left or the top,
  2064.       -> so compensate and calculate the offset.
  2065.       IF gad.gadgettext
  2066.         offx:=gad.gadgettext.leftedge
  2067.         IF offx>0 THEN offx:=0
  2068.         offy:=gad.gadgettext.topedge
  2069.         IF offy>0 THEN offy:=0
  2070.       ENDIF
  2071.       IF x>=(gad.leftedge+offx) THEN
  2072.       IF y>=(gad.topedge+offy) THEN
  2073.       IF gad.leftedge+gad.width>x THEN
  2074.       IF gad.topedge+gad.height>y THEN RETURN gad.userdata
  2075.     ENDIF
  2076.     gad:=gad.nextgadget
  2077.   ENDWHILE
  2078. ENDPROC NIL
  2079. #endif
  2080.  
  2081. -> Set gadget attribute based on real gadget.
  2082. PROC setgadattr(g,w,gad:PTR TO LONG,value,tag,index=0)
  2083.   IF g THEN Gt_SetGadgetAttrsA(g,w,NIL,[tag,value,NIL])
  2084.   IF index THEN ATTR(gad,index):=value
  2085. ENDPROC
  2086.  
  2087. -> Set gadget attribute based on gadget desc list.
  2088. PROC setattr(gh:PTR TO guihandle,gad,value,tag,index=0) IS
  2089.   setgadattr(findgadget(gh,gad),gh.wnd,gad,value,tag,index)
  2090.  
  2091. /********** setXXXXX **********/
  2092. EXPORT PROC setcheck(gh,gad,bool) IS setattr(gh,gad,bool,GTCB_CHECKED,CHK_VAL)
  2093. EXPORT PROC setinteger(gh,gad,new) IS setattr(gh,gad,new,GTIN_NUMBER,INT_VAL)
  2094. EXPORT PROC setmx(gh,gad,active) IS setattr(gh,gad,active,GTMX_ACTIVE,MX_CURR)
  2095. EXPORT PROC setcycle(gh,gad,active) IS setattr(gh,gad,active,GTCY_ACTIVE,CYC_CURR)
  2096. EXPORT PROC setpalette(gh,gad,colour) IS setattr(gh,gad,colour,GTPA_COLOR,PAL_CURR)
  2097. EXPORT PROC setscrolltop(gh,gad,top) IS setattr(gh,gad,top,GTSC_TOP,SCR_TOP)
  2098. EXPORT PROC setscrolltotal(gh,gad,total) IS setattr(gh,gad,total,GTSC_TOTAL,SCR_TOTL)
  2099. EXPORT PROC setscrollvisible(gh,gad,visible) IS setattr(gh,gad,visible,GTSC_VISIBLE,SCR_VIS)
  2100. EXPORT PROC setslide(gh,gad,new) IS setattr(gh,gad,new,GTSL_LEVEL,SLI_CURR)
  2101. EXPORT PROC settext(gh,gad,new) IS setattr(gh,gad,new,GTTX_TEXT,TXT_VAL)
  2102. EXPORT PROC setnum(gh,gad,new) IS setattr(gh,gad,new,GTNM_NUMBER,NUM_VAL)
  2103. EXPORT PROC setlistvlabels(gh,gad,labs) IS setattr(gh,gad,labs,GTLV_LABELS,LST_LIST)
  2104. EXPORT PROC setlistvvisible(gh:PTR TO guihandle,gad,vis) IS setattr(gh,gad,vis,GTLV_MAKEVISIBLE)
  2105.  
  2106. EXPORT PROC setlistvselected(gh:PTR TO guihandle,gad,active)
  2107.   DEF g
  2108.   setgadattr(g:=findgadget(gh,gad),gh.wnd,gad,active,GTLV_SELECTED,LST_CURR)
  2109.   IF active<>-1 THEN setgadattr(g,gh.wnd,gad,active,GTLV_MAKEVISIBLE)
  2110. ENDPROC
  2111.  
  2112. EXPORT PROC setstr(gh,gad:PTR TO LONG,new)
  2113.   setattr(gh,gad,new,GTST_STRING)
  2114. ENDPROC StrCopy(ATTR(gad,STR_STR),new)
  2115.  
  2116. /********** disposegui **********/
  2117. EXPORT PROC disposegui(gui:PTR TO LONG)
  2118.   DEF a,l
  2119.   IF gui
  2120.     IF IsGroup(ATTR(gui,EG_TYPE))
  2121.       l:=ListLen(gui)-1
  2122.       FOR a:=1 TO l DO disposegui(gui[a])
  2123.     ENDIF
  2124.     FastDisposeList(gui)
  2125.   ENDIF
  2126. ENDPROC
  2127.