justburner a72214
#include "toonzqt/hexcolornames.h"
justburner a72214
justburner a72214
// TnzLib includes
justburner a72214
#include "toonz/toonzfolders.h"
justburner a72214
justburner a72214
// TnzCore includes
justburner a72214
#include "tconvert.h"
justburner a72214
#include "tfiletype.h"
justburner a72214
#include "tsystem.h"
justburner a72214
#include "tcolorstyles.h"
justburner a72214
#include "tpalette.h"
justburner a72214
#include "tpixel.h"
justburner a72214
#include "tvectorimage.h"
justburner a72214
#include "trasterimage.h"
justburner a72214
#include "tlevel_io.h"
justburner a72214
justburner a72214
// Qt includes
justburner a72214
#include <qcoreapplication></qcoreapplication>
justburner a72214
#include <qpainter></qpainter>
justburner a72214
#include <qmouseevent></qmouseevent>
justburner a72214
#include <qlabel></qlabel>
justburner a72214
#include <qtooltip></qtooltip>
justburner a72214
#include <qtabwidget></qtabwidget>
justburner a72214
#include <qcheckbox></qcheckbox>
justburner a72214
#include <qfiledialog></qfiledialog>
justburner a72214
#include <qmessagebox></qmessagebox>
justburner a72214
justburner a72214
using namespace DVGui;
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
#define COLORNAMES_FILE "colornames.txt"
justburner a72214
justburner a72214
QMap<qstring, qstring=""> HexColorNames::s_maincolornames;</qstring,>
justburner a72214
QMap<qstring, qstring=""> HexColorNames::s_usercolornames;</qstring,>
justburner a72214
QMap<qstring, qstring=""> HexColorNames::s_tempcolornames;</qstring,>
justburner a72214
justburner a72214
HexColorNames *HexColorNames::instance() {
justburner a72214
  static HexColorNames _instance;
justburner a72214
  return &_instance;
justburner a72214
}
justburner a72214
justburner a72214
HexColorNames::HexColorNames() {}
justburner a72214
justburner a72214
void HexColorNames::loadColorTableXML(QMap<qstring, qstring=""> &table,</qstring,>
justburner a72214
                                    const TFilePath &fp) {
justburner a72214
  if (!TFileStatus(fp).doesExist()) throw TException("File not found");
justburner a72214
justburner a72214
  TIStream is(fp);
justburner a72214
  if (!is) throw TException("Can't read color names");
justburner a72214
justburner a72214
  std::string tagName;
justburner a72214
  if (!is.matchTag(tagName) || tagName != "colors")
justburner a72214
    throw TException("Not a color names file");
justburner a72214
justburner a72214
  while (!is.matchEndTag()) {
justburner a72214
    if (!is.matchTag(tagName)) throw TException("Expected tag");
justburner a72214
    if (tagName == "color") {
justburner a72214
      QString name, hex;
justburner a72214
      name = QString::fromStdString(is.getTagAttribute("name"));
justburner a72214
      std::string hexs;
justburner a72214
      is >> hexs;
justburner a72214
      hex = QString::fromStdString(hexs);
justburner a72214
      if (name.size() != 0 && hex.size() != 0)
justburner a72214
        table.insert(name.toLower(), hex);
justburner a72214
      if (!is.matchEndTag()) throw TException("Expected end tag");
justburner a72214
    } else
justburner a72214
      throw TException("unexpected tag /" + tagName + "/");
justburner a72214
  }
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexColorNames::saveColorTableXML(QMap<qstring, qstring=""> &table,</qstring,>
justburner a72214
                                      const TFilePath &fp) {
justburner a72214
  TOStream os(fp);
justburner a72214
  if (!os) throw TException("Can't write color names");
justburner a72214
justburner a72214
  os.openChild("colors");
justburner a72214
justburner a72214
  QMap<qstring, qstring="">::const_iterator it;</qstring,>
justburner a72214
  std::map<std::string, std::string=""> attrs;</std::string,>
justburner a72214
  for (it = table.cbegin(); it != table.cend(); ++it) {
justburner a72214
    std::string nameStd = it.key().toStdString();
justburner a72214
    attrs.clear();
justburner a72214
    attrs.insert({"name", nameStd});
justburner a72214
    os.openChild("color", attrs);
justburner a72214
    os << it.value();
justburner a72214
    os.closeChild();
justburner a72214
  }
justburner a72214
justburner a72214
  os.closeChild();
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
bool HexColorNames::parseHexInternal(QString text, TPixel &outPixel) {
justburner a72214
  bool ok;
justburner a72214
  uint parsedValue = text.toUInt(&ok, 16);
justburner a72214
  if (!ok) return false;
justburner a72214
justburner a72214
  switch (text.length()) {
justburner a72214
  case 8:  // #RRGGBBAA
justburner a72214
    outPixel.r = parsedValue >> 24;
justburner a72214
    outPixel.g = parsedValue >> 16;
justburner a72214
    outPixel.b = parsedValue >> 8;
justburner a72214
    outPixel.m = parsedValue;
justburner a72214
    break;
justburner a72214
  case 6:  // #RRGGBB
justburner a72214
    outPixel.r = parsedValue >> 16;
justburner a72214
    outPixel.g = parsedValue >> 8;
justburner a72214
    outPixel.b = parsedValue;
justburner a72214
    outPixel.m = 255;
justburner a72214
    break;
justburner a72214
  case 4:  // #RGBA
justburner a72214
    outPixel.r = (parsedValue >> 12) & 15;
justburner a72214
    outPixel.r |= outPixel.r << 4;
justburner a72214
    outPixel.g = (parsedValue >> 8) & 15;
justburner a72214
    outPixel.g |= outPixel.g << 4;
justburner a72214
    outPixel.b = (parsedValue >> 4) & 15;
justburner a72214
    outPixel.b |= outPixel.b << 4;
justburner a72214
    outPixel.m = parsedValue & 15;
justburner a72214
    outPixel.m |= outPixel.m << 4;
justburner a72214
    break;
justburner a72214
  case 3:  // #RGB
justburner a72214
    outPixel.r = (parsedValue >> 8) & 15;
justburner a72214
    outPixel.r |= outPixel.r << 4;
justburner a72214
    outPixel.g = (parsedValue >> 4) & 15;
justburner a72214
    outPixel.g |= outPixel.g << 4;
justburner a72214
    outPixel.b = parsedValue & 15;
justburner a72214
    outPixel.b |= outPixel.b << 4;
justburner a72214
    outPixel.m = 255;
justburner a72214
    break;
justburner a72214
  case 2:  // #VV (non-standard)
justburner a72214
    outPixel.r = parsedValue;
justburner a72214
    outPixel.g = outPixel.r;
justburner a72214
    outPixel.b = outPixel.r;
justburner a72214
    outPixel.m = 255;
justburner a72214
    break;
justburner a72214
  case 1:  // #V (non-standard)
justburner a72214
    outPixel.r = parsedValue & 15;
justburner a72214
    outPixel.r |= outPixel.r << 4;
justburner a72214
    outPixel.g = outPixel.r;
justburner a72214
    outPixel.b = outPixel.r;
justburner a72214
    outPixel.m = 255;
justburner a72214
    break;
justburner a72214
  default:
justburner a72214
    return false;
justburner a72214
  }
justburner a72214
  return true;
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
bool HexColorNames::loadMainFile(bool reload) {
justburner a72214
  TFilePath mainCTFp = TEnv::getConfigDir() + COLORNAMES_FILE;
justburner a72214
justburner a72214
  // Load main color names
justburner a72214
  try {
justburner a72214
    if (reload || s_maincolornames.size() == 0) {
justburner a72214
      s_maincolornames.clear();
justburner a72214
      loadColorTableXML(s_maincolornames, mainCTFp);
justburner a72214
    }
justburner a72214
  } catch (...) {
justburner a72214
    return false;
justburner a72214
  }
justburner a72214
  return true;
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
bool HexColorNames::hasUserFile() {
justburner a72214
  TFilePath userCTFp = ToonzFolder::getMyModuleDir() + COLORNAMES_FILE;
justburner a72214
  return TFileStatus(userCTFp).doesExist();
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
bool HexColorNames::loadUserFile(bool reload) {
justburner a72214
  TFilePath userCTFp = ToonzFolder::getMyModuleDir() + COLORNAMES_FILE;
justburner a72214
justburner a72214
  // Load user color names (if exists...)
justburner a72214
  if (TFileStatus(userCTFp).doesExist()) {
justburner a72214
    try {
justburner a72214
      if (reload || s_usercolornames.size() == 0) {
justburner a72214
        s_usercolornames.clear();
justburner a72214
        loadColorTableXML(s_usercolornames, userCTFp);
justburner a72214
      }
justburner a72214
    } catch (...) {
justburner a72214
      return false;
justburner a72214
    }
justburner a72214
  }
justburner a72214
  return true;
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
bool HexColorNames::loadTempFile(const TFilePath &fp) {
justburner a72214
  if (TFileStatus(fp).doesExist()) {
justburner a72214
    try {
justburner a72214
      s_tempcolornames.clear();
justburner a72214
      loadColorTableXML(s_tempcolornames, fp);
justburner a72214
    } catch (...) {
justburner a72214
      return false;
justburner a72214
    }
justburner a72214
  }
justburner a72214
  return true;
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
bool HexColorNames::saveUserFile() {
justburner a72214
  TFilePath userCTFp = ToonzFolder::getMyModuleDir() + COLORNAMES_FILE;
justburner a72214
justburner a72214
  try {
justburner a72214
    saveColorTableXML(s_usercolornames, userCTFp);
justburner a72214
  } catch (...) {
justburner a72214
    return false;
justburner a72214
  }
justburner a72214
  return true;
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
bool HexColorNames::saveTempFile(const TFilePath &fp) {
justburner a72214
  try {
justburner a72214
    saveColorTableXML(s_tempcolornames, fp);
justburner a72214
  } catch (...) {
justburner a72214
    return false;
justburner a72214
  }
justburner a72214
  return true;
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexColorNames::clearUserEntries() { s_usercolornames.clear(); }
justburner a72214
justburner a72214
void HexColorNames::clearTempEntries() { s_tempcolornames.clear(); }
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexColorNames::setUserEntry(const QString &name, const QString &hex) {
justburner a72214
  s_usercolornames.insert(name, hex);
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexColorNames::setTempEntry(const QString &name, const QString &hex) {
justburner a72214
  s_tempcolornames.insert(name, hex);
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
bool HexColorNames::parseText(QString text, TPixel &outPixel) {
justburner a72214
  static QRegExp space("\\s");
justburner a72214
  text.remove(space);
justburner a72214
  if (text.size() == 0) return false;
justburner a72214
  if (text[0] == "#") {
justburner a72214
    text.remove(0, 1);
justburner a72214
    return parseHexInternal(text, outPixel);
justburner a72214
  }
justburner a72214
  text = text.toLower();  // table names are lowercase
justburner a72214
justburner a72214
  // Find color from tables, user takes priority
justburner a72214
  QMap<qstring, qstring="">::const_iterator it;</qstring,>
justburner a72214
  it = s_usercolornames.constFind(text);
justburner a72214
  if (it == s_usercolornames.constEnd()) {
justburner a72214
    it = s_maincolornames.constFind(text);
justburner a72214
    if (it == s_maincolornames.constEnd()) return false;
justburner a72214
  }
justburner a72214
justburner a72214
  QString hexText = it.value();
justburner a72214
  hexText.remove(space);
justburner a72214
  if (hexText[0] == "#") {
justburner a72214
    hexText.remove(0, 1);
justburner a72214
    return parseHexInternal(hexText, outPixel);
justburner a72214
  }
justburner a72214
  return false;
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
bool HexColorNames::parseHex(QString text, TPixel &outPixel) {
justburner a72214
  static QRegExp space("\\s");
justburner a72214
  text.remove(space);
justburner a72214
  if (text.size() == 0) return false;
justburner a72214
  if (text[0] == "#") {
justburner a72214
    text.remove(0, 1);
justburner a72214
  }
justburner a72214
  return parseHexInternal(text, outPixel);
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
QString HexColorNames::generateHex(TPixel pixel) {
justburner a72214
  if (pixel.m == 255) {
justburner a72214
    // Opaque, omit alpha
justburner a72214
    return QString("#%1%2%3")
justburner a72214
        .arg(pixel.r, 2, 16, QLatin1Char('0'))
justburner a72214
        .arg(pixel.g, 2, 16, QLatin1Char('0'))
justburner a72214
        .arg(pixel.b, 2, 16, QLatin1Char('0'))
justburner a72214
        .toUpper();
justburner a72214
  } else {
justburner a72214
    return QString("#%1%2%3%4")
justburner a72214
        .arg(pixel.r, 2, 16, QLatin1Char('0'))
justburner a72214
        .arg(pixel.g, 2, 16, QLatin1Char('0'))
justburner a72214
        .arg(pixel.b, 2, 16, QLatin1Char('0'))
justburner a72214
        .arg(pixel.m, 2, 16, QLatin1Char('0'))
justburner a72214
        .toUpper();
justburner a72214
  }
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
//*****************************************************************************
justburner a72214
//  Hex line widget
justburner a72214
//*****************************************************************************
justburner a72214
justburner a72214
TEnv::IntVar HexLineEditAutoComplete("HexLineEditAutoComplete", 1);
justburner a72214
justburner a72214
HexLineEdit::HexLineEdit(const QString &contents, QWidget *parent)
justburner a72214
    : QLineEdit(contents, parent)
justburner a72214
    , m_editing(false)
justburner a72214
    , m_color(0, 0, 0)
justburner a72214
    , m_completer(nullptr) {
justburner a72214
  HexColorNames::loadMainFile(false);
justburner a72214
  HexColorNames::loadUserFile(false);
justburner a72214
justburner a72214
  if (HexLineEditAutoComplete != 0) onAutoCompleteChanged(true);
justburner a72214
justburner a72214
  bool ret = true;
justburner a72214
justburner a72214
  ret = ret &&
justburner a72214
        connect(HexColorNames::instance(), SIGNAL(autoCompleteChanged(bool)),
justburner a72214
                this, SLOT(onAutoCompleteChanged(bool)));
justburner a72214
  ret = ret && connect(HexColorNames::instance(), SIGNAL(colorsChanged()), this,
justburner a72214
          SLOT(onColorsChanged()));
justburner a72214
  assert(ret);
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexLineEdit::updateColor() {
justburner a72214
  setText(HexColorNames::generateHex(m_color));
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexLineEdit::setStyle(TColorStyle &style, int index) {
justburner a72214
  setColor(style.getColorParamValue(index));
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexLineEdit::setColor(TPixel color) {
justburner a72214
  if (m_color != color) {
justburner a72214
    m_color = color;
justburner a72214
    if (isVisible()) updateColor();
justburner a72214
  }
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
bool HexLineEdit::fromText(QString text) {
justburner a72214
  bool res = HexColorNames::parseText(text, m_color);
justburner a72214
  if (res) updateColor();
justburner a72214
  return res;
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
bool HexLineEdit::fromHex(QString text) {
justburner a72214
  bool res = HexColorNames::parseHex(text, m_color);
justburner a72214
  if (res) updateColor();
justburner a72214
  return res;
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexLineEdit::mousePressEvent(QMouseEvent *event) {
justburner a72214
  QLineEdit::mousePressEvent(event);
justburner a72214
  // Make Ctrl key disable select all so the user can click a specific character
justburner a72214
  // after a focus-in, this likely will fall into a hidden feature thought.
justburner a72214
  bool ctrlDown = event->modifiers() & Qt::ControlModifier;
justburner a72214
  if (!m_editing && !ctrlDown) selectAll();
justburner a72214
  m_editing = true;
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexLineEdit::focusOutEvent(QFocusEvent *event) {
justburner a72214
  QLineEdit::focusOutEvent(event);
justburner a72214
  deselect();
justburner a72214
  m_editing = false;
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexLineEdit::showEvent(QShowEvent *event) {
justburner a72214
  QLineEdit::showEvent(event);
justburner a72214
  updateColor();
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
QCompleter *HexLineEdit::getCompleter() {
justburner a72214
  QStringList autolist;
justburner a72214
justburner a72214
  // Build words list from all color names tables
justburner a72214
  HexColorNames::iterator it;
justburner a72214
  for (it = HexColorNames::beginMain(); it != HexColorNames::endMain(); ++it) {
justburner a72214
    autolist.append(it.name());
justburner a72214
  }
justburner a72214
  for (it = HexColorNames::beginUser(); it != HexColorNames::endUser(); ++it) {
justburner a72214
    autolist.append(it.name());
justburner a72214
  }
justburner a72214
justburner a72214
  QCompleter *completer = new QCompleter(autolist);
justburner a72214
  completer->setCaseSensitivity(Qt::CaseInsensitive);
justburner a72214
  return completer;
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexLineEdit::onAutoCompleteChanged(bool enable) {
justburner a72214
  if (m_completer) {
justburner a72214
    m_completer->deleteLater();
justburner a72214
    setCompleter(nullptr);
justburner a72214
    m_completer = nullptr;
justburner a72214
  }
justburner a72214
  if (enable) {
justburner a72214
    m_completer = getCompleter();
justburner a72214
    setCompleter(m_completer);
justburner a72214
  }
justburner a72214
}
justburner a72214
justburner a72214
void HexLineEdit::onColorsChanged() { onAutoCompleteChanged(true); }
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
//*****************************************************************************
justburner a72214
//  Hex color names editor
justburner a72214
//*****************************************************************************
justburner a72214
justburner a72214
HexColorNamesEditor::HexColorNamesEditor(QWidget *parent)
justburner a72214
    : DVGui::Dialog(parent, true, false, "HexColorNamesEditor")
justburner a72214
    , m_selectedItem(nullptr)
justburner a72214
    , m_newEntry(false) {
justburner a72214
  setWindowTitle(tr("Hex Color Names Editor"));
justburner a72214
  setModal(false); // user may want to access main style editor and palettes
justburner a72214
justburner a72214
  QPushButton *okButton    = new QPushButton(tr("OK"), this);
justburner a72214
  QPushButton *applyButton = new QPushButton(tr("Apply"), this);
justburner a72214
  QPushButton *closeButton = new QPushButton(tr("Close"), this);
justburner a72214
justburner a72214
  m_unsColorButton = new QPushButton(tr("Unselect"));
justburner a72214
  m_addColorButton = new QPushButton(tr("Add Color"));
justburner a72214
  m_delColorButton = new QPushButton(tr("Delete Color"));
justburner a72214
  m_hexLineEdit    = new HexLineEdit("", this);
justburner a72214
  m_hexLineEdit->setObjectName("HexLineEdit");
justburner a72214
  m_hexLineEdit->setFixedWidth(75);
justburner a72214
justburner a72214
  // Main default color names
justburner a72214
  QGridLayout *mainLay = new QGridLayout();
justburner a72214
  QWidget *mainTab = new QWidget();
justburner a72214
  mainTab->setLayout(mainLay);
justburner a72214
justburner a72214
  m_mainTreeWidget = new QTreeWidget();
justburner a72214
  m_mainTreeWidget->setColumnCount(2);
justburner a72214
  m_mainTreeWidget->setColumnWidth(0, 175);
justburner a72214
  m_mainTreeWidget->setColumnWidth(1, 50);
justburner a72214
  m_mainTreeWidget->setHeaderLabels(QStringList() << "Name"
justburner a72214
                                                  << "Hex value");
justburner a72214
  mainLay->addWidget(m_mainTreeWidget, 0, 0);
justburner a72214
justburner a72214
  // User defined color names
justburner a72214
  QGridLayout *userLay = new QGridLayout();
justburner a72214
  QWidget *userTab     = new QWidget();
justburner a72214
  userTab->setLayout(userLay);
justburner a72214
justburner a72214
  m_userTreeWidget = new QTreeWidget();
justburner a72214
  m_userTreeWidget->setColumnCount(2);
justburner a72214
  m_userTreeWidget->setColumnWidth(0, 175);
justburner a72214
  m_userTreeWidget->setColumnWidth(1, 50);
justburner a72214
  m_userTreeWidget->setHeaderLabels(QStringList() << "Name"
justburner a72214
                                                  << "Hex value");
justburner a72214
  m_colorField = new ColorField(this, true);
justburner a72214
  userLay->addWidget(m_userTreeWidget, 0, 0, 1, 4);
justburner a72214
  userLay->addWidget(m_unsColorButton, 1, 0);
justburner a72214
  userLay->addWidget(m_addColorButton, 1, 1);
justburner a72214
  userLay->addWidget(m_delColorButton, 1, 2);
justburner a72214
  userLay->addWidget(m_hexLineEdit, 1, 3);
justburner a72214
  userLay->addWidget(m_colorField, 2, 0, 1, 4);
justburner a72214
justburner a72214
  // Set delegate
justburner a72214
  m_userEditingDelegate = new HexColorNamesEditingDelegate(m_userTreeWidget);
justburner a72214
  m_mainTreeWidget->setItemDelegate(m_userEditingDelegate);
justburner a72214
  m_userTreeWidget->setItemDelegate(m_userEditingDelegate);
justburner a72214
  populateMainList(false);
justburner a72214
justburner a72214
  // Tabs
justburner a72214
  QTabWidget *tab = new QTabWidget();
justburner a72214
  tab->addTab(userTab, tr("User Defined Colors"));
justburner a72214
  tab->addTab(mainTab, tr("Default Main Colors"));
justburner a72214
  tab->setObjectName("hexTabWidget");
justburner a72214
justburner a72214
  // Bottom widgets
justburner a72214
  QHBoxLayout *bottomLay = new QHBoxLayout();
justburner a72214
  m_autoCompleteCb  = new QCheckBox(tr("Enable Auto-Complete"));
justburner a72214
  m_autoCompleteCb->setChecked(HexLineEditAutoComplete != 0);
justburner a72214
  m_autoCompleteCb->setSizePolicy(QSizePolicy::Expanding,
justburner a72214
                                  QSizePolicy::Preferred);
justburner a72214
  m_importButton = new QPushButton(tr("Import"));
justburner a72214
  m_exportButton = new QPushButton(tr("Export"));
justburner a72214
  bottomLay->setMargin(8);
justburner a72214
  bottomLay->setSpacing(5);
justburner a72214
  bottomLay->addWidget(m_autoCompleteCb);
justburner a72214
  bottomLay->addWidget(m_importButton);
justburner a72214
  bottomLay->addWidget(m_exportButton);
justburner a72214
justburner a72214
  m_topLayout->setContentsMargins(0, 0, 0, 0);
justburner a72214
  m_topLayout->addWidget(tab);
justburner a72214
  m_topLayout->addLayout(bottomLay);
justburner a72214
justburner a72214
  addButtonBarWidget(okButton, applyButton, closeButton);
justburner a72214
justburner a72214
  bool ret = true;
justburner a72214
justburner a72214
  ret = ret && connect(m_userEditingDelegate,
justburner a72214
                       SIGNAL(editingStarted(const QModelIndex &)), this,
justburner a72214
                       SLOT(onEditingStarted(const QModelIndex &)));
justburner a72214
  ret = ret && connect(m_userEditingDelegate,
justburner a72214
                       SIGNAL(editingFinished(const QModelIndex &)), this,
justburner a72214
                       SLOT(onEditingFinished(const QModelIndex &)));
justburner a72214
  ret = ret && connect(m_userEditingDelegate, SIGNAL(editingClosed()), this,
justburner a72214
                       SLOT(onEditingClosed()));
justburner a72214
justburner a72214
  ret =
justburner a72214
      ret &&
justburner a72214
      connect(m_userTreeWidget,
justburner a72214
              SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
justburner a72214
              this,
justburner a72214
              SLOT(onCurrentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
justburner a72214
  ret =
justburner a72214
      ret && connect(m_colorField, SIGNAL(colorChanged(const TPixel32 &, bool)),
justburner a72214
                     this, SLOT(onColorFieldChanged(const TPixel32 &, bool)));
justburner a72214
  ret = ret && connect(m_hexLineEdit, SIGNAL(editingFinished()), this,
justburner a72214
                       SLOT(onHexChanged()));
justburner a72214
justburner a72214
  ret = ret &&
justburner a72214
        connect(m_unsColorButton, SIGNAL(pressed()), this, SLOT(onDeselect()));
justburner a72214
  ret = ret &&
justburner a72214
        connect(m_addColorButton, SIGNAL(pressed()), this, SLOT(onAddColor()));
justburner a72214
  ret = ret &&
justburner a72214
        connect(m_delColorButton, SIGNAL(pressed()), this, SLOT(onDelColor()));
justburner a72214
  ret =
justburner a72214
      ret && connect(m_importButton, SIGNAL(pressed()), this, SLOT(onImport()));
justburner a72214
  ret =
justburner a72214
      ret && connect(m_exportButton, SIGNAL(pressed()), this, SLOT(onExport()));
justburner a72214
justburner a72214
  ret = ret && connect(okButton, SIGNAL(pressed()), this, SLOT(onOK()));
justburner a72214
  ret = ret && connect(applyButton, SIGNAL(pressed()), this, SLOT(onApply()));
justburner a72214
  ret = ret && connect(closeButton, SIGNAL(pressed()), this, SLOT(close()));
justburner a72214
  assert(ret);
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
QTreeWidgetItem *HexColorNamesEditor::addEntry(QTreeWidget *tree,
justburner a72214
                                               const QString &name,
justburner a72214
                                               const QString &hex,
justburner a72214
                                               bool editable) {
justburner a72214
  TPixel pixel = TPixel(0, 0, 0);
justburner a72214
  HexColorNames::parseHex(hex, pixel);
justburner a72214
justburner a72214
  QPixmap pixm(16, 16);
justburner a72214
  pixm.fill(QColor(pixel.r, pixel.g, pixel.b, pixel.m));
justburner a72214
justburner a72214
  QTreeWidgetItem *treeItem = new QTreeWidgetItem(tree);
justburner a72214
  treeItem->setText(0, name);
justburner a72214
  treeItem->setIcon(1, QIcon(pixm));
justburner a72214
  treeItem->setText(1, hex);
justburner a72214
  if (!editable)
justburner a72214
    treeItem->setFlags(treeItem->flags() & ~Qt::ItemIsSelectable);
justburner a72214
  else
justburner a72214
    treeItem->setFlags(treeItem->flags() | Qt::ItemIsEditable);
justburner a72214
justburner a72214
  return treeItem;
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
bool HexColorNamesEditor::updateUserHexEntry(QTreeWidgetItem *treeItem,
justburner a72214
                                             const TPixel32 &color) {
justburner a72214
  if (treeItem) {
justburner a72214
    QPixmap pixm(16, 16);
justburner a72214
    pixm.fill(QColor(color.r, color.g, color.b, color.m));
justburner a72214
justburner a72214
    treeItem->setIcon(1, QIcon(pixm));
justburner a72214
    treeItem->setText(1, HexColorNames::generateHex(color));
justburner a72214
    return true;
justburner a72214
  }
justburner a72214
  return false;
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
bool HexColorNamesEditor::nameValid(const QString& name) {
justburner a72214
  if (name.isEmpty()) return false;
justburner a72214
  return name.count(QRegExp("[\\\\#<>\"']")) == 0;
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
bool HexColorNamesEditor::nameExists(const QString &name,
justburner a72214
                                     QTreeWidgetItem *self) {
justburner a72214
  for (int i = 0; i < m_userTreeWidget->topLevelItemCount(); ++i) {
justburner a72214
    QTreeWidgetItem *item = m_userTreeWidget->topLevelItem(i);
justburner a72214
    if (item == self) continue;
justburner a72214
    if (name.compare(item->text(0), Qt::CaseInsensitive) == 0) return true;
justburner a72214
  }
justburner a72214
  return false;
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexColorNamesEditor::deselectItem(bool treeFocus) {
justburner a72214
  if (m_newEntry) return;
justburner a72214
justburner a72214
  m_userTreeWidget->setCurrentItem(nullptr);
justburner a72214
  if (treeFocus) m_userTreeWidget->setFocus();
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexColorNamesEditor::deleteCurrentItem(bool deselect) {
justburner a72214
  if (m_newEntry) return;
justburner a72214
justburner a72214
  QTreeWidgetItem *treeItem = m_userTreeWidget->currentItem();
justburner a72214
  if (treeItem) delete treeItem;
justburner a72214
  m_selectedItem = nullptr;
justburner a72214
  if (deselect) m_userTreeWidget->setCurrentItem(nullptr);
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexColorNamesEditor::populateMainList(bool reload) {
justburner a72214
  HexColorNames::loadMainFile(reload);
justburner a72214
justburner a72214
  HexColorNames::iterator it;
justburner a72214
  m_mainTreeWidget->clear();
justburner a72214
  for (it = HexColorNames::beginMain(); it != HexColorNames::endMain(); ++it) {
justburner a72214
    addEntry(m_mainTreeWidget, it.name(), it.value(), false);
justburner a72214
  }
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexColorNamesEditor::populateUserList(bool reload) {
justburner a72214
  HexColorNames::loadUserFile(reload);
justburner a72214
justburner a72214
  HexColorNames::iterator it;
justburner a72214
  m_userTreeWidget->clear();
justburner a72214
  for (it = HexColorNames::beginUser(); it != HexColorNames::endUser(); ++it) {
justburner a72214
    if (!nameExists(it.name(), nullptr))
justburner a72214
      addEntry(m_userTreeWidget, it.name(), it.value(), true);
justburner a72214
  }
justburner a72214
justburner a72214
  m_userTreeWidget->sortItems(0, Qt::SortOrder::AscendingOrder);
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexColorNamesEditor::showEvent(QShowEvent *e) {
justburner a72214
  populateUserList(false);
justburner a72214
justburner a72214
  deselectItem(false);
justburner a72214
  m_delColorButton->setEnabled(false);
justburner a72214
  m_unsColorButton->setEnabled(false);
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexColorNamesEditor::keyPressEvent(QKeyEvent *event) {
justburner a72214
  // Blocking dialog default actions is actually desirable
justburner a72214
  // for example when user press Esc or Enter twice while
justburner a72214
  // editing it might close the dialog by accident.
justburner a72214
justburner a72214
  if (!m_userTreeWidget->hasFocus()) return;
justburner a72214
justburner a72214
  switch (event->key()) {
justburner a72214
  case Qt::Key_F5:
justburner a72214
    populateMainList(true);
justburner a72214
    populateUserList(true);
justburner a72214
    m_mainTreeWidget->update();
justburner a72214
    m_userTreeWidget->update();
justburner a72214
    break;
justburner a72214
  case Qt::Key_Escape:
justburner a72214
    deselectItem(true);
justburner a72214
    break;
justburner a72214
  case Qt::Key_Delete:
justburner a72214
    deleteCurrentItem(false);
justburner a72214
    break;
justburner a72214
  case Qt::Key_Insert:
justburner a72214
    onAddColor();
justburner a72214
    break;
justburner a72214
  }
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexColorNamesEditor::focusInEvent(QFocusEvent *e) {
justburner a72214
  QWidget::focusInEvent(e);
justburner a72214
  qApp->installEventFilter(this);
justburner a72214
}
justburner a72214
justburner a72214
//--------------------------------------------------------
justburner a72214
justburner a72214
void HexColorNamesEditor::focusOutEvent(QFocusEvent *e) {
justburner a72214
  QWidget::focusOutEvent(e);
justburner a72214
  qApp->removeEventFilter(this);
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
bool HexColorNamesEditor::eventFilter(QObject *obj, QEvent *e) {
justburner a72214
  if (e->type() == QEvent::Shortcut ||
justburner a72214
      e->type() == QEvent::ShortcutOverride) {
justburner a72214
      e->accept();
justburner a72214
      return true;
justburner a72214
  }
justburner a72214
  return false;
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexColorNamesEditor::onCurrentItemChanged(QTreeWidgetItem *current,
justburner a72214
                                               QTreeWidgetItem *previous) {
justburner a72214
  m_selectedItem = current;
justburner a72214
  m_delColorButton->setEnabled(current);
justburner a72214
  m_unsColorButton->setEnabled(current);
justburner a72214
justburner a72214
  if (!current) return;
justburner a72214
  m_selectedName = current->text(0);
justburner a72214
  m_selectedHex  = current->text(1);
justburner a72214
  m_selectedColn = 0;
justburner a72214
justburner a72214
  // Modify color field
justburner a72214
  TPixel pixel(0, 0, 0);
justburner a72214
  if (HexColorNames::parseHex(m_selectedHex, pixel)) {
justburner a72214
    m_colorField->setColor(pixel);
justburner a72214
    m_hexLineEdit->setColor(pixel);
justburner a72214
  }
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexColorNamesEditor::onEditingStarted(const QModelIndex &modelIndex) {
justburner a72214
  QTreeWidgetItem *item = (QTreeWidgetItem *)modelIndex.internalPointer();
justburner a72214
  int column            = modelIndex.column();
justburner a72214
  onItemStarted(item, column);
justburner a72214
}
justburner a72214
justburner a72214
void HexColorNamesEditor::onEditingFinished(const QModelIndex &modelIndex) {
justburner a72214
  QTreeWidgetItem *item = (QTreeWidgetItem *)modelIndex.internalPointer();
justburner a72214
  int column            = modelIndex.column();
justburner a72214
  onItemFinished(item, column);
justburner a72214
}
justburner a72214
justburner a72214
void HexColorNamesEditor::onEditingClosed() {
justburner a72214
  onItemFinished(m_selectedItem, m_selectedColn);
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexColorNamesEditor::onItemStarted(QTreeWidgetItem *item, int column) {
justburner a72214
  m_selectedName = item->text(0);
justburner a72214
  m_selectedHex  = item->text(1);
justburner a72214
  m_selectedColn = 0;
justburner a72214
  m_selectedItem = item;
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexColorNamesEditor::onItemFinished(QTreeWidgetItem *item, int column) {
justburner a72214
  if (!m_selectedItem || !item) return;
justburner a72214
  m_delColorButton->setEnabled(true);
justburner a72214
  m_unsColorButton->setEnabled(true);
justburner a72214
justburner a72214
  try {
justburner a72214
    if (m_selectedItem == item) {
justburner a72214
      QString text = item->text(column);
justburner a72214
      if (column == 0) {
justburner a72214
        // Edit Name
justburner a72214
        static QRegExp space("\\s");
justburner a72214
        text.remove(space);
justburner a72214
        text = text.toLower();
justburner a72214
        if (text.isEmpty()) throw "";
justburner a72214
        if (!nameValid(text))
justburner a72214
          throw "Color name is not valid.\nFollowing characters can't be used: \\ # < > \" '";
justburner a72214
        if (nameExists(text, item)) throw "Color name already exists.\nPlease use another name.";
justburner a72214
        item->setText(0, text);
justburner a72214
        m_userTreeWidget->sortItems(0, Qt::SortOrder::AscendingOrder);
justburner a72214
      } else {
justburner a72214
        // Edit Hex
justburner a72214
        TPixel pixel;
justburner a72214
        if (HexColorNames::parseHex(text, pixel)) {
justburner a72214
          m_colorField->setColor(pixel);
justburner a72214
          m_hexLineEdit->setColor(pixel);
justburner a72214
          updateUserHexEntry(item, pixel);
justburner a72214
        } else {
justburner a72214
          item->setText(1, m_selectedHex);
justburner a72214
        }
justburner a72214
      }
justburner a72214
    }
justburner a72214
  } catch (const char *reason) {
justburner a72214
    m_selectedItem = nullptr;
justburner a72214
    if (m_selectedName.isEmpty()) {
justburner a72214
      delete item;
justburner a72214
    } else {
justburner a72214
      item->setText(0, m_selectedName);
justburner a72214
    }
justburner a72214
    if (strlen(reason)) DVGui::warning(tr(reason));
justburner a72214
  } catch (...) {
justburner a72214
    m_selectedItem = nullptr;
justburner a72214
    delete item;
justburner a72214
  }
justburner a72214
  m_newEntry = false;
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexColorNamesEditor::onColorFieldChanged(const TPixel32 &color,
justburner a72214
                                              bool isDragging) {
justburner a72214
  QTreeWidgetItem *treeItem = m_userTreeWidget->currentItem();
justburner a72214
  if (updateUserHexEntry(treeItem, color)) {
justburner a72214
    m_userTreeWidget->setCurrentItem(treeItem);
justburner a72214
  }
justburner a72214
  m_hexLineEdit->setColor(color);
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexColorNamesEditor::onHexChanged() {
justburner a72214
  QTreeWidgetItem *treeItem = m_userTreeWidget->currentItem();
justburner a72214
  if (m_hexLineEdit->fromText(m_hexLineEdit->text())) {
justburner a72214
    TPixel pixel = m_hexLineEdit->getColor();
justburner a72214
    updateUserHexEntry(treeItem, pixel);
justburner a72214
    m_colorField->setColor(pixel);
justburner a72214
  }
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexColorNamesEditor::onAddColor() {
justburner a72214
  if (m_newEntry) return;
justburner a72214
justburner a72214
  TPixel pixel = m_colorField->getColor();
justburner a72214
  QString hex = HexColorNames::generateHex(pixel);
justburner a72214
  QTreeWidgetItem *treeItem = addEntry(m_userTreeWidget, "", hex, true);
justburner a72214
justburner a72214
  m_userTreeWidget->setCurrentItem(treeItem);
justburner a72214
  onItemStarted(treeItem, 0);
justburner a72214
  m_newEntry = true;
justburner a72214
  m_userTreeWidget->editItem(treeItem, 0);
justburner a72214
justburner a72214
  m_delColorButton->setEnabled(false);
justburner a72214
  m_unsColorButton->setEnabled(false);
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexColorNamesEditor::onDelColor() {
justburner a72214
  if (m_newEntry) return;
justburner a72214
justburner a72214
  deleteCurrentItem(true);
justburner a72214
  m_userTreeWidget->setFocus();
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexColorNamesEditor::onDeselect() { deselectItem(false); }
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexColorNamesEditor::onImport() {
justburner a72214
  QString fileName = QFileDialog::getOpenFileName(
justburner a72214
      this, tr("Open Color Names"), QString(),
justburner a72214
      tr("Text or XML (*.txt *.xml);;Text files (*.txt);;XML files (*.xml)"));
justburner a72214
  if (fileName.isEmpty()) return;
justburner a72214
justburner a72214
  QMessageBox::StandardButton ret = QMessageBox::question(
justburner a72214
      this, tr("Hex Color Names Import"), tr("Do you want to merge with existing entries?"),
justburner a72214
      QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No |
justburner a72214
                                   QMessageBox::Cancel));
justburner a72214
  if (ret == QMessageBox::Cancel) return;
justburner a72214
justburner a72214
  if (!HexColorNames::loadTempFile(TFilePath(fileName))) {
justburner a72214
    DVGui::warning(tr("Error importing color names XML"));
justburner a72214
  }
justburner a72214
  HexColorNames::iterator it;
justburner a72214
  if (ret == QMessageBox::No) m_userTreeWidget->clear();
justburner a72214
  for (it = HexColorNames::beginTemp(); it != HexColorNames::endTemp(); ++it) {
justburner a72214
    if (!nameExists(it.name(), nullptr))
justburner a72214
      addEntry(m_userTreeWidget, it.name(), it.value(), true);
justburner a72214
  }
justburner a72214
  HexColorNames::clearTempEntries();
justburner a72214
  m_userTreeWidget->sortItems(0, Qt::SortOrder::AscendingOrder);
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexColorNamesEditor::onExport() {
justburner a72214
  QString fileName = QFileDialog::getSaveFileName(
justburner a72214
      this, tr("Save Color Names"), QString(),
justburner a72214
      tr("XML files (*.xml);;Text files (*.txt)"));
justburner a72214
  if (fileName.isEmpty()) return;
justburner a72214
justburner a72214
  HexColorNames::clearTempEntries();
justburner a72214
  for (int i = 0; i < m_userTreeWidget->topLevelItemCount(); ++i) {
justburner a72214
    QTreeWidgetItem *item = m_userTreeWidget->topLevelItem(i);
justburner a72214
    HexColorNames::setTempEntry(item->text(0), item->text(1));
justburner a72214
  }
justburner a72214
  if (!HexColorNames::saveTempFile(TFilePath(fileName))) {
justburner a72214
    DVGui::warning(tr("Error exporting color names XML"));
justburner a72214
  }
justburner a72214
}
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------
justburner a72214
justburner a72214
void HexColorNamesEditor::onOK() {
justburner a72214
  onApply();
justburner a72214
  close();
justburner a72214
};
justburner a72214
justburner a72214
void HexColorNamesEditor::onApply() {
justburner a72214
  HexColorNames::clearUserEntries();
justburner a72214
  for (int i = 0; i < m_userTreeWidget->topLevelItemCount(); ++i) {
justburner a72214
    QTreeWidgetItem *item = m_userTreeWidget->topLevelItem(i);
justburner a72214
    HexColorNames::setUserEntry(item->text(0), item->text(1));
justburner a72214
  }
justburner a72214
  HexColorNames::saveUserFile();
justburner a72214
  HexColorNames::instance()->emitChanged();
justburner a72214
justburner a72214
  bool oldAutoCompState = (HexLineEditAutoComplete != 0);
justburner a72214
  bool newAutoCompState = m_autoCompleteCb->isChecked();
justburner a72214
  if (oldAutoCompState != newAutoCompState) {
justburner a72214
    HexLineEditAutoComplete = newAutoCompState ? 1 : 0;
justburner a72214
    HexColorNames::instance()->emitAutoComplete(newAutoCompState);
justburner a72214
  }
justburner a72214
};
justburner a72214
justburner a72214
//-----------------------------------------------------------------------------