GUI library - another one

Hello It seems that the idea of adding a medium-complexity GUI library to boost is popular, but that there are widely varying opinions on how it should be done. I've written a first draft of a library that fulfils most of my expectations. It's available at http://www.turn.co.za/david/gui. It supports two platforms (Win32 and GTK2), and four user interface elements or widgets (window, label, button, text-entry). The design is such that it is extremely easy to support new platforms or widgets. These are my expectations of how a good C++ GUI library should behave: 1. It should be a consistent yet thin wrapper around the platform's native functionality. 2. It should degrade gracefully in the absence of certain features on the platform. 3. It should be extensible through the factory pattern. 4. It should couple loosely with user code - this means no inheriting from an abstract Window class. 5. It should do what the user (programmer) expects, whenever possible (i.e. no leaky metaphors). 6. Widgets that contain things should behave like containers, whenever this is practical. 7. It should not use device-specific units like pixels, wherever this is practical. and finally 8. It should be extremely easy to use. The library at the link above fulfils most of these requirements. But it's not perfect. There are some interesting design choices. In many respects the most difficult design work is still to be done (list boxes, menus, drawing areas). However, the code that exists has the great advantage of working. I'd like to know what the boost community thinks before proceeding. Regards David Turner

Hi
I'm not religious; and it would be quite easy to have Qt as a back-end. Bear in mind that this is supposed to be a well-designed API that wraps *existing* implementations like GTK and Qt. The fact that Qt is written in C++ and GTK is written in C has absolutely no bearing. Implementation detail. And, just for the record, I think the (C) GTK API is better-designed than the (C++) Qt API :^). That's why my personal choice was to implement GTK first. Regards David Turner

"Neal D. Becker" <ndbecker2@verizon.net> writes: | Not to start any religious war here, but gtk is based on C. Use gtkmm then. -- Lgb

David, I'm in full support of your effort. Just a small comment: int main(int argc, char* argv[]) { window w = create_window(); w->title("Example window"); why is window implicitly a pointer?
and finally
8. It should be extremely easy to use.
Adn maybe 9. It should be possible to create worm-like games in it, where student need to draw the worm by moving pixels or something around :-) br Thorsten

hi
In fact, window is defined thus: typedef boost::shared_ptr<window_base> window; The reason is that widgets are always reference-counted. The alternative would have been to make window a pimpl class, with the impl being reference counted. However, since I wanted to use the factory pattern to firewall the implementation of widgets, I would have to have my widgets on the heap anyway, so I just made widget a shared pointer to the WDT (whole damn thing). Does that make sense? :-)
Ha ha, yes. Regards David Turner

On 3. Mar 2004, at 17:01, David Turner wrote:
In fact, window is defined thus:
typedef boost::shared_ptr<window_base> window;
I think this can easily lead to retain-cycles, as widgets will often need a pointer to their window, which must be a weak pointer, as there are otherwise no ways to get the reference count of the window down to zero, without first having to remove all the widgets who keep a reference to their window. But maybe the widgets explicitly use window_base instead of window?!? -- http://www.diku.dk/hjemmesider/studerende/duff/

Hi
That is, of course, up to the implementer. In fact, my Win32 implementation makes use of a boost::weak_ptr back to the container, to accommodate the auto-sizing mechanism. The GTK implementation has no need of this. It's all an implementation detail. If you have a look at the source code, you'll notice that widget_base declares a member returning a pointer to an undefined implementation class. I'm toying with the idea of exposing this on a per-platform basis. Regards David Turner

"David Turner" <dkturner@telkomsa.net> wrote in message news:30009.165.165.239.17.1078329677.squirrel@webmail.telkomsa.net...
yeah its ok, I was thinking that seing window and not window* could confuse some.
Just to be sure, I'm not kidding. I assume a C++ gui lib should be possible to use to learn C++. Writing small games by moving pixels around is a great way to practice, much more fun than making a menu or pop-up box. br Thorsten

Just to be sure, I'm not kidding. I assume a C++ gui lib should be
At 06:57 PM 3/3/2004, Thorsten Ottosen wrote: possible
See "You can Do It! A Beginner's Introduction to Computer Programming" by Francis Glassborow, 2004. ISBN 0-470-86398-6. He has beginning C++ students drawing stuff in a window within the first few pages. --Beman

On Wed, 3 Mar 2004 18:11:54 +0200, "Peter Dimov" <pdimov@mmltd.net> wrote:
window_ptr w = create_window(); or shared_ptr<window> w = create_window(); Is the former too Hungarian? Tom -- C++ FAQ: http://www.parashift.com/c++-faq-lite/ C FAQ: http://www.eskimo.com/~scs/C-faq/top.html

Tom Widmer wrote:
<shrug> I don't need the _ptr suffix to repeatedly remind me that a type is a pointer (I can remember _that_ much), but I don't actively hate it either; it's just dead weight. (Hungarian is 'window pw = create_window()', and I use that fairly often.) I like shared_ptr<window>, but the Real World(tm) will just invent their own typedefs. It's too much typing and it takes away the illusion that the actual pointer type is "abstracted out".

