From b6c9d4d1e4757a50deb5d5f4fa35e2b7c42666ee Mon Sep 17 00:00:00 2001 From: Steve Fryatt Date: Sat, 21 Jan 2023 00:50:18 +0000 Subject: [PATCH] Perform editing and revision of text and formatting. --- Chapters/ch01-an-example-application.xml | 24 ++++++++++---------- Chapters/ch02-a-side-toolbox.xml | 28 ++++++++++++------------ Chapters/ch03-a-top-toolbar.xml | 20 ++++++++--------- Chapters/ch04-column-headings.xml | 8 +++---- Chapters/ch05-does-order-matter.xml | 26 +++++++++++----------- Chapters/ch06-the-nested-wimp.xml | 12 +++++----- Chapters/ch07-responsive-nesting.xml | 4 ++-- Chapters/ch08-moving-the-furniture.xml | 8 +++---- Chapters/ch09-an-embedded-toolbox.xml | 24 ++++++++++---------- 9 files changed, 77 insertions(+), 77 deletions(-) diff --git a/Chapters/ch01-an-example-application.xml b/Chapters/ch01-an-example-application.xml index 16d61d4..a51e691 100644 --- a/Chapters/ch01-an-example-application.xml +++ b/Chapters/ch01-an-example-application.xml @@ -96,7 +96,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 (remembering that in BASIC, DIM includes zero in its byte count). 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 when calling other Wimp SWIs.

-

The program indicates that it knows about Wimp version 3.10 by passing 310 in R1 to Wimp_Initialise: whilst pane code will work on RISC OS 2, modern applications will usually 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. The 310 means that Wimp_Initialise will expect to be passed a pointer to a zero-terminated list of user messages that the application requires in R3; we only care about Message_Quit, however, so we can simply pass 0 (a “null” pointer) to say “no other messages”.

+

The program indicates that it knows about Wimp version 3.10 by passing 310 in R1 to Wimp_Initialise: whilst pane code will work on RISC OS 2, modern applications will usually 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. The 310 means that Wimp_Initialise will expect to be passed a pointer to a zero-terminated list of user messages that the application requires in R3; we only care about Message_Quit, however, so we can simply pass 0 (a “null” pointer) to say “no other messages”.

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

@@ -164,7 +164,7 @@ Run <PaneDemo$Dir>.!RunImage PROCcreate_iconbar_icon(TaskSprite$) -

It uses a PROCcreate_iconbar_icon() procedure to do the hard work, which is defined in .

+

It uses a PROCcreate_iconbar_icon procedure to do the hard work, which is defined in .

DEF PROCcreate_iconbar_icon(sprite$) q%!0 = -1 @@ -211,7 +211,7 @@ SYS "Wimp_CloseTemplate"

The code opens the Templates file with Wimp_OpenTemplate, then loads the templates for the main window and program information window in turn. For each, a window is created immediately using Wimp_CreateWindow, with the handles being stored in the MainWindow% and InfoWindow% variables respectively. We also take the opportunity to calculate the width and height of the main window in OS Units, and store the values in the WindowWidth% and WindowHeight% variables for future reference.

-

The code uses PROCtemplate_load(), which puts a friendly wrapping around the Wimp_LoadTemplate SWI and expects there to be a global TemplateName% variable pointing to a 12 character, word-aligned buffer for holding the template names. Its definition can be seen in .

+

The code uses PROCtemplate_load, which puts a friendly wrapping around the Wimp_LoadTemplate SWI and expects there to be a global TemplateName% variable pointing to a 12 character, word-aligned buffer for holding the template names. Its definition can be seen in .

DEF PROCtemplate_load(name$, buffer%, size%, fonts%) LOCAL templ_size%, indir_size%, workspace% @@ -286,11 +286,11 @@ ENDPROC

This follows the standard approach to opening a window: obtain the parameter block required by Wimp_OpenWindow with a call to Wimp_GetWindowState, then adjust the parameters as required.

-

If the window isn’t currently on screen – which we can tell by looking at the ‘window is open’ flag at bit 16 of the window flags stored at offset 32 into the returned parameter block – then we take the opportunity to adjust the window’s size and position so that its visible area is centred on the screen and as large as possible without filling more than three quarters of the display. The screen width and height are read using an FNread_mode_dimension() function that we’ll define shortly, and this information is used to decide the maximum size that we wish the window to be. The window’s visible area coordinates (at offsets 4 to 16 in the block) are then updated to centre the window. If the window is already open, we leave the coordinates alone as we don’t want it to jump around or resize itself on screen. Finally, the scroll offsets – at offsets 20 and 24 into the block – are reset to zero so that the window appears fully scrolled to the top-left regardless of size.

+

If the window isn’t currently on screen – which we can tell by looking at the ‘window is open’ flag at bit 16 of the window flags stored at offset 32 into the returned parameter block – then we take the opportunity to adjust the window’s size and position so that its visible area is centred on the screen and as large as possible without filling more than three quarters of the display. The screen width and height are read using an FNread_mode_dimension function that we’ll define shortly, and this information is used to decide the maximum size that we wish the window to be. The window’s visible area coordinates (at offsets 4 to 16 in the block) are then updated to centre the window. If the window is already open, we leave the coordinates alone as we don’t want it to jump around or resize itself on screen. Finally, the scroll offsets – at offsets 20 and 24 into the block – are reset to zero so that the window appears fully scrolled to the top-left regardless of size.

The handle of the window to open behind (at offset 28 into the block) is set to −1, indicating “at the top of the stack”, and then the block is passed to Wimp_OpenWindow to perform the operation. Taken together, this will mean that if the user clicks on our iconbar icon and the window is not open, it will be opened in front of the other windows and centred on the screen. If the window is open, however, a click on the iconbar will simply bring it to the top of the stack in its current position.

-

The FNread_mode_dimension() that is used to read the screen dimensions is defined in .

+

The FNread_mode_dimension that is used to read the screen dimensions is defined in .

DEF FNread_mode_dimension(pixelvar%, eigenvar%) LOCAL flags%, eigenfactor%, pixels% @@ -346,7 +346,7 @@ IconbarMenu% = FNmenu_construct("PaneDemo", 2) PROCmenu_add_entry(IconbarMenu%, 0, "Info", InfoWindow%) PROCmenu_add_entry(IconbarMenu%, 1, "Quit", 0) -

The code initialises a gobal variable named MenuOpen%, which is used to track the handle of the currently open menu. It then uses FNmenu_construct() and PROCmenu_add_entry() to build up the menu structure in memory. A pointer to the structure is stored in the IconbarMenu% variable, so the the menu can be accessed again later.

+

The code initialises a gobal variable named MenuOpen%, which is used to track the handle of the currently open menu. It then uses FNmenu_construct and PROCmenu_add_entry to build up the menu structure in memory. A pointer to the structure is stored in the IconbarMenu% variable, so the the menu can be accessed again later.

