Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_stroke.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2011 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7#include "kis_stroke.h"
8
10
11
12KisStroke::KisStroke(KisStrokeStrategy *strokeStrategy, Type type, int levelOfDetail)
13 : m_strokeStrategy(strokeStrategy),
14 m_strokeInitialized(false),
15 m_strokeEnded(false),
16 m_strokeSuspended(false),
17 m_isCancelled(false),
18 m_worksOnLevelOfDetail(levelOfDetail),
19 m_type(type)
20{
21 m_initStrategy.reset(m_strokeStrategy->createInitStrategy());
22 m_dabStrategy.reset(m_strokeStrategy->createDabStrategy());
23 m_cancelStrategy.reset(m_strokeStrategy->createCancelStrategy());
24 m_finishStrategy.reset(m_strokeStrategy->createFinishStrategy());
25 m_suspendStrategy.reset(m_strokeStrategy->createSuspendStrategy());
26 m_resumeStrategy.reset(m_strokeStrategy->createResumeStrategy());
27
28 m_strokeStrategy->notifyUserStartedStroke();
29
30 if(!m_initStrategy) {
32 }
33 else {
34 enqueue(m_initStrategy.data(), m_strokeStrategy->createInitData());
35 }
36}
37
39{
40 Q_ASSERT(m_strokeEnded);
41 Q_ASSERT(m_jobsQueue.isEmpty());
42}
43
48
50{
52 (m_strokeEnded && !hasJobs())) {
53
54 return;
55 }
56
58
60 m_strokeStrategy->createResumeData(),
61 worksOnLevelOfDetail(), false);
62
63 recipient->prepend(m_suspendStrategy.data(),
64 m_strokeStrategy->createSuspendData(),
65 worksOnLevelOfDetail(), false);
66
67 m_strokeSuspended = true;
68}
69
75
77{
78 // factory methods can return null, if no action is needed
79 if (!m_dabStrategy) {
80 qDeleteAll(list);
81 return;
82 }
83
84 // Find first non-alien (non-suspend/non-resume) job
85 //
86 // Please note that this algorithm will stop working at the day we start
87 // adding alien jobs not to the beginning of the stroke, but to other places.
88 // Right now both suspend and resume jobs are added to the beginning of
89 // the stroke.
90
91 auto it = std::find_if(m_jobsQueue.begin(), m_jobsQueue.end(),
92 std::mem_fn(&KisStrokeJob::isOwnJob));
93
94 Q_FOREACH (KisStrokeJobData *data, list) {
95 it = m_jobsQueue.insert(it, new KisStrokeJob(m_dabStrategy.data(), data, worksOnLevelOfDetail(), true));
96 ++it;
97 }
98}
99
101{
102 KisStrokeJob *job = dequeue();
103
104 if(job) {
105 m_strokeInitialized = true;
106 m_strokeSuspended = false;
107 }
108
109 return job;
110}
111
113{
114 return m_strokeStrategy->name();
115}
116
117QString KisStroke::id() const
118{
119 return m_strokeStrategy->id();
120}
121
123{
124 return !m_jobsQueue.isEmpty();
125}
126
127qint32 KisStroke::numJobs() const
128{
129 return m_jobsQueue.size();
130}
131
133{
135 m_strokeEnded = true;
136
137 enqueue(m_finishStrategy.data(), m_strokeStrategy->createFinishData());
138 m_strokeStrategy->notifyUserEndedStroke();
139}
140
158{
159 // case 6
160 if (m_isCancelled) return;
161
162 const bool effectivelyInitialized =
163 m_strokeInitialized || m_strokeStrategy->needsExplicitCancel();
164
165 if(!effectivelyInitialized) {
179 }
180 else if(effectivelyInitialized &&
181 (!m_jobsQueue.isEmpty() || !m_strokeEnded)) {
182
183 m_strokeStrategy->tryCancelCurrentStrokeJobAsync();
184
187 m_strokeStrategy->createCancelData());
188 }
189 // else {
190 // too late ...
191 // }
192
193 m_isCancelled = true;
194 m_strokeEnded = true;
195}
196
198{
200 !m_jobsQueue.isEmpty() || !m_strokeEnded;
201}
202
204{
205 Q_FOREACH (KisStrokeJob *item, m_jobsQueue) {
206 if (!item->isCancellable()) {
207 return false;
208 }
209 }
210 return true;
211}
212
214{
215 QQueue<KisStrokeJob*>::iterator it = m_jobsQueue.begin();
216
217 while (it != m_jobsQueue.end()) {
218 if ((*it)->isCancellable()) {
219 delete (*it);
220 it = m_jobsQueue.erase(it);
221 } else {
222 ++it;
223 }
224 }
225}
226
228{
229 return m_strokeInitialized;
230}
231
233{
234 return m_strokeEnded;
235}
236
238{
239 return m_isCancelled;
240}
241
243{
244 return m_strokeStrategy->isExclusive();
245}
246
248{
249 return m_strokeStrategy->supportsWrapAroundMode();
250}
251
256
258{
259 return m_strokeStrategy->canForgetAboutMe();
260}
261
263{
264 return m_strokeStrategy->isAsynchronouslyCancellable();
265}
266
268{
269 return m_strokeStrategy->clearsRedoOnStart();
270}
271
273{
274 return m_strokeStrategy->balancingRatioOverride();
275}
276
278{
279 return !m_jobsQueue.isEmpty() ?
280 m_jobsQueue.head()->sequentiality() : KisStrokeJobData::SEQUENTIAL;
281}
282
284{
285 return !m_jobsQueue.isEmpty() ?
286 m_jobsQueue.head()->levelOfDetail() : worksOnLevelOfDetail();
287}
288
290 KisStrokeJobData *data)
291{
292 // factory methods can return null, if no action is needed
293 if(!strategy) {
294 delete data;
295 return;
296 }
297
298 m_jobsQueue.enqueue(new KisStrokeJob(strategy, data, worksOnLevelOfDetail(), true));
299}
300
302 KisStrokeJobData *data,
303 int levelOfDetail,
304 bool isOwnJob)
305{
306 // factory methods can return null, if no action is needed
307 if(!strategy) {
308 delete data;
309 return;
310 }
311
312 // LOG_MERGE_FIXME:
313 Q_UNUSED(levelOfDetail);
314
315 m_jobsQueue.prepend(new KisStrokeJob(strategy, data, worksOnLevelOfDetail(), isOwnJob));
316}
317
319{
320 return !m_jobsQueue.isEmpty() ? m_jobsQueue.dequeue() : 0;
321}
322
324{
325 m_lodBuddy = buddy;
326}
327
329{
330 return m_lodBuddy;
331}
332
334{
335 if (m_type == LOD0) {
336 KIS_ASSERT_RECOVER_NOOP(m_lodBuddy && "LOD0 strokes must always have a buddy");
337 } else if (m_type == LODN) {
338 KIS_ASSERT_RECOVER_NOOP(m_worksOnLevelOfDetail > 0 && "LODN strokes must work on LOD > 0!");
339 } else if (m_type == LEGACY) {
340 KIS_ASSERT_RECOVER_NOOP(m_worksOnLevelOfDetail == 0 && "LEGACY strokes must work on LOD == 0!");
341 }
342
343 return m_type;
344}
bool isOwnJob() const
bool isCancellable() const
KisStrokeJob * dequeue()
bool isExclusive() const
bool canForgetAboutMe() const
QScopedPointer< KisStrokeJobStrategy > m_initStrategy
Definition kis_stroke.h:101
bool supportsSuspension()
void addMutatedJobs(const QVector< KisStrokeJobData * > list)
QScopedPointer< KisStrokeStrategy > m_strokeStrategy
Definition kis_stroke.h:100
QScopedPointer< KisStrokeJobStrategy > m_resumeStrategy
Definition kis_stroke.h:106
Type type() const
void setLodBuddy(KisStrokeSP buddy)
Type m_type
Definition kis_stroke.h:115
bool m_isCancelled
Definition kis_stroke.h:112
bool canCancel() const
bool isAsynchronouslyCancellable() const
QScopedPointer< KisStrokeJobStrategy > m_finishStrategy
Definition kis_stroke.h:104
void prepend(KisStrokeJobStrategy *strategy, KisStrokeJobData *data, int levelOfDetail, bool isOwnJob)
void enqueue(KisStrokeJobStrategy *strategy, KisStrokeJobData *data)
KisStrokeSP m_lodBuddy
Definition kis_stroke.h:116
void clearQueueOnCancel()
QScopedPointer< KisStrokeJobStrategy > m_cancelStrategy
Definition kis_stroke.h:103
bool isCancelled() const
bool supportsWrapAroundMode() const
KisStrokeJobData::Sequentiality nextJobSequentiality() const
KisStroke(KisStrokeStrategy *strokeStrategy, Type type=LEGACY, int levelOfDetail=0)
QScopedPointer< KisStrokeJobStrategy > m_dabStrategy
Definition kis_stroke.h:102
QQueue< KisStrokeJob * > m_jobsQueue
Definition kis_stroke.h:108
bool isInitialized() const
QScopedPointer< KisStrokeJobStrategy > m_suspendStrategy
Definition kis_stroke.h:105
int nextJobLevelOfDetail() const
void endStroke()
QString id() const
bool m_strokeInitialized
Definition kis_stroke.h:109
int worksOnLevelOfDetail() const
bool m_strokeSuspended
Definition kis_stroke.h:111
bool hasJobs() const
KisStrokeSP lodBuddy() const
bool isEnded() const
int m_worksOnLevelOfDetail
Definition kis_stroke.h:114
bool sanityCheckAllJobsAreCancellable() const
qint32 numJobs() const
bool clearsRedoOnStart() const
qreal balancingRatioOverride() const
void cancelStroke()
void suspendStroke(KisStrokeSP recipient)
KUndo2MagicString name() const
void addJob(KisStrokeJobData *data)
KisStrokeJob * popOneJob()
bool m_strokeEnded
Definition kis_stroke.h:110
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define KIS_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:97
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130