Best way to do complex layout?
Pages: 1 2
Loke (8740) 7 posts |
As mentioned in a different post, I’m have been trying to learn RiscOS programming by building a client for Mastodon. The networking parts works fine, and for the general UI I’m currently using Toolbox, which works reasonably well. Now I’m at a point where I want to make the feed look nice, and therefore I have a general question as to how to design a program to do so. If you haven’t used Mastodon, it’s essentially a feed of short-form posts, similar to Twitter, but longer and with support for some markup (bold, italics, bulleted lists, etc). Some posts can also contain polls, which is something I’d like to support eventually. In most other UI frameworks, I’d have a scrollable list of components, where each component represents a single post. The post would then be rendered using a label fo rthe name of the poster, an image for the avatar, a rich text area for the message content, etc, etc. In RiscOS I understand that I am going to have to do a lot of this manually, as there seems to be no rich text widgets for example. That’s all fine, but it also appears that there is not simple way to even have a dynamically generated, scrollable list of interactive elements? Is there some available code out there that does something similar that shows how such a thing can be done? The only program that comes close is Netsurf, but I think it’s much more complicated than what I’m looking for. |
Steffen Huber (91) 1953 posts |
As you have noticed, there is no “geometry management” aka “layout manager” available for either plain WIMP or the Toolbox, everything works with absolute coordinates (“OS units”). So you need to roll your own. It is a lot easier than it sounds – I have written countless specialized layout managers for Java Swing when the standard stuff got unpredictable or inefficient or unmaintainable (GridBoxLayout anyone?). For a “scrollable list” in plain WIMP world, you usually use a nested window. Which is like a standard window but without the title bar, the resize button and maybe only with a vertical scrollbar. Inside this window, you either draw everything yourself, or use the usual icons (or, in you case, the Toolbox objects/gadgets). In Toolbox world, I think there is a “ScrollList” Gadget that lives beside the TextArea – not sure if it is usable in other contexts. |
Loke (8740) 7 posts |
So you are saying that I can design the layout for a single message in the toolbox editor, and then instantiate as many as I need that needs to be displayed at any one time? That sounds like something worth testing. Do you also happen to have some advice as for how to deal with rich text? Is there some simple way to render that? |
Steve Fryatt (216) 2105 posts |
Not quite, although I guess that could work. From what you’re describing, I think you’d want a scrollable main window which can be re-sized as the user wishes. You can use the Nested Wimp to place a toolbar at the top, with a lot of flexibility as to look and feel. You could then nest windows at the appropriate offsets for each message, but you might equally be better to just calculate the offsets of the message “blocks” and use that information to identify which one your redraw code is looking for.
Not really — it’s a do-it-yourself job, unfortunately. The NetSurf project have useful libraries for handling Unicode and the like, which will probably be essential if you’re handling message text from other platforms. The RUfl library is useful for painting Unicode text to screen, IIRC. |
Steffen Huber (91) 1953 posts |
For rich text, I fear that your only option is to use the FontManager directly and handle the redraw for yourself – I am not aware of any ready-made components. You can glance at Martyn Fox’s introductory book “A Beginner’s Guide to Wimp Programming on RISC OS Computers” (all examples are in BASIC) for how to take control of the redraw and how to handle font painting How that works in a Toolbox context, I have no idea. My only piece of software that handles redraw “by hand” uses Wimp_PlotIcon all the way. So you’ll have to hope that some real experts give you meaningful answers. |
Loke (8740) 7 posts |
Thank you. Nested Wimp seems like something that is worth investigating. Do you know of any documentation that could be useful here? Or perhaps some source code for an existing project that does something like this? |
Anton Reiser (471) 63 posts |
For nested windows open first the child window(s) with
nothing will happen, until you open the parent window the usual way. Make sure, the child visible area is within the parent area. And have fun with the bounding flags. |
Alan Adams (2486) 1149 posts |
I have a couple of program which use panes. I tried using the nested wimp, which is supposed to make things easier, and gave up eventually as it seems to add a layer of obscurity I couldn’t get over. The key thing when using panes without the nested wimp, seems to be how to respond to open window requests. The window passed in that request could be the main or the pane, and in both cases the solution I found was to do three opens in succession. From (rather unreliable) memory, it is something like, open main window on the top of the stack. Open the pane behind the main window, open the main window behind the pane. That’s probably wrong in the detail, but it did seem to need three opens. |
Steve Fryatt (216) 2105 posts |
I’m not sure what they were? You open the parent window as normal, then adjust the position of the pane to be correct relative to it. Then you simply call Wimp_OpenWindow for the pane(s), but with the nested option set and flags ticked to indicate which side(s) of the pane are attached to the parent. And that’s it. Thereafter, you just handle open requests for the parent, and the Wimp sorts the pane(s) out for you. And if you want funky things like offset scrollbars, that happens automatically if you place the panes in the correct places.
You see, with the Nested Wimp, you don’t have to worry about getting all of that correct in all of the (often non-trivial) edge cases that you didn’t think of… |
Rick Murray (539) 13851 posts |
Why the first open (main window on the top)? It ought to suffice to open the pane on the top of the window stack, and then the main window behind it. If you want a little more complex, try Ovation. The main window is a plain user-drawn frame with a vertical scroll bar. The horizontal scrollbar and the tools pane (that Ovation did long before anybody else thought of it) are separate windows that are cleverly set up and opened in the right place. |
Fred Graute (114) 645 posts |
@Rick
Not sure if that works correctly when the main window is clipped by the Wimp – eg window is partly off-screen and user drags adjust-size icon. The pane could end up with a different size than the main window. In StrongED, the main window is opened first. Then its state is read and the pane opened using the size and handle-to-open-behind from that state. This ensures the pane is always the correct size, even when the main window has clipped. @Lore Are you aware of ChatCube? It seems that they may have much of what you need already. Might be worth having a chat with them. |
Alan Adams (2486) 1149 posts |
I can’t remember – it was written several years ago. I did a lot of experimenting before I found something that worked, then stuck with it.
The design is a main scrolling window, which gets extended or shrinks depending on the amount of data to display, and a pane which is the column headings, so they are always in view. The Wimp does all the redrawing, as the window contents are all in icons. Wimp_PlotIcon was a step too far for me, as I always get very confused when dealing wuth the various coordinate systems used in windows and the desktop. It’s slower this way, but that’s not a problem in this case. |
Alan Adams (2486) 1149 posts |
A number of my programs use variable size windows, which might help the OP. In the template file I create the icons for the first “structure” – usually a single row of icons. It’s important that these are the highest numbered icons in the template, and that the numbers are consecutive. Then in the program I work out how many sets of these are needed, and use PROCcopyiconrow(copies% etc). This replicates the icons moving them down the window, and adding new text buffers as we go. Finally PROCresizewindow does a scan through the window block finding the max and min X and Y coordinates in use, and uses Wimp_SetExtent to set the window size to fit round the icons. (I think it extends by 16 pixels in each direction.) Note that this doesn’t work if you use the technique of an icon hidden off-screen to provide a place for the input focus for instance. The window would resize to include it. If the number of “structures” needs to decrease then the icons are deleted and the window resized again. I don’t try to delete an intermediate “structure”. Instead I reduce the number of scructures to those needed, and update the contents to show the data currently needed. I think deleting intermediate icons would work, as the Wimp flags them as deleted, but then creating new icons would re-use these deleted icons, and the icon order now doesn’t match the data order. |
Alan Adams (2486) 1149 posts |
Something to watch out for: The icons in the window block have three fields for their data. Using an indirected text icon which uses an anti-aliased font, the three fields are text buffer, validation string buffer, and text buffer length. There’s no length field for the validation string. It matters, because changing text colour requires editing the validation string. It’s rather easy to create a template file where the text and validation buffers are only 4 bytes apart, and in this case changing the colour of one icon can corrupt the text of the following one. I have fudged round this by typing a row of dots into the validation string in the template editor, which forces it to allocate more space. As long as I don’t make the new validation string longer than the row of dots, it works. (Replace the row of dots, don’t add to it.) The alternative, safer way, would be for the program to allocate separate buffer space for validation strings, and go through the window block replacing the buffer address with one pointing into the program’s space. |
Steve Fryatt (216) 2105 posts |
That’s not a great approach. The better way, which scales well, is to create one set of icons in the template, zero the icon count on loading and then use the “orphaned” icons as templates for Wimp_PlotIcon in your redraw loop. See CashBook, PrintPDF, PS2Paper, Locate (and probably other stuff too) from my website. (CashBook and PrintPDF do slightly weird things involving a single row of real icons, which it doesn’t plot over, to allow for user entry.)
This is the advantage of the “virtual” icons and Wimp_PlotIcon approach. It’s easy to set up known buffers for your template icons, and use them as required. There’s also only one icon of each type to fiddle with. But if you’re plotting outline fonts, especially in a “messenger” type application taking unicode data from the internet, you want to be plotting your text directly and not through icons. As I suggested before, look at RUfl for inspiration as this is a solved problem. |
David J. Ruck (33) 1636 posts |
If most people on here want to keep using RISC OS applications over the next few decades, a thought needs to be given to accessibility software. A RISC OS screen reader would be quite easy to write given RISC OS’s complete lack of protection – the screen reader app would have no problems finding out about whatever any other application is doing. The big issue with RISC OS is controlling the machine – if you can’t see too well the mouse interface isn’t much good, so you need to control everything from the keyboard. RISC OS does have some ability to move between controls in simple static dialogs, but has no built in way of jumping between nested windows, or dynamically created icons. So if you are using Wimp_PlotIcon, please ensure you also put in the ability to logically move between icons using the keyboard – while you can still see what you are doing! |
Alan Adams (2486) 1149 posts |
Thanks for the suggestion. I’m trying a fairly simple test program to help understand how to do this. I had a look at Locate, and though I’m pretty unfamiliar with C, it’s well commented, and did help. However… I’ve got to the point where I call Wimp_PlotIcon in the redraw loop, and the new icon appears in the window in the expected place. It’s a write/click/drag icon. However the program doesn’t receive any response when clicking in it. The GetWindowInfo return shows that the icon count in the window did not change due to the addition of the icon. I don’t know whether it should change – this was one of the things I was using the program to test. |
Chris Hall (132) 3559 posts |
Have you used Wimp_CreateIcon? For reasons which I now cannot recall I had exactly the same issue in !MultiTask and solved it this way in July 1991:
|
Steve Fryatt (216) 2105 posts |
That’s because there’s no icon there: Wimp_PlotIcon plots an icon’s shape on screen, but it’s just another drawing tool alongside OS_Plot (or BASIC’s commands). You’ll need to handle the clicks yourself, setting the window background to the correct button type and dicing up the area to give the “icons” and their spaces in between. Locate contains code to do this, as does CashBook (which does all of the grid stuff to create dead areas in between cells). That said, if you want a writable icon, then you might be best off using a writbale icon: as I said, CashBook and PrintPDF both use a single row of real icons, which they don’t plot over, to allow for user entry. The row moves around the work area to always be in the line where the caret is. Locate doesn’t need to take keyboard input in its results windows. But we’re drifting a bit from my point, which was that your suggestion did not sound like a good fit for the OP’s application as described. It might be ideal for what you’re doing, but a chat application taking variable amounts of data in from the internet doesn’t really want to be laying out the page using icons. Add in the fact that the data is almost certainly Unicode, and the Wimp is not the tool to be using, unfortunately. The likelihood of Unicode alone makes this a “hand redraw using a suitable library” territory (and once again, I’ll mention RUfl). |
Alan Adams (2486) 1149 posts |
So in my case, where the rows copied down to form a table contain radio buttons, writable icons and plain text icons, is going to be a nightmare to decode. The reason I looked at this, is because I made some apparently small changes to the copyiconrow routine (to accommodate outline fonts) and discovered how fragile the old code was. It looks as though I’m going to have to work my way through that instead. |
Martin Avison (27) 1494 posts |
But if you can use Wimp_CreateIcon, it is just a matter of ‘decoding’ the icon numbers – and with a fixed number per row, is not difficult. |
Steve Fryatt (216) 2105 posts |
As I’ve now said twice, my caution was to your recommendation to the OP, not to your own use of this. Although, for a regular grid, it’s not that hard to do once you’ve realised what’s going on. The writable icons would be the bit that would discourage me.
That might just be your problem… :) 1 Or so much data that it becomes impractical. For a good example of this, I generally point to Personal Accounts, whose icon-based layout in every window (and consequent restrictions on usability) encouraged me to write my own replacement for personal use which did things properly and could therefore use a large monitor. |
Loke (8740) 7 posts |
There have been a lot of replies to my original post, and I just want to say I thank you all very much for the information. I have not yet gone back to my project which is why I haven’t been participating in the discussion very much. I have been thinking about this a bit though, and as far as I can tell, the easiest way to get something that works quickly would be to simply do all the rendering manually, simply drawing all the text using the low-level text drawing functions (which I seem to need anyway, in order to get Unicode text working?). |
Steffen Huber (91) 1953 posts |
That might have been the case in the mid-90s, but we now have 2021, and there are quite a few toolkits a bit more advanced than what was available 25 years ago. Not on RISC OS of course. Driving the Font Manager directly is NOT fun. It is complicated and error-prone. But – a nice challenge of course.
Unicode on RISC OS is still a nightmare. And RUfl (the NetSurf approach) is probably the only lib that will provide any help, but basically only worries about the display part. And limits you to the limits of the Font Manager, that I am sure Nemo will have happily pointed out in various threads over the years. So “a bit” is the grand understatement of the century. |
Rick Murray (539) 13851 posts |
It appears as if David is picking up some of our Brit tendencies to understatement. You know, where the apocalypse is “a spot of bother” or “an inconvenience”. ;-) Just go put the kettle on, it’ll be alright. |
Pages: 1 2