The memory for the menu is allocated using the general purpose FNmenu_construct, which is defined in .

@@ -411,9 +411,9 @@ IF (buffer% <> 0) THEN menu%!36 = menu%!36 OR &100

Taking the menu title and the number of entries that it will contain as parameters, the function calculates the size of block required (at 28 bytes plus an additional 24 for each entry), then uses DIM to allocate the required amount. In fact, we allocate one additional byte, for reasons which will become apparent when we start to add entries to the block.

-

The menu title is set up – using an indirected string, again allocated using DIM, if it contains more than twelve characters – and then the remainder of the menu header is filled in with the standard values. Finally each of the menu entries is initialised to be non-indirected, with an empty string and the default sets of flags. The final item has the menu flags set to &80 to indicate that it is the last, while after the loop has completed, the first item will have its menu flags updated to include &100 if the title was indirected.

+

The menu title is set up – using an indirected string, again allocated using DIM, if it contains more than twelve characters – and then the remainder of the menu header is filled in with the standard values. Finally each of the menu entries is initialised to be non-indirected, with an empty string and the default sets of flags. The final item has the menu flags set to &80 to indicate that it is the last, while after the loop has completed, the first item will have its menu flags updated to include &100 if the title was indirected.

-

With the structure set up, PROCmenu_add_entry(), as defined in , is used to fill in the entries.

+

With the structure set up, PROCmenu_add_entry, as defined in , is used to fill in the entries.

DEF PROCmenu_add_entry(menu%, entry%, text$, sub_menu%) LOCAL definition%, buffer%, length%, width% @@ -458,11 +458,11 @@ ENDPROC

This routine takes a pointer to the menu block to be updated and the index of the target entry, along with the menu item text and a submenu pointer (which can be zero if not required). It starts by finding the address of the entry within the block by stepping through the menu structure, checking the ‘last item’ flag bits as it goes. This way, there's no danger of inadvertently writing off the end of a menu block by getting entry numbers confused.

-

Once the entry has been found, the text is stored in a similar way to that used by FNmenu_construct() for the menu title. If the text is twelve characters or less in length, then it is stored directly in the icon’s data; otherwise, an indirected buffer is claimed, the text is stored in that, then the icon is configured to use it. The reason that FNmenu_construct() allocated an additional byte for the menu block lies here: if the final item’s text is twelve characters long, then the $ operator used to store the text will write its terminator into the byte immediately following the menu block!

+

Once the entry has been found, the text is stored in a similar way to that used by FNmenu_construct for the menu title. If the text is twelve characters or less in length, then it is stored directly in the icon’s data; otherwise, an indirected buffer is claimed, the text is stored in that, then the icon is configured to use it. The reason that FNmenu_construct allocated an additional byte for the menu block lies here: if the final item’s text is twelve characters long, then the $ operator used to store the text will write its terminator into the byte immediately following the menu block!

With the item’s text stored, the menu’s width is updated to reflect it. This value is only used when the System Font is selected for the desktop, so the code assumes that characters are 16 OS Units wide for the purposes of the calculation. Finally, the submenu pointer is updated with the value supplied.

-

With the menu created, we need to be able to open it on screen – a task which is carried out by PROCmenu_create_iconbar() in .

+

With the menu created, we need to be able to open it on screen – a task which is carried out by PROCmenu_create_iconbar in .

DEF PROCmenu_create_iconbar(menu%, x%) LOCAL ptr%, height% @@ -486,7 +486,7 @@ ENDPROC

The Style Guide dictates that iconbar menus are opened 64 OS Units to the left of the mouse position, with their base 96 OS Units from the bottom of the screen. To achieve this, we step through the menu entries adding up the heights of each entry and its associated gap, plus any separators that they have. At the end of this, we will have one gap too many, so one is removed. Finally, the address of the menu block is stored in the global MenuOpen% for future reference, and the menu is opened with a call to Wimp_CreateMenu.

-

This code needs to be called when the user clicks Menu on our iconbar icon, so we add a new entry to the CASE statements in PROCmouse_click() to handle it:

+

This code needs to be called when the user clicks Menu on our iconbar icon, so we add a new entry to the CASE statements in PROCmouse_click to handle it:

CASE b%!12 OF WHEN -2 : REM Iconbar @@ -498,7 +498,7 @@ WHEN -2 : REM Iconbar ENDCASE ENDCASE -

The final thing that we need to do is to handle Menu_Selection events, for which we will use PROCmenu_selection() as seen in .

+

The final thing that we need to do is to handle Menu_Selection events, for which we will use PROCmenu_selection as seen in .

DEF PROCmenu_selection(b%) LOCAL reopen% diff --git a/Chapters/ch02-a-side-toolbox.xml b/Chapters/ch02-a-side-toolbox.xml index 4392b4e..2ccec5a 100644 --- a/Chapters/ch02-a-side-toolbox.xml +++ b/Chapters/ch02-a-side-toolbox.xml @@ -60,9 +60,9 @@ -

Next, we must adjust the window’s flags and parameters to meet the requirements of a toolbox pane, as seen in . This is the Edit window dialogue in WinEd; other template editors will have a close equivalent.

+

Next,'' we must adjust the window’s flags and parameters to meet the requirements of a toolbox pane, as seen in . This is the Edit window dialogue in WinEd; other template editors will have a close equivalent.

-

The first action is to turn off all of the window furniture – including the title bar. The pane won’t be able to move independently of the window that it’s attached to, so there’s no need to give the user the option of trying! Under the heading of Window behaviour, the Moveable flag is also unset – this corresponds to the ‘window is moveable’ flag in bit 1 of the window flags, and indicates that the user can’t initiate window movement – the application still can, though.

+

Our first action is to turn off all of the window furniture – including the title bar. The pane won’t be able to move independently of the window that it’s attached to, so there’s no need to give the user the option of trying! Under the heading of Window behaviour, the Moveable flag is also unset – this corresponds to the ‘window is moveable’ flag in bit 1 of the window flags, and indicates that the user can’t initiate window movement – the application still can, though.

@@ -89,7 +89,7 @@ SYS "Wimp_CreateWindow",,b% TO ToolBoxWindow%
WHEN 2 : SYS "Wimp_OpenWindow",,b% WHEN 3 : SYS "Wimp_CloseWindow",,b% -

These just pass the requests straight back to the Wimp to handle, which is all that’s necessary for a simple application. If we want to adjust the position of the toolbox pane whenever the main window moves, however, then we will need to do a bit more work. To keep PROCpoll tidy, we will define two new event handling procedures – PROCopen_window_request() and PROCclose_window_request() – and use these to replace the calls to Wimp_OpenWindow and Wimp_CloseWindow, as seen in .

+

