/*************************************************************************** CContainer.cpp The Container class (c) 2000-2007 Benoit Minisini This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ***************************************************************************/ #define __CCONTAINER_CPP #include #include #include #include #include #include "gambas.h" #include "CWidget.h" #include "CWindow.h" #include "CConst.h" #include "CScrollView.h" #include "CContainer.h" // #define DEBUG_ME DECLARE_EVENT(EVENT_Insert); //DECLARE_EVENT(EVENT_Remove); DECLARE_EVENT(EVENT_Arrange); static QWidget *get_widget(QObjectList *list) { for(;;) { QObject *ob = list->current(); if (!ob) return NULL; list->next(); if (ob->isWidgetType()) { if (!((QWidget *)ob)->isHidden() && !((QWidget *)ob)->isA("QSizeGrip")) return (QWidget *)ob; } } } static void resize_container(QWidget *wid, QWidget *cont, int w, int h) { wid->resize(w + wid->width() - cont->width(), h + wid->height() - cont->height()); } #define WIDGET_TYPE QWidget * #define CONTAINER_TYPE QFrame * #define ARRANGEMENT_TYPE CCONTAINER_ARRANGEMENT * #define IS_RIGHT_TO_LEFT() qApp->reverseLayout() #define GET_WIDGET(_object) ((CWIDGET *)_object)->widget #define GET_CONTAINER(_object) ((CCONTAINER *)_object)->container #define GET_ARRANGEMENT(_object) ((CCONTAINER_ARRANGEMENT *)_object) #define IS_EXPAND(_object) (((CWIDGET *)_object)->flag.expand) #define IS_IGNORE(_object) (((CWIDGET *)_object)->flag.ignore) #define IS_DESIGN(_object) (CWIDGET_test_flag(_object, WF_DESIGN) && CWIDGET_test_flag(_object, WF_DESIGN_LEADER)) #define IS_WIDGET_VISIBLE(_widget) (_widget)->isVisible() #define CAN_ARRANGE(_object) ((_object) && (IS_WIDGET_VISIBLE(GET_CONTAINER(_object)) || IS_WIDGET_VISIBLE(GET_WIDGET(_object)))) #define GET_WIDGET_CONTENTS(_widget, _x, _y, _w, _h) \ _x = (_widget)->contentsRect().x(); \ _y = (_widget)->contentsRect().y(); \ _w = (_widget)->contentsRect().width(); \ _h = (_widget)->contentsRect().height(); #define GET_WIDGET_X(_widget) (_widget)->x() #define GET_WIDGET_Y(_widget) (_widget)->y() #define GET_WIDGET_W(_widget) (_widget)->width() #define GET_WIDGET_H(_widget) (_widget)->height() #define MOVE_WIDGET(_widget, _x, _y) (_widget)->move(_x, _y) #define RESIZE_WIDGET(_widget, _w, _h) (_widget)->resize(_w, _h) #define RESIZE_CONTAINER(_widget, _cont, _w, _h) resize_container((_widget), (_cont), (_w), (_h)) #define MOVE_RESIZE_WIDGET(_widget, _x, _y, _w, _h) (_widget)->setGeometry(_x, _y, _w, _h) #define INIT_CHECK_CHILDREN_LIST(_widget) \ QObjectList *list = (QObjectList *)(_widget)->children(); \ if (!list || list->count() == 0) \ return; #define RESET_CHILDREN_LIST() list->first() #define GET_NEXT_CHILD_WIDGET() get_widget(list) #define GET_OBJECT_FROM_WIDGET(_widget) CWidget::getValid(CWidget::get(_widget)) #define RAISE_ARRANGE_EVENT(_object) \ { \ GB.Raise(_object, EVENT_Arrange, 0); \ } //THIS_ARRANGEMENT->dirty = FALSE; #define FUNCTION_NAME CCONTAINER_arrange #include "gb.form.arrangement.h" static int max_w, max_h; static void move_widget(QWidget *wid, int x, int y) { int w = x + wid->width(); int h = y + wid->height(); if (w > max_w) max_w = w; if (h > max_h) max_h = h; } static void move_resize_widget(QWidget *wid, int x, int y, int w, int h) { w += x; h += y; if (w > max_w) max_w = w; if (h > max_h) max_h = h; } #undef MOVE_WIDGET #define MOVE_WIDGET(_widget, _x, _y) move_widget(_widget, _x, _y) #undef RESIZE_WIDGET #define RESIZE_WIDGET(_widget, _w, _h) (0) #undef MOVE_RESIZE_WIDGET #define MOVE_RESIZE_WIDGET(_widget, _x, _y, _w, _h) move_resize_widget(_widget, _x, _y, _w, _h) #undef RAISE_ARRANGE_EVENT #define RAISE_ARRANGE_EVENT(_object) (0) #undef FUNCTION_NAME #define FUNCTION_NAME get_max_size #undef IS_WIDGET_VISIBLE #define IS_WIDGET_VISIBLE(_cont) (1) #include "gb.form.arrangement.h" void CCONTAINER_get_max_size(void *_object, int *w, int *h) { bool locked = THIS_ARRANGEMENT->locked; THIS_ARRANGEMENT->locked = false; max_w = 0; max_h = 0; get_max_size(THIS); *w = max_w; *h = max_h; THIS_ARRANGEMENT->locked = locked; } #define arrange_later arrange_now #define arrange_now(_widget) CCONTAINER_arrange(CWidget::get(_widget)) #if 0 static void post_arrange_later(void *_object) { if (WIDGET && THIS_ARRANGEMENT->dirty) CCONTAINER_arrange(THIS); GB.Unref(&_object); } static void arrange_later(QWidget *cont) { void *_object = CWidget::get(cont); if (THIS_ARRANGEMENT->dirty || THIS_ARRANGEMENT->mode == ARRANGE_NONE) return; GB.Ref(_object); //qDebug("later: %p: dirty = TRUE", THIS); THIS_ARRANGEMENT->dirty = TRUE; GB.Post((void (*)())post_arrange_later, (intptr_t)THIS); } #endif /*************************************************************************** class MyContainer ***************************************************************************/ MyContainer::MyContainer(QWidget *parent) : QFrame(parent) { } void MyContainer::frameChanged(void) { //qDebug("MyContainer::frameChanged %p", CWidget::get(this)); QFrame::frameChanged(); //CCONTAINER_arrange(this); arrange_now(this); } void MyContainer::resizeEvent(QResizeEvent *e) { //qDebug("MyContainer::resizeEvent %s %p", GB.GetClassName(CWidget::get(this)), CWidget::get(this)); QFrame::resizeEvent(e); arrange_now(this); } void MyContainer::showEvent(QShowEvent *e) { //qDebug("MyContainer::showEvent %p %s", CWidget::get(this), GB.GetClassName(CWidget::get(this))); QFrame::showEvent(e); arrange_now(this); } void MyContainer::childEvent(QChildEvent *e) { void *_object = CWidget::get(this); void *child; QFrame::childEvent(e); if (!e->child()->isWidgetType()) return; child = CWidget::get((QWidget *)e->child()); if (e->inserted()) { e->child()->installEventFilter(this); GB.Raise(THIS, EVENT_Insert, 1, GB_T_OBJECT, child); //qApp->sendEvent(WIDGET, new QEvent(EVENT_INSERT)); //if (THIS_ARRANGEMENT->user) // GB.Raise(THIS, EVENT_Insert, 1, GB_T_OBJECT, child); } else if (e->removed()) { e->child()->removeEventFilter(this); //if (THIS_ARRANGEMENT->user) // GB.Raise(THIS, EVENT_Remove, 1, GB_T_OBJECT, child); } arrange_later(this); } bool MyContainer::eventFilter(QObject *o, QEvent *e) { int type = e->type(); if (type == QEvent::Move || type == QEvent::Resize || type == QEvent::Show || type == QEvent::Hide || type == EVENT_EXPAND) { CWIDGET *ob = CWidget::getReal(o); if (ob && (type == EVENT_EXPAND || !ob->flag.ignore)) arrange_now(this); } return QObject::eventFilter(o, e); } /*************************************************************************** CContainer ***************************************************************************/ static QRect getRect(void *_object) { QWidget *w = CONTAINER; if (WIDGET->isA("MyMainWindow")) ((MyMainWindow *)WIDGET)->configure(); if (w->inherits("QFrame")) return ((QFrame *)w)->contentsRect(); else return QRect(0, 0, w->width(), w->height()); } BEGIN_METHOD_VOID(CCONTAINER_children_next) #ifdef DEBUG if (!CONTAINER) qDebug("Null container"); #endif QObjectList *list = (QObjectList *)CONTAINER->children(); unsigned int index; CWIDGET *widget; for(;;) { index = ENUM(int); if (list == NULL || index >= list->count()) { GB.StopEnum(); return; } ENUM(int) = index + 1; widget = CWidget::getValid(CWidget::getReal(list->at(index))); if (widget) { GB.ReturnObject(widget); return; } } END_METHOD BEGIN_METHOD(CCONTAINER_children_get, GB_INTEGER index) QObjectList *list = (QObjectList *)CONTAINER->children(); int index = VARG(index), i; CWIDGET *widget; if (index >= 0) { i = 0; for(i = 0; i < (int)list->count(); i++) { widget = CWidget::getValid(CWidget::getReal(list->at(i))); if (!widget) continue; if (index == 0) { GB.ReturnObject(widget); return; } index--; } } GB.Error(GB_ERR_BOUND); END_METHOD BEGIN_PROPERTY(CCONTAINER_children_count) QWidget *wid = CONTAINER; QObjectList *list; QObject *ob; int n = 0; if (!wid) goto __DONE; list = (QObjectList *)wid->children(); if (!list || !list->count()) goto __DONE; list->first(); for(;;) { ob = list->current(); if (!ob) break; list->next(); if (ob->isWidgetType() && CWidget::getValid(CWidget::getReal(ob))) n++; } __DONE: GB.ReturnInteger(n); END_PROPERTY BEGIN_PROPERTY(CCONTAINER_x) #ifdef DEBUG if (!CONTAINER) qDebug("Null container"); #endif QRect r = getRect(THIS); //_CONTAINER); QPoint p(r.x(), r.y()); GB.ReturnInteger(CONTAINER->mapTo(WIDGET, p).x()); END_PROPERTY BEGIN_PROPERTY(CCONTAINER_y) #ifdef DEBUG if (!CONTAINER) qDebug("Null container"); #endif QRect r = getRect(THIS); // _CONTAINER); QPoint p(r.x(), r.y()); GB.ReturnInteger(CONTAINER->mapTo(WIDGET, p).y()); END_PROPERTY BEGIN_PROPERTY(CCONTAINER_width) #ifdef DEBUG if (!CONTAINER) qDebug("Null container"); #endif GB.ReturnInteger(getRect(THIS).width()); END_PROPERTY BEGIN_PROPERTY(CCONTAINER_height) #ifdef DEBUG if (!CONTAINER) qDebug("Null container"); #endif GB.ReturnInteger(getRect(THIS).height()); END_PROPERTY BEGIN_PROPERTY(CCONTAINER_arrangement) int arr; if (READ_PROPERTY) GB.ReturnInteger(THIS_ARRANGEMENT->mode); else { arr = VPROP(GB_INTEGER); if (arr < 0 || arr > 8) return; THIS_ARRANGEMENT->mode = arr; arrange_now(CONTAINER); } END_PROPERTY BEGIN_PROPERTY(CUSERCONTAINER_arrangement) CCONTAINER *cont = (CCONTAINER *)CWidget::get(CONTAINER); CCONTAINER_arrangement(cont, _param); if (!READ_PROPERTY) { THIS_USERCONTAINER->save = cont->arrangement; //qDebug("(%s %p): save = %08X (arrangement %d)", GB.GetClassName(THIS), THIS, THIS_USERCONTAINER->save, val); } END_PROPERTY BEGIN_PROPERTY(CCONTAINER_auto_resize) if (READ_PROPERTY) GB.ReturnBoolean(THIS_ARRANGEMENT->autoresize); else { THIS_ARRANGEMENT->autoresize = VPROP(GB_BOOLEAN); arrange_now(CONTAINER); } END_PROPERTY BEGIN_PROPERTY(CUSERCONTAINER_auto_resize) CCONTAINER *cont = (CCONTAINER *)CWidget::get(CONTAINER); CCONTAINER_auto_resize(cont, _param); if (!READ_PROPERTY) { THIS_USERCONTAINER->save = cont->arrangement; //qDebug("(%s %p): save = %08X (autoresize)", GB.GetClassName(THIS), THIS, THIS_USERCONTAINER->save); } END_PROPERTY BEGIN_PROPERTY(CCONTAINER_padding) if (READ_PROPERTY) GB.ReturnInteger(THIS_ARRANGEMENT->padding); else { int val = VPROP(GB_INTEGER); if (val >= 0 && val < 32768) { THIS_ARRANGEMENT->padding = val; arrange_now(CONTAINER); } } END_PROPERTY BEGIN_PROPERTY(CUSERCONTAINER_padding) CCONTAINER *cont = (CCONTAINER *)CWidget::get(CONTAINER); CCONTAINER_padding(cont, _param); if (!READ_PROPERTY) { THIS_USERCONTAINER->save = cont->arrangement; //qDebug("(%s %p): save = %08X (padding)", GB.GetClassName(THIS), THIS, THIS_USERCONTAINER->save); } END_PROPERTY BEGIN_PROPERTY(CCONTAINER_spacing) if (READ_PROPERTY) GB.ReturnInteger(THIS_ARRANGEMENT->spacing); else { int val = VPROP(GB_INTEGER); if (val >= 0 && val < 32768) { THIS_ARRANGEMENT->spacing = val; arrange_now(CONTAINER); } } END_PROPERTY BEGIN_PROPERTY(CUSERCONTAINER_spacing) CCONTAINER *cont = (CCONTAINER *)CWidget::get(CONTAINER); CCONTAINER_spacing(cont, _param); if (!READ_PROPERTY) { THIS_USERCONTAINER->save = cont->arrangement; //qDebug("(%s %p): save = %08X (spacing)", GB.GetClassName(THIS), THIS, THIS_USERCONTAINER->save); } END_PROPERTY BEGIN_METHOD(CUSERCONTROL_new, GB_OBJECT parent) MyContainer *wid = new MyContainer(QCONTAINER(VARG(parent))); THIS->container = wid; THIS_ARRANGEMENT->mode = ARRANGE_FILL; THIS_ARRANGEMENT->user = true; CWIDGET_new(wid, (void *)_object); END_METHOD BEGIN_PROPERTY(CUSERCONTROL_container) CCONTAINER *current = (CCONTAINER *)CWidget::get(CONTAINER); if (READ_PROPERTY) GB.ReturnObject(current); else { CCONTAINER *cont = (CCONTAINER *)VPROP(GB_OBJECT); QWidget *w; QWidget *p; // sanity checks if (!cont) { THIS->container = WIDGET; return; } if (GB.CheckObject(cont)) return; w = cont->container; if (w == THIS->container) return; for (p = w; p; p = p->parentWidget()) { if (p == WIDGET) break; } if (!p) GB.Error("Container must be a child control"); else { THIS->container = w; CWIDGET_update_design((CWIDGET *)THIS); CCONTAINER_arrange(THIS); } } END_PROPERTY BEGIN_PROPERTY(CUSERCONTAINER_container) //CCONTAINER *before; CCONTAINER *after; if (READ_PROPERTY) CUSERCONTROL_container(_object, _param); else { CUSERCONTROL_container(_object, _param); after = (CCONTAINER *)CWidget::get(THIS->container); after->arrangement = THIS_USERCONTAINER->save; //qDebug("(%s %p): arrangement = %08X", GB.GetClassName(THIS), THIS, after->arrangement); CCONTAINER_arrange(after); } END_PROPERTY DECLARE_METHOD(CCONTROL_design); BEGIN_PROPERTY(CUSERCONTAINER_design) CCONTROL_design(_object, _param); if (!READ_PROPERTY && VPROP(GB_BOOLEAN)) { CCONTAINER *cont = (CCONTAINER *)CWidget::get(CONTAINER); cont->arrangement = 0; THIS_USERCONTAINER->save = cont->arrangement; } END_PROPERTY BEGIN_METHOD(CCONTAINER_find, GB_INTEGER x; GB_INTEGER y) QWidget *w; void *control; w = CONTAINER->childAt(VARG(x), VARG(y)); control = CWidget::get(w); if (control == THIS) control = NULL; GB.ReturnObject(control); END_METHOD GB_DESC CChildrenDesc[] = { GB_DECLARE(".ContainerChildren", sizeof(CCONTAINER)), GB_VIRTUAL_CLASS(), GB_METHOD("_next", "Control", CCONTAINER_children_next, NULL), GB_METHOD("_get", "Control", CCONTAINER_children_get, "(Index)i"), GB_PROPERTY_READ("Count", "i", CCONTAINER_children_count), GB_END_DECLARE }; GB_DESC CContainerDesc[] = { GB_DECLARE("Container", sizeof(CCONTAINER)), GB_INHERITS("Control"), GB_NOT_CREATABLE(), GB_PROPERTY_SELF("Children", ".ContainerChildren"), GB_PROPERTY_READ("ClientX", "i", CCONTAINER_x), GB_PROPERTY_READ("ClientY", "i", CCONTAINER_y), GB_PROPERTY_READ("ClientW", "i", CCONTAINER_width), GB_PROPERTY_READ("ClientWidth", "i", CCONTAINER_width), GB_PROPERTY_READ("ClientH", "i", CCONTAINER_height), GB_PROPERTY_READ("ClientHeight", "i", CCONTAINER_height), GB_METHOD("Find", "Control", CCONTAINER_find, "(X)i(Y)i"), GB_EVENT("Arrange", NULL, NULL, &EVENT_Arrange), GB_EVENT("Insert", NULL, "(Control)Control", &EVENT_Insert), GB_END_DECLARE }; GB_DESC CUserControlDesc[] = { GB_DECLARE("UserControl", sizeof(CCONTAINER)), GB_INHERITS("Container"), GB_NOT_CREATABLE(), GB_METHOD("_new", NULL, CUSERCONTROL_new, "(Parent)Container;"), GB_PROPERTY("_Container", "Container", CUSERCONTROL_container), GB_PROPERTY("_AutoResize", "b", CCONTAINER_auto_resize), USERCONTROL_DESCRIPTION, GB_END_DECLARE }; GB_DESC CUserContainerDesc[] = { GB_DECLARE("UserContainer", sizeof(CUSERCONTAINER)), GB_INHERITS("Container"), GB_NOT_CREATABLE(), GB_METHOD("_new", NULL, CUSERCONTROL_new, "(Parent)Container;"), //GB_PROPERTY("Container", "Container", CUSERCONTAINER_container), GB_PROPERTY("_Container", "Container", CUSERCONTAINER_container), GB_PROPERTY("Arrangement", "i", CUSERCONTAINER_arrangement), GB_PROPERTY("AutoResize", "b", CUSERCONTAINER_auto_resize), GB_PROPERTY("Padding", "i", CUSERCONTAINER_padding), GB_PROPERTY("Spacing", "i", CUSERCONTAINER_spacing), GB_PROPERTY("Design", "b", CUSERCONTAINER_design), USERCONTAINER_DESCRIPTION, GB_END_DECLARE };