Merge pull request #891 from justburner/HexEditor
Hex color names editor
This commit is contained in:
commit
4075bb5d39
7 changed files with 1298 additions and 241 deletions
|
@ -12,6 +12,10 @@
|
||||||
<color name="1">#FF0000</color>
|
<color name="1">#FF0000</color>
|
||||||
<color name="2">#00FF00</color>
|
<color name="2">#00FF00</color>
|
||||||
<color name="3">#0000FF</color>
|
<color name="3">#0000FF</color>
|
||||||
|
<color name="4">#00FFFF</color>
|
||||||
|
<color name="5">#FF00FF</color>
|
||||||
|
<color name="6">#FFFF00</color>
|
||||||
|
<color name="7">#FFFFFF</color>
|
||||||
<!-- HTML Color Names -->
|
<!-- HTML Color Names -->
|
||||||
<color name="AliceBlue">#F0F8FF</color>
|
<color name="AliceBlue">#F0F8FF</color>
|
||||||
<color name="AntiqueWhite">#FAEBD7</color>
|
<color name="AntiqueWhite">#FAEBD7</color>
|
||||||
|
|
|
@ -44,11 +44,10 @@ class DVAPI CommonChessboard final : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
TRaster32P m_bgRas;
|
TRaster32P m_bgRas;
|
||||||
QPixmap m_bgPix;
|
QPixmap m_bgPix;
|
||||||
|
CommonChessboard();
|
||||||
void setChessboardColors(const TPixel32 &col1, const TPixel32 &col2);
|
void setChessboardColors(const TPixel32 &col1, const TPixel32 &col2);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CommonChessboard();
|
|
||||||
|
|
||||||
const QPixmap &getPixmap() { return m_bgPix; }
|
const QPixmap &getPixmap() { return m_bgPix; }
|
||||||
void update();
|
void update();
|
||||||
|
|
||||||
|
|
315
toonz/sources/include/toonzqt/hexcolornames.h
Normal file
315
toonz/sources/include/toonzqt/hexcolornames.h
Normal file
|
@ -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 <QString>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QCompleter>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QTreeWidget>
|
||||||
|
#include <QStyledItemDelegate>
|
||||||
|
|
||||||
|
#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<QString, QString> s_maincolornames;
|
||||||
|
static QMap<QString, QString> s_usercolornames;
|
||||||
|
static QMap<QString, QString> s_tempcolornames;
|
||||||
|
|
||||||
|
static void loadColorTableXML(QMap<QString, QString> &table,
|
||||||
|
const TFilePath &fp);
|
||||||
|
static void saveColorTableXML(QMap<QString, QString> &table,
|
||||||
|
const TFilePath &fp);
|
||||||
|
static bool parseHexInternal(QString text, TPixel &outPixel);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//! iterator for accessing user entries
|
||||||
|
class iterator {
|
||||||
|
QMap<QString, QString>::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<QString, QString>::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
|
|
@ -24,6 +24,7 @@
|
||||||
#include "toonzqt/tabbar.h"
|
#include "toonzqt/tabbar.h"
|
||||||
#include "toonzqt/glwidget_for_highdpi.h"
|
#include "toonzqt/glwidget_for_highdpi.h"
|
||||||
#include "toonzqt/dvdialog.h"
|
#include "toonzqt/dvdialog.h"
|
||||||
|
#include "toonzqt/hexcolornames.h"
|
||||||
|
|
||||||
// Qt includes
|
// Qt includes
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
@ -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<QString, QString> &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<QString, QString> s_defcolornames; // make it shared
|
|
||||||
static QMap<QString, QString> s_usercolornames; // ...
|
|
||||||
};
|
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
namespace StyleEditorGUI {
|
namespace StyleEditorGUI {
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
@ -817,7 +789,8 @@ class DVAPI StyleEditor final : public QWidget, public SaveLoadQSettings {
|
||||||
PaletteController *m_paletteController;
|
PaletteController *m_paletteController;
|
||||||
TPaletteHandle *m_paletteHandle;
|
TPaletteHandle *m_paletteHandle;
|
||||||
TPaletteHandle *m_cleanupPaletteHandle;
|
TPaletteHandle *m_cleanupPaletteHandle;
|
||||||
HexLineEdit *m_hexLineEdit;
|
DVGui::HexLineEdit *m_hexLineEdit;
|
||||||
|
DVGui::HexColorNamesEditor *m_hexColorNamesEditor;
|
||||||
QWidget *m_parent;
|
QWidget *m_parent;
|
||||||
TXshLevelHandle
|
TXshLevelHandle
|
||||||
*m_levelHandle; //!< for clearing the level cache when the color changed
|
*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_alphaAction;
|
||||||
QAction *m_rgbAction;
|
QAction *m_rgbAction;
|
||||||
QAction *m_hexAction;
|
QAction *m_hexAction;
|
||||||
|
QAction *m_hexEditorAction;
|
||||||
|
|
||||||
TColorStyleP
|
TColorStyleP
|
||||||
m_oldStyle; //!< A copy of current style \a before the last change.
|
m_oldStyle; //!< A copy of current style \a before the last change.
|
||||||
|
@ -1025,6 +999,7 @@ protected slots:
|
||||||
void onParamStyleChanged(bool isDragging);
|
void onParamStyleChanged(bool isDragging);
|
||||||
|
|
||||||
void onHexChanged();
|
void onHexChanged();
|
||||||
|
void onHexEditor();
|
||||||
|
|
||||||
void onHexEdited(const QString &text);
|
void onHexEdited(const QString &text);
|
||||||
void onHideMenu();
|
void onHideMenu();
|
||||||
|
|
|
@ -33,6 +33,7 @@ set(MOC_HEADERS
|
||||||
../include/toonzqt/fxselection.h
|
../include/toonzqt/fxselection.h
|
||||||
../include/toonzqt/fxsettings.h
|
../include/toonzqt/fxsettings.h
|
||||||
../include/toonzqt/gutil.h
|
../include/toonzqt/gutil.h
|
||||||
|
../include/toonzqt/hexcolornames.h
|
||||||
../include/toonzqt/histogram.h
|
../include/toonzqt/histogram.h
|
||||||
../include/toonzqt/icongenerator.h
|
../include/toonzqt/icongenerator.h
|
||||||
../include/toonzqt/imageutils.h
|
../include/toonzqt/imageutils.h
|
||||||
|
@ -122,6 +123,7 @@ set(SOURCES
|
||||||
fxhistogramrender.cpp
|
fxhistogramrender.cpp
|
||||||
fxsettings.cpp
|
fxsettings.cpp
|
||||||
gutil.cpp
|
gutil.cpp
|
||||||
|
hexcolornames.cpp
|
||||||
histogram.cpp
|
histogram.cpp
|
||||||
icongenerator.cpp
|
icongenerator.cpp
|
||||||
imageutils.cpp
|
imageutils.cpp
|
||||||
|
|
955
toonz/sources/toonzqt/hexcolornames.cpp
Normal file
955
toonz/sources/toonzqt/hexcolornames.cpp
Normal file
|
@ -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 <QCoreApplication>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QToolTip>
|
||||||
|
#include <QTabWidget>
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
using namespace DVGui;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define COLORNAMES_FILE "colornames.txt"
|
||||||
|
|
||||||
|
QMap<QString, QString> HexColorNames::s_maincolornames;
|
||||||
|
QMap<QString, QString> HexColorNames::s_usercolornames;
|
||||||
|
QMap<QString, QString> HexColorNames::s_tempcolornames;
|
||||||
|
|
||||||
|
HexColorNames *HexColorNames::instance() {
|
||||||
|
static HexColorNames _instance;
|
||||||
|
return &_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
HexColorNames::HexColorNames() {}
|
||||||
|
|
||||||
|
void HexColorNames::loadColorTableXML(QMap<QString, QString> &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<QString, QString> &table,
|
||||||
|
const TFilePath &fp) {
|
||||||
|
TOStream os(fp);
|
||||||
|
if (!os) throw TException("Can't write color names");
|
||||||
|
|
||||||
|
os.openChild("colors");
|
||||||
|
|
||||||
|
QMap<QString, QString>::const_iterator it;
|
||||||
|
std::map<std::string, std::string> 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<QString, QString>::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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
|
@ -41,7 +41,6 @@
|
||||||
#include "tvectorrenderdata.h"
|
#include "tvectorrenderdata.h"
|
||||||
#include "tsimplecolorstyles.h"
|
#include "tsimplecolorstyles.h"
|
||||||
#include "tvectorbrushstyle.h"
|
#include "tvectorbrushstyle.h"
|
||||||
#include "tenv.h"
|
|
||||||
|
|
||||||
// Qt includes
|
// Qt includes
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
|
@ -71,212 +70,6 @@
|
||||||
using namespace StyleEditorGUI;
|
using namespace StyleEditorGUI;
|
||||||
using namespace DVGui;
|
using namespace DVGui;
|
||||||
|
|
||||||
//*****************************************************************************
|
|
||||||
// Hex line editor
|
|
||||||
//*****************************************************************************
|
|
||||||
|
|
||||||
#define COLORNAMES_FILE "colornames.txt"
|
|
||||||
|
|
||||||
QMap<QString, QString> HexLineEdit::s_defcolornames;
|
|
||||||
QMap<QString, QString> 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<QString, QString>::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<QString, QString> &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
|
// UndoPaletteChange definition
|
||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
|
@ -4238,6 +4031,7 @@ StyleEditor::StyleEditor(PaletteController *paletteController, QWidget *parent)
|
||||||
, m_enabledFirstAndLastTab(false)
|
, m_enabledFirstAndLastTab(false)
|
||||||
, m_oldStyle(0)
|
, m_oldStyle(0)
|
||||||
, m_parent(parent)
|
, m_parent(parent)
|
||||||
|
, m_hexColorNamesEditor(0)
|
||||||
, m_editedStyle(0) {
|
, m_editedStyle(0) {
|
||||||
// TOGLIERE
|
// TOGLIERE
|
||||||
TFilePath libraryPath = ToonzFolder::getLibraryFolder();
|
TFilePath libraryPath = ToonzFolder::getLibraryFolder();
|
||||||
|
@ -4411,8 +4205,6 @@ QFrame *StyleEditor::createBottomWidget() {
|
||||||
m_hexLineEdit = new HexLineEdit("", this);
|
m_hexLineEdit = new HexLineEdit("", this);
|
||||||
m_hexLineEdit->setObjectName("HexLineEdit");
|
m_hexLineEdit->setObjectName("HexLineEdit");
|
||||||
m_hexLineEdit->setFixedWidth(75);
|
m_hexLineEdit->setFixedWidth(75);
|
||||||
m_hexLineEdit->loadDefaultColorNames(false);
|
|
||||||
m_hexLineEdit->loadUserColorNames(false);
|
|
||||||
|
|
||||||
m_toolBar = new QToolBar(this);
|
m_toolBar = new QToolBar(this);
|
||||||
m_toolBar->setMovable(false);
|
m_toolBar->setMovable(false);
|
||||||
|
@ -4447,6 +4239,10 @@ QFrame *StyleEditor::createBottomWidget() {
|
||||||
m_plainColorPage->m_hsvFrame->setVisible(false);
|
m_plainColorPage->m_hsvFrame->setVisible(false);
|
||||||
m_plainColorPage->m_rgbFrame->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);
|
QToolButton *toolButton = new QToolButton(this);
|
||||||
toolButton->setIcon(createQIcon("menu"));
|
toolButton->setIcon(createQIcon("menu"));
|
||||||
toolButton->setFixedSize(22, 22);
|
toolButton->setFixedSize(22, 22);
|
||||||
|
@ -4546,6 +4342,8 @@ QFrame *StyleEditor::createBottomWidget() {
|
||||||
SLOT(setVisible(bool)));
|
SLOT(setVisible(bool)));
|
||||||
ret = ret && connect(m_hexLineEdit, SIGNAL(editingFinished()), this,
|
ret = ret && connect(m_hexLineEdit, SIGNAL(editingFinished()), this,
|
||||||
SLOT(onHexChanged()));
|
SLOT(onHexChanged()));
|
||||||
|
ret = ret && connect(m_hexEditorAction, SIGNAL(triggered()), this,
|
||||||
|
SLOT(onHexEditor()));
|
||||||
ret = ret && connect(m_toggleOrientationAction, SIGNAL(triggered()),
|
ret = ret && connect(m_toggleOrientationAction, SIGNAL(triggered()),
|
||||||
m_plainColorPage, SLOT(toggleOrientation()));
|
m_plainColorPage, SLOT(toggleOrientation()));
|
||||||
ret = ret && connect(m_toggleOrientationAction, SIGNAL(triggered()), this,
|
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) {
|
void StyleEditor::onHexEdited(const QString &text) {
|
||||||
m_hsvAction->setDisabled(true);
|
m_hsvAction->setDisabled(true);
|
||||||
m_alphaAction->setDisabled(true);
|
m_alphaAction->setDisabled(true);
|
||||||
|
|
Loading…
Reference in a new issue