Sidekick coding: sick Pen API

Sidekick has a powerful API but it has this feeling of in-house development where not enough thought has been put into making it clean and well designed. Instead it sometimes feels like methods has been added on an ad-hoc basis whenever someone felt like something is needed. Then there’s really a lot of deprecated/unused methods and constants. Generally it’s not a bad API at all it just feel a bit random at places 🙂

But there are places that are really bad. I know I’m not the most experienced Sidekick programmer out there but I can tell bad API when I see one and one of the things that frustrates me most in Sidekick API is danger.ui.Pen class.

First thing are pointless differences between AWT/MIDP and Sidekick UI. They are mildly annoying. For example:

AWT/MIDP: drawChar(char character, int x, int y, int anchor)
Sidekick: drawChar(int x, int y, char c)
Sidekick: drawText(int x, int y, char[] data, int offset, int length)
Why arguments order is reversed? drawChar/drawImage/etc all take object being displayed (character, image…) as first argument in AWT/MIDP but hell no, Danger had to make it their own way and put it at the end! Or in the middle in case of drawText(…), which is inconsistent even with their own way of doing things.

AWT/MIDP: drawImage(Image img, int x, int y, int anchor)
Sidekick: drawBitmap(int x, int y, Bitmap bm)
Why did they remove anchor? It’s really useful and with SK API programmer is forced to do the required calculations in application code or to write a wrapper (you’ll read about wrappers more later in this post)

AWT/MIDP: drawRect(int x, int y, int width, int height)
Sidekick: drawRect(int left, int top, int right, int bottom)
Why all dimensions are specified as left/top/right/bottom while standard is left/top/width/height?

It’s not like AWT or MIDP are some unknown exotic APIs, so why did Danger made their API different in so annoying way and for no good reason?

That was annoying. What’s really bad is how they screwed up clip handling.

There are two ways to modify clip area with AWT/MIDP:
setClip(int x, int y, int width, int height) Sets the current clip to the rectangle specified by the given coordinates.
clipRect(int x, int y, int width, int height) Intersects the current clip with the specified rectangle.

With Sidekick you’ve got only one way:
setClip(int l, int t, int r, int b) Adjust the clip-rect of the Pen using local coordinates. The clip-rect can never be made *larger* than it currently is.
Its name is misleading since it does not set clip but instead does what clipRect(…) does.

WTF? setClip(…) can only make clip area smaller? What if you want to draw part of an image and then go back to drawing on entire screen? Turns out you can’t do that in easy way. Instead, you have to push and pop entire graphic context state:
pop() Restores the last copy of this pen saved on the statestack. Throws a UIException if the stack is empty.
popAll() Pops all saved state off the statestack
push() Saves a copy of this pen on the statestack

Note that there’s no getStackDepth() method that would tell you current stack depth.

It would be only wasteful and troublesome if stack manipulation methods just worked in some user-friendly way. Instead pop() throws an exception if state stack is empty. popAll()’s javadoc doesn’t say anything about throwing exceptions but it does throw one if stack is empty anyway. So how are you supposed to know if you can safely pop state from the stack or not? I’m starting to suspect it’s a typical way of dealing with Sidekick programming — you have to write a WRAPPER. Wrapper which keeps track of stack depth and on which you can at least call an equivalent of popAll() safely.

I can’t be the first one to complain about it. Why it’s not fixed since it would be really easy to fix all this clip mess? Add resetClip(int l, int t, int r, int b) method (well, it should be setClip(…) but since setClip() already does something else…). Make popAll() not to throw exceptions when stack is empty. Add getStackDepth() method.


Tags: , ,

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

%d bloggers like this: