home *** CD-ROM | disk | FTP | other *** search
- <head>
- <title="...forever...">
- <font=monaco10.fnt>
- <font=newy36.fnt>
- <font=time24.fnt>
- <image=back.raw w=256 h=256 t=-1>
- <buf=4163>
- <bgcolor=-1>
- <background=0>
- <link_color=000>
- <module=console.mod>
- <pal=back.pal>
- colors:
- 251 - black
- </head>
- <body>
- <frame x=0 y=0 w=640 h=4163 b=-1 c=-1>
-
-
- .: GEM in one pill :.
- -----------------------------
- 3) WINDOWS
- --------------------
- Do me window, do me now...
-
- Function wind_create() returns the handle of the newly created window. It takes
- as a paremeters, which determine the maximal size of window which can be set by
- the user.
- The maximal size of window is usually not the whole screen area. In most cases
- it's (the total size of the screen) - (size of menu). We are lucky enough to
- have function wind_get(), which gives several useful informations. One of
- parameters which can be passed to this function is a flag. If this flag will
- have a value of WF_WORKXYWH and the window handle will be 0 (0 it's always
- desktop handle!), then we receive the x,y,w,h values of the desktop.
-
- Next thing to do is to call wind_create() and determine which portions of the
- window should be displayed. Each window can have: scrollable bars, closer etc
- (all that you know from GEM).
- Window without specified objects will appear as a simple frame. Defined objects
- are indicating what actions your program has to handle. This can also tell you
- what your program need not to include.
- For example we cannot receive the message "the size of window has changed" if
- we don't include resizer in our window. Most of compilers define GEM objects as
- a constants in header files (or another ones...).
- In most cases the logica AND operation is performed with predefined names and
- variable passed to the function, e.g window for receiving messages can have two
- objects -closer (to close the window) and title bar (to drag it along), but not
- resizer. So we put as a variable NAME|CLOSER.
-
- After the window creation we are ready to display it. Before we do it, we
- should change the text in the title bar. To do this we use wind_set(). With
- this function we can change the size, position of scrollbars, change the
- content of the text strings etc. After setting everything the window is ready
- to display with the function call wind_open(). This one sets the beginning size
- of the displayed window (maximum size or a standard one). The overal size
- should depend on the role that windows will plays in your program. Window can
- contain nearly everything. Every graphical operation (it also includes
- displaying text in GEM window) should be in "working area" of the window.
-
-
- Finding the working area of the GEM window
-
- To find the windows "working area" we need to call wind_get() and pass to it
- handle of our window and WF_WORKXYWH flag. It will return the size of "working
- area" as x,y,w,h (but with omission of various window gadgets like scrollbars,
- title bar etc.). If as a flag we will use WF_CURRXYWH then this function will
- return the full size of the window (WITH widow gadgets). Alternatively we can
- use wind_calc() to transform the "working area" to the full one. The functions
- wind_get() and wind_set() are the most frequently used in the whole process of
- handling windows.
- So we have the needed coordinates. Next step is to pass those coordinates to
- VDI (which is some kind of GEM display manager) to limit the display to only
- the "working area" of the window (this is called clipping). And now we have a
- PROBLEM. The nature of this problem is that AES and VDI are handling windows
- differently. AES defines the coordinates as a starting vertex and width and
- height, but VDI prefers coordinates of the top left vertex and bottom right
- vertex.
- The solution is GRECT structure. Converting from AES representation to VDI one
- isn't problematic anymore, because we do it with simple equations:
- x1= x
- y1= y
- x2= (x1-(w-1))
- y2= (y1-(h-1))
- If we don't do this (and this is the the frequent source of errors) we can bomb
- out everything.
-
- Graphics clipping
-
- The clipping of the graphics inside the windows is performed with vdi_clip()
- and it takes as a parameter the VDI rectangle with the VDI handle (NOT window
- handle!). After that we can draw the graphics or text. The most common way is
- to write one flexible procedure to which we can pass the coordinates of the
- area to redraw together with the window handle. So the function can be reused
- to redraw another portions of the window.
- But the best solution is the use of the message "redraw the window,
- pleaassseee" which we can issue to our system.
-
- Window handling
-
- System is communicating with the user via messages. Each time the user performs
- an action, the EVENT occurs. Each event sends one or more messages, which are
- handled in one gigantic if-else processing loop. The bad news are that there is
- an enormous amount of messages we can get. Firstly there are messages sent by
- other applications, secondly the messages sent by the windows itself. The
- messages can be checked by one of several function calls.
- One of those function calls is evnt_multi(), which informs you about EVERYTHING
- that will occur - it can be from keystroke to menubar selection. It is for
- fully fledged GEM applications. As we wan't only to handle windows correctly
- the function evnt_mesag() will be good enough.
-
- Multitasking considerations
-
- In some circumstances the system leaves your application and leaves to let go
- another programs (cooperative multitasking). This is the case in which the
- evnt_xxx() calls occur.
- Until the event, which you are expecting will not occur your application will
- simply sit and do nothing at all. If you want to make your program multitasking
- friendly you should put evnt_xxx() call in each long processing job, even if
- you really don't want to know what is really happening. Environments with
- preemptive multitasking (like MultiTOS, Magic or MiNT) don't need this, but as
- this(next?) method is universal to both kinds of multitasking systems.
- The standard function call is evnt_timer(), which forces the program to wait
- the given amount of milioseconds. Evnt_timer() with 0 as a parameter let's the
- system continue switching between the tasks.
- The evnt_mesag() function waits for a messages from pipe to your program. The
- messages can be from system, from another applications or even from your
- program (sended with appl_write() feeded with id of your application). So you
- can send the message to redraw the windows anytime you want. You can send
- another messages, but sending information about events that didn't occured is
- very stupid.
-
- Messages
-
- WM_SIZED (sizer) - use wind_set() to set the new size of the window. After that
- use wind_get() to set the new "working area", set the sliders to the new values
- and redraw the window.
-
- WM_MOVED (title bar) - use the wind_set() to set new size.
-
- WM_FULLED (fuller) - if window is not "fulled" then save the actual window size
- and set it to the maximal size with wind_set().
-
- WM_CLOSED(closer) - use the wind_delete() to erase the window fro the screen.
- You should give the possibility to the user to save the content of the window
- before closing it.
-
- WM_ARROWED (scroll bar and arrows) - this message means several things. Firstly
- it can mean that the user has pressed on the scrollbars. If yes then scroll the
- window content to right/left/up/down by amount of width/height (it can be any
- amount suitable to your application: for text editor height/width of the
- character, for image displayer it can be 1 horizontal/vertical line
- up/down/right/left). If user pressed the free area of the slider bar, then you
- should scroll the window one screen down (or one line as /|\ ATARI Corp.
- states) in appropriate direction. Of course screen redraw is needed plus
- adequate setting of the scrollbars.
-
- WM_HSLID (horizontal slider) - it passes the number from 0 to 1000. This number
- tells how far to the right the horizontal slider was moved in his movement
- range (window width =scrollbar width + width of arrow + sizer width). Simply
- speaking 0=beginning of the document, 1000 = end of the document. Ranges
- between are calculated in dependency from the shape of displayed window. After
- that we have to redraw the screen.
-
- WM_VSLID (vertical slider) - the same as above, but vertically.
-
- WM_REDRAW - the most important message. Your application uses it very
- frequently, so handler should be free of errors. Redraw handler is needed even
- if you plan the use of 1 window and single tasking environment. All of this
- fuss is by those awful accessories, because they also can open windows. If your
- program has menubar, then we can assume that one of accessories will be opened
- over your application.
-
- Details of WM_REDRAW
- All the messages generated by the system have the same lenght (16 bytes or 8
- words or 4 long words as you like). evnt_mesag() returns the pointer to message
- buffer. If you expect messages from other applications, 16 bytes will be a
- little too small. But to keep things simple we will stay with 16 byte buffer.
-
- Message buffer looks like this:
- message[0] - type of message
- message[1] - ID of sending application (we can ignore it at this stage)
- message[2] - lenght of the message over 16 bytes (0 in our case)
- message[3] - handle of the window to redraw
- message[4] - x coordinates of "dirtied" rectangle
- message[5] - y coordinates of "dirtied" rectangle
- message[6] - width of "dirtied" rectangle
- message[7] - height of "dirtied" rectangle
-
- In theory the sufficient way is to get the proper coordinates and pass the to
- the redraw function. But things can get complicated (as usual). Yo can get for
- example redraw message when active window will be partially obscured. The
- solution is wind_get(), which has several predefined values, in which it can
- look in. GEM divides the window onto visible and invisible parts. It divides
- the visible part into smallest possible amount of rectangles. It gives us the
- method for systematic check of "dirtied" rectangle against all visible ones. If
- any of visible rectangles is covering the "dirtied" rectangle you know what to
- redraw. So going down the visible rectangle list you will finally refresh
- window successfully.
-
- Window redraw list "to do"
-
- a) Get "dirtied" rectangle sended in window redraw message.
- b) Use WF_FIRSTXYWH in wind_get() to get the first rectangle from visible
- rectangle list.
- c) If width or height = 0 we are in the end of visible rectangle list and
- redraw is finished.
- d) If width or height not 0 we have to calculate the obscured area and redraw
- this rectangle.
- Calculating of obscured area:
- "dirtied" rectangle - x1, y1, w1, h1
- visible rectangle - x2, y2, w2, h2
- rectangle to redraw - x3, y3, w3, h3
- x3 = choose the greater (x1 or x2)
- y3 = choose the greater (y1 or y2)
- w3 = (choose the greater (x1+w1) or(x2+w2)) - x3
- h3 = (choose the greater (x1+h1) or(x2+h2)) - y3
-
- In Lattice C there is rc_intersect() function which does the same.
-
- e) If w3 and h3 are greater than 0, then we redraw the window:
- - graf_mouse(M_OFF,0x0L) to switch off the mouse
- - wind_update (BEG_UPDATE) to freeze the screen during redraw
- - vs_clip() to limit the area of redrawed rectangle
- - wind_update (END_UPDATE) to unfreeze the screen
- - graf_mouse(M_ON,0x0L) to switch the mouse back on
- f) Get the next visible rectangle from list with the use of WM_NEXTXYWH flag
- and wind_get().
- g) Go to c).
-
- The best solution is to pack everything in one function call and additionally
- put the scrollbars redraw check (to see if we need to redraw scrollbars or
- not).
- We can also use the two standard functions:
- redraw_wind() gets the window handler and "dirtied" rectangle and checks if
- obscuring occured. If the redraw is needed then it calls draw_rect() function
- with window handle and the rectangle to redraw. It can be repeated changing
- only the arguments for draw_rect() to redraw the proper rectangle.
-
- Scrollbars
- Proportional scrollbars are a cool thing, but as always they need the special
- treatment. Each time the user inputs the new data, changes the size of the
- window or clicks on scrollbar we have to redraw it. Everything that is managed
- by wind_set().
-
- Firstly, we have to estimate how big they have to be. GEM sets them
- proportionally to the size of the window and uses the range: 0 (nothing) to
- 1000 (full lenght/width - arrow size).
- Calculating of the position is a little bit complicated, that's because range
- 0-1000 holds the possible movement range of the upper part of scrollbar. As a
- bar is moving on finite width, the upper part cannot be on the bottom.
- Example:
- We have 100 line document. We show 30 lines at time, so the scrollbar holds 20%
- of the whole area. So our range is shortened a little to 0-800, but we still
- receive the number from 0-1000. Range 0-1000 is a whole bar, but movement range
- is 0-800. If we want for scrollbar to start at 48% of then the bar is setted
- on:
- 1000*48/(100-20) or 600-60% of the way down.
- All of this means that if we will go right to the end of the file, our slider
- will be only 80% way down of a bar and it gives our more general equation for
- scrollbar starting point:
- position=1000*starting point/(whole lenght-showed lenght)
-
- Scrollbars redraw
- To redraw scrollbars we have to:
- - calculate the total of a file in given direction (in pixels, lines,
- characters)
- - calculate the size of image/ document shown in the same units (pixels, lines,
- characters).
- - use the equation mentioned above to get the proper parameter
- - use the wind_set() to set the scroll bar
-
- Closing windows
- Firstly we use wind_close() to remove the window from the screen (it also sends
- the redraw message). After that we use the wind_delete to release the window
- handle and free memory.
-
- <link=art50c.scr>Go to PART #3</l>
- </frame>
- </body>
-
-