1 // File: QtxWorkstack.cxx
2 // Author: Sergey TELKOV
4 #include "QtxWorkstack.h"
13 #include <qsplitter.h>
14 #include <qpopupmenu.h>
15 #include <qobjectlist.h>
16 #include <qpushbutton.h>
17 #include <qwidgetstack.h>
18 #include <qapplication.h>
21 Class: QtxWorkstack [Public]
25 QtxWorkstack::QtxWorkstack( QWidget* parent )
30 myActionsMap.insert( SplitVertical, new QAction( tr( "Split vertically" ), 0, this ));
31 myActionsMap.insert( SplitHorizontal, new QAction( tr( "Split horizontally" ), 0, this ));
32 myActionsMap.insert( Close, new QAction( tr( "Close" ), 0, this ));
34 connect( myActionsMap[SplitVertical], SIGNAL( activated() ), this, SLOT( splitVertical() ) );
35 connect( myActionsMap[SplitHorizontal], SIGNAL( activated() ), this, SLOT( splitHorizontal() ) );
36 connect( myActionsMap[Close], SIGNAL( activated() ), this, SLOT( onCloseWindow() ) );
38 QVBoxLayout* base = new QVBoxLayout( this );
39 mySplit = new QSplitter( this );
40 mySplit->setChildrenCollapsible( false );
41 base->addWidget( mySplit );
44 QtxWorkstack::~QtxWorkstack()
48 QWidgetList QtxWorkstack::windowList() const
50 QPtrList<QtxWorkstackArea> lst;
51 areas( mySplit, lst, true );
54 for ( QPtrListIterator<QtxWorkstackArea> it( lst ); it.current(); ++it )
56 QWidgetList wids = it.current()->widgetList();
57 for ( QWidgetListIt itr( wids ); itr.current(); ++itr )
58 widList.append( itr.current() );
64 QWidgetList QtxWorkstack::splitWindowList() const
66 return myArea ? myArea->widgetList() : QWidgetList();
69 QWidget* QtxWorkstack::activeWindow() const
74 void QtxWorkstack::split( const int o )
76 QtxWorkstackArea* area = activeArea();
80 if ( area->widgetList().count() < 2 )
83 QWidget* curWid = area->activeWidget();
87 QSplitter* s = splitter( area );
88 QPtrList<QtxWorkstackArea> areaList;
91 QPtrList<QSplitter> splitList;
92 splitters( s, splitList );
95 if ( areaList.count() + splitList.count() < 2 || s->orientation() == o )
99 trg = wrapSplitter( area );
104 trg->setOrientation( (Orientation)o );
106 QtxWorkstackArea* newArea = createArea( 0 );
107 insertWidget( newArea, trg, area );
109 area->removeWidget( curWid );
110 newArea->insertWidget( curWid );
112 distributeSpace( trg );
119 * \brief Split workarea of the given widget on two parts.
120 * \param wid - widget, belonging to this workstack
121 * \param o - orientation of splitting (Qt::Horizontal or Qt::Vertical)
122 * \param type - type of splitting, see <VAR>SplitType</VAR> enumeration
124 void QtxWorkstack::Split (QWidget* wid, const Qt::Orientation o, const SplitType type)
128 // find area of the given widget
129 QtxWorkstackArea* area = NULL;
130 QPtrList<QtxWorkstackArea> allAreas;
131 areas(mySplit, allAreas, true);
133 QPtrListIterator<QtxWorkstackArea> it (allAreas);
134 for (; it.current() && !area; ++it) {
135 if (it.current()->contains(wid))
140 QWidgetList wids = area->widgetList();
141 if (wids.count() < 2)
144 QSplitter* s = splitter(area);
145 QPtrList<QtxWorkstackArea> areaList;
148 QPtrList<QSplitter> splitList;
149 splitters(s, splitList);
152 if (areaList.count() + splitList.count() < 2 || s->orientation() == o)
155 if (!trg) trg = wrapSplitter(area);
158 trg->setOrientation(o);
160 QtxWorkstackArea* newArea = createArea(0);
161 insertWidget(newArea, trg, area);
166 QWidgetListIt itr (wids);
167 for (; itr.current(); ++itr)
169 QWidget* wid_i = itr.current();
171 area->removeWidget(wid_i);
172 newArea->insertWidget(wid_i);
179 QWidgetListIt itr (wids);
180 for (; itr.current() && itr.current() != wid; ++itr) {
182 for (; itr.current(); ++itr) {
183 area->removeWidget(itr.current());
184 newArea->insertWidget(itr.current());
189 area->removeWidget(wid);
190 newArea->insertWidget(wid);
194 distributeSpace(trg);
198 * \brief Put given widget on top of its workarea
199 * \param wid - widget, belonging to this workstack
202 void QtxWorkstack::OnTop (QWidget* wid)
207 // find area of the given widget
208 QtxWorkstackArea* area = 0;
209 QPtrList<QtxWorkstackArea> allAreas;
210 areas( mySplit, allAreas, true );
211 for ( QPtrListIterator<QtxWorkstackArea> it( allAreas ); it.current() && !area; ++it )
213 if ( it.current()->contains( wid ) )
218 area->setActiveWidget( wid );
223 * \brief Move widget(s) from source workarea into target workarea
224 * or just reorder widgets inside one workarea.
225 * \param wid1 - widget from target workarea
226 * \param wid2 - widget from source workarea
227 * \param all - if this parameter is TRUE, all widgets from source workarea will
228 * be moved into the target one, else only the \a wid2 will be moved
230 * Move \a wid2 in target workarea. Put it right after \a wid1.
231 * If value of boolean argument is TRUE, all widgets from source workarea
232 * will be moved together with \a wid2, source workarea will be deleted.
233 * If \a wid1 and \a wid2 belongs to one workarea, simple reordering will take place.
235 void QtxWorkstack::Attract ( QWidget* wid1, QWidget* wid2, const bool all )
237 if ( !wid1 || !wid2 )
240 // find area of the widgets
241 QtxWorkstackArea *area1 = NULL, *area2 = NULL;
242 QPtrList<QtxWorkstackArea> allAreas;
243 areas(mySplit, allAreas, true);
244 QPtrListIterator<QtxWorkstackArea> it (allAreas);
245 for (; it.current() && !(area1 && area2); ++it) {
246 if (it.current()->contains(wid1))
247 area1 = it.current();
248 if (it.current()->contains(wid2))
249 area2 = it.current();
251 if (!area1 || !area2) return;
253 QWidget* curWid = area1->activeWidget();
256 if (area1 == area2) {
258 // Set wid1 at first position, wid2 at second
259 area1->insertWidget(wid1);
260 area1->insertWidget(wid2, 1);
262 // Set wid2 right after wid1
263 area1->removeWidget(wid2);
265 QWidgetList wids1 = area1->widgetList();
266 QWidgetListIt itr1 (wids1);
267 for (; itr1.current() && itr1.current() != wid1; ++itr1, ++wid1_ind);
268 area1->insertWidget(wid2, wid1_ind + 1);
272 QWidgetList wids1 = area1->widgetList();
273 QWidgetListIt itr1 (wids1);
274 for (; itr1.current() && itr1.current() != wid1; ++itr1, ++wid1_ind);
277 // Set wid2 right after wid1, other widgets from area2 right after wid2
278 QWidgetList wids2 = area2->widgetList();
279 QWidgetListIt itr2 (wids2);
280 for (int ind = wid1_ind + 1; itr2.current(); ++itr2, ++ind)
282 area2->removeWidget(itr2.current());
283 if (itr2.current() == wid2) {
284 area1->insertWidget(itr2.current(), wid1_ind + 1);
286 area1->insertWidget(itr2.current(), ind);
290 // Set wid2 right after wid1
291 area2->removeWidget(wid2);
292 area1->insertWidget(wid2, wid1_ind + 1);
296 area1->setActiveWidget( curWid );
299 static void setSizes (QIntList& szList, const int item_ind,
300 const int new_near, const int new_this, const int new_farr)
302 // set size to all items before an item # <item_ind>
304 QIntList::iterator its = szList.begin();
305 for (; its != szList.end() && cur_pos < item_ind; ++its, ++cur_pos) {
308 if (its == szList.end()) return;
309 // set size to item # <item_ind>
312 // set size to all items after an item # <item_ind>
313 for (; its != szList.end(); ++its) {
319 * \brief Set position of the widget relatively its splitter.
320 * \param wid - widget to set position of
321 * \param pos - position relatively splitter. Value in range [0..1].
323 * Orientation of positioning will correspond to the splitter orientation.
325 void QtxWorkstack::SetRelativePositionInSplitter( QWidget* wid, const double position )
327 if ( position < 0.0 || 1.0 < position)
333 // find area of the given widget
334 QtxWorkstackArea* area = NULL;
335 QPtrList<QtxWorkstackArea> allAreas;
336 areas(mySplit, allAreas, true);
337 for ( QPtrListIterator<QtxWorkstackArea> it( allAreas );
338 it.current() && !area;
341 if (it.current()->contains(wid))
348 QSplitter* split = splitter( area );
352 // find index of the area in its splitter
354 bool isFound = false;
355 const QObjectList* was = split->children();
356 for (QObjectListIt ito (*was); ito.current() && !isFound; ++ito, ++item_ind)
358 if (ito.current() == area)
361 if (!isFound || item_ind == 0)
364 QIntList szList = split->sizes();
365 int splitter_size = (split->orientation() == Horizontal ?
366 split->width() : split->height());
367 int nb = szList.count();
369 int new_prev = int(splitter_size * position / item_ind);
370 int new_next = int(splitter_size * (1.0 - position) / (nb - item_ind));
371 setSizes (szList, item_ind, new_prev, new_next, new_next);
372 split->setSizes(szList);
376 * \brief Set position of the widget relatively the entire workstack.
377 * \param wid - widget to set position of
378 * \param o - orientation of positioning (Qt::Horizontal or Qt::Vertical).
379 * If o = Qt::Horizontal, horizontal position of \a wid will be changed.
380 * If o = Qt::Vertical, vertical position of \a wid will be changed.
381 * \param pos - position relatively workstack. Value in range [0..1].
383 void QtxWorkstack::SetRelativePosition( QWidget* wid, const Qt::Orientation o,
384 const double position )
386 if ( position < 0.0 || 1.0 < position )
392 int splitter_size = o == Horizontal ? mySplit->width() : mySplit->height();
393 int need_pos = int( position * splitter_size );
394 int splitter_pos = 0;
396 if ( setPosition( wid, mySplit, o, need_pos, splitter_pos ) != 0 )
398 // impossible to set required position
403 * \brief Sets the action's accelerator key to accel.
404 * \param id - the key of the action in the actions map.
405 * \param accel - action's accelerator key.
407 void QtxWorkstack::setAccel( const int id, const int accel )
409 if ( !myActionsMap.contains( id ) )
412 myActionsMap[id]->setAccel( accel );
416 * \brief Returns the action's accelerator key.
417 * \param id - the key of the action in the actions map.
418 * \retval int - action's accelerator key.
420 int QtxWorkstack::accel( const int id ) const
423 if ( myActionsMap.contains( id ) )
424 res = myActionsMap[id]->accel();
428 static int positionSimple (QIntList& szList, const int nb, const int splitter_size,
429 const int item_ind, const int item_rel_pos,
430 const int need_pos, const int splitter_pos)
432 if (item_ind == 0) { // cannot move in this splitter
433 return (need_pos - splitter_pos);
438 int new_this = szList[item_ind];
441 bool isToCheck = false;
443 if (need_pos < splitter_pos) {
444 // Set size of all previous workareas to zero <--
445 if (item_ind == nb - 1) {
446 // item iz last in the splitter, it will occupy all the splitter
447 new_this = splitter_size;
449 // recompute size of next items in splitter
450 new_next = (splitter_size - new_this) / (nb - item_ind - 1);
452 delta = need_pos - splitter_pos;
454 } else if (need_pos > (splitter_pos + splitter_size)) {
455 // Set size of all next workareas to zero -->
456 // recompute size of previous items in splitter
458 new_prev = (splitter_size - new_this) / item_ind;
459 delta = need_pos - (splitter_pos + splitter_size - new_this);
461 } else { // required position lays inside this splitter
462 // Move workarea inside splitter into required position <->
463 int new_item_rel_pos = need_pos - splitter_pos;
464 new_prev = new_item_rel_pos / item_ind;
465 if (need_pos < (splitter_pos + item_rel_pos)) {
466 // Make previous workareas smaller, next - bigger
467 // No problem to keep old size of the widget
469 // Make previous workareas bigger, next - smaller
470 if (new_this > splitter_size - new_item_rel_pos) {
471 new_this = splitter_size - new_item_rel_pos;
473 // jfa to do: in this case fixed size of next widgets could prevent right resizing
476 if (item_ind == nb - 1) {
477 new_this = splitter_size - new_item_rel_pos;
479 new_next = (splitter_size - new_item_rel_pos - new_this) / (nb - item_ind - 1);
484 setSizes (szList, item_ind, new_prev, new_this, new_next);
489 * \brief Set position of given widget.
490 * \param wid - widget to be moved
491 * \param split - currently processed splitter (goes from more common
492 * to more particular splitter in recursion calls)
493 * \param o - orientation of positioning
494 * \param need_pos - required position of the given widget in pixels
495 * (from top/left side of workstack area)
496 * \param splitter_pos - position of the splitter \a split
497 * (from top/left side of workstack area)
498 * \retval int - returns difference between a required and a distinguished position.
500 * Internal method. Recursively calls itself.
501 * Is called from <VAR>SetRelativePosition</VAR> public method.
503 int QtxWorkstack::setPosition( QWidget* wid, QSplitter* split, const Qt::Orientation o,
504 const int need_pos, const int splitter_pos )
506 if ( !wid || !split )
507 return need_pos - splitter_pos;
509 // Find corresponding sub-splitter.
510 // Find also index of appropriate item in current splitter.
511 int cur_ind = 0, item_ind = 0;
512 bool isBottom = false, isFound = false;
513 QSplitter* sub_split = NULL;
514 const QObjectList* objs = split->children();
517 for (QObjectListIt it (*objs); it.current() && !isFound; ++it)
519 if (it.current()->inherits( "QtxWorkstackArea")) {
520 if (((QtxWorkstackArea*)it.current())->contains(wid)) {
526 } else if (it.current()->inherits("QSplitter")) {
527 QPtrList<QtxWorkstackArea> areaList;
528 areas((QSplitter*)it.current(), areaList, true);
529 for (QPtrListIterator<QtxWorkstackArea> ita (areaList);
530 ita.current() && !isFound;
533 if (ita.current()->contains(wid)) {
536 sub_split = (QSplitter*)it.current();
544 return (need_pos - splitter_pos);
546 if (split->orientation() == o) {
547 // Find coordinates of near and far sides of the appropriate item relatively current splitter
548 int splitter_size = (o == Horizontal ? split->width() : split->height());
549 QIntList szList = split->sizes();
550 int nb = szList.count();
551 int item_rel_pos = 0; // position of near side of item relatively this splitter
552 for (int i = 0; i < item_ind; i++) {
553 item_rel_pos += szList[i];
555 int item_size = szList[item_ind]; // size of item
556 int item_pos = splitter_pos + item_rel_pos;
558 // Resize splitter items to complete the conditions
560 // I. Bottom of splitters stack reached
562 int delta = positionSimple(szList, nb, splitter_size, item_ind, item_rel_pos, need_pos, splitter_pos);
563 split->setSizes(szList);
564 // Recompute delta, as some windows can reject given size
565 int new_item_rel_pos = 0;
566 QIntList szList1 = split->sizes();
567 for (int i = 0; i < item_ind; i++) {
568 new_item_rel_pos += szList1[i];
570 delta = need_pos - (splitter_pos + new_item_rel_pos);
574 // II. Bottom of splitters stack is not yet reached
576 if (item_ind == 0) { // cannot move in this splitter
577 // Process in sub-splitter
578 return setPosition(wid, sub_split, o, need_pos, splitter_pos);
582 int new_this = szList[item_ind];
585 if (need_pos < splitter_pos) {
586 // Set size of all previous workareas to zero <--
587 if (item_ind == nb - 1) {
588 new_this = splitter_size;
590 new_next = (splitter_size - new_this) / (nb - item_ind - 1);
592 setSizes (szList, item_ind, new_prev, new_this, new_next);
593 split->setSizes(szList);
594 // Recompute splitter_pos, as some windows can reject given size
595 int new_item_rel_pos = 0;
596 QIntList szList1 = split->sizes();
597 for (int i = 0; i < item_ind; i++) {
598 new_item_rel_pos += szList1[i];
600 // Process in sub-splitter
601 return setPosition(wid, sub_split, o, need_pos, splitter_pos + new_item_rel_pos);
602 } else if (need_pos > (splitter_pos + splitter_size)) {
603 // Set size of all next workareas to zero -->
604 new_prev = (splitter_size - new_this) / item_ind;
605 setSizes (szList, item_ind, new_prev, new_this, new_next);
606 split->setSizes(szList);
607 // Recompute splitter_pos, as some windows can reject given size
608 int new_item_rel_pos = 0;
609 QIntList szList1 = split->sizes();
610 for (int i = 0; i < item_ind; i++) {
611 new_item_rel_pos += szList1[i];
613 // Process in sub-splitter
614 return setPosition(wid, sub_split, o, need_pos, splitter_pos + new_item_rel_pos);
616 // Set appropriate size of all previous/next items <->
617 int new_item_rel_pos = item_rel_pos;
618 if (need_pos < item_pos || (item_pos + item_size) < need_pos) {
619 // Move item inside splitter into required position <->
620 int new_this = szList[item_ind];
622 new_item_rel_pos = need_pos - splitter_pos;
623 if ((item_pos + item_size) < need_pos) {
624 //new_item_rel_pos = need_pos - (item_pos + item_size);
625 new_item_rel_pos = item_rel_pos + (need_pos - (item_pos + item_size));
627 int new_prev = new_item_rel_pos / item_ind;
628 if (need_pos < (splitter_pos + item_rel_pos)) {
629 // Make previous workareas smaller, next - bigger
630 // No problem to keep old size of the widget
632 // Make previous workareas bigger, next - smaller
633 if (new_this > splitter_size - new_item_rel_pos) {
634 new_this = splitter_size - new_item_rel_pos;
637 if (item_ind == nb - 1) {
638 new_this = splitter_size - new_item_rel_pos;
640 new_next = (splitter_size - new_item_rel_pos - new_this) / (nb - item_ind - 1);
642 setSizes (szList, item_ind, new_prev, new_this, new_next);
643 split->setSizes(szList);
644 // Recompute new_item_rel_pos, as some windows can reject given size
645 new_item_rel_pos = 0;
646 QIntList szList1 = split->sizes();
647 for (int i = 0; i < item_ind; i++) {
648 new_item_rel_pos += szList1[i];
653 // Process in sub-splitter
654 int add_pos = setPosition(wid, sub_split, o, need_pos, splitter_pos + new_item_rel_pos);
658 // this can be if corresponding workarea is first in sub-splitter
659 // or sub-splitter has another orientation
661 // Resize ones again to reach precize position <->
662 int need_pos_1 = splitter_pos + new_item_rel_pos + add_pos;
664 // Move workarea inside splitter into required position <->
665 int delta_1 = positionSimple(szList, nb, splitter_size, item_ind,
666 new_item_rel_pos, need_pos_1, splitter_pos);
667 split->setSizes(szList);
668 // Recompute new_item_rel_pos, as some windows can reject given size
669 new_item_rel_pos = 0;
670 QIntList szList1 = split->sizes();
671 for (int i = 0; i < item_ind; i++) {
672 new_item_rel_pos += szList1[i];
674 delta_1 = need_pos_1 - (splitter_pos + new_item_rel_pos);
679 return setPosition(wid, sub_split, o, need_pos, splitter_pos);
685 void QtxWorkstack::distributeSpace( QSplitter* split ) const
690 QIntList szList = split->sizes();
691 int size = ( split->orientation() == Horizontal ?
692 split->width() : split->height() ) / szList.count();
693 for ( QIntList::iterator it = szList.begin(); it != szList.end(); ++it )
695 split->setSizes( szList );
698 void QtxWorkstack::splitVertical()
700 split( Qt::Horizontal );
703 void QtxWorkstack::splitHorizontal()
705 split( Qt::Vertical );
708 QSplitter* QtxWorkstack::wrapSplitter( QtxWorkstackArea* area )
713 QSplitter* pSplit = splitter( area );
717 bool upd = pSplit->isUpdatesEnabled();
718 pSplit->setUpdatesEnabled( false );
720 QIntList szList = pSplit->sizes();
722 QSplitter* wrap = new QSplitter( 0 );
723 #if defined QT_VERSION && QT_VERSION >= 0x30200
724 wrap->setChildrenCollapsible( false );
726 insertWidget( wrap, pSplit, area );
727 area->reparent( wrap, QPoint( 0, 0 ), true );
729 pSplit->setSizes( szList );
731 pSplit->setUpdatesEnabled( upd );
736 void QtxWorkstack::insertWidget( QWidget* wid, QWidget* pWid, QWidget* after )
741 QWidgetList moveList;
742 const QObjectList* lst = pWid->children();
746 for ( QObjectListIt it( *lst ); it.current(); ++it )
748 if ( found && ( it.current()->inherits( "QSplitter" ) ||
749 it.current()->inherits( "QtxWorkstackArea" ) ) )
750 moveList.append( (QWidget*)it.current() );
751 if ( it.current() == after )
756 QMap<QWidget*, bool> map;
757 for ( QWidgetListIt it( moveList ); it.current(); ++it )
759 map.insert( it.current(), it.current()->isVisibleTo( it.current()->parentWidget() ) );
760 it.current()->reparent( 0, QPoint( 0, 0 ), false );
763 wid->reparent( pWid, QPoint( 0, 0 ), true );
765 for ( QWidgetListIt itr( moveList ); itr.current(); ++itr )
766 itr.current()->reparent( pWid, QPoint( 0, 0 ), map.contains( itr.current() ) ? map[itr.current()] : false );
770 * \brief Closes the active window.
772 void QtxWorkstack::onCloseWindow()
774 if ( activeWindow() )
775 activeWindow()->close();
778 void QtxWorkstack::onDestroyed( QObject* obj )
780 QtxWorkstackArea* area = (QtxWorkstackArea*)obj;
782 if ( area == myArea )
787 QtxWorkstackArea* cur = neighbourArea( area );
792 QApplication::postEvent( this, new QCustomEvent( QEvent::User ) );
795 void QtxWorkstack::onWindowActivated( QWidget* wid )
797 const QObject* obj = sender();
798 if ( !obj->inherits( "QtxWorkstackArea" ) )
801 setActiveArea( (QtxWorkstackArea*)obj );
804 void QtxWorkstack::onDeactivated( QtxWorkstackArea* area )
806 if ( myArea != area )
809 QPtrList<QtxWorkstackArea> lst;
810 areas( mySplit, lst, true );
812 int idx = lst.find( area );
819 QtxWorkstackArea* newArea = neighbourArea( area );
820 if ( newArea && newArea->activeWidget() )
821 newArea->activeWidget()->setFocus();
823 QApplication::postEvent( this, new QCustomEvent( QEvent::User ) );
826 void QtxWorkstack::onContextMenuRequested( QPoint p )
831 QWidgetList lst = activeArea()->widgetList();
835 QPopupMenu* pm = new QPopupMenu();
837 if ( lst.count() > 1 )
839 myActionsMap[SplitVertical]->addTo( pm );
840 myActionsMap[SplitHorizontal]->addTo( pm );
841 pm->insertSeparator();
843 myActionsMap[Close]->addTo( pm );
850 void QtxWorkstack::childEvent( QChildEvent* e )
852 if ( e->inserted() && e->child()->isWidgetType() )
854 QWidget* w = (QWidget*)e->child();
855 if ( w && w != mySplit )
857 targetArea()->insertWidget( w );
861 QWidget::childEvent( e );
864 void QtxWorkstack::customEvent( QCustomEvent* e )
869 QSplitter* QtxWorkstack::splitter( QtxWorkstackArea* area ) const
874 QSplitter* split = 0;
876 QWidget* wid = area->parentWidget();
877 if ( wid && wid->inherits( "QSplitter" ) )
878 split = (QSplitter*)wid;
883 void QtxWorkstack::splitters( QSplitter* split, QPtrList<QSplitter>& splitList, const bool rec ) const
888 const QObjectList* objs = split->children();
891 for ( QObjectListIt it( *objs ); it.current(); ++it )
894 splitters( (QSplitter*)it.current(), splitList, rec );
895 if ( it.current()->inherits( "QSplitter" ) )
896 splitList.append( (QSplitter*)it.current() );
901 void QtxWorkstack::areas( QSplitter* split, QPtrList<QtxWorkstackArea>& areaList, const bool rec ) const
906 const QObjectList* objs = split->children();
909 for ( QObjectListIt it( *objs ); it.current(); ++it )
911 if ( it.current()->inherits( "QtxWorkstackArea" ) )
912 areaList.append( (QtxWorkstackArea*)it.current() );
913 else if ( rec && it.current()->inherits( "QSplitter" ) )
914 areas( (QSplitter*)it.current(), areaList, rec );
919 QtxWorkstackArea* QtxWorkstack::activeArea() const
924 QtxWorkstackArea* QtxWorkstack::targetArea()
926 QtxWorkstackArea* area = activeArea();
928 area = currentArea();
931 QPtrList<QtxWorkstackArea> lst;
932 areas( mySplit, lst );
933 if ( !lst.isEmpty() )
938 area = createArea( mySplit );
943 QtxWorkstackArea* QtxWorkstack::currentArea() const
945 QtxWorkstackArea* area = 0;
946 QWidget* wid = focusWidget();
947 while ( wid && !area )
949 if ( wid->inherits( "QtxWorkstackArea" ) )
950 area = (QtxWorkstackArea*)wid;
951 wid = wid->parentWidget();
957 QtxWorkstackArea* QtxWorkstack::createArea( QWidget* parent ) const
959 QtxWorkstackArea* area = new QtxWorkstackArea( parent );
961 connect( area, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
962 connect( area, SIGNAL( activated( QWidget* ) ), this, SLOT( onWindowActivated( QWidget* ) ) );
963 connect( area, SIGNAL( contextMenuRequested( QPoint ) ), this, SLOT( onContextMenuRequested( QPoint ) ) );
964 connect( area, SIGNAL( deactivated( QtxWorkstackArea* ) ), this, SLOT( onDeactivated( QtxWorkstackArea* ) ) );
969 void QtxWorkstack::setActiveArea( QtxWorkstackArea* area )
971 QWidget* oldCur = myWin;
973 QtxWorkstackArea* oldArea = myArea;
977 if ( myArea != oldArea )
980 oldArea->updateActiveState();
982 myArea->updateActiveState();
986 myWin = myArea->activeWidget();
988 if ( myWin && oldCur != myWin )
989 emit windowActivated( myWin );
992 QtxWorkstackArea* QtxWorkstack::neighbourArea( QtxWorkstackArea* area ) const
994 QPtrList<QtxWorkstackArea> lst;
995 areas( mySplit, lst, true );
996 int pos = lst.find( area );
1000 QtxWorkstackArea* na = 0;
1001 for ( int i = pos - 1; i >= 0 && !na; i-- )
1003 if ( !lst.at( i )->isEmpty() )
1007 for ( int j = pos + 1; j < (int)lst.count() && !na; j++ )
1009 if ( !lst.at( j )->isEmpty() )
1015 QtxWorkstackArea* QtxWorkstack::areaAt( const QPoint& p ) const
1017 QtxWorkstackArea* area = 0;
1018 QPtrList<QtxWorkstackArea> lst;
1019 areas( mySplit, lst, true );
1020 for ( QPtrListIterator<QtxWorkstackArea> it( lst ); it.current() && !area; ++it )
1022 QtxWorkstackArea* cur = it.current();
1023 QRect r = cur->geometry();
1024 if ( cur->parentWidget() )
1025 r = QRect( cur->parentWidget()->mapToGlobal( r.topLeft() ), r.size() );
1026 if ( r.contains( p ) )
1032 void QtxWorkstack::updateState()
1034 updateState( mySplit );
1037 void QtxWorkstack::updateState( QSplitter* split )
1039 QPtrList<QSplitter> recList;
1040 splitters( split, recList, false );
1041 for ( QPtrListIterator<QSplitter> itr( recList ); itr.current(); ++itr )
1042 updateState( itr.current() );
1044 QPtrList<QSplitter> splitList;
1045 splitters( split, splitList, false );
1047 QPtrList<QtxWorkstackArea> areaList;
1048 areas( split, areaList, false );
1051 for ( QPtrListIterator<QtxWorkstackArea> it( areaList ); it.current(); ++it )
1053 if ( it.current()->isEmpty() )
1054 it.current()->hide();
1057 it.current()->show();
1062 if ( split == mySplit )
1065 for ( QPtrListIterator<QSplitter> iter( splitList ); iter.current() && !vis; ++iter )
1066 vis = iter.current()->isVisibleTo( iter.current()->parentWidget() );
1068 if ( areaList.isEmpty() && splitList.isEmpty() )
1077 Class: QtxWorkstackArea [Internal]
1081 QtxWorkstackArea::QtxWorkstackArea( QWidget* parent )
1084 QVBoxLayout* base = new QVBoxLayout( this );
1086 QHBox* top = new QHBox( this );
1087 base->addWidget( top );
1089 myBar = new QtxWorkstackTabBar( top );
1091 QPushButton* close = new QPushButton( top );
1092 close->setPixmap( style().stylePixmap( QStyle::SP_TitleBarCloseButton ) );
1093 close->setAutoDefault( true );
1094 close->setFlat( true );
1097 top->setStretchFactor( myBar, 1 );
1099 myStack = new QWidgetStack( this );
1101 base->addWidget( myStack, 1 );
1103 connect( myClose, SIGNAL( clicked() ), this, SLOT( onClose() ) );
1104 connect( myBar, SIGNAL( selected( int ) ), this, SLOT( onSelected( int ) ) );
1105 connect( myBar, SIGNAL( dragActiveTab() ), this, SLOT( onDragActiveTab() ) );
1106 connect( myBar, SIGNAL( contextMenuRequested( QPoint ) ), this, SIGNAL( contextMenuRequested( QPoint ) ) );
1110 updateActiveState();
1112 qApp->installEventFilter( this );
1115 QtxWorkstackArea::~QtxWorkstackArea()
1117 qApp->removeEventFilter( this );
1120 bool QtxWorkstackArea::isEmpty() const
1123 for ( WidgetInfoMap::ConstIterator it = myInfo.begin(); it != myInfo.end() && !res; ++it )
1124 res = it.data().vis;
1128 void QtxWorkstackArea::insertWidget( QWidget* wid, const int idx )
1133 int pos = myList.find( wid );
1134 if ( pos != -1 && ( pos == idx || ( idx < 0 && pos == (int)myList.count() - 1 ) ) )
1137 myList.removeRef( wid );
1138 pos = idx < 0 ? myList.count() : idx;
1139 myList.insert( QMIN( pos, (int)myList.count() ), wid );
1140 if ( !myInfo.contains( wid ) )
1142 QtxWorkstackChild* child = new QtxWorkstackChild( wid, myStack );
1143 myChild.insert( wid, child );
1144 myInfo.insert( wid, WidgetInfo() );
1145 myInfo[wid].id = generateId();
1146 myInfo[wid].vis = wid->isVisibleTo( wid->parentWidget() );
1148 connect( child, SIGNAL( destroyed( QObject* ) ), this, SLOT( onChildDestroyed( QObject* ) ) );
1149 connect( wid, SIGNAL( destroyed() ), this, SLOT( onWidgetDestroyed() ) );
1150 connect( child, SIGNAL( shown( QtxWorkstackChild* ) ), this, SLOT( onChildShown( QtxWorkstackChild* ) ) );
1151 connect( child, SIGNAL( hided( QtxWorkstackChild* ) ), this, SLOT( onChildHided( QtxWorkstackChild* ) ) );
1152 connect( child, SIGNAL( activated( QtxWorkstackChild* ) ), this, SLOT( onChildActivated( QtxWorkstackChild* ) ) );
1153 connect( child, SIGNAL( captionChanged( QtxWorkstackChild* ) ), this, SLOT( onChildCaptionChanged( QtxWorkstackChild* ) ) );
1158 setWidgetActive( wid );
1161 void QtxWorkstackArea::onWidgetDestroyed()
1164 removeWidget( (QWidget*)sender(), false );
1167 void QtxWorkstackArea::removeWidget( QWidget* wid, const bool del )
1169 if ( !myList.contains( wid ) )
1172 if ( myBar->tab( widgetId( wid ) ) )
1173 myBar->removeTab( myBar->tab( widgetId( wid ) ) );
1174 myStack->removeWidget( child( wid ) );
1176 myList.remove( wid );
1177 myInfo.remove( wid );
1178 myChild.remove( wid );
1182 delete child( wid );
1183 if( myList.isEmpty() )
1192 QWidgetList QtxWorkstackArea::widgetList() const
1195 for ( QWidgetListIt it( myList ); it.current(); ++it )
1197 if ( widgetVisibility( it.current() ) )
1198 lst.append( it.current() );
1203 QWidget* QtxWorkstackArea::activeWidget() const
1205 return widget( myBar->currentTab() );
1208 void QtxWorkstackArea::setActiveWidget( QWidget* wid )
1210 myBar->setCurrentTab( widgetId( wid ) );
1213 bool QtxWorkstackArea::contains( QWidget* wid ) const
1215 return myList.contains( wid );
1218 void QtxWorkstackArea::show()
1220 QMap<QWidget*, bool> map;
1221 for ( QWidgetListIt it( myList ); it.current(); ++it )
1223 map.insert( it.current(), isBlocked( it.current() ) );
1224 setBlocked( it.current(), true );
1229 for ( QWidgetListIt itr( myList ); itr.current(); ++itr )
1230 setBlocked( itr.current(), map.contains( itr.current() ) ? map[itr.current()] : false );
1233 void QtxWorkstackArea::hide()
1235 QMap<QWidget*, bool> map;
1236 for ( QWidgetListIt it( myList ); it.current(); ++it )
1238 map.insert( it.current(), isBlocked( it.current() ) );
1239 setBlocked( it.current(), true );
1244 for ( QWidgetListIt itr( myList ); itr.current(); ++itr )
1245 setBlocked( itr.current(), map.contains( itr.current() ) ? map[itr.current()] : false );
1248 bool QtxWorkstackArea::isActive() const
1250 QtxWorkstack* ws = workstack();
1254 return ws->activeArea() == this;
1257 void QtxWorkstackArea::updateActiveState()
1259 myBar->setActive( isActive() );
1262 QtxWorkstack* QtxWorkstackArea::workstack() const
1264 QtxWorkstack* ws = 0;
1265 QWidget* wid = parentWidget();
1266 while ( wid && !ws )
1268 if ( wid->inherits( "QtxWorkstack" ) )
1269 ws = (QtxWorkstack*)wid;
1270 wid = wid->parentWidget();
1275 bool QtxWorkstackArea::eventFilter( QObject* o, QEvent* e )
1277 if ( o->isWidgetType() )
1279 QWidget* wid = (QWidget*)o;
1280 if ( e->type() == QEvent::FocusIn || e->type() == QEvent::MouseButtonPress )
1283 while ( !ok && wid && wid != myClose )
1286 wid = wid->parentWidget();
1289 QApplication::postEvent( this, new QCustomEvent( (QEvent::Type)( e->type() == QEvent::FocusIn ? ActivateWidget : FocusWidget ) ) );
1295 QRect QtxWorkstackArea::floatRect() const
1297 QRect r = myStack->geometry();
1298 return QRect( mapToGlobal( r.topLeft() ), mapToGlobal( r.bottomRight() ) );
1301 QRect QtxWorkstackArea::floatTab( const int idx ) const
1303 return myBar->tabRect( idx );
1306 int QtxWorkstackArea::tabAt( const QPoint& p ) const
1309 for ( int i = 0; i < myBar->count() && idx == -1; i++ )
1311 QRect r = myBar->tabRect( i );
1312 if ( r.isValid() && r.contains( p ) )
1318 void QtxWorkstackArea::customEvent( QCustomEvent* e )
1320 switch ( e->type() )
1322 case ActivateWidget:
1323 emit activated( activeWidget() );
1326 if ( activeWidget() && !activeWidget()->focusWidget() )
1327 activeWidget()->setFocus();
1330 removeWidget( (QWidget*)e->data() );
1335 void QtxWorkstackArea::focusInEvent( QFocusEvent* e )
1337 QWidget::focusInEvent( e );
1339 emit activated( activeWidget() );
1342 void QtxWorkstackArea::mousePressEvent( QMouseEvent* e )
1344 QWidget::mousePressEvent( e );
1346 emit activated( activeWidget() );
1349 void QtxWorkstackArea::onClose()
1351 QWidget* wid = activeWidget();
1356 void QtxWorkstackArea::onSelected( int id )
1360 emit activated( activeWidget() );
1363 void QtxWorkstackArea::onDragActiveTab()
1365 QtxWorkstackChild* c = child( activeWidget() );
1369 new QtxWorkstackDrag( workstack(), c );
1372 void QtxWorkstackArea::onChildDestroyed( QObject* obj )
1374 QtxWorkstackChild* child = (QtxWorkstackChild*)obj;
1375 myStack->removeWidget( child );
1378 for ( ChildMap::ConstIterator it = myChild.begin(); it != myChild.end() && !wid; ++it )
1380 if ( it.data() == child )
1384 myChild.remove( wid );
1386 QApplication::postEvent( this, new QCustomEvent( (QEvent::Type)RemoveWidget, wid ) );
1389 void QtxWorkstackArea::onChildShown( QtxWorkstackChild* c )
1391 setWidgetShown( c->widget(), true );
1394 void QtxWorkstackArea::onChildHided( QtxWorkstackChild* c )
1396 setWidgetShown( c->widget(), false );
1399 void QtxWorkstackArea::onChildActivated( QtxWorkstackChild* c )
1401 setWidgetActive( c->widget() );
1404 void QtxWorkstackArea::onChildCaptionChanged( QtxWorkstackChild* c )
1406 updateTab( c->widget() );
1409 void QtxWorkstackArea::updateCurrent()
1411 QMap<QWidget*, bool> map;
1412 for ( QWidgetListIt it( myList ); it.current(); ++it )
1414 map.insert( it.current(), isBlocked( it.current() ) );
1415 setBlocked( it.current(), true );
1418 myStack->raiseWidget( myBar->currentTab() );
1420 for ( QWidgetListIt itr( myList ); itr.current(); ++itr )
1421 setBlocked( itr.current(), map.contains( itr.current() ) ? map[itr.current()] : false );
1424 void QtxWorkstackArea::updateTab( QWidget* wid )
1426 QTab* tab = myBar->tab( widgetId( wid ) );
1433 QPixmap pix = *wid->icon();
1434 pix.convertFromImage( pix.convertToImage().smoothScale( pix.width(), 16, QImage::ScaleMin ) );
1435 icoSet = QIconSet( pix );
1438 tab->setIconSet( icoSet );
1439 tab->setText( wid->caption() );
1442 QWidget* QtxWorkstackArea::widget( const int id ) const
1445 for ( WidgetInfoMap::ConstIterator it = myInfo.begin(); it != myInfo.end() && !wid; ++it )
1447 if ( it.data().id == id )
1453 int QtxWorkstackArea::widgetId( QWidget* wid ) const
1456 if ( myInfo.contains( wid ) )
1457 id = myInfo[wid].id;
1461 bool QtxWorkstackArea::widgetVisibility( QWidget* wid ) const
1464 if ( myInfo.contains( wid ) )
1465 res = myInfo[wid].vis;
1469 void QtxWorkstackArea::setWidgetActive( QWidget* wid )
1471 int id = widgetId( wid );
1475 myBar->setCurrentTab( id );
1478 void QtxWorkstackArea::setWidgetShown( QWidget* wid, const bool on )
1480 if ( isBlocked( wid ) || !myInfo.contains( wid ) || myInfo[wid].vis == on )
1483 myInfo[wid].vis = on;
1487 void QtxWorkstackArea::updateState()
1489 bool updBar = myBar->isUpdatesEnabled();
1490 bool updStk = myStack->isUpdatesEnabled();
1491 myBar->setUpdatesEnabled( false );
1492 myStack->setUpdatesEnabled( false );
1494 bool block = myBar->signalsBlocked();
1495 myBar->blockSignals( true );
1497 QWidget* prev = activeWidget();
1500 for ( QWidgetListIt it( myList ); it.current(); ++it )
1502 QWidget* wid = it.current();
1503 int id = widgetId( wid );
1508 bool vis = widgetVisibility( wid );
1510 if ( myBar->tab( id ) && ( !vis || myBar->indexOf( id ) != idx ) )
1511 myBar->removeTab( myBar->tab( id ) );
1513 if ( !myBar->tab( id ) && vis )
1515 QTab* tab = new QTab( wid->caption() );
1516 myBar->insertTab( tab, idx );
1517 tab->setIdentifier( id );
1522 bool block = isBlocked( wid );
1523 setBlocked( wid, true );
1525 QtxWorkstackChild* cont = child( wid );
1528 myStack->removeWidget( cont );
1529 else if ( !myStack->widget( id ) )
1530 myStack->addWidget( cont, id );
1535 setBlocked( wid, block );
1538 int curId = widgetId( prev );
1539 if ( !myBar->tab( curId ) )
1542 int pos = myList.find( prev );
1543 for ( int i = pos - 1; i >= 0 && !wid; i-- )
1545 if ( widgetVisibility( myList.at( i ) ) )
1546 wid = myList.at( i );
1549 for ( int j = pos + 1; j < (int)myList.count() && !wid; j++ )
1551 if ( widgetVisibility( myList.at( j ) ) )
1552 wid = myList.at( j );
1556 curId = widgetId( wid );
1559 myBar->setCurrentTab( curId );
1561 myBar->blockSignals( block );
1565 myBar->setUpdatesEnabled( updBar );
1566 myStack->setUpdatesEnabled( updStk );
1572 QResizeEvent re( myBar->size(), myBar->size() );
1573 QApplication::sendEvent( myBar, &re );
1578 emit deactivated( this );
1583 if ( prev != activeWidget() )
1584 emit activated( activeWidget() );
1588 int QtxWorkstackArea::generateId() const
1592 for ( WidgetInfoMap::ConstIterator it = myInfo.begin(); it != myInfo.end(); ++it )
1593 map.insert( it.data().id, 0 );
1596 while ( map.contains( id ) )
1602 bool QtxWorkstackArea::isBlocked( QWidget* wid ) const
1604 return myBlock.contains( wid );
1607 void QtxWorkstackArea::setBlocked( QWidget* wid, const bool on )
1610 myBlock.insert( wid, 0 );
1612 myBlock.remove( wid );
1615 QtxWorkstackChild* QtxWorkstackArea::child( QWidget* wid ) const
1617 QtxWorkstackChild* res = 0;
1618 if ( myChild.contains( wid ) )
1624 Class: QtxWorkstackChild [Internal]
1628 QtxWorkstackChild::QtxWorkstackChild( QWidget* wid, QWidget* parent )
1632 myWidget->reparent( this, QPoint( 0, 0 ), myWidget->isVisibleTo( myWidget->parentWidget() ) );
1633 myWidget->installEventFilter( this );
1635 connect( myWidget, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
1638 QtxWorkstackChild::~QtxWorkstackChild()
1640 qApp->removeEventFilter( this );
1645 widget()->removeEventFilter( this );
1646 widget()->reparent( 0, QPoint( 0, 0 ), false );
1647 disconnect( widget(), SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
1650 QWidget* QtxWorkstackChild::widget() const
1655 bool QtxWorkstackChild::eventFilter( QObject* o, QEvent* e )
1657 if ( o->isWidgetType() )
1659 if ( e->type() == QEvent::CaptionChange || e->type() == QEvent::IconChange )
1660 emit captionChanged( this );
1662 if ( !e->spontaneous() && ( e->type() == QEvent::Show || e->type() == QEvent::ShowToParent ) )
1665 if ( !e->spontaneous() && ( e->type() == QEvent::Hide || e->type() == QEvent::HideToParent ) )
1668 if ( e->type() == QEvent::FocusIn )
1669 emit activated( this );
1671 return QHBox::eventFilter( o, e );
1674 void QtxWorkstackChild::onDestroyed( QObject* obj )
1676 if ( obj != widget() )
1683 void QtxWorkstackChild::childEvent( QChildEvent* e )
1685 if ( e->type() == QEvent::ChildRemoved && e->child() == widget() )
1690 QHBox::childEvent( e );
1694 Class: QtxWorkstackTabBar [Internal]
1698 QtxWorkstackTabBar::QtxWorkstackTabBar( QWidget* parent )
1699 : QTabBar( parent ),
1704 QtxWorkstackTabBar::~QtxWorkstackTabBar()
1708 void QtxWorkstackTabBar::setActive( const bool on )
1710 QFont aFont = font();
1711 aFont.setUnderline( on );
1717 QRect QtxWorkstackTabBar::tabRect( const int idx ) const
1720 QTab* t = tabAt( idx );
1724 r.setLeft( QMAX( r.left(), 0 ) );
1726 int x1 = tabAt( 0 )->rect().left();
1727 int x2 = tabAt( count() - 1 )->rect().right();
1730 if ( QABS( x2 - x1 ) > width() )
1731 #if defined QT_VERSION && QT_VERSION >= 0x30300
1732 bw = 2 * style().pixelMetric( QStyle::PM_TabBarScrollButtonWidth, this );
1737 int limit = width() - bw;
1738 r.setRight( QMIN( r.right(), limit ) );
1740 r = QRect( mapToGlobal( r.topLeft() ), r.size() );
1745 void QtxWorkstackTabBar::mouseMoveEvent( QMouseEvent* e )
1747 if ( myId != -1 && !tab( myId )->rect().contains( e->pos() ) )
1750 emit dragActiveTab();
1753 QTabBar::mouseMoveEvent( e );
1756 void QtxWorkstackTabBar::mousePressEvent( QMouseEvent* e )
1758 QTabBar::mousePressEvent( e );
1760 if ( e->button() == LeftButton )
1761 myId = currentTab();
1764 void QtxWorkstackTabBar::mouseReleaseEvent( QMouseEvent* e )
1766 QTabBar::mouseReleaseEvent( e );
1770 if ( e->button() == RightButton )
1771 emit contextMenuRequested( e->globalPos() );
1774 void QtxWorkstackTabBar::contextMenuEvent( QContextMenuEvent* e )
1776 if ( e->reason() != QContextMenuEvent::Mouse )
1777 emit contextMenuRequested( e->globalPos() );
1780 void QtxWorkstackTabBar::paintLabel( QPainter* p, const QRect& br, QTab* t, bool has_focus ) const
1782 if ( currentTab() != t->identifier() )
1784 QFont fnt = p->font();
1785 fnt.setUnderline( false );
1788 QTabBar::paintLabel( p, br, t, has_focus );
1792 Class: QtxWorkstackDrag [Internal]
1796 QtxWorkstackDrag::QtxWorkstackDrag( QtxWorkstack* ws, QtxWorkstackChild* child )
1804 qApp->installEventFilter( this );
1807 QtxWorkstackDrag::~QtxWorkstackDrag()
1809 qApp->removeEventFilter( this );
1814 bool QtxWorkstackDrag::eventFilter( QObject*, QEvent* e )
1816 switch ( e->type() )
1818 case QEvent::MouseMove:
1819 updateTarget( ((QMouseEvent*)e)->globalPos() );
1821 case QEvent::MouseButtonRelease:
1833 void QtxWorkstackDrag::updateTarget( const QPoint& p )
1836 QtxWorkstackArea* area = detectTarget( p, tab );
1837 setTarget( area, tab );
1840 QtxWorkstackArea* QtxWorkstackDrag::detectTarget( const QPoint& p, int& tab ) const
1845 QtxWorkstackArea* area = myWS->areaAt( p );
1847 tab = area->tabAt( p );
1851 void QtxWorkstackDrag::setTarget( QtxWorkstackArea* area, const int tab )
1853 if ( !area || ( myArea == area && tab == myTab ) )
1868 void QtxWorkstackDrag::dropWidget()
1871 myArea->insertWidget( myChild->widget(), myTab );
1874 void QtxWorkstackDrag::drawRect()
1876 if ( !myPainter || !myArea )
1879 QRect r = myArea->floatRect();
1880 int m = myPainter->pen().width();
1882 r.setTop( r.top() + m + 2 );
1883 r.setLeft( r.left() + m + 2 );
1884 r.setRight( r.right() - m - 2 );
1885 r.setBottom( r.bottom() - m - 2 );
1887 myPainter->drawRect( r );
1889 QRect tr = myArea->floatTab( myTab );
1890 tr.setTop( tr.top() + m );
1891 tr.setLeft( tr.left() + m );
1892 tr.setRight( tr.right() - m );
1893 tr.setBottom( tr.bottom() - m );
1895 myPainter->drawRect( tr );
1898 void QtxWorkstackDrag::endDrawRect()
1904 void QtxWorkstackDrag::startDrawRect()
1909 int scr = QApplication::desktop()->screenNumber( (QWidget*)this );
1910 QWidget* paint_on = QApplication::desktop()->screen( scr );
1912 myPainter = new QPainter( paint_on, true );
1913 myPainter->setPen( QPen( gray, 3 ) );
1914 myPainter->setRasterOp( XorROP );