From 0c5058a3ac8bbd3608d83e1d3c8192446304edcf Mon Sep 17 00:00:00 2001 From: jfa Date: Wed, 6 Jul 2005 13:45:50 +0000 Subject: [PATCH] Add methods for view parameters management from program code --- src/Qtx/QtxWorkstack.cxx | 504 +++++++++++++++++++++++++++++++++++++++ src/Qtx/QtxWorkstack.h | 77 ++++++ 2 files changed, 581 insertions(+) diff --git a/src/Qtx/QtxWorkstack.cxx b/src/Qtx/QtxWorkstack.cxx index 2ca7b819a..128baae7f 100644 --- a/src/Qtx/QtxWorkstack.cxx +++ b/src/Qtx/QtxWorkstack.cxx @@ -15,6 +15,8 @@ #include #include +#include + /*! Class: QtxWorkstack [Public] Descr: @@ -105,6 +107,508 @@ void QtxWorkstack::split( const int o ) curWid->setFocus(); } +// begin: jfa 06.07.2005 +void QtxWorkstack::Split (QWidget* wid, const Qt::Orientation o, const SplitType type) +{ + if (!wid) return; + + // find area of the given widget + QtxWorkstackArea* area = NULL; + QPtrList allAreas; + areas(mySplit, allAreas, true); + + QPtrListIterator it (allAreas); + for (; it.current() && !area; ++it) { + if (it.current()->contains(wid)) + area = it.current(); + } + if (!area) return; + + QWidgetList wids = area->widgetList(); + if (wids.count() < 2) + return; + + QSplitter* s = splitter(area); + QPtrList areaList; + areas(s, areaList); + + QPtrList splitList; + splitters(s, splitList); + + QSplitter* trg = 0; + if (areaList.count() + splitList.count() < 2 || s->orientation() == o) + trg = s; + + if (!trg) trg = wrapSplitter(area); + if (!trg) return; + + trg->setOrientation(o); + + QtxWorkstackArea* newArea = createArea(0); + insertWidget(newArea, trg, area); + + switch (type) { + case SPLIT_STAY: + { + QWidgetListIt itr (wids); + for (; itr.current(); ++itr) + { + QWidget* wid_i = itr.current(); + if (wid_i != wid) { + area->removeWidget(wid_i); + newArea->insertWidget(wid_i); + } + } + } + break; + case SPLIT_AT: + { + QWidgetListIt itr (wids); + for (; itr.current() && itr.current() != wid; ++itr) { + } + for (; itr.current(); ++itr) { + area->removeWidget(itr.current()); + newArea->insertWidget(itr.current()); + } + } + break; + case SPLIT_MOVE: + area->removeWidget(wid); + newArea->insertWidget(wid); + break; + } + + distributeSpace(trg); +} + +void QtxWorkstack::OnTop (QWidget* wid) +{ + if (!wid) return; + + // find area of the given widget + QtxWorkstackArea* area = NULL; + QPtrList allAreas; + areas(mySplit, allAreas, true); + QPtrListIterator it (allAreas); + for (; it.current() && !area; ++it) { + if (it.current()->contains(wid)) + area = it.current(); + } + if (!area) return; + + area->setActiveWidget(wid); +} + +void QtxWorkstack::Attract (QWidget* wid1, QWidget* wid2, const bool all) +{ + if (!wid1 || !wid2) return; + + // find area of the widgets + QtxWorkstackArea *area1 = NULL, *area2 = NULL; + QPtrList allAreas; + areas(mySplit, allAreas, true); + QPtrListIterator it (allAreas); + for (; it.current() && !(area1 && area2); ++it) { + if (it.current()->contains(wid1)) + area1 = it.current(); + if (it.current()->contains(wid2)) + area2 = it.current(); + } + if (!area1 || !area2) return; + + QWidget* curWid = area1->activeWidget(); + if (!curWid) return; + + if (area1 == area2) { + if (all) { + // Set wid1 at first position, wid2 at second + area1->insertWidget(wid1); + area1->insertWidget(wid2, 1); + } else { + // Set wid2 right after wid1 + area1->removeWidget(wid2); + int wid1_ind = 0; + QWidgetList wids1 = area1->widgetList(); + QWidgetListIt itr1 (wids1); + for (; itr1.current() && itr1.current() != wid1; ++itr1, ++wid1_ind); + area1->insertWidget(wid2, wid1_ind + 1); + } + } else { + int wid1_ind = 0; + QWidgetList wids1 = area1->widgetList(); + QWidgetListIt itr1 (wids1); + for (; itr1.current() && itr1.current() != wid1; ++itr1, ++wid1_ind); + + if (all) { + // Set wid2 right after wid1, other widgets from area2 right after wid2 + QWidgetList wids2 = area2->widgetList(); + QWidgetListIt itr2 (wids2); + for (int ind = wid1_ind + 1; itr2.current(); ++itr2, ++ind) + { + area2->removeWidget(itr2.current()); + if (itr2.current() == wid2) { + area1->insertWidget(itr2.current(), wid1_ind + 1); + } else { + area1->insertWidget(itr2.current(), ind); + } + } + } else { + // Set wid2 right after wid1 + area2->removeWidget(wid2); + area1->insertWidget(wid2, wid1_ind + 1); + } + } + + /*area2->removeWidget(wid2); + area1->insertWidget(wid2); + + // Reorder widgets + QWidgetListIt itr( wids1 ); + for ( ; itr.current() && itr.current() != wid1; ++itr ) + { + } + ++itr; + for ( ; itr.current(); ++itr ) + { + if (itr.current() != wid2) { + area1->removeWidget( itr.current() ); + area1->insertWidget( itr.current() ); + } + }*/ + + area1->setActiveWidget(curWid); +} + +static void setSizes (QIntList& szList, const int item_ind, + const int new_near, const int new_this, const int new_farr) +{ + // set size to all items before an item # + int cur_pos = 0; + QIntList::iterator its = szList.begin(); + for (; its != szList.end() && cur_pos < item_ind; ++its, ++cur_pos) { + *its = new_near; + } + if (its == szList.end()) return; + // set size to item # + *its = new_this; + ++its; + // set size to all items after an item # + for (; its != szList.end(); ++its) { + *its = new_farr; + } +} + +void QtxWorkstack::SetRelativePositionInSplitter( QWidget* wid, const double position ) +{ + if ( position < 0.0 || 1.0 < position) + return; + if ( !wid ) + return; + + // find area of the given widget + QtxWorkstackArea* area = NULL; + QPtrList allAreas; + areas(mySplit, allAreas, true); + for ( QPtrListIterator it( allAreas ); + it.current() && !area; + ++it ) + { + if (it.current()->contains(wid)) + area = it.current(); + } + + if ( !area ) + return; + + QSplitter* split = splitter( area ); + if ( !split ) + return; + + // find index of the area in its splitter + int item_ind = -1; + bool isFound = false; + const QObjectList* was = split->children(); + for (QObjectListIt ito (*was); ito.current() && !isFound; ++ito, ++item_ind) + { + if (ito.current() == area) + isFound = true; + } + if (!isFound || item_ind == 0) + return; + + QIntList szList = split->sizes(); + int splitter_size = (split->orientation() == Horizontal ? + split->width() : split->height()); + int nb = szList.count(); + + int new_prev = int(splitter_size * position / item_ind); + int new_next = int(splitter_size * (1.0 - position) / (nb - item_ind)); + setSizes (szList, item_ind, new_prev, new_next, new_next); + split->setSizes(szList); +} + +void QtxWorkstack::SetRelativePosition (QWidget* wid, + const Qt::Orientation o, + const double position) +{ + if (position < 0.0 || 1.0 < position) + return; + if (!wid) + return; + + int splitter_size = (o == Horizontal ? mySplit->width() : mySplit->height()); + int need_pos = int(position * splitter_size); + int splitter_pos = 0; + + if (setPosition(wid, mySplit, o, need_pos, splitter_pos) != 0) { + // impossible to set required position + } +} + +static int positionSimple (QIntList& szList, const int nb, const int splitter_size, + const int item_ind, const int item_rel_pos, + const int need_pos, const int splitter_pos) +{ + if (item_ind == 0) { // cannot move in this splitter + return (need_pos - splitter_pos); + } + + int delta = 0; + int new_prev = 0; + int new_this = szList[item_ind]; + int new_next = 0; + + bool isToCheck = false; + + if (need_pos < splitter_pos) { + // Set size of all previous workareas to zero <-- + if (item_ind == nb - 1) { + // item iz last in the splitter, it will occupy all the splitter + new_this = splitter_size; + } else { + // recompute size of next items in splitter + new_next = (splitter_size - new_this) / (nb - item_ind - 1); + } + delta = need_pos - splitter_pos; + + } else if (need_pos > (splitter_pos + splitter_size)) { + // Set size of all next workareas to zero --> + // recompute size of previous items in splitter + new_this = 0; + new_prev = (splitter_size - new_this) / item_ind; + delta = need_pos - (splitter_pos + splitter_size - new_this); + + } else { // required position lays inside this splitter + // Move workarea inside splitter into required position <-> + int new_item_rel_pos = need_pos - splitter_pos; + new_prev = new_item_rel_pos / item_ind; + if (need_pos < (splitter_pos + item_rel_pos)) { + // Make previous workareas smaller, next - bigger + // No problem to keep old size of the widget + } else { + // Make previous workareas bigger, next - smaller + if (new_this > splitter_size - new_item_rel_pos) { + new_this = splitter_size - new_item_rel_pos; + } + // jfa to do: in this case fixed size of next widgets could prevent right resizing + isToCheck = true; + } + if (item_ind == nb - 1) { + new_this = splitter_size - new_item_rel_pos; + } else { + new_next = (splitter_size - new_item_rel_pos - new_this) / (nb - item_ind - 1); + } + delta = 0; + } + + setSizes (szList, item_ind, new_prev, new_this, new_next); + return delta; +} + +int QtxWorkstack::setPosition (QWidget* wid, QSplitter* split, + const Qt::Orientation o, const int need_pos, + const int splitter_pos) +{ + if (!wid || !split) + return need_pos - splitter_pos; + + // Find corresponding sub-splitter. + // Find also index of appropriate item in current splitter. + int cur_ind = 0, item_ind = 0; + bool isBottom = false, isFound = false; + QSplitter* sub_split = NULL; + const QObjectList* objs = split->children(); + if (objs) + { + for (QObjectListIt it (*objs); it.current() && !isFound; ++it) + { + if (it.current()->inherits( "QtxWorkstackArea")) { + if (((QtxWorkstackArea*)it.current())->contains(wid)) { + item_ind = cur_ind; + isBottom = true; + isFound = true; + } + cur_ind++; + } else if (it.current()->inherits("QSplitter")) { + QPtrList areaList; + areas((QSplitter*)it.current(), areaList, true); + for (QPtrListIterator ita (areaList); + ita.current() && !isFound; + ++ita) + { + if (ita.current()->contains(wid)) { + item_ind = cur_ind; + isFound = true; + sub_split = (QSplitter*)it.current(); + } + } + cur_ind++; + } + } + } + if (!isFound) + return (need_pos - splitter_pos); + + if (split->orientation() == o) { + // Find coordinates of near and far sides of the appropriate item relatively current splitter + int splitter_size = (o == Horizontal ? split->width() : split->height()); + QIntList szList = split->sizes(); + int nb = szList.count(); + int item_rel_pos = 0; // position of near side of item relatively this splitter + for (int i = 0; i < item_ind; i++) { + item_rel_pos += szList[i]; + } + int item_size = szList[item_ind]; // size of item + int item_pos = splitter_pos + item_rel_pos; + + // Resize splitter items to complete the conditions + if (isBottom) { + // I. Bottom of splitters stack reached + + int delta = positionSimple(szList, nb, splitter_size, item_ind, item_rel_pos, need_pos, splitter_pos); + split->setSizes(szList); + // Recompute delta, as some windows can reject given size + int new_item_rel_pos = 0; + QIntList szList1 = split->sizes(); + for (int i = 0; i < item_ind; i++) { + new_item_rel_pos += szList1[i]; + } + delta = need_pos - (splitter_pos + new_item_rel_pos); + return delta; + + } else { + // II. Bottom of splitters stack is not yet reached + + if (item_ind == 0) { // cannot move in this splitter + // Process in sub-splitter + return setPosition(wid, sub_split, o, need_pos, splitter_pos); + } + + int new_prev = 0; + int new_this = szList[item_ind]; + int new_next = 0; + + if (need_pos < splitter_pos) { + // Set size of all previous workareas to zero <-- + if (item_ind == nb - 1) { + new_this = splitter_size; + } else { + new_next = (splitter_size - new_this) / (nb - item_ind - 1); + } + setSizes (szList, item_ind, new_prev, new_this, new_next); + split->setSizes(szList); + // Recompute splitter_pos, as some windows can reject given size + int new_item_rel_pos = 0; + QIntList szList1 = split->sizes(); + for (int i = 0; i < item_ind; i++) { + new_item_rel_pos += szList1[i]; + } + // Process in sub-splitter + return setPosition(wid, sub_split, o, need_pos, splitter_pos + new_item_rel_pos); + } else if (need_pos > (splitter_pos + splitter_size)) { + // Set size of all next workareas to zero --> + new_prev = (splitter_size - new_this) / item_ind; + setSizes (szList, item_ind, new_prev, new_this, new_next); + split->setSizes(szList); + // Recompute splitter_pos, as some windows can reject given size + int new_item_rel_pos = 0; + QIntList szList1 = split->sizes(); + for (int i = 0; i < item_ind; i++) { + new_item_rel_pos += szList1[i]; + } + // Process in sub-splitter + return setPosition(wid, sub_split, o, need_pos, splitter_pos + new_item_rel_pos); + } else { + // Set appropriate size of all previous/next items <-> + int new_item_rel_pos = item_rel_pos; + if (need_pos < item_pos || (item_pos + item_size) < need_pos) { + // Move item inside splitter into required position <-> + int new_this = szList[item_ind]; + int new_next = 0; + new_item_rel_pos = need_pos - splitter_pos; + if ((item_pos + item_size) < need_pos) { + //new_item_rel_pos = need_pos - (item_pos + item_size); + new_item_rel_pos = item_rel_pos + (need_pos - (item_pos + item_size)); + } + int new_prev = new_item_rel_pos / item_ind; + if (need_pos < (splitter_pos + item_rel_pos)) { + // Make previous workareas smaller, next - bigger + // No problem to keep old size of the widget + } else { + // Make previous workareas bigger, next - smaller + if (new_this > splitter_size - new_item_rel_pos) { + new_this = splitter_size - new_item_rel_pos; + } + } + if (item_ind == nb - 1) { + new_this = splitter_size - new_item_rel_pos; + } else { + new_next = (splitter_size - new_item_rel_pos - new_this) / (nb - item_ind - 1); + } + setSizes (szList, item_ind, new_prev, new_this, new_next); + split->setSizes(szList); + // Recompute new_item_rel_pos, as some windows can reject given size + new_item_rel_pos = 0; + QIntList szList1 = split->sizes(); + for (int i = 0; i < item_ind; i++) { + new_item_rel_pos += szList1[i]; + } + } else { + // Do nothing + } + // Process in sub-splitter + int add_pos = setPosition(wid, sub_split, o, need_pos, splitter_pos + new_item_rel_pos); + if (add_pos == 0) + return 0; + + // this can be if corresponding workarea is first in sub-splitter + // or sub-splitter has another orientation + + // Resize ones again to reach precize position <-> + int need_pos_1 = splitter_pos + new_item_rel_pos + add_pos; + + // Move workarea inside splitter into required position <-> + int delta_1 = positionSimple(szList, nb, splitter_size, item_ind, + new_item_rel_pos, need_pos_1, splitter_pos); + split->setSizes(szList); + // Recompute new_item_rel_pos, as some windows can reject given size + new_item_rel_pos = 0; + QIntList szList1 = split->sizes(); + for (int i = 0; i < item_ind; i++) { + new_item_rel_pos += szList1[i]; + } + delta_1 = need_pos_1 - (splitter_pos + new_item_rel_pos); + return delta_1; + } + } + } else { + return setPosition(wid, sub_split, o, need_pos, splitter_pos); + } + + return 0; +} +// end: jfa 06.07.2005 + void QtxWorkstack::distributeSpace( QSplitter* split ) const { if ( !split ) diff --git a/src/Qtx/QtxWorkstack.h b/src/Qtx/QtxWorkstack.h index e86ac1ab7..d0eebbb13 100644 --- a/src/Qtx/QtxWorkstack.h +++ b/src/Qtx/QtxWorkstack.h @@ -29,6 +29,7 @@ class QTX_EXPORT QtxWorkstack : public QWidget enum { SplitVertical, SplitHorizontal, Close }; public: + QtxWorkstack( QWidget* = 0 ); virtual ~QtxWorkstack(); @@ -39,6 +40,62 @@ public: void split( const int ); + // begin: jfa 06.07.2005 + enum SplitType { + SPLIT_STAY, //!< given widget stays in its workarea, others are moved into a new one + SPLIT_AT, //!< widgets before a given widget stays in they workarea, others are moved into a new one + SPLIT_MOVE //!< given widget is moved into a new workarea, others stay in an old one + }; + + /*! + * \brief Split workarea of the given widget on two parts. + * \param wid - widget, belonging to this workstack + * \param o - orientation of splitting (Qt::Horizontal or Qt::Vertical) + * \param type - type of splitting, see SplitType enumeration + */ + void Split( QWidget* wid, const Qt::Orientation o, const SplitType type); + + /*! + * \brief Put given widget on top of its workarea + * \param wid - widget, belonging to this workstack + */ + void OnTop( QWidget* wid); + + /*! + * \brief Move widget(s) from source workarea into target workarea + * or just reorder widgets inside one workarea. + * \param wid1 - widget from target workarea + * \param wid2 - widget from source workarea + * \param all - if this parameter is TRUE, all widgets from source workarea will + * be moved into the target one, else only the \a wid2 will be moved + * + * Move \a wid2 in target workarea. Put it right after \a wid1. + * If value of boolean argument is TRUE, all widgets from source workarea + * will be moved together with \a wid2, source workarea will be deleted. + * If \a wid1 and \a wid2 belongs to one workarea, simple reordering will take place. + */ + void Attract( QWidget* wid1, QWidget* wid2, const bool all ); + + /*! + * \brief Set position of the widget relatively its splitter. + * \param wid - widget to set position of + * \param pos - position relatively splitter. Value in range [0..1]. + * + * Orientation of positioning will correspond to the splitter orientation. + */ + void SetRelativePositionInSplitter( QWidget* wid, const double pos ); + + /*! + * \brief Set position of the widget relatively the entire workstack. + * \param wid - widget to set position of + * \param o - orientation of positioning (Qt::Horizontal or Qt::Vertical). + * If o = Qt::Horizontal, horizontal position of \a wid will be changed. + * If o = Qt::Vertical, vertical position of \a wid will be changed. + * \param pos - position relatively workstack. Value in range [0..1]. + */ + void SetRelativePosition( QWidget* wid, const Qt::Orientation o, const double pos ); + // end: jfa 06.07.2005 + signals: void windowActivated( QWidget* ); @@ -81,6 +138,26 @@ private: void distributeSpace( QSplitter* ) const; + // begin: jfa 06.07.2005 + /*! + * \brief Set position of given widget. + * \param wid - widget to be moved + * \param split - currently processed splitter (goes from more common + * to more particular splitter in recursion calls) + * \param o - orientation of positioning + * \param need_pos - required position of the given widget in pixels + * (from top/left side of workstack area) + * \param splitter_pos - position of the splitter \a split + * (from top/left side of workstack area) + * \retval int - returns difference between a required and a distinguished position. + * + * Internal method. Recursively calls itself. + * Is called from SetRelativePosition public method. + */ + int setPosition( QWidget* wid, QSplitter* split, const Qt::Orientation o, + const int need_pos, const int splitter_pos); + // end: jfa 06.07.2005 + private: QWidget* myWin; QtxWorkstackArea* myArea; -- 2.39.2