/*************************************************************************** CTabStrip.cpp (c) 2000-2017 BenoƮt 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 2, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ***************************************************************************/ #define __CTABSTRIP_CPP #include #include #include #include #include #include #include #include "gb_common.h" #include "gambas.h" #include "CPicture.h" #include "CConst.h" #include "CTabStrip.h" DECLARE_METHOD(Container_X); DECLARE_METHOD(Container_Y); DECLARE_EVENT(EVENT_Click); DECLARE_EVENT(EVENT_Close); void CTABSTRIP_arrange(void *_object) { WIDGET->layoutContainer(); } /** CTab *****************************************************************/ class CTab { public: QWidget *widget; QString text; CPICTURE *icon; int id; bool visible; bool enabled; CTab(CTABSTRIP *parent, QWidget *page); ~CTab(); int index() const { return WIDGET->indexOf(widget); } void ensureVisible(); void setEnabled(bool e); bool isEnabled() const { return enabled; } bool isVisible() const { return visible; } void setVisible(bool v); void updateIcon(); void updateText(); int count() const; bool isEmpty() const { return count() == 0; } private: CTABSTRIP *_object; }; CTab::CTab(CTABSTRIP *parent, QWidget *page) { _object = parent; widget = page; icon = 0; id = WIDGET->stack.count(); visible = true; setEnabled(true); //page->setAutoFillBackground(true); page->hide(); } CTab::~CTab() { GB.Unref(POINTER(&icon)); } void CTab::ensureVisible() { setVisible(true); int i = index(); if (i >= 0) { WIDGET->setCurrentIndex(i); if (!WIDGET->isVisible()) WIDGET->layoutContainer(); } } int CTab::count() const { QObjectList list = widget->children(); QObject *ob; int n = 0; int i; for(i = 0; i < list.count(); i++) { ob = list.at(i); if (ob->isWidgetType() && CWidget::getRealExisting(ob)) n++; } return n; } void CTab::setVisible(bool v) { int i, ind; CTab *page; if (v == visible) return; visible = v; if (!visible) { i = index(); if (i >= 0) { text = WIDGET->tabText(i); WIDGET->removeTab(i); } } else { ind = 0; for (i = 0; i < (int)WIDGET->stack.count(); i++) { page = WIDGET->stack.at(i); if (!page->isVisible()) continue; if (id == WIDGET->stack.at(i)->id) break; ind++; } WIDGET->insertTab(ind, widget, text); setEnabled(enabled); updateIcon(); if (WIDGET->count() == 1) ensureVisible(); } } void CTab::setEnabled(bool e) { int i = index(); enabled = e; if (i >= 0) WIDGET->setTabEnabled(i, e && WIDGET->isEnabled()); } void CTab::updateIcon() { int i = index(); QIcon iconset; if (icon) CWIDGET_iconset(iconset, *(icon->pixmap)); if (i >= 0) WIDGET->setTabIcon(i, iconset); } void CTab::updateText() { int i = index(); if (i >= 0) WIDGET->setTabText(i, text); } /** MyTabWidget **********************************************************/ MyTabWidget::MyTabWidget(QWidget *parent) : QTabWidget(parent) { _oldw = _oldh = 0; //setMovable(true); //tabBar()->installEventFilter(this); } MyTabWidget::~MyTabWidget() { int i; CWIDGET *_object = CWidget::getReal(this); for (i = 0; i < stack.count(); i++) delete stack.at(i); CWIDGET_set_flag(THIS, WF_DELETED); } void MyTabWidget::setEnabled(bool e) { CWIDGET *_object = CWidget::get(this); int i; QTabWidget::setEnabled(e); for (i = 0; i < (int)WIDGET->stack.count(); i++) WIDGET->stack.at(i)->widget->setEnabled(e); } void MyTabWidget::layoutContainer() { CWIDGET *_object = CWidget::get(this); #if QT_VERSION >= 0x040600 QStyleOptionTabWidgetFrameV2 option; #else QStyleOptionTabWidgetFrame option; #endif QWidget *w = findChild(); QRect contentsRect; if (_oldw != width() || _oldh != height()) { initStyleOption(&option); contentsRect = style()->subElementRect(QStyle::SE_TabWidgetTabContents, &option, this); _oldw = width(); _oldh = height(); w->setGeometry(contentsRect); } else contentsRect = w->geometry(); if (THIS->container) THIS->container->setGeometry(0, 0, contentsRect.width(), contentsRect.height()); } void MyTabWidget::updateTextFont() { CWIDGET *_object = CWidget::get(this); if (THIS->textFont) tabBar()->setFont(*THIS->textFont->font); else tabBar()->setFont(QFont()); } #if 0 bool MyTabWidget::eventFilter(QObject *o, QEvent *e) { if (e->type() == QEvent::Wheel && qobject_cast(o)) { QWheelEvent *event = (QWheelEvent *)e; QTabBar *tabBar = (QTabBar *)o; int id = tabBar->currentIndex(); if (id >= 0) { for(;;) { if (event->delta() < 0) id++; else id--; if (id < 0 || id >= tabBar->count()) break; if (tabBar->isTabEnabled(id)) { tabBar->setCurrentIndex(id); break; } } } return true; } return QObject::eventFilter(o, e); } #endif /*************************************************************************** TabStrip ***************************************************************************/ static bool remove_page(void *_object, int i) { CTab *tab = WIDGET->stack.at(i); if (!tab->isEmpty()) { GB.Error("Tab is not empty"); return true; } THIS->lock = true; WIDGET->stack.removeAt(i); i = tab->index(); if (i >= 0) WIDGET->removeTab(i); delete tab->widget; delete tab; THIS->lock = false; return false; } static void set_current_index(void *_object, int index) { if (index < 0) return; if (index >= (int)WIDGET->stack.count()) index = WIDGET->stack.count() - 1; while (index > 0 && !WIDGET->stack.at(index)->isVisible()) index--; WIDGET->stack.at(index)->ensureVisible(); THIS->container = WIDGET->stack.at(index)->widget; } static bool set_tab_count(void *_object, int new_count) { int count = WIDGET->stack.count(); int i; int index; QString label; CTab *tab; if (new_count < 1 || new_count > 256) { GB.Error(GB_ERR_ARG); return true; } if (new_count == count) return false; if (new_count > count) { for (i = count; i < new_count; i++) { tab = new CTab(THIS, new MyContainer(WIDGET)); label.sprintf("Tab %d", i); WIDGET->addTab(tab->widget, label); WIDGET->stack.append(tab); } index = new_count - 1; set_current_index(THIS, index); } else { index = WIDGET->currentIndex(); //same = (id == PARAM(index)); for (i = new_count; i < count; i++) { if (!WIDGET->stack.at(i)->isEmpty()) { GB.Error("Tab is not empty"); return true; } } if (index >= new_count) index = new_count - 1; set_current_index(THIS, index); for (i = count - 1; i >= new_count; i--) { remove_page(THIS, i); } //WIDGET->stack.resize(new_count); //THIS->icon->resize(new_count); } return false; } static bool check_index(CTABSTRIP *_object, int index) { if (index < 0 || index >= (int)WIDGET->stack.count()) { GB.Error("Bad index"); return true; } else return false; } static int get_real_index(CTABSTRIP *_object) { int i; QWidget *current = WIDGET->currentWidget(); for (i = 0; i < (int)WIDGET->stack.count(); i++) { if (WIDGET->stack.at(i)->widget == current) return i; } return -1; } BEGIN_METHOD(TabStrip_new, GB_OBJECT parent) MyTabWidget *wid = new MyTabWidget(QCONTAINER(VARG(parent))); //, 0, Qt::WNoMousePropagation); QObject::connect(wid, SIGNAL(currentChanged(int)), &CTabStrip::manager, SLOT(currentChanged(int))); QObject::connect(wid, SIGNAL(tabCloseRequested(int)), &CTabStrip::manager, SLOT(tabCloseRequested(int))); //THIS->widget.flag.fillBackground = TRUE; THIS->container = NULL; THIS->index = -1; CWIDGET_new(wid, (void *)_object); set_tab_count(THIS, 1); //wid->updateLayout(); END_METHOD BEGIN_METHOD_VOID(TabStrip_free) GB.Unref(POINTER(&THIS->textFont)); END_METHOD BEGIN_PROPERTY(TabStrip_Count) if (READ_PROPERTY) GB.ReturnInteger(WIDGET->stack.count()); else set_tab_count(THIS, VPROP(GB_INTEGER)); END_PROPERTY BEGIN_PROPERTY(TabStrip_Index) if (READ_PROPERTY) { GB.ReturnInteger(get_real_index(THIS)); } else { int index = VPROP(GB_INTEGER); if (check_index(THIS, index)) return; if (index == get_real_index(THIS)) return; if (!WIDGET->stack.at(index)->isVisible()) return; WIDGET->stack.at(index)->ensureVisible(); } END_PROPERTY BEGIN_PROPERTY(TabStrip_Current) THIS->index = get_real_index(THIS); if (THIS->index < 0) GB.ReturnNull(); else RETURN_SELF(); END_PROPERTY BEGIN_METHOD(TabStrip_get, GB_INTEGER index) int index = VARG(index); if (check_index(THIS, index)) return; THIS->index = index; RETURN_SELF(); END_METHOD BEGIN_PROPERTY(TabStrip_Orientation) if (READ_PROPERTY) { switch(WIDGET->tabPosition()) { case QTabWidget::North: GB.ReturnInteger(ALIGN_TOP); break; case QTabWidget::South: GB.ReturnInteger(ALIGN_BOTTOM); break; case QTabWidget::West: GB.ReturnInteger(ALIGN_LEFT); break; case QTabWidget::East: GB.ReturnInteger(ALIGN_RIGHT); break; default: GB.ReturnInteger(ALIGN_NORMAL); break; } } else { switch(VPROP(GB_INTEGER)) { case ALIGN_TOP: WIDGET->setTabPosition(QTabWidget::North); break; case ALIGN_BOTTOM: WIDGET->setTabPosition(QTabWidget::South); break; case ALIGN_LEFT: WIDGET->setTabPosition(QTabWidget::West); break; case ALIGN_RIGHT: WIDGET->setTabPosition(QTabWidget::East); break; } } END_PROPERTY /*************************************************************************** .Tab ***************************************************************************/ BEGIN_PROPERTY(CTAB_text) int index = THIS->index; if (index < 0) index = get_real_index(THIS); if (READ_PROPERTY) RETURN_NEW_STRING(WIDGET->stack.at(index)->text); else { WIDGET->stack.at(index)->text = QSTRING_PROP(); WIDGET->stack.at(index)->updateText(); } END_PROPERTY BEGIN_PROPERTY(TabStrip_TextFont) if (READ_PROPERTY) GB.ReturnObject(THIS->textFont); else { GB.StoreObject(PROP(GB_OBJECT), POINTER(&THIS->textFont)); WIDGET->updateTextFont(); } END_PROPERTY BEGIN_PROPERTY(CTAB_picture) int index; index = THIS->index; if (index < 0) index = get_real_index(THIS); if (READ_PROPERTY) { if (index < 0) GB.ReturnNull(); else GB.ReturnObject(WIDGET->stack.at(index)->icon); } else if (index >= 0) { GB.StoreObject(PROP(GB_OBJECT), POINTER(&(WIDGET->stack.at(index))->icon)); WIDGET->stack.at(index)->updateIcon(); } END_PROPERTY BEGIN_PROPERTY(CTAB_enabled) CTab *tab = WIDGET->stack.at(THIS->index); if (READ_PROPERTY) GB.ReturnBoolean(tab->isEnabled()); else tab->setEnabled(VPROP(GB_BOOLEAN)); END_PROPERTY BEGIN_PROPERTY(CTAB_visible) CTab *tab = WIDGET->stack.at(THIS->index); if (READ_PROPERTY) GB.ReturnBoolean(tab->isVisible()); else tab->setVisible(VPROP(GB_BOOLEAN)); END_PROPERTY BEGIN_METHOD_VOID(CTAB_next) CTABSTRIP_ENUM *iter; QWidget *page; QObjectList list; int child; CWIDGET *widget; iter = (CTABSTRIP_ENUM *)GB.GetEnum(); if (!iter->init) { iter->child = 0; iter->index = THIS->index; iter->init = true; } //qDebug("CTAB_next: iter = (%d, %d, %d)", iter->init, iter->index, iter->child); page = WIDGET->stack.at(iter->index)->widget; list = page->children(); for(;;) { child = iter->child; if (child >= list.count()) { GB.StopEnum(); return; } iter->child = child + 1; widget = CWidget::getRealExisting(list.at(child)); if (widget) { GB.ReturnObject(widget); return; } } END_METHOD BEGIN_METHOD(CTAB_get, GB_INTEGER index) QObjectList list = WIDGET->stack.at(THIS->index)->widget->children(); int index = VARG(index); int i; CWIDGET *widget; if (index >= 0) { i = 0; for(i = 0; i < list.count(); i++) { widget = CWidget::getRealExisting(list.at(i)); if (!widget) continue; if (index == 0) { GB.ReturnObject(widget); return; } index--; } } GB.Error(GB_ERR_BOUND); END_METHOD BEGIN_PROPERTY(CTAB_count) GB.ReturnInteger(WIDGET->stack.at(THIS->index)->count()); END_PROPERTY BEGIN_METHOD_VOID(CTAB_delete) int index = get_real_index(THIS); if (WIDGET->stack.count() == 1) { GB.Error("TabStrip cannot be empty"); return; } if (remove_page(THIS, THIS->index)) return; set_current_index(THIS, index); THIS->index = -1; END_METHOD BEGIN_PROPERTY(TabStrip_Enabled) int i; if (READ_PROPERTY) GB.ReturnBoolean(WIDGET->isEnabled()); else { WIDGET->setEnabled(VPROP(GB_BOOLEAN)); for (i = 0; i < WIDGET->stack.count(); i++) WIDGET->stack.at(i)->setEnabled(VPROP(GB_BOOLEAN)); } END_PROPERTY BEGIN_PROPERTY(TabStrip_Text) THIS->index = -1; CTAB_text(_object, _param); END_PROPERTY BEGIN_PROPERTY(TabStrip_Picture) THIS->index = -1; CTAB_picture(_object, _param); END_PROPERTY BEGIN_PROPERTY(TabStrip_Closable) if (READ_PROPERTY) GB.ReturnBoolean(WIDGET->tabsClosable()); else WIDGET->setTabsClosable(VPROP(GB_BOOLEAN)); END_PROPERTY BEGIN_PROPERTY(TabStrip_ClientX) Container_X(_object, _param); END_PROPERTY BEGIN_PROPERTY(TabStrip_ClientY) Container_Y(_object, _param); END_PROPERTY BEGIN_PROPERTY(TabStrip_ClientWidth) GB.ReturnInteger(THIS->container->width()); END_PROPERTY BEGIN_PROPERTY(TabStrip_ClientHeight) GB.ReturnInteger(THIS->container->height()); END_PROPERTY BEGIN_METHOD(TabStrip_FindIndex, GB_OBJECT child) void *child = VARG(child); int i; QWidget *parent; if (GB.CheckObject(child)) return; parent = QWIDGET(child)->parentWidget(); for (i = 0; i < WIDGET->stack.count(); i++) { if (parent == WIDGET->stack.at(i)->widget) { GB.ReturnInteger(i); return; } } GB.ReturnInteger(-1); END_METHOD /** Class CTabStrip ******************************************************/ CTabStrip CTabStrip::manager; void CTabStrip::currentChanged(int index) { QWidget *wid; GET_SENDER(); wid = WIDGET->currentWidget(); // wid can be null! if (wid != THIS->container) { //qDebug("CTabStrip::currentChanged: %d %p -> %p", index, THIS->container, wid); if (THIS->container) THIS->container->hide(); THIS->container = wid; if (wid) wid->show(); CCONTAINER_arrange(THIS); //if (wid->isVisible() && !THIS->lock) if (!THIS->lock) RAISE_EVENT(EVENT_Click); } } void CTabStrip::tabCloseRequested(int index) { GET_SENDER(); GB.Raise(THIS, EVENT_Close, 1, GB_T_INTEGER, index); } /** Descriptions *********************************************************/ GB_DESC CTabStripContainerChildrenDesc[] = { GB_DECLARE_VIRTUAL(".TabStripContainer.Children"), GB_METHOD("_next", "Control", CTAB_next, NULL), GB_PROPERTY_READ("Count", "i", CTAB_count), GB_METHOD("_get", "Control", CTAB_get, "(Index)i"), GB_END_DECLARE }; GB_DESC CTabStripContainerDesc[] = { GB_DECLARE_VIRTUAL(".TabStripContainer"), GB_PROPERTY("Text", "s", CTAB_text), GB_PROPERTY("Picture", "Picture", CTAB_picture), GB_PROPERTY("Caption", "s", CTAB_text), GB_PROPERTY("Enabled", "b", CTAB_enabled), GB_PROPERTY("Visible", "b", CTAB_visible), GB_PROPERTY_SELF("Children", ".TabStripContainer.Children"), GB_METHOD("Delete", NULL, CTAB_delete, NULL), GB_END_DECLARE }; GB_DESC CTabStripDesc[] = { GB_DECLARE("TabStrip", sizeof(CTABSTRIP)), GB_INHERITS("Container"), GB_METHOD("_new", NULL, TabStrip_new, "(Parent)Container;"), GB_METHOD("_free", NULL, TabStrip_free, NULL), GB_PROPERTY("Count", "i", TabStrip_Count), GB_PROPERTY("Text", "s", TabStrip_Text), GB_PROPERTY("TextFont", "Font", TabStrip_TextFont), GB_PROPERTY("Picture", "Picture", TabStrip_Picture), GB_PROPERTY("Closable", "b", TabStrip_Closable), GB_PROPERTY("Caption", "s", TabStrip_Text), GB_PROPERTY_READ("Current", ".TabStripContainer", TabStrip_Current), GB_PROPERTY("Index", "i", TabStrip_Index), GB_PROPERTY("Orientation", "i", TabStrip_Orientation), GB_PROPERTY("Enabled", "b", TabStrip_Enabled), GB_PROPERTY_READ("ClientX", "i", TabStrip_ClientX), GB_PROPERTY_READ("ClientY", "i", TabStrip_ClientY), GB_PROPERTY_READ("ClientW", "i", TabStrip_ClientWidth), GB_PROPERTY_READ("ClientWidth", "i", TabStrip_ClientWidth), GB_PROPERTY_READ("ClientH", "i", TabStrip_ClientHeight), GB_PROPERTY_READ("ClientHeight", "i", TabStrip_ClientHeight), GB_PROPERTY("Arrangement", "i", Container_Arrangement), GB_PROPERTY("AutoResize", "b", Container_AutoResize), GB_PROPERTY("Padding", "i", Container_Padding), GB_PROPERTY("Spacing", "b", Container_Spacing), GB_PROPERTY("Margin", "b", Container_Margin), GB_PROPERTY("Indent", "b", Container_Indent), GB_PROPERTY("Invert", "b", Container_Invert), GB_METHOD("_get", ".TabStripContainer", TabStrip_get, "(Index)i"), GB_METHOD("FindIndex", "i", TabStrip_FindIndex, "(Child)Control;"), TABSTRIP_DESCRIPTION, GB_EVENT("Click", NULL, NULL, &EVENT_Click), GB_EVENT("Close", NULL, "(Index)i", &EVENT_Close), GB_END_DECLARE };