Re: GUI Library Proposal for a Proposal

Message: 16 Date: Tue, 9 Nov 2004 09:38:35 -0500 From: Caleb Epstein <caleb.epstein@gmail.com> Subject: Re: [boost] Re: GUI Library Proposal for a Proposal To: boost@lists.boost.org Message-ID: <989aceac041109063895d91c0@mail.gmail.com> Content-Type: text/plain; charset="us-ascii"
On Mon, 8 Nov 2004 19:18:13 -0500, Edward Diener <eddielee@tropicsoft.com> wrote:
The one area where C++ is weaker than other languages for design time UI, and component, development is in its lack of a general run-time reflection mechanism. That is the only area which I see that is holding it back.
I've been toying with using the properties library Reece Dunn recently submitted (in the boost-sandbox CVS) for this purpose. I've got something very sketchy, but it relies on a visitor pattern to "pass" type information to client code in a manner similar to Boost.Variant.
I'd prefer a way of storing the type information for each reflectable class statically, and in a generic way, e.g. something like std::map<std::string, property>. This would enable the reflection code could be decoupled from the reflected classes entirely and just operate on this property meta-data. It would also allow client code to lookup individual properties (e.g. by name) instead of having to visit all of them.
I'm stumped by how to store this information in any sort of container though, since the properties are of different types. Any thoughts, or is this madness?
The properties are of different types, but the type information for properties will always be of the same type :) So you can generate a property set for your class, that includes the dictionary that maps names to property_type_info structures. Each property_type_info would be automatically generated from the static type of the property. The thing that's bugging me is that all the reflection mechanism is covered by Boost.Python because it relies on the same principles. I *think* the boost-langbinding list seems to know this, since you also need the reflection capabilities in order to support languages that aren't Python. But that list doesn't seem to have much traffic so I haven't much to go on. In order to avoid too many reinvented wheels, I'd like to see Boost.Python split neatly into two stages: (a) Reflect C++ types into C++ objects. Each type for which you provide a reflection map will correspond to exactly one property_set object, which would contain a set of property_type_info objects. (b) Expose the types to Python using the objects created by (a). Once you've made that split, then you can add: (c) Expose the types to Lua using the objects created by (a). (d) Expose the types to <language-of-your-choice> using the objects created by (a). (e) Serialise the types, using results of (a). (f) Bind types to GUI objects, using results of (a). (g) ... you get the point. George

On Tue, 9 Nov 2004 17:37:15 -0000, George van den Driessche <grebe@bigfoot.com> wrote:
Date: Tue, 9 Nov 2004 09:38:35 -0500 From: Caleb Epstein <caleb.epstein@gmail.com>
I've been toying with using the properties library Reece Dunn recently submitted (in the boost-sandbox CVS) for this purpose. I've got something very sketchy, but it relies on a visitor pattern to "pass" type information to client code in a manner similar to Boost.Variant.
I'd prefer a way of storing the type information for each reflectable class statically, and in a generic way, e.g. something like std::map<std::string, property>. This would enable the reflection code could be decoupled from the reflected classes entirely and just operate on this property meta-data. It would also allow client code to lookup individual properties (e.g. by name) instead of having to visit all of them.
I'm stumped by how to store this information in any sort of container though, since the properties are of different types. Any thoughts, or is this madness?
The properties are of different types, but the type information for properties will always be of the same type :) So you can generate a property set for your class, that includes the dictionary that maps names to property_type_info structures. Each property_type_info would be automatically generated from the static type of the property.
You lost me here. The property types each inherit from property_info, but it is similarly templated on the type of object begin stored/referenced/aliased. Are you suggesting another non-template base class which all properties would inherit from? What might this look like? What mechanism would you use to keep track of the type information?
The thing that's bugging me is that all the reflection mechanism is covered by Boost.Python because it relies on the same principles. [...]
Exactly. A reflection mechanism would facilitate lots of different language bindings, serialization, etc. -- Caleb Epstein caleb.epstein@gmail.com

"George van den Driessche" <grebe@bigfoot.com> writes:
I'm stumped by how to store this information in any sort of container though, since the properties are of different types. Any thoughts, or is this madness?
The properties are of different types, but the type information for properties will always be of the same type :) So you can generate a property set for your class, that includes the dictionary that maps names to property_type_info structures. Each property_type_info would be automatically generated from the static type of the property.
The thing that's bugging me is that all the reflection mechanism is covered by Boost.Python because it relies on the same principles. I *think* the boost-langbinding list seems to know this, since you also need the reflection capabilities in order to support languages that aren't Python. But that list doesn't seem to have much traffic so I haven't much to go on.
We did some work on that project recently and presented it at the Boost workshop at OOPSLA. See http://boost-consulting.com/writing/oopsla04.html http://boost-consulting.com/writing/langbinding.ppt
In order to avoid too many reinvented wheels, I'd like to see Boost.Python split neatly into two stages:
(a) Reflect C++ types into C++ objects. Each type for which you provide a reflection map will correspond to exactly one property_set object, which would contain a set of property_type_info objects. (b) Expose the types to Python using the objects created by (a).
We do have a front-end/back-end architecture, but I'm not sure whether we're doing what you want.
Once you've made that split, then you can add: (c) Expose the types to Lua using the objects created by (a). (d) Expose the types to <language-of-your-choice> using the objects created by (a). (e) Serialise the types, using results of (a).
This I have serious doubts about. What you'd expose for Python/Lua binding would be an object's public interface: its abstraction. In order to do serialization in that way, you'd likely have to expose an object's guts: its implementation details.
(f) Bind types to GUI objects, using results of (a).
What does it mean to bind a type to a GUI object?
(g) ... you get the point.
I'm not sure. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

On Wed, 10 Nov 2004 20:52:24 -0500, David Abrahams <dave@boost-consulting.com> wrote:
"George van den Driessche" <grebe@bigfoot.com> writes:
I'm stumped by how to store this information in any sort of container though, since the properties are of different types. Any thoughts, or is this madness?
The properties are of different types, but the type information for properties will always be of the same type :) So you can generate a property set for your class, that includes the dictionary that maps names to property_type_info structures. Each property_type_info would be automatically generated from the static type of the property.
The thing that's bugging me is that all the reflection mechanism is covered by Boost.Python because it relies on the same principles. I *think* the boost-langbinding list seems to know this, since you also need the reflection capabilities in order to support languages that aren't Python. But that list doesn't seem to have much traffic so I haven't much to go on.
We did some work on that project recently and presented it at the Boost workshop at OOPSLA. See http://boost-consulting.com/writing/oopsla04.html http://boost-consulting.com/writing/langbinding.ppt
Is the Boost.Langbinding code available anywhere? This looks like precisely what I have been trying to do, but of course about a million times better written, documented, and full-featured than I could ever hope to do myself :-). -- Caleb Epstein caleb.epstein@gmail.com

Caleb Epstein <caleb.epstein@gmail.com> writes:
On Wed, 10 Nov 2004 20:52:24 -0500, David Abrahams <dave@boost-consulting.com> wrote:
"George van den Driessche" <grebe@bigfoot.com> writes:
I'm stumped by how to store this information in any sort of container though, since the properties are of different types. Any thoughts, or is this madness?
The properties are of different types, but the type information for properties will always be of the same type :) So you can generate a property set for your class, that includes the dictionary that maps names to property_type_info structures. Each property_type_info would be automatically generated from the static type of the property.
The thing that's bugging me is that all the reflection mechanism is covered by Boost.Python because it relies on the same principles. I *think* the boost-langbinding list seems to know this, since you also need the reflection capabilities in order to support languages that aren't Python. But that list doesn't seem to have much traffic so I haven't much to go on.
We did some work on that project recently and presented it at the Boost workshop at OOPSLA. See http://boost-consulting.com/writing/oopsla04.html http://boost-consulting.com/writing/langbinding.ppt
Is the Boost.Langbinding code available anywhere? This looks like precisely what I have been trying to do, but of course about a million times better written, documented, and full-featured than I could ever hope to do myself :-).
There's some very incomplete work in the "langbinding" branch of boost/langbinding and libs/langbinding in the main CVS. We have _lots_ of work left to do. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
"George van den Driessche" <grebe@bigfoot.com> writes:
Once you've made that split, then you can add: (c) Expose the types to Lua using the objects created by (a). (d) Expose the types to <language-of-your-choice> using the objects created by (a). (e) Serialise the types, using results of (a).
This I have serious doubts about. What you'd expose for Python/Lua binding would be an object's public interface: its abstraction. In order to do serialization in that way, you'd likely have to expose an object's guts: its implementation details.
I think the assumption George is going under is that the public interface provides enough information to reconstruct the objects. Although that is not required it is a common way to design classes that are going to be serialized. So if you accept that axiom it's possible to serialize from a reflection of a public interface.
(f) Bind types to GUI objects, using results of (a).
What does it mean to bind a type to a GUI object?
This is something I somewhat do in parts of the GUI code I have. Basically it's being able to tie a variable (class member, global, etc) to be displayed and manipulated "directly" by a GUI widget. For example attaching an enum to a combo-box, or a string to a text-box. Doing something that maps from the type to the widget automatically given the reflection info of the type is not an easy task as there's more to a variable than just the type which one ends up adding when creating the widget bindings, or at least I did. -- -- Grafik - Don't Assume Anything -- Redshift Software, Inc. - http://redshift-software.com -- rrivera/acm.org - grafik/redshift-software.com - 102708583/icq

