1
2
3 #include "tools/toolutils.h"
4 #include "tools/toolhandle.h"
5 #include "toonzqt/imageutils.h"
6 #include "trop.h"
7 #include "tools/tool.h"
8 #include "tstroke.h"
9 #include "timageinfo.h"
10 #include "timagecache.h"
11 #include "tgl.h"
12
13 #include "toonz/txsheethandle.h"
14 #include "toonz/tframehandle.h"
15 #include "toonz/txshlevelhandle.h"
16 #include "toonz/tscenehandle.h"
17 #include "toonz/txshleveltypes.h"
18 #include "toonz/tcolumnhandle.h"
19 #include "toonz/tpalettehandle.h"
20 #include "toonz/txshlevel.h"
21 #include "toonz/txshcell.h"
22 #include "toonz/txshsimplelevel.h"
23 #include "toonz/imagemanager.h"
24 #include "toonz/ttileset.h"
25 #include "toonz/toonzimageutils.h"
26 #include "toonz/levelproperties.h"
27 #include "toonz/tstageobjectspline.h"
28 #include "toonz/tobjecthandle.h"
29 #include "toonz/tstageobject.h"
30 #include "toonz/trasterimageutils.h"
31 #include "toonz/levelset.h"
32 #include "toonz/toonzscene.h"
33 #include "toonz/preferences.h"
34 #include "toonz/palettecontroller.h"
35 #include "toonz/txshchildlevel.h"
36
37 #include "toonzqt/tselectionhandle.h"
38 #include "toonzqt/icongenerator.h"
39 #include "toonzqt/selection.h"
40 #include "toonzqt/gutil.h"
41
42 #include "tools/strokeselection.h"
43
44 #include <QPainter>
45 #include <QPainterPath>
46 #include <QGLWidget> // for QGLWidget::convertToGLFormat
47 #include <QFont>
48 #include <QFontMetrics>
49
50 //****************************************************************************************
51 // Local namespace
52 //****************************************************************************************
53
54 namespace {
55
56 //! Riempie il vettore \b theVect con gli indici degli stroke contenuti nel
57 //! mapping \b theMap.
mapToVector(const std::map<int,VIStroke * > & theMap,std::vector<int> & theVect)58 void mapToVector(const std::map<int, VIStroke *> &theMap,
59 std::vector<int> &theVect) {
60 assert(theMap.size() == theVect.size());
61 std::map<int, VIStroke *>::const_iterator it = theMap.begin();
62 UINT i = 0;
63 for (; it != theMap.end(); ++it) {
64 theVect[i++] = it->first;
65 }
66 }
67
68 //------------------------------------------------------------
69
updateSaveBox(const TToonzImageP & ti)70 void updateSaveBox(const TToonzImageP &ti) {
71 if (ti) {
72 assert(ti->getRaster()); // Image should have a raster
73 assert(ti->getSubsampling() == 1); // Image should not be subsampled -
74 // modified images must be the ORIGINAL
75 // ones
76
77 const TRect &savebox = ti->getSavebox();
78 {
79 TRect newSaveBox;
80 TRop::computeBBox(ti->getRaster(), newSaveBox); // This iterates the
81 // WHOLE raster to find
82 // its new savebox!
83
84 if (!Preferences::instance()->isMinimizeSaveboxAfterEditing())
85 newSaveBox +=
86 savebox; // If not minimizing the savebox, it cannot be shrunk.
87
88 ti->setSavebox(newSaveBox);
89 }
90 }
91 }
92
93 } // namespace
94
95 //****************************************************************************************
96 // ToolUtils namespace
97 //****************************************************************************************
98
updateSaveBox(const TXshSimpleLevelP & sl,const TFrameId & fid)99 void ToolUtils::updateSaveBox(const TXshSimpleLevelP &sl, const TFrameId &fid) {
100 // TODO: Savebox updates should not happen on mouse updates. This is,
101 // unfortunately, what currently happens.
102 sl->setDirtyFlag(true);
103
104 TImageP img = sl->getFrame(fid, true); // The image will be modified (it
105 // should already have been, though)
106 if (!img) return;
107 // Observe that the returned image will forcedly have subsampling 1
108 ::updateSaveBox(img);
109
110 TImageInfo *info = sl->getFrameInfo(fid, true);
111 ImageBuilder::setImageInfo(*info, img.getPointer());
112 }
113
114 //------------------------------------------------------------
115
updateSaveBox(const TXshSimpleLevelP & sl,const TFrameId & fid,TImageP img)116 void ToolUtils::updateSaveBox(const TXshSimpleLevelP &sl, const TFrameId &fid,
117 TImageP img) {
118 sl->setFrame(fid, img);
119 ToolUtils::updateSaveBox(sl, fid);
120 }
121
122 //------------------------------------------------------------
123
updateSaveBox()124 void ToolUtils::updateSaveBox() {
125 TTool::Application *application = TTool::getApplication();
126 if (!application) return;
127
128 TXshLevel *xl = application->getCurrentLevel()->getLevel();
129 if (!xl) return;
130
131 TXshSimpleLevel *sl = xl->getSimpleLevel();
132 if (!sl || sl->getType() != TZP_XSHLEVEL) return;
133
134 TFrameId fid = getFrameId();
135 ToolUtils::updateSaveBox(sl, fid);
136 }
137
138 //-----------------------------------------------------------------------------
139 //! Return the right value in both case: LevelFrame and SceneFrame.
getFrameId()140 TFrameId ToolUtils::getFrameId() {
141 TTool::Application *app = TTool::getApplication();
142 if (!app) return TFrameId();
143
144 TFrameHandle *frameHandle = app->getCurrentFrame();
145 if (frameHandle->isEditingScene()) {
146 TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
147 if (!xsh) return 0;
148 int row = frameHandle->getFrame();
149 int col = app->getCurrentColumn()->getColumnIndex();
150 if (col < 0) return 0;
151 TXshCell cell = xsh->getCell(row, col);
152 return cell.getFrameId();
153 } else
154 return frameHandle->getFid();
155 }
156
157 //------------------------------------------------------------
158
drawRect(const TRectD & rect,const TPixel32 & color,unsigned short stipple,bool doContrast)159 void ToolUtils::drawRect(const TRectD &rect, const TPixel32 &color,
160 unsigned short stipple, bool doContrast) {
161 GLint src, dst;
162 bool isEnabled;
163 tglColor(color);
164 if (doContrast) {
165 if (color == TPixel32::Black) tglColor(TPixel32(90, 90, 90));
166 isEnabled = glIsEnabled(GL_BLEND);
167 glGetIntegerv(GL_BLEND_SRC, &src);
168 glGetIntegerv(GL_BLEND_DST, &dst);
169 glEnable(GL_BLEND);
170 glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA);
171 }
172
173 if (stipple != 0xffff) {
174 glLineStipple(1, stipple);
175 glEnable(GL_LINE_STIPPLE);
176 }
177
178 glBegin(GL_LINE_STRIP);
179 tglVertex(rect.getP00());
180 tglVertex(rect.getP01());
181 tglVertex(rect.getP11());
182 tglVertex(rect.getP10());
183 tglVertex(rect.getP00());
184 glEnd();
185 glDisable(GL_LINE_STIPPLE);
186 if (doContrast) {
187 if (!isEnabled) glDisable(GL_BLEND);
188 glBlendFunc(src, dst);
189 }
190 }
191
192 //-----------------------------------------------------------------------------
193
fillRect(const TRectD & rect,const TPixel32 & color)194 void ToolUtils::fillRect(const TRectD &rect, const TPixel32 &color) {
195 tglColor(color);
196 glBegin(GL_QUADS);
197 tglVertex(rect.getP00());
198 tglVertex(rect.getP01());
199 tglVertex(rect.getP11());
200 tglVertex(rect.getP10());
201 tglVertex(rect.getP00());
202 glEnd();
203 }
204
205 //-----------------------------------------------------------------------------
206
drawPoint(const TPointD & q,double pixelSize)207 void ToolUtils::drawPoint(const TPointD &q, double pixelSize) {
208 double size = pixelSize * 2.0;
209 glBegin(GL_QUADS);
210 glVertex2d(q.x - size, q.y - size);
211 glVertex2d(q.x - size, q.y + size);
212 glVertex2d(q.x + size, q.y + size);
213 glVertex2d(q.x + size, q.y - size);
214 glEnd();
215 }
216
217 //-----------------------------------------------------------------------------
218
drawCross(const TPointD & q,double pixelSize)219 void ToolUtils::drawCross(const TPointD &q, double pixelSize) {
220 double size = pixelSize;
221 glBegin(GL_LINES);
222 glVertex2d(q.x - size, q.y);
223 glVertex2d(q.x + size, q.y);
224 glEnd();
225 glBegin(GL_LINES);
226 glVertex2d(q.x, q.y - size);
227 glVertex2d(q.x, q.y + size);
228 glEnd();
229 }
230
231 //-----------------------------------------------------------------------------
232
drawArrow(const TSegment & s,double pixelSize)233 void ToolUtils::drawArrow(const TSegment &s, double pixelSize) {
234 TPointD v, vn;
235
236 double length = s.getLength() * pixelSize;
237
238 if (length == 0) return;
239
240 v = normalize(s.getSpeed());
241 vn = v;
242
243 TPointD p1 = s.getP0() + v * length;
244 glBegin(GL_LINES);
245 tglVertex(s.getP0());
246 tglVertex(p1);
247 glEnd();
248
249 v = v * length * 0.7;
250
251 vn = vn * length * 0.2;
252
253 TPointD p;
254
255 glBegin(GL_TRIANGLES);
256 p = s.getP0() + v + rotate90(vn);
257 tglVertex(p);
258 tglVertex(p1);
259 p = s.getP0() + v + rotate270(vn);
260 tglVertex(p);
261 glEnd();
262 }
263
264 //-----------------------------------------------------------------------------
265
drawSquare(const TPointD & pos,double r,const TPixel32 & color)266 void ToolUtils::drawSquare(const TPointD &pos, double r,
267 const TPixel32 &color) {
268 TRectD rect(pos - TPointD(r, r), pos + TPointD(r, r));
269 tglColor(color);
270 glBegin(GL_LINE_STRIP);
271 tglVertex(rect.getP00());
272 tglVertex(rect.getP01());
273 tglVertex(rect.getP11());
274 tglVertex(rect.getP10());
275 tglVertex(rect.getP00());
276 glEnd();
277 }
278
279 //-----------------------------------------------------------------------------
280
drawRectWhitArrow(const TPointD & pos,double r)281 void ToolUtils::drawRectWhitArrow(const TPointD &pos, double r) {
282 if (TTool::getApplication()->getCurrentObject()->isSpline()) return;
283 TRectD rect(pos - TPointD(14 * r, 2 * r), pos + TPointD(14 * r, 2 * r));
284 tglColor(TPixel32::Black);
285 glBegin(GL_POLYGON);
286 tglVertex(rect.getP00());
287 tglVertex(rect.getP10());
288 tglVertex(rect.getP11());
289 tglVertex(rect.getP01());
290 glEnd();
291
292 double par = 5 * r;
293
294 TPointD p01 = 0.5 * (rect.getP00() + rect.getP10());
295 TPointD p02 = 0.5 * (rect.getP01() + rect.getP11());
296 TPointD p11 = TPointD(p01.x, p01.y - par);
297 TPointD p12 = TPointD(p02.x, p02.y + par);
298 TPointD p;
299
300 tglColor(TPixel32(130, 130, 130));
301
302 glBegin(GL_TRIANGLES);
303 p = p11 + rotate90(TPointD(0, par));
304 tglVertex(p);
305 tglVertex(p01);
306 p = p11 + rotate270(TPointD(0, par));
307 tglVertex(p);
308 glEnd();
309
310 glBegin(GL_TRIANGLES);
311 p = p12 + rotate90(TPointD(0, -par));
312 tglVertex(p);
313 tglVertex(p02);
314 p = p12 + rotate270(TPointD(0, -par));
315 tglVertex(p);
316 glEnd();
317 }
318
319 //-----------------------------------------------------------------------------
320
getBrushPad(int size,double hardness)321 QRadialGradient ToolUtils::getBrushPad(int size, double hardness) {
322 hardness = tcrop(hardness, 0.0, 0.97);
323 double halfSize = size * 0.5;
324 double x = halfSize * hardness;
325 TQuadratic q(TPointD(x, 1.0), TPointD((halfSize + x) * 0.5, 0.0),
326 TPointD(halfSize, 0.0));
327 QRadialGradient rd(QPointF(halfSize, halfSize), halfSize,
328 QPointF(halfSize, halfSize));
329 rd.setColorAt(0, QColor(0, 0, 0));
330
331 double t;
332 double offset = halfSize - x;
333 assert(offset > 0);
334 for (t = 0; t <= 1; t += 1.0 / offset) {
335 TPointD p = q.getPoint(t);
336 int value = 255 * p.y;
337 rd.setColorAt(p.x / halfSize, QColor(0, 0, 0, value));
338 }
339 return rd;
340 }
341
342 //-----------------------------------------------------------------------------
343
splitRect(const TRect & first,const TRect & second)344 QList<TRect> ToolUtils::splitRect(const TRect &first, const TRect &second) {
345 TRect intersection = first * second;
346 QList<TRect> rects;
347 if (intersection.isEmpty()) {
348 rects.append(first);
349 return rects;
350 }
351
352 TRect rect;
353 if (first.x0 < intersection.x0) {
354 rect = TRect(first.getP00(), TPoint(intersection.x0 - 1, first.y1));
355 rects.append(rect);
356 }
357 if (intersection.x1 < first.x1) {
358 rect = TRect(TPoint(intersection.x1 + 1, first.y0), first.getP11());
359 rects.append(rect);
360 }
361 if (intersection.y1 < first.y1) {
362 rect =
363 TRect(intersection.x0, intersection.y1 + 1, intersection.x1, first.y1);
364 rects.append(rect);
365 }
366 if (first.y0 < intersection.y0) {
367 rect =
368 TRect(intersection.x0, first.y0, intersection.x1, intersection.y0 - 1);
369 rects.append(rect);
370 }
371 return rects;
372 }
373
374 //-----------------------------------------------------------------------------
375
convertStrokeToImage(TStroke * stroke,const TRect & imageBounds,TPoint & pos,bool pencilMode)376 TRaster32P ToolUtils::convertStrokeToImage(TStroke *stroke,
377 const TRect &imageBounds,
378 TPoint &pos, bool pencilMode) {
379 int count = stroke->getControlPointCount();
380 if (count == 0) return TRaster32P();
381 TPointD imgCenter = TPointD((imageBounds.x0 + imageBounds.x1) * 0.5,
382 (imageBounds.y0 + imageBounds.y1) * 0.5);
383
384 TStroke s(*stroke);
385
386 // check self looped stroke
387 TThickPoint first = s.getControlPoint(0);
388 TThickPoint back = s.getControlPoint(count - 1);
389 if (first != back) {
390 TPointD mid = (first + back) * 0.5;
391 s.setControlPoint(count, mid);
392 s.setControlPoint(count + 1, first);
393 }
394
395 // check bounds intersection
396 s.transform(TTranslation(imgCenter));
397 TRectD bbox = s.getBBox();
398 TRect rect(tfloor(bbox.x0), tfloor(bbox.y0), tfloor(bbox.x1),
399 tfloor(bbox.y1));
400 pos = rect.getP00();
401 pos = TPoint(pos.x > 0 ? pos.x : 0, pos.y > 0 ? pos.y : 0);
402 rect *= imageBounds;
403 if (rect.isEmpty()) return TRaster32P();
404
405 // creates the image
406 QImage img(rect.getLx(), rect.getLy(), QImage::Format_ARGB32);
407 img.fill(Qt::transparent);
408 QColor color = Qt::black;
409 QPainter p(&img);
410 p.setPen(QPen(color, 1, Qt::SolidLine));
411 p.setBrush(color);
412 p.setRenderHint(QPainter::Antialiasing, !pencilMode);
413 QPainterPath path = strokeToPainterPath(&s);
414 QRectF pathRect = path.boundingRect();
415 p.translate(-toQPoint(pos));
416 p.drawPath(path);
417 return rasterFromQImage(img, true, false);
418 }
419
420 //-----------------------------------------------------------------------------
421
merge(const ArrayOfStroke & a)422 TStroke *ToolUtils::merge(const ArrayOfStroke &a) {
423 std::vector<TThickPoint> v;
424
425 TStroke *ref = 0;
426 int controlPoints = 0;
427
428 for (UINT i = 0; i < a.size(); ++i) {
429 ref = a[i];
430 assert(ref);
431 if (!ref) continue;
432
433 controlPoints = ref->getControlPointCount() - 1;
434
435 for (int j = 0; j < controlPoints; ++j)
436 v.push_back(ref->getControlPoint(j));
437 }
438
439 if (controlPoints > 0) v.push_back(ref->getControlPoint(controlPoints));
440
441 TStroke *out = new TStroke(v);
442
443 return out;
444 }
445
446 //================================================================================================
447 //
448 // TToolUndo
449 //
450 //================================================================================================
451
TToolUndo(TXshSimpleLevel * level,const TFrameId & frameId,bool createdFrame,bool createdLevel,const TPaletteP & oldPalette)452 ToolUtils::TToolUndo::TToolUndo(TXshSimpleLevel *level, const TFrameId &frameId,
453 bool createdFrame, bool createdLevel,
454 const TPaletteP &oldPalette)
455 : TUndo()
456 , m_level(level)
457 , m_frameId(frameId)
458 , m_oldPalette(oldPalette)
459 , m_col(-2)
460 , m_row(-1)
461 , m_isEditingLevel(false)
462 , m_createdFrame(createdFrame)
463 , m_createdLevel(createdLevel)
464 , m_renumberedLevel(TTool::m_isLevelRenumbererd)
465 , m_imageId("") {
466 TTool::Application *app = TTool::getApplication();
467 m_isEditingLevel = app->getCurrentFrame()->isEditingLevel();
468 if (!m_isEditingLevel) {
469 m_col = app->getCurrentColumn()->getColumnIndex();
470 m_row = app->getCurrentFrame()->getFrameIndex();
471 m_cellsData = TTool::m_cellsData;
472 }
473 if (m_renumberedLevel) {
474 m_oldFids = TTool::m_oldFids;
475 m_newFids = TTool::m_newFids;
476 }
477 if (createdFrame) {
478 m_imageId = "TToolUndo" + std::to_string(m_idCount++);
479 TImageCache::instance()->add(m_imageId, level->getFrame(frameId, false),
480 false);
481 }
482 }
483
484 //------------------------------------------------------------------------------------------
485
~TToolUndo()486 ToolUtils::TToolUndo::~TToolUndo() {
487 TImageCache::instance()->remove(m_imageId);
488 }
489
490 //-----------------------------------------------------------------------------
491
insertLevelAndFrameIfNeeded() const492 void ToolUtils::TToolUndo::insertLevelAndFrameIfNeeded() const {
493 TTool::Application *app = TTool::getApplication();
494 if (m_renumberedLevel) {
495 TXsheet *xsh = app->getCurrentScene()->getScene()->getTopXsheet();
496 std::vector<TXshChildLevel *> childLevels;
497 ToolUtils::doUpdateXSheet(m_level.getPointer(), m_oldFids, m_newFids, xsh,
498 childLevels);
499 m_level->renumber(m_newFids);
500 app->getCurrentXsheet()->notifyXsheetChanged();
501 }
502 if (m_createdLevel) {
503 TLevelSet *levelSet = app->getCurrentScene()->getScene()->getLevelSet();
504 if (levelSet) {
505 levelSet->insertLevel(m_level.getPointer());
506 app->getCurrentScene()->notifyCastChange();
507 }
508 }
509 if (m_createdFrame) {
510 TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
511 TImageP img = TImageCache::instance()->get(m_imageId, false);
512 m_level->setFrame(m_frameId, img);
513 if (!m_isEditingLevel) {
514 for (const TTool::CellOps &cellOps : m_cellsData) {
515 TXshCell cell;
516 if (cellOps.type == TTool::CellOps::BlankToExisting)
517 cell = xsh->getCell(cellOps.r0 - 1, m_col);
518 else
519 cell = TXshCell(m_level.getPointer(), m_frameId);
520 for (int r = cellOps.r0; r <= cellOps.r1; r++)
521 xsh->setCell(r, m_col, cell);
522 }
523 }
524 app->getCurrentLevel()->notifyLevelChange();
525 }
526 }
527
528 //-----------------------------------------------------------------------------
529
removeLevelAndFrameIfNeeded() const530 void ToolUtils::TToolUndo::removeLevelAndFrameIfNeeded() const {
531 TTool::Application *app = TTool::getApplication();
532 if (m_createdFrame) {
533 m_level->eraseFrame(m_frameId);
534 if (!m_isEditingLevel) {
535 TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
536 for (const TTool::CellOps &cellOps : m_cellsData) {
537 TXshCell cell;
538 if (cellOps.type == TTool::CellOps::ExistingToNew)
539 cell = xsh->getCell(cellOps.r0 - 1, m_col);
540 for (int r = cellOps.r0; r <= cellOps.r1; r++)
541 xsh->setCell(r, m_col, cell);
542 }
543 }
544 if (m_createdLevel) {
545 // butta il livello
546 TLevelSet *levelSet = app->getCurrentScene()->getScene()->getLevelSet();
547 if (levelSet) {
548 levelSet->removeLevel(m_level.getPointer());
549 app->getCurrentScene()->notifyCastChange();
550 }
551 }
552 app->getCurrentLevel()->notifyLevelChange();
553 }
554 if (m_oldPalette.getPointer()) {
555 m_level->getPalette()->assign(m_oldPalette->clone());
556 app->getPaletteController()
557 ->getCurrentLevelPalette()
558 ->notifyPaletteChanged();
559 }
560 if (m_renumberedLevel) {
561 TXsheet *xsh = app->getCurrentScene()->getScene()->getTopXsheet();
562 std::vector<TXshChildLevel *> childLevels;
563 ToolUtils::doUpdateXSheet(m_level.getPointer(), m_newFids, m_oldFids, xsh,
564 childLevels);
565 m_level->renumber(m_oldFids);
566 app->getCurrentXsheet()->notifyXsheetChanged();
567 }
568 }
569
570 //------------------------------------------------------------------------------------------
571
notifyImageChanged() const572 void ToolUtils::TToolUndo::notifyImageChanged() const {
573 TTool::Application *app = TTool::getApplication();
574
575 TXshSimpleLevel *currentSl = 0;
576 TFrameId currentFrameId;
577 if (app->getCurrentFrame()->isEditingLevel()) {
578 TXshLevel *xl = app->getCurrentLevel()->getLevel();
579 if (!xl) return;
580 currentSl = xl->getSimpleLevel();
581 currentFrameId = app->getCurrentFrame()->getFid();
582 } else {
583 int row = app->getCurrentFrame()->getFrame();
584 int col = app->getCurrentColumn()->getColumnIndex();
585 if (col < 0) return;
586 TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
587 if (!xsh) return;
588 TXshCell cell = xsh->getCell(row, col);
589 currentSl = cell.getSimpleLevel();
590 currentFrameId = cell.getFrameId();
591 }
592 if (currentSl == m_level.getPointer() && currentFrameId == m_frameId) {
593 TTool *tool = app->getCurrentTool()->getTool();
594 if (tool) tool->onImageChanged();
595 }
596
597 IconGenerator::instance()->invalidate(m_level.getPointer(), m_frameId);
598 IconGenerator::instance()->invalidateSceneIcon();
599
600 if (m_level && m_level->getType() == PLI_XSHLEVEL) {
601 std::string id = m_level->getImageId(m_frameId) + "_rasterized";
602 ImageManager::instance()->invalidate(id);
603 }
604 }
605
606 int ToolUtils::TToolUndo::m_idCount = 0;
607
608 //================================================================================================
609
610 //================================================================================================
611
TRasterUndo(TTileSetCM32 * tiles,TXshSimpleLevel * level,const TFrameId & frameId,bool createdFrame,bool createdLevel,const TPaletteP & oldPalette)612 ToolUtils::TRasterUndo::TRasterUndo(TTileSetCM32 *tiles, TXshSimpleLevel *level,
613 const TFrameId &frameId, bool createdFrame,
614 bool createdLevel,
615 const TPaletteP &oldPalette)
616 : TToolUndo(level, frameId, createdFrame, createdLevel, oldPalette)
617 , m_tiles(tiles) {}
618
619 //------------------------------------------------------------------------------------------
620
~TRasterUndo()621 ToolUtils::TRasterUndo::~TRasterUndo() {
622 if (m_tiles) delete m_tiles;
623 }
624
625 //------------------------------------------------------------------------------------------
626
getImage() const627 TToonzImageP ToolUtils::TRasterUndo::getImage() const {
628 if (m_level->isFid(m_frameId))
629 return (TToonzImageP)m_level->getFrame(m_frameId, true);
630 return 0;
631 }
632
633 //------------------------------------------------------------------------------------------
634
getSize() const635 int ToolUtils::TRasterUndo::getSize() const {
636 int size = sizeof(*this);
637 size += sizeof(*(m_level.getPointer()));
638 size += sizeof(*(m_oldPalette.getPointer()));
639 return m_tiles ? m_tiles->getMemorySize() + size : size;
640 }
641
642 //------------------------------------------------------------------------------------------
643
undo() const644 void ToolUtils::TRasterUndo::undo() const {
645 TTool::Application *app = TTool::getApplication();
646 if (!app) return;
647
648 if (m_tiles && m_tiles->getTileCount() > 0) {
649 TToonzImageP image = getImage();
650 if (!image) return;
651
652 ToonzImageUtils::paste(image, m_tiles);
653 ToolUtils::updateSaveBox(m_level, m_frameId);
654 }
655
656 removeLevelAndFrameIfNeeded();
657
658 app->getCurrentXsheet()->notifyXsheetChanged();
659 notifyImageChanged();
660 }
661
662 //================================================================================================
663
664 //================================================================================================
665
TFullColorRasterUndo(TTileSetFullColor * tiles,TXshSimpleLevel * level,const TFrameId & frameId,bool createdFrame,bool createdLevel,const TPaletteP & oldPalette)666 ToolUtils::TFullColorRasterUndo::TFullColorRasterUndo(
667 TTileSetFullColor *tiles, TXshSimpleLevel *level, const TFrameId &frameId,
668 bool createdFrame, bool createdLevel, const TPaletteP &oldPalette)
669 : TToolUndo(level, frameId, createdFrame, createdLevel, oldPalette)
670 , m_tiles(tiles) {}
671
672 //-----------------------------------------------------------------------------
673
~TFullColorRasterUndo()674 ToolUtils::TFullColorRasterUndo::~TFullColorRasterUndo() { delete m_tiles; }
675
676 //-----------------------------------------------------------------------------
677
getImage() const678 TRasterImageP ToolUtils::TFullColorRasterUndo::getImage() const {
679 if (m_level->isFid(m_frameId))
680 return (TRasterImageP)m_level->getFrame(m_frameId, true);
681 return 0;
682 }
683
684 //-----------------------------------------------------------------------------
685
getSize() const686 int ToolUtils::TFullColorRasterUndo::getSize() const {
687 int size = sizeof(*this);
688 size += sizeof(*(m_level.getPointer()));
689 size += sizeof(*(m_oldPalette.getPointer()));
690 return m_tiles ? m_tiles->getMemorySize() + size : size;
691 }
692
693 //-----------------------------------------------------------------------------
694
undo() const695 void ToolUtils::TFullColorRasterUndo::undo() const {
696 TTool::Application *app = TTool::getApplication();
697 if (!app) return;
698
699 if (m_tiles && m_tiles->getTileCount() > 0) {
700 TRasterImageP image = getImage();
701 if (!image) return;
702 std::vector<TRect> rects = paste(image, m_tiles);
703 int i;
704 TRect resRect = rects[0];
705 for (i = 1; i < (int)rects.size(); i++) resRect += rects[i];
706 }
707
708 removeLevelAndFrameIfNeeded();
709
710 app->getCurrentXsheet()->notifyXsheetChanged();
711 notifyImageChanged();
712 }
713
714 //-----------------------------------------------------------------------------
715
paste(const TRasterImageP & ti,const TTileSetFullColor * tileSet) const716 std::vector<TRect> ToolUtils::TFullColorRasterUndo::paste(
717 const TRasterImageP &ti, const TTileSetFullColor *tileSet) const {
718 std::vector<TRect> rects;
719 TRasterP raster = ti->getRaster();
720 for (int i = 0; i < tileSet->getTileCount(); i++) {
721 const TTileSetFullColor::Tile *tile = tileSet->getTile(i);
722 TRasterP ras;
723 tile->getRaster(ras);
724 assert(!!ras);
725 raster->copy(ras, tile->m_rasterBounds.getP00());
726 rects.push_back(tile->m_rasterBounds);
727 }
728 return rects;
729 }
730
731 //================================================================================================
732
733 //================================================================================================
734
UndoModifyStroke(TXshSimpleLevel * level,const TFrameId & frameId,int strokeIndex)735 ToolUtils::UndoModifyStroke::UndoModifyStroke(TXshSimpleLevel *level,
736 const TFrameId &frameId,
737 int strokeIndex)
738 : TToolUndo(level, frameId), m_strokeIndex(strokeIndex) {
739 TVectorImageP image = level->getFrame(frameId, true);
740 assert(image);
741 TStroke *stroke = image->getStroke(m_strokeIndex);
742 int n = stroke->getControlPointCount();
743 for (int i = 0; i < n; i++) m_before.push_back(stroke->getControlPoint(i));
744
745 m_selfLoopBefore = stroke->isSelfLoop();
746
747 TTool::Application *app = TTool::getApplication();
748 m_row = app->getCurrentFrame()->getFrame();
749 m_column = app->getCurrentColumn()->getColumnIndex();
750 }
751
752 //-----------------------------------------------------------------------------
753
~UndoModifyStroke()754 ToolUtils::UndoModifyStroke::~UndoModifyStroke() {}
755
756 //-----------------------------------------------------------------------------
757
onAdd()758 void ToolUtils::UndoModifyStroke::onAdd() {
759 TVectorImageP image = m_level->getFrame(m_frameId, true);
760 assert(image);
761 if (!image) return;
762
763 TStroke *stroke = image->getStroke(m_strokeIndex);
764 assert(stroke);
765 int n = stroke->getControlPointCount();
766 for (int i = 0; i < n; i++) m_after.push_back(stroke->getControlPoint(i));
767
768 m_selfLoopAfter = stroke->isSelfLoop();
769 }
770
771 //-----------------------------------------------------------------------------
772
undo() const773 void ToolUtils::UndoModifyStroke::undo() const {
774 TTool::Application *app = TTool::getApplication();
775 if (!app) return;
776
777 if (app->getCurrentFrame()->isEditingScene()) {
778 app->getCurrentColumn()->setColumnIndex(m_column);
779 app->getCurrentFrame()->setFrame(m_row);
780 } else
781 app->getCurrentFrame()->setFid(m_frameId);
782
783 TSelection *selection = app->getCurrentSelection()->getSelection();
784 if (selection) selection->selectNone();
785
786 TVectorImageP image = m_level->getFrame(m_frameId, true);
787 assert(image);
788 if (!image) return;
789 QMutexLocker lock(image->getMutex());
790 TStroke *stroke = 0;
791 if (image->getStrokeCount() ==
792 1) // && image->getStroke(0)->getStyle()==SplineStyle)
793 stroke = image->getStroke(0);
794 else
795 stroke = image->getStroke(m_strokeIndex);
796 if (!stroke) return;
797 TStroke *oldStroke = new TStroke(*stroke);
798 stroke->reshape(&m_before[0], m_before.size());
799 stroke->setSelfLoop(m_selfLoopBefore);
800 image->notifyChangedStrokes(m_strokeIndex, oldStroke);
801 notifyImageChanged();
802 delete oldStroke;
803 }
804
805 //-----------------------------------------------------------------------------
806
redo() const807 void ToolUtils::UndoModifyStroke::redo() const {
808 TTool::Application *app = TTool::getApplication();
809 if (!app) return;
810
811 if (app->getCurrentFrame()->isEditingScene()) {
812 app->getCurrentColumn()->setColumnIndex(m_column);
813 app->getCurrentFrame()->setFrame(m_row);
814 } else
815 app->getCurrentFrame()->setFid(m_frameId);
816
817 TSelection *selection = app->getCurrentSelection()->getSelection();
818 if (selection) selection->selectNone();
819
820 TVectorImageP image = m_level->getFrame(m_frameId, true);
821 assert(image);
822 if (!image) return;
823 QMutexLocker lock(image->getMutex());
824 TStroke *stroke = 0;
825 if (image->getStrokeCount() ==
826 1) //&& image->getStroke(0)->getStyle()==SplineStyle)
827 stroke = image->getStroke(0);
828 else
829 stroke = image->getStroke(m_strokeIndex);
830 if (!stroke) return;
831 TStroke *oldStroke = new TStroke(*stroke);
832 stroke->reshape(&m_after[0], m_after.size());
833 stroke->setSelfLoop(m_selfLoopAfter);
834 image->notifyChangedStrokes(m_strokeIndex, oldStroke);
835 delete oldStroke;
836 app->getCurrentXsheet()->notifyXsheetChanged();
837 notifyImageChanged();
838 }
839
840 //-----------------------------------------------------------------------------
841
getSize() const842 int ToolUtils::UndoModifyStroke::getSize() const {
843 return (m_before.capacity() + m_after.capacity()) * sizeof(TThickPoint) +
844 sizeof(*this) + 500;
845 }
846
847 //-----------------------------------------------------------------------------
848
UndoModifyStrokeAndPaint(TXshSimpleLevel * level,const TFrameId & frameId,int strokeIndex)849 ToolUtils::UndoModifyStrokeAndPaint::UndoModifyStrokeAndPaint(
850 TXshSimpleLevel *level, const TFrameId &frameId, int strokeIndex)
851 : UndoModifyStroke(level, frameId, strokeIndex), m_fillInformation(0) {
852 TVectorImageP image = level->getFrame(frameId, true);
853 assert(image);
854 TStroke *stroke = image->getStroke(strokeIndex);
855 m_oldBBox = stroke->getBBox();
856 }
857
858 //-----------------------------------------------------------------------------
859
onAdd()860 void ToolUtils::UndoModifyStrokeAndPaint::onAdd() {
861 TVectorImageP image = m_level->getFrame(m_frameId, true);
862 assert(!!image);
863 if (!image) return;
864
865 UndoModifyStroke::onAdd();
866 TStroke *stroke = image->getStroke(m_strokeIndex);
867 m_fillInformation = new std::vector<TFilledRegionInf>;
868 ImageUtils::getFillingInformationOverlappingArea(
869 image, *m_fillInformation, m_oldBBox, stroke->getBBox());
870 }
871
872 //-----------------------------------------------------------------------------
873
undo() const874 void ToolUtils::UndoModifyStrokeAndPaint::undo() const {
875 TTool::Application *application = TTool::getApplication();
876 if (!application) return;
877
878 UndoModifyStroke::undo();
879 TRegion *reg;
880 UINT size = m_fillInformation->size();
881 if (!size) {
882 application->getCurrentXsheet()->notifyXsheetChanged();
883 notifyImageChanged();
884 return;
885 }
886
887 TVectorImageP image = m_level->getFrame(m_frameId, true);
888 assert(!!image);
889 if (!image) return;
890
891 // image->validateRegions();
892 image->findRegions();
893 for (UINT i = 0; i < size; i++) {
894 reg = image->getRegion((*m_fillInformation)[i].m_regionId);
895 assert(reg);
896 if (reg) reg->setStyle((*m_fillInformation)[i].m_styleId);
897 }
898
899 application->getCurrentXsheet()->notifyXsheetChanged();
900 notifyImageChanged();
901 }
902 //-----------------------------------------------------------------------------
903
~UndoModifyStrokeAndPaint()904 ToolUtils::UndoModifyStrokeAndPaint::~UndoModifyStrokeAndPaint() {
905 delete m_fillInformation;
906 }
907
908 //-----------------------------------------------------------------------------
909
getSize() const910 int ToolUtils::UndoModifyStrokeAndPaint::getSize() const {
911 int size = m_fillInformation
912 ? m_fillInformation->size() * sizeof(TFilledRegionInf)
913 : 0;
914 return UndoModifyStroke::getSize() + size;
915 }
916
917 //-----------------------------------------------------------------------------
918
UndoModifyListStroke(TXshSimpleLevel * level,const TFrameId & frameId,const std::vector<TStroke * > & strokeVect)919 ToolUtils::UndoModifyListStroke::UndoModifyListStroke(
920 TXshSimpleLevel *level, const TFrameId &frameId,
921 const std::vector<TStroke *> &strokeVect)
922 : TToolUndo(level, frameId), m_fillInformation(0) {
923 UINT strokeNum = strokeVect.size();
924 TVectorImageP image = level->getFrame(frameId, true);
925 assert(image);
926 for (UINT i = 0; i < strokeNum; i++) {
927 m_oldBBox += (strokeVect[i])->getBBox();
928 int strokeIndex = image->getStrokeIndex(strokeVect[i]);
929 m_strokeList.push_back(new UndoModifyStroke(level, frameId, strokeIndex));
930 }
931
932 m_beginIt = m_strokeList.begin();
933 m_endIt = m_strokeList.end();
934 }
935
936 //-----------------------------------------------------------------------------
937
~UndoModifyListStroke()938 ToolUtils::UndoModifyListStroke::~UndoModifyListStroke() {
939 clearPointerContainer(m_strokeList);
940 delete m_fillInformation;
941 }
942
943 //-----------------------------------------------------------------------------
944
onAdd()945 void ToolUtils::UndoModifyListStroke::onAdd() {
946 std::list<UndoModifyStroke *>::iterator it = m_beginIt;
947 TRectD newBBox;
948
949 TVectorImageP image = m_level->getFrame(m_frameId, true);
950 assert(!!image);
951 if (!image) return;
952
953 for (; it != m_endIt; ++it) {
954 TStroke *s = image->getStroke((*it)->m_strokeIndex);
955 (*it)->onAdd();
956 }
957 m_fillInformation = new std::vector<TFilledRegionInf>;
958
959 if (m_beginIt != m_endIt)
960 ImageUtils::getFillingInformationOverlappingArea(image, *m_fillInformation,
961 m_oldBBox, newBBox);
962 }
963
964 //-----------------------------------------------------------------------------
965
undo() const966 void ToolUtils::UndoModifyListStroke::undo() const {
967 TTool::Application *app = TTool::getApplication();
968 if (!app) return;
969
970 std::list<UndoModifyStroke *>::iterator stroke_it = m_beginIt;
971 if (m_beginIt == m_endIt) return;
972
973 for (; stroke_it != m_endIt; ++stroke_it) {
974 (*stroke_it)->undo();
975 }
976
977 UINT size = m_fillInformation->size();
978 if (!size) {
979 app->getCurrentXsheet()->notifyXsheetChanged();
980 app->getCurrentTool()->getTool()->notifyImageChanged();
981 return;
982 }
983
984 TVectorImageP image = m_level->getFrame(m_frameId, true);
985 assert(!!image);
986 if (!image) return;
987
988 image->findRegions();
989
990 TRegion *reg;
991 for (UINT i = 0; i < size; i++) {
992 reg = image->getRegion((*m_fillInformation)[i].m_regionId);
993 assert(reg);
994 if (reg) reg->setStyle((*m_fillInformation)[i].m_styleId);
995 }
996 app->getCurrentXsheet()->notifyXsheetChanged();
997 notifyImageChanged();
998 }
999
1000 //-----------------------------------------------------------------------------
1001
redo() const1002 void ToolUtils::UndoModifyListStroke::redo() const {
1003 TTool::Application *app = TTool::getApplication();
1004 if (!app) return;
1005
1006 std::list<UndoModifyStroke *>::iterator it = m_beginIt;
1007
1008 for (; it != m_endIt; ++it) {
1009 (*it)->redo();
1010 }
1011
1012 app->getCurrentXsheet()->notifyXsheetChanged();
1013 notifyImageChanged();
1014 }
1015
1016 //-----------------------------------------------------------------------------
1017
getSize() const1018 int ToolUtils::UndoModifyListStroke::getSize() const {
1019 int sum = 0;
1020
1021 std::list<UndoModifyStroke *>::iterator it = m_beginIt;
1022
1023 for (; it != m_endIt; ++it) {
1024 sum += (*it)->getSize();
1025 }
1026
1027 if (m_fillInformation)
1028 sum += m_fillInformation->capacity() * sizeof(TFilledRegionInf);
1029
1030 return sum;
1031 }
1032
1033 //=============================================================================================
1034
UndoPencil(TStroke * stroke,std::vector<TFilledRegionInf> * fillInformation,TXshSimpleLevel * level,const TFrameId & frameId,bool createdFrame,bool createdLevel,bool autogroup,bool autofill)1035 ToolUtils::UndoPencil::UndoPencil(
1036 TStroke *stroke, std::vector<TFilledRegionInf> *fillInformation,
1037 TXshSimpleLevel *level, const TFrameId &frameId, bool createdFrame,
1038 bool createdLevel, bool autogroup, bool autofill)
1039 : TToolUndo(level, frameId, createdFrame, createdLevel, 0)
1040 , m_strokeId(stroke->getId())
1041 , m_fillInformation(fillInformation)
1042 , m_autogroup(autogroup)
1043 , m_autofill(autofill) {
1044 m_stroke = new TStroke(*stroke);
1045 }
1046
1047 //-----------------------------------------------------------------------------
1048
~UndoPencil()1049 ToolUtils::UndoPencil::~UndoPencil() {
1050 delete m_fillInformation;
1051 delete m_stroke;
1052 }
1053
1054 //-----------------------------------------------------------------------------
1055
undo() const1056 void ToolUtils::UndoPencil::undo() const {
1057 TTool::Application *app = TTool::getApplication();
1058 if (!app) return;
1059
1060 /*if(app->getCurrentFrame()->isEditingScene() && m_col!=-2 && m_row!=-1)
1061 {
1062 app->getCurrentColumn()->setColumnIndex(m_col);
1063 app->getCurrentFrame()->setFrame(m_row);
1064 }
1065 else
1066 app->getCurrentFrame()->setFid(m_frameId);*/
1067
1068 TVectorImageP image = m_level->getFrame(m_frameId, true);
1069 assert(image);
1070 if (!image) return;
1071
1072 QMutexLocker sl(image->getMutex());
1073 VIStroke *stroke = image->getStrokeById(m_strokeId);
1074 if (!stroke) return;
1075 image->deleteStroke(stroke);
1076 TSelection *selection = app->getCurrentSelection()->getSelection();
1077 StrokeSelection *strokeSelection = dynamic_cast<StrokeSelection *>(selection);
1078 if (strokeSelection) strokeSelection->selectNone();
1079
1080 UINT size = m_fillInformation->size();
1081 TRegion *reg;
1082 for (UINT i = 0; i < size; i++) {
1083 reg = image->getRegion((*m_fillInformation)[i].m_regionId);
1084 assert(reg);
1085 if (reg) reg->setStyle((*m_fillInformation)[i].m_styleId);
1086 }
1087
1088 removeLevelAndFrameIfNeeded();
1089
1090 app->getCurrentXsheet()->notifyXsheetChanged();
1091 notifyImageChanged();
1092 }
1093
1094 //-----------------------------------------------------------------------------
1095
redo() const1096 void ToolUtils::UndoPencil::redo() const {
1097 TTool::Application *app = TTool::getApplication();
1098 if (!app) return;
1099
1100 insertLevelAndFrameIfNeeded();
1101
1102 /*if(app->getCurrentFrame()->isEditingScene())
1103 {
1104 app->getCurrentColumn()->setColumnIndex(m_col);
1105 app->getCurrentFrame()->setFrame(m_row);
1106 }
1107 else
1108 app->getCurrentFrame()->setFid(m_frameId);*/
1109
1110 TVectorImageP image = m_level->getFrame(m_frameId, true);
1111 if (!image) return;
1112
1113 QMutexLocker sl(image->getMutex());
1114 TStroke *stroke = new TStroke(*m_stroke);
1115 stroke->setId(m_strokeId);
1116 image->addStroke(stroke);
1117 if (image->isComputedRegionAlmostOnce()) image->findRegions();
1118
1119 if (m_autogroup && stroke->isSelfLoop()) {
1120 int index = image->getStrokeCount() - 1;
1121 image->group(index, 1);
1122 if (m_autofill) {
1123 // to avoid filling other strokes, I enter into the new stroke group
1124 int currentGroup = image->exitGroup();
1125 image->enterGroup(index);
1126 image->selectFill(stroke->getBBox().enlarge(1, 1), 0, stroke->getStyle(),
1127 false, true, false);
1128 if (currentGroup != -1)
1129 image->enterGroup(currentGroup);
1130 else
1131 image->exitGroup();
1132 }
1133 }
1134 app->getCurrentXsheet()->notifyXsheetChanged();
1135 notifyImageChanged();
1136 }
1137
1138 //-----------------------------------------------------------------------------
1139
getSize() const1140 int ToolUtils::UndoPencil::getSize() const {
1141 return sizeof(*this) +
1142 m_fillInformation->capacity() * sizeof(TFilledRegionInf) + 500;
1143 }
1144
1145 //=============================================================================================
1146
UndoRasterPencil(TXshSimpleLevel * level,const TFrameId & frameId,TStroke * stroke,bool selective,bool filled,bool doAntialias,bool createdFrame,bool createdLevel,std::string primitiveName)1147 ToolUtils::UndoRasterPencil::UndoRasterPencil(
1148 TXshSimpleLevel *level, const TFrameId &frameId, TStroke *stroke,
1149 bool selective, bool filled, bool doAntialias, bool createdFrame,
1150 bool createdLevel, std::string primitiveName)
1151 : TRasterUndo(0, level, frameId, createdFrame, createdLevel, 0)
1152 , m_selective(selective)
1153 , m_filled(filled)
1154 , m_doAntialias(doAntialias)
1155 , m_primitiveName(primitiveName) {
1156 TRasterCM32P raster = getImage()->getRaster();
1157 TDimension d = raster->getSize();
1158 m_tiles = new TTileSetCM32(d);
1159 TRect rect =
1160 convert(stroke->getBBox()) + TPoint((int)(d.lx * 0.5), (int)(d.ly * 0.5));
1161 m_tiles->add(raster, rect.enlarge(2));
1162 m_stroke = new TStroke(*stroke);
1163 }
1164
1165 //-----------------------------------------------------------------------------
1166
~UndoRasterPencil()1167 ToolUtils::UndoRasterPencil::~UndoRasterPencil() { delete m_stroke; }
1168
1169 //-----------------------------------------------------------------------------
1170
redo() const1171 void ToolUtils::UndoRasterPencil::redo() const {
1172 insertLevelAndFrameIfNeeded();
1173 TToonzImageP image = getImage();
1174 if (!image) return;
1175
1176 ToonzImageUtils::addInkStroke(image, m_stroke, m_stroke->getStyle(),
1177 m_selective, m_filled, TConsts::infiniteRectD,
1178 m_doAntialias);
1179 ToolUtils::updateSaveBox();
1180 TTool::getApplication()->getCurrentXsheet()->notifyXsheetChanged();
1181 notifyImageChanged();
1182 }
1183
1184 //-----------------------------------------------------------------------------
1185
getSize() const1186 int ToolUtils::UndoRasterPencil::getSize() const {
1187 return TRasterUndo::getSize() +
1188 m_stroke->getControlPointCount() * sizeof(TThickPoint) + 100 +
1189 sizeof(this);
1190 }
1191
1192 //=============================================================================================
1193
UndoFullColorPencil(TXshSimpleLevel * level,const TFrameId & frameId,TStroke * stroke,double opacity,bool doAntialias,bool createdFrame,bool createdLevel)1194 ToolUtils::UndoFullColorPencil::UndoFullColorPencil(
1195 TXshSimpleLevel *level, const TFrameId &frameId, TStroke *stroke,
1196 double opacity, bool doAntialias, bool createdFrame, bool createdLevel)
1197 : TFullColorRasterUndo(0, level, frameId, createdFrame, createdLevel, 0)
1198 , m_opacity(opacity)
1199 , m_doAntialias(doAntialias) {
1200 TRasterP raster = getImage()->getRaster();
1201 TDimension d = raster->getSize();
1202 m_tiles = new TTileSetFullColor(d);
1203 TRect rect =
1204 convert(stroke->getBBox()) + TPoint((int)(d.lx * 0.5), (int)(d.ly * 0.5));
1205 m_tiles->add(raster, rect.enlarge(2));
1206 m_stroke = new TStroke(*stroke);
1207 }
1208
1209 //-----------------------------------------------------------------------------
1210
~UndoFullColorPencil()1211 ToolUtils::UndoFullColorPencil::~UndoFullColorPencil() { delete m_stroke; }
1212
1213 //-----------------------------------------------------------------------------
1214
redo() const1215 void ToolUtils::UndoFullColorPencil::redo() const {
1216 insertLevelAndFrameIfNeeded();
1217 TRasterImageP image = getImage();
1218 if (!image) return;
1219 TRasterImageUtils::addStroke(image, m_stroke, TRectD(), m_opacity,
1220 m_doAntialias);
1221 TTool::getApplication()->getCurrentXsheet()->notifyXsheetChanged();
1222 notifyImageChanged();
1223 }
1224
1225 //-----------------------------------------------------------------------------
1226
getSize() const1227 int ToolUtils::UndoFullColorPencil::getSize() const {
1228 return TFullColorRasterUndo::getSize() +
1229 m_stroke->getControlPointCount() * sizeof(TThickPoint) + 100 +
1230 sizeof(this);
1231 }
1232
1233 //=============================================================================================
1234 //
1235 // undo class (path strokes). call it BEFORE and register it AFTER path change
1236 //
UndoPath(TStageObjectSpline * spline)1237 ToolUtils::UndoPath::UndoPath(TStageObjectSpline *spline) : m_spline(spline) {
1238 assert(!!m_spline);
1239
1240 const TStroke *stroke = m_spline->getStroke();
1241 assert(stroke);
1242 int n = stroke->getControlPointCount();
1243 for (int i = 0; i < n; i++) m_before.push_back(stroke->getControlPoint(i));
1244 m_selfLoopBefore = stroke->isSelfLoop();
1245 }
1246
~UndoPath()1247 ToolUtils::UndoPath::~UndoPath() {}
1248
onAdd()1249 void ToolUtils::UndoPath::onAdd() {
1250 assert(!!m_spline);
1251
1252 const TStroke *stroke = m_spline->getStroke();
1253 assert(stroke);
1254 int n = stroke->getControlPointCount();
1255 for (int i = 0; i < n; i++) m_after.push_back(stroke->getControlPoint(i));
1256 }
1257
undo() const1258 void ToolUtils::UndoPath::undo() const {
1259 assert(!!m_spline);
1260
1261 TTool::Application *app = TTool::getApplication();
1262 TSelection *selection = app->getCurrentSelection()->getSelection();
1263 if (selection) selection->selectNone();
1264
1265 TStroke *stroke = new TStroke(*m_spline->getStroke());
1266 stroke->reshape(&m_before[0], m_before.size());
1267 stroke->setSelfLoop(m_selfLoopBefore);
1268 m_spline->setStroke(stroke);
1269
1270 if (!app->getCurrentObject()->isSpline()) return;
1271
1272 TStageObjectId currentObjectId = app->getCurrentObject()->getObjectId();
1273 TStageObject *stageObject =
1274 app->getCurrentXsheet()->getXsheet()->getStageObject(currentObjectId);
1275 if (stageObject->getSpline()->getId() == m_spline->getId())
1276 app->getCurrentObject()->setSplineObject(m_spline);
1277
1278 app->getCurrentTool()->getTool()->notifyImageChanged();
1279 }
1280
redo() const1281 void ToolUtils::UndoPath::redo() const {
1282 assert(!!m_spline);
1283
1284 TTool::Application *app = TTool::getApplication();
1285 TSelection *selection = app->getCurrentSelection()->getSelection();
1286 if (selection) selection->selectNone();
1287
1288 TStroke *stroke = new TStroke(*m_spline->getStroke());
1289 stroke->reshape(&m_after[0], m_after.size());
1290 stroke->setSelfLoop(m_selfLoopBefore);
1291 m_spline->setStroke(stroke);
1292
1293 if (!app->getCurrentObject()->isSpline()) return;
1294
1295 TStageObjectId currentObjectId = app->getCurrentObject()->getObjectId();
1296 TStageObject *stageObject =
1297 app->getCurrentXsheet()->getXsheet()->getStageObject(currentObjectId);
1298 if (stageObject->getSpline()->getId() == m_spline->getId())
1299 app->getCurrentObject()->setSplineObject(m_spline);
1300
1301 app->getCurrentTool()->getTool()->notifyImageChanged();
1302 }
1303
getSize() const1304 int ToolUtils::UndoPath::getSize() const { return sizeof(*this) + 500; }
1305
1306 //=============================================================================================
1307 //
1308 // UndoControlPointEditor
1309 //
1310
UndoControlPointEditor(TXshSimpleLevel * level,const TFrameId & frameId)1311 ToolUtils::UndoControlPointEditor::UndoControlPointEditor(
1312 TXshSimpleLevel *level, const TFrameId &frameId)
1313 : TToolUndo(level, frameId), m_isStrokeDelete(false) {
1314 TVectorImageP image = level->getFrame(frameId, true);
1315 assert(image);
1316 if (!image) return;
1317
1318 TTool::Application *app = TTool::getApplication();
1319 if (!app) return;
1320
1321 m_row = app->getCurrentFrame()->getFrame();
1322 m_column = app->getCurrentColumn()->getColumnIndex();
1323 }
1324
~UndoControlPointEditor()1325 ToolUtils::UndoControlPointEditor::~UndoControlPointEditor() {
1326 deleteVIStroke(m_oldStroke.second);
1327 if (!m_isStrokeDelete) deleteVIStroke(m_newStroke.second);
1328 }
1329
onAdd()1330 void ToolUtils::UndoControlPointEditor::onAdd() {
1331 TVectorImageP image = m_level->getFrame(m_frameId, true);
1332 assert(image);
1333 if (!image) return;
1334 QMutexLocker lock(image->getMutex());
1335 if (m_isStrokeDelete) return;
1336 addNewStroke(m_oldStroke.first, image->getVIStroke(m_oldStroke.first));
1337 }
1338
addOldStroke(int index,VIStroke * vs)1339 void ToolUtils::UndoControlPointEditor::addOldStroke(int index, VIStroke *vs) {
1340 VIStroke *s = cloneVIStroke(vs);
1341 m_oldStroke = std::make_pair(index, s);
1342 }
1343
addNewStroke(int index,VIStroke * vs)1344 void ToolUtils::UndoControlPointEditor::addNewStroke(int index, VIStroke *vs) {
1345 VIStroke *s = cloneVIStroke(vs);
1346 m_newStroke = std::make_pair(index, s);
1347 }
1348
undo() const1349 void ToolUtils::UndoControlPointEditor::undo() const {
1350 TTool::Application *app = TTool::getApplication();
1351 if (!app) return;
1352
1353 if (app->getCurrentFrame()->isEditingScene()) {
1354 app->getCurrentColumn()->setColumnIndex(m_column);
1355 app->getCurrentFrame()->setFrame(m_row);
1356 } else
1357 app->getCurrentFrame()->setFid(m_frameId);
1358
1359 TSelection *selection = app->getCurrentSelection()->getSelection();
1360 if (selection) selection->selectNone();
1361 TVectorImageP image = m_level->getFrame(m_frameId, true);
1362 assert(image);
1363 if (!image) return;
1364 QMutexLocker lock(image->getMutex());
1365
1366 if (!m_isStrokeDelete) image->removeStroke(m_newStroke.first, false);
1367
1368 UINT i = 0;
1369 VIStroke *s = cloneVIStroke(m_oldStroke.second);
1370 image->insertStrokeAt(s, m_oldStroke.first);
1371
1372 if (image->isComputedRegionAlmostOnce())
1373 image->findRegions(); // in futuro togliere. Serve perche' la
1374 // removeStrokes, se gli si dice
1375 // di non calcolare le regioni, e' piu' veloce ma poi chrash tutto
1376
1377 app->getCurrentXsheet()->notifyXsheetChanged();
1378 notifyImageChanged();
1379 }
1380
redo() const1381 void ToolUtils::UndoControlPointEditor::redo() const {
1382 TTool::Application *app = TTool::getApplication();
1383 if (!app) return;
1384
1385 if (app->getCurrentFrame()->isEditingScene()) {
1386 app->getCurrentColumn()->setColumnIndex(m_column);
1387 app->getCurrentFrame()->setFrame(m_row);
1388 } else
1389 app->getCurrentFrame()->setFid(m_frameId);
1390 TSelection *selection = app->getCurrentSelection()->getSelection();
1391 if (selection) selection->selectNone();
1392 TVectorImageP image = m_level->getFrame(m_frameId, true);
1393 assert(image);
1394 if (!image) return;
1395 QMutexLocker lock(image->getMutex());
1396
1397 image->removeStroke(m_oldStroke.first, false);
1398
1399 if (!m_isStrokeDelete) {
1400 VIStroke *s = cloneVIStroke(m_newStroke.second);
1401 image->insertStrokeAt(s, m_newStroke.first);
1402 }
1403
1404 if (image->isComputedRegionAlmostOnce())
1405 image->findRegions(); // in futuro togliere. Serve perche' la
1406 // removeStrokes, se gli si dice
1407 // di non calcolare le regioni, e' piu' veloce ma poi chrash tutto
1408
1409 app->getCurrentXsheet()->notifyXsheetChanged();
1410 notifyImageChanged();
1411 }
1412
1413 //=============================================================================================
1414 //
1415 // Menu
1416 //
1417
DragMenu()1418 ToolUtils::DragMenu::DragMenu() : QMenu() {}
1419
1420 //-----------------------------------------------------------------------------
1421
exec(const QPoint & p,QAction * action)1422 QAction *ToolUtils::DragMenu::exec(const QPoint &p, QAction *action) {
1423 QAction *execAct = QMenu::exec(p, action);
1424 if (execAct) return execAct;
1425
1426 return defaultAction();
1427 }
1428
1429 //---------------------------------------------------------------------------------------------
1430
mouseReleaseEvent(QMouseEvent * e)1431 void ToolUtils::DragMenu::mouseReleaseEvent(QMouseEvent *e) {
1432 QMenu::mouseReleaseEvent(e);
1433 hide();
1434 }
1435
1436 //=============================================================================================
1437 //
1438 // ColumChooserMenu
1439 //
1440
ColumChooserMenu(TXsheet * xsh,const std::vector<int> & columnIndexes)1441 ToolUtils::ColumChooserMenu::ColumChooserMenu(
1442 TXsheet *xsh, const std::vector<int> &columnIndexes)
1443 : DragMenu() {
1444 int size = columnIndexes.size();
1445 int i;
1446 for (i = size - 1; i >= 0; i--) {
1447 int index = columnIndexes[i];
1448 TStageObjectId id = TStageObjectId::ColumnId(index);
1449 TStageObject *stageObject = xsh->getStageObject(id);
1450 QString cmdStr = "Column " + QString::fromStdString(stageObject->getName());
1451 QAction *act = new QAction(cmdStr, this);
1452 act->setData(index);
1453 addAction(act);
1454 if (size - 1 == i) {
1455 setDefaultAction(act);
1456 setActiveAction(act);
1457 }
1458 }
1459 }
1460
1461 //---------------------------------------------------------------------------------------------
1462
execute()1463 int ToolUtils::ColumChooserMenu::execute() {
1464 QAction *executeAct = exec(QCursor::pos());
1465 return (!executeAct) ? -1 : executeAct->data().toInt();
1466 }
1467
1468 //---------------------------------------------------------------------------------------------
1469
compute(double cover)1470 double ToolUtils::ConeSubVolume::compute(double cover) {
1471 double x = (10 * tcrop(cover, -1.0, 1.0)) + 10;
1472 assert(0 <= x && x <= 20);
1473 int i = tfloor(x);
1474 if (i == 20)
1475 return m_values[i];
1476 else
1477 // Interpolazione lineare.
1478 return (-(x - (i + 1)) * m_values[i]) - (-(x - i) * m_values[i + 1]);
1479 }
1480
1481 const double ToolUtils::ConeSubVolume::m_values[] = {
1482 1.0, 0.99778, 0.987779, 0.967282, 0.934874, 0.889929, 0.832457,
1483 0.763067, 0.683002, 0.594266, 0.5, 0.405734, 0.316998, 0.236933,
1484 0.167543, 0.110071, 0.0651259, 0.0327182, 0.0122208, 0.00221986, 0.0};
1485
1486 //---------------------------------------------------------------------------------------------
1487
drawBalloon(const TPointD & pos,std::string text,const TPixel32 & color,TPoint delta,double pixelSize,bool isPicking,std::vector<TRectD> * otherBalloons)1488 void ToolUtils::drawBalloon(const TPointD &pos, std::string text,
1489 const TPixel32 &color, TPoint delta,
1490 double pixelSize, bool isPicking,
1491 std::vector<TRectD> *otherBalloons) {
1492 int devPixRatio = getDevPixRatio();
1493 QString qText = QString::fromStdString(text);
1494 QFont font("Arial"); // ,QFont::Bold);
1495 font.setPixelSize(13 * devPixRatio);
1496 QFontMetrics fm(font);
1497 QRect textRect = fm.boundingRect(qText);
1498
1499 int baseLine = -textRect.top();
1500 int mrg = 3 * devPixRatio;
1501
1502 // avoid other balloons
1503 if (otherBalloons) {
1504 QRect tmpTextRect = textRect;
1505 int tmpMrg = mrg;
1506 // for high dpi monitors
1507 if (devPixRatio != 1) {
1508 QFont tmpFont = font;
1509 tmpFont.setPixelSize(13);
1510 QFontMetrics tmpFm(tmpFont);
1511 tmpTextRect = tmpFm.boundingRect(qText);
1512 tmpMrg = 3;
1513 }
1514
1515 std::vector<TRectD> &balloons = *otherBalloons;
1516 int n = (int)balloons.size();
1517 TDimensionD balloonSize(pixelSize * (tmpTextRect.width() + tmpMrg * 2),
1518 pixelSize * (tmpTextRect.height() + tmpMrg * 2));
1519 TRectD balloonRect;
1520 for (;;) {
1521 balloonRect = TRectD(
1522 pos + TPointD(delta.x * pixelSize, delta.y * pixelSize), balloonSize);
1523 int i = 0;
1524 while (i < n && !balloons[i].overlaps(balloonRect)) i++;
1525 if (i == n) break;
1526 double y = balloons[i].y0 - balloonSize.ly - 2 * tmpMrg * pixelSize;
1527 delta.y = (y - pos.y) / pixelSize;
1528 }
1529 balloons.push_back(balloonRect);
1530 }
1531
1532 delta.x *= devPixRatio;
1533 delta.y *= devPixRatio;
1534
1535 textRect.moveTo(std::max(delta.x, 10 * devPixRatio + mrg),
1536 std::max(mrg + 2 * devPixRatio, -delta.y - baseLine));
1537
1538 int y = textRect.top() + baseLine;
1539 int x0 = textRect.left() - mrg;
1540 int x1 = textRect.right() + mrg;
1541 int y0 = textRect.top() - mrg;
1542 int y1 = textRect.bottom() + mrg;
1543
1544 if (isPicking) {
1545 TTool::Viewer *viewer =
1546 TTool::getApplication()->getCurrentTool()->getTool()->getViewer();
1547
1548 if (viewer->is3DView()) {
1549 double x0 = pos.x + textRect.left() * pixelSize,
1550 y0 = pos.y + delta.y * pixelSize;
1551 double x1 = x0 + pixelSize * textRect.width();
1552 double y1 = y0 + pixelSize * textRect.height();
1553 double d = pixelSize * 5;
1554 glRectd(x0 - d, y0 - d, x1 + d, y1 + d);
1555 } else {
1556 TPointD posBalloon = viewer->worldToPos(pos);
1557
1558 double d = 5;
1559 double x0 = posBalloon.x + textRect.left() - d;
1560 double y0 = posBalloon.y + delta.y - d;
1561 double x1 = x0 + textRect.width() + d;
1562 double y1 = y0 + textRect.height() + d;
1563
1564 TPointD p1(x0, y0);
1565 TPointD p2(x1, y0);
1566 TPointD p3(x0, y1);
1567 TPointD p4(x1, y1);
1568
1569 TPointD w1(viewer->winToWorld(p1));
1570 TPointD w2(viewer->winToWorld(p2));
1571 TPointD w3(viewer->winToWorld(p3));
1572 TPointD w4(viewer->winToWorld(p4));
1573
1574 glBegin(GL_QUADS);
1575 glVertex2d(w1.x, w1.y);
1576 glVertex2d(w2.x, w2.y);
1577 glVertex2d(w4.x, w4.y);
1578 glVertex2d(w3.x, w3.y);
1579 glEnd();
1580 }
1581
1582 return;
1583 }
1584
1585 QSize size(textRect.width() + textRect.left() + mrg,
1586 std::max(textRect.bottom() + mrg, y + delta.y) + 3 * devPixRatio);
1587
1588 QImage label(size.width(), size.height(), QImage::Format_ARGB32);
1589 label.fill(Qt::transparent);
1590 // label.fill(qRgba(200,200,0,200));
1591 QPainter p(&label);
1592 p.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
1593 p.setBrush(QColor(color.r, color.g, color.b, color.m));
1594 p.setPen(Qt::NoPen);
1595
1596 QPainterPath pp;
1597 pp.moveTo(x0, y - 8 * devPixRatio);
1598 pp.lineTo(0, y + delta.y);
1599 pp.lineTo(x0, y);
1600 /* bordi arrotondati
1601 int arcSize = 10;
1602 pp.arcTo(x0,y1-arcSize,arcSize,arcSize,180,90);
1603 pp.arcTo(x1-arcSize,y1-arcSize,arcSize,arcSize,270,90);
1604 pp.arcTo(x1-arcSize,y0,arcSize,arcSize,0,90);
1605 pp.arcTo(x0,y0,arcSize,arcSize,90,90);
1606 */
1607 // bordi acuti
1608 pp.lineTo(x0, y1);
1609 pp.lineTo(x1, y1);
1610 pp.lineTo(x1, y0);
1611 pp.lineTo(x0, y0);
1612
1613 pp.closeSubpath();
1614
1615 p.drawPath(pp);
1616
1617 p.setPen(Qt::black);
1618 p.setFont(font);
1619 p.drawText(textRect, Qt::AlignCenter | Qt::TextDontClip, qText);
1620
1621 QImage texture = QGLWidget::convertToGLFormat(label);
1622
1623 glRasterPos2f(pos.x, pos.y);
1624 glBitmap(0, 0, 0, 0, 0, -size.height() + (y + delta.y), NULL); //
1625 glEnable(GL_BLEND);
1626 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1627 glDrawPixels(texture.width(), texture.height(), GL_RGBA, GL_UNSIGNED_BYTE,
1628 texture.bits());
1629 glDisable(GL_BLEND);
1630 glColor3d(0, 0, 0);
1631 }
1632
1633 //---------------------------------------------------------------------------------------------
1634
drawHook(const TPointD & pos,ToolUtils::HookType type,bool highlighted,bool onionSkin)1635 void ToolUtils::drawHook(const TPointD &pos, ToolUtils::HookType type,
1636 bool highlighted, bool onionSkin) {
1637 int devPixRatio = getDevPixRatio();
1638 int r = 10, d = r + r;
1639 QImage image(d * devPixRatio, d * devPixRatio, QImage::Format_ARGB32);
1640 image.fill(Qt::transparent);
1641 // image.fill(qRgba(200,200,0,200));
1642 QPainter painter(&image);
1643 painter.scale(devPixRatio, devPixRatio);
1644 // painter.setRenderHints(QPainter::Antialiasing|QPainter::TextAntialiasing);
1645
1646 int matte = onionSkin ? 100 : 255;
1647
1648 QColor color(0, 0, 0, matte);
1649 if (highlighted) color = QColor(0, 175, 175, matte);
1650
1651 if (type == NormalHook || type == PassHookA) {
1652 painter.setPen(QPen(QColor(255, 255, 255, matte), 3));
1653 painter.drawEllipse(5, 5, d - 10, d - 10);
1654 painter.setPen(color);
1655 painter.drawEllipse(5, 5, d - 10, d - 10);
1656 } else if (type == OtherLevelHook) {
1657 QColor color(0, 200, 200, 200);
1658 // painter.setPen(QPen(Qt::white,3));
1659 // painter.drawEllipse(5,5,d-10,d-10);
1660 painter.setPen(Qt::white);
1661 painter.setBrush(color);
1662 painter.drawEllipse(6, 6, d - 12, d - 12);
1663 }
1664 if (type == NormalHook || type == PassHookB) {
1665 painter.setPen(QPen(QColor(255, 255, 255, matte), 3));
1666 painter.drawLine(0, r, d, r);
1667 painter.drawLine(r, 0, r, d);
1668 painter.setPen(color);
1669 painter.drawLine(0, r, d, r);
1670 painter.drawLine(r, 0, r, d);
1671 }
1672
1673 QImage texture = QGLWidget::convertToGLFormat(image);
1674 glRasterPos2f(pos.x, pos.y);
1675 glBitmap(0, 0, 0, 0, -r * devPixRatio, -r * devPixRatio, NULL);
1676 glEnable(GL_BLEND);
1677 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1678 glDrawPixels(texture.width(), texture.height(), GL_RGBA, GL_UNSIGNED_BYTE,
1679 texture.bits());
1680 glDisable(GL_BLEND);
1681 }
1682
1683 //---------------------------------------------------------------------------------------------
1684
isJustCreatedSpline(TImage * image)1685 bool ToolUtils::isJustCreatedSpline(TImage *image) {
1686 TVectorImageP vi = image;
1687 if (!vi) return false;
1688 if (vi->getStrokeCount() != 1) return false;
1689 TStroke *stroke = vi->getStroke(0);
1690 if (stroke->getControlPointCount() != 3) return false;
1691 TPointD p0 = stroke->getControlPoint(0);
1692 TPointD p1 = stroke->getControlPoint(1);
1693 TPointD p2 = stroke->getControlPoint(2);
1694 double d = 30.0;
1695 return p0 == TPointD(-d, 0) && p1 == TPointD(0, 0) && p2 == TPointD(d, 0);
1696 }
1697
1698 //---------------------------------------------------------------------------------------------
1699
interpolateRect(const TRectD & rect1,const TRectD & rect2,double t)1700 TRectD ToolUtils::interpolateRect(const TRectD &rect1, const TRectD &rect2,
1701 double t) {
1702 assert(rect1.x0 <= rect1.x1);
1703 assert(rect1.y0 <= rect1.y1);
1704 assert(rect2.x0 <= rect2.x1);
1705 assert(rect2.y0 <= rect2.y1);
1706
1707 return TRectD(rect1.x0 + (rect2.x0 - rect1.x0) * t,
1708 rect1.y0 + (rect2.y0 - rect1.y0) * t,
1709 rect1.x1 + (rect2.x1 - rect1.x1) * t,
1710 rect1.y1 + (rect2.y1 - rect1.y1) * t);
1711 }
1712
1713 //-----------------------------------------------------------------------------
1714 /*
1715 bool ToolUtils::isASubRegion(int reg, const std::vector<TRegion*> ®ions)
1716 {
1717 TRegion *region=regions[reg];
1718 for (int i=0; i<(int)regions.size(); i++)
1719 {
1720 if(i!=reg)
1721 if(region->isSubRegionOf(*regions[i]))
1722 return true;
1723 }
1724 return false;
1725 }
1726 */
1727 //-----------------------------------------------------------------------------
1728
getBounds(const std::vector<TThickPoint> & points,double maxThickness)1729 TRectD ToolUtils::getBounds(const std::vector<TThickPoint> &points,
1730 double maxThickness) {
1731 TThickPoint p = points[0];
1732 double radius = maxThickness == 0 ? p.thick * 0.5 : maxThickness * 0.5;
1733 TRectD rect(p - TPointD(radius, radius), p + TPointD(radius, radius));
1734 int i;
1735 for (i = 1; i < (int)points.size(); i++) {
1736 p = points[i];
1737 radius = maxThickness == 0 ? p.thick * 0.5 : maxThickness * 0.5;
1738 rect =
1739 rect + TRectD(p - TPointD(radius, radius), p + TPointD(radius, radius));
1740 }
1741 return rect;
1742 }
1743
1744 //-----------------------------------------------------------------------------
1745 /*
1746 template <typename PIXEL>
1747 TRasterPT<PIXEL> ToolUtils::rotate90(const TRasterPT<PIXEL> &ras, bool toRight)
1748 {
1749 if(!ras)
1750 return 0;
1751 int lx=ras->getLy();
1752 int ly=ras->getLx();
1753 TRasterPT<PIXEL> workRas(lx,ly);
1754 for (int i=0; i<ras->getLx(); i++)
1755 {
1756 for (int j=0; j<ras->getLy(); j++)
1757 {
1758 if(toRight)
1759 workRas->pixels(ly-1-i)[j]=ras->pixels(j)[i];
1760 else
1761 workRas->pixels(i)[lx-1-j]=ras->pixels(j)[i];
1762 }
1763 }
1764 return workRas;
1765 }*/
1766
1767 //-----------------------------------------------------------------------------
1768
doUpdateXSheet(TXshSimpleLevel * sl,std::vector<TFrameId> oldFids,std::vector<TFrameId> newFids,TXsheet * xsh,std::vector<TXshChildLevel * > & childLevels)1769 bool ToolUtils::doUpdateXSheet(TXshSimpleLevel *sl,
1770 std::vector<TFrameId> oldFids,
1771 std::vector<TFrameId> newFids, TXsheet *xsh,
1772 std::vector<TXshChildLevel *> &childLevels) {
1773 bool ret = false;
1774 for (int c = 0; c < xsh->getColumnCount(); ++c) {
1775 int r0, r1;
1776 int n = xsh->getCellRange(c, r0, r1);
1777 if (n > 0) {
1778 bool changed = false;
1779 std::vector<TXshCell> cells(n);
1780 xsh->getCells(r0, c, n, &cells[0]);
1781 for (int i = 0; i < n; i++) {
1782 TXshCell currCell = cells[i];
1783 // check the sub xsheets too
1784 if (!cells[i].isEmpty() &&
1785 cells[i].m_level->getType() == CHILD_XSHLEVEL) {
1786 TXshChildLevel *level = cells[i].m_level->getChildLevel();
1787 // make sure we haven't already checked the level
1788 if (level && std::find(childLevels.begin(), childLevels.end(),
1789 level) == childLevels.end()) {
1790 childLevels.push_back(level);
1791 TXsheet *subXsh = level->getXsheet();
1792 ret |= doUpdateXSheet(sl, oldFids, newFids, subXsh, childLevels);
1793 }
1794 }
1795 for (int j = 0; j < oldFids.size(); j++) {
1796 if (oldFids.at(j) == newFids.at(j)) continue;
1797 TXshCell tempCell(sl, oldFids.at(j));
1798 bool sameSl = tempCell.getSimpleLevel() == currCell.getSimpleLevel();
1799 bool sameFid = tempCell.getFrameId() == currCell.getFrameId();
1800 if (sameSl && sameFid) {
1801 TXshCell newCell(sl, newFids.at(j));
1802 cells[i] = newCell;
1803 changed = true;
1804 break;
1805 }
1806 }
1807 }
1808 if (changed) {
1809 xsh->setCells(r0, c, n, &cells[0]);
1810 ret = true;
1811 // TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
1812 }
1813 }
1814 }
1815 return ret;
1816 }
1817
1818 //-----------------------------------------------------------------------------
1819
renumberForInsertFId(TXshSimpleLevel * sl,const TFrameId & fid,const TFrameId & maxFid,TXsheet * xsh)1820 bool ToolUtils::renumberForInsertFId(TXshSimpleLevel *sl, const TFrameId &fid,
1821 const TFrameId &maxFid, TXsheet *xsh) {
1822 std::vector<TFrameId> fids;
1823 std::vector<TFrameId> oldFrames;
1824 sl->getFids(oldFrames);
1825 sl->getFids(fids);
1826 std::vector<TFrameId>::iterator it = std::find(fids.begin(), fids.end(), fid);
1827 if (it == fids.end()) return false;
1828
1829 std::set<TFrameId> fidsSet(fids.begin(), fids.end());
1830 QList<TFrameId> fIdsToBeShifted;
1831 TFrameId tmpFid = fid;
1832 for (auto itr = fidsSet.upper_bound(maxFid); itr != fidsSet.end(); ++itr) {
1833 if (*itr > tmpFid) break;
1834 fIdsToBeShifted.push_back(*itr);
1835 if (fid.getLetter()) {
1836 if ((*itr).getLetter() < 'z')
1837 tmpFid = TFrameId((*itr).getNumber(),
1838 ((*itr).getLetter()) ? (*itr).getLetter() + 1 : 'a');
1839 else
1840 tmpFid = TFrameId((*itr).getNumber() + 1);
1841 } else
1842 tmpFid = TFrameId((*itr).getNumber() + 1, (*itr).getLetter());
1843 }
1844
1845 if (fIdsToBeShifted.isEmpty()) return false;
1846
1847 for (TFrameId &tmpFid : fids) {
1848 if (fIdsToBeShifted.contains(tmpFid)) {
1849 if (fid.getLetter()) {
1850 if (tmpFid.getLetter() < 'z')
1851 tmpFid =
1852 TFrameId(tmpFid.getNumber(),
1853 (tmpFid.getLetter()) ? tmpFid.getLetter() + 1 : 'a');
1854 else
1855 tmpFid = TFrameId(tmpFid.getNumber() + 1);
1856 } else
1857 tmpFid = TFrameId(tmpFid.getNumber() + 1, tmpFid.getLetter());
1858 }
1859 }
1860
1861 std::vector<TXshChildLevel *> childLevels;
1862 doUpdateXSheet(sl, oldFrames, fids, xsh, childLevels);
1863 sl->renumber(fids);
1864
1865 return true;
1866 }
1867