Original Post
In the past, I have been fustrated in attempting to figure out "the perfect design" for a C++ GUI toolkit, as I had a hard time figuring out a good scheme for attempting to meld both implementation that could work within a multitude of contexts (Windows API, X11, OpenGL, etc) and the data of the GUI, as I followed in the steps of so many GUI kits that do so. However, I have realized the melding of these two is probably exactly what I should be avoiding!! My fustration in attempting to generate the desired level of flexibility (a window class should be useable both to access system windowing, as well as be able to provide a window rendered in OpenGL as a subwindow, or as a fullscreen app) stemmed from the attempting to meld multiple implementations, as well as the data. In my new method, classes such as "window" and "font" are simple data (although I will probably include an appropriately wrapped internal pointers allowing classes to store widget-specific cached data), which are then "handled" by implementations. Instead of "gui::button" having a render() function, there is instead a handler that takes care of all implementation details - the equivilant to button.render() would be something like these functions: opengl_context::gui_handler< gui::button >::render( button ); x11r6_context::gui_handler< gui::button >::render( button ); console_context::gui_handler< gui::button >::render( button ); This has nifty features such as allowing, say, a window to be moved between different contexts seamlessly - if managed right anyways. I'm working on building a prototype of this, with the following constraints: 1) Widgets can only be "mounted" once in the GUI heiarchy. The same button can not appear in two seperate windows. This constraint allows me to have a single "context cache" per widget. 2) The first version will only have an OpenGL + FreeType + CSS implementation to start with. I may attempt to port to SDL as well, for the sake of attempting to make sure my implementation truely seperates API from data. 3) Two seperate child lists will be maintained for widgets that have children: Managed and Unmanaged. Managed will be designed for a lifespan that is completely widget-local (the exit button of a window for example) - which will be created directly through template functions of the widget, aka: my_window.create_child< button >( /*...*/ ); my_window.destroy_child( reference_to_button ); This is done to ensure propper new/delete pairing. The data is considered "owned" by the parent, and will be destroyed when the parent widget is destroyed, unless explicitly destroyed earlier via the destroy_child (or equivilant) function. A transfer_child will likely at least be prototyped, to compare against the functionality provided by the second list: A seperate list of "non-owned" (not tied to parent) "children" will be mantained. They will have similar API: my_window.register_child( reference_to_button ); my_window.unregister_child( reference_to_button ); This is done to allow widgets to be displayed that have no fixed owner. A good example would be a sub-window of a program that can be docked. It would be switched from being registered with the window to being registered with one of the "docking groups" of the window. Feedback, links to similar GUI implementations (of which I am aware of none), and critique appreciated. -Mike