These just pass the requests straight back to the Wimp to handle, which is all that’s necessary for a simple application. If we want to adjust the position of the toolbox pane whenever the main window moves, however, then we will need to do a bit more work. To keep PROCpoll tidy, we will define two new event handling procedures – PROCopen_window_request and PROCclose_window_request – and use these to replace the calls to Wimp_OpenWindow and Wimp_CloseWindow, as seen in .

DEF PROCpoll LOCAL reason% @@ -107,7 +107,7 @@ 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.

-

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 once 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 any Open_Window_Request events relating to the main window are passed on once 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.

DEF PROCopen_window_request(b%) IF !b% = MainWindow% THEN @@ -117,7 +117,7 @@ ELSE ENDIF 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() 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.

+

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 @@ -135,7 +135,7 @@ ENDPROC q%!28 = -1 : REM Window to open behind (-1 is top of stack) SYS "Wimp_OpenWindow",,q% -

This is just another call to Wimp_OpenWindow, so we can simply replace it with a call to PROChandle_pane_windows() in the same way as we have done 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 replace it with a call to PROChandle_pane_windows in the same way 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% @@ -180,14 +180,14 @@ q%!28 = -1 : REM Window to open behind (-1 is top of stack) PROChandle_pane_windows(q%) ENDPROC -

Aside from working out what goes into the PROChandle_pane_windows() procedure, that’s all of the code that we will need in order to handle our new toolbox.

+

Aside from working out what goes into the PROChandle_pane_windows procedure, that’s all of the code that we will need in order to handle our new toolbox.

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 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.

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.

@@ -198,7 +198,7 @@ ENDPROC !toolbox% = ToolBoxWindow% SYS "Wimp_GetWindowState",,toolbox% -

We will start by positioning the toolbox in the X and Y dimensions by adjusting its visible area, so that it aligns with the main window. It will be useful later on for this code to be in a procedure of its own, so we will create one called PROCposition_side_toolbox() and call it as follows.

+

We will start by positioning the toolbox in the X and Y dimensions by adjusting its visible area, so that it aligns with the main window. It will be useful later on for this code to be in a procedure of its own, so we will create one called PROCposition_side_toolbox and call it as follows.

PROCposition_side_toolbox(main%, toolbox%) @@ -223,7 +223,7 @@ toolbox%!8 = parent%!16 - height% : REM Visible Area Y0 toolbox%!12 = parent%!4 : REM Visible Area X1 toolbox%!4 = parent%!4 - width% : REM Visible Area X0 -

Putting this all together results in PROCposition_side_toolbox() as seen in .

+

Putting this all together results in PROCposition_side_toolbox as seen in .

DEF PROCposition_side_toolbox(parent%, toolbox%) LOCAL width%, height% @@ -257,7 +257,7 @@ ENDPROC

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 window state 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 that it is positioned beneath at offset 28. Since the toolbox pane should be in front of the main window, then returning to PROChandle_pane_windows() following the call to PROCposition_side_toolbox(), we can 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 should be 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, then returning to PROChandle_pane_windows following the call to PROCposition_side_toolbox, we can copy this value into the pane’s block so that the pane appears at the correct position in the stack.

IF main%!28 <> ToolBoxWindow% THEN toolbox%!28 = main%!28 @@ -271,7 +271,7 @@ ENDPROC SYS "Wimp_OpenWindow",,main% -

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

+

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

DEF PROChandle_pane_windows(main%) LOCAL toolbox% @@ -343,7 +343,7 @@ SYS "Wimp_OpenWindow",,main% SYS "Wimp_OpenWindow",,toolbox% ENDIF -

The toolbox is anchored to the top and left sides of the visible area, so there’s no need to check the right or bottom sides. Adding these changes to PROChandle_pane_windows() results in the code in .

+

The toolbox is anchored to the top and left sides of the visible area, so there’s no need to check the right or bottom sides. Adding these changes to PROChandle_pane_windows results in the code in .

DEF PROChandle_pane_windows(main%) LOCAL toolbox%, top%, left% @@ -408,7 +408,7 @@ ENDPROC -

Since we have complete control over the positioning of the toolbox pane, this is easy to implement in our own application. The changes needed are all in PROCposition_side_toolbox(), where we set the coordinates of the pane’s visible area. In the code above, we used the following fixed calculations:

+

Since we have complete control over the positioning of the toolbox pane, this is easy to implement in our own application. The changes needed are all in PROCposition_side_toolbox, where we set the coordinates of the pane’s visible area. In the code above, we used the following fixed calculations:

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. diff --git a/Chapters/ch03-a-top-toolbar.xml b/Chapters/ch03-a-top-toolbar.xml index d9c97ac..b00d82f 100644 --- a/Chapters/ch03-a-top-toolbar.xml +++ b/Chapters/ch03-a-top-toolbar.xml @@ -82,7 +82,7 @@ SYS "Wimp_CreateWindow",,b% TO ToolBarWindow%
Handling the new pane -

In terms of infrastructure to handle our new toolbar, there’s not much to add since most of the hard work was done in the last chapter. All that we need to do is to make sure that the toolbar opens in the correct place relative to both the main window and the existing toolbox, which will be managed in PROChandle_pane_windows(), and that it closes when the main window closes. For the latter, we can update PROCclose_window_request() as shown in , so that both panes are closed if the main window closes.

+

In terms of infrastructure to handle our new toolbar, there’s not much to add since most of the hard work was done in the last chapter. All that we need to do is to make sure that the toolbar opens in the correct place relative to both the main window and the existing toolbox, which will be managed in PROChandle_pane_windows, and that it closes when the main window closes. For the latter, we can update PROCclose_window_request as shown in , so that both panes are closed if the main window closes.

DEF PROCclose_window_request(b%) IF !b% = MainWindow% THEN @@ -95,18 +95,18 @@ ENDIF SYS "Wimp_CloseWindow",,b% ENDPROC -

The code that we need to add to PROChandle_pane_windows() should already be fairly familiar. First, we need to create a window state block for the toolbar pane, just as we do for the toolbox. To keep things simple, we’ll borrow another 32 bytes from the Open_Window_Request event block, this time placing the toolbar pane’s data at an offset of 128 bytes into the block.

+

The code that we need to add to PROChandle_pane_windows should already be fairly familiar. First, we need to create a window state block for the toolbar pane, just as we do for the toolbox. To keep things simple, we’ll borrow another 32 bytes from the Open_Window_Request event block, this time placing the toolbar pane’s data at an offset of 128 bytes into the block.

toolbar% = main% + 128 !toolbar% = ToolBarWindow% SYS "Wimp_GetWindowState",,toolbar% -

We can then call a new procedure, PROCposition_toolbar(), to do the work of adjusting the toolbar’s visible area to suit the position of the main window.

+

We can then call a new procedure, PROCposition_toolbar, to do the work of adjusting the toolbar’s visible area to suit the position of the main window.

