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.
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.
+
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.
-
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.
+
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.
@@ -253,9 +253,9 @@ ENDPROC
-
There are a couple of more technical reasons, too, which relate to the behaviour of the ‘window is a pane’ flag. When checking to see if our main window is at the top of the window stack, or obscured by any other windows (for the ‘window is fully visible’ flag at bit 17 of the window flags), the Wimp will ignore any windows immediately in front of it so long as they have their pane flags set. Without use of the pane flag, a window whose pane obscures any part of its work area can never be reported as being fully visible by the Wimp.
+
There are a couple of more technical reasons, too, which relate to the behaviour of the ‘window is a pane’ flag. When checking to see if our main window is at the top of the window stack, or obscured by any other windows (for the ‘window is fully visible’ flag at bit 17 of the window flags), the Wimp will ignore any windows immediately in front of it so long as they have their pane flags set. Without use of the pane flag, a window whose pane obscures any part of its work area can never be reported as being fully visible by the Wimp.
-
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.
+
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.
Bit 0 is interesting in itself, as for the first time it makes it possible to change the window flags of a window after it has been created. Previously, doing things like changing the window furniture (scroll bars, back icons, and so on) required a window to be deleted with Wimp_DeleteWindow and then re-created with the new flags. Now, with the Nested Wimp, an application can simply put the desired new values into the correct place within the block passed to Wimp_OpenWindow, and set this bit of the nesting flags.
-
However, this is beside the point: what we’re interested in at present are the anchor points between bit 16 and bit 27. These define how a child window is attached to its parent; in our case, how our toolbar will be attached to the main window. Each of the anchor points is given by a two-bit value, with the possible meanings listed in .
+
However, this is beside the point: what we’re interested in at present are the anchor points between bit 16 and bit 27. These define how a child window is attached to its parent; in our case, how our toolbar will be attached to the main window. Each of the anchor points is given by a two-bit value, with the possible meanings listed in .
The second point is that we call PROCadjust_toolbar_contentafter calling Wimp_OpenWindow. When the SWI has returned, the Wimp will have updated the parent window and all of its children to their new positions – at least within its data structures, if not on screen. This means that we are safe to query the position of any of the windows using the usual Wimp SWIs.
+
We will also need to adjust the position of the icon when the window is first opened, so a call to PROCadjust_toolbar_content is added after the call to Wimp_OpenWindow in PROCopen_main_window.
So far, we have used the Nested Wimp to recreate the same toolbars that we were able to produce by hand using older versions of the Wimp. It has more interesting tricks up its sleeve, however, and we will start to look at these in the next chapter.
+
So far, we have used the Nested Wimp to recreate the same toolbars that we were able to produce by hand using older versions of the Wimp. It has more interesting tricks up its sleeve, however, and we will start to look at these in the next chapter.
diff --git a/Chapters/ch08-moving-the-furniture.xml b/Chapters/ch08-moving-the-furniture.xml
index 002041a..71276dc 100644
--- a/Chapters/ch08-moving-the-furniture.xml
+++ b/Chapters/ch08-moving-the-furniture.xml
@@ -32,7 +32,7 @@
- Moving The Furniture
-->
-
+Chapter08Chapter08
@@ -44,7 +44,188 @@
Our panes don’t have to be over the window’s work area – we can turn them into window furniture, too!
-
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 manually – as seen in the chapters before that.
+
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 .
+
+
+
+
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.
+
+
+
+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 .
+
+
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.
+
+
To get around this, we need to designate the toolbar as being a Furniture Window so that the Nested Wimp knows to integrate it with the main window’s furniture. This is done by setting the ‘furniture’ flag at bit 23 of the window flags; in WinEd, this is done by ticking Furniture / Foreground in the Window Behaviour section of the Edit window dialogue as seen in .
+
+
+
+
The documentation notes that this flag “has no meaning for top-level windows, so the bit should always be cleared in such cases to allow for future expansion”.
+
+
The width of the toolbar work area is currently set to be the same as that of the main window work area, so this will need to be increased to allow the toolbar to extend over the space taken up by the vertical scroll bar. The problem is deciding how much to increase it by: we could simply add on the width of the scroll bar, but this isn’t a fixed value under RISC OS because it depends on the toolsprites which are currently in use. We could guess at a number and double it, but that doesn’t feel very satisfactory; a better option would be to leave the width the same as the main window, and adjust it when the windows are opened. As a result, with the ‘furniture’ flag set, we can save the templates and move on to updating the program itself.
+
+
+
+More window details
+
+
To support the new style of toolbar, we will need to make some changes to PROCopen_main_window. The first thing that we need to do is adjust the extent of the toolbar’s work area, as discussed above: it must span the width of both the main window work area, and any window furniture on the outside. Before we can do that, we must know the extent of both the main window work area and that of the toolbar – so instead of using Wimp_GetWindowState to read the main window and toolbar details, we will use Wimp_GetWindowInfo instead.
+
+
Wimp_GetWindowInfo is similar to Wimp_GetWindowState, but instead of returning just the first 36 bytes of a window’s information block, it returns the full set of data used when calling Wimp_CreateWindow – updated to reflect the current situation, of course. It can optionally return the details of all of the icons in the window, too; again, it reflects any calls to Wimp_CreateIcon and Wimp_DeleteIcon since the window was created.
+
+
The new calls directly replace the calls to Wimp_GetWindowState for both the main window and the toolbar window from , as seen here for the main window.
+
+REM Get the main window details.
+
+!main% = MainWindow%
+SYS "Wimp_GetWindowInfo",,main% OR %01
+
+
A similar change is made for the toolbar as well.
+
+REM Get the toolbar details
+
+!toolbar% = ToolBarWindow%
+SYS "Wimp_GetWindowInfo",,toolbar% OR %1
+
+
Note that in both cases we set bit 0 of the address passed in R1: this is important, as it tells the Wimp that we do not want it to return any icon details, and enables us to rely on the required block only being 92 bytes long. If we did want to read the icon details, we would need to call the SWI twice: once with bit 0 set to read the number of icons in the window, then again with bit 0 clear after making sure that we had allocated sufficient space for all of the icon details to be returned.
+
+
With the returned blocks now being 92 bytes long, instead of the 36 bytes from Wimp_GetWindowState, we will need to adjust the way that main% and toolbar% are assigned from the block pointed to by q% in order to avoid them overwriting each other.
+
+main% = q%
+toolbar% = q% + 100
+
+
The other thing that we will need to know is the outline of the main window, so that we can align the toolbar to it. This is something that we don't often see, since the Wimp usually works in terms of the visible area of windows, but fortunately the Wimp_GetWindowOutline SWI will tell us everything that we need. We start by setting up a new variable, main_outline% to point to another unused bit of the block pointed to by q%.
Again, we have left enough space for the area pointed to by toolbar% now that we are using Wimp_GetWindowInfo instead of Wimp_GetWindowState. Next, we can add a call to Wimp_GetWindowOutline to collect details of the main window outline.
This returns a bounding box at offsets 4 to 16 which completeley encloses both the main window’s visible area and all of its furniture: the title bar, scroll bars, close, back, toggle- and adjust-size buttons.
+
+
Armed with this information, we can start to lay out the toolbar’s visible are relative to the main window. Vertically, the Y0 and Y1 extents remain relative the visible area of the main window, but horizontally the X0 and X1 extents are set to align with their counterparts from the outline bounding box obtained from Wimp_GetWindowOutline.
+
+toolbar%!4 = main_outline%!4 : REM Visible Area X0
+toolbar%!8 = main%!16 - bar_height% : REM Visible Area Y0
+toolbar%!12 = main_outline%!12 : REM Visible Area X1
+toolbar%!16 = main%!16 : REM Visible Area Y1
+
+
Before we call Wimp_OpenWindow, we will need to ensure that the horizontal extent of the toolbar is sufficient to allow it to extend across the full width of the main window’s work area and the window furniture. To achieve this we take the width of the main window’s work area (main%!52 - main%!44), then add on the width of the main window outline (main_outline%!12 - main_outline%!4) less the width of its visible area (main%!12 - main%!4)). This gives us the required horizontal extent.
+
+
The final step is to calculate the X1 value of the extent by taking the value above and adding it to the X0 value. This is used to update the extent values in the toolbar window block, before they are passed to Wimp_SetExtent.
Pulling all of these changes together gives us the complete PROCopen_main_window in .
+
+DEF PROCopen_main_window
+LOCAL screen_width%, screen_height%, window_width%, window_height%, main%, main_outline%, toolbar%, bar_height%
+
+REM Set up the memory blocks.
+
+main% = q%
+toolbar% = q% + 100
+main_outline% = q% + 200
+
+REM Get the main window details.
+
+!main% = MainWindow%
+SYS "Wimp_GetWindowInfo",,main% OR %01
+
+REM If the window isn't open, resize and centre it on the screen.
+
+IF (main%!32 AND &10000) = 0 THEN
+ window_width% = WindowWidth%
+ window_height% = WindowHeight%
+
+ REM Read the screen dimensions.
+
+ screen_width% = FNread_mode_dimension(11, 4)
+ screen_height% = FNread_mode_dimension(12, 5)
+
+ REM Ensure that the window fills no more than 75% of either dimension.
+
+ IF window_width% > (screen_width% * 0.75) THEN window_width% = screen_width% * 0.75
+ IF window_height% > (screen_height% * 0.75) THEN window_height% = screen_height% * 0.75
+
+ REM Update the window dimensions.
+
+ main%!4 = (screen_width% - window_width%) / 2 : REM Visible Area X0
+ main%!8 = (screen_height% - window_height%) / 2 : REM Visible Area Y0
+
+ main%!12 = main%!4 + window_width% : REM Visible Area X1
+ main%!16 = main%!8 + window_height% : REM Visible Area Y1
+
+ REM Reset the scroll offsets.
+
+ main%!20 = 0 : REM X Scroll Offset
+ main%!24 = 0 : REM Y Scroll Offset
+ENDIF
+
+REM Open the window at the top of the window stack.
+
+main%!28 = -1 : REM Window to open behind (-1 is top of stack)
+
+SYS "Wimp_OpenWindow",,main%, &4B534154, -1, &0
+
+REM Get the outline of the main window.
+
+!main_outline% = MainWindow%
+SYS "Wimp_GetWindowOutline",,main_outline%
+
+REM Get the toolbar details
+
+!toolbar% = ToolBarWindow%
+SYS "Wimp_GetWindowInfo",,toolbar% OR %1
+
+REM Find the height of the toolbar pane's visible area.
+
+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_outline%!4 : REM Visible Area X0
+toolbar%!8 = main%!16 - bar_height% : REM Visible Area Y0
+toolbar%!12 = main_outline%!12 : REM Visible Area X1
+toolbar%!16 = main%!16 : REM Visible Area Y1
+
+REM Update the toolbar extent to suit the main window furniture.
+
+toolbar%!52 = toolbar%!44 + (main%!12 - main%!4) + ((main_outline%!12 - main_outline%!4) - (main%!12 - main%!4))
+SYS "Wimp_SetExtent", ToolBarWindow%, toolbar% + 44
+
+REM Open the toolbox pane at the top of the stack, nested into the main window.
+
+toolbar%!28 = -1
+
+SYS "Wimp_OpenWindow",,toolbar%, &4B534154, !main%, &09A90000
+PROCadjust_toolbar_content
+ENDPROC
+
+
+
+Bringing it together
+
+
When run, the application above should produce a window like the one in .
+
+
+
+
One thing to note is that we haven’t had to change the band along the top of the work area of the main window, which allows for the area obscured by the bar. Even though the toolbar has pushed the main window’s vertical scroll bar down, the work area still extends up behind the child window in the same way that it did before.
+
+
The complete application can be found in .
+
+
diff --git a/Downloads/Chapter07/NestedFixed2/!PaneDemo/!RunImage,ffb b/Downloads/Chapter07/NestedFixed2/!PaneDemo/!RunImage,ffb
index 0515a5b..38e11f4 100644
Binary files a/Downloads/Chapter07/NestedFixed2/!PaneDemo/!RunImage,ffb and b/Downloads/Chapter07/NestedFixed2/!PaneDemo/!RunImage,ffb differ
diff --git a/Downloads/Chapter08/NestedFurntiure/!Boot,feb b/Downloads/Chapter08/NestedFurniture/!Boot,feb
similarity index 100%
rename from Downloads/Chapter08/NestedFurntiure/!Boot,feb
rename to Downloads/Chapter08/NestedFurniture/!Boot,feb
diff --git a/Downloads/Chapter08/NestedFurntiure/!PaneDemo/!Boot,feb b/Downloads/Chapter08/NestedFurniture/!PaneDemo/!Boot,feb
similarity index 100%
rename from Downloads/Chapter08/NestedFurntiure/!PaneDemo/!Boot,feb
rename to Downloads/Chapter08/NestedFurniture/!PaneDemo/!Boot,feb
diff --git a/Downloads/Chapter08/NestedFurntiure/!PaneDemo/!Run,feb b/Downloads/Chapter08/NestedFurniture/!PaneDemo/!Run,feb
similarity index 100%
rename from Downloads/Chapter08/NestedFurntiure/!PaneDemo/!Run,feb
rename to Downloads/Chapter08/NestedFurniture/!PaneDemo/!Run,feb
diff --git a/Downloads/Chapter08/NestedFurniture/!PaneDemo/!RunImage,ffb b/Downloads/Chapter08/NestedFurniture/!PaneDemo/!RunImage,ffb
new file mode 100644
index 0000000..459fa83
Binary files /dev/null and b/Downloads/Chapter08/NestedFurniture/!PaneDemo/!RunImage,ffb differ
diff --git a/Downloads/Chapter08/NestedFurntiure/Templates,fec b/Downloads/Chapter08/NestedFurniture/!PaneDemo/Templates,fec
similarity index 76%
rename from Downloads/Chapter08/NestedFurntiure/Templates,fec
rename to Downloads/Chapter08/NestedFurniture/!PaneDemo/Templates,fec
index 56fec84..871bf81 100644
Binary files a/Downloads/Chapter08/NestedFurntiure/Templates,fec and b/Downloads/Chapter08/NestedFurniture/!PaneDemo/Templates,fec differ
diff --git a/Downloads/Chapter08/NestedFurntiure/!Run,feb b/Downloads/Chapter08/NestedFurniture/!Run,feb
similarity index 100%
rename from Downloads/Chapter08/NestedFurntiure/!Run,feb
rename to Downloads/Chapter08/NestedFurniture/!Run,feb
diff --git a/Downloads/Chapter08/NestedFurntiure/!RunImage,ffb b/Downloads/Chapter08/NestedFurniture/!RunImage,ffb
similarity index 100%
rename from Downloads/Chapter08/NestedFurntiure/!RunImage,ffb
rename to Downloads/Chapter08/NestedFurniture/!RunImage,ffb
diff --git a/Downloads/Chapter08/NestedFurntiure/!PaneDemo/Templates,fec b/Downloads/Chapter08/NestedFurniture/Templates,fec
similarity index 100%
rename from Downloads/Chapter08/NestedFurntiure/!PaneDemo/Templates,fec
rename to Downloads/Chapter08/NestedFurniture/Templates,fec
diff --git a/Downloads/Chapter08/NestedFurntiure/!PaneDemo/!RunImage,ffb b/Downloads/Chapter08/NestedFurntiure/!PaneDemo/!RunImage,ffb
deleted file mode 100644
index ee7e737..0000000
Binary files a/Downloads/Chapter08/NestedFurntiure/!PaneDemo/!RunImage,ffb and /dev/null differ
diff --git a/Images/Chapter08/move-furniture-complete.png b/Images/Chapter08/move-furniture-complete.png
new file mode 100644
index 0000000..8c5be67
Binary files /dev/null and b/Images/Chapter08/move-furniture-complete.png differ
diff --git a/Images/Chapter08/move-furniture-flags.png b/Images/Chapter08/move-furniture-flags.png
new file mode 100644
index 0000000..d4e9293
Binary files /dev/null and b/Images/Chapter08/move-furniture-flags.png differ
diff --git a/Images/Chapter08/move-furniture-netsurf.png b/Images/Chapter08/move-furniture-netsurf.png
new file mode 100644
index 0000000..4189adb
Binary files /dev/null and b/Images/Chapter08/move-furniture-netsurf.png differ