3 * Copyright 2004 Sandia Corporation.
5 * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
7 * license for use of this work by or on behalf of the
9 * U.S. Government. Redistribution and use in source and binary forms, with
11 * or without modification, are permitted provided that this Notice and any
13 * statement of authorship are reproduced on all copies.
19 /*========================================================================
21 For general information about using VTK and Qt, see:
23 http://www.trolltech.com/products/3rdparty/vtksupport.html
25 =========================================================================*/
29 /*========================================================================
31 !!! WARNING for those who want to contribute code to this file.
33 !!! If you use a commercial edition of Qt, you can modify this code.
35 !!! If you use an open source version of Qt, you are free to modify
37 !!! and use this code within the guidelines of the GPL license.
39 !!! Unfortunately, you cannot contribute the changes back into this
41 !!! file. Doing so creates a conflict between the GPL and BSD-like VTK
45 =========================================================================*/
51 // Disable warnings that Qt headers give.
53 #pragma warning(disable:4127)
55 #pragma warning(disable:4512)
61 #include "QVTKWidget.h"
67 #include "qapplication.h"
71 #include "qsignalmapper.h"
75 #if QT_VERSION >= 0x040000 && defined(Q_WS_X11)
77 #include "qx11info_x11.h"
85 #include "vtkInteractorStyleTrackballCamera.h"
87 #include "vtkRenderWindow.h"
91 # include "vtkCarbonRenderWindow.h"
95 #include "vtkCommand.h"
97 #include "vtkOStrStreamWrapper.h"
99 #include "vtkObjectFactory.h"
101 #include "vtkCallbackCommand.h"
103 #include "vtkConfigure.h"
105 #include "vtkToolkits.h"
107 #include "vtkUnsignedCharArray.h"
113 // function to get VTK keysyms from ascii characters
115 static const char* ascii_to_key_sym(int);
117 // function to get VTK keysyms from Qt keys
119 static const char* qt_key_to_key_sym(Qt::Key);
123 // function to dirty cache when a render occurs.
125 static void dirty_cache(vtkObject *, unsigned long, void *, void *);
133 #if QT_VERSION < 0x040000
137 QVTKWidget::QVTKWidget(QWidget* parent, const char* name, Qt::WFlags f)
139 #if QT_VERSION < 0x030000
142 QWidget(parent, name, f | 0x10000000) // WWinOwnDC
146 : QWidget(parent, name, f | Qt::WWinOwnDC )
152 cachedImageCleanFlag(false),
154 automaticImageCache(false), maxImageCacheRenderRate(1.0)
160 this->setBackgroundMode( Qt::NoBackground );
164 // default to strong focus
166 this->setFocusPolicy(QWidget::StrongFocus);
170 // default to enable mouse events when a mouse button isn't down
172 // so we can send enter/leave events to VTK
174 this->setMouseTracking(true);
178 // set expanding to take up space for better default layouts
182 QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding )
188 this->mCachedImage = vtkUnsignedCharArray::New();
198 #if QT_VERSION >= 0x040000
202 QVTKWidget::QVTKWidget(QWidget* p, Qt::WFlags f)
204 : QWidget(p, f | Qt::MSWindowsOwnDC), mRenWin(NULL),
206 cachedImageCleanFlag(false),
208 automaticImageCache(false), maxImageCacheRenderRate(1.0)
216 this->setAttribute(Qt::WA_NoBackground);
218 // no double buffering
220 this->setAttribute(Qt::WA_PaintOnScreen);
224 // default to strong focus
226 this->setFocusPolicy(Qt::StrongFocus);
230 // default to enable mouse events when a mouse button isn't down
232 // so we can send enter/leave events to VTK
234 this->setMouseTracking(true);
238 // set expanding to take up space for better default layouts
242 QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding )
248 this->mCachedImage = vtkUnsignedCharArray::New();
252 #if defined(Q_WS_MAC)
254 this->DirtyRegionHandler = 0;
256 this->DirtyRegionHandlerUPP = 0;
274 QVTKWidget::~QVTKWidget()
278 // get rid of the VTK window
280 this->SetRenderWindow(NULL);
284 this->mCachedImage->Delete();
290 /*! get the render window
294 vtkRenderWindow* QVTKWidget::GetRenderWindow()
302 // create a default vtk window
304 vtkRenderWindow* win = vtkRenderWindow::New();
306 this->SetRenderWindow(win);
314 return this->mRenWin;
324 /*! set the render window
326 this will bind a VTK window with the Qt window
328 it'll also replace an existing VTK window
332 void QVTKWidget::SetRenderWindow(vtkRenderWindow* w)
336 // do nothing if we don't have to
338 if (w == this->mRenWin)
348 // unregister previous window
354 //clean up window as one could remap it
356 if (this->mRenWin->GetMapped())
360 this->mRenWin->Finalize();
364 this->mRenWin->SetDisplayId(NULL);
366 this->mRenWin->SetParentId(NULL);
368 this->mRenWin->SetWindowId(NULL);
370 this->mRenWin->UnRegister(NULL);
376 // now set the window
386 // register new window
388 this->mRenWin->Register(NULL);
392 // if it is mapped somewhere else, unmap it
394 if (this->mRenWin->GetMapped())
398 this->mRenWin->Finalize();
406 // give the qt display id to the vtk window
408 #if QT_VERSION < 0x040000
410 this->mRenWin->SetDisplayId( this->x11Display() );
414 this->mRenWin->SetDisplayId(QX11Info::display());
428 // give the qt window id to the vtk window
430 this->mRenWin->SetWindowId( reinterpret_cast<void*>(this->winId()));
434 // mac compatibility issues
436 #if defined(Q_WS_MAC) && (QT_VERSION < 0x040000)
438 this->mRenWin->SetWindowId( NULL );
440 static_cast<vtkCarbonRenderWindow*>(this->mRenWin)->SetRootWindow(
442 reinterpret_cast<WindowPtr>(this->handle()));
450 // tell the vtk window what the size of this window is
452 this->mRenWin->vtkRenderWindow::SetSize(this->width(), this->height());
454 this->mRenWin->vtkRenderWindow::SetPosition(this->x(), this->y());
458 // have VTK start this window and create the necessary graphics resources
464 this->mRenWin->Start();
466 #if defined (Q_WS_MAC) && (QT_VERSION < 0x040000)
476 // if an interactor wasn't provided, we'll make one by default
478 if (!this->mRenWin->GetInteractor())
482 // create a default interactor
484 QVTKInteractor* iren = QVTKInteractor::New();
486 this->mRenWin->SetInteractor(iren);
492 // now set the default style
494 vtkInteractorStyle* s = vtkInteractorStyleTrackballCamera::New();
496 iren->SetInteractorStyle(s);
508 // tell the interactor the size of this window
510 this->mRenWin->GetInteractor()->SetSize(this->width(), this->height());
514 // Add an observer to monitor when the image changes. Should work most
516 // of the time. The application will have to call
518 // markCachedImageAsDirty for any other case.
520 vtkCallbackCommand *cbc = vtkCallbackCommand::New();
522 cbc->SetClientData(this);
524 cbc->SetCallback(dirty_cache);
526 this->mRenWin->AddObserver(vtkCommand::EndEvent, cbc);
534 #if defined(Q_WS_MAC) && QT_VERSION >= 0x040000
536 if (mRenWin && !this->DirtyRegionHandlerUPP)
540 this->DirtyRegionHandlerUPP = NewEventHandlerUPP(QVTKWidget::DirtyRegionProcessor);
542 static EventTypeSpec events[] = { {'cute', 20} };
544 // kEventClassQt, kEventQtRequestWindowChange from qt_mac_p.h
546 // Suggested by Sam Magnuson at Trolltech as best portabile hack
548 // around Apple's missing functionality in HI Toolbox.
550 InstallEventHandler(GetApplicationEventTarget(), this->DirtyRegionHandlerUPP,
552 GetEventTypeCount(events), events,
554 reinterpret_cast<void*>(this), &this->DirtyRegionHandler);
558 else if (!mRenWin && this->DirtyRegionHandlerUPP)
562 RemoveEventHandler(this->DirtyRegionHandler);
564 DisposeEventHandlerUPP(this->DirtyRegionHandlerUPP);
566 this->DirtyRegionHandler = 0;
568 this->DirtyRegionHandlerUPP = 0;
582 /*! get the Qt/VTK interactor
586 QVTKInteractor* QVTKWidget::GetInteractor()
590 return QVTKInteractor
592 ::SafeDownCast(this->GetRenderWindow()->GetInteractor());
598 void QVTKWidget::markCachedImageAsDirty()
602 if (this->cachedImageCleanFlag)
606 this->cachedImageCleanFlag = false;
608 emit cachedImageDirty();
616 void QVTKWidget::saveImageToCache()
620 if (this->cachedImageCleanFlag)
630 this->mRenWin->GetPixelData(0, 0, this->width()-1, this->height()-1, 1,
634 this->cachedImageCleanFlag = true;
636 emit cachedImageClean();
642 void QVTKWidget::setAutomaticImageCacheEnabled(bool flag)
646 this->automaticImageCache = flag;
652 this->mCachedImage->Initialize();
658 bool QVTKWidget::isAutomaticImageCacheEnabled() const
662 return this->automaticImageCache;
668 void QVTKWidget::setMaxRenderRateForImageCache(double rate)
672 this->maxImageCacheRenderRate = rate;
676 double QVTKWidget::maxRenderRateForImageCache() const
680 return this->maxImageCacheRenderRate;
686 vtkUnsignedCharArray* QVTKWidget::cachedImage()
690 // Make sure image is up to date.
692 this->paintEvent(NULL);
694 this->saveImageToCache();
698 return this->mCachedImage;
704 /*! overloaded Qt's event handler to capture additional keys that Qt has
706 default behavior for (for example the Tab and Shift-Tab key)
710 bool QVTKWidget::event(QEvent* e)
714 #if QT_VERSION >= 0x040000
716 if (e->type() == QEvent::ParentAboutToChange)
720 this->markCachedImageAsDirty();
726 // Finalize the window to remove graphics resources associated with
730 if (this->mRenWin->GetMapped())
734 this->mRenWin->Finalize();
742 else if (e->type() == QEvent::ParentChange)
752 // connect to new window
754 this->mRenWin->SetWindowId( reinterpret_cast<void*>(this->winId()));
758 // start up the window to create graphics resources for this window
764 this->mRenWin->Start();
776 if (QObject::event(e))
786 if (e->type() == QEvent::KeyPress)
790 QKeyEvent* ke = static_cast<QKeyEvent*>(e);
792 this->keyPressEvent(ke);
794 return ke->isAccepted();
800 return QWidget::event(e);
808 /*! handle resize event
812 void QVTKWidget::resizeEvent(QResizeEvent* e)
816 QWidget::resizeEvent(e);
830 // give the size to the interactor and vtk window
832 this->mRenWin->vtkRenderWindow::SetSize(this->width(), this->height());
834 if (this->mRenWin->GetInteractor())
838 this->mRenWin->GetInteractor()->SetSize(this->width(), this->height());
842 this->markCachedImageAsDirty();
846 #if defined (Q_WS_MAC) && (QT_VERSION < 0x040000)
856 void QVTKWidget::moveEvent(QMoveEvent* e)
860 QWidget::moveEvent(e);
874 // give the size to the interactor and vtk window
876 this->mRenWin->vtkRenderWindow::SetPosition(this->x(), this->y());
880 #if defined (Q_WS_MAC) && (QT_VERSION < 0x040000)
890 /*! handle paint event
894 void QVTKWidget::paintEvent(QPaintEvent* )
898 vtkRenderWindowInteractor* iren = NULL;
904 iren = this->mRenWin->GetInteractor();
910 if (!iren || !iren->GetEnabled())
922 // if we have a saved image, use it
924 if (this->cachedImageCleanFlag)
928 // put cached image into back buffer if we can
930 this->mRenWin->SetPixelData(0, 0, this->width()-1, this->height()-1,
934 !this->mRenWin->GetDoubleBuffer());
936 // swap buffers, if double buffering
938 this->mRenWin->Frame();
940 // or should we just put it on the front buffer?
952 // In Qt 4.1+ let's support redirected painting
954 #if QT_VERSION >= 0x040100
956 // if redirected, let's grab the image from VTK, and paint it to the device
958 QPaintDevice* device = QPainter::redirected(this);
960 if (device != NULL && device != this)
964 int w = this->width();
966 int h = this->height();
968 QImage img(w, h, QImage::Format_RGB32);
970 vtkUnsignedCharArray* pixels = vtkUnsignedCharArray::New();
972 pixels->SetArray(img.bits(), w*h*4, 1);
974 this->mRenWin->GetRGBACharPixelData(0, 0, w-1, h-1, 1, pixels);
978 img = img.rgbSwapped();
980 img = img.mirrored();
984 QPainter painter(this);
986 painter.drawImage(QPointF(0.0,0.0), img);
998 /*! handle mouse press event
1002 void QVTKWidget::mousePressEvent(QMouseEvent* e)
1008 // Emit a mouse press event for anyone who might be interested
1014 vtkRenderWindowInteractor* iren = NULL;
1020 iren = this->mRenWin->GetInteractor();
1026 if (!iren || !iren->GetEnabled())
1036 // give interactor the event information
1038 #if QT_VERSION < 0x040000
1040 iren->SetEventInformationFlipY(e->x(), e->y(),
1042 (e->state() & Qt::ControlButton) > 0 ? 1 : 0,
1044 (e->state() & Qt::ShiftButton ) > 0 ? 1 : 0, 0,
1046 e->type() == QEvent::MouseButtonDblClick ? 1 : 0);
1050 iren->SetEventInformationFlipY(e->x(), e->y(),
1052 (e->modifiers() & Qt::ControlModifier) > 0 ? 1 : 0,
1054 (e->modifiers() & Qt::ShiftModifier ) > 0 ? 1 : 0,
1058 e->type() == QEvent::MouseButtonDblClick ? 1 : 0);
1064 // invoke appropriate vtk event
1066 switch (e->button())
1070 case Qt::LeftButton:
1072 iren->InvokeEvent(vtkCommand::LeftButtonPressEvent, e);
1080 iren->InvokeEvent(vtkCommand::MiddleButtonPressEvent, e);
1086 case Qt::RightButton:
1088 iren->InvokeEvent(vtkCommand::RightButtonPressEvent, e);
1104 /*! handle mouse move event
1108 void QVTKWidget::mouseMoveEvent(QMouseEvent* e)
1112 vtkRenderWindowInteractor* iren = NULL;
1118 iren = this->mRenWin->GetInteractor();
1124 if (!iren || !iren->GetEnabled())
1134 // give interactor the event information
1136 #if QT_VERSION < 0x040000
1138 iren->SetEventInformationFlipY(e->x(), e->y(),
1140 (e->state() & Qt::ControlButton) > 0 ? 1 : 0,
1142 (e->state() & Qt::ShiftButton ) > 0 ? 1 : 0);
1146 iren->SetEventInformationFlipY(e->x(), e->y(),
1148 (e->modifiers() & Qt::ControlModifier) > 0 ? 1 : 0,
1150 (e->modifiers() & Qt::ShiftModifier ) > 0 ? 1 : 0);
1158 iren->InvokeEvent(vtkCommand::MouseMoveEvent, e);
1166 /*! handle enter event
1170 void QVTKWidget::enterEvent(QEvent* e)
1174 vtkRenderWindowInteractor* iren = NULL;
1180 iren = this->mRenWin->GetInteractor();
1186 if (!iren || !iren->GetEnabled())
1196 iren->InvokeEvent(vtkCommand::EnterEvent, e);
1202 /*! handle leave event
1206 void QVTKWidget::leaveEvent(QEvent* e)
1210 vtkRenderWindowInteractor* iren = NULL;
1216 iren = this->mRenWin->GetInteractor();
1222 if (!iren || !iren->GetEnabled())
1232 iren->InvokeEvent(vtkCommand::LeaveEvent, e);
1238 /*! handle mouse release event
1242 void QVTKWidget::mouseReleaseEvent(QMouseEvent* e)
1246 vtkRenderWindowInteractor* iren = NULL;
1252 iren = this->mRenWin->GetInteractor();
1258 if (!iren || !iren->GetEnabled())
1268 // give vtk event information
1270 #if QT_VERSION < 0x040000
1272 iren->SetEventInformationFlipY(e->x(), e->y(),
1274 (e->state() & Qt::ControlButton) > 0 ? 1 : 0,
1276 (e->state() & Qt::ShiftButton ) > 0 ? 1 : 0);
1280 iren->SetEventInformationFlipY(e->x(), e->y(),
1282 (e->modifiers() & Qt::ControlModifier) > 0 ? 1 : 0,
1284 (e->modifiers() & Qt::ShiftModifier ) > 0 ? 1 : 0);
1290 // invoke appropriate vtk event
1292 switch (e->button())
1296 case Qt::LeftButton:
1298 iren->InvokeEvent(vtkCommand::LeftButtonReleaseEvent, e);
1306 iren->InvokeEvent(vtkCommand::MiddleButtonReleaseEvent, e);
1312 case Qt::RightButton:
1314 iren->InvokeEvent(vtkCommand::RightButtonReleaseEvent, e);
1330 /*! handle key press event
1334 void QVTKWidget::keyPressEvent(QKeyEvent* e)
1338 vtkRenderWindowInteractor* iren = NULL;
1344 iren = this->mRenWin->GetInteractor();
1350 if (!iren || !iren->GetEnabled())
1360 // get key and keysym information
1362 #if QT_VERSION < 0x040000
1364 int ascii_key = e->text().length() ? e->text().unicode()->latin1() : 0;
1368 int ascii_key = e->text().length() ? e->text().unicode()->toLatin1() : 0;
1372 const char* keysym = ascii_to_key_sym(ascii_key);
1380 keysym = qt_key_to_key_sym(static_cast<Qt::Key>(e->key()));
1396 // give interactor event information
1398 #if QT_VERSION < 0x040000
1400 iren->SetKeyEventInformation(
1402 (e->state() & Qt::ControlButton),
1404 (e->state() & Qt::ShiftButton),
1406 ascii_key, e->count(), keysym);
1410 iren->SetKeyEventInformation(
1412 (e->modifiers() & Qt::ControlModifier),
1414 (e->modifiers() & Qt::ShiftModifier),
1416 ascii_key, e->count(), keysym);
1424 iren->InvokeEvent(vtkCommand::KeyPressEvent, e);
1428 // invoke char event only for ascii characters
1434 iren->InvokeEvent(vtkCommand::CharEvent, e);
1442 /*! handle key release event
1446 void QVTKWidget::keyReleaseEvent(QKeyEvent* e)
1452 vtkRenderWindowInteractor* iren = NULL;
1458 iren = this->mRenWin->GetInteractor();
1464 if (!iren || !iren->GetEnabled())
1474 // get key and keysym info
1476 #if QT_VERSION < 0x040000
1478 int ascii_key = e->text().length() ? e->text().unicode()->latin1() : 0;
1482 int ascii_key = e->text().length() ? e->text().unicode()->toLatin1() : 0;
1486 const char* keysym = ascii_to_key_sym(ascii_key);
1494 keysym = qt_key_to_key_sym((Qt::Key)e->key());
1510 // give event information to interactor
1512 #if QT_VERSION < 0x040000
1514 iren->SetKeyEventInformation(
1516 (e->state() & Qt::ControlButton),
1518 (e->state() & Qt::ShiftButton),
1520 ascii_key, e->count(), keysym);
1524 iren->SetKeyEventInformation(
1526 (e->modifiers() & Qt::ControlModifier),
1528 (e->modifiers() & Qt::ShiftModifier),
1530 ascii_key, e->count(), keysym);
1538 iren->InvokeEvent(vtkCommand::KeyReleaseEvent, e);
1544 #ifndef QT_NO_WHEELEVENT
1546 void QVTKWidget::wheelEvent(QWheelEvent* e)
1550 vtkRenderWindowInteractor* iren = NULL;
1556 iren = this->mRenWin->GetInteractor();
1562 if (!iren || !iren->GetEnabled())
1572 // VTK supports wheel mouse events only in version 4.5 or greater
1574 // give event information to interactor
1576 #if QT_VERSION < 0x040000
1578 iren->SetEventInformationFlipY(e->x(), e->y(),
1580 (e->state() & Qt::ControlButton) > 0 ? 1 : 0,
1582 (e->state() & Qt::ShiftButton ) > 0 ? 1 : 0);
1586 iren->SetEventInformationFlipY(e->x(), e->y(),
1588 (e->modifiers() & Qt::ControlModifier) > 0 ? 1 : 0,
1590 (e->modifiers() & Qt::ShiftModifier ) > 0 ? 1 : 0);
1598 // if delta is positive, it is a forward wheel event
1604 iren->InvokeEvent(vtkCommand::MouseWheelForwardEvent, e);
1612 iren->InvokeEvent(vtkCommand::MouseWheelBackwardEvent, e);
1622 void QVTKWidget::focusInEvent(QFocusEvent*)
1626 // These prevent updates when the window
1628 // gains or loses focus. By default, Qt
1630 // does an update because the color group's
1632 // active status changes. We don't even use
1634 // color groups so we do nothing here.
1640 void QVTKWidget::focusOutEvent(QFocusEvent*)
1644 // These prevent updates when the window
1646 // gains or loses focus. By default, Qt
1648 // does an update because the color group's
1650 // active status changes. We don't even use
1652 // color groups so we do nothing here.
1660 void QVTKWidget::contextMenuEvent(QContextMenuEvent* e)
1664 vtkRenderWindowInteractor* iren = NULL;
1670 iren = this->mRenWin->GetInteractor();
1676 if (!iren || !iren->GetEnabled())
1686 // give interactor the event information
1688 #if QT_VERSION < 0x040000
1690 iren->SetEventInformationFlipY(e->x(), e->y(),
1692 (e->state() & Qt::ControlButton) > 0 ? 1 : 0,
1694 (e->state() & Qt::ShiftButton ) > 0 ? 1 : 0);
1698 iren->SetEventInformationFlipY(e->x(), e->y(),
1700 (e->modifiers() & Qt::ControlModifier) > 0 ? 1 : 0,
1702 (e->modifiers() & Qt::ShiftModifier ) > 0 ? 1 : 0);
1708 // invoke event and pass qt event for additional data as well
1710 iren->InvokeEvent(QVTKWidget::ContextMenuEvent, e);
1718 void QVTKWidget::dragEnterEvent(QDragEnterEvent* e)
1722 vtkRenderWindowInteractor* iren = NULL;
1728 iren = this->mRenWin->GetInteractor();
1734 if (!iren || !iren->GetEnabled())
1744 // invoke event and pass qt event for additional data as well
1746 iren->InvokeEvent(QVTKWidget::DragEnterEvent, e);
1752 void QVTKWidget::dragMoveEvent(QDragMoveEvent* e)
1756 vtkRenderWindowInteractor* iren = NULL;
1762 iren = this->mRenWin->GetInteractor();
1768 if (!iren || !iren->GetEnabled())
1778 // give interactor the event information
1780 iren->SetEventInformationFlipY(e->pos().x(), e->pos().y());
1784 // invoke event and pass qt event for additional data as well
1786 iren->InvokeEvent(QVTKWidget::DragMoveEvent, e);
1792 void QVTKWidget::dragLeaveEvent(QDragLeaveEvent* e)
1796 vtkRenderWindowInteractor* iren = NULL;
1802 iren = this->mRenWin->GetInteractor();
1808 if (!iren || !iren->GetEnabled())
1818 // invoke event and pass qt event for additional data as well
1820 iren->InvokeEvent(QVTKWidget::DragLeaveEvent, e);
1826 void QVTKWidget::dropEvent(QDropEvent* e)
1830 vtkRenderWindowInteractor* iren = NULL;
1836 iren = this->mRenWin->GetInteractor();
1842 if (!iren || !iren->GetEnabled())
1852 // give interactor the event information
1854 iren->SetEventInformationFlipY(e->pos().x(), e->pos().y());
1858 // invoke event and pass qt event for additional data as well
1860 iren->InvokeEvent(QVTKWidget::DropEvent, e);
1868 /*! handle reparenting of widgets
1872 #if QT_VERSION < 0x040000
1874 void QVTKWidget::reparent(QWidget* parent, Qt::WFlags f, const QPoint& p, bool showit)
1878 this->markCachedImageAsDirty();
1886 // Finalize the window to remove graphics resources associated with
1890 if (this->mRenWin->GetMapped())
1894 this->mRenWin->Finalize();
1900 // have QWidget reparent as normal, but don't show
1902 QWidget::reparent(parent, f, p, false);
1910 // connect to new window
1912 #if defined(Q_WS_MAC)
1914 static_cast<vtkCarbonRenderWindow*>(this->mRenWin)->SetRootWindow(
1916 reinterpret_cast<WindowPtr>(this->handle()));
1922 this->mRenWin->SetWindowId( reinterpret_cast<void*>(this->winId()));
1928 // start up the window to create graphics resources for this window
1934 this->mRenWin->Start();
1942 // show if requested
1958 void QVTKWidget::showEvent(QShowEvent* e)
1962 this->markCachedImageAsDirty();
1966 QWidget::showEvent(e);
1972 QPaintEngine* QVTKWidget::paintEngine() const
1982 class QVTKInteractorInternal : public QObject
1988 QVTKInteractorInternal(QObject* p)
1994 this->SignalMapper = new QSignalMapper(this);
1998 ~QVTKInteractorInternal()
2004 QSignalMapper* SignalMapper;
2006 typedef vtkstd::map<int, QTimer*> TimerMap;
2016 /*! allocation method for Qt/VTK interactor
2020 vtkStandardNewMacro(QVTKInteractor);
2024 /*! constructor for Qt/VTK interactor
2028 QVTKInteractor::QVTKInteractor()
2032 this->Internal = new QVTKInteractorInternal(this);
2034 QObject::connect(this->Internal->SignalMapper, SIGNAL(mapped(int)), this, SLOT(TimerEvent(int)) );
2040 /*! start method for interactor
2044 void QVTKInteractor::Start()
2048 vtkErrorMacro(<<"QVTKInteractor cannot control the event loop.");
2054 /*! terminate the application
2058 void QVTKInteractor::TerminateApp()
2062 // we are in a GUI so let's terminate the GUI the normal way
2072 /*! handle timer event
2076 void QVTKInteractor::TimerEvent(int timerId)
2080 if ( !this->GetEnabled() )
2088 this->InvokeEvent(vtkCommand::TimerEvent, (void*)&timerId);
2092 if (this->IsOneShotTimer(timerId))
2096 this->DestroyTimer(timerId); // 'cause our Qt timers are always repeating
2108 QVTKInteractor::~QVTKInteractor()
2116 /*! create Qt timer with an interval of 10 msec.
2120 int QVTKInteractor::InternalCreateTimer(int timerId, int vtkNotUsed(timerType), unsigned long duration)
2124 QTimer* timer = new QTimer(this);
2126 timer->start(duration);
2128 this->Internal->SignalMapper->setMapping(timer, timerId);
2130 QObject::connect(timer, SIGNAL(timeout()), this->Internal->SignalMapper, SLOT(map()));
2132 int platformTimerId = timer->timerId();
2134 this->Internal->Timers.insert(QVTKInteractorInternal::TimerMap::value_type(platformTimerId, timer));
2136 return platformTimerId;
2146 int QVTKInteractor::InternalDestroyTimer(int platformTimerId)
2150 QVTKInteractorInternal::TimerMap::iterator iter = this->Internal->Timers.find(platformTimerId);
2152 if (iter != this->Internal->Timers.end())
2156 iter->second->stop();
2158 delete iter->second;
2160 this->Internal->Timers.erase(iter);
2174 // ***** keysym stuff below *****
2178 static const char *AsciiToKeySymTable[] = {
2180 0, 0, 0, 0, 0, 0, 0, 0, 0, "Tab", 0, 0, 0, 0, 0, 0,
2182 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2184 "space", "exclam", "quotedbl", "numbersign",
2186 "dollar", "percent", "ampersand", "quoteright",
2188 "parenleft", "parenright", "asterisk", "plus",
2190 "comma", "minus", "period", "slash",
2192 "0", "1", "2", "3", "4", "5", "6", "7",
2194 "8", "9", "colon", "semicolon", "less", "equal", "greater", "question",
2196 "at", "A", "B", "C", "D", "E", "F", "G",
2198 "H", "I", "J", "K", "L", "M", "N", "O",
2200 "P", "Q", "R", "S", "T", "U", "V", "W",
2202 "X", "Y", "Z", "bracketleft",
2204 "backslash", "bracketright", "asciicircum", "underscore",
2206 "quoteleft", "a", "b", "c", "d", "e", "f", "g",
2208 "h", "i", "j", "k", "l", "m", "n", "o",
2210 "p", "q", "r", "s", "t", "u", "v", "w",
2212 "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", "Delete",
2214 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2216 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2218 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2220 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2222 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2224 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2226 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2228 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
2233 const char* ascii_to_key_sym(int i)
2241 return AsciiToKeySymTable[i];
2251 #define QVTK_HANDLE(x,y) \
2258 const char* qt_key_to_key_sym(Qt::Key i)
2262 const char* ret = 0;
2270 QVTK_HANDLE(Qt::Key_Backspace, "BackSpace")
2272 QVTK_HANDLE(Qt::Key_Tab, "Tab")
2274 #if QT_VERSION < 0x040000
2276 QVTK_HANDLE(Qt::Key_BackTab, "Tab")
2280 QVTK_HANDLE(Qt::Key_Backtab, "Tab")
2284 //QVTK_HANDLE(Qt::Key_Clear, "Clear")
2286 QVTK_HANDLE(Qt::Key_Return, "Return")
2288 QVTK_HANDLE(Qt::Key_Enter, "Return")
2290 QVTK_HANDLE(Qt::Key_Shift, "Shift_L")
2292 QVTK_HANDLE(Qt::Key_Control, "Control_L")
2294 QVTK_HANDLE(Qt::Key_Alt, "Alt_L")
2296 QVTK_HANDLE(Qt::Key_Pause, "Pause")
2298 QVTK_HANDLE(Qt::Key_CapsLock, "Caps_Lock")
2300 QVTK_HANDLE(Qt::Key_Escape, "Escape")
2302 QVTK_HANDLE(Qt::Key_Space, "space")
2304 //QVTK_HANDLE(Qt::Key_Prior, "Prior")
2306 //QVTK_HANDLE(Qt::Key_Next, "Next")
2308 QVTK_HANDLE(Qt::Key_End, "End")
2310 QVTK_HANDLE(Qt::Key_Home, "Home")
2312 QVTK_HANDLE(Qt::Key_Left, "Left")
2314 QVTK_HANDLE(Qt::Key_Up, "Up")
2316 QVTK_HANDLE(Qt::Key_Right, "Right")
2318 QVTK_HANDLE(Qt::Key_Down, "Down")
2326 QVTK_HANDLE(Qt::Key_SysReq, "Snapshot")
2328 QVTK_HANDLE(Qt::Key_Insert, "Insert")
2330 QVTK_HANDLE(Qt::Key_Delete, "Delete")
2332 QVTK_HANDLE(Qt::Key_Help, "Help")
2334 QVTK_HANDLE(Qt::Key_0, "0")
2336 QVTK_HANDLE(Qt::Key_1, "1")
2338 QVTK_HANDLE(Qt::Key_2, "2")
2340 QVTK_HANDLE(Qt::Key_3, "3")
2342 QVTK_HANDLE(Qt::Key_4, "4")
2344 QVTK_HANDLE(Qt::Key_5, "5")
2346 QVTK_HANDLE(Qt::Key_6, "6")
2348 QVTK_HANDLE(Qt::Key_7, "7")
2350 QVTK_HANDLE(Qt::Key_8, "8")
2352 QVTK_HANDLE(Qt::Key_9, "9")
2354 QVTK_HANDLE(Qt::Key_A, "a")
2356 QVTK_HANDLE(Qt::Key_B, "b")
2358 QVTK_HANDLE(Qt::Key_C, "c")
2360 QVTK_HANDLE(Qt::Key_D, "d")
2362 QVTK_HANDLE(Qt::Key_E, "e")
2364 QVTK_HANDLE(Qt::Key_F, "f")
2366 QVTK_HANDLE(Qt::Key_G, "g")
2368 QVTK_HANDLE(Qt::Key_H, "h")
2370 QVTK_HANDLE(Qt::Key_I, "i")
2372 QVTK_HANDLE(Qt::Key_J, "h")
2374 QVTK_HANDLE(Qt::Key_K, "k")
2376 QVTK_HANDLE(Qt::Key_L, "l")
2378 QVTK_HANDLE(Qt::Key_M, "m")
2380 QVTK_HANDLE(Qt::Key_N, "n")
2382 QVTK_HANDLE(Qt::Key_O, "o")
2384 QVTK_HANDLE(Qt::Key_P, "p")
2386 QVTK_HANDLE(Qt::Key_Q, "q")
2388 QVTK_HANDLE(Qt::Key_R, "r")
2390 QVTK_HANDLE(Qt::Key_S, "s")
2392 QVTK_HANDLE(Qt::Key_T, "t")
2394 QVTK_HANDLE(Qt::Key_U, "u")
2396 QVTK_HANDLE(Qt::Key_V, "v")
2398 QVTK_HANDLE(Qt::Key_W, "w")
2400 QVTK_HANDLE(Qt::Key_X, "x")
2402 QVTK_HANDLE(Qt::Key_Y, "y")
2404 QVTK_HANDLE(Qt::Key_Z, "z")
2408 QVTK_HANDLE(Qt::Key_Asterisk, "asterisk")
2410 QVTK_HANDLE(Qt::Key_Plus, "plus")
2414 QVTK_HANDLE(Qt::Key_Minus, "minus")
2416 QVTK_HANDLE(Qt::Key_Period, "period")
2418 QVTK_HANDLE(Qt::Key_Slash, "slash")
2420 QVTK_HANDLE(Qt::Key_F1, "F1")
2422 QVTK_HANDLE(Qt::Key_F2, "F2")
2424 QVTK_HANDLE(Qt::Key_F3, "F3")
2426 QVTK_HANDLE(Qt::Key_F4, "F4")
2428 QVTK_HANDLE(Qt::Key_F5, "F5")
2430 QVTK_HANDLE(Qt::Key_F6, "F6")
2432 QVTK_HANDLE(Qt::Key_F7, "F7")
2434 QVTK_HANDLE(Qt::Key_F8, "F8")
2436 QVTK_HANDLE(Qt::Key_F9, "F9")
2438 QVTK_HANDLE(Qt::Key_F10, "F10")
2440 QVTK_HANDLE(Qt::Key_F11, "F11")
2442 QVTK_HANDLE(Qt::Key_F12, "F12")
2444 QVTK_HANDLE(Qt::Key_F13, "F13")
2446 QVTK_HANDLE(Qt::Key_F14, "F14")
2448 QVTK_HANDLE(Qt::Key_F15, "F15")
2450 QVTK_HANDLE(Qt::Key_F16, "F16")
2452 QVTK_HANDLE(Qt::Key_F17, "F17")
2454 QVTK_HANDLE(Qt::Key_F18, "F18")
2456 QVTK_HANDLE(Qt::Key_F19, "F19")
2458 QVTK_HANDLE(Qt::Key_F20, "F20")
2460 QVTK_HANDLE(Qt::Key_F21, "F21")
2462 QVTK_HANDLE(Qt::Key_F22, "F22")
2464 QVTK_HANDLE(Qt::Key_F23, "F23")
2466 QVTK_HANDLE(Qt::Key_F24, "F24")
2468 QVTK_HANDLE(Qt::Key_NumLock, "Num_Lock")
2470 QVTK_HANDLE(Qt::Key_ScrollLock, "Scroll_Lock")
2492 // X11 stuff near the bottom of the file
2494 // to prevent namespace collisions with Qt headers
2498 #if defined Q_WS_X11
2500 #if defined(VTK_USE_OPENGL_LIBRARY)
2502 #include "vtkXOpenGLRenderWindow.h"
2506 #ifdef VTK_USE_MANGLED_MESA
2508 #include "vtkXMesaRenderWindow.h"
2518 void QVTKWidget::x11_setup_window()
2522 #if defined Q_WS_X11
2526 // this whole function is to allow this window to have a
2528 // different colormap and visual than the rest of the Qt application
2530 // this is very important if Qt's default visual and colormap is
2532 // not enough to get a decent graphics window
2538 // save widget states
2540 bool tracking = this->hasMouseTracking();
2542 #if QT_VERSION < 0x040000
2544 FocusPolicy focus_policy = focusPolicy();
2548 Qt::FocusPolicy focus_policy = focusPolicy();
2552 bool visible = isVisible();
2566 // get visual and colormap from VTK
2568 XVisualInfo* vi = 0;
2572 Display* display = reinterpret_cast<Display*>(mRenWin->GetGenericDisplayId());
2576 // check ogl and mesa and get information we need to create a decent window
2578 #if defined(VTK_USE_OPENGL_LIBRARY)
2580 vtkXOpenGLRenderWindow* ogl_win = vtkXOpenGLRenderWindow::SafeDownCast(mRenWin);
2586 vi = ogl_win->GetDesiredVisualInfo();
2588 cmap = ogl_win->GetDesiredColormap();
2594 #ifdef VTK_USE_MANGLED_MESA
2600 vtkXMesaRenderWindow* mgl_win = vtkXMesaRenderWindow::SafeDownCast(mRenWin);
2606 vi = mgl_win->GetDesiredVisualInfo();
2608 cmap = mgl_win->GetDesiredColormap();
2618 // can't get visual, oh well.
2620 // continue with Qt's default visual as it usually works
2640 // create the X window based on information VTK gave us
2642 XSetWindowAttributes attrib;
2644 attrib.colormap = cmap;
2646 attrib.border_pixel = BlackPixel(display, DefaultScreen(display));
2650 Window p = RootWindow(display, DefaultScreen(display));
2656 p = parentWidget()->winId();
2662 XWindowAttributes a;
2664 XGetWindowAttributes(display, this->winId(), &a);
2668 Window win = XCreateWindow(display, p, a.x, a.y, a.width, a.height,
2670 0, vi->depth, InputOutput, vi->visual,
2672 CWBorderPixel|CWColormap, &attrib);
2676 // backup colormap stuff
2684 if ( XGetWMColormapWindows(display, topLevelWidget()->winId(), &cmwret, &count) )
2688 cmw = new Window[count+1];
2690 memcpy( (char *)cmw, (char *)cmwret, sizeof(Window)*count );
2692 XFree( (char *)cmwret );
2696 for ( i=0; i<count; i++ )
2700 if ( cmw[i] == winId() )
2728 cmw = new Window[count];
2738 // tell Qt to initialize anything it needs to for this window
2744 // restore colormaps
2746 XSetWMColormapWindows( display, topLevelWidget()->winId(), cmw, count );
2758 // restore widget states
2760 this->setMouseTracking(tracking);
2762 #if QT_VERSION < 0x040000
2764 this->setBackgroundMode( Qt::NoBackground );
2768 this->setAttribute(Qt::WA_NoBackground);
2770 this->setAttribute(Qt::WA_PaintOnScreen);
2774 this->setFocusPolicy(focus_policy);
2792 #if defined (Q_WS_MAC) && QT_VERSION >= 0x040000
2794 OSStatus QVTKWidget::DirtyRegionProcessor(EventHandlerCallRef, EventRef event, void* wid)
2798 QVTKWidget* widget = reinterpret_cast<QVTKWidget*>(wid);
2800 UInt32 event_kind = GetEventKind(event);
2802 UInt32 event_class = GetEventClass(event);
2804 if (event_class == 'cute' && event_kind == 20)
2808 static_cast<vtkCarbonRenderWindow*>(widget->GetRenderWindow())->UpdateGLRegion();
2812 return eventNotHandledErr;
2822 #if defined (Q_WS_MAC) && QT_VERSION < 0x040000
2826 // gotta do some special stuff on the MAC to make it work right
2828 // this stuff will need changing when using Qt4 with HIViews
2832 #include <AGL/agl.h>
2836 void QVTKWidget::macFixRect()
2840 AGLContext context = static_cast<vtkCarbonRenderWindow*>(this->GetRenderWindow())->GetContextId();
2844 if (!this->isTopLevel())
2852 // always do AGL_BUFFER_RECT if we have a parent
2854 if (!aglIsEnabled(context, AGL_BUFFER_RECT))
2856 aglEnable(context, AGL_BUFFER_RECT);
2860 // get the clip region
2862 QRegion clip = this->clippedRegion();
2864 QRect clip_rect = clip.boundingRect();
2868 // get the position of this widget with respect to the top level widget
2870 QPoint mp(posInWindow(this));
2872 int win_height = this->topLevelWidget()->height();
2874 win_height -= win_height - this->topLevelWidget()->clippedRegion(FALSE).boundingRect().height();
2878 // give the position and size to agl
2880 bufRect[0] = mp.x();
2882 bufRect[1] = win_height -(mp.y() + this->height());
2884 bufRect[2] = this->width();
2886 bufRect[3] = this->height();
2888 aglSetInteger(context, AGL_BUFFER_RECT, bufRect);
2892 if (clip_rect.isEmpty())
2896 // no clipping, disable it
2898 if (!aglIsEnabled(context, AGL_CLIP_REGION))
2900 aglDisable(context, AGL_CLIP_REGION);
2912 aglSetInteger(context, AGL_BUFFER_RECT, bufRect);
2920 // we are clipping, so lets enable it
2922 if (!aglIsEnabled(context, AGL_CLIP_REGION))
2924 aglEnable(context, AGL_CLIP_REGION);
2928 // give agl the clip region
2930 aglSetInteger(context, AGL_CLIP_REGION, (const GLint*)clip.handle(TRUE));
2938 // update the context
2940 aglUpdateContext(context);
2946 void QVTKWidget::setRegionDirty(bool b)
2950 // the region is dirty and needs redrawn, but not yet
2952 // signal that it needs to be done when it is possible
2954 QWidget::setRegionDirty(b);
2956 QTimer::singleShot(1, this, SLOT(internalMacFixRect()));
2964 void QVTKWidget::macWidgetChangedWindow()
2976 // slot to update the draw region and draw the scene
2978 void QVTKWidget::internalMacFixRect()
2982 #if defined(Q_WS_MAC) && QT_VERSION < 0x040000
2994 static void dirty_cache(vtkObject *caller, unsigned long,
2996 void *clientdata, void *)
3000 QVTKWidget *widget = reinterpret_cast<QVTKWidget *>(clientdata);
3002 widget->markCachedImageAsDirty();
3006 vtkRenderWindow *renwin = vtkRenderWindow::SafeDownCast(caller);
3012 if ( widget->isAutomaticImageCacheEnabled()
3014 && ( renwin->GetDesiredUpdateRate()
3016 < widget->maxRenderRateForImageCache() ) )
3020 widget->saveImageToCache();