(f) Bind types to GUI objects, using results of (a).
What does it mean to bind a type to a GUI object?
This is something I somewhat do in parts of the GUI code I have. Basically it's being able to tie a variable (class member, global, etc) to be displayed and manipulated "directly" by a GUI widget. For example attaching an enum to a combo-box, or a string to a text-box. Doing something that maps from the type to the widget automatically given the reflection info of the type is not an easy task as there's more to a variable than just the type which one ends up adding when creating the widget bindings, or at least I did.
The FOX GUI has exactly this capability, you can connect a variable directly to the widget, without requiring any glue code at all. In fact, you can connect the same variable to multiple widgets at the same time (eg a 'spinner' widget and an 'editeline'), without requiring the programmer to write any type of callback mechanism. This works because all GUI events are bi-directional. For more information, read: http://www.fox-toolkit.org/datatarget.html regards Mathew

"Mathew Robertson" <mathew.robertson@redsheriff.com> writes:
(f) Bind types to GUI objects, using results of (a).
What does it mean to bind a type to a GUI object? This is something I somewhat do in parts of the GUI code I have. Basically it's being able to tie a variable (class member, global, etc) to be displayed and manipulated "directly" by a GUI widget. For example attaching an enum to a combo-box, or a string to a text-box. Doing something that maps from the type to the widget automatically given the reflection info of the type is not an easy task as there's more to a variable than just the type which one ends up adding when creating the widget bindings, or at least I did.
The FOX GUI has exactly this capability, you can connect a variable directly to the widget, without requiring any glue code at all. In fact, you can connect the same variable to multiple widgets at the same time (eg a 'spinner' widget and an 'editeline'), without requiring the programmer to write any type of callback mechanism.
This works because all GUI events are bi-directional. For more information, read: http://www.fox-toolkit.org/datatarget.html
And one of our Boost.Python users has implemented an improved version of FOX: http://www.nedprod.com/TnFOX/ -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

The FOX GUI has exactly this capability, you can connect a variable directly to the widget, without requiring any glue code at all. In fact, you can connect the same variable to multiple widgets at the same time (eg a 'spinner' widget and an 'editeline'), without requiring the programmer to write any type of callback mechanism.
This works because all GUI events are bi-directional. For more information, read: http://www.fox-toolkit.org/datatarget.html
That seems a lot of code, compared to: http://www.torjo.com/win32gui/save_dlg.html Not to say about validation... Best, John -- John Torjo, Contributing editor, C/C++ Users Journal -- "Win32 GUI Generics" -- generics & GUI do mix, after all -- http://www.torjo.com/win32gui/ -- v1.5 - tooltips at your fingertips (work for menus too!) + bitmap buttons (work for MessageBox too!) + tab dialogs, hyper links, lite html

The FOX GUI has exactly this capability, you can connect a variable directly to the widget, without requiring any glue code at all. In fact, you can connect the same variable to multiple widgets at the same time (eg a 'spinner' widget and an 'editeline'), without requiring the programmer to write any type of callback mechanism.
This works because all GUI events are bi-directional. For more information, read: http://www.fox-toolkit.org/datatarget.html
That seems a lot of code, compared to: http://www.torjo.com/win32gui/save_dlg.html Not to say about validation...
The problem with this implementation is that the 'user_name' field cannot (usually) connect to more than one widget at a time. Also, most widget libraries dont allow you to connect a variable to a widget, and still allow user validation. This is because the widget library doesn't callback into the validation code, since it assumes that if it is connected to a widget, then no validation code is necessary. Mathew

Mathew Robertson wrote:
The FOX GUI has exactly this capability, you can connect a variable directly to the widget, without requiring any glue code at all. In fact, you can connect the same variable to multiple widgets at the same time (eg a 'spinner' widget and an 'editeline'), without requiring the programmer to write any type of callback mechanism.
This works because all GUI events are bi-directional. For more information, read: http://www.fox-toolkit.org/datatarget.html
That seems a lot of code, compared to: http://www.torjo.com/win32gui/save_dlg.html Not to say about validation...
The problem with this implementation is that the 'user_name' field cannot (usually) connect to more than one widget at a time.
That is a current limitation, but I don't think you need it so much. Anyway, you can work around it, by listening to kill_focus events: - you will have temporary variables, and each is bound to a control. - You listen for kill_focus from these variables - on kill_focus, you synchronize the temporary variables
Also, most widget libraries dont allow you to connect a variable to a widget, and still allow user validation. This is because the widget library doesn't callback into the validation code, since it assumes that if it is connected to a widget, then no validation code is necessary.
That's the win32gui' advantage :) "if it is connected to a widget, then no validation code is necessary." - that really sounds silly. Best, John -- John Torjo, Contributing editor, C/C++ Users Journal -- "Win32 GUI Generics" -- generics & GUI do mix, after all -- http://www.torjo.com/win32gui/ -- v1.5 - tooltips at your fingertips (work for menus too!) + bitmap buttons (work for MessageBox too!) + tab dialogs, hyper links, lite html

The FOX GUI has exactly this capability, you can connect a variable directly to the widget, without requiring any glue code at all. In fact, you can connect the same variable to multiple widgets at the same time (eg a 'spinner' widget and an 'editeline'), without requiring the programmer to write any type of callback mechanism.
This works because all GUI events are bi-directional. For more information, read: http://www.fox-toolkit.org/datatarget.html
That seems a lot of code, compared to: http://www.torjo.com/win32gui/save_dlg.html Not to say about validation...
The problem with this implementation is that the 'user_name' field cannot (usually) connect to more than one widget at a time.
That is a current limitation, but I don't think you need it so much. Anyway, you can work around it, by listening to kill_focus events: - you will have temporary variables, and each is bound to a control. - You listen for kill_focus from these variables - on kill_focus, you synchronize the temporary variables
Thats a hack, plain and simple... and it requires the application programmer to synchronise the state of these variables -> it should be a capability within the GUI library. What I am suggesting is that the technique described, is added as a native capability to the library so that this error-prone code is eliminated (its error-prone because it requires the programmer to remember that he must synchronise the variables not only on kill_focus, but also on any mouse event including left_click and mouse_over, any key event such as key_press and key_release, as well as when the program itself simply updates the value of the variable. And connecting to more than one widget at a time, is done more frequently than you may expect, eg: anything that allows user input from an editline plus some other widget (a combobox, a scrollbar, a select list, etc). Or you could connect the variable to a statusbar and a tooltip.
Also, most widget libraries dont allow you to connect a variable to a widget, and still allow user validation. This is because the widget library doesn't callback into the validation code, since it assumes that if it is connected to a widget, then no validation code is necessary.
That's the win32gui' advantage :)
"if it is connected to a widget, then no validation code is necessary." - that really sounds silly.
Not really, there are two reasons why validation code is not necessary. 1. User validation always needs to be done by your business/process rules. -> When the 'go' event is generated, your app should validate the application variables (some of which will be connected to widgets). The validation will need to reset any variables which are in an out-of-bound condition (this implies that the GUI will need to re-synchronize to the new state of the variables). I wont comment on whether it is good to intertwine business logic within GUI update code.... 2. Some widgets dont need validation eg: spinner, combobox, slider... These almost never need validation, since they are only ever populated with valid values. Mathew

Not really, there are two reasons why validation code is not necessary.
1. User validation always needs to be done by your business/process rules. -> When the 'go' event is generated, your app should validate the application variables (some of which will be connected to widgets). The validation will need to reset any variables which are in an out-of-bound condition (this implies that the GUI will need to re-synchronize to the new state of the variables). I wont comment on whether it is good to intertwine business logic within GUI update code....
2. Some widgets dont need validation eg: spinner, combobox, slider... These almost never need validation, since they are only ever populated with valid values.
I'm talking about your business logic. Why shouldn't a combo-box / slider not have validation? And as a side-note, combo-boxes can be "drop-down" as well. In which case, you can : - select from existing values - enter a new value yourself (which could require validation). And as for validation, take an employee's data: struct employee { std::string first_name; std::string last_name; int id; unsigned long salary; time_t birth_date; std::string country; std::string address; std::string email; bool has_homepage; std::string homepage; }; Here are possible validations: - First and last names should not be less than 4 chars - ID should be within 10000 and 20000 range - salary should not be bigger than 150,000 - birth_date should not be bigger than 1980 - email address should be valid - homepage should be valid. How do you handle those (and lets not remember user-friendlyness)? And just for fun, try downloading win32gui, and run these examples: examples/samples_dlg/simpl_empl_edit examples/samples_dlg/simpl_empl_edit_bolded , to see what I mean. Best, John -- John Torjo, Contributing editor, C/C++ Users Journal -- "Win32 GUI Generics" -- generics & GUI do mix, after all -- http://www.torjo.com/win32gui/ -- v1.5 - tooltips at your fingertips (work for menus too!) + bitmap buttons (work for MessageBox too!) + tab dialogs, hyper links, lite html

