One of the problems with using a windowing system with the DS is the size of the screens. They’re too small to get a lot of information on-screen at the same time. Woopsi takes its cue from the Amiga and allows the developer to create multiple desktops, each of which the user can flip through, drag down, or push up to the top DS display.
The screens are still small, though, so Woopsi now supports dragging windows beyond the confines of the parent screen’s edges. That’s a feature that had to be bodged into AmigaOS with hacks like MCP much later in its life.
Adding this in wasn’t too difficult - it just required a few more fiddly changes. Gadgets now have a “permeable” flag, which indicates whether or not they can exceed their parent’s limits (they are still clipped to the dimensions of the parent, though, so if they exceed the limits that portion of the gadget is not drawn). The clipping routines now clip all the way up the gadget tree instead of just to a gadget’s immediate parent. The Gadget::moveTo() function enforces the permeable flag, so gadgets cannot be moved outside of the client space by user or developer.
That is, unless they change the _x and _y values themselves. Note to self - these properties should really be private and should have accessors. Another note to self - Gadget::resize() does not check the permeable flag. Note to everyone else - dunno what the “established” name for the permeable flag would be; if you have any suggestions, let me know.
I came across a few annoying bugs on the way. There was an off-by-one error in the Gadget::checkCollision() functions which was easy to spot. GraphicsPort::clipXORRect() didn’t do what it should have done (it re-positioned the lines to fit on-screen instead of just not drawing them), so I scrapped that and replaced it with a more intelligent routine. Lastly, there was a gadget-space to display-space co-ordinate problem in the GraphicsPort’s clipping routines that took a good few hours to track down.
Gadgets are non-permeable by default (ie. children are limited to the client space). Activating a gadget’s permeable edges is a matter of calling gadget->setPermeable(true) or by passing in the correct mask value in the “flags” parameter of the constructor.
Screens are now implemented as three classes. The ScreenBase class provides a completely empty screen, and can be used as such, or it can be added to. The AmigaScreen class provides the usual Woopsi look - Amiga title bar, depth gadget and flip screen gadget. The SimpleScreen class is the same as the AmigaScreen, but provides the helper functions to create a range of gadgets within the screen with no effort. Great for beginners and lazy people.
Last change for this post - I’ve removed the SuperBitmap’s ability to use external bitmaps as its buffer. It will always create a buffer in RAM to use as its drawing space. The drawBitmap() routine can be used to blit a PAGfx or otherwise externally-generated bitmap into the SuperBitmap’s buffer. Solves a lot of potential problems with const data.
Here’s a grab of the new window functionality: