diff --git a/Chapters/ch03-a-top-toolbar.xml b/Chapters/ch03-a-top-toolbar.xml
index 18fd43a..13b0d1e 100644
--- a/Chapters/ch03-a-top-toolbar.xml
+++ b/Chapters/ch03-a-top-toolbar.xml
@@ -46,7 +46,7 @@
An alternative to a toolbox at the side of a window, as we created in the last chapter, is a toolbar across the top of a window. Which to go for is more of a stylistic question than a technical one, and it’s possible to have both at the same time. Ovation Pro does just this, as seen in .
-
+
In this chapter, we’ll add such a toolbar to our own window, to complement the existing toolbox.
diff --git a/Chapters/ch04-column-headings.xml b/Chapters/ch04-column-headings.xml
index d632a7c..0b25b1e 100644
--- a/Chapters/ch04-column-headings.xml
+++ b/Chapters/ch04-column-headings.xml
@@ -44,13 +44,182 @@
So far our toolbar has ignored the main window contents; what if we want it to remain in step with the work area?
-An alternative to a toolbox at the side of a window, as we created in the last chapter, is a toolbar across the top of a window. Which to go for is more of a stylistic question than a technical one, and it’s possible to have both at the same time. Ovation Pro does just this, as seen in .
+Now that we have added both a toolbox and a toolbar to our example application in the past two chapters, it’s time to look a subtle way of altering the configuration.
-
+So far, both of our panes have used ‘fixed’ work areas which don’t scroll: their X and Y scroll offsets were set to zero in the window templates, and remained at that value as the main window moved around. However, there’s no reason why panes can’t scroll in sympathy with their parent windows: a spreadsheet might need to do this if it was using a pane to show the column headings in a document, for example. In fact Fireworkz, seen in , does exactly this.
-In this chapter, we’ll add such a toolbar to our own window, to complement the existing toolbox.
+
+It’s worth noting here that in the screenshot above, the Fireworkz window is actually composed of multiple panes. There’s a pane with a fixed work area containing the button and status bars (the latter containing the text “Page 1”), which – just like the one that we have already created – does not scroll with the work area. Below it is a separate pane containing just the column headings for the sheet (from “b” through to “e” here), which does scroll: ensuring that the headings remain lined up with the associated cells in the main window.
+Although we won’t be assembling a composite set-up like Fireworkz, in this chapter, we’ll see what is required to make a pane scroll with its parent window.
+
+
+
+
+
+Updating the templates
+
+Following the now familiar pattern, we’ll begin by updating the window templates for our new example. As our code was starting to get a little unwieldy, we will begin by losing the toolbox to the left of the window, leaving just the toolbar at the top. The “Toolbox” template can therefore be deleted from the template file, leaving just the three templates for the main window, toolbar and program information window as seen in .
+
+
+
+The toolbar window itself has also been updated, removing the pair of action buttons and the writeable field. In their place are four ‘heading’ icons, which should line up with the columns of coloured squares in the main window. The buttons are now passive – neither visibly pressing nor generating Mouse_Click events – although as before this is merely cosmetic.
+
+For the code itself, we have gone back to and stripped out all of the code relating to the toolbox pane. First, we no longer need to load or the window, reducing the template code in PROCinitialise to loading the remaining three windows as seen in .
+
+REM Load the window templates
+
+DIM TemplateName% 12
+
+SYS "Wimp_OpenTemplate",,"<PaneDemo$Dir>.Templates"
+
+PROCtemplate_load("Main", b%, buffer_size%, -1)
+SYS "Wimp_CreateWindow",,b% TO MainWindow%
+WindowWidth% = b%!8 - b%!0 : REM Width is Visible Area Maximum X - Minimun X
+WindowHeight% = b%!12 - b%!4 : REM Height is Visible Area Maximum Y - Minimun Y
+
+PROCtemplate_load("Toolbar", b%, buffer_size%, -1)
+SYS "Wimp_CreateWindow",,b% TO ToolBarWindow%
+
+PROCtemplate_load("ProgInfo", b%, buffer_size%, -1)
+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 .
+
+DEF PROCclose_window_request(b%)
+IF !b% = MainWindow% THEN
+ !q% = ToolBarWindow%
+ SYS "Wimp_CloseWindow",,q%
+ENDIF
+
+SYS "Wimp_CloseWindow",,b%
+ENDPROC
+
+Finall, PROChandle_pane_windows() can be simplified again; it is now as shown in .
+
+DEF PROChandle_pane_windows(main%)
+LOCAL toolbar%, bar_height%
+
+REM Get the Window State block for the toolbar pane, using more of the
+REM spare space above the data for the state of the main window.
+
+toolbar% = main% + 64
+
+!toolbar% = ToolBarWindow%
+SYS "Wimp_GetWindowState",,toolbar%
+
+REM Find the height of the toolbar pane's visible area.
+
+bar_height% = toolbar%!16 - toolbar%!8 : REM Visible Area Maximum Y - Minimum Y
+
+REM Move the toolbar pane so that it's in the correct X and Y position
+REM relative to where the main window is to go.
+
+toolbar%!4 = main%!4 : REM Visible Area Minimum X
+toolbar%!8 = main%!16 - bar_height% : REM Visible Area Minimum Y
+toolbar%!12 = main%!12 : REM Visible Area Maximum X
+toolbar%!16 = main%!16 : REM Visible Area Maximum Y
+
+REM Unless the main window is to be opened behind the toolbar pane, and the
+REM toolbar pane is already behind the toolbox pane, meaning that all three
+REM windows must already be in the correct place in the stack, set the toolbox's
+REM Open Behind so that it appears in the stack where the main window is to go.
+
+IF main%!28 <> ToolBarWindow% THEN toolbar%!28 = main%!28
+
+SYS "Wimp_OpenWindow",,toolbar%
+
+REM Set the main window's Open Behind so that it opens behind the toolbar.
+
+main%!28 = ToolBarWindow%
+
+SYS "Wimp_OpenWindow",,main%
+ENDPROC
+
+The code here should be comparable to that found in – a single pane, but attached in a toolbar style instead of a toolbox. When run, the window should appear as seen in , with the new column headings lining up with the coloured grid squares below.
+
+
+
+The updated example code can be found in ; it would be a good idea to check through it and ensure that you are comfortable with how relates to the earlier examples.
+
+
+
+
+
+
+Out of alignment
+
+Unfortunately, any satisfaction with our new example is likely to be short-lived. If the width of the main window is reduced, and then the horizontal scroll bar used to shift the work area, we can quickly see that things go out of alignment as shown in . The main window’s work area moves with the scroll bars as expected, but the toolbar’s content remains where it was.
+
+
+
+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 PROChandle_pane_windows(). 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
+
+Things to consider here are that both the main window and the toolbar are the same width (we copy the X0 and X1 across unchanged as part of the pane positioning), and their horizontal extents are identical (both are set to 1040 in their window templates). As such, copying the X scroll offset across from one window to the other will have no unexpected effects.
+
+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 PROChandle_pane_windows() copying the horizontal scroll offset over to the pane.
+
+DEF PROChandle_pane_windows(main%)
+LOCAL toolbar%, bar_height%
+
+REM Get the Window State block for the toolbar pane, using more of the
+REM spare space above the data for the state of the main window.
+
+toolbar% = main% + 64
+
+!toolbar% = ToolBarWindow%
+SYS "Wimp_GetWindowState",,toolbar%
+
+REM Find the height of the toolbar pane's visible area.
+
+bar_height% = toolbar%!16 - toolbar%!8 : REM Visible Area Maximum Y - Minimum Y
+
+REM Move the toolbar pane so that it's in the correct X and Y position
+REM relative to where the main window is to go.
+
+toolbar%!4 = main%!4 : REM Visible Area Minimum X
+toolbar%!8 = main%!16 - bar_height% : REM Visible Area Minimum Y
+toolbar%!12 = main%!12 : REM Visible Area Maximum X
+toolbar%!16 = main%!16 : REM Visible Area Maximum Y
+
+REM Align the toolbar pane's scroll offset with the main window.
+
+toolbar%!20 = main%!20 : REM X Scroll Offset
+
+REM Unless the main window is to be opened behind the toolbar pane, and the
+REM toolbar pane is already behind the toolbox pane, meaning that all three
+REM windows must already be in the correct place in the stack, set the toolbox's
+REM Open Behind so that it appears in the stack where the main window is to go.
+
+IF main%!28 <> ToolBarWindow% THEN toolbar%!28 = main%!28
+
+SYS "Wimp_OpenWindow",,toolbar%
+
+REM Set the main window's Open Behind so that it opens behind the toolbar.
+
+main%!28 = ToolBarWindow%
+
+SYS "Wimp_OpenWindow",,main%
+ENDPROC
+
+Loading this version of the application, we can now scroll around the main window’s work area with the column headings in the toolbar remaining in step as seen in .
+
+
+
+The complete example code can be found in .
+
+
+
+With this example, we have completed our look at how panes can be handed using nothing more than the standard Wimp to help us. However, in 1997 Acorn added a new system for controlling panes, known as the Nested Wimp. In the coming chapters, we will look at this in more detail and see how it compares to the original approach.
diff --git a/Downloads/Chapter04/ColHead1/!PaneDemo/!Boot,feb b/Downloads/Chapter04/ColHead1/!PaneDemo/!Boot,feb
new file mode 100644
index 0000000..05fdbf5
--- /dev/null
+++ b/Downloads/Chapter04/ColHead1/!PaneDemo/!Boot,feb
@@ -0,0 +1,24 @@
+| >!Boot
+|
+| Copyright 2021, Stephen Fryatt (info@stevefryatt.org.uk)
+|
+| This file is part of PaneDemo:
+|
+| http://www.stevefryatt.org.uk/risc-os/panes
+|
+| Permission is hereby granted, free of charge, to any person obtaining
+| a copy of this software and associated documentation files (the
+| "Software"), to deal in the Software without restriction, including
+| without limitation the rights to use, copy, modify, merge, publish,
+| distribute, sublicense, and/or sell copies of the Software, and to
+| permit persons to whom the Software is furnished to do so.
+|
+| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+| OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+| IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+| CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+| TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+| SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+If ""="" Then Set PaneDemo$Dir
diff --git a/Downloads/Chapter04/ColHead1/!PaneDemo/!Run,feb b/Downloads/Chapter04/ColHead1/!PaneDemo/!Run,feb
new file mode 100644
index 0000000..d4679e1
--- /dev/null
+++ b/Downloads/Chapter04/ColHead1/!PaneDemo/!Run,feb
@@ -0,0 +1,27 @@
+| >!Run
+|
+| Copyright 2021, Stephen Fryatt (info@stevefryatt.org.uk)
+|
+| This file is part of PaneDemo:
+|
+| http://www.stevefryatt.org.uk/risc-os/panes
+|
+| Permission is hereby granted, free of charge, to any person obtaining
+| a copy of this software and associated documentation files (the
+| "Software"), to deal in the Software without restriction, including
+| without limitation the rights to use, copy, modify, merge, publish,
+| distribute, sublicense, and/or sell copies of the Software, and to
+| permit persons to whom the Software is furnished to do so.
+|
+| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+| OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+| IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+| CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+| TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+| SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Set PaneDemo$Dir
+
+WimpSlot -min 96K -max 96K
+Run .!RunImage
diff --git a/Downloads/Chapter04/ColHead1/!PaneDemo/!RunImage,ffb b/Downloads/Chapter04/ColHead1/!PaneDemo/!RunImage,ffb
new file mode 100644
index 0000000..17201f9
Binary files /dev/null and b/Downloads/Chapter04/ColHead1/!PaneDemo/!RunImage,ffb differ
diff --git a/Downloads/Chapter04/ColHead1/!PaneDemo/Templates,fec b/Downloads/Chapter04/ColHead1/!PaneDemo/Templates,fec
new file mode 100644
index 0000000..3f3953c
Binary files /dev/null and b/Downloads/Chapter04/ColHead1/!PaneDemo/Templates,fec differ
diff --git a/Downloads/Chapter04/ColHead2/!PaneDemo/!Boot,feb b/Downloads/Chapter04/ColHead2/!PaneDemo/!Boot,feb
new file mode 100644
index 0000000..05fdbf5
--- /dev/null
+++ b/Downloads/Chapter04/ColHead2/!PaneDemo/!Boot,feb
@@ -0,0 +1,24 @@
+| >!Boot
+|
+| Copyright 2021, Stephen Fryatt (info@stevefryatt.org.uk)
+|
+| This file is part of PaneDemo:
+|
+| http://www.stevefryatt.org.uk/risc-os/panes
+|
+| Permission is hereby granted, free of charge, to any person obtaining
+| a copy of this software and associated documentation files (the
+| "Software"), to deal in the Software without restriction, including
+| without limitation the rights to use, copy, modify, merge, publish,
+| distribute, sublicense, and/or sell copies of the Software, and to
+| permit persons to whom the Software is furnished to do so.
+|
+| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+| OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+| IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+| CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+| TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+| SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+If ""="" Then Set PaneDemo$Dir
diff --git a/Downloads/Chapter04/ColHead2/!PaneDemo/!Run,feb b/Downloads/Chapter04/ColHead2/!PaneDemo/!Run,feb
new file mode 100644
index 0000000..d4679e1
--- /dev/null
+++ b/Downloads/Chapter04/ColHead2/!PaneDemo/!Run,feb
@@ -0,0 +1,27 @@
+| >!Run
+|
+| Copyright 2021, Stephen Fryatt (info@stevefryatt.org.uk)
+|
+| This file is part of PaneDemo:
+|
+| http://www.stevefryatt.org.uk/risc-os/panes
+|
+| Permission is hereby granted, free of charge, to any person obtaining
+| a copy of this software and associated documentation files (the
+| "Software"), to deal in the Software without restriction, including
+| without limitation the rights to use, copy, modify, merge, publish,
+| distribute, sublicense, and/or sell copies of the Software, and to
+| permit persons to whom the Software is furnished to do so.
+|
+| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+| OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+| IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+| CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+| TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+| SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Set PaneDemo$Dir
+
+WimpSlot -min 96K -max 96K
+Run .!RunImage
diff --git a/Downloads/Chapter04/ColHead2/!PaneDemo/!RunImage,ffb b/Downloads/Chapter04/ColHead2/!PaneDemo/!RunImage,ffb
new file mode 100644
index 0000000..bfaef9f
Binary files /dev/null and b/Downloads/Chapter04/ColHead2/!PaneDemo/!RunImage,ffb differ
diff --git a/Downloads/Chapter04/ColHead2/!PaneDemo/Templates,fec b/Downloads/Chapter04/ColHead2/!PaneDemo/Templates,fec
new file mode 100644
index 0000000..3f3953c
Binary files /dev/null and b/Downloads/Chapter04/ColHead2/!PaneDemo/Templates,fec differ
diff --git a/Images/Chapter04/col-head-align-fixed.png b/Images/Chapter04/col-head-align-fixed.png
new file mode 100644
index 0000000..8907961
Binary files /dev/null and b/Images/Chapter04/col-head-align-fixed.png differ
diff --git a/Images/Chapter04/col-head-alignment.png b/Images/Chapter04/col-head-alignment.png
new file mode 100644
index 0000000..37a0a98
Binary files /dev/null and b/Images/Chapter04/col-head-alignment.png differ
diff --git a/Images/Chapter04/col-head-fireworkz.png b/Images/Chapter04/col-head-fireworkz.png
new file mode 100644
index 0000000..5391ba4
Binary files /dev/null and b/Images/Chapter04/col-head-fireworkz.png differ
diff --git a/Images/Chapter04/col-head-initial.png b/Images/Chapter04/col-head-initial.png
new file mode 100644
index 0000000..d239f53
Binary files /dev/null and b/Images/Chapter04/col-head-initial.png differ
diff --git a/Images/Chapter04/col-head-template.png b/Images/Chapter04/col-head-template.png
new file mode 100644
index 0000000..ee3bafe
Binary files /dev/null and b/Images/Chapter04/col-head-template.png differ