
Hi Peter
Looks very promising!
Thanks :-).
Why is cast<> using a what looks like a homebrew RTTI system? Is there something that makes dynamic_pointer_cast<T::element_type>(w) inappropriate?
Mm, er, um, ah... Yes, it is a homebrew RTTI system. It does nothing that could not be achieved with dynamic_cast, but it's a bit less weighty. By the way, the widget types already have names (the static type() members) anyway, as a consequence of the use of window_base as a factory. More on that below.
Still on the cast<> subject, it should probably signal failure by throwing an exception derived from std::bad_cast, or maybe just return NULL, to allow the usual
if( grid g = cast<grid>(w) ) { // ... }
Yes, perhaps :-). I have no strong feelings on this. I suspect exceptions are slightly better, since the primary use of cast<> is when you already know what the widget type is. In fact, just about the only place user code uses it is implicitly, when creating a widget: button = cast<button>(window.spawn(button_base::type())); I should be very surprised if the cast failed in this scenario.
Have you considered the 'on_delete', 'on_change' naming scheme for signals (events)? It seems more GUI/RAD-like.
Yes, but I think I'd rather name it after what it is (delete_signal) than after when it happens (on_delete).
Finally, when I see
test->contain(create_label(test, "You pressed the \"Click me!\" button!\nHow clever!"));
I wonder whether it would be feasible to eliminate the inner 'test', as it's logically redundant (a window probably can't contain something that is parented by another window). Although this would probably turn the architecture on its head, as it would require a new concept, a 'free widget'.
This comes down to a technical issue. First, I *really* don't want to introduce "free widgets". Apart from anything else, it keeps the implementation simple, creating the widget in the constructor and destroying it in the destructor. However, there is a deeper problem: On the Win32 platform, everything is a window. Windows have "parent" windows, and "owner" windows. You can change the "parent", but you can't change the "owner", which must be specified at creation. Furthermore, funny things start to happen when you make a window a child of a window that does not own it. This means you have to destroy the HWND in order to reparent it properly. I can't necessarily guarantee that this will be an easy process. In order to avoid this (and similar problems on other platforms), I've turned to the document object model. Essentially, a window models a document, which then contains a hierarchy of nodes or widgets. You can rearrange the hierarchy, but you can't take an element from one document (window) and put it in another. The window_base class acts as a factory for all the other widget types; thus there is really only one library function of any significance: create_window(). So, in the code you underlined, what's actually happening is: // create a label belonging to the test window widget a = test->spawn("label"); label b = cast<label>(widget); // set the text for the label b->set_text("blah blah blah"); // make the label the immediate child of the window test->contain(b); Compare this with the DOM: div = document.createElement("div"); div.id = "links"; body = document.getElementById("body"); body.appendChild(div); Regards David Turner