Woopsi 0.36 Released

November 4th, 2008

Woopsi 0.36 is now out. Available from the SourceForge page, as per usual. Summarised changes are as follows:

  • WoopsiUI namespace for all classes
  • MultiLineTextBox improvements and fixes, including the majority of cursor support
  • New date handling class and calendar gadget
  • Bitmap class with a variety of drawing routines separated out from the SuperBitmap
  • More examples
  • Bugfixes and optimisations

The big change in this release is the move from the standard namespace to a dedicated “WoopsiUI” namespace. This change will almost certainly mean you need to invest some time refactoring any code you’ve written that uses Woopsi. However, it should keep things tidier.

Calendar Resizing

November 2nd, 2008

The calendar now has a resize method, which is another item off the list of things-to-do.

Blog Update - Markdown

November 2nd, 2008

Markdown can now be used in comments.

More Bitmaps and Calendar Fixes

November 1st, 2008

The bitmap class introduced in the last post is now part of the SuperBitmap. The SuperBitmap class has retained the same API, but it now is just a facade wrapped around an instance of the Bitmap class. The Bitmap does all of the hard work.

I’ve made a couple of amendments to the Calendar and Date classes, too. The Date class now has its equals and not-equals operators overloaded, whilst the Calendar now shows Monday as the first column (instead of Sunday). It also handles clicks on buttons correctly if that button represents the currently-selected day in a different month/year.

Cursors and Bitmaps

October 31st, 2008

Two changes today. I’ve optimised the MultiLineTextBox’s cursor drawing routines. It’s not as fast as it could be - the fastest way to draw it would probably be to inject it into the main drawText() routine - but as that class changes so much I think it’s best to keep it readable at this stage.

Secondly, I’ve replaced the Bitmap struct with a Bitmap class. The struct wasn’t being used anywhere. The class includes all of the drawing functionality previously only available in the SuperBitmap, so it is now possible to create and manipulate bitmaps entirely in memory without an associated gadget. This should, I think, answer one of Jeff’s earlier queries. I’ll get around to stripping the code from the SuperBitmap and replacing it with the Bitmap class later. Not sure if the SuperBitmap is going to inherit from the Bitmap or just contain an instance of it yet.

Dates and Text Wrapping

October 28th, 2008

Couple of changes today. The Date class introduced yesterday now has a more optimal “calculateWeekDay()” method, thanks to Jeff. It still seems to work correctly with the calendar, which is curious, because I’m sure it was previously returning “0″ as the value for Sunday whereas it now returns “7″. I must be doing some modulus stuff in the Calendar class.

Secondly, the “wrap()” function in the Text class should now be rather faster than before. Instead of re-wrapping the entire string every time something is inserted, appended or removed from the string, it now locates the line of text that contains the modification and re-wraps from that point forward.

I’d tried to implement this a few days ago but came across a couple of problems. First of all, locating the line of text in which the modification fell was slightly tricky. I’d decided to use a binary search (obvious enough), but came unstuck because I was looking for a value that fell within the range indicated by two values in the wrapping data array. I wasn’t searching for an exact match, but a match between two values. Turned out to be fairly easy to implement once I’d scratched it down on paper.

Secondly, the wrap() function remembers the width (in pixels) of the widest line of text to help with other routines elsewhere in the class. If we try to wrap the text from line n, ignoring the previous lines, and the widest line is actually n-1, we won’t have the correct width. We’ll just have the width of the widest line in the range from n to the last line of text (if we ignore the old value we stored) or the width of a line that may no longer exist (if we use the old value).

The solution to that was pretty straightforward, too. I added a second vector to store the widths of every new widest line that the wrap routine comes across, along with the index of that line in the wrapping data vector. So, if the first line is 10px wide, that’s the widest line we’ve seen up until that point, so we add width 10 and index 0 to the vector. If the second line is 8px wide, we ignore it as it is thinner than the currently-identified widest line. If the third line is 20px wide, we add width 20 and index 2 to the vector. That way, when we re-wrap from line n, we discard all of the longest line data from the vector from line n onwards. The last entry in the width vector is then the width of the longest line in the text we’re not re-wrapping.

The upshot of all this is that if a char is appended to a string 100 lines long, only the last line is re-wrapped. Previously, all 100 lines would be re-wrapped.

Fixes and Examples