"David Turner" <dkturner@telkomsa.net> wrote in message
I would add: 9. (really 0 in my view) It should use an extensive resource description schema or language (for widget properties, layouts and relations) that is either interpreted at run time or (though I like it less) compiled into code transparently to the user. This resource description should probably be XML-based. An alternative for a lower-level GUI library is to _support_ such description rather than to implement it (be designed to interoperate well with different implementations). The danger here IMHO is that without a resource technology built in, the trend over time will be to add enough facilities to the library so it can function without one. In this case, why not use Qt and save oneself the trouble? The rationale behind making the resource schema central in the design is that it allows to decouple the look-and-feel aspects from the code and support graphic design part of the UI development with a suitable graphic design tool. Forgoing code generation on the other hand, or at least making the generated code a strictly transient entity, avoids the fallacy of CASE systems which generate the initial boilerplate and leave the programmer high and dry with lots of ugly unmanageable code. One of course should be able to develop an application without using a graphic tool (especially while the library is in development and one is just not avqailable). But writing an XML description by hand is not any harder than hardcoding numerous create_button() and set_window_position() calls in C++, and the text should look nicer and be more maintainable. 10. It should not attempt to provide its own abstraction of 2D graphics. Some level of portable graphics capability would certainly be necessary but it should be kept to a minimum (your requirement #1 supports this I believe). A portable 2D graphics API is worthy of its own library. Also, speaking of (7) - in many cases it is rather hard to express dimensions in device-independent units such as points or millimeters. Display resolutions are still low enough to require us to consciously consider whether to use 1 pixel wide or 2 pixel wide lines, manually prepare icons of different resolutions instead of resizing the bitmap, etc. The "named units" approach may help. ...Max...

Vladimir Prus wrote:
// create a xml archive, deserialize w widget w = create_widget("description.xml"); // case 1 window w2 = cast<window>(w); grid g = cast<grid>(w2->at(0)); button b = cast<button>(g->at(0, 0)); b->clicked_signal = my_callback; // case 2 button b = cast<button>( w->find_by_name("my_button") ); b->clicked_signal = my_callback; // case 3 button b = cast<button>( w->find_by_path("my_grid/my_button") ); b->clicked_signal = my_callback; // case 4 // do nothing, a Python function is automatically attached to clicked_signal // Python should be able to see the widget as an object // Nontrivial

Peter Dimov wrote:
[...]
button b = cast<button>( w->find_by_name("my_button") ); b->clicked_signal = my_callback;
Aha, and that requires that all functionality is implemented as standalone functions. This might be okay for clicking buttons, but for custom widgets (e.g. text editor), I'd still prefer subclassing. Oh, so we need XML to be able to store not only some predefined widgets, but also custom widgets. And to edit those custom widgets, we'd need GUI editor which can understand plugning. We're getting close to duplicating QDesigner ;-)
This sounds like a best solution. At least for dialogs, Python's performance should not matter. - Volodya

Vladimir Prus wrote:
Are you sure that you do? The equivalent of b1->clicked_signal = my_callback_1; b2->clicked_signal = my_callback_2; b3->clicked_signal = my_callback_3; would require three new 'button' subclasses. Even if the above requires three brand new functions to be written (which is rarely the case, I usually boost::bind existing functions), it's still less code.

Hi
How do you propose to write custom widgets in a cross-platform manner? If it's by building them up out of other widgets, then aggregation is the way to go, not inheritance. The current library makes no allowances for custom widgets, precisely because they require a little too much chumminess with the implementation. Regards David Turner

"Peter Dimov" <pdimov@mmltd.net> wrote in message news:00de01c40145$22818020$1d00a8c0@pdimov2...
Tell that to Lisp programmers :-P No, of course I agree with you. But if you are willing to embed JavaScript, or Python, then a decision to embed C++ is not that much of a leap. Just don't implement business logic in the embedded code and use it strictly for UI behaviors that are hard to express in declarative language. If you are opposed to embedding of script into declarative descriptions as a matter of principle, this logic certainly does not apply. But most people don't seem to be. Personally I dislike the idea of compiling resource descriptions into imperative code and am willing to sacrifice quite a bit of embedding capability, moving such code snippets into library extensions instead. But it is not a matter of principle for me and I can see why some may disagree. ...Max...

"David Bergman" <davidb@home.se> writes:
Well, I'd hope there would be a user-readable/writable format that could be used as a front-end. You can go a long way in plain text: +--------+ | button | +--------+ * radio * buttons [ ] checkbox you get the idea, I hope. -- Dave Abrahams Boost Consulting www.boost-consulting.com

Max Motovilov wrote:
That a XML resource description is needed almost goes without saying, but why interpret or compile it? The GUI library should just be able to deserialize its objects from such an XML file (or any other archive, for that matter). widget w = create_widget("description.xml");

"Peter Dimov" <pdimov@mmltd.net> wrote in message news:00ac01c4013e$6d63e580$1d00a8c0@pdimov2...
That is an option, but I'd have to think for a while to offer a coherent theory why it may not be sufficient. In the meanwhile, I'll just name a capability that can be trivially implemented with a centralized run-time schema repository as opposed to a decentralized collection of objects created by de-serialization of such schema: support for the "ID" tag. That is, being able to write: list_widget lw = find_named_widget( "ListOfNames" ); or something to the same effect. Doing it as: list_widget lw = root->find( "EmployeeData" )->find( "PersonalDataPage" )->find( "ListOfNames" ); doesn't cut it because the actual hierarchy of windows may be an implementation detail determined by look-and-feel requirements and totally irrelevant to the code in question. Of course, the named objects can register themselves in a centralized directory, but this already places us on the path of intepreting at least _some_ information contained in the original schema... ...Max...

Max Motovilov wrote:
list_widget lw = cast<list_widget>( root->find_by_name("ListOfNames") ); works for me. David's current implementation doesn't attach names to widgets but that's easily correctable. A global find_by_name is too limited; it doesn't let you resolve collisions, for example. If you only want a centralized repository, just use a global 'root' variable.

Hi
I agree that this is a Good Idea.
This is much better from a design point of view, and in fact the library I posted is well on its way to supporting just this: take note of window_base::spawn. The one problem I forsee with automatic deserialization is connecting the signals: because C++ does not really have an adequate metadata system, it will be necessary to provide some kind of signal-to-function dictionary. There might be a good metaprogramming framework that can achieve this; I don't know. Possibly judicious use of the factory pattern.
I've been thinking about that. On the one hand, you Really Need a drawing-area widget, but on the other hand, it just about doubles the size of the library. I like your way of thinking, but how to integrate this unnamed graphics API nicely with the gui library? There should be implementation-dependent hooks for this.
Yes, I agree. As things stand, I use pixels to specify the padding around windows and between grid elements. Everything else is auto-sized and arranged. I think if the implementation provides reasonable defaults for padding, etc., then there will be no practical problems. Regards David Turner

On Wednesday 03 March 2004 12:35 pm, David Turner wrote:
IMHO, this need not be in the GUI library to start with so long as it's clear that it can be added. A GUI library, just like a Sockets or XML library, is a huge undertaking. Many libraries addressing these areas have been started, but have not been finished due to "planned feature bloat", i.e., the authors and reviewers wanted too much out of the first version of the libraries. Don't be afraid to say "that's version 2" to a feature; bonus points if you have a paragraph or two in a "Future Directions" document that explains how such a feature fits into the library. Doug

Hi
Excellent point. DrawingArea is hereby removed from the pending widget implementations list :-). What I expect is that individual platforms could provide extensions or hooks for more elaborate features, such as OpenGL widgets. It's about time to start deciding what should be included, I think. At present, we have Window Label Button Grid Text-entry I plan to add List Selection Menu Tab-set / Notebook And possibly Divider With these tools, I think the requirements of a great many C++ project could be satisfied. Anything glaringly obvious that I've left out? Is a multi-line text input control necessary? Regards David Turner

