It is the 1727th of March 2020 (aka the 21st of November 2024)
You are 18.219.207.11,
pleased to meet you!
mailto:blog-at-heyrick-dot-eu
A random Christmas-season-sucks song - NSFW!
Just in case you missed it in the above title - this song is "NSFW" which means Not Safe For Work. Contains swearing, and plenty of truth about why Christmas sucks...
A toolbar window
Something that seems to be fairly popular nowadays is to place little toolbars in places traditionally reserved for scrollbars. This has benefits - a horizontal scrollbar, if scaled sanely, doesn't need to take the entire width of the window. As such, some of the space could be liberated for use as a toolbar without needing to claim space with tool buttons overlaying the main window (like Impression or Fireworkz), a button bar attached to the main window in some manner (like Draw), or a completely free-standing set of tools (like Paint).
Obviously an in-scrollbar toolbar would not be so useful for a word processor or drawing program as the choice of tools may be too numerous for a small toolbar (though for a word processor, it could offer easy access to common styles like bold/italic and left/justify/centre?). However when there are only a few tools, a toolbar of that sort may be a good choice.
David Pilling made it work in the original Ovation to good effect (the tools were chapter/page number, writing mode, text frame mode, picture frame mode, line drawng mode, and frame link mode). NetSurf uses this behaviour for status.
With the nested Wimp (available as an upgrade since the days of Acorn, and as standard in RISC OS 5), it becomes quite simple to create and attach toolbars.
I will demonstrate a toolbar at the bottom left, using DeskLib. Essentially, this:
With many thanks to Martin Avison for some source code in assembler that demonstrated how to use the toolbar window functions and helped explain some of the things in the API that weren't clear.
Create the window
You will need to create a window with a work area and minimum size of 36 units height, and as wide as necessary (my toolbar is 248 units). Units are "OS units", not pixels. These sizes are derived from the height of the scrollbar determined by experimentation, and a width suitable for five small icons broken into a group of two, a small space, then a group of three.
The problem with having buttons this small is that you can't use uppercase letters - many don't fit properly. Thankfully many lower case letters resemble their upper case counterparts and are small enough that they 'look' correct.
Create this window as you would any normal window, only there is no window furniture (no title bar, scroll bars, etc).
Note - the actual height of the scrollbar is 38 OS units, but a toolbar that tall didn't seem to sit nicely in the space beside the scrollbar. Experiment, see what works for you.
Load the toolbar
In your program, you will have a part that handles the Wimp initialisation and deals with loading windows. Stuff like this:
// Create and attach the main window
main_window = Window_Create("main", 128); // Title and page
if (main_window == 0)
{
Error_ReportWithType(Error_ProgramStop, 0, message_read("wimp.tempfail"), "main", appname);
exit(EXIT_FAILURE);
}
Event_Claim(event_CLICK, main_window, event_ANY, main_clickhandler, NULL);
In here, insert some code to load your toolbar window. It will look like this:
// Load the definition of the toolbar window, but do NOT create it yet.
if ( event_wimpversion >= 380 )
{
// Don't bother doing this if the Wimp version is too old
toolbar_window = toolbar_create("toolbar"); // No title
if (toolbar_window == 0)
{
Error_ReportWithType(Error_ProgramStop, 0, message_read("wimp.tempfail"), "toolbar", appname);
exit(EXIT_FAILURE);
}
Event_Claim(event_CLICK, toolbar_window, event_ANY, toolbar_clickhandler, NULL);
}
You do not need to call the Wimp with version 380 in order to make use of the toolbar attachment functions, however you should check that the current Wimp version is at least 380 in order that the toolbar behaviour works as expected.
Notice that we must call a special function to load the window, but we can set up the normal event handlers.
Open the toolbar
When you come to open the window that has a toolbar, you should call a function to "attach" it. This may be in the routine that draws the window prior to its display, or it may be dynamic. In my Manga software, ALT-click toggles the toolbar visible or not with the following code in the click handler:
// Alt-click toggles the toolbar
if ( Kbd_KeyDown(inkey_ALT) )
{
if ( event_wimpversion >= 380 )
{
Wimp_GetWindowState(toolbar_window, &wstate);
if ( !wstate.flags.data.open )
toolbar_attach(); // not open? attach it to the main window
else
Window_Hide(toolbar_window); // open? close it
}
else
{
Error_Report(1, message_read("wimp.nonested"),
(float)( (float)event_wimpversion / (float)100) );
}
return TRUE;
}
This code will make the toolbar visible, via a custom routine, or hide it (using the standard Window_Hide), or pop up a notification if the Wimp version is too old.
If you simply want to paste a toolbar onto the window, you could cut that down to:
if ( event_wimpversion >= 380 )
toolbar_attach();
Creating the toolbar
In essence, this is the same as the Window_Create function, with a couple of extra lines to set up flags.
static window_handle toolbar_create(char *templname)
{
// This is Window_Create, only we fudge a flag prior to creating the window.
windowrec *record;
window_block *windowptr;
window_handle window;
windowptr = Template_Clone(templname, 8);
if (windowptr == NULL)
return NULL;
windowptr->flags.data.dummy23 = 1; // flag it as a "furniture" window
windowptr->colours[0] = 0xFF; // no outline
Wimp_CreateWindow(windowptr, &window);
record = (windowrec *) malloc(sizeof(windowrec));
if (record == NULL)
return NULL;
LinkList_AddToHead(&window_listanchor, &(record->header));
strncpy(record->templatename, templname, wimp_MAXNAME);
record->templatename[wimp_MAXNAME] = 0; /* Record of name for help */
record->window = window; /* Remember window handle */
record->memory = windowptr; /* remember to dealloc later */
return(window);
}
The first extra line is windowptr->flags.data.dummy23 = 1; which marks the window as a "furniture" window. Without this, it will never be opened in the intended manner.
The second extra line is windowptr->colours[0] = 0xFF; to set the window colour to an invalid value, which is a flag meaning "don't draw an outline around this window". You may prefer the window with an outline. Try it both ways, see what you think.
Showing the toolbar
The next thing we need to do is to open the window in the correct place. Without this, the Wimp won't recognise it as a toolbar and so won't readjust the scrollbar size.
static void toolbar_attach(void)
{
window_outline main_outline;
window_state wstate;
// Okay, so the first thing we must do is locate the bottom left of the parent window ("main").
main_outline.window = main_window;
Wimp_GetWindowOutline(&main_outline);
// Now pick up the state of the toolbar window
Wimp_GetWindowState(toolbar_window, &wstate);
wstate.openblock.behind = -1;
// Fudge our on-screen dimensions
wstate.openblock.screenrect.min.x = main_outline.screenrect.min.x + 2; // Left
wstate.openblock.screenrect.min.y = main_outline.screenrect.min.y + 2; // Bottom
wstate.openblock.screenrect.max.x = main_outline.screenrect.min.x + 248; // Right (width)
wstate.openblock.screenrect.max.y = main_outline.screenrect.min.y + 38; // Top (height)
// Now we can't just call Wimp_OpenWindow() as it doesn't understand the extended flags, so...
__asm
{
MOV R1, &wstate.openblock
MOV R2, 0x4B534154
MOV R3, main_window
MOV R4, 0x00550000
SWI (SWI_Wimp_OpenWindow + XOS_Bit), {R1-R4}, {R0}, {LR, PSR}
}
return;
}
The first thing we do is to work out where the "main_window" is placed. This is the parent window of the toolbar. Next, we pick up the data block relating to the toolbar. The "openblock" (data passed to Wimp_OpenWindow) is manipulated to place the toolbar at the bottom left of the parent. The two +2s are to fudge the position a little so it looks better. The right and top position are also set accordingly from the size of the window.
We then drop to some inline assembler as the current DeskLib OpenWindow call does not support the extended API. That is to say, R2 is "TASK" (the magic value traditionally given to Wimp SWIs to indicate a better API is being used), R3 is a pointer to the parent window, and R4 specifies alignment to the lower left.
The Wimp needs the alignment to be specified as being lower right and the window to be touching the correct placement. If these conditions are both satisfied, it'll adjust the scroll bar accordingly.
Interacting with the toolbar
It's a normal window. You can set up a click handler for it, change icons as normal, and Window_Hide to remove it.
Caveats
It is your responsibility to ensure that the window's width does not become insufficient for the toolbar and a minimal scrollbar. In the case of Manga, the title bar text assures this.
It is your responsibility to check the Wimp version. Earlier (RISC OS 3.xx) Wimps do not support this functionality and won't work as expected (David Pilling did something complicated for Ovation where both the toolbar and the horizontal scroll bar were separate windows that moved with the main window, and thus behaved like a window with a toolbar in it - quite clever, but it complicated window handling as you can imagine...).
Theoretically you can have a toolbar on the right, or vertical toolbars at the top or bottom of the vertical scrollbar. One might suppose that it would be possible to have, for instance, two toolbars - to the left and right of the scrollbar, for instance. Or possibly a toolbar within the toolbar?
I hope this introduction to creating a toolbar with the nested Wimp helps to demonstrate some of the flexibility that you can use in your own programs.
Vanishing comments
There's something rather weird with my host, in that if the space allocation fills up (due to something managing to spew out gigabytes of log file), the server will create new files (via SFTP), silently throw away the data, and just leave zero length files. It also turns out, and thanks to David Pilling for spotting this, that the server would also affect comments by opening the comment file to append a comment, silently throw away the data, and close the file, with no indication whatsoever that anything went wrong (and since there's no more space, the call to email me a copy of the comment is also silently dropped on the floor).
Personally, I don't think a server that silently discards data is fit for purpose, but since my hosting is the generosity of a friend, I don't push the issue. Instead, I have devised a technical means of attempting to trap this situation. Ever the pragmatist, the comment script will now attempt to open a specific file and write something to it. If the result afterwards is an empty file, then commenting will be disabled (existing comments will still be shown), otherwise it will work as expected.
A quiet December
I'm glad I'm not writing an article a day this year. The run up to Christmas has been long and I'm very tired. Looking forward to clocking out next Friday evening for the Christmas holiday. For the most part, I've basically just come home and watched DVDs - Veronica Mars, New Girl, and various films I pick up cheap from the library (like "Spiders 3D" (only it wasn't the 3D version thankfully)) which was pretty crappy but a way to waste an hour and a half wondering when the babysitter would get it (just after they made her a sympathetic character, shame it wasn't the annoying daughter) and it only cost me €0.50 so no big loss...
Other times, I've probably been working on Manga. I'm in the course of removing all of the embedded messages and texts and getting it to use a Messages file. You know, in case somebody wants to translate it into French or something... ☺
Your comments:
Please note that while I check this page every so often, I am not able to control what users write; therefore I disclaim all liability for unpleasant and/or infringing and/or defamatory material. Undesired content will be removed as soon as it is noticed. By leaving a comment, you agree not to post material that is illegal or in bad taste, and you should be aware that the time and your IP address are both recorded, should it be necessary to find out who you are. Oh, and don't bother trying to inline HTML. I'm not that stupid! ☺ ADDING COMMENTS DOES NOT WORK IF READING TRANSLATED VERSIONS.
You can now follow comment additions with the comment RSS feed. This is distinct from the b.log RSS feed, so you can subscribe to one or both as you wish.
David Pilling, 18th December 2017, 22:38
Oh the agonies of that tool/scroll bar in Ovation (which might have been copied from Quark). Good idea to use the nested wimp.
I wonder if one could get rid of scroll bars. Doesn't RISC OS have this thing of scrolling with Adjust on the scroll bar. No scroll bars just drag the work area around. Of course why you'd do that with modern screens which are so much bigger than those of the late 80s.
Rick, 18th December 2017, 23:12
You could look at it that RISC OS took about a decade and a half to catch up with you? ;-)
Adjust clicking on the scroll bar engages two dimensional scrolling. I think we might need scroll bars to indicate to people that there's more than visible in the window (and give an idea of roughly how much more).
Rob, 9th January 2018, 22:26
Damn. Sorry about the comments thing. I found 2.5G (!!) of bounce emails sitting in root's mailbox, so killed them. Also set up logrotate, which is keeping the log files you mentioned under control. Server is looking a little more healthy now.. :)
Rick, 9th January 2018, 23:09
It's okay about the comments. Gave me a chance to dust off my blog code and realise how much PHP I've forgotten. :-/
Damn this useless out-of-warranty memory I have installed...
This web page is licenced for your personal, private, non-commercial use only. No automated processing by advertising systems is permitted.
RIPA notice: No consent is given for interception of page transmission.