FLTK 1.3 Tab in tile widget refresh issue of the tab widget when resizing the tile widget

233 views
Skip to first unread message

Andr EBERSOLD

unread,
Aug 3, 2013, 8:58:02 AM8/3/13
to fltkg...@googlegroups.com
Hello,

With fluid, I designed a basic user interface based on Tile, Tree and Tab widgets :
 
     Tile Widget
  ----------------------------------------------------
  |                     |                                       |
  |  Tree            |      Box                           |
  |                     |                                       |
  |                     |                                       |
  |---------------------------------------------------|   <- move the horizontal border
  |   Tab widget                                         |
  |                                                             |
  ----------------------------------------------------

When the user moves the horizontal tile border, the Tab widow is not properly refreshed (the background of the tabs with the titles contains weird lines).
The whole tab is only refreshed when I select a new tab entry or when I resize the main window.

Could someone tell me if this is a bug or If I missed something ?

Thanks,
Andre E.
Capture d’écran 2013-08-03 à 14.56.09.png

Greg Ercolano

unread,
Aug 3, 2013, 2:39:47 PM8/3/13
to fltkg...@googlegroups.com
I would suggest viewing the Tab widget's properties, and change the
Style -> Box to one of the options that ends in "_BOX" (eg. FLAT_BOX)
so that it has a background that can be drawn.

I'm guessing it was maybe changed to NO_BOX or something that ends
in "_FRAME" which prevents it from having a background at all, causing
artifacts in the 'invisible' region that doesn't get redrawn.

Andr EBERSOLD

unread,
Aug 3, 2013, 3:03:41 PM8/3/13
to fltkg...@googlegroups.com, erco_...@seriss.com
Hi thanks for the reply.

The style of the Tab already ends up with _BOX . I checked playing with the value but still have the same behavior (_BOX style)

 

Greg Ercolano

unread,
Aug 3, 2013, 3:51:49 PM8/3/13
to fltkg...@googlegroups.com
On 08/03/13 12:03, Andr EBERSOLD wrote:
On Saturday, August 3, 2013 8:39:47 PM UTC+2, Greg Ercolano wrote:
On 08/03/13 05:58, Andr EBERSOLD wrote:
>      Tile Widget
>   ----------------------------------------------------
>   |                     |                             |
>   |  Tree               |      Box                    |
>   |                     |                             |
>   |                     |                             |
>   |---------------------------------------------------|   <- move the horizontal border
>   |   Tab widget                                      |
>   |                                                   |
>   ----------------------------------------------------
>
> When the user moves the horizontal tile border, the Tab widow is not properly refreshed

        I would suggest viewing the Tab widget's properties, and change the
        Style -> Box to one of the options that ends in "_BOX" (eg. FLAT_BOX)
        so that it has a background that can be drawn.

        I'm guessing it was maybe changed to NO_BOX or something that ends
        in "_FRAME" which prevents it from having a background at all, causing
        artifacts in the 'invisible' region that doesn't get redrawn.

Hi thanks for the reply.
The style of the Tab already ends up with _BOX . I checked playing with the value but still have the same behavior (_BOX style)

    OK, yep, just tried a test, and I could easily replicate your problem.

    Strange; seems like the Fl_Tabs widget is not drawing its background
    even if we give it a box type. Seems like it could be a bug, not sure, will check.
   

    Meanwhile, an easy workaround is to use a group in place of the tab widget,
    make that group have e.g. a FLAT_BOX, and then put the tab widget into that.
    You can do this by highlighting tab widget (and all its children), hit ^X (cut),
    then select the tile, create a group, position the group into the tile with the exact same
    xywh coords the tab had, set the box type to FLAT_BOX, then hit ^V to paste your tab
    group into the new group, and position the tab widget inside of it.

    That seems to work; here's a sample .fl file that seems to work for me.


# data file for the Fltk User Interface Designer (fluid)
version 1.0300
header_name {.h}
code_name {.cxx}
Function {} {open
} {
  Fl_Window {} {open
    xywh {410 93 600 565} type Double visible
  } {
    Fl_Tile {} {open
      xywh {5 8 590 547}
    } {
      Fl_Tree {} {
        xywh {10 10 300 355}
      }
      Fl_Box {} {
        label box
        xywh {310 10 285 355} box BORDER_BOX color 45
      }
      Fl_Group {} {open selected
        xywh {10 365 585 190} box FLAT_BOX
      } {
        Fl_Tabs {} {open
          xywh {10 370 585 185} color 46
        } {
          Fl_Group {} {
            label Aaa open
            xywh {40 395 555 145} hide
          } {}
          Fl_Group {} {
            label Bbb open
            xywh {35 395 550 145}
          } {}
        }
      }
    }
  }
}
    

