commit 56213bb0b578e7bedd3ab5f7d4f251d4ad32e996
Author: Juergen Spitzmueller <[email protected]>
Date: Mon Mar 17 16:48:43 2025 +0100
Implement central model for ColorsCombos
This should hopefully reduce redundant cycles.
---
src/frontends/qt/ColorsCombo.cpp | 600 ++++++++++++++++++++++++++++++++------
src/frontends/qt/ColorsCombo.h | 52 +++-
src/frontends/qt/GuiBox.cpp | 3 -
src/frontends/qt/GuiBox.h | 3 -
src/frontends/qt/GuiCharacter.cpp | 8 -
src/frontends/qt/GuiCharacter.h | 2 -
src/frontends/qt/GuiDocument.cpp | 21 +-
src/frontends/qt/GuiTabular.cpp | 8 -
src/frontends/qt/GuiTabular.h | 2 -
src/frontends/qt/GuiView.cpp | 117 +++++++-
src/frontends/qt/GuiView.h | 16 +
11 files changed, 688 insertions(+), 144 deletions(-)
diff --git a/src/frontends/qt/ColorsCombo.cpp b/src/frontends/qt/ColorsCombo.cpp
index 734df200f8..5ae8c787d7 100644
--- a/src/frontends/qt/ColorsCombo.cpp
+++ b/src/frontends/qt/ColorsCombo.cpp
@@ -11,141 +11,565 @@
#include <config.h>
#include "ColorsCombo.h"
-#include "LaTeXColors.h"
+#include "GuiView.h"
+#include "support/debug.h"
#include "support/gettext.h"
+#include "support/lassert.h"
#include "support/lstrings.h"
+#include "support/qstring_helpers.h"
+
#include "qt_helpers.h"
-#include "support/qstring_helpers.h"
+#include <QAbstractTextDocumentLayout>
+#include <QComboBox>
+#include <QHeaderView>
+#include <QItemDelegate>
+#include <QPainter>
+#include <QSortFilterProxyModel>
+#include <QStandardItemModel>
+#include <QTextFrame>
+
+#include "GuiApplication.h"
#include <QPainter>
+#include <QListView>
using namespace lyx::support;
namespace lyx {
namespace frontend {
+class ColItemDelegate : public QItemDelegate {
+public:
+ ///
+ explicit ColItemDelegate(ColorsCombo * cc)
+ : QItemDelegate(cc), cc_(cc)
+ {}
+ ///
+ void paint(QPainter * painter, QStyleOptionViewItem const & option,
+ QModelIndex const & index) const override;
+ ///
+ void drawDisplay(QPainter * painter, QStyleOptionViewItem const & opt,
+ const QRect & /*rect*/, const QString & text ) const override;
+ ///
+ QSize sizeHint(QStyleOptionViewItem const & opt,
+ QModelIndex const & index) const override;
+
+private:
+ ///
+ void drawCategoryHeader(QPainter * painter, QStyleOptionViewItem const
& opt,
+ QString const & category) const;
+ ///
+ QString underlineFilter(QString const & s) const;
+ ///
+ ColorsCombo * cc_;
+};
+
+
+class CCFilterModel : public QSortFilterProxyModel {
+public:
+ ///
+ CCFilterModel(QObject * parent = nullptr)
+ : QSortFilterProxyModel(parent)
+ {}
+};
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// ColorsCombo::Private
+//
+/////////////////////////////////////////////////////////////////////
+
+struct ColorsCombo::Private
+{
+ Private(ColorsCombo * parent) : p(parent),
+ // set the model with five columns
+ // 1st: translated item names
+ // 2nd: raw names
+ // 3rd: category
+ // 4th: availability (bool)
+ model_(guiApp->currentView()->viewColorsModel()),
+ filterModel_(new CCFilterModel(p)),
+ lastSel_(-1),
+ ColItemDelegate_(new ColItemDelegate(parent)),
+ visibleCategories_(0), inShowPopup_(false)
+ {
+ filterModel_->setSourceModel(model_);
+ }
+
+ void resetFilter() { setFilter(QString()); }
+ ///
+ void setFilter(QString const & s);
+ ///
+ void countCategories();
+ ///
+ void toggleRows(QString const data, bool const toggle);
+ ///
+ ColorsCombo * p;
+
+ /** the layout model:
+ * 1st column: translated GUI name,
+ * 2nd column: raw item name,
+ * 3rd column: category,
+ * 4th column: custom color?
+ **/
+ QStandardItemModel * model_;
+ /// the proxy model filtering \c model_
+ CCFilterModel * filterModel_;
+ /// the (model-) index of the last successful selection
+ int lastSel_;
+ /// the character filter
+ QString filter_;
+ ///
+ ColItemDelegate * ColItemDelegate_;
+ ///
+ unsigned visibleCategories_;
+ ///
+ bool inShowPopup_;
+};
+
+
+static QString categoryCC(QAbstractItemModel const & model, int row)
+{
+ return model.data(model.index(row, 2), Qt::DisplayRole).toString();
+}
+
+
+static int headerHeightCC(QStyleOptionViewItem const & opt)
+{
+ return opt.fontMetrics.height();
+}
+
+
+void ColItemDelegate::paint(QPainter * painter, QStyleOptionViewItem const &
option,
+ QModelIndex const & index) const
+{
+ QStyleOptionViewItem opt = option;
+
+ // default background
+ painter->fillRect(opt.rect, opt.palette.color(QPalette::Base));
+
+ QString cat = categoryCC(*index.model(), index.row());
+
+ // not the same as in the previous line?
+ if (cc_->d->visibleCategories_ > 0
+ && (index.row() == 0 || cat != categoryCC(*index.model(),
index.row() - 1))) {
+ painter->save();
+
+ // draw unselected background
+ QStyle::State state = opt.state;
+ opt.state = opt.state & ~QStyle::State_Selected;
+ drawBackground(painter, opt, index);
+ opt.state = state;
+
+ // draw category header
+ drawCategoryHeader(painter, opt,
+ categoryCC(*index.model(), index.row()));
+
+ // move rect down below header
+ opt.rect.setTop(opt.rect.top() + headerHeightCC(opt));
+
+ painter->restore();
+ }
+
+ QItemDelegate::paint(painter, opt, index);
+}
+
+
+void ColItemDelegate::drawDisplay(QPainter * painter, QStyleOptionViewItem
const & opt,
+ const QRect & /*rect*/, const QString &
text_in) const
+{
+ QString text(text_in);
+ // Mark default color
+ if (cc_->need_default_color_ && cc_->isDefaultColor(text))
+ text = toqstr(bformat(_("%1$s (= Default[[color]])"),
qstring_to_ucs4(text)));
+
+ QString utext = underlineFilter(text);
+
+ // Draw the rich text.
+ painter->save();
+ QColor col = opt.palette.text().color();
+ if (opt.state & QStyle::State_Selected)
+ col = opt.palette.highlightedText().color();
+ QAbstractTextDocumentLayout::PaintContext context;
+ context.palette.setColor(QPalette::Text, col);
+
+ QTextDocument doc;
+ doc.setDefaultFont(opt.font);
+ doc.setHtml(utext);
+
+ QTextFrameFormat fmt = doc.rootFrame()->frameFormat();
+ fmt.setMargin(0);
+ if (cc_->left_margin_ != -1)
+ fmt.setLeftMargin(cc_->left_margin_);
+
+ doc.rootFrame()->setFrameFormat(fmt);
+
+ painter->translate(opt.rect.x() + 5,
+ opt.rect.y() + (opt.rect.height() - opt.fontMetrics.height()) /
2);
+ doc.documentLayout()->draw(painter, context);
+ painter->restore();
+}
+
+
+QSize ColItemDelegate::sizeHint(QStyleOptionViewItem const & opt,
+ QModelIndex const & index) const
+{
+ QSize size = QItemDelegate::sizeHint(opt, index);
+
+ /// QComboBox uses the first row height to estimate the
+ /// complete popup height during QComboBox::showPopup().
+ /// To avoid scrolling we have to sneak in space for the headers.
+ /// So we tweak this value accordingly. It's not nice, but the
+ /// only possible way it seems.
+ // Add space for the category headers here
+ QString cat = categoryCC(*index.model(), index.row());
+ if (index.row() == 0 || cat != categoryCC(*index.model(), index.row() -
1)) {
+ size.setHeight(size.height() + headerHeightCC(opt));
+ }
+
+ return size;
+}
+
+
+void ColItemDelegate::drawCategoryHeader(QPainter * painter,
QStyleOptionViewItem const & opt,
+ QString const & category) const
+{
+ // slightly blended color
+ QColor lcol = opt.palette.text().color();
+ lcol.setAlpha(127);
+ painter->setPen(lcol);
+
+ // set 80% scaled, bold font
+ QFont font = opt.font;
+ font.setBold(true);
+ font.setWeight(QFont::Black);
+ font.setPointSize(opt.font.pointSize() * 8 / 10);
+ painter->setFont(font);
+
+ // draw the centered text
+ QFontMetrics fm(font);
+ int w = fm.boundingRect(category).width();
+ int x = opt.rect.x() + (opt.rect.width() - w) / 2;
+ int y = opt.rect.y() + 3 * fm.ascent() / 2;
+ int left = x;
+ int right = x + w;
+ painter->drawText(x, y, category);
+
+ // the vertical position of the line: middle of lower case chars
+ int ymid = y - 1 - fm.xHeight() / 2; // -1 for the baseline
+
+ // draw the horizontal line
+ if (!category.isEmpty()) {
+ painter->drawLine(opt.rect.x(), ymid, left - 1, ymid);
+ painter->drawLine(right + 1, ymid, opt.rect.right(), ymid);
+ } else
+ painter->drawLine(opt.rect.x(), ymid, opt.rect.right(), ymid);
+}
+
+
+QString ColItemDelegate::underlineFilter(QString const & s) const
+{
+ QString const & f = cc_->filter();
+ if (f.isEmpty())
+ return s;
+ QString r(s);
+ QRegularExpression pattern(charFilterRegExpC(f));
+ r.replace(pattern, "<u><b>\\1</b></u>");
+ return r;
+}
+
+
+void ColorsCombo::Private::setFilter(QString const & s)
+{
+ bool enabled = p->view()->updatesEnabled();
+ p->view()->setUpdatesEnabled(false);
+
+ // remember old selection
+ int sel = p->currentIndex();
+ if (sel != -1)
+ lastSel_ = filterModel_->mapToSource(filterModel_->index(sel,
0)).row();
+
+ filter_ = s;
+
+ // toggle context-dependent entries
+ toggleRows("ignore", p->has_ignore_);
+ toggleRows("inherit", p->has_inherit_);
+ toggleRows("none", p->has_none_ && p->default_color_.isEmpty());
+
+#if QT_VERSION < QT_VERSION_CHECK(5, 12, 0)
+ filterModel_->setFilterRegExp(charFilterRegExp(filter_));
+#else
+ filterModel_->setFilterRegularExpression(charFilterRegExp(filter_));
+#endif
+ countCategories();
+
+ // restore old selection
+ if (lastSel_ != -1) {
+ QModelIndex i =
filterModel_->mapFromSource(model_->index(lastSel_, 0));
+ if (i.isValid())
+ p->setCurrentIndex(i.row());
+ }
+
+ // Workaround to resize to content size
+ // FIXME: There must be a better way. The QComboBox::AdjustToContents)
+ // does not help.
+ if (p->view()->isVisible()) {
+ // call QComboBox::showPopup. But set the inShowPopup_ flag to
switch on
+ // the hack in the item delegate to make space for the headers.
+ // We do not call our implementation of showPopup because that
+ // would reset the filter again. This is only needed if the
user clicks
+ // on the QComboBox.
+ LASSERT(!inShowPopup_, /**/);
+ inShowPopup_ = true;
+ p->QComboBox::showPopup();
+ inShowPopup_ = false;
+ }
+
+ p->view()->setUpdatesEnabled(enabled);
+}
+
+
+void ColorsCombo::Private::toggleRows(QString const data, bool const toggle)
+{
+ QList<QStandardItem *> cis = model_->findItems(data, Qt::MatchExactly,
1);
+ if (cis.empty())
+ return;
+
+ QListView * view = qobject_cast<QListView *>(p->view());
+ QStandardItem * item = cis.front();
+ view->setRowHidden(item->row(), !toggle);
+ if (toggle)
+ item->setFlags(item->flags() & Qt::ItemIsEnabled);
+ else
+ item->setFlags(item->flags() & ~Qt::ItemIsEnabled);
+}
+
+
+void ColorsCombo::Private::countCategories()
+{
+ int n = filterModel_->rowCount();
+ visibleCategories_ = 0;
+ if (n == 0)
+ return;
+
+ QString prevCat = model_->index(0, 2).data().toString();
+
+ // count categories
+ for (int i = 1; i < n; ++i) {
+ QString cat = filterModel_->index(i, 2).data().toString();
+ if (cat != prevCat)
+ ++visibleCategories_;
+ prevCat = cat;
+ }
+}
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// ColorsCombo
+//
+/////////////////////////////////////////////////////////////////////
+
ColorsCombo::ColorsCombo(QWidget * parent)
- : CategorizedCombo(parent),
+ : QComboBox(parent),
has_ignore_(false), has_inherit_(false),
- has_none_(false), default_value_("none")
+ has_none_(false), default_value_("none"),
+ need_default_color_(false),
+ d(new Private(this))
{
setLeftMargin(32);
- fillComboColor();
setToolTip(qt_("Type on the list to filter on color names."));
+
+ setSizeAdjustPolicy(QComboBox::AdjustToContents);
+ setMinimumWidth(sizeHint().width());
+ setMaxVisibleItems(100);
+
+ setModel(d->filterModel_);
+ connect(guiApp->currentView(), SIGNAL(colorsModelChanged()),
+ this, SLOT(modelChanged()));
+
+ // for the filtering we have to intercept characters
+ view()->installEventFilter(this);
+ view()->setItemDelegateForColumn(0, d->ColItemDelegate_);
+
+ updateCombo();
}
ColorsCombo::~ColorsCombo()
-{}
+{
+ delete d;
+}
-void ColorsCombo::setColorIcon(int const i, QString const color)
+void ColorsCombo::showPopup()
{
- if (color.isEmpty())
- return;
+ lastCurrentIndex_ = currentIndex();
+ bool enabled = view()->updatesEnabled();
+ view()->setUpdatesEnabled(false);
+
+ d->resetFilter();
- QPixmap pixmap(32, 20);
- QColor col(color);
- pixmap.fill(col);
- QPainter painter(&pixmap);
- QRect pixmapRect = QRect(0, 0, 31, 19);
- painter.drawPixmap(pixmapRect.x(), pixmapRect.y(), pixmap);
- painter.drawRect(pixmapRect);
+ // call QComboBox::showPopup. But set the inShowPopup_ flag to switch on
+ // the hack in the item delegate to make space for the headers.
+ LASSERT(!d->inShowPopup_, /**/);
+ d->inShowPopup_ = true;
+ QComboBox::showPopup();
+ d->inShowPopup_ = false;
- setItemIcon(i, QIcon(pixmap));
+ view()->setUpdatesEnabled(enabled);
}
-void ColorsCombo::addItemSort(QString const & item, QString const & guiname,
- QString const & category, QString const color)
+bool ColorsCombo::eventFilter(QObject * o, QEvent * e)
{
- QString titem = (item != default_color_)
- ? guiname
- : toqstr(bformat(_("%1$s (= Default[[color]])"),
- qstring_to_ucs4(guiname)));
+ if (e->type() != QEvent::KeyPress)
+ return QComboBox::eventFilter(o, e);
- QList<QStandardItem *> row;
- QStandardItem * gui = new QStandardItem(titem);
- row.append(gui);
- row.append(new QStandardItem(item));
- row.append(new QStandardItem(category));
- row.append(new QStandardItem(true));
- if (!color.isEmpty())
- row.append(new QStandardItem(color));
+ QKeyEvent * ke = static_cast<QKeyEvent*>(e);
+ bool modified = (ke->modifiers() == Qt::ControlModifier)
+ || (ke->modifiers() == Qt::AltModifier)
+ || (ke->modifiers() == Qt::MetaModifier);
- // the first entry is easy
- int const end = model()->rowCount();
- if (end == 0) {
- model()->appendRow(row);
- setColorIcon(0, color);
- return;
+ switch (ke->key()) {
+ case Qt::Key_Escape:
+ if (!modified && !d->filter_.isEmpty()) {
+ d->resetFilter();
+ setCurrentIndex(lastCurrentIndex_);
+ return true;
+ }
+ break;
+ case Qt::Key_Backspace:
+ if (!modified) {
+ // cut off one character
+ d->setFilter(d->filter_.left(d->filter_.length() - 1));
+ }
+ break;
+ default:
+ if (modified || ke->text().isEmpty())
+ break;
+ // find chars for the filter string
+ QString s;
+ for (int i = 0; i < ke->text().length(); ++i) {
+ QChar c = ke->text()[i];
+ if (c.isLetterOrNumber()
+ || c.isSymbol()
+ || c.isPunct()
+ || c.category() == QChar::Separator_Space) {
+ s += c;
+ }
+ }
+ if (!s.isEmpty()) {
+ // append new chars to the filter string
+ d->setFilter(d->filter_ + s);
+ return true;
+ }
+ break;
+ }
+
+ return QComboBox::eventFilter(o, e);
+}
+
+
+bool ColorsCombo::set(QString const & item_in, bool const report_missing)
+{
+ d->resetFilter();
+
+ int const curItem = currentIndex();
+ QModelIndex const mindex =
+ d->filterModel_->mapToSource(d->filterModel_->index(curItem,
1));
+ QString const & currentItem = d->model_->itemFromIndex(mindex)->text();
+ QString const item = (item_in == default_value_) ? "default" : item_in;
+ last_item_ = item;
+ if (item == currentItem) {
+ LYXERR(Debug::GUI, "Already had " << item << " selected.");
+ return true;
}
- // find category
- int i = 0;
- // sort categories alphabetically
- while (i < end && model()->item(i, 2)->text() != category
- && model()->item(i, 2)->text() != qt_("Uncategorized"))
- ++i;
+ QList<QStandardItem *> r = d->model_->findItems(item, Qt::MatchExactly,
1);
+ if (r.empty()) {
+ if (report_missing)
+ LYXERR0("Trying to select non existent entry " << item);
+ return false;
+ }
+
+
setCurrentIndex(d->filterModel_->mapFromSource(r.first()->index()).row());
+ return true;
+}
+
+
+QString ColorsCombo::getData(int row) const
+{
+ int srow = d->filterModel_->mapToSource(d->filterModel_->index(row,
1)).row();
+ QString const result = d->model_->data(d->model_->index(srow, 1),
Qt::DisplayRole).toString();
+ return (result == "default") ? default_value_ : result;
+}
- // jump to the end of the category group to sort in order
- // specified in input
- while (i < end && model()->item(i, 2)->text() == category)
- ++i;
- model()->insertRow(i, row);
- setColorIcon(i, color);
+void ColorsCombo::resetFilter()
+{
+ d->resetFilter();
}
-void ColorsCombo::setCustomColors(std::map<std::string, std::string> const &
custom_colors)
+void ColorsCombo::setLeftMargin(int const i)
{
- custom_colors_ = custom_colors;
- fillComboColor();
+ left_margin_ = i;
}
-void ColorsCombo::fillComboColor()
+void ColorsCombo::setDefaultColor(std::string const & col)
+{
+ default_color_ = toqstr(col);
+ need_default_color_ = !col.empty();
+}
+
+
+void ColorsCombo::updateCombo()
+{
+ d->countCategories();
+
+ // needed to recalculate size hint
+ hide();
+ setMinimumWidth(sizeHint().width());
+ show();
+}
+
+
+QString const & ColorsCombo::filter() const
+{
+ return d->filter_;
+}
+
+
+QStandardItemModel * ColorsCombo::model()
+{
+ return d->model_;
+}
+
+
+void ColorsCombo::modelChanged()
+{
+ // restore last setting
+ set(last_item_, false);
+}
+
+
+bool ColorsCombo::isDefaultColor(QString const & guiname)
{
- reset();
- // at first add the general values as required
- if (has_ignore_)
- addItemSort(QString("ignore"), qt_("No change"),
- QString());
if (default_color_.isEmpty())
- addItemSort(default_value_, qt_("Default"),
- QString());
- if (has_none_ && default_value_ != "none")
- addItemSort("none", qt_("None[[color]]"),
- QString());
- if (has_inherit_)
- addItemSort(QString("inherit"), qt_("(Without)[[color]]"),
- QString());
- // now custom colors
- for (auto const & lc : custom_colors_) {
- QString const lyxname = toqstr(lc.first);
- QString const guiname = toqstr(lc.first);
- QString const category = qt_("Custom Colors");
- QString const color = toqstr(lc.second);
- addItemSort(lyxname,
- guiname,
- category,
- color);
- }
- // then real colors
- for (auto const & lc : theLaTeXColors().getLaTeXColors()) {
- QString const lyxname = toqstr(lc.first);
- QString const guiname =
toqstr(translateIfPossible(lc.second.guiname()));
- QString const category =
toqstr(translateIfPossible(lc.second.category()));
- QString const color = toqstr(lc.second.hexname());
- addItemSort(lyxname,
- guiname,
- category,
- color);
- }
+ return false;
+ QList<QStandardItem *> cis = d->model_->findItems(guiname,
Qt::MatchExactly, 0);
+ bool const res = d->model_->data(d->model_->index(cis.front()->row(),
1),
+ Qt::DisplayRole).toString() ==
default_color_;
+ if (res)
+ // no need to look further
+ need_default_color_ = false;
+ return res;
}
diff --git a/src/frontends/qt/ColorsCombo.h b/src/frontends/qt/ColorsCombo.h
index 71f8f143c7..1c3bd032d6 100644
--- a/src/frontends/qt/ColorsCombo.h
+++ b/src/frontends/qt/ColorsCombo.h
@@ -12,34 +12,35 @@
#ifndef LYX_COLORSCOMBO_H
#define LYX_COLORSCOMBO_H
-#include "CategorizedCombo.h"
#include "support/qstring_helpers.h"
#include <QComboBox>
+#include <QStandardItemModel>
namespace lyx {
namespace frontend {
-class CCItemDelegate;
+class ColItemDelegate;
/**
* A combo box with categorization
*/
-class ColorsCombo : public CategorizedCombo
+class ColorsCombo : public QComboBox
{
Q_OBJECT
public:
ColorsCombo(QWidget * parent);
~ColorsCombo();
+ /// select an item in the combobox. Returns false if item does not exist
+ bool set(QString const & cc, bool const report_missing = true);
+ /// Reset the combobox filter.
+ void resetFilter();
/// Update combobox.
void updateCombo();
- /// Add item to combo with optional color icon
- void addItemSort(QString const & item, QString const & guiname,
- QString const & category, QString color = QString());
- /// Set BufferParams to access custom colors
- void setCustomColors(std::map<std::string, std::string> const &
custom_colors);
+ ///
+ QString getData(int row) const;
/// Add "ignore" color entry?
void hasIgnore(bool const b) { has_ignore_ = b; }
/// Add "inherit" color entry?
@@ -47,17 +48,28 @@ public:
/// Add dedicated "none" color entry if default_value_ != "none"
void hasNone(bool const b) { has_none_ = b; }
/// Flag a color as default. This will also omit the "none" entry
- void setDefaultColor(std::string const & col) { default_color_ =
toqstr(col); }
+ void setDefaultColor(std::string const & col);
/// Set the value of the default entry. Preset is "none"
void setDefaultValue(std::string const & val) { default_value_ =
toqstr(val); }
+ ///
+ bool isDefaultColor(QString const & guiname);
+ ///
+ void showPopup() override;
-private:
///
- void setColorIcon(int const i, QString const color);
+ bool eventFilter(QObject * o, QEvent * e) override;
///
- void fillComboColor();
+ QString const & filter() const;
///
- std::map<std::string, std::string> custom_colors_;
+ QStandardItemModel * model();
+ ///
+ void setLeftMargin(int const);
+
+private Q_SLOTS:
+ ///
+ void modelChanged();
+
+private:
///
bool has_ignore_;
///
@@ -68,6 +80,20 @@ private:
QString default_color_;
///
QString default_value_;
+ ///
+ bool need_default_color_;
+ ///
+ friend class ColItemDelegate;
+ ///
+ struct Private;
+ ///
+ Private * const d;
+ ///
+ int lastCurrentIndex_;
+ ///
+ int left_margin_ = -1;
+ ///
+ QString last_item_;
};
diff --git a/src/frontends/qt/GuiBox.cpp b/src/frontends/qt/GuiBox.cpp
index b0134c8719..c8c932ed54 100644
--- a/src/frontends/qt/GuiBox.cpp
+++ b/src/frontends/qt/GuiBox.cpp
@@ -223,9 +223,6 @@ void GuiBox::paramsToDialog(Inset const * inset)
{
InsetBox const * box = static_cast<InsetBox const *>(inset);
InsetBoxParams const & params = box->params();
- custom_colors_cache_ = inset->buffer().masterParams().custom_colors;
- frameColorCO->setCustomColors(custom_colors_cache_);
- backgroundColorCO->setCustomColors(custom_colors_cache_);
QString type = toqstr(params.type);
if (type == "Framed") {
pagebreakCB->setChecked(true);
diff --git a/src/frontends/qt/GuiBox.h b/src/frontends/qt/GuiBox.h
index a63d0cae7e..fa4b908502 100644
--- a/src/frontends/qt/GuiBox.h
+++ b/src/frontends/qt/GuiBox.h
@@ -13,7 +13,6 @@
#ifndef GUIBOX_H
#define GUIBOX_H
-#include "ColorCode.h"
#include "InsetParamsWidget.h"
#include "ui_BoxUi.h"
@@ -58,8 +57,6 @@ private:
QStringList ids_spec_;
///
QStringList gui_names_spec_;
- ///
- std::map<std::string, std::string> custom_colors_cache_;
};
} // namespace frontend
diff --git a/src/frontends/qt/GuiCharacter.cpp
b/src/frontends/qt/GuiCharacter.cpp
index aa6b3a1d25..bdc180d597 100644
--- a/src/frontends/qt/GuiCharacter.cpp
+++ b/src/frontends/qt/GuiCharacter.cpp
@@ -201,8 +201,6 @@ GuiCharacter::GuiCharacter(GuiView & lv)
fillCombo(langCO, language);
colorCO->hasIgnore(true);
colorCO->hasInherit(true);
- colorCO->setCustomColors(buffer().masterParams().custom_colors);
- custom_colors_cache_ = buffer().masterParams().custom_colors;
bc().setPolicy(ButtonPolicy::OkApplyCancelAutoReadOnlyPolicy);
bc().setOK(buttonBox->button(QDialogButtonBox::Ok));
@@ -485,12 +483,6 @@ void GuiCharacter::updateContents()
if (font_.language() == buffer().params().language)
font_.setLanguage(reset_language);
- // Update custom colors if needed
- if (custom_colors_cache_ != buffer().masterParams().custom_colors) {
- colorCO->setCustomColors(buffer().masterParams().custom_colors);
- custom_colors_cache_ = buffer().masterParams().custom_colors;
- }
-
paramsToDialog(font_);
checkRestoreDefaults();
diff --git a/src/frontends/qt/GuiCharacter.h b/src/frontends/qt/GuiCharacter.h
index e968f7f381..d3345c210f 100644
--- a/src/frontends/qt/GuiCharacter.h
+++ b/src/frontends/qt/GuiCharacter.h
@@ -109,8 +109,6 @@ private:
bool noun_;
///
bool nospellcheck_;
- ///
- std::map<std::string, std::string> custom_colors_cache_;
///
QAction * resetdefault_ = new QAction(this);
diff --git a/src/frontends/qt/GuiDocument.cpp b/src/frontends/qt/GuiDocument.cpp
index 30f692804c..e129637447 100644
--- a/src/frontends/qt/GuiDocument.cpp
+++ b/src/frontends/qt/GuiDocument.cpp
@@ -1377,14 +1377,7 @@ GuiDocument::GuiDocument(GuiView & lv)
this, SLOT(alterCustomColor()));
connect(colorModule->customColorsTW,
SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)),
this, SLOT(toggleCustomColor(QTreeWidgetItem *, int)));
-
colorModule->textColorCO->setCustomColors(buffer().masterParams().custom_colors);
-
colorModule->pageColorCO->setCustomColors(buffer().masterParams().custom_colors);
-
colorModule->noteColorCO->setCustomColors(buffer().masterParams().custom_colors);
-
colorModule->shadedColorCO->setCustomColors(buffer().masterParams().custom_colors);
-
colorModule->oddRowColorCO->setCustomColors(buffer().masterParams().custom_colors);
-
colorModule->evenRowColorCO->setCustomColors(buffer().masterParams().custom_colors);
-
colorModule->borderColorCO->setCustomColors(buffer().masterParams().custom_colors);
- colorModule->noteColorCO->setDefaultColor("lightgrey");
+ colorModule->noteColorCO->setDefaultColor("lightgray");
colorModule->shadedColorCO->setDefaultColor("red");
colorModule->oddRowColorCO->setDefaultValue("default");
colorModule->evenRowColorCO->setDefaultValue("default");
@@ -5336,6 +5329,10 @@ void GuiDocument::dispatchParams()
table->tabular.updateIndexes();
}
}
+
+ // and the custom colors
+ lyxview().updateColorsModel();
+
// FIXME LFUN
// If we used an LFUN, we would not need these two lines:
BufferView * bv = const_cast<BufferView *>(bufferview());
@@ -5595,14 +5592,6 @@ void GuiDocument::updateCustomColors()
}
colorModule->customColorsTW->resizeColumnToContents(0);
- colorModule->textColorCO->setCustomColors(ccs);
- colorModule->noteColorCO->setCustomColors(ccs);
- colorModule->pageColorCO->setCustomColors(ccs);
- colorModule->shadedColorCO->setCustomColors(ccs);
- colorModule->oddRowColorCO->setCustomColors(ccs);
- colorModule->evenRowColorCO->setCustomColors(ccs);
- colorModule->borderColorCO->setCustomColors(ccs);
-
change_adaptor();
}
diff --git a/src/frontends/qt/GuiTabular.cpp b/src/frontends/qt/GuiTabular.cpp
index ca3b7ca54c..2905fa6ac1 100644
--- a/src/frontends/qt/GuiTabular.cpp
+++ b/src/frontends/qt/GuiTabular.cpp
@@ -913,14 +913,6 @@ void GuiTabular::paramsToDialog(Inset const * inset)
// Copy Tabular of current inset.
Tabular const & tabular = itab->tabular;
- custom_colors_cache_ = itab->buffer().masterParams().custom_colors;
- borderColorCO->setCustomColors(custom_colors_cache_);
- cellColorCO->setCustomColors(custom_colors_cache_);
- columnColorCO->setCustomColors(custom_colors_cache_);
- rowColorCO->setCustomColors(custom_colors_cache_);
- evenRowColorCO->setCustomColors(custom_colors_cache_);
- oddRowColorCO->setCustomColors(custom_colors_cache_);
-
BufferView const * bv = guiApp->currentView()->currentBufferView();
size_t const cell = bv->cursor().idx();
diff --git a/src/frontends/qt/GuiTabular.h b/src/frontends/qt/GuiTabular.h
index 733e0edce8..631365e4df 100644
--- a/src/frontends/qt/GuiTabular.h
+++ b/src/frontends/qt/GuiTabular.h
@@ -82,8 +82,6 @@ private:
docstring decimal_sep_;
///
std::set<std::string> features_;
- ///
- std::map<std::string, std::string> custom_colors_cache_;
};
} // namespace frontend
diff --git a/src/frontends/qt/GuiView.cpp b/src/frontends/qt/GuiView.cpp
index d95ce16f56..6f12a0fed5 100644
--- a/src/frontends/qt/GuiView.cpp
+++ b/src/frontends/qt/GuiView.cpp
@@ -108,6 +108,7 @@
#include <QShowEvent>
#include <QSlider>
#include <QSplitter>
+#include <QStandardItemModel>
#include <QStackedWidget>
#include <QStatusBar>
#include <QSvgRenderer>
@@ -569,7 +570,8 @@ GuiView::GuiView(int id)
: d(*new GuiViewPrivate(this)), id_(id), closing_(false), busy_(0),
command_execute_(false), minibuffer_focus_(false),
word_count_enabled_(true),
char_count_enabled_(true), char_nb_count_enabled_(false),
- toolbarsMovable_(false), devel_mode_(false)
+ toolbarsMovable_(false), devel_mode_(false),
+ colors_model_(new QStandardItemModel(0, 4, this))
{
connect(this, SIGNAL(bufferViewChanged()),
this, SLOT(onBufferViewChanged()));
@@ -1211,6 +1213,117 @@ TocModels & GuiView::tocModels()
}
+void GuiView::addColorItem(QString const & item, QString const & guiname,
+ QString const & category, QString const color,
+ bool const custom, int const r) const
+{
+ QList<QStandardItem *> row;
+ QStandardItem * gui = new QStandardItem(guiname);
+ // add color icon if applicable
+ if (!color.isEmpty()) {
+ QPixmap pixmap(32, 20);
+ QColor col(color);
+ pixmap.fill(col);
+ QPainter painter(&pixmap);
+ QRect pixmapRect = QRect(0, 0, 31, 19);
+ painter.drawPixmap(pixmapRect.x(), pixmapRect.y(), pixmap);
+ painter.drawRect(pixmapRect);
+ gui->setIcon(QIcon(pixmap));
+ }
+ row.append(gui);
+ row.append(new QStandardItem(item));
+ row.append(new QStandardItem(category));
+ row.append(new QStandardItem(custom ? QString("custom") : QString()));
+ if (!color.isEmpty())
+ row.append(new QStandardItem(color));
+
+ // specified row
+ if (r != -1) {
+ colors_model_->insertRow(r, row);
+ return;
+ }
+
+ int const end = colors_model_->rowCount();
+ // first entry
+ if (end == 0) {
+ colors_model_->appendRow(row);
+ return;
+ }
+
+ // find category
+ int i = 0;
+ // sort categories alphabetically
+ while (i < end && colors_model_->item(i, 2)->text() != category)
+ ++i;
+
+ // jump to the end of the category group to sort in order
+ // specified in input
+ while (i < end && colors_model_->item(i, 2)->text() == category)
+ ++i;
+
+ colors_model_->insertRow(i, row);
+}
+
+
+QStandardItemModel * GuiView::viewColorsModel()
+{
+ if (colors_model_->rowCount() > 0)
+ return colors_model_;
+
+ // at first add the general values as required
+ addColorItem("ignore", qt_("No change"));
+ addColorItem("default", qt_("Default"));
+ addColorItem("none", qt_("None[[color]]"));
+ addColorItem("inherit", qt_("(Without)[[color]]"));
+ // then custom colors
+ if (currentBufferView()) {
+ for (auto const & lc :
currentBufferView()->buffer().masterParams().custom_colors) {
+ addColorItem(toqstr(lc.first),
+ toqstr(lc.first),
+ qt_("Custom Colors"),
+ toqstr(lc.second),
+ true);
+ }
+ }
+ // finally the latex colors
+ for (auto const & lc : theLaTeXColors().getLaTeXColors()) {
+ addColorItem(toqstr(lc.first),
+ toqstr(translateIfPossible(lc.second.guiname())),
+ toqstr(translateIfPossible(lc.second.category())),
+ toqstr(lc.second.hexname()));
+ }
+
+ return colors_model_;
+}
+
+
+void GuiView::updateColorsModel() const
+{
+ bool changed = false;
+ // remove custom colors
+ QList<QStandardItem *> cis = colors_model_->findItems("custom",
Qt::MatchExactly, 3);
+ for (qsizetype i = 0; i < cis.size(); ++i) {
+ colors_model_->removeRow(cis.at(i)->row());
+ changed = true;
+ }
+ // and add anew
+ if (currentBufferView()) {
+ int r = 4;
+ for (auto const & lc :
currentBufferView()->buffer().masterParams().custom_colors) {
+ addColorItem(toqstr(lc.first),
+ toqstr(lc.first),
+ qt_("Custom Colors"),
+ toqstr(lc.second),
+ true, r);
+ ++r;
+ changed = true;
+ }
+ }
+ if (changed)
+ Q_EMIT colorsModelChanged();
+}
+
+
void GuiView::setFocus()
{
LYXERR(Debug::DEBUG, "GuiView::setFocus()" << this);
@@ -1600,6 +1713,8 @@ void GuiView::onBufferViewChanged()
zoom_out_->setEnabled(currentBufferView()
&& zoom_slider_->value() >
zoom_slider_->minimum());
d.stats_update_trigger_ = true;
+ if (!closing_)
+ updateColorsModel();
}
diff --git a/src/frontends/qt/GuiView.h b/src/frontends/qt/GuiView.h
index a202279b20..4fd713308b 100644
--- a/src/frontends/qt/GuiView.h
+++ b/src/frontends/qt/GuiView.h
@@ -22,6 +22,7 @@
#include <QMenu>
#include <QSvgWidget>
+class QStandardItemModel;
class QCloseEvent;
class QDragEnterEvent;
class QDropEvent;
@@ -190,6 +191,16 @@ public:
///
TocModels & tocModels();
+ ///
+ void addColorItem(QString const & item, QString const & guiname,
+ QString const & category = QString(),
+ QString const color = QString(),
+ bool custom = false, int row = -1) const;
+ ///
+ QStandardItemModel * viewColorsModel();
+ ///
+ void updateColorsModel() const;
+
/// called on timeout
void autoSave();
@@ -245,6 +256,8 @@ Q_SIGNALS:
void changeTrackingToggled(bool);
///
void dockWidgetVisibilityChanged();
+ ///
+ void colorsModelChanged() const;
public Q_SLOTS:
///
@@ -575,6 +588,9 @@ private:
// initial zoom for pinch gesture
int initialZoom_;
+
+ ///
+ QStandardItemModel * colors_model_;
};
--
lyx-cvs mailing list
[email protected]
https://lists.lyx.org/mailman/listinfo/lyx-cvs