diff --git a/stuff/config/colornames.txt b/stuff/config/colornames.txt index f139a27..802e686 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 9148f26..763cf3b 100644 --- a/toonz/sources/include/toonzqt/colorfield.h +++ b/toonz/sources/include/toonzqt/colorfield.h @@ -44,11 +44,11 @@ class DVAPI CommonChessboard final : public QObject { Q_OBJECT TRaster32P m_bgRas; QPixmap m_bgPix; - void setChessboardColors(const TPixel32 &col1, const TPixel32 &col2); -public: CommonChessboard(); + void setChessboardColors(const TPixel32 &col1, const TPixel32 &col2); +public: 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 0000000..a2d303c --- /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 346a738..ba9afc9 100644 --- a/toonz/sources/include/toonzqt/styleeditor.h +++ b/toonz/sources/include/toonzqt/styleeditor.h @@ -22,6 +22,7 @@ #include "toonzqt/colorfield.h" #include "toonzqt/tabbar.h" #include "toonzqt/glwidget_for_highdpi.h" +#include "toonzqt/hexcolornames.h" // Qt includes #include @@ -74,35 +75,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 { //============================================================================= @@ -652,7 +624,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 @@ -693,6 +666,7 @@ class DVAPI StyleEditor final : public QWidget, public SaveLoadQSettings { QAction *m_rgbAction; QAction *m_hexAction; QActionGroup *m_sliderAppearanceAG; + QAction *m_hexEditorAction; TColorStyleP m_oldStyle; //!< A copy of current style \a before the last change. @@ -795,6 +769,7 @@ protected slots: void onParamStyleChanged(bool isDragging); void onHexChanged(); + void onHexEditor(); void onSpecialButtonToggled(bool on); void onCustomButtonToggled(bool on); diff --git a/toonz/sources/toonzqt/CMakeLists.txt b/toonz/sources/toonzqt/CMakeLists.txt index 6c8451e..b4c2897 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 0000000..201b305 --- /dev/null +++ b/toonz/sources/toonzqt/hexcolornames.cpp @@ -0,0 +1,953 @@ +#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->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->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 9953396..65dced8 100644 --- a/toonz/sources/toonzqt/styleeditor.cpp +++ b/toonz/sources/toonzqt/styleeditor.cpp @@ -37,7 +37,6 @@ #include "tvectorrenderdata.h" #include "tsimplecolorstyles.h" #include "tvectorbrushstyle.h" -#include "tenv.h" // Qt includes #include @@ -71,212 +70,6 @@ TEnv::IntVar StyleEditorColorSliderAppearance( 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 //***************************************************************************** @@ -3207,6 +3000,7 @@ StyleEditor::StyleEditor(PaletteController *paletteController, QWidget *parent) , m_enabledFirstAndLastTab(false) , m_oldStyle(0) , m_parent(parent) + , m_hexColorNamesEditor(0) , m_editedStyle(0) { setFocusPolicy(Qt::NoFocus); // TOGLIERE @@ -3358,11 +3152,9 @@ QFrame *StyleEditor::createBottomWidget() { m_newColor->setEnable(false); m_newColor->setSystemChessboard(true); - m_hexLineEdit = new HexLineEdit("", this); + m_hexLineEdit = new DVGui::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); @@ -3411,6 +3203,9 @@ QFrame *StyleEditor::createBottomWidget() { appearanceSubMenu->addAction(relColorAct); appearanceSubMenu->addAction(absColorAct); + 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); @@ -3490,6 +3285,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, @@ -4081,6 +3878,15 @@ void StyleEditor::onHexChanged() { //----------------------------------------------------------------------------- +void StyleEditor::onHexEditor() { + if (!m_hexColorNamesEditor) { + m_hexColorNamesEditor = new DVGui::HexColorNamesEditor(this); + } + m_hexColorNamesEditor->show(); +} + +//----------------------------------------------------------------------------- + void StyleEditor::onSpecialButtonToggled(bool on) { m_specialStylePage->setVisible(on); m_vectorArea->widget()->resize(m_vectorArea->widget()->sizeHint()); @@ -4180,4 +3986,4 @@ void StyleEditor::onPopupMenuAboutToShow() { if (ok && appearanceId == StyleEditorColorSliderAppearance) action->setChecked(true); } -} \ No newline at end of file +}