diff --git a/Chapters/ch01-an-example-application.xml b/Chapters/ch01-an-example-application.xml index f50dc5e..faadb4b 100644 --- a/Chapters/ch01-an-example-application.xml +++ b/Chapters/ch01-an-example-application.xml @@ -98,7 +98,7 @@ ENDPROC

For now, we do very little in the way of initialisation. The global variable Quit% is initialised to FALSE, to ensure that the appliction does not exit immediately, and a couple of buffers – pointed to by the variables b% and q% – are initialised to 1024 and 256 bytes respectively. Whilst these will both be used as general purpose buffers, b% will be used as a store for loading template definitions and be passed as the event block to Wimp_Poll; q% will mostly be used as a second parameter block by other Wimp SWI calls.

-

The program indicates that it knows about Wimp version 310: whilst pane code will work on RISC OS 2, modern applications should use this as a minimum, since a lot of now-standard functionality such was interactive help in menus as introduced at this point. This means that Wimp_Initialise needs to be passed a list of user messages that the application requires in R3, so we build one up in the block pointed to by q%: the only entry is zero, for Message_Quit.

+

The program indicates that it knows about Wimp version 310: whilst pane code will work on RISC OS 2, modern applications should aim for RISC OS 3.1 as a minimum, since a lot of now-standard functionality such was interactive help in menus as introduced at this point. This means that Wimp_Initialise needs to be passed a list of user messages that the application requires in R3, so we build one up in the block pointed to by q%: the only entry is zero, for Message_Quit.

Error handling is looked after by FNwimperror_program, which can be seen in .

@@ -131,11 +131,11 @@ LOCAL reason% SYS "Wimp_Poll", &3C01, b% TO reason% CASE reason% OF - WHEN 17, 18 : IF b%!16 = 0 THEN Quit% = TRUE + WHEN 17, 18 : IF b%!16 = 0 THEN Quit% = TRUE ENDCASE ENDPROC -

For now, there’s not much here: we’re only interested in Message_Quit, which has the value of zero; if one of these arrives, we set the Quit% to TRUE so that the program will terminate. This ensures that, in the absence of any other user interface, it can still be shut down from the Task Manager.

+

For now, there’s not much here: we’re only interested in Message_Quit, which has the value of zero; if one of these messages arrives, we set the Quit% variable to TRUE so that the program will terminate. This ensures that, in the absence of any other user interface, it can still be shut down from the Task Manager.

The BASIC program can be saved as !RunImage inside a !PaneDemo application folder, as seen in .

@@ -145,7 +145,7 @@ ENDPROC If "<PaneDemo$Dir>"="" Then Set PaneDemo$Dir <Obey$Dir> -

The !Run file, seen in , is similarly minimalist: setting the system variable, adjusting the wimpslot and launching the BASIC code.

+

The !Run file, in , is similarly minimalist: setting the system variable, adjusting the wimpslot and launching the BASIC code.

Set PaneDemo$Dir <Obey$Dir> @@ -201,8 +201,8 @@ SYS "Wimp_OpenTemplate",,"<PaneDemo$Dir>.Templates" PROCtemplate_load("Main", b%, buffer_size%, -1) SYS "Wimp_CreateWindow",,b% TO MainWindow% -WindowWidth% = b%!8 - b%!0 : REM Width is Visible Area Maximum X - Minimum X -WindowHeight% = b%!12 - b%!4 : REM Height is Visible Area Maximum Y - Minimum Y +WindowWidth% = b%!8 - b%!0 : REM Width is Visible Area X1 - X0 +WindowHeight% = b%!12 - b%!4 : REM Height is Visible Area Y1 - Y0 PROCtemplate_load("ProgInfo", b%, buffer_size%, -1) SYS "Wimp_CreateWindow",,b% TO InfoWindow% @@ -219,7 +219,7 @@ LOCAL templ_size%, indir_size%, workspace% REM Find the size required for the template and indirected data. $TemplateName%=LEFT$(name$ + STRING$(12, CHR$(13)), 12) -SYS "Wimp_LoadTemplate",,,,, -1, TemplateName%, 0 TO ,templ_size%, indir_size% +SYS "Wimp_LoadTemplate",,,,,-1, TemplateName%, 0 TO ,templ_size%, indir_size% REM Return if the template won't fit in the buffer. @@ -264,21 +264,22 @@ IF (q%!32 AND &10000) = 0 THEN REM Update the window dimensions. - q%!4 = (screen_width% - window_width%) / 2 : REM Visible Area Minimum X - q%!8 = (screen_height% - window_height%) / 2 : REM Visible Area Minimum Y + q%!4 = (screen_width% - window_width%) / 2 : REM Visible Area X0 + q%!8 = (screen_height% - window_height%) / 2 : REM Visible Area Y0 - q%!12 = q%!4 + window_width% : REM Visible Area Maximum X - q%!16 = q%!8 + window_height% : REM Visible Area Maximum Y + q%!12 = q%!4 + window_width% : REM Visible Area X1 + q%!16 = q%!8 + window_height% : REM Visible Area Y1 REM Reset the scroll offsets. - q%!20 = 0 - q%!24 = 0 + q%!20 = 0 : REM X Scroll Offset + q%!24 = 0 : REM Y Scroll Offset ENDIF REM Open the window at the top of the window stack. -q%!28 = -1 : REM Open window at top of stack +q%!28 = -1 : REM Window to open behind (-1 is top of stack) + SYS "Wimp_OpenWindow",,q% ENDPROC diff --git a/Chapters/ch02-a-side-toolbox.xml b/Chapters/ch02-a-side-toolbox.xml index 6de3eb6..a556c5b 100644 --- a/Chapters/ch02-a-side-toolbox.xml +++ b/Chapters/ch02-a-side-toolbox.xml @@ -44,7 +44,7 @@ Everyone knows what the toolbox in Draw looks like, so let’s make one of our own.
-

If one were to survey members of the RISC OS community to find out what a “toolbox” looked like, the answer which came back would probably be along the lines of “like the one in Draw”. Draw’s toolbox has been present as standard on all systems since the days of RISC OS 2, and is still functional to this day. It’s also one of the easiest panes to implement, so let’s start by making one of our own.

+

If one were to survey members of the RISC OS community to find out what a “toolbox” looked like, the answer which would come back would probably be along the lines of “like the one in Draw”. Draw’s toolbox has been present as standard on all systems since RISC OS 2, and is still functional to this day. It’s also one of the easiest panes to implement, so let’s start by making one of our own.

@@ -66,7 +66,7 @@ -

