KTextEditor

katecolortreewidget.cpp
1/*
2 SPDX-FileCopyrightText: 2012-2018 Dominik Haumann <dhaumann@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "katecolortreewidget.h"
8
9#include "katecategorydrawer.h"
10
11#include <QPainter>
12#include <QStyledItemDelegate>
13
14#include <KLocalizedString>
15
16#include <QColorDialog>
17#include <QEvent>
18#include <QKeyEvent>
19#include <qdrawutil.h>
20
21// BEGIN KateColorTreeItem
22class KateColorTreeItem : public QTreeWidgetItem
23{
24public:
25 KateColorTreeItem(const KateColorItem &colorItem, QTreeWidgetItem *parent = nullptr)
27 , m_colorItem(colorItem)
28 {
29 setText(0, m_colorItem.name);
30 if (!colorItem.whatsThis.isEmpty()) {
31 setData(1, Qt::WhatsThisRole, colorItem.whatsThis);
32 }
33 if (!colorItem.useDefault) {
34 setData(2, Qt::ToolTipRole, i18n("Use default color from the color theme"));
35 }
36 }
37
38 QColor color() const
39 {
40 return m_colorItem.color;
41 }
42
43 void setColor(const QColor &c)
44 {
45 m_colorItem.color = c;
46 }
47
48 QColor defaultColor() const
49 {
50 return m_colorItem.defaultColor;
51 }
52
53 bool useDefaultColor() const
54 {
55 return m_colorItem.useDefault;
56 }
57
58 void setUseDefaultColor(bool useDefault)
59 {
60 m_colorItem.useDefault = useDefault;
61 QString tooltip = useDefault ? QString() : i18n("Use default color from the color theme");
62 setData(2, Qt::ToolTipRole, tooltip);
63 }
64
65 QString key() const
66 {
67 return m_colorItem.key;
68 }
69
70 KateColorItem colorItem() const
71 {
72 return m_colorItem;
73 }
74
75private:
76 KateColorItem m_colorItem;
77};
78// END KateColorTreeItem
79
80// BEGIN KateColorTreeDelegate
81class KateColorTreeDelegate : public QStyledItemDelegate
82{
83public:
84 KateColorTreeDelegate(KateColorTreeWidget *widget)
85 : QStyledItemDelegate(widget)
86 , m_tree(widget)
87 {
88 }
89
90 QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override
91 {
92 QSize sh = QStyledItemDelegate::sizeHint(option, index);
93 if (!index.parent().isValid()) {
94 sh.rheight() += 2 * m_categoryDrawer.leftMargin();
95 } else {
96 sh.rheight() += m_categoryDrawer.leftMargin();
97 }
98 if (index.column() == 0) {
99 sh.rwidth() += m_categoryDrawer.leftMargin();
100 } else if (index.column() == 1) {
101 sh.rwidth() = 150;
102 } else {
103 sh.rwidth() += m_categoryDrawer.leftMargin();
104 }
105
106 return sh;
107 }
108
109 QRect fullCategoryRect(const QStyleOptionViewItem &option, const QModelIndex &index) const
110 {
111 QModelIndex i = index;
112 if (i.parent().isValid()) {
113 i = i.parent();
114 }
115
116 QTreeWidgetItem *item = m_tree->itemFromIndex(i);
117 QRect r = m_tree->visualItemRect(item);
118
119 // adapt width
120 r.setLeft(m_categoryDrawer.leftMargin());
121 r.setWidth(m_tree->viewport()->width() - m_categoryDrawer.leftMargin() - m_categoryDrawer.rightMargin());
122
123 // adapt height
124 if (item->isExpanded() && item->childCount() > 0) {
125 const int childCount = item->childCount();
126 const int h = sizeHint(option, index.model()->index(0, 0, index)).height();
127 r.setHeight(r.height() + childCount * h);
128 }
129
130 r.setTop(r.top() + m_categoryDrawer.leftMargin());
131
132 return r;
133 }
134
135 void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
136 {
137 Q_ASSERT(index.isValid());
138 Q_ASSERT(index.column() >= 0 && index.column() <= 2);
139
140 // BEGIN: draw toplevel items
141 if (!index.parent().isValid()) {
142 QStyleOptionViewItem opt(option);
143 const QRegion cl = painter->clipRegion();
144 painter->setClipRect(opt.rect);
145 opt.rect = fullCategoryRect(option, index);
146 m_categoryDrawer.drawCategory(index, 0, opt, painter);
147 painter->setClipRegion(cl);
148 return;
149 }
150 // END: draw toplevel items
151
152 // BEGIN: draw background of category for all other items
153 {
154 QStyleOptionViewItem opt(option);
155 opt.rect = fullCategoryRect(option, index);
156 const QRegion cl = painter->clipRegion();
157 QRect cr = option.rect;
158 if (index.column() == 0) {
159 if (m_tree->layoutDirection() == Qt::LeftToRight) {
160 cr.setLeft(5);
161 } else {
162 cr.setRight(opt.rect.right());
163 }
164 }
165 painter->setClipRect(cr);
166 m_categoryDrawer.drawCategory(index, 0, opt, painter);
167 painter->setClipRegion(cl);
168 painter->setRenderHint(QPainter::Antialiasing, false);
169 }
170 // END: draw background of category for all other items
171
172 painter->setClipRect(option.rect);
173
174 // BEGIN: draw color button
175 if (index.column() == 1) {
176 KateColorTreeItem *item = static_cast<KateColorTreeItem *>(m_tree->itemFromIndex(index));
177 QColor color = item->useDefaultColor() ? item->defaultColor() : item->color();
178
180 opt.rect = option.rect;
181 opt.palette = m_tree->palette();
182
183 m_tree->style()->drawControl(QStyle::CE_PushButton, &opt, painter, m_tree);
184 opt.rect = m_tree->style()->subElementRect(QStyle::SE_PushButtonContents, &opt, m_tree);
185 opt.rect.adjust(1, 1, -1, -1);
186 painter->fillRect(opt.rect, color);
187
188 qDrawShadePanel(painter, opt.rect, opt.palette, true, 1, nullptr);
189 }
190 // END: draw color button
191
192 // BEGIN: draw reset icon
193 if (index.column() == 2 && !static_cast<KateColorTreeItem *>(m_tree->itemFromIndex(index))->useDefaultColor()) {
194 // get right pixmap
195 const bool enabled = (option.state & QStyle::State_MouseOver || option.state & QStyle::State_HasFocus);
196 const QPixmap p = QIcon::fromTheme(QStringLiteral("edit-undo")).pixmap(16, 16, enabled ? QIcon::Normal : QIcon::Disabled);
197
198 // compute rect with scaled sizes
199 const QRect rect(option.rect.left() + 10,
200 option.rect.top() + (option.rect.height() - p.height() / p.devicePixelRatio() + 1) / 2,
201 p.width() / p.devicePixelRatio(),
202 p.height() / p.devicePixelRatio());
203 painter->drawPixmap(rect, p);
204 }
205 // END: draw reset icon
206
207 // paint the text
208 QStyledItemDelegate::paint(painter, option, index);
209 }
210
211private:
212 KateColorTreeWidget *m_tree;
213 KateCategoryDrawer m_categoryDrawer;
214};
215// END KateColorTreeDelegate
216
217KateColorTreeWidget::KateColorTreeWidget(QWidget *parent)
218 : QTreeWidget(parent)
219{
220 setItemDelegate(new KateColorTreeDelegate(this));
221
222 QStringList headers;
223 headers << QString() // i18nc("@title:column the color name", "Color Role")
224 << QString() // i18nc("@title:column a color button", "Color")
225 << QString(); // i18nc("@title:column use default color", "Reset")
226 setHeaderLabels(headers);
227 setHeaderHidden(true);
228 setRootIsDecorated(false);
229 setIndentation(25);
230 setSelectionMode(QAbstractItemView::NoSelection);
231}
232
233bool KateColorTreeWidget::edit(const QModelIndex &index, EditTrigger trigger, QEvent *event)
234{
235 if (m_readOnly) {
236 return false;
237 }
238
239 // accept edit only for color buttons in column 1 and reset in column 2
240 if (!index.parent().isValid() || index.column() < 1) {
241 return QTreeWidget::edit(index, trigger, event);
242 }
243
244 bool accept = false;
245 if (event && event->type() == QEvent::KeyPress) {
246 QKeyEvent *ke = static_cast<QKeyEvent *>(event);
247 accept = (ke->key() == Qt::Key_Space); // allow Space to edit
248 }
249
250 switch (trigger) {
254 accept = true;
255 break;
256 default:
257 break;
258 }
259
260 if (accept) {
261 KateColorTreeItem *item = static_cast<KateColorTreeItem *>(itemFromIndex(index));
262 const QColor color = item->useDefaultColor() ? item->defaultColor() : item->color();
263
264 if (index.column() == 1) {
265 const QColor selectedColor = QColorDialog::getColor(color, this, QString(), QColorDialog::ShowAlphaChannel);
266
267 if (selectedColor.isValid()) {
268 item->setUseDefaultColor(false);
269 item->setColor(selectedColor);
270 viewport()->update();
271 Q_EMIT changed();
272 }
273 } else if (index.column() == 2 && !item->useDefaultColor()) {
274 item->setUseDefaultColor(true);
275 viewport()->update();
276 Q_EMIT changed();
277 }
278
279 return false;
280 }
281 return QTreeWidget::edit(index, trigger, event);
282}
283
284void KateColorTreeWidget::drawBranches(QPainter *painter, const QRect &rect, const QModelIndex &index) const
285{
286 Q_UNUSED(painter)
287 Q_UNUSED(rect)
288 Q_UNUSED(index)
289}
290
291void KateColorTreeWidget::selectDefaults()
292{
293 bool somethingChanged = false;
294
295 // use default colors for all selected items
296 for (int a = 0; a < topLevelItemCount(); ++a) {
298 for (int b = 0; b < top->childCount(); ++b) {
299 KateColorTreeItem *it = static_cast<KateColorTreeItem *>(top->child(b));
300 Q_ASSERT(it);
301 if (!it->useDefaultColor()) {
302 it->setUseDefaultColor(true);
303 somethingChanged = true;
304 }
305 }
306 }
307
308 if (somethingChanged) {
309 viewport()->update();
310 Q_EMIT changed();
311 }
312}
313
314void KateColorTreeWidget::addColorItem(const KateColorItem &colorItem)
315{
316 QTreeWidgetItem *categoryItem = nullptr;
317 for (int i = 0; i < topLevelItemCount(); ++i) {
318 if (topLevelItem(i)->text(0) == colorItem.category) {
319 categoryItem = topLevelItem(i);
320 break;
321 }
322 }
323
324 if (!categoryItem) {
325 categoryItem = new QTreeWidgetItem();
326 categoryItem->setText(0, colorItem.category);
327 addTopLevelItem(categoryItem);
328 expandItem(categoryItem);
329 }
330
331 new KateColorTreeItem(colorItem, categoryItem);
332
334}
335
336void KateColorTreeWidget::addColorItems(const QList<KateColorItem> &colorItems)
337{
338 for (const KateColorItem &item : colorItems) {
339 addColorItem(item);
340 }
341}
342
343QList<KateColorItem> KateColorTreeWidget::colorItems() const
344{
346 for (int a = 0; a < topLevelItemCount(); ++a) {
348 for (int b = 0; b < top->childCount(); ++b) {
349 KateColorTreeItem *item = static_cast<KateColorTreeItem *>(top->child(b));
350 Q_ASSERT(item);
351 items.append(item->colorItem());
352 }
353 }
354 return items;
355}
356
357QColor KateColorTreeWidget::findColor(const QString &key) const
358{
359 for (int a = 0; a < topLevelItemCount(); ++a) {
361 for (int b = 0; b < top->childCount(); ++b) {
362 KateColorTreeItem *item = static_cast<KateColorTreeItem *>(top->child(b));
363 if (item->key() == key) {
364 if (item->useDefaultColor()) {
365 return item->defaultColor();
366 } else {
367 return item->color();
368 }
369 }
370 }
371 }
372 return QColor();
373}
374
375bool KateColorTreeWidget::readOnly() const
376{
377 return m_readOnly;
378}
379
380void KateColorTreeWidget::setReadOnly(bool readOnly)
381{
382 m_readOnly = readOnly;
383}
384
385#include "moc_katecolortreewidget.cpp"
QString i18n(const char *text, const TYPE &arg...)
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const=0
virtual bool edit(const QModelIndex &index, EditTrigger trigger, QEvent *event)
QWidget * viewport() const const
bool isValid() const const
QColor getColor(const QColor &initial, QWidget *parent, const QString &title, ColorDialogOptions options)
QPixmap pixmap(QWindow *window, const QSize &size, Mode mode, State state) const const
QIcon fromTheme(const QString &name)
int key() const const
void append(QList< T > &&value)
int column() const const
bool isValid() const const
const QAbstractItemModel * model() const const
QModelIndex parent() const const
Q_EMITQ_EMIT
QRegion clipRegion() const const
void drawPixmap(const QPoint &point, const QPixmap &pixmap)
void fillRect(const QRect &rectangle, QGradient::Preset preset)
void setClipRect(const QRect &rectangle, Qt::ClipOperation operation)
void setClipRegion(const QRegion &region, Qt::ClipOperation operation)
void setRenderHint(RenderHint hint, bool on)
qreal devicePixelRatio() const const
int height() const const
int width() const const
int height() const const
void setHeight(int height)
void setLeft(int x)
void setRight(int x)
void setTop(int y)
void setWidth(int width)
int top() const const
int height() const const
int & rheight()
int & rwidth()
bool isEmpty() const const
SE_PushButtonContents
virtual void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const const=0
virtual QRect subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const const=0
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const const override
virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const const override
WhatsThisRole
Key_Space
LeftToRight
void resizeColumnToContents(int column)
void addTopLevelItem(QTreeWidgetItem *item)
virtual bool event(QEvent *e) override
void expandItem(const QTreeWidgetItem *item)
QTreeWidgetItem * itemFromIndex(const QModelIndex &index) const const
QTreeWidgetItem * topLevelItem(int index) const const
QRect visualItemRect(const QTreeWidgetItem *item) const const
QTreeWidgetItem * child(int index) const const
int childCount() const const
bool isExpanded() const const
QTreeWidgetItem * parent() const const
virtual void setData(int column, int role, const QVariant &value)
void setText(int column, const QString &text)
QStyle * style() const const
void update()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Wed Nov 6 2024 12:09:46 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.