]> git.cworth.org Git - apitrace/commitdiff
gui: Implement a new surface viewer
authorZack Rusin <zack@kde.org>
Wed, 11 Sep 2013 00:30:59 +0000 (20:30 -0400)
committerZack Rusin <zack@kde.org>
Wed, 11 Sep 2013 00:30:59 +0000 (20:30 -0400)
Adds support for showing individual pixels and zooming in on the
image itself. All ready to be used for showing the actual original
pixel values, rather than the fake qimage pixels which it shows
right now.

gui/CMakeLists.txt
gui/imageviewer.cpp
gui/imageviewer.h
gui/mainwindow.cpp
gui/pixelwidget.cpp [new file with mode: 0644]
gui/pixelwidget.h [new file with mode: 0644]
gui/ui/imageviewer.ui

index 03e3d39ce78c2d1ecd1310957bbcbd94a8410b0d..ad13475ece3398181e6d8c9ae9b54317df874b5b 100644 (file)
@@ -14,6 +14,7 @@ set(qapitrace_SRCS
    jumpwidget.cpp
    mainwindow.cpp
    main.cpp
+   pixelwidget.cpp
    profiledialog.cpp
    profiletablemodel.cpp
    retracer.cpp
index 1a1fe5aeec63656421a7ab3027a182f2a5fa787f..cd034138f9aaa52ce79dc58b4aa638a24171293e 100644 (file)
@@ -1,4 +1,5 @@
 #include "imageviewer.h"
+#include "pixelwidget.h"
 
 #include <QDebug>
 #include <QDesktopWidget>
@@ -34,14 +35,28 @@ ImageViewer::ImageViewer(QWidget *parent)
     pal.setBrush(QPalette::Base,
                  QBrush(px));
     scrollAreaWidgetContents->setPalette(pal);
+
+    m_pixelWidget = new PixelWidget(scrollAreaWidgetContents);
+    verticalLayout_2->addWidget(m_pixelWidget);
+
+    rectLabel->hide();
+    pixelLabel->hide();
+
+    connect(m_pixelWidget, SIGNAL(zoomChanged(int)),
+            zoomSpinBox, SLOT(setValue(int)));
+    connect(zoomSpinBox, SIGNAL(valueChanged(int)),
+            m_pixelWidget, SLOT(setZoom(int)));
+    connect(m_pixelWidget, SIGNAL(mousePosition(int, int)),
+            this, SLOT(showPixel(int, int)));
+    connect(m_pixelWidget, SIGNAL(gridGeometry(const QRect &)),
+            this, SLOT(showGrid(const QRect &)));
 }
 
 void ImageViewer::setImage(const QImage &image)
 {
     m_image = image;
     m_temp = m_image;
-    QPixmap px = QPixmap::fromImage(m_temp);
-    imageLabel->setPixmap(px);
+    m_pixelWidget->setSurface(m_image);
     updateGeometry();
 }
 
@@ -112,8 +127,7 @@ void ImageViewer::slotUpdate()
         }
     }
 
-    QPixmap px = QPixmap::fromImage(m_temp);
-    imageLabel->setPixmap(px);
+    m_pixelWidget->setSurface(m_temp);
 
     updateGeometry();
 }
@@ -138,4 +152,36 @@ QSize ImageViewer::sizeHint() const
                  qMin(optimalWindowSize.height(), maxAvailableSize.height()));
 }
 
+void ImageViewer::resizeEvent(QResizeEvent *e)
+{
+    QWidget::resizeEvent(e);
+}
+
+void ImageViewer::showPixel(int x, int y)
+{
+    xSpinBox->setValue(x);
+    ySpinBox->setValue(y);
+    QColor clr = m_pixelWidget->colorAtCurrentPosition();
+    pixelLabel->setText(tr("RGBA: (%1, %2, %3, %4)")
+                        .arg(clr.red())
+                        .arg(clr.green())
+                        .arg(clr.blue())
+                        .arg(clr.alpha()));
+    pixelLabel->show();
+}
+
+void ImageViewer::showGrid(const QRect &rect)
+{
+    if (rect.isEmpty()) {
+        rectLabel->hide();
+        return;
+    }
+    rectLabel->setText(tr("Grid: [%1, %2, %3, %4]")
+                       .arg(rect.x())
+                       .arg(rect.y())
+                       .arg(rect.width())
+                       .arg(rect.height()));
+    rectLabel->show();
+}
+
 #include "imageviewer.moc"
