2 // File : OCCViewer_ViewPort.cxx
3 // Created : Wed Mar 20 10:44:24 2002
4 // Author : Nicolas REJNERI
7 // Copyright : Open CASCADE 2002
14 #define QT_CLEAN_NAMESPACE /* avoid definition of INT32 and INT8 */
17 #include "OCCViewer_ViewPort.h"
20 #include "QAD_Tools.h"
21 #include "QAD_Desktop.h"
22 #include "QAD_MessageBox.h"
27 #include <X11/Xutil.h>
28 #include <X11/Xatom.h>
29 #include <X11/Xmu/StdCmap.h>
30 #undef QT_CLEAN_NAMESPACE
31 #include <Xw_Window.hxx>
32 #include <Graphic3d_GraphicDevice.hxx>
38 const char* imageZoomCursor[] = {
43 "................................",
44 "................................",
45 ".#######........................",
46 "..aaaaaaa.......................",
47 "................................",
48 ".............#####..............",
49 "...........##.aaaa##............",
50 "..........#.aa.....a#...........",
51 ".........#.a.........#..........",
52 ".........#a..........#a.........",
53 "........#.a...........#.........",
54 "........#a............#a........",
55 "........#a............#a........",
56 "........#a............#a........",
57 "........#a............#a........",
58 ".........#...........#.a........",
59 ".........#a..........#a.........",
60 ".........##.........#.a.........",
61 "........#####.....##.a..........",
62 ".......###aaa#####.aa...........",
63 "......###aa...aaaaa.......#.....",
64 ".....###aa................#a....",
65 "....###aa.................#a....",
66 "...###aa...............#######..",
67 "....#aa.................aa#aaaa.",
68 ".....a....................#a....",
69 "..........................#a....",
70 "...........................a....",
71 "................................",
72 "................................",
73 "................................",
74 "................................"};
76 const char* imageRotateCursor[] = {
81 "................................",
82 "................................",
83 "................................",
84 "................................",
85 "........#.......................",
86 ".......#.a......................",
87 "......#######...................",
88 ".......#aaaaa#####..............",
89 "........#..##.a#aa##........##..",
90 ".........a#.aa..#..a#.....##.aa.",
91 ".........#.a.....#...#..##.aa...",
92 ".........#a.......#..###.aa.....",
93 "........#.a.......#a..#aa.......",
94 "........#a.........#..#a........",
95 "........#a.........#a.#a........",
96 "........#a.........#a.#a........",
97 "........#a.........#a.#a........",
98 ".........#.........#a#.a........",
99 "........##a........#a#a.........",
100 "......##.a#.......#.#.a.........",
101 "....##.aa..##.....##.a..........",
102 "..##.aa.....a#####.aa...........",
103 "...aa.........aaa#a.............",
104 "................#.a.............",
105 "...............#.a..............",
106 "..............#.a...............",
107 "...............a................",
108 "................................",
109 "................................",
110 "................................",
111 "................................",
112 "................................"};
119 XStandardColormap scmap;
122 CMapEntry::CMapEntry()
129 CMapEntry::~CMapEntry()
132 XFreeColormap( QPaintDevice::x11AppDisplay(), cmap );
135 static QIntDict<CMapEntry> *cmap_dict = 0;
136 static bool mesa_gl = false;
138 static void cleanup_cmaps()
142 cmap_dict->setAutoDelete(true);
147 static Colormap choose_cmap(Display *dpy, XVisualInfo *vi)
151 cmap_dict = new QIntDict<CMapEntry>;
152 const char *v = glXQueryServerString( dpy, vi->screen, GLX_VERSION );
153 mesa_gl = strstr(v,"Mesa") != 0;
154 qAddPostRoutine( cleanup_cmaps );
157 CMapEntry *x = cmap_dict->find( (long)vi->visualid );
158 if ( x ) // found colormap for visual
163 XStandardColormap *c;
167 MESSAGE( "Choosing cmap for vID = " << vi->visualid );
170 if ( vi->visualid == XVisualIDFromVisual( (Visual*)QPaintDevice::x11AppVisual() ) )
173 MESSAGE( "Using x11AppColormap" );
175 return QPaintDevice::x11AppColormap();
180 Atom hp_cmaps = XInternAtom( dpy, "_HP_RGB_SMOOTH_MAP_LIST", true );
181 if ( hp_cmaps && vi->visual->c_class == TrueColor && vi->depth == 8 )
183 if ( XGetRGBColormaps(dpy, RootWindow(dpy,vi->screen), &c, &n, hp_cmaps) )
186 while ( i < n && x->cmap == 0 )
188 if ( c[i].visualid == vi->visual->visualid )
190 x->cmap = c[i].colormap;
192 // Using HP_RGB scmap
201 #if !defined(_OS_SOLARIS_)
204 if ( XmuLookupStandardColormap(dpy,vi->screen,vi->visualid,vi->depth,
205 XA_RGB_DEFAULT_MAP,false,true) )
207 if ( XGetRGBColormaps(dpy,RootWindow(dpy,vi->screen),&c,&n,
208 XA_RGB_DEFAULT_MAP) )
211 while ( i < n && x->cmap == 0 )
213 if ( c[i].visualid == vi->visualid )
215 x->cmap = c[i].colormap;
217 // Using RGB_DEFAULT scmap
228 // no shared cmap found
229 x->cmap = XCreateColormap( dpy, RootWindow(dpy,vi->screen), vi->visual,
235 cmap_dict->insert( (long)vi->visualid, x ); // associate cmap with visualid
241 int OCCViewer_ViewPort::nCounter = 0;
242 QCursor* OCCViewer_ViewPort::defCursor = NULL;
243 QCursor* OCCViewer_ViewPort::handCursor = NULL;
244 QCursor* OCCViewer_ViewPort::panCursor = NULL;
245 QCursor* OCCViewer_ViewPort::zoomCursor = NULL;
246 QCursor* OCCViewer_ViewPort::rotCursor = NULL;
247 QCursor* OCCViewer_ViewPort::glPanCursor = NULL;
250 Creates the necessary viewport cursors [ static ]
252 void OCCViewer_ViewPort::createCursors ()
254 defCursor = new QCursor ( ArrowCursor );
255 handCursor = new QCursor ( PointingHandCursor );
256 panCursor = new QCursor ( SizeAllCursor );
257 zoomCursor = new QCursor (QPixmap(imageZoomCursor));
258 rotCursor = new QCursor (QPixmap(imageRotateCursor));
259 glPanCursor = new QCursor (CrossCursor);
260 // QAD_ResourceMgr* rmgr = QAD_Desktop::getResourceManager();
261 // zoomCursor = new QCursor ( rmgr->loadPixmap( "QAD", tr("ICON_CURSOR_ZOOM") ));
262 // rotCursor = new QCursor ( rmgr->loadPixmap( "QAD", tr("ICON_CURSOR_ROTATE") ));
266 Destroys the viewport cursors [ static ]
268 void OCCViewer_ViewPort::destroyCursors ()
270 if ( defCursor ) delete defCursor;
272 if ( handCursor ) delete handCursor;
274 if ( panCursor ) delete panCursor;
276 if ( zoomCursor ) delete zoomCursor;
278 if ( rotCursor ) delete rotCursor;
280 if ( glPanCursor ) delete glPanCursor;
285 Sets new default cursor [ static ]
287 void OCCViewer_ViewPort::setDefaultCursor(const QCursor& newCursor)
289 if ( !defCursor ) defCursor = new QCursor;
290 *defCursor = newCursor;
294 Sets new cursor for drawing rectangle in the viewport [ static ]
296 void OCCViewer_ViewPort::setHandCursor(const QCursor& newCursor)
298 if ( !handCursor ) handCursor = new QCursor;
299 *handCursor = newCursor;
303 Sets new cursor for panning [ static ]
305 void OCCViewer_ViewPort::setPanCursor(const QCursor& newCursor)
307 if ( !panCursor ) panCursor = new QCursor;
308 *panCursor = newCursor;
312 Sets new cursor for zooming [ static ]
314 void OCCViewer_ViewPort::setZoomCursor(const QCursor& newCursor)
316 if ( !zoomCursor ) zoomCursor = new QCursor;
317 *zoomCursor = newCursor;
321 Sets new cursor for rotating [ static ]
323 void OCCViewer_ViewPort::setRotCursor(const QCursor& newCursor)
325 if ( !rotCursor ) rotCursor = new QCursor;
326 *rotCursor = newCursor;
330 Sets new cursor for global panning [ static ]
332 void OCCViewer_ViewPort::setGlPanCursor(const QCursor& newCursor)
334 if ( !glPanCursor ) glPanCursor = new QCursor;
335 *glPanCursor = newCursor;
341 OCCViewer_ViewPort::OCCViewer_ViewPort(QWidget* parent) :
342 QWidget( parent, 0, WRepaintNoErase | WResizeNoErase)
350 OCCViewer_ViewPort::~OCCViewer_ViewPort()
358 void OCCViewer_ViewPort::initialize()
360 /* initialize cursors */
361 if ( nCounter++ == 0 ) createCursors();
365 XVisualInfo* pVisualInfo;
368 /* Initialization with the default VisualID
370 //NRI Visual *v = DefaultVisual(x11Display(), DefaultScreen(x11Display()));
371 //NRI int visualID = XVisualIDFromVisual(v);
373 /* Here we use the settings from
374 Optimizer_ViewInfo::TxglCreateWindow()
376 int visualAttr[] = { GLX_RGBA, GLX_DEPTH_SIZE, 1,
377 GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1,
378 GLX_BLUE_SIZE, 1, GLX_DOUBLEBUFFER,
381 pVisualInfo = ::glXChooseVisual (x11Display(), DefaultScreen(x11Display()), visualAttr);
383 if ( isVisible() ) hide();
385 XSetWindowAttributes a;
387 a.colormap = choose_cmap( x11Display(), pVisualInfo ); /* find best colormap */
388 a.background_pixel = backgroundColor().pixel();
389 a.border_pixel = black.pixel();
390 Window p = RootWindow( x11Display(), DefaultScreen(x11Display()) );
391 if ( parentWidget() ) p = parentWidget()->winId();
393 Window w = XCreateWindow( x11Display(), p, x(), y(), width(), height(),
394 0, pVisualInfo->depth, InputOutput, pVisualInfo->visual,
395 CWBackPixel | CWBorderPixel | CWColormap, &a );
399 if ( XGetWMColormapWindows( x11Display(), topLevelWidget()->winId(), &cmwret, &count ) )
401 cmw = new Window[count+1];
402 memcpy( (char *)cmw, (char *)cmwret, sizeof(Window)*count );
403 XFree( (char *)cmwret );
406 for (i = 0; i < count; i++)
408 if ( cmw[i] == winId() ) /* replace old window */
415 if ( i >= count ) /* append new window */
421 cmw = new Window[count];
425 /* Creating new window (with good VisualID) for this widget
428 XSetWMColormapWindows( x11Display(), topLevelWidget()->winId(), cmw, count );
431 if ( isVisible() ) show();
434 XFree( (char *)pVisualInfo );
437 XFlush(x11Display());
438 // XSync(x11Display(), false);
439 // XSynchronize(x11Display(), true);
441 #endif // !defined WNT
443 myOriginalViewport = NULL;
444 myCursorIsHand = false;
445 myCursor = *defCursor;
448 myStartX = myStartY = myCurrX = myCurrY =0;
449 myPaintersRedrawing = false;
450 myEnableDrawMode = true;
452 setTransformRequested ( NOTHING );
453 setTransformInProcess ( false );
455 setMouseTracking( true );
456 setBackgroundMode(NoBackground);
462 Cleans up the viewport
464 void OCCViewer_ViewPort::cleanup()
466 if ( --nCounter == 0 )
471 Sets the original view for the viewport
473 void OCCViewer_ViewPort::setOriginalView( OCCViewer_ViewPort* viewport,
474 const QRect& magnify )
476 myOriginalViewport = viewport;
477 myMagnifyRect = magnify;
481 Returns the original view or null
483 OCCViewer_ViewPort* OCCViewer_ViewPort::getOriginalView() const
485 return myOriginalViewport;
489 Returns the 'magnify' rect ( used for 'magnify' operation )
491 const QRect& OCCViewer_ViewPort::getMagnifyRect() const
493 return myMagnifyRect;
497 Returns the sketched rect ( used for multiple selection )
499 const QRect& OCCViewer_ViewPort::getSelectionRect() const
505 Returns 'true' if the viewport has a native window
507 bool OCCViewer_ViewPort::hasWindow() const
513 Must be called if native window was changed
515 void OCCViewer_ViewPort::windowChanged()
521 Sets the default cursor active
523 void OCCViewer_ViewPort::setDefaultCursorOn()
525 setCursor ( *OCCViewer_ViewPort::defCursor );
529 Sets the 'hand' cursor active
531 void OCCViewer_ViewPort::setHandCursorOn()
533 setCursor ( *OCCViewer_ViewPort::handCursor );
537 Sets the panning cursor active
539 void OCCViewer_ViewPort::setPanCursorOn()
541 setCursor( *OCCViewer_ViewPort::panCursor );
545 Sets the zooming cursor active
547 void OCCViewer_ViewPort::setZoomCursorOn()
549 setCursor( *OCCViewer_ViewPort::zoomCursor );
553 Sets the rotating cursor active
555 void OCCViewer_ViewPort::setRotCursorOn()
557 setCursor( *OCCViewer_ViewPort::rotCursor );
561 Sets the global panning cursor active
563 void OCCViewer_ViewPort::setGlPanCursorOn()
565 setCursor( *OCCViewer_ViewPort::glPanCursor );
569 Returns the default background color
571 QColor OCCViewer_ViewPort::backgroundColor() const
577 Activates 'zoom' transformation
579 void OCCViewer_ViewPort::activateZoom()
581 if ( !transformRequested() && !myCursorIsHand )
582 myCursor = cursor(); /* save old cursor */
584 if ( myOperation != ZOOMVIEW ) {
585 setTransformRequested ( ZOOMVIEW );
586 setCursor( *zoomCursor );
591 Activates 'panning' transformation
593 void OCCViewer_ViewPort::activatePanning()
595 if ( !transformRequested() && !myCursorIsHand )
596 myCursor = cursor(); /* save old cursor */
598 if ( myOperation != PANVIEW ) {
599 setTransformRequested ( PANVIEW );
600 setCursor( *panCursor );
605 Activates 'rotation' transformation
607 void OCCViewer_ViewPort::activateRotation()
609 if ( !transformRequested() && !myCursorIsHand )
610 myCursor = cursor(); /* save old cursor */
612 if ( myOperation != ROTATE ) {
613 setTransformRequested ( ROTATE );
614 setCursor( *rotCursor );
619 Activates 'fit' transformation
621 void OCCViewer_ViewPort::activateWindowFit()
623 if ( !transformRequested() && !myCursorIsHand )
624 myCursor = cursor(); /* save old cursor */
626 if ( myOperation != WINDOWFIT ) {
627 setTransformRequested ( WINDOWFIT );
628 setCursor ( *handCursor );
629 myCursorIsHand = true;
631 // setTransformInProcess( true );
632 // emit vpTransformationStarted ( WINDOWFIT );
636 Activates 'global panning' transformation
638 void OCCViewer_ViewPort::activateGlobalPanning()
640 if ( !transformRequested() && !myCursorIsHand )
641 myCursor = cursor(); /* save old cursor */
643 if ( myOperation != PANGLOBAL )
645 fitAll(); /* fits view before selecting a new scene center */
646 setTransformRequested ( PANGLOBAL );
647 setCursor( *glPanCursor );
649 // setTransformInProcess( true );
650 // emit vpTransformationStarted ( PANGLOBAL );
654 Sets the viewport to its initial state
655 ( no transformations in process etc. )
657 void OCCViewer_ViewPort::resetState()
661 /* make rectangle empty (left > right) */
665 if ( transformRequested() || myCursorIsHand )
666 setCursor( myCursor );
667 myCursorIsHand = false;
669 if ( transformRequested() )
670 emit vpTransformationFinished (myOperation);
672 setTransformInProcess( false );
673 setTransformRequested ( NOTHING );
674 QAD_Application::getDesktop()->putInfo( tr("INF_READY") );
678 Enable/disable user's ability to sketch a rect in the viewport
680 void OCCViewer_ViewPort::enableDrawMode(bool bEnable )
682 myEnableDrawMode = bEnable;
686 Returns 'true' if user can sketch a rect in the viewport
688 bool OCCViewer_ViewPort::enableDrawMode() const
690 return myEnableDrawMode;
694 Sets the active operation 'op'
696 void OCCViewer_ViewPort::setTransformRequested ( OperationType op )
699 setMouseTracking ( myOperation == NOTHING );
705 void OCCViewer_ViewPort::mousePressEvent (QMouseEvent* event)
707 myStartX = event->x();
708 myStartY = event->y();
709 switch ( myOperation )
712 if ( event->button() == Qt::LeftButton )
713 emit vpTransformationStarted ( WINDOWFIT );
717 if ( event->button() == Qt::LeftButton )
718 emit vpTransformationStarted ( PANGLOBAL );
723 if ( event->button() == Qt::LeftButton )
724 emit vpTransformationStarted ( ZOOMVIEW );
728 if ( event->button() == Qt::LeftButton )
729 emit vpTransformationStarted ( PANVIEW );
733 if ( event->button() == Qt::LeftButton )
735 startRotation(myStartX, myStartY);
736 emit vpTransformationStarted ( ROTATE );
742 /* Try to activate a transformation
744 if ( (event->state() == Qt::ControlButton) &&
745 (event->button() == Qt::LeftButton) )
747 /* MB1 + CTRL = Zooming */
750 else if ( (event->state() == Qt::ControlButton) &&
751 (event->button() == Qt::MidButton) )
753 /* MB2 + CTRL = Panning */
756 else if ( (event->state() == Qt::ControlButton) &&
757 (event->button() == Qt::RightButton) )
759 /* MB3 + CTRL = Rotation */
761 startRotation(myStartX, myStartY);
764 /* notify that we start a transformation */
765 if ( transformRequested() )
766 emit vpTransformationStarted ( myOperation );
769 if ( transformRequested() )
770 setTransformInProcess( true );
772 /* NOTE: this signal must be emitted at the end
773 because we must to detect a transformation first
775 emit vpMousePress (event);
781 void OCCViewer_ViewPort::mouseMoveEvent (QMouseEvent* event)
783 myCurrX = event->x();
784 myCurrY = event->y();
788 rotate(myCurrX, myCurrY);
792 zoom(myStartX, myStartY, myCurrX, myCurrY);
798 pan(myCurrX - myStartX, myStartY - myCurrY);
812 if ( event->state() == Qt::LeftButton ||
813 event->state() == ( Qt::LeftButton | Qt::ShiftButton) )
815 myDrawRect = myEnableDrawMode;
818 repaint( visibleRect(), false);
819 if ( !myCursorIsHand )
820 { /* we are going to sketch a rectangle */
821 myCursorIsHand = true;
823 setCursor ( *handCursor );
828 emit vpMouseMove( event );
834 void OCCViewer_ViewPort::mouseReleaseEvent (QMouseEvent* event)
836 if ( !transformRequested() && (event->button() == Qt::RightButton) )
838 QPopupMenu* popup = createPopup();
840 QAD_Tools::checkPopup( popup );
841 if ( popup->count()>0 ) {
842 popup->exec( QCursor::pos() );
849 switch ( myOperation )
864 if ( event->button() == Qt::LeftButton )
866 setCenter( event->x(), event->y() );
872 if ( event->state() == Qt::LeftButton )
874 myCurrX = event->x();
875 myCurrY = event->y();
876 QRect rect = QAD_Tools::makeRect(myStartX, myStartY, myCurrX, myCurrY);
877 if ( !rect.isEmpty() ) fitWindow(rect);
883 // NOTE: viewer 3D detects a rectangle of selection using this event
884 // so we must emit it BEFORE resetting the selection rectangle
885 emit vpMouseRelease (event);
887 if ( event->button() == Qt::LeftButton && myDrawRect )
890 repaint(visibleRect(), false);
898 void OCCViewer_ViewPort::mouseDoubleClickEvent(QMouseEvent *event)
900 emit vpMouseDoubleClick (event);
906 void OCCViewer_ViewPort::keyPressEvent(QKeyEvent *event)
908 emit vpKeyPress (event);
914 void OCCViewer_ViewPort::keyReleaseEvent(QKeyEvent *event)
916 emit vpKeyRelease (event);
920 Called when the viewport gets the focus
922 void OCCViewer_ViewPort::focusInEvent(QFocusEvent *event)
924 emit vpFocusIn (event);
928 Called when the viewport loses the focus
930 void OCCViewer_ViewPort::focusOutEvent(QFocusEvent *event)
932 emit vpFocusOut (event);
938 void OCCViewer_ViewPort::resizeEvent (QResizeEvent* event)
946 void OCCViewer_ViewPort::update(int x, int y, int w, int h)
949 myHasWindow = setWindow();
951 repaint(x, y, w, h, true);
955 Repaints the viewport
957 void OCCViewer_ViewPort::paintEvent (QPaintEvent *ev)
962 QPainter thePainter(this);
963 thePainter.setRasterOp(Qt::XorROP);
964 thePainter.setPen(Qt::white);
965 QRect aRect = QAD_Tools::makeRect(myStartX, myStartY, myCurrX, myCurrY);
966 if ( !myRect.isEmpty() )
967 thePainter.drawRect( myRect );
968 thePainter.drawRect(aRect);
972 if ( myPaintersRedrawing )
974 QPainter thePainter(this);
975 emit vpDrawExternal (&thePainter);
976 myPaintersRedrawing = false;
981 Forces to redraw the viewport by an external painter
983 void OCCViewer_ViewPort::redrawPainters()
985 myPaintersRedrawing = true;