home *** CD-ROM | disk | FTP | other *** search
INI File | 1994-11-09 | 16.8 KB | 448 lines |
- [Here's the new EasyGUI! This version is really usable.
- NOTE: read this first before recompiling any old EasyGUI stuff!]
-
- Introducing:
-
- E A S Y G U I
-
- An interface builder for E, with the following highlights:
-
- - It's totally Font-Sensitive
- - It's Resizable
- - It's Self-Organising, i.e. it arranges gadgets
- - It's more StyleGuide compliant than your granny
- - It's Fast and Flexible
- - It's relatively small, needs no extra external libraries
- - And above all: It's extremely easy to use!!!
-
- changes from the v3.1a version (features):
- - new functions to access/modify gadgets while GUI is active
- - easily add gadtools menus
- - more complete docs
- - works better with multiple simultanuous EasyGUIs
- - LISTV, MX and CYCLE have an extra "current" parameter now
- - STR now takes an _estring_ as value (make sure you change
- this in old sources!)
- bugs:
- - current gadget values would reset upon resize
- - would open in middle of screen instead of visible part
- - many tiny bugs removed
-
- +---------------------------------------------------------------+
- | 1. EasyGUI Intro |
- +---------------------------------------------------------------+
-
- EasyGUI takes the form a module file that needs to be included into your
- E source (needless to say, it needs v2.04/v37 of the OS). The most simple
- form of constructing a GUI consist of calling the function easygui() with
- a (possibly nested) E list which describes your GUI. just to show how Easy,
- try this source:
-
- MODULE 'tools/EasyGUI'
- PROC main() IS easygui('um,...',[BUTTON,0,'Ok!'])
-
- This'll open a window with just one gadget in it, and wait for the
- user to push it. If easygui() can't get what it wants, it'll start
- throwing around exceptions, so we'll probably need an exception
- handler to be able to inform the user properly (see below).
-
- The first arg of easygui() is the window title, the second one is the
- GUI description. The form of these desciptions is quite simple: It's a
- list with as first element the type of gadget, the second is called an
- action value (more later), and the rest is gadget-specific.
-
- To be able to build GUI's outof more components than just one gadget,
- one can group gadgets with a ROW and a COL list:
-
- [COLS,
- [BUTTON,1,'Ok'],
- [BUTTON,0,'Cancel']
- ]
-
- This'll create a new group, consisting of two gadgets next to each other.
- COLS and ROWS groups are like a single gadget, i.e. you can easily put them
- into other groups, to create GUI's of infinite complexity.
-
- Other Grouping functions are EQCOLS and EQCOLS, which try to align gadgets
- in a group.
-
- [BEVEL,a] will put a bevel box around a, whatever it is (a gadget, a group...),
- and BEVELR is the recessed version.
-
- Other elements of groups are mostly gadgets, which have a specific #of
- arguments. [If the number of arguments is incorrect, EasyGUI will raise
- the "Egui" exception.]
-
- The first element is always the type of gadget to create (see below). The
- second element is always something called an "actionvalue", which tells
- EasyGUI what needs to be done when the user interacts with the gadget.
- All elements after that are gadget specific.
-
- An action value may be:
- - a small positive integer (0-1000). If the user selects this gadget,
- EasyGUI will close the window, and return that value as returnvalue
- from the easygui() call. This is meant for "Ok" / "Cancel" type buttons.
- - a pointer to an "actionfunction". If the user selects this gadget,
- EasyGUI will call the function with as arguments depending on the
- type of gadget (for example a slider will get it's current value).
- After the actionfunction returns, EasyGUI continues processing messages
- from the GUI.
- example:
-
- ...[BUTTON,{load},'Load'],...
-
- PROC load(info) IS WriteF('You pushed the "Load" button!\n')
-
-
- the value of `info' is explained below. Or:
-
- DEF s[100]:STRING
-
- ...[STR,{str},'input:',s,50,4],
- [CYCLE,{cycle},'choose:',['Yep','Nope',NIL],1],...
-
- PROC str(info,news) IS WriteF('the new string is: \s\n',news)
- PROC cycle(info,newc) IS WriteF('the new choice is: \d\n',newc)
-
- In the action function, you can store the new value, however EasyGUI keeps
- track of it itself too: In the case of the STR above it will StrCopy() new
- values into your estring, so it automatically has the correct value after
- closing. In the case of all other gadgets it stores the new (integer) value
- in the list (so that `1' in `CYCLE' may become `0'). This has the added
- benefit that windows that are opened and then closed again will automatically
- start with the current values.
-
- The easygui() function:
-
- easygui(windowtitle,gui,info=0,screen=0,textattr=0,newmenus=0)
-
- `info' may be ANY value, and is always passed as first arg to the
- action functions. For example if you write a prefsrequester, this may
- be the the prefs OBJECT. Your actionfunctions then have a simple task
- changing the value of the element in question.
- `screen' is an optional screen to open on. if not present, EasyGUI opens
- on the current public screen.
- `textattr' is a fontdescription, and is best left NIL. If NIL, EasyGUI
- will pick the font the user selected as "screenfont" in fontprefs.
- `newmenus' can be a newmenus structure (as in gadtools.library). EasyGUI
- will then automatically attach it to the window and arrange any messages.
- You can give the same actionvalues as gadgets in the newmenu.userdata,
- and the actionfunction can be the same as for a `BUTTON', i.e.:
-
- [...,2,0,'Load','l',0,0,{load},...]:newmenu
-
- can use the same load() as in the example further above.
-
-
- +---------------------------------------------------------------+
- | 2. Gadgets |
- +---------------------------------------------------------------+
-
-
- general format: [NAME,action,text,...]
- in {}: which direction it may resize.
- * = not implemented or things missing.
- + = a value that can be affected lateron with the set#? functions
-
- Each gadget shows the gadget template, explanation, the form of the
- actionfunction, and a typical example).
-
-
- [BUTTON,action,intext]
- buttonaction(info)
- example: [BUTTON,0,'Cancel']
-
- [CHECK,action,righttext,checkedbool+,lefttextbool]
- checkedbool = whether gadget should initially be check-marked
- checkaction(info,checkedbool)
- example: [CHECK,{case},'Ignore case',TRUE,FALSE]
-
- [INTEGER,action,lefttext,num+,relsize]
- num = initial value
- integeraction(info,newnum) {x}
- example: [INTEGER,{v},'int:',5,3]
-
- [LISTV,action,textabove,relx,rely,execlist+,readbool,selected,current+]
- execlist = ptr to an execlist. (see tools/constructors.m)
- readbool = whether listview is read-only
- *selected = 0=none, 1=read, 2=strgad (fill in 0 for compat.)
- listviewaction(info,num_selected) {x,y}
- example: [LISTV,0,NIL,5,5,filenamelist,0,NIL,0]
-
- [MX,action,abovetext,nil_term_elist,lefttextbool,current]
- mxaction(info,num_selected)
- example: [MX,{v},NIL,['One','Two','Three',NIL],FALSE,1]
-
- [CYCLE,action,lefttext,nil_term_elist,current]
- cycleaction(info,num_selected)
- example: [CYCLE,{v},'choose:',['Yep','Nope',NIL],1]
-
- [PALETTE,action,lefttext,depth,relx,rely]
- depth = 1..8, number of bitplanes this color is for
- paletteaction(info,colour) {x,y}
- example: [PALETTE,{v},'color:',3,5,2]
-
- [SCROLL,action,isvert,total+,top+,visible+,relsize]
- total = resolution of scroller
- top = current top represented
- visible = current
- scolleraction(info,curtop) {x|y}
- example: [SCROLL,{v},FALSE,10,0,2,2]
-
- [SLIDE,action,lefttext,isvert,min,max,cur+,relsize,levelformat]
- min,max = value range of slider
- cur = current value
- levelformat = string that shows levelformat, example '%2ld'. leave
- a large amount of spaces left in lefttext for this.
- slideraction(info,cur) {x|y}
- example: [SLIDE,0,'Colors:',FALSE,1,8,3,5,'']
-
- [STR,action,lefttext,initial+,maxchars,relsize]
- initial = initial string contents: NOTE: HAS TO BE AN ESTRING!
- maxchars = max #of chars for string
- stringaction(info,newstring) {x}
- example: [STR,0,'Pattern',s,200,5] (DEF s[100]:STRING)
-
- [TEXT,text,lefttext,borderbool,relsize] {x}
- borderbool = whether or not a recessed bevelbox should be placed around 'text'
- example: [TEXT,'Selected Fonts',NIL,FALSE,3]
-
- *[NUM,int,lefttext,borderbool,relsize] {x}
-
- *[RENDER,actionr,actionp,x,y] -> in fontunits
- renderrefresh(x,y,xs,ys)
- renderpress(x,y) -> relative to topcorner
-
- *[RENDERFIXED,actionr,actionp,x,y] -> in pixels
- renderfixedrefresh(x,y)
- renderfixedpress(x,y)
-
- [SBUTTON] {x}
- same as button, only now resizes.
-
- [BAR], [SPACE] {x,y}, [SPACEH] {x}, [SPACEV] {y}
- BAR places a nice divider-bar between gadgets/groups. Whether it's
- horizontal or vertical depends on which group it is in. SPACE/SPACEH/SPACEV
- do nothing, they only eat up space. This can be very handy in GUI design,
- they act like a spring between elements (do not use them on the borders of a
- GUI, only in the middle).
-
- See the example GUI's how to use these.
-
- #?text:
- (where #? is left/right etc.): a text to place next to the gadget. often
- is allowed to be NIL.
-
- relsize,relx,rely:
- generally gadgets will automatically get a size depending on a number of
- factors, but relsize allows the programmer to give a minimum size for
- certain gadgets, thereby sizing a whole group. If other gadgets already
- account for the minimum size, this one can safely be set to a low value
- such as 2. All these sizes are calculate in terms of the hight of the font.
-
- nil_term_elist:
- a nil-terminated E list, such as ['One','Two','Three',NIL]
-
- isvert:
- TRUE if gadget needs to be vertical, horizontal by default.
-
- +---------------------------------------------------------------+
- | 3. How Layout Works |
- +---------------------------------------------------------------+
-
- EasyGUI works by automatically layouting the gadgets on the
- screen. In a first pass, it will compute the minimum size for
- each element: for gadgets this involves the size of fonts and
- various other things. For a ROWS list, for example, it will take
- the width of the biggest gadget as its width, and computes its
- height by adding the heights of all other gadgets. For EQROWS
- this is slightly more complicated: EasyGUI also computes a "middle"
- for various gadgets, often between the text that denotes what a
- gadget is about and the gadget itself. It then tries to align
- all of these. for EQCOLS it simply tries to make all columns
- equal width.
- In a second pass, EasyGUI assigns the final coordinates to all
- gadgets. Important to notice is that in a GUI often there is
- more space available than is required for a gadget, for example
- the gadget above it in a ROWS environment is much wider. Also, the
- user may have resized the window. To do something useful with this
- space, EasyGUI looks at which gadgets can do something useful
- with extra space, such as LISTV, or STR, SCROLL etc. This process
- of granting extra space propagates through ROWS/COLS, which act
- as gadgets themselves. Gadgets like BUTTON don't benefit from more
- space, so they give that away to their neighbours.
-
-
- +---------------------------------------------------------------+
- | 4. Advanced features |
- +---------------------------------------------------------------+
-
- Throwing exceptions from actionfunctions
- ----------------------------------------
- is allowed: EasyGUI will catch it, close the window properly,
- and then ReThrow() it.
-
- exceptions raised by EasyGUI itself:
-
- "MEM" -- no mem
- "GUI" -- for things like CreateGadgetA, OpenWindowTagList etc.
- "GT" -- couldn't open gadtools.library
- "bigg" -- for "BIG Gui": interface is calculated to be bigger than the screen.
- generally you should keep gui's small, so that they still fit on
- 640x200 topaz screens. If the user runs Times/30 on a screen this size,
- he probably knows he has a problem.
- "Egui" -- a design error: most probably handed over a list to dogui()
- that was either to long or too short
- <other> -- Raise()ed by own function
-
- You can also use a "quit" exception or somesuch if you need to quit from an
- actionfunction (i.e. other than with an actionvalue).
-
-
- Multiple Windows
- ----------------
- The simplest use of EasyGUI is just by calling easygui(). You can however
- open any number of windows, and check messages for all of them.
-
- guiinit(windowtitle,gui,info=0,screen=0,textattr=0,newmenus=0)
- guimessage(guihandle)
- cleangui(guihandle)
-
- Call guiinit() for each window (exactly the same arguments as easygui(). Then,
- keep calling guimessage() for each of them, when messages arive. you can
- close them again with cleangui(), for example when a gui returns a
- positive integer (the actioncode). Negative integers signal that it simply
- finished processing all messages, but no need to close the window yet.
-
- example of usage of these three function (= definition easygui())
-
-
- EXPORT PROC easygui(windowtitle,gui,info=NIL,screen=NIL,textattr=NIL,newmenus=NIL) HANDLE
- DEF gh=NIL:PTR TO guihandle,res=-1
- gh:=guiinit(windowtitle,gui,info,screen,textattr,newmenus)
- WHILE res<0
- Wait(gh.sig)
- res:=guimessage(gh)
- ENDWHILE
- EXCEPT DO
- cleangui(gh)
- ReThrow()
- ENDPROC res
-
-
- the object you get has some handy field in there: the window in question,
- and the sigmask (i.e. Shl(1,sigbit)), if you want to do a proper Wait()
- (OR them).
-
- OBJECT guihandle
- wnd:PTR TO window
- sig:LONG
- ENDOBJECT /* SIZEOF=64 */
- ^^^^private!
-
- if you want to draw into `wnd': stdrast is automatically set to the last
- EasyGUI opened.
-
-
- Multiple copies of a GUI
- ------------------------
- if your app allows to have multiple copies of the _same_ gui open
- at the same time (for example if you open windows recursively, or
- you use the multiple window technique described above to open more
- instances of one GUI), you might need to dynamically allocate the GUI
- description, because of the way dynamically computed values are
- put into static E lists. A GUI desciption with [] lists is static,
- i.e. only allocated once. Adding NEW to all of them is hard to deallocate,
- and this is where disposegui() comes in. To safely use this feature,
- allocate ALL lists belonging to the GUI desciption dynamically with
- NEW [...] (this does not include lists such as the one used for the
- various labels in CYCLE-gadgets).
-
- easygui('Bla',
- gui:=NEW [ROWS,
- NEW [STR,{str},'input:',s,50,4],
- NEW [CYCLE,{cycle},'choose:',['Yep','Nope',NIL],1]])
- disposegui(gui)
-
- Call disposegui() with the top-level list. on each gadget-list (i.e.
- NEW [CYCLE,...]) it will simply call FastDisposeList(), on COLS and
- ROWS etc. it will first deallocate each element recursively.
-
-
- Manipulating Gadgets
- --------------------
- [currently, this assumes you're using the DIY version of EasyGUI (as
- described under "multiple windows".]
- You might need to modify gadgets while a GUI is active, for example
- to set a slider when a corresponding integer gadget is modified by
- the user, or to change the contents of a listview.
-
- You can denote gadgets to change by simply storing their addresses,
- i.e.:
-
- [COLS,
- mygad:=[CHECK,....],
- ...
- ]
-
- Now you can use `mygad' with some of the functions below. Note that,
- of course `mygad' isn't a gadget, but it helps EasyGUI to find the
- real gadget.
-
- setscrollvisible(gh,gad,visible)
- setscrolltop(gh,gad,top)
- setscrolltotal(gh,gad,total)
- setlistvselected(gh,gad,active)
- setlistvlabels(gh,gad,labs)
- setinteger(gh,gad,new)
- setcycle(gh,gad,active)
- setmx(gh,gad,active)
- setstr(gh,gad,new)
- setslide(gh,gad,new)
- setcheck(gh,gad,bool)
-
- for all these: `gh' is the gui you're talking about (as returned from
- guiinit()), `gad' is a value that denotes the gadget as described above.
- the third value is whatever you're changing about the gadget. Note that
- in doing so, you need to respect usual restrictions on gadtools gadgets,
- for example setlistlables() requires that you first set it to -1, then
- modify the list, and put it back.
-
- realgadget:=findgadget(gh,list)
-
- allows you to find the gadget address, for all those modifications
- that aren't possible with the above set#? functions. It returns an intuition
- gadget structure. Note that preferably you will want to use the set#?
- functions, as these cooperate with EasyGUI very well (in keeping
- track of the current value, for example: setstr() also copies the new
- value to the estring you attached to the gadget).
-
-
- +---------------------------------------------------------------+
- | 5. bugs/future |
- +---------------------------------------------------------------+
-
- bugs:
- - method of displaying slider values not bulletproof
- - sometimes problems with finding correct size for gadgets with a
- lefttext in an EQROWS
-
- future:
- - implement render spaces for draw/edit purposes
- - implement gadgets with images on them
- - implement a BOOPSI door
- - easy blocking (for now, look at the JRH's RKRM intuition/requesters_alerts/
- blockinput.e if you need this)
-
-
-
- ----------------------------------------------------------------
-
- General advice: try out and modify the examples. Sometimes something won't work,
- but EasyGUI is flexible enough that at least one way of arranging groups etc.
- will give you a nice GUI :-). If you need more power than EasyGUI currently
- gives, you'll have to use MUI/BGUI/WhatEver instead.
-
- Wouter
-
-