themes: Workaround for bug where a background color of RGB 0,0,0 in Black color schem...
[ntk.git] / src / Fl_Group.cxx
blobc1a78c902c3e48834ee85c680fb666d93cd5e651
1 //
2 // "$Id: Fl_Group.cxx 8184 2011-01-04 18:28:01Z matt $"
3 //
4 // Group widget for the Fast Light Tool Kit (FLTK).
5 //
6 // Copyright 1998-2010 by Bill Spitzak and others.
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Library General Public License for more details.
18 // You should have received a copy of the GNU Library General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 // USA.
23 // Please report all bugs and problems on the following page:
25 // http://www.fltk.org/str.php
28 // The Fl_Group is the only defined container type in FLTK.
30 // Fl_Window itself is a subclass of this, and most of the event
31 // handling is designed so windows themselves work correctly.
33 #include <stdio.h>
34 #include <FL/Fl.H>
35 #include <FL/Fl_Group.H>
36 #include <FL/Fl_Window.H>
37 #include <FL/fl_draw.H>
38 #include <stdlib.h>
40 Fl_Group* Fl_Group::current_;
42 // Hack: A single child is stored in the pointer to the array, while
43 // multiple children are stored in an allocated array:
45 /**
46 Returns a pointer to the array of children. <I>This pointer is only
47 valid until the next time a child is added or removed.</I>
49 Fl_Widget*const* Fl_Group::array() const {
50 return children_ <= 1 ? (Fl_Widget**)(&array_) : array_;
53 /**
54 Searches the child array for the widget and returns the index. Returns children()
55 if the widget is NULL or not found.
57 int Fl_Group::find(const Fl_Widget* o) const {
58 Fl_Widget*const* a = array();
59 int i; for (i=0; i < children_; i++) if (*a++ == o) break;
60 return i;
63 // Metrowerks CodeWarrior and others can't export the static
64 // class member: current_, so these methods can't be inlined...
66 /**
67 Sets the current group so you can build the widget
68 tree by just constructing the widgets.
70 begin() is automatically called by the constructor for Fl_Group (and thus for
71 Fl_Window as well). begin() <I>is exactly the same as</I> current(this).
72 <I>Don't forget to end() the group or window!</I>
74 void Fl_Group::begin() {current_ = this;}
76 /**
77 <I>Exactly the same as</I> current(this->parent()). Any new widgets
78 added to the widget tree will be added to the parent of the group.
80 void Fl_Group::end() {current_ = parent();}
82 /**
83 Returns the currently active group.
85 The Fl_Widget constructor automatically does current()->add(widget) if this
86 is not null. To prevent new widgets from being added to a group, call
87 Fl_Group::current(0).
89 Fl_Group *Fl_Group::current() {return current_;}
91 /**
92 Sets the current group.
93 \see Fl_Group::current()
95 void Fl_Group::current(Fl_Group *g) {current_ = g;}
97 extern Fl_Widget* fl_oldfocus; // set by Fl::focus
99 // For back-compatibility, we must adjust all events sent to child
100 // windows so they are relative to that window.
102 static int send(Fl_Widget* o, int event) {
103 if (o->type() < FL_WINDOW) return o->handle(event);
104 switch ( event )
106 case FL_DND_ENTER: /* FALLTHROUGH */
107 case FL_DND_DRAG:
108 // figure out correct type of event:
109 event = (o->contains(Fl::belowmouse())) ? FL_DND_DRAG : FL_DND_ENTER;
111 int save_x = Fl::e_x; Fl::e_x -= o->x();
112 int save_y = Fl::e_y; Fl::e_y -= o->y();
113 int ret = o->handle(event);
114 Fl::e_y = save_y;
115 Fl::e_x = save_x;
116 switch ( event )
118 case FL_ENTER: /* FALLTHROUGH */
119 case FL_DND_ENTER:
120 // Successful completion of FL_ENTER means the widget is now the
121 // belowmouse widget, but only call Fl::belowmouse if the child
122 // widget did not do so:
123 if (!o->contains(Fl::belowmouse())) Fl::belowmouse(o);
124 break;
126 return ret;
129 // translate the current keystroke into up/down/left/right for navigation:
130 #define ctrl(x) (x^0x40)
131 static int navkey() {
132 switch (Fl::event_key()) {
133 case 0: // not an FL_KEYBOARD/FL_SHORTCUT event
134 break;
135 case FL_Tab:
136 if (!Fl::event_state(FL_SHIFT)) return FL_Right;
137 return FL_Left;
138 case FL_Right:
139 return FL_Right;
140 case FL_Left:
141 return FL_Left;
142 case FL_Up:
143 return FL_Up;
144 case FL_Down:
145 return FL_Down;
147 return 0;
150 int Fl_Group::handle(int event) {
152 Fl_Widget*const* a = array();
153 int i;
154 Fl_Widget* o;
156 switch (event) {
158 case FL_FOCUS:
159 switch (navkey()) {
160 default:
161 if (savedfocus_ && savedfocus_->take_focus()) return 1;
162 case FL_Right:
163 case FL_Down:
164 for (i = children(); i--;) if ((*a++)->take_focus()) return 1;
165 break;
166 case FL_Left:
167 case FL_Up:
168 for (i = children(); i--;) if (a[i]->take_focus()) return 1;
169 break;
171 return 0;
173 case FL_UNFOCUS:
174 savedfocus_ = fl_oldfocus;
175 return 0;
177 case FL_KEYBOARD:
178 return navigation(navkey());
180 case FL_SHORTCUT:
181 for (i = children(); i--;) {
182 o = a[i];
183 if (o->takesevents() && Fl::event_inside(o) && send(o,FL_SHORTCUT))
184 return 1;
186 for (i = children(); i--;) {
187 o = a[i];
188 if (o->takesevents() && !Fl::event_inside(o) && send(o,FL_SHORTCUT))
189 return 1;
191 if ((Fl::event_key() == FL_Enter || Fl::event_key() == FL_KP_Enter)) return navigation(FL_Down);
192 return 0;
194 case FL_ENTER:
195 case FL_MOVE:
196 for (i = children(); i--;) {
197 o = a[i];
198 if (o->visible() && Fl::event_inside(o)) {
199 if (o->contains(Fl::belowmouse())) {
200 return send(o,FL_MOVE);
201 } else {
202 Fl::belowmouse(o);
203 if (send(o,FL_ENTER)) return 1;
207 Fl::belowmouse(this);
208 return 1;
210 case FL_DND_ENTER:
211 case FL_DND_DRAG:
212 for (i = children(); i--;) {
213 o = a[i];
214 if (o->takesevents() && Fl::event_inside(o)) {
215 if (o->contains(Fl::belowmouse())) {
216 return send(o,FL_DND_DRAG);
217 } else if (send(o,FL_DND_ENTER)) {
218 if (!o->contains(Fl::belowmouse())) Fl::belowmouse(o);
219 return 1;
223 Fl::belowmouse(this);
224 return 0;
226 case FL_PUSH:
227 for (i = children(); i--;) {
228 o = a[i];
229 if (o->takesevents() && Fl::event_inside(o)) {
230 Fl_Widget_Tracker wp(o);
231 if (send(o,FL_PUSH)) {
232 if (Fl::pushed() && wp.exists() && !o->contains(Fl::pushed())) Fl::pushed(o);
233 return 1;
237 return 0;
239 case FL_RELEASE:
240 case FL_DRAG:
241 o = Fl::pushed();
242 if (o == this) return 0;
243 else if (o) send(o,event);
244 else {
245 for (i = children(); i--;) {
246 o = a[i];
247 if (o->takesevents() && Fl::event_inside(o)) {
248 if (send(o,event)) return 1;
252 return 0;
254 case FL_MOUSEWHEEL:
255 for (i = children(); i--;) {
256 o = a[i];
257 if (o->takesevents() && Fl::event_inside(o) && send(o,FL_MOUSEWHEEL))
258 return 1;
260 for (i = children(); i--;) {
261 o = a[i];
262 if (o->takesevents() && !Fl::event_inside(o) && send(o,FL_MOUSEWHEEL))
263 return 1;
265 return 0;
267 case FL_DEACTIVATE:
268 case FL_ACTIVATE:
269 for (i = children(); i--;) {
270 o = *a++;
271 if (o->active()) o->handle(event);
273 return 1;
275 case FL_SHOW:
276 case FL_HIDE:
277 for (i = children(); i--;) {
278 o = *a++;
279 if (event == FL_HIDE && o == Fl::focus()) {
280 // Give up input focus...
281 int old_event = Fl::e_number;
282 o->handle(Fl::e_number = FL_UNFOCUS);
283 Fl::e_number = old_event;
284 Fl::focus(0);
286 if (o->visible()) o->handle(event);
288 return 1;
290 default:
291 // For all other events, try to give to each child, starting at focus:
292 for (i = 0; i < children(); i ++)
293 if (Fl::focus_ == a[i]) break;
295 if (i >= children()) i = 0;
297 if (children()) {
298 for (int j = i;;) {
299 if (a[j]->takesevents()) if (send(a[j], event)) return 1;
300 j++;
301 if (j >= children()) j = 0;
302 if (j == i) break;
306 return 0;
310 //void Fl_Group::focus(Fl_Widget *o) {Fl::focus(o); o->handle(FL_FOCUS);}
312 #if 0
313 const char *nameof(Fl_Widget *o) {
314 if (!o) return "NULL";
315 if (!o->label()) return "<no label>";
316 return o->label();
318 #endif
320 // try to move the focus in response to a keystroke:
321 int Fl_Group::navigation(int key) {
322 if (children() <= 1) return 0;
323 int i;
324 for (i = 0; ; i++) {
325 if (i >= children_) return 0;
326 if (array_[i]->contains(Fl::focus())) break;
328 Fl_Widget *previous = array_[i];
330 for (;;) {
331 switch (key) {
332 case FL_Right:
333 case FL_Down:
334 i++;
335 if (i >= children_) {
336 if (parent()) return 0;
337 i = 0;
339 break;
340 case FL_Left:
341 case FL_Up:
342 if (i) i--;
343 else {
344 if (parent()) return 0;
345 i = children_-1;
347 break;
348 default:
349 return 0;
351 Fl_Widget* o = array_[i];
352 if (o == previous) return 0;
353 switch (key) {
354 case FL_Down:
355 case FL_Up:
356 // for up/down, the widgets have to overlap horizontally:
357 if (o->x() >= previous->x()+previous->w() ||
358 o->x()+o->w() <= previous->x()) continue;
360 if (o->take_focus()) return 1;
364 ////////////////////////////////////////////////////////////////
366 Fl_Group::Fl_Group(int X,int Y,int W,int H,const char *l)
367 : Fl_Widget(X,Y,W,H,l) {
368 align(FL_ALIGN_TOP);
369 children_ = 0;
370 array_ = 0;
371 savedfocus_ = 0;
372 resizable_ = this;
373 sizes_ = 0; // this is allocated when first resize() is done
374 // Subclasses may want to construct child objects as part of their
375 // constructor, so make sure they are add()'d to this object.
376 // But you must end() the object!
377 begin();
381 Deletes all child widgets from memory recursively.
383 This method differs from the remove() method in that it
384 affects all child widgets and deletes them from memory.
386 void Fl_Group::clear() {
387 savedfocus_ = 0;
388 resizable_ = this;
389 init_sizes();
391 // we must change the Fl::pushed() widget, if it is one of
392 // the group's children. Otherwise fl_fix_focus() would send
393 // lots of events to children that are about to be deleted
394 // anyway.
396 Fl_Widget *pushed = Fl::pushed(); // save pushed() widget
397 if (contains(pushed)) pushed = this; // set it to be the group, if it's a child
398 Fl::pushed(this); // for fl_fix_focus etc.
400 // okay, now it is safe to destroy the children:
402 #define REVERSE_CHILDREN
403 #ifdef REVERSE_CHILDREN
404 // Reverse the order of the children. Doing this and deleting
405 // always the last child is much faster than the other way around.
406 if (children_ > 1) {
407 Fl_Widget *temp;
408 Fl_Widget **a = (Fl_Widget**)array();
409 for (int i=0,j=children_-1; i<children_/2; i++,j--) {
410 temp = a[i];
411 a[i] = a[j];
412 a[j] = temp;
415 #endif // REVERSE_CHILDREN
417 while (children_) { // delete all children
418 int idx = children_-1; // last child's index
419 Fl_Widget* w = child(idx); // last child widget
420 if (w->parent()==this) { // should always be true
421 if (children_>2) { // optimized removal
422 w->parent_ = 0; // reset child's parent
423 children_--; // update counter
424 } else { // slow removal
425 remove(idx);
427 delete w; // delete the child
428 } else { // should never happen
429 remove(idx); // remove it anyway
433 if (pushed != this) Fl::pushed(pushed); // reset pushed() widget
438 The destructor <I>also deletes all the children</I>. This allows a
439 whole tree to be deleted at once, without having to keep a pointer to
440 all the children in the user code.
442 It is allowed that the Fl_Group and all of its children are automatic
443 (local) variables, but you must declare the Fl_Group \e first, so that
444 it is destroyed last.
446 If you add static or automatic (local) variables to an Fl_Group, then it
447 is your responsibility to remove (or delete) all such static or automatic
448 child widgets \e \b before destroying the group - otherwise the child
449 widgets' destructors would be called twice!
451 Fl_Group::~Fl_Group() {
452 clear();
456 The widget is removed from its current group (if any) and then
457 inserted into this group. It is put at index n - or at the end,
458 if n >= children(). This can also be used to rearrange
459 the widgets inside a group.
461 void Fl_Group::insert(Fl_Widget &o, int index) {
462 if (o.parent()) {
463 Fl_Group* g = o.parent();
464 int n = g->find(o);
465 if (g == this) {
466 if (index > n) index--;
467 if (index == n) return;
469 g->remove(n);
471 o.parent_ = this;
472 if (children_ == 0) { // use array pointer to point at single child
473 array_ = (Fl_Widget**)&o;
474 } else if (children_ == 1) { // go from 1 to 2 children
475 Fl_Widget* t = (Fl_Widget*)array_;
476 array_ = (Fl_Widget**)malloc(2*sizeof(Fl_Widget*));
477 if (index) {array_[0] = t; array_[1] = &o;}
478 else {array_[0] = &o; array_[1] = t;}
479 } else {
480 if (!(children_ & (children_-1))) // double number of children
481 array_ = (Fl_Widget**)realloc((void*)array_,
482 2*children_*sizeof(Fl_Widget*));
483 int j; for (j = children_; j > index; j--) array_[j] = array_[j-1];
484 array_[j] = &o;
486 children_++;
487 init_sizes();
491 The widget is removed from its current group (if any) and then added
492 to the end of this group.
494 void Fl_Group::add(Fl_Widget &o) {insert(o, children_);}
497 Removes the widget at \p index from the group but does not delete it.
499 This method does nothing if \p index is out of bounds.
501 This method differs from the clear() method in that it only affects
502 a single widget and does not delete it from memory.
504 \since FLTK 1.3.0
506 void Fl_Group::remove(int index) {
507 if (index < 0 || index >= children_) return;
508 Fl_Widget &o = *child(index);
509 if (&o == savedfocus_) savedfocus_ = 0;
510 if (o.parent_ == this) { // this should always be true
511 o.parent_ = 0;
514 // remove the widget from the group
516 children_--;
517 if (children_ == 1) { // go from 2 to 1 child
518 Fl_Widget *t = array_[!index];
519 free((void*)array_);
520 array_ = (Fl_Widget**)t;
521 } else if (children_ > 1) { // delete from array
522 for (; index < children_; index++) array_[index] = array_[index+1];
524 init_sizes();
528 Removes a widget from the group but does not delete it.
530 This method does nothing if the widget is not a child of the group.
532 This method differs from the clear() method in that it only affects
533 a single widget and does not delete it from memory.
535 \note If you have the child's index anyway, use remove(int index)
536 instead, because this doesn't need a child lookup in the group's
537 table of children. This can be much faster, if there are lots of
538 children.
540 void Fl_Group::remove(Fl_Widget &o) {
541 if (!children_) return;
542 int i = find(o);
543 if (i < children_) remove(i);
546 ////////////////////////////////////////////////////////////////
548 // Rather lame kludge here, I need to detect windows and ignore the
549 // changes to X,Y, since all children are relative to X,Y. That
550 // is why I check type():
552 // sizes array stores the initial positions of widgets as
553 // left,right,top,bottom quads. The first quad is the group, the
554 // second is the resizable (clipped to the group), and the
555 // rest are the children. This is a convenient order for the
556 // algorithm. If you change this be sure to fix Fl_Tile which
557 // also uses this array!
560 Resets the internal array of widget sizes and positions.
562 The Fl_Group widget keeps track of the original widget sizes and
563 positions when resizing occurs so that if you resize a window back to its
564 original size the widgets will be in the correct places. If you rearrange
565 the widgets in your group, call this method to register the new arrangement
566 with the Fl_Group that contains them.
568 If you add or remove widgets, this will be done automatically.
570 \note The internal array of widget sizes and positions will be allocated and
571 filled when the next resize() occurs.
573 \sa sizes()
575 void Fl_Group::init_sizes() {
576 delete[] sizes_; sizes_ = 0;
580 Returns the internal array of widget sizes and positions.
582 If the sizes() array does not exist, it will be allocated and filled
583 with the current widget sizes and positions.
585 \note You should never need to use this method directly, unless you have
586 special needs to rearrange the children of a Fl_Group. Fl_Tile uses
587 this to rearrange its widget positions.
589 \sa init_sizes()
591 \todo Should the internal representation of the sizes() array be documented?
593 int* Fl_Group::sizes() {
594 if (!sizes_) {
595 int* p = sizes_ = new int[4*(children_+2)];
596 // first thing in sizes array is the group's size:
597 if (type() < FL_WINDOW) {p[0] = x(); p[2] = y();} else {p[0] = p[2] = 0;}
598 p[1] = p[0]+w(); p[3] = p[2]+h();
599 // next is the resizable's size:
600 p[4] = p[0]; // init to the group's size
601 p[5] = p[1];
602 p[6] = p[2];
603 p[7] = p[3];
604 Fl_Widget* r = resizable();
605 if (r && r != this) { // then clip the resizable to it
606 int t;
607 t = r->x(); if (t > p[0]) p[4] = t;
608 t +=r->w(); if (t < p[1]) p[5] = t;
609 t = r->y(); if (t > p[2]) p[6] = t;
610 t +=r->h(); if (t < p[3]) p[7] = t;
612 // next is all the children's sizes:
613 p += 8;
614 Fl_Widget*const* a = array();
615 for (int i=children_; i--;) {
616 Fl_Widget* o = *a++;
617 *p++ = o->x();
618 *p++ = o->x()+o->w();
619 *p++ = o->y();
620 *p++ = o->y()+o->h();
623 return sizes_;
627 Resizes the Fl_Group widget and all of its children.
629 The Fl_Group widget first resizes itself, and then it moves and resizes
630 all its children according to the rules documented for
631 Fl_Group::resizable(Fl_Widget*)
633 \sa Fl_Group::resizable(Fl_Widget*)
634 \sa Fl_Group::resizable()
635 \sa Fl_Widget::resize(int,int,int,int)
637 void Fl_Group::resize(int X, int Y, int W, int H) {
639 int dx = X-x();
640 int dy = Y-y();
641 int dw = W-w();
642 int dh = H-h();
644 int *p = sizes(); // save initial sizes and positions
646 Fl_Widget::resize(X,Y,W,H); // make new xywh values visible for children
648 if (!resizable() || (dw==0 && dh==0) ) {
650 if (type() < FL_WINDOW) {
651 Fl_Widget*const* a = array();
652 for (int i=children_; i--;) {
653 Fl_Widget* o = *a++;
654 o->resize(o->x()+dx, o->y()+dy, o->w(), o->h());
658 } else if (children_) {
660 // get changes in size/position from the initial size:
661 dx = X - p[0];
662 dw = W - (p[1]-p[0]);
663 dy = Y - p[2];
664 dh = H - (p[3]-p[2]);
665 if (type() >= FL_WINDOW) dx = dy = 0;
666 p += 4;
668 // get initial size of resizable():
669 int IX = *p++;
670 int IR = *p++;
671 int IY = *p++;
672 int IB = *p++;
674 Fl_Widget*const* a = array();
675 for (int i=children_; i--;) {
676 Fl_Widget* o = *a++;
677 #if 1
678 int XX = *p++;
679 if (XX >= IR) XX += dw;
680 else if (XX > IX) XX = IX+((XX-IX)*(IR+dw-IX)+(IR-IX)/2)/(IR-IX);
681 int R = *p++;
682 if (R >= IR) R += dw;
683 else if (R > IX) R = IX+((R-IX)*(IR+dw-IX)+(IR-IX)/2)/(IR-IX);
685 int YY = *p++;
686 if (YY >= IB) YY += dh;
687 else if (YY > IY) YY = IY+((YY-IY)*(IB+dh-IY)+(IB-IY)/2)/(IB-IY);
688 int B = *p++;
689 if (B >= IB) B += dh;
690 else if (B > IY) B = IY+((B-IY)*(IB+dh-IY)+(IB-IY)/2)/(IB-IY);
691 #else // much simpler code from Francois Ostiguy:
692 int XX = *p++;
693 if (XX >= IR) XX += dw;
694 else if (XX > IX) XX += dw * (XX-IX)/(IR-IX);
695 int R = *p++;
696 if (R >= IR) R += dw;
697 else if (R > IX) R = R + dw * (R-IX)/(IR-IX);
699 int YY = *p++;
700 if (YY >= IB) YY += dh;
701 else if (YY > IY) YY = YY + dh*(YY-IY)/(IB-IY);
702 int B = *p++;
703 if (B >= IB) B += dh;
704 else if (B > IY) B = B + dh*(B-IY)/(IB-IY);
705 #endif
706 o->resize(XX+dx, YY+dy, R-XX, B-YY);
712 Draws all children of the group.
714 This is useful, if you derived a widget from Fl_Group and want to draw a special
715 border or background. You can call draw_children() from the derived draw() method
716 after drawing the box, border, or background.
718 void Fl_Group::draw_children() {
719 Fl_Widget*const* a = array();
721 if (clip_children()) {
722 fl_push_clip(x() + Fl::box_dx(box()),
723 y() + Fl::box_dy(box()),
724 w() - Fl::box_dw(box()),
725 h() - Fl::box_dh(box()));
728 if (damage() & ~FL_DAMAGE_CHILD) { // redraw the entire thing:
729 // if ( damage() & FL_DAMAGE_ALL ) {
730 for (int i=children_; i--;) {
731 Fl_Widget& o = **a++;
732 draw_child(o);
733 draw_outside_label(o);
735 } else { // only redraw the children that need it:
736 for (int i=children_; i--;) update_child(**a++);
739 if (clip_children()) fl_pop_clip();
742 void Fl_Group::draw() {
743 if (damage() & ~FL_DAMAGE_CHILD) { // redraw the entire thing:
744 draw_box();
745 draw_label();
747 draw_children();
751 Draws a child only if it needs it.
753 This draws a child widget, if it is not clipped \em and if any damage() bits
754 are set. The damage bits are cleared after drawing.
756 \sa Fl_Group::draw_child(Fl_Widget& widget) const
758 void Fl_Group::update_child(Fl_Widget& widget) const {
759 if (widget.damage() && widget.visible() && widget.type() < FL_WINDOW &&
760 fl_not_clipped(widget.x(), widget.y(), widget.w(), widget.h())) {
761 widget.draw();
762 widget.clear_damage();
767 Forces a child to redraw.
769 This draws a child widget, if it is not clipped.
770 The damage bits are cleared after drawing.
772 void Fl_Group::draw_child(Fl_Widget& widget) const {
773 if (widget.visible() && widget.type() < FL_WINDOW &&
774 fl_not_clipped(widget.x(), widget.y(), widget.w(), widget.h())) {
775 widget.clear_damage(FL_DAMAGE_ALL);
776 widget.draw();
777 widget.clear_damage();
781 extern char fl_draw_shortcut;
783 /** Parents normally call this to draw outside labels of child widgets. */
784 void Fl_Group::draw_outside_label(const Fl_Widget& widget) const {
785 if (!widget.visible()) return;
786 // skip any labels that are inside the widget:
787 if (!(widget.align()&15) || (widget.align() & FL_ALIGN_INSIDE)) return;
788 // invent a box that is outside the widget:
789 Fl_Align a = widget.align();
790 int X = widget.x();
791 int Y = widget.y();
792 int W = widget.w();
793 int H = widget.h();
794 int wx, wy;
795 if (const_cast<Fl_Group*>(this)->as_window()) {
796 wx = wy = 0;
797 } else {
798 wx = x(); wy = y();
800 if ( (a & 0x0f) == FL_ALIGN_LEFT_TOP ) {
801 a = (a &~0x0f ) | FL_ALIGN_TOP_RIGHT;
802 X = wx;
803 W = widget.x()-X-3;
804 } else if ( (a & 0x0f) == FL_ALIGN_LEFT_BOTTOM ) {
805 a = (a &~0x0f ) | FL_ALIGN_BOTTOM_RIGHT;
806 X = wx;
807 W = widget.x()-X-3;
808 } else if ( (a & 0x0f) == FL_ALIGN_RIGHT_TOP ) {
809 a = (a &~0x0f ) | FL_ALIGN_TOP_LEFT;
810 X = X+W+3;
811 W = wx+this->w()-X;
812 } else if ( (a & 0x0f) == FL_ALIGN_RIGHT_BOTTOM ) {
813 a = (a &~0x0f ) | FL_ALIGN_BOTTOM_LEFT;
814 X = X+W+3;
815 W = wx+this->w()-X;
816 } else if (a & FL_ALIGN_TOP) {
817 a ^= (FL_ALIGN_BOTTOM|FL_ALIGN_TOP);
818 Y = wy;
819 H = widget.y()-Y;
820 } else if (a & FL_ALIGN_BOTTOM) {
821 a ^= (FL_ALIGN_BOTTOM|FL_ALIGN_TOP);
822 Y = Y+H;
823 H = wy+h()-Y;
824 } else if (a & FL_ALIGN_LEFT) {
825 a ^= (FL_ALIGN_LEFT|FL_ALIGN_RIGHT);
826 X = wx;
827 W = widget.x()-X-3;
828 } else if (a & FL_ALIGN_RIGHT) {
829 a ^= (FL_ALIGN_LEFT|FL_ALIGN_RIGHT);
830 X = X+W+3;
831 W = wx+this->w()-X;
833 widget.draw_label(X,Y,W,H,(Fl_Align)a);
837 // End of "$Id: Fl_Group.cxx 8184 2011-01-04 18:28:01Z matt $".