On Wed, 3 Mar 2004, David Turner wrote:
Selection
Just to be sure I understand: this is equivalent to a "combo box" or "radio group", I presume?
With these tools, I think the requirements of a great many C++ project could be satisfied. Anything glaringly obvious that I've left out?
Perhaps a tree control, but again that's pretty specific and could be delayed.
Is a multi-line text input control necessary?
Perhaps a very simple one should be provided. You might think of an application-oriented approach to selecting features. Maybe version 1 should have enough widgets to build a spreadsheet program, then version 2 might have enough to build a web browser, and version 3 could perhaps be powerful enough to build a scientific visualization app. with OpenGL. It's all about managing expectations :) Doug

"David Turner" <dkturner@telkomsa.net> wrote
It's about time to start deciding what should be included, I think. At present, we have
[widget list snipped]
With these tools, I think the requirements of a great many C++ project could be satisfied. Anything glaringly obvious that I've left out?
How will be data values assigned to UI elements? Will it be possible to pass a container directly to listbox? Would one be able to define bidirectional "transformations" between UI and data structures and if, what will be granularity? How about input data validation? Can it have support of Mediator GOF pattern? /Pavel

"David Turner" <dkturner@telkomsa.net> wrote in message news:000001c40145$ea9e7180$6300000a@onyx...
I did not find the documentation in your ZIP and can't really spend enough time right away to read through the code. So I responded to your requirement list rather than commented on the implementation. You do seem to gravitate to hardcoding the window creation code in your examples though :(
I've been thinking about that. On the one hand, you Really Need a drawing-area widget,
No, not really - it is usually thought of as a "must have", but it really isn't. Lots of form-based GUI applications are written in VB without issuing any GDI calls, or at least any that are necessary to implement the application functionality. HTML-based GUIs are an even better example; there to have a drawing area capability you have to embed applets or ActiveX controls.
Of course, there you will need a concept of drawing area widget that exports a thinly wrapped graphics context. Even better, you can provide a way of exporting a graphics context for all, or most widgets (though that might prove harder to implement in a portable manner - sub/superclassing Windows controls for the purpose of changing their look is an ugly endeavor). If you're pressed for time (who isn't?), you can just provide the graphics_context class encapsulating a platform-dependent handle/pointer. Getting it from the widget (or widgets) is portable but from that point the user is on his own. This should be sufficient for a surprisingly large class of applications. Besides, there are portable 2D graphics libraries out there already, even if not quite up to Boostish level of modernity. I have been designing one 8-9 years ago and it looks like it's still for sale, but I'm not gonna be plugging it here :-)
You'll still want to have those "metric" (or English :) ) dimensions - they are very, very convenient when you create professional looking graphic designs... provided you can reliably query the screen DPI. Perhaps a 3-tiered system of dimensions will be universal enough: NNN pt + NNN px + NNN fil (borrowing a term from TeX). I like points better than inches or millimeters, but that's just personal preference. ...Max...

Hi
Ah, yes, fair point. No documentation :-). I'll make that a priority.
the implementation. You do seem to gravitate to hardcoding the window creation code in your examples though :(
Yes, true. The examples are intended to show how easy it is to set up a basic UI, though.
Very true. I've changed my mind about the drawing area. Regards David Turner

I was reading these posts to try and stay in touch with as much as possible. What I'm trying to say here is that my GUI expertise sucks. The sub-thread regarding window pointers (i.e. shared_ptr) rang a wee bell and an item below produced a nice resonant <bong>.
Is there no overlap between the "reactive object" requirements and what you are touching on here? I have effectively applied the ActiveObject pattern in the limited GUI work that I do and this has taken care of the routing of signals-to-functions. In the ActiveWorld (TM) I would have expressed this as message-to-object, i.e. when you say "function" you are actually referring to a specific method you wish to call on a window instance? Maybe the active object approach is interesting for its asynchronous messaging. Maybe it becomes more so when you consider that it brings thread control along with it. If the implementation (in-progress) is not interesting then maybe the pattern is? Or am I way off base? Otherwise I like your goals. Personally think there is an unfortunate difference between a GUI library that provides for quick development of "typical" applications and a library that tackles movement of pixels in a spritely fashion. No reason there couldnt be two complementary libs I s'pose. Good luck. Note: I have successfully overlaid ActiveObject templates/classes onto pre-existing GUI applications. It works.

At 12:35 PM 3/3/2004, David Turner wrote:
Maybe, maybe not. I've been burned a number of times in the past by pixel defaults for padding, line widths, etc. The defaults were reasonable based on the most common hardware. But some of my customers paid the money for much higher resolution hardware, and the defaults were not good there. Meanwhile another customer did an in-vehicle system with a very lo-res display. Same software. But because the hardware was so different, the usual defaults were useless. Might have been OK if the defaults were somehow tied to the particular device. --Beman

Hi
Well, yes, that's what I meant. Presumably different hardware implies different back-end library. What seems clear to me at this point is that there should be a mechanism to allow other libraries to modify or extend the implementation on a particular platform. My idea is this: there is currently a shared header file for each platform that basically defines the implementation class. What if that header were available by including, say, <gui/platform.hpp>? It would then be possible, at least on a platform-by-platform basis, to extend the implementation with new widgets. For example, somebody might write an OpenGL widget that interoperates with the GUI library. It would have to be ported to each target platform, but then that's not much worse than the current state of affairs :-). At least there would be an existing framework to hook into, which would be reasonably similar on the different platforms. Regards David Turner

"Max Motovilov" <max@yymap.com> wrote
XML adds very little except troubles (IMHO). Enhanced RTTI can be implemented directly in C++, either using: - macros approach (GUI framework called VCF does this) - having class description similar to one found in Boost.Python. AFAIK Daniel Wallin is refactoring this functionality into general purpose library. Builders/customization software/etc than has direct access to always valid GUI information.. /Pavel

