1 
2 
3 #include "toonzqt/dvdialog.h"
4 
5 // TnzQt includes
6 #include "toonzqt/checkbox.h"
7 #include "toonzqt/lineedit.h"
8 #include "toonzqt/fxsettings.h"
9 
10 // TnzLib includes
11 #include "toonz/txsheethandle.h"
12 #include "toonz/txshsimplelevel.h"
13 #include "toonz/palettecmd.h"
14 #include "toonz/preferences.h"
15 #include "toonz/toonzfolders.h"
16 
17 // TnzCore includes
18 #include "tversion.h"
19 
20 // Qt includes
21 #include <QFrame>
22 #include <QLayout>
23 #include <QLabel>
24 #include <QPushButton>
25 #include <QApplication>
26 #include <QStyle>
27 #include <QButtonGroup>
28 #include <QPainter>
29 #include <QRadioButton>
30 #include <QThread>
31 #include <QDesktopWidget>
32 #include <QCheckBox>
33 
34 #include <algorithm>
35 
36 using namespace DVGui;
37 
38 //=============================================================================
39 namespace {
getMsgBoxPixmap(MsgType type)40 QPixmap getMsgBoxPixmap(MsgType type) {
41   int iconSize =
42       QApplication::style()->pixelMetric(QStyle::PM_MessageBoxIconSize);
43   QIcon msgBoxIcon;
44 
45   switch (type) {
46   case DVGui::INFORMATION:
47     msgBoxIcon =
48         QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation);
49     break;
50   case DVGui::WARNING:
51     msgBoxIcon =
52         QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning);
53     break;
54   case DVGui::CRITICAL:
55     msgBoxIcon =
56         QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical);
57     break;
58   case DVGui::QUESTION:
59     msgBoxIcon =
60         QApplication::style()->standardIcon(QStyle::SP_MessageBoxQuestion);
61     break;
62   default:
63     break;
64   }
65 
66   if (!msgBoxIcon.isNull()) return msgBoxIcon.pixmap(iconSize, iconSize);
67   return QPixmap();
68 }
69 
70 //-----------------------------------------------------------------------------
71 
getMsgBoxTitle(MsgType type)72 QString getMsgBoxTitle(MsgType type) {
73   TVER::ToonzVersion tver;
74   QString title = QString::fromStdString(tver.getAppName() + " " +
75                                          tver.getAppVersionString() + " - ");
76 
77   switch (type) {
78   case DVGui::INFORMATION:
79     title.append(QObject::tr("Information"));
80     break;
81   case DVGui::WARNING:
82     title.append(QObject::tr("Warning"));
83     break;
84   case DVGui::CRITICAL:
85     title.append(QObject::tr("Critical"));
86     break;
87   case DVGui::QUESTION:
88     title.append(QObject::tr("Question"));
89     break;
90   default:
91     break;
92   }
93   return title;
94 }
95 
96 //-----------------------------------------------------------------------------
97 }  // namespace
98 //-----------------------------------------------------------------------------
99 
100 //=============================================================================
101 // Separator
102 //-----------------------------------------------------------------------------
103 
Separator(QString name,QWidget * parent,bool isHorizontal)104 Separator::Separator(QString name, QWidget *parent, bool isHorizontal)
105     : QFrame(parent), m_name(name), m_isHorizontal(isHorizontal) {
106   //	if(m_name.isEmpty())
107   //		setMinimumSize(1,1);
108   //	else
109   setMinimumSize(1, 15);
110 }
111 
112 //-----------------------------------------------------------------------------
113 
~Separator()114 Separator::~Separator() {}
115 
116 //-----------------------------------------------------------------------------
117 
paintEvent(QPaintEvent *)118 void Separator::paintEvent(QPaintEvent *) {
119   QPainter p(this);
120   ParamsPage *page = dynamic_cast<ParamsPage *>(parentWidget());
121   if (!page)
122     p.setPen(palette().alternateBase().color());
123   else
124     p.setPen(page->getTextColor());
125 
126   QRect contents(contentsRect());
127 
128   int textWidth = p.fontMetrics().width(m_name);
129 
130   p.drawText(contents.left(), 10, m_name);
131 
132   // make the line semi-transparent
133   QColor lineColor = Qt::black;
134   lineColor.setAlpha(128);
135 
136   p.setPen(lineColor);
137   int h = contents.height();
138   if (m_isHorizontal) {
139     int y     = contents.center().y();
140     int space = (textWidth == 0) ? 0 : 8;
141     p.drawLine(textWidth + space, y, contents.width(), y);
142   } else {
143     double w       = width();
144     int space      = (textWidth == 0) ? 0 : 2;
145     int x0         = (w > textWidth) ? w * 0.5 : (double)textWidth * 0.5;
146     int textHeghit = (space == 0) ? 0 : p.fontMetrics().height();
147     p.drawLine(x0, textHeghit + space, x0, contents.bottom());
148   }
149 }
150 
151 //=============================================================================
152 /*! \class DVGui::Dialog
153                 \brief The Dialog class is the base class of dialog windows.
154 
155                 Inherits \b QDialog.
156 
157                 A dialog window is a top-level window, defined in \b QDialog,
158 this class provides
159                 a collection of functions to manage \b QDialog widget
160 visualization.
161                 Dialog window can be modal or modeless, from this it depends
162 dialog visualization.
163                 You set your dialog to modal or modeless directly in
164 constructor, with \b bool
165                 hasButton, in fact if the dialog has button then is modal too.
166 
167                 If dialog is \b modal it's composed of two part, two \b QFrame;
168 the first, \b main
169                 \b part at top of dialog, contains a vertical box layout \b
170 QVBoxLayout, the second,
171                 \b button \b part at bottom, contains an horizontal box layout
172 \b QHBoxLayout.
173                 Else if dialog is modeless it is composed only of first part, to
174 be more precise,
175                 it is composed of a \b QFrame containing a vertical box layout
176 \b QVBoxLayout.
177 
178                 The first part of dialog can be implemented using different
179 objects. You can manage
180                 directly vertical box layout, insert widget addWidget(), or
181 layout addLayout(), set
182                 border and spacing, using setTopMargin() and setTopSpacing(), or
183 insert a spece,
184                 addSpacing().
185 \n	If you need an horizontal layout you can use an implemented horizontal
186 box layout;
187                 the function beginHLayout() initialize the horizontal box
188 layout, a collection of
189                 function permit to insert object in this layout; at the end you
190 must recall
191                 endVLayout(), this add horizontal layout to first part of
192 dialog.
193                 This struct permit you to allign the object you insert.
194 \n	If you need vertical layout you can use an implemented vertical box
195 layout composed
196                 of two column, the function beginVLayout() initialize the
197 vertical box layout,
198                 a collection of function permit to insert object in this layout.
199                 All this functions insert a pair of object in two vertical
200 layout and permit
201                 to allign the objects, all pairs you insert are tabulated.
202                 At the end you must recall endVLayout(), this add vertical
203 layout to first part of
204                 dialog.
205 
206                 The second part of dialog may be implemented if dialog is modal.
207                 It's possible insert one, two or three widget in its horizontal
208 box layout using
209                 addButtonBarWidget(), or clear all widget using
210 clearButtonBar(). You can also
211                 set margin and spacing with setButtonBarMargin() and
212 setButtonBarSpacing() functions.
213 */
214 //-----------------------------------------------------------------------------
215 
216 namespace {
217 QString settingsPath;
218 };
219 
Dialog(QWidget * parent,bool hasButton,bool hasFixedSize,const QString & name)220 Dialog::Dialog(QWidget *parent, bool hasButton, bool hasFixedSize,
221                const QString &name)
222     : QDialog(parent, Qt::CustomizeWindowHint | Qt::WindowTitleHint |
223                           Qt::WindowCloseButtonHint)
224     , m_hasButton(hasButton)
225     , m_mainHLayout(0)
226     , m_leftVLayout(0)
227     , m_rightVLayout(0)
228     , m_isMainVLayout(false)
229     , m_isMainHLayout(false)
230     , m_layoutSpacing(5)
231     , m_layoutMargin(0)
232     , m_labelWidth(100)
233     , m_name() {
234   QVBoxLayout *mainLayout = new QVBoxLayout;
235   mainLayout->setMargin(0);
236   mainLayout->setSpacing(0);
237   m_mainFrame = new QFrame(this);
238   m_mainFrame->setObjectName("dialogMainFrame");
239   m_mainFrame->setMinimumHeight(41);
240   m_mainFrame->setFrameStyle(QFrame::StyledPanel);
241   m_topLayout = new QVBoxLayout;
242   m_topLayout->setMargin(12);
243   m_topLayout->setSpacing(m_layoutSpacing);
244   m_topLayout->setAlignment(Qt::AlignCenter);
245   m_mainFrame->setLayout(m_topLayout);
246 
247   mainLayout->addWidget(m_mainFrame);
248 
249   if (m_hasButton) {
250     // The dialog is modal
251     setModal(true);
252 
253     m_buttonFrame = new QFrame(this);
254     m_buttonFrame->setObjectName("dialogButtonFrame");
255     m_buttonFrame->setFrameStyle(QFrame::StyledPanel);
256     m_buttonFrame->setFixedHeight(45);
257 
258     m_buttonLayout = new QHBoxLayout;
259     m_buttonLayout->setMargin(0);
260     m_buttonLayout->setSpacing(20);
261     m_buttonLayout->setAlignment(Qt::AlignHCenter);
262 
263     QVBoxLayout *buttonFrameLayout = new QVBoxLayout;
264     buttonFrameLayout->setAlignment(Qt::AlignVCenter);
265     buttonFrameLayout->addLayout(m_buttonLayout);
266     m_buttonFrame->setLayout(buttonFrameLayout);
267 
268     mainLayout->addWidget(m_buttonFrame);
269   }
270 
271   if (hasFixedSize)
272     mainLayout->setSizeConstraint(QLayout::SetFixedSize);
273   else
274     mainLayout->setSizeConstraint(QLayout::SetMinimumSize);
275 
276   setLayout(mainLayout);
277 // this->setGeometry(30, 30, 300, 300);
278 #ifdef MACOSX
279   setWindowFlags(Qt::Tool);
280 #endif
281 
282   if (settingsPath.isEmpty()) {
283     TFilePath savePath =
284         ToonzFolder::getMyModuleDir() + TFilePath("popups.ini");
285     settingsPath = QString::fromStdWString(savePath.getWideString());
286   }
287 
288   QSettings settings(settingsPath, QSettings::IniFormat);
289 
290   if (name == QString()) return;
291   m_name      = name + "DialogGeometry";
292   QString geo = settings.value(m_name).toString();
293   if (geo != QString()) {
294     QStringList values = geo.split(" ");
295     assert(values.size() == 4);
296     // Ensure that the dialog is visible in the screen.
297     // The dialog opens with some offset to bottom-right direction
298     // if a flag Qt::WindowMaximizeButtonHint is set. (e.g. PencilTestPopup)
299     // Therefore, if the dialog is moved to the bottom-end of the screen,
300     // it will be got out of the screen on the next launch.
301     // The following position adjustment will also prevent such behavior.
302 
303     // try and get active screen
304     if (parent != NULL) {
305       m_currentScreen = QApplication::desktop()->screenNumber(parent);
306     }
307     QRect screen = QApplication::desktop()->availableGeometry(m_currentScreen);
308     int x        = values.at(0).toInt();
309     int y        = values.at(1).toInt();
310 
311     // make sure that the window is visible on the screen
312     // all popups will popup on the active window the first time
313     // so popups moved to other monitors will be moved back
314     // when restarting OpenToonz.
315 
316     // This may be somewhat annoying if a user REALLY wants the popup
317     // on another monitor by default, but this is better than
318     // a user thinking the program is broken because they didn't notice
319     // the popup on another monitor
320     if (x > screen.right() - 50) x = screen.right() - 50;
321     if (x < screen.left()) x = screen.left();
322     if (y > screen.bottom() - 90) y = screen.bottom() - 90;
323     if (y < screen.top()) y = screen.top();
324     setGeometry(x, y, values.at(2).toInt(), values.at(3).toInt());
325     settings.setValue(m_name, QString::number(x) + " " + QString::number(y) +
326                                   " " + QString::number(values.at(2).toInt()) +
327                                   " " + QString::number(values.at(3).toInt()));
328   }
329 }
330 
331 //-----------------------------------------------------------------------------
332 
~Dialog()333 Dialog::~Dialog() {
334   if (m_name == QString()) return;
335 
336   QRect r = geometry();
337   QSettings settings(settingsPath, QSettings::IniFormat);
338   settings.setValue(m_name, QString::number(r.left()) + " " +
339                                 QString::number(r.top()) + " " +
340                                 QString::number(r.width()) + " " +
341                                 QString::number(r.height()));
342 }
343 
344 //---------------------------------------------------------------------------------
345 
resizeEvent(QResizeEvent * e)346 void Dialog::resizeEvent(QResizeEvent *e) {
347   if (Preferences::instance()->getCurrentLanguage() != "English") {
348     QSize t = this->size();
349     for (QLabel *s : m_labelList) s->setFixedWidth(t.width() * .35);
350   }
351 }
352 
353 //-----------------------------------------------------------------------------
354 
355 //! By default, QDialogs always reset position/size upon hide events. However,
356 //! we want to prevent such behaviour on Toonz Dialogs - this method is
357 //! reimplemented
358 //! for this purpose.
hideEvent(QHideEvent * event)359 void Dialog::hideEvent(QHideEvent *event) {
360   int x = pos().rx();
361   int y = pos().ry();
362   // make sure the dialog is actually visible on a screen
363   int screenCount = QApplication::desktop()->screenCount();
364   int currentScreen;
365   for (int i = 0; i < screenCount; i++) {
366     if (QApplication::desktop()->screenGeometry(i).contains(pos())) {
367       currentScreen = i;
368       break;
369     } else {
370       // if not - put it back on the main window
371       currentScreen = m_currentScreen;
372     }
373   }
374   QRect screen = QApplication::desktop()->availableGeometry(currentScreen);
375 
376   if (x > screen.right() - 50) x = screen.right() - 50;
377   if (x < screen.left()) x = screen.left();
378   if (y > screen.bottom() - 90) y = screen.bottom() - 90;
379   if (y < screen.top()) y = screen.top();
380   move(QPoint(x, y));
381   resize(size());
382   QRect r = geometry();
383   QSettings settings(settingsPath, QSettings::IniFormat);
384   settings.setValue(m_name, QString::number(r.left()) + " " +
385                                 QString::number(r.top()) + " " +
386                                 QString::number(r.width()) + " " +
387                                 QString::number(r.height()));
388   emit dialogClosed();
389 }
390 
391 //-----------------------------------------------------------------------------
392 /*! Create the new layouts (2 Vertical) for main part of dialog.
393  */
beginVLayout()394 void Dialog::beginVLayout() {
395   m_isMainVLayout = true;
396 
397   m_leftVLayout = new QVBoxLayout;
398   m_leftVLayout->setMargin(m_layoutMargin);
399   m_leftVLayout->setSpacing(m_layoutSpacing);
400 
401   m_rightVLayout = new QVBoxLayout;
402   m_rightVLayout->setMargin(m_layoutMargin);
403   m_rightVLayout->setSpacing(m_layoutSpacing);
404 }
405 
406 //-----------------------------------------------------------------------------
407 /*! Add to main part of dialog the Vertical Layouts ,insert them in a orizontal
408                 layout to form two column, set Vertical Layouts to 0 .
409 */
endVLayout()410 void Dialog::endVLayout() {
411   if (!m_leftVLayout || !m_rightVLayout) return;
412   m_isMainVLayout = false;
413 
414   QHBoxLayout *layout = new QHBoxLayout;
415   layout->setMargin(m_layoutMargin);
416   layout->setSpacing(m_layoutSpacing);
417   layout->setSizeConstraint(QLayout::SetFixedSize);
418 
419   layout->addLayout(m_leftVLayout);
420   layout->setAlignment(m_leftVLayout, Qt::AlignLeft);
421   layout->addLayout(m_rightVLayout);
422   layout->setAlignment(m_rightVLayout, Qt::AlignLeft);
423 
424   addLayout(layout);
425 
426   m_leftVLayout  = 0;
427   m_rightVLayout = 0;
428 }
429 
430 //-----------------------------------------------------------------------------
431 /*! Create a new Horizontal Layout for main part of dialog.
432  */
beginHLayout()433 void Dialog::beginHLayout() {
434   m_isMainHLayout = true;
435   m_mainHLayout   = new QHBoxLayout;
436   m_mainHLayout->setMargin(m_layoutMargin);
437   m_mainHLayout->setSpacing(m_layoutSpacing);
438 }
439 
440 //-----------------------------------------------------------------------------
441 /*! Add to main part of dialog the Horizontal Layout  and set it to 0.
442  */
endHLayout()443 void Dialog::endHLayout() {
444   m_isMainHLayout = false;
445   if (!m_mainHLayout) return;
446   addLayout(m_mainHLayout);
447   m_mainHLayout = 0;
448 }
449 
450 //-----------------------------------------------------------------------------
451 /*! Add a widget \b widget to main part of dialog. If vertical layout is
452                 initialized add widget in right column if \b isRight is true,
453    otherwise in
454                 left column. \b isRight by default is true.
455 */
addWidget(QWidget * widget,bool isRight)456 void Dialog::addWidget(QWidget *widget, bool isRight) {
457   if (m_isMainVLayout) {
458     assert(m_leftVLayout && m_rightVLayout);
459     QWidget *w = new QWidget();
460     int h      = widget->height() + m_layoutSpacing;
461     if (isRight) {
462       m_leftVLayout->addSpacing(h);
463       m_rightVLayout->addWidget(widget);
464     } else {
465       m_leftVLayout->addWidget(widget, 1, Qt::AlignRight);
466       m_rightVLayout->addSpacing(h);
467     }
468     return;
469   } else if (m_isMainHLayout) {
470     assert(m_mainHLayout);
471     m_mainHLayout->addWidget(widget);
472     return;
473   }
474   m_topLayout->addWidget(widget);
475 }
476 
477 //-----------------------------------------------------------------------------
478 /*! Add a pair [widget,widget] to main part of dialog.
479 \n	If vertical and horizontal layout are not initialized create an
480 horizontal
481                 box layout containing the two widgets and recall \b addLayout().
482                 If vertical layout is current add the pair to vertical layout of
483 main part,
484                 \b firstW on first column and \b secondW on second column.
485                 Else if horizontal layout is current create an horizontal box
486 layout containing
487                 \b firstW and \b secondW and add it to horizontal layout.
488 */
addWidgets(QWidget * firstW,QWidget * secondW)489 void Dialog::addWidgets(QWidget *firstW, QWidget *secondW) {
490   if (m_isMainVLayout) {
491     assert(m_leftVLayout && m_rightVLayout);
492     m_leftVLayout->addWidget(firstW);
493     m_rightVLayout->addWidget(secondW);
494     return;
495   }
496   QHBoxLayout *pairLayout = new QHBoxLayout;
497   pairLayout->setMargin(m_layoutMargin);
498   pairLayout->setSpacing(m_layoutSpacing);
499   pairLayout->addWidget(firstW);
500   pairLayout->addWidget(secondW);
501 
502   if (m_isMainHLayout) {
503     assert(m_mainHLayout);
504     m_mainHLayout->addLayout(pairLayout);
505     return;
506   }
507   addLayout(pairLayout);
508 }
509 
510 //-----------------------------------------------------------------------------
511 /*! Add a pair [label,widget] to main part of dialog, label is created from
512                 \b QString \b nameLabel.
513 \n	Recall \b addWidgets(QWdiget* firstW, QWdiget* secondW).
514 */
addWidget(QString labelName,QWidget * widget)515 void Dialog::addWidget(QString labelName, QWidget *widget) {
516   QLabel *label = new QLabel(labelName);
517   m_labelList.push_back(label);
518   label->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
519   label->setFixedSize(m_labelWidth, widget->height());
520   addWidgets(label, widget);
521 }
522 
523 //-----------------------------------------------------------------------------
524 /*! Add a layout \b layout to main part of dialog. If vertical layout is
525                 initialized add widget in right column if \b isRight is true,
526    otherwise in
527                 left column. \b isRight by default is true.
528 */
addLayout(QLayout * layout,bool isRight)529 void Dialog::addLayout(QLayout *layout, bool isRight) {
530   if (m_isMainVLayout) {
531     assert(m_leftVLayout && m_rightVLayout);
532     int h = layout->itemAt(0)->widget()->height() + m_layoutSpacing;
533     if (isRight) {
534       m_leftVLayout->addSpacing(h);
535       m_rightVLayout->addLayout(layout);
536     } else {
537       m_leftVLayout->addLayout(layout);
538       m_rightVLayout->addSpacing(h);
539     }
540     return;
541   } else if (m_isMainHLayout) {
542     assert(m_mainHLayout);
543     m_mainHLayout->addLayout(layout);
544     return;
545   }
546   m_topLayout->addLayout(layout);
547 }
548 
549 //-----------------------------------------------------------------------------
550 /*! Add a pair [widget,layout] to main part of dialog.
551 \n	If vertical and horizontal layout are not initialized create an
552 horizontal
553                 box layout containing \b widget and \b layout and recall \b
554 addLayout().
555                 If vertical layout is current add the pair [label,layout] to
556 vertical layout
557                 of main part, label on first column and layout on second column.
558                 Else if horizontal layout is current create an horizontal box
559 layout containing
560                 \b widget and \b layout and add it to horizontal layout.
561 */
addWidgetLayout(QWidget * widget,QLayout * layout)562 void Dialog::addWidgetLayout(QWidget *widget, QLayout *layout) {
563   layout->setMargin(m_layoutMargin);
564   layout->setSpacing(m_layoutSpacing);
565 
566   if (m_isMainVLayout) {
567     assert(m_leftVLayout && m_rightVLayout);
568     m_leftVLayout->addWidget(widget);
569     m_rightVLayout->addLayout(layout);
570     return;
571   }
572 
573   QHBoxLayout *pairLayout = new QHBoxLayout;
574   pairLayout->setMargin(m_layoutMargin);
575   pairLayout->setSpacing(m_layoutSpacing);
576   pairLayout->addWidget(widget);
577   pairLayout->addLayout(layout);
578 
579   if (m_isMainHLayout) {
580     assert(m_mainHLayout);
581     m_mainHLayout->addLayout(pairLayout);
582     return;
583   }
584 
585   addLayout(pairLayout);
586 }
587 
588 //-----------------------------------------------------------------------------
589 /*! Add a pair [label,layout] to main part of dialog, label is created from
590                 \b QString \b nameLabel.
591 \n	Recall \b addWidgetLayout(QWdiget* widget, QWdiget* layout).
592 */
addLayout(QString labelName,QLayout * layout)593 void Dialog::addLayout(QString labelName, QLayout *layout) {
594   QLabel *label = new QLabel(labelName);
595   m_labelList.push_back(label);
596   label->setFixedWidth(m_labelWidth);
597   label->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
598   addWidgetLayout(label, layout);
599 }
600 
601 //-----------------------------------------------------------------------------
602 /*! Add a pair [layout,layout] to main part of dialog.
603 \n	If vertical and horizontal layout are not initialized create an
604 horizontal
605                 box layout containing the two layouts and recall \b addLayout().
606                 If vertical layout is current add the pair [layout,layout] to
607 vertical layout
608                 of main part, \b firstL on first column and \b secondL on second
609 column.
610                 Else if horizontal layout is current create an horizontal box
611 layout containing
612                 \b firstL and \b secondL and add it to horizontal layout.
613 */
addLayouts(QLayout * firstL,QLayout * secondL)614 void Dialog::addLayouts(QLayout *firstL, QLayout *secondL) {
615   firstL->setMargin(m_layoutMargin);
616   firstL->setSpacing(m_layoutSpacing);
617   secondL->setMargin(m_layoutMargin);
618   secondL->setSpacing(m_layoutSpacing);
619 
620   if (m_isMainVLayout) {
621     assert(m_leftVLayout && m_rightVLayout);
622     m_leftVLayout->addLayout(firstL);
623     m_rightVLayout->addLayout(secondL);
624     return;
625   }
626 
627   QHBoxLayout *pairLayout = new QHBoxLayout;
628   pairLayout->setMargin(m_layoutMargin);
629   pairLayout->setSpacing(m_layoutSpacing);
630   pairLayout->addLayout(firstL);
631   pairLayout->addLayout(secondL);
632 
633   if (m_isMainHLayout) {
634     assert(m_mainHLayout);
635     m_mainHLayout->addLayout(pairLayout);
636     return;
637   }
638 
639   addLayout(pairLayout);
640 }
641 
642 //-----------------------------------------------------------------------------
643 /*! Add spacing \b spacing to main part of dialog.
644  */
addSpacing(int spacing)645 void Dialog::addSpacing(int spacing) {
646   if (m_isMainVLayout) {
647     assert(m_leftVLayout && m_rightVLayout);
648     m_leftVLayout->addSpacing(spacing);
649     m_rightVLayout->addSpacing(spacing);
650     return;
651   } else if (m_isMainHLayout) {
652     assert(m_mainHLayout);
653     m_mainHLayout->addSpacing(spacing);
654     return;
655   }
656   m_topLayout->addSpacing(spacing);
657 }
658 
659 //-----------------------------------------------------------------------------
660 /*! Add a separator \b Separator to main part of dialog.
661                 If vertical layout is initialized add an horizontal separator.
662                 If horizontal layout is initialized add a vertical separator.
663 */
addSeparator(QString name)664 void Dialog::addSeparator(QString name) {
665   Separator *separator = new Separator(name);
666   if (m_isMainVLayout) {
667     assert(m_leftVLayout && m_rightVLayout);
668     endVLayout();
669     addWidget(separator);
670     beginVLayout();
671     return;
672   } else if (m_isMainHLayout) {
673     assert(m_mainHLayout);
674     separator->setOrientation(false);
675     m_mainHLayout->addWidget(separator);
676     return;
677   }
678   addWidget(separator);
679 }
680 
681 //-----------------------------------------------------------------------------
682 /*! Set the alignement of the main layout
683  */
setAlignment(Qt::Alignment alignment)684 void Dialog::setAlignment(Qt::Alignment alignment) {
685   m_mainFrame->layout()->setAlignment(alignment);
686 }
687 
688 //-----------------------------------------------------------------------------
689 /*! Set to \b spacing spacing of main part of dialog.
690  */
setTopSpacing(int spacing)691 void Dialog::setTopSpacing(int spacing) {
692   m_layoutSpacing = spacing;
693   m_topLayout->setSpacing(spacing);
694 }
695 //-----------------------------------------------------------------------------
696 
setLabelWidth(int labelWidth)697 void Dialog::setLabelWidth(int labelWidth) { m_labelWidth = labelWidth; }
698 
699 //-----------------------------------------------------------------------------
700 /*! Set to \b spacing spacing of all layout inserted in main part of dialog,
701                 horizontal layout and vertical layout.
702 */
setLayoutInsertedSpacing(int spacing)703 void Dialog::setLayoutInsertedSpacing(int spacing) {
704   m_layoutSpacing = spacing;
705 }
706 
707 //-----------------------------------------------------------------------------
708 /*! Return the spacing of all layout inserted in main part of dialog,
709                 horizontal layout and vertical layout.
710 */
getLayoutInsertedSpacing()711 int Dialog::getLayoutInsertedSpacing() { return m_layoutSpacing; }
712 
713 //-----------------------------------------------------------------------------
714 /*! Set to \b margin margin of main part of dialog.
715  */
setTopMargin(int margin)716 void Dialog::setTopMargin(int margin) { m_topLayout->setMargin(margin); }
717 
718 //-----------------------------------------------------------------------------
719 /*! Set to \b margin margin of button part of dialog.
720  */
setButtonBarMargin(int margin)721 void Dialog::setButtonBarMargin(int margin) {
722   m_buttonLayout->setMargin(margin);
723 }
724 
725 //-----------------------------------------------------------------------------
726 /*! Set to \b spacing spacing of button part of dialog.
727  */
setButtonBarSpacing(int spacing)728 void Dialog::setButtonBarSpacing(int spacing) {
729   m_buttonLayout->setSpacing(spacing);
730 }
731 
732 //-----------------------------------------------------------------------------
733 /*! Add a widget to the button part of dialog.
734  */
addButtonBarWidget(QWidget * widget)735 void Dialog::addButtonBarWidget(QWidget *widget) {
736   widget->setMinimumSize(65, 25);
737   assert(m_hasButton);
738   if (m_hasButton) {
739     m_buttonLayout->addWidget(widget);
740     m_buttonBarWidgets.push_back(widget);
741   }
742 }
743 
744 //-----------------------------------------------------------------------------
745 /*! Remove all widget from the button part of dialog.
746  */
clearButtonBar()747 void Dialog::clearButtonBar() {
748   for (int i = 0; i < (int)m_buttonBarWidgets.size(); i++) {
749     m_buttonLayout->removeWidget(m_buttonBarWidgets[i]);
750   }
751   m_buttonBarWidgets.clear();
752 }
753 
754 //-----------------------------------------------------------------------------
755 /*! Add two widget to the button part of dialog.
756  */
addButtonBarWidget(QWidget * first,QWidget * second)757 void Dialog::addButtonBarWidget(QWidget *first, QWidget *second) {
758   first->setMinimumSize(65, 25);
759   second->setMinimumSize(65, 25);
760   assert(m_hasButton);
761   if (m_hasButton) {
762     m_buttonLayout->addWidget(first);
763     m_buttonLayout->addWidget(second);
764   }
765 }
766 
767 //-----------------------------------------------------------------------------
768 /*! Add three widget to the button part of dialog.
769  */
addButtonBarWidget(QWidget * first,QWidget * second,QWidget * third)770 void Dialog::addButtonBarWidget(QWidget *first, QWidget *second,
771                                 QWidget *third) {
772   first->setMinimumSize(65, 25);
773   second->setMinimumSize(65, 25);
774   third->setMinimumSize(65, 25);
775   assert(m_hasButton);
776   if (m_hasButton) {
777     m_buttonLayout->addWidget(first);
778     m_buttonLayout->addWidget(second);
779     m_buttonLayout->addWidget(third);
780   }
781 }
782 
783 //-----------------------------------------------------------------------------
784 /*! Add four widget to the button part of dialog.
785  */
addButtonBarWidget(QWidget * first,QWidget * second,QWidget * third,QWidget * fourth)786 void Dialog::addButtonBarWidget(QWidget *first, QWidget *second, QWidget *third,
787                                 QWidget *fourth) {
788   first->setMinimumSize(65, 25);
789   second->setMinimumSize(65, 25);
790   third->setMinimumSize(65, 25);
791   assert(m_hasButton);
792   if (m_hasButton) {
793     m_buttonLayout->addWidget(first);
794     m_buttonLayout->addWidget(second);
795     m_buttonLayout->addWidget(third);
796     m_buttonLayout->addWidget(fourth);
797   }
798 }
799 
800 //=============================================================================
801 
MessageAndCheckboxDialog(QWidget * parent,bool hasButton,bool hasFixedSize,const QString & name,Qt::CheckState checkButtonState)802 MessageAndCheckboxDialog::MessageAndCheckboxDialog(
803     QWidget *parent, bool hasButton, bool hasFixedSize, const QString &name,
804     Qt::CheckState checkButtonState)
805     : Dialog(parent, hasButton, hasFixedSize, name)
806     , m_checked(checkButtonState) {}
807 
808 //=============================================================================
809 
onButtonPressed(int id)810 void MessageAndCheckboxDialog::onButtonPressed(int id) { done(id); }
811 
812 //=============================================================================
813 
onCheckboxChanged(int checked)814 void MessageAndCheckboxDialog::onCheckboxChanged(int checked) {
815   m_checked = checked;
816 }
817 
818 //=============================================================================
819 
RadioButtonDialog(const QString & labelText,const QList<QString> & radioButtonList,QWidget * parent,Qt::WindowFlags f)820 RadioButtonDialog::RadioButtonDialog(const QString &labelText,
821                                      const QList<QString> &radioButtonList,
822                                      QWidget *parent, Qt::WindowFlags f)
823     : Dialog(parent, true, true), m_result(1) {
824   setWindowTitle(tr("OpenToonz"));
825 
826   setMinimumSize(20, 20);
827 
828   beginVLayout();
829 
830   QLabel *label = new QLabel(labelText);
831   label->setAlignment(Qt::AlignLeft);
832   label->setFixedHeight(2 * WidgetHeight);
833   addWidget(label);
834 
835   QButtonGroup *buttonGroup = new QButtonGroup(this);
836   int i;
837   for (i = 0; i < radioButtonList.count(); i++) {
838     QRadioButton *radioButton = new QRadioButton(radioButtonList.at(i));
839     if (i == m_result - 1) radioButton->setChecked(true);
840     radioButton->setFixedHeight(WidgetHeight);
841     buttonGroup->addButton(radioButton);
842     buttonGroup->setId(radioButton, i);
843     addWidget(radioButton);
844   }
845 
846   bool ret = connect(buttonGroup, SIGNAL(buttonClicked(int)),
847                      SLOT(onButtonClicked(int)));
848 
849   endVLayout();
850 
851   QPushButton *applyButton = new QPushButton(QObject::tr("Apply"));
852   ret = ret && connect(applyButton, SIGNAL(pressed()), this, SLOT(onApply()));
853   QPushButton *cancelButton = new QPushButton(QObject::tr("Cancel"));
854   ret = ret && connect(cancelButton, SIGNAL(pressed()), this, SLOT(onCancel()));
855 
856   addButtonBarWidget(applyButton, cancelButton);
857 
858   assert(ret);
859 }
860 
861 //-----------------------------------------------------------------------------
862 
onButtonClicked(int id)863 void RadioButtonDialog::onButtonClicked(int id) {
864   // Add "1" because "0" is cancel button.
865   m_result = id + 1;
866 }
867 
868 //-----------------------------------------------------------------------------
869 
onCancel()870 void RadioButtonDialog::onCancel() { done(0); }
871 
872 //-----------------------------------------------------------------------------
873 
onApply()874 void RadioButtonDialog::onApply() { done(m_result); }
875 
876 //=============================================================================
877 
RadioButtonMsgBox(MsgType type,const QString & labelText,const QList<QString> & radioButtonList,QWidget * parent)878 int DVGui::RadioButtonMsgBox(MsgType type, const QString &labelText,
879                              const QList<QString> &radioButtonList,
880                              QWidget *parent) {
881   RadioButtonDialog *dialog =
882       new RadioButtonDialog(labelText, radioButtonList, parent);
883   QString msgBoxTitle = getMsgBoxTitle(DVGui::WARNING);
884   dialog->setWindowTitle(msgBoxTitle);
885   return dialog->exec();
886 }
887 
888 //=============================================================================
889 
ProgressDialog(const QString & labelText,const QString & cancelButtonText,int minimum,int maximum,QWidget * parent,Qt::WindowFlags f)890 ProgressDialog::ProgressDialog(const QString &labelText,
891                                const QString &cancelButtonText, int minimum,
892                                int maximum, QWidget *parent, Qt::WindowFlags f)
893     : Dialog(parent, true, true), m_isCanceled(false) {
894   setWindowTitle(tr("OpenToonz"));
895 
896   setMinimumSize(20, 20);
897 
898   beginVLayout();
899 
900   m_label = new QLabel(this);
901   m_label->setText(labelText);
902   addWidget(m_label);
903 
904   m_progressBar = new QProgressBar(this);
905   m_progressBar->setRange(minimum, maximum);
906   m_progressBar->setMinimumWidth(250);
907   addWidget(m_progressBar);
908 
909   endVLayout();
910 
911   if (!cancelButtonText.isEmpty())
912     setCancelButton(new QPushButton(cancelButtonText));
913 }
914 
915 //-----------------------------------------------------------------------------
916 
setLabelText(const QString & text)917 void ProgressDialog::setLabelText(const QString &text) {
918   m_label->setText(text);
919 }
920 
921 //-----------------------------------------------------------------------------
922 
setCancelButton(QPushButton * cancelButton)923 void ProgressDialog::setCancelButton(QPushButton *cancelButton) {
924   m_cancelButton = cancelButton;
925   bool ret = connect(cancelButton, SIGNAL(pressed()), this, SLOT(onCancel()));
926   ret =
927       ret && connect(cancelButton, SIGNAL(pressed()), this, SIGNAL(canceled()));
928   assert(ret);
929   addButtonBarWidget(m_cancelButton);
930 }
931 
932 //-----------------------------------------------------------------------------
933 
maximum()934 int ProgressDialog::maximum() { return m_progressBar->maximum(); }
935 //-----------------------------------------------------------------------------
936 
setMaximum(int maximum)937 void ProgressDialog::setMaximum(int maximum) {
938   m_progressBar->setMaximum(maximum);
939 }
940 
941 //-----------------------------------------------------------------------------
942 
minimum()943 int ProgressDialog::minimum() { return m_progressBar->minimum(); }
944 //-----------------------------------------------------------------------------
945 
setMinimum(int minimum)946 void ProgressDialog::setMinimum(int minimum) {
947   m_progressBar->setMinimum(minimum);
948 }
949 
950 //-----------------------------------------------------------------------------
951 
value()952 int ProgressDialog::value() { return m_progressBar->value(); }
953 
954 //-----------------------------------------------------------------------------
955 
setValue(int progress)956 void ProgressDialog::setValue(int progress) {
957   m_progressBar->setValue(progress);
958   if (isModal()) qApp->processEvents();
959 }
960 
961 //-----------------------------------------------------------------------------
962 
reset()963 void ProgressDialog::reset() { m_progressBar->reset(); }
964 
965 //-----------------------------------------------------------------------------
966 
wasCanceled() const967 bool ProgressDialog::wasCanceled() const { return m_isCanceled; }
968 
969 //-----------------------------------------------------------------------------
970 
onCancel()971 void ProgressDialog::onCancel() {
972   m_isCanceled = true;
973   reset();
974   hide();
975 }
976 
977 //=============================================================================
978 
MsgBox(MsgType type,const QString & text,const std::vector<QString> & buttons,int defaultButtonIndex,QWidget * parent)979 int DVGui::MsgBox(MsgType type, const QString &text,
980                   const std::vector<QString> &buttons, int defaultButtonIndex,
981                   QWidget *parent) {
982   Dialog dialog(parent, true);
983   dialog.setWindowFlags(dialog.windowFlags() | Qt::WindowStaysOnTopHint);
984   dialog.setAlignment(Qt::AlignLeft);
985   QString msgBoxTitle = getMsgBoxTitle(type);
986 
987   dialog.setWindowTitle(msgBoxTitle);
988 
989   QLabel *mainTextLabel = new QLabel(text, &dialog);
990   QPixmap iconPixmap    = getMsgBoxPixmap(type);
991   if (!iconPixmap.isNull()) {
992     QLabel *iconLabel = new QLabel(&dialog);
993     iconLabel->setPixmap(iconPixmap);
994 
995     QHBoxLayout *mainLayout = new QHBoxLayout;
996     mainLayout->addWidget(iconLabel);
997     mainLayout->addSpacing(16);
998     mainLayout->addWidget(mainTextLabel);
999     dialog.addLayout(mainLayout);
1000   } else
1001     dialog.addWidget(mainTextLabel);
1002 
1003   // ButtonGroup: is used only to retrieve the clicked button
1004   QButtonGroup *buttonGroup = new QButtonGroup(&dialog);
1005 
1006   for (int i = 0; i < (int)buttons.size(); i++) {
1007     QPushButton *button = new QPushButton(buttons[i], &dialog);
1008     if (defaultButtonIndex == i)
1009       button->setDefault(true);
1010     else
1011       button->setDefault(false);
1012     dialog.addButtonBarWidget(button);
1013 
1014     buttonGroup->addButton(button, i + 1);
1015   }
1016 
1017   QObject::connect(buttonGroup, SIGNAL(buttonPressed(int)), &dialog,
1018                    SLOT(done(int)));
1019 
1020   dialog.raise();
1021 
1022   return dialog.exec();
1023 }
1024 
1025 //-----------------------------------------------------------------------------
1026 
MsgBoxInPopup(MsgType type,const QString & text)1027 void DVGui::MsgBoxInPopup(MsgType type, const QString &text) {
1028   // this function must be called by the main thread only
1029   // (only the main thread should access directly the GUI)
1030   // (note: working thread can and should call MsgBox(type,text) instead; see
1031   // tmsgcore.h)
1032 
1033   Q_ASSERT(QApplication::instance()->thread() == QThread::currentThread());
1034 
1035   // a working thread can trigger a call to this function (by the main thread)
1036   // also when a popup is already open
1037   // therefore we need a messageQueue
1038   // note: no mutex are needed because only the main thread call this function
1039   static QList<QPair<MsgType, QString>> messageQueue;
1040   static bool popupIsOpen = false;
1041 
1042   messageQueue.append(qMakePair(type, text));
1043   if (popupIsOpen) return;
1044   popupIsOpen = true;
1045 
1046   Dialog dialog(0, true);
1047 
1048   dialog.setWindowFlags(dialog.windowFlags() | Qt::WindowStaysOnTopHint);
1049   dialog.setAlignment(Qt::AlignLeft);
1050   QLabel *mainTextLabel = new QLabel("", &dialog);
1051   mainTextLabel->setMinimumWidth(400);
1052   QLabel *iconLabel = new QLabel(&dialog);
1053 
1054   QHBoxLayout *mainLayout = new QHBoxLayout;
1055   mainLayout->addWidget(iconLabel);
1056   mainLayout->addStretch();
1057   mainLayout->addWidget(mainTextLabel);
1058   mainLayout->addStretch();
1059   dialog.addLayout(mainLayout);
1060 
1061   // ButtonGroup: is used only to retrieve the clicked button
1062   QButtonGroup *buttonGroup = new QButtonGroup(&dialog);
1063   QPushButton *button       = new QPushButton(QPushButton::tr("OK"), &dialog);
1064   button->setDefault(true);
1065   dialog.addButtonBarWidget(button);
1066   buttonGroup->addButton(button, 1);
1067   QObject::connect(buttonGroup, SIGNAL(buttonPressed(int)), &dialog,
1068                    SLOT(done(int)));
1069 
1070   while (!messageQueue.empty()) {
1071     MsgType type1 = messageQueue.first().first;
1072     QString text1 = messageQueue.first().second;
1073     messageQueue.pop_front();
1074 
1075     mainTextLabel->setText(text1);
1076 
1077     QString msgBoxTitle = getMsgBoxTitle(type1);
1078     dialog.setWindowTitle(msgBoxTitle);
1079 
1080     QPixmap iconPixmap = getMsgBoxPixmap(type1);
1081     if (!iconPixmap.isNull()) {
1082       iconLabel->setPixmap(iconPixmap);
1083       iconLabel->setVisible(true);
1084     } else {
1085       iconLabel->setVisible(false);
1086     }
1087 
1088     dialog.raise();
1089     dialog.exec();
1090 
1091   }  // loop: open the next dialog in the queue
1092   popupIsOpen = false;
1093 }
1094 
1095 //-----------------------------------------------------------------------------
1096 
MsgBox(const QString & text,const QString & button1Text,const QString & button2Text,const QString & button3Text,int defaultButtonIndex,QWidget * parent)1097 int DVGui::MsgBox(const QString &text, const QString &button1Text,
1098                   const QString &button2Text, const QString &button3Text,
1099                   int defaultButtonIndex, QWidget *parent) {
1100   Dialog dialog(parent, true);
1101   dialog.setWindowFlags(dialog.windowFlags() | Qt::WindowStaysOnTopHint);
1102   dialog.setAlignment(Qt::AlignLeft);
1103   QString msgBoxTitle = getMsgBoxTitle(QUESTION);
1104   dialog.setWindowTitle(msgBoxTitle);
1105 
1106   QLabel *mainTextLabel = new QLabel(text, &dialog);
1107   QPixmap iconPixmap    = getMsgBoxPixmap(QUESTION);
1108   if (!iconPixmap.isNull()) {
1109     QLabel *iconLabel = new QLabel(&dialog);
1110     iconLabel->setPixmap(iconPixmap);
1111 
1112     QHBoxLayout *mainLayout = new QHBoxLayout;
1113     mainLayout->addWidget(iconLabel);
1114     mainLayout->addSpacing(16);
1115     mainLayout->addWidget(mainTextLabel);
1116     dialog.addLayout(mainLayout);
1117   } else
1118     dialog.addWidget(mainTextLabel);
1119 
1120   // ButtonGroup: is used only to retrieve the clicked button
1121   QButtonGroup *buttonGroup = new QButtonGroup(&dialog);
1122 
1123   QPushButton *button1 = new QPushButton(button1Text, &dialog);
1124   button1->setDefault(false);
1125   if (defaultButtonIndex == 0) button1->setDefault(true);
1126   dialog.addButtonBarWidget(button1);
1127   buttonGroup->addButton(button1, 1);
1128 
1129   QPushButton *button2 = new QPushButton(button2Text, &dialog);
1130   button2->setDefault(false);
1131   if (defaultButtonIndex == 1) button2->setDefault(true);
1132   dialog.addButtonBarWidget(button2);
1133   buttonGroup->addButton(button2, 2);
1134 
1135   QPushButton *button3 = new QPushButton(button3Text, &dialog);
1136   button3->setDefault(false);
1137   if (defaultButtonIndex == 2) button3->setDefault(true);
1138   dialog.addButtonBarWidget(button3);
1139   buttonGroup->addButton(button3, 3);
1140 
1141   QObject::connect(buttonGroup, SIGNAL(buttonPressed(int)), &dialog,
1142                    SLOT(done(int)));
1143   dialog.raise();
1144   return dialog.exec();
1145 }
1146 
1147 //-----------------------------------------------------------------------------
1148 
MsgBox(const QString & text,const QString & button1Text,const QString & button2Text,const QString & button3Text,const QString & button4Text,int defaultButtonIndex,QWidget * parent)1149 int DVGui::MsgBox(const QString &text, const QString &button1Text,
1150                   const QString &button2Text, const QString &button3Text,
1151                   const QString &button4Text, int defaultButtonIndex,
1152                   QWidget *parent) {
1153   Dialog dialog(parent, true);
1154   dialog.setWindowFlags(dialog.windowFlags() | Qt::WindowStaysOnTopHint);
1155   dialog.setAlignment(Qt::AlignLeft);
1156   QString msgBoxTitle = getMsgBoxTitle(QUESTION);
1157   dialog.setWindowTitle(msgBoxTitle);
1158 
1159   QLabel *mainTextLabel = new QLabel(text, &dialog);
1160   QPixmap iconPixmap    = getMsgBoxPixmap(QUESTION);
1161   if (!iconPixmap.isNull()) {
1162     QLabel *iconLabel = new QLabel(&dialog);
1163     iconLabel->setPixmap(iconPixmap);
1164 
1165     QHBoxLayout *mainLayout = new QHBoxLayout;
1166     mainLayout->addWidget(iconLabel);
1167     mainLayout->addSpacing(16);
1168     mainLayout->addWidget(mainTextLabel);
1169     dialog.addLayout(mainLayout);
1170   } else
1171     dialog.addWidget(mainTextLabel);
1172 
1173   // ButtonGroup: is used only to retrieve the clicked button
1174   QButtonGroup *buttonGroup = new QButtonGroup(&dialog);
1175 
1176   QPushButton *button1 = new QPushButton(button1Text, &dialog);
1177   button1->setDefault(false);
1178   if (defaultButtonIndex == 0) button1->setDefault(true);
1179   dialog.addButtonBarWidget(button1);
1180   buttonGroup->addButton(button1, 1);
1181 
1182   QPushButton *button2 = new QPushButton(button2Text, &dialog);
1183   button2->setDefault(false);
1184   if (defaultButtonIndex == 1) button2->setDefault(true);
1185   dialog.addButtonBarWidget(button2);
1186   buttonGroup->addButton(button2, 2);
1187 
1188   QPushButton *button3 = new QPushButton(button3Text, &dialog);
1189   button3->setDefault(false);
1190   if (defaultButtonIndex == 2) button3->setDefault(true);
1191   dialog.addButtonBarWidget(button3);
1192   buttonGroup->addButton(button3, 3);
1193 
1194   QPushButton *button4 = new QPushButton(button4Text, &dialog);
1195   button4->setDefault(false);
1196   if (defaultButtonIndex == 3) button4->setDefault(true);
1197   dialog.addButtonBarWidget(button4);
1198   buttonGroup->addButton(button4, 4);
1199 
1200   QObject::connect(buttonGroup, SIGNAL(buttonPressed(int)), &dialog,
1201                    SLOT(done(int)));
1202   dialog.raise();
1203   return dialog.exec();
1204 }
1205 
1206 //-----------------------------------------------------------------------------
1207 
MsgBox(const QString & text,const QString & button1,const QString & button2,int defaultButtonIndex,QWidget * parent)1208 int DVGui::MsgBox(const QString &text, const QString &button1,
1209                   const QString &button2, int defaultButtonIndex,
1210                   QWidget *parent) {
1211   Dialog dialog(parent, true);
1212   dialog.setWindowFlags(dialog.windowFlags() | Qt::WindowStaysOnTopHint);
1213   std::vector<QString> buttons;
1214   buttons.push_back(button1);
1215   buttons.push_back(button2);
1216   return DVGui::MsgBox(DVGui::QUESTION, text, buttons, defaultButtonIndex,
1217                        parent);
1218 }
1219 
1220 //-----------------------------------------------------------------------------
1221 
createMsgBox(MsgType type,const QString & text,const QStringList & buttons,int defaultButtonIndex,QWidget * parent)1222 Dialog *DVGui::createMsgBox(MsgType type, const QString &text,
1223                             const QStringList &buttons, int defaultButtonIndex,
1224                             QWidget *parent) {
1225   Dialog *dialog = new Dialog(parent, true);
1226   dialog->setWindowFlags(dialog->windowFlags() | Qt::WindowStaysOnTopHint);
1227   dialog->setAlignment(Qt::AlignLeft);
1228   QString msgBoxTitle = getMsgBoxTitle(type);
1229 
1230   dialog->setWindowTitle(msgBoxTitle);
1231 
1232   QLabel *mainTextLabel = new QLabel(text, dialog);
1233   mainTextLabel->setObjectName("Label");
1234   QPixmap iconPixmap = getMsgBoxPixmap(type);
1235   if (!iconPixmap.isNull()) {
1236     QLabel *iconLabel = new QLabel(dialog);
1237     iconLabel->setPixmap(iconPixmap);
1238 
1239     QHBoxLayout *mainLayout = new QHBoxLayout;
1240     mainLayout->addWidget(iconLabel);
1241     mainLayout->addSpacing(16);
1242     mainLayout->addWidget(mainTextLabel);
1243     dialog->addLayout(mainLayout);
1244   } else
1245     dialog->addWidget(mainTextLabel);
1246 
1247   // ButtonGroup: is used only to retrieve the clicked button
1248   QButtonGroup *buttonGroup = new QButtonGroup(dialog);
1249 
1250   for (int i = 0; i < (int)buttons.size(); i++) {
1251     QPushButton *button = new QPushButton(buttons[i], dialog);
1252     if (defaultButtonIndex == i)
1253       button->setDefault(true);
1254     else
1255       button->setDefault(false);
1256     dialog->addButtonBarWidget(button);
1257 
1258     buttonGroup->addButton(button, i + 1);
1259   }
1260 
1261   QObject::connect(buttonGroup, SIGNAL(buttonPressed(int)), dialog,
1262                    SLOT(done(int)));
1263 
1264   return dialog;
1265 }
1266 
1267 //-----------------------------------------------------------------------------
1268 
createMsgandCheckbox(MsgType type,const QString & text,const QString & checkBoxText,const QStringList & buttons,int defaultButtonIndex,Qt::CheckState defaultCheckBoxState,QWidget * parent)1269 MessageAndCheckboxDialog *DVGui::createMsgandCheckbox(
1270     MsgType type, const QString &text, const QString &checkBoxText,
1271     const QStringList &buttons, int defaultButtonIndex,
1272     Qt::CheckState defaultCheckBoxState, QWidget *parent) {
1273   MessageAndCheckboxDialog *dialog = new MessageAndCheckboxDialog(
1274       parent, true, true, "", defaultCheckBoxState);
1275   dialog->setWindowFlags(dialog->windowFlags() | Qt::WindowStaysOnTopHint);
1276   dialog->setAlignment(Qt::AlignLeft);
1277   QString msgBoxTitle = getMsgBoxTitle(type);
1278 
1279   dialog->setWindowTitle(msgBoxTitle);
1280 
1281   QLabel *mainTextLabel = new QLabel(text, dialog);
1282   mainTextLabel->setObjectName("Label");
1283   QPixmap iconPixmap = getMsgBoxPixmap(type);
1284   if (!iconPixmap.isNull()) {
1285     QLabel *iconLabel = new QLabel(dialog);
1286     iconLabel->setPixmap(iconPixmap);
1287 
1288     QHBoxLayout *mainLayout = new QHBoxLayout;
1289     mainLayout->addWidget(iconLabel);
1290     mainLayout->addSpacing(16);
1291     mainLayout->addWidget(mainTextLabel);
1292     dialog->addLayout(mainLayout);
1293   } else
1294     dialog->addWidget(mainTextLabel);
1295 
1296   // ButtonGroup: is used only to retrieve the clicked button
1297   QButtonGroup *buttonGroup = new QButtonGroup(dialog);
1298 
1299   for (int i = 0; i < (int)buttons.size(); i++) {
1300     QPushButton *button = new QPushButton(buttons[i], dialog);
1301     if (defaultButtonIndex == i)
1302       button->setDefault(true);
1303     else
1304       button->setDefault(false);
1305     dialog->addButtonBarWidget(button);
1306 
1307     buttonGroup->addButton(button, i + 1);
1308   }
1309 
1310   QCheckBox *dialogCheckBox   = new QCheckBox(checkBoxText, dialog);
1311   QHBoxLayout *checkBoxLayout = new QHBoxLayout;
1312   checkBoxLayout->addWidget(dialogCheckBox);
1313   checkBoxLayout->addStretch(0);
1314   dialog->addLayout(checkBoxLayout);
1315 
1316   dialogCheckBox->setCheckState(defaultCheckBoxState);
1317 
1318   QObject::connect(dialogCheckBox, SIGNAL(stateChanged(int)), dialog,
1319                    SLOT(onCheckboxChanged(int)));
1320   QObject::connect(buttonGroup, SIGNAL(buttonPressed(int)), dialog,
1321                    SLOT(onButtonPressed(int)));
1322 
1323   return dialog;
1324 }
1325 
1326 //-----------------------------------------------------------------------------
1327 
getText(const QString & title,const QString & labelText,const QString & text,bool * ok)1328 QString DVGui::getText(const QString &title, const QString &labelText,
1329                        const QString &text, bool *ok) {
1330   Dialog dialog(0, true);
1331 
1332   dialog.setWindowTitle(title);
1333   dialog.setWindowFlags(Qt::WindowStaysOnTopHint | Qt::WindowTitleHint |
1334                         Qt::CustomizeWindowHint);
1335 
1336   QVBoxLayout *layout = new QVBoxLayout(&dialog);
1337   dialog.addLayout(layout);
1338 
1339   QLabel *label = new QLabel(labelText, &dialog);
1340   layout->addWidget(label);
1341 
1342   LineEdit *nameFld = new LineEdit(text, &dialog);
1343   layout->addWidget(nameFld);
1344 
1345   QPushButton *okBtn = new QPushButton(QObject::tr("OK"), &dialog);
1346   okBtn->setDefault(true);
1347   QPushButton *cancelBtn = new QPushButton(QObject::tr("Cancel"), &dialog);
1348   QObject::connect(okBtn, SIGNAL(clicked()), &dialog, SLOT(accept()));
1349   QObject::connect(cancelBtn, SIGNAL(clicked()), &dialog, SLOT(reject()));
1350 
1351   dialog.addButtonBarWidget(okBtn, cancelBtn);
1352 
1353   int ret = dialog.exec();
1354   if (ok) *ok = (ret == QDialog::Accepted);
1355 
1356   return nameFld->text();
1357 }
1358 
1359 //-----------------------------------------------------------------------------
1360 
1361 namespace {
isStyleIdInPalette(int styleId,const TPalette * palette)1362 bool isStyleIdInPalette(int styleId, const TPalette *palette) {
1363   if (palette->getStyleCount() == 0) return false;
1364   int i;
1365   for (i = 0; i < palette->getPageCount(); i++) {
1366     const TPalette::Page *page = palette->getPage(i);
1367     if (!page) return false;  // La pagina dovrebbe esserci sempre
1368     int j;
1369     for (j = 0; j < page->getStyleCount(); j++)
1370       if (page->getStyleId(j) == styleId) return true;
1371   }
1372   return false;
1373 }
1374 }  // namespace
1375 
1376 //-----------------------------------------------------------------------------
1377 
eraseStylesInDemand(TPalette * palette,const TXsheetHandle * xsheetHandle,TPalette * newPalette)1378 int DVGui::eraseStylesInDemand(TPalette *palette,
1379                                const TXsheetHandle *xsheetHandle,
1380                                TPalette *newPalette) {
1381   // Verifico se gli stili della paletta sono usati : eraseStylesInDemand()
1382   std::vector<int> styleIds;
1383   int h;
1384   for (h = 0; h < palette->getPageCount(); h++) {
1385     TPalette::Page *page = palette->getPage(h);
1386     if (!page) continue;  // La pagina dovrebbe esserci sempre
1387     int k;
1388     for (k = 0; k < page->getStyleCount(); k++) {
1389       int styleId = page->getStyleId(k);
1390       bool isStyleIdInNewPalette =
1391           (!newPalette) ? false : isStyleIdInPalette(styleId, newPalette);
1392       if (styleId > 0 && !isStyleIdInNewPalette) styleIds.push_back(styleId);
1393     }
1394   }
1395 
1396   return eraseStylesInDemand(palette, styleIds, xsheetHandle);
1397 }
1398 
1399 //-----------------------------------------------------------------------------
1400 
eraseStylesInDemand(TPalette * palette,std::vector<int> styleIds,const TXsheetHandle * xsheetHandle)1401 int DVGui::eraseStylesInDemand(TPalette *palette, std::vector<int> styleIds,
1402                                const TXsheetHandle *xsheetHandle) {
1403   struct locals {
1404     static bool isRasterLevel(const TXshSimpleLevel *level) {
1405       return level->getType() == TZP_XSHLEVEL ||
1406              level->getType() == OVL_XSHLEVEL;
1407     }
1408   };  // locals
1409 
1410   // Search xsheet levels attached to the palette
1411   std::set<TXshSimpleLevel *> levels;
1412   int row, column;
1413   findPaletteLevels(levels, row, column, palette, xsheetHandle->getXsheet());
1414 
1415   bool someStyleIsUsed =
1416       !levels.empty() ||
1417       styleIds.empty();  // I guess this is wrong... but I'm not touching it
1418   if (someStyleIsUsed) someStyleIsUsed = areStylesUsed(levels, styleIds);
1419 
1420   if (!someStyleIsUsed) return 1;
1421 
1422   // At least a style is selected and present in some level - ask user if and
1423   // how styles
1424   // should be deleted
1425 
1426   QString question = QObject::tr(
1427                          "Styles you are going to delete are used to paint "
1428                          "lines and areas in the animation level.\n") +
1429                      QObject::tr("How do you want to proceed?");
1430 
1431   int ret = DVGui::MsgBox(question, QObject::tr("Delete Styles Only"),
1432                           QObject::tr("Delete Styles, Lines and Areas"),
1433                           QObject::tr("Cancel"), 0);
1434   if (ret != 2) return (ret == 0 || ret == 3) ? 0 : 1;
1435 
1436   // Inform the user that case 2 will not produce an undo if a raster-based
1437   // level is detected
1438   if (std::any_of(levels.begin(), levels.end(), locals::isRasterLevel)) {
1439     std::vector<QString> buttons(2);
1440     buttons[0] = QObject::tr("Ok"), buttons[1] = QObject::tr("Cancel");
1441 
1442     if (DVGui::MsgBox(DVGui::WARNING,
1443                       QObject::tr("Deletion of Lines and Areas from "
1444                                   "raster-based levels is not undoable.\n"
1445                                   "Are you sure?"),
1446                       buttons) != 1)
1447       return 0;
1448   }
1449 
1450   QApplication::setOverrideCursor(Qt::WaitCursor);
1451   PaletteCmd::eraseStyles(levels, styleIds);
1452   QApplication::restoreOverrideCursor();
1453 
1454   return (assert(ret == 2), ret);  // return 2 ?     :D
1455 }
1456 
1457 //-----------------------------------------------------------------------------