1
2
3 #include "vectorizerpopup.h"
4
5 // Tnz6 includes
6 #include "tapp.h"
7 #include "fileselection.h"
8 #include "castselection.h"
9 #include "cellselection.h"
10 #include "overwritepopup.h"
11 #include "vectorizerswatch.h"
12 #include "filebrowserpopup.h"
13 #include "menubarcommandids.h"
14
15 // TnzQt includes
16 #include "toonzqt/menubarcommand.h"
17 #include "toonzqt/intfield.h"
18 #include "toonzqt/colorfield.h"
19 #include "toonzqt/checkbox.h"
20 #include "toonzqt/gutil.h"
21
22 // TnzLib includes
23 #include "toonz/namebuilder.h"
24 #include "toonz/txshsimplelevel.h"
25 #include "toonz/txshleveltypes.h"
26 #include "toonz/txsheet.h"
27 #include "toonz/txshcell.h"
28 #include "toonz/toonzscene.h"
29 #include "toonz/tcenterlinevectorizer.h"
30 #include "toonz/dpiscale.h"
31 #include "toonz/txshchildlevel.h"
32 #include "toonz/levelset.h"
33 #include "toonz/tscenehandle.h"
34 #include "toonz/txsheethandle.h"
35 #include "toonz/txshlevelhandle.h"
36 #include "toonz/sceneproperties.h"
37 #include "toonz/imagemanager.h"
38 #include "toonz/Naa2TlvConverter.h"
39
40 // TnzCore includes
41 #include "tsystem.h"
42 #include "tconvert.h"
43 #include "tpalette.h"
44 #include "trasterimage.h"
45 #include "ttoonzimage.h"
46 #include "tcolorstyles.h"
47 #include "tstroke.h"
48 #include "tpersistset.h"
49 #include "columncommand.h"
50
51 // Qt includes
52 #include <QFrame>
53 #include <QComboBox>
54 #include <QCoreApplication>
55 #include <QPushButton>
56 #include <QHBoxLayout>
57 #include <QVBoxLayout>
58 #include <QString>
59 #include <QLabel>
60 #include <QSplitter>
61 #include <QGridLayout>
62 #include <QScrollArea>
63 #include <QAction>
64 #include <QMainWindow>
65 #include <QToolButton>
66
67 using namespace DVGui;
68
69 //********************************************************************************
70 // Local namespace classes
71 //********************************************************************************
72
73 namespace {
74
75 struct Param {
76 QString m_name;
77 int m_bit;
78
Param__anon0ff2ca300111::Param79 Param(const QString &name, int bit) : m_name(name), m_bit(bit) {}
80 };
81
82 struct ParamGroup {
83 int m_startRow, m_separatorRow;
84 std::vector<Param> m_params;
85
ParamGroup__anon0ff2ca300111::ParamGroup86 ParamGroup(int startRow, int separatorRow)
87 : m_startRow(startRow), m_separatorRow(separatorRow) {}
88 };
89
90 } // namespace
91
92 //********************************************************************************
93 // Local namespace stuff
94 //********************************************************************************
95
96 namespace {
97
98 std::vector<ParamGroup> l_centerlineParamGroups;
99 std::vector<ParamGroup> l_outlineParamGroups;
100
101 bool l_quitLoop = false;
102
103 //=============================================================================
104
getCurrentVectorizerParameters()105 VectorizerParameters *getCurrentVectorizerParameters() {
106 return TApp::instance()
107 ->getCurrentScene()
108 ->getScene()
109 ->getProperties()
110 ->getVectorizerParameters();
111 }
112
113 //-----------------------------------------------------------------------------
114
getSelectedLevels(std::set<TXshLevel * > & levels,int & r0,int & c0,int & r1,int & c1)115 bool getSelectedLevels(std::set<TXshLevel *> &levels, int &r0, int &c0, int &r1,
116 int &c1) {
117 TXsheet *xsheet = TApp::instance()->getCurrentXsheet()->getXsheet();
118
119 CastSelection *castSelection =
120 dynamic_cast<CastSelection *>(TSelection::getCurrent());
121 TCellSelection *cellSelection =
122 dynamic_cast<TCellSelection *>(TSelection::getCurrent());
123
124 if (castSelection) {
125 std::vector<TXshLevel *> selectedLevels;
126 castSelection->getSelectedLevels(selectedLevels);
127
128 for (int i = 0; i < (int)selectedLevels.size(); ++i)
129 levels.insert(selectedLevels[i]);
130
131 return false;
132 } else if (cellSelection) {
133 cellSelection->getSelectedCells(r0, c0, r1, c1);
134
135 for (int c = c0; c <= c1; ++c) {
136 for (int r = r0; r <= r1; ++r) {
137 TXshCell cell = xsheet->getCell(r, c);
138
139 if (TXshLevel *level = cell.isEmpty() ? 0 : cell.getSimpleLevel())
140 levels.insert(level);
141 }
142 }
143
144 return true;
145 }
146
147 return false;
148 }
149
150 //-----------------------------------------------------------------------------
151
getSelectedLevel()152 TXshLevel *getSelectedLevel() {
153 std::set<TXshLevel *> levels;
154 int r0, c0, r1, c1;
155
156 getSelectedLevels(levels, r0, c0, r1, c1);
157
158 return (levels.size() == 1) ? *levels.begin() : (TXshLevel *)0;
159 }
160
161 //-----------------------------------------------------------------------------
162
getSelectedLevelPath()163 TFilePath getSelectedLevelPath() {
164 TXshLevel *level = getSelectedLevel();
165
166 return level
167 ? TApp::instance()->getCurrentScene()->getScene()->decodeFilePath(
168 level->getPath())
169 : TFilePath();
170 }
171
172 //-----------------------------------------------------------------------------
173
getSelectedFids(std::vector<TFrameId> & fids,TXshSimpleLevel * level,int r0,int c0,int r1,int c1)174 void getSelectedFids(std::vector<TFrameId> &fids, TXshSimpleLevel *level,
175 int r0, int c0, int r1, int c1) {
176 TXsheet *xsheet = TApp::instance()->getCurrentXsheet()->getXsheet();
177
178 std::set<TFrameId> fidsSet;
179 for (int c = c0; c <= c1; ++c) {
180 for (int r = r0; r <= r1; ++r) {
181 TXshCell cell = xsheet->getCell(r, c);
182
183 TXshSimpleLevel *curLevel = cell.isEmpty() ? 0 : cell.getSimpleLevel();
184 if (curLevel != level) continue;
185
186 fidsSet.insert(cell.getFrameId());
187 }
188 }
189
190 std::set<TFrameId>::iterator fst, fsEnd = fidsSet.end();
191 for (fst = fidsSet.begin(); fst != fsEnd; ++fst) fids.push_back(*fst);
192 }
193
194 // Toonz Raster Level may have palette including MyPaint styles,
195 // which cannot be rendered in vector levels.
196 // In such case replace MyPaint styles by solid color styles.
replaceMyPaintBrushStyles(TPalette * palette)197 void replaceMyPaintBrushStyles(TPalette *palette) {
198 for (int s = 0; s < palette->getStyleCount(); s++) {
199 TColorStyle *style = palette->getStyle(s);
200 if (style->getTagId() == 4001) // TMyPaintBrushStyle
201 palette->setStyle(s, style->getMainColor());
202 }
203 }
204
205 } // namespace
206
207 //*****************************************************************************
208 // Vectorizer implementation
209 //*****************************************************************************
210
Vectorizer()211 Vectorizer::Vectorizer()
212 : m_dialog(new OverwriteDialog)
213 , m_isCanceled(false)
214 , m_dialogShown(false) {}
215
216 //-----------------------------------------------------------------------------
217
~Vectorizer()218 Vectorizer::~Vectorizer() {
219 // DO NOT REMOVE - DESTRUCTS INCOMPLETE TYPES IN THE HEADER FILE
220 }
221
222 //-----------------------------------------------------------------------------
223
doVectorize(TImageP img,TPalette * palette,const VectorizerConfiguration & conf)224 TVectorImageP Vectorizer::doVectorize(TImageP img, TPalette *palette,
225 const VectorizerConfiguration &conf) {
226 TToonzImageP ti = img;
227 TRasterImageP ri = img;
228
229 if (!ti && !ri) return TVectorImageP();
230
231 VectorizerCore vCore;
232 connect(&vCore, SIGNAL(partialDone(int, int)), this,
233 SIGNAL(partialDone(int, int)));
234 connect(this, SIGNAL(transmitCancel()), &vCore, SLOT(onCancel()),
235 Qt::DirectConnection); // Direct connection *must* be
236 // established for child cancels
237 return vCore.vectorize(img, conf, palette);
238 }
239
240 //-----------------------------------------------------------------------------
241
setLevel(const TXshSimpleLevelP & level)242 void Vectorizer::setLevel(const TXshSimpleLevelP &level) {
243 m_level = level;
244
245 // Creo il livello pli
246 TXshSimpleLevel *sl = m_level.getPointer();
247 if (!sl) return;
248
249 int rowCount = sl->getFrameCount();
250 if (rowCount <= 0 || sl->isEmpty()) return;
251
252 TXshLevel *xl;
253 ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
254
255 // Build the new level name
256 std::wstring levelName = sl->getName() + L"v";
257 {
258 std::unique_ptr<NameBuilder> nameBuilder(
259 NameBuilder::getBuilder(levelName));
260
261 for (;;) {
262 levelName = nameBuilder->getNext();
263 if (scene->getLevelSet()->getLevel(levelName) == 0) break;
264 }
265 }
266
267 TFilePath dstPath = sl->getPath().withName(levelName).withType("pli");
268 dstPath = scene->decodeFilePath(dstPath);
269
270 bool overWrite = false;
271 if (TSystem::doesExistFileOrLevel(dstPath)) {
272 m_dialogShown = true;
273
274 std::wstring name = m_dialog->execute(scene, dstPath, true);
275 if (m_dialog->cancelPressed()) return;
276
277 switch (m_dialog->getChoice()) {
278 case OverwriteDialog::KEEP_OLD:
279 xl = scene->getLevelSet()->getLevel(levelName);
280 if (!xl) xl = scene->loadLevel(dstPath);
281
282 m_vLevel = xl->getSimpleLevel();
283 return;
284 case OverwriteDialog::OVERWRITE:
285 overWrite = true;
286 break;
287 default:
288 levelName = name;
289 break;
290 }
291 }
292
293 xl = scene->createNewLevel(PLI_XSHLEVEL, levelName);
294
295 TXshSimpleLevel *vl = xl->getSimpleLevel();
296 assert(vl);
297
298 if (overWrite) {
299 vl->setPath(scene->codeFilePath(dstPath));
300 vl->setName(levelName);
301 }
302
303 TPalette *palette = 0;
304 if (sl->getType() == TZP_XSHLEVEL) {
305 palette = sl->getPalette()->clone();
306 replaceMyPaintBrushStyles(palette);
307 } else
308 palette = new TPalette;
309
310 palette->setPaletteName(vl->getName());
311 vl->setPalette(palette);
312
313 m_vLevel = vl;
314 }
315
316 //-----------------------------------------------------------------------------
317
doVectorize()318 int Vectorizer::doVectorize() {
319 struct {
320 Vectorizer *m_this;
321
322 CenterlineConfiguration m_cConf;
323 NewOutlineConfiguration m_oConf;
324
325 void updateConfig(double weight) {
326 if (m_this->m_params.m_isOutline)
327 m_oConf = m_this->m_params.getOutlineConfiguration(weight);
328 else
329 m_cConf = m_this->m_params.getCenterlineConfiguration(weight);
330 }
331
332 } locals = {this};
333
334 VectorizerConfiguration &configuration =
335 m_params.m_isOutline
336 ? static_cast<VectorizerConfiguration &>(locals.m_oConf)
337 : static_cast<VectorizerConfiguration &>(locals.m_cConf);
338
339 if (!m_vLevel) return 0;
340
341 if (m_dialog->getChoice() == OverwriteDialog::KEEP_OLD && m_dialogShown)
342 return m_fids.size();
343
344 TXshSimpleLevel *sl = m_level.getPointer();
345 if (!sl) return 0;
346
347 int rowCount = sl->getFrameCount();
348 if (rowCount <= 0 || sl->isEmpty()) return 0;
349
350 double frameRange[2] = {static_cast<double>(m_fids.front().getNumber()) - 1,
351 static_cast<double>(m_fids.back().getNumber()) - 1};
352
353 int count = 0;
354
355 std::vector<TFrameId>::const_iterator ft, fEnd = m_fids.end();
356 for (ft = m_fids.begin(); ft != fEnd; ++ft) {
357 // Retrieve the image to be vectorized
358 TImageP img;
359 if (sl->getType() == OVL_XSHLEVEL || sl->getType() == TZP_XSHLEVEL ||
360 sl->getType() == TZI_XSHLEVEL)
361 img = sl->getFullsampledFrame(*ft, ImageManager::dontPutInCache);
362
363 if (!img) continue;
364
365 // Build image-toonz coordinate transformation
366 TAffine dpiAff = getDpiAffine(sl, *ft, true);
367 double factor = norm(dpiAff * TPointD(1, 0));
368
369 TPointD center;
370 if (TToonzImageP ti = img)
371 center = ti->getRaster()->getCenterD();
372 else if (TRasterImageP ri = img)
373 center = ri->getRaster()->getCenterD();
374
375 // Build vectorizer configuration
376 double weight = (ft->getNumber() - 1 - frameRange[0]) /
377 std::max(frameRange[1] - frameRange[0], 1.0);
378 weight = tcrop(weight, 0.0, 1.0);
379
380 locals.updateConfig(weight); // TEMPORARY
381
382 configuration.m_affine = dpiAff * TTranslation(-center);
383 configuration.m_thickScale = factor;
384
385 // Build vectorization label to be displayed
386 QString labelName = QString::fromStdWString(sl->getShortName());
387 labelName.push_back(' ');
388 labelName.append(QString::fromStdString(ft->expand(TFrameId::NO_PAD)));
389
390 emit frameName(labelName);
391
392 // Perform vectorization
393 if (TVectorImageP vi =
394 doVectorize(img, m_vLevel->getPalette(), configuration)) {
395 TFrameId fid = *ft;
396
397 if (fid.getNumber() < 0) fid = TFrameId(1, ft->getLetter());
398
399 m_vLevel->setFrame(fid, vi);
400 vi->setPalette(m_vLevel->getPalette());
401
402 emit frameDone(++count);
403 }
404
405 // Stop if canceled
406 if (m_isCanceled) break;
407 }
408
409 m_dialogShown = false;
410
411 return count;
412 }
413
414 //-----------------------------------------------------------------------------
415
run()416 void Vectorizer::run() { doVectorize(); }
417
418 //*****************************************************************************
419 // VectorizerPopup implentation
420 //*****************************************************************************
421
422 #if QT_VERSION >= 0x050500
VectorizerPopup(QWidget * parent,Qt::WindowFlags flags)423 VectorizerPopup::VectorizerPopup(QWidget *parent, Qt::WindowFlags flags)
424 #else
425 VectorizerPopup::VectorizerPopup(QWidget *parent, Qt::WFlags flags)
426 #endif
427 : Dialog(TApp::instance()->getMainWindow(), true, false, "Vectorizer")
428 , m_sceneHandle(TApp::instance()->getCurrentScene()) {
429 struct Locals {
430 int m_bit;
431
432 Locals() : m_bit() {}
433
434 static void addParameterGroup(std::vector<ParamGroup> ¶mGroups,
435 int group, int startRow,
436 int separatorRow = -1) {
437 assert(group <= paramGroups.size());
438
439 if (group == paramGroups.size())
440 paramGroups.push_back(ParamGroup(startRow, separatorRow));
441 }
442
443 void addParameter(std::vector<ParamGroup> ¶mGroups,
444 const QString ¶mName) {
445 paramGroups.back().m_params.push_back(Param(paramName, m_bit++));
446 }
447
448 } locals;
449
450 // Su MAC i dialog modali non hanno bottoni di chiusura nella titleBar
451 setModal(false);
452 setWindowTitle(tr("Convert-to-Vector Settings"));
453
454 setLabelWidth(125);
455
456 setTopMargin(0);
457 setTopSpacing(0);
458
459 // Build vertical layout
460 beginVLayout();
461
462 QSplitter *splitter = new QSplitter(Qt::Vertical, this);
463 splitter->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding,
464 QSizePolicy::MinimumExpanding));
465 addWidget(splitter);
466
467 QToolBar *leftToolBar = new QToolBar, *rightToolBar = new QToolBar;
468 leftToolBar->setObjectName("MediumPaddingToolBar");
469 rightToolBar->setObjectName("MediumPaddingToolBar");
470 leftToolBar->setIconSize(QSize(17, 17));
471 rightToolBar->setIconSize(QSize(17, 17));
472 {
473 QWidget *toolbarsContainer = new QWidget(this);
474 toolbarsContainer->setFixedHeight(22);
475 addWidget(toolbarsContainer);
476
477 QHBoxLayout *toolbarsLayout = new QHBoxLayout(toolbarsContainer);
478 toolbarsContainer->setLayout(toolbarsLayout);
479
480 toolbarsLayout->setMargin(0);
481 toolbarsLayout->setSpacing(0);
482
483 QToolBar *spacingToolBar = new QToolBar(
484 toolbarsContainer); // The spacer object must be a toolbar.
485 spacingToolBar->setFixedHeight(
486 22); // It's related to qss choices... I know it's stinky
487
488 toolbarsLayout->addWidget(leftToolBar, 0, Qt::AlignLeft);
489 toolbarsLayout->addWidget(spacingToolBar, 1);
490 toolbarsLayout->addWidget(rightToolBar, 0, Qt::AlignRight);
491 }
492
493 endVLayout();
494
495 // Build parameters area
496 QScrollArea *paramsArea = new QScrollArea(splitter);
497 paramsArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
498 paramsArea->setWidgetResizable(true);
499 splitter->addWidget(paramsArea);
500 splitter->setStretchFactor(0, 1);
501
502 m_paramsWidget = new QFrame(paramsArea);
503 paramsArea->setWidget(m_paramsWidget);
504
505 m_paramsLayout = new QGridLayout;
506 m_paramsWidget->setLayout(m_paramsLayout);
507
508 int group = 0, row = 0;
509
510 locals.addParameterGroup(::l_centerlineParamGroups, group, row);
511 locals.addParameterGroup(::l_outlineParamGroups, group++, row);
512
513 // Vectorization mode
514 m_typeMenu = new QComboBox(this);
515 m_typeMenu->setFixedSize(245, WidgetHeight);
516 QStringList formats;
517 formats << tr("Centerline") << tr("Outline");
518 m_typeMenu->addItems(formats);
519 m_typeMenu->setMinimumHeight(WidgetHeight);
520 bool isOutline = m_sceneHandle->getScene()
521 ->getProperties()
522 ->getVectorizerParameters()
523 ->m_isOutline;
524 m_typeMenu->setCurrentIndex(isOutline ? 1 : 0);
525 connect(m_typeMenu, SIGNAL(currentIndexChanged(int)), this,
526 SLOT(onTypeChange(int)));
527
528 m_paramsLayout->addWidget(new QLabel(tr("Mode")), row, 0, Qt::AlignRight);
529 m_paramsLayout->addWidget(m_typeMenu, row++, 1);
530
531 locals.addParameter(l_centerlineParamGroups, tr("Mode"));
532 locals.addParameter(l_outlineParamGroups, tr("Mode"));
533
534 //-------------------- Parameters area - Centerline ------------------------
535
536 locals.addParameterGroup(l_centerlineParamGroups, group++, row);
537
538 // Threshold
539 m_cThresholdLabel = new QLabel(tr("Threshold"));
540 m_cThreshold = new IntField(this);
541
542 m_paramsLayout->addWidget(m_cThresholdLabel, row, 0, Qt::AlignRight);
543 m_paramsLayout->addWidget(m_cThreshold, row++, 1);
544
545 locals.addParameter(l_centerlineParamGroups, tr("Threshold"));
546
547 // Accuracy
548 m_cAccuracyLabel = new QLabel(tr("Accuracy"));
549 m_cAccuracy = new IntField(this);
550
551 m_paramsLayout->addWidget(m_cAccuracyLabel, row, 0, Qt::AlignRight);
552 m_paramsLayout->addWidget(m_cAccuracy, row++, 1);
553
554 locals.addParameter(l_centerlineParamGroups, tr("Accuracy"));
555
556 // Despeckling
557 m_cDespecklingLabel = new QLabel(tr("Despeckling"));
558 m_cDespeckling = new IntField(this);
559
560 m_paramsLayout->addWidget(m_cDespecklingLabel, row, 0, Qt::AlignRight);
561 m_paramsLayout->addWidget(m_cDespeckling, row++, 1);
562
563 locals.addParameter(l_centerlineParamGroups, tr("Despeckling"));
564
565 // Max Thickness
566 m_cMaxThicknessLabel = new QLabel(tr("Max Thickness"));
567 m_paramsLayout->addWidget(m_cMaxThicknessLabel, row, 0, Qt::AlignRight);
568
569 m_cMaxThickness = new IntField(this);
570 m_cMaxThickness->enableSlider(false);
571 m_paramsLayout->addWidget(m_cMaxThickness, row++, 1, Qt::AlignLeft);
572
573 locals.addParameter(l_centerlineParamGroups, tr("Max Thickness"));
574
575 // Thickness Calibration
576 m_cThicknessRatioLabel = new QLabel(tr("Thickness Calibration"));
577 m_paramsLayout->addWidget(m_cThicknessRatioLabel, row, 0, Qt::AlignRight);
578
579 /*m_cThicknessRatio = new IntField(this);
580 paramsLayout->addWidget(m_cThicknessRatio, row++, 1);*/
581
582 QHBoxLayout *cThicknessRatioLayout = new QHBoxLayout;
583
584 cThicknessRatioLayout->addSpacing(20);
585
586 m_cThicknessRatioFirstLabel = new QLabel(tr("Start:"));
587 cThicknessRatioLayout->addWidget(m_cThicknessRatioFirstLabel);
588
589 m_cThicknessRatioFirst = new MeasuredDoubleLineEdit(this);
590 m_cThicknessRatioFirst->setMeasure("percentage");
591 cThicknessRatioLayout->addWidget(m_cThicknessRatioFirst);
592
593 m_cThicknessRatioLastLabel = new QLabel(tr("End:"));
594 cThicknessRatioLayout->addWidget(m_cThicknessRatioLastLabel);
595
596 m_cThicknessRatioLast = new MeasuredDoubleLineEdit(this);
597 m_cThicknessRatioLast->setMeasure("percentage");
598 cThicknessRatioLayout->addWidget(m_cThicknessRatioLast);
599
600 cThicknessRatioLayout->addStretch(1);
601
602 m_paramsLayout->addLayout(cThicknessRatioLayout, row++, 1);
603
604 locals.addParameter(l_centerlineParamGroups, tr("Thickness Calibration"));
605
606 // Checkboxes
607 {
608 static const QString name = tr("Preserve Painted Areas");
609 locals.addParameter(l_centerlineParamGroups, name);
610
611 m_cPaintFill = new CheckBox(name, this);
612 m_cPaintFill->setFixedHeight(WidgetHeight);
613 m_paramsLayout->addWidget(m_cPaintFill, row++, 1);
614 }
615
616 {
617 static const QString name = tr("Align Boundary Strokes Direction");
618 locals.addParameter(l_centerlineParamGroups, name);
619
620 m_cAlignBoundaryStrokesDirection = new CheckBox(name, this);
621 m_cAlignBoundaryStrokesDirection->setFixedHeight(WidgetHeight);
622 m_cAlignBoundaryStrokesDirection->setToolTip(
623 tr("Align boundary strokes direction to be the same.\n(clockwise, i.e. "
624 "left to right as viewed from inside of the shape)"));
625 m_paramsLayout->addWidget(m_cAlignBoundaryStrokesDirection, row++, 1);
626 }
627
628 {
629 static const QString name = tr("Add Border");
630 locals.addParameter(l_centerlineParamGroups, name);
631
632 m_cMakeFrame = new CheckBox(name, this);
633 m_cMakeFrame->setFixedHeight(WidgetHeight);
634 m_paramsLayout->addWidget(m_cMakeFrame, row++, 1);
635 }
636
637 locals.addParameterGroup(l_centerlineParamGroups, group++, row + 1, row);
638
639 m_cNaaSourceSeparator = new Separator(tr("Full color non-AA images"));
640 m_paramsLayout->addWidget(m_cNaaSourceSeparator, row++, 0, 1, 2);
641
642 {
643 static const QString name = tr("Enhanced ink recognition");
644 locals.addParameter(l_centerlineParamGroups, name);
645
646 m_cNaaSource = new CheckBox(name, this);
647 m_cNaaSource->setFixedHeight(WidgetHeight);
648 m_paramsLayout->addWidget(m_cNaaSource, row++, 1);
649 }
650
651 //-------------------- Parameters area - Outline ------------------------
652
653 group = 1;
654 locals.addParameterGroup(l_outlineParamGroups, group++, row);
655
656 // Accuracy
657 m_oAccuracyLabel = new QLabel(tr("Accuracy"));
658 m_oAccuracy = new IntField(this);
659
660 m_paramsLayout->addWidget(m_oAccuracyLabel, row, 0, Qt::AlignRight);
661 m_paramsLayout->addWidget(m_oAccuracy, row++, 1);
662
663 locals.addParameter(l_outlineParamGroups, tr("Accuracy"));
664
665 // Despeckling
666 m_oDespecklingLabel = new QLabel(tr("Despeckling"));
667 m_oDespeckling = new IntField(this);
668
669 m_paramsLayout->addWidget(m_oDespecklingLabel, row, 0, Qt::AlignRight);
670 m_paramsLayout->addWidget(m_oDespeckling, row++, 1);
671
672 locals.addParameter(l_outlineParamGroups, tr("Despeckling"));
673
674 // Paint Fill
675 {
676 static const QString name = tr("Preserve Painted Areas");
677 locals.addParameter(l_outlineParamGroups, name);
678
679 m_oPaintFill = new CheckBox(name, this);
680 m_oPaintFill->setFixedHeight(WidgetHeight);
681 m_paramsLayout->addWidget(m_oPaintFill, row++, 1);
682 }
683
684 {
685 static const QString name = tr("Align Boundary Strokes Direction");
686 locals.addParameter(l_outlineParamGroups, name);
687
688 m_oAlignBoundaryStrokesDirection = new CheckBox(name, this);
689 m_oAlignBoundaryStrokesDirection->setFixedHeight(WidgetHeight);
690 m_oAlignBoundaryStrokesDirection->setToolTip(
691 tr("Align boundary strokes direction to be the same.\n(clockwise, i.e. "
692 "left to right as viewed from inside of the shape)"));
693 m_paramsLayout->addWidget(m_oAlignBoundaryStrokesDirection, row++, 1);
694 }
695 locals.addParameterGroup(l_outlineParamGroups, group++, row + 1, row);
696
697 m_oCornersSeparator = new Separator(tr("Corners"));
698 m_paramsLayout->addWidget(m_oCornersSeparator, row++, 0, 1, 2);
699
700 // Adherence
701 m_oAdherenceLabel = new QLabel(tr("Adherence"));
702 m_oAdherence = new IntField(this);
703
704 m_paramsLayout->addWidget(m_oAdherenceLabel, row, 0, Qt::AlignRight);
705 m_paramsLayout->addWidget(m_oAdherence, row++, 1);
706
707 locals.addParameter(l_outlineParamGroups, tr("Adherence"));
708
709 // Angle
710 m_oAngleLabel = new QLabel(tr("Angle"));
711 m_oAngle = new IntField(this);
712
713 m_paramsLayout->addWidget(m_oAngleLabel, row, 0, Qt::AlignRight);
714 m_paramsLayout->addWidget(m_oAngle, row++, 1);
715
716 locals.addParameter(l_outlineParamGroups, tr("Angle"));
717
718 // Relative
719 m_oRelativeLabel = new QLabel(tr("Curve Radius"));
720 m_oRelative = new IntField(this);
721
722 m_paramsLayout->addWidget(m_oRelativeLabel, row, 0, Qt::AlignRight);
723 m_paramsLayout->addWidget(m_oRelative, row++, 1);
724
725 locals.addParameter(l_outlineParamGroups, tr("Curve Radius"));
726
727 locals.addParameterGroup(l_outlineParamGroups, group++, row + 1, row);
728
729 m_oFullColorSeparator = new Separator(tr("Raster Levels"));
730 m_paramsLayout->addWidget(m_oFullColorSeparator, row++, 0, 1, 2);
731
732 // Max Colors
733 m_oMaxColorsLabel = new QLabel(tr("Max Colors"));
734 m_oMaxColors = new IntField(this);
735
736 m_paramsLayout->addWidget(m_oMaxColorsLabel, row, 0, Qt::AlignRight);
737 m_paramsLayout->addWidget(m_oMaxColors, row++, 1);
738
739 locals.addParameter(l_outlineParamGroups, tr("Max Colors"));
740
741 // Transparent Color
742 m_oTransparentColorLabel = new QLabel(tr("Transparent Color"), this);
743 m_oTransparentColor = new ColorField(this, true, TPixel32::Transparent, 48);
744 m_paramsLayout->addWidget(m_oTransparentColorLabel, row, 0, Qt::AlignRight);
745 m_paramsLayout->addWidget(m_oTransparentColor, row++, 1);
746
747 locals.addParameter(l_outlineParamGroups, tr("Transparent Color"));
748
749 locals.addParameterGroup(l_outlineParamGroups, group++, row + 1, row);
750
751 m_oTlvSeparator = new Separator(tr("TLV Levels"));
752 m_paramsLayout->addWidget(m_oTlvSeparator, row++, 0, 1, 2);
753
754 // Tone Threshold
755 m_oToneThresholdLabel = new QLabel(tr("Tone Threshold"));
756 m_oToneThreshold = new IntField(this);
757
758 m_paramsLayout->addWidget(m_oToneThresholdLabel, row, 0, Qt::AlignRight);
759 m_paramsLayout->addWidget(m_oToneThreshold, row++, 1);
760
761 locals.addParameter(l_outlineParamGroups, tr("Tone Threshold"));
762
763 m_paramsLayout->setRowStretch(row, 1);
764
765 //-------------------- Swatch area ------------------------
766
767 m_swatchArea = new VectorizerSwatchArea(this);
768 splitter->addWidget(m_swatchArea);
769 m_swatchArea->setEnabled(false); // Initally not enabled
770
771 connect(this, SIGNAL(valuesChanged()), m_swatchArea,
772 SLOT(invalidateContents()));
773
774 //---------------------- Toolbar --------------------------
775
776 QAction *swatchAct =
777 new QAction(createQIcon("preview"), tr("Toggle Swatch Preview"), this);
778 swatchAct->setCheckable(true);
779 leftToolBar->addAction(swatchAct);
780
781 QAction *centerlineAct = new QAction(createQIcon("centerline"),
782 tr("Toggle Centerlines Check"), this);
783 centerlineAct->setCheckable(true);
784 leftToolBar->addAction(centerlineAct);
785
786 QToolButton *visibilityButton = new QToolButton(this);
787 visibilityButton->setIcon(createQIcon("menu"));
788 visibilityButton->setText(tr("Options"));
789 visibilityButton->setPopupMode(QToolButton::InstantPopup);
790
791 QMenu *visibilityMenu = new QMenu(visibilityButton);
792 visibilityButton->setMenu(visibilityMenu);
793
794 rightToolBar->addWidget(visibilityButton);
795 rightToolBar->addSeparator();
796
797 QAction *saveAct =
798 new QAction(createQIcon("save"), tr("Save Settings"), this);
799 rightToolBar->addAction(saveAct);
800 QAction *loadAct =
801 new QAction(createQIcon("load"), tr("Load Settings"), this);
802 rightToolBar->addAction(loadAct);
803 rightToolBar->addSeparator();
804
805 QAction *resetAct =
806 new QAction(createQIcon("settings_reset"), tr("Reset Settings"), this);
807 rightToolBar->addAction(resetAct);
808
809 connect(swatchAct, SIGNAL(triggered(bool)), m_swatchArea,
810 SLOT(enablePreview(bool)));
811 connect(centerlineAct, SIGNAL(triggered(bool)), m_swatchArea,
812 SLOT(enableDrawCenterlines(bool)));
813 connect(visibilityMenu, SIGNAL(aboutToShow()), this,
814 SLOT(populateVisibilityMenu()));
815 connect(saveAct, SIGNAL(triggered()), this, SLOT(saveParameters()));
816 connect(loadAct, SIGNAL(triggered()), this, SLOT(loadParameters()));
817 connect(resetAct, SIGNAL(triggered()), this, SLOT(resetParameters()));
818
819 //------------------- Convert Button ----------------------
820
821 // Convert Button
822 m_okBtn = new QPushButton(QString(tr("Convert")), this);
823 connect(m_okBtn, SIGNAL(clicked()), this, SLOT(onOk()));
824
825 addButtonBarWidget(m_okBtn);
826
827 // All detailed signals convey to the unique valuesChanged() signal. That
828 // makes it easier
829 // to disconnect update notifications whenever we loadConfiguration(..).
830 connect(this, SIGNAL(valuesChanged()), this, SLOT(updateSceneSettings()));
831
832 // Connect value changes to update the global
833 // VectorizerPopUpSettingsContainer.
834 // connect(m_typeMenu,SIGNAL(currentIndexChanged(const QString
835 // &)),this,SLOT(updateSceneSettings()));
836 connect(m_cThreshold, SIGNAL(valueChanged(bool)), this,
837 SLOT(onValueEdited(bool)));
838 connect(m_cAccuracy, SIGNAL(valueChanged(bool)), this,
839 SLOT(onValueEdited(bool)));
840 connect(m_cDespeckling, SIGNAL(valueChanged(bool)), this,
841 SLOT(onValueEdited(bool)));
842 connect(m_cMaxThickness, SIGNAL(valueChanged(bool)), this,
843 SLOT(onValueEdited(bool)));
844 // connect(m_cThicknessRatio,SIGNAL(valueChanged(bool)),this,SLOT(onValueEdited(bool)));
845 connect(m_cThicknessRatioFirst, SIGNAL(valueChanged()), this,
846 SLOT(onValueEdited()));
847 connect(m_cThicknessRatioLast, SIGNAL(valueChanged()), this,
848 SLOT(onValueEdited()));
849 connect(m_cMakeFrame, SIGNAL(stateChanged(int)), this, SLOT(onValueEdited()));
850 connect(m_cPaintFill, SIGNAL(stateChanged(int)), this, SLOT(onValueEdited()));
851 connect(m_cAlignBoundaryStrokesDirection, SIGNAL(stateChanged(int)), this,
852 SLOT(onValueEdited()));
853 connect(m_cNaaSource, SIGNAL(stateChanged(int)), this, SLOT(onValueEdited()));
854
855 connect(m_oAccuracy, SIGNAL(valueChanged(bool)), this,
856 SLOT(onValueEdited(bool)));
857 connect(m_oDespeckling, SIGNAL(valueChanged(bool)), this,
858 SLOT(onValueEdited(bool)));
859 connect(m_oPaintFill, SIGNAL(stateChanged(int)), this, SLOT(onValueEdited()));
860 connect(m_oAlignBoundaryStrokesDirection, SIGNAL(stateChanged(int)), this,
861 SLOT(onValueEdited()));
862 connect(m_oAdherence, SIGNAL(valueChanged(bool)), this,
863 SLOT(onValueEdited(bool)));
864 connect(m_oAngle, SIGNAL(valueChanged(bool)), this,
865 SLOT(onValueEdited(bool)));
866 connect(m_oRelative, SIGNAL(valueChanged(bool)), this,
867 SLOT(onValueEdited(bool)));
868 connect(m_oDespeckling, SIGNAL(valueChanged(bool)), this,
869 SLOT(onValueEdited(bool)));
870 connect(m_oMaxColors, SIGNAL(valueChanged(bool)), this,
871 SLOT(onValueEdited(bool)));
872 connect(m_oTransparentColor, SIGNAL(colorChanged(const TPixel32 &, bool)),
873 this, SLOT(onValueEdited(const TPixel32 &, bool)));
874 connect(m_oToneThreshold, SIGNAL(valueChanged(bool)), this,
875 SLOT(onValueEdited(bool)));
876
877 refreshPopup();
878
879 // Non e' corretto: manca la possibilita' di aggiornare la selezione del
880 // livello corrente
881 // connect(TApp::instance()->getCurrentLevel(), SIGNAL(xshLevelChanged()),
882 // this, SLOT(updateValues()));
883 }
884
885 //-----------------------------------------------------------------------------
886
getParameters() const887 VectorizerParameters *VectorizerPopup::getParameters() const {
888 assert(m_sceneHandle);
889
890 ToonzScene *scene = m_sceneHandle->getScene();
891 assert(scene);
892
893 TSceneProperties *sceneProp = scene->getProperties();
894 assert(sceneProp);
895
896 assert(sceneProp->getVectorizerParameters());
897 return sceneProp->getVectorizerParameters();
898 }
899
900 //-----------------------------------------------------------------------------
901
onValueEdited(bool isDrag)902 void VectorizerPopup::onValueEdited(bool isDrag) {
903 if (!isDrag) emit valuesChanged();
904 }
905
906 //-----------------------------------------------------------------------------
907
isLevelToConvert(TXshSimpleLevel * sl)908 bool VectorizerPopup::isLevelToConvert(TXshSimpleLevel *sl) {
909 return (sl->getPath().getType() != "pli");
910 }
911
912 //-----------------------------------------------------------------------------
913
apply()914 bool VectorizerPopup::apply() {
915 std::set<TXshLevel *> levels;
916
917 ToonzScene *scene = m_sceneHandle->getScene();
918 if (!scene) {
919 assert(scene);
920 return false;
921 }
922
923 TSceneProperties *sceneProp = scene->getProperties();
924 if (!sceneProp) return false;
925
926 VectorizerParameters *vectorizerParameters =
927 sceneProp->getVectorizerParameters();
928 if (!vectorizerParameters) return false;
929
930 int r0 = 0;
931 int c0 = 0;
932 int r1 = 0;
933 int c1 = 0;
934 bool isCellSelection = getSelectedLevels(levels, r0, c0, r1, c1);
935 if (c0 < 0) c0 = 0;
936 if (levels.empty()) {
937 error(tr("The current selection is invalid."));
938 return false;
939 }
940
941 // Initialize Progress bar
942 m_progressDialog = new DVGui::ProgressDialog("", "Cancel", 0, 1);
943 m_progressDialog->setWindowFlags(
944 Qt::Dialog | Qt::WindowTitleHint); // Don't show ? and X buttons
945 m_progressDialog->setWindowTitle(QString("Convert To Vector..."));
946 m_progressDialog->setAttribute(Qt::WA_DeleteOnClose);
947 m_progressDialog->setWindowModality(
948 Qt::WindowModal); // No user interaction is allowed during vectorization
949 m_progressDialog->setFixedSize(200, 100);
950
951 // Initialize vectorizer
952 m_vectorizer = new Vectorizer;
953
954 m_vectorizer->setParameters(*vectorizerParameters);
955
956 connect(m_vectorizer, SIGNAL(frameName(QString)), this,
957 SLOT(onFrameName(QString)), Qt::QueuedConnection);
958 connect(m_vectorizer, SIGNAL(frameDone(int)), this, SLOT(onFrameDone(int)),
959 Qt::QueuedConnection);
960 connect(m_vectorizer, SIGNAL(partialDone(int, int)), this,
961 SLOT(onPartialDone(int, int)), Qt::QueuedConnection);
962 // We DON'T want the progress bar to be hidden at cancel press - since its
963 // modal
964 // behavior prevents the user to interfere with a possibly still active
965 // vectorization.
966 disconnect(m_progressDialog, SIGNAL(canceled()), m_progressDialog,
967 SLOT(onCancel()));
968 // We first inform the vectorizer of a cancel press;
969 bool ret = connect(m_progressDialog, SIGNAL(canceled()), m_vectorizer,
970 SLOT(cancel()));
971 // which eventually transmits the command to vectorization core, allowing
972 // full-time cancels
973 ret = ret && connect(m_progressDialog, SIGNAL(canceled()), m_vectorizer,
974 SIGNAL(transmitCancel()));
975 // Only after the vectorizer has terminated its process - or got cancelled, we
976 // are allowed
977 // to proceed here.
978 ret = ret && connect(m_vectorizer, SIGNAL(finished()), this,
979 SLOT(onFinished()), Qt::QueuedConnection);
980 assert(ret);
981
982 std::set<int> newColumnIndices;
983 int newIndexColumn = c1 + 1;
984 for (auto const level : levels) {
985 TXshSimpleLevel *sl = dynamic_cast<TXshSimpleLevel *>(level);
986 if (!sl || !sl->getSimpleLevel() || !isLevelToConvert(sl)) {
987 QString levelName = tr(::to_string(sl->getName()).c_str());
988 QString errorMsg =
989 tr("Cannot convert to vector the current selection.") + levelName;
990 error(errorMsg);
991 continue;
992 }
993
994 std::vector<TFrameId> fids;
995
996 if (isCellSelection)
997 getSelectedFids(fids, sl, r0, c0, r1, c1);
998 else
999 sl->getFids(fids);
1000 assert(fids.size() > 0);
1001
1002 close();
1003
1004 // Re-initialize progress Bar
1005 m_progressDialog->setMaximum(fids.size() * 100);
1006 m_progressDialog->setValue(0);
1007 m_currFrame = 0;
1008
1009 // Re-initialize vectorizer
1010 m_vectorizer->setLevel(sl);
1011 m_vectorizer->setFids(fids);
1012
1013 // Start vectorizing
1014 m_vectorizer->start();
1015 m_progressDialog->show();
1016
1017 // Wait the vectorizer...
1018 while (!l_quitLoop)
1019 QCoreApplication::processEvents(QEventLoop::AllEvents |
1020 QEventLoop::WaitForMoreEvents);
1021
1022 l_quitLoop = false;
1023
1024 // Assign output X-sheet cells
1025 TXshSimpleLevel *vl = m_vectorizer->getVectorizedLevel();
1026 if (isCellSelection && vl) {
1027 TXsheet *xsheet = TApp::instance()->getCurrentXsheet()->getXsheet();
1028 xsheet->insertColumn(newIndexColumn);
1029
1030 int r, c;
1031 for (c = c0; c <= c1; c++) {
1032 for (r = r0; r <= r1; r++) {
1033 TXshCell cell = xsheet->getCell(r, c);
1034 TXshSimpleLevel *level =
1035 (!cell.isEmpty()) ? cell.getSimpleLevel() : 0;
1036 if (level != sl) continue;
1037 TFrameId curFid = cell.getFrameId();
1038 std::vector<TFrameId> newFids;
1039 vl->getFids(newFids);
1040 for (auto const &fid : newFids) {
1041 if (fid.getNumber() ==
1042 curFid.getNumber() || // Hanno stesso numero di frame
1043 (fid.getNumber() == 1 &&
1044 curFid.getNumber() ==
1045 -2)) // La vecchia cella non ha numero di frame
1046 xsheet->setCell(r, newIndexColumn, TXshCell(vl, fid));
1047 }
1048 }
1049 }
1050 newColumnIndices.insert(newIndexColumn);
1051 newIndexColumn += 1;
1052 } else if (vl) {
1053 std::vector<TFrameId> gomi;
1054 newColumnIndices.insert(scene->getXsheet()->getFirstFreeColumnIndex());
1055 scene->getXsheet()->exposeLevel(
1056 0, scene->getXsheet()->getFirstFreeColumnIndex(), vl, gomi);
1057 }
1058
1059 if (m_vectorizer->isCanceled()) break;
1060 }
1061
1062 // Add undo object
1063 if (!m_vectorizer->isCanceled())
1064 ColumnCmd::addConvertToVectorUndo(newColumnIndices);
1065
1066 m_progressDialog->close();
1067 delete m_vectorizer;
1068
1069 TApp::instance()->getCurrentScene()->notifyCastChange();
1070 TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
1071
1072 return true;
1073 }
1074
1075 //-----------------------------------------------------------------------------
1076
onFinished()1077 void VectorizerPopup::onFinished() { l_quitLoop = true; }
1078
1079 //-----------------------------------------------------------------------------
1080
onFrameName(QString frameName)1081 void VectorizerPopup::onFrameName(QString frameName) {
1082 QString label = tr("Conversion in progress: ") + frameName;
1083 m_progressDialog->setLabelText(label);
1084 }
1085
1086 //-----------------------------------------------------------------------------
1087
onFrameDone(int frameCount)1088 void VectorizerPopup::onFrameDone(int frameCount) {
1089 m_progressDialog->setValue(
1090 frameCount * 100); // 100 multiplier stands for partial progresses
1091 m_currFrame = frameCount;
1092 }
1093
1094 //-----------------------------------------------------------------------------
1095
onPartialDone(int partial,int total)1096 void VectorizerPopup::onPartialDone(int partial, int total) {
1097 int value = (m_currFrame + partial / (double)total) * 100.0;
1098
1099 // NOTA: Puo' essere che la seguente non sia vera - dipende dall'ordine di
1100 // esecuzione dei segnali
1101 // onFrameDone e onPartialDone - se i primi si fanno in massa prima... Puo'
1102 // generare uno stack overflow...
1103 // NOTA: Non va ancora bene. Cosi' si attenua largamente il problema, ma a
1104 // volte puo' ancora succedere.
1105 if (value > m_progressDialog->value() + 5 &&
1106 value < m_progressDialog->maximum()) {
1107 // qDebug("Partial %d of %d; Value %d of %d", partial, total, value,
1108 // m_progressDialog->maximum());
1109 m_progressDialog->setValue(value);
1110 }
1111 /*else
1112 {
1113 if(value != m_progressDialog->value())
1114 qDebug("ERRORE: VALORE PB= %d; Valore: %d",m_progressDialog->value(),value);
1115 }*/
1116 }
1117
1118 //-----------------------------------------------------------------------------
1119
onOk()1120 void VectorizerPopup::onOk() { apply(); }
1121
1122 //-----------------------------------------------------------------------------
1123
1124 //! Copies the pop-up settings into scene settings.
updateSceneSettings()1125 void VectorizerPopup::updateSceneSettings() {
1126 VectorizerParameters *vParams = getParameters();
1127 assert(vParams);
1128
1129 bool outline = (m_typeMenu->currentIndex() == 1);
1130 vParams->m_isOutline = outline;
1131
1132 if (outline) {
1133 vParams->m_oDespeckling = m_oDespeckling->getValue();
1134 vParams->m_oAccuracy = m_oAccuracy->getValue();
1135 vParams->m_oAdherence = m_oAdherence->getValue();
1136 vParams->m_oAngle = m_oAngle->getValue();
1137 vParams->m_oRelative = m_oRelative->getValue();
1138 vParams->m_oMaxColors = m_oMaxColors->getValue();
1139 vParams->m_oToneThreshold = m_oToneThreshold->getValue();
1140 vParams->m_oTransparentColor = m_oTransparentColor->getColor();
1141 vParams->m_oPaintFill = m_oPaintFill->isChecked();
1142 vParams->m_oAlignBoundaryStrokesDirection =
1143 m_oAlignBoundaryStrokesDirection->isChecked();
1144 } else {
1145 vParams->m_cThreshold = m_cThreshold->getValue();
1146 vParams->m_cAccuracy = m_cAccuracy->getValue();
1147 vParams->m_cDespeckling = m_cDespeckling->getValue();
1148 vParams->m_cMaxThickness = m_cMaxThickness->getValue();
1149 vParams->m_cThicknessRatioFirst =
1150 m_cThicknessRatioFirst->getValue() * 100.0;
1151 vParams->m_cThicknessRatioLast = m_cThicknessRatioLast->getValue() * 100.0;
1152 vParams->m_cMakeFrame = m_cMakeFrame->isChecked();
1153 vParams->m_cPaintFill = m_cPaintFill->isChecked();
1154 vParams->m_cAlignBoundaryStrokesDirection =
1155 m_cAlignBoundaryStrokesDirection->isChecked();
1156 vParams->m_cNaaSource = m_cNaaSource->isChecked();
1157 }
1158 }
1159
1160 //-----------------------------------------------------------------------------
1161
refreshPopup()1162 void VectorizerPopup::refreshPopup() { setType(getParameters()->m_isOutline); }
1163
1164 //-----------------------------------------------------------------------------
1165
updateVisibility()1166 void VectorizerPopup::updateVisibility() {
1167 struct Locals {
1168 QGridLayout *const m_paramsLayout;
1169
1170 void setVisible(QLayoutItem *item, bool visible) {
1171 if (item) {
1172 if (QWidget *w = item->widget())
1173 w->setVisible(visible);
1174 else if (QLayout *l = item->layout()) {
1175 int i, iCount = l->count();
1176 for (i = 0; i != iCount; ++i) setVisible(l->itemAt(i), visible);
1177 }
1178 }
1179 }
1180
1181 void setVisible(int row, bool visible) {
1182 int c, cCount = m_paramsLayout->columnCount();
1183 for (c = 0; c != cCount; ++c)
1184 setVisible(m_paramsLayout->itemAtPosition(row, c), visible);
1185 }
1186
1187 void setVisible(const std::vector<ParamGroup> ¶mGroups,
1188 int visibilityBits) {
1189 // Iterate parameter groups
1190 std::vector<ParamGroup>::const_iterator pgt, pgEnd = paramGroups.end();
1191 for (pgt = paramGroups.begin(); pgt != pgEnd; ++pgt) {
1192 bool groupVisible = false;
1193
1194 // Iterate parameters
1195 int r, rCount = int(pgt->m_params.size());
1196 for (r = 0; r != rCount; ++r) {
1197 bool visible = (visibilityBits >> pgt->m_params[r].m_bit) & 1;
1198
1199 setVisible(pgt->m_startRow + r, visible);
1200 groupVisible = visible | groupVisible;
1201 }
1202
1203 // Finally, set group header's visibility
1204 if (pgt->m_separatorRow >= 0)
1205 setVisible(pgt->m_separatorRow, groupVisible);
1206 }
1207 }
1208
1209 } locals = {m_paramsLayout};
1210
1211 VectorizerParameters *vParams = getParameters();
1212 assert(vParams);
1213
1214 locals.setVisible(
1215 vParams->m_isOutline ? l_outlineParamGroups : l_centerlineParamGroups,
1216 vParams->m_visibilityBits);
1217 }
1218
1219 //-----------------------------------------------------------------------------
1220
onTypeChange(int indexType)1221 void VectorizerPopup::onTypeChange(int indexType) {
1222 ToonzScene *scene = m_sceneHandle->getScene();
1223 if (!scene) return;
1224 TSceneProperties *sceneProp = scene->getProperties();
1225 if (!sceneProp) return;
1226 VectorizerParameters *vectorizerParameters =
1227 sceneProp->getVectorizerParameters();
1228 if (!vectorizerParameters) return;
1229 bool isOutline = vectorizerParameters->m_isOutline;
1230 bool isNewTypeOutline = (indexType == 0) ? false : true;
1231 if (isNewTypeOutline == isOutline) return;
1232
1233 vectorizerParameters->m_isOutline = isNewTypeOutline;
1234 setType(isNewTypeOutline);
1235
1236 m_swatchArea->invalidateContents();
1237 }
1238
1239 //-----------------------------------------------------------------------------
1240
setType(bool outline)1241 void VectorizerPopup::setType(bool outline) {
1242 disconnect(m_typeMenu, SIGNAL(currentIndexChanged(int)), this,
1243 SLOT(onTypeChange(int)));
1244
1245 // Setting child visibility alot invokes several layout updates - causing
1246 // extensive flickering
1247 m_paramsWidget->layout()->setEnabled(false);
1248
1249 bool centerline = !outline;
1250 m_typeMenu->setCurrentIndex((int)outline);
1251
1252 m_cThresholdLabel->setVisible(centerline);
1253 m_cThreshold->setVisible(centerline);
1254 m_cAccuracyLabel->setVisible(centerline);
1255 m_cAccuracy->setVisible(centerline);
1256 m_cDespecklingLabel->setVisible(centerline);
1257 m_cDespeckling->setVisible(centerline);
1258 m_cMaxThicknessLabel->setVisible(centerline);
1259 m_cMaxThickness->setVisible(centerline);
1260 // m_cThicknessRatio->setVisible(centerline);
1261 m_cThicknessRatioLabel->setVisible(centerline);
1262 m_cThicknessRatioFirstLabel->setVisible(centerline);
1263 m_cThicknessRatioFirst->setVisible(centerline);
1264 m_cThicknessRatioLastLabel->setVisible(centerline);
1265 m_cThicknessRatioLast->setVisible(centerline);
1266
1267 m_cPaintFill->setVisible(centerline);
1268 m_cAlignBoundaryStrokesDirection->setVisible(centerline);
1269 m_cMakeFrame->setVisible(centerline);
1270 m_cNaaSourceSeparator->setVisible(centerline);
1271 m_cNaaSource->setVisible(centerline);
1272
1273 m_oAccuracyLabel->setVisible(outline);
1274 m_oAccuracy->setVisible(outline);
1275 m_oDespecklingLabel->setVisible(outline);
1276 m_oDespeckling->setVisible(outline);
1277 m_oPaintFill->setVisible(outline);
1278 m_oAlignBoundaryStrokesDirection->setVisible(outline);
1279 m_oCornersSeparator->setVisible(outline);
1280 m_oAngleLabel->setVisible(outline);
1281 m_oAngle->setVisible(outline);
1282 m_oAdherenceLabel->setVisible(outline);
1283 m_oAdherence->setVisible(outline);
1284 m_oRelativeLabel->setVisible(outline);
1285 m_oRelative->setVisible(outline);
1286 m_oFullColorSeparator->setVisible(outline);
1287 m_oMaxColorsLabel->setVisible(outline);
1288 m_oMaxColors->setVisible(outline);
1289 m_oTransparentColorLabel->setVisible(outline);
1290 m_oTransparentColor->setVisible(outline);
1291 m_oTlvSeparator->setVisible(outline);
1292 m_oToneThresholdLabel->setVisible(outline);
1293 m_oToneThreshold->setVisible(outline);
1294
1295 m_paramsWidget->layout()->setEnabled(true);
1296
1297 loadConfiguration(outline);
1298
1299 connect(m_typeMenu, SIGNAL(currentIndexChanged(int)), this,
1300 SLOT(onTypeChange(int)));
1301
1302 updateVisibility();
1303 }
1304
1305 //-----------------------------------------------------------------------------
1306
1307 // This is essentially the inverse of the previous one.
loadConfiguration(bool isOutline)1308 void VectorizerPopup::loadConfiguration(bool isOutline) {
1309 disconnect(SIGNAL(valuesChanged())); // Avoid notifications for value changes
1310
1311 ToonzScene *scene = m_sceneHandle->getScene();
1312 assert(scene);
1313
1314 TSceneProperties *sceneProp = scene->getProperties();
1315 assert(sceneProp);
1316
1317 VectorizerParameters *vParams = sceneProp->getVectorizerParameters();
1318 assert(vParams);
1319
1320 loadRanges(isOutline);
1321
1322 if (isOutline) {
1323 m_oDespeckling->setValue(vParams->m_oDespeckling);
1324 m_oAdherence->setValue(vParams->m_oAdherence);
1325 m_oAngle->setValue(vParams->m_oAngle);
1326 m_oRelative->setValue(vParams->m_oRelative);
1327 m_oAccuracy->setValue(vParams->m_oAccuracy);
1328 m_oPaintFill->setChecked(vParams->m_oPaintFill);
1329 m_oAlignBoundaryStrokesDirection->setChecked(
1330 vParams->m_oAlignBoundaryStrokesDirection);
1331 m_oMaxColors->setValue(vParams->m_oMaxColors);
1332 m_oTransparentColor->setColor(vParams->m_oTransparentColor);
1333 m_oToneThreshold->setValue(vParams->m_oToneThreshold);
1334 } else {
1335 m_cThreshold->setValue(vParams->m_cThreshold);
1336 m_cDespeckling->setValue(vParams->m_cDespeckling);
1337 m_cPaintFill->setChecked(vParams->m_cPaintFill);
1338 m_cAlignBoundaryStrokesDirection->setChecked(
1339 vParams->m_cAlignBoundaryStrokesDirection);
1340 m_cMakeFrame->setChecked(vParams->m_cMakeFrame);
1341 m_cNaaSource->setChecked(vParams->m_cNaaSource);
1342 m_cMaxThickness->setValue(vParams->m_cMaxThickness);
1343 m_cAccuracy->setValue(vParams->m_cAccuracy);
1344 // m_cThicknessRatio->setValue(vParams->m_cThicknessRatio);
1345 m_cThicknessRatioFirst->setValue(vParams->m_cThicknessRatioFirst / 100.0);
1346 m_cThicknessRatioLast->setValue(vParams->m_cThicknessRatioLast / 100.0);
1347 }
1348
1349 // Reconnect changes update
1350 connect(this, SIGNAL(valuesChanged()), this, SLOT(updateSceneSettings()));
1351 connect(this, SIGNAL(valuesChanged()), m_swatchArea,
1352 SLOT(invalidateContents()));
1353
1354 m_swatchArea->updateContents();
1355 }
1356
1357 //-----------------------------------------------------------------------------
1358
loadRanges(int outline)1359 void VectorizerPopup::loadRanges(int outline) {
1360 if (outline) {
1361 m_oAccuracy->setRange(0, 10);
1362 m_oDespeckling->setRange(0, 10);
1363 m_oAdherence->setRange(0, 100);
1364 m_oAngle->setRange(0, 180);
1365 m_oRelative->setRange(0, 100);
1366 m_oMaxColors->setRange(1, 256);
1367 m_oToneThreshold->setRange(0, 255);
1368 } else {
1369 m_cThreshold->setRange(1, 10);
1370 m_cAccuracy->setRange(1, 10);
1371 m_cDespeckling->setRange(1, 10);
1372 m_cMaxThickness->setRange(0, (std::numeric_limits<int>::max)());
1373 // m_cThicknessRatio->setRange(0,100);
1374 m_cThicknessRatioFirst->setRange(0, 1.0);
1375 m_cThicknessRatioLast->setRange(0, 1.0);
1376 }
1377 }
1378
1379 //-----------------------------------------------------------------------------
1380
showEvent(QShowEvent * se)1381 void VectorizerPopup::showEvent(QShowEvent *se) {
1382 refreshPopup();
1383 connect(m_sceneHandle, SIGNAL(sceneSwitched()), SLOT(refreshPopup()));
1384 }
1385
1386 //-----------------------------------------------------------------------------
1387
hideEvent(QHideEvent * he)1388 void VectorizerPopup::hideEvent(QHideEvent *he) {
1389 refreshPopup();
1390 disconnect(m_sceneHandle, SIGNAL(sceneSwitched()), this,
1391 SLOT(refreshPopup()));
1392 Dialog::hideEvent(he);
1393 }
1394
1395 //-----------------------------------------------------------------------------
1396
populateVisibilityMenu()1397 void VectorizerPopup::populateVisibilityMenu() {
1398 struct Locals {
1399 VectorizerPopup *m_this;
1400
1401 void addActions(QMenu *menu, const std::vector<ParamGroup> ¶mGroups,
1402 int visibilityBits) {
1403 std::vector<ParamGroup>::const_iterator gt, gEnd = paramGroups.end();
1404
1405 for (gt = paramGroups.begin(); gt != gEnd; ++gt) {
1406 if (gt->m_separatorRow >= 0) menu->addSeparator();
1407
1408 std::vector<Param>::const_iterator pt, pEnd = gt->m_params.end();
1409 for (pt = gt->m_params.begin(); pt != pEnd; ++pt) {
1410 QAction *visibleParam = menu->addAction(pt->m_name);
1411 visibleParam->setCheckable(true);
1412 visibleParam->setChecked(visibilityBits & (1 << pt->m_bit));
1413 visibleParam->setData(pt->m_bit);
1414
1415 bool ret = connect(visibleParam, SIGNAL(toggled(bool)), m_this,
1416 SLOT(visibilityToggled()));
1417 assert(ret);
1418 }
1419 }
1420 }
1421
1422 } locals = {this};
1423
1424 QMenu *menu = qobject_cast<QMenu *>(sender());
1425 menu->clear();
1426
1427 VectorizerParameters *vParams = getParameters();
1428 locals.addActions(
1429 menu,
1430 vParams->m_isOutline ? l_outlineParamGroups : l_centerlineParamGroups,
1431 vParams->m_visibilityBits);
1432 }
1433
1434 //-----------------------------------------------------------------------------
1435
visibilityToggled()1436 void VectorizerPopup::visibilityToggled() {
1437 QAction *action = qobject_cast<QAction *>(sender());
1438 assert(action);
1439
1440 const QVariant &data = action->data();
1441 assert(data.canConvert<int>());
1442
1443 int row = action->data().toInt();
1444
1445 VectorizerParameters *vParams = getParameters();
1446 vParams->m_visibilityBits ^= (1 << row);
1447
1448 updateVisibility();
1449 }
1450
1451 //-----------------------------------------------------------------------------
1452
saveParameters()1453 void VectorizerPopup::saveParameters() {
1454 struct {
1455 VectorizerPopup *m_this;
1456
1457 static bool vectorizerType(TPersist *persist) {
1458 return (dynamic_cast<VectorizerParameters *>(persist) != 0);
1459 }
1460
1461 void saveParams(const TFilePath &fp) // May throw due to I/O failure
1462 {
1463 // Read the complete file first
1464 TPersistSet levelSettings;
1465
1466 if (TSystem::doesExistFileOrLevel(fp)) {
1467 TIStream is(fp);
1468
1469 if (!is)
1470 throw TException(
1471 tr("File could not be opened for read").toStdWString());
1472
1473 is >> levelSettings;
1474 }
1475
1476 // Replace data to be saved
1477 VectorizerParameters *params = getCurrentVectorizerParameters();
1478
1479 levelSettings.insert(
1480 std::unique_ptr<TPersist>(new VectorizerParameters(*params)));
1481
1482 // Save the new settings
1483 TOStream os(fp);
1484
1485 if (!os)
1486 throw TException(
1487 tr("File could not be opened for write").toStdWString());
1488
1489 os << levelSettings;
1490 }
1491
1492 } locals = {this};
1493
1494 // Retrieve current level path
1495 TFilePath folder, fileName;
1496
1497 const TFilePath &levelPath = getSelectedLevelPath();
1498 if (!levelPath.isEmpty()) {
1499 folder = levelPath.getParentDir();
1500 fileName = TFilePath(levelPath.getWideName()).withType("tnzsettings");
1501 }
1502
1503 // Open save popup with defaulted path
1504 static GenericSaveFilePopup *popup =
1505 new GenericSaveFilePopup(tr("Save Vectorizer Parameters"));
1506
1507 popup->setFilterTypes(QStringList("tnzsettings"));
1508 popup->setFolder(folder);
1509 popup->setFilename(fileName);
1510
1511 fileName = popup->getPath();
1512 if (!fileName.isEmpty()) {
1513 try {
1514 locals.saveParams(fileName);
1515 } catch (const TException &e) {
1516 DVGui::error(QString::fromStdWString(e.getMessage()));
1517 }
1518 }
1519 }
1520
1521 //-----------------------------------------------------------------------------
1522
loadParameters()1523 void VectorizerPopup::loadParameters() {
1524 struct {
1525 VectorizerPopup *m_this;
1526
1527 void loadParams(const TFilePath &fp) // May throw due to I/O failure
1528 {
1529 TIStream is(fp);
1530
1531 if (!is)
1532 throw TException(
1533 tr("File could not be opened for read").toStdWString());
1534
1535 VectorizerParameters *vParams = getCurrentVectorizerParameters();
1536 const std::string &vParamsTag = vParams->getStreamTag();
1537
1538 std::string tagName;
1539 while (is.matchTag(tagName)) {
1540 if (tagName == vParamsTag)
1541 is >> *vParams, is.matchEndTag();
1542 else
1543 is.skipCurrentTag();
1544 }
1545 }
1546
1547 } locals = {this};
1548
1549 // Retrieve current level path
1550 TFilePath folder, fileName;
1551
1552 const TFilePath &levelPath = getSelectedLevelPath();
1553 if (!levelPath.isEmpty()) {
1554 folder = levelPath.getParentDir();
1555 fileName = TFilePath(levelPath.getWideName()).withType("tnzsettings");
1556 }
1557
1558 // Open load popup with defaulted path
1559 static GenericLoadFilePopup *popup =
1560 new GenericLoadFilePopup(tr("Load Vectorizer Parameters"));
1561
1562 popup->setFilterTypes(QStringList("tnzsettings"));
1563 popup->setFolder(folder);
1564 popup->setFilename(fileName);
1565
1566 fileName = popup->getPath();
1567 if (!fileName.isEmpty()) {
1568 try {
1569 locals.loadParams(fileName);
1570 refreshPopup(); // Update GUI to reflect changes
1571 } catch (const TException &e) {
1572 DVGui::error(QString::fromStdWString(e.getMessage()));
1573 }
1574 }
1575 }
1576
1577 //-----------------------------------------------------------------------------
1578
resetParameters()1579 void VectorizerPopup::resetParameters() {
1580 *getCurrentVectorizerParameters() = VectorizerParameters();
1581 refreshPopup();
1582 }
1583
1584 //*****************************************************************************
1585 // VectorizerPopupCommand instantiation
1586 //*****************************************************************************
1587
1588 OpenPopupCommandHandler<VectorizerPopup> openVectorizerPopup(
1589 MI_ConvertToVectors);
1590