2011-04-06

Woopsi 1.2 Released

Another version of Woopsi is out. Get it from the Woopsi website:

In my last Woopsi post I discussed the removal of the AmigaWindow and AmigaScreen-specific flags. I’ve decided to get rid of all gadget flags supplied as constructor arguments. This was the old way of creating draggable, borderless windows (ignore for a moment the impossibility of such a window):

AmigaWindow* window = new AmigaWindow(0, 0, 100, 100, "My Window", Gadget::GADGET_BORDERLESS | Gadget::GADGET_DRAGGABLE, true, true);

This is the new way:

AmigaWindow* window = new AmigaWindow(0, 0, 100, 100, "My Window", true, true);
window->setBorderless(true);

There were multiple problems with the gadget flags idea:

  • Most gadgets weren’t set up to receive the flags in their constructors;
  • Gadget::GADGET_TOO_MUCH_POINTLESS_TYPING;
  • Impossible for the compiler to check for any errors;
  • Discovering which options were available for a given gadget was very difficult;
  • Annoying to have to constantly set the same options every time a gadget was created (windows are more often draggable than not, for example).

Instead, I’ve chosen sensible defaults that are set automatically in gadget constructors. If these need to be changed, they can be via the usual getters and setters available in all gadgets. The change leads to:

  • Less code;
  • Easier to create gadgets;
  • Fewer bugs that the compiler can’t catch;
  • A more consistent API.

This is another breaking change.

Let’s see what other bugs are in this changelog… (Rummages around the hard disk.) As mentioned previously, the Woopsi gadget creates a couple of background screens at startup to ensure that the background is always grey. These are now passed the Woopsi gadget’s style object, so if the colours have been changed by a developer the background will change to match. The ProgressBar gadget also accepts a style object in its constructor.

Disabling or enabling the border around a Label gadget now repositions its text to match. Getting rid of the flags system let me spot this one. Related to that, the Gadget class’ setBorderless() method is now virtual so that subclasses can react to changes in their border state.

One of the improvements I hoped to get in after implementing the damaged rect redraw system was to reduce the amount of redrawing done by textboxes. This is now in place. It’s not as efficient as I’d hoped because I’d previously opted for a design that eliminated code repetition. Whenever the text in a textbox is changed, an “onTextChanged()” method is called. Unfortunately, the method doesn’t know what the text was before it was called, so it can’t make informed decisions about how much of the gadget to redraw. For example, if the width of the text has shrunk, it needs to redraw the region covered by the original text. If the text has grown wider, it needs to redraw the region covered by the new text. I considered the benefits of redesigning this to be more efficient against the downside of increasing the complexity of the class, and decided to just stick with the current design.

What I did do was change the redrawing system so that it just redraws the total area within the gadget that could conceivably be covered by any text for the current font, which should save exponentially larger amounts of redrawing as the size of a textbox increases relative to its font size. The same thing happens when the cursor moves.

The Gadget class included a lot of methods for working with subgadgets, such as “addGadget()”, “raiseGadgetToTop()” and “lowerGadgetToBottom()”. It also included other methods for working with subgadgets such as “closeChild()”, removeChild()” and “shelveChild()”. The obvious inconsistency in the naming convention is now fixed, and all methods that previously referred to “child” now refer to “gadget”.

Lastly, the Bitmap class has a couple of new features. It has a real copy constructor, so it is now possible to create a duplicate of any bitmap that inherits from BitmapBase with no effort. It also has a “setDimensions()” method that will resize the bitmap in the same way that PhotoShop resizes a canvas. It doesn’t feature any clever scaling algorithms; it just increases or decreases the space available to draw on. Any existing data is preserved unless the bitmap is reduced in size, in which case data on the right and at the bottom is cropped out.

Instead of hosting the downloadable files on this website, I’m storing them on BitBucket. This is mainly just so I can easily see how often Woopsi is downloaded (uncannily-accurate prediction: not many).

The Woopsi todo list is growing increasingly short. In fact, there are less than half a dozen items left:

  • Create a tree gadget;
  • Create tab/tab group gadgets
  • Add a “Parent” button to the FileRequester and get rid of the “..” entry;
  • Add a file type filter to the FileRequester;
  • Rethink the appearance of the GUI - can I come up with something that looks better than the current Amiga-inspired design?

This last item is tricky. The more complex the GUI design gets, the more visually interesting it becomes; it also becomes more demanding on the DS. Is it worth trying to make the appearance more modern if it potentially causes slower performance?

As for the other items in the list, the FileRequester changes are fairly trivial (especially as the WoopsiString is now set up to make the file filtering task easier), and I’m not in any hurry to get the tabs or tree gadgets written. Other than that, there are a few things that I won’t implement that I’ll have to describe in a future blog post.