From 5cbe64dac73083b1c65916a69075735804d23d06 Mon Sep 17 00:00:00 2001
From: Yannick Verdie <no@email>
Date: Sat, 19 Jun 2010 18:57:04 +0000
Subject: [PATCH] New functions with  QT GUI Shortcut for zoom (CTRL + and CTRL
 - for zoomin/out, CTRL Left/Right/Up/Down for panning, CTRL P for zoom = 1)
 Fix bug with key event

---
 modules/highgui/src/window_QT.cpp | 136 ++++++++++++++++++++++-----
 modules/highgui/src/window_QT.h   | 151 +++++++++++++++++-------------
 2 files changed, 198 insertions(+), 89 deletions(-)

diff --git a/modules/highgui/src/window_QT.cpp b/modules/highgui/src/window_QT.cpp
index 89ae871ad5..8b41792c12 100755
--- a/modules/highgui/src/window_QT.cpp
+++ b/modules/highgui/src/window_QT.cpp
@@ -630,7 +630,6 @@ int GuiReceiver::start()
 
 CvTrackbar::CvTrackbar(CvWindow* arg, QString name, int* value, int count, CvTrackbarCallback on_change )
 {
-    //moveToThread(qApp->instance()->thread());
     setObjectName(trackbar_name);
     parent = arg;
     trackbar_name = name;
@@ -638,7 +637,6 @@ CvTrackbar::CvTrackbar(CvWindow* arg, QString name, int* value, int count, CvTra
 
     callback = on_change;
     slider = new QSlider(Qt::Horizontal);
-    //slider->setObjectName(trackbar_name);
     slider->setFocusPolicy(Qt::StrongFocus);
     slider->setMinimum(0);
     slider->setMaximum(count);
@@ -742,10 +740,27 @@ CvWindow::CvWindow(QString arg, int arg2)
     myview = new ViewPort(this, CV_MODE_NORMAL);
     myview->setAlignment(Qt::AlignHCenter);
 
+
+    shortcutZ = new QShortcut(Qt::CTRL + Qt::Key_P, this);
+    QObject::connect( shortcutZ, SIGNAL( activated ()),myview, SLOT( resetZoom( ) ));
+    shortcutPlus = new QShortcut(QKeySequence(QKeySequence::ZoomIn), this);
+    QObject::connect( shortcutPlus, SIGNAL( activated ()),myview, SLOT( ZoomIn() ));
+    shortcutMinus = new QShortcut(QKeySequence(QKeySequence::ZoomOut), this);
+    QObject::connect(shortcutMinus, SIGNAL( activated ()),myview, SLOT( ZoomOut() ));
+    shortcutLeft = new QShortcut(Qt::CTRL + Qt::Key_Left, this);
+    QObject::connect( shortcutLeft, SIGNAL( activated ()),myview, SLOT( siftWindowOnLeft() ));
+    shortcutRight = new QShortcut(Qt::CTRL + Qt::Key_Right, this);
+    QObject::connect( shortcutRight, SIGNAL( activated ()),myview, SLOT( siftWindowOnRight() ));
+    shortcutUp = new QShortcut(Qt::CTRL + Qt::Key_Up, this);
+    QObject::connect(shortcutUp, SIGNAL( activated ()),myview, SLOT( siftWindowOnUp() ));
+    shortcutDown = new QShortcut(Qt::CTRL + Qt::Key_Down, this);
+    QObject::connect(shortcutDown, SIGNAL( activated ()),myview, SLOT( siftWindowOnDown() ));
+
     layout = new QBoxLayout(QBoxLayout::TopToBottom);
     layout->setSpacing(5);
     layout->setObjectName(QString::fromUtf8("boxLayout"));
     layout->setContentsMargins(0, 0, 0, 0);
+    layout->setMargin(0);
     layout->addWidget(myview);
 
     if (flags == CV_WINDOW_AUTOSIZE)
@@ -792,12 +807,37 @@ void CvWindow::addSlider(QString name, int* value, int count,CvTrackbarCallback
     layout->insertLayout(layout->count()-1,t);
 }
 
+//Need more test here !
 void CvWindow::keyPressEvent(QKeyEvent *event)
 {
-    mutexKey.lock();
-    last_key = (int)event->text().toLocal8Bit().at(0);
-    mutexKey.unlock();
-    key_pressed.wakeAll();
+    //see http://doc.trolltech.com/4.6/qt.html#Key-enum
+    int key = event->key();
+    bool goodKey = false;
+
+    if (key>=20 && key<=255 )
+    {
+        key = (int)event->text().toLocal8Bit().at(0);
+        goodKey = true;
+    }
+
+    if (key == Qt::Key_Escape)
+    {
+        key = 27;
+        goodKey = true;
+    }
+
+    //control plus Z, plus +, and plus - are used for zoom functions
+    if (event->modifiers() != Qt::ControlModifier && goodKey)
+    {
+        mutexKey.lock();
+        last_key = key;
+
+        //last_key = event->nativeVirtualKey ();
+        mutexKey.unlock();
+        key_pressed.wakeAll();
+        //event->accept();
+    }
+
     QWidget::keyPressEvent(event);
 }
 
@@ -823,8 +863,10 @@ ViewPort::ViewPort(QWidget* arg, int arg2)
 {
     mode = arg2;
     centralWidget = arg,
+
     setupViewport(centralWidget);
-    setUpdatesEnabled(true);
+    setContentsMargins(0,0,0,0);
+
     setObjectName(QString::fromUtf8("graphicsView"));
     timerDisplay = new QTimer(this);
     timerDisplay->setSingleShot(true);
@@ -833,21 +875,20 @@ ViewPort::ViewPort(QWidget* arg, int arg2)
     positionGrabbing = QPointF(0,0);
     positionCorners = QRect(0,0,size().width(),size().height());
 
+
+
+
+#if defined(OPENCV_GL)
     if (mode == CV_MODE_OPENGL)
     {
-#if defined(OPENCV_GL)
         setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
         initGL();
-#endif
     }
+#endif
 
     image2Draw=cvCreateImage(cvSize(centralWidget->width(),centralWidget->height()),IPL_DEPTH_8U,3);
     cvZero(image2Draw);
-
-    setSceneRect(0,0,size().width(),size().height());
-    this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
-    this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
-    this->setInteractive(false);
+    setInteractive(false);
 }
 
 ViewPort::~ViewPort()
@@ -858,6 +899,51 @@ ViewPort::~ViewPort()
     delete timerDisplay;
 }
 
+void ViewPort::resetZoom()
+{
+   matrixWorld.reset();
+   controlImagePosition();
+}
+
+void ViewPort::ZoomIn()
+{
+    scaleView( 0.5,QPointF(size().width()/2,size().height()/2));
+}
+
+void ViewPort::ZoomOut()
+{
+    scaleView( -0.5,QPointF(size().width()/2,size().height()/2));
+}
+
+
+//Note: move 2 percent of the window
+void  ViewPort::siftWindowOnLeft()
+{
+    float delta = 2*width()/(100.0*matrixWorld.m11());
+    moveView(QPointF(delta,0));
+}
+
+//Note: move 2 percent of the window
+void  ViewPort::siftWindowOnRight()
+{
+    float delta = -2*width()/(100.0*matrixWorld.m11());
+    moveView(QPointF(delta,0));
+}
+
+//Note: move 2 percent of the window
+void  ViewPort::siftWindowOnUp()
+{
+    float delta = 2*height()/(100.0*matrixWorld.m11());
+    moveView(QPointF(0,delta));
+}
+
+//Note: move 2 percent of the window
+void  ViewPort::siftWindowOnDown()
+{
+    float delta = -2*height()/(100.0*matrixWorld.m11());
+    moveView(QPointF(0,delta));
+}
+
 void ViewPort::startDisplayInfo(QString text, int delayms)
 {
     if (timerDisplay->isActive())
@@ -939,8 +1025,18 @@ void ViewPort::controlImagePosition()
 
     //save also the inv matrix
     matrixWorld_inv = matrixWorld.inverted();
+
+
+    viewport()->update();
 }
 
+void ViewPort::moveView(QPointF delta)
+{
+    matrixWorld.translate(delta.x(),delta.y());
+    controlImagePosition();
+}
+
+//factor is -0.5 (zoom out) or 0.5 (zoom in)
 void ViewPort::scaleView(qreal factor,QPointF center)
 {
     factor/=5;//-0.1 <-> 0.1
@@ -965,8 +1061,6 @@ void ViewPort::scaleView(qreal factor,QPointF center)
         setCursor(Qt::OpenHandCursor);
     else
         unsetCursor();
-
-    viewport()->update();
 }
 
 void ViewPort::wheelEvent(QWheelEvent *event)
@@ -1184,8 +1278,7 @@ void ViewPort::mouseMoveEvent(QMouseEvent *event)
 
         positionGrabbing = event->pos();
 
-        matrixWorld.translate(dxy.x(),dxy.y());
-        controlImagePosition();
+        moveView(dxy);
     }
 
     QWidget::mouseMoveEvent(event);
