I'm opening a new thread here to have a correct subject. First of all: The term "composite" may be misleading or even "wrong" in someone's eyes. If this is so after reading this post, please find another name, and I would gladly use this.
I wrote in another thread: > I'm working on a change that Fl_Scroll would not have its scrollbars > as children in its Fl_Group - IMO a _valuable_ change. But OTOH this > could affect user code, where someone relies an these two additional > children of the group. > > BTW: There's a working version that you can check out at: > > <http://svn.easysw.com/public/fltk/fltk/branches/branch-1.3-composite> > > Please read the CHANGES.branch file for more info. Feedback would be > welcome. The current version has some printf debug statements > active, I'll fix that soon. Fabien Costantini replied: > For Fl_Scroll, I read what you propose and I'm 100% favorable to the modification. Fine. > Then, I had a look to the modifications concerning the composite aspect. > and had a look to the sources. > > This is not what I would call a composite because it seems to lack the capacity for a widget to iterate on all its children. > I think we may regret this critical absence of functionality. > > A composite permits tree walking without having to distinguish groups from leaves, the latter one having no child as the main difference. Well, "composite" is only a working title, maybe I could have used another word. Please don't associate anything like "composite pattern" or anything else with this branch or my work. I came along this line, because I had a concrete problem: Fl_Group::clear() could access deleted widgets when checking, if the widget was already deleted (it tested the parent_ member, and Fl_Widget's d'tor reset this to 0, just for this reason (and maybe more)). That's what was documented as a "kludge" in the official FLTK 1.1 docs. And since I found that it really crashed my program, I decided to investigate... (see STR 1894). Then I made my own patch to try, if it would work, and it crashed at program exit in fluid. It turned out to happen in a destructor, but I didn't know, where, and didn't have the time to look further. Eventually, when I found the time, I found the bug. It was another "kludge" in Fl_Value_Input's constructor: This is from the sources: // FLTK widget for drag-adjusting a floating point value. // Warning: this works by making a child Fl_Input object, even // though this object is *not* an Fl_Group. May be a kludge? <<<*** [...] Fl_Value_Input::Fl_Value_Input(int X,int Y,int W,int H,const char* l) : Fl_Valuator(X, Y, W, H, l), input(X, Y, W, H, 0) { soft_ = 0; if (input.parent()) // defeat automatic-add ((Fl_Group*)input.parent())->remove(input); input.parent((Fl_Group *)this); // kludge! <<<*** I thought that this is enough to start doing something and generalize my attempts to fix bugs and remove "kludges" from the code. My attempt is to use the current FLTK code and design and extend it with _minor_ changes to consolidate, what is already available, and to enable widget designers to do something useful without deriving widgets from Fl_Group. Matt pointed out that there was another "strange" widget: Fl_Input_Choice is derived from Fl_Group, but should better be derived from Fl_Input, because it extends Fl_Input. I had a similar (or almost identical) problem with a widget in my real life application. > As I saw it when we discussed, the widget would have all the children tree related api, thus permitting to any widget to handle widgets it may not know at creation time for instance. No, that was not intended. I think that this is what Bill wanted to do with FLTK 2 (every widget is also a group, or the group is the base class of all other widgets), but this would be a major redesign of FLTK, and it was rejected for FLTK 2. I don't want to go the same way, see below. > Then the Fl_Group would only provide a concrete version (with draw() implemented) of the pure class Fl_Widget. > > But in the composite svn branch, we can have Fl_Widget having as parent an Fl_Widget but not explicitly real subwidgets, what I mean by this is that it would be quite difficult for a widget to discover and handle its children dynamically as a group would do as there is no children() iteration api. Again, this is not intended. I don't want to redesign the FLTK core. All I want to achieve is that the current widget and "subwidget" construction can be done reliably. The Fl_Group widget shall stay as it is. > We shouldn't understimate the flexibility that further the real composite pattern, i.e: you get a widget or a group as an input parameter of a widget iterating based function transparently. This would be FLTK 4.0, I guess ;-) > I also think about the fundations of future potential version of tree browser widgets here :-) Interesting thing, but another path. I would like to commit my minimal changes and small extensions to FLTK 1.3 shortly, when some more things are implemented. > Sorry for this long message, Sorry for this also very long reply > but I think we should take this opportunity as maybe the only one we will have to add such an internal change for the Fl_Widget. After it is made we will be more or less slaved to compatibilities issues, so we should consider all possibilities/options now ;-) I think that this step is simply consolidating and bug fixing with minor changes, most of which won't be visible outside the FLTK core. With some exceptions. I wouldn't have started a branch for development on my own, if I had intended to redesign the FLTK widget structure completely, like you seem to suggest (no offense intended, but this is _really_ another project). Back to my implementation and my plans: The major point was the implementation of this feature that a widget removes itself from any parent group on destruction. It was not as easy as one may think, and it was tried before and reverted, because it didn't work. My implementation works now in my own FLTK 1.1 application since several months without problems. :-) I extended my work when I saw the problems with Fl_Value_Input. Maybe I must explain, what happened with this kludge: After setting the parent_ pointer to point to a Fl_Valuator instead of a Fl_Group, my code to remove the input (sub-)widget from its group crashed, because the parent was not a group, and the supposed children_ member variable was a giant number, and the child array_ pointers pointed nowhere... You can imagine, what happened. My fix in my first implementation was to add a destructor and revert the constructor kludge in the destructor. It's still in the currently submitted code, but it is subject to be deleted again, because the new parent() features take care of this. As you can see, there are lots of printf statements in there. I needed them to verify that my code did what was intended. As I wrote before, I don't plan to redesign the FLTK core. Therefore, my work does only intend to be able to have so called "subwidgets" in another widget, and still to be able to handle all events easily and correctly. The problem of Fl_Input_Choice and my own widget was that the widget extends (with its subwidget) beyond its own coordinates that are visible to the group. Therefore, the subwidget wouldn't get any events, unless it would be entered into the parent group of the main widget. That's what I did with my implementation. But then, when a widget is destroyed and has embedded subwidgets, strange things can happen, and the subwidget may be deleted twice (once by its parent group, and once by the automatic destructor like in Fl_Valuator's input subwidget). And furthermore, if the subwidget does not have a closed chain of parent() widgets, it can't become the Fl::pushed() or Fl::belowmouse() widget, because the existing code (in Fl_Group::handle()) would make wrong assumptions and set the parent widget to be the pushed() or belowmouse() widget. I saw this with my experiments with Fl_Scroll, but I need further testing to verify that it is all as I assume now. The next addition would be another simple (trivial) virtual Fl_Widget method: virtual int Fl_Widget::event_inside() This would be called from Fl::event_inside(Fl_Widget*) to test, if a widget should get an event. With this method, a widget can claim to get events for the "scattered" areas of all its subwidgets by redefining the event_inside() method. Think of this: +--------------------++---+ | Fl_Input || X | X = Fl_Box +--------------------++---+ [please use a fixed font to view the "grapics"] [ I copied this from a previous thread with the same topic. ] If Fl_Input is a child of a group, but the box "X" is not a child of any group, the box won't get any events, because Fl::event_inside() checks the boundaries of the Fl_Input widget (and any other children), but for the group, the box's area is empty space. Thus, the box doesn't get any events. Now, if Fl::event_inside() "asks" the Fl_Input widget, if an event is inside of it, and this event is really inside the _box_ widget, then the Fl_Input can return 1 and get all events for the box widget. It must then deliver the events to the box widget in its own handle() method. This is some work, but IMHO it is worth it. It should be simplified, however, as Matt suggested in another thread. I'll look at this, too. Now, when the box widget gets e.g. an FL_FOCUS event, it would maybe call take_focus(). After this, it is the Fl::focus() widget. However, as it is now, the group's code checks if the focus widget is inside the group, and if not, it sets the focus widget to be the group widget. But right now, it seems _not_ to be within the group, because Fl_Widget::contains() returns 0, since the box's parent does not point to a group widget (within the parent group). My implementation allows this to work, even if the parent_ of the box would be the Fl_Input widget. [And this is the reason, why Fl_Value_Input uses this parent "kludge"!] The Fl_Scroll widget has the same problem: Either it must put the scrollbars in its own Fl_Group (then they count as children and must be sorted to the end now and then), or it must handle the events for the scrollbar widgets. But then we need the new parent() feature to support all these nice methods like contains(), window(), delivering events directly to the Fl::pushed() or Fl::belowmouse() widget and maybe more. However, the Fl_Scroll widget is less complicated, because (a) it is derived from Fl_Group (b) the scrollbars don't extend beyond the Fl_Group's widget area. Another application of these scattered widget areas might be the idea to put the widget label(s) in own widgets. Maybe we could then also deliver events to the label widgets, although they are not members of the parent group ... Last but not least, let me explain what I wanted to say with this term "composite": A widget can have a certain number of "named" subwidgets and manages these subwidgets by itself. Best example: Fl_Input_Choice, as written above. But it can also (additionally) be derived from Fl_Group and have "anonymous" children, managed by the Fl_Group. Fl_Scroll would be such a widget: it has two fix scrollbar subwidgets and an arbitrary number of children, managed by its Fl_Group. BTW: FLTK 2 does it this way, but didn't change the parent() method. IMHO, this should either be done, or we could define a parent_widget() method that would be used in the FLTK core (then there would be more code to change, but IMHO it's doable). Wow, that's really been long now. I hope that someone could follow my arguments, and I would like to read your comments. But please note that the modifications are not yet ready, and that this is *not* intended to be a major rewrite of FLTK core functions. It should be seen as a logical extension and a necessary consolidation without big impact on user code. Otherwise we could not include it in FLTK 1.3, IMHO. Regards Albrecht _______________________________________________ fltk-dev mailing list [email protected] http://lists.easysw.com/mailman/listinfo/fltk-dev
