1 
2 
3 #include "toonzqt/fxsettings.h"
4 #include "toonzqt/gutil.h"
5 #include "toonzqt/keyframenavigator.h"
6 #include "toonzqt/dvdialog.h"
7 #include "toonzqt/fxhistogramrender.h"
8 #include "toonzqt/histogram.h"
9 
10 #include "tmacrofx.h"
11 #include "tstream.h"
12 #include "tparamcontainer.h"
13 #include "tspectrumparam.h"
14 #include "tfxattributes.h"
15 #include "toutputproperties.h"
16 #include "pluginhost.h"
17 #include "tenv.h"
18 #include "tsystem.h"
19 #include "docklayout.h"
20 
21 #include "toonz/tcamera.h"
22 #include "toonz/toonzfolders.h"
23 #include "toonz/tcolumnfx.h"
24 #include "toonz/tscenehandle.h"
25 #include "toonz/txshlevelhandle.h"
26 #include "toonz/tobjecthandle.h"
27 #include "toonz/scenefx.h"
28 #include "toonz/toonzscene.h"
29 #include "toonz/sceneproperties.h"
30 #include "toonz/preferences.h"
31 #include "tw/stringtable.h"
32 
33 #include <QVBoxLayout>
34 #include <QToolBar>
35 #include <QIcon>
36 #include <QAction>
37 #include <QStackedWidget>
38 #include <QLabel>
39 #include <QMap>
40 #include <QPainter>
41 #include <QCheckBox>
42 #include <QPushButton>
43 
44 #include <QDesktopServices>
45 #include <QUrl>
46 
47 using namespace DVGui;
48 
49 namespace {
50 
getCurrentFx(const TFxP & currentFx,std::wstring actualId)51 TFxP getCurrentFx(const TFxP &currentFx, std::wstring actualId) {
52   if (currentFx->getFxId() == actualId) return currentFx;
53   int i;
54   for (i = 0; i < currentFx->getInputPortCount(); i++) {
55     TFxP fx = getCurrentFx(currentFx->getInputPort(i)->getFx(), actualId);
56     if (fx.getPointer()) return fx;
57   }
58   return 0;
59 }
60 
hasEmptyInputPort(const TFxP & currentFx)61 bool hasEmptyInputPort(const TFxP &currentFx) {
62   if (!currentFx.getPointer()) return true;
63   if (currentFx->getInputPortCount() == 0) return false;
64   return hasEmptyInputPort(currentFx->getInputPort(0)->getFx());
65 }
66 /*
67 TFxP cloneInputPort(const TFxP &currentFx)
68 {
69         int i;
70   for (i=0; i<getInputPortCount(); ++i)
71   {
72                 TFx *inputFx = sceneFx->getInputPort(i)->getFx();
73                 if(inputFx)
74                 {
75                         if(TLevelColumnFx* affFx = dynamic_cast<TLevelColumnFx*
76 >(inputFx))
77                                 currentFx->getInputPort(i)->setFx(inputFx);
78                         else
79                                 currentFx->getInputPort(i)->setFx(cloneInputPort());
80                 }
81                 TFxPort *port = getInputPort(i);
82                 if (port->getFx())
83                         fx->connect(getInputPortName(i),
84 cloneInputPort(port->getFx()));
85 }
86 void setLevelFxInputPort(const TFxP &currentFx, const TFxP &sceneFx)
87 {
88         for (int i=0; i<sceneFx->getInputPortCount(); ++i)
89         {
90                 TFx *inputFx = sceneFx->getInputPort(i)->getFx();
91                 if(inputFx)
92                 {
93                         if(TLevelColumnFx* affFx = dynamic_cast<TLevelColumnFx*
94 >(inputFx))
95                                 currentFx->getInputPort(i)->setFx(inputFx);
96                         else
97                                 setLevelFxInputPort(currentFx->getInputPort(i)->getFx(),
98 inputFx);
99                 }
100         }
101 }
102 */
103 }  // namespace
104 
105 //=============================================================================
106 // ParamViewer
107 //-----------------------------------------------------------------------------
108 
ParamsPage(QWidget * parent,ParamViewer * paramViewer)109 ParamsPage::ParamsPage(QWidget *parent, ParamViewer *paramViewer)
110     : QFrame(parent)
111     , m_paramViewer(paramViewer)
112     , m_horizontalLayout(NULL)
113     , m_groupLayout(NULL) {
114   m_fxHistogramRender = new FxHistogramRender();
115   setFrameStyle(QFrame::StyledPanel);
116 
117   m_mainLayout = new QGridLayout(this);
118   m_mainLayout->setMargin(12);
119   m_mainLayout->setVerticalSpacing(10);
120   m_mainLayout->setHorizontalSpacing(5);
121 
122   m_mainLayout->setColumnStretch(0, 0);
123   m_mainLayout->setColumnStretch(1, 1);
124 
125   setLayout(m_mainLayout);
126 }
127 
128 //-----------------------------------------------------------------------------
129 
~ParamsPage()130 ParamsPage::~ParamsPage() {}
131 
132 //-----------------------------------------------------------------------------
133 
setPageField(TIStream & is,const TFxP & fx,bool isVertical)134 void ParamsPage::setPageField(TIStream &is, const TFxP &fx, bool isVertical) {
135   // m_horizontalLayout dovrebbe essere stato inizializzato prima di entrare nel
136   // metodo, per sicurezza verifico.
137   if (isVertical == false && !m_horizontalLayout) {
138     m_horizontalLayout = new QHBoxLayout();
139     m_horizontalLayout->setMargin(0);
140     m_horizontalLayout->setSpacing(5);
141   }
142 
143   /*--
144    * HBoxLayoutを挿入するとき、最初のパラメータ名はGridlayoutのColumn0に入れるため
145    * --*/
146   bool isFirstParamInRow = true;
147 
148   while (!is.matchEndTag()) {
149     std::string tagName;
150     if (!is.matchTag(tagName)) throw TException("expected tag");
151     if (tagName == "control") {
152       /*--- 設定ファイルからインタフェースの桁数を決める (PairSliderのみ実装。)
153        * ---*/
154       int decimals            = 0;
155       std::string decimalsStr = is.getTagAttribute("decimals");
156       if (decimalsStr != "") {
157         decimals = QString::fromStdString(decimalsStr).toInt();
158       }
159 
160       std::string name;
161       is >> name;
162       is.matchEndTag();
163       /*-- Layout設定名とFxParameterの名前が一致するものを取得 --*/
164       TParamP param = fx->getParams()->getParam(name);
165       if (param) {
166         std::string paramName = fx->getFxType() + "." + name;
167         QString str =
168             QString::fromStdWString(TStringTable::translate(paramName));
169         ParamField *field = ParamField::create(this, str, param);
170         if (field) {
171           if (decimals) field->setPrecision(decimals);
172           m_fields.push_back(field);
173           /*-- hboxタグに挟まれているとき --*/
174           if (isVertical == false) {
175             assert(m_horizontalLayout);
176             QLabel *label = new QLabel(str, this);
177             label->setObjectName("FxSettingsLabel");
178             if (isFirstParamInRow) {
179               int currentRow = m_mainLayout->rowCount();
180               m_mainLayout->addWidget(label, currentRow, 0,
181                                       Qt::AlignRight | Qt::AlignVCenter);
182               isFirstParamInRow = false;
183             } else
184               m_horizontalLayout->addWidget(label, 0,
185                                             Qt::AlignRight | Qt::AlignVCenter);
186             m_horizontalLayout->addWidget(field);
187             m_horizontalLayout->addSpacing(10);
188           } else {
189             int currentRow = m_mainLayout->rowCount();
190             QLabel *label  = new QLabel(str, this);
191             label->setObjectName("FxSettingsLabel");
192             m_mainLayout->addWidget(label, currentRow, 0,
193                                     Qt::AlignRight | Qt::AlignVCenter);
194             m_mainLayout->addWidget(field, currentRow, 1);
195           }
196           connect(field, SIGNAL(currentParamChanged()), m_paramViewer,
197                   SIGNAL(currentFxParamChanged()));
198           connect(field, SIGNAL(actualParamChanged()), m_paramViewer,
199                   SIGNAL(actualFxParamChanged()));
200           connect(field, SIGNAL(paramKeyToggle()), m_paramViewer,
201                   SIGNAL(paramKeyChanged()));
202         }
203       }
204     } else if (tagName == "label") {
205       std::string name;
206       is >> name;
207       is.matchEndTag();
208       QString str;
209       if (isVertical == false) {
210         assert(m_horizontalLayout);
211         m_horizontalLayout->addWidget(new QLabel(str.fromStdString(name)));
212       } else {
213         int currentRow = m_mainLayout->rowCount();
214         m_mainLayout->addWidget(new QLabel(str.fromStdString(name)), currentRow,
215                                 0, 1, 2);
216       }
217     } else if (tagName == "separator") {
218       // <separator/> o <separator label="xxx"/>
219       std::string label = is.getTagAttribute("label");
220       QString str;
221       Separator *sep = new Separator(str.fromStdString(label), this);
222       int currentRow = m_mainLayout->rowCount();
223       m_mainLayout->addWidget(sep, currentRow, 0, 1, 2);
224       m_mainLayout->setRowStretch(currentRow, 0);
225     } else if (tagName == "histogram") {
226       Histogram *histogram = new Histogram();
227       m_fxHistogramRender->setHistograms(histogram->getHistograms());
228       if (isVertical == false) {
229         assert(m_horizontalLayout);
230         m_horizontalLayout->addWidget(histogram);
231       } else {
232         int currentRow = m_mainLayout->rowCount();
233         m_mainLayout->addWidget(histogram, currentRow, 0, 1, 2);
234       }
235     } else if (tagName == "test") {
236       // <test/>
237       // box->add(new WidgetBox(new TestSeparator(page)));
238     } else if (tagName == "hbox") {
239       int currentRow     = m_mainLayout->rowCount();
240       m_horizontalLayout = new QHBoxLayout();
241       m_horizontalLayout->setMargin(0);
242       m_horizontalLayout->setSpacing(5);
243       setPageField(is, fx, false);
244       m_mainLayout->addLayout(m_horizontalLayout, currentRow, 1, 1, 2);
245     } else if (tagName == "vbox") {
246       int shrink                   = 0;
247       std::string shrinkStr        = is.getTagAttribute("shrink");
248       std::string modeSensitiveStr = is.getTagAttribute("modeSensitive");
249       if (shrinkStr != "" || modeSensitiveStr != "") {
250         QWidget *tmpWidget;
251         if (shrinkStr != "") {
252           tmpWidget           = new QWidget(this);
253           shrink              = QString::fromStdString(shrinkStr).toInt();
254           std::string label   = is.getTagAttribute("label");
255           QCheckBox *checkBox = new QCheckBox(this);
256           QHBoxLayout *sepLay = new QHBoxLayout();
257           sepLay->setMargin(0);
258           sepLay->setSpacing(5);
259           sepLay->addWidget(checkBox, 0);
260           sepLay->addWidget(new Separator(QString::fromStdString(label), this),
261                             1);
262           int currentRow = m_mainLayout->rowCount();
263           m_mainLayout->addLayout(sepLay, currentRow, 0, 1, 2);
264           m_mainLayout->setRowStretch(currentRow, 0);
265           //--- signal-slot connection
266           connect(checkBox, SIGNAL(toggled(bool)), tmpWidget,
267                   SLOT(setVisible(bool)));
268           checkBox->setChecked(shrink == 1);
269           tmpWidget->setVisible(shrink == 1);
270         } else {  // modeSensitiveStr != ""
271           QList<int> modes;
272           QStringList modeListStr =
273               QString::fromStdString(is.getTagAttribute("mode"))
274                   .split(',', QString::SkipEmptyParts);
275           for (QString modeNum : modeListStr) modes.push_back(modeNum.toInt());
276           // find the mode combobox
277           ModeChangerParamField *modeChanger = nullptr;
278           for (int r = 0; r < m_mainLayout->rowCount(); r++) {
279             QLayoutItem *li = m_mainLayout->itemAtPosition(r, 1);
280             if (!li || !li->widget()) continue;
281             ModeChangerParamField *field =
282                 dynamic_cast<ModeChangerParamField *>(li->widget());
283             if (!field ||
284                 field->getParamName().toStdString() != modeSensitiveStr)
285               continue;
286             modeChanger = field;
287             break;
288           }
289           assert(modeChanger);
290           tmpWidget = new ModeSensitiveBox(this, modeChanger, modes);
291         }
292 
293         int currentRow           = m_mainLayout->rowCount();
294         QGridLayout *keepMainLay = m_mainLayout;
295         // temporary switch the layout
296         m_mainLayout = new QGridLayout();
297         m_mainLayout->setMargin(0);
298         m_mainLayout->setVerticalSpacing(10);
299         m_mainLayout->setHorizontalSpacing(5);
300         m_mainLayout->setColumnStretch(0, 0);
301         m_mainLayout->setColumnStretch(1, 1);
302         setPageField(is, fx, true);
303         tmpWidget->setLayout(m_mainLayout);
304         // turn back the layout
305         m_mainLayout = keepMainLay;
306         m_mainLayout->addWidget(tmpWidget, currentRow, 0, 1, 2);
307       } else
308         setPageField(is, fx, true);
309     }
310     /*-- PixelParamFieldが2つあるとき、一方のRGB値を他方にコピーするボタン --*/
311     else if (tagName == "rgb_link_button") {
312       /*-- リンクさせたいパラメータを2つ得る --*/
313       std::string name1, name2;
314       is >> name1;
315       is >> name2;
316       is.matchEndTag();
317 
318       /*-- 既に作ってあるGUIを探索し、対応する2つを得て格納 --*/
319       PixelParamField *ppf1 = 0;
320       PixelParamField *ppf2 = 0;
321       for (int r = 0; r < m_mainLayout->rowCount(); r++) {
322         QLayoutItem *li = m_mainLayout->itemAtPosition(r, 1);
323         if (!li) continue;
324         QWidget *w = li->widget();
325         if (!w) continue;
326 
327         ParamField *pf = dynamic_cast<ParamField *>(w);
328         if (pf) {
329           PixelParamField *ppf = dynamic_cast<PixelParamField *>(pf);
330           if (ppf) {
331             if (ppf1 == 0 && ppf->getParamName().toStdString() == name1)
332               ppf1 = ppf;
333 
334             if (ppf2 == 0 && ppf->getParamName().toStdString() == name2)
335               ppf2 = ppf;
336           }
337         }
338       }
339       if (ppf1 == 0 || ppf2 == 0) continue;
340 
341       /*-- ボタンのラベルのため 翻訳する --*/
342       std::string paramName1 = fx->getFxType() + "." + name1;
343       std::string paramName2 = fx->getFxType() + "." + name2;
344       QString str1 =
345           QString::fromStdWString(TStringTable::translate(paramName1));
346       QString str2 =
347           QString::fromStdWString(TStringTable::translate(paramName2));
348 
349       RgbLinkButtons *linkBut =
350           new RgbLinkButtons(str1, str2, this, ppf1, ppf2);
351 
352       int currentRow = m_mainLayout->rowCount();
353       m_mainLayout->addWidget(linkBut, currentRow, 1,
354                               Qt::AlignLeft | Qt::AlignVCenter);
355     }
356     /*-- チェックボックスによって他のインタフェースを表示/非表示させる ---*/
357     else if (tagName == "visibleToggle") {
358       BoolParamField *controller_bpf = 0;
359       QList<QWidget *> on_items;
360       QList<QWidget *> off_items;
361       while (!is.matchEndTag()) {
362         std::string tagName;
363         if (!is.matchTag(tagName)) throw TException("expected tag");
364 
365         if (tagName ==
366                 "controller" || /*-- 表示をコントロールするチェックボックス --*/
367             tagName == "on" || /*-- ONのとき表示されるインタフェース --*/
368             tagName == "off") /*-- OFFのとき表示されるインタフェース --*/
369         {
370           std::string name;
371           is >> name;
372           is.matchEndTag();
373           for (int r = 0; r < m_mainLayout->rowCount(); r++) {
374             QLayoutItem *li = m_mainLayout->itemAtPosition(r, 1);
375             if (!li) continue;
376             QWidget *w = li->widget();
377             if (!w) continue;
378             ParamField *pf = dynamic_cast<ParamField *>(w);
379             if (pf) {
380               if (pf->getParamName().toStdString() == name) {
381                 if (tagName == "controller")
382                   controller_bpf = dynamic_cast<BoolParamField *>(pf);
383                 else if (tagName == "on") {
384                   on_items.push_back(w);
385                   on_items.push_back(
386                       m_mainLayout->itemAtPosition(r, 0)->widget());
387                 } else if (tagName == "off") {
388                   off_items.push_back(w);
389                   off_items.push_back(
390                       m_mainLayout->itemAtPosition(r, 0)->widget());
391                 }
392               }
393             }
394             /*-- 入れ子のLayoutも1段階探す --*/
395             else {
396               QGridLayout *gridLay = dynamic_cast<QGridLayout *>(w->layout());
397               if (!gridLay) continue;
398               for (int r_s = 0; r_s < gridLay->rowCount(); r_s++) {
399                 QLayoutItem *li_s = gridLay->itemAtPosition(r_s, 1);
400                 if (!li_s) continue;
401                 ParamField *pf_s = dynamic_cast<ParamField *>(li_s->widget());
402                 if (pf_s) {
403                   if (pf_s->getParamName().toStdString() == name) {
404                     if (tagName == "controller")
405                       controller_bpf = dynamic_cast<BoolParamField *>(pf_s);
406                     else if (tagName == "on") {
407                       on_items.push_back(pf_s);
408                       on_items.push_back(
409                           gridLay->itemAtPosition(r_s, 0)->widget());
410                     } else if (tagName == "off") {
411                       off_items.push_back(pf_s);
412                       off_items.push_back(
413                           gridLay->itemAtPosition(r_s, 0)->widget());
414                     }
415                   }
416                 }
417               }
418             }
419           }
420         } else
421           throw TException("unexpected tag " + tagName);
422       }
423       /*-- 表示コントロールをconnect --*/
424       if (controller_bpf) {
425         /*-- ラベルとWidgetを両方表示/非表示 --*/
426         for (int i = 0; i < on_items.size(); i++) {
427           connect(controller_bpf, SIGNAL(toggled(bool)), on_items[i],
428                   SLOT(setVisible(bool)));
429           on_items[i]->hide();
430         }
431         for (int i = 0; i < off_items.size(); i++) {
432           connect(controller_bpf, SIGNAL(toggled(bool)), off_items[i],
433                   SLOT(setHidden(bool)));
434           off_items[i]->show();
435         }
436       } else
437         std::cout << "controller_bpf NOT found!" << std::endl;
438     } else
439       throw TException("unexpected tag " + tagName);
440   }
441 
442   if (isVertical == false && m_horizontalLayout) {
443     m_horizontalLayout->addStretch(1);
444   }
445 }
446 
447 //-----------------------------------------------------------------------------
448 
setPageSpace()449 void ParamsPage::setPageSpace() {
450   if (m_fields.count() != 0) {
451     QWidget *spaceWidget = new QWidget();
452 
453     int currentRow = m_mainLayout->rowCount();
454     m_mainLayout->addWidget(spaceWidget, currentRow, 0, 1, 2);
455 
456     for (int i = 0; i < currentRow; i++) m_mainLayout->setRowStretch(i, 0);
457     m_mainLayout->setRowStretch(currentRow, 1);
458   }
459 }
460 
461 //-----------------------------------------------------------------------------
beginGroup(const char * name)462 void ParamsPage::beginGroup(const char *name) {
463   m_groupLayout = new QGridLayout();
464 
465   QGroupBox *group = new QGroupBox(QString::fromUtf8(name), this);
466   group->setLayout(m_groupLayout);
467   m_mainLayout->addWidget(group, m_mainLayout->rowCount(), 0, 1, 2);
468 }
469 
endGroup()470 void ParamsPage::endGroup() { m_groupLayout = NULL; }
471 
addWidget(QWidget * field,bool isVertical)472 void ParamsPage::addWidget(QWidget *field, bool isVertical) {
473   QLabel *label  = NULL;
474   ParamField *pf = qobject_cast<ParamField *>(field);
475   if (pf) {
476     label = new QLabel(pf->getUIName(), this);
477     label->setObjectName("FxSettingsLabel");
478     if (!pf->getDescription().isEmpty())
479       label->setToolTip(pf->getDescription());
480   }
481 
482   if (isVertical) {
483     if (m_groupLayout) {
484       int row = m_groupLayout->rowCount();
485       if (label)
486         m_groupLayout->addWidget(label, row, 0,
487                                  Qt::AlignRight | Qt::AlignVCenter);
488       m_groupLayout->addWidget(field, row, 1);
489     } else {
490       int row = m_mainLayout->rowCount();
491       if (label)
492         m_mainLayout->addWidget(label, row, 0,
493                                 Qt::AlignRight | Qt::AlignVCenter);
494       m_mainLayout->addWidget(field, row, 1);
495     }
496   } else {
497     if (!m_horizontalLayout) {
498       m_horizontalLayout = new QHBoxLayout();
499       m_horizontalLayout->setMargin(0);
500       m_horizontalLayout->setSpacing(5);
501     }
502     m_horizontalLayout->addWidget(field);
503   }
504 }
505 
506 #define TOONZ_DEFINE_NEW_COMPONENT(NAME, MAKE)                                 \
507   QWidget *ParamsPage::NAME(TFx *fx, const char *name) {                       \
508     TParamP param = fx->getParams()->getParam(name);                           \
509     if (!param) return NULL;                                                   \
510     QString const paramName =                                                  \
511         QString::fromStdString(fx->getFxType() + "." + name);                  \
512     ParamField *field = MAKE(this, paramName, param);                          \
513     if (!field) return NULL;                                                   \
514     m_fields.push_back(field);                                                 \
515     connect(field, SIGNAL(currentParamChanged()), m_paramViewer,               \
516             SIGNAL(currentFxParamChanged()));                                  \
517     connect(field, SIGNAL(actualParamChanged()), m_paramViewer,                \
518             SIGNAL(actualFxParamChanged()));                                   \
519     connect(field, SIGNAL(paramKeyToggle()), m_paramViewer,                    \
520             SIGNAL(paramKeyChanged()));                                        \
521     return field;                                                              \
522   }
523 
524 TOONZ_DEFINE_NEW_COMPONENT(newParamField, ParamField::create);
525 TOONZ_DEFINE_NEW_COMPONENT(newLineEdit, make_lineedit);
526 TOONZ_DEFINE_NEW_COMPONENT(newSlider, make_slider);
527 TOONZ_DEFINE_NEW_COMPONENT(newSpinBox, make_spinbox);
528 TOONZ_DEFINE_NEW_COMPONENT(newCheckBox, make_checkbox);
529 TOONZ_DEFINE_NEW_COMPONENT(newRadioButton, make_radiobutton);
530 TOONZ_DEFINE_NEW_COMPONENT(newComboBox, make_combobox);
531 
532 #undef TOONZ_DEFINE_NEW_COMPONENT
533 
534 //-----------------------------------------------------------------------------
535 
setFx(const TFxP & currentFx,const TFxP & actualFx,int frame)536 void ParamsPage::setFx(const TFxP &currentFx, const TFxP &actualFx, int frame) {
537   assert(currentFx);
538   assert(actualFx);
539   for (int i = 0; i < (int)m_fields.size(); i++) {
540     ParamField *field = m_fields[i];
541     QString fieldName = field->getParamName();
542 
543     TFxP fx = getCurrentFx(currentFx, actualFx->getFxId());
544     assert(fx.getPointer());
545     TParamP currentParam =
546         currentFx->getParams()->getParam(fieldName.toStdString());
547     TParamP actualParam =
548         actualFx->getParams()->getParam(fieldName.toStdString());
549     assert(currentParam);
550     assert(actualParam);
551     field->setParam(currentParam, actualParam, frame);
552   }
553   if (actualFx->getInputPortCount() > 0)
554     m_fxHistogramRender->computeHistogram(actualFx->getInputPort(0)->getFx(),
555                                           frame);
556 }
557 
558 //-----------------------------------------------------------------------------
559 
setPointValue(int index,const TPointD & p)560 void ParamsPage::setPointValue(int index, const TPointD &p) {
561   if (0 <= index && index < (int)m_fields.size())
562     m_fields[index]->setPointValue(p);
563 }
564 
565 //-----------------------------------------------------------------------------
566 
update(int frame)567 void ParamsPage::update(int frame) {
568   int i;
569   for (i = 0; i < (int)m_fields.size(); i++) {
570     ParamField *field = m_fields[i];
571     field->update(frame);
572   }
573 }
574 
575 //-----------------------------------------------------------------------------
576 
577 namespace {
578 
getItemSize(QLayoutItem * item)579 QSize getItemSize(QLayoutItem *item) {
580   // layout case
581   QHBoxLayout *hLay = dynamic_cast<QHBoxLayout *>(item->layout());
582   if (hLay) {
583     int tmpWidth = 0, tmpHeight = 0;
584     for (int c = 0; c < hLay->count(); c++) {
585       QLayoutItem *subItem = hLay->itemAt(c);
586       if (!subItem) continue;
587       QSize subItemSize = getItemSize(subItem);
588       tmpWidth += subItemSize.width();
589       if (tmpHeight < subItemSize.height()) tmpHeight = subItemSize.height();
590     }
591     tmpWidth += (hLay->count() - 1) * 5;
592     return QSize(tmpWidth, tmpHeight);
593   }
594 
595   ParamField *pF = dynamic_cast<ParamField *>(item->widget());
596   if (pF) return pF->getPreferedSize();
597 
598   Separator *sep = dynamic_cast<Separator *>(item->widget());
599   if (sep) return QSize(0, 16);
600 
601   Histogram *histo = dynamic_cast<Histogram *>(item->widget());
602   if (histo) return QSize(278, 162);
603 
604   RgbLinkButtons *linkBut = dynamic_cast<RgbLinkButtons *>(item->widget());
605   if (linkBut) return QSize(0, 21);
606 
607   return QSize();
608 }
609 
updateMaximumPageSize(QGridLayout * layout,int & maxLabelWidth,int & maxWidgetWidth,int & fieldsHeight)610 void updateMaximumPageSize(QGridLayout *layout, int &maxLabelWidth,
611                            int &maxWidgetWidth, int &fieldsHeight) {
612   /*-- Label側の横幅の最大値を得る --*/
613   for (int r = 0; r < layout->rowCount(); r++) {
614     /*-- アイテムが無ければ次の行へ --*/
615     if (!layout->itemAtPosition(r, 0)) continue;
616     /*-- ラベルの横幅を得て、最大値を更新していく --*/
617     QLabel *label =
618         dynamic_cast<QLabel *>(layout->itemAtPosition(r, 0)->widget());
619     QGroupBox *gBox =
620         dynamic_cast<QGroupBox *>(layout->itemAtPosition(r, 0)->widget());
621     if (label) {
622       int tmpWidth = label->fontMetrics().width(label->text());
623       if (maxLabelWidth < tmpWidth) maxLabelWidth = tmpWidth;
624     }
625     /*-- PlugInFxのGroupパラメータのサイズ --*/
626     else if (gBox) {
627       QGridLayout *gridLay = dynamic_cast<QGridLayout *>(gBox->layout());
628       if (gridLay) {
629         updateMaximumPageSize(gridLay, maxLabelWidth, maxWidgetWidth,
630                               fieldsHeight);
631         /*-- GroupBoxのマージン --*/
632         maxLabelWidth += 10;
633         maxWidgetWidth += 10;
634         fieldsHeight += 20;
635       }
636     }
637   }
638 
639   /*-- Widget側の最適な縦サイズおよび横幅の最大値を得る --*/
640   QMap<int, int> heightsByMode;
641   int maxModeHeight = 0;
642   for (int r = 0; r < layout->rowCount(); r++) {
643     /*-- Column1にある可能性のあるもの:ParamField, Histogram, Layout,
644      * RgbLinkButtons --*/
645 
646     QLayoutItem *item = layout->itemAtPosition(r, 1);
647     if (!item) continue;
648 
649     ModeSensitiveBox *box = dynamic_cast<ModeSensitiveBox *>(item->widget());
650     if (box) {
651       // if (box->isHidden()) continue;
652       QGridLayout *innerLay = dynamic_cast<QGridLayout *>(box->layout());
653       if (!innerLay) continue;
654       int tmpHeight = 0;
655       updateMaximumPageSize(innerLay, maxLabelWidth, maxWidgetWidth, tmpHeight);
656       for (int mode : box->modes()) {
657         heightsByMode[mode] += tmpHeight;
658         maxModeHeight = std::max(maxModeHeight, heightsByMode[mode]);
659       }
660 
661       // attempt to align the label column
662       innerLay->setColumnMinimumWidth(0, maxLabelWidth);
663       continue;
664     }
665 
666     QSize itemSize = getItemSize(item);
667     if (maxWidgetWidth < itemSize.width()) maxWidgetWidth = itemSize.width();
668     fieldsHeight += itemSize.height();
669   }
670   if (maxModeHeight > 0) fieldsHeight += maxModeHeight;
671 
672   if (layout->rowCount() > 1) fieldsHeight += (layout->rowCount() - 1) * 10;
673 }
674 };  // namespace
675 
getPreferredSize()676 QSize ParamsPage::getPreferredSize() {
677   int maxLabelWidth  = 0;
678   int maxWidgetWidth = 0;
679   int fieldsHeight   = 0;
680 
681   updateMaximumPageSize(m_mainLayout, maxLabelWidth, maxWidgetWidth,
682                         fieldsHeight);
683   return QSize(maxLabelWidth + maxWidgetWidth +
684                    m_mainLayout->horizontalSpacing() +
685                    2 * m_mainLayout->margin(),
686                fieldsHeight + 2 * m_mainLayout->margin() +
687                    31 /* spacing for the swatch */);
688 }
689 
690 //=============================================================================
691 // ParamsPageSet
692 //-----------------------------------------------------------------------------
693 
694 #if QT_VERSION >= 0x050500
ParamsPageSet(QWidget * parent,Qt::WindowFlags flags)695 ParamsPageSet::ParamsPageSet(QWidget *parent, Qt::WindowFlags flags)
696 #else
697 ParamsPageSet::ParamsPageSet(QWidget *parent, Qt::WFlags flags)
698 #endif
699     : QWidget(parent, flags)
700     , m_preferredSize(0, 0)
701     , m_helpFilePath("")
702     , m_helpCommand("") {
703   // TabBar
704   m_tabBar = new TabBar(this);
705   // This widget is used to set the background color of the tabBar
706   // using the styleSheet and to draw the two lines on the bottom size.
707   m_tabBarContainer = new TabBarContainter(this);
708   m_pagesList       = new QStackedWidget(this);
709 
710   m_helpButton = new QPushButton(tr(""), this);
711   m_helpButton->setIconSize(QSize(20, 20));
712   m_helpButton->setIcon(createQIcon("help"));
713   m_helpButton->setFixedWidth(28);
714   m_helpButton->setToolTip(tr("View help page"));
715 
716   m_parent = dynamic_cast<ParamViewer *>(parent);
717   m_pageFxIndexTable.clear();
718   m_tabBar->setDrawBase(false);
719   m_tabBar->setObjectName("FxSettingsTabBar");
720   m_helpButton->setFixedHeight(20);
721   m_helpButton->setObjectName("FxSettingsHelpButton");
722   m_helpButton->setFocusPolicy(Qt::NoFocus);
723 
724   //----layout
725   QVBoxLayout *mainLayout = new QVBoxLayout();
726   mainLayout->setMargin(0);
727   mainLayout->setSpacing(0);
728   {
729     QHBoxLayout *hLayout = new QHBoxLayout();
730     hLayout->setMargin(0);
731     hLayout->addSpacing(0);
732     {
733       hLayout->addWidget(m_tabBar);
734       hLayout->addStretch(1);
735       hLayout->addWidget(m_helpButton);
736     }
737     m_tabBarContainer->setLayout(hLayout);
738 
739     mainLayout->addWidget(m_tabBarContainer);
740 
741     mainLayout->addWidget(m_pagesList);
742 
743     mainLayout->addWidget(new Separator("", this), 0);
744   }
745   setLayout(mainLayout);
746 
747   connect(m_tabBar, SIGNAL(currentChanged(int)), this, SLOT(setPage(int)));
748 
749   m_helpButton->hide();
750 }
751 
752 //-----------------------------------------------------------------------------
753 
~ParamsPageSet()754 ParamsPageSet::~ParamsPageSet() {}
755 
756 //-----------------------------------------------------------------------------
757 
setPage(int index)758 void ParamsPageSet::setPage(int index) {
759   if (m_tabBar->count() == 0 || m_pagesList->count() == 0) return;
760   assert(index >= 0 && index < m_pagesList->count());
761   m_pagesList->setCurrentIndex(index);
762 }
763 
764 //-----------------------------------------------------------------------------
765 
setFx(const TFxP & currentFx,const TFxP & actualFx,int frame)766 void ParamsPageSet::setFx(const TFxP &currentFx, const TFxP &actualFx,
767                           int frame) {
768   TMacroFx *currentFxMacro = dynamic_cast<TMacroFx *>(currentFx.getPointer());
769   if (currentFxMacro) {
770     TMacroFx *actualFxMacro = dynamic_cast<TMacroFx *>(actualFx.getPointer());
771     assert(actualFxMacro);
772     const std::vector<TFxP> &currentFxMacroFxs = currentFxMacro->getFxs();
773     const std::vector<TFxP> &actualFxMacroFxs  = actualFxMacro->getFxs();
774     assert(currentFxMacroFxs.size() == actualFxMacroFxs.size());
775     for (int i = 0; i < m_pagesList->count(); i++) {
776       ParamsPage *page = getParamsPage(i);
777       if (!page || !m_pageFxIndexTable.contains(page)) continue;
778       int index = m_pageFxIndexTable[page];
779       page->setFx(currentFxMacroFxs[index], actualFxMacroFxs[index], frame);
780     }
781   } else {
782     for (int i = 0; i < m_pagesList->count(); i++) {
783       ParamsPage *page = getParamsPage(i);
784       if (!page) continue;
785       page->setFx(currentFx, actualFx, frame);
786     }
787   }
788 }
789 
790 //-----------------------------------------------------------------------------
791 
updatePage(int frame,bool onlyParam)792 void ParamsPageSet::updatePage(int frame, bool onlyParam) {
793   if (!m_pagesList) return;
794   int i;
795   for (i = 0; i < m_pagesList->count(); i++) {
796     ParamsPage *page = getParamsPage(i);
797     if (!page) continue;
798     page->update(frame);
799     if (!onlyParam) page->getFxHistogramRender()->invalidateFrame(frame);
800   }
801 }
802 
803 //-----------------------------------------------------------------------------
804 
setScene(ToonzScene * scene)805 void ParamsPageSet::setScene(ToonzScene *scene) {
806   if (!m_pagesList) return;
807   int i;
808   for (i = 0; i < m_pagesList->count(); i++) {
809     ParamsPage *page = getParamsPage(i);
810     if (!page) continue;
811     page->getFxHistogramRender()->setScene(scene);
812   }
813 }
814 
815 //-----------------------------------------------------------------------------
816 
setIsCameraViewMode(bool isCameraViewMode)817 void ParamsPageSet::setIsCameraViewMode(bool isCameraViewMode) {
818   if (!m_pagesList) return;
819   int i;
820   for (i = 0; i < m_pagesList->count(); i++) {
821     ParamsPage *page = getParamsPage(i);
822     if (!page) continue;
823     page->getFxHistogramRender()->setIsCameraViewMode(isCameraViewMode);
824   }
825 }
826 
827 //-----------------------------------------------------------------------------
828 
createParamsPage()829 ParamsPage *ParamsPageSet::createParamsPage() {
830   return new ParamsPage(this, m_parent);
831 }
832 
addParamsPage(ParamsPage * page,const char * name)833 void ParamsPageSet::addParamsPage(ParamsPage *page, const char *name) {
834   /*-- このFxで最大サイズのページに合わせてダイアログをリサイズ --*/
835   QSize pagePreferredSize = page->getPreferredSize();
836   m_preferredSize         = m_preferredSize.expandedTo(
837       pagePreferredSize + QSize(m_tabBarContainer->height() + 2,
838                                 2)); /*-- 2は上下左右のマージン --*/
839 
840   QScrollArea *pane = new QScrollArea(this);
841   pane->setWidgetResizable(true);
842   pane->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
843   pane->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
844   pane->setWidget(page);
845 
846   m_tabBar->addSimpleTab(QString::fromUtf8(name));
847   m_pagesList->addWidget(pane);
848 }
849 
850 //-----------------------------------------------------------------------------
851 
createControls(const TFxP & fx,int index)852 void ParamsPageSet::createControls(const TFxP &fx, int index) {
853   if (TMacroFx *macroFx = dynamic_cast<TMacroFx *>(fx.getPointer())) {
854     const std::vector<TFxP> &fxs = macroFx->getFxs();
855     for (int i = 0; i < (int)fxs.size(); i++) createControls(fxs[i], i);
856     return;
857   }
858   if (RasterFxPluginHost *plugin =
859           dynamic_cast<RasterFxPluginHost *>(fx.getPointer())) {
860     plugin->build(this);
861     std::string url = plugin->getUrl();
862     if (!url.empty()) {
863       connect(m_helpButton, SIGNAL(pressed()), this, SLOT(openHelpUrl()));
864       m_helpButton->show();
865       m_helpUrl = url;
866     }
867     return;
868   }
869 
870   TFilePath fp = ToonzFolder::getProfileFolder() + "layouts" + "fxs" +
871                  (fx->getFxType() + ".xml");
872 
873   TIStream is(fp);
874   if (!is) return;
875 
876   if (fx->getParams()->getParamCount()) {
877     try {
878       std::string tagName;
879       if (!is.matchTag(tagName) || tagName != "fxlayout")
880         throw TException("expected <fxlayout>");
881 
882       m_helpFilePath = is.getTagAttribute("help_file");
883       if (m_helpFilePath != "") {
884         connect(m_helpButton, SIGNAL(pressed()), this, SLOT(openHelpFile()));
885         m_helpButton->show();
886         /*-- pdfファイルのページ指定など、引数が必要な場合の追加fragmentを取得
887          * --*/
888         m_helpCommand = is.getTagAttribute("help_command");
889       }
890 
891       while (!is.matchEndTag()) createPage(is, fx, index);
892     } catch (TException const &) {
893     }
894   }
895   // else createEmptyPage();
896 }
897 
898 //-----------------------------------------------------------------------------
899 
getCurrentParamsPage() const900 ParamsPage *ParamsPageSet::getCurrentParamsPage() const {
901   QScrollArea *scrollAreaPage =
902       dynamic_cast<QScrollArea *>(m_pagesList->currentWidget());
903   assert(scrollAreaPage);
904   return dynamic_cast<ParamsPage *>(scrollAreaPage->widget());
905 }
906 
907 //-----------------------------------------------------------------------------
908 
getParamsPage(int index) const909 ParamsPage *ParamsPageSet::getParamsPage(int index) const {
910   QScrollArea *scrollAreaPage =
911       dynamic_cast<QScrollArea *>(m_pagesList->widget(index));
912   assert(scrollAreaPage);
913   return dynamic_cast<ParamsPage *>(scrollAreaPage->widget());
914 }
915 
916 //-----------------------------------------------------------------------------
917 
createPage(TIStream & is,const TFxP & fx,int index)918 void ParamsPageSet::createPage(TIStream &is, const TFxP &fx, int index) {
919   std::string tagName;
920   if (!is.matchTag(tagName) || tagName != "page")
921     throw TException("expected <page>");
922   std::string pageName         = is.getTagAttribute("name");
923   if (pageName == "") pageName = "page";
924 
925   ParamsPage *paramsPage = new ParamsPage(this, m_parent);
926   paramsPage->setPage(is, fx);
927 
928   connect(paramsPage, SIGNAL(preferredPageSizeChanged()), this,
929           SLOT(recomputePreferredSize()));
930 
931   /*-- このFxで最大サイズのページに合わせてダイアログをリサイズ --*/
932   QSize pagePreferredSize = paramsPage->getPreferredSize();
933   m_preferredSize         = m_preferredSize.expandedTo(
934       pagePreferredSize + QSize(m_tabBarContainer->height() + 2,
935                                 2)); /*-- 2は上下左右のマージン --*/
936 
937   QScrollArea *scrollAreaPage = new QScrollArea(this);
938   scrollAreaPage->setWidgetResizable(true);
939   scrollAreaPage->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
940   scrollAreaPage->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
941   scrollAreaPage->setWidget(paramsPage);
942 
943   QString str;
944   m_tabBar->addSimpleTab(str.fromStdString(pageName));
945   m_pagesList->addWidget(scrollAreaPage);
946   if (index >= 0) m_pageFxIndexTable[paramsPage] = index;
947 }
948 
949 //-----------------------------------------------------------------------------
950 
recomputePreferredSize()951 void ParamsPageSet::recomputePreferredSize() {
952   QSize newSize(0, 0);
953   for (int i = 0; i < m_pagesList->count(); i++) {
954     QScrollArea *area = dynamic_cast<QScrollArea *>(m_pagesList->widget(i));
955     if (!area) continue;
956     ParamsPage *page = dynamic_cast<ParamsPage *>(area->widget());
957     if (!page) continue;
958     QSize pagePreferredSize = page->getPreferredSize();
959     newSize                 = newSize.expandedTo(pagePreferredSize +
960                                  QSize(m_tabBarContainer->height() + 2, 2));
961   }
962   if (!newSize.isEmpty()) {
963     m_preferredSize = newSize;
964     // resize the parent FxSettings
965     m_parent->notifyPreferredSizeChanged(m_preferredSize + QSize(2, 50));
966   }
967 }
968 
969 //-----------------------------------------------------------------------------
970 
971 /* TODO: Webサイト内のヘルプに対応すべきか検討 2016.02.01 shun_iwasawa */
openHelpFile()972 void ParamsPageSet::openHelpFile() {
973   if (m_helpFilePath == "") return;
974 
975   // if (m_helpCommand != "")
976   //	commandString += m_helpCommand + " ";
977 
978   // Get UI language as set in "Preferences"
979   QString currentLanguage = Preferences::instance()->getCurrentLanguage();
980   std::string helpDocLang = currentLanguage.toStdString();
981 
982   // Assume associated language subdir exists
983   TFilePath helpFp = TEnv::getStuffDir() + "doc" + helpDocLang + m_helpFilePath;
984 
985   // Verify subdir exists; if not, default to standard doc dir
986   if (!TFileStatus(helpFp).doesExist()) {
987     helpFp = TEnv::getStuffDir() + "doc" + m_helpFilePath;
988   }
989 
990   // commandString +=
991   // QString::fromStdWString(helpFp.getWideString()).toStdString();
992   // QString command = QString::fromStdString(m_helpFilePath);
993   // system(commandString.c_str());
994   // QProcess process;
995   // process.start(command);
996   QDesktopServices::openUrl(
997       QUrl::fromLocalFile(QString::fromStdWString(helpFp.getWideString())));
998 }
999 
openHelpUrl()1000 void ParamsPageSet::openHelpUrl() {
1001   QDesktopServices::openUrl(QUrl(QString(m_helpUrl.c_str())));
1002 }
1003 
1004 //=============================================================================
1005 // ParamViewer
1006 //-----------------------------------------------------------------------------
1007 
1008 #if QT_VERSION >= 0x050500
ParamViewer(QWidget * parent,Qt::WindowFlags flags)1009 ParamViewer::ParamViewer(QWidget *parent, Qt::WindowFlags flags)
1010 #else
1011 ParamViewer::ParamViewer(QWidget *parent, Qt::WFlags flags)
1012 #endif
1013     : QFrame(parent, flags), m_fx(0) {
1014   m_tablePageSet = new QStackedWidget(this);
1015   m_tablePageSet->addWidget(new QWidget());
1016 
1017   /*-- SwatchViewerを表示/非表示するボタン --*/
1018   QPushButton *showSwatchButton = new QPushButton("", this);
1019   QLabel *swatchLabel           = new QLabel(tr("Swatch Viewer"), this);
1020 
1021   swatchLabel->setObjectName("TitleTxtLabel");
1022   showSwatchButton->setObjectName("menuToggleButton");
1023   showSwatchButton->setFixedSize(15, 15);
1024   showSwatchButton->setIcon(createQIcon("menu_toggle"));
1025   showSwatchButton->setCheckable(true);
1026   showSwatchButton->setChecked(false);
1027   showSwatchButton->setFocusPolicy(Qt::NoFocus);
1028 
1029   QVBoxLayout *mainLayout = new QVBoxLayout(this);
1030   mainLayout->setMargin(0);
1031   mainLayout->setSpacing(0);
1032   {
1033     mainLayout->addWidget(m_tablePageSet, 1);
1034 
1035     QHBoxLayout *showPreviewButtonLayout = new QHBoxLayout(this);
1036     showPreviewButtonLayout->setMargin(3);
1037     showPreviewButtonLayout->setSpacing(3);
1038     {
1039       showPreviewButtonLayout->addWidget(showSwatchButton, 0);
1040       showPreviewButtonLayout->addWidget(swatchLabel, 0);
1041       showPreviewButtonLayout->addStretch(1);
1042     }
1043     mainLayout->addLayout(showPreviewButtonLayout, 0);
1044   }
1045   setLayout(mainLayout);
1046 
1047   connect(showSwatchButton, SIGNAL(toggled(bool)), this,
1048           SIGNAL(showSwatchButtonToggled(bool)));
1049 }
1050 
1051 //-----------------------------------------------------------------------------
1052 
~ParamViewer()1053 ParamViewer::~ParamViewer() {}
1054 
1055 //-----------------------------------------------------------------------------
1056 
setFx(const TFxP & currentFx,const TFxP & actualFx,int frame,ToonzScene * scene)1057 void ParamViewer::setFx(const TFxP &currentFx, const TFxP &actualFx, int frame,
1058                         ToonzScene *scene) {
1059   if (!actualFx) {
1060     m_tablePageSet->setCurrentIndex(0);
1061     return;
1062   }
1063   std::string name = actualFx->getFxType();
1064   if (name == "macroFx") {
1065     TMacroFx *macroFx = dynamic_cast<TMacroFx *>(currentFx.getPointer());
1066     if (macroFx) name = macroFx->getMacroFxType();
1067   }
1068 
1069   int currentIndex = -1;
1070 
1071   QMap<std::string, int>::iterator it;
1072   it = m_tableFxIndex.find(name);
1073   if (it == m_tableFxIndex.end()) {
1074     ParamsPageSet *pageSet = new ParamsPageSet(this);
1075     currentIndex           = m_tablePageSet->addWidget(pageSet);
1076     m_tableFxIndex[name]   = currentIndex;
1077     pageSet->createControls(actualFx);
1078   } else
1079     currentIndex = it.value();
1080 
1081   assert(currentIndex >= 0);
1082 
1083   m_tablePageSet->setCurrentIndex(currentIndex);
1084 
1085   getCurrentPageSet()->setScene(scene);
1086 
1087   if (m_fx != currentFx) {
1088     getCurrentPageSet()->setFx(currentFx, actualFx, frame);
1089     if (m_actualFx != actualFx) {
1090       m_actualFx = actualFx;
1091       QSize pageViewerPreferredSize =
1092           getCurrentPageSet()->getPreferredSize() + QSize(2, 50);
1093       emit preferredSizeChanged(pageViewerPreferredSize);
1094     }
1095   }
1096 }
1097 
1098 //-----------------------------------------------------------------------------
1099 
setScene(ToonzScene * scene)1100 void ParamViewer::setScene(ToonzScene *scene) {
1101   ParamsPageSet *paramsPageSet = getCurrentPageSet();
1102   if (!paramsPageSet) return;
1103   paramsPageSet->setScene(scene);
1104 }
1105 
1106 //-----------------------------------------------------------------------------
1107 
setIsCameraViewMode(bool isCameraViewMode)1108 void ParamViewer::setIsCameraViewMode(bool isCameraViewMode) {
1109   ParamsPageSet *paramsPageSet = getCurrentPageSet();
1110   if (!paramsPageSet) return;
1111   paramsPageSet->setIsCameraViewMode(isCameraViewMode);
1112 }
1113 
1114 //-----------------------------------------------------------------------------
1115 
update(int frame,bool onlyParam)1116 void ParamViewer::update(int frame, bool onlyParam) {
1117   ParamsPageSet *paramsPageSet = getCurrentPageSet();
1118   if (!paramsPageSet) return;
1119   paramsPageSet->updatePage(frame, onlyParam);
1120 }
1121 
1122 //-----------------------------------------------------------------------------
1123 
setPointValue(int index,const TPointD & p)1124 void ParamViewer::setPointValue(int index, const TPointD &p) {
1125   // Search the index-th param among all pages
1126   ParamsPageSet *pageSet = getCurrentPageSet();
1127   ParamsPage *page       = 0;
1128 
1129   for (int i = 0; i < pageSet->getParamsPageCount(); ++i) {
1130     page            = pageSet->getParamsPage(i);
1131     int paramsCount = page->m_fields.count();
1132 
1133     if (index <= paramsCount) break;
1134     index -= paramsCount;
1135   }
1136 
1137   if (page) page->setPointValue(index, p);
1138 }
1139 
1140 //-----------------------------------------------------------------------------
1141 
getCurrentPageSet() const1142 ParamsPageSet *ParamViewer::getCurrentPageSet() const {
1143   return dynamic_cast<ParamsPageSet *>(m_tablePageSet->currentWidget());
1144 }
1145 
1146 //=============================================================================
1147 // FxSettings
1148 //-----------------------------------------------------------------------------
1149 
FxSettings(QWidget * parent,const TPixel32 & checkCol1,const TPixel32 & checkCol2)1150 FxSettings::FxSettings(QWidget *parent, const TPixel32 &checkCol1,
1151                        const TPixel32 &checkCol2)
1152     : QSplitter(Qt::Vertical, parent)
1153     , m_frameHandle(0)
1154     , m_fxHandle(0)
1155     , m_xsheetHandle(0)
1156     , m_sceneHandle(0)
1157     , m_levelHandle(0)
1158     , m_objectHandle(0)
1159     , m_checkCol1(checkCol1)
1160     , m_checkCol2(checkCol2)
1161     , m_isCameraModeView(false)
1162     , m_container_height(184)
1163     , m_container_width(390) {
1164   // param viewer
1165   m_paramViewer = new ParamViewer(this);
1166   // swatch
1167   QWidget *swatchContainer = new QWidget(this);
1168   m_viewer                 = new SwatchViewer(swatchContainer);
1169   setWhiteBg();
1170   createToolBar();
1171 
1172   m_paramViewer->setMinimumHeight(50);
1173   swatchContainer->setSizePolicy(QSizePolicy::MinimumExpanding,
1174                                  QSizePolicy::MinimumExpanding);
1175 
1176   //---layout
1177   addWidget(m_paramViewer);
1178 
1179   QVBoxLayout *swatchLayout = new QVBoxLayout(swatchContainer);
1180   swatchLayout->setMargin(0);
1181   swatchLayout->setSpacing(0);
1182   {
1183     swatchLayout->addWidget(m_viewer, 0, Qt::AlignHCenter);
1184 
1185     QHBoxLayout *toolBarLayout = new QHBoxLayout(swatchContainer);
1186     {
1187       toolBarLayout->addWidget(m_toolBar, 0,
1188                                Qt::AlignHCenter | Qt::AlignBottom);
1189     }
1190     swatchLayout->addLayout(toolBarLayout);
1191   }
1192   swatchContainer->setLayout(swatchLayout);
1193 
1194   addWidget(swatchContainer);
1195 
1196   //---signal-slot connections
1197   bool ret = true;
1198   ret      = ret && connect(m_paramViewer, SIGNAL(currentFxParamChanged()),
1199                        SLOT(updateViewer()));
1200   ret = ret &&
1201         connect(m_viewer, SIGNAL(pointPositionChanged(int, const TPointD &)),
1202                 SLOT(onPointChanged(int, const TPointD &)));
1203   ret = ret && connect(m_paramViewer, SIGNAL(preferredSizeChanged(QSize)), this,
1204                        SLOT(onPreferredSizeChanged(QSize)));
1205   ret = ret && connect(m_paramViewer, SIGNAL(showSwatchButtonToggled(bool)),
1206                        this, SLOT(onShowSwatchButtonToggled(bool)));
1207   assert(ret);
1208 
1209   swatchContainer->hide();
1210 
1211   // Swatch updates should happen only at the end of a separator resize op.
1212   setStretchFactor(0, 1);
1213   setStretchFactor(1, 0);
1214   setOpaqueResize(false);
1215 }
1216 
1217 //-----------------------------------------------------------------------------
1218 
~FxSettings()1219 FxSettings::~FxSettings() {}
1220 
1221 //-----------------------------------------------------------------------------
1222 
setFxHandle(TFxHandle * fxHandle)1223 void FxSettings::setFxHandle(TFxHandle *fxHandle) {
1224   m_fxHandle = fxHandle;
1225   m_keyframeNavigator->setFxHandle(m_fxHandle);
1226 
1227   ParamField::setFxHandle(m_fxHandle);
1228 }
1229 
1230 //-----------------------------------------------------------------------------
1231 
setFrameHandle(TFrameHandle * frameHandle)1232 void FxSettings::setFrameHandle(TFrameHandle *frameHandle) {
1233   m_frameHandle = frameHandle;
1234   m_keyframeNavigator->setFrameHandle(m_frameHandle);
1235   m_frameNavigator->setFrameHandle(m_frameHandle);
1236 }
1237 
1238 //-----------------------------------------------------------------------------
1239 
setXsheetHandle(TXsheetHandle * xsheetHandle)1240 void FxSettings::setXsheetHandle(TXsheetHandle *xsheetHandle) {
1241   m_xsheetHandle = xsheetHandle;
1242 }
1243 
1244 //-----------------------------------------------------------------------------
1245 
setSceneHandle(TSceneHandle * sceneHandle)1246 void FxSettings::setSceneHandle(TSceneHandle *sceneHandle) {
1247   m_sceneHandle = sceneHandle;
1248   setCurrentScene();
1249 }
1250 
1251 //-----------------------------------------------------------------------------
1252 
setLevelHandle(TXshLevelHandle * levelHandle)1253 void FxSettings::setLevelHandle(TXshLevelHandle *levelHandle) {
1254   m_levelHandle = levelHandle;
1255 }
1256 
1257 //-----------------------------------------------------------------------------
1258 
setObjectHandle(TObjectHandle * objectHandle)1259 void FxSettings::setObjectHandle(TObjectHandle *objectHandle) {
1260   m_objectHandle = objectHandle;
1261 }
1262 
1263 //-----------------------------------------------------------------------------
1264 
createToolBar()1265 void FxSettings::createToolBar() {
1266   m_toolBar = new QToolBar(this);
1267   m_toolBar->setMovable(false);
1268   m_toolBar->setFixedHeight(24);
1269   m_toolBar->setIconSize(QSize(20, 20));
1270   m_toolBar->setObjectName("MediumPaddingToolBar");
1271   // m_toolBar->setSizePolicy(QSizePolicy::MinimumExpanding,
1272   // QSizePolicy::MinimumExpanding);
1273 
1274   // View mode
1275   QActionGroup *viewModeActGroup = new QActionGroup(m_toolBar);
1276   viewModeActGroup->setExclusive(false);
1277   // camera
1278   QIcon camera       = createQIcon("camera");
1279   QAction *cameraAct = new QAction(camera, tr("&Camera Preview"), m_toolBar);
1280   cameraAct->setCheckable(true);
1281   viewModeActGroup->addAction(cameraAct);
1282   m_toolBar->addAction(cameraAct);
1283   // preview
1284   QIcon preview       = createQIcon("preview");
1285   QAction *previewAct = new QAction(preview, tr("&Preview"), m_toolBar);
1286   previewAct->setCheckable(true);
1287   viewModeActGroup->addAction(previewAct);
1288   m_toolBar->addAction(previewAct);
1289   connect(viewModeActGroup, SIGNAL(triggered(QAction *)),
1290           SLOT(onViewModeChanged(QAction *)));
1291 
1292   m_toolBar->addSeparator();
1293 
1294   QActionGroup *viewModeGroup = new QActionGroup(m_toolBar);
1295   viewModeGroup->setExclusive(true);
1296 
1297   QAction *whiteBg = new QAction(createQIcon("preview_white"),
1298                                  tr("&White Background"), m_toolBar);
1299   whiteBg->setCheckable(true);
1300   whiteBg->setChecked(true);
1301   viewModeGroup->addAction(whiteBg);
1302   connect(whiteBg, SIGNAL(triggered()), this, SLOT(setWhiteBg()));
1303   m_toolBar->addAction(whiteBg);
1304 
1305   QAction *blackBg = new QAction(createQIcon("preview_black"),
1306                                  tr("&Black Background"), m_toolBar);
1307   blackBg->setCheckable(true);
1308   viewModeGroup->addAction(blackBg);
1309   connect(blackBg, SIGNAL(triggered()), this, SLOT(setBlackBg()));
1310   m_toolBar->addAction(blackBg);
1311 
1312   m_checkboardBg = new QAction(createQIcon("preview_checkboard"),
1313                                tr("&Checkered Background"), m_toolBar);
1314   m_checkboardBg->setCheckable(true);
1315   viewModeGroup->addAction(m_checkboardBg);
1316   connect(m_checkboardBg, SIGNAL(triggered()), this, SLOT(setCheckboardBg()));
1317   m_toolBar->addAction(m_checkboardBg);
1318 
1319   m_toolBar->addSeparator();
1320 
1321   m_keyframeNavigator = new FxKeyframeNavigator(m_toolBar);
1322   m_toolBar->addWidget(m_keyframeNavigator);
1323 
1324   m_toolBar->addSeparator();
1325 
1326   m_frameNavigator = new FrameNavigator(m_toolBar);
1327   m_frameNavigator->setFrameHandle(m_frameHandle);
1328   m_toolBar->addWidget(m_frameNavigator);
1329 }
1330 
1331 //-----------------------------------------------------------------------------
1332 
setFx(const TFxP & currentFx,const TFxP & actualFx)1333 void FxSettings::setFx(const TFxP &currentFx, const TFxP &actualFx) {
1334   // disconnecting from the fxChanged() signals avoid useless and dangerous
1335   // updates!!!
1336   if (m_fxHandle)
1337     disconnect(m_fxHandle, SIGNAL(fxChanged()), this,
1338                SLOT(updateParamViewer()));
1339 
1340   TFxP currentFxWithoutCamera = 0;
1341   if (currentFx && actualFx)
1342     currentFxWithoutCamera = getCurrentFx(currentFx, actualFx->getFxId());
1343 
1344   if (currentFxWithoutCamera)
1345     TFxUtil::setKeyframe(currentFxWithoutCamera, m_frameHandle->getFrameIndex(),
1346                          actualFx, m_frameHandle->getFrameIndex());
1347 
1348   ToonzScene *scene        = 0;
1349   if (m_sceneHandle) scene = m_sceneHandle->getScene();
1350 
1351   int frameIndex                = 0;
1352   if (m_frameHandle) frameIndex = m_frameHandle->getFrameIndex();
1353 
1354   m_paramViewer->setFx(currentFxWithoutCamera, actualFx, frameIndex, scene);
1355   m_paramViewer->setIsCameraViewMode(m_isCameraModeView);
1356   m_viewer->setCameraMode(m_isCameraModeView);
1357 
1358   TDimension cameraSize = TDimension(-1, -1);
1359   if (scene) cameraSize = scene->getCurrentCamera()->getRes();
1360   m_viewer->setCameraSize(cameraSize);
1361 
1362   m_viewer->setFx(currentFx, actualFx, frameIndex);
1363 
1364   if (m_fxHandle)
1365     connect(m_fxHandle, SIGNAL(fxChanged()), this, SLOT(updateParamViewer()));
1366 }
1367 
1368 //-----------------------------------------------------------------------------
1369 
setCurrentFrame()1370 void FxSettings::setCurrentFrame() {
1371   int frame = m_frameHandle->getFrameIndex();
1372   m_paramViewer->update(frame, false);
1373 
1374   // if(m_isCameraModeView)
1375   setCurrentFx();
1376   m_viewer->updateFrame(frame);
1377 }
1378 
1379 //-----------------------------------------------------------------------------
1380 
changeTitleBar(TFx * fx)1381 void FxSettings::changeTitleBar(TFx *fx) {
1382   DockWidget *popup = dynamic_cast<DockWidget *>(parentWidget());
1383   if (!popup) return;
1384 
1385   QString titleText(tr("Fx Settings"));
1386   if (fx) {
1387     titleText += tr(" : ");
1388     titleText += QString::fromStdWString(fx->getName());
1389   }
1390 
1391   popup->setWindowTitle(titleText);
1392 }
1393 
1394 //-----------------------------------------------------------------------------
1395 
setCurrentFx()1396 void FxSettings::setCurrentFx() {
1397   TFx *currFx = m_fxHandle->getFx();
1398 
1399   TFxP actualFx, currentFx;
1400   if (!currFx || 0 != dynamic_cast<TXsheetFx *>(currFx)) {
1401     actualFx = currentFx = TFxP();
1402     setFx(actualFx, currentFx);
1403     changeTitleBar(currentFx.getPointer());
1404     return;
1405   }
1406   TFxP fx(currFx);
1407   bool hasEmptyInput = false;
1408   if (TZeraryColumnFx *zfx = dynamic_cast<TZeraryColumnFx *>(fx.getPointer()))
1409     fx = zfx->getZeraryFx();
1410   else
1411     hasEmptyInput   = hasEmptyInputPort(fx);
1412   int frame         = m_frameHandle->getFrame();
1413   ToonzScene *scene = m_sceneHandle->getScene();
1414   actualFx          = fx;
1415   bool isEnabled    = actualFx->getAttributes()->isEnabled();
1416   actualFx->getAttributes()->enable(true);
1417   if (hasEmptyInput)
1418     currentFx = actualFx;
1419   else if (m_viewer->isEnabled()) {
1420     if (!m_isCameraModeView)
1421       currentFx = buildSceneFx(scene, frame, actualFx, false);
1422     else {
1423       const TRenderSettings rs =
1424           scene->getProperties()->getPreviewProperties()->getRenderSettings();
1425       currentFx = buildPartialSceneFx(scene, (double)frame, actualFx, 1, false);
1426     }
1427   } else
1428     currentFx = TFxP();
1429 
1430   if (currentFx) currentFx = currentFx->clone(true);
1431 
1432   // se al frame corrente non c'e' il livello a cui e' applicato l'effetto:
1433   // current=0, actual!=0
1434   if (!currentFx) currentFx = actualFx->clone(false);
1435 
1436   actualFx->getAttributes()->enable(isEnabled);
1437   setFx(currentFx, actualFx);
1438   changeTitleBar(currentFx.getPointer());
1439 }
1440 
1441 //-----------------------------------------------------------------------------
1442 
setCurrentScene()1443 void FxSettings::setCurrentScene() {
1444   ToonzScene *scene = m_sceneHandle->getScene();
1445   m_paramViewer->setScene(scene);
1446 }
1447 
1448 //-----------------------------------------------------------------------------
1449 
notifySceneChanged()1450 void FxSettings::notifySceneChanged() {
1451   TPixel32 col1, col2;
1452   Preferences::instance()->getChessboardColors(col1, col2);
1453   setCheckboardColors(col1, col2);
1454 }
1455 
1456 //-----------------------------------------------------------------------------
1457 
showEvent(QShowEvent * event)1458 void FxSettings::showEvent(QShowEvent *event) {
1459   setCurrentFx();
1460   setCurrentFrame();
1461   connect(m_frameHandle, SIGNAL(frameSwitched()), SLOT(setCurrentFrame()));
1462   if (m_fxHandle) {
1463     connect(m_paramViewer, SIGNAL(actualFxParamChanged()), m_fxHandle,
1464             SIGNAL(fxChanged()));
1465     connect(m_fxHandle, SIGNAL(fxChanged()), SLOT(updateParamViewer()));
1466     connect(m_fxHandle, SIGNAL(fxSettingsShouldBeSwitched()),
1467             SLOT(setCurrentFx()));
1468   }
1469   if (m_sceneHandle) {
1470     connect(m_sceneHandle, SIGNAL(sceneChanged()), this,
1471             SLOT(notifySceneChanged()));
1472     connect(m_sceneHandle, SIGNAL(sceneSwitched()), this,
1473             SLOT(setCurrentScene()));
1474   }
1475   if (m_xsheetHandle)
1476     connect(m_xsheetHandle, SIGNAL(xsheetChanged()), SLOT(setCurrentFx()));
1477   if (m_levelHandle)
1478     connect(m_levelHandle, SIGNAL(xshLevelChanged()), SLOT(setCurrentFx()));
1479   if (m_objectHandle)
1480     connect(m_objectHandle, SIGNAL(objectChanged(bool)), SLOT(setCurrentFx()));
1481 }
1482 
1483 //-----------------------------------------------------------------------------
1484 
hideEvent(QHideEvent *)1485 void FxSettings::hideEvent(QHideEvent *) {
1486   setFx(0, 0);
1487   disconnect(m_frameHandle, SIGNAL(frameSwitched()), this,
1488              SLOT(setCurrentFrame()));
1489   if (m_fxHandle) {
1490     disconnect(m_fxHandle, SIGNAL(fxChanged()), this, SLOT(setCurrentFx()));
1491     disconnect(m_fxHandle, SIGNAL(fxChanged()), this,
1492                SLOT(updateParamViewer()));
1493     disconnect(m_fxHandle, SIGNAL(fxSettingsShouldBeSwitched()), this,
1494                SLOT(setCurrentFx()));
1495   }
1496   if (m_sceneHandle) {
1497     disconnect(m_sceneHandle, SIGNAL(sceneChanged()), this,
1498                SLOT(notifySceneChanged()));
1499     disconnect(m_sceneHandle, SIGNAL(sceneSwitched()), this,
1500                SLOT(setCurrentScene()));
1501   }
1502   if (m_xsheetHandle)
1503     disconnect(m_xsheetHandle, SIGNAL(xsheetChanged()), this,
1504                SLOT(setCurrentFx()));
1505   if (m_levelHandle)
1506     disconnect(m_levelHandle, SIGNAL(xshLevelChanged()), this,
1507                SLOT(setCurrentFx()));
1508   if (m_objectHandle)
1509     disconnect(m_objectHandle, SIGNAL(objectChanged(bool)), this,
1510                SLOT(setCurrentFx()));
1511 }
1512 
1513 //-----------------------------------------------------------------------------
1514 
setCheckboardColors(const TPixel32 & col1,const TPixel32 & col2)1515 void FxSettings::setCheckboardColors(const TPixel32 &col1,
1516                                      const TPixel32 &col2) {
1517   m_checkCol1 = col1;
1518   m_checkCol2 = col2;
1519   if (m_checkboardBg->isChecked())
1520     m_viewer->setBgPainter(m_checkCol1, m_checkCol2);
1521 }
1522 
1523 //-----------------------------------------------------------------------------
1524 
setWhiteBg()1525 void FxSettings::setWhiteBg() { m_viewer->setBgPainter(TPixel32::White); }
1526 
1527 //-----------------------------------------------------------------------------
1528 
setBlackBg()1529 void FxSettings::setBlackBg() { m_viewer->setBgPainter(TPixel32::Black); }
1530 
1531 //-----------------------------------------------------------------------------
1532 
setCheckboardBg()1533 void FxSettings::setCheckboardBg() {
1534   m_viewer->setBgPainter(m_checkCol1, m_checkCol2);
1535 }
1536 
1537 //-----------------------------------------------------------------------------
1538 
updateViewer()1539 void FxSettings::updateViewer() {
1540   if (m_viewer->isEnabled())
1541     m_viewer->updateFrame(m_frameHandle->getFrameIndex());
1542 }
1543 
1544 //-----------------------------------------------------------------------------
1545 
updateParamViewer()1546 void FxSettings::updateParamViewer() {
1547   if (!m_paramViewer || !m_frameHandle) return;
1548   m_paramViewer->update(m_frameHandle->getFrameIndex(), true);
1549 }
1550 
1551 //-----------------------------------------------------------------------------
1552 
onPointChanged(int index,const TPointD & p)1553 void FxSettings::onPointChanged(int index, const TPointD &p) {
1554   m_paramViewer->setPointValue(index, p);
1555 }
1556 
1557 //-----------------------------------------------------------------------------
1558 
onViewModeChanged(QAction * triggeredAct)1559 void FxSettings::onViewModeChanged(QAction *triggeredAct) {
1560   setFocus();
1561   QString name             = triggeredAct->text();
1562   bool actIsChecked        = triggeredAct->isChecked();
1563   QList<QAction *> actions = m_toolBar->actions();
1564   QAction *cameraAct       = actions[0];
1565   QAction *previewAct      = actions[1];
1566   if (name == previewAct->text()) {
1567     if (cameraAct->isChecked()) cameraAct->setChecked(false);
1568     if (actIsChecked) {
1569       m_isCameraModeView = false;
1570       m_paramViewer->setIsCameraViewMode(false);
1571       setCurrentFx();
1572     }
1573     m_viewer->setEnable(actIsChecked);
1574   } else if (name == cameraAct->text()) {
1575     if (previewAct->isChecked()) previewAct->setChecked(false);
1576     if (actIsChecked) {
1577       m_isCameraModeView = true;
1578       m_paramViewer->setIsCameraViewMode(true);
1579       setCurrentFx();
1580     }
1581     m_viewer->setEnable(actIsChecked);
1582   }
1583 }
1584 
1585 //-----------------------------------------------------------------------------
1586 
onPreferredSizeChanged(QSize pvBestSize)1587 void FxSettings::onPreferredSizeChanged(QSize pvBestSize) {
1588   QSize popupBestSize = pvBestSize;
1589 
1590   // Set minimum size, just in case
1591   popupBestSize.setHeight(std::max(popupBestSize.height(), 85));
1592   popupBestSize.setWidth(std::max(popupBestSize.width(), 390));
1593 
1594   if (m_toolBar->isVisible()) {
1595     popupBestSize += QSize(0, m_viewer->height() + m_toolBar->height() + 4);
1596     popupBestSize.setWidth(
1597         std::max(popupBestSize.width(), m_viewer->width() + 13));
1598   }
1599 
1600   DockWidget *popup = dynamic_cast<DockWidget *>(parentWidget());
1601   if (popup && popup->isFloating()) {
1602     QRect geom = popup->geometry();
1603     geom.setSize(popupBestSize);
1604     popup->setGeometry(geom);
1605     popup->update();
1606   }
1607 }
1608 
1609 //-----------------------------------------------------------------------------
1610 
onShowSwatchButtonToggled(bool on)1611 void FxSettings::onShowSwatchButtonToggled(bool on) {
1612   QWidget *bottomContainer = widget(1);
1613 
1614   if (!on) {
1615     m_container_height =
1616         bottomContainer->height() + handleWidth() /* ハンドル幅 */;
1617     m_container_width = m_viewer->width() + 13;
1618   }
1619   bottomContainer->setVisible(on);
1620 
1621   DockWidget *popup = dynamic_cast<DockWidget *>(parentWidget());
1622   if (popup && popup->isFloating()) {
1623     QRect geom = popup->geometry();
1624 
1625     int height_change = (on) ? m_container_height : -m_container_height;
1626     int width_change  = 0;
1627 
1628     if (on && m_container_width > geom.width())
1629       width_change = m_container_width - geom.width();
1630 
1631     geom.setSize(geom.size() + QSize(width_change, height_change));
1632     popup->setGeometry(geom);
1633     popup->update();
1634   }
1635 }
1636 
1637 //-----------------------------------------------------------------------------
1638