bammi@cwruecmp.UUCP (Jwahar R. Bammi) (03/22/86)
#!/bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #!/bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # wind1.prf # wind2.prf # wind3.prf # This archive created: Fri Mar 21 22:40:48 1986 # By: Jwahar R. Bammi () export PATH; PATH=/bin:$PATH echo shar: extracting "'wind1.prf'" '(13142 characters)' if test -f 'wind1.prf' then echo shar: over-writing existing file "'wind1.prf'" fi sed 's/^X//' << \SHAR_EOF > 'wind1.prf' X.!**************************************************************************** X.! X.! ANTIC PUBLISHING INC., COPYRIGHT 1985. REPRINTED BY PERMISSION. X.! X.! ** Professional GEM ** by Tim Oren X.! X.! Proff File by ST enthusiasts at X.! Case Western Reserve University X.! Cleveland, Ohio X.! uucp : decvax!cwruecmp!bammi X.! csnet: bammi@case X.! arpa : bammi%case@csnet-relay X.! compuserve: 71515,155 X.! X.!**************************************************************************** X.! X.! X.!**************************************************************************** X.! X.! Begin Part I X.! X.!**************************************************************************** X.! X.PART I Windows X.SH IN THE BEGINNING XIn GEM, creating a window and displaying it are two different functions. The Xcreation function is called wind_create, and its calling sequence is: X.FB wind_create() Xhandle = wind_create(parts, xfull, yfull, wfull, hfull); X.FE XThis function asks GEM to reserve space in its memory for a new window Xdescription, and to return a code or "handle" which you can use to refer to the Xwindow in the future. Valid window handles are positive integers; they are not Xmemory pointers. X.PP XGEM can run out of window handles. If it does so, the value returned is Xnegative. Your code should always check for this situation and ask the Xprogram's user to close some windows and retry if possible. Handle zero is Xspecial. It refers to the "desktop", which is predefined as light green (or Xgray) on the ST. Window zero is always present and may be used, but never Xdeleted, by the programmer. X.PP XThe xfull, yfull, wfull, and hfull parameters are integers which determine Xthe maximum size of the window. Xfull and yfull define the upper left corner of Xthe window, and wfull and hfull specify its width and height. (Note that all of Xthe window coordinates which we use are in pixel units.) X.PP XGEM saves these values so that the program can get them later when processing XFULL requests. Usually the best maximum size for a window is the entire Xdesktop area, excepting the menu bar. You can find this by asking wind_get for Xthe working area of the desktop (handle zero, remember): X.FB wind_get() Xwind_get(0, WF_WXYWH, &xfull, &yfull, &wfull, &hfull); X.FE XNote that WF_WXYWH, and all of the other mnemonics used in this article, are Xdefined in the GEMDEFS.H file in the ST Toolkit. X.PP XThe parts parameter of wind_create defines what features will be included in Xthe window when it is drawn. It is a word of single bit flags which indicate Xthe presence/absence of each feature. To request multiple features, the flags Xare "or-ed" together. The flags' mnemonics and meanings are: X.BO XNAME - A one character high title bar at the top of the window. X.EO X.BO XINFO - A second character line below the NAME. X.EO X.BO XMOVER - This lets the user move the window around by "dragging" in the NAME Xarea. NAME also needs to be defined. X.EO X.BO XCLOSER - A square box at the upper left. Clicking this control point asks Xthat the window be removed from the screen. X.EO X.BO XFULLER - A diamond at upper right. Clicking this control point requests Xthat the window grow to its maximum size, or shrink back down if it is already Xbig. X.EO X.BO XSIZER - An arrow at bottom right. Dragging the SIZER lets the user choose Xa new size for the window. X.EO X.BO XVSLIDE - defines a right-hand scroll box and bar for the window. By dragging Xthe scroll bar, the user requests that the window's "viewport" into the Xinformation be moved. Clicking on the gray box above the bar requests that Xthe window be moved up one "page". Clicking below the bar requests a down page Xmovement. You have to define what constitutes a page or line in the Xcontext of your application. X.EO X.BO XUPARROW - An arrow above the right scroll bar. Clicking here requests that Xthe window be moved up one "line". Sliders and arrows almost always appear Xtogether. X.EO X.BO XDNARROW - An arrow below the right scroll bar. Requests that window be Xmoved down a line. X.EO X.BO XHSLIDE - These features are the horizontal equivalent of the RTARROW Xabove. They appear at the bottom of the window. Arrows LFARROW usually Xindicate "character" sized movement left and right. "Page" sized Xmovement has to be defined by each application. X.EO X.PP XIt is important to understand the correspondence between window features and Xevent messages which are sent to the application by the GEM window manager. If Xa feature is not included in a window's creation, the user cannot perform the Xcorresponding action, and your application will never receive the matching Xmessage type. For example, a window without a MOVER may not be dragged by the Xuser, and your app will never get a WM_MOVED message for that window. X.PP XAnother important principle is that the application itself is responsible for Ximplementing the user's window action request when a message is received. This Xgives the application a chance to accept, modify, or reject the user's request. X.PP XAs an example, if a WM_MOVED message is received, it indicates that the user Xhas dragged the window. You might want to byte or word align the requested Xposition before proceeding to move the window. The wind_set calls used to Xperform the actual movements will be described in the next article. X.SH OPEN, SESAME! XThe wind_open call is used to actually make the window appear Xon the screen. It animates a "zoom box" on the screen and then draws in the Xwindow's frame. The calling sequence is: X.FB wind_open() Xwind_open(handle, x, y, w, h); X.FE XThe handle is the one returned by wind_create. Parameters x, y, w, and h Xdefine the initial location and size of the window. Note that these Xmeasurements INCLUDE all of the window frame parts which you have requested. To Xfind out the size of the area inside the frame, you can use X.FB wind_get() Xwind_get(handle, WF_WXYWH, &inner_x, &inner_y, &inner_w, &inner_h); X.FE XWhatever size you choose for the window display, it cannot be any larger than Xthe full size declared in wind_create. X.PP XHere is a good place to take note of a useful utility for calculating window Xsizes. If you know the "parts list" for a window, and its inner or outer size, Xyou can find the other size with the wind_calc call: X.FB wind_calc() Xwind_calc(parts, kind, input_x, input_y, input_w, input_h, &output_x, X&output_y, &output_w, &output_h); X.FE XKind is set to zero if the input coordinates are the inner area, and you are Xcalculating the outer size. Kind is one if the inputs are the outer size and Xyou want the equivalent inner size. Parts are just the same as in wind_create. X.PP XThere is one common bug in using wind_open. If the NAME feature is Xspecified, then the window title must be initialized BEFORE opening the window: X.FB wind_set() Xwind_set(handle, WF_NAME, ADDR(title), 0, 0); X.FE XIf you don't do this, you may get gibberish in the NAME area or the system Xmay crash. Likewise, if you have specified the INFO feature, you must make a Xwind_set call for WF_INFO before opening the window. X.PP XNote that ADDR() specifies the 32-bit address of title. This expression is Xportable to other (Intel-based) GEM systems. If you don't care about Xportability, then &title[0], or just title alone will work fine on the ST. X.SH CLEANING UP XWhen you are done with a window, it should be closed and Xdeleted. The call X.FB wind_close() Xwind_close(handle); X.FE Xtakes the window off the screen, redraws the desktop underneath it, Xand animates a "zoom down" box. It doesn't delete the window's Xdefinition, so you can reopen it later. X.PP XDeleting the window removes its definition from the system, and makes that Xhandle available for reuse. Always close windows before deleting, or you may Xleave a "dead" picture on the screen. Also be sure to delete all of your Xwindows before ending the program, or your app may "eat" window handles. The Xsyntax for deleting a window is: X.FB wind_delete() Xwind_delete(handle); X.FE X.SH THOSE FAT SLIDERS XOne of ST GEM's unique features is the proportional Xslider bar. Unlike other windowing systems, this type of bar gives visual Xfeedback on the fraction of a document which is being viewed, as well as the Xposition within the document. The catch, of course, is that you have two Xvariables to maintain for each scroll bar: size and position. X.PP XBoth bar size and position range from 1 to 1000. A bar size of 1000 fills Xthe slide box, and a value of one gets the minimum bar size. To compute the Xproper size, you can use the formula: X.br X.sp 1 X.ce 1 Xsize = min(1000, 1000 * seen_doc / total_doc) X.br X.sp 1 XSeen_doc and total_doc are the visible and total size of the document Xrespectively, in whatever units are appropriate. As an example, if your window Xcould show 20 lines of a 100 line text file, you should set a slider size of X200. Since the window might be bigger than the total document at some points, Xyou need the maximum function. If the document size is zero, force the slider Xsize to 1000. (Note: You will probably need to do the computation above with X32-bit arithmetic to avoid overflow problems). X.PP XOnce you have computed the size, use the wind_set function to configure the Xscroll bar: X.FB wind_set() Xwind_set(handle, WF_VSLSIZE, size, 0, 0, 0); X.FE XThis call sets the vertical (right hand) scroll bar. Use WF_HSLSIZE for the Xhorizontal scroller. All of these examples are done for the vertical Xdimension, but the principles are identical in the other direction. X.PP XBar positioning is a little tougher. The most confusing aspect is that the X1-1000 range does not set an absolute position of the bar within the Xscroll box. Instead, it positions the TOP of the bar within its Xpossible range of variation. X.PP XLet's look at our text file example again to make this clearer. If there are Xalways 20 lines of a 100 line file visible, then the top of the window must be Xalways be somewhere between line 1 and line 81. This 80 line range is Xthe actual freedom of movement of the window. So, if the window were Xactually positioned with its top at line 61, it would be at the Xthree-quarter position within the range, and we should set a scroll Xbar position of 750. The actual formula for computing the position is: X.sp 1 X.ce 1 Xpos = 1000 * (top_wind - top_doc) / (total_doc - seen_doc) X.sp 1 XTop_wind and top_doc are the top line in the current window and the whole Xdocument, respectively. Obviously, if seen_doc is greater or equal to Xtotal_doc, you need to force a zero value for pos. This calculation may seem Xrather convoluted the first time through, but is easy once you have done it. XWhen you have computed the position, wind_set configures the scroll bar: X.FB wind_set() Xwind_set(handle, WF_VSLIDE, pos, 0, 0, 0); X.FE X.sp 1 X.ce 1 XWF_HSLIDE is the equivalent for horizontal scrolling. X.sp 1 XIt is a good practice to avoid setting the slider size or position if they Xare already at the value which you need. This avoids an annoying redraw flash Xon the screen when it is not necessary. You can check on the current Xvalue of a slider parameter with wind_get: X.FB wind_get() Xwind_get(handle, WF_VSLIDE, &curr_value, &foo, &foo, &foo); X.FE XFoo is a dummy variable which needs to be there, but is not used. Substitute XWF_VSLIDE with whatever parameter you are checking. X.PP XOne philosophical note on the use of sliders: It is probably best to avoid Xthe use of both sliders at once unless it is clearly appropriate to the type of Xdata which is being viewed. X.PP XSince Write and Paint programs make use of the sheet-of-paper metaphor, Xmoving the window around in both dimensions is reasonable. However, if the data Xis more randomly organized, such as a tableau of icons, then it is probably Xbetter to only scroll in the vertical dimension and "reshuffle" if Xthe window's width is changed. Then the user only needs to manipulate Xone control to find information which is off-screen. Anyone who has Xhad trouble finding a file or folder within a Desktop window will Xrecognize this problem. X.SH COMING UP NEXT XIn my next column in Antic Online, we'll conclude the tour of the ST's Xwindowing system. I'll discuss the correct way to redraw a window's contents, Xand how to handle the various messages which an application receives from the Xwindow manager. Finally, we'll look at a way to redesign the desktop Xbackground to your own specifications. X.SH FEEDBACK XOne of the beauties of an on-line column is that you can make your comments Xknown immediately. To register your opinions, select ST FEEDBACK, enter your Xmessage, leave your name, and enter a blank line to exit. X.PP XI am interested in hearing proposals for topics, feedback on the technical Xlevel of the column, and reports on bugs and other "features" in both Xthe column and the ST itself. Your comments will be read by the ANTIC Xstaff and myself and, though we might not answer individual questions, Xthey will be used to steer the course of future columns. X.! X.! X.!***************************************************************************** X.!* * X.!* End Part 1 * X.!* * X.!***************************************************************************** SHAR_EOF if test 13142 -ne "`wc -c 'wind1.prf'`" then echo shar: error transmitting "'wind1.prf'" '(should have been 13142 characters)' fi echo shar: extracting "'wind2.prf'" '(20216 characters)' if test -f 'wind2.prf' then echo shar: over-writing existing file "'wind2.prf'" fi sed 's/^X//' << \SHAR_EOF > 'wind2.prf' X.!**************************************************************************** X.! X.! ANTIC PUBLISHING INC., COPYRIGHT 1985. REPRINTED BY PERMISSION. X.! X.! ** Professional GEM ** by Tim Oren X.! X.! Proff File by ST enthusiasts at X.! Case Western Reserve University X.! Cleveland, Ohio X.! uucp : decvax!cwruecmp!bammi X.! csnet: bammi@case X.! arpa : bammi%case@csnet-relay X.! compuserve: 71515,155 X.! X.!**************************************************************************** X.! X.! X.!**************************************************************************** X.! X.! Begin Part 2 X.! X.!**************************************************************************** X.! X.PART II Windows X.SH EXCELSIOR XIn this installment, we continue the exploration of GEM's window manager by Xfinding out how to process the messages received by an application Xwhen it has a window defined on the screen. X.PP XAlso, beginning with this column, sample C code demonstrating the techniques Xdiscussed will be available on SIG*ATARI in DL5. This will allow you to Xdownload the code without interference by the CIS text-formatter used by ANTIC XONLINE output. X.PP XThe file for this column is GEMCL2.XMO. All references to non-GEM routines in Xthis column refer to this file. Please note that these files will not contain Xentire programs. Instead, they consist of small pieces of utility code which Xyou may copy and modify in your own programs. X.SH REDRAWING WINDOWS XOne of the most misunderstood parts of GEM is the correct method for drawing Xwithin a window. Most requests for redrawing are generated by the GEM system, Xand arrive as messages (read with evnt_multi) which contain the handle of the Xwindow, and the screen rectangle which is "dirty" and needs to be redrawn. X.PP XScreen areas may become dirty as a result of windows being closed, sized down, Xor moved, thus "exposing" an area underneath. The completion of a dialog, or Xclosing of a desk accessory may also free up a screen area which needs to be Xredrawn. When GEM detects the presence of a dirty rectangle, it checks its Xlist of open windows, and sends the application a redraw message for each of Xits windows which intersects the dirty area. X.SH CAVEAT EMPTOR XGEM does not "clip" the rectangle which it sends to the application; that is, Xthe rectangle may not lie entirely within the portion of the window which is Xexposed on the screen. It is the job of the application to determine in what Xportion of the rectangle it may safely draw. This is done by examining the X"rectangle list" associated with the window. X.PP XA rectangle list is maintained by GEM for each active window. It contains the Xportions of the window's interior which are exposed, i.e., topmost, on the Xscreen and within which the app may draw. X.PP XLet's consider an example to make this clear. Suppose an app has opened two Xwindows, and there are no desk accessory windows open. The window which is Xtopmost will always have only one rectangle in its list. If the two are Xseparate on the screen, then the second window will also have one rectangle. XIf they overlap, then the top window will "break" the rectangle of the bottom Xone. If the overlap is at a corner, two rectangles will be generated for the Xbottom window. If the overlap is on a side only, then three rectangles are Xrequired to cover the exposed portion of the bottom window. Finally, if the Xfirst window is entirely within the second, it requires four rectangles in the Xlist to tile the second window. X.PP XTry working out a few rectangle examples with pencil and paper to get the feel Xof it. You will see that the possible combinations with more than two windows Xare enormous. This, by the way, is the reason that GEM does not send one Xmessage for each rectangle on the list: With multiple windows, the number of Xmessages generated would quickly fill up the application's message queue. X.PP XFinally, note that every app MUST use this method, even if it only Xuses a single window, because there may be desk accessories with their Xown windows in the system at the same time. If you do not use the Xrectangle lists, you may overwrite an accessory's window. X.SH INTO THE BITS XFirst, we should note that the message type for a redraw request is WM_REDRAW, Xwhich is stored in msg[0], the first location of the message returned by Xevnt_multi. The window handle is stored in msg[3]. These locations are the Xsame for all of the message types being discuss. The rectangle which needs to Xbe redrawn is stored in msg[4] through msg[7]. X.PP XNow let's examine the sample redraw code in more detail. The redraw loop is Xbracketed with mouse off and mouse on calls. If you forget to do this, the Xmouse pointer will be over-written if it is within the window and the next Xmovement of the mouse will leave a rectangular blotch on the screen as a piece Xof the "old" screen is incorrectly restored. X.PP XThe other necessary step is to set the window update flag. This prevents the Xmenu manager from dropping a menu on top of the screen portion being redrawn. XYou must release this flag at the end of the redraw, or the you will be unable Xto use any menus afterwards. X.PP XThe window rectangles are retrieved using a get-first, get-next scheme which Xwill be familiar if you have used the GEM DOS or PC-DOS wildcard file calls. XThe end of the rectangle list has been reached when both the width and height Xreturned are zero. Since some part of a window might be off-screen X(unless you have clamped its position - see below), the retrieved Xrectangle is intersected with the desktop's area, and then with the Xscreen area for which a redraw was requested. X.PP XNow you have the particular area of the screen in which it is legal to draw. XUnless there is only one window in your application, you will have to test the Xhandle in the redraw request to figure out what to put in the rectangle. X.PP XDepending on the app, you may be drawing an AES object tree, or executing VDI Xcalls, or some combination of the two. In the AES case, the computed Xrectangle is used to specify the bounds of the objc_draw. For VDI Xwork, the rectangle is used to set the clipping area before executing Xthe VDI calls. X.SH A SMALL CONFESSION XAt the beginning of this discussion, I deliberately omitted one class of Xredraws: those initiated by the application itself. XIn some cases a part of the screen must be redrawn immediately to give feedback Xto the user following a keystroke, button, or mouse action. In these cases, Xthe application could call do_redraw directly, without waiting for a message. X.PP XThe only time you can bypass do_redraw, and draw without walking the rectangle Xlist, is when you can be sure that the target window is on top, and that the Xfigure being drawn is entirely contained within it. X.PP XIn many cases, however, an application initiated redraw happens because of a Xcomputed change, for instance, a spreadsheet update, and its timing is not Xcrucial. In this instance, you may wish to have the app send ITSELF a redraw Xrequest. X.PP XThe main advantage of this approach is that the AES is smart enough to see if Xthere is already a redraw request for the same window in the queue, and, if so, Xto merge the requests by doing a union of their rectangles. In this fashion, Xthe "blinky" appearance of multiple redraws is avoided, without the need to Xinclude logic for merging redraws within the program. XA utility routine for sending the "self-redraw" is included in the Xdown-load for this article. X.SH WINDOW CONTROL REQUESTS XAn application is notified by the AES, via the message system, when the user Xmanipulates one of the window control points. Remember that you must have Xspecified each control point when the window was created, or will not receive Xthe associated control message. X.PP XThe most important thing to understand about window control is that the change Xwhich the user requested does not take place until the application forwards it Xto the AES. While this makes for a little extra work, it gives the program a Xchance to intervene and validate or modify the request to suit. X.PP XA second thing to keep in mind is that not all window updates cause a redraw Xrequest to be generated for the window, because the AES attempts to save time Xwith raster moves on the screen. XNow let's look at each window control request in detail. The message Xcode for a window move is WM_MOVED. If you are willing to accept any Xsuch request, just do: X.FB wind_set() Xwind_set(wh, WF_CXYWH, msg[4], msg[5], msg[6], msg[7]); X.FE X.sp 1 X.ce 1 X(Remember that wh, the window handle, is always in msg[3]). X.sp 1 XThe AES will not request a redraw of the window following this call, unless the Xwindow is being moved from a location which is partially "off-screen". Instead, Xit will do a "blit" (raster copy) of the window and its contents to the new Xlocation without intervention by the app. X.PP XThere are two constraints which you may often wish to apply to the user's move Xrequest. The first is to force the new location to lie entirely within the Xdesktop, rather than partially off-screen. You can do this with the Xrc_constrain utility by executing: X.FB rc_constrain() Xrc_constrain(&full, &msg[4]); X.FE Xbefore making the wind_set call. (Full is assumed to contain the desktop Xdimensions.) X.PP XThe second common constraint is to "snap" the x-dimension location of the new Xlocation to a word boundary. This operation will speed up GEM's "blit" because Xno shifting or masking will need to be done when moving the window. To perform Xthis operation, use align() before the wind_set call: X.FB align() Xmsg[4] = align(msg[4], 16); X.FE XThe message code for a window size request is WM_SIZED. Again, if you are Xwilling to accept any request, you can just "turn it around" with the same Xwind_set call as given for WM_MOVED. X.PP XActually, GEM enforces a couple of constraints on sizing. First, the Xwindow may not be sized off screen. Second, there is a minimum window Xsize which is dependent on the window components specified when it was Xcreated. This prevents features like scroll arrows from being Xsqueezed into oblivion. The most common application constraint on Xsizing is to snap the size to horizontal words (as above) and/or Xvertical character lines. In the latter case, the vertical dimension Xof the output font is used with align(). X.PP XAlso, be aware that the size message which you receive specifies the XEXTERNAL dimensions of the window. To assure an "even" size for the XINTERNAL dimensions, you must make a wind_calc call to compute them, Xuse align() on the computed values, back out the corresponding Xexternal dimensions with the reverse wind_calc, and then make the Xwind_set call with this set of values. X.PP XA window resize will only cause a redraw request for the window if the size is Xbeing increased in at least one dimension. This is satisfactory for most Xapplications, but if you must "reshuffle" the window after a size-down, you Xshould send yourself a redraw (as described above) after you make the wind_set Xcall. This will guarantee that the display is updated correctly. Also note Xthat the sizing or movement of one window may cause redraw requests to be Xgenerated for other windows which are uncovered by the change. X.PP XThe window full request, with code WM_FULLED, is actually a toggle. If the Xwindow is already at its full size (as specified in the wind_create), then this Xis a request to shrink to its previous size. If the window is currently small, Xthen the request is to grow to full size. X.PP XSince the AES records the current, previous, and maximum window size, Xyou can use wind_get calls to determine which situation pertains. The Xhndl_full utility in the down-load (modified from Doodle), shows how Xto do this. X.PP XThe "zoom box" effects when changing size are optional, and can be removed to Xspeed things up. Again, if the window's size is decreasing, no redraw is Xgenerated, so you must send yourself one if necessary. You should not have to Xperform any constraint or "snap" operations here, since (presumably) the full Xand previous sizes have had these checks applied to them already. X.PP XThe WM_CLOSED message is received when the close box is clicked. What Xaction you perform depends on the application. If you want to remove Xthe window, use wind_close as described in the last column. In many Xapplications, however, the close message may indicate that a file is Xto be saved, or a directory or editing level is to be closed. In Xthese cases, the message is used to trigger this action before or Xinstead of the wind_close. (Folders on the Desktop are an example of Xthis situation.) X.PP XThe WM_TOPPED message indicates that the AES wants to bring the Xindicated window to the "top" and make it active. This happens if the Xuser clicks within a window which is not on top, or if the currently Xtopped window is closed by its application or desk accessory. XNormally, the application should respond to this message with: X.FB wind_set() Xwind_set(wh, WF_TOP, 0, 0); X.FE Xand allow the process to complete. X.PP XIn a few instances, a window may be used in an output only mode, such as a Xstatus display, with at least one other window present for input. In Xthis case, a WM_TOPPED message for the status window may be ignored. XIn all other cases, you must handle the WM_TOPPED message even if your Xapplication has only one window: Invocation of a desk accessory could Xalways place another window on top. If you fail to do so, subsequent Xredraws for your window may not be processed correctly. X.SH WINDOW SLIDER MESSAGES XIf you specify all of the slider bar parts for your window, you may receive up Xto five different message types for each of the two sets of sliders. To Xsimplify things a little, I will discuss everything in terms of the vertical X(right hand side) sliders. If you are also using the horizontal sliders, the Xsame techniques will work, just use the alternate mnemonics. X.PP XThe WM_VSLID message indicates that the user has dragged the slider bar within Xits box, indicating a new relative position within the document. XAlong with the window handle, this message includes the relative Xposition between 1 and 1000 in msg[4]. X.PP XRecall from last column's discussion that this interval corresponds to the X"freedom of movement" of the slider. If you want to accept the user's request, Xjust make the call: X.FB wind_set Xwind_set(wh, WF_VSLIDE, msg[4], 0, 0, 0); X.FE X.sp 1 X.ce 1 X(Corresponding horizontal mnemonics are WM_HSLID and WF_HSLIDE). X.sp 1 XNote that this wind_set call will not cause a redraw message to be sent. You Xmust update the display to reflect the new scrolled position, either by Xexecuting a redraw directly, or by sending yourself a message. X.PP XIf the document within the window has some structure, you may not wish Xto accept all slider positions. Instead you may want to force the Xscroll position to the nearest text line (for instance). Using terms Xdefined in the last column, you may convert the slider position to X"document units" with: X.sp 1 X.ce 1 Xtop_wind = msg[4] * (total_doc - seen_doc) / 1000 + top_doc X.sp 1 X.ce 1 X(This will probably require 32-bit arithmetic). X.sp 1 XAfter rounding off or otherwise modifying the request, convert it back Xto slider units and make the WF_VSLIDE request. X.PP XThe other four slider requests all share one message code: WM_ARROWED. XThey are distinguished by sub-codes stored in msg[4]: WA_UPPAGE, XWA_DNPAGE, WA_UPLINE, and WA_DNLINE. These are produced by clicking Xabove and below the slider, and on the up and down arrows, Xrespectively. (I have no idea why sub-codes were used in this one Xinstance.) The corresponding horizontal slider codes are: XWA_LFPAGE, WA_RTPAGE, WA_LFLINE, and WA_RTLINE. X.PP XWhat interpretation you give to these requests will depend on the application. XIn the most common instance, text documents, the customary method is to change Xthe top of window position (top_wind) by one line for a WA_UPLINE or XWA_DNLINE, and by seen_doc (the number of lines in the window) for a XWA_UPPAGE or WA_DNPAGE. X.PP XAfter making the change, compute a new slider position, and make the wind_set Xcall as given above. If the document's length is not an even multiple of X"lines" or "pages" you will have to be careful that incrementing or Xdecrementing top_wind does not exceed its range of freedom: top_doc to (top_doc X+ total_doc - seen_doc). X.PP XIf you have such an odd size document, you will also have to make a decision on Xwhether to violate the line positioning rule so that the slider may be put at Xits bottom-most position, or to follow the rule but make it impossible to get Xthe slider to the extreme of its range. X.SH A COMMON BUG XIt is easy to forget that user clicks are not the only things that Xaffect slider position. If the window size changes as a result of a XWM_SIZED or WM_FULLED message, the app must also update its sliders X(if they are present). This is a good reason to keep the top of Xwindow information in "document units". X.PP XYou can just redo the position calculation with the new "seen_doc" value, and Xcall wind_set. Also remember that changing the size of the Xunderlying document (adding or deleting a bottom line, for instance) Xmust also cause the sliders to be adjusted. X.SH DEPT. OF DIRTY TRICKS XThere are two remaining window calls which are useful to advanced programmers. XThey require techniques which I have not yet discussed, so you may need to file Xthem for future reference. X.PP XThe AES maintains a quarter-screen sized buffer which is used to save the area Xunder alerts and menu drop-downs. It is occasionally useful for the Xapplication to gain access to this buffer for its own use in saving Xscreen areas with raster copies. To do so, use: X.FB wind_get() Xwind_get(0, WF_SCREEN, &loaddr, &hiaddr, &lolen, &hilen); X.FE XHiaddr and loaddr are the top and bottom 16-bits (respectively) of the 32-bit Xaddress of the buffer. Hilen and lolen are the two halves of its length. X.PP XDue to a preculiarity of the binding you have to reassemble these Xpieces before using them. (The actual value of WF_SCREEN is 17; this Xdoes not appear in some versions of the GEMDEFS.H file.) X.PP XIf you use this buffer, you MUST prevent menus from dropping down by using Xeither the BEG_UPDATE or BEG_MCTRL wind_update calls. Failure to do so will Xresult in your data being destroyed. Remember to use the matching wind_update: XEND_UPDATE or END_MCTRL, when you are done. X.PP XThe other useful call enables you to replace the system's desktop definition Xwith a resource of your choosing. The call: X.FB wind_set() Xwind_set(0, WF_NEWDESK, tree, 0, 0); X.FE Xwhere tree is the 32-bit address of the object tree, will cause the AES to draw Xyour definition instead of the usual gray or green background. Not Xonly that, it will continue to redraw this tree with no intervention Xon your part. X.PP XObviously, the new definition must be carefully built to fit the desktop area Xexactly or garbage will be left around the edges. For the truly sophisticated, Xa user-defined object could be used in this tree, with the result that your Xapplication's code would be entered from the AES whenever the desktop was Xredrawn. This would allow you to put VDI pictures or complex images onto the Xdesktop background. X.SH A SIN OF OMISSION XIn the last column, I neglected to mention that strings whose addresses are Xpassed in the WF_NAME and WF_INFO wind_set calls must be allocated in a static Xdata area. Since the AES remembers the addresses (not the characters), a Xdisaster may result if the storage has been reused when the window manager next Xattempts to draw the window title area. X.SH COMING SOON XThis concludes our tour of GEM's basic window management techniques. There have Xbeen some unavoidable glimpses of paths not yet taken (forward references), but Xwe will return in time. X.PP XOn our next excursion, we will take a look at techniques for handling simple Xdialog boxes, and start exploring the mysteries of resources and object trees. X.! X.! X.!***************************************************************************** X.!* * X.!* End Part 2 * X.!* * X.!***************************************************************************** SHAR_EOF if test 20216 -ne "`wc -c 'wind2.prf'`" then echo shar: error transmitting "'wind2.prf'" '(should have been 20216 characters)' fi echo shar: extracting "'wind3.prf'" '(16916 characters)' if test -f 'wind3.prf' then echo shar: over-writing existing file "'wind3.prf'" fi sed 's/^X//' << \SHAR_EOF > 'wind3.prf' X.!**************************************************************************** X.! X.! ANTIC PUBLISHING INC., COPYRIGHT 1985. REPRINTED BY PERMISSION. X.! X.! ** Professional GEM ** by Tim Oren X.! X.! Proff File by ST enthusiasts at X.! Case Western Reserve University X.! Cleveland, Ohio X.! uucp : decvax!cwruecmp!bammi X.! csnet: bammi@case X.! arpa : bammi%case@csnet-relay X.! compuserve: 71515,155 X.! X.!**************************************************************************** X.! X.! X.!**************************************************************************** X.! X.! Begin Part 3 X.! X.!**************************************************************************** X.! X.PART III THE DIALOG HANDLER X.SH A MEANINGFUL DIALOG XThis issue of ST PRO GEM begins an exploration of ST GEM's dialog handler. I Xwill discuss basic system calls for presenting the dialog, and then continue Xwith techniques for initializing and reading on/off button and "radio" button Xobjects. We will also take some short side-trips into the operation Xof the GEM Resource Construction Set to assist you in building these dialogs. X.PP XThere are a number of short C routines which accompany this column. These are Xstored as file GEMCL3.XMO in DL 5 on SIG*ATARI. Before reading this column, you Xshould visit SIG*ATARI (go pcs-132) and download this file. X.PP X.SH DEFINING TERMS XA dialog box is an "interactive form" in which the user may enter text and Xindicate selections by pointing with the mouse. Dialogs in GEM are X"modal", that is, when a dialog is activated other screen functions Xsuch as menus and window controls are suspended until the dialog is completed. X.PP XIn most cases, the visual structure of a GEM dialog is specified within your Xapplication's resource file. The GEM Resource Construction Set (RCS) Xis used to build a picture of the dialog. X.PP XWhen the RCS writes out a resource, it converts that picture into a tree of XGEM drawing objects and stores this data structure within the resource. Before Xyour application can display the dialog, it must load this resource file and Xfind the address of the tree which defines the dialog. X.PP XTo load a resource, the AES checks its size and allocates memory for the Xload. It then reads in the resource, adjusting internal pointers to Xreflect the load address. Finally, the object sizes stored in the Xresource are converted from characters to pixels using the system font size. X.PP XA note for those with Macintosh experience: Although Mac and GEM resources Xshare a name, there are fundamental differences which can be misleading. A Mac Xresource is a fork within a file; a GEM resource is a TOS file by itself. Mac Xresources may be paged in and out of memory; GEM resources are monolithic. GEM Xresources are internally tree structured; Mac resources are not. Finally, Mac Xresources include font information, while ST GEM does this with font loading at Xthe VDI level. X.PP XThe resource load is done with the GEM AES call: X.FB rsrc_load() Xok = rsrc_load(ADDR("MYAPP.RSC")); X.FE X"MYAPP" should be replaced with the name of your program. Resources Xconventionally have the same primary name as their application, with the RSC Xextent name instead of PRG. The ok flag returned by rsrc_load will be FALSE is Xanything went wrong during the load. X.PP XThe most common causes of failure are the resource not being in the Xapplication's subdirectory, or lack of sufficient memory for GEM to allocate Xspace for the resource. If this happens, you must terminate the program Ximmediately. X.PP XOnce you have loaded the resource, you find the address of a dialog's object Xtree with: X.FB rsrc_gaddr() Xrsrc_gaddr(R_TREE, MYDIALOG, &tree); X.FE XTree is a 32-bit variable which will receive the address of the root Xnode of the tree. X.PP XThe mnemonic MYDIALOG should be replaced with the name you gave your dialog Xwhen defining it in the RCS. At the same time that it writes the resource, RCS Xgenerates a corresponding .H file containing tree and object names. XIn order to use these mnemonics within your program, you must include Xthe name file in your compile: #include "MYAPP.H" X.SH BUG ALERT! XWhen using the DRI/Alcyon C compiler, .H files must be in the compiler's home Xdirectory or they will not be found. This is especially annoying using a two Xfloppy drive ST development system. The only way around this is to explicitly Xreference an alternate disk in the #include, for instance: "B:MYAPP.H". X[Ed. Note: Use the -i flag with the C pre-processor to name the include Xdirectories]. X.PP XNow that the address of the dialog tree has been found, you are ready to Xdisplay it. The standard (and minimal) sequence for doing so is given in Xroutine hndl_dial() in the download. We will now walk through each Xstep in this procedure. X.PP XThe form_center call establishes the location of the dialog on the screen. XDialog trees generated by the RCS have an undefined origin (upper-left corner). X.PP XForm_center computes the upper-left location necessary to center the dialog Xon the screen, and inserts it into the OB_X and OB_Y fields of the ROOT object Xof the tree. It also computes the screen rectangle which the dialog Xwill occupy on screen and writes its pixel coordinates into variables Xxdial, ydial, wdial, and hdial. X.PP XThere is one peculiarity of form_center which occasionally causes trouble. XNormally the rectangle returned in xdial, etc., is exactly the same size as the Xbasic dialog box. X.PP XHowever, when the OUTLINED enhancement has been specified for the box, Xform_center adds a three pixel margin to the rectangle returned. This Xcauses the screen area under the outline to be correctly redrawn later X(see below). Note that OUTLINED is part of the standard dialog box in Xthe RCS. Other enhancements, such as SHADOWED or "outside" borders Xare NOT handled in this fashion, and you must compensate for them in Xyour code. X.PP XThe next part of the sequence is a form_dial call with a zero parameter. XThis reserves the screen for the dialog action about to occur. Note that the C Xbinding given for form_dial in the DRI documents is in error: there are nine Xparameters, not five. The first set of xywh arguments is actually used with Xform_dial calls 1 and 2 only, but place holders must be supplied in all cases. X.PP XThe succeeding form_dial call (parameter one) animates a "zoom box" on the Xscreen which moves and grows from the first screen rectangle given to Xthe second rectangle, where the dialog will be displayed. X.PP XThe use of this call is entirely optional. In choosing whether to use it or Xnot, you should consider whether the origin of the "zoom" is relevant to the Xoperation. For instance, a zoom from the menu bar is relatively meaningless, Xwhile a zoom from an object about to be edited in the dialog provides visual Xfeedback to the user, showing whether the correct object was chosen. X.PP XIf the origin is not relevant, then the zoom is just a time-waster. If you Xdecide to include these effects, consider a "preferences" option in your app Xwhich will allow the experienced and jaded user to turn them off in the Xinterests of speed. X.PP XThe objc_draw call actually displays the dialog on the screen. Note that the Xaddress of the tree, the beginning drawing object, and the drawing depth are Xpassed as arguments, as well as the rectangle allotted for the dialog. X.PP XIn general, dialogs (and parts of dialogs) are ALWAYS drawn beginning at the XROOT (object zero). When you want to draw only a portion of the Xdialog, adjust the clipping rectangle, but not the object number. XThis ensures that the background of the dialog is always drawn correctly. X.PP XThe objc_xywh() utility in the download can be used to find the clipping Xrectangle for any object within a dialog, though you may have to allow an extra Xmargin is you have used shadows, outlines, or outside borders with the object. X.PP XCalling form_do transfers control to the AES, which animates the dialog for Xuser interaction. The address of the dialog tree is passed as a Xparameter. The second paramter is the number of the editable object Xat which the text cursor will first be positioned. If you have no text Xfields, pass a zero. Note that again the DRI documents are in error: Xpassing a -1 default may crash the system. Also be careful that the Xdefault which you specify is actually a text field; no error checking Xis performed. X.PP XThe form_do call returns the number of the object on which the clicked to Xterminate the dialog. Usually this is a button type object with the EXIT and XSELECTABLE attributes set. Setting the DEFAULT attribute as well will cause an Xexit on that object is a carriage return is struck while in the dialog. X.PP XIf the top bit of the return is set, it indicates that the exit object had Xthe TOUCHEXIT attribute and was selected with a double-click. Since very few Xdialogs use this combination, the sample code simply masks off the top bit. X.PP XThe next form_dial call reverses the "zoom box", moving it from the dialog's Xlocation back to the given x,y,w,h. The same cautions apply here as above. X.PP XThe final form_dial call tells GEM that the dialog is complete, and that the Xscreen area occupied by the dialog is now considered "dirty" and needs to be Xredrawn. Using the methods described in our last column, GEM then Xsends redraws to all windows which were overlaid, and does any Xnecessary redrawing of the menu or desktop itself. X.PP XThere is one notable "feature" of form_dial(3): It always redraws an area Xwhich is two pixels wider and higher than your request! This was probably Xincluded to make sure that drop-shadows were cleaned up, and is usually Xinnocuous. X.SH A HANDY TRICK XUse of the form_dial(3) call is not limited to dialogs. You can use Xit to force the system to redraw any part of the screen. The Xadvantage of this method is that the redraw area need not lie entirely Xwithin a window, as was necessary with the send_redraw method detailed Xin the last column. A disadvantage is that this method is somewhat Xslower, since the AES has to decide who gets the redraws. X.SH CLEAN UP XAs a last step, you need to clear the SELECTED flag in the object which was Xclicked. If you do not do this, the object will be drawn inverted the next Xtime you call the dialog. You could clear the flag with the GEM objc_change Xcall, but it is inefficient since you do not need to redraw the object. X.PP XInstead, use the desel_obj() code in the download, which modifies the Xobject's OB_STATE field directly. Assuming that ret_obj contains the exit Xobject returned by hndl_dial, the call: X.FB desel_obj() Xdesel_obj(tree, ret_obj); X.FE Xwill do the trick. X.SH RECAP XThe basic dialog handling method I have described contains three steps: Xinitialization (rsrc_gaddr), dialog presentation (hndl_dial), and cleanup X(desel_obj). X.PP XAs we build more advanced dialogs, these same basic steps will be performed, Xbut they will grow more complex. The initialization will include setting up Xproper object text and states, and the cleanup phase will also interrogate the Xfinal states of objects to find out what the user did. X.SH BUTTON, BUTTON XThe simple dialogs described above contain only exit buttons as active objects. XAs such, they are little more than glorified alert boxes. X.PP XWe will now increase the complexity a little by considering non-exit buttons. XThese are constructed by setting the SELECTABLE attribute on a button object. XAt run-time, such an object will toggle its state between selected X(highlighted) and non-selected whenever the user clicks on it. (You Xcan set the SELECTABLE attribute of other types of objects and use Xthem instead of actual buttons, but be sure that the user will be Xable to figure out what you intend!) X.PP XHaving non-exit buttons forces us to consider the problem of initializing Xthem before the dialog, and interrogating and resetting them afterward. X.PP XSince a button is a toggle, it is usually associated with a flag variable in Xthe program. As part of the initialization, you should test the flag variable, Xand if true call: X.FB sel_obj() Xsel_obj(tree, BTNOBJ); X.FE Xwhich will cause the button to appear highlighted when the dialog is first Xdrawn. Sel_obj() is in the download. BTNOBJ is replaced with the name you Xgave your button when you defined it in the RCS. Since the button starts out Xdeselected, you don't have to do anything if your flag variable is false. X.PP XAfter the dialog has completed, you need to check the object's state. The Xselectp() utility does so by masking the OB_STATE field. You can simply assign Xthe result of this test to your flag variable, but be sure that the dialog was Xexited with an OK button, not with a CANCEL! Again, remember to clean up the Xbutton with desel_obj(). (It's often easiest to deselect all buttons Xjust before you leave the dialog routine, regardless of the final Xdialog state.) X.SH WHO'S GOT THE BUTTON? XAnother common use of buttons in a dialog is to select one of a set Xof possible options. In GEM, such objects are called radio buttons. XThis term recalls automobile radio tuners where pushing in one button Xpops out any others. In like fashion, selecting any one of a set of Xradio buttons automatically deselects all of the others. X.PP XTo use the radio button feature, you must do some careful work with the XResource Construction Set. X.PP XFirst, each member of a set of radio buttons must be children of the same Xparent object within the object tree. To create this structure, put a hollow Xbox type object in the dialog, make it big enough to hold all of the buttons, Xand then put the buttons into the box one at a time. X.PP XBy nesting the buttons within the box object, you force them to be its Xchildren. Each of the buttons must have both the SELECTABLE and RADIO BUTTON Xattributes set. When you are done, you may make the containing box Xinvisible by setting its border to zero, but do not FLATTEN it! X.PP XSince each radio button represents a different option, you must usually Xassign a name to each object. When initializing the dialog, you must check Xwhich option is currently set, and turn on the corresponding button only. A Xchain of if-then-else structures assures that only one button will be selected. X.PP XAt the conclusion of the dialog, you must check each button with selectp() Xand make the appropriate adjustments to internal variables. Again, an Xif-then-else chain is appropriate since only one button may be Xselected. Either deselect the chosen button within this chain or do Xthem all at the end. X.PP XThere is one common use of radio buttons in which you may short-cut this Xprocedure. If the buttons each represent one possible value of a numeric Xvariable, for instance, a set of selector buttons representing colors Xfrom zero to seven, then you can compute the initial object directly. X.PP XIn order for this technique to work, you must use a special capability of the XRCS. Insert the object corresponding to a zero value at the top (or left) of Xyour array of buttons, then put the "one" button below (or right) of it, and so Xon. X.PP XWhen the buttons are complete, the SORT operation is used to guarantee that Xthe top/left object is in fact the first child of the parent box with Xthe others following in order. Due to the details of object tree Xstructure (to be discussed in the next column), this will guarantee Xthat these objects are contiguous in the resource. X.PP XIf you assign a name (say BUTTON1) to the first button, then you can Xinitialize the correct button with the call: X.FB sel_obj() Xsel_obj(tree, BUTTON1 + field); X.FE Xwhere field is the variable of interest. X.PP XWhen the dialog is complete, you can scan the radio buttons to compute the Xnew value for the underlying variable. The encode() procedure in the download Xwill do this. As always, remember to deselect the buttons at the end. X.PP XYou can use offsets or multipliers if your variable's values don't start with Xzero or increment by one. If the values are irregular you may be able to use a Xlookup table, at the cost of additional code. X.SH COMING UP NEXT XIn the next column, I will discuss the internal structure of object Xtrees. Then we'll use that knowledge to build a piece of code which Xwill "walk" an entire tree and apply a function to each object. We'll Xapply this code to do all of the button deselects with a single call! XI'll also look at handling editable text fields and discuss some ways Xto alter a dialog's appearance at run-time. X.SH DISPELL GREMLINS XAn editing error caused an omission in the first installment of ST PRO XGEM. The window components RTARROW and DNARROW should have been Xlisted along with HSLIDE as the horizontal equivalents of the vertical Xslider components which were discussed. X.! X.! X.!***************************************************************************** X.!* * X.!* End Part 3 * X.!* * X.!***************************************************************************** SHAR_EOF if test 16916 -ne "`wc -c 'wind3.prf'`" then echo shar: error transmitting "'wind3.prf'" '(should have been 16916 characters)' fi # End of shell archive exit 0 -- Jwahar R. Bammi Usenet: .....!decvax!cwruecmp!bammi CSnet: bammi@case Arpa: bammi%case@csnet-relay CompuServe: 71515,155