PROCposition_toolbar(main%, toolbar%) -

This will work in a similar way to the PROCposition_side_toolbox() procedure that we defined in the last chapter and takes two parameters: a pointer to the main window state block as parent%, and a pointer to the toolbar pane’s window state block as toolbox%. We will pass main% and toolbar% to these respectively.

+

This will work in a similar way to the PROCposition_side_toolbox procedure that we defined in the last chapter and takes two parameters: a pointer to the main window state block as parent%, and a pointer to the toolbar pane’s window state block as toolbox%. We will pass main% and toolbar% to these respectively.

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 to know the height of the bar – which we can get from its visible area as before.

@@ -153,7 +153,7 @@ ENDPROC

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.

-

Returning to PROChandle_pane_windows(), we will 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 supposed to be in front of the main window, exactly as we did before.

+

Returning to PROChandle_pane_windows, we will 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 supposed to be in front of the main window, exactly as we did before.

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

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

+

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

DEF PROChandle_pane_windows(main%) LOCAL toolbox%, toolbar%, top%, left%, right% @@ -300,7 +300,7 @@ ENDPROC

As it is, this isn’t an enormous problem, and a simple solution might just be to have the toolbox fixed so that it doesn’t push back over the main window.

-

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 a vertical offset to the calculation in PROCposition_side_toolbox(), which sets the vertical position of the toolbox relative to the top of the parent window’s visible area – the changes required can be seen in .

+

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 a vertical offset to the calculation in PROCposition_side_toolbox, which sets the vertical position of the toolbox relative to the top of the parent window’s visible area – the changes required can be seen in .

DEF PROCposition_side_toolbox(parent%, toolbox%, offset%) LOCAL width%, height% @@ -330,7 +330,7 @@ toolbox%!16 = parent%!16 - offset% : REM Visible Area Y1 ENDPROC -

To be able to supply this information, we will also need to know the height of the toolbar: to this end, we will convert the PROCposition_toolbar() procedure into the FNposition_toolbar() function, which returns this information. The change can be seen in .

+

To be able to supply this information, we will also need to know the height of the toolbar: to this end, we will convert the PROCposition_toolbar procedure into the FNposition_toolbar function, which returns this information. The change can be seen in .

DEF FNposition_toolbar(parent%, toolbar%) LOCAL height% @@ -349,7 +349,7 @@ toolbar%!16 = parent%!16 : REM Visible Area Y1 =height% -

Tying these two changes together is simply a case of updating PROChandle_pane_windows() so that it stores the value returned by FNposition_toolbar() and passes it on to PROCposition_side_toolbox() as seen in .

+

Tying these two changes together is simply a case of updating PROChandle_pane_windows so that it stores the value returned by FNposition_toolbar and passes it on to PROCposition_side_toolbox as seen in .

toolbar_height% = FNposition_toolbar(main%, toolbar%) PROCposition_side_toolbox(main%, toolbox%, toolbar_height%) @@ -380,7 +380,7 @@ ResizeIconAvailable% = ((flags% AND 1) = 0)

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.

+

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.

IF ResizeIconAvailable% THEN icon% = main% + 192 diff --git a/Chapters/ch04-column-headings.xml b/Chapters/ch04-column-headings.xml index 51493cc..d6f8d2c 100644 --- a/Chapters/ch04-column-headings.xml +++ b/Chapters/ch04-column-headings.xml @@ -87,7 +87,7 @@ SYS "Wimp_CreateWindow",,b% TO InfoWindow% SYS "Wimp_CloseTemplate" -

Since there is no longer a toolbox to close when the main window closes, PROCclose_window_request() can be reduced to the code shown in .

+

Since there is no longer a toolbox to close when the main window closes, PROCclose_window_request can be reduced to the code shown in .

DEF PROCclose_window_request(b%) IF !b% = MainWindow% THEN @@ -98,7 +98,7 @@ ENDIF SYS "Wimp_CloseWindow",,b% ENDPROC -

Finally, PROChandle_pane_windows() can be simplified again; it is now as shown in . There’s no longer any need to know the height of the toolbar, so PROCposition_toolbar() has returned to the procedure originally seen in .

+

Finally, PROChandle_pane_windows can be simplified again; it is now as shown in . There’s no longer any need to know the height of the toolbar, so PROCposition_toolbar has returned to the procedure originally seen in .

DEF PROChandle_pane_windows(main%) LOCAL toolbar%, top%, left%, right% @@ -169,7 +169,7 @@ ENDPROC

The problem that we have is that moving the scroll bars alters the scroll offsets for the main window’s work area, but – as we noted above – the the scroll offsets for the work areas of our panes have always been left at zero. Up to now this has been the required behaviour, but this new example is calling for something different.

-

To keep the pane’s contents in alignment with that of the main window, we will need to ensure that its scroll offsets are updated correctly whenever we change its position in PROCposition_toolbar(). We only want the pane to track the main window’s horizontal scrolling, so we can simply copy the X scroll offset from the main window block to the pane.

+

To keep the pane’s contents in alignment with that of the main window, we will need to ensure that its scroll offsets are updated correctly whenever we change its position in PROCposition_toolbar. We only want the pane to track the main window’s horizontal scrolling, so we can simply copy the X scroll offset from the main window block to the pane.

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

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.

-

Putting the code together for the last time gives us , showing PROCposition_toolbar() copying the horizontal scroll offset over to the pane.

+

Putting the code together for the last time gives us , showing PROCposition_toolbar copying the horizontal scroll offset over to the pane.

DEF PROCposition_toolbar(parent%, toolbar%) LOCAL height% diff --git a/Chapters/ch05-does-order-matter.xml b/Chapters/ch05-does-order-matter.xml index 3c2a812..879bd1c 100644 --- a/Chapters/ch05-does-order-matter.xml +++ b/Chapters/ch05-does-order-matter.xml @@ -44,7 +44,7 @@ The order in which we open our windows can have some surprising effects – at least on some systems.
-

So far, we’ve seen how we can manually create one or more panes on our window, and have them behave in a number of distinct ways. Throughout the examples, however, the PROChandle_pane_windows() procedure has always called Wimp_OpenWindow for the different windows in a very specific order: first the pane, then the main window, and finally the pane again.

+

So far, we’ve seen how we can manually create one or more panes on our window, and have them behave in a number of distinct ways. Throughout the examples, however, the PROChandle_pane_windows procedure has always called Wimp_OpenWindow for the different windows in a very specific order: first the pane, then the main window, and finally the pane again.

Back in we stated that this order was necessary, but hinted that we might be able to simplify things in certain circumstances. Now, with all of the main details covered, it seems like a good time to go back and fill in this missing information!

@@ -52,7 +52,7 @@
An optimisation? -

If we go back to look at the code in again, we can see that when an Open_Window_Request event arrives for the main window, it is treated as a special case by PROCopen_window_request().