Greg Ercolano

unread,
Aug 4, 2013, 1:10:08 AM8/4/13
to fltkg...@googlegroups.com
On 08/03/13 12:51, Greg Ercolano wrote:
> seems like the Fl_Tabs widget is not drawing its background
> even if we give it a box type. Seems like it could be a bug, not sure, will check.

OK, looked into this a bit.

The way Fl_Tabs is currently implemented, the area behind and to the right
of the tabs is never drawn by the tabs widget, regardless of the tab's box() type.

This means that area is 'invisible', always seeing through to the parent,
which in this case is the window. Or the tile's background (if it has one).

The tab widget's box type is used to draw the child's background only,
ie. the 'card' for the currently selected 'tab'.

So if the tab widget is resized in such a way that it doesn't cause
the parent to redraw (such as this tile resizing), that area behind
the tabs will leave behind digital garbage.

I tried setting the tile widget's box() type to FL_FLAT_BOX, thinking
that it would redraw its background when a child is moved, but that's
not the case, the tile widget only draws its background when the entire
tile is resized, not its children. This is probably to prevent "flicker"
in single buffered windows. (But perhaps it should redraw itself if
the parent is double buffered, where flicker would be impossible)

A lot of this behavior is probably rooted to the days when double buffering
was not always supported by hardware, and it was more desirable to prevent
flicker in single buffer cases.

Some clarification in Fl_Tabs' docs might be needed here.
Fl_Tabs currently says this about how drawing is handled:

"The selection color of [the selected child] is used to color the tab,
while the color of the child determines the background color of the pane."

..I think that last sentence should continue with "using the box type of the
tab widget." because that is what the code currently does.

And further elaboration to document that the area beneath and to the right
of the tabs are 'see-through', and is never drawn, regardless of the widget's
box() type.

Ian MacArthur

unread,
Aug 4, 2013, 5:56:50 AM8/4/13
to fltkg...@googlegroups.com

On 4 Aug 2013, at 06:10, Greg Ercolano wrote:

> On 08/03/13 12:51, Greg Ercolano wrote:
>> seems like the Fl_Tabs widget is not drawing its background
>> even if we give it a box type. Seems like it could be a bug, not sure, will check.
>
> OK, looked into this a bit.
>
> The way Fl_Tabs is currently implemented, the area behind and to the right
> of the tabs is never drawn by the tabs widget, regardless of the tab's box() type.
>
> This means that area is 'invisible', always seeing through to the parent,
> which in this case is the window. Or the tile's background (if it has one).
>
> The tab widget's box type is used to draw the child's background only,
> ie. the 'card' for the currently selected 'tab'.
>
> So if the tab widget is resized in such a way that it doesn't cause
> the parent to redraw (such as this tile resizing), that area behind
> the tabs will leave behind digital garbage.


This being so, then your proposed "workaround" of putting a group (with, say, a FLAT_BOX style) into the tile then putting the tab inside the group... that would be promoted form "workaround" to "best practice" status I guess!




Andr EBERSOLD

unread,
Aug 4, 2013, 10:42:46 AM8/4/13
to fltkg...@googlegroups.com, erco_...@seriss.com
Indeed, after the recommendation to use an *_BOX type that did not change the behavior, I also came up with the same idea. Instead of putting the Tab widget directly under the Tile, I used a FL_Group widget and the the Tab. This proposal works fine.

Tile
  -> Tree
  -> Box
  -> Group
       -> Tab

Thank you so much for your help and analysis.

Is there a way to prevent the Tab titles to be resized when you adjust the Tile widget ? I unselected the resizable property in fluid but it has no effect. The Tab titles are streched and it's not nice at all if
you move the horizontal separation to the top.

 Kind regards,
Andre E.

