From 4c51ee27c358c88e6982f8ea3b42470ccd7f1308 Mon Sep 17 00:00:00 2001 From: Steve Fryatt Date: Sun, 22 Jan 2023 02:04:51 +0000 Subject: [PATCH] Edit Chapters 8 and 9. --- Chapters/ch08-moving-the-furniture.xml | 20 +++++----- Chapters/ch09-an-embedded-toolbox.xml | 54 +++++++++++++------------- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/Chapters/ch08-moving-the-furniture.xml b/Chapters/ch08-moving-the-furniture.xml index bd793b8..e878893 100644 --- a/Chapters/ch08-moving-the-furniture.xml +++ b/Chapters/ch08-moving-the-furniture.xml @@ -44,7 +44,7 @@ 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 easily by hand – as seen in the chapters before it.

+

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 we’ve already shown 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 .

@@ -60,15 +60,15 @@

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.

+

The first thing that we will need to do is to 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 do this, the toolbar would still be clipped such that it doesn’t obscure the main window’s scroll bar unless we also make a second change.

-

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 .

+

To make the design work, we will also 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 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”. Our toolbar is a child window, so this isn’t a problem.

-

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.

+

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

@@ -92,9 +92,9 @@ SYS "Wimp_GetWindowInfo",,main% OR %1 !toolbar% = ToolBarWindow% SYS "Wimp_GetWindowInfo",,toolbar% OR %1 -

Note that in both cases we set bit 0 of the address passed in R1 using OR: 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 wish 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.

+

Note that in both cases we set bit 0 of the address that we pass in R1 using the OR keyword: 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 wish to read the icon details, we would need to call the SWI twice: once as above 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.

+

With the returned blocks now being 92 bytes long, instead of the 36 bytes from Wimp_GetWindowState, we will also 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 @@ -103,7 +103,7 @@ toolbar% = q% + 100 -

The outline of a window is something that we don't often see, since the Wimp usually works in terms of the visible area, but fortunately the Wimp_GetWindowOutline SWI will tell us almost everything that we need to know. We start by setting up a new variable, main_outline% to point to another unused bit of the block pointed to by q%.

+

The outline of a window is something that we don't often see, since the Wimp usually works in terms of the visible area; fortunately, the Wimp_GetWindowOutline SWI will tell us almost everything that we need to know. We start by setting up a new variable, main_outline%, to point to another unused bit of the block pointed to by q%.

main% = q% toolbar% = q% + 100 @@ -127,9 +127,9 @@ toolbar%!16 = main%!16 : REM Visible Area Y1 -

In practice, this specific instance does not matter too much: we’re still using visible area for aligning the X0 coordinates, so the horizontal work area coodinates for the two windows will be aligned and all that will happen is that we will include one pixel too many at the top end of the horizontal axis. The Wimp will clip this out for us, since child windows can’t extend outside of their parents, and there will be no visible effects. However it can have an effect in some situations, as we’ll see later on.

+

In practice, it does not matter too much in this specific instance: we’re still using visible area for aligning the X0 coordinates, so the horizontal work area coodinates for the two windows will be aligned and all that will happen is that we will include one pixel too many at the top end of the horizontal axis. The Wimp will clip this out for us, since child windows can’t extend outside of their parents, and there will be no visible effects. However it can have an effect in some situations, as we’ll see later on.

-

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.

+

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.

diff --git a/Chapters/ch09-an-embedded-toolbox.xml b/Chapters/ch09-an-embedded-toolbox.xml index 5d32e38..65253ff 100644 --- a/Chapters/ch09-an-embedded-toolbox.xml +++ b/Chapters/ch09-an-embedded-toolbox.xml @@ -50,7 +50,7 @@

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.

+

As with the full-width toolbar that we created in the previous chapter, 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,14 +68,14 @@ -

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 save and close the templates, then 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 as seen in .

-PROCtemplate_load("Embedded", b%, buffer_size%, -1) +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 as seen in .

-CASE reason% OF +CASE reason% OF WHEN 2 : SYS "Wimp_OpenWindow",,b% WHEN 3 : SYS "Wimp_CloseWindow",,b% WHEN 6 : PROCmouse_click(b%) @@ -104,33 +104,33 @@ SYS "Wimp_GetWindowInfo",,toolbox% OR %1 -