The other flag which we have set is Pane, which corresponds to the ‘window is a pane’ flag at bit 5 of the window flags. The Programmer’s Reference Manual is a little vague about what this flag does, but most developers will probably have discovered that what it doesn’t do is cause the window follow its parent around the screen automatically! In fact it does a few important things, which we’ll discuss later in this chapter.

+

The other flag which we have set is Pane, which corresponds to the ‘window is a pane’ flag at bit 5 of the window flags. The Programmer’s Reference Manual is a little vague about what this flag does, but most developers will probably have been disappointed to discover that what it doesn’t do is cause the window follow its parent around the screen automatically! In fact it does a few important things, which we’ll discuss later in this chapter.

Down at the bottom of the dialogue, all of the scroll events are off, since we don’t need the pane to scroll. In addition, all of the window colours have been left at their default, Style Guide compliant values.

@@ -82,7 +82,7 @@ SYS "Wimp_CreateWindow",,b% TO ToolBoxWindow%
Handling pane events -

Handling panes is actually fairly straight-forward: it’s just the details which can seem confusing! It boils down to this: if the Wimp won’t do the work for us, we need to track movement of the main window and ensure that every time it moves, we also move the pane into the correct relative position. Fortunately, there are only two ways that a window can move: if we do it ourselves, or if it is done by something outside our application (such as the user, or another application). In the latter case, the request will arrive through the Open_Window_Request event; in the former, we’ll know about it.

+

Handling panes is actually fairly straight-forward: it’s just the details which can seem confusing at first sight! It boils down to this: if the Wimp won’t do the work for us, we need to track movement of the main window and ensure that every time it moves, we also move the pane into the correct relative position. Fortunately, there are only two ways that a window can move: if we do it ourselves, or if it is done by something outside our application (such as the user, or another application). In the latter case, the request will arrive through the Open_Window_Request event; in the former we’ll have initiated the action, so we’ll know about it.

In our existing application, we have the following two lines in PROCpoll, to handle the Open_Window_Request and Close_Window_Request events:

@@ -105,19 +105,16 @@ CASE reason% OF ENDCASE ENDPROC -

Before either of these two new procedures will do anything, they will check the handle of the window to which the event applies. If it’s the handle of the main window, then they will need to do the work required to handle the pane as well; for any other window, they can simply call the appropriate Wimp SWI as before.

+

Each of these event-handling procedures will need to check each incoming event, to see which window it applies to. If it’s the handle of the main window, then – in addition to calling the appropriate Wimp SWI as before – any additional work required to handle the pane will need to be performed as well.

-

In the case of PROCopen_window_request(), we will change the code so that any Open_Window_Request events relating to the main window are passed on again to another new procedure: PROChandle_pane_windows(). Events for other windows will simply be passed on to the Wimp_OpenWindow SWI. This code to do this can be seen in ; We’ll worry about what PROChandle_pane_windows() looks like later on.

+

In the case of PROCopen_window_request(), we will change the code so that for any Open_Window_Request events relating to the main window, a new PROChandle_pane_windows() procedure will be called after the event has been passed to the Wimp_OpenWindow SWI. This code to do this can be seen in ; PROChandle_pane_windows() will handle the panes for us, but we’ll worry about what it looks like later on.

DEF PROCopen_window_request(b%) -IF !b% = MainWindow% THEN - PROChandle_pane_windows(b%) -ELSE - SYS "Wimp_OpenWindow",,b% -ENDIF +SYS "Wimp_OpenWindow",,b% +IF !b% = MainWindow% THEN PROChandle_pane_windows(b%) ENDPROC -

Of course, if the main window and its toolbox should be acting as one, then in addition to moving when the main window moves, the pane should be closed when the main window closes. We can look after this in a very similar way with our new PROCclose_window_request(), seen in . If the window being closed is the main window, then the toolbox window will be closed first; either way, the window referenced by the event is closed afterwards.

+

Of course, if the main window and its toolbox should be acting as one then, in addition to moving when the main window moves, the pane should be closed when the main window closes. We can look after this in a very similar way with our new PROCclose_window_request() procedure, seen in . If the window being closed is the main window, then the toolbox window will be closed first; either way, the window referenced by the event is closed afterwards.

DEF PROCclose_window_request(b%) IF !b% = MainWindow% THEN @@ -128,14 +125,15 @@ ENDIF SYS "Wimp_CloseWindow",,b% ENDPROC -

These changes deal with things outside of our application moving the main window, but what about us doing it ourselves? Fortunately, there’s only one place where we do, which is at the end of PROCopen_main_window:

+

These changes deal with things outside of our application moving the main window, but what about when we change its position ourselves? Fortunately, there’s only one place where we do this, which is at the end of PROCopen_main_window.

REM Open the window at the top of the window stack. -q%!28 = -1 : REM Open window at top of stack +q%!28 = -1 : REM Window to open behind (-1 is top of stack) + SYS "Wimp_OpenWindow",,q% -

Fortunately, this is just another call to Wimp_OpenWindow, so we should just be able to replace it with a call to PROChandle_pane_windows() in the same was as we did in the Open_Window_Request event handler. This means that our new PROCopen_main_window() will look as seen in .

+

This is just another call to Wimp_OpenWindow, so we can simply follow it with a call to PROChandle_pane_windows() in the same was as we have done in the Open_Window_Request event handler. This means that our new PROCopen_main_window() will look as seen in .

DEF PROCopen_main_window LOCAL screen_width%, screen_height%, window_size% @@ -162,16 +160,23 @@ IF (q%!32 AND &10000) = 0 THEN REM Update the window dimensions. - q%!4 = (screen_width% - window_size%) / 2 : REM Visible Area Minimum X - q%!8 = (screen_height% - window_size%) / 2 : REM Visible Area Minimum Y + q%!4 = (screen_width% - window_width%) / 2 : REM Visible Area X0 + q%!8 = (screen_height% - window_height%) / 2 : REM Visible Area Y0 + + q%!12 = q%!4 + window_width% : REM Visible Area X1 + q%!16 = q%!8 + window_height% : REM Visible Area Y1 - q%!12 = q%!4 + window_size% : REM Visible Area Maximum X - q%!16 = q%!8 + window_size% : REM Visible Area Maximum Y + REM Reset the scroll offsets. + + q%!20 = 0 : REM X Scroll Offset + q%!24 = 0 : REM Y Scroll Offset ENDIF REM Open the window at the top of the window stack. -q%!28 = -1 : REM Open window at top of stack +q%!28 = -1 : REM Window to open behind (-1 is top of stack) + +SYS "Wimp_OpenWindow",,q% PROChandle_pane_windows(q%) ENDPROC @@ -182,43 +187,46 @@ ENDPROC
Setting the visible area -

