Previous: 17 Startup and closedown
Next: 19 I shall say this only once ...
In this section:
I like to think about the graphical interaction possible in a program using ClearWin+ as having three possible levels. In level I the user draws something on a drawing surface but all the details of that are supplied from the contents of the data file or dialog boxes. Level I can include hardcopy, but again without direct interaction with the graphics.
Level II, on the other hand, is where the user does interact with the graphics with the mouse pointer, for example by selecting objects or inserting or deleting them. Zooming in or out is somewhat transitional between level I and level II, as is rotating the object or even the complete contents of the drawing surface.
When it comes to level III, the user can actually move objects around on the screen and reposition them.
There are some applications where level I is completely appropriate, and many more where level II is perfectly adequate. However, there are some where level III is required. If you consider that a level III is needed in your application, then you must be prepared for a great deal of additional programming. To move an object or to reshape it interactively is a matter of rubbing it out and redrawing it in real time which definitely requires full_mouse_input. It also requires knowledge of drawing modes.
There are basically four drawing modes:
Mode 0 is what we normally do, and it does the ‘Painter’s Algorithm’ with the new replacing the old. Mode 3 is interesting in the context of level III graphics, because if you draw something in XOR mode over something else, and then redraw it a second time in the same place also in XOR mode, that new graphic disappears and the old one returns. Basically, that’s what’s happening to your mouse pointer when you move it – it is drawn initially in XOR mode, and when you move it, it is drawn again in both where it was (to rub it out) and again in its new position (or positions, as you can see it moving).
You can select the graphics write mode using a standard subroutine GRAPHICS_WRITE_MODE@ with a single parameter, one of the four options above. In principle, anything movable has to be drawn in mode 3 and if it is to be moved, it needs to be redrawn at the original position in mode 3 and then moved and redrawn again also in mode 3 in the new position. If it is left where it ended up, that’s no problem and you don’t have to redraw it in mode 0.
The problem comes if you do everything originally in mode 0, because then you would have to redraw everything except the object be moved, and redraw that particular one in mode 3. If you changed the colour of the object so that it could stand out while moving, then you would need to redraw it but probably after a change back to the original colour and if you’d finished moving it, then back in mode 0. Should the object be partly obscured by later objects, or be lower in the ‘Z-order’ (and so be partly obscured by later objects), then you probably need to redraw everything. The Z-order implies that some objects are at the bottom of a pile of objects, and others are progressively more and more on top. This can be a real order if a 3-D object is being drawn, or a virtual order in a 2-D drawing.
You will find an example of the use of Mode 3 (XOR) drawing in Appendix D, where a whole program is presented. I call the program ‘Stretchy Box’ and it was written in a fairly explicit way to illustrate the points, which makes it good for this book too. No doubt the logic could be tidied up. Basically, a quadrilateral with nodes at its corners and in the middle of its sides is drawn and the user can by picking up any one of the nodes move it and cause the box to change shape. The program also changes cursors on-the-fly, and uses some cursors from the ‘Smooth set’ by Vlastimil Milér. I could have used the standard cursors in ClearWin+ had I known at the time that they were available.
Modes 1 and 2 get us out of the realms of ClearWin+ and into the realms of advanced computer graphics. A readable text if one that is a little dated is Angell and Griffith’s “High-resolution computer graphics using Fortran 77” published by Macmillan. There are later versions of the book and also doing the same material in other languages.
By default, ClearWin+ uses a very standard mouse pointer for just about everything except when that pointer moves over a drawing surface, when the cursor changes automatically to a small crosshair or cross. A total of 11 cursors are defined in the various .INS files (or the related .MOD files if you prefer modules):
INTEGER*4 CURSOR_ARROW,CURSOR_IBEAM,CURSOR_WAIT,CURSOR_CROSS, & &CURSOR_UPARROW,CURSOR_SIZE,CURSOR_ICON,CURSOR_SIZENWSE, & &CURSOR_SIZENESW,CURSOR_SIZEWE,CURSOR_SIZENS PARAMETER(CURSOR_ARROW = 32512) PARAMETER(CURSOR_IBEAM = 32513) PARAMETER(CURSOR_WAIT = 32514) PARAMETER(CURSOR_CROSS = 32515) PARAMETER(CURSOR_UPARROW = 32516) PARAMETER(CURSOR_SIZE = 32640) PARAMETER(CURSOR_ICON = 32641) PARAMETER(CURSOR_SIZENWSE = 32642) PARAMETER(CURSOR_SIZENESW = 32643) PARAMETER(CURSOR_SIZEWE = 32644) PARAMETER(CURSOR_SIZENS = 32645)
When you want to add something to a drawing surface that you can see, and which represents a physical scene with real world dimensions, it is useful to be given a hint as to where the mouse cursor is in those real-world coordinates. There are several methods, but none of them can be any more precise than to the real-world size of a single pixel.
One method is to follow the cursor in full_mouse_input mode and in real time, convert the mouse position into real world coordinates. A good place to display those coordinates would be a status bar, but what seems to be a good alternative would be to put the coordinates in a dialog that follows the mouse pointer around. Such a dialog would conventionally be above and to the right of the mouse pointer, but it needs then to flip to the left of the pointer as the right margin of the drawing surface is approached, or from above to below at the top of the drawing surface. Sadly, doing that causes a most annoying flickering, especially on comparatively slow computers, and the status bar approach is far better. The following code illustrates the procedure, but simply reporting pixel coordinates for brevity.
WINAPP OPTIONS (INTL, DREAL) PROGRAM FOLLOW_THE_MOUSE C ------------------------ COMMON /MOUSE/ IX, IY, LW INCLUDE <WINDOWS.INS> EXTERNAL KB_GET_CURSOR_POS DIMENSION IAR(3) IAR = 25 ! whole array IW = WINIO@ ('%ca[Follow the cursor]&') IW = WINIO@ ('%3sb%lc&', IAR, LW) IW = WINIO@ ('%`cu&', 32652) IW = WINIO@ ('%^gr[blue,full_mouse_input]', 600, 400, & KB_GET_CURSOR_POS) END INTEGER FUNCTION KB_GET_CURSOR_POS() C ------------------------------------ COMMON /MOUSE/ IX, IY, LW CHARACTER*(20) XTEXT, YTEXT INCLUDE <WINDOWS.INS> IX = CLEARWIN_INFO@ ('GRAPHICS_MOUSE_X') IY = CLEARWIN_INFO@ ('GRAPHICS_MOUSE_Y') WRITE(XTEXT,'(" X=",I4)') IX WRITE(YTEXT,'(" Y=",I4)') IY CALL SET_STATUS_TEXT@ (LW, 0, XTEXT) CALL SET_STATUS_TEXT@ (LW, 1, YTEXT) KB_GET_CURSOR_POS = 2 END
Note that the simple status bar created with %sb needs the displayed contents to be converted into character strings first.
Another method that does not require the programming effort in a graphics callback is to draw rulers around the periphery of the drawing surface, and change the cursor to a pair of long cross-hairs, so that the user can read off the position from the rulers. Rulers are enhanced if the object is covered by a grid, which can be underneath the object (and therefore drawn first) or on top (and therefore drawn last). Grids work well in blue or green shades. Appendix B contains a routine for drawing such a grid and labelling it. To gain the most benefit from rulers you need a cursor that extends to them, which you can switch on with a call initially to SET_GRAPHICS_SELECTION@(3) and subsequently return to the original cursor with SET_GRAPHICS_SELECTION@(0).
The example in the previous section of a status bar created using %sb also shows how to change the text in the different parts of the bar by means of the SET_STATUS_TEXT@ subroutine. At the time I write this, a status bar created in this way can only contain panels with character strings. An alternative way of creating a status bar uses a box defined beginning with %ob[status] and finishing in the ordinary way with %cb (as described in section 6.14). Inside such a box you can have any controls that you like not limited to text panels but including icons, bitmaps,
buttons, slider bars and so on.
FORTRAN and the ART of Windows Programming, Copyright © Eddie Bromhead, 2023.