2008-06-17

Woopsi Status Report

Woopsi progress is suffering at the moment due to my other commitments, but I’ll get back to it soon. I’m patching up bugs as they get reported in the forums, though, or if I spot any when I’m fixing other problems.

Two fixes today. First of all, the Screen class was still bitshifting left by 8 places instead of multiplying by SCREEN_WIDTH in its drag() routine. Although the bitshift is potentially faster, it’s a barrier to portability and I’m guessing that the compiler is smart enough to replace the multiply with a shift anyway.

Secondly, I noticed that the XOR dragging rect displayed when dragging a window could be dragged out of the parent screen if the screen had itself been dragged down. This is now fixed.

Both of these fixes came out of my search for an SDL bug identified by John in the forum (he’s managed to get SDL working with VC++, and documented the process).

Here’s something for discussion. Jeff notes that gadgets should raise “MOVED_FORWARD” and “MOVED_BACK” events when their z-order is changed. However, the z-order is controlled by the parent gadget. The only way to raise these events would be if the parent gadget called “child->raiseMoveForwardEvent()” or something similar when the order changed. This goes against the conventions in the rest of the system. Only the gadget should be able to raise events from itself.

The way around this is to expose the child gadget vector (or introduce methods for working with it, such as “getChildCount()”, “swapChildOrder(source, dest)”, etc) and allow gadgets to re-order their parents’ children. This means that each gadget can control how it re-orders itself instead of parents assuming that their children should all be re-ordered in the same way, and allows the usual way of raising events. It introduces other complexities, though. Thoughts?

Comments

Jeff on 2008-06-18 at 03:48 said:

Hmmm, technically I was only thinking about it with respect to Windows and Screens where changing in Z-order is expected. A window will come forward off its own bat, if you click in it, won’t it? Its not the parent Screen that brings it forward? (Or is it?)

Similiarly, a screen coming forward (or switching from top to bottom) is something that happens as a function of the user clicking on screen titlebar gadgets ( or by calling API’s on the Screen itself, in which case its fine for it to raise the event )

john on 2008-06-18 at 08:08 said:

ant on 2008-06-26 at 14:13 said:

Trying to catch up on comments whilst I have a couple of free minutes. I haven’t had chance to do anything at all recently; I might put a post up about the reasons behind the lack of progress lately - mainly to prove that I’m still here - but it always bugs me when blogs go off-topic.

Anyhoo, if I remember this correctly, when you click on a window, the click() method will call the screen’s setFocusedGadget() method, which will ultimately call a method in the screen to move the window to the front of the screen’s child list. The window can’t do it because the screen’s child list is private, so whatever happens it’s the screen that controls its child windows’ z-order.

John ran into this problem when he tried adding buttons directly to a screen - the buttons kept changing z-order when he clicked on them. If you put the buttons into a window instead, the z-order doesn’t change since the window’s setFocusedGadget() method doesn’t muck about with its children’s z-order.

If I moved more control over z-ordering into the children, and allowed more external control over the parent’s child list (not totally exposing it as that will definitely cause problems, but I can introduce a set of methods for working with it), I think I’d solve some of the problems. However, I’d introduce more (decorations would be difficult), so I’m not really sure.

John on 2008-06-28 at 20:33 said:

So, to avoid the confusion I encountered, would it be better to place some restrictions on users - you can add any only add windows to screens ?

Jeff on 2008-06-29 at 07:48 said:

I think the issue is that screens also have their own title bar gadgets, etc. You can’t prevent it from having them.

Of course, my answer (which Ant won’t like) is to use RTTI and only bring the gadget forward if its derived from Window.

Failing that, add another ‘info’ method to the Gadget class that answers the question doYouLikeToComeForwardOnActivation() and only Window would return TRUE.

John on 2008-06-30 at 07:48 said:

Was thinking along the lines of making gadget a private/protected base class of screen so it can still contain other gadgets (title bar etc) but addGadget() would be private, preventing users from adding any old gadget type. Windows would have to be added to the screen via a new addWindow() method.

John on 2008-06-30 at 07:59 said:

[ Assuming screen’s are only really supposed to contain windows - not other gadgets (except for title bar etc which could remain internal to the implementation of screen). ]

Jeff on 2008-06-30 at 10:17 said:

Screen::addWindow() used to exist, almost, though it was essentially newWindow() which did the creation for you as well - that went away because it precluded the ability to subclass Window.

You could do what you are suggesting by adding a superclass called ScreenGadget which Window and the other screen-gadgets inherit from, then changing Screen to overload addGadget() and make it private-ish, ie.

public: virtual void addGadget(ScreenGadget* gadget); private: virtual void addGadget(Gadget* gadget);

That is, you could do that if Gadget::addGadget() were virtual, but its not. So, two files need to change, gadget.h and screen.h

ant on 2008-06-30 at 14:41 said:

Possible, but it starts to introduce weird special-cases. Gadget::addGadget() is one of the critical bits of code that users shouldn’t be able to replace, so I’d prefer a solution that didn’t make the API less robust.

Jeff on 2008-07-05 at 00:39 said:

Understood, though I think that people overloading addGadget() get what they deserve. And, of course, it becomes harder for people to overload if there are other variants out there, because they have to hit them all, and therefore subclass more classes.

ie, overloading Gadget::addGadget() can’t affect ScrollBars, or Windows, or CheckBoxes, etc without the user deliberately subclassing those classes - you aren’t going to do that by accident

The same argument could be made for adding Window::addGadget(WindowGadget*) which took the titlebar, etc distinct from Window::addGadget(Gadget*).