Engauge Digitizer 2
Loading...
Searching...
No Matches
PdfFrameHandle.cpp
Go to the documentation of this file.
1/******************************************************************************************************
2 * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released *
3 * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file *
4 * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. *
5 ******************************************************************************************************/
6
7#include "PdfCropping.h"
8#include "PdfFrameHandle.h"
9#include <QBrush>
10#include <QGraphicsScene>
11#include <QGraphicsView>
12#include <qmath.h>
13#include <QStyleOptionGraphicsItem>
14
16
17PdfFrameHandle::PdfFrameHandle (QGraphicsScene &scene,
18 QGraphicsView &view,
19 const QPointF &pointReference,
20 int orientationFlags,
21 PdfCropping &pdfCropping,
22 int zValue) :
23 m_pdfCropping (pdfCropping),
24 m_orientationFlags (orientationFlags),
25 m_disableEventsWhileMovingAutomatically (false),
26 m_scene (scene),
27 m_view (view)
28{
29 const double SUBTLE_OPACITY = 0.2;
30
31 // Advantages of using ItemIgnoresTransformations:
32 // 1) handles do not get bigger or smaller depending on the size of the image
33 // 2) handles never get ugly when zoomed in
34 // 3) handles never get too tiny when zoomed out
35 // Disadvantages of using ItemIgnoresTransformation:
36 // 1) Resizing the preview window with ItemIgnoresTransformations moves the handles out of position
37 // 2) More conversions back and forth between untransformed and transformed coordinates. This was the deal breaker since
38 // the transformations were undocumented and ultimately too difficult
39 // The solution is to have constant-size handles WITHOUT ItemIgnoresTransformations. This means resizing the window
40 // also involves resizing the handles, but everything else is pretty easy
41 //
42 // ItemIgnoresTransformations flag must agree with the QGraphicsRectItem used for the frame box by PdfCropping
43 setFlags (QGraphicsItem::ItemIsMovable |
44 QGraphicsItem::ItemIsSelectable |
45 QGraphicsItem::ItemSendsScenePositionChanges);
46
47 // Fill with nice color for better visibility. Note that the pen is disabled by overriding the paint method
48 setBrush (QBrush (Qt::blue));
49 setVisible (true);
50 setZValue (zValue);
51 setOpacity (SUBTLE_OPACITY);
52 setPos (pointReference); // Point position is handled in scene/view coordinates
53
54 // Add to scene
55 scene.addItem (this);
56
57 QSize handleSize = m_pdfCropping.windowSize() / HANDLE_SIZE_AS_FRACTION_OF_WINDOW_SIZE;
58
59 // Adjust positions of handles that are not at the top left so handles are laid out symmetrically
60 QPointF pointPos = pointReference;
61 if ((orientationFlags & PdfCropping::PDF_CROPPING_LEFT) != 0) {
62 pointPos.setX (pointPos.x() - handleSize.width() / 2.0);
63 } else if ((orientationFlags & PdfCropping::PDF_CROPPING_RIGHT) != 0) {
64 pointPos.setX (pointPos.x() + handleSize.width() / 2.0);
65 }
66 if ((orientationFlags & PdfCropping::PDF_CROPPING_TOP) != 0) {
67 pointPos.setY (pointPos.y() - handleSize.height() / 2.0);
68 } else if ((orientationFlags & PdfCropping::PDF_CROPPING_BOTTOM) != 0) {
69 pointPos.setY (pointPos.y() + handleSize.height() / 2.0);
70 }
71
72 // Start with geometry. Since point positions are handled in scene/view coordinates, we have to convert
73 // to local coordinates for the rectangle
74 QPointF topLeftLocal = mapFromScene (pointPos);
75
76 setRect (QRectF (topLeftLocal,
77 handleSize));
78}
79
80QVariant PdfFrameHandle::itemChange (GraphicsItemChange change,
81 const QVariant &value)
82{
83 QVariant valueFiltered = value;
84
85 if (change == ItemPositionChange && scene()) {
86
87 QPointF sizeAsPointF (boundingRect().size().width(),
88 boundingRect().size().height());
89
90 // New position is in the value argument
91 QPointF newPos = valueFiltered.toPointF();
92 QPointF oldPos = pos ();
93
94 // This sequence is from http://www.qtcentre.org/threads/47248-How-to-efficiently-get-position-of-a-QGraphicsItem-in-view-coordinates
95 QRectF newRectItem (newPos,
96 QSize (qFloor (boundingRect().size().width()),
97 qFloor (boundingRect().size().height())));
98 QPolygonF newRectScene = mapToScene (newRectItem);
99 QPolygon newRectView = m_view.mapFromScene (newRectScene.boundingRect());
100
101 // Skip moving of this handle if it will go outside of the window
102 QRectF rectWindow = m_scene.sceneRect();
103 if (!rectWindow.contains (newRectView.boundingRect())) {
104
105 // Keep the item inside the scene rectangle
106 newPos.setX (qMin (rectWindow.right(), qMax (newPos.x(), rectWindow.left())));
107 newPos.setY (qMin (rectWindow.bottom(), qMax (newPos.y(), rectWindow.top())));
108
109 valueFiltered = (newPos);
110
111 }
112
113 // Skip moving of other handles, in response to the move of this handle, if event handling is (temporarily) off,
114 // to prevent an infinite loop
115 if (!m_disableEventsWhileMovingAutomatically) {
116
117 bool left = ((m_orientationFlags & PdfCropping::PDF_CROPPING_LEFT ) != 0);
118 bool right = ((m_orientationFlags & PdfCropping::PDF_CROPPING_RIGHT ) != 0);
119 bool top = ((m_orientationFlags & PdfCropping::PDF_CROPPING_TOP ) != 0);
120 bool bottom = ((m_orientationFlags & PdfCropping::PDF_CROPPING_BOTTOM) != 0);
121
122 if (left && top) {
123 m_pdfCropping.moveTL (newPos, oldPos);
124 } else if (right && top) {
125 m_pdfCropping.moveTR (newPos, oldPos);
126 } else if (right && bottom) {
127 m_pdfCropping.moveBR (newPos, oldPos);
128 } else if (left && bottom) {
129 m_pdfCropping.moveBL (newPos, oldPos);
130 }
131 }
132 }
133
134 return QGraphicsItem::itemChange(change, valueFiltered);
135}
136
137void PdfFrameHandle::paint (QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
138{
139 // Temporarily remove the selected option
140 QStyleOptionGraphicsItem scrubbed (*option);
141 scrubbed.state &= ~QStyle::State_Selected;
142 QGraphicsRectItem::paint (painter, &scrubbed, widget);
143}
144
146{
147 m_disableEventsWhileMovingAutomatically = disable;
148}
const double HANDLE_SIZE_AS_FRACTION_OF_WINDOW_SIZE
This class shows a frame around the selected portion of the pdf import preview window.
Definition PdfCropping.h:25
static const int PDF_CROPPING_LEFT
Bit flag when handle is aligned with left edge at reference point.
Definition PdfCropping.h:51
static const int PDF_CROPPING_BOTTOM
Bit flag when handle is aligned with bottom edge at reference point.
Definition PdfCropping.h:50
static const int PDF_CROPPING_TOP
Bit flag when handle is aligned with top edge at reference point.
Definition PdfCropping.h:53
static const int PDF_CROPPING_RIGHT
Bit flag when handle is aligned with right edge at reference point.
Definition PdfCropping.h:52
PdfFrameHandle(QGraphicsScene &scene, QGraphicsView &view, const QPointF &pointReference, int orientationFlags, PdfCropping &pdfCropping, int zValue)
Single constructor.
void setDisableEventsWhileMovingAutomatically(bool disable)
Temporarily disable event handling so code can move this object without triggering a cascade of event...
virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value)
Intercept the drags and process them, which is the whole point of handles.
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
Override the paint method so the dashed-border-when-selected can be removed.