Now that we have ensured that our PROChandle_pane_windows() procedure will be called every time the positions of the main window and toolbox pane need to be updated, all that remains is to work out how to join the two windows together on screen.

+

Now that we have ensured that our PROChandle_pane_windows() procedure will be called following every Wimp_OpenWindow call which applies to the main window, all that remains is to work out how to adjust the toolbox pane so that the two windows appear to be joined together on screen. We need to know where the main window ended up on screen, and fortunately this information is waiting for us.

+ +

Since the arrival of the Nested Wimp with RISC OS 4.02, the Wimp_OpenWindow SWI has been documented as returning with the contents of the window state block passed in R1 updated to reflect where the window was actually opened. In the Nested Window Manager Functional Specification, Acorn wrote that “since RISC OS 2 (and possibly even earlier), Wimp_OpenWindow has had undocumented return conditions: values at R1+4 to R1+24 are updated to represent the actual parameters of the opened window after valid ranges have been taken into account, and the window has been forced on-screen (if applicable).”

-

The procedure takes a single parameter, main%, which is a pointer to the Wimp_WindowState block for the main window. Whether this arrived through Wimp_Poll into the block pointed to by b%, or was put into the block pointed to by q% using Wimp_WindowState in PROCopen_main_window, it contains details of where the main window is required to be opened.

+

Thanks to this piece of retrospective documentation, it is safe for us to rely on this behaviour in new software. The PROChandle_pane_windows() procedure takes a single parameter, main%, which is a pointer to the block that was used to open the main window. Whether this arrived through Wimp_Poll into the block pointed to by b%, or was set up in the block pointed to by q% by a call to Wimp_WindowState in PROCopen_main_window, it has been passed to Wimp_OpenWindow and now contains details of where the main window is on screen.

-

The first thing that we need to do is to create an equivalent window state block for the toolbox pane, which we can then update with the necessary values calculated from the main window’s position. Unfortunately we can’t use our usual scratch block of memory pointed to by q%, because that could already be holding the data for the main window if we have been called from PROCopen_main_window. However, we know that only 36 bytes will be in use from what is at least a 256 byte block, so we can just load the pane information in at an offset of 64 bytes.

+

The first thing that we need to do is to create an equivalent window state block for the toolbox pane, which we can then update with the necessary values calculated from the main window’s position. Unfortunately we can’t use our usual scratch block of memory pointed to by q%, because that could already be holding the data for the main window if we have been called from PROCopen_main_window. However, we know that only 36 bytes will be in use from what is at least a 256 byte block, so we can just load the pane information in at an offset of 64 bytes. To make things simpler to follow, we’ll define a local variable toolbox% which points to this offset, then access the toolbox pane’s data through it.

toolbox% = main% + 64 !toolbox% = ToolBoxWindow% SYS "Wimp_GetWindowState",,toolbox% -

Since the pane can’t be resized by the user, we can be fairly confident that its width and height will still be as they were saved in the templates file. These can be used to give us the values for the pane’s width and height, saving us from having to use constants in the code. Before making any changes to the pane window state block’s contents, we therefore calculate the width and height of the pane’s visible area and store the two values for future use.

+

Since the toolbox can’t be resized by the user, we can be fairly confident that its width and height will still be as they were saved in the templates file. These can be used to give us the values for the pane’s width and height, saving us from having to use constants in the code. Before making any changes to the toolbox’s window state block’s contents, we therefore calculate the width and height of the pane’s visible area and store the two values for future use.

-box_width% = toolbox%!12 - toolbox%!4 : REM Visible Area Maximum X - Minimum X -box_height% = toolbox%!16 - toolbox%!8 : REM Visible Area Maximum Y - Minimum Y +box_width% = toolbox%!12 - toolbox%!4 : REM Visible Area X1 - X0 +box_height% = toolbox%!16 - toolbox%!8 : REM Visible Area Y1 - Y0 -

As already noted, we know where the main window should be on screen. We also know the relationship that we want to have between the main window and its pane, as shown in . We can therefore move the pane so that it is in the correct position relative to the main window, update the main window’s position if necessary, then call Wimp_OpenWindow for both windows in turn.

+

As already noted, we know where the main window has ended up on screen. We also know the relationship that we want to have between the main window and its pane, as shown in . We can therefore update the pane’s window state block so that it is in the correct position relative to the main window, then call Wimp_OpenWindow to open it on the screen.

shows the relationship between the main window and its pane. The tops of the two windows (Y1 for the two visible areas) should be level, so we can copy the Y1 value from the main window to the pane. The bottom of the pane (its Y0) is the height of the pane below the top of the main window.

-toolbox%!16 = main%!16 : REM Visible Area Maximum Y -toolbox%!8 = main%!16 - box_height% : REM Visible Area Minimum Y +toolbox%!16 = main%!16 : REM Visible Area Y1 +toolbox%!8 = main%!16 - box_height% : REM Visible Area Y0

In a similar way, the right-hand side of the pane (its X1) is on the left-hand side of the main window, while its left-hand side is the width of the pane further to the left.

-toolbox%!12 = main%!4 : REM Visible Area Maximum X -toolbox%!4 = main%!4 - box_width% : REM Visible Area Minimum X +toolbox%!12 = main%!4 : REM Visible Area X1 +toolbox%!4 = main%!4 - box_width% : REM Visible Area X0
+
Lost in the stack

The code above deals with the position of the pane in the X and Y dimensions, but what about the Z dimension – its position in the window stack? The Wimp requires that panes appear directly above their parent window; however, this is still left up to the application to manage.

-

There's a very practical reason for this requirement. If something like a toolbar pane goes behind its parent window in the stack, then it will very likely be obscured by its parent. Even if the pane is in front, if it isn’t immediately in front, then it’s possible for other windows to get in between as seen in (the application was deliberately broken in order to allow this to occur).

+

There’s a very practical reason for this stacking requirement. If something like a toolbar pane goes behind its parent window in the stack, then it will very likely be obscured by its parent. Even if the pane is in front, if it isn’t immediately in front, then it’s possible for other windows to get in between as seen in (the application was deliberately broken in order to allow this to occur).

@@ -226,59 +234,50 @@ toolbox%!4 = main%!4 - box_width% : REM Visible Area Minimum X

In a similar way, if a window with its pane flag set gains the caret, then the Wimp will give input focus to (and set the ‘window has input focus’ flag at bit 20 of the window flags for) the first window below it in the stack which is not a pane. Finally, when working out which bits of a window might need redrawing following a re-size, the Wimp will treat any panes immediately above it as being transparent – on the basis that the application may be about to move them anyway.