"Pavel Vozenilek" <pavel_vozenilek@hotmail.com> wrote in message news:c255kj$k7t$1@sea.gmane.org...
XML adds very little except troubles (IMHO).
Not in my HO. Would you value automatic creation of property dialogs/forms from the database metadata using XSLT? Stylesheets?
Builders/customization software/etc than has direct access to always valid GUI information..
...and that is another reason to have the resource description available at run-time without having the widget implementations expose all necesasry information explicitly (that's in response to Peter Dimov though...) ...Max...

On Wed, 3 Mar 2004, Peter Dimov wrote:
I think the right answer here is to have an XML library that supports reflection. I've been toying with the idea for a while (with no time to write the actual library...) but the basic notion is to create an XML "view" of an existing object that plays well with pure XML data (i.e., elements with no corresponding concrete class). But this is all out of scope for a GUI library :) Doug

"Peter Dimov" <pdimov@mmltd.net> wrote in message news:038301c40150$3f870040$1d00a8c0@pdimov2...
Looks to me like this is all about tradeoffs. A runtime UI data repository (DOM-based, perhaps) simplifies widgets (well maybe not, it is all a matter of the right wrapping of the interfaces after all - what is easier, writing marshalling code or using property mechanism to expose your essential data?) and promotes flexibility: with serialization-based approach your RAD tool may have to re-create all or large part of application's windows every time a change is made, same applies to user-customizable UI elements (menu editing, stylesheets etc.). Also, the ID tag example may be extended to allow XPointer/XPath addressing at which point you'll have to give up the serialization approach for sure :) On the other hand, XML marshalling is much more lightweight, it may not even require a DOM parser (you'll still want an XSLT engine to support stylesheets, but at least this way you can invoke it in a child process). For a Boost library this is a big advantage since we'll have to provide a DOM parser as part of Boost otherwise. In fact, compiling XML to source code provides another benefit aside from C++ code embedding: it can be implemented fully outside of the library. You can pretty much generate C++ code with XSLT and with good library primitives/syntax the actual "compiler" may turn out to be small enough to be easily customizable by users. And this way we are not tied to a specific engine either because XML parsing is never even required at run time. It just so happens that in _my_ mind the benefits of DOM outweigh the liabilities. Therefore I am rather skeptical about adding a GUI library to Boost: one compact enough to be there will not be enough things to enough people to get wide acceptance. Yet I'd be glad to participate in design/development of an open source GUI library that would promise to significantly improve upon the likes of Qt. ...Max...

Max Motovilov wrote:
Hmm, it looks like you have a DOM hammer and you see a GUI nail. ;-) A widget graph can be represented as a DOM but from where I sit it's simply not needed. No, my RAD tool does not recreate anything (note present tense here), when you change (the equivalent of) a label's text it just calls (the equivalent of) l->set_text. It only serializes (to XML, binary, or whatever the archive du jour is) when I save the widget graph to a file. With an appropriate query engine, you should be able to do XPointer/XPath on a widget graph directly if you feel so inclined, although I'd probably prefer a visitor approach. Anyway, I have tried the serialization approach and it works. I haven't tried a DOM-based graph representation (probably because I haven't grown accustomed to the DOM hammer yet), so I can't say how well it would perform.

"Peter Dimov" <pdimov@mmltd.net> wrote in message news:040801c4016a$abe26a80$1d00a8c0@pdimov2...
Hmm, it looks like you have a DOM hammer and you see a GUI nail. ;-) A
I disagree, and won't head down the path of mutual psychoanalysis ;-)
not needed. No, my RAD tool does not recreate anything (note present tense here),
Duly noted. Is it something I can look at?
when you change (the equivalent of) a label's text it just calls (the equivalent of) l->set_text.
Which means it knows about SomeInterface::set_text(). Will it handle a custom widget with a custom property just as smoothly? How much effort on part of a custom widget developer is required?
appropriate query engine, you should be able to do XPointer/XPath on a widget graph directly if you feel so inclined,
That won't give me a pointer to the run-time instance of a widget, would it? perform. HTML GUIs. We can argue all night what "well" is, but you have to agree it's been tried very extensively. ...Max...

Max Motovilov wrote:
No, sorry.
I have to admit that you do raise some interesting points. A widget graph can indeed be given a (restricted) DOM interface (it does not need to be implemented as a generic DOM graph) so that a XPointer/XPath engine can traverse it. The UI editor/builder can use an XSD schema to enumerate a widget's properties and perform validation. XSLT can rewrite a GUI graph.

I think this is a great idea - my interest would probably be atypical in that I would love to have a cross-platform system on which to hang a 2D/3D scientific visualization library.
I'm not so sure about this requirement - from an efficiency standpoint in applications such as image processing it is best to be able to discriminate between integral and continuous screen scaling. As far as the demo program : int main(int argc, char* argv[]) { window w = create_window(); w->title("Example window"); w->contain(create_button(w, "Hello, world!")); wait_for_signal(w->delete_signal); } why not : int main(int argc, char* argv[]) { window w("Example window"); // more consistent with button syntax below w.add(button("Hello, world!")); // no need to have w be a pointer? w.wait_for(delete_signal()); } or something like that. Matthias ------------------------------------------------------------------------ --------------------------- Matthias Schabel, Ph.D. Utah Center for Advanced Imaging Research 729 Arapeen Drive Salt Lake City, UT 84108 801-587-9413 (work) 801-585-3592 (fax) 801-706-5760 (cell) 801-484-0811 (home) mschabel at ucair med utah edu

Matthias Schabel wrote:
Many C++ people like shallow copy things to explicitly have a pointer-like syntax. I, personally, can happily tolerate either. For an apples to apples comparison, window w("Example window"); should be compared with window w = create_window("Example window"); Finally, w.wait_for( delete_signal() ); just introduces a redundant top-level tag class and a corresponding redundant window_base overload.

Shrug. I'm not a GUI person, in large part because every time I look into it, I end up deciding that it's far more work to learn how to use than the benefits would justify. A boost-supported cross platform GUI would definitely go far in addressing the issue of not wanting to invest time learning something which is largely tied to a single platform. But what I'd really like to see is a system that allows one to accomplish conceptually simple things in a correspondingly simple way, with sensible default behavior of any aspects which aren't explicitly specified and a minimum of exposed implementation details to contend with. While window may very well be implemented as a pointer, I don't see how that fact should be relevant to the user of the library (other than, I suspect, historical antecedents). Of course, I understand that I'm an atypical programmer in that the bulk of my code is written solely for my own use or the use of other scientists rather than end users, and a GUI would be nice but is nonessential.
I would be willing to sacrifice added complexity of implementation to have a more intuitive syntax. Unless I'm reading this wrong, what wait_for_signal(w->delete_signal) is trying to say is that w should wait for a generic delete signal - that is, delete_signal isn't really something that belongs to the window type but is instead an abstract directive to a window (or button or widget or whatever) to delete itself. What it actually says to me, on reading it, is that the main program is waiting for a signal from w to quit running. Anyway, bear in mind that this is all coming from a computational physicist with no real experience in GUI programming who'd love to see something simple and intuitive appear. ------------------------------------------------------------------------ --------------------------- Matthias Schabel, Ph.D. Utah Center for Advanced Imaging Research 729 Arapeen Drive Salt Lake City, UT 84108 801-587-9413 (work) 801-585-3592 (fax) 801-706-5760 (cell) 801-484-0811 (home) mschabel at ucair med utah edu

