Changeset View
Changeset View
Standalone View
Standalone View
src/QuickEditor/QuickEditor.cpp
Show All 19 Lines | |||||
20 | #include <KLocalizedString> | 20 | #include <KLocalizedString> | ||
21 | #include <KWayland/Client/plasmashell.h> | 21 | #include <KWayland/Client/plasmashell.h> | ||
22 | #include <KWayland/Client/surface.h> | 22 | #include <KWayland/Client/surface.h> | ||
23 | #include <QGuiApplication> | 23 | #include <QGuiApplication> | ||
24 | #include <QScreen> | 24 | #include <QScreen> | ||
25 | #include <QtCore/qmath.h> | 25 | #include <QtCore/qmath.h> | ||
26 | #include <QPainterPath> | 26 | #include <QPainterPath> | ||
27 | 27 | | |||
28 | #include <QFile> | ||||
28 | #include "QuickEditor.h" | 29 | #include "QuickEditor.h" | ||
29 | #include "settings.h" | 30 | #include "settings.h" | ||
31 | #include <KScreen/kscreen/output.h> | ||||
32 | #include <KScreen/kscreen/config.h> | ||||
30 | 33 | | |||
31 | const int QuickEditor::handleRadiusMouse = 9; | 34 | const int QuickEditor::handleRadiusMouse = 9; | ||
32 | const int QuickEditor::handleRadiusTouch = 12; | 35 | const int QuickEditor::handleRadiusTouch = 12; | ||
33 | const qreal QuickEditor::increaseDragAreaFactor = 2.0; | 36 | const qreal QuickEditor::increaseDragAreaFactor = 2.0; | ||
34 | const int QuickEditor::minSpacingBetweenHandles = 20; | 37 | const int QuickEditor::minSpacingBetweenHandles = 20; | ||
35 | const int QuickEditor::borderDragAreaSize = 10; | 38 | const int QuickEditor::borderDragAreaSize = 10; | ||
36 | 39 | | |||
37 | const int QuickEditor::selectionSizeThreshold = 100; | 40 | const int QuickEditor::selectionSizeThreshold = 100; | ||
Show All 10 Lines | |||||
48 | const int QuickEditor::midHelpTextFontSize = 12; | 51 | const int QuickEditor::midHelpTextFontSize = 12; | ||
49 | 52 | | |||
50 | const int QuickEditor::magnifierLargeStep = 15; | 53 | const int QuickEditor::magnifierLargeStep = 15; | ||
51 | 54 | | |||
52 | const int QuickEditor::magZoom = 5; | 55 | const int QuickEditor::magZoom = 5; | ||
53 | const int QuickEditor::magPixels = 16; | 56 | const int QuickEditor::magPixels = 16; | ||
54 | const int QuickEditor::magOffset = 32; | 57 | const int QuickEditor::magOffset = 32; | ||
55 | 58 | | |||
56 | QuickEditor::QuickEditor(const QPixmap &thePixmap, KWayland::Client::PlasmaShell *plasmashell, QWidget *parent) : | 59 | QuickEditor::QuickEditor(const QPixmap &thePixmap, KWayland::Client::PlasmaShell *plasmashell, KScreen::ConfigPtr screenConfiguration, QWidget *parent) : | ||
57 | QWidget(parent), | 60 | QWidget(parent), | ||
61 | mScreenConfiguration(screenConfiguration), | ||||
58 | mMaskColor(QColor::fromRgbF(0, 0, 0, 0.15)), | 62 | mMaskColor(QColor::fromRgbF(0, 0, 0, 0.15)), | ||
59 | mStrokeColor(palette().highlight().color()), | 63 | mStrokeColor(palette().highlight().color()), | ||
60 | mCrossColor(QColor::fromRgbF(mStrokeColor.redF(), mStrokeColor.greenF(), mStrokeColor.blueF(), 0.7)), | 64 | mCrossColor(QColor::fromRgbF(mStrokeColor.redF(), mStrokeColor.greenF(), mStrokeColor.blueF(), 0.7)), | ||
61 | mLabelBackgroundColor(QColor::fromRgbF( | 65 | mLabelBackgroundColor(QColor::fromRgbF( | ||
62 | palette().light().color().redF(), | 66 | palette().light().color().redF(), | ||
63 | palette().light().color().greenF(), | 67 | palette().light().color().greenF(), | ||
64 | palette().light().color().blueF(), | 68 | palette().light().color().blueF(), | ||
65 | 0.85 | 69 | 0.85 | ||
Show All 18 Lines | 87 | { | |||
84 | if (Settings::useLightMaskColour()) { | 88 | if (Settings::useLightMaskColour()) { | ||
85 | mMaskColor = QColor(255, 255, 255, 100); | 89 | mMaskColor = QColor(255, 255, 255, 100); | ||
86 | } | 90 | } | ||
87 | 91 | | |||
88 | setMouseTracking(true); | 92 | setMouseTracking(true); | ||
89 | setAttribute(Qt::WA_StaticContents); | 93 | setAttribute(Qt::WA_StaticContents); | ||
90 | setWindowFlags(Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint | Qt::Popup | Qt::WindowStaysOnTopHint); | 94 | setWindowFlags(Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint | Qt::Popup | Qt::WindowStaysOnTopHint); | ||
91 | 95 | | |||
92 | dprI = 1.0 / devicePixelRatioF(); | 96 | inWayland = plasmashell != nullptr; | ||
93 | setGeometry(0, 0, static_cast<int>(mPixmap.width() * dprI), static_cast<int>(mPixmap.height() * dprI)); | 97 | | ||
98 | devicePixelRatio = plasmashell ? 1.0 : devicePixelRatioF(); | ||||
99 | devicePixelRatioI = 1.0 / devicePixelRatio; | ||||
100 | | ||||
101 | setGeometry(0, 0, static_cast<int>(mPixmap.width() * devicePixelRatioI), static_cast<int>(mPixmap.height() * devicePixelRatioI)); | ||||
94 | // TODO This is a hack until a better interface is available | 102 | // TODO This is a hack until a better interface is available | ||
95 | if (plasmashell) { | 103 | if (plasmashell) { | ||
96 | using namespace KWayland::Client; | 104 | using namespace KWayland::Client; | ||
97 | winId(); | 105 | winId(); | ||
98 | auto surface = Surface::fromWindow(windowHandle()); | 106 | auto surface = Surface::fromWindow(windowHandle()); | ||
99 | if (surface) { | 107 | if (surface) { | ||
100 | PlasmaShellSurface *plasmashellSurface = plasmashell->createSurface(surface, this); | 108 | PlasmaShellSurface *plasmashellSurface = plasmashell->createSurface(surface, this); | ||
101 | plasmashellSurface->setRole(PlasmaShellSurface::Role::Panel); | 109 | plasmashellSurface->setRole(PlasmaShellSurface::Role::Panel); | ||
102 | plasmashellSurface->setPanelTakesFocus(true); | 110 | plasmashellSurface->setPanelTakesFocus(true); | ||
103 | plasmashellSurface->setPosition(geometry().topLeft()); | 111 | plasmashellSurface->setPosition(geometry().topLeft()); | ||
104 | } | 112 | } | ||
105 | } | 113 | } | ||
106 | if (Settings::rememberLastRectangularRegion() || Settings::alwaysRememberRegion()) { | 114 | if (Settings::rememberLastRectangularRegion() || Settings::alwaysRememberRegion()) { | ||
107 | auto savedRect = Settings::cropRegion(); | 115 | auto savedRect = Settings::cropRegion(); | ||
108 | QRect cropRegion = QRect(savedRect[0], savedRect[1], savedRect[2], savedRect[3]); | 116 | QRect cropRegion = QRect(savedRect[0], savedRect[1], savedRect[2], savedRect[3]); | ||
109 | if (!cropRegion.isEmpty()) { | 117 | if (!cropRegion.isEmpty()) { | ||
110 | mSelection = QRectF( | 118 | mSelection = QRectF( | ||
111 | cropRegion.x() * dprI, | 119 | cropRegion.x() * devicePixelRatioI, | ||
112 | cropRegion.y() * dprI, | 120 | cropRegion.y() * devicePixelRatioI, | ||
113 | cropRegion.width() * dprI, | 121 | cropRegion.width() * devicePixelRatioI, | ||
114 | cropRegion.height() * dprI | 122 | cropRegion.height() * devicePixelRatioI | ||
115 | ).intersected(geometry()); | 123 | ).intersected(geometry()); | ||
116 | } | 124 | } | ||
117 | setMouseCursor(QCursor::pos()); | 125 | setMouseCursor(QCursor::pos()); | ||
118 | } else { | 126 | } else { | ||
119 | setCursor(Qt::CrossCursor); | 127 | setCursor(Qt::CrossCursor); | ||
120 | } | 128 | } | ||
121 | 129 | | |||
122 | setBottomHelpText(); | 130 | setBottomHelpText(); | ||
123 | mMidHelpTextFont.setPointSize(midHelpTextFontSize); | 131 | mMidHelpTextFont.setPointSize(midHelpTextFontSize); | ||
124 | if (!bottomHelpTextPrepared) { | 132 | if (!bottomHelpTextPrepared) { | ||
125 | bottomHelpTextPrepared = true; | 133 | bottomHelpTextPrepared = true; | ||
126 | const auto prepare = [this](QStaticText& item) { | 134 | const auto prepare = [this](QStaticText& item) { | ||
127 | item.prepare(QTransform(), mBottomHelpTextFont); | 135 | item.prepare(QTransform(), mBottomHelpTextFont); | ||
128 | item.setPerformanceHint(QStaticText::AggressiveCaching); | 136 | item.setPerformanceHint(QStaticText::AggressiveCaching); | ||
129 | }; | 137 | }; | ||
130 | for (auto& pair : mBottomHelpText) { | 138 | for (auto& pair : mBottomHelpText) { | ||
131 | prepare(pair.first); | 139 | prepare(pair.first); | ||
132 | for (auto &item : pair.second) { | 140 | for (auto &item : pair.second) { | ||
133 | prepare(item); | 141 | prepare(item); | ||
134 | } | 142 | } | ||
135 | } | 143 | } | ||
136 | } | 144 | } | ||
137 | layoutBottomHelpText(); | 145 | layoutBottomHelpText(); | ||
138 | 146 | | |||
147 | if (screenConfiguration) { | ||||
148 | preparePaint(); | ||||
149 | } | ||||
150 | | ||||
139 | update(); | 151 | update(); | ||
140 | } | 152 | } | ||
141 | 153 | | |||
142 | void QuickEditor::acceptSelection() | 154 | void QuickEditor::acceptSelection() | ||
143 | { | 155 | { | ||
144 | if (!mSelection.isEmpty()) { | 156 | if (!mSelection.isEmpty()) { | ||
145 | const qreal dpr = devicePixelRatioF(); | | |||
146 | QRect scaledCropRegion = QRect( | 157 | QRect scaledCropRegion = QRect( | ||
147 | qRound(mSelection.x() * dpr), | 158 | qRound(mSelection.x() * devicePixelRatio), | ||
148 | qRound(mSelection.y() * dpr), | 159 | qRound(mSelection.y() * devicePixelRatio), | ||
149 | qRound(mSelection.width() * dpr), | 160 | qRound(mSelection.width() * devicePixelRatio), | ||
150 | qRound(mSelection.height() * dpr) | 161 | qRound(mSelection.height() * devicePixelRatio) | ||
151 | ); | 162 | ); | ||
152 | Settings::setCropRegion({scaledCropRegion.x(), scaledCropRegion.y(), scaledCropRegion.width(), scaledCropRegion.height()}); | 163 | Settings::setCropRegion({scaledCropRegion.x(), scaledCropRegion.y(), scaledCropRegion.width(), scaledCropRegion.height()}); | ||
153 | emit grabDone(mPixmap.copy(scaledCropRegion)); | 164 | emit grabDone(mPixmap.copy(scaledCropRegion)); | ||
154 | } | 165 | } | ||
155 | } | 166 | } | ||
156 | 167 | | |||
168 | void QuickEditor::onScreenConfigurationReceived(KScreen::ConfigPtr screenConfiguration) | ||||
169 | { | ||||
170 | mScreenConfiguration = screenConfiguration; | ||||
171 | | ||||
172 | preparePaint(); | ||||
173 | // repaint once we have screen information | ||||
174 | update(); | ||||
175 | } | ||||
176 | | ||||
157 | void QuickEditor::keyPressEvent(QKeyEvent* event) | 177 | void QuickEditor::keyPressEvent(QKeyEvent* event) | ||
158 | { | 178 | { | ||
159 | const auto modifiers = event->modifiers(); | 179 | const auto modifiers = event->modifiers(); | ||
160 | const bool shiftPressed = modifiers & Qt::ShiftModifier; | 180 | const bool shiftPressed = modifiers & Qt::ShiftModifier; | ||
161 | if (shiftPressed) { | 181 | if (shiftPressed) { | ||
162 | mToggleMagnifier = true; | 182 | mToggleMagnifier = true; | ||
163 | } | 183 | } | ||
164 | switch(event->key()) { | 184 | switch(event->key()) { | ||
165 | case Qt::Key_Escape: | 185 | case Qt::Key_Escape: | ||
166 | emit grabCancelled(); | 186 | emit grabCancelled(); | ||
167 | break; | 187 | break; | ||
168 | case Qt::Key_Return: | 188 | case Qt::Key_Return: | ||
169 | case Qt::Key_Enter: | 189 | case Qt::Key_Enter: | ||
170 | acceptSelection(); | 190 | acceptSelection(); | ||
171 | break; | 191 | break; | ||
172 | case Qt::Key_Up: { | 192 | case Qt::Key_Up: { | ||
173 | if(mDisableArrowKeys) { | 193 | if(mDisableArrowKeys) { | ||
174 | update(); | 194 | update(); | ||
175 | break; | 195 | break; | ||
176 | } | 196 | } | ||
177 | const qreal step = (shiftPressed ? 1 : magnifierLargeStep); | 197 | const qreal step = (shiftPressed ? 1 : magnifierLargeStep); | ||
178 | const int newPos = boundsUp(qRound(mSelection.top() * devicePixelRatioF() - step), false); | 198 | const int newPos = boundsUp(qRound(mSelection.top() * devicePixelRatio - step), false); | ||
179 | if (modifiers & Qt::AltModifier) { | 199 | if (modifiers & Qt::AltModifier) { | ||
180 | mSelection.setBottom(dprI * newPos + mSelection.height()); | 200 | mSelection.setBottom(devicePixelRatioI * newPos + mSelection.height()); | ||
181 | mSelection = mSelection.normalized(); | 201 | mSelection = mSelection.normalized(); | ||
182 | } else { | 202 | } else { | ||
183 | mSelection.moveTop(dprI * newPos); | 203 | mSelection.moveTop(devicePixelRatioI * newPos); | ||
184 | } | 204 | } | ||
185 | update(); | 205 | update(); | ||
186 | break; | 206 | break; | ||
187 | } | 207 | } | ||
188 | case Qt::Key_Right: { | 208 | case Qt::Key_Right: { | ||
189 | if(mDisableArrowKeys) { | 209 | if(mDisableArrowKeys) { | ||
190 | update(); | 210 | update(); | ||
191 | break; | 211 | break; | ||
192 | } | 212 | } | ||
193 | const qreal step = (shiftPressed ? 1 : magnifierLargeStep); | 213 | const qreal step = (shiftPressed ? 1 : magnifierLargeStep); | ||
194 | const int newPos = boundsRight(qRound(mSelection.left() * devicePixelRatioF() + step), false); | 214 | const int newPos = boundsRight(qRound(mSelection.left() * devicePixelRatio + step), false); | ||
195 | if (modifiers & Qt::AltModifier) { | 215 | if (modifiers & Qt::AltModifier) { | ||
196 | mSelection.setRight(dprI * newPos + mSelection.width()); | 216 | mSelection.setRight(devicePixelRatioI * newPos + mSelection.width()); | ||
197 | } else { | 217 | } else { | ||
198 | mSelection.moveLeft(dprI * newPos); | 218 | mSelection.moveLeft(devicePixelRatioI * newPos); | ||
199 | } | 219 | } | ||
200 | update(); | 220 | update(); | ||
201 | break; | 221 | break; | ||
202 | } | 222 | } | ||
203 | case Qt::Key_Down: { | 223 | case Qt::Key_Down: { | ||
204 | if(mDisableArrowKeys) { | 224 | if(mDisableArrowKeys) { | ||
205 | update(); | 225 | update(); | ||
206 | break; | 226 | break; | ||
207 | } | 227 | } | ||
208 | const qreal step = (shiftPressed ? 1 : magnifierLargeStep); | 228 | const qreal step = (shiftPressed ? 1 : magnifierLargeStep); | ||
209 | const int newPos = boundsDown(qRound(mSelection.top() * devicePixelRatioF() + step), false); | 229 | const int newPos = boundsDown(qRound(mSelection.top() * devicePixelRatio + step), false); | ||
210 | if (modifiers & Qt::AltModifier) { | 230 | if (modifiers & Qt::AltModifier) { | ||
211 | mSelection.setBottom(dprI * newPos + mSelection.height()); | 231 | mSelection.setBottom(devicePixelRatioI * newPos + mSelection.height()); | ||
212 | } else { | 232 | } else { | ||
213 | mSelection.moveTop(dprI * newPos); | 233 | mSelection.moveTop(devicePixelRatioI * newPos); | ||
214 | } | 234 | } | ||
215 | update(); | 235 | update(); | ||
216 | break; | 236 | break; | ||
217 | } | 237 | } | ||
218 | case Qt::Key_Left: { | 238 | case Qt::Key_Left: { | ||
219 | if(mDisableArrowKeys) { | 239 | if(mDisableArrowKeys) { | ||
220 | update(); | 240 | update(); | ||
221 | break; | 241 | break; | ||
222 | } | 242 | } | ||
223 | const qreal step = (shiftPressed ? 1 : magnifierLargeStep); | 243 | const qreal step = (shiftPressed ? 1 : magnifierLargeStep); | ||
224 | const int newPos = boundsLeft(qRound(mSelection.left() * devicePixelRatioF() - step), false); | 244 | const int newPos = boundsLeft(qRound(mSelection.left() * devicePixelRatio - step), false); | ||
225 | if (modifiers & Qt::AltModifier) { | 245 | if (modifiers & Qt::AltModifier) { | ||
226 | mSelection.setRight(dprI * newPos + mSelection.width()); | 246 | mSelection.setRight(devicePixelRatioI * newPos + mSelection.width()); | ||
227 | mSelection = mSelection.normalized(); | 247 | mSelection = mSelection.normalized(); | ||
228 | } else { | 248 | } else { | ||
229 | mSelection.moveLeft(dprI * newPos); | 249 | mSelection.moveLeft(devicePixelRatioI * newPos); | ||
230 | } | 250 | } | ||
231 | update(); | 251 | update(); | ||
232 | break; | 252 | break; | ||
233 | } | 253 | } | ||
234 | default: | 254 | default: | ||
235 | break; | 255 | break; | ||
236 | } | 256 | } | ||
237 | event->accept(); | 257 | event->accept(); | ||
238 | } | 258 | } | ||
239 | 259 | | |||
240 | void QuickEditor::keyReleaseEvent(QKeyEvent* event) | 260 | void QuickEditor::keyReleaseEvent(QKeyEvent* event) | ||
241 | { | 261 | { | ||
242 | if (mToggleMagnifier && !(event->modifiers() & Qt::ShiftModifier)) { | 262 | if (mToggleMagnifier && !(event->modifiers() & Qt::ShiftModifier)) { | ||
243 | mToggleMagnifier = false; | 263 | mToggleMagnifier = false; | ||
244 | update(); | 264 | update(); | ||
245 | } | 265 | } | ||
246 | event->accept(); | 266 | event->accept(); | ||
247 | } | 267 | } | ||
248 | 268 | | |||
249 | int QuickEditor::boundsLeft(int newTopLeftX, const bool mouse) | 269 | int QuickEditor::boundsLeft(int newTopLeftX, const bool mouse) | ||
250 | { | 270 | { | ||
251 | if (newTopLeftX < 0) { | 271 | if (newTopLeftX < 0) { | ||
252 | if (mouse) { | 272 | if (mouse) { | ||
253 | // tweak startPos to prevent rectangle from getting stuck | 273 | // tweak startPos to prevent rectangle from getting stuck | ||
254 | mStartPos.setX(mStartPos.x() + newTopLeftX * dprI); | 274 | mStartPos.setX(mStartPos.x() + newTopLeftX * devicePixelRatioI); | ||
255 | } | 275 | } | ||
256 | newTopLeftX = 0; | 276 | newTopLeftX = 0; | ||
257 | } | 277 | } | ||
258 | 278 | | |||
259 | return newTopLeftX; | 279 | return newTopLeftX; | ||
260 | } | 280 | } | ||
261 | 281 | | |||
262 | int QuickEditor::boundsRight(int newTopLeftX, const bool mouse) | 282 | int QuickEditor::boundsRight(int newTopLeftX, const bool mouse) | ||
263 | { | 283 | { | ||
264 | // the max X coordinate of the top left point | 284 | const int realMaxX = qRound((width() - mSelection.width()) * devicePixelRatio); | ||
265 | const int realMaxX = qRound((width() - mSelection.width()) * devicePixelRatioF()); | | |||
266 | const int xOffset = newTopLeftX - realMaxX; | 285 | const int xOffset = newTopLeftX - realMaxX; | ||
267 | if (xOffset > 0) { | 286 | if (xOffset > 0) { | ||
268 | if (mouse) { | 287 | if (mouse) { | ||
269 | mStartPos.setX(mStartPos.x() + xOffset * dprI); | 288 | mStartPos.setX(mStartPos.x() + xOffset * devicePixelRatioI); | ||
270 | } | 289 | } | ||
271 | newTopLeftX = realMaxX; | 290 | newTopLeftX = realMaxX; | ||
272 | } | 291 | } | ||
273 | 292 | | |||
274 | return newTopLeftX; | 293 | return newTopLeftX; | ||
275 | | ||||
276 | | ||||
277 | | ||||
278 | } | 294 | } | ||
279 | 295 | | |||
280 | int QuickEditor::boundsUp(int newTopLeftY, const bool mouse) | 296 | int QuickEditor::boundsUp(int newTopLeftY, const bool mouse) | ||
281 | { | 297 | { | ||
282 | if (newTopLeftY < 0) { | 298 | if (newTopLeftY < 0) { | ||
283 | if (mouse) { | 299 | if (mouse) { | ||
284 | mStartPos.setY(mStartPos.y() + newTopLeftY * dprI); | 300 | mStartPos.setY(mStartPos.y() + newTopLeftY * devicePixelRatioI); | ||
285 | } | 301 | } | ||
286 | newTopLeftY = 0; | 302 | newTopLeftY = 0; | ||
287 | } | 303 | } | ||
288 | 304 | | |||
289 | return newTopLeftY; | 305 | return newTopLeftY; | ||
290 | } | 306 | } | ||
291 | 307 | | |||
292 | int QuickEditor::boundsDown(int newTopLeftY, const bool mouse) | 308 | int QuickEditor::boundsDown(int newTopLeftY, const bool mouse) | ||
293 | { | 309 | { | ||
294 | // the max Y coordinate of the top left point | 310 | // the max Y coordinate of the top left point | ||
295 | const int realMaxY = qRound((height() - mSelection.height()) * devicePixelRatioF()); | 311 | const int realMaxY = qRound((height() - mSelection.height()) * devicePixelRatio); | ||
296 | const int yOffset = newTopLeftY - realMaxY; | 312 | const int yOffset = newTopLeftY - realMaxY; | ||
297 | if (yOffset > 0) { | 313 | if (yOffset > 0) { | ||
298 | if (mouse) { | 314 | if (mouse) { | ||
299 | mStartPos.setY(mStartPos.y() + yOffset * dprI); | 315 | mStartPos.setY(mStartPos.y() + yOffset * devicePixelRatioI); | ||
300 | } | 316 | } | ||
301 | newTopLeftY = realMaxY; | 317 | newTopLeftY = realMaxY; | ||
302 | } | 318 | } | ||
303 | 319 | | |||
304 | return newTopLeftY; | 320 | return newTopLeftY; | ||
305 | } | 321 | } | ||
306 | 322 | | |||
307 | void QuickEditor::mousePressEvent(QMouseEvent* event) | 323 | void QuickEditor::mousePressEvent(QMouseEvent* event) | ||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Line(s) | 380 | { | |||
375 | case MouseState::TopRight: | 391 | case MouseState::TopRight: | ||
376 | case MouseState::BottomRight: | 392 | case MouseState::BottomRight: | ||
377 | case MouseState::BottomLeft: { | 393 | case MouseState::BottomLeft: { | ||
378 | const bool afterX = pos.x() >= mStartPos.x(); | 394 | const bool afterX = pos.x() >= mStartPos.x(); | ||
379 | const bool afterY = pos.y() >= mStartPos.y(); | 395 | const bool afterY = pos.y() >= mStartPos.y(); | ||
380 | mSelection.setRect( | 396 | mSelection.setRect( | ||
381 | afterX ? mStartPos.x() : pos.x(), | 397 | afterX ? mStartPos.x() : pos.x(), | ||
382 | afterY ? mStartPos.y() : pos.y(), | 398 | afterY ? mStartPos.y() : pos.y(), | ||
383 | qAbs(pos.x() - mStartPos.x()) + (afterX ? dprI : 0), | 399 | qAbs(pos.x() - mStartPos.x()) + (afterX ? devicePixelRatioI : 0), | ||
384 | qAbs(pos.y() - mStartPos.y()) + (afterY ? dprI : 0) | 400 | qAbs(pos.y() - mStartPos.y()) + (afterY ? devicePixelRatioI : 0) | ||
385 | ); | 401 | ); | ||
386 | update(); | 402 | update(); | ||
387 | break; | 403 | break; | ||
388 | } | 404 | } | ||
389 | case MouseState::Outside: { | 405 | case MouseState::Outside: { | ||
390 | mSelection.setRect( | 406 | mSelection.setRect( | ||
391 | qMin(pos.x(), mStartPos.x()), | 407 | qMin(pos.x(), mStartPos.x()), | ||
392 | qMin(pos.y(), mStartPos.y()), | 408 | qMin(pos.y(), mStartPos.y()), | ||
393 | qAbs(pos.x() - mStartPos.x()) + dprI, | 409 | qAbs(pos.x() - mStartPos.x()) + devicePixelRatioI, | ||
394 | qAbs(pos.y() - mStartPos.y()) + dprI | 410 | qAbs(pos.y() - mStartPos.y()) + devicePixelRatioI | ||
395 | ); | 411 | ); | ||
396 | update(); | 412 | update(); | ||
397 | break; | 413 | break; | ||
398 | } | 414 | } | ||
399 | case MouseState::Top: | 415 | case MouseState::Top: | ||
400 | case MouseState::Bottom: { | 416 | case MouseState::Bottom: { | ||
401 | const bool afterY = pos.y() >= mStartPos.y(); | 417 | const bool afterY = pos.y() >= mStartPos.y(); | ||
402 | mSelection.setRect( | 418 | mSelection.setRect( | ||
403 | mSelection.x(), | 419 | mSelection.x(), | ||
404 | afterY ? mStartPos.y() : pos.y(), | 420 | afterY ? mStartPos.y() : pos.y(), | ||
405 | mSelection.width(), | 421 | mSelection.width(), | ||
406 | qAbs(pos.y() - mStartPos.y()) + (afterY ? dprI : 0) | 422 | qAbs(pos.y() - mStartPos.y()) + (afterY ? devicePixelRatioI : 0) | ||
407 | ); | 423 | ); | ||
408 | update(); | 424 | update(); | ||
409 | break; | 425 | break; | ||
410 | } | 426 | } | ||
411 | case MouseState::Right: | 427 | case MouseState::Right: | ||
412 | case MouseState::Left: { | 428 | case MouseState::Left: { | ||
413 | const bool afterX = pos.x() >= mStartPos.x(); | 429 | const bool afterX = pos.x() >= mStartPos.x(); | ||
414 | mSelection.setRect( | 430 | mSelection.setRect( | ||
415 | afterX ? mStartPos.x() : pos.x(), | 431 | afterX ? mStartPos.x() : pos.x(), | ||
416 | mSelection.y(), | 432 | mSelection.y(), | ||
417 | qAbs(pos.x() - mStartPos.x()) + (afterX ? dprI : 0), | 433 | qAbs(pos.x() - mStartPos.x()) + (afterX ? devicePixelRatioI : 0), | ||
418 | mSelection.height() | 434 | mSelection.height() | ||
419 | ); | 435 | ); | ||
420 | update(); | 436 | update(); | ||
421 | break; | 437 | break; | ||
422 | } | 438 | } | ||
423 | case MouseState::Inside: { | 439 | case MouseState::Inside: { | ||
424 | mMagnifierAllowed = false; | 440 | mMagnifierAllowed = false; | ||
425 | // We use some math here to figure out if the diff with which we | 441 | // We use some math here to figure out if the diff with which we | ||
426 | // move the rectangle with moves it out of bounds, | 442 | // move the rectangle with moves it out of bounds, | ||
427 | // in which case we adjust the diff to not let that happen | 443 | // in which case we adjust the diff to not let that happen | ||
428 | 444 | | |||
429 | const qreal dpr = devicePixelRatioF(); | | |||
430 | // new top left point of the rectangle | 445 | // new top left point of the rectangle | ||
431 | QPoint newTopLeft = ((pos - mStartPos + mInitialTopLeft) * dpr).toPoint(); | 446 | QPoint newTopLeft = ((pos - mStartPos + mInitialTopLeft) * devicePixelRatio).toPoint(); | ||
432 | 447 | | |||
433 | int newTopLeftX = boundsLeft(newTopLeft.x()); | 448 | auto newRect = QRect(newTopLeft, mSelection.size().toSize() * devicePixelRatio); | ||
434 | if (newTopLeftX != 0) { | | |||
435 | newTopLeftX = boundsRight(newTopLeftX); | | |||
436 | } | | |||
437 | 449 | | |||
438 | int newTopLeftY = boundsUp(newTopLeft.y()); | 450 | auto screenBoundingRect = mScreenRegion.boundingRect(); | ||
439 | if (newTopLeftY != 0) { | 451 | screenBoundingRect = QRect(screenBoundingRect.topLeft(), screenBoundingRect.size()); | ||
440 | newTopLeftY = boundsDown(newTopLeftY); | 452 | if (!screenBoundingRect.contains(newRect)) { | ||
453 | // Keep the item inside the scene screen region bounding rect. | ||||
454 | newTopLeft.setX(qMin(screenBoundingRect.right() - newRect.width(), qMax(newTopLeft.x(), screenBoundingRect.left()))); | ||||
455 | newTopLeft.setY(qMin(screenBoundingRect.bottom() - newRect.height(), qMax(newTopLeft.y(), screenBoundingRect.top()))); | ||||
441 | } | 456 | } | ||
442 | 457 | | |||
443 | const auto newTopLeftF = QPointF(newTopLeftX * dprI, newTopLeftY * dprI); | 458 | const auto newTopLeftF = QPointF(newTopLeft.x() * devicePixelRatioI, newTopLeft.y() * devicePixelRatioI); | ||
444 | | ||||
445 | mSelection.moveTo(newTopLeftF); | 459 | mSelection.moveTo(newTopLeftF); | ||
446 | update(); | 460 | update(); | ||
447 | break; | 461 | break; | ||
448 | } | 462 | } | ||
449 | default: | 463 | default: | ||
450 | break; | 464 | break; | ||
451 | } | 465 | } | ||
452 | 466 | | |||
453 | event->accept(); | 467 | event->accept(); | ||
454 | } | 468 | } | ||
455 | 469 | | |||
456 | void QuickEditor::mouseReleaseEvent(QMouseEvent* event) | 470 | void QuickEditor::mouseReleaseEvent(QMouseEvent* event) | ||
457 | { | 471 | { | ||
458 | const auto button = event->button(); | 472 | const auto button = event->button(); | ||
459 | if (button == Qt::LeftButton) { | 473 | if (button == Qt::LeftButton) { | ||
460 | mDisableArrowKeys = false; | 474 | mDisableArrowKeys = false; | ||
461 | if(mMouseDragState == MouseState::Inside) { | 475 | if (mMouseDragState == MouseState::Inside) { | ||
462 | setCursor(Qt::OpenHandCursor); | 476 | setCursor(Qt::OpenHandCursor); | ||
463 | } | 477 | } else if (mMouseDragState == MouseState::Outside && mReleaseToCapture) { | ||
464 | else if(mMouseDragState == MouseState::Outside && mReleaseToCapture) { | | |||
465 | event->accept(); | 478 | event->accept(); | ||
466 | mMouseDragState = MouseState::None; | 479 | mMouseDragState = MouseState::None; | ||
467 | return acceptSelection(); | 480 | return acceptSelection(); | ||
468 | } | 481 | } | ||
469 | } else if (button == Qt::RightButton) { | 482 | } else if (button == Qt::RightButton) { | ||
470 | mSelection.setWidth(0); | 483 | mSelection.setWidth(0); | ||
471 | mSelection.setHeight(0); | 484 | mSelection.setHeight(0); | ||
472 | } | 485 | } | ||
473 | event->accept(); | 486 | event->accept(); | ||
474 | mMouseDragState = MouseState::None; | 487 | mMouseDragState = MouseState::None; | ||
475 | update(); | 488 | update(); | ||
476 | } | 489 | } | ||
477 | 490 | | |||
478 | void QuickEditor::mouseDoubleClickEvent(QMouseEvent* event) | 491 | void QuickEditor::mouseDoubleClickEvent(QMouseEvent* event) | ||
479 | { | 492 | { | ||
480 | event->accept(); | 493 | event->accept(); | ||
481 | if (event->button() == Qt::LeftButton && mSelection.contains(event->pos())) { | 494 | if (event->button() == Qt::LeftButton && mSelection.contains(event->pos())) { | ||
482 | acceptSelection(); | 495 | acceptSelection(); | ||
483 | } | 496 | } | ||
484 | } | 497 | } | ||
485 | 498 | | |||
486 | void QuickEditor::paintEvent(QPaintEvent*) | 499 | QMap<ComparableQPoint, OuputInfo> QuickEditor::computeCoordinatesAfterScaling(QMap<ComparableQPoint, QPair<qreal, QSize>> outputsRect) | ||
500 | { | ||||
501 | QMap<ComparableQPoint, ComparableQPoint> translationMap; | ||||
meven: Would it make sense to add this to KScreen ? for instance a `static KScreen::`pixelGeometry()`… | |||||
502 | | ||||
503 | for (auto i = outputsRect.keyBegin(); i != outputsRect.keyEnd(); ++i) { | ||||
504 | translationMap.insert(*i, *i); | ||||
505 | } | ||||
506 | | ||||
507 | for (auto i = outputsRect.constBegin(); i != outputsRect.constEnd(); ++i) { | ||||
508 | const auto p = i.key(); | ||||
509 | const auto size = i.value().second; | ||||
510 | const auto dpr = i.value().first; | ||||
511 | if (!qFuzzyCompare(dpr, 1.0)) { | ||||
512 | // must update all coordinates of next rects | ||||
513 | int newWidth = size.width(); | ||||
514 | int newHeight = size.height(); | ||||
515 | | ||||
516 | int deltaX = newWidth - (size.width()); | ||||
517 | int deltaY = newHeight - (size.height()); | ||||
518 | | ||||
519 | // for the next size | ||||
520 | for (auto i2 = outputsRect.constFind(p); i2 != outputsRect.constEnd(); ++i2) { | ||||
521 | | ||||
522 | auto point = i2.key(); | ||||
523 | auto finalPoint = translationMap.value(point); | ||||
524 | | ||||
525 | if (point.x() >= newWidth + p.x() - deltaX) { | ||||
526 | finalPoint.setX(finalPoint.x() + deltaX); | ||||
527 | } | ||||
528 | if (point.y() >= newHeight + p.y() - deltaY) { | ||||
529 | finalPoint.setY(finalPoint.y() + deltaY); | ||||
530 | } | ||||
531 | // update final position point with the necessary deltas | ||||
532 | translationMap.insert(point, finalPoint); | ||||
533 | } | ||||
534 | } | ||||
535 | } | ||||
536 | | ||||
537 | // make the new values effective | ||||
538 | QMap<ComparableQPoint, OuputInfo> result; | ||||
539 | for (auto i = translationMap.keyBegin(); i != translationMap.keyEnd(); ++i) { | ||||
540 | const auto key = *i; | ||||
541 | const auto v = outputsRect.take(key); | ||||
542 | const qreal dpr = v.first; | ||||
543 | const QSize size = v.second; | ||||
544 | result.insert(translationMap.value(key), {dpr, size, key, QBrush()}); | ||||
545 | } | ||||
546 | return result; | ||||
547 | } | ||||
548 | | ||||
549 | | ||||
550 | void QuickEditor::preparePaint() | ||||
487 | { | 551 | { | ||
552 | mScreenRegion = QRegion(); | ||||
553 | | ||||
554 | QMap<ComparableQPoint, QPair<qreal, QSize>> outputsRect; | ||||
555 | | ||||
556 | for (const auto output : mScreenConfiguration->outputs()) { | ||||
557 | | ||||
558 | const ComparableQPoint originPos = output->pos(); | ||||
559 | const QSize logicalSize = output->logicalSize().toSize(); | ||||
560 | | ||||
561 | outputsRect.insert(ComparableQPoint(originPos), | ||||
562 | QPair<qreal, QSize>( | ||||
563 | inWayland ? output->scale(): devicePixelRatio, | ||||
564 | inWayland ? logicalSize * devicePixelRatio : logicalSize )); | ||||
565 | } | ||||
566 | | ||||
567 | mRects = QuickEditor::computeCoordinatesAfterScaling(outputsRect); | ||||
568 | | ||||
569 | for (auto i = mRects.begin(); i != mRects.end(); ++i) { | ||||
570 | | ||||
571 | const auto dpr = i.value().dpr; | ||||
572 | const auto dprI = 1.0 / dpr; | ||||
573 | | ||||
574 | const auto virtualScreenRect = QRect(i.value().originPos, i.value().newSize); | ||||
575 | mScreenRegion = mScreenRegion.united(virtualScreenRect); | ||||
576 | | ||||
577 | const auto intersect = QRect(i.key(), i.value().newSize); | ||||
578 | | ||||
579 | // must this out of paintEvent, using a pixmapCache/brush in OuputInfo | ||||
580 | auto pix = mPixmap.copy(intersect); | ||||
581 | | ||||
582 | QBrush brush(pix); | ||||
583 | brush.setTransform(QTransform().scale(dprI, dprI)); | ||||
584 | | ||||
585 | i.value().brush = brush; | ||||
586 | } | ||||
587 | } | ||||
588 | | ||||
589 | void QuickEditor::paintEvent(QPaintEvent *event) | ||||
590 | { | ||||
591 | Q_UNUSED(event) | ||||
592 | | ||||
593 | // Must do a paint Per screen in Wayland to respect the devicePixelRatio per screen | ||||
594 | if (mScreenConfiguration.isNull()) { | ||||
595 | return; | ||||
596 | } | ||||
597 | | ||||
488 | QPainter painter(this); | 598 | QPainter painter(this); | ||
489 | painter.setRenderHints(QPainter::Antialiasing); | 599 | painter.setRenderHints(QPainter::Antialiasing); | ||
490 | QBrush brush(mPixmap); | | |||
491 | brush.setTransform(QTransform().scale(dprI, dprI)); | | |||
492 | painter.setBackground(brush); | | |||
493 | painter.eraseRect(geometry()); | 600 | painter.eraseRect(geometry()); | ||
601 | | ||||
602 | for (auto i = mRects.begin(); i != mRects.end(); ++i) { | ||||
603 | const auto dpr = i.value().dpr; | ||||
604 | | ||||
605 | QRect virtualScreenRect = QRect(i.value().originPos / dpr, i.value().newSize * dpr); | ||||
606 | if (inWayland) { | ||||
607 | virtualScreenRect = QRect(virtualScreenRect.topLeft(), virtualScreenRect.size() / dpr); | ||||
608 | } | ||||
609 | | ||||
610 | painter.setBrushOrigin(i.value().originPos / dpr); | ||||
611 | painter.fillRect(virtualScreenRect, i.value().brush); | ||||
612 | } | ||||
613 | | ||||
494 | if (!mSelection.size().isEmpty() || mMouseDragState != MouseState::None) { | 614 | if (!mSelection.size().isEmpty() || mMouseDragState != MouseState::None) { | ||
495 | painter.fillRect(mSelection, mStrokeColor); | | |||
496 | const QRectF innerRect = mSelection.adjusted(1, 1, -1, -1); | 615 | const QRectF innerRect = mSelection.adjusted(1, 1, -1, -1); | ||
497 | if (innerRect.width() > 0 && innerRect.height() > 0) { | 616 | if (innerRect.width() > 0 && innerRect.height() > 0) { | ||
498 | painter.eraseRect(mSelection.adjusted(1, 1, -1, -1)); | 617 | painter.setPen(mStrokeColor); | ||
618 | painter.drawLine(mSelection.topLeft(), mSelection.topRight()); | ||||
619 | painter.drawLine(mSelection.bottomRight(), mSelection.topRight()); | ||||
620 | painter.drawLine(mSelection.bottomRight(), mSelection.bottomLeft()); | ||||
621 | painter.drawLine(mSelection.bottomLeft(), mSelection.topLeft()); | ||||
499 | } | 622 | } | ||
500 | 623 | | |||
501 | QRectF top(0, 0, width(), mSelection.top()); | 624 | QRectF top(0, 0, width(), mSelection.top()); | ||
502 | QRectF right(mSelection.right(), mSelection.top(), width() - mSelection.right(), mSelection.height()); | 625 | QRectF right(mSelection.right(), mSelection.top(), width() - mSelection.right(), mSelection.height()); | ||
503 | QRectF bottom(0, mSelection.bottom(), width(), height() - mSelection.bottom()); | 626 | QRectF bottom(0, mSelection.bottom(), width(), height() - mSelection.bottom()); | ||
504 | QRectF left(0, mSelection.top(), mSelection.left(), mSelection.height()); | 627 | QRectF left(0, mSelection.top(), mSelection.left(), mSelection.height()); | ||
505 | for (const auto& rect : { top, right, bottom, left }) { | 628 | for (const auto& rect : { top, right, bottom, left }) { | ||
506 | painter.fillRect(rect, mMaskColor); | 629 | painter.fillRect(rect, mMaskColor); | ||
Show All 28 Lines | 652 | for (int i = 0; i < mbottomHelpLength; i++) { | |||
535 | for (const auto& item : right) { | 658 | for (const auto& item : right) { | ||
536 | const auto rightItemSize = item.size().toSize(); | 659 | const auto rightItemSize = item.size().toSize(); | ||
537 | maxRightWidth = qMax(maxRightWidth, rightItemSize.width()); | 660 | maxRightWidth = qMax(maxRightWidth, rightItemSize.width()); | ||
538 | contentHeight += rightItemSize.height(); | 661 | contentHeight += rightItemSize.height(); | ||
539 | } | 662 | } | ||
540 | contentWidth = qMax(contentWidth, mBottomHelpGridLeftWidth + maxRightWidth + bottomHelpBoxPairSpacing); | 663 | contentWidth = qMax(contentWidth, mBottomHelpGridLeftWidth + maxRightWidth + bottomHelpBoxPairSpacing); | ||
541 | contentHeight += (i != bottomHelpMaxLength ? bottomHelpBoxMarginBottom : 0); | 664 | contentHeight += (i != bottomHelpMaxLength ? bottomHelpBoxMarginBottom : 0); | ||
542 | } | 665 | } | ||
543 | mBottomHelpContentPos.setX((mPrimaryScreenGeo.width() - contentWidth) / 2 + mPrimaryScreenGeo.x()); | 666 | mBottomHelpContentPos.setX((mPrimaryScreenGeo.width() - contentWidth) / 2 + mPrimaryScreenGeo.x() / devicePixelRatio); | ||
544 | mBottomHelpContentPos.setY(height() - contentHeight - 8); | 667 | mBottomHelpContentPos.setY((mPrimaryScreenGeo.height() + mPrimaryScreenGeo.y() / devicePixelRatio) - contentHeight - 8 ); | ||
545 | mBottomHelpGridLeftWidth += mBottomHelpContentPos.x(); | 668 | mBottomHelpGridLeftWidth += mBottomHelpContentPos.x(); | ||
546 | mBottomHelpBorderBox.setRect( | 669 | mBottomHelpBorderBox.setRect( | ||
547 | mBottomHelpContentPos.x() - bottomHelpBoxPaddingX, | 670 | mBottomHelpContentPos.x() - bottomHelpBoxPaddingX, | ||
548 | mBottomHelpContentPos.y() - bottomHelpBoxPaddingY, | 671 | mBottomHelpContentPos.y() - bottomHelpBoxPaddingY, | ||
549 | contentWidth + bottomHelpBoxPaddingX * 2, | 672 | contentWidth + bottomHelpBoxPaddingX * 2, | ||
550 | contentHeight + bottomHelpBoxPaddingY * 2 - 1 | 673 | contentHeight + bottomHelpBoxPaddingY * 2 - 1 | ||
551 | ); | 674 | ); | ||
552 | } | 675 | } | ||
▲ Show 20 Lines • Show All 113 Lines • ▼ Show 20 Line(s) | 727 | { | |||
666 | 789 | | |||
667 | // draw the path | 790 | // draw the path | ||
668 | painter.fillPath(path, mStrokeColor); | 791 | painter.fillPath(path, mStrokeColor); | ||
669 | } | 792 | } | ||
670 | 793 | | |||
671 | void QuickEditor::drawMagnifier(QPainter &painter) | 794 | void QuickEditor::drawMagnifier(QPainter &painter) | ||
672 | { | 795 | { | ||
673 | const int pixels = 2 * magPixels + 1; | 796 | const int pixels = 2 * magPixels + 1; | ||
674 | int magX = static_cast<int>(mMousePos.x() * devicePixelRatioF() - magPixels); | 797 | int magX = static_cast<int>(mMousePos.x() * devicePixelRatio - magPixels); | ||
675 | int offsetX = 0; | 798 | int offsetX = 0; | ||
676 | if (magX < 0) { | 799 | if (magX < 0) { | ||
677 | offsetX = magX; | 800 | offsetX = magX; | ||
678 | magX = 0; | 801 | magX = 0; | ||
679 | } else { | 802 | } else { | ||
680 | const int maxX = mPixmap.width() - pixels; | 803 | const int maxX = mPixmap.width() - pixels; | ||
681 | if (magX > maxX) { | 804 | if (magX > maxX) { | ||
682 | offsetX = magX - maxX; | 805 | offsetX = magX - maxX; | ||
683 | magX = maxX; | 806 | magX = maxX; | ||
684 | } | 807 | } | ||
685 | } | 808 | } | ||
686 | int magY = static_cast<int>(mMousePos.y() * devicePixelRatioF() - magPixels); | 809 | int magY = static_cast<int>(mMousePos.y() * devicePixelRatio - magPixels); | ||
687 | int offsetY = 0; | 810 | int offsetY = 0; | ||
688 | if (magY < 0) { | 811 | if (magY < 0) { | ||
689 | offsetY = magY; | 812 | offsetY = magY; | ||
690 | magY = 0; | 813 | magY = 0; | ||
691 | } else { | 814 | } else { | ||
692 | const int maxY = mPixmap.height() - pixels; | 815 | const int maxY = mPixmap.height() - pixels; | ||
693 | if (magY > maxY) { | 816 | if (magY > maxY) { | ||
694 | offsetY = magY - maxY; | 817 | offsetY = magY - maxY; | ||
Show All 26 Lines | |||||
721 | } | 844 | } | ||
722 | } | 845 | } | ||
723 | 846 | | |||
724 | void QuickEditor::drawMidHelpText(QPainter &painter) | 847 | void QuickEditor::drawMidHelpText(QPainter &painter) | ||
725 | { | 848 | { | ||
726 | painter.fillRect(geometry(), mMaskColor); | 849 | painter.fillRect(geometry(), mMaskColor); | ||
727 | painter.setFont(mMidHelpTextFont); | 850 | painter.setFont(mMidHelpTextFont); | ||
728 | QRect textSize = painter.boundingRect(QRect(), Qt::AlignCenter, mMidHelpText); | 851 | QRect textSize = painter.boundingRect(QRect(), Qt::AlignCenter, mMidHelpText); | ||
729 | QPoint pos((mPrimaryScreenGeo.width() - textSize.width()) / 2 + mPrimaryScreenGeo.x(), (height() - textSize.height()) / 2); | 852 | QPoint pos((mPrimaryScreenGeo.width() - textSize.width()) / 2 + mPrimaryScreenGeo.x(), | ||
853 | (mPrimaryScreenGeo.height() - textSize.height()) / 2 + mPrimaryScreenGeo.y()); | ||||
730 | 854 | | |||
731 | painter.setBrush(mLabelBackgroundColor); | 855 | painter.setBrush(mLabelBackgroundColor); | ||
732 | QPen pen(mLabelForegroundColor); | 856 | QPen pen(mLabelForegroundColor); | ||
733 | pen.setWidth(2); | 857 | pen.setWidth(2); | ||
734 | painter.setPen(pen); | 858 | painter.setPen(pen); | ||
735 | painter.drawRoundedRect(QRect(pos.x() - 20, pos.y() - 20, textSize.width() + 40, textSize.height() + 40), 4, 4); | 859 | painter.drawRoundedRect(QRect(pos.x() - 20, pos.y() - 20, textSize.width() + 40, textSize.height() + 40), 4, 4); | ||
736 | 860 | | |||
737 | painter.setCompositionMode(QPainter::CompositionMode_Source); | 861 | painter.setCompositionMode(QPainter::CompositionMode_Source); | ||
738 | painter.drawText(QRect(pos, textSize.size()), Qt::AlignCenter, mMidHelpText); | 862 | painter.drawText(QRect(pos, textSize.size()), Qt::AlignCenter, mMidHelpText); | ||
739 | } | 863 | } | ||
740 | 864 | | |||
741 | void QuickEditor::drawSelectionSizeTooltip(QPainter &painter, bool dragHandlesVisible) | 865 | void QuickEditor::drawSelectionSizeTooltip(QPainter &painter, bool dragHandlesVisible) | ||
742 | { | 866 | { | ||
743 | // Set the selection size and finds the most appropriate position: | 867 | // Set the selection size and finds the most appropriate position: | ||
744 | // - vertically centered inside the selection if the box is not covering the a large part of selection | 868 | // - vertically centered inside the selection if the box is not covering the a large part of selection | ||
745 | // - on top of the selection if the selection x position fits the box height plus some margin | 869 | // - on top of the selection if the selection x position fits the box height plus some margin | ||
746 | // - at the bottom otherwise | 870 | // - at the bottom otherwise | ||
747 | const qreal dpr = devicePixelRatioF(); | 871 | QString selectionSizeText = ki18n("%1×%2").subs(qRound(mSelection.width() * devicePixelRatio)).subs(qRound(mSelection.height() * devicePixelRatio)).toString(); | ||
748 | QString selectionSizeText = ki18n("%1×%2").subs(qRound(mSelection.width() * dpr)).subs(qRound(mSelection.height() * dpr)).toString(); | | |||
749 | const QRect selectionSizeTextRect = painter.boundingRect(QRect(), 0, selectionSizeText); | 872 | const QRect selectionSizeTextRect = painter.boundingRect(QRect(), 0, selectionSizeText); | ||
750 | 873 | | |||
751 | const int selectionBoxWidth = selectionSizeTextRect.width() + selectionBoxPaddingX * 2; | 874 | const int selectionBoxWidth = selectionSizeTextRect.width() + selectionBoxPaddingX * 2; | ||
752 | const int selectionBoxHeight = selectionSizeTextRect.height() + selectionBoxPaddingY * 2; | 875 | const int selectionBoxHeight = selectionSizeTextRect.height() + selectionBoxPaddingY * 2; | ||
753 | const int selectionBoxX = qBound( | 876 | const int selectionBoxX = qBound( | ||
754 | 0, | 877 | 0, | ||
755 | static_cast<int>(mSelection.x()) + (static_cast<int>(mSelection.width()) - selectionSizeTextRect.width()) / 2 - selectionBoxPaddingX, | 878 | static_cast<int>(mSelection.x()) + (static_cast<int>(mSelection.width()) - selectionSizeTextRect.width()) / 2 - selectionBoxPaddingX, | ||
756 | width() - selectionBoxWidth | 879 | width() - selectionBoxWidth | ||
▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Line(s) | 958 | auto inRange = [](qreal low, qreal high, qreal value) { | |||
836 | return value >= low && value <= high; | 959 | return value >= low && value <= high; | ||
837 | }; | 960 | }; | ||
838 | 961 | | |||
839 | auto withinThreshold = [](qreal offset, qreal threshold) { | 962 | auto withinThreshold = [](qreal offset, qreal threshold) { | ||
840 | return qFabs(offset) <= threshold; | 963 | return qFabs(offset) <= threshold; | ||
841 | }; | 964 | }; | ||
842 | 965 | | |||
843 | //Rectangle can be resized when border is dragged, if it's big enough | 966 | //Rectangle can be resized when border is dragged, if it's big enough | ||
844 | if(mSelection.width() >= 100 && mSelection.height() >= 100) { | 967 | if (mSelection.width() >= 100 && mSelection.height() >= 100) { | ||
845 | if(inRange(mSelection.x(), mSelection.x() + mSelection.width(), pos.x())) { | 968 | if (inRange(mSelection.x(), mSelection.x() + mSelection.width(), pos.x())) { | ||
846 | if(withinThreshold(pos.y() - mSelection.y(), borderDragAreaSize)) { | 969 | if (withinThreshold(pos.y() - mSelection.y(), borderDragAreaSize)) { | ||
847 | return MouseState::Top; | 970 | return MouseState::Top; | ||
848 | } else if(withinThreshold(pos.y() - mSelection.y() - mSelection.height(), borderDragAreaSize)) { | 971 | } else if (withinThreshold(pos.y() - mSelection.y() - mSelection.height(), borderDragAreaSize)) { | ||
849 | return MouseState::Bottom; | 972 | return MouseState::Bottom; | ||
850 | } | 973 | } | ||
851 | } | 974 | } | ||
852 | if(inRange(mSelection.y(), mSelection.y() + mSelection.height(), pos.y())) { | 975 | if (inRange(mSelection.y(), mSelection.y() + mSelection.height(), pos.y())) { | ||
853 | if(withinThreshold(pos.x() - mSelection.x(), borderDragAreaSize)) { | 976 | if (withinThreshold(pos.x() - mSelection.x(), borderDragAreaSize)) { | ||
854 | return MouseState::Left; | 977 | return MouseState::Left; | ||
855 | } else if(withinThreshold(pos.x() - mSelection.x() - mSelection.width(), borderDragAreaSize)) { | 978 | } else if (withinThreshold(pos.x() - mSelection.x() - mSelection.width(), borderDragAreaSize)) { | ||
856 | return MouseState::Right; | 979 | return MouseState::Right; | ||
857 | } | 980 | } | ||
858 | } | 981 | } | ||
859 | } | 982 | } | ||
860 | if (mSelection.contains(pos)) { | 983 | if (mSelection.contains(pos)) { | ||
861 | return MouseState::Inside; | 984 | return MouseState::Inside; | ||
862 | } else { | 985 | } else { | ||
863 | return MouseState::Outside; | 986 | return MouseState::Outside; | ||
864 | } | 987 | } | ||
865 | } | 988 | } |
Would it make sense to add this to KScreen ? for instance a static KScreen::pixelGeometry()` that would return {QScreen* or kscreen/output*-> Geometry} (either QVector or Hashmap)
Since this function is in KWin already and would be essentially copied here.