Changeset View
Changeset View
Standalone View
Standalone View
src/QuickEditor/QuickEditor.cpp
Show All 29 Lines | |||||
30 | const int QuickEditor::selectionBoxPaddingY = 4; | 30 | const int QuickEditor::selectionBoxPaddingY = 4; | ||
31 | const int QuickEditor::selectionBoxMarginY = 2; | 31 | const int QuickEditor::selectionBoxMarginY = 2; | ||
32 | 32 | | |||
33 | const int QuickEditor::bottomHelpBoxPaddingX = 12; | 33 | const int QuickEditor::bottomHelpBoxPaddingX = 12; | ||
34 | const int QuickEditor::bottomHelpBoxPaddingY = 8; | 34 | const int QuickEditor::bottomHelpBoxPaddingY = 8; | ||
35 | const int QuickEditor::bottomHelpBoxPairSpacing = 6; | 35 | const int QuickEditor::bottomHelpBoxPairSpacing = 6; | ||
36 | const int QuickEditor::bottomHelpBoxLineHeight = 24; | 36 | const int QuickEditor::bottomHelpBoxLineHeight = 24; | ||
37 | 37 | | |||
38 | const int QuickEditor::magZoom = 5; | ||||
39 | const int QuickEditor::magPixels = 16; | ||||
40 | const int QuickEditor::magOffset = 32; | ||||
41 | | ||||
38 | QuickEditor::QuickEditor(const QPixmap& pixmap, QObject* parent) : | 42 | QuickEditor::QuickEditor(const QPixmap& pixmap, QObject* parent) : | ||
39 | mMaskColour(QColor::fromRgbF(0, 0, 0, 0.15)), | 43 | mMaskColour(QColor::fromRgbF(0, 0, 0, 0.15)), | ||
40 | mStrokeColour(palette().highlight().color()), | 44 | mStrokeColour(palette().highlight().color()), | ||
45 | mCrossColour(QColor::fromRgbF(mStrokeColour.redF(), mStrokeColour.greenF(), mStrokeColour.blueF(), 0.7)), | ||||
41 | mLabelBackgroundColour(QColor::fromRgbF( | 46 | mLabelBackgroundColour(QColor::fromRgbF( | ||
42 | palette().light().color().redF(), | 47 | palette().light().color().redF(), | ||
43 | palette().light().color().greenF(), | 48 | palette().light().color().greenF(), | ||
44 | palette().light().color().blueF(), | 49 | palette().light().color().blueF(), | ||
45 | 0.85 | 50 | 0.85 | ||
46 | )), | 51 | )), | ||
47 | mLabelForegroundColour(palette().windowText().color()), | 52 | mLabelForegroundColour(palette().windowText().color()), | ||
48 | mMidHelpText(tr("Click and drag to draw a selection rectangle,\nor press Esc to quit")), | 53 | mMidHelpText(tr("Click and drag to draw a selection rectangle,\nor press Esc to quit")), | ||
49 | mMidHelpTextFont(font()), | 54 | mMidHelpTextFont(font()), | ||
50 | mBottomHelpText({ | 55 | mBottomHelpText({ | ||
51 | {QStaticText(tr("Enter, double-click:")), QStaticText(tr("Take screenshot"))}, | 56 | {QStaticText(tr("Enter, double-click:")), QStaticText(tr("Take screenshot"))}, | ||
52 | {QStaticText(tr("Shift:")), QStaticText(tr("Hold to toggle magnifier"))}, | 57 | {QStaticText(tr("Shift:")), QStaticText(tr("Hold to toggle magnifier"))}, | ||
53 | {QStaticText(tr("Right-click:")), QStaticText(tr("Reset selection"))}, | 58 | {QStaticText(tr("Right-click:")), QStaticText(tr("Reset selection"))}, | ||
54 | {QStaticText(tr("Esc:")), QStaticText(tr("Cancel"))}, | 59 | {QStaticText(tr("Esc:")), QStaticText(tr("Cancel"))}, | ||
55 | }), | 60 | }), | ||
56 | mBottomHelpTextFont(font()), | 61 | mBottomHelpTextFont(font()), | ||
57 | mBottomHelpGridLeftWidth(0), | 62 | mBottomHelpGridLeftWidth(0), | ||
58 | mMouseDragState(MouseState::None), | 63 | mMouseDragState(MouseState::None), | ||
59 | mPixmap(pixmap) | 64 | mPixmap(pixmap), | ||
65 | mMagnifierAllowed(false), | ||||
66 | mShowMagnifier(SpectacleConfig::instance()->showMagnifierChecked()), | ||||
67 | mToggleMagnifier(false) | ||||
60 | { | 68 | { | ||
61 | Q_UNUSED(parent); | 69 | Q_UNUSED(parent); | ||
62 | 70 | | |||
63 | SpectacleConfig *config = SpectacleConfig::instance(); | 71 | SpectacleConfig *config = SpectacleConfig::instance(); | ||
64 | if (config->useLightRegionMaskColour()) { | 72 | if (config->useLightRegionMaskColour()) { | ||
65 | mMaskColour = QColor(255, 255, 255, 100); | 73 | mMaskColour = QColor(255, 255, 255, 100); | ||
66 | } | 74 | } | ||
67 | 75 | | |||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Line(s) | 132 | case Qt::Key_Escape: | |||
126 | delete this; | 134 | delete this; | ||
127 | break; | 135 | break; | ||
128 | case Qt::Key_Return: | 136 | case Qt::Key_Return: | ||
129 | case Qt::Key_Enter: | 137 | case Qt::Key_Enter: | ||
130 | acceptSelection(); | 138 | acceptSelection(); | ||
131 | default: | 139 | default: | ||
132 | break; | 140 | break; | ||
133 | } | 141 | } | ||
142 | if (event->modifiers() & Qt::ShiftModifier) { | ||||
143 | mToggleMagnifier = true; | ||||
144 | update(); | ||||
145 | } | ||||
146 | event->accept(); | ||||
147 | } | ||||
148 | | ||||
149 | void QuickEditor::keyReleaseEvent(QKeyEvent* event) | ||||
150 | { | ||||
151 | if (mToggleMagnifier && !(event->modifiers() & Qt::ShiftModifier)) { | ||||
152 | mToggleMagnifier = false; | ||||
153 | update(); | ||||
154 | } | ||||
155 | event->accept(); | ||||
134 | } | 156 | } | ||
135 | 157 | | |||
136 | void QuickEditor::mousePressEvent(QMouseEvent* event) | 158 | void QuickEditor::mousePressEvent(QMouseEvent* event) | ||
137 | { | 159 | { | ||
138 | if (event->button() & Qt::LeftButton) { | 160 | if (event->button() & Qt::LeftButton) { | ||
139 | const QPointF& pos = event->screenPos(); | 161 | const QPointF& pos = event->screenPos(); | ||
162 | mMousePos = pos; | ||||
163 | mMagnifierAllowed = true; | ||||
140 | mMouseDragState = whereIsTheMouse(pos); | 164 | mMouseDragState = whereIsTheMouse(pos); | ||
141 | switch(mMouseDragState) { | 165 | switch(mMouseDragState) { | ||
142 | case MouseState::Outside: | 166 | case MouseState::Outside: | ||
143 | mStartPos = pos; | 167 | mStartPos = pos; | ||
144 | break; | 168 | break; | ||
145 | case MouseState::Inside: | 169 | case MouseState::Inside: | ||
146 | mStartPos = pos; | 170 | mStartPos = pos; | ||
171 | mMagnifierAllowed = false; | ||||
147 | mInitialTopLeft = mSelection.topLeft(); | 172 | mInitialTopLeft = mSelection.topLeft(); | ||
148 | setCursor(Qt::ClosedHandCursor); | 173 | setCursor(Qt::ClosedHandCursor); | ||
149 | break; | 174 | break; | ||
150 | case MouseState::Top: | 175 | case MouseState::Top: | ||
151 | case MouseState::Left: | 176 | case MouseState::Left: | ||
152 | case MouseState::TopLeft: | 177 | case MouseState::TopLeft: | ||
153 | mStartPos = mSelection.bottomRight(); | 178 | mStartPos = mSelection.bottomRight(); | ||
154 | break; | 179 | break; | ||
155 | case MouseState::Bottom: | 180 | case MouseState::Bottom: | ||
156 | case MouseState::Right: | 181 | case MouseState::Right: | ||
157 | case MouseState::BottomRight: | 182 | case MouseState::BottomRight: | ||
158 | mStartPos = mSelection.topLeft(); | 183 | mStartPos = mSelection.topLeft(); | ||
159 | break; | 184 | break; | ||
160 | case MouseState::TopRight: | 185 | case MouseState::TopRight: | ||
161 | mStartPos = mSelection.bottomLeft(); | 186 | mStartPos = mSelection.bottomLeft(); | ||
162 | break; | 187 | break; | ||
163 | case MouseState::BottomLeft: | 188 | case MouseState::BottomLeft: | ||
164 | mStartPos = mSelection.topRight(); | 189 | mStartPos = mSelection.topRight(); | ||
165 | default: | 190 | default: | ||
166 | break; | 191 | break; | ||
167 | } | 192 | } | ||
168 | } | 193 | } | ||
194 | if (mMagnifierAllowed) { | ||||
195 | update(); | ||||
196 | } | ||||
169 | event->accept(); | 197 | event->accept(); | ||
170 | } | 198 | } | ||
171 | 199 | | |||
172 | void QuickEditor::mouseMoveEvent(QMouseEvent* event) | 200 | void QuickEditor::mouseMoveEvent(QMouseEvent* event) | ||
173 | { | 201 | { | ||
174 | const QPointF& pos = event->screenPos(); | 202 | const QPointF& pos = event->screenPos(); | ||
203 | mMousePos = pos; | ||||
204 | mMagnifierAllowed = true; | ||||
175 | switch (mMouseDragState) { | 205 | switch (mMouseDragState) { | ||
176 | case MouseState::None: { | 206 | case MouseState::None: { | ||
177 | setMouseCursor(pos); | 207 | setMouseCursor(pos); | ||
208 | mMagnifierAllowed = false; | ||||
178 | break; | 209 | break; | ||
179 | } | 210 | } | ||
180 | case MouseState::TopLeft: | 211 | case MouseState::TopLeft: | ||
181 | case MouseState::TopRight: | 212 | case MouseState::TopRight: | ||
182 | case MouseState::BottomRight: | 213 | case MouseState::BottomRight: | ||
183 | case MouseState::BottomLeft: | 214 | case MouseState::BottomLeft: | ||
184 | case MouseState::Outside: { | 215 | case MouseState::Outside: { | ||
185 | mSelection.setRect( | 216 | mSelection.setRect( | ||
Show All 23 Lines | 238 | mSelection.setRect( | |||
209 | mSelection.y(), | 240 | mSelection.y(), | ||
210 | qAbs(pos.x() - mStartPos.x()) + dprI, | 241 | qAbs(pos.x() - mStartPos.x()) + dprI, | ||
211 | mSelection.height() | 242 | mSelection.height() | ||
212 | ); | 243 | ); | ||
213 | update(); | 244 | update(); | ||
214 | break; | 245 | break; | ||
215 | } | 246 | } | ||
216 | case MouseState::Inside: { | 247 | case MouseState::Inside: { | ||
248 | mMagnifierAllowed = false; | ||||
217 | // We use some math here to figure out if the diff with which we | 249 | // We use some math here to figure out if the diff with which we | ||
218 | // move the rectangle with moves it out of bounds, | 250 | // move the rectangle with moves it out of bounds, | ||
219 | // in which case we adjust the diff to not let that happen | 251 | // in which case we adjust the diff to not let that happen | ||
220 | 252 | | |||
221 | // new top left point of the rectangle | 253 | // new top left point of the rectangle | ||
222 | QPointF newTopLeft = pos - mStartPos + mInitialTopLeft; | 254 | QPointF newTopLeft = pos - mStartPos + mInitialTopLeft; | ||
223 | 255 | | |||
224 | // the max coordinates of the top left point | 256 | // the max coordinates of the top left point | ||
▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Line(s) | 326 | if (!mSelection.size().isEmpty() || mMouseDragState != MouseState::None) { | |||
304 | } | 336 | } | ||
305 | 337 | | |||
306 | drawSelectionSizeTooltip(painter); | 338 | drawSelectionSizeTooltip(painter); | ||
307 | if (mMouseDragState == MouseState::None) { // mouse is up | 339 | if (mMouseDragState == MouseState::None) { // mouse is up | ||
308 | if ((mSelection.width() > 20) && (mSelection.height() > 20)) { | 340 | if ((mSelection.width() > 20) && (mSelection.height() > 20)) { | ||
309 | drawDragHandles(painter); | 341 | drawDragHandles(painter); | ||
310 | } | 342 | } | ||
311 | 343 | | |||
344 | } else if (mMagnifierAllowed && (mShowMagnifier ^ mToggleMagnifier)) { | ||||
345 | drawMagnifier(painter); | ||||
312 | } | 346 | } | ||
313 | drawBottomHelpText(painter); | 347 | drawBottomHelpText(painter); | ||
314 | } else { | 348 | } else { | ||
315 | drawMidHelpText(painter); | 349 | drawMidHelpText(painter); | ||
316 | } | 350 | } | ||
317 | } | 351 | } | ||
318 | 352 | | |||
319 | inline void QuickEditor::layoutBottomHelpText() | 353 | inline void QuickEditor::layoutBottomHelpText() | ||
▲ Show 20 Lines • Show All 92 Lines • ▼ Show 20 Line(s) | 402 | { | |||
412 | // left-center handle | 446 | // left-center handle | ||
413 | path.moveTo(leftX, centerY); | 447 | path.moveTo(leftX, centerY); | ||
414 | path.arcTo(leftX - midHandleRadius, centerY - midHandleRadius, midHandleDiameter, midHandleDiameter, 90, -180); | 448 | path.arcTo(leftX - midHandleRadius, centerY - midHandleRadius, midHandleDiameter, midHandleDiameter, 90, -180); | ||
415 | 449 | | |||
416 | // draw the path | 450 | // draw the path | ||
417 | painter.fillPath(path, mStrokeColour); | 451 | painter.fillPath(path, mStrokeColour); | ||
418 | } | 452 | } | ||
419 | 453 | | |||
454 | inline void QuickEditor::drawMagnifier(QPainter &painter) | ||||
455 | { | ||||
456 | const int pixels = 2 * magPixels + 1; | ||||
457 | int magX = mMousePos.x() * devicePixelRatioF() - magPixels; | ||||
458 | int offsetX = 0; | ||||
459 | if (magX < 0) { | ||||
460 | offsetX = magX; | ||||
461 | magX = 0; | ||||
462 | } else { | ||||
463 | const int maxX = mPixmap.width() - pixels; | ||||
464 | if (magX > maxX) { | ||||
465 | offsetX = magX - maxX; | ||||
466 | magX = maxX; | ||||
467 | } | ||||
468 | } | ||||
469 | int magY = mMousePos.y() * devicePixelRatioF() - magPixels; | ||||
470 | int offsetY = 0; | ||||
471 | if (magY < 0) { | ||||
472 | offsetY = magY; | ||||
473 | magY = 0; | ||||
474 | } else { | ||||
475 | const int maxY = mPixmap.height() - pixels; | ||||
476 | if (magY > maxY) { | ||||
477 | offsetY = magY - maxY; | ||||
478 | magY = maxY; | ||||
479 | } | ||||
480 | } | ||||
481 | QRectF magniRect(magX, magY, pixels, pixels); | ||||
482 | | ||||
483 | qreal drawPosX = mMousePos.x() + magOffset + pixels * magZoom / 2; | ||||
484 | if (drawPosX > width() - pixels * magZoom / 2) { | ||||
485 | drawPosX = mMousePos.x() - magOffset - pixels * magZoom / 2; | ||||
486 | } | ||||
487 | qreal drawPosY = mMousePos.y() + magOffset + pixels * magZoom / 2; | ||||
488 | if (drawPosY > height() - pixels * magZoom / 2) { | ||||
489 | drawPosY = mMousePos.y() - magOffset - pixels * magZoom / 2; | ||||
490 | } | ||||
491 | QPointF drawPos(drawPosX, drawPosY); | ||||
492 | QRectF crossHairTop(drawPos.x() + magZoom * (offsetX - 0.5), drawPos.y() - magZoom * (magPixels + 0.5), magZoom, magZoom * (magPixels + offsetY)); | ||||
493 | QRectF crossHairRight(drawPos.x() + magZoom * (0.5 + offsetX), drawPos.y() + magZoom * (offsetY - 0.5), magZoom * (magPixels - offsetX), magZoom); | ||||
494 | QRectF crossHairBottom(drawPos.x() + magZoom * (offsetX - 0.5), drawPos.y() + magZoom * (0.5 + offsetY), magZoom, magZoom * (magPixels - offsetY)); | ||||
495 | QRectF crossHairLeft(drawPos.x() - magZoom * (magPixels + 0.5), drawPos.y() + magZoom * (offsetY - 0.5), magZoom * (magPixels + offsetX), magZoom); | ||||
496 | QRectF crossHairBorder(drawPos.x() - magZoom * (magPixels + 0.5) - 1, drawPos.y() - magZoom * (magPixels + 0.5) - 1, pixels * magZoom + 2, pixels * magZoom + 2); | ||||
497 | const auto frag = QPainter::PixmapFragment::create(drawPos, magniRect, magZoom, magZoom); | ||||
498 | | ||||
499 | painter.fillRect(crossHairBorder, mLabelForegroundColour); | ||||
500 | painter.drawPixmapFragments(&frag, 1, mPixmap, QPainter::OpaqueHint); | ||||
501 | painter.setCompositionMode(QPainter::CompositionMode_SourceOver); | ||||
502 | for (auto& rect : { crossHairTop, crossHairRight, crossHairBottom, crossHairLeft }) { | ||||
503 | painter.fillRect(rect, mCrossColour); | ||||
504 | } | ||||
505 | } | ||||
506 | | ||||
420 | inline void QuickEditor::drawMidHelpText(QPainter &painter) | 507 | inline void QuickEditor::drawMidHelpText(QPainter &painter) | ||
421 | { | 508 | { | ||
422 | painter.fillRect(geometry(), mMaskColour); | 509 | painter.fillRect(geometry(), mMaskColour); | ||
423 | painter.setFont(mMidHelpTextFont); | 510 | painter.setFont(mMidHelpTextFont); | ||
424 | QRect textSize = painter.boundingRect(QRect(), Qt::AlignCenter, mMidHelpText); | 511 | QRect textSize = painter.boundingRect(QRect(), Qt::AlignCenter, mMidHelpText); | ||
425 | QPoint pos((width() - textSize.width()) / 2, (height() - textSize.height()) / 2); | 512 | QPoint pos((width() - textSize.width()) / 2, (height() - textSize.height()) / 2); | ||
426 | 513 | | |||
427 | painter.setBrush(mLabelBackgroundColour); | 514 | painter.setBrush(mLabelBackgroundColour); | ||
▲ Show 20 Lines • Show All 110 Lines • Show Last 20 Lines |