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*> &regions)
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