index e8781182ebf8ae88343f4f6d0110934f469f97ef..141ca175a91676b3a04d7e3c9429f60510330330 100644 (file)
@@ -4,6 +4,9 @@
 #include "ui_imageviewer.h"
 #include <QDialog>
 
+class PixelWidget;
+class QLabel;
+
 class ImageViewer : public QDialog, public Ui_ImageViewer
 {
     Q_OBJECT
@@ -14,12 +17,19 @@ public:
 
     QSize sizeHint() const;
 
+protected:
+    void resizeEvent(QResizeEvent *event);
+
 private slots:
     void slotUpdate();
+    void showPixel(int, int);
+    void showGrid(const QRect &rect);
 
 private:
     QImage m_image;
     QImage m_temp;
+    PixelWidget *m_pixelWidget;
+    QLabel *m_pixelLabel;
 };
 
 
index 23729cd6d274f7f7b920fb2278286b13dcc6a05c..00469bca3d9f67450daa196472ef4a7302eeed53 100644 (file)
@@ -370,8 +370,11 @@ void MainWindow::replayTrace(bool dumpState, bool dumpThumbnails)
 
 void MainWindow::trimEvent()
 {
+    int trimIndex = 0;
+
+    Q_ASSERT(m_trimEvent->type() == ApiTraceEvent::Call ||
+             m_trimEvent->type() == ApiTraceEvent::Frame);
 
-    int trimIndex;
     if (m_trimEvent->type() == ApiTraceEvent::Call) {
         ApiTraceCall *call = static_cast<ApiTraceCall*>(m_trimEvent);
         trimIndex = call->index();
diff --git a/gui/pixelwidget.cpp b/gui/pixelwidget.cpp
new file mode 100644 (file)
index 0000000..88a1c5c
--- /dev/null
@@ -0,0 +1,407 @@
+/**
+ * The source code is based on qpixeltool.cpp.
+ * Original license follows.
+ */
+
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "pixelwidget.h"
+
+#include <qapplication.h>
+#include <qdesktopwidget.h>
+#include <qapplication.h>
+#ifndef QT_NO_CLIPBOARD
+#include <qclipboard.h>
+#endif
+#include <qpainter.h>
+#include <qevent.h>
+#include <qfiledialog.h>
+#include <qmenu.h>
+#include <qactiongroup.h>
+
+#include <qdebug.h>
+
+PixelWidget::PixelWidget(QWidget *parent)
+    : QWidget(parent)
+{
+    setWindowTitle(QLatin1String("PixelTool"));
+    setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+
+    m_gridSize = 1;
+    m_gridActive = 0;
+    m_zoom = 1;
+    m_displayGridSize = false;
+    m_displayGridSizeId = 0;
+
+    m_mouseDown = false;
+
+    m_initialSize = QSize(250, 250);
+
+    setMouseTracking(true);
+    setAttribute(Qt::WA_NoBackground);
+}
+
+PixelWidget::~PixelWidget()
+{
+}
+
+void PixelWidget::setSurface(const QImage &image)
+{
+    m_surface = image;
+    updateGeometry();
+    update();
+}
+
+void PixelWidget::timerEvent(QTimerEvent *event)
+{
+    if (event->timerId() == m_displayGridSizeId) {
+        killTimer(m_displayGridSizeId);
+        m_displayGridSize = false;
+    }
+}
+
+void render_string(QPainter *p, int w, int h, const QString &text, int flags)
+{
+    p->setBrush(QColor(255, 255, 255, 191));
+    p->setPen(Qt::black);
+    QRect bounds;
+    p->drawText(0, 0, w, h, Qt::TextDontPrint | flags, text, &bounds);
+
+    if (bounds.x() == 0) bounds.adjust(0, 0, 10, 0);
+    else bounds.adjust(-10, 0, 0, 0);
+
+    if (bounds.y() == 0) bounds.adjust(0, 0, 0, 10);
+    else bounds.adjust(0, -10, 0, 0);
+
+    p->drawRect(bounds);
+    p->drawText(bounds, flags, text);
+}
+
+void PixelWidget::paintEvent(QPaintEvent *)
+{
+    QPainter p(this);
+
+    int w = width();
+    int h = height();
+
+    p.save();
+    p.scale(zoomValue(), zoomValue());
+    p.drawImage(0, 0, m_surface);
+    p.scale(1/zoomValue(), 1/zoomValue());
+    p.restore();
+
+    // Draw the grid on top.
+    if (m_gridActive) {
+        p.setPen(m_gridActive == 1 ? Qt::black : Qt::white);
+        int incr = m_gridSize * zoomValue();
+        for (int x=0; x<w; x+=incr)
+            p.drawLine(x, 0, x, h);
+        for (int y=0; y<h; y+=incr)
+            p.drawLine(0, y, w, y);
+    }
+
+    QFont f(QLatin1String("courier"));
+    f.setBold(true);
+    p.setFont(f);
+
+    if (m_displayGridSize) {
+        render_string(&p, w, h,
+            QString::fromLatin1("Grid size: %1").arg(m_gridSize),
+                      Qt::AlignBottom | Qt::AlignLeft);
+    }
+
+    if (m_mouseDown && m_dragStart != m_dragCurrent) {
+        int x1 = (m_dragStart.x() / zoomValue()) * zoomValue();
+        int y1 = (m_dragStart.y() / zoomValue()) * zoomValue();
+        int x2 = (m_dragCurrent.x() / zoomValue()) * zoomValue();
+        int y2 = (m_dragCurrent.y() / zoomValue()) * zoomValue();
+        QRect r = QRect(x1, y1, x2 - x1, y2 - y1).normalized();
+        p.setBrush(Qt::NoBrush);
+        p.setPen(QPen(Qt::red, 3, Qt::SolidLine));
+        p.drawRect(r);
+        p.setPen(QPen(Qt::black, 1, Qt::SolidLine));
+        p.drawRect(r);
+
+        QRect rect(
+            int(r.x() / zoomValue()),
+            int(r.y() / zoomValue()),
+            int(r.width() / zoomValue()),
+            int(r.height() / zoomValue()));
+        emit gridGeometry(rect);
+    } else {
+        QRect empty;
+        emit gridGeometry(empty);
+    }
+
+
+}
+
+void PixelWidget::keyPressEvent(QKeyEvent *e)
+{
+    switch (e->key()) {
+    case Qt::Key_Plus:
+        increaseZoom();
+        break;
+    case Qt::Key_Minus:
+        decreaseZoom();
+        break;
+    case Qt::Key_PageUp:
+        setGridSize(m_gridSize + 1);
+        break;
+    case Qt::Key_PageDown:
+        setGridSize(m_gridSize - 1);
+        break;
+    case Qt::Key_G:
+        toggleGrid();
+        break;
+    case Qt::Key_C:
+        if (e->modifiers() & Qt::ControlModifier)
+            copyToClipboard();
+        break;
+    case Qt::Key_S:
+        if (e->modifiers() & Qt::ControlModifier) {
+            releaseKeyboard();
+            saveToFile();
+        }
+        break;
+    case Qt::Key_Control:
+        grabKeyboard();
+        break;
+    }
+}
+
+void PixelWidget::keyReleaseEvent(QKeyEvent *e)
+{
+    switch(e->key()) {
+    case Qt::Key_Control:
+        releaseKeyboard();
+        break;
+    default:
+        break;
+    }
+}
+
+void PixelWidget::resizeEvent(QResizeEvent *e)
+{
+    QWidget::resizeEvent(e);
+}
+
+void PixelWidget::mouseMoveEvent(QMouseEvent *e)
+{
+    if (m_mouseDown)
+        m_dragCurrent = e->pos();
+
+    int x = e->x() / zoomValue();
+    int y = e->y() / zoomValue();
+
+    if (x < m_surface.width() && y < m_surface.height() && x >= 0 && y >= 0) {
+        m_currentColor = m_surface.pixel(x, y);
+    } else
+        m_currentColor = QColor();
+
+    emit mousePosition(x, y);
+    update();
+}
+
+void PixelWidget::mousePressEvent(QMouseEvent *e)
+{
+    if (e->button() == Qt::LeftButton)
+        m_mouseDown = true;
+    m_dragStart = e->pos();
+}
+
+void PixelWidget::mouseReleaseEvent(QMouseEvent *)
+{
+    m_mouseDown = false;
+}
+
+void PixelWidget::contextMenuEvent(QContextMenuEvent *e)
+{
+    QMenu menu;
+
+    QAction title(QLatin1String("Surface Pixel Tool"), &menu);
+    title.setEnabled(false);
+
+    // Grid color options...
+    QActionGroup gridGroup(this);
+    QAction whiteGrid(QLatin1String("White grid"), &gridGroup);
+    whiteGrid.setCheckable(true);
+    whiteGrid.setChecked(m_gridActive == 2);
+    whiteGrid.setShortcut(QKeySequence(Qt::Key_G));
+    QAction blackGrid(QLatin1String("Black grid"), &gridGroup);
+    blackGrid.setCheckable(true);
+    blackGrid.setChecked(m_gridActive == 1);
+    blackGrid.setShortcut(QKeySequence(Qt::Key_G));
+    QAction noGrid(QLatin1String("No grid"), &gridGroup);
+    noGrid.setCheckable(true);
+    noGrid.setChecked(m_gridActive == 0);
+    noGrid.setShortcut(QKeySequence(Qt::Key_G));
+
+    // Grid size options
+    QAction incrGrid(QLatin1String("Increase grid size"), &menu);
+    incrGrid.setShortcut(QKeySequence(Qt::Key_PageUp));
+    connect(&incrGrid, SIGNAL(triggered()), this, SLOT(increaseGridSize()));
+    QAction decrGrid(QLatin1String("Decrease grid size"), &menu);
+    decrGrid.setShortcut(QKeySequence(Qt::Key_PageDown));
+    connect(&decrGrid, SIGNAL(triggered()), this, SLOT(decreaseGridSize()));
+
+    // Zoom options
+    QAction incrZoom(QLatin1String("Zoom in"), &menu);
+    incrZoom.setShortcut(QKeySequence(Qt::Key_Plus));
+    connect(&incrZoom, SIGNAL(triggered()), this, SLOT(increaseZoom()));
+    QAction decrZoom(QLatin1String("Zoom out"), &menu);
+    decrZoom.setShortcut(QKeySequence(Qt::Key_Minus));
+    connect(&decrZoom, SIGNAL(triggered()), this, SLOT(decreaseZoom()));
+
+    // Copy to clipboard / save
+    QAction save(QLatin1String("Save as image"), &menu);
+    save.setShortcut(QKeySequence(QLatin1String("Ctrl+S")));
+    connect(&save, SIGNAL(triggered()), this, SLOT(saveToFile()));
+#ifndef QT_NO_CLIPBOARD
+    QAction copy(QLatin1String("Copy to clipboard"), &menu);
+    copy.setShortcut(QKeySequence(QLatin1String("Ctrl+C")));
+    connect(&copy, SIGNAL(triggered()), this, SLOT(copyToClipboard()));
+#endif
+
+    menu.addAction(&title);
+    menu.addSeparator();
+    menu.addAction(&whiteGrid);
+    menu.addAction(&blackGrid);
+    menu.addAction(&noGrid);
+    menu.addSeparator();
+    menu.addAction(&incrGrid);
+    menu.addAction(&decrGrid);
+    menu.addSeparator();
+    menu.addAction(&incrZoom);
+    menu.addAction(&decrZoom);
+    menu.addSeparator();
+    menu.addAction(&save);
+#ifndef QT_NO_CLIPBOARD
+    menu.addAction(&copy);
+#endif
+
+    menu.exec(mapToGlobal(e->pos()));
+
+    if (noGrid.isChecked()) m_gridActive = 0;
+    else if (blackGrid.isChecked()) m_gridActive = 1;
+    else m_gridActive = 2;
+}
+
+QSize PixelWidget::sizeHint() const
+{
+    if (m_surface.isNull())
+        return m_initialSize;
+
+    QSize sz(m_surface.width() * zoomValue(),
+             m_surface.height() * zoomValue());
+    return sz;
+}
+
+void PixelWidget::startGridSizeVisibleTimer()
+{
+    if (m_gridActive) {
+        if (m_displayGridSizeId > 0)
+            killTimer(m_displayGridSizeId);
+        m_displayGridSizeId = startTimer(5000);
+        m_displayGridSize = true;
+        update();
+    }
+}
+
+void PixelWidget::setZoom(int zoom)
+{
+    if (zoom > 0 && zoom != m_zoom) {
+        QPoint pos = m_lastMousePos;
+        m_lastMousePos = QPoint();
+        m_zoom = zoom;
+        m_lastMousePos = pos;
+        m_dragStart = m_dragCurrent = QPoint();
+
+        if (m_zoom == 1)
+            m_gridActive = 0;
+        else if (!m_gridActive)
+            m_gridActive = 1;
+
+        zoomChanged(m_zoom);
+        updateGeometry();
+        update();
+    }
+}
+
+void PixelWidget::toggleGrid()
+{
+    if (++m_gridActive > 2)
+        m_gridActive = 0;
+    update();
+}
+
+void PixelWidget::setGridSize(int gridSize)
+{
+    if (m_gridActive && gridSize > 0) {
+        m_gridSize = gridSize;
+        startGridSizeVisibleTimer();
+        update();
+    }
+}
+
+void PixelWidget::copyToClipboard()
+{
+    QClipboard *cb = QApplication::clipboard();
+    cb->setImage(m_surface);
+}
+
+void PixelWidget::saveToFile()
+{
+    QString name = QFileDialog::getSaveFileName(this, QLatin1String("Save as image"), QString(), QLatin1String("*.png"));
+    if (!name.isEmpty()) {
+        if (!name.endsWith(QLatin1String(".png")))
+            name.append(QLatin1String(".png"));
+        m_surface.save(name, "PNG");
+    }
+}
+
+QColor PixelWidget::colorAtCurrentPosition() const
+{
+    return m_currentColor;
+}
+
+#include "pixelwidget.moc"
diff --git a/gui/pixelwidget.h b/gui/pixelwidget.h
new file mode 100644 (file)
index 0000000..0db7e01
--- /dev/null
@@ -0,0 +1,116 @@
+/**
+ * The source code is based on qpixeltool.h.
+ * Original license follows.
+ */
+
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PIXELWIDGET_H
+#define PIXELWIDGET_H
+
+#include <qwidget.h>
+#include <qpixmap.h>
+
+class PixelWidget : public QWidget
+{
+    Q_OBJECT
+public:
+    PixelWidget(QWidget *parent = 0);
+    ~PixelWidget();
+    
+    void setSurface(const QImage &image);
+
+    QColor colorAtCurrentPosition() const;
+
+signals:
+    void zoomChanged(int);
+    void mousePosition(int x, int y);
+    void gridGeometry(const QRect &rect);
+
+public:
+    void timerEvent(QTimerEvent *event);
+    void paintEvent(QPaintEvent *event);
+    void keyPressEvent(QKeyEvent *event);
+    void keyReleaseEvent(QKeyEvent *event);
+    void resizeEvent(QResizeEvent *event);
+    void mouseMoveEvent(QMouseEvent *event);
+    void mousePressEvent(QMouseEvent *event);
+    void mouseReleaseEvent(QMouseEvent *event);
+    void contextMenuEvent(QContextMenuEvent *event);
+
+    QSize sizeHint() const;
+
+public slots:
+    void setZoom(int zoom);
+    void setGridSize(int gridSize);
+    void toggleGrid();
+    void copyToClipboard();
+    void saveToFile();
+    void increaseGridSize() { setGridSize(m_gridSize + 1); }
+    void decreaseGridSize() { setGridSize(m_gridSize - 1); }
+    void increaseZoom() { setZoom(m_zoom + 1); }
+    void decreaseZoom() { setZoom(m_zoom - 1); }
+
+private:
+    void startGridSizeVisibleTimer();
+    double zoomValue() const { return m_zoom; }
+
+    bool m_displayGridSize;
+    bool m_mouseDown;
+
+    int m_gridActive;
+    int m_zoom;
+    int m_gridSize;
+
+    int m_displayZoomId;
+    int m_displayGridSizeId;
+
+    QPoint m_lastMousePos;
+    QPoint m_dragStart;
+    QPoint m_dragCurrent;
+    QImage m_surface;
+
+    QSize m_initialSize;
+    QColor m_currentColor;
+};
+
+#endif // PIXELWIDGET_H
index a595ba790a4b8604f303fda282ca41e22adadbd4..cd0a9d8e04730d7f76847c1c0881dcc7aaa9113b 100644 (file)
      <property name="widgetResizable">
       <bool>true</bool>
      </property>
+     <property name="alignment">
+      <set>Qt::AlignCenter</set>
+     </property>
      <widget class="QWidget" name="scrollAreaWidgetContents">
       <property name="geometry">
        <rect>
         <x>0</x>
         <y>0</y>
-        <width>811</width>
-        <height>615</height>
+        <width>805</width>
+        <height>539</height>
        </rect>
       </property>
-      <layout class="QVBoxLayout" name="verticalLayout_2">
-       <item>
-        <widget class="QLabel" name="imageLabel">
-         <property name="text">
-          <string/>
-         </property>
-         <property name="alignment">
-          <set>Qt::AlignCenter</set>
-         </property>
-        </widget>
-       </item>
-      </layout>
+      <layout class="QVBoxLayout" name="verticalLayout_2"/>
      </widget>
     </widget>
    </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_2">
+     <item>
+      <widget class="QLabel" name="label_2">
+       <property name="text">
+        <string>X:</string>
+       </property>
+       <property name="buddy">
+        <cstring>xSpinBox</cstring>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QSpinBox" name="xSpinBox">
+       <property name="frame">
+        <bool>false</bool>
+       </property>
+       <property name="readOnly">
+        <bool>true</bool>
+       </property>
+       <property name="buttonSymbols">
+        <enum>QAbstractSpinBox::NoButtons</enum>
+       </property>
+       <property name="keyboardTracking">
+        <bool>false</bool>
+       </property>
+       <property name="maximum">
+        <number>16000</number>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QLabel" name="label_3">
+       <property name="text">
+        <string>Y:</string>
+       </property>
+       <property name="buddy">
+        <cstring>xSpinBox</cstring>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QSpinBox" name="ySpinBox">
+       <property name="frame">
+        <bool>false</bool>
+       </property>
+       <property name="readOnly">
+        <bool>true</bool>
+       </property>
+       <property name="buttonSymbols">
+        <enum>QAbstractSpinBox::NoButtons</enum>
+       </property>
+       <property name="keyboardTracking">
+        <bool>false</bool>
+       </property>
+       <property name="maximum">
+        <number>16000</number>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QLabel" name="pixelLabel">
+       <property name="text">
+        <string>TextLabel</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QLabel" name="rectLabel">
+       <property name="text">
+        <string>TextLabel</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
+   </item>
    <item>
     <layout class="QHBoxLayout" name="horizontalLayout">
      <item>
       </widget>
      </item>
      <item>
-      <spacer name="horizontalSpacer">
-       <property name="orientation">
-        <enum>Qt::Horizontal</enum>
+      <widget class="QLabel" name="label">
+       <property name="text">
+        <string>Zoom:</string>
        </property>
-       <property name="sizeHint" stdset="0">
-        <size>
-         <width>40</width>
-         <height>20</height>
-        </size>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
        </property>
-      </spacer>
+      </widget>
+     </item>
+     <item>
+      <widget class="QSpinBox" name="zoomSpinBox">
+       <property name="specialValueText">
+        <string/>
+       </property>
+       <property name="suffix">
+        <string>x</string>
+       </property>
+       <property name="prefix">
+        <string/>
+       </property>
+       <property name="minimum">
+        <number>1</number>
+       </property>
+       <property name="maximum">
+        <number>15</number>
+       </property>
+       <property name="singleStep">
+        <number>1</number>
+       </property>
+       <property name="value">
+        <number>1</number>
+       </property>
+      </widget>
      </item>
     </layout>
    </item>