+

If we go back to look at the code in again, we can see that when an Open_Window_Request event arrives for the main window, it is treated as a special case by PROCopen_window_request.

DEF PROCopen_window_request(b%) IF !b% = MainWindow% THEN @@ -62,16 +62,16 @@ ELSE ENDIF ENDPROC -

Instead of just calling Wimp_OpenWindow, control is immediately passed to the PROChandle_pane_windows() procedure. This goes on to position and open the pane, then open the main window. Finally, it checks the position in which the main window opened, before re-opening the pane if it wasn’t in the expected place.

+

Instead of just calling Wimp_OpenWindow, control is immediately passed to the PROChandle_pane_windows procedure. This goes on to position and open the pane, then open the main window. Finally, it checks the position in which the main window opened, before re-opening the pane if it wasn’t in the expected place.

-

Given that we need to go back and adjust the position of the toolbox pane after the main window has been opened, it would seem that we could save some effort by only doing it once: after opening the main window. We could even streamline the code in PROCopen_window_request() by always calling Wimp_OpenWindow for the target window, before calling PROChandle_pane_windows() if the target is the main window. This alternative approach can be seen in .

+

Given that we need to go back and adjust the position of the toolbox pane after the main window has been opened, it would seem that we could save some effort by only doing it once: after opening the main window. We could even streamline the code in PROCopen_window_request by always calling Wimp_OpenWindow for the target window, before calling PROChandle_pane_windows if the target is the main window. This alternative approach can be seen in .

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

By the time PROChandle_pane_windows() is called, Wimp_OpenWindow will already have updated the window state block pointed to by main% with the coordinates of the actual visible area – we discussed why we can rely on this in . As a result, PROChandle_pane_windows() can start by calling PROCposition_toolbar() to update the visible area of the toolbox.

+

By the time PROChandle_pane_windows is called, Wimp_OpenWindow will already have updated the window state block pointed to by main% with the coordinates of the actual visible area – we discussed why we can rely on this in . As a result, PROChandle_pane_windows can start by calling PROCposition_toolbar to update the visible area of the toolbox.

PROCposition_toolbar(main%, toolbar%) @@ -81,7 +81,7 @@ ENDPROC
SYS "Wimp_OpenWindow",,toolbox%
-

The full code for our new PROChandle_pane_windows() can be seen in , and it’s a lot simpler than the version seen in .

+

The full code for our new PROChandle_pane_windows can be seen in , and it’s a lot simpler than the version that we had in .

DEF PROChandle_pane_windows(main%) LOCAL toolbar% @@ -111,7 +111,7 @@ toolbar%!28 = main%!28 SYS "Wimp_OpenWindow",,toolbar% ENDPROC -

Now that PROChandle_pane_windows() doesn’t open the main window, we will also need to make a small change to PROCopen_main_window so that it also does that task for itself. The change is simply adding a call to Wimp_OpenWindow before the call to PROChandle_pane_windows(), at the end of the procedure.

+

Now that PROChandle_pane_windows doesn’t open the main window, we will also need to make a small change to PROCopen_main_window so that it also does that task for itself. The change is simply adding a call to Wimp_OpenWindow before the call to PROChandle_pane_windows, at the end of the procedure.

q%!28 = -1 : REM Window to open behind (-1 is top of stack) @@ -133,17 +133,17 @@ PROChandle_pane_windows(q%) -

If we follow the new approach outlined in this chapter with , then the first thing that our application does is to call the PROCopen_window_request() procedure, which in turn calls Wimp_OpenWindow for the main window using all of the values supplied by the Wimp. This will result in the main window being inserted at the top of the window stack as shown in – pushing the toolbar pane down below it.

+

If we follow the new approach outlined in this chapter with , then the first thing that our application does is to call the PROCopen_window_request procedure, which in turn calls Wimp_OpenWindow for the main window using all of the values supplied by the Wimp. This will result in the main window being inserted at the top of the window stack as shown in – pushing the toolbar pane down below it.

-

Since the event was for the main window, PROCopen_window_request() goes on to call PROChandle_pane_windows(), which positions the toolbar pane’s visible area correctly and then opens it behind the same window that the main window is behind: in this case, at the top of the window stack. This results in the toolbar pane being inserted back at the top of the stack as seen in , pushing the main window down behind it again – back into its correct place.

+

Since the event was for the main window, PROCopen_window_request goes on to call PROChandle_pane_windows, which positions the toolbar pane’s visible area correctly and then opens it behind the same window that the main window is behind: in this case, at the top of the window stack. This results in the toolbar pane being inserted back at the top of the stack as seen in , pushing the main window down behind it again – back into its correct place.

-

Compare this to the approach taken by in . With the two windows once again starting in the relative positions shown in , an Open_Window_Request event arrives for the main window. This time, however, PROCopen_window_request() simply calls PROChandle_pane_windows() without calling Wimp_OpenWindow for either window.

+

Compare this to the approach taken by in . With the two windows once again starting in the relative positions shown in , an Open_Window_Request event arrives for the main window. This time, however, PROCopen_window_request simply calls PROChandle_pane_windows without calling Wimp_OpenWindow for either window.

-

PROChandle_pane_windows() begins by positioning the toolbar pane as best it can, then opens it in the position in the stack which was supplied by the Wimp for the main window. This results in the pane opening behind the window above the main window’s new position. In the case of a Select drag, this will leave the toolbar pane in front of the main window, as shown in .

+

PROChandle_pane_windows begins by positioning the toolbar pane as best it can, then opens it in the position in the stack which was supplied by the Wimp for the main window. This results in the pane opening behind the window above the main window’s new position. In the case of a Select drag, this will leave the toolbar pane in front of the main window, as shown in .

@@ -151,7 +151,7 @@ PROChandle_pane_windows(q%) -

If the main window moved during opening, then the last thing that PROChandle_pane_windows() will do is to re-position and re-open the toolbar pane – exactly as shown in .

+

If the main window moved during opening, then the last thing that PROChandle_pane_windows will do is to re-position and re-open the toolbar pane – exactly as shown in .

The difference between the two approaches can be seen in and : in our new approach, the main window and its toolbar pane are very briefly swapped over during the opening sequence, whilst in our original code they are not.

@@ -164,7 +164,7 @@ PROChandle_pane_windows(q%)

When an application calls Wimp_OpenWindow, the window in question isn’t immediately opened. Instead, the details are logged in a list of pending updates along with any other windows to be opened or closed – all of which are actioned after the application next calls Wimp_Poll. This means that when our application opens its main window and toolbar pane, both windows will be updated together after control has returned to the Wimp.

-

Prior to the Nested Wimp, all of these pending actions would be carried out in full, in the order that they were specified. In contrast, the Nested Wimp scans the whole list of requests and optimises out any inefficiencies, before carrying out the minimum number of actions actually required to achieve the end result.