Hi
I agree 100%. Simple things should be done in simple ways. I have no problem with using the following syntax: window w("my window"); label l("Some text"); w.contain(l); The only real "gotcha" here is that w is a copyable type that refers to a shared resource - you don't get a new window by copying an existing one. I'm not sure how well this plays with the user's expectations. That's why I preferred pointer syntax initially (so that the idea stays in the user's mind that he's using a reference type).
Er... I don't really see how you could arrive at that interpretation. To me, it's quite clear: wait_for_signal(). Which signal? W's delete_signal. In an earlier incarnation of the library, I had this: w->wait_for_close(); There are several problems with this, however, which should be obvious. On the whole, I prefer wait_for_signal. Regards David Turner

"Peter Dimov" <pdimov@mmltd.net> writes:
Me too.
http://news.gmane.org/find-root.php?message_id=%3cuel05uq5p.fsf%40boost%2dco... shows a way to make the first syntax a little easier to produce. -- Dave Abrahams Boost Consulting www.boost-consulting.com

At 11:13 AM 3/3/2004, Matthias Schabel wrote:
I really took an instant dislike to the original demo code. Matthias' "why not" version is much more to my taste. The "why not" version seems more like C++. The "demo" version seems like something left over from the C days. My own interest in a Boost GUI library would be for pretty simple applications and for teaching C++. Maybe a few medium complexity apps if the GUI requirements weren't too hard to meet. Now if such a GUI could also handle more complex apps, fine, but only if there is no impact on the simple "hello, world" level applications. Even the "why not" version seems overly complex compared to a console iostreams "Hello, world". Why not just: winout << title("Example window") << button("Hello, world!") << wait_for(delete_signal); I'm not necessarily pushing that exact approach, but just pointing out more C++-like alternatives. --Beman

Beman Dawes <bdawes@acm.org> writes:
[snip]
Now if such a GUI could also handle more complex apps, fine, but only if there is no impact on the simple "hello, world" level applications.
Even the "why not" version seems overly complex compared to a console iostreams "Hello, world". Why not just:
winout << title("Example window") << button("Hello, world!") << wait_for(delete_signal);
I'm not necessarily pushing that exact approach, but just pointing out more C++-like alternatives.
If it is so simple that it does nothing more than can be done with simple input and output streams, then what is the point in having it at all? -- Jeremy Maitin-Shepard

At 09:57 PM 3/3/2004, Jeremy Maitin-Shepard wrote:
That's the point of the abstraction. To hide complexity ("A full-blown GUI") behind an apparently simple facade ("a window stream" or "a window object" or some other apparently simple abstraction). Questions to ask of a GUI aren't just how well and easily does it do complex tasks, but also how well and easily does it do simple tasks? --Beman

Beman Dawes wrote:
I had a feeling some people might have this reaction. I don't mind either syntax (although wait_for is certainly not going to be a member of the window class). Since the majority of people seem to be either in the "don't mind" or "why not" categories, I'll change the syntax to be more like the "why not" example. The only real problem with "why not" is that gui widgets have shallow copy semantics.
That's my initial goal. I want to keep it as light-weight as possible.
As I pointed out in another post, stream-like syntax can be implemented outside of the framework of the gui library. I'd rather do it that way, if at all. Regards David Turner

Hi Thorsten wrote:
Because it's surprising to the user (I think). More to the point, there is a very real problem with creating popup windows. Remember that the window acts as a factory for all other widgets, including popup (child) windows. If I were to use the "why not" syntax, I would have to pass in the owner window as the first parameter of the constructor, as in: window w; button b(w, "Click here"); w.contain(b); Now consider creating a popup window. The natural syntax is: window w; window p(w); But now I've invoked the copy constructor of p, which isn't what I wanted. The way to make it work properly is to force new windows to be constructed with a title: window w("Example Window"); window p(w, "Popup Window"); This is probably the "best" approach, but it still leaves some room for user error. Regards David Turner

"David Turner" <dkturner@telkomsa.net> wrote in message news:30013.165.165.239.17.1078386042.squirrel@webmail.telkomsa.net...
more surprising than hiding the type of window?
Hm...maybe I don't understand why it has to be that way?
why can't we say window w; w.add( button( "Click me" ) ); (*) or window.add( new button( "Click me" ) ); ? br Thorsten (*) I can imagine how this could work with a clonable class hierarchy. It must be possible for an object to register itself as a child of a parent window within the w.add() function. That function could first create a clone heap-allocated of the argument (to get polymorphism) and then add that pointer to its list of children.

Thorsten wrote:
Because it's surprising to the user (I think).
more surprising than hiding the type of window?
Perhaps. At any rate, I'm busy changing the implementation to be more conventional.
As I explained in an earlier post to Peter Dimov, there are technical reasons why this isn't possible. Widgets have to be rooted in an owning window, and it's not possible to transfer widgets from one window to another. Therefore, button has to take an owner-window parameter in its constructor. There is a precedent for this: look at the W3C DOM. The syntax I'm currently considering would make it: window w("Example Window"); w.contain(button(w, "Click me")); The inner w seems redundant at first, but bear in mind that the button isn't necessarily going to be contained directly in the owning window. A more usual case would be: window w("Example Window"); grid g(w, 2, 2); g.contain(button(w, "Click me"), 1, 1); w.contain(g); I could even make it: window w("Example Window"); w.contain(w.button("Click me")); But I think that's pushing it...
window.add( new button( "Click me" ) );
?
This is even more problematic... who now owns the button? Regards David Turner

"David Turner" <dkturner@telkomsa.net> writes:
Sure, though I would never call the function "add". I'd be looking for declarative DSELs like: window("Warning: now entering twilight zone") [ text_field("my favorite color is:"), button("OK") | button("cancel") ] Cheers, -- Dave Abrahams Boost Consulting www.boost-consulting.com

-----Original Message----- On Behalf Of David Abrahams
I've got a library that works a lot like this. The code might not be much use to boost since it is all win32, but my experiences with the syntax might. My version of the above would look something like: +( "my favorite color is:" | push_button(on_ok)*"OK" & push_button(on_cancel)*"Cancel )*"Warning: now entering twighlight zone" This would create a window that looked something like: -----Warning: now entering twighlight zone----- | | | my favorite color is: | | | | ----- ---------- | | | OK | | Cancel | | | ------ ---------- | ----------------------------------------------- The unary '+' operator creates a "group" box from an expression. '|' puts the first operator on top of the second '&' puts the first operator in front (horizontally) of the second push_button is a widget that must have a function object in its constructor '*' sets the text of a window