@@ -1204,8 +1297,8 @@ QSize ViewPort::sizeHint() const
 
 void ViewPort::resizeEvent ( QResizeEvent *event)
 {
-     controlImagePosition();
-     return QGraphicsView::resizeEvent(event);
+    controlImagePosition();
+    return QGraphicsView::resizeEvent(event);
 }
 
 
@@ -1258,7 +1351,7 @@ void ViewPort::drawOverview(QPainter *painter)
 
     const int margin = 5;
 
-    painter->setBrush(QBrush ( QColor(0, 0, 0, 127)));
+    painter->setBrush(QColor(0, 0, 0, 127));
     painter->setPen(Qt::darkGreen);
 
     painter->drawRect(QRect(width()-viewSize.width()-margin, 0,viewSize.width(),viewSize.height()));
@@ -1266,7 +1359,6 @@ void ViewPort::drawOverview(QPainter *painter)
     qreal ratioSize = 1/matrixWorld.m11();
     qreal ratioWindow = (qreal)(viewSize.height())/(qreal)(size().height());
 
-    painter->setBrush(QColor(0, 0, 0, 127));
     painter->setPen(Qt::darkBlue);
     painter->drawRect(QRectF(width()-viewSize.width()-positionCorners.left()*ratioSize*ratioWindow-margin,
                              -positionCorners.top()*ratioSize*ratioWindow,
diff --git a/modules/highgui/src/window_QT.h b/modules/highgui/src/window_QT.h
index 4db7aa112c..d62b623cc4 100644
--- a/modules/highgui/src/window_QT.h
+++ b/modules/highgui/src/window_QT.h
@@ -65,6 +65,7 @@
 #include <QSlider>
 #include <QLabel>
 #include <QIODevice>
+#include <QShortcut>
 
 //Macro here
 #define CV_MODE_NORMAL   0
@@ -83,7 +84,7 @@ public:
     GuiReceiver();
     int start();
     bool _bTimeOut;
-    
+
 private:
 
 
@@ -124,7 +125,7 @@ private:
     QString createLabel();
     QPointer<QPushButton > label;
     CvTrackbarCallback callback;
-    CvWindow* parent;
+    QPointer<CvWindow> parent;
     int* dataSlider;
 };
 
@@ -151,9 +152,15 @@ protected:
 
 private:
     QPointer<ViewPort> myview;
-    
-    int status;//0 normal, 1 fullscreen (YV)
 
+    int status;//0 normal, 1 fullscreen (YV)
+    QPointer<QShortcut> shortcutZ;
+    QPointer<QShortcut> shortcutPlus;
+    QPointer<QShortcut> shortcutMinus;
+    QPointer<QShortcut> shortcutLeft;
+    QPointer<QShortcut> shortcutRight;
+    QPointer<QShortcut> shortcutUp;
+    QPointer<QShortcut> shortcutDown;
 };
 
 