+

Prior to the Nested Wimp, all of these pending actions would be carried out in full, in the order that they were requested. In contrast, the Nested Wimp scans the whole list of requests and optimises out any inefficiencies, before carrying out the minimum number of actions actually required to achieve the end result.

What this means in practice is that the Nested Wimp will notice that, despite the toolbar pane ending up behind the main window in , it ultimately ends up back in front in . As a result, the Wimp will conclude that there’s no point redrawing the area of the main window which will be ending up behind the pane – even during the short period that it is on top – and so won’t ask for it to be done.

diff --git a/Chapters/ch06-the-nested-wimp.xml b/Chapters/ch06-the-nested-wimp.xml index 348d6a4..d8ef255 100644 --- a/Chapters/ch06-the-nested-wimp.xml +++ b/Chapters/ch06-the-nested-wimp.xml @@ -86,7 +86,7 @@ Run <PaneDemo$Dir>.!RunImage

The big change between the two examples will be in how the toolbar pane is handled. Up to now, we have had to position our panes when the main window is initially opened, and then keep them up to date on every single Open_Window_Request event after that; we also need to remember to close them on the Close_Window_Request event. With the Nested Wimp we still need to position our panes when the window is initially opened, but when we do, we also let the Wimp know that they are attached to the main window – and more crucially, how they are attached.

-

After that, with the main window and its toolbar open on screen, the Wimp deals with all of the positioning work that we have so far done by hand. This means that we can delete bot h PROCopen_window_request() and PROCclose_window_request(), because we no longer need to do any special work on Open_Window_Request or Close_Window_Request events. Instead, we can just pass them to the Wimp_OpenWindow and Wimp_CloseWindow SWIs respectively, as we did before we added any panes to our application. As a result, PROCpoll can return to how it was in , as seen in .

+

After that, with the main window and its toolbar open on screen, the Wimp deals with all of the positioning work that we have so far done by hand. This means that we can delete both PROCopen_window_request and PROCclose_window_request, because we no longer need to do any special work on Open_Window_Request or Close_Window_Request events. Instead, we can just pass them to the Wimp_OpenWindow and Wimp_CloseWindow SWIs respectively, as we did before we added any panes to our application. As a result, PROCpoll can return to how it was in , as seen in .

DEF PROCpoll LOCAL reason% @@ -157,11 +157,11 @@ main%!28 = -1 : REM Window to open behind (-1 is top of stack) SYS "Wimp_OpenWindow",,main%, &4B534154, -1, &0 -

This extended form still takes a pointer to the window state block, but now R2 contains the familiar Wimp magic constant of &4B534154 – or ‘TASK’ in ASCII. If present, this unlocks more functionality from the call: R3 will then take the handle of this window’s parent window, while R4 takes the nesting flags.

+

This extended form still takes a pointer to the window state block, but now R2 contains the familiar Wimp magic constant of &4B534154 – or ‘TASK’ in ASCII. If present, this unlocks more functionality from the call: R3 will then take the handle of this window’s parent window, while R4 takes the nesting flags.

-

For the main window, we supply a parent window handle of −1 to indicate that it will be a top level window – that it is not to be treated as being nested within any other window. This makes it exactly the same as a window opened using the conventional version of the SWI. None of the nesting flags apply, so they are set to &0.

+

For the main window, we supply a parent window handle of −1 to indicate that it will be a top level window – that it is not to be treated as being nested within any other window. This makes it exactly the same as a window opened using the conventional version of the SWI. None of the nesting flags apply, so they are set to &0.

-

Previously, having called Wimp_OpenWindow for the main window, we would go on to call PROChandle_pane_windows() to set up and open the toolbar pane. Since positioning the windows is a one-off operation with the Nested Wimp, however, we will bring the code into PROCopen_main_window. Most of the code is identical to that which we have used before: getting the toolbar pane’s details with Wimp_GetWindowState, then adjusting the position to suit the location of the main window.

+

Previously, having called Wimp_OpenWindow for the main window, we would go on to call PROChandle_pane_windows to set up and open the toolbar pane. Since positioning the windows is a one-off operation with the Nested Wimp, however, we will bring the code into PROCopen_main_window. Most of the code is identical to that which we have used before: getting the toolbar pane’s details with Wimp_GetWindowState, then adjusting the position to suit the location of the main window.

REM Get the toolbar details @@ -272,7 +272,7 @@ toolbar%!16 = main%!16 : REM Visible Area Y1

In contrast, we never change the vertical scroll offset. To make sure that the Nested Wimp doesn’t either, we link it to the same part of the window as the visible area Y1 value: %10 – “Link to the right or top (X1 or Y1) of the parent’s visible area” – from .

-

Putting these values together gives us %00 00 10 00 10 10 10 01 for the top 16 bits of the nesting flags, or &08A9 in hex. The bottom 16 bits are all clear, since we don’t wish to have Wimp_OpenWindow updating the window flags, which gives a complete value of &08A90000 for the nesting flags. shows how the value is assembled.

+

Putting these values together gives us %00 00 10 00 10 10 10 01 for the top 16 bits of the nesting flags, or &08A9 in hex. The bottom 16 bits are all clear, since we don’t wish to have Wimp_OpenWindow updating the window flags, which gives a complete value of &08A90000 for the nesting flags. shows how the value is assembled.

@@ -281,7 +281,7 @@ toolbar%!16 = main%!16 : REM Visible Area Y1
A complete application -

Putting it all together, we can delete PROChandle_pane_windows(); all of the functionality is now in the new PROCopen_main_window, in .

+

Putting it all together, we can delete PROChandle_pane_windows; all of the functionality is now in the new PROCopen_main_window, in .

DEF PROCopen_main_window LOCAL screen_width%, screen_height%, window_width%, window_height%, main%, toolbar%, bar_height% diff --git a/Chapters/ch07-responsive-nesting.xml b/Chapters/ch07-responsive-nesting.xml index ba3bc52..ebc4883 100644 --- a/Chapters/ch07-responsive-nesting.xml +++ b/Chapters/ch07-responsive-nesting.xml @@ -107,7 +107,7 @@ SYS "Wimp_OpenWindow",,toolbar%, &4B534154, !main%, &09A90000<

Fortunately, it’s a similar process with the Nested Wimp as it was when we were doing things manually – although there is one optimisation that we can make this time around. Last time, we checked for the presence of the Wimp_ResizeIcon SWI when the application initialised, and omitted the resizing on systems where it wasn’t available. Since this time we know that we’re using the Nested Wimp, because we test for it in the !Run file, we also know that the SWI we need will be present – and so we can safely use it without any further checks.

-

