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>
57 const char* imageZoomCursor[] = {
62 "................................",
63 "................................",
64 ".#######........................",
65 "..aaaaaaa.......................",
66 "................................",
67 ".............#####..............",
68 "...........##.aaaa##............",
69 "..........#.aa.....a#...........",
70 ".........#.a.........#..........",
71 ".........#a..........#a.........",
72 "........#.a...........#.........",
73 "........#a............#a........",
74 "........#a............#a........",
75 "........#a............#a........",
76 "........#a............#a........",
77 ".........#...........#.a........",
78 ".........#a..........#a.........",
79 ".........##.........#.a.........",
80 "........#####.....##.a..........",
81 ".......###aaa#####.aa...........",
82 "......###aa...aaaaa.......#.....",
83 ".....###aa................#a....",
84 "....###aa.................#a....",
85 "...###aa...............#######..",
86 "....#aa.................aa#aaaa.",
87 ".....a....................#a....",
88 "..........................#a....",
89 "...........................a....",
90 "................................",
91 "................................",
92 "................................",
93 "................................"};
95 const char* imageRotateCursor[] = {
100 "................................",
101 "................................",
102 "................................",
103 "................................",
104 "........#.......................",
105 ".......#.a......................",
106 "......#######...................",
107 ".......#aaaaa#####..............",
108 "........#..##.a#aa##........##..",
109 ".........a#.aa..#..a#.....##.aa.",
110 ".........#.a.....#...#..##.aa...",
111 ".........#a.......#..###.aa.....",
112 "........#.a.......#a..#aa.......",
113 "........#a.........#..#a........",
114 "........#a.........#a.#a........",
115 "........#a.........#a.#a........",
116 "........#a.........#a.#a........",
117 ".........#.........#a#.a........",
118 "........##a........#a#a.........",
119 "......##.a#.......#.#.a.........",
120 "....##.aa..##.....##.a..........",
121 "..##.aa.....a#####.aa...........",
122 "...aa.........aaa#a.............",
123 "................#.a.............",
124 "...............#.a..............",
125 "..............#.a...............",
126 "...............a................",
127 "................................",
128 "................................",
129 "................................",
130 "................................",
131 "................................"};
138 XStandardColormap scmap;
141 CMapEntry::CMapEntry()
148 CMapEntry::~CMapEntry()
151 XFreeColormap( QPaintDevice::x11AppDisplay(), cmap );
154 static QIntDict<CMapEntry> *cmap_dict = 0;
155 static bool mesa_gl = false;
157 static void cleanup_cmaps()
161 cmap_dict->setAutoDelete(true);
166 static Colormap choose_cmap(Display *dpy, XVisualInfo *vi)
170 cmap_dict = new QIntDict<CMapEntry>;
171 const char *v = glXQueryServerString( dpy, vi->screen, GLX_VERSION );
172 mesa_gl = strstr(v,"Mesa") != 0;
173 qAddPostRoutine( cleanup_cmaps );
176 CMapEntry *x = cmap_dict->find( (long)vi->visualid );
177 if ( x ) // found colormap for visual
182 XStandardColormap *c;
186 MESSAGE( "Choosing cmap for vID = " << vi->visualid );
189 if ( vi->visualid == XVisualIDFromVisual( (Visual*)QPaintDevice::x11AppVisual() ) )
192 MESSAGE( "Using x11AppColormap" );
194 return QPaintDevice::x11AppColormap();
199 Atom hp_cmaps = XInternAtom( dpy, "_HP_RGB_SMOOTH_MAP_LIST", true );
200 if ( hp_cmaps && vi->visual->c_class == TrueColor && vi->depth == 8 )
202 if ( XGetRGBColormaps(dpy, RootWindow(dpy,vi->screen), &c, &n, hp_cmaps) )
205 while ( i < n && x->cmap == 0 )
207 if ( c[i].visualid == vi->visual->visualid )
209 x->cmap = c[i].colormap;
211 // Using HP_RGB scmap
220 #if !defined(_OS_SOLARIS_)
223 if ( XmuLookupStandardColormap(dpy,vi->screen,vi->visualid,vi->depth,
224 XA_RGB_DEFAULT_MAP,false,true) )
226 if ( XGetRGBColormaps(dpy,RootWindow(dpy,vi->screen),&c,&n,
227 XA_RGB_DEFAULT_MAP) )
230 while ( i < n && x->cmap == 0 )
232 if ( c[i].visualid == vi->visualid )
234 x->cmap = c[i].colormap;
236 // Using RGB_DEFAULT scmap
247 // no shared cmap found
248 x->cmap = XCreateColormap( dpy, RootWindow(dpy,vi->screen), vi->visual,
254 cmap_dict->insert( (long)vi->visualid, x ); // associate cmap with visualid
260 int OCCViewer_ViewPort::nCounter = 0;
261 QCursor* OCCViewer_ViewPort::defCursor = NULL;
262 QCursor* OCCViewer_ViewPort::handCursor = NULL;
263 QCursor* OCCViewer_ViewPort::panCursor = NULL;
264 QCursor* OCCViewer_ViewPort::zoomCursor = NULL;
265 QCursor* OCCViewer_ViewPort::rotCursor = NULL;
266 QCursor* OCCViewer_ViewPort::glPanCursor = NULL;
269 Creates the necessary viewport cursors [ static ]
271 void OCCViewer_ViewPort::createCursors ()
273 defCursor = new QCursor ( ArrowCursor );
274 handCursor = new QCursor ( PointingHandCursor );
275 panCursor = new QCursor ( SizeAllCursor );
276 zoomCursor = new QCursor (QPixmap(imageZoomCursor));
277 rotCursor = new QCursor (QPixmap(imageRotateCursor));
278 glPanCursor = new QCursor (CrossCursor);
279 // QAD_ResourceMgr* rmgr = QAD_Desktop::getResourceManager();
280 // zoomCursor = new QCursor ( rmgr->loadPixmap( "QAD", tr("ICON_CURSOR_ZOOM") ));
281 // rotCursor = new QCursor ( rmgr->loadPixmap( "QAD", tr("ICON_CURSOR_ROTATE") ));
285 Destroys the viewport cursors [ static ]
287 void OCCViewer_ViewPort::destroyCursors ()
289 if ( defCursor ) delete defCursor;
291 if ( handCursor ) delete handCursor;
293 if ( panCursor ) delete panCursor;
295 if ( zoomCursor ) delete zoomCursor;
297 if ( rotCursor ) delete rotCursor;
299 if ( glPanCursor ) delete glPanCursor;
304 Sets new default cursor [ static ]
306 void OCCViewer_ViewPort::setDefaultCursor(const QCursor& newCursor)
308 if ( !defCursor ) defCursor = new QCursor;
309 *defCursor = newCursor;
313 Sets new cursor for drawing rectangle in the viewport [ static ]
315 void OCCViewer_ViewPort::setHandCursor(const QCursor& newCursor)
317 if ( !handCursor ) handCursor = new QCursor;
318 *handCursor = newCursor;
322 Sets new cursor for panning [ static ]
324 void OCCViewer_ViewPort::setPanCursor(const QCursor& newCursor)
326 if ( !panCursor ) panCursor = new QCursor;
327 *panCursor = newCursor;
331 Sets new cursor for zooming [ static ]
333 void OCCViewer_ViewPort::setZoomCursor(const QCursor& newCursor)
335 if ( !zoomCursor ) zoomCursor = new QCursor;
336 *zoomCursor = newCursor;
340 Sets new cursor for rotating [ static ]
342 void OCCViewer_ViewPort::setRotCursor(const QCursor& newCursor)
344 if ( !rotCursor ) rotCursor = new QCursor;
345 *rotCursor = newCursor;
349 Sets new cursor for global panning [ static ]
351 void OCCViewer_ViewPort::setGlPanCursor(const QCursor& newCursor)
353 if ( !glPanCursor ) glPanCursor = new QCursor;
354 *glPanCursor = newCursor;
360 OCCViewer_ViewPort::OCCViewer_ViewPort(QWidget* parent) :
361 QWidget( parent, 0, WRepaintNoErase | WResizeNoErase)
369 OCCViewer_ViewPort::~OCCViewer_ViewPort()
377 void OCCViewer_ViewPort::initialize()
379 /* initialize cursors */
380 if ( nCounter++ == 0 ) createCursors();
384 XVisualInfo* pVisualInfo;
387 /* Initialization with the default VisualID
389 //NRI Visual *v = DefaultVisual(x11Display(), DefaultScreen(x11Display()));
390 //NRI int visualID = XVisualIDFromVisual(v);
392 /* Here we use the settings from
393 Optimizer_ViewInfo::TxglCreateWindow()
395 int visualAttr[] = { GLX_RGBA, GLX_DEPTH_SIZE, 1,
396 GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1,
397 GLX_BLUE_SIZE, 1, GLX_DOUBLEBUFFER,
400 pVisualInfo = ::glXChooseVisual (x11Display(), DefaultScreen(x11Display()), visualAttr);
402 if ( isVisible() ) hide();
404 XSetWindowAttributes a;
406 a.colormap = choose_cmap( x11Display(), pVisualInfo ); /* find best colormap */
407 a.background_pixel = backgroundColor().pixel();
408 a.border_pixel = black.pixel();
409 Window p = RootWindow( x11Display(), DefaultScreen(x11Display()) );
410 if ( parentWidget() ) p = parentWidget()->winId();
412 Window w = XCreateWindow( x11Display(), p, x(), y(), width(), height(),
413 0, pVisualInfo->depth, InputOutput, pVisualInfo->visual,
414 CWBackPixel | CWBorderPixel | CWColormap, &a );
418 if ( XGetWMColormapWindows( x11Display(), topLevelWidget()->winId(), &cmwret, &count ) )
420 cmw = new Window[count+1];
421 memcpy( (char *)cmw, (char *)cmwret, sizeof(Window)*count );
422 XFree( (char *)cmwret );
425 for (i = 0; i < count; i++)
427 if ( cmw[i] == winId() ) /* replace old window */
434 if ( i >= count ) /* append new window */
440 cmw = new Window[count];
444 /* Creating new window (with good VisualID) for this widget
447 XSetWMColormapWindows( x11Display(), topLevelWidget()->winId(), cmw, count );
450 if ( isVisible() ) show();
453 XFree( (char *)pVisualInfo );
456 XFlush(x11Display());
457 // XSync(x11Display(), false);
458 // XSynchronize(x11Display(), true);
460 #endif // !defined WNT
462 myOriginalViewport = NULL;
463 myCursorIsHand = false;
464 myCursor = *defCursor;
467 myStartX = myStartY = myCurrX = myCurrY =0;
468 myPaintersRedrawing = false;
469 myEnableDrawMode = true;
471 setTransformRequested ( NOTHING );
472 setTransformInProcess ( false );
474 setMouseTracking( true );
475 setBackgroundMode(NoBackground);
481 Cleans up the viewport
483 void OCCViewer_ViewPort::cleanup()
485 if ( --nCounter == 0 )
490 Sets the original view for the viewport
492 void OCCViewer_ViewPort::setOriginalView( OCCViewer_ViewPort* viewport,
493 const QRect& magnify )
495 myOriginalViewport = viewport;
496 myMagnifyRect = magnify;
500 Returns the original view or null
502 OCCViewer_ViewPort* OCCViewer_ViewPort::getOriginalView() const
504 return myOriginalViewport;
508 Returns the 'magnify' rect ( used for 'magnify' operation )
510 const QRect& OCCViewer_ViewPort::getMagnifyRect() const
512 return myMagnifyRect;
516 Returns the sketched rect ( used for multiple selection )
518 const QRect& OCCViewer_ViewPort::getSelectionRect() const
524 Returns 'true' if the viewport has a native window
526 bool OCCViewer_ViewPort::hasWindow() const
532 Must be called if native window was changed
534 void OCCViewer_ViewPort::windowChanged()
540 Sets the default cursor active
542 void OCCViewer_ViewPort::setDefaultCursorOn()
544 setCursor ( *OCCViewer_ViewPort::defCursor );
548 Sets the 'hand' cursor active
550 void OCCViewer_ViewPort::setHandCursorOn()
552 setCursor ( *OCCViewer_ViewPort::handCursor );
556 Sets the panning cursor active
558 void OCCViewer_ViewPort::setPanCursorOn()
560 setCursor( *OCCViewer_ViewPort::panCursor );
564 Sets the zooming cursor active
566 void OCCViewer_ViewPort::setZoomCursorOn()
568 setCursor( *OCCViewer_ViewPort::zoomCursor );
572 Sets the rotating cursor active
574 void OCCViewer_ViewPort::setRotCursorOn()
576 setCursor( *OCCViewer_ViewPort::rotCursor );
580 Sets the global panning cursor active
582 void OCCViewer_ViewPort::setGlPanCursorOn()
584 setCursor( *OCCViewer_ViewPort::glPanCursor );
588 Returns the default background color
590 QColor OCCViewer_ViewPort::backgroundColor() const
596 Activates 'zoom' transformation
598 void OCCViewer_ViewPort::activateZoom()
600 if ( !transformRequested() && !myCursorIsHand )
601 myCursor = cursor(); /* save old cursor */
603 if ( myOperation != ZOOMVIEW ) {
604 setTransformRequested ( ZOOMVIEW );
605 setCursor( *zoomCursor );
610 Activates 'panning' transformation
612 void OCCViewer_ViewPort::activatePanning()
614 if ( !transformRequested() && !myCursorIsHand )
615 myCursor = cursor(); /* save old cursor */
617 if ( myOperation != PANVIEW ) {
618 setTransformRequested ( PANVIEW );
619 setCursor( *panCursor );
624 Activates 'rotation' transformation
626 void OCCViewer_ViewPort::activateRotation()
628 if ( !transformRequested() && !myCursorIsHand )
629 myCursor = cursor(); /* save old cursor */
631 if ( myOperation != ROTATE ) {
632 setTransformRequested ( ROTATE );
633 setCursor( *rotCursor );
638 Activates 'fit' transformation
640 void OCCViewer_ViewPort::activateWindowFit()
642 if ( !transformRequested() && !myCursorIsHand )
643 myCursor = cursor(); /* save old cursor */
645 if ( myOperation != WINDOWFIT ) {
646 setTransformRequested ( WINDOWFIT );
647 setCursor ( *handCursor );
648 myCursorIsHand = true;
650 // setTransformInProcess( true );
651 // emit vpTransformationStarted ( WINDOWFIT );
655 Activates 'global panning' transformation
657 void OCCViewer_ViewPort::activateGlobalPanning()
659 if ( !transformRequested() && !myCursorIsHand )
660 myCursor = cursor(); /* save old cursor */
662 if ( myOperation != PANGLOBAL )
664 fitAll(); /* fits view before selecting a new scene center */
665 setTransformRequested ( PANGLOBAL );
666 setCursor( *glPanCursor );
668 // setTransformInProcess( true );
669 // emit vpTransformationStarted ( PANGLOBAL );
673 Sets the viewport to its initial state
674 ( no transformations in process etc. )
676 void OCCViewer_ViewPort::resetState()
680 /* make rectangle empty (left > right) */
684 if ( transformRequested() || myCursorIsHand )
685 setCursor( myCursor );
686 myCursorIsHand = false;
688 if ( transformRequested() )
689 emit vpTransformationFinished (myOperation);
691 setTransformInProcess( false );
692 setTransformRequested ( NOTHING );
693 QAD_Application::getDesktop()->putInfo( tr("INF_READY") );
697 Enable/disable user's ability to sketch a rect in the viewport
699 void OCCViewer_ViewPort::enableDrawMode(bool bEnable )
701 myEnableDrawMode = bEnable;
705 Returns 'true' if user can sketch a rect in the viewport
707 bool OCCViewer_ViewPort::enableDrawMode() const
709 return myEnableDrawMode;
713 Sets the active operation 'op'
715 void OCCViewer_ViewPort::setTransformRequested ( OperationType op )
718 setMouseTracking ( myOperation == NOTHING );
724 void OCCViewer_ViewPort::mousePressEvent (QMouseEvent* event)
726 myStartX = event->x();
727 myStartY = event->y();
728 switch ( myOperation )
731 if ( event->button() == Qt::LeftButton )
732 emit vpTransformationStarted ( WINDOWFIT );
736 if ( event->button() == Qt::LeftButton )
737 emit vpTransformationStarted ( PANGLOBAL );
742 if ( event->button() == Qt::LeftButton )
743 emit vpTransformationStarted ( ZOOMVIEW );
747 if ( event->button() == Qt::LeftButton )
748 emit vpTransformationStarted ( PANVIEW );
752 if ( event->button() == Qt::LeftButton )
754 startRotation(myStartX, myStartY);
755 emit vpTransformationStarted ( ROTATE );
761 /* Try to activate a transformation
763 if ( (event->state() == Qt::ControlButton) &&
764 (event->button() == Qt::LeftButton) )
766 /* MB1 + CTRL = Zooming */
769 else if ( (event->state() == Qt::ControlButton) &&
770 (event->button() == Qt::MidButton) )
772 /* MB2 + CTRL = Panning */
775 else if ( (event->state() == Qt::ControlButton) &&
776 (event->button() == Qt::RightButton) )
778 /* MB3 + CTRL = Rotation */
780 startRotation(myStartX, myStartY);
783 /* notify that we start a transformation */
784 if ( transformRequested() )
785 emit vpTransformationStarted ( myOperation );
788 if ( transformRequested() )
789 setTransformInProcess( true );
791 /* NOTE: this signal must be emitted at the end
792 because we must to detect a transformation first
794 emit vpMousePress (event);
800 void OCCViewer_ViewPort::mouseMoveEvent (QMouseEvent* event)
802 myCurrX = event->x();
803 myCurrY = event->y();
807 rotate(myCurrX, myCurrY);
811 zoom(myStartX, myStartY, myCurrX, myCurrY);
817 pan(myCurrX - myStartX, myStartY - myCurrY);
831 if ( event->state() == Qt::LeftButton ||
832 event->state() == ( Qt::LeftButton | Qt::ShiftButton) )
834 myDrawRect = myEnableDrawMode;
837 repaint( visibleRect(), false);
838 if ( !myCursorIsHand )
839 { /* we are going to sketch a rectangle */
840 myCursorIsHand = true;
842 setCursor ( *handCursor );
847 emit vpMouseMove( event );
853 void OCCViewer_ViewPort::mouseReleaseEvent (QMouseEvent* event)
855 if ( !transformRequested() && (event->button() == Qt::RightButton) )
857 QPopupMenu* popup = createPopup();
859 QAD_Tools::checkPopup( popup );
860 if ( popup->count()>0 ) {
861 popup->exec( QCursor::pos() );
868 switch ( myOperation )
883 if ( event->button() == Qt::LeftButton )
885 setCenter( event->x(), event->y() );
891 if ( event->state() == Qt::LeftButton )
893 myCurrX = event->x();
894 myCurrY = event->y();
895 QRect rect = QAD_Tools::makeRect(myStartX, myStartY, myCurrX, myCurrY);
896 if ( !rect.isEmpty() ) fitWindow(rect);
902 // NOTE: viewer 3D detects a rectangle of selection using this event
903 // so we must emit it BEFORE resetting the selection rectangle
904 emit vpMouseRelease (event);
906 if ( event->button() == Qt::LeftButton && myDrawRect )
909 repaint(visibleRect(), false);
917 void OCCViewer_ViewPort::mouseDoubleClickEvent(QMouseEvent *event)
919 emit vpMouseDoubleClick (event);
925 void OCCViewer_ViewPort::keyPressEvent(QKeyEvent *event)
927 emit vpKeyPress (event);
933 void OCCViewer_ViewPort::keyReleaseEvent(QKeyEvent *event)
935 emit vpKeyRelease (event);
939 Called when the viewport gets the focus
941 void OCCViewer_ViewPort::focusInEvent(QFocusEvent *event)
943 emit vpFocusIn (event);
947 Called when the viewport loses the focus
949 void OCCViewer_ViewPort::focusOutEvent(QFocusEvent *event)
951 emit vpFocusOut (event);
957 void OCCViewer_ViewPort::resizeEvent (QResizeEvent* event)
965 void OCCViewer_ViewPort::update(int x, int y, int w, int h)
968 myHasWindow = setWindow();
970 repaint(x, y, w, h, true);
974 Repaints the viewport
976 void OCCViewer_ViewPort::paintEvent (QPaintEvent *ev)
981 QPainter thePainter(this);
982 thePainter.setRasterOp(Qt::XorROP);
983 thePainter.setPen(Qt::white);
984 QRect aRect = QAD_Tools::makeRect(myStartX, myStartY, myCurrX, myCurrY);
985 if ( !myRect.isEmpty() )
986 thePainter.drawRect( myRect );
987 thePainter.drawRect(aRect);
991 if ( myPaintersRedrawing )
993 QPainter thePainter(this);
994 emit vpDrawExternal (&thePainter);
995 myPaintersRedrawing = false;
1000 Forces to redraw the viewport by an external painter
1002 void OCCViewer_ViewPort::redrawPainters()
1004 myPaintersRedrawing = true;