C WIMP Tutorial?
Andy Burgess (1662) 14 posts |
Rick: Re removing the ! on Resource_initialise – thanks very much – that’s sorted it! I’ve wasted hours on this – till you told me! Re Graphics/Drawfiles etc, on my proposed application I want to display a circle with an interactive arrow pointer on it – showing a bearing, plus displaying a map with a “you are here” pointer – a la GoogleMaps (I’d be getting maps from a third party, which I could convert). Is this feasible for a programmer using C and desklib (or OSlib), without resorting to Assembler – an area of programming that really scares me! I like the idea of Drawfiles. I’ve always liked !Draw. Incidentally – does anyone know – is it based on a type-in program I remember called ASTAAD (Any Size Text Absolutely Anywhere on a Diagram) on the Beeb I once typed in? |
Rick Murray (539) 13806 posts |
Will it be static or animated? If static, I’d say… render the JPEG, then build a DrawFile on the fly in memory (sorry, datablocks and such) and then render the DrawFile on top of the image. As long as you can get the two to line up correctly, it’ll be some fairly straightforward C code (a bunch of array/memory setups, and a SWI to plot the image and another to plot the drawfile). No assembler necessary, unless you like that sort of thing (cough…I do ;-) ).
It is my understanding that Draw has a fairly large nod to PostScript. |
Andy Burgess (1662) 14 posts |
I’ve put up a screenshot of the end result of what I’m trying to achieve in RISC OS (app was written in Visual Basic) at www.jet-net.co.uk/gps.png The project is for a Raspberry Pi computer. I’d prefer to do it in RISC OS as it’s more memory efficient, but if it’s going to be too big a learning curve I’ll have to do it on Linux. The compass (and other items on the right of the app) will need to be updated on a regular basis, but initially the map will remain static – with a view to being dynamic in later development. |
Steve Pampling (1551) 8155 posts |
Ah, maps with overlay data. I started looking at a means of obtaining the plot data for that kind of thing a few1 years ago. For that kind of thing and quick plot methods you might want to contact Martin Wuthner http://www.mw-software.com/ about using the Artworks methods. 1 “A few” being a number greater than the normal 3 unfortunately. |
Martin Bazley (331) 379 posts |
How regular is “a regular basis”? This has an impact on what method I’d recommend you use. The easy way is to make everything in there a normal Wimp icon (so automatically redrawable), using sprites where appropriate (for the static map and the compass). Then whenever you want to change an image you can call Wimp_SetIconState with all flags set to 0, to force that icon to redraw. The disadvantage here is that it will flicker every time it is redrawn. In the long run, especially if you want the map picture to be dynamic, you’re going to need to activate redraw requests. I’ve never used DeskLib so I’ve no idea how much of this rather nasty process2 it abstracts for you, but it disables clearing of the graphics rectangle (so you can simply over-plot with no flicker3), and removes the setup and maintenance overheads of displaying everything via indirected Wimp icons. On the downside, if you don’t use Wimp icons then the Wimp won’t give you a nice helpful icon handle in a mouse click notification, so you’ll be obliged to calculate it from the coordinates yourself. As long as your compass doesn’t do anything when clicked on, this won’t be a problem (and you’ll probably need to calculate coordinates from a click on the map in any case). As for the learning curve, I’m afraid that’s part and parcel of learning a new OS! RISC OS desktop programming is dramatically different from desktop programming in, say, Java, but you seem to have got over the biggest hurdles (like getting used to the concept of a polling loop) OK. 2 A prime example, if you’re used to pre-emptively multitasked and thread-safe systems, both of which RISC OS is emphatically not, is the requirement for your initial call to Wimp_RedrawWindow (I think that’s what it’s called) to be your very first SWI call after Wimp_Poll. After that you have to call a separate SWI, Wimp_GetRectangle, for the second and subsequent iterations of the loop. 3 Except if you use drawfiles instead of sprites it’ll flicker anyway due to the way they’re constructed. |
nemo (145) 2529 posts |
The map is made up of tiles, which you’ll want to convert to sprites and cache if the map moves or can be scrolled. If it’s fixed, you can cache the whole display. It is not necessary to use more than one window. Use the confusingly-named “graphics window” capability of the OS to limit the area you paint while drawing the map. The wind speed indicator is a simple OS_Plot affair. The text is quite small – the Wimp’s default font is rather chunky (the scale of the GUI was chosen when interlaced 256 line CRTs were the best you could hope for) so you’ll probably want to plot that yourself using the Font Manager. The amplitude plot (whatever that is) may require cleverness depending on the nature of the data – if it’s already an image you just convert to a sprite. If the apparent anti-aliasing needs to be done locally from numerical data, then that is probably best drawn into a sprite (once) and that sprite redrawn (thereafter). The only icon I see is the superfluous “Exit” button – that’s what the window’s Close icon is for! |
Andy Burgess (1662) 14 posts |
Thanks again for this feedback! I really value it all! My priority for this app is to get a static map and the compass working. Maps: I presume I could convert a TIFF / JPEG / GIF map into smaller Sprite tiles? I like the idea of tiles! |
nemo (145) 2529 posts |
I had assumed you were fetching Google JPEG tiles on demand. If you have a static map you don’t need to tile it. That’s just a convenient way of caching something significantly larger than available memory.
Use Wimp_PollIdle with a suitable delay. When it is time to update your indicator draw the old position in white and the new position in red – that’s quicker than drawing the whole circle again. Less flickery too. If you’re prepared to be clever you can use EOR and draw both simultaneously – it seems to flicker less if the new position is drawn before removing the old (because of overlap you need to EOR if doing it that way).
Circles, triangles, lines and dots. Moving and copying of rectangles. Simple drawing stuff. |
patric aristide (434) 418 posts |
You’re probably aware of them but these lists might come in handy when looking for software (e.g. TIFF to sprite conversion etc.:) http://www.riscos.info/index.php/Recommended_software ARMv6/7 compatibillity list: http://www.riscosopen.org/wiki/documentation/show/ARMv6%2Fv7%20software%20compatibility%20list Looks like a very interesting project btw. Good luck! |
Rick Murray (539) 13806 posts |
Good grief… I used to live down Moulsham Lane back in the ’80s.
Not sure what that “mag” thing is, but the rest is pretty simple looking. |
Rick Murray (539) 13806 posts |
Ever tried that while waiting on VSync? OS_Byte 19, I think (but look it up to be sure).
Oh. My. God. Okay. I get it. You have a particular peculiar aversion to redrawing stuff. So, please allow me to guide you in this <largeham> terribly difficult </largeham> aspect of programming. What we want to achieve is a program that lists videos. A video database. The main window lists ‘em, and we need to know which one the user clicked upon. Now, we can create an icon for each video and use that, however such methods are reserved for people that would be better off sticking to toy programming languages like Befunge ! You might think it would work, and for twenty videos it would. But it won’t scale. I made a stress-test file of 32,000 videos. You want to try creating and managing 32,0000 icons? [erm… can the Wimp even cope with 32,000 icons in a window?] The first job is to attach a redraw handler to the listing window.
Actually, I pass “event_ANY” as one function caters for all of the user-specific redraws. Yes, that’s all DeskLib needs to know. The redraw handler is defined thus:
And if we skip to the part to redraw the listing, I’ll walk you through that.
As you pointed out, you should call the RedrawWindow function first. Then…
Fiddle the rectangle given with the scroll offsets to determine the origin of the displayed content; the 0,0 location, if you will.
Now such my video listing works in lines (a line of text), I translate this using the min/max values. What we have here is “top_line” and “bottom_line” being the number of pixels from the top our first/last line to be redrawn are. The subtraction of “o_top” is a fudge because there is a toolbar along the top of the window (so everything is displaced downwards on the screen). Next…
We take each value in turn and divide it by the known height of each line. This means we now have a top and a bottom line number for the content to be redrawn, for example, lines 5 to 9 need redrawn.
Now we just step through redrawing each line. The x_origin is because lines begin on the left; and the y_origin is because the redraw routine itself works out where to perform the redraw. The actual redraw function is written in assembler, because it was a little bit laggy on an 8MHz A3000 (but good enough on an A5000, and rockin’ on a RiscPC). I just went the assembler route to eke out a few cycles extra. ;-) And finally…
Now, having seen this, please, go look at http://www.heyrick.co.uk/software/verodes/ The click handler gives me an X and a Y. Because I use a picture object, the scrolling is already taken into account, but I must still resort to maths to calculate which ‘hole’ the user has clicked upon. Doing these sorts of calculations isn’t something unusual, it is fairly normal!
Here’s the code to translate a mouse click block into a line (ie which video the user clicked upon):
The “position++” is because the video index (and array) counts from one, not zero. This can be easily adapted to two-dimensional regular shaped things, or in the case of Andy’s compass, I’d say a simple:
would suffice.
…and this relates to redrawing and handling clicking HOW?
And? You calling Wimp_RedrawWindow informs the Wimp that you are going to handle the redraw now and to get everything in order for that activity. The calls to Wimp_GetRectangle are for subsequent redraw blocks, if any. It is a formality of writing programs for the RISC OS Desktop. This isn’t really so different to DOS/Win’s “Dir()” function, where the first iteration takes a path and some options, and subsequent iterations do not want parameters. [I prefer how OS_GBPB enumerates directories] Now, for consistency, why don’t you point out also how all menus are pop-up, we don’t waste space with a menu bar. And the novelties that you can have writeable menu entries and you can hang windows as submenu items. RISC OS is not Windows, or Linux. It looks, feels, and operates differently.
Time for another piccy. My video listing program came with a user guide. The user guide was written in OvationPro, printed as PDF, converted to DrawFile, and my UserGuide application displayed this. It is lame code – I get DrawFile to redraw the entire thing each time (I was going to calc the clipping rectangles, but never got around to doing so). When opening a page for the first time, it takes a brief moment to draw, just as you can see Excel plotting a table the first time it is opened. |
Martin Bazley (331) 379 posts |
The disadvantage here is that it will flicker every time it is redrawn.Ever tried that while waiting on VSync? OS_Byte 19, I think (but look it up to be sure). How would that help? The Wimp isn't double-buffered and I can't think of any other advantage. (Oh, and calling OS_Byte 19 in the desktop is extremely unfriendly, if not forbidden.) A prime example, if you’re used to pre-emptively multitasked and thread-safe systems, both of which RISC OS is emphatically not…and this relates to redrawing and handling clicking HOW? I’ll just say straw man and leave it at that. Consider the following:
Don't try to argue with the guy who was in a concurrent programming lecture this morning. :-) Subsequently (and you can see in the picture I’m dragging a menu over the page), it flickers the tiniest bit. Now scale that up to what effectively amounts to an animation. Granted, it's probably barely noticeable on new hardware, but by using a sprite with a solid background you eliminate the need to clear the area first, which is what causes the flicker. Drawing directly on the screen is unsightly for the same reason, although I've never tried the EOR method so that might work. |
Rick Murray (539) 13806 posts |
It isn’t for double buffering. It is to delay processing until the VSync pulse. You then have from VSync to the first scan line to fart around in screen memory doing what needs to be done to have the screen update without side-effects (tearing, flickering, etc). Yeah, it probably is a less-than-friendly thing to do, but it does raise the question of how one is expected to have smooth animation in the Desktop environment. I suspect the first reponse will be “don’t use icons”! :-) [does the Wimp itself delay to VSync upon a Wimp_RedrawWindow SWI?]
I think you’ll find your threads and stuff is a very specific example involving getting RISC OS to do activities that were not part of its design specification. Additionally, why raise threading and such at all? I know there are some schools of thought that would implement Andy’s idea as: thread to redraw, thread to fetch map tiles, thread to retrieve GPS data, thread to convert map to native image, thread to…
Okay – quick poll. Hands up anybody who has made animation by running a sequence of DrawFiles… It’s like complaining that redrawing and threading are precarious under the Wimp2. You use the things available in ways they aren’t really designed for, you should expect headaches.
…I think I’d go with direct drawing. You aren’t so much drawing to the screen as drawing into your window. I suppose if you are drawing something complicated, it may well work out that a sprite is better as you can draw into the sprite at leisure and then blit it to the screen in one go. But not as an icon. The icon is good in that it takes care of all of the tedious redraw issues, but it is a higher level thing and this additional work may be the difference between flicker and non-flicker. Also, does the icon clear to icon bgcolour prior to plotting? That would add the possibility of flicker as well. 1 Taken to extremes with the Atom which is two logical processors but only has one actual execution unit (the ALU and scheduling are duped). 2 I think the typical approach is to have a module running in the background for stuff that would ordinarily be a ‘thread’, like http fetches. This might seem a little bit hairy (and it is!), however it is actually a fairly responsible way of getting around the problem of how you cope with an external event when your task is paged out. Modules don’t get paged out, so… |
Chris Hall (132) 3554 posts |
Okay – quick poll. Hands up anybody who has made animation by running a sequence of DrawFiles… Hand up. I created a draw file with two alternative paths – one with invisible (-1) outline and fill colours and the other with the intended colours, marked their position in memory and swapped values and then did an intelligent Wimp_UpdateWindow where each group was examined and only if it was in the area to be redrawn was it processed. I later found that DrawFile_Render did the same job. I used this technique in my app !SignalBox to show signals operating on a track diagram. |
Steve Fryatt (216) 2103 posts |
And how likely is this, given that stuff using UnixLib’s pthreads emulation is very unlikely to also be calling RISC OS SWIs directly? |
Rick Murray (539) 13806 posts |
Forgot to add: Callbacks are conventionally triggered on exit from a SWI when the SVC stack is empty. I do not know how the Wimp works internally, but the stack requirement ought to stop a callback happening at a weird time (think: if you OS_AddCallBack you probably don’t want it firing on exit from the SWI to add it!). https://www.riscosopen.org/viewer/view/castle/RiscOS/Sources/Kernel/s/Kernel?rev=4.12.2.34;content-type=text%2Fplain about halfway down (reformatted to fit here without scrollbars):
There’s a crazy amount of conditionals in that section of code. I think callbacks are a good idea in principle, but I can imagine them being fiendishly difficult to implement in a way that doesn’t have numerous side-effects, especially with a system that is intended to multitask. |
Martin Bazley (331) 379 posts |
This was exactly my point, which you seem to have missed by a mile. Most people coming to RISC OS desktop programming from a background in Linux or Windows would expect to be able to do something like that. I was giving a specific example of why assumptions which are common elsewhere are invalid under certain parts of RISC OS, including the window redraw API.
There’s no rule that only ported software is allowed to use pthreads. It’s just that software written specifically for RISC OS is usually written by people who know they’re a bad idea.
Yes, it does, and yes, that is why it flickers. The only way to overplot is by buffering data in a sprite and redrawing the icon yourself.
Hold on – a few hours ago you were dismissing the effort involved in following the API as trivial and of little consequence! :-) |
Rick Murray (539) 13806 posts |
And I expected to do some things under Windows that are tediously difficult. Example – why is there nothing consistent like MessageTrans? But, hey, wait… if you are used to Linux then you might be in for a surprise with the Android API; but then remember GTK is not Qt4 is not… Different systems have different APIs. Duh.
This is why assumptions, in general, are not a good idea. Assumption. int == long == 32 bit. Works on RISC OS. Fails badly when it comes to an x86 compiler (where “int” is often 16 bit and “long” 32 bit). Assumption. You can allocate a large chunk of memory and address it. Works in theory, but do you remember all the balls with __near and __far and memory models and extenders to address memory beyond the initial ~640K? Assumption. Unsigned integers. Try that with VisualBasic. Especially try it with VB when the API returns an unsigned value and you have to mess around with “variant” data types in order to be able to handle it. Assumption. Text files. The two main types are LF terminated and CRLF terminated. In general, you require smart software to cope with this, as crappy software and even default programming libraries get it horribly horribly wrong (as in loading an entire long RISC OS textfile as a single line of text…). If I had the MS WinXP SDK on this computer, I’d open up the viewer and lay rip. But I try to stay away from the murky depths of the Windows API if possible. It is frequently unpleasant, and my personal favourite is how GDIPlus is not so much an evolution of GDI as an enhanced replacement, but an incomplete replacement that misses some stuff that requires you to consider using both. Oh, and they share very little in common in terms of data structures, leaving you with a headache of botching stuff around so the two can work in tandem… I could go on, but I think you get the point. Different operating systems are different. End of. What you may be thinking of is POSIX compliancy. You’ll notice Windows needs some add-ons to be sort-of compliant. But this, POSIX, talks about threads and filesystems and such. The base specification is available here: http://pubs.opengroup.org/onlinepubs/9699919799/ If you read the “Directory structure and devices” section, you’ll see POSIX is hardwired to the “everything starts at /” idea with mountpoints and such, with stuff like /dev/console; fork(), setsid()… you can see how Windows is by definition non-compliant, and how there’s little hope in hell of RISC OS being anything near compliant (well, hack around UnixLib you might end up with a sort of compatibility layer). But this covers the base OS. Windowing systems? Time to reinvent the wheel, yet again…
There’s no rule saying native software has to use threads. I believe a threading library is necessary for RISC OS, if only to make it that much simpler to port software from a system that uses these sorts of things extensively. This is, pretty much, UnixLib. There is no reason why we couldn’t have the rather nice Android browser running under RISC OS, except for the “getting it to actually work” aspect. ;-)
Perhaps the answer here is to have an icon flag “don’t clear background”?
I was referring to your obvious dislike of do-it-yourself redraws. Using an icon avoids all of this, though with some of its own consequences. |
Steve Fryatt (216) 2103 posts |
That’s bit 7, isn’t it? You have to set it to force a background clear; otherwise, the Wimp does the bare minimum that it can get away with. |
Peter Miller (248) 1 post |
A bit after the fact but I was, somewhat unexpectedly, moving house in October. On the make file error message, “DrWimpC”: I had a look at DrWimpC – looks good, but moaned “Cannot find ‘make’” or something so I switched to DeskLib Just for the record, in case others might be confused by this message appearing – all you need to do to use the Acorn/ROOL C compiler tools with DrWimpC is to set the compiler options in the Dev Choices dialogue to the ROOL C compiler, as described in the Getting Started instructions on the DrWimpC web site. (And unset the shared/debug flag on the main compile menu so that debug information is not generated during the compile). The reason for the ‘make not found’ message is that the DrWimpC compile settings were left at the default which is to use GCC 4 and GNU make, so when the compilation task attempts the first call to the GNU make utility, the message appeared. In the list of ways of doing things, 3. DrWimp/DrWimpC: similarly higher-level routines for BASIC and C (not exactly sure how DrWimp and DeskLib compare). Its worth noting that while both DrWimp and DrWimpC interact with the wimp at the wimp event level, they both use a standard predefined event handler function interface for an application. In addition DrWimpC App Builder allows the linking of event handler functions to windows and icons defined in application template files. Using that mechanism you can group icons together to form template objects, effectively giving a way for you to write your own ‘gadgets’ for DrWimpC applications that could also be released for others to use in their DrWimpC applications. |
Andy Burgess (1662) 14 posts |
Peter, thanks for posting that DrWimpC fix – I’ll give it a go when I’ve time! |
GavinWraith (26) 1563 posts |
May I suggest that Andy Burgess have a look at Joe Taylor’s AppBasic. This hides the low level details of the wimp and uses the nice idea of having a !RunImage directory – that is, seeing the program as a tree rather than just a clump of functions. Joe spent a huge amount of time on AppBasic, especially on the docummentation. |
Chris Hall (132) 3554 posts |
Have a look at this link for some overlay files plus line drawing (in IE). I used MakeDraw to create the necessary precise Draw files than plotted then on screen and captured them as sprites and converted to gif using !InterGIF. |
nemo (145) 2529 posts |
This is how I develop large BASIC programs. The !Run is a BASIC program that manages memory, scans the directory, loads all other BASIC programs, links them as LIBRARIES (without using the command) and calls their initialisation functions.
Well, I wouldn’t go that far. It doesn’t make it easy. But it’s not as hard as JavaScript makes it! |
Andrew Daniel (376) 70 posts |
Chris are you not aware that !InterGIF can produce .gif files directly from drawfiles? As per the logo at the top of the page here; www.lnerca.org This image was originally created on my A410/1 and with an ARM 2 used to take several seconds to render! |