PS: By the way, there is a little bug in the CMake build process for FLTK 1.3.2  (in one of the examples (I think the multithread ), the pthread lib is missing. that makes the build process to be interrupted.

Greg Ercolano

unread,
Aug 5, 2013, 10:25:36 AM8/5/13
to fltkg...@googlegroups.com
On 08/04/13 07:42, Andr EBERSOLD wrote:
> Is there a way to prevent the Tab titles to be resized when you adjust the Tile widget ?
> I unselected the resizable property in fluid but it has no effect. The Tab titles are
> streched and it's not nice at all if you move the horizontal separation to the top.

You can, but it's non-trivial; unless I'm missing something obvious,
I think you'd have to subclass Fl_Tabs and overload the resize() method
to resize the children to keep the tab height constant.

In other words, keep the children's y() a fixed distance from the tab's y().

Having a way to keep the tab height constant is something the Fl_Tabs
widget really should have built into it but it doesn't. I've played
with adding such a feature today, and might check it in if there's
no other way to solve it.

MacArthur, Ian (Selex ES, UK)

unread,
Aug 5, 2013, 10:45:57 AM8/5/13
to fltkg...@googlegroups.com
> You can, but it's non-trivial; unless I'm missing something
> obvious,
> I think you'd have to subclass Fl_Tabs and overload the resize()
> method
> to resize the children to keep the tab height constant.
>
> In other words, keep the children's y() a fixed distance from the
> tab's y().


I seem to recall (and I might be making this up; I have not tried this prior to posting...) that if you put a group inside the tab area and make that explicitly resizable, that then makes the tab height "work" OK.

Or; I might be misremembering...



> Having a way to keep the tab height constant is something the
> Fl_Tabs
> widget really should have built into it but it doesn't. I've
> played
> with adding such a feature today, and might check it in if there's
> no other way to solve it.

I'd be in favour of that anyway, I think!




Selex ES Ltd
Registered Office: Sigma House, Christopher Martin Road, Basildon, Essex SS14 3EL
A company registered in England & Wales. Company no. 02426132
********************************************************************
This email and any attachments are confidential to the intended
recipient and may also be privileged. If you are not the intended
recipient please delete it from your system and notify the sender.
You should not copy it or use it for any purpose nor disclose or
distribute its contents to any other person.
********************************************************************

Greg Ercolano

unread,
Aug 5, 2013, 11:39:08 AM8/5/13
to fltkg...@googlegroups.com
On 08/05/13 07:45, MacArthur, Ian (Selex ES, UK) wrote:
>> You can, but it's non-trivial; unless I'm missing something obvious,
>> I think you'd have to subclass Fl_Tabs and overload the resize() method
>> to resize the children to keep the tab height constant.
>>
>> In other words, keep the children's y() a fixed distance from the tab's y().
>
> I seem to recall (and I might be making this up; I have not tried this prior
> to posting...) that if you put a group inside the tab area and make that
> explicitly resizable, that then makes the tab height "work" OK.
>
> Or; I might be misremembering...

Nice! That does seem to work. So basically:

tabs = new Fl_Tabs(..);
child_a = new Fl_Group(..);
child_b = new Fl_Group(..);
tabs->end();
tabs->resizable(child_a); // ADD THIS

Huh, this should be in the docs for Fl_Tabs, jeez.
Woulda saved me a bit of work (below).

I'll see about adding that doc mod,
along with others I mentioned earlier in this thread.

>> Having a way to keep the tab height constant is something the Fl_Tabs
>> widget really should have built into it but it doesn't. I've played
>> with adding such a feature today, and might check it in if there's
>> no other way to solve it.
>
> I'd be in favour of that anyway, I think!

Here's a patch.

But given the above works and seems functionally the same,
I think it's kinda moot.

The following adds a new method to Fl_Tabs called fixed_height_tabs(int)
which takes an integer pixel size for the tab height.

Positive values for tabs along the top,
negative value for tabs along the bottom.

So to have 25 pixel high tabs along the top: tabs->fixed_height_tabs(25);
And same for bottom tabs: tabs->fixed_height_tabs(-25);

When set, the children's y() and h() are managed automatically,
keeping the margin opposite the tabs constant.


$ svn diff FL/Fl_Tabs.H src/Fl_Tabs.cxx
Index: FL/Fl_Tabs.H
===================================================================
--- FL/Fl_Tabs.H (revision 9925)
+++ FL/Fl_Tabs.H (working copy)
@@ -98,6 +98,7 @@
Fl_Widget *push_;
int *tab_pos; // array of x-offsets of tabs per child + 1
int *tab_width; // array of widths of tabs per child + 1
+ int tabs_fixed_height;// fixed height of tabs (0=off)
int tab_count; // array size
int tab_positions(); // allocate and calculate tab positions
void clear_tab_positions();
@@ -109,6 +110,7 @@

public:
int handle(int);
+ void resize(int X,int Y,int W,int H);
Fl_Widget *value();
int value(Fl_Widget *);
/**
@@ -127,6 +129,8 @@
Fl_Widget *which(int event_x, int event_y);
~Fl_Tabs();
void client_area(int &rx, int &ry, int &rw, int &rh, int tabh=0);
+ void fixed_height_tabs(int val);
+ int fixed_height_tabs() const;
};

#endif
Index: src/Fl_Tabs.cxx
===================================================================
--- src/Fl_Tabs.cxx (revision 9925)
+++ src/Fl_Tabs.cxx (working copy)
@@ -101,6 +101,7 @@
// Returns full height, if children() = 0.
int Fl_Tabs::tab_height() {
if (children() == 0) return h();
+ if ( fixed_height_tabs() != 0 ) return fixed_height_tabs();
int H = h();
int H2 = y();
Fl_Widget*const* a = array();
@@ -549,6 +550,7 @@
tab_pos = 0;
tab_width = 0;
tab_count = 0;
+ tabs_fixed_height = 0;
}

Fl_Tabs::~Fl_Tabs() {
@@ -623,6 +625,63 @@
}
}

+/**
+ Enables fixed height for tabs, so that tabs remain a constant height when resized.
+
+ Positive values indicate the desired height of the tabs along the top in pixels.
+ Negative values indicate the desired height of the tabs along the bottom in pixels.
+ Zero value disables fixed height tabs (default behavior).
+ **/
+void Fl_Tabs::fixed_height_tabs(int val) {
+ tabs_fixed_height = val;
+ if ( val == 0 ) return;
+ resize(x(), y(), w(), h()); // apply settings to children
+ redraw();
+}
+
+/**
+ Returns the set by fixed_height_tabs(int).
+
+ A value of zero indicates fixed height tabs are disabled (default).
+ **/
+int Fl_Tabs::fixed_height_tabs() const {
+ return tabs_fixed_height;
+}
+
+void Fl_Tabs::resize(int X,int Y,int W,int H) {
+ int th = fixed_height_tabs();
+ if ( th != 0 && children()>0 ) {
+ // Save children's vertical margin opposite tabs
+ int *vmargins = (int*)malloc(children() * sizeof(int));
+ int t;
+ for ( t=0; t<children(); t++ ) {
+ Fl_Widget *o = child(t);
+ if ( th > 0 ) vmargins[t] = (y()+h()) - (o->y()+o->h()); // tabs on top
+ else vmargins[t] = o->y() - y(); // tabs on bottom
+ }
+ // Resize group. Children's y() and h() will be wrong for our needs.
+ Fl_Group::resize(X,Y,W,H);
+ // Now fix up children's y() and h()
+ for ( t=0; t<children(); t++ ) {
+ Fl_Widget *o = child(t);
+ if ( th > 0 )
+ o->resize(o->x(), // tabs on top
+ Y + th,
+ o->w(),
+ H - vmargins[t] - th);
+ else
+ o->resize(o->x(), // tabs on bottom
+ Y + vmargins[t],
+ o->w(),
+ H - vmargins[t] + th);
+ }
+ free((void*)vmargins);
+ init_sizes(); // we resized children
+ } else {
+ Fl_Group::resize(X,Y,W,H);
+ }
+}
+
//
// End of "$Id$".
//

Greg Ercolano

unread,
Aug 5, 2013, 2:29:25 PM8/5/13
to fltkg...@googlegroups.com
On 08/05/13 08:39, Greg Ercolano wrote:
> On 08/05/13 07:45, MacArthur, Ian (Selex ES, UK) wrote:
>> I seem to recall [..] if you put a group inside the tab area and make that
>> explicitly resizable, that then makes the tab height "work" OK.
>
> Nice! That does seem to work. [..]
> Huh, this should be in the docs for Fl_Tabs, jeez.
> I'll see about adding that [to the docs]


OK, I modified the docs for Fl_Tabs, checked in as r9955 to fltk-1.3.x svn current.

Here's a screenshot of the mods highlighted in red:
http://seriss.com/people/erco/fltk/tmp/fltabs-doc-additions.png

Hopefully that will help prevent folks running into all this in the future.

Albrecht Schlosser

unread,
Aug 5, 2013, 3:40:26 PM8/5/13
to fltkg...@googlegroups.com
On 05.08.2013 17:39, Greg Ercolano wrote:
> On 08/05/13 07:45, MacArthur, Ian (Selex ES, UK) wrote:
>>> You can, but it's non-trivial; unless I'm missing something obvious,
>>> I think you'd have to subclass Fl_Tabs and overload the resize() method
>>> to resize the children to keep the tab height constant.
>>>
>>> In other words, keep the children's y() a fixed distance from the tab's y().
>>
>> I seem to recall (and I might be making this up; I have not tried this prior
>> to posting...) that if you put a group inside the tab area and make that
>> explicitly resizable, that then makes the tab height "work" OK.
>>
>> Or; I might be misremembering...
>
> Nice! That does seem to work. So basically:
>
> tabs = new Fl_Tabs(..);
> child_a = new Fl_Group(..);
> child_b = new Fl_Group(..);
> tabs->end();
> tabs->resizable(child_a); // ADD THIS
>
> Huh, this should be in the docs for Fl_Tabs, jeez.

It's probably there implicitly, since the way the tabs are positioned
(top or bottom) is described somewhere (taking the bigger part of what
the children leave of free space, or something like that). Making one of
the children resizable fixes the top/bottom part, and there you are.

But I agree, it should be more explicit, telling users how it can be
achieved easily.

> Woulda saved me a bit of work (below).

Yeah, but it was a nice exercise, wasn't it ? ;-)

> I'll see about adding that doc mod,
> along with others I mentioned earlier in this thread.

That would be great !

>>> Having a way to keep the tab height constant is something the Fl_Tabs
>>> widget really should have built into it but it doesn't. I've played
>>> with adding such a feature today, and might check it in if there's
>>> no other way to solve it.
>>
>> I'd be in favour of that anyway, I think!
>
> Here's a patch.
>
> But given the above works and seems functionally the same,
> I think it's kinda moot.

Yep. Please don't add code that really isn't needed. Docs should be
added, however. That's my opinion, and I'd vote -1 if requested.

Thanks for the try anyway [code removed]. Maybe someone can learn from
your code and use similar techniques in his own code.

Albrecht Schlosser

unread,
Aug 5, 2013, 3:42:27 PM8/5/13
to fltkg...@googlegroups.com
On 05.08.2013 20:29, Greg Ercolano wrote:

> OK, I modified the docs for Fl_Tabs, checked in as r9955 to fltk-1.3.x svn current.
>
> Here's a screenshot of the mods highlighted in red:
> http://seriss.com/people/erco/fltk/tmp/fltabs-doc-additions.png
>
> Hopefully that will help prevent folks running into all this in the future.

Great, thanks!

Greg Ercolano

unread,
Aug 5, 2013, 5:34:50 PM8/5/13
to fltkg...@googlegroups.com
On 08/05/13 12:40, Albrecht Schlosser wrote:
>> Huh, this should be in the docs for Fl_Tabs, jeez.
>
> It's probably there implicitly, since the way the tabs are positioned
> (top or bottom) is described somewhere (taking the bigger part of what
> the children leave of free space, or something like that). Making one of
> the children resizable fixes the top/bottom part, and there you are.

For whatever reason, I just never would have made the jump
that resizables would affect the size of the tabs. But yes,
it makes sense..

> Yep. Please don't add code that really isn't needed.
> Docs should be added, however.

Yes, agreed; done and done.

Andr EBERSOLD

unread,
Aug 7, 2013, 4:06:53 AM8/7/13
to fltkg...@googlegroups.com, erco_...@seriss.com
Thank you so much for the interest regards to my question.
 -> Setting the Fl_Group in the first tab resizable solved my issue. It's just impossible to guess. I'm glad that the documentation does contain more details now.

Best regards,
Andre E.
Reply all
Reply to author
Forward
0 new messages