On Thu, 04 Mar 2004 11:32:24 -0500, David Abrahams wrote:
I like this approach. I can see how the expression in the "[...]" can be an abstract structure that is only converted into concrete widgets when passed to a "real" window factory, and that opens up all sorts of possibilities for reuse of GUI design patterns. widget_ast common_buttons(button("OK") | button("Cancel")); window("Window 1")[ text_field("Hello"), common_buttons ] window("Window 2")[ text_field("Goodbye"), common_buttons ] It also gives a really rather neat way of supporting multiple concrete widget sets: widget_ast demo_widgets(/*...*/); gtk_window("gtk window")[demo_widgets]; // specifically GTK+ widgets qt_window("qt window")[demo_widgets]; // specifically QT widgets It isn't immediately obvious how to bind actions to the various widgets - it doesn't seem sensible for it to be done at the AST level since you wouldn't generally want all OK buttons to perform the same action... Anyway, I was just adding my support for a less procedural approach to constructing GUIs. phil -- change name before "@" to "phil" for email

David Abrahams wrote:
As usual, David is right ;-) Look at some of the GUI implementations for Haskell (it is legite to mention Haskell now after FC++ has entered the Boost scene ;-)) They use expressions, which are converted to GUI elements through monadic transitions. I love the notion of *only* dealing with (abstract) expressions when constructing things, and then having it come alive at some point, such as when the expression is attached to a main window. That way, one can more easily serialize/deserialize whole GUI trees, and avoid carrying around "ifdefs" in the GUI expressions. It is a bit similar to the Bridge Pattern applied in the Java AWT library, where all GUI components have peers doing the dirty work, but I would prefer an even more lose connection, through (1) GUI Syntax on one hand and (2) GUI Interaction on the other. Losing the wrapper luggage, we could focus on proper expressions for GUI components and write (dynamic or precompilation) converters from XUL or any other XMLish specification onto that expression language. Then, it is "just" a matter of (monadically) blow some life into the expressions, via std::vector<std::string> occupations; gui::gui_toolkit g; // The implementation, corresponding to David Turner's "window" // Certain people do not like 'list' being reused ;-) // The iterators are saved, but not traversed for now. // 'occupationList' is just an expression, holding the "frozen" iterators gui::list occupationList(occupations.begin(), occupations.end()); g.add(occupationList); // This is where the list come alive, and the iterators are traversed One question is whether Model Objects should be attached to the GUI expressions or the live GUI components? If attached to the former notions, they will have to be frozen, and then populated by the GUI components. Yes, there is a transaction problem here... /David

"David Turner" <dkturner@telkomsa.net> wrote in message news:30067.165.165.239.17.1078392630.squirrel@webmail.telkomsa.net...
ok, if you say so.
[note: just one little stupid question more :-)] Why can't window::container be like window::contain( const button& b ) { b.set_owner( this ); add(b ); } button::set_owner( window* w ) { owner_->remove( this ); owner_ = w; } ? br Thorsten

Hi Thorsten Ottosen wrote:
It's not always that simple. In particular, on the Win32 architecture, changing ownership amounts to DestroyWindow(hwnd); hwnd = CreateWindow(TEXT("BUTTON"), label.c_str(), WS_CHILD, 0, 0, new_owner->get_hwnd(), 0); and from that point on things start to get complicated. So I neatly avoided said complications by drawing a line and saying, "on this side, widgets don't change owners". I think it's an acceptable limitation. Regards David Turner

"David Turner" <dkturner@telkomsa.net> wrote in message news:30062.165.165.239.17.1078414261.squirrel@webmail.telkomsa.net...
Ok, I should have stated it was pseudo code.
yeah, I hate the win32 API.
Still, you could let set_owner() be called only once and throw something if its done twice. br Thorsten

"Thorsten Ottosen" <nesotto@cs.auc.dk> wrote in message news:c27ip1$i78$1@sea.gmane.org...
Ummm.... what's wrong with SetParent() ? http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui... ...Max...

Max wrote:
Ummm.... what's wrong with SetParent() ?
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui...
Doesn't change the owner. http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwui/html/... There is no facility to change the owner. I tried SetWindowLong, but that doesn't work :->. Obviously it's stored in an internal table somewhere. It's a bit of a bugger that owned windows are automatically destroyed with their owners... Regards David Turner

Beman Dawes wrote:
A 'window' with reference semantics is a pointer. But this is not the important issue here, see below. David Abrahams wrote:
He later added:
And clarified that:
Douglas Paul Gregor agreed:
I'm solidly behind the proposals to use a DSEL for describing GUI elements. It's the right level of abstraction for the task.
In my opinion, this approach, while enticing, is misguided. What makes it dangerous is the consensus that is being built around it. Please allow me to present the opposite point of view. A GUI DSEL that masks the underlying architecture can do more harm than good across all programmer skill levels, and, with all due respect to Beman, a stream-based DSEL can be even more damaging, especially to novices (its intended audience). What is the most important task of a Hello World program? It must teach the programmer the fundamental principles of the underlying language or library. In our case, given a GUI architecture that does not support unowned/free widgets and clearly distinguishes between ownership and containment, a Hello World program must clearly communicate these principles to the user. A stream-based DSEL can be even more deceiving, it not only masks this important principle, but also establishes a false analogy with respect to stream I/O, and can lead a novice programmer to believe that "C++-like" equals "stream-based". It is also important to show that the on_delete member of a window is a plain ordinary boost::signal that can be manipulated independently of its window owner, and that the only thing that wait_for_signal has in common with GUI is that it automatically avoids one particular form of deadlock by starting the message loop when invoked from the same thread that is supposed to fire the signal. The other important principle that GUI programmers will inevitably need to learn, earlier or later, is that appearance and logic must be kept as separate as possible. (Just ask anyone that has been programming active Web sites.) In our domain this means that we must drop the E from the DSEL and concentrate our efforts on supporting the use case where the GUI appearance is described by a _separate data file_ that is not embedded in the C++ code. We can afford to do that, because GUI building is not a performance-critical task. I have done GUI design in C++ code and believe me, it's a fundamentally flawed approach. ;-) The compile-link cycle can drive you mad. There are actually two Hello World programs, one that builds the GUI by hand and hence needs to map closely to the underlying architecture in order to 'teach' it by example, and another, that simply reads a GUI description from an external resource (XML is popular these days). We are trying to cram these two introductory programs into one. This is not needed, and can be harmful to both.

