diff --git a/stuff/config/colornames.txt b/stuff/config/colornames.txt new file mode 100644 index 0000000..f139a27 --- /dev/null +++ b/stuff/config/colornames.txt @@ -0,0 +1,164 @@ + + + + #FF0000 + #00FF00 + #0000FF + + #FFFFFF00 + #FFFFFF00 + #00000000 + #000000 + #FF0000 + #00FF00 + #0000FF + + #F0F8FF + #FAEBD7 + #00FFFF + #7FFFD4 + #F0FFFF + #F5F5DC + #FFE4C4 + #000000 + #FFEBCD + #0000FF + #8A2BE2 + #A52A2A + #DEB887 + #5F9EA0 + #7FFF00 + #D2691E + #FF7F50 + #6495ED + #FFF8DC + #DC143C + #00FFFF + #00008B + #008B8B + #B8860B + #A9A9A9 + #A9A9A9 + #006400 + #BDB76B + #8B008B + #556B2F + #FF8C00 + #9932CC + #8B0000 + #E9967A + #8FBC8F + #483D8B + #2F4F4F + #2F4F4F + #00CED1 + #9400D3 + #FF1493 + #00BFFF + #696969 + #696969 + #1E90FF + #B22222 + #FFFAF0 + #228B22 + #FF00FF + #DCDCDC + #F8F8FF + #FFD700 + #DAA520 + #808080 + #808080 + #008000 + #ADFF2F + #F0FFF0 + #FF69B4 + #CD5C5C + #4B0082 + #FFFFF0 + #F0E68C + #E6E6FA + #FFF0F5 + #7CFC00 + #FFFACD + #ADD8E6 + #F08080 + #E0FFFF + #FAFAD2 + #D3D3D3 + #D3D3D3 + #90EE90 + #FFB6C1 + #FFA07A + #20B2AA + #87CEFA + #778899 + #778899 + #B0C4DE + #FFFFE0 + #00FF00 + #32CD32 + #FAF0E6 + #FF00FF + #800000 + #66CDAA + #0000CD + #BA55D3 + #9370DB + #3CB371 + #7B68EE + #00FA9A + #48D1CC + #C71585 + #191970 + #F5FFFA + #FFE4E1 + #FFE4B5 + #FFDEAD + #000080 + #FDF5E6 + #808000 + #6B8E23 + #FFA500 + #FF4500 + #DA70D6 + #EEE8AA + #98FB98 + #AFEEEE + #DB7093 + #FFEFD5 + #FFDAB9 + #CD853F + #FFC0CB + #DDA0DD + #B0E0E6 + #800080 + #663399 + #FF0000 + #BC8F8F + #4169E1 + #8B4513 + #FA8072 + #F4A460 + #2E8B57 + #FFF5EE + #A0522D + #C0C0C0 + #87CEEB + #6A5ACD + #708090 + #708090 + #FFFAFA + #00FF7F + #4682B4 + #D2B48C + #008080 + #D8BFD8 + #FF6347 + #40E0D0 + #EE82EE + #F5DEB3 + #FFFFFF + #F5F5F5 + #FFFF00 + #9ACD32 + diff --git a/toonz/sources/common/tvrender/tcolorstyles.cpp b/toonz/sources/common/tvrender/tcolorstyles.cpp index 98d0da4..9a8cfee 100644 --- a/toonz/sources/common/tvrender/tcolorstyles.cpp +++ b/toonz/sources/common/tvrender/tcolorstyles.cpp @@ -292,13 +292,12 @@ void TColorStyle::makeIcon(const TDimension &d) { bbox = bbox.enlarge(TDimensionD(-10, -10)); checkErrorsByGL; - double scx = 0.9 * d.lx / bbox.getLx(); - double scy = 0.9 * d.ly / bbox.getLy(); - double sc = std::min(scx, scy); - double dx = (d.lx - bbox.getLx() * sc) * 0.5; - double dy = (d.ly - bbox.getLy() * sc) * 0.5; - TAffine aff = - TScale(scx, scy) * TTranslation(-bbox.getP00() + TPointD(dx, dy)); + double scx = 0.9 * d.lx / bbox.getLx(); + double scy = 0.9 * d.ly / bbox.getLy(); + double sc = std::min(scx, scy); + double dx = (d.lx - bbox.getLx() * sc) * 0.5; + double dy = (d.ly - bbox.getLy() * sc) * 0.5; + TAffine aff = TScale(sc) * TTranslation(-bbox.getP00() + TPointD(dx, dy)); checkErrorsByGL; if (isRegionStyle() && !isStrokeStyle()) aff = aff * TTranslation(-10, -10); @@ -388,7 +387,7 @@ class ColorStyleList { // singleton public: static ColorStyleList *instance() { static ColorStyleList *_instance = 0; - if (!_instance) _instance = new ColorStyleList(); + if (!_instance) _instance = new ColorStyleList(); return _instance; } diff --git a/toonz/sources/include/toonzqt/colorfield.h b/toonz/sources/include/toonzqt/colorfield.h index 4e44902..9148f26 100644 --- a/toonz/sources/include/toonzqt/colorfield.h +++ b/toonz/sources/include/toonzqt/colorfield.h @@ -37,6 +37,25 @@ class TPaletteHandle; namespace DVGui { //============================================================================= +// CommonChessboard singleton +//----------------------------------------------------------------------------- + +class DVAPI CommonChessboard final : public QObject { + Q_OBJECT + TRaster32P m_bgRas; + QPixmap m_bgPix; + void setChessboardColors(const TPixel32 &col1, const TPixel32 &col2); + +public: + CommonChessboard(); + + const QPixmap &getPixmap() { return m_bgPix; } + void update(); + + static CommonChessboard *instance(); +}; + +//============================================================================= // StyleSample //----------------------------------------------------------------------------- @@ -49,6 +68,10 @@ class DVAPI StyleSample final : public QWidget { bool m_drawEnable; TPixel m_chessColor1; TPixel m_chessColor2; + bool m_cloneStyle; + bool m_sysChessboard; + bool m_stretch; + QColor m_currentColor; bool m_isEditing; @@ -58,7 +81,7 @@ public: void enableClick(bool on) { m_clickEnabled = on; } - void setStyle(TColorStyle &style); + void setStyle(TColorStyle &style, int colorParameterIndex); TColorStyle *getStyle() const; void setColor(const TPixel32 &color); @@ -73,13 +96,16 @@ public: void setEnable(bool drawEnable) { m_drawEnable = drawEnable; } bool isEnable() const { return m_drawEnable; } + void setCloneStyle(bool enable) { m_cloneStyle = enable; } + void setSystemChessboard(bool enable) { m_sysChessboard = enable; } + protected: void paintEvent(QPaintEvent *event) override; void mousePressEvent(QMouseEvent *) override; void mouseDoubleClickEvent(QMouseEvent *event) override; signals: - void clicked(const TColorStyle &style); + void clicked(); }; //============================================================================= diff --git a/toonz/sources/include/toonzqt/styleeditor.h b/toonz/sources/include/toonzqt/styleeditor.h index e4e93c6..346a738 100644 --- a/toonz/sources/include/toonzqt/styleeditor.h +++ b/toonz/sources/include/toonzqt/styleeditor.h @@ -74,6 +74,35 @@ class LutCalibrator; //============================================= +class HexLineEdit : public QLineEdit { + Q_OBJECT + +public: + HexLineEdit(const QString &contents, QWidget *parent); + ~HexLineEdit() {} + + bool loadDefaultColorNames(bool reload); + bool hasUserColorNames(); + bool loadUserColorNames(bool reload); + void setStyle(TColorStyle &style, int index); + void updateColor(); + void setColor(TPixel color); + TPixel getColor() { return m_color; } + bool fromText(QString text); + bool fromHex(QString text); + +protected: + void loadColorTableXML(QMap &table, const TFilePath &fp); + void mousePressEvent(QMouseEvent *event) override; + void focusOutEvent(QFocusEvent *event) override; + void showEvent(QShowEvent *event) override; + + bool m_editing; + TPixel m_color; + static QMap s_defcolornames; // make it shared + static QMap s_usercolornames; // ... +}; + //============================================================================= namespace StyleEditorGUI { //============================================================================= @@ -238,14 +267,15 @@ signals: //============================================================================= /*! \brief The ColorSlider is used to set a color channel. - Inherits \b QSlider. + Inherits \b QAbstractSlider. This object show a bar which colors differ from minimum to maximum channel color value. */ -class DVAPI ColorSlider final : public QSlider { +class DVAPI ColorSlider final : public QAbstractSlider { Q_OBJECT + public: ColorSlider(Qt::Orientation orientation, QWidget *parent = 0); @@ -259,6 +289,9 @@ protected: void paintEvent(QPaintEvent *event) override; void mousePressEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + + void chandleMouse(int x, int y); // QIcon getFirstArrowIcon(); // QIcon getLastArrowIcon(); @@ -268,6 +301,11 @@ protected: private: ColorChannel m_channel; ColorModel m_color; + static int s_chandle_size; + static int s_chandle_tall; + +public: + static int s_slider_appearance; }; //============================================================================= @@ -614,6 +652,7 @@ class DVAPI StyleEditor final : public QWidget, public SaveLoadQSettings { PaletteController *m_paletteController; TPaletteHandle *m_paletteHandle; TPaletteHandle *m_cleanupPaletteHandle; + HexLineEdit *m_hexLineEdit; QWidget *m_parent; TXshLevelHandle *m_levelHandle; //!< for clearing the level cache when the color changed @@ -652,6 +691,8 @@ class DVAPI StyleEditor final : public QWidget, public SaveLoadQSettings { QAction *m_hsvAction; QAction *m_alphaAction; QAction *m_rgbAction; + QAction *m_hexAction; + QActionGroup *m_sliderAppearanceAG; TColorStyleP m_oldStyle; //!< A copy of current style \a before the last change. @@ -727,7 +768,8 @@ protected slots: void onStyleSwitched(); void onStyleChanged(bool isDragging); void onCleanupStyleChanged(bool isDragging); - void onOldStyleClicked(const TColorStyle &); + void onOldStyleClicked(); + void onNewStyleClicked(); void updateOrientationButton(); void checkPaletteLock(); // called (e.g.) by PaletteController when an other StyleEditor change the @@ -752,10 +794,15 @@ protected slots: void onParamStyleChanged(bool isDragging); + void onHexChanged(); + void onSpecialButtonToggled(bool on); void onCustomButtonToggled(bool on); void onVectorBrushButtonToggled(bool on); + void onSliderAppearanceSelected(QAction *); + void onPopupMenuAboutToShow(); + private: QFrame *createBottomWidget(); QFrame *createVectorPage(); diff --git a/toonz/sources/toonz/preferencespopup.cpp b/toonz/sources/toonz/preferencespopup.cpp index dda75ac..a655dc4 100644 --- a/toonz/sources/toonz/preferencespopup.cpp +++ b/toonz/sources/toonz/preferencespopup.cpp @@ -706,6 +706,12 @@ void PreferencesPopup::onTranspCheckDataChanged() { invalidateIcons(); } //----------------------------------------------------------------------------- +void PreferencesPopup::onChessboardChanged() { + CommonChessboard::instance()->update(); +} + +//----------------------------------------------------------------------------- + void PreferencesPopup::onSVNEnabledChanged() { if (m_pref->getBoolValue(SVNEnabled)) { if (!VersionControl::instance()->testSetup()) @@ -1173,7 +1179,8 @@ QString PreferencesPopup::getUIString(PreferencesItemId id) { {ffmpegPath, tr("FFmpeg Path:")}, {ffmpegTimeout, tr("FFmpeg Timeout:")}, {fastRenderPath, tr("Fast Render Path:")}, - {ffmpegMultiThread, tr("Allow Multi-Thread in FFMPEG Rendering (UNSTABLE)")}, + {ffmpegMultiThread, + tr("Allow Multi-Thread in FFMPEG Rendering (UNSTABLE)")}, // Drawing {scanLevelType, tr("Scan File Format:")}, @@ -2043,6 +2050,10 @@ QWidget* PreferencesPopup::createColorsPage() { &PreferencesPopup::notifySceneChanged); m_onEditedFuncMap.insert(chessboardColor2, &PreferencesPopup::notifySceneChanged); + m_onEditedFuncMap.insert(chessboardColor1, + &PreferencesPopup::onChessboardChanged); + m_onEditedFuncMap.insert(chessboardColor2, + &PreferencesPopup::onChessboardChanged); return widget; } diff --git a/toonz/sources/toonz/preferencespopup.h b/toonz/sources/toonz/preferencespopup.h index df95d9b..06d986c 100644 --- a/toonz/sources/toonz/preferencespopup.h +++ b/toonz/sources/toonz/preferencespopup.h @@ -147,6 +147,7 @@ private: void onOnionColorChanged(); // Colors void onTranspCheckDataChanged(); + void onChessboardChanged(); // Version Control void onSVNEnabledChanged(); // Commonly used diff --git a/toonz/sources/toonzlib/mypaintbrushstyle.cpp b/toonz/sources/toonzlib/mypaintbrushstyle.cpp index eecc712..a23a084 100644 --- a/toonz/sources/toonzlib/mypaintbrushstyle.cpp +++ b/toonz/sources/toonzlib/mypaintbrushstyle.cpp @@ -149,8 +149,8 @@ static std::string mybToVersion3(std::string origStr) { outStr += " \"inputs\": {\n"; while (pipe != line.length()) { if (startPos > 0) outStr += ",\n"; - startPos = pipe + 1; - pipe = line.find("|", startPos); + startPos = pipe + 1; + pipe = line.find("|", startPos); if (pipe == std::string::npos) pipe = line.length(); settingInfo = line.substr(startPos, pipe - startPos); int firstCharPos = settingInfo.find_first_not_of(" "); @@ -161,7 +161,7 @@ static std::string mybToVersion3(std::string origStr) { baseValue = settingInfo.substr(firstCharPos, pipe - startPos); int comma = baseValue.find(", "); if (comma == std::string::npos) comma = baseValue.length(); - std::string value = baseValue.substr(0, comma); + std::string value = baseValue.substr(0, comma); std::replace(value.begin(), value.end(), '(', '['); std::replace(value.begin(), value.end(), ')', ']'); std::replace(value.begin(), value.end(), ' ', ','); @@ -250,28 +250,43 @@ void TMyPaintBrushStyle::resetBaseValues() { void TMyPaintBrushStyle::makeIcon(const TDimension &d) { TFilePath path = m_fullpath.getParentDir() + (m_fullpath.getWideName() + L"_prev.png"); + TPointD offset(0, 0); if (!m_preview) { m_icon = TRaster32P(d); m_icon->fill(TPixel32::Red); } else if (m_preview->getSize() == d) { m_icon = m_preview; } else { - m_icon = TRaster32P(d); - double sx = (double)d.lx / (double)m_preview->getLx(); - double sy = (double)d.ly / (double)m_preview->getLy(); - TRop::resample(m_icon, m_preview, TScale(sx, sy)); + m_icon = TRaster32P(d); + if (d.lx != d.ly) { + TPixel32 col = getMainColor(); + if (col.m == 255) + m_icon->fill(col); + else { + TRaster32P fg(d); + fg->fill(premultiply(col)); + TRop::checkBoard(m_icon, TPixel32::Black, TPixel32::White, + TDimensionD(6, 6), TPointD()); + TRop::over(m_icon, fg); + } + } + double sx = (double)d.lx / (double)m_preview->getLx(); + double sy = (double)d.ly / (double)m_preview->getLy(); + double scale = std::min(sx, sy); + TRop::quickPut(m_icon, m_preview, TScale(scale)); } // paint color marker if (d.lx > 0 && d.ly > 0) { - int size = std::min(1 + std::min(d.lx, d.ly) * 2 / 3, + int size = std::min(1 + std::min(d.lx, d.ly) * 2 / 3, 1 + std::max(d.lx, d.ly) / 2); TPixel32 color = getMainColor(); + color.m = 255; // show full opac color for (int y = 0; y < size; ++y) { - TPixel32 *p = m_icon->pixels(d.ly - y - 1); - TPixel32 *endp = p + size - y - 1; + TPixel32 *p = m_icon->pixels(d.ly - y - 1); + TPixel32 *endp = p + size - y - 1; for (; p != endp; ++p) *p = color; - *p = blend(*p, color, 0.5); + *p = blend(*p, color, 0.5); } } } diff --git a/toonz/sources/toonzqt/Resources/h_chandle_arrow.svg b/toonz/sources/toonzqt/Resources/h_chandle_arrow.svg new file mode 100644 index 0000000..34c1405 --- /dev/null +++ b/toonz/sources/toonzqt/Resources/h_chandle_arrow.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/toonz/sources/toonzqt/Resources/v_chandle_arrow.svg b/toonz/sources/toonzqt/Resources/v_chandle_arrow.svg new file mode 100644 index 0000000..1863d86 --- /dev/null +++ b/toonz/sources/toonzqt/Resources/v_chandle_arrow.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/toonz/sources/toonzqt/colorfield.cpp b/toonz/sources/toonzqt/colorfield.cpp index 52bc928..dfb4f53 100644 --- a/toonz/sources/toonzqt/colorfield.cpp +++ b/toonz/sources/toonzqt/colorfield.cpp @@ -48,6 +48,31 @@ QPixmap getIconPm(const QColor &color) { } // namespace //============================================================================= + +CommonChessboard *CommonChessboard::instance() { + static CommonChessboard _instance; + return &_instance; +} + +CommonChessboard::CommonChessboard() : m_bgRas(40.0, 40.0) { update(); } + +void CommonChessboard::setChessboardColors(const TPixel32 &col1, + const TPixel32 &col2) { + TRop::checkBoard(m_bgRas, col1, col2, + TDimensionD(m_bgRas->getLx() / 8, m_bgRas->getLy() / 8), + TPointD(0, 0)); + QImage img(m_bgRas->getRawData(), m_bgRas->getLx(), m_bgRas->getLy(), + QImage::Format_ARGB32); + m_bgPix = QPixmap::fromImage(img); +} + +void CommonChessboard::update() { + TPixel32 col1, col2; + Preferences::instance()->getChessboardColors(col1, col2); + setChessboardColors(col1, col2); +} + +//============================================================================= /*! \class DVGui::StyleSample \brief The StyleSample class provides to view a square color. @@ -82,6 +107,8 @@ StyleSample::StyleSample(QWidget *parent, int sizeX, int sizeY) , m_clickEnabled(false) , m_chessColor1(0, 0, 0) , m_chessColor2(255, 255, 255) + , m_sysChessboard(false) + , m_stretch(true) , m_isEditing(false) { setMinimumSize(sizeX, sizeY); setColor(TPixel32::Transparent); @@ -106,17 +133,39 @@ TColorStyle *StyleSample::getStyle() const { return m_style; } /*! Update current square colore and, if click event is enable set current StyleSample \b TColorStyle style to \b style. */ -void StyleSample::setStyle(TColorStyle &style) { +void StyleSample::setStyle(TColorStyle &style, int colorParameterIndex) { + // Store current color + TPixel32 color = style.getColorParamValue(colorParameterIndex); + m_currentColor = QColor(color.r, color.g, color.b, color.m); + if (LutManager::instance()->isValid()) + LutManager::instance()->convert(m_currentColor); + /*-- TSolidColorStyleの場合のみ、単色塗りつぶし --*/ - if (style.getTagId() == 3) + if (style.getTagId() == 3) { setColor(style.getMainColor()); - else { - TRaster32P icon = - style.getIcon(qsize2Dimension(m_samplePixmap.rect().size())); + m_stretch = true; + } else { + TDimension iconDim(width(), height()); + + // obtain square icon for the TMyPaintBrushStyle + // so that the checkerboard color will become consistent with solido style + // when the main color is semi-transparent. + if (style.getTagId() == 4001) { + int d = std::min(width(), height()); + iconDim = TDimension(d, d); + } + + TRaster32P icon = style.getIcon(iconDim); + // TRaster32P icon = + // style.getIcon(qsize2Dimension(m_samplePixmap.rect().size())); m_samplePixmap = rasterToQImage(icon, false); // modified in 6.2 + m_stretch = false; update(); } - if (m_clickEnabled) m_style = style.clone(); + if (m_cloneStyle) { + if (m_style) delete m_style; // avoid memory leak + m_style = style.clone(); + } } //----------------------------------------------------------------------------- @@ -149,10 +198,24 @@ void StyleSample::setChessboardColors(const TPixel32 &col1, void StyleSample::paintEvent(QPaintEvent *event) { if (!isEnable()) return; QPainter painter(this); - QImage img(m_bgRas->getRawData(), m_bgRas->getLx(), m_bgRas->getLy(), - QImage::Format_ARGB32); - painter.drawImage(0, 0, img.scaled(size())); - painter.drawImage(0, 0, m_samplePixmap.scaled(size())); + if (m_sysChessboard) { + painter.drawTiledPixmap(rect(), + DVGui::CommonChessboard::instance()->getPixmap()); + } else { + QImage img(m_bgRas->getRawData(), m_bgRas->getLx(), m_bgRas->getLy(), + QImage::Format_ARGB32); + painter.drawImage(0, 0, img.scaled(size())); + } + if (m_stretch) { + painter.drawImage(0, 0, m_samplePixmap.scaled(size())); + } else { + // put the icon on the left + int x = 0; + // int x = (width() - m_samplePixmap.width()) / 2; + int y = (height() - m_samplePixmap.height()) / 2; + painter.fillRect(rect(), m_currentColor); + painter.drawImage(x, y, m_samplePixmap); + } if (m_isEditing) { // QRect rect(0,0,m_bgRas->getLx(),m_bgRas->getLy()); painter.setPen(Qt::white); @@ -168,8 +231,8 @@ void StyleSample::paintEvent(QPaintEvent *event) { clicked(const TColorStyle &style). */ void StyleSample::mousePressEvent(QMouseEvent *event) { - if (m_style && m_clickEnabled) - emit clicked(*m_style); + if (m_clickEnabled) + emit clicked(); else event->ignore(); } @@ -771,7 +834,7 @@ CleanupColorField::CleanupColorField(QWidget *parent, } } - m_colorSample->setStyle(*cleanupStyle); + m_colorSample->setStyle(*cleanupStyle, 0); //---- layout @@ -828,7 +891,7 @@ CleanupColorField::CleanupColorField(QWidget *parent, void CleanupColorField::updateColor() { if (m_cleanupStyle->canUpdate()) { m_cleanupStyle->invalidateIcon(); - m_colorSample->setStyle(*m_cleanupStyle); + m_colorSample->setStyle(*m_cleanupStyle, 0); m_brightnessChannel->setChannel(m_cleanupStyle->getBrightness()); if (m_cleanupStyle->isContrastEnabled()) @@ -860,7 +923,7 @@ void CleanupColorField::setColor(const TPixel32 &color) { m_cleanupStyle->setMainColor(color); m_cleanupStyle->invalidateIcon(); - m_colorSample->setStyle(*m_cleanupStyle); + m_colorSample->setStyle(*m_cleanupStyle, 0); m_ph->notifyColorStyleChanged(false); } @@ -877,7 +940,7 @@ void CleanupColorField::setOutputColor(const TPixel32 &color) { m_cleanupStyle->setColorParamValue(1, color); m_cleanupStyle->invalidateIcon(); - m_colorSample->setStyle(*m_cleanupStyle); + m_colorSample->setStyle(*m_cleanupStyle, 0); m_ph->notifyColorStyleChanged(); } @@ -891,7 +954,7 @@ void CleanupColorField::setStyle(TColorStyle *style) { m_cleanupStyle->setMainColor(style->getMainColor()); m_cleanupStyle->setColorParamValue(1, style->getColorParamValue(1)); m_cleanupStyle->invalidateIcon(); - m_colorSample->setStyle(*m_cleanupStyle); + m_colorSample->setStyle(*m_cleanupStyle, 0); m_ph->notifyColorStyleChanged(); } diff --git a/toonz/sources/toonzqt/styleeditor.cpp b/toonz/sources/toonzqt/styleeditor.cpp index 78334a9..9953396 100644 --- a/toonz/sources/toonzqt/styleeditor.cpp +++ b/toonz/sources/toonzqt/styleeditor.cpp @@ -37,6 +37,7 @@ #include "tvectorrenderdata.h" #include "tsimplecolorstyles.h" #include "tvectorbrushstyle.h" +#include "tenv.h" // Qt includes #include @@ -58,9 +59,224 @@ #include #include +namespace { +enum ColorSliderAppearance { + RelativeColoredTriangleHandle, + AbsoluteColoredLineHandle +}; +} +TEnv::IntVar StyleEditorColorSliderAppearance( + "StyleEditorColorSliderAppearance", RelativeColoredTriangleHandle); + using namespace StyleEditorGUI; //***************************************************************************** +// Hex line editor +//***************************************************************************** + +#define COLORNAMES_FILE "colornames.txt" + +QMap HexLineEdit::s_defcolornames; +QMap HexLineEdit::s_usercolornames; + +HexLineEdit::HexLineEdit(const QString &contents, QWidget *parent) + : QLineEdit(contents, parent), m_editing(false), m_color(0, 0, 0) {} + +bool HexLineEdit::loadDefaultColorNames(bool reload) { + TFilePath defCTFp = TEnv::getConfigDir() + COLORNAMES_FILE; + + // Load default color names + try { + if (reload || s_defcolornames.size() == 0) { + s_defcolornames.clear(); + loadColorTableXML(s_defcolornames, defCTFp); + } + } catch (...) { + return false; + } + return true; +} + +bool HexLineEdit::hasUserColorNames() { + TFilePath userCTFp = ToonzFolder::getMyModuleDir() + COLORNAMES_FILE; + return TFileStatus(userCTFp).doesExist(); +} + +bool HexLineEdit::loadUserColorNames(bool reload) { + TFilePath userCTFp = ToonzFolder::getMyModuleDir() + COLORNAMES_FILE; + + // Load user color names (if exists...) + if (TFileStatus(userCTFp).doesExist()) { + try { + if (reload || s_usercolornames.size() == 0) { + s_usercolornames.clear(); + loadColorTableXML(s_usercolornames, userCTFp); + } + } catch (...) { + return false; + } + } + return true; +} + +void HexLineEdit::updateColor() { + if (m_color.m == 255) { + // Opaque, omit alpha + setText(QString("#%1%2%3") + .arg(m_color.r, 2, 16, QLatin1Char('0')) + .arg(m_color.g, 2, 16, QLatin1Char('0')) + .arg(m_color.b, 2, 16, QLatin1Char('0')) + .toUpper()); + } else { + setText(QString("#%1%2%3%4") + .arg(m_color.r, 2, 16, QLatin1Char('0')) + .arg(m_color.g, 2, 16, QLatin1Char('0')) + .arg(m_color.b, 2, 16, QLatin1Char('0')) + .arg(m_color.m, 2, 16, QLatin1Char('0')) + .toUpper()); + } +} + +void HexLineEdit::setColor(TPixel color) { + if (m_color != color) { + m_color = color; + if (isVisible()) updateColor(); + } +} + +bool HexLineEdit::fromText(QString text) { + static QRegExp space("\\s"); + text.remove(space); + if (text.size() == 0) return false; + if (text[0] == "#") return fromHex(text); + text = text.toLower(); // table names are lowercase + + // Find color from tables, user takes priority + QMap::const_iterator it; + it = s_usercolornames.constFind(text); + if (it == s_usercolornames.constEnd()) { + it = s_defcolornames.constFind(text); + if (it == s_defcolornames.constEnd()) return false; + } + + QString hexText = it.value(); + return fromHex(hexText); +} + +// Whitespaces can break this implementation, thankfully +// '.fromText' already took care of it. +bool HexLineEdit::fromHex(QString text) { + if (text.size() == 0) return false; + if (text[0] != "#") return false; + text.remove(0, 1); + bool ok; + uint parsedValue = text.toUInt(&ok, 16); + if (!ok) return false; + + switch (text.length()) { + case 8: // #RRGGBBAA + m_color.r = parsedValue >> 24; + m_color.g = parsedValue >> 16; + m_color.b = parsedValue >> 8; + m_color.m = parsedValue; + break; + case 6: // #RRGGBB + m_color.r = parsedValue >> 16; + m_color.g = parsedValue >> 8; + m_color.b = parsedValue; + m_color.m = 255; + break; + case 4: // #RGBA + m_color.r = (parsedValue >> 12) & 15; + m_color.r |= m_color.r << 4; + m_color.g = (parsedValue >> 8) & 15; + m_color.g |= m_color.g << 4; + m_color.b = (parsedValue >> 4) & 15; + m_color.b |= m_color.b << 4; + m_color.m = parsedValue & 15; + m_color.m |= m_color.m << 4; + break; + case 3: // #RGB + m_color.r = (parsedValue >> 8) & 15; + m_color.r |= m_color.r << 4; + m_color.g = (parsedValue >> 4) & 15; + m_color.g |= m_color.g << 4; + m_color.b = parsedValue & 15; + m_color.b |= m_color.b << 4; + m_color.m = 255; + break; + case 2: // #VV (non-standard) + m_color.r = parsedValue; + m_color.g = m_color.r; + m_color.b = m_color.r; + m_color.m = 255; + break; + case 1: // #V (non-standard) + m_color.r = parsedValue & 15; + m_color.r |= m_color.r << 4; + m_color.g = m_color.r; + m_color.b = m_color.r; + m_color.m = 255; + break; + default: + return false; + } + updateColor(); + return true; +} + +void HexLineEdit::loadColorTableXML(QMap &table, + const TFilePath &fp) { + if (!TFileStatus(fp).doesExist()) throw TException("File not found"); + + TIStream is(fp); + if (!is) throw TException("Can't read color names"); + + std::string tagName; + if (!is.matchTag(tagName) || tagName != "colors") + throw TException("Not a color names file"); + + while (!is.matchEndTag()) { + if (!is.matchTag(tagName)) throw TException("Expected tag"); + if (tagName == "color") { + QString name, hex; + name = QString::fromStdString(is.getTagAttribute("name")); + std::string hexs; + is >> hexs; + hex = QString::fromStdString(hexs); + if (name.size() != 0 && hex.size() != 0) + table.insert(name.toLower(), hex); + if (!is.matchEndTag()) throw TException("Expected end tag"); + } else + throw TException("unexpected tag /" + tagName + "/"); + } +} + +void HexLineEdit::setStyle(TColorStyle &style, int index) { + setColor(style.getColorParamValue(index)); +} + +void HexLineEdit::mousePressEvent(QMouseEvent *event) { + QLineEdit::mousePressEvent(event); + // Make Ctrl key disable select all so the user can click a specific character + // after a focus-in, this likely will fall into a hidden feature thought. + bool ctrlDown = event->modifiers() & Qt::ControlModifier; + if (!m_editing && !ctrlDown) selectAll(); + m_editing = true; +} + +void HexLineEdit::focusOutEvent(QFocusEvent *event) { + QLineEdit::focusOutEvent(event); + deselect(); + m_editing = false; +} + +void HexLineEdit::showEvent(QShowEvent *event) { + QLineEdit::showEvent(event); + updateColor(); +} + +//***************************************************************************** // UndoPaletteChange definition //***************************************************************************** @@ -474,24 +690,26 @@ QPixmap makeLinearShading(const ShadeMaker &shadeMaker, int size, QPixmap makeLinearShading(const ColorModel &color, ColorChannel channel, int size, bool isVertical) { + bool relative = + ColorSlider::s_slider_appearance == RelativeColoredTriangleHandle; switch (channel) { case eRed: - if (isVertical) + if (isVertical || relative) return makeLinearShading(RedShadeMaker(color), size, isVertical); else return QPixmap(":Resources/grad_r.png").scaled(size, 1); case eGreen: - if (isVertical) + if (isVertical || relative) return makeLinearShading(GreenShadeMaker(color), size, isVertical); else return QPixmap(":Resources/grad_g.png").scaled(size, 1); case eBlue: - if (isVertical) + if (isVertical || relative) return makeLinearShading(BlueShadeMaker(color), size, isVertical); else return QPixmap(":Resources/grad_b.png").scaled(size, 1); case eAlpha: - if (isVertical) + if (isVertical || relative) return makeLinearShading(AlphaShadeMaker(color), size, isVertical); else return QPixmap(":Resources/grad_m.png").scaled(size, 1); @@ -579,6 +797,13 @@ HexagonalColorWheel::~HexagonalColorWheel() { void HexagonalColorWheel::updateColorCalibration() { if (Preferences::instance()->isColorCalibrationEnabled()) { + // prevent to initialize LutCalibrator before this instance is initialized + // or OT may crash due to missing OpenGL context + if (m_firstInitialized) { + cueCalibrationUpdate(); + return; + } + makeCurrent(); if (!m_lutCalibrator) m_lutCalibrator = new LutCalibrator(); @@ -981,8 +1206,13 @@ void SquaredColorWheel::setChannel(int channel) { // ColorSlider implementation //***************************************************************************** +// Adquire size later... +int ColorSlider::s_chandle_size = -1; +int ColorSlider::s_chandle_tall = -1; +int ColorSlider::s_slider_appearance = -1; + ColorSlider::ColorSlider(Qt::Orientation orientation, QWidget *parent) - : QSlider(orientation, parent), m_channel(eRed), m_color() { + : QAbstractSlider(parent), m_channel(eRed), m_color() { setFocusPolicy(Qt::NoFocus); setOrientation(orientation); @@ -992,6 +1222,14 @@ ColorSlider::ColorSlider(Qt::Orientation orientation, QWidget *parent) setMinimumHeight(7); setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + // Get color handle size once + if (s_chandle_size == -1) { + QImage chandle = QImage(":Resources/h_chandle_arrow.svg"); + s_chandle_size = chandle.width(); + s_chandle_tall = chandle.height(); + s_slider_appearance = StyleEditorColorSliderAppearance; + } + // Attenzione: necessario per poter individuare l'oggetto nel file di // definizione dello stile setObjectName("colorSlider"); @@ -1020,19 +1258,34 @@ void ColorSlider::paintEvent(QPaintEvent *event) { int h = height(); bool isVertical = orientation() == Qt::Vertical; + bool isLineHandle = + ColorSlider::s_slider_appearance == AbsoluteColoredLineHandle; - if (!isVertical) h -= 5; + if (isVertical) { + y += s_chandle_size / 2; + h -= s_chandle_size; + w -= 3; + } else { + x += s_chandle_size / 2; + w -= s_chandle_size; + h -= 3; + if (isLineHandle) { + y += 1; + h -= 2; + } + } + if (w < 2 || h < 2) return; QPixmap bgPixmap = makeLinearShading(m_color, m_channel, isVertical ? h : w, isVertical); if (m_channel == eAlpha) { - static QPixmap checkboard(":Resources/backg.png"); - p.drawTiledPixmap(x, y + 1, w, h, checkboard); + p.drawTiledPixmap(x, y, w, h, + DVGui::CommonChessboard::instance()->getPixmap()); } if (!bgPixmap.isNull()) { - p.drawTiledPixmap(x, y + 1, w, h, bgPixmap); + p.drawTiledPixmap(x, y, w, h, bgPixmap); } /*! @@ -1040,59 +1293,34 @@ void ColorSlider::paintEvent(QPaintEvent *event) { In this case we draw "manually" the slider handle at correct position */ if (isVertical) { - int pos = QStyle::sliderPositionFromValue(minimum(), maximum(), value(), - h - 9, true); - static QPixmap vHandlePixmap(":Resources/v_chandle.png"); - p.drawPixmap(0, pos, vHandlePixmap); + static QPixmap vHandlePixmap = + svgToPixmap(":Resources/v_chandle_arrow.svg"); + int pos = QStyle::sliderPositionFromValue(0, maximum(), value(), h, true); + p.drawPixmap(width() - s_chandle_tall, pos, vHandlePixmap); } else { - static QPixmap hHandleUpPm(":Resources/h_chandleUp.png"); - static QPixmap hHandleDownPm(":Resources/h_chandleDown.png"); - static QPixmap hHandleCenterPm(":Resources/h_chandleCenter.png"); - int pos = QStyle::sliderPositionFromValue( - 0, maximum(), value(), width() - hHandleCenterPm.width(), false); - p.drawPixmap(pos, 0, hHandleUpPm); - p.drawPixmap(pos, height() - hHandleDownPm.height(), hHandleDownPm); - p.drawPixmap(pos, hHandleUpPm.height(), hHandleCenterPm.width(), - height() - hHandleUpPm.height() - hHandleDownPm.height(), - hHandleCenterPm); + int pos = QStyle::sliderPositionFromValue(0, maximum(), value(), w, false); + if (isLineHandle) { + static QPixmap hHandleUpPm(":Resources/h_chandleUp.png"); + static QPixmap hHandleDownPm(":Resources/h_chandleDown.png"); + static QPixmap hHandleCenterPm(":Resources/h_chandleCenter.png"); + int linePos = pos + (s_chandle_size - hHandleCenterPm.width()) / 2; + p.drawPixmap(linePos, 0, hHandleUpPm); + p.drawPixmap(linePos, height() - hHandleDownPm.height(), hHandleDownPm); + p.drawPixmap(linePos, hHandleUpPm.height(), hHandleCenterPm.width(), + height() - hHandleUpPm.height() - hHandleDownPm.height(), + hHandleCenterPm); + } else { + static QPixmap hHandlePixmap = + svgToPixmap(":Resources/h_chandle_arrow.svg"); + p.drawPixmap(pos, height() - s_chandle_tall, hHandlePixmap); + } } }; //----------------------------------------------------------------------------- void ColorSlider::mousePressEvent(QMouseEvent *event) { - // vogliamo che facendo click sullo slider, lontano dall'handle - // l'handle salti subito nella posizione giusta invece di far partire - // l'autorepeat. - // - // cfr. qslider.cpp:429: sembra che questo comportamento si possa ottenere - // anche con SH_Slider_AbsoluteSetButtons. Ma non capisco come si possa fare - // per definire quest hint - QStyleOptionSlider opt; - initStyleOption(&opt); - const QRect handleRect = style()->subControlRect( - QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this); - if (!handleRect.contains(event->pos())) { - const QPoint handleCenter = handleRect.center(); - const QRect grooveRect = style()->subControlRect( - QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, this); - int pos, span; - bool upsideDown = false; - if (opt.orientation == Qt::Vertical) { - upsideDown = true; - int handleSize = handleRect.height(); - pos = event->pos().y() - handleSize / 2; - span = grooveRect.height() - handleSize; - } else { - int handleSize = QPixmap(":Resources/h_chandleCenter.png").width(); - pos = event->pos().x() - handleSize / 2; - span = grooveRect.width() - handleSize; - } - int value = QStyle::sliderValueFromPosition(minimum(), maximum(), pos, span, - upsideDown); - setValue(value); - } - QSlider::mousePressEvent(event); + chandleMouse(event->pos().x(), event->pos().y()); } //----------------------------------------------------------------------------- @@ -1101,6 +1329,26 @@ void ColorSlider::mouseReleaseEvent(QMouseEvent *event) { emit sliderReleased(); } +//----------------------------------------------------------------------------- + +void ColorSlider::mouseMoveEvent(QMouseEvent *event) { + chandleMouse(event->pos().x(), event->pos().y()); +} + +//----------------------------------------------------------------------------- + +void ColorSlider::chandleMouse(int mouse_x, int mouse_y) { + if (orientation() == Qt::Vertical) { + int pos = mouse_y - s_chandle_size / 2; + int span = height() - s_chandle_size; + setValue(QStyle::sliderValueFromPosition(0, maximum(), pos, span, true)); + } else { + int pos = mouse_x - s_chandle_size / 2; + int span = width() - s_chandle_size; + setValue(QStyle::sliderValueFromPosition(0, maximum(), pos, span, false)); + } +} + //***************************************************************************** // ArrowButton implementation //***************************************************************************** @@ -1425,7 +1673,7 @@ StyleEditorPage::StyleEditorPage(QWidget *parent) : QFrame(parent) { ColorParameterSelector::ColorParameterSelector(QWidget *parent) : QWidget(parent) - , m_index(-1) + , m_index(0) , m_chipSize(21, 21) , m_chipOrigin(0, 1) , m_chipDelta(21, 0) { @@ -1463,6 +1711,7 @@ void ColorParameterSelector::setStyle(const TColorStyle &style) { clear(); return; } + show(); if (m_colors.size() != count) { m_index = 0; m_colors.resize(count); @@ -1479,8 +1728,12 @@ void ColorParameterSelector::setStyle(const TColorStyle &style) { void ColorParameterSelector::clear() { if (m_colors.size() != 0) m_colors.clear(); - m_index = -1; - update(); + m_index = 0; + if (isVisible()) { + hide(); + update(); + qApp->processEvents(); + } } //----------------------------------------------------------------------------- @@ -1490,7 +1743,7 @@ void ColorParameterSelector::mousePressEvent(QMouseEvent *event) { int index = pos.x() / m_chipDelta.x(); QRect chipRect(index * m_chipDelta, m_chipSize); if (chipRect.contains(pos)) { - m_index = index; + if (index < m_colors.size()) m_index = index; emit colorParamChanged(); update(); } @@ -2391,7 +2644,7 @@ void SpecialStyleChooserPage::loadItems() { tagId == 2000 || // imagepattern tagId == 2800 || // imagepattern tagId == 2001 || // cleanup - tagId == 2002 || // ?? + tagId == 2002 || // black cleanup tagId == 3000 || // vector brush tagId == 4001 // mypaint brush ) @@ -3002,50 +3255,6 @@ StyleEditor::StyleEditor(PaletteController *paletteController, QWidget *parent) m_styleChooser->setFocusPolicy(Qt::NoFocus); QFrame *bottomWidget = createBottomWidget(); - - m_toolBar = new QToolBar(this); - m_toolBar->setMovable(false); - m_toolBar->setMaximumHeight(22); - m_toolBar->addWidget(m_colorParameterSelector); - - QMenu *menu = new QMenu(); - m_wheelAction = new QAction(tr("Wheel"), this); - m_hsvAction = new QAction(tr("HSV"), this); - m_alphaAction = new QAction(tr("Alpha"), this); - m_rgbAction = new QAction(tr("RGB"), this); - - m_wheelAction->setCheckable(true); - m_hsvAction->setCheckable(true); - m_alphaAction->setCheckable(true); - m_rgbAction->setCheckable(true); - m_wheelAction->setChecked(true); - m_hsvAction->setChecked(true); - m_alphaAction->setChecked(true); - m_rgbAction->setChecked(true); - menu->addAction(m_wheelAction); - menu->addAction(m_hsvAction); - menu->addAction(m_alphaAction); - menu->addAction(m_rgbAction); - - QToolButton *toolButton = new QToolButton(this); - toolButton->setIcon(createQIcon("menu")); - toolButton->setFixedSize(22, 22); - toolButton->setMenu(menu); - toolButton->setPopupMode(QToolButton::InstantPopup); - toolButton->setToolTip(tr("Show or hide parts of the Color Page.")); - QToolBar *displayToolbar = new QToolBar(this); - m_toggleOrientationAction = - displayToolbar->addAction(createQIcon("orientation_h"), ""); - m_toggleOrientationAction->setToolTip( - tr("Toggle orientation of the Color Page.")); - QWidget *toggleOrientationButton = - displayToolbar->widgetForAction(m_toggleOrientationAction); - toggleOrientationButton->setFixedSize(22, 22); - toggleOrientationButton->setFocusPolicy(Qt::NoFocus); - displayToolbar->addWidget(toolButton); - displayToolbar->setMaximumHeight(22); - displayToolbar->setIconSize(QSize(16, 16)); - /* ------- layout ------- */ QGridLayout *mainLayout = new QGridLayout; mainLayout->setMargin(0); @@ -3063,8 +3272,8 @@ StyleEditor::StyleEditor(PaletteController *paletteController, QWidget *parent) mainLayout->addWidget(m_tabBarContainer, 0, 0, 1, 2); mainLayout->addWidget(m_styleChooser, 1, 0, 1, 2); mainLayout->addWidget(bottomWidget, 2, 0, 1, 2); - mainLayout->addWidget(m_toolBar, 3, 0); - mainLayout->addWidget(displayToolbar, 3, 1); + // mainLayout->addWidget(m_toolBar, 3, 0); + // mainLayout->addWidget(displayToolbar, 3, 1); } mainLayout->setColumnStretch(0, 1); mainLayout->setRowStretch(1, 1); @@ -3097,19 +3306,6 @@ StyleEditor::StyleEditor(PaletteController *paletteController, QWidget *parent) ret = ret && connect(m_plainColorPage, SIGNAL(colorChanged(const ColorModel &, bool)), this, SLOT(onColorChanged(const ColorModel &, bool))); - - ret = ret && connect(m_wheelAction, SIGNAL(toggled(bool)), - m_plainColorPage->m_wheelFrame, SLOT(setVisible(bool))); - ret = ret && connect(m_hsvAction, SIGNAL(toggled(bool)), - m_plainColorPage->m_hsvFrame, SLOT(setVisible(bool))); - ret = ret && connect(m_alphaAction, SIGNAL(toggled(bool)), - m_plainColorPage->m_alphaFrame, SLOT(setVisible(bool))); - ret = ret && connect(m_rgbAction, SIGNAL(toggled(bool)), - m_plainColorPage->m_rgbFrame, SLOT(setVisible(bool))); - ret = ret && connect(m_toggleOrientationAction, SIGNAL(triggered()), - m_plainColorPage, SLOT(toggleOrientation())); - ret = ret && connect(m_toggleOrientationAction, SIGNAL(triggered()), this, - SLOT(updateOrientationButton())); assert(ret); /* ------- initial conditions ------- */ enable(false, false, false); @@ -3135,13 +3331,14 @@ void StyleEditor::setPaletteHandle(TPaletteHandle* paletteHandle) QFrame *StyleEditor::createBottomWidget() { QFrame *bottomWidget = new QFrame(this); m_autoButton = new QPushButton(tr("Auto")); - m_oldColor = new DVGui::StyleSample(this, 42, 20); - m_newColor = new DVGui::StyleSample(this, 42, 20); + m_oldColor = new DVGui::StyleSample(this, 42, 24); + m_newColor = new DVGui::StyleSample(this, 42, 24); m_applyButton = new QPushButton(tr("Apply")); bottomWidget->setFrameStyle(QFrame::StyledPanel); bottomWidget->setObjectName("bottomWidget"); bottomWidget->setContentsMargins(0, 0, 0, 0); + bottomWidget->setMinimumHeight(60); m_applyButton->setToolTip(tr("Apply changes to current style")); m_applyButton->setDisabled(m_paletteController->isColorAutoApplyEnabled()); m_applyButton->setFocusPolicy(Qt::NoFocus); @@ -3154,31 +3351,120 @@ QFrame *StyleEditor::createBottomWidget() { m_oldColor->setToolTip(tr("Return To Previous Style")); m_oldColor->enableClick(true); m_oldColor->setEnable(false); + m_oldColor->setSystemChessboard(true); + m_oldColor->setCloneStyle(true); m_newColor->setToolTip(tr("Current Style")); + m_newColor->enableClick(true); m_newColor->setEnable(false); + m_newColor->setSystemChessboard(true); + + m_hexLineEdit = new HexLineEdit("", this); + m_hexLineEdit->setObjectName("HexLineEdit"); + m_hexLineEdit->setFixedWidth(75); + m_hexLineEdit->loadDefaultColorNames(false); + m_hexLineEdit->loadUserColorNames(false); + + m_toolBar = new QToolBar(this); + m_toolBar->setMovable(false); + m_toolBar->setMaximumHeight(22); + QMenu *menu = new QMenu(); + m_wheelAction = new QAction(tr("Wheel"), this); + m_hsvAction = new QAction(tr("HSV"), this); + m_alphaAction = new QAction(tr("Alpha"), this); + m_rgbAction = new QAction(tr("RGB"), this); + m_hexAction = new QAction(tr("Hex"), this); + + m_wheelAction->setCheckable(true); + m_hsvAction->setCheckable(true); + m_alphaAction->setCheckable(true); + m_rgbAction->setCheckable(true); + m_hexAction->setCheckable(true); + m_wheelAction->setChecked(true); + m_hsvAction->setChecked(true); + m_alphaAction->setChecked(true); + m_rgbAction->setChecked(true); + m_hexAction->setChecked(false); + menu->addAction(m_wheelAction); + menu->addAction(m_hsvAction); + menu->addAction(m_alphaAction); + menu->addAction(m_rgbAction); + menu->addAction(m_hexAction); + + m_sliderAppearanceAG = new QActionGroup(this); + QAction *relColorAct = + new QAction(tr("Relative colored + Triangle handle"), this); + QAction *absColorAct = + new QAction(tr("Absolute colored + Line handle"), this); + relColorAct->setData(RelativeColoredTriangleHandle); + absColorAct->setData(AbsoluteColoredLineHandle); + relColorAct->setCheckable(true); + absColorAct->setCheckable(true); + if (StyleEditorColorSliderAppearance == RelativeColoredTriangleHandle) + relColorAct->setChecked(true); + else + absColorAct->setChecked(true); + m_sliderAppearanceAG->addAction(relColorAct); + m_sliderAppearanceAG->addAction(absColorAct); + m_sliderAppearanceAG->setExclusive(true); + menu->addSeparator(); + QMenu *appearanceSubMenu = menu->addMenu(tr("Slider Appearance")); + appearanceSubMenu->addAction(relColorAct); + appearanceSubMenu->addAction(absColorAct); + QToolButton *toolButton = new QToolButton(this); + toolButton->setIcon(createQIcon("menu")); + toolButton->setFixedSize(22, 22); + toolButton->setMenu(menu); + toolButton->setPopupMode(QToolButton::InstantPopup); + toolButton->setToolTip(tr("Show or hide parts of the Color Page.")); + // QToolBar* displayToolbar = new QToolBar(this); + m_toggleOrientationAction = + m_toolBar->addAction(createQIcon("orientation_h"), ""); + m_toggleOrientationAction->setToolTip( + tr("Toggle orientation of the Color Page.")); + QWidget *toggleOrientationButton = + m_toolBar->widgetForAction(m_toggleOrientationAction); + toggleOrientationButton->setFixedSize(22, 22); + toggleOrientationButton->setFocusPolicy(Qt::NoFocus); + m_toolBar->addWidget(toolButton); + m_toolBar->setMaximumHeight(22); + m_toolBar->setIconSize(QSize(16, 16)); /* ------ layout ------ */ - QVBoxLayout *mainLayout = new QVBoxLayout; + QHBoxLayout *mainLayout = new QHBoxLayout; mainLayout->setMargin(2); - mainLayout->setSpacing(1); + mainLayout->setSpacing(0); { - QHBoxLayout *hLayout = new QHBoxLayout; - hLayout->setMargin(0); - hLayout->setSpacing(0); + mainLayout->addWidget(m_autoButton); + mainLayout->addSpacing(4); + mainLayout->addWidget(m_applyButton); + mainLayout->addSpacing(4); + + QVBoxLayout *colorLay = new QVBoxLayout(); + colorLay->setMargin(0); + colorLay->setSpacing(2); { - hLayout->addWidget(m_autoButton); - hLayout->addWidget(m_applyButton); - hLayout->addSpacing(2); - hLayout->addWidget(m_newColor, 1); - hLayout->addWidget(m_oldColor, 1); + QHBoxLayout *chipLay = new QHBoxLayout(); + chipLay->setMargin(0); + chipLay->setSpacing(0); + { + chipLay->addWidget(m_newColor, 1); + chipLay->addWidget(m_oldColor, 1); + } + colorLay->addLayout(chipLay, 1); + + colorLay->addWidget(m_colorParameterSelector, 0); } - mainLayout->addLayout(hLayout); + mainLayout->addLayout(colorLay, 1); + mainLayout->addSpacing(4); - // QHBoxLayout *buttonsLayout = new QHBoxLayout; - // buttonsLayout->setMargin(0); - // buttonsLayout->setSpacing(5); - //{ buttonsLayout->addWidget(m_applyButton); } - // mainLayout->addLayout(buttonsLayout); + QVBoxLayout *hexLay = new QVBoxLayout(); + hexLay->setMargin(0); + hexLay->setSpacing(2); + { + hexLay->addWidget(m_hexLineEdit); + hexLay->addWidget(m_toolBar, 0, Qt::AlignBottom | Qt::AlignRight); + } + mainLayout->addLayout(hexLay, 0); } bottomWidget->setLayout(mainLayout); @@ -3188,8 +3474,30 @@ QFrame *StyleEditor::createBottomWidget() { SLOT(applyButtonClicked())); ret = ret && connect(m_autoButton, SIGNAL(toggled(bool)), this, SLOT(autoCheckChanged(bool))); - ret = ret && connect(m_oldColor, SIGNAL(clicked(const TColorStyle &)), this, - SLOT(onOldStyleClicked(const TColorStyle &))); + ret = ret && + connect(m_oldColor, SIGNAL(clicked()), this, SLOT(onOldStyleClicked())); + ret = ret && + connect(m_newColor, SIGNAL(clicked()), this, SLOT(onNewStyleClicked())); + ret = ret && connect(m_wheelAction, SIGNAL(toggled(bool)), + m_plainColorPage->m_wheelFrame, SLOT(setVisible(bool))); + ret = ret && connect(m_hsvAction, SIGNAL(toggled(bool)), + m_plainColorPage->m_hsvFrame, SLOT(setVisible(bool))); + ret = ret && connect(m_alphaAction, SIGNAL(toggled(bool)), + m_plainColorPage->m_alphaFrame, SLOT(setVisible(bool))); + ret = ret && connect(m_rgbAction, SIGNAL(toggled(bool)), + m_plainColorPage->m_rgbFrame, SLOT(setVisible(bool))); + ret = ret && connect(m_hexAction, SIGNAL(toggled(bool)), m_hexLineEdit, + SLOT(setVisible(bool))); + ret = ret && connect(m_hexLineEdit, SIGNAL(editingFinished()), this, + SLOT(onHexChanged())); + ret = ret && connect(m_toggleOrientationAction, SIGNAL(triggered()), + m_plainColorPage, SLOT(toggleOrientation())); + ret = ret && connect(m_toggleOrientationAction, SIGNAL(triggered()), this, + SLOT(updateOrientationButton())); + ret = ret && connect(m_sliderAppearanceAG, SIGNAL(triggered(QAction *)), this, + SLOT(onSliderAppearanceSelected(QAction *))); + ret = ret && connect(menu, SIGNAL(aboutToShow()), this, + SLOT(onPopupMenuAboutToShow())); assert(ret); return bottomWidget; @@ -3308,6 +3616,7 @@ void StyleEditor::showEvent(QShowEvent *) { m_plainColorPage->m_hsvFrame->setVisible(m_hsvAction->isChecked()); m_plainColorPage->m_alphaFrame->setVisible(m_alphaAction->isChecked()); m_plainColorPage->m_rgbFrame->setVisible(m_rgbAction->isChecked()); + m_hexLineEdit->setVisible(m_hexAction->isChecked()); updateOrientationButton(); assert(ret); } @@ -3404,9 +3713,11 @@ void StyleEditor::onStyleChanged(bool isDragging) { m_plainColorPage->setColor(*m_editedStyle, getColorParam()); m_colorParameterSelector->setStyle(*m_editedStyle); m_settingsPage->setStyle(m_editedStyle); - m_newColor->setStyle(*m_editedStyle); + m_newColor->setStyle(*m_editedStyle, getColorParam()); m_oldColor->setStyle( - *m_oldStyle); // This line is needed for proper undo behavior + *m_oldStyle, + getColorParam()); // This line is needed for proper undo behavior + m_hexLineEdit->setStyle(*m_editedStyle, getColorParam()); } //----------------------------------------------------------------------- @@ -3501,8 +3812,9 @@ void StyleEditor::onColorChanged(const ColorModel &color, bool isDragging) { delete style; } - m_newColor->setStyle(*m_editedStyle); + m_newColor->setStyle(*m_editedStyle, getColorParam()); m_colorParameterSelector->setStyle(*m_editedStyle); + m_hexLineEdit->setStyle(*m_editedStyle, getColorParam()); // Auto Button should be disabled with locked palette if (m_autoButton->isEnabled() && m_autoButton->isChecked()) { copyEditedStyleToPalette(isDragging); @@ -3524,6 +3836,7 @@ void StyleEditor::enable(bool enabled, bool enabledOnlyFirstTab, m_applyButton->setDisabled(!enabled || m_autoButton->isChecked()); m_oldColor->setEnable(enabled); m_newColor->setEnable(enabled); + m_hexLineEdit->setEnabled(enabled); if (enabled == false) { m_oldColor->setColor(TPixel32::Transparent); m_newColor->setColor(TPixel32::Transparent); @@ -3558,13 +3871,17 @@ void StyleEditor::checkPaletteLock() { //----------------------------------------------------------------------------- -void StyleEditor::onOldStyleClicked(const TColorStyle &) { +void StyleEditor::onOldStyleClicked() { if (!m_enabled) return; selectStyle(*(m_oldColor->getStyle())); } //----------------------------------------------------------------------------- +void StyleEditor::onNewStyleClicked() { applyButtonClicked(); } + +//----------------------------------------------------------------------------- + void StyleEditor::setPage(int index) { if (!m_enabledFirstAndLastTab) { m_styleChooser->setCurrentIndex(index); @@ -3636,8 +3953,9 @@ bool StyleEditor::setStyle(TColorStyle *currentStyle) { if (currentStyle) { m_colorParameterSelector->setStyle(*currentStyle); m_plainColorPage->setColor(*currentStyle, getColorParam()); - m_oldColor->setStyle(*currentStyle); - m_newColor->setStyle(*currentStyle); + m_oldColor->setStyle(*currentStyle, getColorParam()); + m_newColor->setStyle(*currentStyle, getColorParam()); + m_hexLineEdit->setStyle(*m_editedStyle, getColorParam()); setOldStyleToStyle(currentStyle); } @@ -3702,10 +4020,11 @@ void StyleEditor::selectStyle(const TColorStyle &newStyle) { } // Update editor widgets - m_newColor->setStyle(*m_editedStyle); - m_plainColorPage->setColor(*m_editedStyle, getColorParam()); m_colorParameterSelector->setStyle(*m_editedStyle); + m_newColor->setStyle(*m_editedStyle, getColorParam()); + m_plainColorPage->setColor(*m_editedStyle, getColorParam()); m_settingsPage->setStyle(m_editedStyle); + m_hexLineEdit->setStyle(*m_editedStyle, getColorParam()); } //----------------------------------------------------------------------------- @@ -3717,13 +4036,19 @@ void StyleEditor::onColorParamChanged() { int styleIndex = getStyleIndex(); if (styleIndex < 0 || palette->getStyleCount() <= styleIndex) return; + if (*m_oldStyle != *m_editedStyle) applyButtonClicked(); + m_paletteHandle->setStyleParamIndex(getColorParam()); if (TColorStyle *currentStyle = palette->getStyle(styleIndex)) { setEditedStyleToStyle(currentStyle); + m_colorParameterSelector->setStyle(*m_editedStyle); + m_newColor->setStyle(*m_editedStyle, getColorParam()); + m_oldColor->setStyle(*m_editedStyle, getColorParam()); m_plainColorPage->setColor(*m_editedStyle, getColorParam()); m_settingsPage->setStyle(m_editedStyle); + m_hexLineEdit->setStyle(*m_editedStyle, getColorParam()); } } @@ -3738,8 +4063,20 @@ void StyleEditor::onParamStyleChanged(bool isDragging) { if (m_autoButton->isChecked()) copyEditedStyleToPalette(isDragging); - m_editedStyle->invalidateIcon(); // Refresh the new color icon - m_newColor->setStyle(*m_editedStyle); // + m_editedStyle->invalidateIcon(); // Refresh the new color icon + m_newColor->setStyle(*m_editedStyle, getColorParam()); + m_hexLineEdit->setStyle(*m_editedStyle, getColorParam()); +} + +//----------------------------------------------------------------------------- + +void StyleEditor::onHexChanged() { + if (m_hexLineEdit->fromText(m_hexLineEdit->text())) { + ColorModel cm; + cm.setTPixel(m_hexLineEdit->getColor()); + onColorChanged(cm, false); + m_hexLineEdit->selectAll(); + } } //----------------------------------------------------------------------------- @@ -3775,6 +4112,7 @@ void StyleEditor::save(QSettings &settings) const { if (m_hsvAction->isChecked()) visibleParts |= 0x02; if (m_alphaAction->isChecked()) visibleParts |= 0x04; if (m_rgbAction->isChecked()) visibleParts |= 0x08; + if (m_hexAction->isChecked()) visibleParts |= 0x10; settings.setValue("visibleParts", visibleParts); settings.setValue("splitterState", m_plainColorPage->getSplitterState()); } @@ -3804,6 +4142,10 @@ void StyleEditor::load(QSettings &settings) { m_rgbAction->setChecked(true); else m_rgbAction->setChecked(false); + if (visiblePartsInt & 0x10) + m_hexAction->setChecked(true); + else + m_hexAction->setChecked(false); } QVariant splitterState = settings.value("splitterState"); if (splitterState.canConvert(QVariant::ByteArray)) @@ -3814,4 +4156,28 @@ void StyleEditor::load(QSettings &settings) { void StyleEditor::updateColorCalibration() { m_plainColorPage->updateColorCalibration(); +} + +//----------------------------------------------------------------------------- + +void StyleEditor::onSliderAppearanceSelected(QAction *action) { + bool ok = true; + int appearanceId = action->data().toInt(&ok); + if (!ok) return; + if (appearanceId == StyleEditorColorSliderAppearance) return; + StyleEditorColorSliderAppearance = appearanceId; + ColorSlider::s_slider_appearance = appearanceId; + m_plainColorPage->update(); +} + +//----------------------------------------------------------------------------- + +void StyleEditor::onPopupMenuAboutToShow() { + // sync radio button state to the current user env settings + for (auto action : m_sliderAppearanceAG->actions()) { + bool ok = true; + int appearanceId = action->data().toInt(&ok); + if (ok && appearanceId == StyleEditorColorSliderAppearance) + action->setChecked(true); + } } \ No newline at end of file diff --git a/toonz/sources/toonzqt/toonzqt.qrc b/toonz/sources/toonzqt/toonzqt.qrc index a2a8845..66ab744 100644 --- a/toonz/sources/toonzqt/toonzqt.qrc +++ b/toonz/sources/toonzqt/toonzqt.qrc @@ -29,6 +29,8 @@ Resources/h_chandleDown.png Resources/h_chandleCenter.png Resources/h_chandleUp.png + Resources/h_chandle_arrow.svg + Resources/v_chandle_arrow.svg Resources/schematic_palette.png Resources/schematic_tablenode.png Resources/port_red.svg