diff --git a/stuff/config/colornames.txt b/stuff/config/colornames.txt
index fefe1631..49a46463 100644
--- a/stuff/config/colornames.txt
+++ b/stuff/config/colornames.txt
@@ -12,6 +12,10 @@
#FF0000
#00FF00
#0000FF
+ #00FFFF
+ #FF00FF
+ #FFFF00
+ #FFFFFF
#F0F8FF
#FAEBD7
diff --git a/toonz/sources/include/toonzqt/colorfield.h b/toonz/sources/include/toonzqt/colorfield.h
index 9148f265..d2649d7b 100644
--- a/toonz/sources/include/toonzqt/colorfield.h
+++ b/toonz/sources/include/toonzqt/colorfield.h
@@ -44,11 +44,10 @@ class DVAPI CommonChessboard final : public QObject {
Q_OBJECT
TRaster32P m_bgRas;
QPixmap m_bgPix;
+ CommonChessboard();
void setChessboardColors(const TPixel32 &col1, const TPixel32 &col2);
public:
- CommonChessboard();
-
const QPixmap &getPixmap() { return m_bgPix; }
void update();
diff --git a/toonz/sources/include/toonzqt/hexcolornames.h b/toonz/sources/include/toonzqt/hexcolornames.h
new file mode 100644
index 00000000..a2d303cd
--- /dev/null
+++ b/toonz/sources/include/toonzqt/hexcolornames.h
@@ -0,0 +1,315 @@
+#pragma once
+
+#ifndef HEXCOLORNAMES_H
+#define HEXCOLORNAMES_H
+
+// TnzCore includes
+#include "tcommon.h"
+#include "tfilepath.h"
+#include "tpixel.h"
+#include "tpalette.h"
+#include "tenv.h"
+
+// TnzQt includes
+#include "toonzqt/dvdialog.h"
+#include "toonzqt/colorfield.h"
+
+// Qt includes
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#undef DVAPI
+#undef DVVAR
+#ifdef TOONZQT_EXPORTS
+#define DVAPI DV_EXPORT_API
+#define DVVAR DV_EXPORT_VAR
+#else
+#define DVAPI DV_IMPORT_API
+#define DVVAR DV_IMPORT_VAR
+#endif
+
+namespace DVGui {
+
+//-----------------------------------------------------------------------------
+
+//! Manage all Hex and named colors conversions.
+class HexColorNames final : public QObject {
+ Q_OBJECT
+ HexColorNames();
+
+ static QMap s_maincolornames;
+ static QMap s_usercolornames;
+ static QMap s_tempcolornames;
+
+ static void loadColorTableXML(QMap &table,
+ const TFilePath &fp);
+ static void saveColorTableXML(QMap &table,
+ const TFilePath &fp);
+ static bool parseHexInternal(QString text, TPixel &outPixel);
+
+public:
+
+ //! iterator for accessing user entries
+ class iterator {
+ QMap::iterator m_it;
+ bool m_mutable;
+
+ public:
+ inline iterator() : m_it(nullptr), m_mutable(false) {}
+ inline iterator(iterator *it)
+ : m_it(it->m_it), m_mutable(it->m_mutable) {}
+ inline iterator(QMap::iterator it, bool isMutable)
+ : m_it(it), m_mutable(isMutable) {}
+
+ inline const QString &name() const { return m_it.key(); }
+ inline const QString &value() const { return m_it.value(); }
+ inline void setValue(const QString &value) { if (m_mutable) m_it.value() = value; }
+ inline bool operator==(const iterator &o) const { return m_it == o.m_it; }
+ inline bool operator!=(const iterator &o) const { return m_it != o.m_it; }
+ inline iterator &operator++() {
+ ++m_it;
+ return *this;
+ }
+ inline iterator &operator--() {
+ --m_it;
+ return *this;
+ }
+ inline iterator operator++(int) {
+ iterator r = *this;
+ m_it++;
+ return r;
+ }
+ inline iterator operator--(int) {
+ iterator r = *this;
+ m_it--;
+ return r;
+ }
+ };
+
+ //! Load entries from main colornames.txt file
+ static bool loadMainFile(bool reload);
+
+ //! Load entries from user colornames.txt file
+ static bool loadUserFile(bool reload);
+
+ //! Load temporary entries from custom file
+ static bool loadTempFile(const TFilePath& fp);
+
+ //! Verify if there's personal colornames.txt file
+ static bool hasUserFile();
+
+ //! Save entries to user colornames.txt file
+ static bool saveUserFile();
+
+ //! Load temporary entries from custom file
+ static bool saveTempFile(const TFilePath &fp);
+
+ //! Clear all user entries
+ static void clearUserEntries();
+
+ //! Clear all user entries
+ static void clearTempEntries();
+
+ //! Set single user entry
+ static void setUserEntry(const QString &name, const QString &hex);
+
+ //! Set single user entry
+ static void setTempEntry(const QString &name, const QString &hex);
+
+ //! Get first main entry
+ static inline iterator beginMain() {
+ return iterator(s_maincolornames.begin(), false);
+ }
+
+ //! Get last main entry
+ static inline iterator endMain() {
+ return iterator(s_maincolornames.end(), false);
+ }
+
+ //! Get first user entry
+ static inline iterator beginUser() {
+ return iterator(s_usercolornames.begin(), true);
+ }
+
+ //! Get last user entry
+ static inline iterator endUser() {
+ return iterator(s_usercolornames.end(), true);
+ }
+
+ //! Get first user entry
+ static inline iterator beginTemp() {
+ return iterator(s_tempcolornames.begin(), true);
+ }
+
+ //! Get last user entry
+ static inline iterator endTemp() {
+ return iterator(s_tempcolornames.end(), true);
+ }
+
+ //! Parse raw text into RGBA color
+ static bool parseText(QString text, TPixel &outPixel);
+
+ //! Parse hex format into RGBA color
+ static bool parseHex(QString text, TPixel &outPixel);
+
+ //! Generate hex format from RGBA color
+ static QString generateHex(TPixel pixel);
+
+ //! To access singleton for signaling
+ static HexColorNames *instance();
+
+ //! Emit that user entries were changed
+ inline void emitChanged() { emit colorsChanged(); }
+ inline void emitAutoComplete(bool enable) { emit autoCompleteChanged(enable); }
+
+signals:
+ void autoCompleteChanged(bool);
+ void colorsChanged();
+};
+
+//-----------------------------------------------------------------------------
+
+//! Hex line-edit widget
+class DVAPI HexLineEdit : public QLineEdit {
+ Q_OBJECT
+
+public:
+ HexLineEdit(const QString &contents, QWidget *parent);
+ ~HexLineEdit() {}
+
+ 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 mousePressEvent(QMouseEvent *event) override;
+ void focusOutEvent(QFocusEvent *event) override;
+ void showEvent(QShowEvent *event) override;
+
+ QCompleter *getCompleter();
+
+ bool m_editing;
+ TPixel m_color;
+ QCompleter *m_completer;
+
+protected slots:
+ void onAutoCompleteChanged(bool);
+ void onColorsChanged();
+};
+
+//-----------------------------------------------------------------------------
+
+//! Editing delegate for editor
+class HexColorNamesEditingDelegate : public QStyledItemDelegate {
+ Q_OBJECT
+
+public:
+ HexColorNamesEditingDelegate(QObject *parent = nullptr)
+ : QStyledItemDelegate(parent) {
+ connect(this,
+ SIGNAL(closeEditor(QWidget *,
+ QAbstractItemDelegate::EndEditHint)),
+ this,
+ SLOT(onCloseEditor(QWidget *, QAbstractItemDelegate::EndEditHint)));
+ }
+ virtual QWidget *createEditor(QWidget *parent,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &index) const {
+ QWidget *widget = QStyledItemDelegate::createEditor(parent, option, index);
+ emit editingStarted(index);
+ return widget;
+ }
+ virtual void setModelData(QWidget *editor, QAbstractItemModel *model,
+ const QModelIndex &index) const {
+ QStyledItemDelegate::setModelData(editor, model, index);
+ emit editingFinished(index);
+ }
+
+signals:
+ void editingStarted(const QModelIndex &) const;
+ void editingFinished(const QModelIndex &) const;
+ void editingClosed() const;
+
+private slots:
+ inline void onCloseEditor(QWidget *editor,
+ QAbstractItemDelegate::EndEditHint hint = NoHint) {
+ emit editingClosed();
+ }
+};
+
+//-----------------------------------------------------------------------------
+
+//! Dialog: Hex color names editor
+class HexColorNamesEditor final : public DVGui::Dialog {
+ Q_OBJECT
+
+ HexColorNamesEditingDelegate *m_userEditingDelegate;
+ QTreeWidget *m_userTreeWidget;
+ QTreeWidget *m_mainTreeWidget;
+ QCheckBox *m_autoCompleteCb;
+ QPushButton *m_addColorButton;
+ QPushButton *m_delColorButton;
+ QPushButton *m_unsColorButton;
+ QPushButton *m_importButton;
+ QPushButton *m_exportButton;
+ HexLineEdit *m_hexLineEdit;
+ ColorField *m_colorField;
+ bool m_autoComplete;
+
+ bool m_newEntry;
+ int m_selectedColn;
+ QTreeWidgetItem *m_selectedItem;
+ QString m_selectedName, m_selectedHex;
+
+ QTreeWidgetItem *addEntry(QTreeWidget *tree, const QString &name,
+ const QString &hex, bool editable);
+ bool updateUserHexEntry(QTreeWidgetItem *treeItem, const TPixel32 &color);
+ bool nameValid(const QString& name);
+ bool nameExists(const QString &name, QTreeWidgetItem *self);
+ void deselectItem(bool treeFocus);
+ void deleteCurrentItem(bool deselect);
+ void populateMainList(bool reload);
+ void populateUserList(bool reload);
+
+ void showEvent(QShowEvent *e) override;
+ void keyPressEvent(QKeyEvent *event) override;
+ void focusInEvent(QFocusEvent *e) override;
+ void focusOutEvent(QFocusEvent *e) override;
+ bool eventFilter(QObject *obj, QEvent *e) override;
+
+private slots:
+ void onCurrentItemChanged(QTreeWidgetItem *current,
+ QTreeWidgetItem *previous);
+ void onEditingStarted(const QModelIndex &);
+ void onEditingFinished(const QModelIndex &);
+ void onEditingClosed();
+ void onItemStarted(QTreeWidgetItem *item, int column);
+ void onItemFinished(QTreeWidgetItem *item, int column);
+ void onColorFieldChanged(const TPixel32 &color, bool isDragging);
+ void onHexChanged();
+ void onAddColor();
+ void onDelColor();
+ void onDeselect();
+ void onImport();
+ void onExport();
+ void onOK();
+ void onApply();
+
+public:
+ HexColorNamesEditor(QWidget *parent);
+};
+
+//-----------------------------------------------------------------------------
+} // namespace DVGui
+//-----------------------------------------------------------------------------
+
+#endif // HEXCOLORNAMES_H
diff --git a/toonz/sources/include/toonzqt/styleeditor.h b/toonz/sources/include/toonzqt/styleeditor.h
index 071503ff..f0bbf535 100644
--- a/toonz/sources/include/toonzqt/styleeditor.h
+++ b/toonz/sources/include/toonzqt/styleeditor.h
@@ -24,6 +24,7 @@
#include "toonzqt/tabbar.h"
#include "toonzqt/glwidget_for_highdpi.h"
#include "toonzqt/dvdialog.h"
+#include "toonzqt/hexcolornames.h"
// Qt includes
#include
@@ -79,35 +80,6 @@ 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 {
//=============================================================================
@@ -817,7 +789,8 @@ class DVAPI StyleEditor final : public QWidget, public SaveLoadQSettings {
PaletteController *m_paletteController;
TPaletteHandle *m_paletteHandle;
TPaletteHandle *m_cleanupPaletteHandle;
- HexLineEdit *m_hexLineEdit;
+ DVGui::HexLineEdit *m_hexLineEdit;
+ DVGui::HexColorNamesEditor *m_hexColorNamesEditor;
QWidget *m_parent;
TXshLevelHandle
*m_levelHandle; //!< for clearing the level cache when the color changed
@@ -856,6 +829,7 @@ class DVAPI StyleEditor final : public QWidget, public SaveLoadQSettings {
QAction *m_alphaAction;
QAction *m_rgbAction;
QAction *m_hexAction;
+ QAction *m_hexEditorAction;
TColorStyleP
m_oldStyle; //!< A copy of current style \a before the last change.
@@ -1025,6 +999,7 @@ protected slots:
void onParamStyleChanged(bool isDragging);
void onHexChanged();
+ void onHexEditor();
void onHexEdited(const QString &text);
void onHideMenu();
diff --git a/toonz/sources/toonzqt/CMakeLists.txt b/toonz/sources/toonzqt/CMakeLists.txt
index 6c8451e3..b4c28971 100644
--- a/toonz/sources/toonzqt/CMakeLists.txt
+++ b/toonz/sources/toonzqt/CMakeLists.txt
@@ -33,6 +33,7 @@ set(MOC_HEADERS
../include/toonzqt/fxselection.h
../include/toonzqt/fxsettings.h
../include/toonzqt/gutil.h
+ ../include/toonzqt/hexcolornames.h
../include/toonzqt/histogram.h
../include/toonzqt/icongenerator.h
../include/toonzqt/imageutils.h
@@ -122,6 +123,7 @@ set(SOURCES
fxhistogramrender.cpp
fxsettings.cpp
gutil.cpp
+ hexcolornames.cpp
histogram.cpp
icongenerator.cpp
imageutils.cpp
diff --git a/toonz/sources/toonzqt/hexcolornames.cpp b/toonz/sources/toonzqt/hexcolornames.cpp
new file mode 100644
index 00000000..7cbdeaee
--- /dev/null
+++ b/toonz/sources/toonzqt/hexcolornames.cpp
@@ -0,0 +1,955 @@
+#include "toonzqt/hexcolornames.h"
+
+// TnzLib includes
+#include "toonz/toonzfolders.h"
+
+// TnzCore includes
+#include "tconvert.h"
+#include "tfiletype.h"
+#include "tsystem.h"
+#include "tcolorstyles.h"
+#include "tpalette.h"
+#include "tpixel.h"
+#include "tvectorimage.h"
+#include "trasterimage.h"
+#include "tlevel_io.h"
+
+// Qt includes
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+using namespace DVGui;
+
+//-----------------------------------------------------------------------------
+
+#define COLORNAMES_FILE "colornames.txt"
+
+QMap HexColorNames::s_maincolornames;
+QMap HexColorNames::s_usercolornames;
+QMap HexColorNames::s_tempcolornames;
+
+HexColorNames *HexColorNames::instance() {
+ static HexColorNames _instance;
+ return &_instance;
+}
+
+HexColorNames::HexColorNames() {}
+
+void HexColorNames::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 HexColorNames::saveColorTableXML(QMap &table,
+ const TFilePath &fp) {
+ TOStream os(fp);
+ if (!os) throw TException("Can't write color names");
+
+ os.openChild("colors");
+
+ QMap::const_iterator it;
+ std::map attrs;
+ for (it = table.cbegin(); it != table.cend(); ++it) {
+ std::string nameStd = it.key().toStdString();
+ attrs.clear();
+ attrs.insert({"name", nameStd});
+ os.openChild("color", attrs);
+ os << it.value();
+ os.closeChild();
+ }
+
+ os.closeChild();
+}
+
+//-----------------------------------------------------------------------------
+
+bool HexColorNames::parseHexInternal(QString text, TPixel &outPixel) {
+ bool ok;
+ uint parsedValue = text.toUInt(&ok, 16);
+ if (!ok) return false;
+
+ switch (text.length()) {
+ case 8: // #RRGGBBAA
+ outPixel.r = parsedValue >> 24;
+ outPixel.g = parsedValue >> 16;
+ outPixel.b = parsedValue >> 8;
+ outPixel.m = parsedValue;
+ break;
+ case 6: // #RRGGBB
+ outPixel.r = parsedValue >> 16;
+ outPixel.g = parsedValue >> 8;
+ outPixel.b = parsedValue;
+ outPixel.m = 255;
+ break;
+ case 4: // #RGBA
+ outPixel.r = (parsedValue >> 12) & 15;
+ outPixel.r |= outPixel.r << 4;
+ outPixel.g = (parsedValue >> 8) & 15;
+ outPixel.g |= outPixel.g << 4;
+ outPixel.b = (parsedValue >> 4) & 15;
+ outPixel.b |= outPixel.b << 4;
+ outPixel.m = parsedValue & 15;
+ outPixel.m |= outPixel.m << 4;
+ break;
+ case 3: // #RGB
+ outPixel.r = (parsedValue >> 8) & 15;
+ outPixel.r |= outPixel.r << 4;
+ outPixel.g = (parsedValue >> 4) & 15;
+ outPixel.g |= outPixel.g << 4;
+ outPixel.b = parsedValue & 15;
+ outPixel.b |= outPixel.b << 4;
+ outPixel.m = 255;
+ break;
+ case 2: // #VV (non-standard)
+ outPixel.r = parsedValue;
+ outPixel.g = outPixel.r;
+ outPixel.b = outPixel.r;
+ outPixel.m = 255;
+ break;
+ case 1: // #V (non-standard)
+ outPixel.r = parsedValue & 15;
+ outPixel.r |= outPixel.r << 4;
+ outPixel.g = outPixel.r;
+ outPixel.b = outPixel.r;
+ outPixel.m = 255;
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool HexColorNames::loadMainFile(bool reload) {
+ TFilePath mainCTFp = TEnv::getConfigDir() + COLORNAMES_FILE;
+
+ // Load main color names
+ try {
+ if (reload || s_maincolornames.size() == 0) {
+ s_maincolornames.clear();
+ loadColorTableXML(s_maincolornames, mainCTFp);
+ }
+ } catch (...) {
+ return false;
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool HexColorNames::hasUserFile() {
+ TFilePath userCTFp = ToonzFolder::getMyModuleDir() + COLORNAMES_FILE;
+ return TFileStatus(userCTFp).doesExist();
+}
+
+//-----------------------------------------------------------------------------
+
+bool HexColorNames::loadUserFile(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;
+}
+
+//-----------------------------------------------------------------------------
+
+bool HexColorNames::loadTempFile(const TFilePath &fp) {
+ if (TFileStatus(fp).doesExist()) {
+ try {
+ s_tempcolornames.clear();
+ loadColorTableXML(s_tempcolornames, fp);
+ } catch (...) {
+ return false;
+ }
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool HexColorNames::saveUserFile() {
+ TFilePath userCTFp = ToonzFolder::getMyModuleDir() + COLORNAMES_FILE;
+
+ try {
+ saveColorTableXML(s_usercolornames, userCTFp);
+ } catch (...) {
+ return false;
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool HexColorNames::saveTempFile(const TFilePath &fp) {
+ try {
+ saveColorTableXML(s_tempcolornames, fp);
+ } catch (...) {
+ return false;
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+
+void HexColorNames::clearUserEntries() { s_usercolornames.clear(); }
+
+void HexColorNames::clearTempEntries() { s_tempcolornames.clear(); }
+
+//-----------------------------------------------------------------------------
+
+void HexColorNames::setUserEntry(const QString &name, const QString &hex) {
+ s_usercolornames.insert(name, hex);
+}
+
+//-----------------------------------------------------------------------------
+
+void HexColorNames::setTempEntry(const QString &name, const QString &hex) {
+ s_tempcolornames.insert(name, hex);
+}
+
+//-----------------------------------------------------------------------------
+
+bool HexColorNames::parseText(QString text, TPixel &outPixel) {
+ static QRegExp space("\\s");
+ text.remove(space);
+ if (text.size() == 0) return false;
+ if (text[0] == "#") {
+ text.remove(0, 1);
+ return parseHexInternal(text, outPixel);
+ }
+ 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_maincolornames.constFind(text);
+ if (it == s_maincolornames.constEnd()) return false;
+ }
+
+ QString hexText = it.value();
+ hexText.remove(space);
+ if (hexText[0] == "#") {
+ hexText.remove(0, 1);
+ return parseHexInternal(hexText, outPixel);
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+
+bool HexColorNames::parseHex(QString text, TPixel &outPixel) {
+ static QRegExp space("\\s");
+ text.remove(space);
+ if (text.size() == 0) return false;
+ if (text[0] == "#") {
+ text.remove(0, 1);
+ }
+ return parseHexInternal(text, outPixel);
+}
+
+//-----------------------------------------------------------------------------
+
+QString HexColorNames::generateHex(TPixel pixel) {
+ if (pixel.m == 255) {
+ // Opaque, omit alpha
+ return QString("#%1%2%3")
+ .arg(pixel.r, 2, 16, QLatin1Char('0'))
+ .arg(pixel.g, 2, 16, QLatin1Char('0'))
+ .arg(pixel.b, 2, 16, QLatin1Char('0'))
+ .toUpper();
+ } else {
+ return QString("#%1%2%3%4")
+ .arg(pixel.r, 2, 16, QLatin1Char('0'))
+ .arg(pixel.g, 2, 16, QLatin1Char('0'))
+ .arg(pixel.b, 2, 16, QLatin1Char('0'))
+ .arg(pixel.m, 2, 16, QLatin1Char('0'))
+ .toUpper();
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+//*****************************************************************************
+// Hex line widget
+//*****************************************************************************
+
+TEnv::IntVar HexLineEditAutoComplete("HexLineEditAutoComplete", 1);
+
+HexLineEdit::HexLineEdit(const QString &contents, QWidget *parent)
+ : QLineEdit(contents, parent)
+ , m_editing(false)
+ , m_color(0, 0, 0)
+ , m_completer(nullptr) {
+ HexColorNames::loadMainFile(false);
+ HexColorNames::loadUserFile(false);
+
+ if (HexLineEditAutoComplete != 0) onAutoCompleteChanged(true);
+
+ bool ret = true;
+
+ ret = ret &&
+ connect(HexColorNames::instance(), SIGNAL(autoCompleteChanged(bool)),
+ this, SLOT(onAutoCompleteChanged(bool)));
+ ret = ret && connect(HexColorNames::instance(), SIGNAL(colorsChanged()), this,
+ SLOT(onColorsChanged()));
+ assert(ret);
+}
+
+//-----------------------------------------------------------------------------
+
+void HexLineEdit::updateColor() {
+ setText(HexColorNames::generateHex(m_color));
+}
+
+//-----------------------------------------------------------------------------
+
+void HexLineEdit::setStyle(TColorStyle &style, int index) {
+ setColor(style.getColorParamValue(index));
+}
+
+//-----------------------------------------------------------------------------
+
+void HexLineEdit::setColor(TPixel color) {
+ if (m_color != color) {
+ m_color = color;
+ if (isVisible()) updateColor();
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+bool HexLineEdit::fromText(QString text) {
+ bool res = HexColorNames::parseText(text, m_color);
+ if (res) updateColor();
+ return res;
+}
+
+//-----------------------------------------------------------------------------
+
+bool HexLineEdit::fromHex(QString text) {
+ bool res = HexColorNames::parseHex(text, m_color);
+ if (res) updateColor();
+ return res;
+}
+
+//-----------------------------------------------------------------------------
+
+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();
+}
+
+//-----------------------------------------------------------------------------
+
+QCompleter *HexLineEdit::getCompleter() {
+ QStringList autolist;
+
+ // Build words list from all color names tables
+ HexColorNames::iterator it;
+ for (it = HexColorNames::beginMain(); it != HexColorNames::endMain(); ++it) {
+ autolist.append(it.name());
+ }
+ for (it = HexColorNames::beginUser(); it != HexColorNames::endUser(); ++it) {
+ autolist.append(it.name());
+ }
+
+ QCompleter *completer = new QCompleter(autolist);
+ completer->setCaseSensitivity(Qt::CaseInsensitive);
+ return completer;
+}
+
+//-----------------------------------------------------------------------------
+
+void HexLineEdit::onAutoCompleteChanged(bool enable) {
+ if (m_completer) {
+ m_completer->deleteLater();
+ setCompleter(nullptr);
+ m_completer = nullptr;
+ }
+ if (enable) {
+ m_completer = getCompleter();
+ setCompleter(m_completer);
+ }
+}
+
+void HexLineEdit::onColorsChanged() { onAutoCompleteChanged(true); }
+
+//-----------------------------------------------------------------------------
+
+//*****************************************************************************
+// Hex color names editor
+//*****************************************************************************
+
+HexColorNamesEditor::HexColorNamesEditor(QWidget *parent)
+ : DVGui::Dialog(parent, true, false, "HexColorNamesEditor")
+ , m_selectedItem(nullptr)
+ , m_newEntry(false) {
+ setWindowTitle(tr("Hex Color Names Editor"));
+ setModal(false); // user may want to access main style editor and palettes
+
+ QPushButton *okButton = new QPushButton(tr("OK"), this);
+ QPushButton *applyButton = new QPushButton(tr("Apply"), this);
+ QPushButton *closeButton = new QPushButton(tr("Close"), this);
+
+ m_unsColorButton = new QPushButton(tr("Unselect"));
+ m_addColorButton = new QPushButton(tr("Add Color"));
+ m_delColorButton = new QPushButton(tr("Delete Color"));
+ m_hexLineEdit = new HexLineEdit("", this);
+ m_hexLineEdit->setObjectName("HexLineEdit");
+ m_hexLineEdit->setFixedWidth(75);
+
+ // Main default color names
+ QGridLayout *mainLay = new QGridLayout();
+ QWidget *mainTab = new QWidget();
+ mainTab->setLayout(mainLay);
+
+ m_mainTreeWidget = new QTreeWidget();
+ m_mainTreeWidget->setRootIsDecorated(false);
+ m_mainTreeWidget->setColumnCount(2);
+ m_mainTreeWidget->setColumnWidth(0, 175);
+ m_mainTreeWidget->setColumnWidth(1, 50);
+ m_mainTreeWidget->setHeaderLabels(QStringList() << "Name"
+ << "Hex value");
+ mainLay->addWidget(m_mainTreeWidget, 0, 0);
+
+ // User defined color names
+ QGridLayout *userLay = new QGridLayout();
+ QWidget *userTab = new QWidget();
+ userTab->setLayout(userLay);
+
+ m_userTreeWidget = new QTreeWidget();
+ m_userTreeWidget->setRootIsDecorated(false);
+ m_userTreeWidget->setColumnCount(2);
+ m_userTreeWidget->setColumnWidth(0, 175);
+ m_userTreeWidget->setColumnWidth(1, 50);
+ m_userTreeWidget->setHeaderLabels(QStringList() << "Name"
+ << "Hex value");
+ m_colorField = new ColorField(this, true);
+ userLay->addWidget(m_userTreeWidget, 0, 0, 1, 4);
+ userLay->addWidget(m_unsColorButton, 1, 0);
+ userLay->addWidget(m_addColorButton, 1, 1);
+ userLay->addWidget(m_delColorButton, 1, 2);
+ userLay->addWidget(m_hexLineEdit, 1, 3);
+ userLay->addWidget(m_colorField, 2, 0, 1, 4);
+
+ // Set delegate
+ m_userEditingDelegate = new HexColorNamesEditingDelegate(m_userTreeWidget);
+ m_mainTreeWidget->setItemDelegate(m_userEditingDelegate);
+ m_userTreeWidget->setItemDelegate(m_userEditingDelegate);
+ populateMainList(false);
+
+ // Tabs
+ QTabWidget *tab = new QTabWidget();
+ tab->addTab(userTab, tr("User Defined Colors"));
+ tab->addTab(mainTab, tr("Default Main Colors"));
+ tab->setObjectName("hexTabWidget");
+
+ // Bottom widgets
+ QHBoxLayout *bottomLay = new QHBoxLayout();
+ m_autoCompleteCb = new QCheckBox(tr("Enable Auto-Complete"));
+ m_autoCompleteCb->setChecked(HexLineEditAutoComplete != 0);
+ m_autoCompleteCb->setSizePolicy(QSizePolicy::Expanding,
+ QSizePolicy::Preferred);
+ m_importButton = new QPushButton(tr("Import"));
+ m_exportButton = new QPushButton(tr("Export"));
+ bottomLay->setMargin(8);
+ bottomLay->setSpacing(5);
+ bottomLay->addWidget(m_autoCompleteCb);
+ bottomLay->addWidget(m_importButton);
+ bottomLay->addWidget(m_exportButton);
+
+ m_topLayout->setContentsMargins(0, 0, 0, 0);
+ m_topLayout->addWidget(tab);
+ m_topLayout->addLayout(bottomLay);
+
+ addButtonBarWidget(okButton, applyButton, closeButton);
+
+ bool ret = true;
+
+ ret = ret && connect(m_userEditingDelegate,
+ SIGNAL(editingStarted(const QModelIndex &)), this,
+ SLOT(onEditingStarted(const QModelIndex &)));
+ ret = ret && connect(m_userEditingDelegate,
+ SIGNAL(editingFinished(const QModelIndex &)), this,
+ SLOT(onEditingFinished(const QModelIndex &)));
+ ret = ret && connect(m_userEditingDelegate, SIGNAL(editingClosed()), this,
+ SLOT(onEditingClosed()));
+
+ ret =
+ ret &&
+ connect(m_userTreeWidget,
+ SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
+ this,
+ SLOT(onCurrentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
+ ret =
+ ret && connect(m_colorField, SIGNAL(colorChanged(const TPixel32 &, bool)),
+ this, SLOT(onColorFieldChanged(const TPixel32 &, bool)));
+ ret = ret && connect(m_hexLineEdit, SIGNAL(editingFinished()), this,
+ SLOT(onHexChanged()));
+
+ ret = ret &&
+ connect(m_unsColorButton, SIGNAL(pressed()), this, SLOT(onDeselect()));
+ ret = ret &&
+ connect(m_addColorButton, SIGNAL(pressed()), this, SLOT(onAddColor()));
+ ret = ret &&
+ connect(m_delColorButton, SIGNAL(pressed()), this, SLOT(onDelColor()));
+ ret =
+ ret && connect(m_importButton, SIGNAL(pressed()), this, SLOT(onImport()));
+ ret =
+ ret && connect(m_exportButton, SIGNAL(pressed()), this, SLOT(onExport()));
+
+ ret = ret && connect(okButton, SIGNAL(pressed()), this, SLOT(onOK()));
+ ret = ret && connect(applyButton, SIGNAL(pressed()), this, SLOT(onApply()));
+ ret = ret && connect(closeButton, SIGNAL(pressed()), this, SLOT(close()));
+ assert(ret);
+}
+
+//-----------------------------------------------------------------------------
+
+QTreeWidgetItem *HexColorNamesEditor::addEntry(QTreeWidget *tree,
+ const QString &name,
+ const QString &hex,
+ bool editable) {
+ TPixel pixel = TPixel(0, 0, 0);
+ HexColorNames::parseHex(hex, pixel);
+
+ QPixmap pixm(16, 16);
+ pixm.fill(QColor(pixel.r, pixel.g, pixel.b, pixel.m));
+
+ QTreeWidgetItem *treeItem = new QTreeWidgetItem(tree);
+ treeItem->setText(0, name);
+ treeItem->setIcon(1, QIcon(pixm));
+ treeItem->setText(1, hex);
+ if (!editable)
+ treeItem->setFlags(treeItem->flags() & ~Qt::ItemIsSelectable);
+ else
+ treeItem->setFlags(treeItem->flags() | Qt::ItemIsEditable);
+
+ return treeItem;
+}
+
+//-----------------------------------------------------------------------------
+
+bool HexColorNamesEditor::updateUserHexEntry(QTreeWidgetItem *treeItem,
+ const TPixel32 &color) {
+ if (treeItem) {
+ QPixmap pixm(16, 16);
+ pixm.fill(QColor(color.r, color.g, color.b, color.m));
+
+ treeItem->setIcon(1, QIcon(pixm));
+ treeItem->setText(1, HexColorNames::generateHex(color));
+ return true;
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+
+bool HexColorNamesEditor::nameValid(const QString& name) {
+ if (name.isEmpty()) return false;
+ return name.count(QRegExp("[\\\\#<>\"']")) == 0;
+}
+
+//-----------------------------------------------------------------------------
+
+bool HexColorNamesEditor::nameExists(const QString &name,
+ QTreeWidgetItem *self) {
+ for (int i = 0; i < m_userTreeWidget->topLevelItemCount(); ++i) {
+ QTreeWidgetItem *item = m_userTreeWidget->topLevelItem(i);
+ if (item == self) continue;
+ if (name.compare(item->text(0), Qt::CaseInsensitive) == 0) return true;
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+
+void HexColorNamesEditor::deselectItem(bool treeFocus) {
+ if (m_newEntry) return;
+
+ m_userTreeWidget->setCurrentItem(nullptr);
+ if (treeFocus) m_userTreeWidget->setFocus();
+}
+
+//-----------------------------------------------------------------------------
+
+void HexColorNamesEditor::deleteCurrentItem(bool deselect) {
+ if (m_newEntry) return;
+
+ QTreeWidgetItem *treeItem = m_userTreeWidget->currentItem();
+ if (treeItem) delete treeItem;
+ m_selectedItem = nullptr;
+ if (deselect) m_userTreeWidget->setCurrentItem(nullptr);
+}
+
+//-----------------------------------------------------------------------------
+
+void HexColorNamesEditor::populateMainList(bool reload) {
+ HexColorNames::loadMainFile(reload);
+
+ HexColorNames::iterator it;
+ m_mainTreeWidget->clear();
+ for (it = HexColorNames::beginMain(); it != HexColorNames::endMain(); ++it) {
+ addEntry(m_mainTreeWidget, it.name(), it.value(), false);
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+void HexColorNamesEditor::populateUserList(bool reload) {
+ HexColorNames::loadUserFile(reload);
+
+ HexColorNames::iterator it;
+ m_userTreeWidget->clear();
+ for (it = HexColorNames::beginUser(); it != HexColorNames::endUser(); ++it) {
+ if (!nameExists(it.name(), nullptr))
+ addEntry(m_userTreeWidget, it.name(), it.value(), true);
+ }
+
+ m_userTreeWidget->sortItems(0, Qt::SortOrder::AscendingOrder);
+}
+
+//-----------------------------------------------------------------------------
+
+void HexColorNamesEditor::showEvent(QShowEvent *e) {
+ populateUserList(false);
+
+ deselectItem(false);
+ m_delColorButton->setEnabled(false);
+ m_unsColorButton->setEnabled(false);
+}
+
+//-----------------------------------------------------------------------------
+
+void HexColorNamesEditor::keyPressEvent(QKeyEvent *event) {
+ // Blocking dialog default actions is actually desirable
+ // for example when user press Esc or Enter twice while
+ // editing it might close the dialog by accident.
+
+ if (!m_userTreeWidget->hasFocus()) return;
+
+ switch (event->key()) {
+ case Qt::Key_F5:
+ populateMainList(true);
+ populateUserList(true);
+ m_mainTreeWidget->update();
+ m_userTreeWidget->update();
+ break;
+ case Qt::Key_Escape:
+ deselectItem(true);
+ break;
+ case Qt::Key_Delete:
+ deleteCurrentItem(false);
+ break;
+ case Qt::Key_Insert:
+ onAddColor();
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+void HexColorNamesEditor::focusInEvent(QFocusEvent *e) {
+ QWidget::focusInEvent(e);
+ qApp->installEventFilter(this);
+}
+
+//--------------------------------------------------------
+
+void HexColorNamesEditor::focusOutEvent(QFocusEvent *e) {
+ QWidget::focusOutEvent(e);
+ qApp->removeEventFilter(this);
+}
+
+//-----------------------------------------------------------------------------
+
+bool HexColorNamesEditor::eventFilter(QObject *obj, QEvent *e) {
+ if (e->type() == QEvent::Shortcut ||
+ e->type() == QEvent::ShortcutOverride) {
+ e->accept();
+ return true;
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+
+void HexColorNamesEditor::onCurrentItemChanged(QTreeWidgetItem *current,
+ QTreeWidgetItem *previous) {
+ m_selectedItem = current;
+ m_delColorButton->setEnabled(current);
+ m_unsColorButton->setEnabled(current);
+
+ if (!current) return;
+ m_selectedName = current->text(0);
+ m_selectedHex = current->text(1);
+ m_selectedColn = 0;
+
+ // Modify color field
+ TPixel pixel(0, 0, 0);
+ if (HexColorNames::parseHex(m_selectedHex, pixel)) {
+ m_colorField->setColor(pixel);
+ m_hexLineEdit->setColor(pixel);
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+void HexColorNamesEditor::onEditingStarted(const QModelIndex &modelIndex) {
+ QTreeWidgetItem *item = (QTreeWidgetItem *)modelIndex.internalPointer();
+ int column = modelIndex.column();
+ onItemStarted(item, column);
+}
+
+void HexColorNamesEditor::onEditingFinished(const QModelIndex &modelIndex) {
+ QTreeWidgetItem *item = (QTreeWidgetItem *)modelIndex.internalPointer();
+ int column = modelIndex.column();
+ onItemFinished(item, column);
+}
+
+void HexColorNamesEditor::onEditingClosed() {
+ onItemFinished(m_selectedItem, m_selectedColn);
+}
+
+//-----------------------------------------------------------------------------
+
+void HexColorNamesEditor::onItemStarted(QTreeWidgetItem *item, int column) {
+ m_selectedName = item->text(0);
+ m_selectedHex = item->text(1);
+ m_selectedColn = 0;
+ m_selectedItem = item;
+}
+
+//-----------------------------------------------------------------------------
+
+void HexColorNamesEditor::onItemFinished(QTreeWidgetItem *item, int column) {
+ if (!m_selectedItem || !item) return;
+ m_delColorButton->setEnabled(true);
+ m_unsColorButton->setEnabled(true);
+
+ try {
+ if (m_selectedItem == item) {
+ QString text = item->text(column);
+ if (column == 0) {
+ // Edit Name
+ static QRegExp space("\\s");
+ text.remove(space);
+ text = text.toLower();
+ if (text.isEmpty()) throw "";
+ if (!nameValid(text))
+ throw "Color name is not valid.\nFollowing characters can't be used: \\ # < > \" '";
+ if (nameExists(text, item)) throw "Color name already exists.\nPlease use another name.";
+ item->setText(0, text);
+ m_userTreeWidget->sortItems(0, Qt::SortOrder::AscendingOrder);
+ } else {
+ // Edit Hex
+ TPixel pixel;
+ if (HexColorNames::parseHex(text, pixel)) {
+ m_colorField->setColor(pixel);
+ m_hexLineEdit->setColor(pixel);
+ updateUserHexEntry(item, pixel);
+ } else {
+ item->setText(1, m_selectedHex);
+ }
+ }
+ }
+ } catch (const char *reason) {
+ m_selectedItem = nullptr;
+ if (m_selectedName.isEmpty()) {
+ delete item;
+ } else {
+ item->setText(0, m_selectedName);
+ }
+ if (strlen(reason)) DVGui::warning(tr(reason));
+ } catch (...) {
+ m_selectedItem = nullptr;
+ delete item;
+ }
+ m_newEntry = false;
+}
+
+//-----------------------------------------------------------------------------
+
+void HexColorNamesEditor::onColorFieldChanged(const TPixel32 &color,
+ bool isDragging) {
+ QTreeWidgetItem *treeItem = m_userTreeWidget->currentItem();
+ if (updateUserHexEntry(treeItem, color)) {
+ m_userTreeWidget->setCurrentItem(treeItem);
+ }
+ m_hexLineEdit->setColor(color);
+}
+
+//-----------------------------------------------------------------------------
+
+void HexColorNamesEditor::onHexChanged() {
+ QTreeWidgetItem *treeItem = m_userTreeWidget->currentItem();
+ if (m_hexLineEdit->fromText(m_hexLineEdit->text())) {
+ TPixel pixel = m_hexLineEdit->getColor();
+ updateUserHexEntry(treeItem, pixel);
+ m_colorField->setColor(pixel);
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+void HexColorNamesEditor::onAddColor() {
+ if (m_newEntry) return;
+
+ TPixel pixel = m_colorField->getColor();
+ QString hex = HexColorNames::generateHex(pixel);
+ QTreeWidgetItem *treeItem = addEntry(m_userTreeWidget, "", hex, true);
+
+ m_userTreeWidget->setCurrentItem(treeItem);
+ onItemStarted(treeItem, 0);
+ m_newEntry = true;
+ m_userTreeWidget->editItem(treeItem, 0);
+
+ m_delColorButton->setEnabled(false);
+ m_unsColorButton->setEnabled(false);
+}
+
+//-----------------------------------------------------------------------------
+
+void HexColorNamesEditor::onDelColor() {
+ if (m_newEntry) return;
+
+ deleteCurrentItem(true);
+ m_userTreeWidget->setFocus();
+}
+
+//-----------------------------------------------------------------------------
+
+void HexColorNamesEditor::onDeselect() { deselectItem(false); }
+
+//-----------------------------------------------------------------------------
+
+void HexColorNamesEditor::onImport() {
+ QString fileName = QFileDialog::getOpenFileName(
+ this, tr("Open Color Names"), QString(),
+ tr("Text or XML (*.txt *.xml);;Text files (*.txt);;XML files (*.xml)"));
+ if (fileName.isEmpty()) return;
+
+ QMessageBox::StandardButton ret = QMessageBox::question(
+ this, tr("Hex Color Names Import"), tr("Do you want to merge with existing entries?"),
+ QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No |
+ QMessageBox::Cancel));
+ if (ret == QMessageBox::Cancel) return;
+
+ if (!HexColorNames::loadTempFile(TFilePath(fileName))) {
+ DVGui::warning(tr("Error importing color names XML"));
+ }
+ HexColorNames::iterator it;
+ if (ret == QMessageBox::No) m_userTreeWidget->clear();
+ for (it = HexColorNames::beginTemp(); it != HexColorNames::endTemp(); ++it) {
+ if (!nameExists(it.name(), nullptr))
+ addEntry(m_userTreeWidget, it.name(), it.value(), true);
+ }
+ HexColorNames::clearTempEntries();
+ m_userTreeWidget->sortItems(0, Qt::SortOrder::AscendingOrder);
+}
+
+//-----------------------------------------------------------------------------
+
+void HexColorNamesEditor::onExport() {
+ QString fileName = QFileDialog::getSaveFileName(
+ this, tr("Save Color Names"), QString(),
+ tr("XML files (*.xml);;Text files (*.txt)"));
+ if (fileName.isEmpty()) return;
+
+ HexColorNames::clearTempEntries();
+ for (int i = 0; i < m_userTreeWidget->topLevelItemCount(); ++i) {
+ QTreeWidgetItem *item = m_userTreeWidget->topLevelItem(i);
+ HexColorNames::setTempEntry(item->text(0), item->text(1));
+ }
+ if (!HexColorNames::saveTempFile(TFilePath(fileName))) {
+ DVGui::warning(tr("Error exporting color names XML"));
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+void HexColorNamesEditor::onOK() {
+ onApply();
+ close();
+};
+
+void HexColorNamesEditor::onApply() {
+ HexColorNames::clearUserEntries();
+ for (int i = 0; i < m_userTreeWidget->topLevelItemCount(); ++i) {
+ QTreeWidgetItem *item = m_userTreeWidget->topLevelItem(i);
+ HexColorNames::setUserEntry(item->text(0), item->text(1));
+ }
+ HexColorNames::saveUserFile();
+ HexColorNames::instance()->emitChanged();
+
+ bool oldAutoCompState = (HexLineEditAutoComplete != 0);
+ bool newAutoCompState = m_autoCompleteCb->isChecked();
+ if (oldAutoCompState != newAutoCompState) {
+ HexLineEditAutoComplete = newAutoCompState ? 1 : 0;
+ HexColorNames::instance()->emitAutoComplete(newAutoCompState);
+ }
+};
+
+//-----------------------------------------------------------------------------
diff --git a/toonz/sources/toonzqt/styleeditor.cpp b/toonz/sources/toonzqt/styleeditor.cpp
index 14a84796..b1bd29f3 100644
--- a/toonz/sources/toonzqt/styleeditor.cpp
+++ b/toonz/sources/toonzqt/styleeditor.cpp
@@ -41,7 +41,6 @@
#include "tvectorrenderdata.h"
#include "tsimplecolorstyles.h"
#include "tvectorbrushstyle.h"
-#include "tenv.h"
// Qt includes
#include
@@ -71,212 +70,6 @@
using namespace StyleEditorGUI;
using namespace DVGui;
-//*****************************************************************************
-// 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
//*****************************************************************************
@@ -4238,6 +4031,7 @@ StyleEditor::StyleEditor(PaletteController *paletteController, QWidget *parent)
, m_enabledFirstAndLastTab(false)
, m_oldStyle(0)
, m_parent(parent)
+ , m_hexColorNamesEditor(0)
, m_editedStyle(0) {
// TOGLIERE
TFilePath libraryPath = ToonzFolder::getLibraryFolder();
@@ -4411,8 +4205,6 @@ QFrame *StyleEditor::createBottomWidget() {
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);
@@ -4447,6 +4239,10 @@ QFrame *StyleEditor::createBottomWidget() {
m_plainColorPage->m_hsvFrame->setVisible(false);
m_plainColorPage->m_rgbFrame->setVisible(false);
+ menu->addSeparator();
+ m_hexEditorAction = new QAction(tr("Hex Color Names..."), this);
+ menu->addAction(m_hexEditorAction);
+
QToolButton *toolButton = new QToolButton(this);
toolButton->setIcon(createQIcon("menu"));
toolButton->setFixedSize(22, 22);
@@ -4546,6 +4342,8 @@ QFrame *StyleEditor::createBottomWidget() {
SLOT(setVisible(bool)));
ret = ret && connect(m_hexLineEdit, SIGNAL(editingFinished()), this,
SLOT(onHexChanged()));
+ ret = ret && connect(m_hexEditorAction, SIGNAL(triggered()), this,
+ SLOT(onHexEditor()));
ret = ret && connect(m_toggleOrientationAction, SIGNAL(triggered()),
m_plainColorPage, SLOT(toggleOrientation()));
ret = ret && connect(m_toggleOrientationAction, SIGNAL(triggered()), this,
@@ -5568,6 +5366,15 @@ void StyleEditor::onHexChanged() {
//-----------------------------------------------------------------------------
+void StyleEditor::onHexEditor() {
+ if (!m_hexColorNamesEditor) {
+ m_hexColorNamesEditor = new DVGui::HexColorNamesEditor(this);
+ }
+ m_hexColorNamesEditor->show();
+}
+
+//-----------------------------------------------------------------------------
+
void StyleEditor::onHexEdited(const QString &text) {
m_hsvAction->setDisabled(true);
m_alphaAction->setDisabled(true);