Not really, there are two reasons why validation code is not necessary.
1. User validation always needs to be done by your business/process rules. -> When the 'go' event is generated, your app should validate the application variables (some of which will be connected to widgets). The validation will need to reset any variables which are in an out-of-bound condition (this implies that the GUI will need to re-synchronize to the new state of the variables). I wont comment on whether it is good to intertwine business logic within GUI update code....
2. Some widgets dont need validation eg: spinner, combobox, slider... These almost never need validation, since they are only ever populated with valid values.
I'm talking about your business logic. Why shouldn't a combo-box / slider not have validation?
And as a side-note, combo-boxes can be "drop-down" as well. In which
What other combo-box is there which doesn't drop down?
case, you can : - select from existing values - enter a new value yourself
(which could require validation).
Combo-boxes shouldn't be populated with something which wont produce a valid business rule. Editable combo-boxes are more rare -> usually they allow you "select an entry by typing the first few characters". Truely editable combo-boxes are just about always used in the wrong context -> usually the interface needs the use of an editline with history-popup. Sliders should always only allow you to select valid values. I'm not sure why you would have a slider which would allow you to select invalid business rules...
And as for validation, take an employee's data:
struct employee { std::string first_name; std::string last_name; int id; unsigned long salary;
time_t birth_date;
std::string country; std::string address; std::string email;
bool has_homepage; std::string homepage; };
Here are possible validations: - First and last names should not be less than 4 chars
This is a feature of the editline -> no validation is necessary
- ID should be within 10000 and 20000 range
A slider with the lower value set to 10000 and the upper value to 20000
- salary should not be bigger than 150,000
An numeric editline has the feature of having a bounded upper limit.
- birth_date should not be bigger than 1980
You should be using a "calendar widget", I'm not sure what you mean by 'bigger' in the context of dates...
- email address should be valid
Define 'valid' for an email address. Should it contain an @ symbol? If so, then use an Email-Editline widget, dont use a generic text editline widget.
- homepage should be valid.
Same response as email address question.
How do you handle those (and lets not remember user-friendlyness)?
I think you ment to say "lets not forget user-friendlyness"... In each case I have provided a reasonable example where no validation was necessary by the application programmer. All of which provide a reasonable good HCI, far better than simple editlines.
And just for fun, try downloading win32gui, and run these examples: examples/samples_dlg/simpl_empl_edit examples/samples_dlg/simpl_empl_edit_bolded
, to see what I mean.
Prior to the Boost::GUI discussions of the last month or two, I have previously taken a good look at win32gui as I have been following widget library development for a few years now. My analysis of each toolkit is irrelevant here, except to say that I found the FOX toolkit to offer what I would call "the most technically correct toolkit" (for some arbitrary value of 'correct'...). That said, it suffers from slow development (although minor releases are frequent). The origonal point was that variables connected to widgets, always need validation (which they dont always) and they need synchronisation (which they dont always). I'm just letting other know what the state of the art is wrt. GUI toolkits. regards, Mathew

Mathew Robertson wrote:
Combo-boxes shouldn't be populated with something which wont produce a valid business rule. Editable combo-boxes are more rare -> usually they allow you "select an entry by typing the first few characters". Truely editable combo-boxes are just about always used in the wrong context -> usually the interface needs the use of an editline with history-popup.
Sliders should always only allow you to select valid values. I'm not sure why you would have a slider which would allow you to select invalid business rules...
I'm not sure I agree. It is a general principle to _never trust_ input, no matter how sure one might be that the control has only been populated with good values. Of course this comes naturally when the business logic is on the server.

And as a side-note, combo-boxes can be "drop-down" as well. In which
What other combo-box is there which doesn't drop down?
"drop-list" for instance, is what I think you assume for "drop-down" (that is, you can only select from a list). "drop-down" - you can select an item from a list, but also write it yourself.
And as for validation, take an employee's data:
struct employee { std::string first_name; std::string last_name; int id; unsigned long salary;
time_t birth_date;
std::string country; std::string address; std::string email;
bool has_homepage; std::string homepage; };
Here are possible validations: - First and last names should not be less than 4 chars
This is a feature of the editline -> no validation is necessary
- ID should be within 10000 and 20000 range
A slider with the lower value set to 10000 and the upper value to 20000
kidding, right? Would you have a user select an Employee ID with a slider? What if, for instance, valid IDs are from 5000 -10000, and 15000-20000? I'm all for XXXYYY-Widgets, where possible. However, saying that you should always use widgets for validation, is about the equivalent of saying that all a class needs are some member variables, and no validation whatsoever, since the members will take care of that.
Define 'valid' for an email address. Should it contain an @ symbol? If so, then use an Email-Editline widget, dont use a generic text editline widget.
Again, I'm all for this, but you should impose your application logic on the controls, and not the other way around. I'm sure you'll find cases whre you need specific logic for, lets say, an edit control, and no widgets provide it out of the box.
How do you handle those (and lets not remember user-friendlyness)?
I think you ment to say "lets not forget user-friendlyness"...
Yes :)
In each case I have provided a reasonable example where no validation was necessary by the application programmer. All of which provide a reasonable good HCI, far better than simple editlines.
Because what I've shown was too simple - my mistake here. There are more complex scenarios where some invariants need to be kept, just like invariants that appear in a class. You can even think about it like this: if you have a class that needs to be editable (in a dialog), if that class has an invariant, so will the dialog need to have some validation associated with it. Best, John -- John Torjo, Contributing editor, C/C++ Users Journal -- "Win32 GUI Generics" -- generics & GUI do mix, after all -- http://www.torjo.com/win32gui/ -- v1.5 - tooltips at your fingertips (work for menus too!) + bitmap buttons (work for MessageBox too!) + tab dialogs, hyper links, lite html

