Changeset View
Changeset View
Standalone View
Standalone View
src/QuickEditor/QuickEditor.cpp
Show All 27 Lines | |||||
28 | const qreal QuickEditor::cornerHandleRadius = 8.0; | 28 | const qreal QuickEditor::cornerHandleRadius = 8.0; | ||
29 | const qreal QuickEditor::midHandleRadius = 5.0; | 29 | const qreal QuickEditor::midHandleRadius = 5.0; | ||
30 | const int QuickEditor::selectionSizeThreshold = 100; | 30 | const int QuickEditor::selectionSizeThreshold = 100; | ||
31 | 31 | | |||
32 | const int QuickEditor::selectionBoxPaddingX = 5; | 32 | const int QuickEditor::selectionBoxPaddingX = 5; | ||
33 | const int QuickEditor::selectionBoxPaddingY = 4; | 33 | const int QuickEditor::selectionBoxPaddingY = 4; | ||
34 | const int QuickEditor::selectionBoxMarginY = 2; | 34 | const int QuickEditor::selectionBoxMarginY = 2; | ||
35 | 35 | | |||
36 | bool QuickEditor::bottomHelpTextPrepared = false; | | |||
37 | const int QuickEditor::bottomHelpBoxPaddingX = 12; | | |||
38 | const int QuickEditor::bottomHelpBoxPaddingY = 8; | | |||
39 | const int QuickEditor::bottomHelpBoxPairSpacing = 6; | | |||
40 | const int QuickEditor::bottomHelpBoxMarginBottom = 5; | | |||
41 | const int QuickEditor::midHelpTextFontSize = 12; | 36 | const int QuickEditor::midHelpTextFontSize = 12; | ||
42 | 37 | | |||
43 | const int QuickEditor::magnifierLargeStep = 15; | 38 | const int QuickEditor::magnifierLargeStep = 15; | ||
44 | 39 | | |||
45 | const int QuickEditor::magZoom = 5; | 40 | const int QuickEditor::magZoom = 5; | ||
46 | const int QuickEditor::magPixels = 16; | 41 | const int QuickEditor::magPixels = 16; | ||
47 | const int QuickEditor::magOffset = 32; | 42 | const int QuickEditor::magOffset = 32; | ||
48 | 43 | | |||
49 | QuickEditor::QuickEditor(const QPixmap& thePixmap, QWidget *parent) : | 44 | QuickEditor::QuickEditor(const QPixmap& thePixmap, const QScreen *activeScreen, QWidget *parent) : | ||
50 | QWidget(parent), | 45 | QWidget(parent), | ||
51 | mMaskColor(QColor::fromRgbF(0, 0, 0, 0.15)), | 46 | mMaskColor(QColor::fromRgbF(0, 0, 0, 0.15)), | ||
52 | mStrokeColor(palette().highlight().color()), | 47 | mStrokeColor(palette().highlight().color()), | ||
53 | mCrossColor(QColor::fromRgbF(mStrokeColor.redF(), mStrokeColor.greenF(), mStrokeColor.blueF(), 0.7)), | 48 | mCrossColor(QColor::fromRgbF(mStrokeColor.redF(), mStrokeColor.greenF(), mStrokeColor.blueF(), 0.7)), | ||
54 | mLabelBackgroundColor(QColor::fromRgbF( | 49 | mLabelBackgroundColor(QColor::fromRgbF( | ||
55 | palette().light().color().redF(), | 50 | palette().light().color().redF(), | ||
56 | palette().light().color().greenF(), | 51 | palette().light().color().greenF(), | ||
57 | palette().light().color().blueF(), | 52 | palette().light().color().blueF(), | ||
58 | 0.85 | 53 | 0.85 | ||
59 | )), | 54 | )), | ||
60 | mLabelForegroundColor(palette().windowText().color()), | 55 | mLabelForegroundColor(palette().windowText().color()), | ||
56 | mSelection(static_cast<QRectF>(QRect(activeScreen->geometry().topLeft(), QSize(0,0)))), | ||||
61 | mMidHelpText(i18n("Click and drag to draw a selection rectangle,\nor press Esc to quit")), | 57 | mMidHelpText(i18n("Click and drag to draw a selection rectangle,\nor press Esc to quit")), | ||
62 | mMidHelpTextFont(font()), | 58 | mMidHelpTextFont(font()), | ||
63 | mBottomHelpTextFont(font()), | | |||
64 | mBottomHelpGridLeftWidth(0), | | |||
65 | mMouseDragState(MouseState::None), | 59 | mMouseDragState(MouseState::None), | ||
66 | mPixmap(thePixmap), | 60 | mPixmap(thePixmap), | ||
67 | mMagnifierAllowed(false), | 61 | mMagnifierAllowed(false), | ||
68 | mShowMagnifier(SpectacleConfig::instance()->showMagnifierChecked()), | 62 | mShowMagnifier(SpectacleConfig::instance()->showMagnifierChecked()), | ||
69 | mToggleMagnifier(false), | 63 | mToggleMagnifier(false), | ||
70 | mReleaseToCapture(SpectacleConfig::instance()->useReleaseToCapture()), | | |||
71 | mRememberRegion(SpectacleConfig::instance()->alwaysRememberRegion() || SpectacleConfig::instance()->rememberLastRectangularRegion()), | 64 | mRememberRegion(SpectacleConfig::instance()->alwaysRememberRegion() || SpectacleConfig::instance()->rememberLastRectangularRegion()), | ||
72 | mDisableArrowKeys(false), | 65 | mDisableArrowKeys(false) | ||
73 | mPrimaryScreenGeo(QGuiApplication::primaryScreen()->geometry()), | | |||
74 | mbottomHelpLength(bottomHelpMaxLength) | | |||
75 | { | 66 | { | ||
76 | SpectacleConfig *config = SpectacleConfig::instance(); | 67 | SpectacleConfig *config = SpectacleConfig::instance(); | ||
77 | if (config->useLightRegionMaskColour()) { | 68 | if (config->useLightRegionMaskColour()) { | ||
78 | mMaskColor = QColor(255, 255, 255, 100); | 69 | mMaskColor = QColor(255, 255, 255, 100); | ||
79 | } | 70 | } | ||
80 | 71 | | |||
81 | setMouseTracking(true); | 72 | setMouseTracking(true); | ||
82 | setAttribute(Qt::WA_StaticContents); | 73 | setAttribute(Qt::WA_StaticContents); | ||
Show All 11 Lines | 82 | mSelection = QRectF( | |||
94 | cropRegion.width() * dprI, | 85 | cropRegion.width() * dprI, | ||
95 | cropRegion.height() * dprI | 86 | cropRegion.height() * dprI | ||
96 | ).intersected(geometry()); | 87 | ).intersected(geometry()); | ||
97 | } | 88 | } | ||
98 | setMouseCursor(QCursor::pos()); | 89 | setMouseCursor(QCursor::pos()); | ||
99 | } else { | 90 | } else { | ||
100 | setCursor(Qt::CrossCursor); | 91 | setCursor(Qt::CrossCursor); | ||
101 | } | 92 | } | ||
102 | 93 | mBottomHelpText = new BottomHelpTextWidget(mSelection.size().isEmpty(), this); | |||
103 | setBottomHelpText(); | | |||
104 | mMidHelpTextFont.setPointSize(midHelpTextFontSize); | 94 | mMidHelpTextFont.setPointSize(midHelpTextFontSize); | ||
105 | if (!bottomHelpTextPrepared) { | | |||
106 | bottomHelpTextPrepared = true; | | |||
107 | const auto prepare = [this](QStaticText& item) { | | |||
108 | item.prepare(QTransform(), mBottomHelpTextFont); | | |||
109 | item.setPerformanceHint(QStaticText::AggressiveCaching); | | |||
110 | }; | | |||
111 | for (auto& pair : mBottomHelpText) { | | |||
112 | prepare(pair.first); | | |||
113 | for (auto &item : pair.second) { | | |||
114 | prepare(item); | | |||
115 | } | | |||
116 | } | | |||
117 | } | | |||
118 | layoutBottomHelpText(); | | |||
119 | | ||||
120 | update(); | 95 | update(); | ||
121 | } | 96 | } | ||
122 | 97 | | |||
123 | void QuickEditor::acceptSelection() | 98 | void QuickEditor::acceptSelection() | ||
124 | { | 99 | { | ||
125 | if (!mSelection.isEmpty()) { | 100 | if (!mSelection.isEmpty()) { | ||
126 | const qreal dpr = devicePixelRatioF(); | 101 | const qreal dpr = devicePixelRatioF(); | ||
127 | QRect scaledCropRegion = QRect( | 102 | QRect scaledCropRegion = QRect( | ||
▲ Show 20 Lines • Show All 303 Lines • ▼ Show 20 Line(s) | |||||
431 | void QuickEditor::mouseReleaseEvent(QMouseEvent* event) | 406 | void QuickEditor::mouseReleaseEvent(QMouseEvent* event) | ||
432 | { | 407 | { | ||
433 | const auto button = event->button(); | 408 | const auto button = event->button(); | ||
434 | if (button == Qt::LeftButton) { | 409 | if (button == Qt::LeftButton) { | ||
435 | mDisableArrowKeys = false; | 410 | mDisableArrowKeys = false; | ||
436 | if(mMouseDragState == MouseState::Inside) { | 411 | if(mMouseDragState == MouseState::Inside) { | ||
437 | setCursor(Qt::OpenHandCursor); | 412 | setCursor(Qt::OpenHandCursor); | ||
438 | } | 413 | } | ||
439 | else if(mMouseDragState == MouseState::Outside && mReleaseToCapture) { | 414 | else if(mMouseDragState == MouseState::Outside && SpectacleConfig::instance()->useReleaseToCapture()) { | ||
440 | event->accept(); | 415 | event->accept(); | ||
441 | mMouseDragState = MouseState::None; | 416 | mMouseDragState = MouseState::None; | ||
442 | return acceptSelection(); | 417 | return acceptSelection(); | ||
443 | } | 418 | } | ||
444 | } else if (button == Qt::RightButton) { | 419 | } else if (button == Qt::RightButton) { | ||
445 | mSelection.setWidth(0); | 420 | mSelection.setWidth(0); | ||
446 | mSelection.setHeight(0); | 421 | mSelection.setHeight(0); | ||
447 | } | 422 | } | ||
Show All 37 Lines | 444 | if (!mSelection.size().isEmpty() || mMouseDragState != MouseState::None) { | |||
485 | if (mMouseDragState == MouseState::None) { // mouse is up | 460 | if (mMouseDragState == MouseState::None) { // mouse is up | ||
486 | if ((mSelection.width() > 20) && (mSelection.height() > 20)) { | 461 | if ((mSelection.width() > 20) && (mSelection.height() > 20)) { | ||
487 | drawDragHandles(painter); | 462 | drawDragHandles(painter); | ||
488 | } | 463 | } | ||
489 | 464 | | |||
490 | } else if (mMagnifierAllowed && (mShowMagnifier ^ mToggleMagnifier)) { | 465 | } else if (mMagnifierAllowed && (mShowMagnifier ^ mToggleMagnifier)) { | ||
491 | drawMagnifier(painter); | 466 | drawMagnifier(painter); | ||
492 | } | 467 | } | ||
493 | drawBottomHelpText(painter); | 468 | QRect activeScreenGeo = QGuiApplication::screenAt(mSelection.center().toPoint())->geometry(); | ||
469 | mBottomHelpText->move((activeScreenGeo.width() - mBottomHelpText->width())/2 + activeScreenGeo.x(), | ||||
470 | height() - mBottomHelpText->height()); | ||||
471 | //Only draw bottom help text, if possible (no selection rectangle in that area) | ||||
472 | if(!mSelection.intersects(mBottomHelpText->geometry())) { | ||||
473 | mBottomHelpText->setVisible(true); | ||||
494 | } else { | 474 | } else { | ||
495 | drawMidHelpText(painter); | 475 | mBottomHelpText->setVisible(false); | ||
496 | } | | |||
497 | } | | |||
498 | | ||||
499 | void QuickEditor::layoutBottomHelpText() | | |||
500 | { | | |||
501 | int maxRightWidth = 0; | | |||
502 | int contentWidth = 0; | | |||
503 | int contentHeight = 0; | | |||
504 | mBottomHelpGridLeftWidth = 0; | | |||
505 | for (int i = 0; i < mbottomHelpLength; i++) { | | |||
506 | const auto& item = mBottomHelpText[i]; | | |||
507 | const auto& left = item.first; | | |||
508 | const auto& right = item.second; | | |||
509 | const auto leftSize = left.size().toSize(); | | |||
510 | mBottomHelpGridLeftWidth = qMax(mBottomHelpGridLeftWidth, leftSize.width()); | | |||
511 | for (const auto& item : right) { | | |||
512 | const auto rightItemSize = item.size().toSize(); | | |||
513 | maxRightWidth = qMax(maxRightWidth, rightItemSize.width()); | | |||
514 | contentHeight += rightItemSize.height(); | | |||
515 | } | | |||
516 | contentWidth = qMax(contentWidth, mBottomHelpGridLeftWidth + maxRightWidth + bottomHelpBoxPairSpacing); | | |||
517 | contentHeight += (i != bottomHelpMaxLength ? bottomHelpBoxMarginBottom : 0); | | |||
518 | } | | |||
519 | mBottomHelpContentPos.setX((mPrimaryScreenGeo.width() - contentWidth) / 2 + mPrimaryScreenGeo.x()); | | |||
520 | mBottomHelpContentPos.setY(height() - contentHeight - 8); | | |||
521 | mBottomHelpGridLeftWidth += mBottomHelpContentPos.x(); | | |||
522 | mBottomHelpBorderBox.setRect( | | |||
523 | mBottomHelpContentPos.x() - bottomHelpBoxPaddingX, | | |||
524 | mBottomHelpContentPos.y() - bottomHelpBoxPaddingY, | | |||
525 | contentWidth + bottomHelpBoxPaddingX * 2, | | |||
526 | contentHeight + bottomHelpBoxPaddingY * 2 - 1 | | |||
527 | ); | | |||
528 | } | | |||
529 | | ||||
530 | void QuickEditor::setBottomHelpText() { | | |||
531 | if (mReleaseToCapture) { | | |||
532 | if(mRememberRegion && !mSelection.size().isEmpty()) { | | |||
533 | //Release to capture enabled and saved region available | | |||
534 | mBottomHelpText[0] = {QStaticText(i18nc("Mouse action", "Click and drag,")),{QStaticText(i18n(" "))}}; | | |||
535 | mBottomHelpText[1] = {QStaticText(i18nc("Keyboard/mouse action", "Enter, double-click:")), | | |||
536 | {QStaticText(i18n("Take screenshot"))}}; | | |||
537 | mBottomHelpText[2] = {QStaticText(i18nc("Keyboard action", "Shift:")), { | | |||
538 | QStaticText(i18nc("Shift key action first half", "Hold to toggle magnifier")), | | |||
539 | QStaticText(i18nc("Shift key action second half", "while dragging selection handles")) | | |||
540 | }}; | | |||
541 | mBottomHelpText[3] = {QStaticText(i18nc("Keyboard action", "Arrow keys:")), { | | |||
542 | QStaticText(i18nc("Shift key action first line", "Move selection rectangle")), | | |||
543 | QStaticText(i18nc("Shift key action second line", "Hold Alt to resize, Shift to fine‑tune")) | | |||
544 | }}; | | |||
545 | mBottomHelpText[4] = {QStaticText(i18nc("Mouse action", "Right-click:")), | | |||
546 | {QStaticText(i18n("Reset selection"))}}; | | |||
547 | mBottomHelpText[5] = {QStaticText(i18nc("Keyboard action", "Esc:")), {QStaticText(i18n("Cancel"))}}; | | |||
548 | | ||||
549 | } else { | | |||
550 | //Release to capture enabled and NO saved region available | | |||
551 | mbottomHelpLength = 4; | | |||
552 | mBottomHelpText[0] = {QStaticText(i18nc("Keyboard/mouse action", "Release left-click, Enter:")), | | |||
553 | {QStaticText(i18n("Take Screenshot"))}}; | | |||
554 | mBottomHelpText[1] = {QStaticText(i18nc("Keyboard action", "Shift:")), { | | |||
555 | QStaticText(i18nc("Shift key action first half", "Hold to toggle magnifier"))}}; | | |||
556 | mBottomHelpText[2] = {QStaticText(i18nc("Mouse action", "Right-click:")), | | |||
557 | {QStaticText(i18n("Reset selection"))}}; | | |||
558 | mBottomHelpText[3] = {QStaticText(i18nc("Keyboard action", "Esc:")), {QStaticText(i18n("Cancel"))}}; | | |||
559 | } | | |||
560 | }else { | | |||
561 | //Default text, Release to capture option disabled | | |||
562 | mbottomHelpLength = 5; | | |||
563 | mBottomHelpText[0] = {QStaticText(i18nc("Keyboard/mouse action", "Enter, double-click:")), | | |||
564 | {QStaticText(i18n("Take screenshot"))}}; | | |||
565 | mBottomHelpText[1] = {QStaticText(i18nc("Keyboard action", "Shift:")), { | | |||
566 | QStaticText(i18nc("Shift key action first half", "Hold to toggle magnifier")), | | |||
567 | QStaticText(i18nc("Shift key action second half", "while dragging selection handles")) | | |||
568 | }}; | | |||
569 | mBottomHelpText[2] = {QStaticText(i18nc("Keyboard action", "Arrow keys:")), { | | |||
570 | QStaticText(i18nc("Shift key action first line", "Move selection rectangle")), | | |||
571 | QStaticText(i18nc("Shift key action second line", "Hold Alt to resize, Shift to fine‑tune")) | | |||
572 | }}; | | |||
573 | mBottomHelpText[3] = {QStaticText(i18nc("Mouse action", "Right-click:")), | | |||
574 | {QStaticText(i18n("Reset selection"))}}; | | |||
575 | mBottomHelpText[4] = {QStaticText(i18nc("Keyboard action", "Esc:")), {QStaticText(i18n("Cancel"))}}; | | |||
576 | } | | |||
577 | } | | |||
578 | | ||||
579 | void QuickEditor::drawBottomHelpText(QPainter &painter) | | |||
580 | { | | |||
581 | if (mSelection.intersects(mBottomHelpBorderBox)) { | | |||
582 | return; | | |||
583 | } | | |||
584 | | ||||
585 | painter.setBrush(mLabelBackgroundColor); | | |||
586 | painter.setPen(mLabelForegroundColor); | | |||
587 | painter.setFont(mBottomHelpTextFont); | | |||
588 | painter.setRenderHint(QPainter::Antialiasing, false); | | |||
589 | painter.drawRect(mBottomHelpBorderBox); | | |||
590 | painter.setRenderHint(QPainter::Antialiasing, true); | | |||
591 | | ||||
592 | int topOffset = mBottomHelpContentPos.y(); | | |||
593 | for (int i = 0; i < mbottomHelpLength; i++) { | | |||
594 | const auto& item = mBottomHelpText[i]; | | |||
595 | const auto& left = item.first; | | |||
596 | const auto& right = item.second; | | |||
597 | const auto leftSize = left.size().toSize(); | | |||
598 | painter.drawStaticText(mBottomHelpGridLeftWidth - leftSize.width(), topOffset, left); | | |||
599 | for (const auto& item : right) { | | |||
600 | const auto rightItemSize = item.size().toSize(); | | |||
601 | painter.drawStaticText(mBottomHelpGridLeftWidth + bottomHelpBoxPairSpacing, topOffset, item); | | |||
602 | topOffset += rightItemSize.height(); | | |||
603 | } | | |||
604 | if (i != bottomHelpMaxLength) { | | |||
605 | topOffset += bottomHelpBoxMarginBottom; | | |||
606 | } | 476 | } | ||
477 | } else { | ||||
478 | mBottomHelpText->setVisible(false); | ||||
479 | drawMidHelpText(painter); | ||||
607 | } | 480 | } | ||
608 | } | 481 | } | ||
609 | 482 | | |||
610 | void QuickEditor::drawDragHandles(QPainter& painter) | 483 | void QuickEditor::drawDragHandles(QPainter& painter) | ||
611 | { | 484 | { | ||
612 | const qreal left = mSelection.x(); | 485 | const qreal left = mSelection.x(); | ||
613 | const qreal width = mSelection.width(); | 486 | const qreal width = mSelection.width(); | ||
614 | const qreal centerX = left + width / 2.0; | 487 | const qreal centerX = left + width / 2.0; | ||
▲ Show 20 Lines • Show All 107 Lines • ▼ Show 20 Line(s) | 546 | { | |||
722 | } | 595 | } | ||
723 | } | 596 | } | ||
724 | 597 | | |||
725 | void QuickEditor::drawMidHelpText(QPainter &painter) | 598 | void QuickEditor::drawMidHelpText(QPainter &painter) | ||
726 | { | 599 | { | ||
727 | painter.fillRect(geometry(), mMaskColor); | 600 | painter.fillRect(geometry(), mMaskColor); | ||
728 | painter.setFont(mMidHelpTextFont); | 601 | painter.setFont(mMidHelpTextFont); | ||
729 | QRect textSize = painter.boundingRect(QRect(), Qt::AlignCenter, mMidHelpText); | 602 | QRect textSize = painter.boundingRect(QRect(), Qt::AlignCenter, mMidHelpText); | ||
730 | QPoint pos((mPrimaryScreenGeo.width() - textSize.width()) / 2 + mPrimaryScreenGeo.x(), (height() - textSize.height()) / 2); | 603 | QRect activeScreenGeo = QGuiApplication::screenAt(mSelection.center().toPoint())->geometry(); | ||
604 | QPoint pos((activeScreenGeo.width() - textSize.width()) / 2 + activeScreenGeo.x(), (height() - textSize.height()) / 2); | ||||
731 | 605 | | |||
732 | painter.setBrush(mLabelBackgroundColor); | 606 | painter.setBrush(mLabelBackgroundColor); | ||
733 | QPen pen(mLabelForegroundColor); | 607 | QPen pen(mLabelForegroundColor); | ||
734 | pen.setWidth(2); | 608 | pen.setWidth(2); | ||
735 | painter.setPen(pen); | 609 | painter.setPen(pen); | ||
736 | painter.drawRoundedRect(QRect(pos.x() - 20, pos.y() - 20, textSize.width() + 40, textSize.height() + 40), 4, 4); | 610 | painter.drawRoundedRect(QRect(pos.x() - 20, pos.y() - 20, textSize.width() + 40, textSize.height() + 40), 4, 4); | ||
737 | 611 | | |||
738 | painter.setCompositionMode(QPainter::CompositionMode_Source); | 612 | painter.setCompositionMode(QPainter::CompositionMode_Source); | ||
▲ Show 20 Lines • Show All 109 Lines • Show Last 20 Lines |