@@ -166,30 +173,41 @@ public:
     ~ViewPort();
     void updateImage(void* arr);
     void startDisplayInfo(QString text, int delayms);
-	void setMouseCallBack(CvMouseCallback m, void* param);
+    void setMouseCallBack(CvMouseCallback m, void* param);
 
 public slots:
     //reference:
     //http://www.qtcentre.org/wiki/index.php?title=QGraphicsView:_Smooth_Panning_and_Zooming
     //http://doc.qt.nokia.com/4.6/gestures-imagegestures-imagewidget-cpp.html
     void scaleView(qreal scaleFactor, QPointF center);
+    void moveView(QPointF delta);
+    void resetZoom();
+    void ZoomIn();
+    void ZoomOut();
+    void siftWindowOnLeft();
+    void siftWindowOnRight();
+    void siftWindowOnUp() ;
+    void siftWindowOnDown();
     void resizeEvent ( QResizeEvent * );
 
 private:
+    QGraphicsScene *myScene;
+
     QPointF positionGrabbing;
     QRect   positionCorners;
     QTransform matrixWorld;
     QTransform matrixWorld_inv;
-    
-	CvMouseCallback on_mouse;
+
+    CvMouseCallback on_mouse;
     void* on_mouse_param;
 
     int mode;
     IplImage* image2Draw;
+
     bool isSameSize(IplImage* img1,IplImage* img2);
     QSize sizeHint() const;
-    QWidget* centralWidget;
-    QTimer* timerDisplay;
+    QPointer<QWidget> centralWidget;
+    QPointer<QTimer> timerDisplay;
     bool drawInfo;
     QString infoText;
     //QImage* image;
@@ -201,10 +219,9 @@ private:
     void mouseReleaseEvent(QMouseEvent *event);
     void mouseDoubleClickEvent(QMouseEvent *event);
     void drawInstructions(QPainter *painter);
+    void drawOverview(QPainter *painter);
     void draw2D(QPainter *painter);
     void controlImagePosition();
-    void drawOverview(QPainter *painter);
-
 
 #if defined(OPENCV_GL)
     void draw3D();
