Creating a docked window
Steve Drain (222) 1620 posts |
+1 I started to put together a few paragraphs about panes, but nothing anything near as comprehensive as this, so I bow down before you, Steve. ;-) However, I think there is one mistake: I cannot find any I would also say that there are places where there is more code than necessary to achieve the end, but that is really a matter of style, and has no practical implications. ;-) |
Steve Fryatt (216) 2105 posts |
Fair point… What’s the recommended way to do this in a multitasking application? I’d ideally like the global error handler to remain in place if the user clicks “continue”, but I’m not sure how to do this neatly if the structure is
whilst doing
Out of curiosity, where? I’m happy to reduce things if it doesn’t affect clarity – the primary aim here is to be clear to the reader, and also to support all of the forthcoming examples that haven’t been published yet… :-) |
Steve Fryatt (216) 2105 posts |
The answer is “no”, it seems, but we can do something that’s probably more useful:
and then continue into the function. Thanks for the suggestion; I’ll do some updating. :-) |
Steve Drain (222) 1620 posts |
That’s a novel idea, and I may use it, thanks. ;-) I have both a multi-tasking Toolbox error dialogue and a wimp error window a bit like yours. Mine offer a throwback option as well, with PROC/FN backtrace. The latter is a bit complex to implement in just BASIC so it would have been a candidate for Basalt once upon a time. I am not sure that you can usefully |
Steve Drain (222) 1620 posts |
As I said, it is really a matter of style, but here are some tiny morsels. I may be mistaken, of course. IF !b% = MainWindow% THEN PROChandle_pane_windows(b%) ELSE SYS "Wimp_OpenWindow",,b% ENDIF It is not necessary to open windows with panes any differently to other windows. The code to add a pane can be after the window has been opened.
SYS "Wimp_OpenWindow",,b% IF !b% = MainWindow% THEN PROChandle_pane_windows(b%) This in parallel: pane%!28 = main%!28 SYS "Wimp_OpenWindow",,pane% main%!28 = !pane% It is not necessary to explicitly set the main window to behind the pane. Inserting the pane above the main pushes the main down the stack so that it is behind, but this is only so if the main is opened first, as above. I would use one call to My style is rather minimalist. I like to see the whole of any routine on screen at one go and for it to be aesthetically pleasing. This has its drawbacks, but it is not ascetic like nemo, for example. ;-) |
Paul Sprangers (346) 525 posts |
That is my experience too. Wrestling with code before Steve published his exemplary instructions, I managed to achieve a nicely behaving pane with a minimum of magic. It appeared to come down to do everything after poll reason 2 (OpenWindowRequest). Open the main window first, then calculate the coordinates of the pane, and finally open the pane too, all in one go. I wonder in what circumstances this will go wrong, as I assume that Steve’s approach undoubtedly is the proper one. For example, in my code there’s no such thing as By the way, is |
Steve Drain (222) 1620 posts |
Just for interest I wanted to see how much the minimal code would be to do the pane example using the Toolbox from BASIC. Here it is in total: REM> <PaneDemo$Dir>.!RunImage ON ERROR ON ERROR OFF:ERROR EXT ERR,STR$ERR+", "+REPORT$+" "+STR$ERL DIM block% 255,id% 23,desc% 15:REM wimp block,id block,messages descr quit%=FALSE:!block%=0:REM return all toolbox events SYS"Toolbox_Initialise",,310,0,block%,"<PaneDemo$Dir>",desc%,id% REPEAT SYS"Wimp_Poll",%1,block% TO reason% CASE reason% OF WHEN 17,18:quit%=TRUE:REM Message 0 only WHEN &200:IF block%!8=&400 THEN quit%=TRUE:REM Quit entry ENDCASE UNTIL quit% It is not quite identical in effect, it does not show the effort put into the design of the Res file and it is a poor basis for further development, but it shows how the Toolbox can simplify things. ;-) |
Simon Willcocks (1499) 522 posts |
I can’t talk about the pane mechanism, but, no those are absolutely not the same. pane% Is the address of a block of memory, and !pane% is the contents of the first word in that block of memory. They won’t be the same value unless you’ve first done !pane% = pane% |
Steve Fryatt (216) 2105 posts |
Having pondered this a bit, I think you’re correct here: looking at what Maestro does, the trick is to open the main window, see where it ends up, then open the panes around that. Doing it the way I do it, things get detached if the Wimp doesn’t open the main window exactly where it was requested (which is possible). So the Open_Window_Request handler becomes:
where that is defined as
The call to Wimp_GetWindowState isn’t required on the Nested Wimp, as that is documented as returning the actual state of the window that was opened from Wimp_OpenWindow. Apparently (according to the Nested Wimp docs), Wimp_OpenWindow has always done this, so if we’re OK to rely on retrospective documentation, then we don’t need the call to Wimp_GetWindowState at all. Thanks again for the comments; it’s educational stuff, this tutorial writing… I think it might be time for a second revision, too. |
Steve Fryatt (216) 2105 posts |
As noted above, I think this is probably the correct approach.
Is that a problem? It’s just allocating a block of memory to pass to Wimp_GetWindowState for the pane, because unless you know that you’re running on RISC OS 5, BASIC doesn’t do dynamic memory allocation inside functions or procedures. Instead we’re stealing space from the end of the block passed to Wimp_Poll, because we know that the Open_Window_Request only uses the first 32 bytes of the 256 available in the block. Setting On RISC OS 5, we could replace that line entirely with
and the space would be claimed off the stack instead (which is how I’d do it in C, as well).
It should have been
No, they are not the same. It should be Omitting this could just mean that the Z order of the windows gets out of step, which probably won’t be noticeable – at least until the pane gets behind the main window, or until another window gets between the main window and its pane. |
Paul Sprangers (346) 525 posts |
No doubt, but I think I found something interesting… However, when I omit the ! (thus: |
Steve Fryatt (216) 2105 posts |
Whose code are we talking about, here? Is it from an example that I’ve written, or one of your own applications? |
Paul Sprangers (346) 525 posts |
Apologise, this is about my own code. That might explain the unexpected results. |
Steve Fryatt (216) 2105 posts |
No problem; I’m just trying to weed the bugs out of my own examples… If you wanted analysis, and the code can be posted, we can always try to spot the problem! |
Steve Fryatt (216) 2105 posts |
I’ve re-worked the text and examples to follow the approach used by Maestro (and Steve D), which I agree is the “correct” way to do things. It still needs some editing and proofing, but that’s for another day… Thanks for all of the suggestions and feedback so far; it’s definitely been educational, and hopefully the summarised version will be useful to others in the future. :-) |
Steve Drain (222) 1620 posts |
Very impressive. ;-) Just a note that the Toolbox clips internal toolbars to fit the window, but I do not know how to scroll them to follow the main window contents (yet). While we are exchanging ideas, why do you, and many others, put otherwise empty lines with a colon in them between definitions, but not other blank lines? Is it a hangover from the BBC B? With BASIC$Crunch set, BASIC will remove the colon but not the blank line, but any blank line takes memory and fractionally slows a program, neither of which may be of much concern, but it feel awkward to me. ;-) |
Steve Fryatt (216) 2105 posts |
I think it’s just to visually tie the FN/PROC header comments to the definition itself, but it’s just something that I’ve always done.
Ah, I don’t care about that! :-) All of my production code is passed through Tokenize with the |
Steffen Huber (91) 1953 posts |
The thing where most pane handling code goes wrong is when clever tools like Mauser or MouseAxess are used to move the pane instead of the main window. I think there was a comprehensive pane handling example by Ian Jeffray that handled that (as well as moving panes around via the miniature desktop representation in MultiDesk). In BASIC, IIRC. Maybe someone can dig that out. |
Rick Murray (539) 13851 posts |
I used to do this. The primary idea was a blank line, a line with a colon, and then another blank line went between each procedure/function definition and was specifically to act as a separation between them. The comma doesn’t actually do anything, it’s more a visual note for the programmer than anything else. Probably not so important when one can code in Zap with a nice font, but I started out with MODE 7 (!) so everything bit of roadmap was helpful. Blank lines (usually two) with no comma are separations between related code blocks within the same function. And a single blank line is just to break things up at a natural change so it’s less of a jumble. The difference between one and two blank lines is subtle. If what follows ties to the previous, it’s a single line. If it is logically related but different, it’s two lines. For instance, creating windows and creating menus in the Wimp startup function are logically related (getting the task going) but they aren’t dealing with the same thing, hence two lines. I don’t tend to use commas any more as I lost the habit when writing C. Functions still have three lines between (BASIC and C) but no comma these days. Oh, and since I’m talking about personal coding style, here’s how to handle braces: void function (int val) { if (val == TRUE) { printf("Yes!\n"); } else { printf("Wah, no!\n"); } return; } Don’t fear white space, it’s not a Beeb! I won’t say “death to people who put their braces in the wrong place”, as my ire is reserved for those who put tabs in source…especially when the tab width is something weird. Doubly so when tabs and spaces are mixed in the same code and the indent amounts are not the same! Oh, and a note for the pedantic: the braces in the if aren’t strictly necessary as there’s only one statement in each clause, it’s just to demonstrate. |
Steve Drain (222) 1620 posts |
I have tested both my original plain BASIC pane code and my Toolbox toolbar code. With Mauser a pane moves independently, as it does with Draw, but a toolbar produces an error. With my pane code I can prevent this movement just by taking no action on a WindowOpen request for the pane 1, which looks like a filter is in use. With MouseAxess a pane/toolbar movement results in the main window moving as well, as it does with Draw. MouseAxess is clearly looking after things. ;-) 1 Like this CASE !B% OF |
David J. Ruck (33) 1636 posts |
I’m more concerned with the comparison of an int with TRUE. FALSE is zero and any other value is true, so the comparison should be |
André Timmermans (100) 655 posts |
If your toolbar covers part of the main window, you will have a lot of redraw occurring (main window redrawn on top of stack obscuring the toolbar then the toolbar being redrawn on top of it). An other way to do it is: |
Steve Fryatt (216) 2105 posts |
Experimentation says that you don’t… If I take Download 3.3 from my tutorial and make all three windows user-redraw, just moving the main window around on screen results in no redraw events being generated. I did wonder if this was another “window is a pane” optimisation, but it doesn’t appear to be. It appears that the Wimp simply doesn’t start working out invalidated rectangles until the application has returned from Wimp_Poll.
That’s what I originally did… Steve D convinced me that it’s wrong, not least because if the main window doesn’t open where you expect it to (the Wimp reserves the right not to put it where the application asks, if constraints prevent it), then the pane becomes detached and you need a second Wimp_OpenWindow for the pane to reattach it. Also, Acorn did it Steve’s way in Maestro… and the Nested Wimp Technical Spec broadly hints that it’s the correct way to do things, too. |
Stuart Swales (8827) 1357 posts |
I wonder if this was just a RISC OS 2 thing? I have a vague memory of having to try to get the opening order right (circa 1992) to avoid flicker when dragging a stack of windows – a Fireworkz document window can be up to 13 windows when all the rulers, borders and document view splits are active. |
Steve Fryatt (216) 2105 posts |
This may be turning into a rabbit hole… Should child windows under the nested wimp have their pane flags set if they’re being used as panes, or not? It looks as though I’ve never set the flag in any of my software, but having just tried it (copying templates from non-nested example code, and not thinking to unset it), it gets interesting if you have a writeable icon in a child window and try to place the caret in it. Or, on RO5, double-click to select… (don’t do this with unsaved work on the machine, as random stuff will probably die). RO4.02 is equally unhappy, but at least has the grace to complain with an error box and then continue without further incident. Am I correct to assume that the pane flag should not be set for child windows, because the pane behaviour is implicit in the nestedness? I’ve not seen it documented either way. FWIW, the RO5 crash appears to be somewhere around here in the CnPCaret source file:
|