As we currently have nothing to go into the toolbox, the width is largely immaterial and so for now we will set it to 200 OS Units.

+

As we currently have nothing to go into the toolbox, the width is largely immaterial and so for now we will set it to 200 OS Units. Later on, when we have some content for the toolbox, we can calculate the width to contain this neatly.

-box_width% = 200 +

Horizontally, the toolbox should align with the left-hand edge of the main window’s work area, which we achieve by aligning the X0 extents of the two windows’s visible areas. As the toolbox is a fixed width, its X1 extent is offset from the main window’s X0 extent by that width.

-

Horizontally, the toolbox should align with the left-hand edge of the main window’s work area, which we achieve in the usual way. The X0 extent remains relative to the visible area of the main window, but the X1 extent is offset from the main window’s X0 extent by the calculated width.

+box_width% = 200 -toolbox%!4 = main%!4 : REM Visible Area X0 +toolbox%!4 = main%!4 : REM Visible Area X0 toolbox%!12 = main%!4 + box_width% : REM Visible Area X1 -

Positioning the toolbox in the vertical dimension, however, is more tricky than anything which we have encountered up to now. As can be seen in , we need to ensure that the top and bottom outlines of the toolbox line up with the top and bottom outlines of the main window’s horizontal scroll bar.

+

Positioning the toolbox in the vertical dimension, however, is more tricky than anything which we have encountered up to this point. As can be seen in , we need to ensure that the top and bottom outlines of the toolbox line up with the top and bottom outlines of the main window’s horizontal scroll bar.

-

The Y0 coordinate for the toolbox visible area must line up with the Y0 coordinate of the main window’s outline. As we saw in the previous chapter, the outline includes the window border, and so its X0 is one pixel further down the screen than the X0 of the visible area will be.

+

The Y0 coordinate for the visible area of the toolbox must line up with the Y0 coordinate of the main window’s outline. As we saw in the previous chapter, the outline includes the window border, and so its X0 is one pixel further down the screen than the X0 of the visible area will be.

-

However, unlike last time, we can no longer rely on the Wimp clipping the visible area of the toolbox for us. If we look at the Y1 coordinate of the toolbox visible area, we can see that it must be aligned to the Y0 coordinate of the main window’s visible area. The Y1 is exclusive, while the Y0 is inclusive, so we’re actually aligning the border of the toolbox with the bottom pixel of the main window’s visible area – again, we’re a pixel adrift!

+

On this occasion, however, we can no longer rely on the Wimp clipping the visible area of the toolbox for us. If we look at the Y1 coordinate of the toolbox visible area, we can see that it must be aligned to the Y0 coordinate of the main window’s visible area. The Y1 is exclusive, while the Y0 is inclusive, so we’re actually aligning the border of the toolbox with the bottom pixel of the main window’s visible area – again, we’re a pixel adrift!

From this, we can see that the height of the toolbox visible area will be

box_height% = (main%!8 - pixel_height%) - (main_outline%!8 + pixel_height%) -

where pixel_height% is a variable holding the number of OS Units which represent the height of a pixel in the current screen mode. This will vary between modes, but as we saw when we created our simple application, we can read the information in the form of the vertical eigenfactor and then convert that in to OS Units by raising 2 to its power.

+

where pixel_height% is a variable holding the number of OS Units which represent the height of a pixel in the current screen mode. This will vary between modes but, as we saw when we created our simple application, we can read the information in the form of the vertical eigenfactor and then convert that in to OS Units by raising 2 to its power.

SYS "OS_ReadModeVariable", -1, 5 TO ,,eigenfactor% pixel_height% = 2 ^ eigenfactor% -

With the toolbox positioned, the final thing to do before opening it as a child window is to use Wimp_SetExtent to ensure that the extent is sufficient to cover the whole visible area.

+

With the toolbox positioned, the final thing to do before opening it as a child window is to use Wimp_SetExtent to ensure that its extent is sufficient to cover the whole visible area.

toolbox%!52 = toolbox%!44 + box_width% toolbox%!48 = toolbox%!56 - box_height% @@ -244,7 +244,7 @@ toolbox%!28 = -1 SYS "Wimp_OpenWindow",,toolbox%, &4B534154, !main%, &05550000 ENDPROC -

