From a266be7a5bd9a932ea1df2d39d0848914a70cbbc Mon Sep 17 00:00:00 2001 From: shun-iwasawa Date: Tue, 27 Sep 2022 16:56:45 +0900 Subject: [PATCH 1/2] customizable column color filters --- toonz/sources/include/toonz/sceneproperties.h | 18 ++ toonz/sources/include/toonz/txshcolumn.h | 24 +- toonz/sources/toonz/scenesettingspopup.cpp | 237 +++++++++++++++++- toonz/sources/toonz/scenesettingspopup.h | 20 ++ toonz/sources/toonz/xshcolumnviewer.cpp | 50 ++-- toonz/sources/toonz/xshcolumnviewer.h | 2 +- toonz/sources/toonzlib/scenefx.cpp | 11 +- toonz/sources/toonzlib/sceneproperties.cpp | 71 ++++++ toonz/sources/toonzlib/stage.cpp | 13 +- toonz/sources/toonzlib/txshcolumn.cpp | 40 +-- toonz/sources/toonzlib/txshlevelcolumn.cpp | 8 +- toonz/sources/toonzlib/txshmeshcolumn.cpp | 2 +- 12 files changed, 406 insertions(+), 90 deletions(-) diff --git a/toonz/sources/include/toonz/sceneproperties.h b/toonz/sources/include/toonz/sceneproperties.h index c1a258d213..39639c2632 100644 --- a/toonz/sources/include/toonz/sceneproperties.h +++ b/toonz/sources/include/toonz/sceneproperties.h @@ -58,6 +58,14 @@ class DVAPI TSceneProperties { } }; + struct ColorFilter { + QString name; + TPixel32 color; + bool operator==(const ColorFilter &cf) { + return name == cf.name && color == cf.color; + } + }; + private: Guides m_hGuides, m_vGuides; @@ -86,6 +94,9 @@ class DVAPI TSceneProperties { // Cell Mark colors and names QList m_cellMarks; + // Color Filter colors and names + QList m_colorFilters; + bool m_columnColorFilterOnRender; TFilePath m_camCapSaveInPath; @@ -297,6 +308,13 @@ and height. bool hasDefaultCellMarks() const; // check if the cell mark settings are modified + QList getColorFilters() const; + ColorFilter getColorFilter(int index) const; + TPixel32 getColorFilterColor(int index) const; + void setColorFilter(const ColorFilter &filter, int index); + bool hasDefaultColorFilters() + const; // check if the color filter settings are modified + // templateFId in preview settings is used for "input" file format // such as new raster level, captured images by camera capture feature, etc. TFrameId &formatTemplateFIdForInput(); diff --git a/toonz/sources/include/toonz/txshcolumn.h b/toonz/sources/include/toonz/txshcolumn.h index 3f75975907..e1a5fcc8b7 100644 --- a/toonz/sources/include/toonz/txshcolumn.h +++ b/toonz/sources/include/toonz/txshcolumn.h @@ -69,19 +69,8 @@ class DVAPI TXshColumn : public TColumnHeader, public TPersist { UCHAR m_opacity; public: - enum FilterColor { - FilterNone = 0, - FilterRed, - FilterGreen, - FilterBlue, - FilterDarkYellow, - FilterDarkCyan, - FilterDarkMagenta, - FilterAmount - }; - private: - FilterColor m_filterColorId; + int m_colorFilterId; protected: enum { @@ -114,7 +103,8 @@ Constructs a TXshColumn with default value. , m_xsheet(0) , m_colorTag(0) , m_opacity(255) - , m_filterColorId(FilterNone) {} + , m_colorFilterId(0) // None + {} enum ColumnType { eLevelType = 0, @@ -264,12 +254,8 @@ Set column color tag to \b colorTag. m_colorTag = colorTag; } // Usato solo in tabkids - FilterColor getFilterColorId() const { return m_filterColorId; } - void setFilterColorId(FilterColor id) { m_filterColorId = id; } - TPixel32 getFilterColor(); - static QPair getFilterInfo(FilterColor key); - static void initColorFilters(); - + int getColorFilterId() const { return m_colorFilterId; } + void setColorFilterId(int id) { m_colorFilterId = id; } void resetColumnProperties(); }; diff --git a/toonz/sources/toonz/scenesettingspopup.cpp b/toonz/sources/toonz/scenesettingspopup.cpp index b3bddb526e..cc790b4df6 100644 --- a/toonz/sources/toonz/scenesettingspopup.cpp +++ b/toonz/sources/toonz/scenesettingspopup.cpp @@ -9,6 +9,7 @@ // TnzQt includes #include "toonzqt/menubarcommand.h" +#include "toonzqt/gutil.h" // TnzLib includes #include "toonz/txsheet.h" @@ -84,6 +85,46 @@ class EditCellMarkUndo final : public TUndo { } }; +//----------------------------------------------------------------------------- + +class EditColorFilterUndo final : public TUndo { + int m_id; + TSceneProperties::ColorFilter m_filterBefore, m_filterAfter; + ColorFiltersPopup *m_popup; + +public: + EditColorFilterUndo(int id, TPixel32 color, QString name, + ColorFiltersPopup *popup) + : m_id(id), m_popup(popup) { + m_filterBefore = TApp::instance() + ->getCurrentScene() + ->getScene() + ->getProperties() + ->getColorFilter(id); + m_filterAfter = {name, color}; + } + + void set(const TSceneProperties::ColorFilter &filter) const { + TApp::instance() + ->getCurrentScene() + ->getScene() + ->getProperties() + ->setColorFilter(filter, m_id); + m_popup->updateContents(); + TApp::instance()->getCurrentScene()->notifySceneChanged(); + } + + void undo() const override { set(m_filterBefore); } + + void redo() const override { set(m_filterAfter); } + + int getSize() const override { return sizeof *this; } + + QString getHistoryString() override { + return QObject::tr("Edit Color Filter #%1").arg(QString::number(m_id)); + } +}; + //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- } // namespace @@ -235,12 +276,190 @@ void CellMarksPopup::onNameChanged() { TUndoManager::manager()->add(undo); } +//============================================================================= +// ColorFiltersPopup +//----------------------------------------------------------------------------- + +ColorFiltersPopup::ColorFiltersPopup(QWidget *parent) : QDialog(parent) { + setWindowTitle(tr("Color Filters Settings")); + + QList filters = TApp::instance() + ->getCurrentScene() + ->getScene() + ->getProperties() + ->getColorFilters(); + + QGridLayout *layout = new QGridLayout(); + layout->setMargin(10); + layout->setHorizontalSpacing(5); + layout->setVerticalSpacing(10); + { + int id = 0; + for (auto filter : filters) { + // skip filter#0 (None) + if (id == 0) { + id++; + continue; + } + ColorField *colorF = new ColorField(this, false, filter.color, 20); + colorF->hideChannelsFields(true); + QLineEdit *nameF = new QLineEdit(filter.name, this); + QPushButton *clearBtn = new QPushButton(this); + clearBtn->setFixedSize(20, 20); + clearBtn->setToolTip(tr("Clear")); + clearBtn->setIcon(createQIcon("delete")); + clearBtn->setFocusPolicy(Qt::NoFocus); + clearBtn->setDisabled(filter.name.isEmpty()); + + m_fields.insert(id, {colorF, nameF, clearBtn}); + + int row = layout->rowCount(); + + layout->addWidget(colorF, row, 0); + layout->addWidget(nameF, row, 1); + layout->addWidget(clearBtn, row, 2); + + connect(colorF, SIGNAL(colorChanged(const TPixel32 &, bool)), this, + SLOT(onColorChanged(const TPixel32 &, bool))); + connect(nameF, SIGNAL(editingFinished()), this, SLOT(onNameChanged())); + connect(clearBtn, SIGNAL(clicked()), this, SLOT(onClearButtonClicked())); + id++; + } + } + layout->setColumnStretch(1, 1); + setLayout(layout); +} + +void ColorFiltersPopup::updateContents() { + QList filters = TApp::instance() + ->getCurrentScene() + ->getScene() + ->getProperties() + ->getColorFilters(); + assert(filters.count() == m_fields.count() + 1); + int id = 0; + for (const auto &filter : filters) { + // skip filter#0 (None) + if (id == 0) { + id++; + continue; + } + assert(m_fields.contains(id)); + m_fields[id].colorField->setColor(filter.color); + m_fields[id].nameField->setText(filter.name); + m_fields[id].clearBtn->setDisabled(filter.name.isEmpty()); + id++; + } +} + +void ColorFiltersPopup::onColorChanged(const TPixel32 &color, bool isDragging) { + if (isDragging) return; + // obtain id + int id = -1; + ColorField *colorF = qobject_cast(sender()); + for (const int keyId : m_fields.keys()) { + if (m_fields[keyId].colorField == colorF) { + id = keyId; + break; + } + } + if (id <= 0) return; + + // return if the value is unchanged + TSceneProperties::ColorFilter oldCF = TApp::instance() + ->getCurrentScene() + ->getScene() + ->getProperties() + ->getColorFilter(id); + if (color == oldCF.color) return; + + QString name = oldCF.name; + if (name.isEmpty()) { + name = tr("Color Filter %1").arg(id); + m_fields[id].nameField->setText(name); + m_fields[id].clearBtn->setEnabled(true); + } + + EditColorFilterUndo *undo = new EditColorFilterUndo(id, color, name, this); + undo->redo(); + TUndoManager::manager()->add(undo); +} + +void ColorFiltersPopup::onNameChanged() { + // obtain id + int id = -1; + QLineEdit *nameF = qobject_cast(sender()); + for (const int keyId : m_fields.keys()) { + if (m_fields[keyId].nameField == nameF) { + id = keyId; + break; + } + } + if (id <= 0) return; + + // return if the value is unchanged + TSceneProperties::ColorFilter oldCF = TApp::instance() + ->getCurrentScene() + ->getScene() + ->getProperties() + ->getColorFilter(id); + if (nameF->text() == oldCF.name) return; + // reject empty string + if (nameF->text().isEmpty()) { + nameF->setText(oldCF.name); + return; + } + + TPixel32 color = oldCF.color; + if (oldCF.name.isEmpty()) { + color = TPixel::Red; + m_fields[id].colorField->setColor(color); + m_fields[id].clearBtn->setEnabled(true); + } + + EditColorFilterUndo *undo = + new EditColorFilterUndo(id, color, nameF->text(), this); + undo->redo(); + TUndoManager::manager()->add(undo); +} + +void ColorFiltersPopup::onClearButtonClicked() { + // obtain id + int id = -1; + QPushButton *clearBtn = qobject_cast(sender()); + for (const int keyId : m_fields.keys()) { + if (m_fields[keyId].clearBtn == clearBtn) { + id = keyId; + break; + } + } + if (id <= 0) return; + + // return if the value is unchanged + TSceneProperties::ColorFilter oldCF = TApp::instance() + ->getCurrentScene() + ->getScene() + ->getProperties() + ->getColorFilter(id); + if (oldCF.name.isEmpty()) return; + + m_fields[id].colorField->setColor(TPixel::Black); + m_fields[id].nameField->setText(""); + m_fields[id].clearBtn->setEnabled(false); + + EditColorFilterUndo *undo = + new EditColorFilterUndo(id, TPixel::Black, "", this); + undo->redo(); + TUndoManager::manager()->add(undo); +} //============================================================================= // SceneSettingsPopup //----------------------------------------------------------------------------- SceneSettingsPopup::SceneSettingsPopup() - : QDialog(TApp::instance()->getMainWindow()), m_cellMarksPopup(nullptr) { + : QDialog(TApp::instance()->getMainWindow()) + , m_cellMarksPopup(nullptr) + , m_colorFiltersPopup(nullptr) { setWindowTitle(tr("Scene Settings")); setObjectName("SceneSettings"); TSceneProperties *sprop = getProperties(); @@ -285,6 +504,9 @@ SceneSettingsPopup::SceneSettingsPopup() QPushButton *editCellMarksButton = new QPushButton(tr("Edit Cell Marks"), this); + QPushButton *editColorFiltersButton = + new QPushButton(tr("Edit Column Color Filters"), this); + // layout QGridLayout *mainLayout = new QGridLayout(); mainLayout->setMargin(10); @@ -327,6 +549,8 @@ SceneSettingsPopup::SceneSettingsPopup() // Use Color Filter and Transparency for Rendering mainLayout->addWidget(m_colorFilterOnRenderCB, 6, 0, 1, 4); + mainLayout->addWidget(editColorFiltersButton, 6, 4, + Qt::AlignRight | Qt::AlignVCenter); // cell marks mainLayout->addWidget(new QLabel(tr("Cell Marks:"), this), 7, 0, @@ -371,6 +595,9 @@ SceneSettingsPopup::SceneSettingsPopup() // Use Color Filter and Transparency for Rendering ret = ret && connect(m_colorFilterOnRenderCB, SIGNAL(stateChanged(int)), this, SLOT(onColorFilterOnRenderChanged())); + ret = ret && connect(editColorFiltersButton, SIGNAL(clicked()), this, + SLOT(onEditColorFiltersButtonClicked())); + // Cell Marks ret = ret && connect(editCellMarksButton, SIGNAL(clicked()), this, SLOT(onEditCellMarksButtonClicked())); @@ -429,6 +656,7 @@ void SceneSettingsPopup::update() { sprop->isColumnColorFilterOnRenderEnabled()); if (m_cellMarksPopup) m_cellMarksPopup->update(); + if (m_colorFiltersPopup) m_colorFiltersPopup->updateContents(); } //----------------------------------------------------------------------------- @@ -530,6 +758,13 @@ void SceneSettingsPopup::onColorFilterOnRenderChanged() { //----------------------------------------------------------------------------- +void SceneSettingsPopup::onEditColorFiltersButtonClicked() { + if (!m_colorFiltersPopup) m_colorFiltersPopup = new ColorFiltersPopup(this); + m_colorFiltersPopup->show(); + m_colorFiltersPopup->raise(); +} +//----------------------------------------------------------------------------- + void SceneSettingsPopup::onEditCellMarksButtonClicked() { if (!m_cellMarksPopup) m_cellMarksPopup = new CellMarksPopup(this); m_cellMarksPopup->show(); diff --git a/toonz/sources/toonz/scenesettingspopup.h b/toonz/sources/toonz/scenesettingspopup.h index 7ea1756eb1..fcfd520bbb 100644 --- a/toonz/sources/toonz/scenesettingspopup.h +++ b/toonz/sources/toonz/scenesettingspopup.h @@ -33,6 +33,24 @@ protected slots: void onNameChanged(); }; +class ColorFiltersPopup final : public QDialog { + Q_OBJECT + struct FilterField { + DVGui::ColorField *colorField; + QLineEdit *nameField; + QPushButton *clearBtn; + }; + + QMap m_fields; + +public: + ColorFiltersPopup(QWidget *parent); + void updateContents(); +protected slots: + void onColorChanged(const TPixel32 &, bool); + void onNameChanged(); + void onClearButtonClicked(); +}; //============================================================================= // SceneSettingsPopup //----------------------------------------------------------------------------- @@ -57,6 +75,7 @@ class SceneSettingsPopup final : public QDialog { TSceneProperties *getProperties() const; CellMarksPopup *m_cellMarksPopup; + ColorFiltersPopup *m_colorFiltersPopup; DVGui::DoubleLineEdit *m_colorSpaceGammaFld; @@ -85,6 +104,7 @@ public slots: void onColorFilterOnRenderChanged(); void onEditCellMarksButtonClicked(); + void onEditColorFiltersButtonClicked(); }; #endif // SCENESETTINGSPOPUP_H diff --git a/toonz/sources/toonz/xshcolumnviewer.cpp b/toonz/sources/toonz/xshcolumnviewer.cpp index bd86e0eac7..ca2cc4b1d8 100644 --- a/toonz/sources/toonz/xshcolumnviewer.cpp +++ b/toonz/sources/toonz/xshcolumnviewer.cpp @@ -1321,15 +1321,20 @@ void ColumnArea::DrawHeader::drawParentHandleName() const { } void ColumnArea::DrawHeader::drawFilterColor() const { - if (col < 0 || isEmpty || !column->getFilterColorId() || + if (col < 0 || isEmpty || column->getColorFilterId() == 0 || column->getSoundColumn() || column->getSoundTextColumn() || column->getPaletteColumn()) return; + TPixel32 filterColor = TApp::instance() + ->getCurrentScene() + ->getScene() + ->getProperties() + ->getColorFilterColor(column->getColorFilterId()); + QRect filterColorRect = o->rect(PredefinedRect::FILTER_COLOR).translated(orig); - p.drawPixmap(filterColorRect, - getColorChipIcon(column->getFilterColor()).pixmap(12, 12)); + p.drawPixmap(filterColorRect, getColorChipIcon(filterColor).pixmap(12, 12)); } void ColumnArea::DrawHeader::drawSoundIcon(bool isPlaying) const { @@ -1925,15 +1930,8 @@ m_value->setFixedWidth(30); static QFont font("Helvetica", 7, QFont::Normal); m_value->setFont(font);*/ + // contents of the combo box will be updated in setColumn m_filterColorCombo = new QComboBox(this); - for (int f = 0; f < (int)TXshColumn::FilterAmount; f++) { - QPair info = - TXshColumn::getFilterInfo((TXshColumn::FilterColor)f); - if ((TXshColumn::FilterColor)f == TXshColumn::FilterNone) - m_filterColorCombo->addItem(info.first, f); - else - m_filterColorCombo->addItem(getColorChipIcon(info.second), info.first, f); - } // Lock button is moved in the popup for Minimum layout QPushButton *lockExtraBtn = nullptr; @@ -2000,7 +1998,7 @@ m_value->setFont(font);*/ SLOT(onValueChanged(const QString &))); ret = ret && connect(m_filterColorCombo, SIGNAL(activated(int)), this, - SLOT(onFilterColorChanged(int))); + SLOT(onFilterColorChanged())); if (m_lockBtn) ret = ret && connect(m_lockBtn, SIGNAL(clicked(bool)), this, SLOT(onLockButtonClicked(bool))); @@ -2045,9 +2043,11 @@ void ColumnTransparencyPopup::onValueChanged(const QString &str) { } //---------------------------------------------------------------- - -void ColumnTransparencyPopup::onFilterColorChanged(int id) { - m_column->setFilterColorId((TXshColumn::FilterColor)id); +// TODO : UNDO +void ColumnTransparencyPopup::onFilterColorChanged() { + int id = m_filterColorCombo->currentData().toInt(); + if (m_column->getColorFilterId() == id) return; + m_column->setColorFilterId(id); TApp::instance()->getCurrentScene()->notifySceneChanged(); TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); ((ColumnArea *)parent())->update(); @@ -2076,7 +2076,25 @@ void ColumnTransparencyPopup::setColumn(TXshColumn *column) { connect(m_value, SIGNAL(textChanged(const QString &)), this, SLOT(onValueChanged(const QString &))); - m_filterColorCombo->setCurrentIndex(m_column->getFilterColorId()); + m_filterColorCombo->clear(); + // initialize color filter combo box + QList filters = TApp::instance() + ->getCurrentScene() + ->getScene() + ->getProperties() + ->getColorFilters(); + + for (int f = 0; f < filters.size(); f++) { + TSceneProperties::ColorFilter filter = filters.at(f); + if (f == 0) + m_filterColorCombo->addItem(filter.name, f); + else if (!filter.name.isEmpty()) + m_filterColorCombo->addItem(getColorChipIcon(filter.color), filter.name, + f); + } + + m_filterColorCombo->setCurrentIndex( + m_filterColorCombo->findData(m_column->getColorFilterId())); if (m_lockBtn) m_lockBtn->setChecked(m_column->isLocked()); } diff --git a/toonz/sources/toonz/xshcolumnviewer.h b/toonz/sources/toonz/xshcolumnviewer.h index e30b8b334d..bad711f511 100644 --- a/toonz/sources/toonz/xshcolumnviewer.h +++ b/toonz/sources/toonz/xshcolumnviewer.h @@ -236,7 +236,7 @@ protected slots: void onSliderValueChanged(int); void onValueChanged(const QString &); - void onFilterColorChanged(int id); + void onFilterColorChanged(); void onLockButtonClicked(bool on); }; diff --git a/toonz/sources/toonzlib/scenefx.cpp b/toonz/sources/toonzlib/scenefx.cpp index 54ce9c4d90..1bf5468943 100644 --- a/toonz/sources/toonzlib/scenefx.cpp +++ b/toonz/sources/toonzlib/scenefx.cpp @@ -972,11 +972,14 @@ PlacedFx FxBuilder::makePF(TLevelColumnFx *lcfx) { // Apply column's color filter and semi-transparency for rendering TXshLevelColumn *column = lcfx->getColumn(); if (m_scene->getProperties()->isColumnColorFilterOnRenderEnabled() && - (column->getFilterColorId() != TXshColumn::FilterNone || + (column->getColorFilterId() != 0 || // None (column->isCamstandVisible() && column->getOpacity() != 255))) { - TPixel32 colorScale = column->getFilterColor(); - colorScale.m = column->getOpacity(); - pf.m_fx = TFxUtil::makeColumnColorFilter(pf.m_fx, colorScale); + TPixel32 colorScale = m_scene->getProperties()->getColorFilterColor( + column->getColorFilterId()); + if (colorScale != TPixel::Black) { + colorScale.m = column->getOpacity(); + pf.m_fx = TFxUtil::makeColumnColorFilter(pf.m_fx, colorScale); + } } return pf; diff --git a/toonz/sources/toonzlib/sceneproperties.cpp b/toonz/sources/toonzlib/sceneproperties.cpp index af188368cb..56e5290cf0 100644 --- a/toonz/sources/toonzlib/sceneproperties.cpp +++ b/toonz/sources/toonzlib/sceneproperties.cpp @@ -40,6 +40,21 @@ const QList getDefaultCellMarks() { {QObject::tr("Dark Pink"), TPixel32(111, 29, 108)}, {QObject::tr("White"), TPixel32(255, 255, 255)}}; } + +const QList getDefaultColorFilters() { + return QList{ + {QObject::tr("None"), TPixel::Black}, // not editable + {QObject::tr("Red"), TPixel::Red}, + {QObject::tr("Green"), TPixel::Green}, + {QObject::tr("Blue"), TPixel::Blue}, + {QObject::tr("DarkYellow"), TPixel(128, 128, 0)}, + {QObject::tr("DarkCyan"), TPixel32(0, 128, 128)}, + {QObject::tr("DarkMagenta"), TPixel32(128, 0, 128)}, + {"", TPixel::Black}, + {"", TPixel::Black}, + {"", TPixel::Black}, + {"", TPixel::Black}}; +} } // namespace //============================================================================= @@ -71,6 +86,8 @@ TSceneProperties::TSceneProperties() // Default Cell Marks m_cellMarks = getDefaultCellMarks(); + // Default Color Filters + m_colorFilters = getDefaultColorFilters(); } //----------------------------------------------------------------------------- @@ -117,6 +134,10 @@ void TSceneProperties::assign(const TSceneProperties *sprop) { int i; for (i = 0; i < m_notesColor.size(); i++) m_notesColor.replace(i, sprop->getNoteColor(i)); + for (i = 0; i < m_cellMarks.size(); i++) + m_cellMarks.replace(i, sprop->getCellMark(i)); + for (i = 0; i < m_colorFilters.size(); i++) + m_colorFilters.replace(i, sprop->getColorFilter(i)); } //----------------------------------------------------------------------------- @@ -383,6 +404,12 @@ void TSceneProperties::saveData(TOStream &os) const { for (auto mark : m_cellMarks) os << mark.name.toStdString() << mark.color; os.closeChild(); } + if (!hasDefaultColorFilters()) { + os.openChild("colorFilters"); + for (auto filter : m_colorFilters) + os << filter.name.toStdString() << filter.color; + os.closeChild(); + } } //----------------------------------------------------------------------------- @@ -809,6 +836,15 @@ void TSceneProperties::loadData(TIStream &is, bool isLoadingProject) { m_cellMarks.replace(i, {QString::fromStdString(name), color}); i++; } + } else if (tagName == "colorFilters") { + int i = 0; + while (!is.eos()) { + TPixel32 color; + std::string name; + is >> name >> color; + m_colorFilters.replace(i, {QString::fromStdString(name), color}); + i++; + } } else { throw TException("unexpected property tag: " + tagName); } @@ -916,6 +952,41 @@ bool TSceneProperties::hasDefaultCellMarks() const { return m_cellMarks == getDefaultCellMarks(); } +//----------------------------------------------------------------------------- + +QList TSceneProperties::getColorFilters() const { + return m_colorFilters; +} + +//----------------------------------------------------------------------------- + +TSceneProperties::ColorFilter TSceneProperties::getColorFilter( + int index) const { + return m_colorFilters[index]; +} + +//----------------------------------------------------------------------------- + +TPixel32 TSceneProperties::getColorFilterColor(int index) const { + return m_colorFilters[index].color; +} + +//----------------------------------------------------------------------------- + +void TSceneProperties::setColorFilter( + const TSceneProperties::ColorFilter &filter, int index) { + assert(index != 0); // the first item (None) is not editable + if (index == 0) return; + m_colorFilters[index] = filter; +} + +//----------------------------------------------------------------------------- +// check if the cell mark settings are modified +bool TSceneProperties::hasDefaultColorFilters() const { + if (m_colorFilters.size() != 11) return false; + return m_colorFilters == getDefaultColorFilters(); +} + //----------------------------------------------------------------------------- // templateFId in preview settings is used for "input" file format // such as new raster level, captured images by camera capture feature, etc. diff --git a/toonz/sources/toonzlib/stage.cpp b/toonz/sources/toonzlib/stage.cpp index 0db4d808c3..d82ba766cd 100644 --- a/toonz/sources/toonzlib/stage.cpp +++ b/toonz/sources/toonzlib/stage.cpp @@ -36,6 +36,8 @@ #include "toonz/autoclose.h" #include "toonz/txshleveltypes.h" #include "imagebuilders.h" +#include "toonz/toonzscene.h" +#include "toonz/sceneproperties.h" // Qt includes #include @@ -46,7 +48,7 @@ #include "toonz/stage.h" -//#define NUOVO_ONION +// #define NUOVO_ONION //============================================================================= /*! \namespace Stage @@ -425,14 +427,15 @@ void StageBuilder::addCell(PlayerSet &players, ToonzScene *scene, TXsheet *xsh, player.m_dpiAff = sl ? getDpiAffine(sl, cell.m_frameId) : TAffine(); player.m_onionSkinDistance = m_onionSkinDistance; // when visiting the subxsheet, valuate the subxsheet column index - bool isCurrent = (subSheetColIndex >= 0) - ? (subSheetColIndex == m_currentColumnIndex) - : (col == m_currentColumnIndex); + bool isCurrent = (subSheetColIndex >= 0) + ? (subSheetColIndex == m_currentColumnIndex) + : (col == m_currentColumnIndex); player.m_isCurrentColumn = isCurrent; player.m_ancestorColumnIndex = m_ancestorColumnIndex; player.m_masks = m_masks; player.m_opacity = column->getOpacity(); - player.m_filterColor = column->getFilterColor(); + player.m_filterColor = + scene->getProperties()->getColorFilterColor(column->getColorFilterId()); if (m_subXSheetStack.empty()) { player.m_z = columnZ; diff --git a/toonz/sources/toonzlib/txshcolumn.cpp b/toonz/sources/toonzlib/txshcolumn.cpp index b529ada121..d80f3eb477 100644 --- a/toonz/sources/toonzlib/txshcolumn.cpp +++ b/toonz/sources/toonzlib/txshcolumn.cpp @@ -700,47 +700,9 @@ void TXshColumn::setIsMask(bool on) { //----------------------------------------------------------------------------- -void TXshColumn::initColorFilters() { - static bool _firstTime = true; - if (!_firstTime) return; - filterColors[TXshColumn::FilterNone] = - QPair(QObject::tr("None"), TPixel::Black); - filterColors[TXshColumn::FilterRed] = - QPair(QObject::tr("Red"), TPixel::Red); - filterColors[TXshColumn::FilterGreen] = - QPair(QObject::tr("Green"), TPixel::Green); - filterColors[TXshColumn::FilterBlue] = - QPair(QObject::tr("Blue"), TPixel::Blue); - filterColors[TXshColumn::FilterDarkYellow] = - QPair(QObject::tr("DarkYellow"), TPixel(128, 128, 0)); - filterColors[TXshColumn::FilterDarkCyan] = - QPair(QObject::tr("DarkCyan"), TPixel(0, 128, 128)); - filterColors[TXshColumn::FilterDarkMagenta] = - QPair(QObject::tr("DarkMagenta"), TPixel(128, 0, 128)); - _firstTime = false; -} - -//----------------------------------------------------------------------------- - -TPixel32 TXshColumn::getFilterColor() { - return TXshColumn::getFilterInfo(m_filterColorId).second; -} - -//----------------------------------------------------------------------------- - -QPair TXshColumn::getFilterInfo( - TXshColumn::FilterColor key) { - TXshColumn::initColorFilters(); - if (!filterColors.contains(key)) - return QPair(QObject::tr("None"), TPixel::Black); - return filterColors.value(key); -} - -//----------------------------------------------------------------------------- - void TXshColumn::resetColumnProperties() { setStatusWord(0); setOpacity(255); setColorTag(0); - setFilterColorId(FilterNone); + setColorFilterId(0); // None } diff --git a/toonz/sources/toonzlib/txshlevelcolumn.cpp b/toonz/sources/toonzlib/txshlevelcolumn.cpp index 609c93adeb..777446525e 100644 --- a/toonz/sources/toonzlib/txshlevelcolumn.cpp +++ b/toonz/sources/toonzlib/txshlevelcolumn.cpp @@ -85,7 +85,7 @@ TXshColumn *TXshLevelColumn::clone() const { column->m_cells = m_cells; column->m_first = m_first; column->setColorTag(getColorTag()); - column->setFilterColorId(getFilterColorId()); + column->setColorFilterId(getColorFilterId()); // column->updateIcon(); return column; @@ -111,7 +111,7 @@ void TXshLevelColumn::loadData(TIStream &is) { } else if (tagName == "filter_color_id") { int id; is >> id; - setFilterColorId((TXshColumn::FilterColor)id); + setColorFilterId(id); } else if (tagName == "cells") { while (is.openChild(tagName)) { if (tagName == "cell") { @@ -164,8 +164,8 @@ void TXshLevelColumn::loadData(TIStream &is) { void TXshLevelColumn::saveData(TOStream &os) { os.child("status") << getStatusWord(); if (getOpacity() < 255) os.child("camerastand_opacity") << (int)getOpacity(); - if (getFilterColorId() != 0) - os.child("filter_color_id") << (int)getFilterColorId(); + if (getColorFilterId() != 0) + os.child("filter_color_id") << (int)getColorFilterId(); int r0, r1; if (getRange(r0, r1)) { os.openChild("cells"); diff --git a/toonz/sources/toonzlib/txshmeshcolumn.cpp b/toonz/sources/toonzlib/txshmeshcolumn.cpp index 7e0080d122..a08317fb69 100644 --- a/toonz/sources/toonzlib/txshmeshcolumn.cpp +++ b/toonz/sources/toonzlib/txshmeshcolumn.cpp @@ -51,7 +51,7 @@ TXshColumn *TXshMeshColumn::clone() const { column->m_cells = m_cells; column->m_first = m_first; column->setColorTag(getColorTag()); - column->setFilterColorId(getFilterColorId()); + column->setColorFilterId(getColorFilterId()); return column; } From 646fd4f121c605ff003883ec02224ed11098d98c Mon Sep 17 00:00:00 2001 From: shun-iwasawa Date: Wed, 1 Mar 2023 16:23:01 +0900 Subject: [PATCH 2/2] consider alpha channel of the filter color --- toonz/sources/toonz/xshcolumnviewer.cpp | 16 +++++++++++++++- toonz/sources/toonzlib/scenefx.cpp | 4 +++- toonz/sources/toonzlib/stagevisitor.cpp | 18 ++++++++++-------- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/toonz/sources/toonz/xshcolumnviewer.cpp b/toonz/sources/toonz/xshcolumnviewer.cpp index ca2cc4b1d8..d9e38f37ea 100644 --- a/toonz/sources/toonz/xshcolumnviewer.cpp +++ b/toonz/sources/toonz/xshcolumnviewer.cpp @@ -116,7 +116,21 @@ bool containsRasterLevel(TColumnSelection *selection) { const QIcon getColorChipIcon(TPixel32 color) { QColor qCol((int)color.r, (int)color.g, (int)color.b, (int)color.m); QPixmap pixmap(12, 12); - pixmap.fill(qCol); + if (color.m == TPixel32::maxChannelValue) { + pixmap.fill(qCol); + return QIcon(pixmap); + } + static QPixmap checkPm; + if (checkPm.isNull()) { + checkPm = QPixmap(12, 12); + checkPm.fill(Qt::white); + QPainter cp(&checkPm); + cp.fillRect(0, 0, 6, 6, Qt::black); + cp.fillRect(6, 6, 6, 6, Qt::black); + } + pixmap = checkPm; + QPainter p(&pixmap); + p.fillRect(0, 0, 12, 12, qCol); return QIcon(pixmap); } diff --git a/toonz/sources/toonzlib/scenefx.cpp b/toonz/sources/toonzlib/scenefx.cpp index 1bf5468943..691b5a129b 100644 --- a/toonz/sources/toonzlib/scenefx.cpp +++ b/toonz/sources/toonzlib/scenefx.cpp @@ -977,7 +977,9 @@ PlacedFx FxBuilder::makePF(TLevelColumnFx *lcfx) { TPixel32 colorScale = m_scene->getProperties()->getColorFilterColor( column->getColorFilterId()); if (colorScale != TPixel::Black) { - colorScale.m = column->getOpacity(); + colorScale.m = (typename TPixel32::Channel)((int)colorScale.m * + (int)column->getOpacity() / + TPixel32::maxChannelValue); pf.m_fx = TFxUtil::makeColumnColorFilter(pf.m_fx, colorScale); } } diff --git a/toonz/sources/toonzlib/stagevisitor.cpp b/toonz/sources/toonzlib/stagevisitor.cpp index 304ba53622..5e1c90c822 100644 --- a/toonz/sources/toonzlib/stagevisitor.cpp +++ b/toonz/sources/toonzlib/stagevisitor.cpp @@ -549,7 +549,9 @@ void RasterPainter::flushRasterImages() { } else { if (m_nodes[i].m_filterColor != TPixel32::Black) { colorscale = m_nodes[i].m_filterColor; - colorscale.m = m_nodes[i].m_alpha; + colorscale.m = (typename TPixel32::Channel)((int)colorscale.m * + (int)m_nodes[i].m_alpha / + TPixel32::maxChannelValue); } inksOnly = tc & ToonzCheck::eInksOnly; } @@ -843,9 +845,9 @@ void RasterPainter::onVectorImage(TVectorImage *vi, TPalette *vPalette = vi->getPalette(); TPixel32 bgColor = TPixel32::White; - int tc = (m_checkFlags && player.m_isCurrentColumn) - ? ToonzCheck::instance()->getChecks() - : 0; + int tc = (m_checkFlags && player.m_isCurrentColumn) + ? ToonzCheck::instance()->getChecks() + : 0; bool inksOnly = tc & ToonzCheck::eInksOnly; int oldFrame = vPalette->getFrame(); @@ -1017,7 +1019,7 @@ void RasterPainter::onRasterImage(TRasterImage *ri, ? 0.9 : (1.0 - OnionSkinMask::getOnionSkinFade( player.m_onionSkinDistance)); - alpha = tcrop(tround(onionSkiFade * 255.0), 0, 255); + alpha = tcrop(tround(onionSkiFade * 255.0), 0, 255); if (player.m_isShiftAndTraceEnabled && !Preferences::instance()->areOnionColorsUsedForShiftAndTraceGhosts()) onionMode = Node::eOnionSkinNone; @@ -1080,7 +1082,7 @@ void RasterPainter::onToonzImage(TToonzImage *ti, const Stage::Player &player) { ? 0.9 : (1.0 - OnionSkinMask::getOnionSkinFade( player.m_onionSkinDistance)); - alpha = tcrop(tround(onionSkiFade * 255.0), 0, 255); + alpha = tcrop(tround(onionSkiFade * 255.0), 0, 255); if (player.m_isShiftAndTraceEnabled && !Preferences::instance()->areOnionColorsUsedForShiftAndTraceGhosts()) @@ -1369,9 +1371,9 @@ void onMeshImage(TMeshImage *mi, const Stage::Player &player, assert(mi); static const double soMinColor[4] = {0.0, 0.0, 0.0, - 0.6}; // Translucent black + 0.6}; // Translucent black static const double soMaxColor[4] = {1.0, 1.0, 1.0, - 0.6}; // Translucent white + 0.6}; // Translucent white static const double rigMinColor[4] = {0.0, 1.0, 0.0, 0.6}; // Translucent green static const double rigMaxColor[4] = {1.0, 0.0, 0.0, 0.6}; // Translucent red