Hello Peter Dimov wrote an excellent post to which I can only say "Hoor, hoor!" (which means the same as "hear, hear", only it's a little less understated than the English ;-)). I think the primitives that appear on-screen should map as directly as possible to the C++ constructs that represent them. Most importantly, their lifetimes should be the same. This means, for example, that the window should not disappear automatically just because the user clicked on the little "X" in the title bar. That action is properly represented as a signal - a notification of the user's desire to have the window closed. What actually happens after the signal is generated is up to the programmer. I've tried to make explicit the fact that the lifetime of the program as a whole is governed by a (possibly quite complicated) boolean condition. Thus instead of, say, MFC's DoModal() method, we have the more generic wait_for_signal construction, or wait_for_bool_condition: gui::util::boolean_condition time_to_close; void do_exit() { time_to_close = true; } window w("Example"); w.contain(button("Exit", &do_exit)); w.delete_signal().connect(&do_exit); wait_for_bool_condition(time_to_close); The gui C++ objects are not abstract representatives of the _properties_ of the widgets, they represent the widgets themselves. A property representation/DSEL is perfectly possible, it's just outside the scope of what I'm trying to achieve. I also agree with Peter that making the appearance part of the code is (apart from trivial cases) a fundamentally flawed approach. Better is to implement some sort of serialization schema a la Glade XML. Again, this is outside of the scope of the gui library proper. There is one issue that I think would benefit from some serious debate, because there is a reasonable case to be made for both sides:
On the whole, I think the fact that there should be ownership semantics in a GUI library is totally counterintuitive. It took me a long time to "know" in a visceral sense the difference between an Owner and a Parent (in Windows parlance). It still doesn't make sense in many ways. I agree with David Abrahams that this sort of detail should be hidden away from the user. Metaphors shouldn't leak; Donald Norman's advice applies equally to programmers designing interfaces for other programmers :-). On the other hand, I'm not sure that we should be encouraging programmers to copy-paste elements between windows. Two windows aren't necessarily implemented the same way. Why should their elements be compatible? The idea of the window as the entry-point to the implementation, and as the factory for all other elements, is quite appealing. And of course there are the implementation efficiencies ;-). http://www.w3.org/DOM/faq.html#ownerdoc At the end of the day, the strongest argument for encouraging the owner-window model is the practical one. Thus if I were forced to concede that practical issues should not make a difference to the design, I must conclude that the owner-window model is not the right one. I'd like to hear some more comments about this, from both sides. In the mean time, I'm implementing a free-widget version of the library, which I'll release later tonight as concept-3. Depending on which way the discussion goes, the first testing release can branch off from either concept-2 or concept-3. Regards David Turner

Hi Concept release 3 is available for download. Windows binaries will be available tomorrow morning. This version implements free/non-owned widgets. http://sourceforge.net/project/showfiles.php?group_id=103008 Regards David Turner

Peter Dimov wrote:
How can a cross-platform GUI library not mask the underlying architecture? ...
I agree with this. GUIs are not streams. ...
The reason that this is true in traditional GUI environments is that there is a tremendous amount of housekeeping and overhead in even very simple interfaces. It makes sense to isolate this code because there is so much of it that has very little to do with the logic of your program. The truth is, however, that the appearance of an application has a great deal to do with its logic. Changes in a program's logic will almost always change its appearance. If you can automate the largely redundant bookkeeping behind a GUI all you really have left is expressing the relationship between your program's logic and its appearance. This is done with a DSEL.
But then you still have to define the relationship between your program and this external data file. If your logic changes you have to change your C++ code and the external file. Many mistakes that could have been caught by the compiler will be delayed until runtime. For comparison what if in Spirit you had to put your EBNF in an external file instead of embedded in C++?
My goal with the GUI library I've made is that you only need to know C++ to use it - I don't want our programmers to have to waste their time mastering the ins and outs of MFC - I've already suffered for them :). Again, I don't see how any platform independent library can "map closely" to the underlying architecture. Brock

Hi On Sun, 2004-03-07 at 21:10, Brock Peabody wrote:
This is definitely beside the point. It may make sense to lay out the GUI with a DSEL, and it may make sense to use a data file. I'm not interested in tackling that problem (directly), and I don't think it's the business of the hardware abstraction layer to present one or another interface. The HALs job is to be as close as possible to the hardware - but no closer. This GUI library is, by and large, a hardware abstraction layer. In many ways, it's comparable to boost::thread or boost::filesystem: it represents the underlying primitives directly, but in such a way as to be (a) much easier to use in terms of housekeeping, and (b) safer in terms of reducing programmer errors. Fancy frameworks can be built on top of it.
The devil is in the details, as they say. In fact, almost all platforms that have a GUI support more or less the same primitives: windows, buttons, text-entry boxes, menus, selection boxes, list boxes. The abstract representations of these can be mapped very closely indeed to the underlying implementation without any significant impact on portability. I think there is a threshold where the underlying implementation changes from being dead-simple to being a nasty, bloated hack that's difficult to follow and dangerous to maintain. The trick is to sneak in just under that threshold, while still keeping the interfaces abstract enough to be unsurprising. Have you had a look at the current interface? I think it's very unsurprising. From a newbie perspective, anyway. Regards David Turner

On Behalf Of David Turner ...
I agree with that. Without an HAL type library anyone wanting to implement a fancier interface would have to do it practically from scratch for every platform they wanted to target.
That's good news.
Yes, and I think that we will be able to create a lot of useful software with this level of abstraction. No matter where you draw the line though there will be some people who will feel that the interface doesn't give them enough control.
Have you had a look at the current interface? I think it's very unsurprising. From a newbie perspective, anyway.
Not yet but I will! If your library has abstracted all the basic primitives it will be easy to put a DSEL on top of it. Brock

David Turner wrote:
Looks very promising! 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? 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) ) { // ... } Have you considered the 'on_delete', 'on_change' naming scheme for signals (events)? It seems more GUI/RAD-like. 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'.

Hi Peter
Looks very promising!
Thanks :-).
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.
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).
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

David Turner wrote:
Well, the assumption is that we all will know that on_* is a signal, so there'd be no need to explicitly tag it as one. 'on_click' and 'on_change' seem more natural to me compared to 'clicked_signal' and 'changed_signal', and the on_* naming seems more consistent. It's a minor point, of course.

