#include <qwidgetstack.h>
#include <qapplication.h>
+#include <stream.h>
+
/*!
Class: QtxWorkstack [Public]
Descr:
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<QtxWorkstackArea> allAreas;
+ areas(mySplit, allAreas, true);
+
+ QPtrListIterator<QtxWorkstackArea> 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<QtxWorkstackArea> areaList;
+ areas(s, areaList);
+
+ QPtrList<QSplitter> 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<QtxWorkstackArea> allAreas;
+ areas(mySplit, allAreas, true);
+ QPtrListIterator<QtxWorkstackArea> 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<QtxWorkstackArea> allAreas;
+ areas(mySplit, allAreas, true);
+ QPtrListIterator<QtxWorkstackArea> 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 # <item_ind>
+ 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 # <item_ind>
+ *its = new_this;
+ ++its;
+ // set size to all items after an item # <item_ind>
+ 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<QtxWorkstackArea> allAreas;
+ areas(mySplit, allAreas, true);
+ for ( QPtrListIterator<QtxWorkstackArea> 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<QtxWorkstackArea> areaList;
+ areas((QSplitter*)it.current(), areaList, true);
+ for (QPtrListIterator<QtxWorkstackArea> 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 )
enum { SplitVertical, SplitHorizontal, Close };
public:
+
QtxWorkstack( QWidget* = 0 );
virtual ~QtxWorkstack();
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 <VAR>SplitType</VAR> 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* );
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 <VAR>SetRelativePosition</VAR> 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;