1 // SALOME OCCViewer : build OCC Viewer into Salome desktop
3 // Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org
24 // File : OCCViewer_ViewPort.cxx
25 // Author : Nicolas REJNERI
32 #define QT_CLEAN_NAMESPACE /* avoid definition of INT32 and INT8 */
35 #include "OCCViewer_ViewPort.h"
38 #include "QAD_Tools.h"
39 #include "QAD_Desktop.h"
40 #include "QAD_MessageBox.h"
45 #include <X11/Xutil.h>
46 #include <X11/Xatom.h>
47 #include <X11/Xmu/StdCmap.h>
48 #undef QT_CLEAN_NAMESPACE
49 #include <Xw_Window.hxx>
50 #include <Graphic3d_GraphicDevice.hxx>
55 #include "utilities.h"
60 const char* imageZoomCursor[] = {
65 "................................",
66 "................................",
67 ".#######........................",
68 "..aaaaaaa.......................",
69 "................................",
70 ".............#####..............",
71 "...........##.aaaa##............",
72 "..........#.aa.....a#...........",
73 ".........#.a.........#..........",
74 ".........#a..........#a.........",
75 "........#.a...........#.........",
76 "........#a............#a........",
77 "........#a............#a........",
78 "........#a............#a........",
79 "........#a............#a........",
80 ".........#...........#.a........",
81 ".........#a..........#a.........",
82 ".........##.........#.a.........",
83 "........#####.....##.a..........",
84 ".......###aaa#####.aa...........",
85 "......###aa...aaaaa.......#.....",
86 ".....###aa................#a....",
87 "....###aa.................#a....",
88 "...###aa...............#######..",
89 "....#aa.................aa#aaaa.",
90 ".....a....................#a....",
91 "..........................#a....",
92 "...........................a....",
93 "................................",
94 "................................",
95 "................................",
96 "................................"};
98 const char* imageRotateCursor[] = {
103 "................................",
104 "................................",
105 "................................",
106 "................................",
107 "........#.......................",
108 ".......#.a......................",
109 "......#######...................",
110 ".......#aaaaa#####..............",
111 "........#..##.a#aa##........##..",
112 ".........a#.aa..#..a#.....##.aa.",
113 ".........#.a.....#...#..##.aa...",
114 ".........#a.......#..###.aa.....",
115 "........#.a.......#a..#aa.......",
116 "........#a.........#..#a........",
117 "........#a.........#a.#a........",
118 "........#a.........#a.#a........",
119 "........#a.........#a.#a........",
120 ".........#.........#a#.a........",
121 "........##a........#a#a.........",
122 "......##.a#.......#.#.a.........",
123 "....##.aa..##.....##.a..........",
124 "..##.aa.....a#####.aa...........",
125 "...aa.........aaa#a.............",
126 "................#.a.............",
127 "...............#.a..............",
128 "..............#.a...............",
129 "...............a................",
130 "................................",
131 "................................",
132 "................................",
133 "................................",
134 "................................"};
141 XStandardColormap scmap;
144 CMapEntry::CMapEntry()
151 CMapEntry::~CMapEntry()
154 XFreeColormap( QPaintDevice::x11AppDisplay(), cmap );
157 static QIntDict<CMapEntry> *cmap_dict = 0;
158 static bool mesa_gl = false;
160 static void cleanup_cmaps()
164 cmap_dict->setAutoDelete(true);
169 static Colormap choose_cmap(Display *dpy, XVisualInfo *vi)
173 cmap_dict = new QIntDict<CMapEntry>;
174 const char *v = glXQueryServerString( dpy, vi->screen, GLX_VERSION );
175 mesa_gl = strstr(v,"Mesa") != 0;
176 qAddPostRoutine( cleanup_cmaps );
179 CMapEntry *x = cmap_dict->find( (long)vi->visualid );
180 if ( x ) // found colormap for visual
185 XStandardColormap *c;
189 MESSAGE( "Choosing cmap for vID = " << vi->visualid );
192 if ( vi->visualid == XVisualIDFromVisual( (Visual*)QPaintDevice::x11AppVisual() ) )
195 MESSAGE( "Using x11AppColormap" );
197 return QPaintDevice::x11AppColormap();
202 Atom hp_cmaps = XInternAtom( dpy, "_HP_RGB_SMOOTH_MAP_LIST", true );
203 if ( hp_cmaps && vi->visual->c_class == TrueColor && vi->depth == 8 )
205 if ( XGetRGBColormaps(dpy, RootWindow(dpy,vi->screen), &c, &n, hp_cmaps) )
208 while ( i < n && x->cmap == 0 )
210 if ( c[i].visualid == vi->visual->visualid )
212 x->cmap = c[i].colormap;
214 // Using HP_RGB scmap
223 #if !defined(_OS_SOLARIS_)
226 if ( XmuLookupStandardColormap(dpy,vi->screen,vi->visualid,vi->depth,
227 XA_RGB_DEFAULT_MAP,false,true) )
229 if ( XGetRGBColormaps(dpy,RootWindow(dpy,vi->screen),&c,&n,
230 XA_RGB_DEFAULT_MAP) )
233 while ( i < n && x->cmap == 0 )
235 if ( c[i].visualid == vi->visualid )
237 x->cmap = c[i].colormap;
239 // Using RGB_DEFAULT scmap
250 // no shared cmap found
251 x->cmap = XCreateColormap( dpy, RootWindow(dpy,vi->screen), vi->visual,
257 cmap_dict->insert( (long)vi->visualid, x ); // associate cmap with visualid
263 int OCCViewer_ViewPort::nCounter = 0;
264 QCursor* OCCViewer_ViewPort::defCursor = NULL;
265 QCursor* OCCViewer_ViewPort::handCursor = NULL;
266 QCursor* OCCViewer_ViewPort::panCursor = NULL;
267 QCursor* OCCViewer_ViewPort::zoomCursor = NULL;
268 QCursor* OCCViewer_ViewPort::rotCursor = NULL;
269 QCursor* OCCViewer_ViewPort::glPanCursor = NULL;
272 Creates the necessary viewport cursors [ static ]
274 void OCCViewer_ViewPort::createCursors ()
276 defCursor = new QCursor ( ArrowCursor );
277 handCursor = new QCursor ( PointingHandCursor );
278 panCursor = new QCursor ( SizeAllCursor );
279 zoomCursor = new QCursor (QPixmap(imageZoomCursor));
280 rotCursor = new QCursor (QPixmap(imageRotateCursor));
281 glPanCursor = new QCursor (CrossCursor);
282 // QAD_ResourceMgr* rmgr = QAD_Desktop::getResourceManager();
283 // zoomCursor = new QCursor ( rmgr->loadPixmap( "QAD", tr("ICON_CURSOR_ZOOM") ));
284 // rotCursor = new QCursor ( rmgr->loadPixmap( "QAD", tr("ICON_CURSOR_ROTATE") ));
288 Destroys the viewport cursors [ static ]
290 void OCCViewer_ViewPort::destroyCursors ()
292 if ( defCursor ) delete defCursor;
294 if ( handCursor ) delete handCursor;
296 if ( panCursor ) delete panCursor;
298 if ( zoomCursor ) delete zoomCursor;
300 if ( rotCursor ) delete rotCursor;
302 if ( glPanCursor ) delete glPanCursor;
307 Sets new default cursor [ static ]
309 void OCCViewer_ViewPort::setDefaultCursor(const QCursor& newCursor)
311 if ( !defCursor ) defCursor = new QCursor;
312 *defCursor = newCursor;
316 Sets new cursor for drawing rectangle in the viewport [ static ]
318 void OCCViewer_ViewPort::setHandCursor(const QCursor& newCursor)
320 if ( !handCursor ) handCursor = new QCursor;
321 *handCursor = newCursor;
325 Sets new cursor for panning [ static ]
327 void OCCViewer_ViewPort::setPanCursor(const QCursor& newCursor)
329 if ( !panCursor ) panCursor = new QCursor;
330 *panCursor = newCursor;
334 Sets new cursor for zooming [ static ]
336 void OCCViewer_ViewPort::setZoomCursor(const QCursor& newCursor)
338 if ( !zoomCursor ) zoomCursor = new QCursor;
339 *zoomCursor = newCursor;
343 Sets new cursor for rotating [ static ]
345 void OCCViewer_ViewPort::setRotCursor(const QCursor& newCursor)
347 if ( !rotCursor ) rotCursor = new QCursor;
348 *rotCursor = newCursor;
352 Sets new cursor for global panning [ static ]
354 void OCCViewer_ViewPort::setGlPanCursor(const QCursor& newCursor)
356 if ( !glPanCursor ) glPanCursor = new QCursor;
357 *glPanCursor = newCursor;
363 OCCViewer_ViewPort::OCCViewer_ViewPort(QWidget* parent) :
364 QWidget( parent, 0, WRepaintNoErase | WResizeNoErase)
372 OCCViewer_ViewPort::~OCCViewer_ViewPort()
380 void OCCViewer_ViewPort::initialize()
382 /* initialize cursors */
383 if ( nCounter++ == 0 ) createCursors();
387 XVisualInfo* pVisualInfo;
390 /* Initialization with the default VisualID
392 //NRI Visual *v = DefaultVisual(x11Display(), DefaultScreen(x11Display()));
393 //NRI int visualID = XVisualIDFromVisual(v);
395 /* Here we use the settings from
396 Optimizer_ViewInfo::TxglCreateWindow()
398 int visualAttr[] = { GLX_RGBA, GLX_DEPTH_SIZE, 1,
399 GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1,
400 GLX_BLUE_SIZE, 1, GLX_DOUBLEBUFFER,
403 pVisualInfo = ::glXChooseVisual (x11Display(), DefaultScreen(x11Display()), visualAttr);
405 if ( isVisible() ) hide();
407 XSetWindowAttributes a;
409 a.colormap = choose_cmap( x11Display(), pVisualInfo ); /* find best colormap */
410 a.background_pixel = backgroundColor().pixel();
411 a.border_pixel = black.pixel();
412 Window p = RootWindow( x11Display(), DefaultScreen(x11Display()) );
413 if ( parentWidget() ) p = parentWidget()->winId();
415 Window w = XCreateWindow( x11Display(), p, x(), y(), width(), height(),
416 0, pVisualInfo->depth, InputOutput, pVisualInfo->visual,
417 CWBackPixel | CWBorderPixel | CWColormap, &a );
421 if ( XGetWMColormapWindows( x11Display(), topLevelWidget()->winId(), &cmwret, &count ) )
423 cmw = new Window[count+1];
424 memcpy( (char *)cmw, (char *)cmwret, sizeof(Window)*count );
425 XFree( (char *)cmwret );
428 for (i = 0; i < count; i++)
430 if ( cmw[i] == winId() ) /* replace old window */
437 if ( i >= count ) /* append new window */
443 cmw = new Window[count];
447 /* Creating new window (with good VisualID) for this widget
450 XSetWMColormapWindows( x11Display(), topLevelWidget()->winId(), cmw, count );
453 if ( isVisible() ) show();
456 XFree( (char *)pVisualInfo );
459 XFlush(x11Display());
460 // XSync(x11Display(), false);
461 // XSynchronize(x11Display(), true);
463 #endif // !defined WNT
465 myOriginalViewport = NULL;
466 myCursorIsHand = false;
467 myCursor = *defCursor;
470 myStartX = myStartY = myCurrX = myCurrY =0;
471 myPaintersRedrawing = false;
472 myEnableDrawMode = true;
474 setTransformRequested ( NOTHING );
475 setTransformInProcess ( false );
477 setMouseTracking( true );
478 setBackgroundMode(NoBackground);
484 Cleans up the viewport
486 void OCCViewer_ViewPort::cleanup()
488 if ( --nCounter == 0 )
493 Sets the original view for the viewport
495 void OCCViewer_ViewPort::setOriginalView( OCCViewer_ViewPort* viewport,
496 const QRect& magnify )
498 myOriginalViewport = viewport;
499 myMagnifyRect = magnify;
503 Returns the original view or null
505 OCCViewer_ViewPort* OCCViewer_ViewPort::getOriginalView() const
507 return myOriginalViewport;
511 Returns the 'magnify' rect ( used for 'magnify' operation )
513 const QRect& OCCViewer_ViewPort::getMagnifyRect() const
515 return myMagnifyRect;
519 Returns the sketched rect ( used for multiple selection )
521 const QRect& OCCViewer_ViewPort::getSelectionRect() const
527 Returns 'true' if the viewport has a native window
529 bool OCCViewer_ViewPort::hasWindow() const
535 Must be called if native window was changed
537 void OCCViewer_ViewPort::windowChanged()
543 Sets the default cursor active
545 void OCCViewer_ViewPort::setDefaultCursorOn()
547 setCursor ( *OCCViewer_ViewPort::defCursor );
551 Sets the 'hand' cursor active
553 void OCCViewer_ViewPort::setHandCursorOn()
555 setCursor ( *OCCViewer_ViewPort::handCursor );
559 Sets the panning cursor active
561 void OCCViewer_ViewPort::setPanCursorOn()
563 setCursor( *OCCViewer_ViewPort::panCursor );
567 Sets the zooming cursor active
569 void OCCViewer_ViewPort::setZoomCursorOn()
571 setCursor( *OCCViewer_ViewPort::zoomCursor );
575 Sets the rotating cursor active
577 void OCCViewer_ViewPort::setRotCursorOn()
579 setCursor( *OCCViewer_ViewPort::rotCursor );
583 Sets the global panning cursor active
585 void OCCViewer_ViewPort::setGlPanCursorOn()
587 setCursor( *OCCViewer_ViewPort::glPanCursor );
591 Returns the default background color
593 QColor OCCViewer_ViewPort::backgroundColor() const
599 Activates 'zoom' transformation
601 void OCCViewer_ViewPort::activateZoom()
603 if ( !transformRequested() && !myCursorIsHand )
604 myCursor = cursor(); /* save old cursor */
606 if ( myOperation != ZOOMVIEW ) {
607 setTransformRequested ( ZOOMVIEW );
608 setCursor( *zoomCursor );
613 Activates 'panning' transformation
615 void OCCViewer_ViewPort::activatePanning()
617 if ( !transformRequested() && !myCursorIsHand )
618 myCursor = cursor(); /* save old cursor */
620 if ( myOperation != PANVIEW ) {
621 setTransformRequested ( PANVIEW );
622 setCursor( *panCursor );
627 Activates 'rotation' transformation
629 void OCCViewer_ViewPort::activateRotation()
631 if ( !transformRequested() && !myCursorIsHand )
632 myCursor = cursor(); /* save old cursor */
634 if ( myOperation != ROTATE ) {
635 setTransformRequested ( ROTATE );
636 setCursor( *rotCursor );
641 Activates 'fit' transformation
643 void OCCViewer_ViewPort::activateWindowFit()
645 if ( !transformRequested() && !myCursorIsHand )
646 myCursor = cursor(); /* save old cursor */
648 if ( myOperation != WINDOWFIT ) {
649 setTransformRequested ( WINDOWFIT );
650 setCursor ( *handCursor );
651 myCursorIsHand = true;
653 // setTransformInProcess( true );
654 // emit vpTransformationStarted ( WINDOWFIT );
658 Activates 'global panning' transformation
660 void OCCViewer_ViewPort::activateGlobalPanning()
662 if ( !transformRequested() && !myCursorIsHand )
663 myCursor = cursor(); /* save old cursor */
665 if ( myOperation != PANGLOBAL )
667 fitAll(); /* fits view before selecting a new scene center */
668 setTransformRequested ( PANGLOBAL );
669 setCursor( *glPanCursor );
671 // setTransformInProcess( true );
672 // emit vpTransformationStarted ( PANGLOBAL );
676 Sets the viewport to its initial state
677 ( no transformations in process etc. )
679 void OCCViewer_ViewPort::resetState()
683 /* make rectangle empty (left > right) */
687 if ( transformRequested() || myCursorIsHand )
688 setCursor( myCursor );
689 myCursorIsHand = false;
691 if ( transformRequested() )
692 emit vpTransformationFinished (myOperation);
694 setTransformInProcess( false );
695 setTransformRequested ( NOTHING );
696 QAD_Application::getDesktop()->putInfo( tr("INF_READY") );
700 Enable/disable user's ability to sketch a rect in the viewport
702 void OCCViewer_ViewPort::enableDrawMode(bool bEnable )
704 myEnableDrawMode = bEnable;
708 Returns 'true' if user can sketch a rect in the viewport
710 bool OCCViewer_ViewPort::enableDrawMode() const
712 return myEnableDrawMode;
716 Sets the active operation 'op'
718 void OCCViewer_ViewPort::setTransformRequested ( OperationType op )
721 setMouseTracking ( myOperation == NOTHING );
727 void OCCViewer_ViewPort::mousePressEvent (QMouseEvent* event)
729 myStartX = event->x();
730 myStartY = event->y();
731 switch ( myOperation )
734 if ( event->button() == Qt::LeftButton )
735 emit vpTransformationStarted ( WINDOWFIT );
739 if ( event->button() == Qt::LeftButton )
740 emit vpTransformationStarted ( PANGLOBAL );
745 if ( event->button() == Qt::LeftButton )
746 emit vpTransformationStarted ( ZOOMVIEW );
750 if ( event->button() == Qt::LeftButton )
751 emit vpTransformationStarted ( PANVIEW );
755 if ( event->button() == Qt::LeftButton )
757 startRotation(myStartX, myStartY);
758 emit vpTransformationStarted ( ROTATE );
764 /* Try to activate a transformation
766 if ( (event->state() == Qt::ControlButton) &&
767 (event->button() == Qt::LeftButton) )
769 /* MB1 + CTRL = Zooming */
772 else if ( (event->state() == Qt::ControlButton) &&
773 (event->button() == Qt::MidButton) )
775 /* MB2 + CTRL = Panning */
778 else if ( (event->state() == Qt::ControlButton) &&
779 (event->button() == Qt::RightButton) )
781 /* MB3 + CTRL = Rotation */
783 startRotation(myStartX, myStartY);
786 /* notify that we start a transformation */
787 if ( transformRequested() )
788 emit vpTransformationStarted ( myOperation );
791 if ( transformRequested() )
792 setTransformInProcess( true );
794 /* NOTE: this signal must be emitted at the end
795 because we must to detect a transformation first
797 emit vpMousePress (event);
803 void OCCViewer_ViewPort::mouseMoveEvent (QMouseEvent* event)
805 myCurrX = event->x();
806 myCurrY = event->y();
810 rotate(myCurrX, myCurrY);
814 zoom(myStartX, myStartY, myCurrX, myCurrY);
820 pan(myCurrX - myStartX, myStartY - myCurrY);
834 if ( event->state() == Qt::LeftButton ||
835 event->state() == ( Qt::LeftButton | Qt::ShiftButton) )
837 myDrawRect = myEnableDrawMode;
840 repaint( visibleRect(), false);
841 if ( !myCursorIsHand )
842 { /* we are going to sketch a rectangle */
843 myCursorIsHand = true;
845 setCursor ( *handCursor );
850 emit vpMouseMove( event );
856 void OCCViewer_ViewPort::mouseReleaseEvent (QMouseEvent* event)
858 if ( !transformRequested() && (event->button() == Qt::RightButton) )
860 QPopupMenu* popup = createPopup();
862 QAD_Tools::checkPopup( popup );
863 if ( popup->count()>0 ) {
864 popup->exec( QCursor::pos() );
871 switch ( myOperation )
886 if ( event->button() == Qt::LeftButton )
888 setCenter( event->x(), event->y() );
894 if ( event->state() == Qt::LeftButton )
896 myCurrX = event->x();
897 myCurrY = event->y();
898 QRect rect = QAD_Tools::makeRect(myStartX, myStartY, myCurrX, myCurrY);
899 if ( !rect.isEmpty() ) fitWindow(rect);
905 // NOTE: viewer 3D detects a rectangle of selection using this event
906 // so we must emit it BEFORE resetting the selection rectangle
907 emit vpMouseRelease (event);
909 if ( event->button() == Qt::LeftButton && myDrawRect )
912 repaint(visibleRect(), false);
920 void OCCViewer_ViewPort::mouseDoubleClickEvent(QMouseEvent *event)
922 emit vpMouseDoubleClick (event);
928 void OCCViewer_ViewPort::keyPressEvent(QKeyEvent *event)
930 emit vpKeyPress (event);
936 void OCCViewer_ViewPort::keyReleaseEvent(QKeyEvent *event)
938 emit vpKeyRelease (event);
942 Called when the viewport gets the focus
944 void OCCViewer_ViewPort::focusInEvent(QFocusEvent *event)
946 emit vpFocusIn (event);
950 Called when the viewport loses the focus
952 void OCCViewer_ViewPort::focusOutEvent(QFocusEvent *event)
954 emit vpFocusOut (event);
960 void OCCViewer_ViewPort::resizeEvent (QResizeEvent* event)
968 void OCCViewer_ViewPort::update(int x, int y, int w, int h)
971 myHasWindow = setWindow();
973 repaint(x, y, w, h, true);
977 Repaints the viewport
979 void OCCViewer_ViewPort::paintEvent (QPaintEvent *ev)
984 QPainter thePainter(this);
985 thePainter.setRasterOp(Qt::XorROP);
986 thePainter.setPen(Qt::white);
987 QRect aRect = QAD_Tools::makeRect(myStartX, myStartY, myCurrX, myCurrY);
988 if ( !myRect.isEmpty() )
989 thePainter.drawRect( myRect );
990 thePainter.drawRect(aRect);
994 if ( myPaintersRedrawing )
996 QPainter thePainter(this);
997 emit vpDrawExternal (&thePainter);
998 myPaintersRedrawing = false;
1003 Forces to redraw the viewport by an external painter
1005 void OCCViewer_ViewPort::redrawPainters()
1007 myPaintersRedrawing = true;