Running the application will produce a window with a toolbox embedded into the horizontal scroll bar, as seen in .

+

Running the application will produce a window with an empty toolbox embedded into the horizontal scroll bar, as seen in .

@@ -257,7 +257,7 @@ ENDPROC
Adding some icons -

A toolbox isn’t much use without some icons in it, so the next thing that we will need to do is add some. Unlike all of our previous panes, however, the critical dimension – the height of the toolbox window, which will determine the size of the icons within it – is dependent on a factor outside of our control. It is defined by the height of the horizontal scroll bar, which in turn will depend on the desktop theme and mode that user has selected.

+

A toolbox isn’t much use without some icons in it, so the next thing that we will need to do is to add some. Unlike all of our previous panes, however, the critical dimension – the height of the toolbox window, which will determine the size of the icons within it – is dependent on a factor outside of our control. It is defined by the height of the horizontal scroll bar, which in turn will depend on the desktop theme and mode that user has selected.

As a result, we will need to arrange the icons in the toolbox as we align it to the main window. This isn’t a problem: we’ve already seen how to move icons around using Wimp_ResizeIcon in several of the previous examples – it just adds another step to the process of opening the window.

@@ -265,7 +265,7 @@ ENDPROC
-

Given that space is limited, we will lay the toolbox out with the minimum of wasted real estate as shown in : a border of one pixel around the outside of the icons, and one pixel between each icon. Usually icons are placed on a 4 by 4 OS Unit grid to ensure that designs will work in all modes including the old rectangular pixel ones found on early systems (see the Style Guide for details), but we’re reading the mode details when we arrange the toolbox and so only need to match the capability of the current screen mode.

+

Given that space is limited, we will lay the toolbox out with the minimum of wasted real estate as shown in : a border of one pixel around the outside of the icons, and one pixel between each icon. Usually icons are placed on a grid of 4 by 4 OS Units to ensure that designs will work in all modes including the old rectangular pixel ones found on early systems (see the Style Guide for details), but since we’re reading the mode details when we arrange the toolbox, it is safe to only worry about matching the capability of the current screen mode.

@@ -354,11 +354,11 @@ FOR icon% = 0 TO toolbox%!88 - 1 NEXT icon% ENDPROC -

When the code is run, the window should now look something like the one in .

+

When the code is run, the window should now look something like the one in – the toolbox now has some icons in it!

-

One of the things that is worth noting here is the very limited – not to mention variable – space available for the icons in the toolbox. Care needs to be taken when designing the contents, to ensure that it can handle different screen modes and sizes of scroll bar whilst remaining clear and intuitive to the user. This is a problem that is getting worse as screen sizes reduce, and it may be that in a modern application, embedded toolboxes are best limited to the kinds of uses seen in Paint () and NetSurf ().

+

One of the things that is worth noting here is the very limited – not to mention variable – space available for the icons in the toolbox. Care needs to be taken when designing the contents, to ensure that it can handle different screen modes and sizes of scroll bar whilst remaining clear and intuitive to the user. This is a problem that is getting worse as screen sizes increase, and it may be that in a modern application, embedded toolboxes are best limited to the kinds of uses seen in Paint () and NetSurf ().

The full application with the code to position the icons can be found in .

@@ -374,7 +374,7 @@ 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 kept this separate from PROCarrange_toolbox earlier, because now 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.

@@ -409,17 +409,17 @@ 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 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.

+

In order to be sent Message_ModeChange, we will need to update PROCinitialise as seen in 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.

- + q%!0 = &400C1 : REM Message_ModeChange 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 as shown in . 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 +CASE reason% OF WHEN 2 : SYS "Wimp_OpenWindow",,b% WHEN 3 : SYS "Wimp_CloseWindow",,b% WHEN 6 : PROCmouse_click(b%) @@ -427,9 +427,9 @@ 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, and can be seen in . 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%) +DEF PROCuser_message(b%) CASE b%!16 OF WHEN 0 : REM Message_Quit Quit% = TRUE @@ -438,7 +438,7 @@ WHEN &400C1 : REM Message_ModeChange ENDCASE ENDPROC -

With all of these changes in place, the full application can be found in .

+

With all of these changes in place, the full application can be found in . There should no functional differences from the previous version, besides its ability to more gracefully handle mode changes.