-

Keeping the Z order of the windows correct is fairly straight-forward. The Open_Window_Request block for the main window contains the position in the window stack at which it should be opened, in terms of the handle of the window below which it should be opened at offset 28. Since the toolbox pane should be in front of the window, we copy this value into the pane’s block so that the pane appears at the correct position in the stack.

+

Keeping the Z order of the windows correct is fairly straight-forward. The window state block for the main window contains the position in the window stack at which it was opened, in terms of the handle of the window that it is positioned beneath at offset 28. Since the toolbox pane should be in front of the main window, we can open it behind the same window that the main window is behind: meaning that it will end up between that window and our main window. To achieve this, we copy the window handle from the main window’s block into the pane’s block.

-IF main%!28 <> ToolBoxWindow% THEN toolbox%!28 = main%!28 +toolbox%!28 = main%!28 -

There’s one exception to this, however. If the Wimp is already asking us to open the main window behind the pane, then both the pane and the main window must already be in the correct positions in the window stack. In this case, there’s no point attempting to open the pane behind itself, so we just leave things as they are. The pane is now ready to be opened in its new location, using a call to Wimp_OpenWindow.

+

Opening the toolbox pane directly behind the same window that the main window has been opened behind will result in the pane ending up in front of the main window – exactly where we need it to be. The pane is now ready to be opened in its new location, using a call to Wimp_OpenWindow.

SYS "Wimp_OpenWindow",,toolbox% -

With the pane open in the correct place, all that remains to do is to open the main window. This is done using the block from the Open_Window_Request event almost unchanged: the only thing that we alter is the handle of the window to open behind, which we set to the handle of the pane. This ensures that the pane is always directly in front of the main window.

- -main%!28 = ToolBoxWindow% - -SYS "Wimp_OpenWindow",,main% - -

Putting all of the code above together, PROChandle_pane_windows() will look as shown in .

+

With the pane open in the correct place, there’s nothing else to be done! Putting all of the code above together, PROChandle_pane_windows() will look as shown in .

DEF PROChandle_pane_windows(main%) LOCAL toolbox%, box_width%, box_height% -REM Get the Window State block for the pane, using some of the spare -REM space above the data for the state of the main window. +REM Get the Window State block for the toolbox pane, using some of the +REM spare space above the data for the state of the main window. +REM +REM Note: ON RISC OS 5, we could more clearly use DIM toolbox% LOCAL 64 +REM here to allocate the required memory from the stack. toolbox% = main% + 64 !toolbox% = ToolBoxWindow% SYS "Wimp_GetWindowState",,toolbox% -REM Find the width and height of the pane's visible area. +REM Find the width and height of the toolbox pane's visible area. -box_width% = toolbox%!12 - toolbox%!4 : REM Visible Area Maximum X - Minimum X -box_height% = toolbox%!16 - toolbox%!8 : REM Visible Area Maximum Y - Minimum Y +box_width% = toolbox%!12 - toolbox%!4 : REM Visible Area X1 - X0 +box_height% = toolbox%!16 - toolbox%!8 : REM Visible Area Y1 - Y0 -REM Move the pane so that it's in the correct X and Y position +REM Move the toolbox pane so that it's in the correct X and Y position REM relative to where the main window is to go. -toolbox%!4 = main%!4 - box_width% : REM Visible Area Minimum X -toolbox%!8 = main%!16 - box_height% : REM Visible Area Minimum Y -toolbox%!12 = main%!4 : REM Visible Area Maximum X -toolbox%!16 = main%!16 : REM Visible Area Maximum Y +toolbox%!4 = main%!4 - box_width% : REM Visible Area X0 +toolbox%!8 = main%!16 - box_height% : REM Visible Area Y0 +toolbox%!12 = main%!4 : REM Visible Area X1 +toolbox%!16 = main%!16 : REM Visible Area Y1 -REM Unless the main window is to be opened behind the pane, meaning that the -REM pane must already be in the correct place in the stack, set the pane's -REM Open Behind so that it appears in the stack where the main window is to go. +REM Open the toolbox pane behind the same window that the main window +REM was opened behind. This will place it directly in front of the +REM main window. -IF main%!28 <> ToolBoxWindow% THEN toolbox%!28 = main%!28 +toolbox%!28 = main%!28 SYS "Wimp_OpenWindow",,toolbox% - -REM Set the main window's Open Behind so that it opens behind the pane. - -main%!28 = ToolBoxWindow% - -SYS "Wimp_OpenWindow",,main% ENDPROC

Running our new application should reveal a main window similar to that shown in . If the main window is moved, the pane should remain securely attached at all times.

@@ -303,12 +302,12 @@ ENDPROC REM Move the pane so that it's in the correct X and Y position REM relative to where the main window is to go. -toolbox%!4 = main%!4 - box_width% : REM Visible Area Minimum X -toolbox%!8 = main%!16 - box_height% : REM Visible Area Minimum Y -toolbox%!12 = main%!4 : REM Visible Area Maximum X -toolbox%!16 = main%!16 : REM Visible Area Maximum Y +toolbox%!4 = main%!4 - box_width% : REM Visible Area X0 +toolbox%!8 = main%!16 - box_height% : REM Visible Area Y0 +toolbox%!12 = main%!4 : REM Visible Area X1 +toolbox%!16 = main%!16 : REM Visible Area Y1 -

We can replace this by testing the minimum X coordinate of the main window’s visible area, then applying different calculations for the pane’s X coordinates as follows:

+