@@ -221,61 +238,61 @@ private slots:
 //here css for trackbar
 /* from http://thesmithfam.org/blog/2010/03/10/fancy-qslider-stylesheet */
 static const QString str_Trackbar_css = QString("")
-+										"QSlider::groove:horizontal {"
-+										"border: 1px solid #bbb;"
-+										"background: white;"
-+										"height: 10px;"
-+										"border-radius: 4px;"
-+										"}"
-
-+										"QSlider::sub-page:horizontal {"
-+										"background: qlineargradient(x1: 0, y1: 0,    x2: 0, y2: 1,"
-+										"stop: 0 #66e, stop: 1 #bbf);"
-+										"background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1,"
-+										"stop: 0 #bbf, stop: 1 #55f);"
-+										"border: 1px solid #777;"
-+										"height: 10px;"
-+										"border-radius: 4px;"
-+										"}"
-
-+										"QSlider::add-page:horizontal {"
-+										"background: #fff;"
-+										"border: 1px solid #777;"
-+										"height: 10px;"
-+										"border-radius: 4px;"
-+										"}"
-										
-+										"QSlider::handle:horizontal {"
-+										"background: qlineargradient(x1:0, y1:0, x2:1, y2:1,"
-+										"stop:0 #eee, stop:1 #ccc);"
-+										"border: 1px solid #777;"
-+										"width: 13px;"
-+										"margin-top: -2px;"
-+										"margin-bottom: -2px;"
-+										"border-radius: 4px;"
-+										"}"
-
-+										"QSlider::handle:horizontal:hover {"
-+										"background: qlineargradient(x1:0, y1:0, x2:1, y2:1,"
-+										"stop:0 #fff, stop:1 #ddd);"
-+										"border: 1px solid #444;"
-+										"border-radius: 4px;"
-+										"}"
-										
-+										"QSlider::sub-page:horizontal:disabled {"
-+										"background: #bbb;"
-+										"border-color: #999;"
-+										"}"
-										
-+										"QSlider::add-page:horizontal:disabled {"
-+										"background: #eee;"
-+										"border-color: #999;"
-+										"}"
-										
-+										"QSlider::handle:horizontal:disabled {"
-+										"background: #eee;"
-+										"border: 1px solid #aaa;"
-+										"border-radius: 4px;"
-+										"}";
+                                        +										"QSlider::groove:horizontal {"
+                                        +										"border: 1px solid #bbb;"
+                                        +										"background: white;"
+                                        +										"height: 10px;"
+                                        +										"border-radius: 4px;"
+                                        +										"}"
+
+                                        +										"QSlider::sub-page:horizontal {"
+                                        +										"background: qlineargradient(x1: 0, y1: 0,    x2: 0, y2: 1,"
+                                        +										"stop: 0 #66e, stop: 1 #bbf);"
+                                        +										"background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1,"
+                                        +										"stop: 0 #bbf, stop: 1 #55f);"
+                                        +										"border: 1px solid #777;"
+                                        +										"height: 10px;"
+                                        +										"border-radius: 4px;"
+                                        +										"}"
+
+                                        +										"QSlider::add-page:horizontal {"
+                                        +										"background: #fff;"
+                                        +										"border: 1px solid #777;"
+                                        +										"height: 10px;"
+                                        +										"border-radius: 4px;"
+                                        +										"}"
+
+                                        +										"QSlider::handle:horizontal {"
+                                        +										"background: qlineargradient(x1:0, y1:0, x2:1, y2:1,"
+                                        +										"stop:0 #eee, stop:1 #ccc);"
+                                        +										"border: 1px solid #777;"
+                                        +										"width: 13px;"
+                                        +										"margin-top: -2px;"
+                                        +										"margin-bottom: -2px;"
+                                        +										"border-radius: 4px;"
+                                        +										"}"
+
+                                        +										"QSlider::handle:horizontal:hover {"
+                                        +										"background: qlineargradient(x1:0, y1:0, x2:1, y2:1,"
+                                        +										"stop:0 #fff, stop:1 #ddd);"
+                                        +										"border: 1px solid #444;"
+                                        +										"border-radius: 4px;"
+                                        +										"}"
+
+                                        +										"QSlider::sub-page:horizontal:disabled {"
+                                        +										"background: #bbb;"
+                                        +										"border-color: #999;"
+                                        +										"}"
+
+                                        +										"QSlider::add-page:horizontal:disabled {"
+                                        +										"background: #eee;"
+                                        +										"border-color: #999;"
+                                        +										"}"
+
+                                        +										"QSlider::handle:horizontal:disabled {"
+                                        +										"background: #eee;"
+                                        +										"border: 1px solid #aaa;"
+                                        +										"border-radius: 4px;"
+                                        +										"}";
 
 #endif
-- 
2.18.0