1998-10-20 00:46:58 +04:00
|
|
|
//
|
|
|
|
// Group widget for the Fast Light Tool Kit (FLTK).
|
|
|
|
//
|
2022-01-08 18:23:01 +03:00
|
|
|
// Copyright 1998-2022 by Bill Spitzak and others.
|
1998-10-20 00:46:58 +04:00
|
|
|
//
|
2011-07-19 08:49:30 +04:00
|
|
|
// This library is free software. Distribution and use rights are outlined in
|
|
|
|
// the file "COPYING" which should have been included with this file. If this
|
|
|
|
// file is missing or damaged, see the license at:
|
|
|
|
//
|
2020-03-11 16:38:02 +03:00
|
|
|
// https://www.fltk.org/COPYING.php
|
1998-10-20 00:46:58 +04:00
|
|
|
//
|
2020-07-01 19:03:10 +03:00
|
|
|
// Please see the following page on how to report bugs and issues:
|
2005-04-16 04:13:17 +04:00
|
|
|
//
|
2020-07-01 19:03:10 +03:00
|
|
|
// https://www.fltk.org/bugs.php
|
1998-10-20 00:46:58 +04:00
|
|
|
//
|
1998-10-06 22:21:25 +04:00
|
|
|
|
2022-01-08 18:23:01 +03:00
|
|
|
// Fl_Group is the basic container type in FLTK. Other container types
|
|
|
|
// (classes) are usually subclasses of Fl_Group.
|
1998-10-06 22:21:25 +04:00
|
|
|
|
|
|
|
// Fl_Window itself is a subclass of this, and most of the event
|
|
|
|
// handling is designed so windows themselves work correctly.
|
|
|
|
|
|
|
|
#include <FL/Fl_Group.H>
|
2018-06-26 16:43:18 +03:00
|
|
|
#include "Fl_Window_Driver.H"
|
2018-04-12 15:58:10 +03:00
|
|
|
#include <FL/Fl_Rect.H>
|
1998-10-06 22:21:25 +04:00
|
|
|
#include <FL/fl_draw.H>
|
2018-04-12 15:58:10 +03:00
|
|
|
|
|
|
|
#include <stdlib.h> // malloc etc.
|
1998-10-06 22:21:25 +04:00
|
|
|
|
|
|
|
Fl_Group* Fl_Group::current_;
|
|
|
|
|
|
|
|
// Hack: A single child is stored in the pointer to the array, while
|
|
|
|
// multiple children are stored in an allocated array:
|
2008-12-09 11:49:25 +03:00
|
|
|
|
2008-09-14 02:33:03 +04:00
|
|
|
/**
|
2018-04-12 15:58:10 +03:00
|
|
|
Returns a pointer to the array of children.
|
|
|
|
|
2020-07-01 19:03:10 +03:00
|
|
|
\note This pointer is only valid until the next time a child
|
|
|
|
is added or removed.
|
2008-09-14 02:33:03 +04:00
|
|
|
*/
|
1998-10-06 22:21:25 +04:00
|
|
|
Fl_Widget*const* Fl_Group::array() const {
|
2020-07-09 04:07:50 +03:00
|
|
|
return children_ <= 1 ? &child1_ : array_;
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
|
2008-09-14 02:33:03 +04:00
|
|
|
/**
|
2018-04-12 15:58:10 +03:00
|
|
|
Searches the child array for the widget and returns the index.
|
|
|
|
|
|
|
|
Returns children() if the widget is NULL or not found.
|
2008-09-14 02:33:03 +04:00
|
|
|
*/
|
1998-10-06 22:21:25 +04:00
|
|
|
int Fl_Group::find(const Fl_Widget* o) const {
|
|
|
|
Fl_Widget*const* a = array();
|
|
|
|
int i; for (i=0; i < children_; i++) if (*a++ == o) break;
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2020-03-11 16:38:02 +03:00
|
|
|
// Some (* which? *) compilers / toolchains can't export the static
|
2002-07-14 21:03:31 +04:00
|
|
|
// class member: current_, so these methods can't be inlined...
|
2008-12-09 11:49:25 +03:00
|
|
|
|
2008-09-14 02:33:03 +04:00
|
|
|
/**
|
|
|
|
Sets the current group so you can build the widget
|
2008-12-09 11:49:25 +03:00
|
|
|
tree by just constructing the widgets.
|
|
|
|
|
|
|
|
begin() is automatically called by the constructor for Fl_Group (and thus for
|
|
|
|
Fl_Window as well). begin() <I>is exactly the same as</I> current(this).
|
|
|
|
<I>Don't forget to end() the group or window!</I>
|
2008-09-14 02:33:03 +04:00
|
|
|
*/
|
2002-07-12 02:43:53 +04:00
|
|
|
void Fl_Group::begin() {current_ = this;}
|
2008-12-09 11:49:25 +03:00
|
|
|
|
2008-09-14 02:33:03 +04:00
|
|
|
/**
|
2008-12-09 11:49:25 +03:00
|
|
|
<I>Exactly the same as</I> current(this->parent()). Any new widgets
|
2008-09-14 02:33:03 +04:00
|
|
|
added to the widget tree will be added to the parent of the group.
|
|
|
|
*/
|
2010-02-21 00:14:47 +03:00
|
|
|
void Fl_Group::end() {current_ = parent();}
|
2008-12-09 11:49:25 +03:00
|
|
|
|
2008-09-14 02:33:03 +04:00
|
|
|
/**
|
2008-12-09 11:49:25 +03:00
|
|
|
Returns the currently active group.
|
2017-07-07 22:16:40 +03:00
|
|
|
|
2008-12-09 11:49:25 +03:00
|
|
|
The Fl_Widget constructor automatically does current()->add(widget) if this
|
|
|
|
is not null. To prevent new widgets from being added to a group, call
|
|
|
|
Fl_Group::current(0).
|
2008-09-14 02:33:03 +04:00
|
|
|
*/
|
2002-07-14 21:03:31 +04:00
|
|
|
Fl_Group *Fl_Group::current() {return current_;}
|
2008-12-09 11:49:25 +03:00
|
|
|
|
2008-09-14 02:33:03 +04:00
|
|
|
/**
|
2011-01-04 21:28:01 +03:00
|
|
|
Sets the current group.
|
2017-07-07 22:16:40 +03:00
|
|
|
\see Fl_Group::current()
|
2008-09-14 02:33:03 +04:00
|
|
|
*/
|
2002-07-14 21:03:31 +04:00
|
|
|
void Fl_Group::current(Fl_Group *g) {current_ = g;}
|
2002-07-12 02:43:53 +04:00
|
|
|
|
1998-10-06 22:21:25 +04:00
|
|
|
extern Fl_Widget* fl_oldfocus; // set by Fl::focus
|
|
|
|
|
2008-09-15 21:46:42 +04:00
|
|
|
// For back-compatibility, we must adjust all events sent to child
|
1998-10-06 22:21:25 +04:00
|
|
|
// windows so they are relative to that window.
|
|
|
|
|
|
|
|
static int send(Fl_Widget* o, int event) {
|
2018-04-12 15:58:10 +03:00
|
|
|
if (!o->as_window()) return o->handle(event);
|
2002-02-24 20:52:18 +03:00
|
|
|
switch ( event )
|
|
|
|
{
|
2010-02-27 00:10:46 +03:00
|
|
|
case FL_DND_ENTER: /* FALLTHROUGH */
|
2002-02-24 20:52:18 +03:00
|
|
|
case FL_DND_DRAG:
|
|
|
|
// figure out correct type of event:
|
|
|
|
event = (o->contains(Fl::belowmouse())) ? FL_DND_DRAG : FL_DND_ENTER;
|
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
int save_x = Fl::e_x; Fl::e_x -= o->x();
|
|
|
|
int save_y = Fl::e_y; Fl::e_y -= o->y();
|
|
|
|
int ret = o->handle(event);
|
|
|
|
Fl::e_y = save_y;
|
|
|
|
Fl::e_x = save_x;
|
2002-02-24 20:52:18 +03:00
|
|
|
switch ( event )
|
|
|
|
{
|
2010-02-27 00:10:46 +03:00
|
|
|
case FL_ENTER: /* FALLTHROUGH */
|
2002-02-24 20:52:18 +03:00
|
|
|
case FL_DND_ENTER:
|
|
|
|
// Successful completion of FL_ENTER means the widget is now the
|
|
|
|
// belowmouse widget, but only call Fl::belowmouse if the child
|
|
|
|
// widget did not do so:
|
|
|
|
if (!o->contains(Fl::belowmouse())) Fl::belowmouse(o);
|
|
|
|
break;
|
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
1999-01-27 00:37:14 +03:00
|
|
|
// translate the current keystroke into up/down/left/right for navigation:
|
|
|
|
static int navkey() {
|
2014-08-29 16:10:11 +04:00
|
|
|
// The app may want these for hotkeys, check key state
|
|
|
|
if (Fl::event_state(FL_CTRL | FL_ALT | FL_META)) return 0;
|
|
|
|
|
1999-01-27 00:37:14 +03:00
|
|
|
switch (Fl::event_key()) {
|
2000-02-18 10:11:09 +03:00
|
|
|
case 0: // not an FL_KEYBOARD/FL_SHORTCUT event
|
|
|
|
break;
|
1999-01-27 00:37:14 +03:00
|
|
|
case FL_Tab:
|
|
|
|
if (!Fl::event_state(FL_SHIFT)) return FL_Right;
|
|
|
|
return FL_Left;
|
|
|
|
case FL_Right:
|
|
|
|
return FL_Right;
|
|
|
|
case FL_Left:
|
|
|
|
return FL_Left;
|
|
|
|
case FL_Up:
|
|
|
|
return FL_Up;
|
|
|
|
case FL_Down:
|
|
|
|
return FL_Down;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1998-10-06 22:21:25 +04:00
|
|
|
int Fl_Group::handle(int event) {
|
|
|
|
|
|
|
|
Fl_Widget*const* a = array();
|
|
|
|
int i;
|
|
|
|
Fl_Widget* o;
|
|
|
|
|
|
|
|
switch (event) {
|
|
|
|
|
|
|
|
case FL_FOCUS:
|
1999-01-27 00:37:14 +03:00
|
|
|
switch (navkey()) {
|
|
|
|
default:
|
|
|
|
if (savedfocus_ && savedfocus_->take_focus()) return 1;
|
|
|
|
case FL_Right:
|
|
|
|
case FL_Down:
|
|
|
|
for (i = children(); i--;) if ((*a++)->take_focus()) return 1;
|
|
|
|
break;
|
|
|
|
case FL_Left:
|
|
|
|
case FL_Up:
|
|
|
|
for (i = children(); i--;) if (a[i]->take_focus()) return 1;
|
|
|
|
break;
|
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
case FL_UNFOCUS:
|
|
|
|
savedfocus_ = fl_oldfocus;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case FL_KEYBOARD:
|
1999-01-27 00:37:14 +03:00
|
|
|
return navigation(navkey());
|
1998-10-06 22:21:25 +04:00
|
|
|
|
|
|
|
case FL_SHORTCUT:
|
|
|
|
for (i = children(); i--;) {
|
|
|
|
o = a[i];
|
|
|
|
if (o->takesevents() && Fl::event_inside(o) && send(o,FL_SHORTCUT))
|
2020-07-01 19:03:10 +03:00
|
|
|
return 1;
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
for (i = children(); i--;) {
|
|
|
|
o = a[i];
|
|
|
|
if (o->takesevents() && !Fl::event_inside(o) && send(o,FL_SHORTCUT))
|
2020-07-01 19:03:10 +03:00
|
|
|
return 1;
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
2003-11-01 04:49:35 +03:00
|
|
|
if ((Fl::event_key() == FL_Enter || Fl::event_key() == FL_KP_Enter)) return navigation(FL_Down);
|
1998-10-06 22:21:25 +04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
case FL_ENTER:
|
|
|
|
case FL_MOVE:
|
|
|
|
for (i = children(); i--;) {
|
|
|
|
o = a[i];
|
2002-04-09 21:20:24 +04:00
|
|
|
if (o->visible() && Fl::event_inside(o)) {
|
2020-07-01 19:03:10 +03:00
|
|
|
if (o->contains(Fl::belowmouse())) {
|
|
|
|
return send(o,FL_MOVE);
|
|
|
|
} else {
|
|
|
|
Fl::belowmouse(o);
|
|
|
|
if (send(o,FL_ENTER)) return 1;
|
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Fl::belowmouse(this);
|
|
|
|
return 1;
|
|
|
|
|
2002-02-24 20:52:18 +03:00
|
|
|
case FL_DND_ENTER:
|
|
|
|
case FL_DND_DRAG:
|
|
|
|
for (i = children(); i--;) {
|
|
|
|
o = a[i];
|
|
|
|
if (o->takesevents() && Fl::event_inside(o)) {
|
2020-07-01 19:03:10 +03:00
|
|
|
if (o->contains(Fl::belowmouse())) {
|
|
|
|
return send(o,FL_DND_DRAG);
|
|
|
|
} else if (send(o,FL_DND_ENTER)) {
|
|
|
|
if (!o->contains(Fl::belowmouse())) Fl::belowmouse(o);
|
|
|
|
return 1;
|
|
|
|
}
|
2002-02-24 20:52:18 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Fl::belowmouse(this);
|
|
|
|
return 0;
|
|
|
|
|
1998-10-06 22:21:25 +04:00
|
|
|
case FL_PUSH:
|
|
|
|
for (i = children(); i--;) {
|
|
|
|
o = a[i];
|
|
|
|
if (o->takesevents() && Fl::event_inside(o)) {
|
2020-07-01 19:03:10 +03:00
|
|
|
Fl_Widget_Tracker wp(o);
|
|
|
|
if (send(o,FL_PUSH)) {
|
|
|
|
if (Fl::pushed() && wp.exists() && !o->contains(Fl::pushed())) Fl::pushed(o);
|
|
|
|
return 1;
|
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
|
2001-08-03 19:48:20 +04:00
|
|
|
case FL_RELEASE:
|
2001-08-04 16:21:34 +04:00
|
|
|
case FL_DRAG:
|
|
|
|
o = Fl::pushed();
|
|
|
|
if (o == this) return 0;
|
|
|
|
else if (o) send(o,event);
|
|
|
|
else {
|
|
|
|
for (i = children(); i--;) {
|
2020-07-01 19:03:10 +03:00
|
|
|
o = a[i];
|
|
|
|
if (o->takesevents() && Fl::event_inside(o)) {
|
|
|
|
if (send(o,event)) return 1;
|
|
|
|
}
|
2001-08-03 19:48:20 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
|
2005-02-20 03:23:36 +03:00
|
|
|
case FL_MOUSEWHEEL:
|
|
|
|
for (i = children(); i--;) {
|
|
|
|
o = a[i];
|
|
|
|
if (o->takesevents() && Fl::event_inside(o) && send(o,FL_MOUSEWHEEL))
|
2020-07-01 19:03:10 +03:00
|
|
|
return 1;
|
2005-02-20 03:23:36 +03:00
|
|
|
}
|
|
|
|
for (i = children(); i--;) {
|
|
|
|
o = a[i];
|
|
|
|
if (o->takesevents() && !Fl::event_inside(o) && send(o,FL_MOUSEWHEEL))
|
2020-07-01 19:03:10 +03:00
|
|
|
return 1;
|
2005-02-20 03:23:36 +03:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
|
1998-10-06 22:21:25 +04:00
|
|
|
case FL_DEACTIVATE:
|
|
|
|
case FL_ACTIVATE:
|
|
|
|
for (i = children(); i--;) {
|
|
|
|
o = *a++;
|
|
|
|
if (o->active()) o->handle(event);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
case FL_SHOW:
|
|
|
|
case FL_HIDE:
|
|
|
|
for (i = children(); i--;) {
|
|
|
|
o = *a++;
|
2004-10-19 00:22:25 +04:00
|
|
|
if (event == FL_HIDE && o == Fl::focus()) {
|
|
|
|
// Give up input focus...
|
2020-07-01 19:03:10 +03:00
|
|
|
int old_event = Fl::e_number;
|
2004-12-03 06:14:17 +03:00
|
|
|
o->handle(Fl::e_number = FL_UNFOCUS);
|
2020-07-01 19:03:10 +03:00
|
|
|
Fl::e_number = old_event;
|
|
|
|
Fl::focus(0);
|
2004-10-19 00:22:25 +04:00
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
if (o->visible()) o->handle(event);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
default:
|
2001-08-03 01:11:43 +04:00
|
|
|
// For all other events, try to give to each child, starting at focus:
|
|
|
|
for (i = 0; i < children(); i ++)
|
2002-04-09 21:20:24 +04:00
|
|
|
if (Fl::focus_ == a[i]) break;
|
2001-08-03 01:11:43 +04:00
|
|
|
|
|
|
|
if (i >= children()) i = 0;
|
|
|
|
|
|
|
|
if (children()) {
|
|
|
|
for (int j = i;;) {
|
2008-02-20 20:42:08 +03:00
|
|
|
if (a[j]->takesevents()) if (send(a[j], event)) return 1;
|
2001-08-03 01:11:43 +04:00
|
|
|
j++;
|
|
|
|
if (j >= children()) j = 0;
|
|
|
|
if (j == i) break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-10-06 22:21:25 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// try to move the focus in response to a keystroke:
|
|
|
|
int Fl_Group::navigation(int key) {
|
|
|
|
if (children() <= 1) return 0;
|
1999-01-27 00:37:14 +03:00
|
|
|
int i;
|
|
|
|
for (i = 0; ; i++) {
|
|
|
|
if (i >= children_) return 0;
|
|
|
|
if (array_[i]->contains(Fl::focus())) break;
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
1999-01-27 00:37:14 +03:00
|
|
|
Fl_Widget *previous = array_[i];
|
1998-10-06 22:21:25 +04:00
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
switch (key) {
|
|
|
|
case FL_Right:
|
|
|
|
case FL_Down:
|
1999-01-27 00:37:14 +03:00
|
|
|
i++;
|
|
|
|
if (i >= children_) {
|
2020-07-01 19:03:10 +03:00
|
|
|
if (parent()) return 0;
|
|
|
|
i = 0;
|
1999-01-27 00:37:14 +03:00
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
break;
|
|
|
|
case FL_Left:
|
|
|
|
case FL_Up:
|
1999-01-27 00:37:14 +03:00
|
|
|
if (i) i--;
|
|
|
|
else {
|
2020-07-01 19:03:10 +03:00
|
|
|
if (parent()) return 0;
|
|
|
|
i = children_-1;
|
1999-01-27 00:37:14 +03:00
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
Fl_Widget* o = array_[i];
|
1999-01-27 00:37:14 +03:00
|
|
|
if (o == previous) return 0;
|
1998-10-06 22:21:25 +04:00
|
|
|
switch (key) {
|
|
|
|
case FL_Down:
|
|
|
|
case FL_Up:
|
1999-01-27 00:37:14 +03:00
|
|
|
// for up/down, the widgets have to overlap horizontally:
|
|
|
|
if (o->x() >= previous->x()+previous->w() ||
|
2020-07-01 19:03:10 +03:00
|
|
|
o->x()+o->w() <= previous->x()) continue;
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
if (o->take_focus()) return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
Fl_Group::Fl_Group(int X,int Y,int W,int H,const char *l)
|
|
|
|
: Fl_Widget(X,Y,W,H,l) {
|
|
|
|
align(FL_ALIGN_TOP);
|
|
|
|
children_ = 0;
|
|
|
|
array_ = 0;
|
|
|
|
savedfocus_ = 0;
|
|
|
|
resizable_ = this;
|
2017-07-07 22:16:40 +03:00
|
|
|
bounds_ = 0; // this is allocated when first resize() is done
|
|
|
|
sizes_ = 0; // see bounds_ (FLTK 1.3 compatibility)
|
|
|
|
|
1998-10-06 22:21:25 +04:00
|
|
|
// Subclasses may want to construct child objects as part of their
|
|
|
|
// constructor, so make sure they are add()'d to this object.
|
|
|
|
// But you must end() the object!
|
|
|
|
begin();
|
|
|
|
}
|
|
|
|
|
2008-09-14 02:33:03 +04:00
|
|
|
/**
|
2008-12-09 11:54:00 +03:00
|
|
|
Deletes all child widgets from memory recursively.
|
2008-12-09 11:49:25 +03:00
|
|
|
|
|
|
|
This method differs from the remove() method in that it
|
2008-09-14 02:33:03 +04:00
|
|
|
affects all child widgets and deletes them from memory.
|
2017-07-07 22:16:40 +03:00
|
|
|
|
|
|
|
The resizable() widget of the Fl_Group is set to the Fl_Group itself.
|
|
|
|
|
|
|
|
\internal If the Fl_Group widget contains the Fl::focus() or the
|
|
|
|
Fl::pushed() widget these are set to sensible values (other widgets
|
|
|
|
or the Fl_Group widget itself).
|
2008-09-14 02:33:03 +04:00
|
|
|
*/
|
1998-10-06 22:21:25 +04:00
|
|
|
void Fl_Group::clear() {
|
|
|
|
savedfocus_ = 0;
|
|
|
|
resizable_ = this;
|
|
|
|
init_sizes();
|
2010-10-12 12:12:44 +04:00
|
|
|
|
|
|
|
// we must change the Fl::pushed() widget, if it is one of
|
2017-07-07 22:16:40 +03:00
|
|
|
// the group's children. Otherwise fl_fix_focus() would send lots
|
|
|
|
// of events to children that are about to be deleted anyway.
|
2010-10-12 12:12:44 +04:00
|
|
|
|
2020-07-01 19:03:10 +03:00
|
|
|
Fl_Widget *pushed = Fl::pushed(); // save pushed() widget
|
|
|
|
if (contains(pushed)) pushed = this; // set it to be the group, if it's a child
|
|
|
|
Fl::pushed(this); // for fl_fix_focus etc.
|
2010-10-12 12:12:44 +04:00
|
|
|
|
2022-11-01 19:25:07 +03:00
|
|
|
// Implementation note (AlbrechtS, Nov. 01, 2022):
|
|
|
|
// For some obscure reason the order of all children had been
|
|
|
|
// reversed in FLTK 1.3.x so the first child would be deleted
|
|
|
|
// first but this is no longer done since FLTK 1.4.0.
|
|
|
|
// Reasoning:
|
|
|
|
// (1) it is supposedly better to remove children in the
|
|
|
|
// order "last in, first out"
|
|
|
|
// (2) it would not be compatible with the new subclass
|
|
|
|
// notification feature Fl_Group::on_remove().
|
|
|
|
// See git commit a918292547cfb154 or earlier for removed code.
|
|
|
|
// End of implementation note.
|
|
|
|
|
|
|
|
// Okay, now it is safe to destroy the children. Children are
|
|
|
|
// removed and deleted in the order from last child to first
|
|
|
|
// child which is much faster than the other way around and
|
|
|
|
// should be the "natural order" (last in, first out).
|
2010-10-12 12:12:44 +04:00
|
|
|
|
2020-07-01 19:03:10 +03:00
|
|
|
while (children_) { // delete all children
|
|
|
|
int idx = children_-1; // last child's index
|
|
|
|
Fl_Widget* w = child(idx); // last child widget
|
|
|
|
if (w->parent()==this) { // should always be true
|
|
|
|
if (children_>2) { // optimized removal
|
|
|
|
w->parent_ = 0; // reset child's parent
|
2022-11-01 22:45:31 +03:00
|
|
|
on_remove(idx);
|
2020-07-01 19:03:10 +03:00
|
|
|
children_--; // update counter
|
|
|
|
} else { // slow removal
|
2010-10-12 12:12:44 +04:00
|
|
|
remove(idx);
|
|
|
|
}
|
2020-07-01 19:03:10 +03:00
|
|
|
delete w; // delete the child
|
|
|
|
} else { // should never happen
|
|
|
|
remove(idx); // remove it anyway
|
2010-10-12 12:12:44 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pushed != this) Fl::pushed(pushed); // reset pushed() widget
|
|
|
|
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
|
2008-09-14 02:33:03 +04:00
|
|
|
/**
|
|
|
|
The destructor <I>also deletes all the children</I>. This allows a
|
|
|
|
whole tree to be deleted at once, without having to keep a pointer to
|
2009-02-08 20:26:02 +03:00
|
|
|
all the children in the user code.
|
2017-07-07 22:16:40 +03:00
|
|
|
|
2009-02-08 20:26:02 +03:00
|
|
|
It is allowed that the Fl_Group and all of its children are automatic
|
|
|
|
(local) variables, but you must declare the Fl_Group \e first, so that
|
|
|
|
it is destroyed last.
|
2017-07-07 22:16:40 +03:00
|
|
|
|
2009-02-08 20:26:02 +03:00
|
|
|
If you add static or automatic (local) variables to an Fl_Group, then it
|
|
|
|
is your responsibility to remove (or delete) all such static or automatic
|
|
|
|
child widgets \e \b before destroying the group - otherwise the child
|
|
|
|
widgets' destructors would be called twice!
|
2008-09-14 02:33:03 +04:00
|
|
|
*/
|
2001-08-02 01:24:49 +04:00
|
|
|
Fl_Group::~Fl_Group() {
|
2020-06-15 02:38:18 +03:00
|
|
|
if (current_ == this)
|
|
|
|
end();
|
2001-08-02 01:24:49 +04:00
|
|
|
clear();
|
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
|
2022-11-01 22:45:31 +03:00
|
|
|
/**
|
|
|
|
Allow derived groups to act when a widget is added as a child.
|
|
|
|
|
|
|
|
Widgets derived from Fl_Group may store additional data for their children.
|
|
|
|
Overriding this method will allow derived classes to generate these data
|
|
|
|
structures just before the child is added.
|
|
|
|
|
|
|
|
This method usually returns the same index that was given in the parameters.
|
|
|
|
By setting a new index, the position of other widgets in the child pointer
|
|
|
|
array can be preserved (e.g. Fl_Scroll keeps its scroll bars as the last
|
|
|
|
two children).
|
|
|
|
|
|
|
|
By returning -1, Fl_Group::insert will not add the child to
|
|
|
|
array_. This is not recommended, but Fl_Table does something similar to
|
|
|
|
forward children to a hidden group.
|
|
|
|
|
|
|
|
\param candidate the candidate will be added to the child array_ after this
|
|
|
|
method returns.
|
|
|
|
\param index add the child at this position in the array_
|
|
|
|
\return index to position the child as planned
|
|
|
|
\return a new index to force the child to a different position
|
|
|
|
\return -1 to keep the group from adding the candidate
|
|
|
|
*/
|
|
|
|
int Fl_Group::on_insert(Fl_Widget *candidate, int index) {
|
|
|
|
(void)candidate;
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Allow derived groups to act when a widget is moved within the group.
|
|
|
|
|
|
|
|
Widgets derived from Fl_Group may store additional data for their children.
|
|
|
|
Overriding this method will allow derived classes to move these data
|
|
|
|
structures just before the child itself is moved.
|
|
|
|
|
|
|
|
This method usually returns the new index that was given in the
|
|
|
|
parameters. By setting a different destination index, the position of other
|
|
|
|
widgets in the child pointer array can be preserved.
|
|
|
|
|
|
|
|
By returning -1, Fl_Group::insert will not move the child.
|
|
|
|
|
|
|
|
\param oldIndex the current index of the child that will be moved
|
2022-11-17 10:34:06 +03:00
|
|
|
\param newIndex the new index of the child
|
|
|
|
\return \p newIndex to position the child as planned
|
|
|
|
\return a different index to force the child to a different position
|
2022-11-01 22:45:31 +03:00
|
|
|
\return -1 to keep the group from moving the child
|
|
|
|
*/
|
|
|
|
int Fl_Group::on_move(int oldIndex, int newIndex) {
|
|
|
|
(void)oldIndex;
|
|
|
|
return newIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-09-14 02:33:03 +04:00
|
|
|
/**
|
2008-12-09 11:49:25 +03:00
|
|
|
The widget is removed from its current group (if any) and then
|
2009-02-08 20:26:02 +03:00
|
|
|
inserted into this group. It is put at index n - or at the end,
|
2008-12-09 11:49:25 +03:00
|
|
|
if n >= children(). This can also be used to rearrange
|
2008-09-14 02:33:03 +04:00
|
|
|
the widgets inside a group.
|
|
|
|
*/
|
2000-10-22 00:01:56 +04:00
|
|
|
void Fl_Group::insert(Fl_Widget &o, int index) {
|
|
|
|
if (o.parent()) {
|
2010-02-21 00:14:47 +03:00
|
|
|
Fl_Group* g = o.parent();
|
2000-10-22 00:01:56 +04:00
|
|
|
int n = g->find(o);
|
2022-11-17 10:34:06 +03:00
|
|
|
if (g == this) {
|
|
|
|
// avoid expensive remove() and add() if we just move a widget within the group
|
2022-11-01 22:45:31 +03:00
|
|
|
index = on_move(n, index);
|
2022-11-20 16:11:19 +03:00
|
|
|
if (index < 0) return; // don't move: requested by subclass
|
|
|
|
if (index > children_)
|
|
|
|
index = children_;
|
|
|
|
if (index > n) index--; // compensate for removal and re-insertion
|
|
|
|
if (index == n) return; // same position; this includes (children_ == 1)
|
2022-11-01 22:45:31 +03:00
|
|
|
if (index > n)
|
|
|
|
memmove(array_+n, array_+(n+1), (index-n) * sizeof(Fl_Widget*));
|
|
|
|
else
|
|
|
|
memmove(array_+(index+1), array_+index, (n-index) * sizeof(Fl_Widget*));
|
|
|
|
array_[index] = &o;
|
|
|
|
init_sizes();
|
|
|
|
return;
|
2000-10-22 00:01:56 +04:00
|
|
|
}
|
2010-08-31 14:01:59 +04:00
|
|
|
g->remove(n);
|
2000-10-22 00:01:56 +04:00
|
|
|
}
|
2022-11-01 22:45:31 +03:00
|
|
|
|
|
|
|
index = on_insert(&o, index);
|
|
|
|
if (index == -1) return;
|
|
|
|
|
1998-10-06 22:21:25 +04:00
|
|
|
o.parent_ = this;
|
|
|
|
if (children_ == 0) { // use array pointer to point at single child
|
2020-07-09 04:07:50 +03:00
|
|
|
child1_ = &o;
|
1998-10-06 22:21:25 +04:00
|
|
|
} else if (children_ == 1) { // go from 1 to 2 children
|
2020-07-09 04:07:50 +03:00
|
|
|
Fl_Widget* t = child1_;
|
1998-10-06 22:21:25 +04:00
|
|
|
array_ = (Fl_Widget**)malloc(2*sizeof(Fl_Widget*));
|
2000-10-22 00:01:56 +04:00
|
|
|
if (index) {array_[0] = t; array_[1] = &o;}
|
1998-12-29 16:59:48 +03:00
|
|
|
else {array_[0] = &o; array_[1] = t;}
|
1998-10-06 22:21:25 +04:00
|
|
|
} else {
|
|
|
|
if (!(children_ & (children_-1))) // double number of children
|
|
|
|
array_ = (Fl_Widget**)realloc((void*)array_,
|
2020-07-01 19:03:10 +03:00
|
|
|
2*children_*sizeof(Fl_Widget*));
|
2000-10-22 00:01:56 +04:00
|
|
|
int j; for (j = children_; j > index; j--) array_[j] = array_[j-1];
|
1998-12-29 16:59:48 +03:00
|
|
|
array_[j] = &o;
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
children_++;
|
|
|
|
init_sizes();
|
|
|
|
}
|
|
|
|
|
2008-09-14 02:33:03 +04:00
|
|
|
/**
|
2008-12-09 11:49:25 +03:00
|
|
|
The widget is removed from its current group (if any) and then added
|
2008-09-14 02:33:03 +04:00
|
|
|
to the end of this group.
|
|
|
|
*/
|
1998-10-06 22:21:25 +04:00
|
|
|
void Fl_Group::add(Fl_Widget &o) {insert(o, children_);}
|
|
|
|
|
2022-11-01 22:45:31 +03:00
|
|
|
/**
|
|
|
|
Allow derived groups to act when a child widget is removed from the group.
|
|
|
|
|
|
|
|
Widgets derived from Fl_Group may store additional data for their children.
|
|
|
|
Overriding this method will allow derived classes to remove these data
|
|
|
|
structures just before the child is removed.
|
|
|
|
|
|
|
|
\param index remove the child at this position in the array_
|
|
|
|
*/
|
|
|
|
void Fl_Group::on_remove(int index) {
|
|
|
|
(void)index;
|
|
|
|
}
|
|
|
|
|
2008-09-14 02:33:03 +04:00
|
|
|
/**
|
2010-08-31 14:01:59 +04:00
|
|
|
Removes the widget at \p index from the group but does not delete it.
|
2008-12-09 11:49:25 +03:00
|
|
|
|
2010-08-31 14:01:59 +04:00
|
|
|
This method does nothing if \p index is out of bounds.
|
2008-12-09 11:49:25 +03:00
|
|
|
|
|
|
|
This method differs from the clear() method in that it only affects
|
|
|
|
a single widget and does not delete it from memory.
|
2017-07-07 22:16:40 +03:00
|
|
|
|
2010-08-31 14:01:59 +04:00
|
|
|
\since FLTK 1.3.0
|
2008-09-14 02:33:03 +04:00
|
|
|
*/
|
2010-08-31 14:01:59 +04:00
|
|
|
void Fl_Group::remove(int index) {
|
|
|
|
if (index < 0 || index >= children_) return;
|
2022-11-01 22:45:31 +03:00
|
|
|
on_remove(index);
|
|
|
|
|
2010-08-31 14:01:59 +04:00
|
|
|
Fl_Widget &o = *child(index);
|
1998-10-06 22:21:25 +04:00
|
|
|
if (&o == savedfocus_) savedfocus_ = 0;
|
2022-10-28 18:37:18 +03:00
|
|
|
if (&o == resizable_) resizable_ = this;
|
2020-07-01 19:03:10 +03:00
|
|
|
if (o.parent_ == this) { // this should always be true
|
2009-01-08 20:12:34 +03:00
|
|
|
o.parent_ = 0;
|
2017-07-07 22:16:40 +03:00
|
|
|
}
|
2009-01-08 20:12:34 +03:00
|
|
|
|
|
|
|
// remove the widget from the group
|
|
|
|
|
1998-10-06 22:21:25 +04:00
|
|
|
children_--;
|
|
|
|
if (children_ == 1) { // go from 2 to 1 child
|
2010-08-31 14:01:59 +04:00
|
|
|
Fl_Widget *t = array_[!index];
|
1998-10-06 22:21:25 +04:00
|
|
|
free((void*)array_);
|
2020-07-09 04:07:50 +03:00
|
|
|
child1_ = t;
|
1998-10-06 22:21:25 +04:00
|
|
|
} else if (children_ > 1) { // delete from array
|
2010-08-31 14:01:59 +04:00
|
|
|
for (; index < children_; index++) array_[index] = array_[index+1];
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
init_sizes();
|
|
|
|
}
|
|
|
|
|
2010-08-31 14:01:59 +04:00
|
|
|
/**
|
|
|
|
Removes a widget from the group but does not delete it.
|
|
|
|
|
|
|
|
This method does nothing if the widget is not a child of the group.
|
|
|
|
|
|
|
|
This method differs from the clear() method in that it only affects
|
|
|
|
a single widget and does not delete it from memory.
|
2017-07-07 22:16:40 +03:00
|
|
|
|
2010-08-31 14:01:59 +04:00
|
|
|
\note If you have the child's index anyway, use remove(int index)
|
|
|
|
instead, because this doesn't need a child lookup in the group's
|
|
|
|
table of children. This can be much faster, if there are lots of
|
|
|
|
children.
|
|
|
|
*/
|
|
|
|
void Fl_Group::remove(Fl_Widget &o) {
|
|
|
|
if (!children_) return;
|
|
|
|
int i = find(o);
|
|
|
|
if (i < children_) remove(i);
|
|
|
|
}
|
|
|
|
|
2021-05-25 18:39:20 +03:00
|
|
|
/**
|
|
|
|
Removes the widget at \p index from the group and deletes it.
|
|
|
|
|
|
|
|
This method does nothing if \p index is out of bounds.
|
|
|
|
|
|
|
|
This method differs from the remove() method in that it deletes
|
|
|
|
the widget from memory. Since this method is virtual it can be
|
|
|
|
reimplemented in subclasses with additional requirements and
|
|
|
|
consequences. See the documentation of subclasses.
|
|
|
|
|
|
|
|
Many subclasses don't need to reimplement this method.
|
|
|
|
|
|
|
|
\note This method \b may refuse to remove and delete the widget
|
|
|
|
if it is an essential part of the Fl_Group, for instance
|
|
|
|
a scrollbar in an Fl_Scroll group. In this case the widget is
|
|
|
|
neither removed nor deleted.
|
|
|
|
|
|
|
|
This method does not call init_sizes() or redraw(). This is left
|
|
|
|
to user code if necessary.
|
|
|
|
|
|
|
|
Returns 0 if the widget was removed and deleted.
|
|
|
|
Return values \> 0 are reserved for use by FLTK core widgets.
|
|
|
|
Return values \< 0 are free to be used by user defined widgets.
|
|
|
|
|
2022-08-15 22:29:00 +03:00
|
|
|
\todo Reimplementation of Fl_Group::delete_child(int) in more FLTK
|
2021-05-25 18:39:20 +03:00
|
|
|
subclasses. This is not yet complete.
|
|
|
|
|
|
|
|
\param[in] index index of child to be removed
|
|
|
|
|
|
|
|
\returns success (0) or error code
|
|
|
|
\retval 0 success
|
|
|
|
\retval 1 index out of range
|
|
|
|
\retval 2 widget not allowed to be removed (see note)
|
|
|
|
\retval >2 reserved for FLTK use
|
|
|
|
|
|
|
|
\since FLTK 1.4.0
|
|
|
|
*/
|
|
|
|
int Fl_Group::delete_child(int index) {
|
|
|
|
if (index < 0 || index >= children_)
|
|
|
|
return 1;
|
|
|
|
Fl_Widget *w = child(index);
|
|
|
|
remove(index);
|
|
|
|
delete w;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-09-14 02:33:03 +04:00
|
|
|
/**
|
2008-12-09 11:49:25 +03:00
|
|
|
Resets the internal array of widget sizes and positions.
|
|
|
|
|
2008-09-14 02:33:03 +04:00
|
|
|
The Fl_Group widget keeps track of the original widget sizes and
|
2017-07-07 22:16:40 +03:00
|
|
|
positions when resizing occurs so that if you resize a window back to
|
|
|
|
its original size the widgets will be in the correct places. If you
|
|
|
|
rearrange the widgets in your group, call this method to register the
|
|
|
|
new arrangement with the Fl_Group that contains them.
|
|
|
|
|
2008-09-29 02:25:23 +04:00
|
|
|
If you add or remove widgets, this will be done automatically.
|
2017-07-07 22:16:40 +03:00
|
|
|
|
|
|
|
\note The internal array of widget sizes and positions will be allocated
|
2020-07-01 19:03:10 +03:00
|
|
|
and filled when the next resize() occurs. For more information on
|
|
|
|
the contents and structure of the bounds() array see bounds().
|
2017-07-07 22:16:40 +03:00
|
|
|
|
|
|
|
\see bounds()
|
|
|
|
\see sizes() (deprecated)
|
2008-09-14 02:33:03 +04:00
|
|
|
*/
|
1998-10-06 22:21:25 +04:00
|
|
|
void Fl_Group::init_sizes() {
|
2017-07-07 22:16:40 +03:00
|
|
|
delete[] bounds_;
|
|
|
|
bounds_ = 0;
|
2020-07-01 19:03:10 +03:00
|
|
|
delete[] sizes_; // FLTK 1.3 compatibility
|
|
|
|
sizes_ = 0; // FLTK 1.3 compatibility
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
|
2008-09-29 02:25:23 +04:00
|
|
|
/**
|
2008-12-09 11:49:25 +03:00
|
|
|
Returns the internal array of widget sizes and positions.
|
|
|
|
|
2017-07-07 22:16:40 +03:00
|
|
|
If the bounds() array does not exist, it will be allocated and filled
|
2008-09-29 02:25:23 +04:00
|
|
|
with the current widget sizes and positions.
|
2008-12-09 11:49:25 +03:00
|
|
|
|
2017-07-07 22:16:40 +03:00
|
|
|
The bounds() array stores the initial positions of widgets as Fl_Rect's.
|
|
|
|
The size of the array is children() + 2.
|
|
|
|
|
|
|
|
- The first Fl_Rect is the group,
|
|
|
|
- the second is the resizable (clipped to the group),
|
|
|
|
- the rest are the children.
|
|
|
|
|
|
|
|
This is a convenient order for the resize algorithm.
|
|
|
|
|
|
|
|
If the group and/or the resizable() is a Fl_Window (or subclass) then
|
|
|
|
the x() and y() coordinates of their respective Fl_Rect's are zero.
|
2008-12-09 11:49:25 +03:00
|
|
|
|
2017-07-07 22:16:40 +03:00
|
|
|
\note You should never need to use this \e protected method directly,
|
2020-07-01 19:03:10 +03:00
|
|
|
unless you have special needs to rearrange the children of a
|
|
|
|
Fl_Group. Fl_Tile uses this to rearrange its widget positions.
|
|
|
|
The returned array should be considered read-only. Do not change
|
|
|
|
its contents. If you need to rearrange children in a group, do
|
|
|
|
so by resizing the children and call init_sizes().
|
2017-07-07 22:16:40 +03:00
|
|
|
|
2018-04-12 15:58:10 +03:00
|
|
|
\#include \<FL/Fl_Rect.H\> if you want to access the bounds() array in
|
|
|
|
your derived class. Fl_Rect.H is intentionally not included by
|
|
|
|
Fl_Group.H to avoid unnecessary dependencies.
|
|
|
|
|
|
|
|
\returns Array of Fl_Rect's with widget positions and sizes. The
|
2020-07-01 19:03:10 +03:00
|
|
|
returned array is only valid until init_sizes() is called
|
|
|
|
or widgets are added to or removed from the group.
|
2018-04-12 15:58:10 +03:00
|
|
|
|
2017-07-07 22:16:40 +03:00
|
|
|
\see init_sizes()
|
|
|
|
|
|
|
|
\since FLTK 1.4.0
|
|
|
|
|
2018-04-12 15:58:10 +03:00
|
|
|
\internal Notes to developers:
|
|
|
|
- If you change this be sure to fix Fl_Tile which also uses this array!
|
2023-01-02 17:55:55 +03:00
|
|
|
- Do not \#include Fl_Rect.H in Fl_Group.H because this would introduce
|
2018-04-12 15:58:10 +03:00
|
|
|
lots of unnecessary dependencies on Fl_Rect.H.
|
2008-12-09 11:49:25 +03:00
|
|
|
*/
|
2017-07-07 22:16:40 +03:00
|
|
|
Fl_Rect* Fl_Group::bounds() {
|
|
|
|
if (!bounds_) {
|
|
|
|
Fl_Rect* p = bounds_ = new Fl_Rect[children_+2];
|
|
|
|
// first thing in bounds array is the group's size:
|
|
|
|
if (as_window())
|
|
|
|
p[0] = Fl_Rect(w(),h()); // x = y = 0
|
|
|
|
else
|
|
|
|
p[0] = Fl_Rect(this);
|
1998-10-06 22:21:25 +04:00
|
|
|
// next is the resizable's size:
|
2017-07-07 22:16:40 +03:00
|
|
|
int left = p->x(); // init to the group's position and size
|
|
|
|
int top = p->y();
|
|
|
|
int right = p->r();
|
|
|
|
int bottom = p->b();
|
1998-10-06 22:21:25 +04:00
|
|
|
Fl_Widget* r = resizable();
|
|
|
|
if (r && r != this) { // then clip the resizable to it
|
|
|
|
int t;
|
2017-07-07 22:16:40 +03:00
|
|
|
t = r->x(); if (t > left) left = t;
|
|
|
|
t +=r->w(); if (t < right) right = t;
|
|
|
|
t = r->y(); if (t > top) top = t;
|
|
|
|
t +=r->h(); if (t < bottom) bottom = t;
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
2017-07-07 22:16:40 +03:00
|
|
|
p[1] = Fl_Rect(left, top, right-left, bottom-top);
|
1998-10-06 22:21:25 +04:00
|
|
|
// next is all the children's sizes:
|
2017-07-07 22:16:40 +03:00
|
|
|
p += 2;
|
1998-10-06 22:21:25 +04:00
|
|
|
Fl_Widget*const* a = array();
|
|
|
|
for (int i=children_; i--;) {
|
2017-07-07 22:16:40 +03:00
|
|
|
*p++ = Fl_Rect(*a++);
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
}
|
2017-07-07 22:16:40 +03:00
|
|
|
return bounds_;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Returns the internal array of widget sizes and positions.
|
|
|
|
|
|
|
|
For backward compatibility with FLTK versions before 1.4.
|
|
|
|
|
|
|
|
The sizes() array stores the initial positions of widgets as
|
|
|
|
(left, right, top, bottom) quads. The first quad is the group, the
|
|
|
|
second is the resizable (clipped to the group), and the rest are the
|
|
|
|
children. If the group and/or the resizable() is a Fl_Window, then
|
|
|
|
the first (left) and third (top) entries of their respective quads
|
|
|
|
(x,y) are zero.
|
|
|
|
|
|
|
|
\deprecated Deprecated since 1.4.0. Please use bounds() instead.
|
|
|
|
|
|
|
|
\note This method will be removed in a future FLTK version (1.5.0 or higher).
|
|
|
|
|
2020-07-01 19:03:10 +03:00
|
|
|
\returns Array of int's with widget positions and sizes. The returned
|
|
|
|
array is only valid until init_sizes() is called or widgets
|
|
|
|
are added to or removed from the group.
|
2017-07-07 22:16:40 +03:00
|
|
|
|
2020-07-01 19:03:10 +03:00
|
|
|
\note Since FLTK 1.4.0 the returned array is a \b read-only and re-ordered
|
|
|
|
copy of the internal bounds() array. Do not change its contents.
|
|
|
|
If you need to rearrange children in a group, do so by resizing
|
|
|
|
the children and call init_sizes().
|
2017-07-07 22:16:40 +03:00
|
|
|
|
|
|
|
\see bounds()
|
|
|
|
*/
|
|
|
|
int* Fl_Group::sizes()
|
|
|
|
{
|
|
|
|
if (sizes_) return sizes_;
|
|
|
|
// allocate new sizes_ array and copy bounds_ over to sizes_
|
|
|
|
int* pi = sizes_ = new int[4*(children_+2)];
|
|
|
|
Fl_Rect *rb = bounds();
|
|
|
|
for (int i = 0; i < children_+2; i++, rb++) {
|
|
|
|
*pi++ = rb->x();
|
|
|
|
*pi++ = rb->r();
|
|
|
|
*pi++ = rb->y();
|
|
|
|
*pi++ = rb->b();
|
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
return sizes_;
|
|
|
|
}
|
2008-12-09 11:49:25 +03:00
|
|
|
|
2008-09-29 02:25:23 +04:00
|
|
|
/**
|
2008-12-09 11:49:25 +03:00
|
|
|
Resizes the Fl_Group widget and all of its children.
|
|
|
|
|
2008-09-29 02:25:23 +04:00
|
|
|
The Fl_Group widget first resizes itself, and then it moves and resizes
|
|
|
|
all its children according to the rules documented for
|
|
|
|
Fl_Group::resizable(Fl_Widget*)
|
2008-12-09 11:49:25 +03:00
|
|
|
|
2008-09-29 02:25:23 +04:00
|
|
|
\sa Fl_Group::resizable(Fl_Widget*)
|
|
|
|
\sa Fl_Group::resizable()
|
|
|
|
\sa Fl_Widget::resize(int,int,int,int)
|
|
|
|
*/
|
1998-10-06 22:21:25 +04:00
|
|
|
void Fl_Group::resize(int X, int Y, int W, int H) {
|
|
|
|
|
2018-03-29 18:09:32 +03:00
|
|
|
int dx = X - x();
|
|
|
|
int dy = Y - y();
|
|
|
|
int dw = W - w();
|
|
|
|
int dh = H - h();
|
2017-07-07 22:16:40 +03:00
|
|
|
|
|
|
|
Fl_Rect* p = bounds(); // save initial sizes and positions
|
2008-09-07 15:22:14 +04:00
|
|
|
|
2018-03-29 18:09:32 +03:00
|
|
|
Fl_Widget::resize(X, Y, W, H); // make new xywh values visible for children
|
2008-09-07 15:22:14 +04:00
|
|
|
|
2020-05-08 18:08:20 +03:00
|
|
|
if ((!resizable() || (dw==0 && dh==0 )) && !Fl_Window::is_a_rescale()) {
|
1998-10-06 22:21:25 +04:00
|
|
|
|
2017-07-07 22:16:40 +03:00
|
|
|
if (!as_window()) {
|
1998-10-06 22:21:25 +04:00
|
|
|
Fl_Widget*const* a = array();
|
|
|
|
for (int i=children_; i--;) {
|
2020-07-01 19:03:10 +03:00
|
|
|
Fl_Widget* o = *a++;
|
|
|
|
o->resize(o->x() + dx, o->y() + dy, o->w(), o->h());
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (children_) {
|
|
|
|
|
|
|
|
// get changes in size/position from the initial size:
|
2017-07-07 22:16:40 +03:00
|
|
|
dx = X - p->x();
|
|
|
|
dw = W - p->w();
|
|
|
|
dy = Y - p->y();
|
2018-03-29 18:09:32 +03:00
|
|
|
dh = H - p->h();
|
|
|
|
if (as_window())
|
|
|
|
dx = dy = 0;
|
|
|
|
p++;
|
|
|
|
|
|
|
|
// Developer note:
|
|
|
|
// The following code uses T = top, L = left, R = right, and B = bottom
|
|
|
|
// widget bounds. T and L are equivalent to x() and y(), whereas
|
|
|
|
// R = x() + w() and B = y() + h(), respectively, i.e. the next pixel
|
|
|
|
// beyond the widget border.
|
|
|
|
// RL, RR, RT, and RB are those values of the resizable widget.
|
1998-10-06 22:21:25 +04:00
|
|
|
|
|
|
|
// get initial size of resizable():
|
2018-03-29 18:09:32 +03:00
|
|
|
int RL = p->x();
|
|
|
|
int RR = RL + p->w();
|
|
|
|
int RT = p->y();
|
|
|
|
int RB = RT + p->h();
|
|
|
|
p++;
|
1998-10-06 22:21:25 +04:00
|
|
|
|
2018-03-29 18:09:32 +03:00
|
|
|
// resize children
|
1998-10-06 22:21:25 +04:00
|
|
|
Fl_Widget*const* a = array();
|
2018-03-29 18:09:32 +03:00
|
|
|
|
|
|
|
for (int i = children_; i--; p++) {
|
|
|
|
|
1998-10-06 22:21:25 +04:00
|
|
|
Fl_Widget* o = *a++;
|
2018-03-29 18:09:32 +03:00
|
|
|
int L = p->x();
|
|
|
|
int R = L + p->w();
|
|
|
|
int T = p->y();
|
|
|
|
int B = T + p->h();
|
|
|
|
|
2022-01-08 18:23:01 +03:00
|
|
|
// widget resizing code from Francois Ostiguy (since FLTK 1.4.0)
|
2018-03-29 18:09:32 +03:00
|
|
|
|
|
|
|
if (L >= RR) L += dw;
|
|
|
|
else if (L > RL) L += dw * (L-RL) / (RR-RL);
|
|
|
|
if (R >= RR) R += dw;
|
2018-03-30 13:11:24 +03:00
|
|
|
else if (R > RL) R += dw * (R-RL) / (RR-RL);
|
2018-03-29 18:09:32 +03:00
|
|
|
if (T >= RB) T += dh;
|
2018-03-30 13:11:24 +03:00
|
|
|
else if (T > RT) T += dh * (T-RT) / (RB-RT);
|
2018-03-29 18:09:32 +03:00
|
|
|
if (B >= RB) B += dh;
|
2018-03-30 13:11:24 +03:00
|
|
|
else if (B > RT) B += dh * (B-RT) / (RB-RT);
|
2018-03-29 18:09:32 +03:00
|
|
|
|
|
|
|
o->resize(L+dx, T+dy, R-L, B-T);
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-09-29 02:25:23 +04:00
|
|
|
/**
|
2008-12-09 11:49:25 +03:00
|
|
|
Draws all children of the group.
|
|
|
|
|
2008-09-29 02:25:23 +04:00
|
|
|
This is useful, if you derived a widget from Fl_Group and want to draw a special
|
|
|
|
border or background. You can call draw_children() from the derived draw() method
|
|
|
|
after drawing the box, border, or background.
|
|
|
|
*/
|
2002-11-08 18:22:15 +03:00
|
|
|
void Fl_Group::draw_children() {
|
1998-10-06 22:21:25 +04:00
|
|
|
Fl_Widget*const* a = array();
|
2007-12-15 19:42:00 +03:00
|
|
|
|
2007-12-17 02:34:06 +03:00
|
|
|
if (clip_children()) {
|
|
|
|
fl_push_clip(x() + Fl::box_dx(box()),
|
|
|
|
y() + Fl::box_dy(box()),
|
2020-07-01 19:03:10 +03:00
|
|
|
w() - Fl::box_dw(box()),
|
|
|
|
h() - Fl::box_dh(box()));
|
2007-12-17 02:34:06 +03:00
|
|
|
}
|
2007-12-15 19:42:00 +03:00
|
|
|
|
1998-10-19 21:53:09 +04:00
|
|
|
if (damage() & ~FL_DAMAGE_CHILD) { // redraw the entire thing:
|
1998-10-06 22:21:25 +04:00
|
|
|
for (int i=children_; i--;) {
|
|
|
|
Fl_Widget& o = **a++;
|
|
|
|
draw_child(o);
|
|
|
|
draw_outside_label(o);
|
|
|
|
}
|
2020-07-01 19:03:10 +03:00
|
|
|
} else { // only redraw the children that need it:
|
1998-10-06 22:21:25 +04:00
|
|
|
for (int i=children_; i--;) update_child(**a++);
|
|
|
|
}
|
2007-12-15 19:42:00 +03:00
|
|
|
|
|
|
|
if (clip_children()) fl_pop_clip();
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
|
2002-11-08 18:22:15 +03:00
|
|
|
void Fl_Group::draw() {
|
|
|
|
if (damage() & ~FL_DAMAGE_CHILD) { // redraw the entire thing:
|
|
|
|
draw_box();
|
|
|
|
draw_label();
|
|
|
|
}
|
|
|
|
draw_children();
|
|
|
|
}
|
|
|
|
|
2008-09-29 02:25:23 +04:00
|
|
|
/**
|
|
|
|
Draws a child only if it needs it.
|
2008-12-09 11:49:25 +03:00
|
|
|
|
2008-09-29 02:25:23 +04:00
|
|
|
This draws a child widget, if it is not clipped \em and if any damage() bits
|
|
|
|
are set. The damage bits are cleared after drawing.
|
2008-12-09 11:49:25 +03:00
|
|
|
|
2008-09-29 02:25:23 +04:00
|
|
|
\sa Fl_Group::draw_child(Fl_Widget& widget) const
|
|
|
|
*/
|
2002-08-09 05:09:49 +04:00
|
|
|
void Fl_Group::update_child(Fl_Widget& widget) const {
|
|
|
|
if (widget.damage() && widget.visible() && widget.type() < FL_WINDOW &&
|
|
|
|
fl_not_clipped(widget.x(), widget.y(), widget.w(), widget.h())) {
|
2017-07-07 22:16:40 +03:00
|
|
|
widget.draw();
|
2002-08-09 05:09:49 +04:00
|
|
|
widget.clear_damage();
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-09 11:49:25 +03:00
|
|
|
/**
|
|
|
|
Forces a child to redraw.
|
2008-09-29 02:25:23 +04:00
|
|
|
|
|
|
|
This draws a child widget, if it is not clipped.
|
|
|
|
The damage bits are cleared after drawing.
|
|
|
|
*/
|
2002-08-09 05:09:49 +04:00
|
|
|
void Fl_Group::draw_child(Fl_Widget& widget) const {
|
|
|
|
if (widget.visible() && widget.type() < FL_WINDOW &&
|
|
|
|
fl_not_clipped(widget.x(), widget.y(), widget.w(), widget.h())) {
|
|
|
|
widget.clear_damage(FL_DAMAGE_ALL);
|
|
|
|
widget.draw();
|
|
|
|
widget.clear_damage();
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-09-29 02:25:23 +04:00
|
|
|
/** Parents normally call this to draw outside labels of child widgets. */
|
2002-08-09 05:09:49 +04:00
|
|
|
void Fl_Group::draw_outside_label(const Fl_Widget& widget) const {
|
|
|
|
if (!widget.visible()) return;
|
1998-10-06 22:21:25 +04:00
|
|
|
// skip any labels that are inside the widget:
|
2002-08-09 05:09:49 +04:00
|
|
|
if (!(widget.align()&15) || (widget.align() & FL_ALIGN_INSIDE)) return;
|
1998-10-06 22:21:25 +04:00
|
|
|
// invent a box that is outside the widget:
|
2010-08-24 12:16:54 +04:00
|
|
|
Fl_Align a = widget.align();
|
2002-08-09 05:09:49 +04:00
|
|
|
int X = widget.x();
|
|
|
|
int Y = widget.y();
|
|
|
|
int W = widget.w();
|
|
|
|
int H = widget.h();
|
2010-10-31 01:32:15 +04:00
|
|
|
int wx, wy;
|
|
|
|
if (const_cast<Fl_Group*>(this)->as_window()) {
|
|
|
|
wx = wy = 0;
|
|
|
|
} else {
|
|
|
|
wx = x(); wy = y();
|
|
|
|
}
|
2017-02-27 20:00:41 +03:00
|
|
|
if ( (a & FL_ALIGN_POSITION_MASK) == FL_ALIGN_LEFT_TOP ) {
|
|
|
|
a = (a &(~FL_ALIGN_POSITION_MASK) ) | FL_ALIGN_TOP_RIGHT;
|
2010-10-31 01:32:15 +04:00
|
|
|
X = wx;
|
2010-04-08 03:17:33 +04:00
|
|
|
W = widget.x()-X-3;
|
2017-02-27 20:00:41 +03:00
|
|
|
} else if ( (a & FL_ALIGN_POSITION_MASK) == FL_ALIGN_LEFT_BOTTOM ) {
|
|
|
|
a = (a &(~FL_ALIGN_POSITION_MASK) ) | FL_ALIGN_BOTTOM_RIGHT;
|
2010-10-31 01:32:15 +04:00
|
|
|
X = wx;
|
2010-04-08 03:17:33 +04:00
|
|
|
W = widget.x()-X-3;
|
2017-02-27 20:00:41 +03:00
|
|
|
} else if ( (a & FL_ALIGN_POSITION_MASK) == FL_ALIGN_RIGHT_TOP ) {
|
|
|
|
a = (a &(~FL_ALIGN_POSITION_MASK) ) | FL_ALIGN_TOP_LEFT;
|
2010-04-08 03:17:33 +04:00
|
|
|
X = X+W+3;
|
2010-10-31 01:32:15 +04:00
|
|
|
W = wx+this->w()-X;
|
2017-02-27 20:00:41 +03:00
|
|
|
} else if ( (a & FL_ALIGN_POSITION_MASK) == FL_ALIGN_RIGHT_BOTTOM ) {
|
|
|
|
a = (a &(~FL_ALIGN_POSITION_MASK) ) | FL_ALIGN_BOTTOM_LEFT;
|
2010-04-08 03:17:33 +04:00
|
|
|
X = X+W+3;
|
2010-10-31 01:32:15 +04:00
|
|
|
W = wx+this->w()-X;
|
2010-04-08 03:17:33 +04:00
|
|
|
} else if (a & FL_ALIGN_TOP) {
|
2017-02-27 20:00:41 +03:00
|
|
|
a ^= FL_ALIGN_TOP;
|
|
|
|
a |= FL_ALIGN_BOTTOM;
|
2010-10-31 01:32:15 +04:00
|
|
|
Y = wy;
|
2002-08-09 05:09:49 +04:00
|
|
|
H = widget.y()-Y;
|
|
|
|
} else if (a & FL_ALIGN_BOTTOM) {
|
2017-02-27 20:00:41 +03:00
|
|
|
a ^= FL_ALIGN_BOTTOM;
|
|
|
|
a |= FL_ALIGN_TOP;
|
1998-10-06 22:21:25 +04:00
|
|
|
Y = Y+H;
|
2010-10-31 01:32:15 +04:00
|
|
|
H = wy+h()-Y;
|
2002-08-09 05:09:49 +04:00
|
|
|
} else if (a & FL_ALIGN_LEFT) {
|
2017-02-27 20:00:41 +03:00
|
|
|
a ^= FL_ALIGN_LEFT;
|
|
|
|
a |= FL_ALIGN_RIGHT;
|
2010-10-31 01:32:15 +04:00
|
|
|
X = wx;
|
2002-08-09 05:09:49 +04:00
|
|
|
W = widget.x()-X-3;
|
|
|
|
} else if (a & FL_ALIGN_RIGHT) {
|
2017-02-27 20:00:41 +03:00
|
|
|
a ^= FL_ALIGN_RIGHT;
|
|
|
|
a |= FL_ALIGN_LEFT;
|
1998-10-06 22:21:25 +04:00
|
|
|
X = X+W+3;
|
2010-10-31 01:32:15 +04:00
|
|
|
W = wx+this->w()-X;
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
2002-08-09 05:09:49 +04:00
|
|
|
widget.draw_label(X,Y,W,H,(Fl_Align)a);
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|