The actual process of moving the icon as the toolbar grows and shrinks is very similar under the Nested Wimp to how it was when we were handling the panes manually. We simply look out for Open_Window_Request events for the toolbar, and adjust the icon once we know the new position of its parent window. To this end, we will start by reinstating a call to PROCopen_window_request() in our Wimp_Poll routine from PROCpoll.

+

The actual process of moving the icon as the toolbar grows and shrinks is very similar under the Nested Wimp to how it was when we were handling the panes manually. We simply look out for Open_Window_Request events for the toolbar, and adjust the icon once we know the new position of its parent window. To this end, we will start by reinstating a call to PROCopen_window_request in our Wimp_Poll routine from PROCpoll.

CASE reason% OF WHEN 2 : PROCopen_window_request(b%) @@ -117,7 +117,7 @@ SYS "Wimp_OpenWindow",,toolbar%, &4B534154, !main%, &09A90000< WHEN 17, 18 : IF b%!16 = 0 THEN Quit% = TRUE ENDCASE -

The new PROCopen_window_request() will be defined as shown in . We still call Wimp_OpenWindow to let the Wimp handle the opening of the window for us, but if the window in question is the main window, then we will call PROCadjust_toolbar_content to perform the toolbar icon updates.

+

The new PROCopen_window_request will be defined as shown in . We still call Wimp_OpenWindow to let the Wimp handle the opening of the window for us, but if the window in question is the main window, then we will call PROCadjust_toolbar_content to perform the toolbar icon updates.

DEF PROCopen_window_request(b%) SYS "Wimp_OpenWindow",,b% diff --git a/Chapters/ch08-moving-the-furniture.xml b/Chapters/ch08-moving-the-furniture.xml index ef8d310..bd793b8 100644 --- a/Chapters/ch08-moving-the-furniture.xml +++ b/Chapters/ch08-moving-the-furniture.xml @@ -46,19 +46,19 @@

In the last chapter, we saw how the Nested Wimp can be used to look after a pane within our application’s window. Whilst useful, however, this is no more than we can do easily by hand – as seen in the chapters before it.

-

Those familiar with RISC OS will know that some applications handle their toolbars slightly differently, however. NetSurf is one such application, as seen in , and we saw a much more elaborate example with Fireworkz back in .

+

Those familiar with RISC OS will know that some applications handle their toolbars slightly differently, however. NetSurf is one such application, as seen in , and we saw a much more elaborate example with Fireworkz back in .

-

Look closely at NetSurf’s main browser window, and we can see that the toolbar extends across the full width of the window outline: on the right hand side, it even pushes the scroll bar down to make space for it. This can be done manually as well, by building a composite window consisting of many different panes in the way that Fireworkz does. If you have access to a copy of Fireworkz and a tool like WimpInfo which will show the handles of windows on the desktop (both of which are free to download), it may be interesting to count how many different panes are required to display a single Fireworkz document!

+

Look closely at NetSurf’s main browser window, and we can see that the toolbar extends across the full width of the window outline: on the right hand side, it even pushes the scroll bar down to make space for it. This can be done manually as well, by building a composite window consisting of many different panes in the way that Fireworkz does. If you have access to a copy of Fireworkz and a tool like WimpInfo which will show the handles of windows on the desktop (both of which are free to download), it may be interesting to count how many different panes are required to display a single Fireworkz document!

-

NetSurf, on the other hand, uses the easy option and takes advantage of what the Nested Wimp calls Furniture Windows. When writing new software which isn’t targetted at the ‘retro’ scene, the simplicity of the Nested Wimp for this task almost certainly makes it the way to go.

+

NetSurf, on the other hand, uses the easy option and takes advantage of what the Nested Wimp calls Furniture Windows. When writing new software which isn’t targetted at the ‘retro’ scene, the simplicity of the Nested Wimp for this task almost certainly makes it the way to go.

A full-width toolbar -

To show how this works, we will take the responsive toolbar that we created in the previous chapter and make it span the full width of the window – just like NetSurf’s URL bar in .

+

To show how this works, we will take the responsive toolbar that we created in the previous chapter and make it span the full width of the window – just like NetSurf’s URL bar in .

The first thing that we will need to do is make a couple of small changes to the window templates. The toolbar will need to be wide enough to span the full width of the main window and its furniture (the vertical scroll bar on the right), so we will need to increase the toolbar’s work area by the width of that furniture. However, the Nested Wimp constrains child windows to the work area of their parent by default, so even if we did this, the toolbar would still be clipped such that it didn’s obscure the main window’s scroll bar.

diff --git a/Chapters/ch09-an-embedded-toolbox.xml b/Chapters/ch09-an-embedded-toolbox.xml index 97a9dd7..5d32e38 100644 --- a/Chapters/ch09-an-embedded-toolbox.xml +++ b/Chapters/ch09-an-embedded-toolbox.xml @@ -44,11 +44,11 @@ For a truly minimalist look, we can embed a toolbox into one of our window’s scroll bars.
-

Back in the late 1980s, when RISC OS was a new system, space on the screens of the day was limited and there was a trend for using minimalist toolboxes embedded into the space used by the scrollbars of a window. Of the numerous applications which used the technique, the original Ovation is still well-known – its take on the idea can be seen in .

+

Back in the late 1980s, when RISC OS was a new system, space on the screens of the day was limited and there was a trend for using minimalist toolboxes embedded into the space used by the scrollbars of a window. Of the numerous applications which used the technique, the original Ovation is still well-known – its take on the idea can be seen in .

-

At the time, Ovation’s author created this effect using three windows, which are all interleaved carefully. These days, the effect can be achieved more easily using the Nested Wimp, and in previous chapters we have already seen examples from Paint () and NetSurf () in passing.

+

At the time, Ovation’s author created this effect using three windows, which are all interleaved carefully. These days, the effect can be achieved more easily using the Nested Wimp, and in previous chapters we have already seen examples from Paint () and NetSurf () in passing.

As with the full-width toolbar that we created in , such toolboxes can be created using Furniture Windows. In this chapter, we will create ourselves a simple embedded toolbox in the bottom scroll bar of our window.

@@ -68,12 +68,12 @@ -

With these changes in place, we can now close the templates and move on to updating the program itself. We’ll need to update PROCinitialise in order to load the new “Embedded” template instead of the “Toolbar” that we had before – this is simply a change to the name passed to PROCtemplate_load().

+

With these changes in place, we can now close the templates and move on to updating the program itself. We’ll need to update PROCinitialise in order to load the new “Embedded” template instead of the “Toolbar” that we had before – this is simply a change to the name passed to PROCtemplate_load.

PROCtemplate_load("Embedded", b%, buffer_size%, -1) SYS "Wimp_CreateWindow",,b% TO ToolBoxWindow% -

We can also simplify the Open_Window_Request event handler in PROCpoll again. We will no longer need to make any adjustments to the contents of the toolbox, so we can delete PROCopen_window_request() completely and just call Wimp_OpenWindow in the CASE statement once again.

+