Hello, I'm probably too late and what I'd like to say is too general, but maybe somebody will find the following thoughts useful. There are many GUI frameworks - platform-specific, platform-independent, something in between, but most of them (I'm afraid to say all of them :) have the same problems. On the one hand they give a user many really good things: windowing, controls, event handling, geometry, drag&drop support, etc... On the other hand they are monolithic - you have to use the *whole* framework, you cannot take and use only one subsystem. My application is based on MapApp and I see nice implementation of general event handlers in other framework but I cannot use it because I cannot rewrite whole application on new framework. IMO, the best GUI "framework" would be a *set* of separate, specific libraries each of which would provide good abstractions/algorithms in some specific gui-related area: ** general-purpose 2d lightweight geometry and general algorithms ( boost::gui::2d::point, rect, path, ...) ** painting areas, canvases and painting algorithms ** events, propagation and handling mechanisms, (event_target, listener, subscribers...) ** windowing (windows, views...) ** layout algorithms (placing visual elements relatively to each other), language to express constrains. ** widgets, controls, text engine and etc... ** ... In other words GUI "framework" should have good separation and provide set of useful abstractions, algorithms which I can use separately (more or less) and bind to platform API or some platform-specific already existent "low-level" framework (MacApp, MFC, QT, WxWindows... ). I believe it's possible and I'm not the only one who wants it. Thanks, Aleksey Chernoraenko.

Aleksey Chernoraenko wrote:
IMO, the best GUI "framework" would be a *set* of separate, specific libraries each of which would provide good abstractions/algorithms in some specific gui-related area:
I'd like to emphasize the importance of Aleksey Chernoraenko's point. I know we've all gotten very used to using so-called "toolkits" or "frameworks" for GUI developments, that provide everything from string classes to threading support. Good programmers know better than this; lets not create yet another one of these horrible things that is doomed to die by its own limited entanglement. I think two primary design goals of any new GUI work should be "no unnecessary coupling" and "a model of the Open-Closed Principle" (OCP). As a refresher, the OCP is a design philosophy of classes, functions, and similar abstract entities, loosely stated as "open for extension, closed for modification." I think that any new GUI interfaces created that fail to make these items a priority in their design will share the fate of all traditional user-interface frameworks, being inappropriate for modern design, and doomed to obsoletion. Aaron W. LaFramboise

Aaron W. LaFramboise wrote:
Aleksey Chernoraenko wrote:
IMO, the best GUI "framework" would be a *set* of separate, specific libraries each of which would provide good abstractions/algorithms in some specific gui-related area:
I'd like to emphasize the importance of Aleksey Chernoraenko's point. I know we've all gotten very used to using so-called "toolkits" or "frameworks" for GUI developments, that provide everything from string classes to threading support. Good programmers know better than this; lets not create yet another one of these horrible things that is doomed to die by its own limited entanglement.
That's exactly what I meant. Thanks, Aleksey Chernoraenko.

"Aaron W. LaFramboise" <aaronrabiddog51@aaronwl.com> wrote in message news:419EB968.1050508@aaronwl.com...
Aleksey Chernoraenko wrote:
IMO, the best GUI "framework" would be a *set* of separate, specific libraries each of which would provide good abstractions/algorithms in some specific gui-related area:
I think that any new GUI interfaces created that fail to make these items a priority in their design will share the fate of all traditional user-interface frameworks, being inappropriate for modern design, and doomed to obsoletion.
Just to revive discussion about GUI allow me to offer my 2c worth. (Sorry for big post). LetÂ’s split GUI into two parts: G (2D graphics) and UI (user interface). :-) G can be used without UI: printing, generation of metafiles (e.g., Postscript, SVG) or pixmaps/bitmaps. UI can be used without G, if only stock components are used: simple dialog boxes. Graphics requires following components to be implemented: canvas, graphics primitives (shapes to describe geometric parameters, attributes to describe visual parameters, clipping facilities), and 2D geometry. User interface requires following components to be implemented: events, windowing, layout facilities, and widgets/controls. Layout requires 2D geometry. Widgets may require all listed components. Now we want to make all these components as light-weight as possible for performance reasons. Ideally they should be mapped 1-to-1 to facilities of underlying platform, while preserving platform independence. I donÂ’t think it is productive to walk original Java way and implement all widgets in terms of graphics primitives, nor implement graphics primitives in term of pixel rasterizer. What do we need from graphics? There are specific requirements imposed by UI: 1) Zooming. All users want to rescale a drawing, e.g. making it fit in a window, to drill down to see some details, and so on. Mapping from absolute units (e.g., inches) to device units (e.g., pixels) is a kind of zooming as well. 2) Scrolling. It is useful for big drawings and usually goes in hand with zooming. UI provides special controls for that: scroll bars. Variation on scrolling is panning, when user can drag picture with mouse. 3) Picture regeneration. In a world of overlapping windows we have to support a way to regenerate only damaged part of window. Typically it is done with clipping and associated regions. Scrolling and panning is another source of picture regeneration, when part of picture is moved somehow, and the rest should be regenerated. First order of business is 2D geometry. Following stuff is required: 1) Point. Simple 2D entity with X and Y components. In real life at least two versions are required: integral (screen coordinates are integral) and floating point (for precise calculations). Depending of task conversion between them may require rounding off, ceil/ or floor operations. Additional consideration: it may be integrated with more general geometric toolkit, which may implement 2D and 3D points as well as N-dimensional vectors. Additional consideration: point should play well with native platform-dependent coordinate. 2) Rectangle. Again, two versions are required. A bunch of algorithms should be implemented: intersection of 2 rectangles, bounding rectangle of two (or more) rectangles and/or points, subtraction of two rectangles, test if there is intersection between two rectangle, test if point is within a rectangle, and so on. These algorithms are required to support interactivity (mouse), and efficient screen regeneration, which is crucial for complex pictures. Additional consideration: rectangle should play well with native platform-dependent rectangle. There is a slight problem here: two most popular platforms implement rectangles differently. MS Windows keeps 2 points, while X-Window keeps point and size. From my experience 2 points representation is needed more frequently. Additional consideration: usually integral rectangle doesnÂ’t include its left/bottom boundary. E.g., rectangle from (1,1) to (3,3) covers 4 pixels only, not 9. This is convention used by MS Windows and X-Window. 3) Ordered collection of points (vector, list) to represent polylines and polygons. 4) Region. Most typically region is represented as (unordered) collection of rectangles. It is used mostly for picture regeneration and complex clipping. For performance reasons it is better to have such collection spatially indexed. Additional consideration: region should play well with native platform-dependent regions. Because region is relatively complex object, which is used mostly in specific context, it may make sense to implement it as a wrapper around native region. Facilities to extract/set clipping from/to canvas should be provided. Additional consideration: some native regions are implemented as collection arbitrary geometric shapes, e.g. polygons. In my opinion this is rarely (if ever) used. We should skip it. 5) Transformation matrix. In 2D case it can be implemented as 3x3 matrix or (to conserve cycles and spaces) as 2x2 matrix + offset vector (6 values total). Usually it doesnÂ’t make any sense to use integer matrix. Algorithms to be implemented: addition, multiplication. It is beneficial to have construction from offset vector, rotation angle, mapping from rectangle to rectangle (with and without preserving aspect ratio) and so on. More complex algorithms are practical as well like "zoom around given point". Special implementation of matrix should be provided to enforce restrictions automatically. Most useful restrictions are to ensure that any transformations keep picture within scrolling boundaries. Another potentially useful type of restrictions are putting boundaries on zoom factor. Additional consideration: it may be integrated with more general geometric toolkit, which may implement generic matrices. 6) Vector as some kind of directional entity? Usually I use coordinate for that for practical reasons. I donÂ’t think that there is a big practical difference between vector and point in 2D space. 7) Size. See #6 above. Graphics primitives are easy too. (I will use Windows terminology below). 1) Attributes: pen, brush. Pen is a line type, which allows specifying color, thickness, and line pattern. Brush is a fill, which can be specified as solid color, some kind of pattern, or bitmap/pixmap. Obviously pen makes sense for outlines and brush makes sense for filled shapes. 2) Shapes: rectangle (efficiency!), polyline/polygon, Bezier curve, ellipse. 3) Text. Font plays role of attribute for text. Special strings should carry characters to be shown, position of text, alignment, and formatting options. IÂ’ll skip all multi-line formatting issues for now. 4) Markers. These are symbols anchored to 2D point. Frequently used in charts, plotting, maps, and so on. Symbol (raster or vector image) plays role of attribute. Usually more than one marker is required in a picture. Unordered collection of points is a shape of some kind. Polyline can be reused to describe such geometry. Why do we need to separate attributes and shapes? In most complex computer drawings number of different attributes is much smaller than number of different shapes (think charts, maps, and so on). It means they can be cached to improve performance. In some cases it is even possible to sort shapes by attributes to group objects sharing the same attribute together. Shapes have another thing in common: bounding rectangle, which can be used for spatial separation to improve speed of picture regeneration. And finally canvas. This is essentially Windows DC, X-Window GC, file stream (for metafiles like Postscript or SVG), and so on. Facilities to create canvas of required type should be provided. Some portable way to extract canvas from window should be provided as well. Now about some implementation points. 1) Points and rectangles should be implemented platform-independently. It allows achieving predictable performance results on all platforms. Additionally it is easier to use binary input/output to transfer them between platforms because layout is standardized. E.g., once I implemented rectangles like this (pseudo code): template<typename T> class Rect : public RectTrait<T>::layout { typedef RectTrait<T>::component_type component_type; // and so on }; On Windows I used Rect<int> and Rect<double> for calculations and Rect<RECT> for platform-dependent interface. Rect<RECT> was based on RECT and was binary compatible with all native functions. Anyway this stuff was hidden usually. 2) There are two drawing modes: immediate and delayed. MS Windows and X-Window emulate immediate mode. I prefer delayed mode. It allows to accumulate (cache) all graphics primitives in some kind of intermediate facility (in-memory spatial database of sort), which can be used to automate picture regeneration, zooming, and scrolling. This solution allows for great simplification of drawing part: just dump primitives in correct order and be done with it: no complex checks of visibility in your code, no output of unnecessary objects. Even bigger benefit: it allows automating object selection. When user clicked a mouse (or selected a rectangle), we can set neighborhood of the point (or selected rectangle) as a clipping area and "draw" picture in reverse stacking order. In this case we know what object was visible (on top), or what objects are inside our selection. In order to facilitate selection objects may have handles. Absence of handle (or some predefined handle) means that object is not selectable (e.g., background rectangle). Some objects may have the same handle, which can be used to signify that all of them are parts of some high level object. Some facilities to modify cached graphics objects should be provided. Such change would generate an update request for picture regeneration with proper bounding rectangle. For efficiency reason, before massive updates an update request may be prohibited. In this case, after update, one single update request (e.g., redraw everything) may be generated. In order to support extra big pictures we should define some protocol so intermediate database can request additional graphics data. One possible implementation is to support notion of pages, which are defined as rectangular containers of certain size. 3) Double buffer should be implemented for windows. It plays two roles: eliminates flicker, and reduces CPU cycles spent on picture regeneration. Basically, if canvas has associated buffer, all picture damage from overlapping windows is fixed using copy from buffer. Only scrolling, zooming, and internal damage would require (partial) data regeneration from original source. What do we need from user interface? Graphics can be easily abstracted without big loss of performance. Most common graphics tasks can be automated and done once. The reason is quite simple: foundation is pretty much universal. Unfortunately it is not the case with user interface. All OS vendors regard UI as a major differentiator between platforms. Different look and feel is the minor part of it. Standard set of controls/widgets is different across platforms. Different conventions are used to implement similar things. E.g., hot keys are different, menu layout is different, mouse buttons and click patterns can be different, and so on. Localization rules complicate everything. Introduction of "special look and feel" is not viable. Just remember unsuccessful Java efforts. Users of respective platforms prefer applications with native look and feel. Given all that it looks like the practical way is to provide a declarative way to describe user interface. (XUL, XAML?) We should be able to combine components (widgets/controls) on 2D surface, define event handling, and layout properties. Widgets/controls can be taken from predefined set of library components, which are mapped to native controls, if possible, or can be custom components. This description of UI can be internal (in the program) or external (e.g., in file using some format). External declaration can be replaced without recompiling a program. It simplifies localization, and minor (mostly visual) tweaks. Downside is possible mismatch with program code. Each UI object should carry a list of properties, which can be used by layout engine (replaceable component itself) to modify geometry of component depending on window size. This facility should be used for initial layout to take care of different DPI of physical device, and for potential resizing. Some required properties are obvious like size and position of component in some units in some reference coordinate system, and so on. Some properties can be more elaborate like glue in TeX (elasticity, preferred size), which will govern transformation and position of component in different conditions. In order to implement all this we need an engine, which will interpret UI description according to platform-specific rules, and work as intermediary for event processing code, and, possibly, custom painting. Obviously this engine should be customizable with replaceable components. Sketch above is not sufficiently detailed. For example it doesnÂ’t define how to implement custom component. But I think it gives a preview of what can be done with this approach: true multi-platform support, simplified creation of UI (instantiate user interface from description), simplified painting (in most cases just dump graphics primitives once), simplified selection (get list of selected objects or top object), simplified UI refresh of visuals (just modify description), virtually no-code zooming/panning, unified printing (including metafiles and raster images), and so on. Now if you look up you will see that this is a big ambitious project. I am not sure it should be done under Boost umbrella. I am not sure we have available bandwidth to do it. If you think otherwise, please give me your reasons. Of course, it can be downscaled. For example, 2D geometry is universally useful. Even if you donÂ’t want to go multi-platform (most popular choice of developers) you can still find some use for it. Graphics-heavy applications can use G part implementing UI separately for 1-2 platforms they want to support. Simplified UI part can be used to generate simple dialog boxes for different platforms. Different C++ UI bindings can be created for different platforms. It is not multiplatform way, but it is still would be better than most popular "toolkits". Well, what are your thoughts? Discussions of UI are recurrent event in Boost. I saw several proposals for 2D geometry in this mail list. Authors of several GUI toolkits are frequent visitors here. Are we ripe already? Thanks, Eugene

