I’ve made a number of fixes to Woopsi today. First of all, sliders and scrollbars. The slider grip now automatically resizes itself, meaning there’s no need to call resizeGrip() when setting the max/min/value properties of a slider/scrollbar. The resizeGrip() method is now private. Still on the topic of scrollbars, the grip in the ScrollingTextbox’s scrollbar now adjusts to the correct position when the textbox is first initialised. It was previously placed at the top of the scrollbar regardless of the position of the text.
Next, some fixes related to the event refactoring. The Alert, Requester and WoopsiKeyboard gadgets now handle events from their decorations correctly. Previously, the XOR dragging rect wasn’t being drawn correctly when they were first clicked.
Lastly, I’ve made some improvements to the visible region caching system. There are two types of rectangles used in the system. The first, which was already being cached, represents the entire visible surface of a gadget, ignoring any children it might have. The closest Java analogy would be Swing’s “glass pane”. Drawing to these rects draws over the top of the entire gadget, even over the top of any children the gadget might have. The second type of rects represent the visible portions of a gadget once its children have been drawn; they can be thought of as background rects, behind everything else in the gadget. Woopsi only draws the background rects; everything else is left to children to draw (and so on, recursively, until the screen is filled).
Whilst looking at the Gadget::redraw() method, I noticed that the background rects were being recalculated every time redraw() was called. I’ve now changed this so that both foreground and background rects are cached, which should provide a small speed boost. Note that, as I type this, I’ve realised that calling the rects “foreground” and “background” is a far better convention than their current names, so I’ll probably rename them soon.
Still on the subject of caching, I’ve moved the caching code and the rect splitting code into a new class, “RectCache”. The Gadget class is overloaded with functionality at the moment, so I want to extract some of it out to make it easier to work with. As a byproduct, I’ve made the “removeOverlappedRects()” method non-recursive, which should make that a little faster, too.
A major reason for trying to move this code into a separate class is to try and either optimise it (by making the rect splitting smarter) or replace it with the BSP tree code I came up with - oops - a year ago. I’ve fixed a raft of bugs in that code, but I’m still struggling to work out how exactly I can integrate it into Woopsi, or if I even need to. On a system with a little more CPU oomph and no DMA hardware (GP2x or Wiz, for example), it makes sense to replace the current system with the BSP code. It’s tidier, more efficient, and simpler. On the DS, however, I keep encountering optimisations that I’ve made in Woopsi that can’t be replicated using the BSP method and that offer significant speed gains. I might put up a longer post specifically on this topic later.
Why is it that you only find really obvious bugs once you’ve put out a new release?
There’s a bug in the keyboard. More specifically, there’s a problem with the Gadget class that exhibits itself in the keyboard. The loops that work with the visible/invisible rectangular regions of each gadget use bytes as their iterators. Unfortunately, the keyboard layout is so complex that it can have more than 256 rectangles in its rect cache, which means the redraw code gets into an infinite loop because the iterator overflows and wraps back around to 0.
I’ve fixed this in the SVN version - the iterators are now signed ints. I’ve also changed the child gadget iterators to use signed ints. Expect version 0.36 fairly soon. I’ve also updated the SVN version of the XCode Woopsi project to match the 0.35 VC++ code.
I do still have the BSP tree code I mentioned a while back. I’d like to get that plugged in at some point.