We can also simplify the Open_Window_Request event handler in PROCpoll again. We will no longer need to make any adjustments to the contents of the toolbox, so we can delete PROCopen_window_request completely and just call Wimp_OpenWindow in the CASE statement once again.

CASE reason% OF WHEN 2 : SYS "Wimp_OpenWindow",,b% @@ -136,7 +136,7 @@ pixel_height% = 2 ^ eigenfactor% toolbox%!48 = toolbox%!56 - box_height% SYS "Wimp_SetExtent", ToolBoxWindow%, toolbox% + 44
-

For reasons which will become apparent a little later, we will split this code out into a separate procedure called PROCarrange_toolbox(), which is shown in .

+

For reasons which will become apparent a little later, we will split this code out into a separate procedure called PROCarrange_toolbox, which is shown in .

DEF PROCarrange_toolbox(main%, main_outline%, toolbox%) LOCAL box_width%, box_height%, eigenfactor%, pixel_width%, pixel_height%, icon_height%, icon_width%, icon% @@ -174,7 +174,7 @@ toolbox%!48 = toolbox%!56 - box_height% SYS "Wimp_SetExtent", ToolBoxWindow%, toolbox% + 44 ENDPROC -

This can be called from PROCopen_main_window, in between opening the main window itself and opening the toolbox as a child. The toolbox is anchored a little differently to what we have seen before, as it is connected to the left and bottom of the main window’s work area. This results in us using flags of &05550000.

+

This can be called from PROCopen_main_window, in between opening the main window itself and opening the toolbox as a child. The toolbox is anchored a little differently to what we have seen before, as it is connected to the left and bottom of the main window’s work area. This results in us using flags of &05550000.

toolbox%!28 = -1 @@ -303,7 +303,7 @@ NEXT icon%

The coordinates passed to Wimp_ResizeIcon are xpos% and xpos% plus the icon width in the horizontal direction, along with the Y0 and Y1 extents of the work area inset by a single pixel.

-

With these changes added to the code, PROCarrange_toolbox() should now look as seen in .

+

With these changes added to the code, PROCarrange_toolbox should now look as seen in .

DEF PROCarrange_toolbox(main%, main_outline%, toolbox%) LOCAL box_width%, box_height%, eigenfactor%, pixel_width%, pixel_height%, icon_height%, icon_width%, icon% @@ -374,9 +374,9 @@ ENDPROC -

Fortunately the solution is simple: if a mode change occurs whilst our window is open, we should calculate all of the positioning again and then re-open it. Recalculating the position is fairly straight forward, as we can re-use the positioning code in PROCarrange_toolbox() to do the hard work. We start out by setting up the pointers in main%, toolbox% and main_outline%, before calling Wimp_GetWindowInfo for the main window. We have separated this out from PROCarrange_toolbox() because we must check that the window is actually open before doing any re-arranging – this can be done by testing the window flags in the usual way.

+

Fortunately the solution is simple: if a mode change occurs whilst our window is open, we should calculate all of the positioning again and then re-open it. Recalculating the position is fairly straight-forward, as we can re-use the positioning code in PROCarrange_toolbox to do the hard work. We start out by setting up the pointers in main%, toolbox% and main_outline%, before calling Wimp_GetWindowInfo for the main window. We have separated this out from PROCarrange_toolbox because we must check that the window is actually open before doing any re-arranging – this can be done by testing the window flags in the usual way.

-

We don’t call Wimp_OpenWindow for the main window, as it should already have been positioned in a suitable place for the new mode by the Wimp. Instead, we call PROCarrange_toolbox() to calculate the toolbox position, then call Wimp_OpenWindow to apply it. In contrast to the code in PROCopen_main_window, we do not adjust the position of the toolbox in the window stack and so it should remain in the correct position relative to its parent.

+

We don’t call Wimp_OpenWindow for the main window, as it should already have been positioned in a suitable place for the new mode by the Wimp. Instead, we call PROCarrange_toolbox to calculate the toolbox position, then call Wimp_OpenWindow to apply it. In contrast to the code in PROCopen_main_window, we do not adjust the position of the toolbox in the window stack and so it should remain in the correct position relative to its parent.

Bringing all of this code together results in the procedure in .

@@ -407,7 +407,7 @@ REM Reopen the toolbox pane nested into the main window. SYS "Wimp_OpenWindow",,toolbox%, &4B534154, !main%, &05550000 ENDPROC
-

In order to be able to call PROCrecalculate_toolbox whenever the mode changes, we will need to listen out for the Message_ModeChange User Message, which has the code &400C1. The Wimp sends this around all interested applications once a mode change has completed, and it will give us the cue that we require.

+

In order to be able to call PROCrecalculate_toolbox whenever the mode changes, we will need to listen out for the Message_ModeChange User Message, which has the code &400C1. The Wimp sends this around all interested applications once a mode change has completed, and it will give us the cue that we require.

In order to be sent Message_ModeChange, we will need to update PROCinitialise so that our call to Wimp_Initialise includes a request to receive it. Up to now, we have passed zero in R3, which indicates that we only wish to receive the obligatory Message_Quit. To add Message_ModeChange to the messages that the Wimp will send us, we need to create a list of the message numbers that interest us in memory, then pass a pointer to that in R3 instead. The list is zero-terminated, which happens to also correspond to Message_Quit.

@@ -417,7 +417,7 @@ q%!4 = 0 : REM Message_Quit & End of List SYS "Wimp_Initialise", 380, &4B534154, TaskName$, q% -

To allow us to handle the new message, we will update the CASE which dispatches our Wimp_Poll events. Instead of simply setting the Quit% variable to TRUE when Message_Quit is received, we will instead call a new procedure called PROCuser_message() which can then the different codes which are received.

+

To allow us to handle the new message, we will update the CASE which dispatches our Wimp_Poll events. Instead of simply setting the Quit% variable to TRUE when Message_Quit is received, we will instead call a new procedure called PROCuser_message which can then the different codes which are received.

CASE reason% OF WHEN 2 : SYS "Wimp_OpenWindow",,b% @@ -427,7 +427,7 @@ SYS "Wimp_Initialise", 380, &4B534154, TaskName$, q% WHEN 17, 18 : PROCuser_message(b%) ENDCASE -

PROCuser_message() itself is fairly simple. It contains a CASE structure to test the reason code of the incoming message, and call appropriate code in each case. A Message_Quit still sets the Quit% variable to TRUE, while Message_ModeChange will in turn call the new PROCrecalculate_toolbox procedure.

+

PROCuser_message itself is fairly simple. It contains a CASE structure to test the reason code of the incoming message, and call appropriate code in each case. A Message_Quit still sets the Quit% variable to TRUE, while Message_ModeChange will in turn call the new PROCrecalculate_toolbox procedure.

DEF PROCuser_message(b%) CASE b%!16 OF