Eugene Lazutkin wrote:
"Aaron W. LaFramboise" <aaronrabiddog51@aaronwl.com> wrote in message news:419EB968.1050508@aaronwl.com...
Aleksey Chernoraenko wrote:
IMO, the best GUI "framework" would be a *set* of separate, specific libraries each of which would provide good abstractions/algorithms in some specific gui-related area:
I think that any new GUI interfaces created that fail to make these items a priority in their design will share the fate of all traditional user-interface frameworks, being inappropriate for modern design, and doomed to obsoletion.
Just to revive discussion about GUI allow me to offer my 2c worth. (Sorry for big post).
Let’s split GUI into two parts: G (2D graphics) and UI (user interface). :-) G can be used without UI: printing, generation of metafiles (e.g., Postscript, SVG) or pixmaps/bitmaps. UI can be used without G, if only stock components are used: simple dialog boxes.
That's the general idea :).
Graphics requires following components to be implemented: canvas, graphics primitives (shapes to describe geometric parameters, attributes to describe visual parameters, clipping facilities), and 2D geometry.
The 2D Geometry (the basics of it, anyway) is common between graphics and UI (e.g. position/size of the components).
User interface requires following components to be implemented: events, windowing, layout facilities, and widgets/controls. Layout requires 2D geometry. Widgets may require all listed components.
I am working on a GUI library in the boost-sandbox (boost/gui). At the moment, it isn't very comprehensive and doesn't have any docs. I have been busy lately, so haven't had chance to work on it. events -- yes (using boost::signal and std::map). windowing -- yes (basic 'frame'; need a 'form' (read dialog box) class). layout facilities -- simple move/resize is supported. (layout managers are an extension that can be implemented on top of this framework). components -- what subset of available controls do we use?
Now we want to make all these components as light-weight as possible for performance reasons. Ideally they should be mapped 1-to-1 to facilities of underlying platform, while preserving platform independence. I don’t think it is productive to walk original Java way and implement all widgets in terms of graphics primitives, nor implement graphics primitives in term of pixel rasterizer.
I entirely agree with this. This is what I am trying to achieve with the library I am working on in the sandbox.
First order of business is 2D geometry. Following stuff is required:
1) Point. Simple 2D entity with X and Y components. In real life at least two versions are required: integral (screen coordinates are integral) and floating point (for precise calculations). Depending of task conversion between them may require rounding off, ceil/ or floor operations.
Also, platforms use integral (Win32) or floating point (Cocoa) values, so it is hard to use a standard representation.
Additional consideration: it may be integrated with more general geometric toolkit, which may implement 2D and 3D points as well as N-dimensional vectors.
I have separated out point (as poisition) and size, causing some heated discussions!
Additional consideration: point should play well with native platform-dependent coordinate.
This is a given. The base types derive from the platform types in my library, so boost::gui::point is a POINT in Win32, NSPoint in Cocoa, etc. I also use library-implemented properties to map the names to standard names.
2) Rectangle. Again, two versions are required. [snip]
Additional consideration: rectangle should play well with native platform-dependent rectangle. There is a slight problem here: two most popular platforms implement rectangles differently. MS Windows keeps 2 points, while X-Window keeps point and size. From my experience 2 points representation is needed more frequently.
I have this as area. The difference in representation is problematic, since it makes writing generic code more complex.
[snip] 6) Vector as some kind of directional entity? Usually I use coordinate for that for practical reasons. I don’t think that there is a big practical difference between vector and point in 2D space. 7) Size. See #6 above.
There is no practical difference, but consider: gui::window mainwnd( gui::point(5, 5)); // what does this do? Is this: * setting mainwnd to be at (5, 5) on the screen? * creating mainwnd with a width and height of 5? gui::window mainwnd( gui::position(5, 5)); // at (5, 5) gui::window mainwnd2( gui::size(150, 500)); // 150x500 Having the two as distinct types makes it easier to see what is going on.
1) Points and rectangles should be implemented platform-independently. It allows achieving predictable performance results on all platforms. Additionally it is easier to use binary input/output to transfer them between platforms because layout is standardized.
E.g., once I implemented rectangles like this (pseudo code):
template<typename T> class Rect : public RectTrait<T>::layout { typedef RectTrait<T>::component_type component_type; // and so on };
On Windows I used Rect<int> and Rect<double> for calculations and Rect<RECT> for platform-dependent interface. Rect<RECT> was based on RECT and was binary compatible with all native functions. Anyway this stuff was hidden usually.
I chose to do: NSRect --> gui::cocoa::area RECT --> gui::win::area RectangleType --> gui::palmos::area where gui::cocoa, gui::win, etc. are where platform-specific details are contained, providing a common interface. This makes it easier to write the platform independant layer. <boost/gui/platform.hpp> is responsible for detecting the operating system+API used. It sets gui::platf to be a namespace alias to the namespace of the selected API. Thus, on Linux/GTK, gui::platf = gui::gtk. This then allows: gui::platf::area --> gui::area There are still some details to work out, and I only really have a working implementation for Win32.
What do we need from user interface?
Graphics can be easily abstracted without big loss of performance. Most common graphics tasks can be automated and done once. The reason is quite simple: foundation is pretty much universal. Unfortunately it is not the case with user interface. All OS vendors regard UI as a major differentiator between platforms. Different look and feel is the minor part of it. Standard set of controls/widgets is different across platforms. Different conventions are used to implement similar things. E.g., hot keys are different, menu layout is different, mouse buttons and click patterns can be different, and so on. Localization rules complicate everything.
Ah, the joys of GUI programming! ;)
Introduction of "special look and feel" is not viable. Just remember unsuccessful Java efforts. Users of respective platforms prefer applications with native look and feel.
I believe the default should be to use the native L&F, but allow owner/custom draw facilities to be built on top of the library.
Given all that it looks like the practical way is to provide a declarative way to describe user interface. (XUL, XAML?) We should be able to combine components (widgets/controls) on 2D surface, define event handling, and layout properties. Widgets/controls can be taken from predefined set of library components, which are mapped to native controls, if possible, or can be custom components.
I was thinking of a Java-style approach: gui::frame myframe( "C++GUI is easy..." ); gui::button yes( &myframe, "Yes" ); gui::button no( &myframe, "No" ); Note: * The use of constructors to create the components (Java-style). This does not mean that the components have to be custom drawn - I use this technique for creating GUIs in Windows without needing the Create/OnCreate creation flow of MFC. * There are no demands on the management of the component objects. The lifetime of the objects is managed by the user and not the library.
This description of UI can be internal (in the program) or external (e.g., in file using some format). External declaration can be replaced without recompiling a program. It simplifies localization, and minor (mostly visual) tweaks. Downside is possible mismatch with program code.
Yes -- how do you map the external file to the components in the program code. Note that I intend on supporting a "form" component. This is similar to what you are describing, I think. Mac, I believe, support forms. Windows supports the form concept as dialog boxes described in a resource file bound to the application at link time.
Each UI object should carry a list of properties, which can be used by layout engine (replaceable component itself) to modify geometry of component depending on window size. This facility should be used for initial layout to take care of different DPI of physical device, and for potential resizing. Some required properties are obvious like size and position of component in some units in some reference coordinate system, and so on. Some properties can be more elaborate like glue in TeX (elasticity, preferred size), which will govern transformation and position of component in different conditions.
It depends on how complex you want to make the library. I agree that size/position information should be available. In order to implement layouts, you would need to get the minimum (preferred) size of the component and alignment (horizontal|vertical) used to adjust a rectangle when resizing. Windows allows you to do resizing of components en mass, which makes resizing complex UIs efficient. Do we support this? How does it port to other platforms? How does this affect the resizing execution flow? I think that the layout architecture should be orthogonal to the UI elements, i.e. we should not impose layout code on the user: class my_frame: public gui::frame, public gui::grid_layout { ... }; The layout managers can then implement "stretchy" component logic as they require.
In order to implement all this we need an engine, which will interpret UI description according to platform-specific rules, and work as intermediary for event processing code, and, possibly, custom painting. Obviously this engine should be customizable with replaceable components.
Sketch above is not sufficiently detailed. For example it doesn’t define how to implement custom component. But I think it gives a preview of what can be done with this approach: true multi-platform support,
available with my code.
simplified creation of UI (instantiate user interface from description),
easy to build using constructors.
simplified painting (in most cases just dump graphics primitives once),
I do not have any graphics code -- I make no assumptions on how this is done.
simplified selection (get list of selected objects or top object),simplified UI refresh of visuals (just modify description), virtually no-code zooming/panning, unified printing (including metafiles and raster images), and so on.
These are not supported in my code as it stands. The zooming/panning code falls into the category of layout managers: how does this work with a drawing application? a text editor? web browser (using an external HTML rendering component?) etc.
Now if you look up you will see that this is a big ambitious project. I am not sure it should be done under Boost umbrella. I am not sure we have available bandwidth to do it. If you think otherwise, please give me your reasons.
I would like to collaborate on a joint effort. The way I see it is to have two project elements: * core -- basic windowing facilities; events; etc. This would be a candidate for adoption into Boost. Benefits: support (ability to test on a large number of platforms, etc.); standardization (C++ needs a decent GUI library as a part of the standard and Boost is the best platform to develop such a proposal). * extension -- advanced components; layout managers; etc. These will be a sort of "proof of concept".
Of course, it can be downscaled. For example, 2D geometry is universally useful. Even if you don’t want to go multi-platform (most popular choice of developers) you can still find some use for it. Graphics-heavy applications can use G part implementing UI separately for 1-2 platforms they want to support. Simplified UI part can be used to generate simple dialog boxes for different platforms. Different C++ UI bindings can be created for different platforms. It is not multiplatform way, but it is still would be better than most popular "toolkits".
Well, what are your thoughts? Discussions of UI are recurrent event in Boost. I saw several proposals for 2D geometry in this mail list. Authors of several GUI toolkits are frequent visitors here. Are we ripe already?
It is about time that C++ has a standard GUI framework. Maybe we can have an offshoot of Boost (and a boost.gui mailinglist) like there is for boost.build, etc. This would allow us to focus our efforts on developing such a library. I see this project as a collaborative effort because of its complexity. Regards, Reece

