1 /* 2 Scan Tailor - Interactive post-processing tool for scanned pages. 3 Copyright (C) 2007-2009 Joseph Artsimovich <joseph_a@mail.ru> 4 5 This program is free software: you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation, either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #ifndef PAGE_LAYOUT_IMAGEVIEW_H_ 20 #define PAGE_LAYOUT_IMAGEVIEW_H_ 21 22 #include <imageproc/BinaryImage.h> 23 #include <interaction/DraggableLineSegment.h> 24 #include <QMenu> 25 #include <QPoint> 26 #include <QPointF> 27 #include <QRectF> 28 #include <QSizeF> 29 #include <QTransform> 30 #include <unordered_map> 31 #include "Alignment.h" 32 #include "DragHandler.h" 33 #include "DraggableObject.h" 34 #include "Guide.h" 35 #include "ImageTransformation.h" 36 #include "ImageViewBase.h" 37 #include "InteractionHandler.h" 38 #include "ObjectDragHandler.h" 39 #include "PageId.h" 40 #include "ZoomHandler.h" 41 #include "intrusive_ptr.h" 42 43 class Margins; 44 45 namespace imageproc { 46 class GrayImage; 47 } 48 49 namespace page_layout { 50 class OptionsWidget; 51 class Settings; 52 53 class ImageView : public ImageViewBase, private InteractionHandler { 54 Q_OBJECT 55 public: 56 ImageView(const intrusive_ptr<Settings>& settings, 57 const PageId& page_id, 58 const QImage& image, 59 const QImage& downscaled_image, 60 const imageproc::GrayImage& gray_image, 61 const ImageTransformation& xform, 62 const QRectF& adapted_content_rect, 63 const OptionsWidget& opt_widget); 64 65 ~ImageView() override; 66 67 signals: 68 69 void invalidateThumbnail(const PageId& page_id); 70 71 void invalidateAllThumbnails(); 72 73 void marginsSetLocally(const Margins& margins_mm); 74 75 public slots: 76 77 void marginsSetExternally(const Margins& margins_mm); 78 79 void leftRightLinkToggled(bool linked); 80 81 void topBottomLinkToggled(bool linked); 82 83 void alignmentChanged(const Alignment& alignment); 84 85 void aggregateHardSizeChanged(); 86 87 protected: 88 void updatePhysSize() override; 89 90 private: 91 enum Edge { LEFT = 1, RIGHT = 2, TOP = 4, BOTTOM = 8 }; 92 93 enum FitMode { FIT, DONT_FIT }; 94 95 enum AggregateSizeChanged { AGGREGATE_SIZE_UNCHANGED, AGGREGATE_SIZE_CHANGED }; 96 97 struct StateBeforeResizing { 98 /** 99 * Transformation from virtual image coordinates to widget coordinates. 100 */ 101 QTransform virtToWidget; 102 103 /** 104 * Transformation from widget coordinates to virtual image coordinates. 105 */ 106 QTransform widgetToVirt; 107 108 /** 109 * m_middleRect in widget coordinates. 110 */ 111 QRectF middleWidgetRect; 112 113 /** 114 * Mouse pointer position in widget coordinates. 115 */ 116 QPointF mousePos; 117 118 /** 119 * The point in image that is to be centered on the screen, 120 * in pixel image coordinates. 121 */ 122 QPointF focalPoint; 123 }; 124 125 void onPaint(QPainter& painter, const InteractionState& interaction) override; 126 127 void onContextMenuEvent(QContextMenuEvent* event, InteractionState& interaction) override; 128 129 void onMouseDoubleClickEvent(QMouseEvent* event, InteractionState& interaction) override; 130 131 Proximity cornerProximity(int edge_mask, const QRectF* box, const QPointF& mouse_pos) const; 132 133 Proximity edgeProximity(int edge_mask, const QRectF* box, const QPointF& mouse_pos) const; 134 135 void dragInitiated(const QPointF& mouse_pos); 136 137 void innerRectDragContinuation(int edge_mask, const QPointF& mouse_pos); 138 139 void middleRectDragContinuation(int edge_mask, const QPointF& mouse_pos); 140 141 void dragFinished(); 142 143 void recalcBoxesAndFit(const Margins& margins_mm); 144 145 void updatePresentationTransform(FitMode fit_mode); 146 147 void forceNonNegativeHardMargins(QRectF& middle_rect) const; 148 149 Margins calcHardMarginsMM() const; 150 151 void recalcOuterRect(); 152 153 QSizeF origRectToSizeMM(const QRectF& rect) const; 154 155 AggregateSizeChanged commitHardMargins(const Margins& margins_mm); 156 157 void invalidateThumbnails(AggregateSizeChanged agg_size_changed); 158 159 void setupContextMenuInteraction(); 160 161 void setupGuides(); 162 163 void addHorizontalGuide(double y); 164 165 void addVerticalGuide(double x); 166 167 void removeAllGuides(); 168 169 void removeGuide(int index); 170 171 QTransform widgetToGuideCs() const; 172 173 QTransform guideToWidgetCs() const; 174 175 void syncGuidesSettings(); 176 177 void setupGuideInteraction(int index); 178 179 QLineF guidePosition(int index) const; 180 181 void guideMoveRequest(int index, QLineF line); 182 183 void guideDragFinished(); 184 185 QLineF widgetGuideLine(int index) const; 186 187 int getGuideUnderMouse(const QPointF& screenMousePos, const InteractionState& state) const; 188 189 void enableGuidesInteraction(bool state); 190 191 void forceInscribeGuides(); 192 193 Proximity rectProximity(const QRectF& box, const QPointF& mouse_pos) const; 194 195 void innerRectMoveRequest(const QPointF& mouse_pos, Qt::KeyboardModifiers mask = Qt::NoModifier); 196 197 void buildContentImage(const imageproc::GrayImage& gray_image, const ImageTransformation& xform); 198 199 void attachContentToNearestGuide(const QPointF& pos, Qt::KeyboardModifiers mask = Qt::NoModifier); 200 201 QRect findContentInArea(const QRect& area) const; 202 203 void enableMiddleRectInteraction(bool state); 204 205 bool isShowingMiddleRectEnabled() const; 206 207 208 DraggableObject m_innerCorners[4]; 209 ObjectDragHandler m_innerCornerHandlers[4]; 210 DraggableObject m_innerEdges[4]; 211 ObjectDragHandler m_innerEdgeHandlers[4]; 212 213 DraggableObject m_middleCorners[4]; 214 ObjectDragHandler m_middleCornerHandlers[4]; 215 DraggableObject m_middleEdges[4]; 216 ObjectDragHandler m_middleEdgeHandlers[4]; 217 218 DragHandler m_dragHandler; 219 ZoomHandler m_zoomHandler; 220 221 intrusive_ptr<Settings> m_settings; 222 223 const PageId m_pageId; 224 225 /** 226 * Transformation between the pixel image coordinates and millimeters, 227 * assuming that point (0, 0) in pixel coordinates corresponds to point 228 * (0, 0) in millimeter coordinates. 229 */ 230 const QTransform m_pixelsToMmXform; 231 const QTransform m_mmToPixelsXform; 232 233 const ImageTransformation m_xform; 234 235 /** 236 * Content box in virtual image coordinates. 237 */ 238 const QRectF m_innerRect; 239 240 /** 241 * \brief Content box + hard margins in virtual image coordinates. 242 * 243 * Hard margins are margins that will be there no matter what. 244 * Soft margins are those added to extend the page to match its 245 * size with other pages. 246 */ 247 QRectF m_middleRect; 248 249 /** 250 * \brief Content box + hard + soft margins in virtual image coordinates. 251 * 252 * Hard margins are margins that will be there no matter what. 253 * Soft margins are those added to extend the page to match its 254 * size with other pages. 255 */ 256 QRectF m_outerRect; 257 258 /** 259 * \brief Aggregate (max width + max height) hard page size. 260 * 261 * This one is for displaying purposes only. It changes during 262 * dragging, and it may differ from what 263 * m_settings->getAggregateHardSizeMM() would return. 264 * 265 * \see m_committedAggregateHardSizeMM 266 */ 267 QSizeF m_aggregateHardSizeMM; 268 269 /** 270 * \brief Aggregate (max width + max height) hard page size. 271 * 272 * This one is supposed to be the cached version of what 273 * m_settings->getAggregateHardSizeMM() would return. 274 * 275 * \see m_aggregateHardSizeMM 276 */ 277 QSizeF m_committedAggregateHardSizeMM; 278 279 Alignment m_alignment; 280 281 /** 282 * Some data saved at the beginning of a resizing operation. 283 */ 284 StateBeforeResizing m_beforeResizing; 285 286 bool m_leftRightLinked; 287 bool m_topBottomLinked; 288 289 /** Guides settings. */ 290 std::unordered_map<int, Guide> m_guides; 291 int m_guidesFreeIndex; 292 293 std::unordered_map<int, DraggableLineSegment> m_draggableGuides; 294 std::unordered_map<int, ObjectDragHandler> m_draggableGuideHandlers; 295 296 QMenu* m_contextMenu; 297 QAction* m_addHorizontalGuideAction; 298 QAction* m_addVerticalGuideAction; 299 QAction* m_removeAllGuidesAction; 300 QAction* m_removeGuideUnderMouseAction; 301 QAction* m_guideActionsSeparator; 302 QAction* m_showMiddleRectAction; 303 QPointF m_lastContextMenuPos; 304 int m_guideUnderMouse; 305 306 DraggableObject m_innerRectArea; 307 ObjectDragHandler m_innerRectAreaHandler; 308 309 Qt::KeyboardModifier m_innerRectVerticalDragModifier; 310 Qt::KeyboardModifier m_innerRectHorizontalDragModifier; 311 312 imageproc::BinaryImage m_contentImage; 313 QTransform m_originalToContentImage; 314 QTransform m_contentImageToOriginal; 315 316 const bool m_nullContentRect; 317 }; 318 } // namespace page_layout 319 #endif // ifndef PAGE_LAYOUT_IMAGEVIEW_H_ 320