Changeset View
Changeset View
Standalone View
Standalone View
plugins/tools/basictools/kis_tool_line.cc
Show First 20 Lines • Show All 54 Lines • ▼ Show 20 Line(s) | |||||
55 | { | 55 | { | ||
56 | KisCanvas2 *kritaCanvas = dynamic_cast<KisCanvas2*>(canvas); | 56 | KisCanvas2 *kritaCanvas = dynamic_cast<KisCanvas2*>(canvas); | ||
57 | return kritaCanvas->coordinatesConverter(); | 57 | return kritaCanvas->coordinatesConverter(); | ||
58 | } | 58 | } | ||
59 | 59 | | |||
60 | 60 | | |||
61 | KisToolLine::KisToolLine(KoCanvasBase * canvas) | 61 | KisToolLine::KisToolLine(KoCanvasBase * canvas) | ||
62 | : KisToolPaint(canvas, KisCursor::load("tool_line_cursor.png", 6, 6)), | 62 | : KisToolPaint(canvas, KisCursor::load("tool_line_cursor.png", 6, 6)), | ||
63 | m_showOutline(false), | 63 | m_showGuideline(true), | ||
64 | m_strokeIsRunning(false), | 64 | m_strokeIsRunning(false), | ||
65 | m_infoBuilder(new KisConverterPaintingInformationBuilder(getCoordinatesConverter(canvas))), | 65 | m_infoBuilder(new KisConverterPaintingInformationBuilder(getCoordinatesConverter(canvas))), | ||
66 | m_helper(new KisToolLineHelper(m_infoBuilder.data(), kundo2_i18n("Draw Line"))), | 66 | m_helper(new KisToolLineHelper(m_infoBuilder.data(), kundo2_i18n("Draw Line"))), | ||
67 | m_strokeUpdateCompressor(500, KisSignalCompressor::FIRST_ACTIVE), | 67 | m_strokeUpdateCompressor(500, KisSignalCompressor::POSTPONE), | ||
68 | m_longStrokeUpdateCompressor(1000, KisSignalCompressor::FIRST_INACTIVE) | 68 | m_longStrokeUpdateCompressor(1000, KisSignalCompressor::FIRST_INACTIVE) | ||
69 | { | 69 | { | ||
70 | setObjectName("tool_line"); | 70 | setObjectName("tool_line"); | ||
71 | 71 | | |||
72 | setSupportOutline(true); | 72 | setSupportOutline(true); | ||
73 | 73 | | |||
74 | connect(&m_strokeUpdateCompressor, SIGNAL(timeout()), SLOT(updateStroke())); | 74 | connect(&m_strokeUpdateCompressor, SIGNAL(timeout()), SLOT(updateStroke())); | ||
75 | connect(&m_longStrokeUpdateCompressor, SIGNAL(timeout()), SLOT(updateStroke())); | 75 | connect(&m_longStrokeUpdateCompressor, SIGNAL(timeout()), SLOT(updateStroke())); | ||
Show All 29 Lines | |||||
105 | 105 | | |||
106 | QWidget* KisToolLine::createOptionWidget() | 106 | QWidget* KisToolLine::createOptionWidget() | ||
107 | { | 107 | { | ||
108 | QWidget* widget = KisToolPaint::createOptionWidget(); | 108 | QWidget* widget = KisToolPaint::createOptionWidget(); | ||
109 | 109 | | |||
110 | m_chkUseSensors = new QCheckBox(i18n("Use sensors")); | 110 | m_chkUseSensors = new QCheckBox(i18n("Use sensors")); | ||
111 | addOptionWidgetOption(m_chkUseSensors); | 111 | addOptionWidgetOption(m_chkUseSensors); | ||
112 | 112 | | |||
113 | m_chkShowOutline = new QCheckBox(i18n("Preview")); | 113 | m_chkShowPreview = new QCheckBox(i18n("Show Preview")); | ||
114 | addOptionWidgetOption(m_chkShowOutline); | 114 | addOptionWidgetOption(m_chkShowPreview); | ||
115 | | ||||
116 | m_chkShowGuideline = new QCheckBox(i18n("Show Guideline")); | ||||
117 | addOptionWidgetOption(m_chkShowGuideline); | ||||
dkazakov: Probably, rename it into "Show Preview" to keep it consistent with the other option? | |||||
115 | 118 | | |||
116 | // hook up connections for value changing | 119 | // hook up connections for value changing | ||
117 | connect(m_chkUseSensors, SIGNAL(clicked(bool)), this, SLOT(setUseSensors(bool)) ); | 120 | connect(m_chkUseSensors, SIGNAL(clicked(bool)), this, SLOT(setUseSensors(bool)) ); | ||
118 | connect(m_chkShowOutline, SIGNAL(clicked(bool)), this, SLOT(setShowOutline(bool)) ); | 121 | connect(m_chkShowPreview, SIGNAL(clicked(bool)), this, SLOT(setShowPreview(bool)) ); | ||
122 | connect(m_chkShowGuideline, SIGNAL(clicked(bool)), this, SLOT(setShowGuideline(bool)) ); | ||||
119 | 123 | | |||
120 | 124 | | |||
121 | // read values in from configuration | 125 | // read values in from configuration | ||
122 | m_chkUseSensors->setChecked(configGroup.readEntry("useSensors", true)); | 126 | m_chkUseSensors->setChecked(configGroup.readEntry("useSensors", true)); | ||
123 | m_chkShowOutline->setChecked(configGroup.readEntry("showOutline", false)); | 127 | m_chkShowPreview->setChecked(configGroup.readEntry("showPreview", true)); | ||
128 | m_chkShowGuideline->setChecked(configGroup.readEntry("showGuideline", true)); | ||||
124 | 129 | | |||
125 | return widget; | 130 | return widget; | ||
126 | } | 131 | } | ||
127 | 132 | | |||
128 | void KisToolLine::setUseSensors(bool value) | 133 | void KisToolLine::setUseSensors(bool value) | ||
129 | { | 134 | { | ||
130 | configGroup.writeEntry("useSensors", value); | 135 | configGroup.writeEntry("useSensors", value); | ||
131 | } | 136 | } | ||
132 | 137 | | |||
133 | void KisToolLine::setShowOutline(bool value) | 138 | void KisToolLine::setShowGuideline(bool value) | ||
134 | { | 139 | { | ||
135 | configGroup.writeEntry("showOutline", value); | 140 | m_showGuideline = value; | ||
141 | configGroup.writeEntry("showGuideline", value); | ||||
142 | } | ||||
143 | | ||||
144 | void KisToolLine::setShowPreview(bool value) | ||||
145 | { | ||||
146 | configGroup.writeEntry("showPreview", value); | ||||
136 | } | 147 | } | ||
137 | 148 | | |||
138 | void KisToolLine::requestStrokeCancellation() | 149 | void KisToolLine::requestStrokeCancellation() | ||
139 | { | 150 | { | ||
140 | cancelStroke(); | 151 | cancelStroke(); | ||
141 | } | 152 | } | ||
142 | 153 | | |||
143 | void KisToolLine::requestStrokeEnd() | 154 | void KisToolLine::requestStrokeEnd() | ||
144 | { | 155 | { | ||
156 | // Terminate any in-progress strokes | ||||
157 | if (nodePaintAbility() == PAINT && m_helper->isRunning()) { | ||||
145 | endStroke(); | 158 | endStroke(); | ||
146 | } | 159 | } | ||
160 | } | ||||
161 | | ||||
162 | void KisToolLine::updatePreviewTimer(bool showGuideline) | ||||
163 | { | ||||
164 | // If the user disables the guideline, we will want to try to draw some | ||||
165 | // preview lines even if they're slow, so set the timer to FIRST_ACTIVE. | ||||
166 | if (showGuideline) { | ||||
167 | m_strokeUpdateCompressor.setMode(KisSignalCompressor::POSTPONE); | ||||
168 | } else { | ||||
169 | m_strokeUpdateCompressor.setMode(KisSignalCompressor::FIRST_ACTIVE); | ||||
170 | } | ||||
171 | } | ||||
172 | | ||||
147 | 173 | | |||
148 | void KisToolLine::paint(QPainter& gc, const KoViewConverter &converter) | 174 | void KisToolLine::paint(QPainter& gc, const KoViewConverter &converter) | ||
149 | { | 175 | { | ||
150 | Q_UNUSED(converter); | 176 | Q_UNUSED(converter); | ||
151 | 177 | | |||
152 | if(mode() == KisTool::PAINT_MODE) { | 178 | if(mode() == KisTool::PAINT_MODE) { | ||
153 | paintLine(gc,QRect()); | 179 | paintLine(gc,QRect()); | ||
154 | } | 180 | } | ||
155 | KisToolPaint::paint(gc,converter); | 181 | KisToolPaint::paint(gc,converter); | ||
156 | } | 182 | } | ||
157 | 183 | | |||
158 | void KisToolLine::beginPrimaryAction(KoPointerEvent *event) | 184 | void KisToolLine::beginPrimaryAction(KoPointerEvent *event) | ||
159 | { | 185 | { | ||
160 | NodePaintAbility nodeAbility = nodePaintAbility(); | 186 | NodePaintAbility nodeAbility = nodePaintAbility(); | ||
161 | if (nodeAbility == NONE || !nodeEditable()) { | 187 | if (nodeAbility == NONE || !nodeEditable()) { | ||
162 | event->ignore(); | 188 | event->ignore(); | ||
163 | return; | 189 | return; | ||
164 | } | 190 | } | ||
165 | 191 | | |||
166 | setMode(KisTool::PAINT_MODE); | 192 | setMode(KisTool::PAINT_MODE); | ||
167 | 193 | | |||
168 | m_showOutline = m_chkShowOutline->isChecked() || nodeAbility != PAINT; | 194 | // Always show guideline on vector layers | ||
195 | m_showGuideline = m_chkShowGuideline->isChecked() || nodeAbility != PAINT; | ||||
196 | updatePreviewTimer(m_showGuideline); | ||||
169 | m_helper->setEnabled(nodeAbility == PAINT); | 197 | m_helper->setEnabled(nodeAbility == PAINT); | ||
170 | m_helper->setUseSensors(m_chkUseSensors->isChecked()); | 198 | m_helper->setUseSensors(m_chkUseSensors->isChecked()); | ||
171 | m_helper->start(event); | 199 | m_helper->start(event); | ||
172 | 200 | | |||
173 | m_startPoint = convertToPixelCoordAndSnap(event); | 201 | m_startPoint = convertToPixelCoordAndSnap(event); | ||
174 | m_endPoint = m_startPoint; | 202 | m_endPoint = m_startPoint; | ||
175 | m_lastUpdatedPoint = m_startPoint; | 203 | m_lastUpdatedPoint = m_startPoint; | ||
176 | 204 | | |||
Show All 11 Lines | 212 | m_helper->repaintLine(canvas()->resourceManager(), | |||
188 | image()->postExecutionUndoAdapter()); | 216 | image()->postExecutionUndoAdapter()); | ||
189 | } | 217 | } | ||
190 | 218 | | |||
191 | void KisToolLine::continuePrimaryAction(KoPointerEvent *event) | 219 | void KisToolLine::continuePrimaryAction(KoPointerEvent *event) | ||
192 | { | 220 | { | ||
193 | CHECK_MODE_SANITY_OR_RETURN(KisTool::PAINT_MODE); | 221 | CHECK_MODE_SANITY_OR_RETURN(KisTool::PAINT_MODE); | ||
194 | if (!m_strokeIsRunning) return; | 222 | if (!m_strokeIsRunning) return; | ||
195 | 223 | | |||
196 | // First ensure the old temp line is deleted | 224 | // First ensure the old guideline is deleted | ||
197 | updatePreview(); | 225 | updateGuideline(); | ||
198 | 226 | | |||
199 | QPointF pos = convertToPixelCoordAndSnap(event); | 227 | QPointF pos = convertToPixelCoordAndSnap(event); | ||
200 | 228 | | |||
201 | if (event->modifiers() == Qt::AltModifier) { | 229 | if (event->modifiers() == Qt::AltModifier) { | ||
202 | QPointF trans = pos - m_endPoint; | 230 | QPointF trans = pos - m_endPoint; | ||
203 | m_helper->translatePoints(trans); | 231 | m_helper->translatePoints(trans); | ||
204 | m_startPoint += trans; | 232 | m_startPoint += trans; | ||
205 | m_endPoint += trans; | 233 | m_endPoint += trans; | ||
206 | } else if (event->modifiers() == Qt::ShiftModifier) { | 234 | } else if (event->modifiers() == Qt::ShiftModifier) { | ||
207 | pos = straightLine(pos); | 235 | pos = straightLine(pos); | ||
208 | m_helper->addPoint(event, pos); | 236 | m_helper->addPoint(event, pos); | ||
209 | } else { | 237 | } else { | ||
210 | m_helper->addPoint(event, pos); | 238 | m_helper->addPoint(event, pos); | ||
211 | } | 239 | } | ||
240 | m_endPoint = pos; | ||||
212 | 241 | | |||
213 | if ((pixelToView(m_lastUpdatedPoint) - pixelToView(pos)).manhattanLength() > 10) { | 242 | // Draw preview if requested | ||
243 | if (m_chkShowPreview->isChecked()) { | ||||
244 | // If the cursor has moved a significant amount, immediately clear the | ||||
245 | // current preview and redraw. Otherwise, do slow redraws periodically. | ||||
246 | auto updateDistance = (pixelToView(m_lastUpdatedPoint) - pixelToView(pos)).manhattanLength(); | ||||
247 | if (updateDistance > 10) { | ||||
248 | m_helper->clearPaint(); | ||||
214 | m_longStrokeUpdateCompressor.stop(); | 249 | m_longStrokeUpdateCompressor.stop(); | ||
215 | m_strokeUpdateCompressor.start(); | 250 | m_strokeUpdateCompressor.start(); | ||
216 | m_lastUpdatedPoint = pos; | 251 | m_lastUpdatedPoint = pos; | ||
217 | } else { | 252 | } else if (updateDistance > 1) { | ||
218 | m_longStrokeUpdateCompressor.start(); | 253 | m_longStrokeUpdateCompressor.start(); | ||
219 | } | 254 | } | ||
220 | m_endPoint = pos; | 255 | } | ||
256 | | ||||
221 | 257 | | |||
222 | updatePreview(); | 258 | updateGuideline(); | ||
223 | KisToolPaint::requestUpdateOutline(event->point, event); | 259 | KisToolPaint::requestUpdateOutline(event->point, event); | ||
224 | } | 260 | } | ||
225 | 261 | | |||
226 | void KisToolLine::endPrimaryAction(KoPointerEvent *event) | 262 | void KisToolLine::endPrimaryAction(KoPointerEvent *event) | ||
227 | { | 263 | { | ||
228 | Q_UNUSED(event); | 264 | Q_UNUSED(event); | ||
229 | CHECK_MODE_SANITY_OR_RETURN(KisTool::PAINT_MODE); | 265 | CHECK_MODE_SANITY_OR_RETURN(KisTool::PAINT_MODE); | ||
230 | setMode(KisTool::HOVER_MODE); | 266 | setMode(KisTool::HOVER_MODE); | ||
231 | 267 | | |||
232 | updatePreview(); | 268 | updateGuideline(); | ||
233 | | ||||
234 | endStroke(); | 269 | endStroke(); | ||
235 | } | 270 | } | ||
236 | 271 | | |||
237 | void KisToolLine::endStroke() | 272 | void KisToolLine::endStroke() | ||
238 | { | 273 | { | ||
239 | NodePaintAbility nodeAbility = nodePaintAbility(); | 274 | NodePaintAbility nodeAbility = nodePaintAbility(); | ||
240 | 275 | | |||
241 | if (!m_strokeIsRunning || | 276 | if (!m_strokeIsRunning || m_startPoint == m_endPoint || nodeAbility == NONE) { | ||
242 | (nodeAbility == PAINT && !m_helper->isRunning())|| | | |||
243 | m_startPoint == m_endPoint || | | |||
244 | nodeAbility == NONE) { | | |||
245 | | ||||
246 | return; | 277 | return; | ||
247 | } | 278 | } | ||
248 | 279 | | |||
249 | if (nodeAbility == PAINT) { | 280 | if (nodeAbility == PAINT) { | ||
250 | updateStroke(); | 281 | updateStroke(); | ||
251 | m_helper->end(); | 282 | m_helper->end(); | ||
252 | } | 283 | } | ||
253 | else { | 284 | else { | ||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Line(s) | 325 | { | |||
309 | const QPointF constrainedLineVector(lineLength * std::cos(constrainedLineAngle), lineLength * std::sin(constrainedLineAngle)); | 340 | const QPointF constrainedLineVector(lineLength * std::cos(constrainedLineAngle), lineLength * std::sin(constrainedLineAngle)); | ||
310 | 341 | | |||
311 | const QPointF result = m_startPoint + constrainedLineVector; | 342 | const QPointF result = m_startPoint + constrainedLineVector; | ||
312 | 343 | | |||
313 | return result; | 344 | return result; | ||
314 | } | 345 | } | ||
315 | 346 | | |||
316 | 347 | | |||
317 | void KisToolLine::updatePreview() | 348 | void KisToolLine::updateGuideline() | ||
318 | { | 349 | { | ||
319 | if (canvas()) { | 350 | if (canvas()) { | ||
320 | QRectF bound(m_startPoint, m_endPoint); | 351 | QRectF bound(m_startPoint, m_endPoint); | ||
321 | canvas()->updateCanvas(convertToPt(bound.normalized().adjusted(-3, -3, 3, 3))); | 352 | canvas()->updateCanvas(convertToPt(bound.normalized().adjusted(-3, -3, 3, 3))); | ||
322 | } | 353 | } | ||
323 | } | 354 | } | ||
324 | 355 | | |||
325 | 356 | | |||
326 | void KisToolLine::paintLine(QPainter& gc, const QRect&) | 357 | void KisToolLine::paintLine(QPainter& gc, const QRect&) | ||
327 | { | 358 | { | ||
328 | QPointF viewStartPos = pixelToView(m_startPoint); | 359 | QPointF viewStartPos = pixelToView(m_startPoint); | ||
329 | QPointF viewStartEnd = pixelToView(m_endPoint); | 360 | QPointF viewStartEnd = pixelToView(m_endPoint); | ||
330 | 361 | | |||
331 | if (m_showOutline && canvas()) { | 362 | if (m_showGuideline && canvas()) { | ||
332 | QPainterPath path; | 363 | QPainterPath path; | ||
333 | path.moveTo(viewStartPos); | 364 | path.moveTo(viewStartPos); | ||
334 | path.lineTo(viewStartEnd); | 365 | path.lineTo(viewStartEnd); | ||
335 | paintToolOutline(&gc, path); | 366 | paintToolOutline(&gc, path); | ||
336 | } | 367 | } | ||
337 | } | 368 | } | ||
338 | 369 | | |||
339 | QString KisToolLine::quickHelp() const | 370 | QString KisToolLine::quickHelp() const | ||
340 | { | 371 | { | ||
341 | return i18n("Alt+Drag will move the origin of the currently displayed line around, Shift+Drag will force you to draw straight lines"); | 372 | return i18n("Alt+Drag will move the origin of the currently displayed line around, Shift+Drag will force you to draw straight lines"); | ||
342 | } | 373 | } | ||
343 | 374 | | |||
344 | 375 | |
Probably, rename it into "Show Preview" to keep it consistent with the other option?