Hi Aleksey,
Hello,
I'm probably too late and what I'd like to say is too general, but maybe somebody will find the following thoughts useful. There are many GUI frameworks - platform-specific, platform-independent, something in between, but most of them (I'm afraid to say all of them :) have the same problems.
On the one hand they give a user many really good things: windowing, controls, event handling, geometry, drag&drop support, etc... On the other hand they are monolithic - you have to use the *whole* framework, you cannot take and use only one subsystem.
I would like to think that win32gui is close to what you're hoping for. I've put a lot of work in trying to accomplish just that. However, it's not as easy as one might think. I might have failed at some parts. If you're willing to take a look at win32gui, I'd welcome all feedback you or anyone else might have. You also can email me privately (john at torjo dot com).
** general-purpose 2d lightweight geometry and general algorithms ( boost::gui::2d::point, rect, path, ...)
some of it it's there
** painting areas, canvases and painting algorithms
not yet
** events, propagation and handling mechanisms, (event_target, listener, subscribers...)
I would say most of it is there
** windowing (windows, views...)
yup
** layout algorithms (placing visual elements relatively to each other), language to express constrains.
not yet
** widgets, controls, text engine and etc...
yes Best, John -- John Torjo, Contributing editor, C/C++ Users Journal -- "Win32 GUI Generics" -- generics & GUI do mix, after all -- http://www.torjo.com/win32gui/ -- v1.5 - tooltips at your fingertips (work for menus too!) + bitmap buttons (work for MessageBox too!) + tab dialogs, hyper links, lite html

[...] On the one hand they give a user many really good things: windowing, controls, event handling, geometry, drag&drop support, etc... On the other hand they are monolithic - you have to use the *whole*
Hello, John Torjo wrote: framework, you cannot take
and use only one subsystem.
I would like to think that win32gui is close to what you're hoping for. I've put a lot of work in trying to accomplish just that.
However, it's not as easy as one might think. I might have failed at some parts. If you're willing to take a look at win32gui, I'd welcome all feedback you or anyone else might have. You also can email me privately (john at torjo dot com).
OK, I read your article in CUJ, the library looks really interesting but I need to take a closer look at it to be more specific. Thanks, Aleksey Chernoraenko.

On Sat, 20 Nov 2004 11:28:38 +0200 in gmane.comp.lib.boost.devel, John Torjo <john.lists@torjo.com> wrote:
If you're willing to take a look at win32gui, I'd welcome all feedback you or anyone else might have. You also can email me privately (john at torjo dot com).
Other than private email, what is the most appropriate forum for such discussion? Perhaps gmane.comp.lib.boost.user, or is that bad because win32gui is not official Boost yet? For example of what I am thinking of: I tried out your "Multiple frames" example and after selecting SDI mode I find that the main window is created blank instead of containing the sample dialog it is supposed to have. In order to try to figure out why, I added the commented line to the code below in main.cpp, and with that line uncommented everything works properly. Why? else new_view = create_dlg<sample_view>(view_name, window()); view_frame *self = dynamic_cast<view_frame *>(window()); // msg_box(window(), "Continue!"); self->activate(new_view); I compiled everything with the free download command-line version of VC 7.1, which means I am presently limited to non-debug mode build as libcmtd.lib is not supplied with that.

David Harmon wrote:
On Sat, 20 Nov 2004 11:28:38 +0200 in gmane.comp.lib.boost.devel, John Torjo <john.lists@torjo.com> wrote:
If you're willing to take a look at win32gui, I'd welcome all feedback you or anyone else might have. You also can email me privately (john at torjo dot com).
Other than private email, what is the most appropriate forum for such discussion? Perhaps gmane.comp.lib.boost.user, or is that bad because win32gui is not official Boost yet?
I don't know if it'll ever be.
For example of what I am thinking of: I tried out your "Multiple frames" example and after selecting SDI mode I find that the main window is created blank instead of containing the sample dialog it is supposed to have. In order to try to figure out why, I added the commented line to the code below in main.cpp, and with that line uncommented everything works properly. Why?
Sorry - this is a known bug, and I will fix it soon. There are a few more <g>, and I will solve them all at once. Best, John -- John Torjo, Contributing editor, C/C++ Users Journal -- "Win32 GUI Generics" -- generics & GUI do mix, after all -- http://www.torjo.com/win32gui/ -- v1.6 - documentation, bitmap buttons, tab dialogs, lite html

Aleksey Chernoraenko wrote:
Hello,
I'm probably too late and what I'd like to say is too general, but maybe somebody will find the following thoughts useful.
It is not too late. This is a complex topic, and everybody's input is welcome.
There are many GUI frameworks - platform-specific, platform-independent, something in between, but most of them (I'm afraid to say all of them :) have the same problems.
On the one hand they give a user many really good things: windowing, controls, event handling, geometry, drag&drop support, etc... On the other hand they are monolithic - you have to use the *whole* framework, you cannot take and use only one subsystem. My application is based on MapApp and I see nice implementation of general event handlers in other framework but I cannot use it because I cannot rewrite whole application on new framework.
And they also tend to provide their own array, list, string and vector classes, instead of making use of those in the standard library. Not to mention, several provide their own bool! The problem is that the GUI framework needs to use these classes to provide the apropriate facilities. I have chosen (for the GUI library under development in the sandbox - still at the experimental stage) to make use of the STL for containers and Boost.Signals for event handling. If I were to allow you to use your own signal/slot class, I would need some mechnism for registering that so my framework can understand and use it. That means either: [1] templatize the class -- this would move the implementation code over to the headers, making it harder to separate the interface from various platforms and may lead to code bloat. [2] use macros -- this would make the code harder to understand and lead to unnecessarily complex code.
IMO, the best GUI "framework" would be a *set* of separate, specific libraries each of which would provide good abstractions/algorithms in some specific gui-related area:
** general-purpose 2d lightweight geometry and general algorithms ( boost::gui::2d::point, rect, path, ...)
I have designed my core geometry classes (point, size, rect) such that they derive from the native class (e.g. rect derives from NSRect in Cocoa). I am not sure on putting these in a separate namespace (BTW, 2d is an invalid name, it would have to be either _2d, twod, twoD or geometry/geom). There are, in general, two types of GUI objects: [1] struct wrappers -- classes that encapsulate a concept defined in the OS as a struct. The geometry classes belong to this group. These classes should derive from the struct and allow access to that struct. This makes it eay to interoperate with other classes, for example: CPoint pt( static_cast< POINT >( gui::point( 5, 7 ))); This is a pointless example, but demonstrates that these classes can interoperate with other frameworks. [2] pointer/handle wrappers -- classes that wrap concepts defined by the OS using handle types. This includes window, canvas, pen, font and other such objects. I have chosen to provide a conversion to the handle type, allowing interaction with existing code. For example: main_window frame( "Main Frame" ); ::ShowWindow( frame, SW_SHOW );
** painting areas, canvases and painting algorithms
I agree that these should be separate. It should be possible to interact well with existing graphics wrappers as well, e.g. on Windows, allowing you to use MFC CDC, GDI+, DirectX, etc.. This would be used something like: void main_window::draw( canvas c ) { Graphics g( static_cast< HDC >( c )); g.DrawImage( &im, 10, 10 ); }
** events, propagation and handling mechanisms, (event_target, listener, subscribers...)
** windowing (windows, views...)
The event mechanism is tied to the windowing model. That is, the base window (component) is bound to the chosen event handling mechanism. Having said that, you only need to provide a few windowing classes: * component -- provides the basic OS-native window handling (allocates OS resources for the component). This should provide a mechanism for hooking the event mechanism (i.e. subclassing in Windows terminology). * UI-less component -- does not allocate OS resources for the component. This would be used to implement layout managers, etc. * form -- a special window that is defined by an external resource, identified by a specific ID. Note that this covers dialog boxes in Windows and forms in MacOS. Those three classes form the "core" windowing model.
** layout algorithms (placing visual elements relatively to each other), language to express constrains.
** widgets, controls, text engine and etc...
These form an extension to the base framework. It would be useful to have a set of standard cross-platform components (buttons, textboxes, listboxes, etc.) to facilitate portability, however, these do not need to be a part of the "core" framework. Advanced components (tree control, list control, grid control, toolbar, statusbar, etc.) should be separate. The same goes for layout managers and views (Q: do we classify views as layout managers?).
In other words GUI "framework" should have good separation and provide set of useful abstractions, algorithms which I can use separately (more or less) and bind to platform API or some platform-specific already existent "low-level" framework (MacApp, MFC, QT, WxWindows... ). I believe it's possible and I'm not the only one who wants it.
See above. The boost-sandbox code is mainly Win32/64, but contains a mechanism for switching platforms, as well as basic support for Cocoa and PalmOS (i.e. the geometry classes). There are still several open issues: * How do I register a window type in a way that is platform independant, supports built-in components and "common controls" in windows (requiring a call to InitCommonControls(Ex). The problem is that Windows requires a window class to be registered once before a window can be created. Since I am using the constructor to create a window, I cannot use a virtual function to get the name of the class and register it since the vtable is not resolved in the base window class. I don't want to templatize the class for reasons stated above. The solution I have arrived at is to use a static instance of a class that will register itself on construction. E.g.: class frame: public gui::component { static gui::platf::window_class wc; public: inline frame( ... ): component( wc(), ... ) { } }; gui::platf::window_class frame::wc( "CppGUI::Frame", COLOR_WINDOW ); * I am still using Windows-specific code in several places (especially when providing constants). This includes the names of events and window/component frame styles. Regards, Reece

And they also tend to provide their own array, list, string and vector classes, instead of making use of those in the standard library. Not to mention, several provide their own bool!
There is a reason that several provide there own 'bool' - what is the official size of a bool? And more importantly, is it the same size on every platform (ie so that you can serailise on one latform, then deserailise on another) ? Mathew

Mathew Robertson wrote:
And they also tend to provide their own array, list, string and vector classes, instead of making use of those in the standard library. Not to mention, several provide their own bool!
There is a reason that several provide there own 'bool' - what is the official size of a bool? And more importantly, is it the same size on every platform (ie so that you can serailise on one latform, then deserailise on another) ?
sizeof(bool) can vary, but this gives you the storage bits. bool always has exactly one _value bit_, so it can be serialized portably as a char.

And they also tend to provide their own array, list, string and vector classes, instead of making use of those in the standard library. Not to mention, several provide their own bool!
There is a reason that several provide there own 'bool' - what is the official size of a bool? And more importantly, is it the same size on every platform (ie so that you can serailise on one latform, then deserailise on another) ?
sizeof(bool) can vary, but this gives you the storage bits. bool always has exactly one _value bit_, so it can be serialized portably as a char.
Exactly - so thats why every GUI library includes their own definition of bool

Mathew Robertson wrote:
Also, most widget libraries dont allow you to connect a variable to a widget, and still allow user validation. This is because the widget library doesn't callback into the validation code, since it assumes that if it is connected to a widget, then no validation code is necessary.
the Lit Window Library is a layer above a widget library and allows you to do that. It will do validation using rules (predicate like language) and it will allow seamless calls between rules and custom C++ code. http://www.litwindow.com/library Best regards Hajo

Also, most widget libraries dont allow you to connect a variable to a widget, and still allow user validation. This is because the widget library doesn't callback into the validation code, since it assumes that if it is connected to a widget, then no validation code is necessary.
the Lit Window Library is a layer above a widget library and allows you to do that. It will do validation using rules (predicate like language) and it will allow seamless calls between rules and custom C++ code.
Yes, I have been reading the docs this afternoon... Interesting concepts... some ideas are very useful, although I'm not sure that some of the examples are all that relevant... ie the first example (from "How RapidUI speeds up your development work...") where some settings are loaded. The example is invalid as the comparision is being done using operator>> vs. raw implementation code. I am familar with the FOX Toolkit's concept of N+M blocks-of-code for handling events (vs. the concept of NxM blocks-of-code, see http://www.fox-toolkit.org/introduction.html). I am tending to think that Lit still has this problem. Mathew

Mathew Robertson wrote:
the Lit Window Library is a layer above a widget library and allows you
ie the first example (from "How RapidUI speeds up your development work...") where some settings are loaded. The example is invalid as the comparision is being done using operator>> vs. raw implementation code.
Err, sorry? Why is the example invalid because I am using the >> operator? I could have used write_config(config, s) instead. I think you may have missed the point: the operator >> (or write_config) is a generic function and will work with any data type! So while you have to write code for ReadSettings/WriteSettings again for every different actual 'Settings' definition, you don't have to do that if you are using the generic function. You simply *use* (rather than rewrite) write_config instead. Don't mistake the operator>> used in the example for the standard iostream operator >>. The example is not writing the 'Settings' class as a binary blob. The operator >> is implemented by the lit window library and it is not a template. Or did I misunderstand you? Also, regarding the relevancy of the examples and the concept, have you had the time to look at the RssReader tutorial yet? Step 3 and 4 of the tutorial will be especially interesting. Here's the link to step 4 http://www.litwindow.com/lwl/doc/html/tutorial_step_4.html Best regards and thank you for your comments Hajo

----- Original Message ----- From: "Hajo Kirchhoff" <mailinglists@hajo-kirchhoff.de> To: <boost@lists.boost.org> Sent: Tuesday, November 16, 2004 6:42 PM Subject: [boost] Re: GUI Library Proposal for a Proposal
Mathew Robertson wrote:
the Lit Window Library is a layer above a widget library and allows you
ie the first example (from "How RapidUI speeds up your development work...") where some settings are loaded. The example is invalid as the comparision is being done using operator>> vs. raw implementation code.
Err, sorry? Why is the example invalid because I am using the >> operator?
I could have used
write_config(config, s)
instead.
I think you may have missed the point: the operator >> (or write_config) is a generic function and will work with any data type!
The point was that I could also write an operator>> which read the config, into the settings object. What is not clear, is how the cfg object (which has accessor members) can write into the Settings struct. Does Lit parse the header file of wxConfigBase? I just dont see how one object can map data into another object of completely different type, without there being an operator>> (wcConfigBase, Settings) operator (or a variation thereof, such as a member operator). Could you explain this please?
So while you have to write code for ReadSettings/WriteSettings again for every different actual 'Settings' definition, you don't have to do that if you are using the generic function. You simply *use* (rather than rewrite) write_config instead.
Don't mistake the operator>> used in the example for the standard iostream operator >>. The example is not writing the 'Settings' class as a binary blob. The operator >> is implemented by the lit window library and it is not a template.
obviously.
Or did I misunderstand you?
Also, regarding the relevancy of the examples and the concept, have you had the time to look at the RssReader tutorial yet? Step 3 and 4 of the tutorial will be especially interesting.
Here's the link to step 4
http://www.litwindow.com/lwl/doc/html/tutorial_step_4.html
Best regards and thank you for your comments
I'll take more of a look this coming weekend, as I'm not sure I follow the tutorials... cheers, Mathew

Mathew Robertson wrote:
the Lit Window Library is a layer above a widget library and allows you
The point was that I could also write an operator>> which read the config, into the settings object. What is not clear, is how the cfg object (which has accessor members) can write into the Settings struct.
Ah, now I see. Please scroll to the end of the document after this section http://www.litwindow.com/lwl/doc/html/comparison_10x.html#complex_rules "Preparing to use the Lit Window Library". The cfg object accesses the Settings object or any other object through a 'data abstraction layer', a type of reflection mechanism. The "Preparing to use..." section shows you what you have to do for the Settings class definition so that the operator >> knows what to do. A 'data adapter' is basically a map<string, accessor>, mapping member variables of a class to get/set functions.
Does Lit parse the header file of wxConfigBase?
No, it does not parse header files. You have to include a small declaration for the data adapter. See the "Preparing..." text part of the document above.
I'll take more of a look this coming weekend, as I'm not sure I follow the tutorials...
Thanks a lot, I am looking forward to your comments. Best regards Hajo Kirchhoff

Rene Rivera wrote:
attaching an enum to a combo-box, or a string to a text-box. Doing something that maps from the type to the widget automatically given the reflection info of the type is not an easy task as there's more to a variable than just the type which one ends up adding when creating the widget bindings, or at least I did.
Have a look at http://www.litwindow.com/library especially also at the RssReader tutorial step 3 and 4. The Lit Window Library lets you bind a container with an interface that follows STL conventions to a list box. The list box will be filled with the elements from the container. You specify a rule ListBox.Items = Container It also lets you bind the current list box selection to a form. You write a rule ListBox.Current = Form.Details Upon seeing this the generic mediator "RapidUI" will automatically transfer the contents of the currently selected element from the Container to the Form and back again, when a user changes a widget. I am looking for people willing to contribute to the Lit Window Library. Regards Hajo Kirchhoff

David Abrahams wrote:
class_< Derived(Base1, Base2) > is magnificent. You ought to be eligible for a design award.

"Peter Dimov" <pdimov@mmltd.net> writes:
David Abrahams wrote:
class_< Derived(Base1, Base2) > is magnificent. You ought to be eligible for a design award.
You can thank Daniel Wallin for that idea :-) -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

On 11/10/2004 07:52 PM, David Abrahams wrote:
"George van den Driessche" <grebe@bigfoot.com> writes:
[snip]
(a) Reflect C++ types into C++ objects. Each type for which you provide a reflection map will correspond to exactly one property_set object, which would contain a set of property_type_info objects. [snip] (e) Serialise the types, using results of (a). [snip] order to do serialization in that way, you'd likely have to expose an object's guts: its implementation details.
If you could "reflect" all the reference counted smart_ptrs, like shared_ptr, for a class, T, into some class specific structure, say gc_desc<T>, then you could use this for precise garbage collection, AFAICT. Although it does expose the guts (after all, shared_ptr<X>, might be private in T), this is what you'd need to detect cycles. Does this seem a reasonable additional use for (a)?

Larry Evans wrote:
On 11/10/2004 07:52 PM, David Abrahams wrote:
"George van den Driessche" <grebe@bigfoot.com> writes:
[snip]
(a) Reflect C++ types into C++ objects. Each type for which you provide a reflection map will correspond to exactly one property_set object, which would contain a set of property_type_info objects.
[snip]
(e) Serialise the types, using results of (a).
[snip]
order to do serialization in that way, you'd likely have to expose an object's guts: its implementation details.
If you could "reflect" all the reference counted smart_ptrs, like shared_ptr, for a class, T, into some class specific structure, say gc_desc<T>, then you could use this for precise garbage collection, AFAICT. Although it does expose the guts (after all, shared_ptr<X>, might be private in T), this is what you'd need to detect cycles.
A "faster" way to infer cycles for pointers could be done with a bit more information on the shared_ptr. If you keep a set of object memory spans (heap address, and class sizeof) for all shared instances you can find all shared_ptrs that fall within those shared instances. With that you can build the reference graph to detect the cycles.
Does this seem a reasonable additional use for (a)?
Seems like overkill to me :-) -- Especially give how compiler intensive generating the reflection information is. -- -- Grafik - Don't Assume Anything -- Redshift Software, Inc. - http://redshift-software.com -- rrivera/acm.org - grafik/redshift-software.com - 102708583/icq

Rene Rivera wrote:
A "faster" way to infer cycles for pointers could be done with a bit more information on the shared_ptr. If you keep a set of object memory spans (heap address, and class sizeof) for all shared instances you can find all shared_ptrs that fall within those shared instances.
See sp_collector.cpp.
With that you can build the reference graph to detect the cycles.
Except that you can't. :-) struct X { std::vector<Y> v_; }; If Y has shared_ptr instances that refer back to X, this is untraceable, because the tracer doesn't know that it should follow the pointer inside the std::vector.

On 11/11/2004 12:40 PM, Peter Dimov wrote: [snip]
With that you can build the reference graph to detect the cycles.
Except that you can't. :-)
struct X { std::vector<Y> v_; };
If Y has shared_ptr instances that refer back to X, this is untraceable, because the tracer doesn't know that it should follow the pointer inside the std::vector.
Couldn't each stl container which contains (or might contain) a shared_ptr also be reflected (e.g. v_'s presence in X recorded in gc_desc<X> )? In this case, the cycle-finder could iterate through each Y in v_ to find any cycles.

Larry Evans wrote:
If you could "reflect" all the reference counted smart_ptrs, like shared_ptr, for a class, T, into some class specific structure, say gc_desc<T>, then you could use this for precise garbage collection, AFAICT. Although it does expose the guts (after all, shared_ptr<X>, might be private in T), this is what you'd need to detect cycles.
sp_collector.cpp finds shared_ptr instances with a memory scan. That's not the problem. The problem is following other owning pointers. Or, in more general terms, the problem is that different reflection clients need different things to be reflected.

"Peter Dimov" <pdimov@mmltd.net> writes:
Larry Evans wrote:
If you could "reflect" all the reference counted smart_ptrs, like shared_ptr, for a class, T, into some class specific structure, say gc_desc<T>, then you could use this for precise garbage collection, AFAICT. Although it does expose the guts (after all, shared_ptr<X>, might be private in T), this is what you'd need to detect cycles.
sp_collector.cpp finds shared_ptr instances with a memory scan. That's not the problem. The problem is following other owning pointers.
Or, in more general terms, the problem is that different reflection clients need different things to be reflected.
Sounds like what I've been saying in a different thread. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com
participants (14)
-
Aaron W. LaFramboise
-
Aleksey Chernoraenko
-
Caleb Epstein
-
David Abrahams
-
David Harmon
-
Eugene Lazutkin
-
George van den Driessche
-
Hajo Kirchhoff
-
John Torjo
-
Larry Evans
-
Mathew Robertson
-
Peter Dimov
-
Reece Dunn
-
Rene Rivera