October 26th, 2008

Following on from the last post, the Date class now works correctly (as far as I’ve tested). I’ve tidied it up a bit too, and moved most of the code out of the header file and into the cpp file. I’ve also fixed rounding errors in the MultiLineTextBox’s vertical alignment option (centred) - it moves around as you’d expect now. Lastly, the WoopsiString class doesn’t crash if you try to insert text into an empty string. This was causing the demo released the other day to lock up if you deleted all of the text and then pressed a key.

In other news, there are now examples illustrating the use of the Date class and ProgressBar gadget. I’m hoping to get examples done for all of the gadgets, where possible, because they double as unit tests as well as providing guidance for users.

I think it’s about time for another release…

EDIT: Oh, and the cursor in the MultiLineTextBox is hidden by default, now that I’ve got the preliminary work done.

Calendars and Dates

October 26th, 2008

Here’s a new gadget that might prove useful to those people determined to create a replacement for DSOrganise:

Yep, it’s a calendar/date picker. It raises EVENT_ACTION events each time a new day is clicked. The left and right arrows page through the months and years.

Working out the layout of a calendar is actually very simple. It’s much simpler than I was expecting it to be. First of all, we make a few assumptions:

  • We will only show one month at a time (though we will show days that border the start and end of the current month)
  • We will always have 7 columns (7 days in the week)
  • We will always have 6 rows (this caters for the worst-case scenario, or largest number of visible days, and sticking to this reduces the complexity of the algorithms we need to use)

Once we’ve got that set up, we need to know what day of the week the current month starts on. The magic for this is handled inside a new Date class that can manipulate the days, months and years of a given date, the logic for which came from here (note that the rest of that site seems to be totally bonkers). If we know what day of the week the month starts on, we can generate all of the preceding day buttons, then the buttons for the current month, and finally any buttons from the next month.

Using the Calendar gadget is simple. It automatically grows and shrinks to fit within the dimensions specified in its constructor, it raises an EVENT_ACTION event when a day is clicked (as noted previously), and it has methods to set and get the date. It doesn’t inherit from the Window class, so it can be added to screens or an existing window alongside other gadges. There’s an example in the “examples” folder.

Two caveats with the Calendar and Date classes at the moment. I’m not sure that Date::addDays() works correctly for negative days (need to write a test, but as it’s not used by the Calendar it’s not a problem right now) and the Calendar doesn’t have a resize() function.

Cursors and Textboxes

October 25th, 2008

The MultiLineTextBox now has cursor support. At present there’s no simple way to move the cursor up or down between rows, and it lacks the stylus support built into the standard TextBox. I’ll get around to that next. However, the cursor can easily be made to jump to different locations in the text, so supporting d-pad movement is simple. There’s still a lot of optimisation I could do, but I think I’ll leave that for later.

Download a demo here:

CursorTest

Cursor Test

Lastly, I’ve synced the OSX version with the standard version.

Namespaces

October 25th, 2008

Woopsi now has a new namespace: “WoopsiUI”. All of the classes are now part of this namespace. This will impact user code in a number of ways. Firstly, you might be doing this in your .h files:

#ifndef _MYCLASS_H_
#define _MYCLASS_H_

#include "woopsi.h"

class Button;

class MyClass {

}

#endif
 

Declaring the Button class won’t work any more. as it is now in a different namespace. You have two options. You can do this instead:

namespace WoopsiUI {
    class Button;
}

This seems like a nasty workaround to me, as you shouldn’t really be changing the WoopsiUI namespace, even if all you’re doing is declaring something that’s already in there. Alternatively, you can just #include the “button.h” file.

Trying to do this doesn’t work, despite how logical it looks:

class WoopsiUI::Button;

I imagine the reason for this is that prefixing a class name with the namespace means you’re trying to access something that already exists, not define something new.

You’ll probably find that you need to add this near the top of your .h files:

using namespace WoopsiUI;

Purists will tell you that what you should really do is prefix any calls to the Woopsi gadgets with “WoopsiUI::” instead, or just include the bits of the namespace you want with “using WoopsiUI::SomeClass”, but if you’re just trying to get your application to compile again then using the entire namespace is a quick way to get things working.

I did this mainly so I could rename “WoopsiString” to “String”. Once I’d renamed the class everything broke, so I switched it back to “WoopsiString” again. Curses.