David Turner wrote:
This might invoke some screaming: I would love to have a GUI library that could wrap .NET's Forms (using Managed C++.) I know that Boost is supposed to be a library for standard C++, but there has been room for pragmatism to accomodate compiler limitations. I just wondered if there could be a tiny little room for this particular "limitation" of C++ ;-) Maybe one should start a list for "Boost in Managed C++," which could host .NET Framework interactions as well? I might be the only one actually using Boost for Managed C++, but a list of one is better than a list of none... /David

"David Bergman" <davidb@home.se> wrote in message news:200403031650.i23GoINF021225@milliways.osl.iu.edu...
You might want to wait a bit till Longhorn beta becomes widely available. IMNSHO it is just too early to start doing GUI development in .Net in earnest since ASP.Net was hogging most of Microsoft's attention up to now. Besides, CLR will start supporting templates of some sort and maybe some of the more ridiculous restrictions on relationships between managed and unmanaged classes will be removed. ...Max...

David Turner wrote:
I can't help asking -- what's "medium-complexity"? I'm not a GUI programmer, but these are things I wanted to implement at moments: - a configuration dialog (several tabs with some options in each) - an application to show a program graph (and another one for parse tree) - drawing a diagraph (two axes and several data series) Supposedly, the first should be doable. What about others? They'd require a fairly complete 2D layer.
3. It should be extensible through the factory pattern.
What do you mean?
4. It should couple loosely with user code - this means no inheriting from an abstract Window class.
So, the code to implement graph drawing would have to be freestanding function that takes window as parameter. What does it buy? - Volodya

Hi
Good design, for one thing. What business does a window have knowing about graphs? A window is a window is a window. Same for a drawing surface. I've seen too many 3000-line CMyDialog: public CDialog classes to buy the reuse-is-inheritance argument. If you _really_ want to create a CMyWindow class, you can always use aggregation. Regards David Turner

David Turner wrote:
So, if I want to create a widget for drawing graph, I'll have to write: void draw_the_graph(window w, ....) { ..... } void handle_click(window w, ....) { // Add new vertex } void handle_right_click(window w, ...) { // show vertex properties, if mouse points // to a vertex } window make_graph_widget() { windows w; w.on_draw = &draw_the_graph; w.on_mouse_click = &handle_click; w.on_mouse_right_click = &handle_right_click; return w; } ? What are the chances that handle_right_click can be reused anywhere else, is it really independent from GUI, and isn't this too complex a solution? Note that I buy the idea of non using inheritance for dialogs, to a certain degree. It just seems that for more complex cases this won't work as nice.
If you _really_ want to create a CMyWindow class, you can always use aggregation.
In the case above, I'd have to assign to all the signal handlers in the constructor. Ok, I think I have live with it, so it's not so elegant. - Volodya

Vladimir Prus wrote:
Slim, but possible.
is it really independent from GUI,
No, but irrelevant.
and isn't this too complex a solution?
No. The alternative solution is comparable in complexity, and as soon as you add another graph widget that has different left or right click behaviors, or make w change its appearance dynamically on response to a combo box cb (by just assigning different drawing functions to w.on_draw in cb.on_change), you'll see why the event-based model is superior. It's not a new invention, just look at Delphi.

Peter Dimov wrote:
and isn't this too complex a solution?
No. The alternative solution is comparable in complexity,
Well, except for impicit *this pointer, which makes member function a bit easier to write.
Good point. Okay, if I ever get to implement my graph drawer and the proposed library will be mature enough, I'll see how this approach works out.
It's not a new invention, just look at Delphi.
Last time I tried, a click on event created a method linked to that event. Ah... nothing prevents me to implement 'on_draw' as member functions bound to the signal. Yes, that's definititely similiar. - Volodya

Me and Daniel Walling have been toying some with a gui library approach where the user would build the gui trees using a DSEL. Something like this: void clicked_ok(button::clicked_event e) { /* .. */ } void clicked_cancel(button::clicked_event e) { /* .. */ } int main() { window w("my gui"); gadget my_gui = + vgroup() + "Buttons below me!" + hgroup() + button("OK") [ button::clicked = &clicked_ok ] + space() + button("Cancel") [ button::clicked = &clicked_cancel ] - hgroup() + button("Maybe") [ button::clicked = &clicked_maybe ] + space() + button("Foobar") [ button::clicked = &clicked_foobar ] ; w.set_gadget(my_gui); w.show(); /* ... */ } which would produce a gui like this: +---------------------------+ | Buttons below me! | | | | +----------+ +----------+ | | | OK | | Cancel | | | +----------+ +----------+ | | +----------+ +----------+ | | | Maybe | | Foobar | | | +----------+ +----------+ | +---------------------------+ of course the functions would be boost::function and possible to boost::bind to member functions. The expressions within the []-operators should of course be a list where it's possible to assign callbacks for more than one event. One important requirement I see with a gui lib is to be able to easily create dynamic guis. Where sub-trees can be exchanged, removed or added on the fly. -- Arvid Norberg David Turner wrote:

Hello all! New version of the circular_buffer is available. It can be found at http://groups.yahoo.com/group/boost/files/circular_buffer_v3.6.zip Release notes: - fixed bug regarding not destroyed elements - requirements for element types were changed to CopyConstructible concept - changed debug support classes - no dynamic memory allocation needed - changed debug support for invalidated iterators: assertion raised also when used iterator which points to the overwritten element - added allocator& get_allocator() /* NONCONST */ {...} method - added functionality to set_capacity() and resize() methods - changed circular_buffer_space_optimized constructor signatures Regards Jan __________________________________ Do you Yahoo!? Yahoo! Search - Find what you�re looking for faster http://search.yahoo.com

Hi Jan, you should repost your mail so it don't appear under the gui-thread. br Thorsten
participants (25)
-
Allan Odgaard
-
Arvid Norberg
-
Beman Dawes
-
Brock Peabody
-
David Abrahams
-
David Bergman
-
David Turner
-
Douglas Gregor
-
Douglas Paul Gregor
-
Gregory Colvin
-
Jan Gaspar
-
Jeremy Maitin-Shepard
-
Joel Young
-
larsbj@gullik.net
-
Matthias Schabel
-
Max Motovilov
-
Neal D. Becker
-
Pavel Vozenilek
-
Peter Dimov
-
Phil Richards
-
Russell Hind
-
scott
-
Thorsten Ottosen
-
Tom Widmer
-
Vladimir Prus