We can replace this by testing the minimum X0 coordinate of the main window’s visible area, then applying different calculations for the pane’s X coordinates as follows:

  • If the main window is on-screen by more than the width of the pane, then the pane is anchored by its right-hand edge as before.
  • @@ -323,18 +322,18 @@ REM relative to where the main window is to go. CASE TRUE OF WHEN main%!4 > box_width% - toolbox%!4 = main%!4 - box_width% : REM Visible Area Minimum X - toolbox%!12 = main%!4 : REM Visible Area Maximum X + toolbox%!4 = main%!4 - box_width% : REM Visible Area X0 + toolbox%!12 = main%!4 : REM Visible Area X1 WHEN main%!4 > 0 - toolbox%!4 = 0 : REM Visible Area Minimum X - toolbox%!12 = box_width% : REM Visible Area Maximum X + toolbox%!4 = 0 : REM Visible Area X0 + toolbox%!12 = box_width% : REM Visible Area X1 OTHERWISE - toolbox%!4 = main%!4 : REM Visible Area Minimum X - toolbox%!12 = main%!4 + box_width% : REM Visible Area Maximum X + toolbox%!4 = main%!4 : REM Visible Area X0 + toolbox%!12 = main%!4 + box_width% : REM Visible Area X1 ENDCASE -toolbox%!8 = main%!16 - box_height% : REM Visible Area Minimum Y -toolbox%!16 = main%!16 : REM Visible Area Maximum Y +toolbox%!8 = main%!16 - box_height% : REM Visible Area Y0 +toolbox%!16 = main%!16 : REM Visible Area Y1

    With this in place, our own pane begins to behave in a more Draw-like way when it reaches the edge of the screen, as seen in .

    diff --git a/Chapters/ch03-a-top-toolbar.xml b/Chapters/ch03-a-top-toolbar.xml index 13b0d1e..7b5e77d 100644 --- a/Chapters/ch03-a-top-toolbar.xml +++ b/Chapters/ch03-a-top-toolbar.xml @@ -44,7 +44,7 @@ Many applications have toolbars across the tops of their windows; just don’t call them ribbons.
    -

    An alternative to a toolbox at the side of a window, as we created in the last chapter, is a toolbar across the top of a window. Which to go for is more of a stylistic question than a technical one, and it’s possible to have both at the same time. Ovation Pro does just this, as seen in .

    +

    An alternative to a toolbox at the side of a window, as we created in the last chapter, is a toolbar across the top of a window. Which to go for is more of a stylistic question than a technical one, and it’s even possible to have both at the same time. Ovation Pro does just this, as can be seen in .

    @@ -66,7 +66,7 @@

    The height of the work area (Y1Y0) is set to be 60 OS Units: this allows a standard writeable icon with a height of 52 OS Units, plus a 4 OS Unit space above and below it.

    -

    We have also adjusted the minimum sizes of the bar, although this is as much to keep WinEd happy: with the minimum y dimenstion set to zero, the Wimp will limit the size to that required for the vertical scroll bar which WinEd applies in editing mode, making it hard to set the dimensions that we require.

    +

    We have also adjusted the minimum sizes of the bar, although this is as much to keep WinEd happy as anything else: with the minimum y dimension set to zero, the Wimp will limit the size to that required for the vertical scroll bar which WinEd applies in editing mode, making it hard to set the dimensions that we require.

    The window contains two action buttons and a writeable icon, so that we can easily see how the work area moves around in relation to its parent window. All three icons are 52 OS Units high, to match the standard height for a writeable icon, and there is a 4 OS Unit gap around the edges of the work area on all four sides.

    @@ -104,7 +104,7 @@ SYS "Wimp_GetWindowState",,toolbar%

    The calculations for the position of the toolbox will remain as they are, before which we will insert in a similar set of calculations for the new toolbar. To be able to do this, we’ll need the height of the bar – which we can get from its visible area as before.

    -box_height% = toolbar%!16 - toolbar%!8 : REM Visible Area Maximum Y - Minimum Y +bar_height% = toolbar%!16 - toolbar%!8 : REM Visible Area Y1 - Y0

    We don’t need the width of the bar, because that will be tied to the width of the main window’s visible area as shown in .

    @@ -112,13 +112,13 @@ SYS "Wimp_GetWindowState",,toolbar%

    The tops of the two windows (Y1 for the two visible areas) are once again level, whilst the bottom of the pane (its Y0) is the height of the pane below the top (Y1) of the main window. This means that the vertical dimensions for the toolbar’s visible area are calculated in exactly the same way as for the toolbox.

    -toolbar%!8 = main%!16 - box_height% : REM Visible Area Minimum Y -toolbar%!16 = main%!16 : REM Visible Area Maximum Y +toolbar%!8 = main%!16 - bar_height% : REM Visible Area Y0 +toolbar%!16 = main%!16 : REM Visible Area Y1

    The horizontal positioning of the toolbar is, if anything, easier than for the toolbox: it aligns completely with the visible area of the main window, so X0 and X1 can be copied directly from the main window’s data block.

    -toolbar%!4 = main%!4 : REM Visible Area Minimum X -toolbar%!12 = main%!12 : REM Visible Area Maximum X +toolbar%!4 = main%!4 : REM Visible Area X0 +toolbar%!12 = main%!12 : REM Visible Area X1

    This is why the horizontal extent of the pane has to match that of the main window: if the main window is fully extended, the pane has to be able to follow suit.

    @@ -129,26 +129,18 @@ toolbar%!12 = main%!12 : REM Visible Area Maximum X

    Just as with our previous example, the two panes must appear directly in front of the main window in the window stack. The exact order doesn’t matter to the Wimp, so we will choose to put the toolbar in front of the main window, and the toolbox in front of the toolbar. When deciding, it pays to look at positions where the different panes might overlap, and consider which will look best to the user.

    -

    As before, we start at the top of the pile of panes and work down towards the main window – so the first thing to open is the toolbox.

    +

    As before, we start at the top of the pile of panes and work down towards the main window – so the first thing to open is the toolbox directly behind the window that’s in fronty of the main window – exactly as we did before.

    -IF (main%!28 <> ToolBarWindow%) OR (toolbar%!28 <> ToolBoxWindow%) THEN toolbox%!28 = main%!28 +toolbox%!28 = main%!28 SYS "Wimp_OpenWindow",,toolbox% -

    We still need to check to see if the windows are already in their correct places in the stack, but with two panes to consider we must now check both whether the main window is behind the toolbar, and whether the toolbar is behind the toolbox. If either isn’t in the correct place, then we will need to re-position the toolbox – as the top window of the pile – and work down from that.

    - -

    With the toolbox open, we can open the toolbar behind it...

    +

    With the toolbox open in the correct place, we can open the toolbar behind it, which will mean that it will end up directly in front of the main window.

    toolbar%!28 = ToolBoxWindow% SYS "Wimp_OpenWindow",,toolbar% -

    ...and then, at the bottom of our little pile of windows, comes the main window itself.

    - -main%!28 = ToolBarWindow% - -SYS "Wimp_OpenWindow",,main% -

    Putting all of the new code together with the old, PROChandle_pane_windows() now looks as shown in .

    DEF PROChandle_pane_windows(main%) @@ -156,6 +148,9 @@ LOCAL toolbox%, toolbar%, box_width%, box_height%, bar_height% REM Get the Window State block for the toolbox pane, using some of the REM spare space above the data for the state of the main window. +REM +REM Note: ON RISC OS 5, we could more clearly use DIM toolbox% LOCAL 64 +REM here to allocate the required memory from the stack. toolbox% = main% + 64 @@ -172,45 +167,44 @@ SYS "Wimp_GetWindowState",,toolbar% REM Find the height of the toolbar pane's visible area. -bar_height% = toolbar%!16 - toolbar%!8 : REM Visible Area Maximum Y - Minimum Y +bar_height% = toolbar%!16 - toolbar%!8 : REM Visible Area Y1 - Y0 REM Move the toolbar pane so that it's in the correct X and Y position REM relative to where the main window is to go. -toolbar%!4 = main%!4 : REM Visible Area Minimum X -toolbar%!8 = main%!16 - bar_height% : REM Visible Area Minimum Y -toolbar%!12 = main%!12 : REM Visible Area Maximum X -toolbar%!16 = main%!16 : REM Visible Area Maximum Y +toolbar%!4 = main%!4 : REM Visible Area X0 +toolbar%!8 = main%!16 - bar_height% : REM Visible Area Y0 +toolbar%!12 = main%!12 : REM Visible Area X1 +toolbar%!16 = main%!16 : REM Visible Area Y1 REM Find the width and height of the toolbox pane's visible area. -box_width% = toolbox%!12 - toolbox%!4 : REM Visible Area Maximum X - Minimum X -box_height% = toolbox%!16 - toolbox%!8 : REM Visible Area Maximum Y - Minimum Y +box_width% = toolbox%!12 - toolbox%!4 : REM Visible Area X1 - X0 +box_height% = toolbox%!16 - toolbox%!8 : REM Visible Area Y1 - Y0 REM Move the toolbox pane so that it's in the correct X and Y position REM relative to where the main window is to go. CASE TRUE OF WHEN main%!4 > box_width% - toolbox%!4 = main%!4 - box_width% : REM Visible Area Minimum X - toolbox%!12 = main%!4 : REM Visible Area Maximum X + toolbox%!4 = main%!4 - box_width% : REM Visible Area X0 + toolbox%!12 = main%!4 : REM Visible Area X1 WHEN main%!4 > 0 - toolbox%!4 = 0 : REM Visible Area Minimum X - toolbox%!12 = box_width% : REM Visible Area Maximum X + toolbox%!4 = 0 : REM Visible Area X0 + toolbox%!12 = box_width% : REM Visible Area X1 OTHERWISE - toolbox%!4 = main%!4 : REM Visible Area Minimum X - toolbox%!12 = main%!4 + box_width% : REM Visible Area Maximum X + toolbox%!4 = main%!4 : REM Visible Area X0 + toolbox%!12 = main%!4 + box_width% : REM Visible Area X1 ENDCASE -toolbox%!8 = main%!16 - box_height% : REM Visible Area Minimum Y -toolbox%!16 = main%!16 : REM Visible Area Maximum Y +toolbox%!8 = main%!16 - box_height% : REM Visible Area Y0 +toolbox%!16 = main%!16 : REM Visible Area Y1 -REM Unless the main window is to be opened behind the toolbar pane, and the -REM toolbar pane is already behind the toolbox pane, meaning that all three -REM windows must already be in the correct place in the stack, set the toolbox's -REM Open Behind so that it appears in the stack where the main window is to go. +REM Open the toolbox pane behind the same window that the main window +REM was opened behind. This will place it directly in front of the +REM main window. -IF (main%!28 <> ToolBarWindow%) OR (toolbar%!28 <> ToolBoxWindow%) THEN toolbox%!28 = main%!28 +toolbox%!28 = main%!28 SYS "Wimp_OpenWindow",,toolbox% @@ -219,12 +213,6 @@ REM Set the toolbar window's Open Behind so that it opens behind the toolbox. toolbar%!28 = ToolBoxWindow% SYS "Wimp_OpenWindow",,toolbar% - -REM Set the main window's Open Behind so that it opens behind the toolbar. - -main%!28 = ToolBarWindow% - -SYS "Wimp_OpenWindow",,main% ENDPROC

    Running the updated application should reveal a new toolbar attached to the top of the main window, as shown in . If resized or moved around the screen, both the toolbar and the original toolbox should move and adjust their sizes together. Note that if the caret is placed in the toolbar’s writeable icon, the main window is shown as having input focus: this is a result of the panes having their ‘window is a pane’ flags set.

    @@ -268,8 +256,8 @@ ENDPROC

    An alternative approach would be to push the toolbox down the side of the main window, so that it sits below the base of the toolbar. This is simple enough to do, and can be achieved by adding in the height of the toolbar to the calculation in PROChandle_pane_windows() which sets the vertical position of the toolbox – the changes required can be seen in .

    -toolbox%!8 = main%!16 - (bar_height% + box_height%) : REM Visible Area Minimum Y -toolbox%!16 = main%!16 - bar_height% : REM Visible Area Maximum Y +toolbox%!8 = main%!16 - (bar_height% + box_height%) : REM Visible Area Y0 +toolbox%!16 = main%!16 - bar_height% : REM Visible Area Y1

    With this small modification in place, the toolbar is now anchored lower down the side of the main window and slides in below the work area of the toolbar as seen in .

    @@ -290,12 +278,12 @@ toolbox%!16 = main%!16 - bar_height% : REM Visible Area Maximum Y

    However, if we’re happy to only support machines from the RiscPC onwards – which isn’t an unreasonable idea in modern software – then we can improve things more easily. RISC OS 3.5 introduced a new Wimp_ResizeIcon SWI, which we can use to adjust the size of the writeable icon as we re-open the panes.

    -

    To make the application as general as possible, we’ll start by adding the code shown in to PROCinitialise. This will check to see if the Wimp_ResizeIcon functionality is available; if it isn’t, we can just skip the resizing operation.

    +

    To make the application as general as possible, we’ll start by adding the code shown in to PROCinitialise. This will check to see if the Wimp_ResizeIcon functionality is available; if it isn’t, we can just skip the resizing operation. This way, the application will still work all the way back to RISC OS 3.1, albeit with less visual finesse.

    SYS "XOS_SWINumberFromString",,"Wimp_ResizeIcon" TO ;flags% ResizeIconAvailable% = ((flags% AND 1) = 0) -

    This attempts to read the number for the Wimp_ResizeIcon SWI; if the SWI doesn’t exist, an error will be raised and the call will return with the V flag set. The value of the flag is tested, and the ResizeIconAvailable% variable set to TRUE or FALSE depending on the outcome. It’s good practice to test for specific functionality when possible, instead of testing Wimp or OS version numbers – aside from anything else, it’s much easier to keep on top of in terms of code complexity!

    +

    The code attempts to read the number for the Wimp_ResizeIcon SWI; if the SWI doesn’t exist, an error will be raised and the call will return with the V flag set. The value of the flag is tested, and the ResizeIconAvailable% variable set to TRUE or FALSE depending on the outcome. It’s good practice to test for specific functionality when possible, instead of testing Wimp or OS version numbers – aside from anything else, it’s much easier to keep on top of in terms of code complexity!

    The resizing operation itself can be performed in PROChandle_pane_windows(), immediately after the position of the toolbar window has been set. The code required can be seen in – it has been bracketed in an IF ... ENDIF statement, so that it will only be called if the Wimp_ResizeIcon SWI is available.

    @@ -306,7 +294,7 @@ ResizeIconAvailable% = ((flags% AND 1) = 0) icon%!4 = 0 : REM Writeable Icon Handle SYS "Wimp_GetIconState",,icon% - bar_rhs% = (toolbar%!12 - toolbar%!4) + toolbar%!20 : REM Visible Area (Maximum - Minimum) + X Scroll Offset + bar_rhs% = (toolbar%!12 - toolbar%!4) + toolbar%!20 : REM Visible Area (X1 - X0) + X Scroll Offset SYS "Wimp_ResizeIcon", icon%!0, icon%!4, icon%!8, icon%!12, bar_rhs% - 4, icon%!20 SYS "Wimp_ForceRedraw", ToolBarWindow%, icon%!8, icon%!12, bar_rhs%, icon%!20 diff --git a/Chapters/ch04-column-headings.xml b/Chapters/ch04-column-headings.xml index 0b25b1e..017e447 100644 --- a/Chapters/ch04-column-headings.xml +++ b/Chapters/ch04-column-headings.xml @@ -76,8 +76,8 @@ SYS "Wimp_OpenTemplate",,"<PaneDemo$Dir>.Templates" PROCtemplate_load("Main", b%, buffer_size%, -1) SYS "Wimp_CreateWindow",,b% TO MainWindow% -WindowWidth% = b%!8 - b%!0 : REM Width is Visible Area Maximum X - Minimun X -WindowHeight% = b%!12 - b%!4 : REM Height is Visible Area Maximum Y - Minimun Y +WindowWidth% = b%!8 - b%!0 : REM Width is Visible Area X1 - X0 +WindowHeight% = b%!12 - b%!4 : REM Height is Visible Area Y1 - Y0 PROCtemplate_load("Toolbar", b%, buffer_size%, -1) SYS "Wimp_CreateWindow",,b% TO ToolBarWindow% @@ -98,13 +98,16 @@ ENDIF SYS "Wimp_CloseWindow",,b% ENDPROC -

    Finall, PROChandle_pane_windows() can be simplified again; it is now as shown in .

    +

    Finally, PROChandle_pane_windows() can be simplified again; it is now as shown in .

    DEF PROChandle_pane_windows(main%) LOCAL toolbar%, bar_height% -REM Get the Window State block for the toolbar pane, using more of the +REM Get the Window State block for the toolbar pane, using some of the REM spare space above the data for the state of the main window. +REM +REM Note: ON RISC OS 5, we could more clearly use DIM toolbox% LOCAL 64 +REM here to allocate the required memory from the stack. toolbar% = main% + 64 @@ -113,30 +116,23 @@ SYS "Wimp_GetWindowState",,toolbar% REM Find the height of the toolbar pane's visible area. -bar_height% = toolbar%!16 - toolbar%!8 : REM Visible Area Maximum Y - Minimum Y +bar_height% = toolbar%!16 - toolbar%!8 : REM Visible Area Y1 - Y0 REM Move the toolbar pane so that it's in the correct X and Y position REM relative to where the main window is to go. -toolbar%!4 = main%!4 : REM Visible Area Minimum X -toolbar%!8 = main%!16 - bar_height% : REM Visible Area Minimum Y -toolbar%!12 = main%!12 : REM Visible Area Maximum X -toolbar%!16 = main%!16 : REM Visible Area Maximum Y +toolbar%!4 = main%!4 : REM Visible Area X0 +toolbar%!8 = main%!16 - bar_height% : REM Visible Area Y0 +toolbar%!12 = main%!12 : REM Visible Area X1 +toolbar%!16 = main%!16 : REM Visible Area Y1 -REM Unless the main window is to be opened behind the toolbar pane, and the -REM toolbar pane is already behind the toolbox pane, meaning that all three -REM windows must already be in the correct place in the stack, set the toolbox's -REM Open Behind so that it appears in the stack where the main window is to go. +REM Open the toolbar pane behind the same window that the main window +REM was opened behind. This will place it directly in front of the +REM main window. -IF main%!28 <> ToolBarWindow% THEN toolbar%!28 = main%!28 +toolbar%!28 = main%!28 SYS "Wimp_OpenWindow",,toolbar% - -REM Set the main window's Open Behind so that it opens behind the toolbar. - -main%!28 = ToolBarWindow% - -SYS "Wimp_OpenWindow",,main% ENDPROC

    The code here should be comparable to that found in – a single pane, but attached in a toolbar style instead of a toolbox. When run, the window should appear as seen in , with the new column headings lining up with the coloured grid squares below.

    @@ -162,7 +158,7 @@ ENDPROC toolbar%!20 = main%!20 : REM X Scroll Offset -

    Things to consider here are that both the main window and the toolbar are the same width (we copy the X0 and X1 across unchanged as part of the pane positioning), and their horizontal extents are identical (both are set to 1040 in their window templates). As such, copying the X scroll offset across from one window to the other will have no unexpected effects.

    +

    Things to consider here are that both the main window and the toolbar are the same width (we copy the X0 and X1 across unchanged as part of the pane positioning), and their horizontal extents are identical (both are set to 1040 OS Units in their window templates). As such, copying the X scroll offset across from one window to the other will have no unexpected effects.

    If the pane were up the side of the window instead of across the top, and the vertical extents were the same, it would be possible to copy the vertical scroll offset (at offset 24 into the window state block) across to the pane instead. This might be useful for a pane containing row numbers, as seen in the Fireworkz window above, for example.

    @@ -171,8 +167,11 @@ ENDPROC DEF PROChandle_pane_windows(main%) LOCAL toolbar%, bar_height% -REM Get the Window State block for the toolbar pane, using more of the +REM Get the Window State block for the toolbar pane, using some of the REM spare space above the data for the state of the main window. +REM +REM Note: ON RISC OS 5, we could more clearly use DIM toolbox% LOCAL 64 +REM here to allocate the required memory from the stack. toolbar% = main% + 64 @@ -181,34 +180,27 @@ SYS "Wimp_GetWindowState",,toolbar% REM Find the height of the toolbar pane's visible area. -bar_height% = toolbar%!16 - toolbar%!8 : REM Visible Area Maximum Y - Minimum Y +bar_height% = toolbar%!16 - toolbar%!8 : REM Visible Area Y1 - Y0 REM Move the toolbar pane so that it's in the correct X and Y position REM relative to where the main window is to go. -toolbar%!4 = main%!4 : REM Visible Area Minimum X -toolbar%!8 = main%!16 - bar_height% : REM Visible Area Minimum Y -toolbar%!12 = main%!12 : REM Visible Area Maximum X -toolbar%!16 = main%!16 : REM Visible Area Maximum Y +toolbar%!4 = main%!4 : REM Visible Area X0 +toolbar%!8 = main%!16 - bar_height% : REM Visible Area Y0 +toolbar%!12 = main%!12 : REM Visible Area X1 +toolbar%!16 = main%!16 : REM Visible Area Y1 REM Align the toolbar pane's scroll offset with the main window. -toolbar%!20 = main%!20 : REM X Scroll Offset +toolbar%!20 = main%!20 : REM X Scroll Offset -REM Unless the main window is to be opened behind the toolbar pane, and the -REM toolbar pane is already behind the toolbox pane, meaning that all three -REM windows must already be in the correct place in the stack, set the toolbox's -REM Open Behind so that it appears in the stack where the main window is to go. +REM Open the toolbar pane behind the same window that the main window +REM was opened behind. This will place it directly in front of the +REM main window. -IF main%!28 <> ToolBarWindow% THEN toolbar%!28 = main%!28 +toolbar%!28 = main%!28 SYS "Wimp_OpenWindow",,toolbar% - -REM Set the main window's Open Behind so that it opens behind the toolbar. - -main%!28 = ToolBarWindow% - -SYS "Wimp_OpenWindow",,main% ENDPROC

    Loading this version of the application, we can now scroll around the main window’s work area with the column headings in the toolbar remaining in step as seen in .

    diff --git a/Downloads/Chapter01/ExampleApp/!PaneDemo/!RunImage,ffb b/Downloads/Chapter01/ExampleApp/!PaneDemo/!RunImage,ffb index 78c50e5..62a6a37 100644 Binary files a/Downloads/Chapter01/ExampleApp/!PaneDemo/!RunImage,ffb and b/Downloads/Chapter01/ExampleApp/!PaneDemo/!RunImage,ffb differ diff --git a/Downloads/Chapter02/SideBox1/!PaneDemo/!RunImage,ffb b/Downloads/Chapter02/SideBox1/!PaneDemo/!RunImage,ffb index 54905c1..dfae01c 100644 Binary files a/Downloads/Chapter02/SideBox1/!PaneDemo/!RunImage,ffb and b/Downloads/Chapter02/SideBox1/!PaneDemo/!RunImage,ffb differ diff --git a/Downloads/Chapter02/SideBox2/!PaneDemo/!RunImage,ffb b/Downloads/Chapter02/SideBox2/!PaneDemo/!RunImage,ffb index 26ad07b..bc44401 100644 Binary files a/Downloads/Chapter02/SideBox2/!PaneDemo/!RunImage,ffb and b/Downloads/Chapter02/SideBox2/!PaneDemo/!RunImage,ffb differ diff --git a/Downloads/Chapter03/TopBar1/!PaneDemo/!RunImage,ffb b/Downloads/Chapter03/TopBar1/!PaneDemo/!RunImage,ffb index cbfeef7..06d4ae8 100644 Binary files a/Downloads/Chapter03/TopBar1/!PaneDemo/!RunImage,ffb and b/Downloads/Chapter03/TopBar1/!PaneDemo/!RunImage,ffb differ diff --git a/Downloads/Chapter03/TopBar2/!PaneDemo/!RunImage,ffb b/Downloads/Chapter03/TopBar2/!PaneDemo/!RunImage,ffb index 0d66539..760dd4b 100644 Binary files a/Downloads/Chapter03/TopBar2/!PaneDemo/!RunImage,ffb and b/Downloads/Chapter03/TopBar2/!PaneDemo/!RunImage,ffb differ diff --git a/Downloads/Chapter03/TopBar3/!PaneDemo/!RunImage,ffb b/Downloads/Chapter03/TopBar3/!PaneDemo/!RunImage,ffb index 0c69086..e41efcd 100644 Binary files a/Downloads/Chapter03/TopBar3/!PaneDemo/!RunImage,ffb and b/Downloads/Chapter03/TopBar3/!PaneDemo/!RunImage,ffb differ diff --git a/Downloads/Chapter03/TopBar4/!PaneDemo/!RunImage,ffb b/Downloads/Chapter03/TopBar4/!PaneDemo/!RunImage,ffb index a030967..80eaa83 100644 Binary files a/Downloads/Chapter03/TopBar4/!PaneDemo/!RunImage,ffb and b/Downloads/Chapter03/TopBar4/!PaneDemo/!RunImage,ffb differ diff --git a/Downloads/Chapter04/ColHead1/!PaneDemo/!RunImage,ffb b/Downloads/Chapter04/ColHead1/!PaneDemo/!RunImage,ffb index 29c9805..ba647b6 100644 Binary files a/Downloads/Chapter04/ColHead1/!PaneDemo/!RunImage,ffb and b/Downloads/Chapter04/ColHead1/!PaneDemo/!RunImage,ffb differ diff --git a/Downloads/Chapter04/ColHead2/!PaneDemo/!RunImage,ffb b/Downloads/Chapter04/ColHead2/!PaneDemo/!RunImage,ffb index ba22c8e..cf28fa6 100644 Binary files a/Downloads/Chapter04/ColHead2/!PaneDemo/!RunImage,ffb and b/Downloads/Chapter04/ColHead2/!PaneDemo/!RunImage,ffb differ diff --git a/panes.xml b/panes.xml index c11a6fd..68b19bb 100644 --- a/panes.xml +++ b/panes.xml @@ -56,7 +56,7 @@

    The examples in this tutorial are written in BASIC, but the techniques are equally applicable to other languages such as C – I hope that I have managed to explain them in a way that allows them to be applied in your environment of choice. The example code is all licenced under the MIT No Attribution Licence, with the aim of making it as widely useful as possible.

    -

    Many thanks to all those on the ROOL Forums who have offered suggestions while I’ve worked on this guide.

    +

    Many thanks to all those on the ROOL Forums who have offered suggestions while I’ve worked on this guide; in particular Steve Drain, whose input helped to clarify some of my misunderstandings on the subject.