From 63610baef46236317dce5f7ecc9a7a80f0b5099c Mon Sep 17 00:00:00 2001 From: Jeremy Bullock Date: Oct 03 2016 04:33:36 +0000 Subject: Merge pull request #764 from shun-iwasawa/organize_palette "Organize palette" and "Update colors by using picked position" features for the workflow using raster level as a color model --- diff --git a/toonz/sources/common/tvrender/tcolorstyles.cpp b/toonz/sources/common/tvrender/tcolorstyles.cpp index 3b18ce5..a67f8f1 100644 --- a/toonz/sources/common/tvrender/tcolorstyles.cpp +++ b/toonz/sources/common/tvrender/tcolorstyles.cpp @@ -50,7 +50,8 @@ TColorStyle::TColorStyle() , m_enabled(true) , m_icon(0) , m_validIcon(false) - , m_isEditedFromOriginal(false) {} + , m_isEditedFromOriginal(false) + , m_pickedPosition() {} //------------------------------------------------------------------- @@ -66,7 +67,8 @@ TColorStyle::TColorStyle(const TColorStyle &other) , m_flags(other.m_flags) , m_enabled(other.m_enabled) , m_validIcon(false) - , m_isEditedFromOriginal(other.m_isEditedFromOriginal) {} + , m_isEditedFromOriginal(other.m_isEditedFromOriginal) + , m_pickedPosition(other.m_pickedPosition) {} //------------------------------------------------------------------- @@ -79,6 +81,7 @@ TColorStyle &TColorStyle::operator=(const TColorStyle &other) { m_enabled = other.m_enabled; m_validIcon = false; m_isEditedFromOriginal = other.m_isEditedFromOriginal; + m_pickedPosition = other.m_pickedPosition; return *this; } @@ -100,6 +103,7 @@ bool TColorStyle::operator==(const TColorStyle &cs) const { if (m_originalName != cs.getOriginalName()) return false; if (m_globalName != cs.getGlobalName()) return false; if (m_isEditedFromOriginal != cs.getIsEditedFlag()) return false; + if (m_pickedPosition != cs.getPickedPosition()) return false; for (int p = 0; p < colorParamCount; ++p) if (getColorParamValue(p) != cs.getColorParamValue(p)) return false; diff --git a/toonz/sources/common/tvrender/tpalette.cpp b/toonz/sources/common/tvrender/tpalette.cpp index e301908..902a439 100644 --- a/toonz/sources/common/tvrender/tpalette.cpp +++ b/toonz/sources/common/tvrender/tpalette.cpp @@ -15,6 +15,7 @@ #include "tpalette.h" #include +#include PERSIST_IDENTIFIER(TPalette, "palette") @@ -30,6 +31,21 @@ namespace { const int maxStyleIndex = 32765; +const std::string pointToString(const TPoint &point) { + return std::to_string(point.x) + "," + std::to_string(point.y); +} + +// splitting string with ',' +const TPoint stringToPoint(const std::string &string) { + std::string buffer; + std::stringstream ss(string); + std::getline(ss, buffer, ','); // getting the first part of string + int x = std::stoi(buffer); + std::getline(ss, buffer); // getting the second part of string + int y = std::stoi(buffer); + return TPoint(x, y); +} + } // namespace //=================================================================== @@ -563,10 +579,17 @@ void TPalette::saveData(TOStream &os) { os.openChild("styles"); { for (int i = 0; i < getStyleCount(); ++i) { - os.openChild("style"); + TColorStyleP style = m_styles[i].second; + if (style->getPickedPosition() == TPoint()) + os.openChild("style"); + else { + std::map attr; + attr["pickedpos"] = pointToString(style->getPickedPosition()); + os.openChild("style", attr); + } { StyleWriter w(os, i); - m_styles[i].second->save(w); + style->save(w); } os.closeChild(); } @@ -680,6 +703,10 @@ void TPalette::loadData(TIStream &is) { StyleReader r(is, version); TColorStyle *cs = TColorStyle::load(r); + std::string pickedPosStr; + if (is.getTagParam("pickedpos", pickedPosStr)) + cs->setPickedPosition(stringToPoint(pickedPosStr)); + addStyle(cs); } @@ -1088,3 +1115,15 @@ void TPalette::setShortcutValue(int key, int styleId) { m_shortcuts[key] = styleId; } } + +//------------------------------------------------------------------- +// Returns true if there is at least one style with picked pos value +//------------------------------------------------------------------- + +bool TPalette::hasPickedPosStyle() { + for (int i = 0; i < getStyleCount(); ++i) { + TColorStyleP style = m_styles[i].second; + if (style->getPickedPosition() != TPoint()) return true; + } + return false; +} \ No newline at end of file diff --git a/toonz/sources/include/tcolorstyles.h b/toonz/sources/include/tcolorstyles.h index 1b999e7..2aecdad 100644 --- a/toonz/sources/include/tcolorstyles.h +++ b/toonz/sources/include/tcolorstyles.h @@ -118,6 +118,9 @@ private: // This flag will be set when the //! style is edited from the original one. + TPoint m_pickedPosition; // picked position from color model by using style + // picker tool with "organize palette" option. + protected: TRaster32P m_icon; //!< Icon shown on TPalette viewers. bool m_validIcon; //!< Icon's validity status. @@ -212,6 +215,9 @@ The \a global name contains information about palette id. m_flags = flags; } //!< Returns color attributes. + void setPickedPosition(const TPoint &pos) { m_pickedPosition = pos; } + TPoint getPickedPosition() const { return m_pickedPosition; } + // Color-related functions /*! \detail diff --git a/toonz/sources/include/tools/cursors.h b/toonz/sources/include/tools/cursors.h index a912ffa..16eec82 100644 --- a/toonz/sources/include/tools/cursors.h +++ b/toonz/sources/include/tools/cursors.h @@ -66,6 +66,8 @@ enum { PickerCursorWhite, PickerCursorWhiteLine, PickerCursorWhiteArea, + PickerCursorOrganize, + PickerCursorWhiteOrganize, PickerRGB, PickerRGBWhite, diff --git a/toonz/sources/include/toonz/palettecmd.h b/toonz/sources/include/toonz/palettecmd.h index bca5440..ada5ee4 100644 --- a/toonz/sources/include/toonz/palettecmd.h +++ b/toonz/sources/include/toonz/palettecmd.h @@ -88,6 +88,17 @@ DVAPI void renamePalettePage(TPaletteHandle *paletteHandle, int pageIndex, DVAPI void renamePaletteStyle(TPaletteHandle *paletteHandle, const std::wstring &newName); +/* called in ColorModelViewer::pick() - move selected style to the first page */ +DVAPI void organizePaletteStyle(TPaletteHandle *paletteHandle, int styleId, + const TPoint &point); + +/* +called in ColorModelViewer::repickFromColorModel(). +Pick color from the img for all styles with "picked position" value. +*/ +DVAPI void pickColorByUsingPickedPosition(TPaletteHandle *paletteHandle, + TImageP img); + } // namespace #endif diff --git a/toonz/sources/include/tpalette.h b/toonz/sources/include/tpalette.h index bf16794..a1085ce 100644 --- a/toonz/sources/include/tpalette.h +++ b/toonz/sources/include/tpalette.h @@ -417,6 +417,9 @@ between RGBA color components. m_isLocked = lock; } + bool hasPickedPosStyle(); // Returns true if there is at least one style with + // picked pos value + public: // Deprecated functions diff --git a/toonz/sources/tnztools/CMakeLists.txt b/toonz/sources/tnztools/CMakeLists.txt index b3d5525..8f2b1c2 100644 --- a/toonz/sources/tnztools/CMakeLists.txt +++ b/toonz/sources/tnztools/CMakeLists.txt @@ -11,6 +11,7 @@ set(MOC_HEADERS ../include/tools/screenpicker.h rgbpickertool.h rulertool.h + stylepickertool.h ) set(HEADERS ${MOC_HEADERS} diff --git a/toonz/sources/tnztools/Resources/picker_style_organize.png b/toonz/sources/tnztools/Resources/picker_style_organize.png new file mode 100644 index 0000000..c502b37 Binary files /dev/null and b/toonz/sources/tnztools/Resources/picker_style_organize.png differ diff --git a/toonz/sources/tnztools/Resources/picker_style_white_organize.png b/toonz/sources/tnztools/Resources/picker_style_white_organize.png new file mode 100644 index 0000000..b905466 Binary files /dev/null and b/toonz/sources/tnztools/Resources/picker_style_white_organize.png differ diff --git a/toonz/sources/tnztools/cursormanager.cpp b/toonz/sources/tnztools/cursormanager.cpp index 126610f..323ba47 100644 --- a/toonz/sources/tnztools/cursormanager.cpp +++ b/toonz/sources/tnztools/cursormanager.cpp @@ -73,6 +73,9 @@ const struct { {ToolCursor::PickerCursorWhiteLine, "picker_style_white_line", 7, 22}, {ToolCursor::PickerCursorWhiteArea, "picker_style_white_area", 7, 22}, {ToolCursor::PickerCursorWhite, "picker_style_white", 7, 22}, + {ToolCursor::PickerCursorOrganize, "picker_style_organize", 7, 22}, + {ToolCursor::PickerCursorWhiteOrganize, "picker_style_white_organize", 7, + 22}, {ToolCursor::PickerRGB, "picker_rgb", 7, 22}, {ToolCursor::PickerRGBWhite, "picker_rgb_white", 7, 22}, {ToolCursor::FillCursorF, "fill_f", 6, 23}, diff --git a/toonz/sources/tnztools/stylepickertool.cpp b/toonz/sources/tnztools/stylepickertool.cpp index e73625c..4c21641 100644 --- a/toonz/sources/tnztools/stylepickertool.cpp +++ b/toonz/sources/tnztools/stylepickertool.cpp @@ -1,238 +1,307 @@ +#include "stylepickertool.h" - +// TnzTools includes #include "tools/tool.h" #include "tools/cursors.h" #include "tools/stylepicker.h" -#include "toonz/txshsimplelevel.h" -#include "toonz/txshlevelhandle.h" +#include "tools/toolhandle.h" -#include "drawutil.h" -#include "tvectorimage.h" -#include "ttoonzimage.h" -#include "tundo.h" +// TnzQt includes +#include "toonzqt/tselectionhandle.h" +#include "toonzqt/styleselection.h" +// TnzLib includes +#include "toonz/txshsimplelevel.h" +#include "toonz/txshlevelhandle.h" #include "toonz/tpalettehandle.h" - #include "toonz/stage2.h" -#include "tproperty.h" -#include "toonzqt/tselectionhandle.h" -#include "toonzqt/styleselection.h" -#include "tools/toolhandle.h" #include "toonz/tframehandle.h" #include "toonz/txsheethandle.h" #include "toonz/preferences.h" #include "toonz/tcolumnhandle.h" #include "toonz/dpiscale.h" #include "toonz/palettecontroller.h" +#include "toonz/txshleveltypes.h" +#include "toonz/txshpalettelevel.h" + +// TnzCore includes +#include "drawutil.h" +#include "tvectorimage.h" +#include "ttoonzimage.h" +#include "tundo.h" +#include "tmsgcore.h" #define LINES L"Lines" #define AREAS L"Areas" #define ALL L"Lines & Areas" -namespace { - //======================================================================== // Pick Style Tool //------------------------------------------------------------------------ -class StylePickerTool final : public TTool { - int m_oldStyleId, m_currentStyleId; - - TEnumProperty m_colorType; - TPropertyGroup m_prop; - - TBoolProperty m_passivePick; +StylePickerTool::StylePickerTool() + : TTool("T_StylePicker") + , m_currentStyleId(0) + , m_colorType("Mode:") + , m_passivePick("Passive Pick", false) + , m_organizePalette("Organize Palette", false) + , m_paletteToBeOrganized(NULL) { + m_prop.bind(m_colorType); + m_colorType.addValue(AREAS); + m_colorType.addValue(LINES); + m_colorType.addValue(ALL); + m_colorType.setId("Mode"); + bind(TTool::CommonLevels); + + m_prop.bind(m_passivePick); + m_passivePick.setId("PassivePick"); + + m_prop.bind(m_organizePalette); + m_organizePalette.setId("OrganizePalette"); +} -public: - TPropertyGroup *getProperties(int targetType) override { return &m_prop; } +void StylePickerTool::leftButtonDown(const TPointD &pos, const TMouseEvent &e) { + m_oldStyleId = m_currentStyleId = + getApplication()->getCurrentLevelStyleIndex(); + pick(pos, e); +} - StylePickerTool() - : TTool("T_StylePicker") - , m_currentStyleId(0) - , m_colorType("Mode:") - , m_passivePick("Passive Pick", false) { - m_prop.bind(m_colorType); - m_colorType.addValue(AREAS); - m_colorType.addValue(LINES); - m_colorType.addValue(ALL); - m_colorType.setId("Mode"); - bind(TTool::CommonLevels); +void StylePickerTool::leftButtonDrag(const TPointD &pos, const TMouseEvent &e) { + pick(pos, e); +} - m_prop.bind(m_passivePick); - m_passivePick.setId("PassivePick"); +void StylePickerTool::pick(const TPointD &pos, const TMouseEvent &e) { + // Area = 0, Line = 1, All = 2 + int modeValue = m_colorType.getIndex(); + + //------------------------------------ + // MultiLayerStylePicker + /*--- + PickしたStyleId = 0、かつ + Preference で MultiLayerStylePickerが有効、かつ + Scene編集モード、かつ + 下のカラムから拾った色がTransparentでない場合、 + → カレントLevelを移動する。 + ---*/ + if (Preferences::instance()->isMultiLayerStylePickerEnabled() && + getApplication()->getCurrentFrame()->isEditingScene()) { + int superPickedColumnId = getViewer()->posToColumnIndex( + e.m_pos, getPixelSize() * getPixelSize(), false); + + if (superPickedColumnId >= 0 /*-- 何かColumnに当たった場合 --*/ + && + getApplication()->getCurrentColumn()->getColumnIndex() != + superPickedColumnId) /*-- かつ、Current Columnでない場合 --*/ + { + /*-- そのColumnからPickを試みる --*/ + int currentFrame = getApplication()->getCurrentFrame()->getFrame(); + TXshCell pickedCell = + getApplication()->getCurrentXsheet()->getXsheet()->getCell( + currentFrame, superPickedColumnId); + TImageP pickedImage = pickedCell.getImage(false).getPointer(); + TToonzImageP picked_ti = pickedImage; + TVectorImageP picked_vi = pickedImage; + TXshSimpleLevel *picked_level = pickedCell.getSimpleLevel(); + if ((picked_ti || picked_vi) && picked_level) { + TPointD tmpMousePosition = getColumnMatrix(superPickedColumnId).inv() * + getViewer()->winToWorld(e.m_pos); + + TPointD tmpDpiScale = getCurrentDpiScale(picked_level, getCurrentFid()); + + tmpMousePosition.x /= tmpDpiScale.x; + tmpMousePosition.y /= tmpDpiScale.y; + + StylePicker superPicker(pickedImage); + int picked_subsampling = + picked_level->getImageSubsampling(pickedCell.getFrameId()); + int superPicked_StyleId = superPicker.pickStyleId( + TScale(1.0 / picked_subsampling) * tmpMousePosition + + TPointD(-0.5, -0.5), + getPixelSize() * getPixelSize(), modeValue); + /*-- 何かStyleが拾えて、Transparentでない場合 --*/ + if (superPicked_StyleId > 0) { + /*-- Levelの移動 --*/ + getApplication()->getCurrentLevel()->setLevel(picked_level); + /*-- Columnの移動 --*/ + getApplication()->getCurrentColumn()->setColumnIndex( + superPickedColumnId); + /*-- 選択の解除 --*/ + if (getApplication()->getCurrentSelection()->getSelection()) + getApplication() + ->getCurrentSelection() + ->getSelection() + ->selectNone(); + /*-- StyleIdの移動 --*/ + getApplication()->setCurrentLevelStyleIndex(superPicked_StyleId); + return; + } + } + } + } + /*-- MultiLayerStylePicker ここまで --*/ + //------------------------------------ + TImageP image = getImage(false); + TToonzImageP ti = image; + TVectorImageP vi = image; + TXshSimpleLevel *level = + getApplication()->getCurrentLevel()->getSimpleLevel(); + if ((!ti && !vi) || !level) return; + + /*-- 画面外をpickしても拾えないようにする --*/ + if (!m_viewer->getGeometry().contains(pos)) return; + + int subsampling = level->getImageSubsampling(getCurrentFid()); + StylePicker picker(image); + int styleId = + picker.pickStyleId(TScale(1.0 / subsampling) * pos + TPointD(-0.5, -0.5), + getPixelSize() * getPixelSize(), modeValue); + + if (styleId < 0) return; + + if (modeValue == 1) // LINES + { + /*-- pickLineモードのとき、取得Styleが0の場合はカレントStyleを変えない。 + * --*/ + if (styleId == 0) return; + /*-- + * pickLineモードのとき、PurePaintの部分をクリックしてもカレントStyleを変えない + * --*/ + if (ti && + picker.pickTone(TScale(1.0 / subsampling) * pos + + TPointD(-0.5, -0.5)) == 255) + return; } - ToolType getToolType() const override { return TTool::LevelReadTool; } + /*--- Styleを選択している場合は選択を解除する ---*/ + TSelection *selection = + TTool::getApplication()->getCurrentSelection()->getSelection(); + if (selection) { + TStyleSelection *styleSelection = + dynamic_cast(selection); + if (styleSelection) styleSelection->selectNone(); + } - void draw() override {} + getApplication()->setCurrentLevelStyleIndex(styleId); +} - void leftButtonDown(const TPointD &pos, const TMouseEvent &e) override { - m_oldStyleId = m_currentStyleId = - getApplication()->getCurrentLevelStyleIndex(); - pick(pos, e); - } - void leftButtonDrag(const TPointD &pos, const TMouseEvent &e) override { - pick(pos, e); +void StylePickerTool::mouseMove(const TPointD &pos, const TMouseEvent &e) { + if (!m_passivePick.getValue()) return; + /*--- PassiveにStyleを拾う機能 ---*/ + PaletteController *controller = + TTool::getApplication()->getPaletteController(); + + TImageP image = getImage(false); + TToonzImageP ti = image; + TVectorImageP vi = image; + TXshSimpleLevel *level = + getApplication()->getCurrentLevel()->getSimpleLevel(); + if ((!ti && !vi) || !level || !m_viewer->getGeometry().contains(pos)) { + controller->notifyStylePassivePicked(-1, -1, -1); + return; } - void pick(const TPointD &pos, const TMouseEvent &e) { - // Area = 0, Line = 1, All = 2 - int modeValue = m_colorType.getIndex(); - - //------------------------------------ - // MultiLayerStylePicker - /*--- - PickしたStyleId = 0、かつ - Preference で MultiLayerStylePickerが有効、かつ - Scene編集モード、かつ - 下のカラムから拾った色がTransparentでない場合、 - → カレントLevelを移動する。 - ---*/ - if (Preferences::instance()->isMultiLayerStylePickerEnabled() && - getApplication()->getCurrentFrame()->isEditingScene()) { - int superPickedColumnId = getViewer()->posToColumnIndex( - e.m_pos, getPixelSize() * getPixelSize(), false); - - if (superPickedColumnId >= 0 /*-- 何かColumnに当たった場合 --*/ - && - getApplication()->getCurrentColumn()->getColumnIndex() != - superPickedColumnId) /*-- かつ、Current Columnでない場合 --*/ - { - /*-- そのColumnからPickを試みる --*/ - int currentFrame = getApplication()->getCurrentFrame()->getFrame(); - TXshCell pickedCell = - getApplication()->getCurrentXsheet()->getXsheet()->getCell( - currentFrame, superPickedColumnId); - TImageP pickedImage = pickedCell.getImage(false).getPointer(); - TToonzImageP picked_ti = pickedImage; - TVectorImageP picked_vi = pickedImage; - TXshSimpleLevel *picked_level = pickedCell.getSimpleLevel(); - if ((picked_ti || picked_vi) && picked_level) { - TPointD tmpMousePosition = - getColumnMatrix(superPickedColumnId).inv() * - getViewer()->winToWorld(e.m_pos); - - TPointD tmpDpiScale = - getCurrentDpiScale(picked_level, getCurrentFid()); - - tmpMousePosition.x /= tmpDpiScale.x; - tmpMousePosition.y /= tmpDpiScale.y; - - StylePicker superPicker(pickedImage); - int picked_subsampling = - picked_level->getImageSubsampling(pickedCell.getFrameId()); - int superPicked_StyleId = superPicker.pickStyleId( - TScale(1.0 / picked_subsampling) * tmpMousePosition + - TPointD(-0.5, -0.5), - getPixelSize() * getPixelSize(), modeValue); - /*-- 何かStyleが拾えて、Transparentでない場合 --*/ - if (superPicked_StyleId > 0) { - /*-- Levelの移動 --*/ - getApplication()->getCurrentLevel()->setLevel(picked_level); - /*-- Columnの移動 --*/ - getApplication()->getCurrentColumn()->setColumnIndex( - superPickedColumnId); - /*-- 選択の解除 --*/ - if (getApplication()->getCurrentSelection()->getSelection()) - getApplication() - ->getCurrentSelection() - ->getSelection() - ->selectNone(); - /*-- StyleIdの移動 --*/ - getApplication()->setCurrentLevelStyleIndex(superPicked_StyleId); - return; - } - } - } - } - /*-- MultiLayerStylePicker ここまで --*/ - //------------------------------------ - TImageP image = getImage(false); - TToonzImageP ti = image; - TVectorImageP vi = image; - TXshSimpleLevel *level = - getApplication()->getCurrentLevel()->getSimpleLevel(); - if ((!ti && !vi) || !level) return; - - /*-- 画面外をpickしても拾えないようにする --*/ - if (!m_viewer->getGeometry().contains(pos)) return; - - int subsampling = level->getImageSubsampling(getCurrentFid()); - StylePicker picker(image); - int styleId = picker.pickStyleId( - TScale(1.0 / subsampling) * pos + TPointD(-0.5, -0.5), - getPixelSize() * getPixelSize(), modeValue); - - if (styleId < 0) return; - - if (modeValue == 1) // LINES - { - /*-- pickLineモードのとき、取得Styleが0の場合はカレントStyleを変えない。 - * --*/ - if (styleId == 0) return; - /*-- - * pickLineモードのとき、PurePaintの部分をクリックしてもカレントStyleを変えない - * --*/ - if (ti && - picker.pickTone(TScale(1.0 / subsampling) * pos + - TPointD(-0.5, -0.5)) == 255) - return; - } - - /*--- Styleを選択している場合は選択を解除する ---*/ - TSelection *selection = - TTool::getApplication()->getCurrentSelection()->getSelection(); - if (selection) { - TStyleSelection *styleSelection = - dynamic_cast(selection); - if (styleSelection) styleSelection->selectNone(); - } + int subsampling = level->getImageSubsampling(getCurrentFid()); + StylePicker picker(image); + TPointD pickPos(TScale(1.0 / subsampling) * pos + TPointD(-0.5, -0.5)); + int inkStyleId = + picker.pickStyleId(pickPos, getPixelSize() * getPixelSize(), 1); + int paintStyleId = + picker.pickStyleId(pickPos, getPixelSize() * getPixelSize(), 0); + int tone = picker.pickTone(pickPos); + controller->notifyStylePassivePicked(inkStyleId, paintStyleId, tone); +} - getApplication()->setCurrentLevelStyleIndex(styleId); - } +int StylePickerTool::getCursorId() const { + bool isBlackBG = ToonzCheck::instance()->getChecks() & ToonzCheck::eBlackBg; + + /* in case the "organize palette" option is active */ + if (m_organizePalette.getValue()) + return (isBlackBG) ? ToolCursor::PickerCursorWhiteOrganize + : ToolCursor::PickerCursorOrganize; + + if (m_colorType.getValue() == LINES) + return (isBlackBG) ? ToolCursor::PickerCursorWhiteLine + : ToolCursor::PickerCursorLine; + else if (m_colorType.getValue() == AREAS) + return (isBlackBG) ? ToolCursor::PickerCursorWhiteArea + : ToolCursor::PickerCursorArea; + else // line&areas + return (isBlackBG) ? ToolCursor::PickerCursorWhite + : ToolCursor::PickerCursor; +} - void mouseMove(const TPointD &pos, const TMouseEvent &e) override { - if (!m_passivePick.getValue()) return; - /*--- PassiveにStyleを拾う機能 ---*/ - PaletteController *controller = - TTool::getApplication()->getPaletteController(); - - TImageP image = getImage(false); - TToonzImageP ti = image; - TVectorImageP vi = image; - TXshSimpleLevel *level = - getApplication()->getCurrentLevel()->getSimpleLevel(); - if ((!ti && !vi) || !level || !m_viewer->getGeometry().contains(pos)) { - controller->notifyStylePassivePicked(-1, -1, -1); - return; +bool StylePickerTool::onPropertyChanged(std::string propertyName) { + if (propertyName == m_organizePalette.getName()) { + if (m_organizePalette.getValue()) { + if (!startOrganizePalette()) { + m_organizePalette.setValue(false); + getApplication()->getCurrentTool()->notifyToolChanged(); + return false; + } + } else { + std::cout << "End Organize Palette" << std::endl; + m_paletteToBeOrganized = NULL; } + } + return true; +} - int subsampling = level->getImageSubsampling(getCurrentFid()); - StylePicker picker(image); - TPointD pickPos(TScale(1.0 / subsampling) * pos + TPointD(-0.5, -0.5)); - int inkStyleId = - picker.pickStyleId(pickPos, getPixelSize() * getPixelSize(), 1); - int paintStyleId = - picker.pickStyleId(pickPos, getPixelSize() * getPixelSize(), 0); - int tone = picker.pickTone(pickPos); - controller->notifyStylePassivePicked(inkStyleId, paintStyleId, tone); +bool StylePickerTool::startOrganizePalette() { + /* Check if the organizing operation is available */ + TXshLevel *level = getApplication()->getCurrentLevel()->getLevel(); + if (!level) { + DVGui::error(tr("No current level.")); + return false; + } + if (level->getType() != PLI_XSHLEVEL && level->getType() != TZP_XSHLEVEL && + level->getType() != PLT_XSHLEVEL) { + DVGui::error(tr("Current level has no available palette.")); + return false; + } + /* palette should have more than one page to organize */ + TPalette *pal = NULL; + if (level->getType() == PLT_XSHLEVEL) + pal = level->getPaletteLevel()->getPalette(); + else + pal = level->getSimpleLevel()->getPalette(); + if (!pal || pal->getPageCount() < 2) { + DVGui::error( + tr("Palette must have more than one palette to be organized.")); + return false; } - void onActivate() override {} + m_paletteToBeOrganized = pal; - int getCursorId() const override { - bool isBlackBG = ToonzCheck::instance()->getChecks() & ToonzCheck::eBlackBg; + std::cout << "Start Organize Palette" << std::endl; - if (m_colorType.getValue() == LINES) - return (isBlackBG) ? ToolCursor::PickerCursorWhiteLine - : ToolCursor::PickerCursorLine; - else if (m_colorType.getValue() == AREAS) - return (isBlackBG) ? ToolCursor::PickerCursorWhiteArea - : ToolCursor::PickerCursorArea; - else // line&areas - return (isBlackBG) ? ToolCursor::PickerCursorWhite - : ToolCursor::PickerCursor; - } + return true; +} -} stylePickerTool; +/* + If the working palette is changed, then deactivate the "organize palette" + toggle. +*/ +void StylePickerTool::onImageChanged() { + std::cout << "StylePickerTool::onImageChanged" << std::endl; + if (!m_organizePalette.getValue() || !m_paletteToBeOrganized) return; + + TXshLevel *level = getApplication()->getCurrentLevel()->getLevel(); + if (!level) { + m_organizePalette.setValue(false); + getApplication()->getCurrentTool()->notifyToolChanged(); + return; + } + TPalette *pal = NULL; + if (level->getType() == PLT_XSHLEVEL) + pal = level->getPaletteLevel()->getPalette(); + else if (level->getSimpleLevel()) { + pal = level->getSimpleLevel()->getPalette(); + } + if (!pal || pal != m_paletteToBeOrganized) { + m_organizePalette.setValue(false); + getApplication()->getCurrentTool()->notifyToolChanged(); + return; + } } + +StylePickerTool stylePickerTool; diff --git a/toonz/sources/tnztools/stylepickertool.h b/toonz/sources/tnztools/stylepickertool.h new file mode 100644 index 0000000..2a6982a --- /dev/null +++ b/toonz/sources/tnztools/stylepickertool.h @@ -0,0 +1,54 @@ +#pragma once + +#ifndef STYLEPICKERTOOL_H +#define STYLEPICKERTOOL_H + +#include "tools/tool.h" +#include "tproperty.h" +#include + +class StylePickerTool final : public TTool, public QObject { + int m_oldStyleId, m_currentStyleId; + + TEnumProperty m_colorType; + TPropertyGroup m_prop; + TBoolProperty m_passivePick; + + TBoolProperty m_organizePalette; + TPalette *m_paletteToBeOrganized; + + bool startOrganizePalette(); + +public: + TPropertyGroup *getProperties(int targetType) override { return &m_prop; } + + StylePickerTool(); + + ToolType getToolType() const override { return TTool::LevelReadTool; } + + void draw() override {} + + void leftButtonDown(const TPointD &pos, const TMouseEvent &e) override; + + void leftButtonDrag(const TPointD &pos, const TMouseEvent &e) override; + + void pick(const TPointD &pos, const TMouseEvent &e); + + void mouseMove(const TPointD &pos, const TMouseEvent &e) override; + + int getCursorId() const override; + + bool onPropertyChanged(std::string propertyName); + + bool isOrganizePaletteActive() { return m_organizePalette.getValue(); } + + /* + This function is called when either frame/column/level/scene is switched or + either scene/level/object is changed (see tapp.cpp). + If the working palette is changed, then deactivate the "organize palette" + toggle. + */ + void onImageChanged() override; +}; + +#endif \ No newline at end of file diff --git a/toonz/sources/tnztools/tnztools.qrc b/toonz/sources/tnztools/tnztools.qrc index 98087dc..1b5b91b 100644 --- a/toonz/sources/tnztools/tnztools.qrc +++ b/toonz/sources/tnztools/tnztools.qrc @@ -50,6 +50,8 @@ Resources/picker_style_white_line.png Resources/picker_style_white_area.png Resources/picker_style_white.png + Resources/picker_style_organize.png + Resources/picker_style_white_organize.png Resources/picker_rgb.png Resources/picker_rgb_white.png Resources/fill_f.png diff --git a/toonz/sources/tnztools/tooloptions.cpp b/toonz/sources/tnztools/tooloptions.cpp index f19ee3b..28ed771 100644 --- a/toonz/sources/tnztools/tooloptions.cpp +++ b/toonz/sources/tnztools/tooloptions.cpp @@ -2182,6 +2182,17 @@ StylePickerToolOptionsBox::StylePickerToolOptionsBox( m_layout->addWidget(m_currentStyleLabel, 0); m_layout->addStretch(1); + // retrieve the "organize palette" checkbox from the layout and insert + // into rightmost of the tool option bar + ToolOptionCheckbox *organizePaletteCB = + dynamic_cast(m_controls.value("Organize Palette")); + m_layout->removeWidget(organizePaletteCB); + m_layout->addWidget(new ToolOptionsBarSeparator(this), 0); + m_layout->addWidget(organizePaletteCB); + organizePaletteCB->setToolTip( + tr("With this option being activated, the picked style will be\nmoved to " + "the end of the first page of the palette.")); + if (m_realTimePickMode) { connect(m_realTimePickMode, SIGNAL(toggled(bool)), m_currentStyleLabel, SLOT(setVisible(bool))); diff --git a/toonz/sources/toonz/colormodelviewer.cpp b/toonz/sources/toonz/colormodelviewer.cpp index 2e063b5..9ff95ab 100644 --- a/toonz/sources/toonz/colormodelviewer.cpp +++ b/toonz/sources/toonz/colormodelviewer.cpp @@ -14,6 +14,7 @@ #include "tools/toolcommandids.h" #include "tools/tool.h" #include "tools/toolhandle.h" +#include "../tnztools/stylepickertool.h" // TnzQt includes #include "toonzqt/menubarcommand.h" @@ -222,11 +223,28 @@ void ColorModelViewer::contextMenuEvent(QContextMenuEvent *event) { connect(loadCurrentFrame, SIGNAL(triggered()), SLOT(loadCurrentFrame())); menu.addAction(loadCurrentFrame); + if (!m_imageViewer->getImage()) { + menu.exec(event->globalPos()); + return; + } + QAction *removeColorModel = new QAction(QString(tr("Remove Color Model")), this); connect(removeColorModel, SIGNAL(triggered()), SLOT(removeColorModel())); menu.addAction(removeColorModel); + /* If there is at least one style with "picked pos" parameter, then enable + * repick command */ + TRasterImageP ri = m_imageViewer->getImage(); + if (ri && currentPalette->hasPickedPosStyle()) { + menu.addSeparator(); + QAction *repickFromColorModelAct = new QAction( + QString(tr("Update Colors by Using Picked Positions")), this); + connect(repickFromColorModelAct, SIGNAL(triggered()), + SLOT(repickFromColorModel())); + menu.addAction(repickFromColorModelAct); + } + menu.addSeparator(); QString shortcut = QString::fromStdString( @@ -306,6 +324,19 @@ void ColorModelViewer::pick(const QPoint &p) { if (styleSelection) styleSelection->selectNone(); } + /* + if the Style Picker tool is current and "organize palette" is activated, + then move the picked style to the first page of the palette. + */ + TTool *tool = TApp::instance()->getCurrentTool()->getTool(); + if (tool->getName() == "T_StylePicker") { + StylePickerTool *spTool = dynamic_cast(tool); + if (spTool && spTool->isOrganizePaletteActive()) { + TPoint point = picker.getRasterPoint(pos); + PaletteCmd::organizePaletteStyle(ph, styleIndex, point); + } + } + ph->setStyleIndex(styleIndex); } @@ -356,8 +387,16 @@ void ColorModelViewer::showEvent(QShowEvent *e) { //----------------------------------------------------------------------------- /*- ツールのTypeに合わせてPickのタイプも変え、カーソルも切り替える -*/ void ColorModelViewer::changePickType() { - TPropertyGroup *propGroup = - TApp::instance()->getCurrentTool()->getTool()->getProperties(0); + TTool *tool = TApp::instance()->getCurrentTool()->getTool(); + if (tool->getName() == T_StylePicker) { + StylePickerTool *stylePickerTool = dynamic_cast(tool); + if (stylePickerTool->isOrganizePaletteActive()) { + setToolCursor(m_imageViewer, ToolCursor::PickerCursorOrganize); + return; + } + } + + TPropertyGroup *propGroup = tool->getProperties(0); /*- Propertyの無いツールの場合 -*/ if (!propGroup) { m_mode = 2; @@ -573,6 +612,17 @@ void ColorModelViewer::onRefImageNotFound() { "level.")); } +//----------------------------------------------------------------------------- + +void ColorModelViewer::repickFromColorModel() { + TImageP img = m_imageViewer->getImage(); + if (!img) return; + TPaletteHandle *ph = + TApp::instance()->getPaletteController()->getCurrentLevelPalette(); + + PaletteCmd::pickColorByUsingPickedPosition(ph, img); +} + //============================================================================= OpenFloatingPanel openColorModelCommand(MI_OpenColorModel, "ColorModel", diff --git a/toonz/sources/toonz/colormodelviewer.h b/toonz/sources/toonz/colormodelviewer.h index e068080..833a62d 100644 --- a/toonz/sources/toonz/colormodelviewer.h +++ b/toonz/sources/toonz/colormodelviewer.h @@ -48,6 +48,7 @@ protected: * UseCurrentFrameのLevelに移動してきたときに、改めてCurrentFrameを格納しなおす * -*/ void reloadCurrentFrame(); + protected slots: void showCurrentImage(); @@ -62,6 +63,8 @@ protected slots: * -*/ void changePickType(); + void repickFromColorModel(); + signals: void refImageNotFound(); }; diff --git a/toonz/sources/toonzlib/convert2tlv.cpp b/toonz/sources/toonzlib/convert2tlv.cpp index 8e9c529..2fbed64 100644 --- a/toonz/sources/toonzlib/convert2tlv.cpp +++ b/toonz/sources/toonzlib/convert2tlv.cpp @@ -566,6 +566,18 @@ TPalette *Convert2Tlv::buildPalette() { page->addStyle(stylesToBeAddedToPage.at(s)); } + /* + If the palette path is empty, an initial palette with four colors are set in + the palette here. + ( see Convert2Tlv::init() ) So here I make the latter three styles in the + initial palette to set + "AutoPaint" options. + */ + if (m_palettePath.isEmpty()) { + assert(m_palette->getStyleCount() >= 5); + for (int id = 2; id <= 4; id++) m_palette->getStyle(id)->setFlags(1); + } + if (!m_appendDefaultPalette) return m_palette; /*-- Adding styles in the default palette to the result palette, starts here @@ -810,11 +822,17 @@ bool Convert2Tlv::init(std::string &errorMessage) { m_it = m_level1->begin(); - /*- 既定のパレットを作る。黒、赤、青、緑の順 -*/ - m_colorMap[TPixel::Black] = ++m_lastIndex; - m_colorMap[TPixel::Red] = ++m_lastIndex; - m_colorMap[TPixel::Blue] = ++m_lastIndex; - m_colorMap[TPixel::Green] = ++m_lastIndex; + /*- + If the palette is empty, make an initial palette with black, red, blue and + green styles. + For the latter three styles the "autopaint" option should be set. + -*/ + if (m_lastIndex == 0) { + m_colorMap[TPixel::Black] = ++m_lastIndex; + m_colorMap[TPixel::Red] = ++m_lastIndex; + m_colorMap[TPixel::Blue] = ++m_lastIndex; + m_colorMap[TPixel::Green] = ++m_lastIndex; + } return true; } diff --git a/toonz/sources/toonzlib/palettecmd.cpp b/toonz/sources/toonzlib/palettecmd.cpp index 5e16930..c23f12e 100644 --- a/toonz/sources/toonzlib/palettecmd.cpp +++ b/toonz/sources/toonzlib/palettecmd.cpp @@ -33,6 +33,7 @@ #include "tstroke.h" #include "tregion.h" #include "tlevel_io.h" +#include "tpixelutils.h" #include "historytypes.h" @@ -45,6 +46,8 @@ #include #include +#include + //=================================================================== void findPaletteLevels(set &levels, int &rowIndex, @@ -1168,3 +1171,177 @@ void PaletteCmd::renamePaletteStyle(TPaletteHandle *paletteHandle, paletteHandle->notifyColorStyleChanged(false); TUndoManager::manager()->add(undo); } + +//============================================================================= +// organizePaletteStyle +// called in ColorModelViewer::pick() - move selected style to the first page +//----------------------------------------------------------------------------- +namespace { + +class setStylePickedPositionUndo final : public TUndo { + TPaletteHandle *m_paletteHandle; // Used in undo and redo to notify change + int m_styleId; + TPaletteP m_palette; + TPoint m_newPos; + TPoint m_oldPos; + +public: + setStylePickedPositionUndo(TPaletteHandle *paletteHandle, int styleId, + const TPoint &newPos) + : m_paletteHandle(paletteHandle), m_styleId(styleId), m_newPos(newPos) { + m_palette = paletteHandle->getPalette(); + assert(m_palette); + TColorStyle *style = m_palette->getStyle(m_styleId); + assert(style); + m_oldPos = style->getPickedPosition(); + } + void undo() const override { + TColorStyle *style = m_palette->getStyle(m_styleId); + assert(style); + style->setPickedPosition(m_oldPos); + m_paletteHandle->notifyColorStyleChanged(false); + } + void redo() const override { + TColorStyle *style = m_palette->getStyle(m_styleId); + assert(style); + style->setPickedPosition(m_newPos); + m_paletteHandle->notifyColorStyleChanged(false); + } + int getSize() const override { return sizeof *this; } + QString getHistoryString() override { + return QObject::tr("Set Picked Position of Style#%1 in Palette%2 : %3,%4") + .arg(QString::number(m_styleId)) + .arg(QString::fromStdWString(m_palette->getPaletteName())) + .arg(QString::number(m_newPos.x)) + .arg(QString::number(m_newPos.y)); + } + int getHistoryType() override { return HistoryType::Palette; } +}; +} + +void PaletteCmd::organizePaletteStyle(TPaletteHandle *paletteHandle, + int styleId, const TPoint &point) { + if (!paletteHandle) return; + TPalette *palette = paletteHandle->getPalette(); + if (!palette) return; + // if the style is already in the first page, then do nothing + TPalette::Page *page = palette->getStylePage(styleId); + if (!page || page->getIndex() == 0) return; + + int indexInPage = page->search(styleId); + + TUndoManager::manager()->beginBlock(); + + // call arrangeStyles() to move style to the first page + arrangeStyles(paletteHandle, 0, palette->getPage(0)->getStyleCount(), + page->getIndex(), {indexInPage}); + // then set the picked position + setStylePickedPositionUndo *undo = + new setStylePickedPositionUndo(paletteHandle, styleId, point); + undo->redo(); + TUndoManager::manager()->add(undo); + + TUndoManager::manager()->endBlock(); +} + +//============================================================================= +// called in ColorModelViewer::repickFromColorModel(). +// Pick color from the img for all styles with "picked position" value. +//----------------------------------------------------------------------------- +namespace { + +class pickColorByUsingPickedPositionUndo final : public TUndo { + TPaletteHandle *m_paletteHandle; // Used in undo and redo to notify change + TPaletteP m_palette; + QHash> m_styleList; + +public: + pickColorByUsingPickedPositionUndo( + TPaletteHandle *paletteHandle, + QHash> styleList) + : m_paletteHandle(paletteHandle), m_styleList(styleList) { + m_palette = paletteHandle->getPalette(); + assert(m_palette); + } + void undo() const override { + QHash>::const_iterator i = + m_styleList.constBegin(); + while (i != m_styleList.constEnd()) { + TColorStyle *style = m_palette->getStyle(i.key()); + assert(style); + style->setMainColor(i.value().first); + ++i; + } + m_paletteHandle->notifyColorStyleChanged(false); + } + void redo() const override { + QHash>::const_iterator i = + m_styleList.constBegin(); + while (i != m_styleList.constEnd()) { + TColorStyle *style = m_palette->getStyle(i.key()); + assert(style); + style->setMainColor(i.value().second); + ++i; + } + m_paletteHandle->notifyColorStyleChanged(false); + } + int getSize() const override { return sizeof *this; } + QString getHistoryString() override { + return QObject::tr("Update Colors by Using Picked Positions in Palette %1") + .arg(QString::fromStdWString(m_palette->getPaletteName())); + } + int getHistoryType() override { return HistoryType::Palette; } +}; + +TPixel32 pickColor(TRasterImageP ri, const TPoint &rasterPoint) { + TRasterP raster; + raster = ri->getRaster(); + + if (!TRect(raster->getSize()).contains(rasterPoint)) + return TPixel32::Transparent; + + TRaster32P raster32 = raster; + if (raster32) return raster32->pixels(rasterPoint.y)[rasterPoint.x]; + + TRasterGR8P rasterGR8 = raster; + if (rasterGR8) + return toPixel32(rasterGR8->pixels(rasterPoint.y)[rasterPoint.x]); + + return TPixel32::Transparent; +} +} + +void PaletteCmd::pickColorByUsingPickedPosition(TPaletteHandle *paletteHandle, + TImageP img) { + TRasterImageP ri = img; + if (!ri) return; + + TPalette *currentPalette = paletteHandle->getPalette(); + if (!currentPalette) return; + + TDimension imgSize = ri->getRaster()->getSize(); + QHash> styleList; + + // For all styles (starting from #1 as #0 is reserved for the transparent) + for (int sId = 1; sId < currentPalette->getStyleCount(); sId++) { + TColorStyle *style = currentPalette->getStyle(sId); + TPoint pp = style->getPickedPosition(); + // If style has a valid picked position + if (pp != TPoint() && pp.x >= 0 && pp.x < imgSize.lx && pp.y >= 0 && + pp.y < imgSize.ly && style->hasMainColor()) { + TPixel32 beforeColor = style->getMainColor(); + TPixel32 afterColor = pickColor(ri, pp); + style->setMainColor(afterColor); + //... store the style in the list for undo + styleList.insert(sId, QPair(beforeColor, afterColor)); + } + } + + // if some style has been changed, then register undo and notify changes + if (!styleList.isEmpty()) { + pickColorByUsingPickedPositionUndo *undo = + new pickColorByUsingPickedPositionUndo(paletteHandle, styleList); + TUndoManager::manager()->add(undo); + paletteHandle->notifyColorStyleChanged(false, true); // set dirty flag here + } +} \ No newline at end of file diff --git a/toonz/sources/toonzqt/paletteviewergui.cpp b/toonz/sources/toonzqt/paletteviewergui.cpp index bf826a7..c42db3b 100644 --- a/toonz/sources/toonzqt/paletteviewergui.cpp +++ b/toonz/sources/toonzqt/paletteviewergui.cpp @@ -454,6 +454,10 @@ void PageViewer::drawColorName(QPainter &p, QRect &nameRect, TColorStyle *style, name += " " + toQString(g.first) + ":" + QString::number(g.second); if (style->getFlags() != 0) name += "(autopaint)"; + TPoint pickedPos = style->getPickedPosition(); + if (pickedPos != TPoint()) + name += QString(" (%1,%2)").arg(pickedPos.x).arg(pickedPos.y); + p.drawText(nameRect.adjusted(6, 4, -6, -4), name); QColor borderCol(getTextColor()); @@ -772,10 +776,23 @@ void PageViewer::paintEvent(QPaintEvent *e) { p.drawText(indexRect, Qt::AlignCenter, QString().setNum(styleIndex)); // draw "Autopaint for lines" indicator + int offset = 0; if (style->getFlags() != 0) { QRect aflRect(chipRect.bottomLeft() + QPoint(0, -14), QSize(12, 15)); p.drawRect(aflRect); p.drawText(aflRect, Qt::AlignCenter, "A"); + offset += 12; + } + + // draw "Picked Position" indicator (not show on small chip mode) + if (style->getPickedPosition() != TPoint() && m_viewMode != SmallChips) { + QRect ppRect(chipRect.bottomLeft() + QPoint(offset, -14), + QSize(12, 15)); + p.drawRect(ppRect); + QPoint markPos = ppRect.center() + QPoint(1, 0); + p.drawEllipse(markPos, 3, 3); + p.drawLine(markPos - QPoint(5, 0), markPos + QPoint(5, 0)); + p.drawLine(markPos - QPoint(0, 5), markPos + QPoint(0, 5)); } // revert font set diff --git a/toonz/sources/toonzqt/styleeditor.cpp b/toonz/sources/toonzqt/styleeditor.cpp index 107db3e..361b879 100644 --- a/toonz/sources/toonzqt/styleeditor.cpp +++ b/toonz/sources/toonzqt/styleeditor.cpp @@ -3060,9 +3060,13 @@ void StyleEditor::onStyleSwitched() { QString::fromStdWString(L" Palette : " + palette->getPaletteName()); // style name - statusText += QString::fromStdWString(L" | Style#"); + statusText += QString::fromStdWString(L" | #"); statusText += QString::number(styleIndex); statusText += QString::fromStdWString(L" : " + m_editedStyle->getName()); + TPoint pickedPos = m_editedStyle->getPickedPosition(); + if (pickedPos != TPoint()) + statusText += + QString(" (Picked from %1,%2)").arg(pickedPos.x).arg(pickedPos.y); m_statusLabel->setText(statusText); } else