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 // paint the text
173 QStyledItemDelegate::paint(painter, option, index);
174 if (index.column() == 0) {
175 return;
176 }
177
178 painter->setClipRect(option.rect);
179 KateColorTreeItem *item = static_cast<KateColorTreeItem *>(m_tree->itemFromIndex(index));
180
181 // BEGIN: draw color button
182 if (index.column() == 1) {
183 QColor color = item->useDefaultColor() ? item->defaultColor() : item->color();
184
186 opt.rect = option.rect;
187 opt.palette = m_tree->palette();
188
189 m_tree->style()->drawControl(QStyle::CE_PushButton, &opt, painter, m_tree);
190 opt.rect = m_tree->style()->subElementRect(QStyle::SE_PushButtonContents, &opt, m_tree);
191 opt.rect.adjust(1, 1, -1, -1);
192 painter->fillRect(opt.rect, color);
193
194 qDrawShadePanel(painter, opt.rect, opt.palette, true, 1, nullptr);
195 }
196 // END: draw color button
197
198 // BEGIN: draw reset icon
199 if (index.column() == 2 && !item->useDefaultColor()) {
200 // get right pixmap
201 const bool enabled = (option.state & QStyle::State_MouseOver || option.state & QStyle::State_HasFocus);
202 const QPixmap p = QIcon::fromTheme(QStringLiteral("edit-undo")).pixmap(16, 16, enabled ? QIcon::Normal : QIcon::Disabled);
203
204 // compute rect with scaled sizes
205 const QRect rect(option.rect.left() + 10,
206 option.rect.top() + (option.rect.height() - p.height() / p.devicePixelRatio() + 1) / 2,
207 p.width() / p.devicePixelRatio(),
208 p.height() / p.devicePixelRatio());
209 painter->drawPixmap(rect, p);
210 }
211 // END: draw reset icon
212 }
213
214private:
215 KateColorTreeWidget *m_tree;
216 KateCategoryDrawer m_categoryDrawer;
217};
218// END KateColorTreeDelegate
219
220KateColorTreeWidget::KateColorTreeWidget(QWidget *parent)
221 : QTreeWidget(parent)
222{
223 setItemDelegate(new KateColorTreeDelegate(this));
224
225 QStringList headers;
226 headers << QString() // i18nc("@title:column the color name", "Color Role")
227 << QString() // i18nc("@title:column a color button", "Color")
228 << QString(); // i18nc("@title:column use default color", "Reset")
229 setHeaderLabels(headers);
230 setHeaderHidden(true);
231 setRootIsDecorated(false);
232 setIndentation(25);
233}
234
235bool KateColorTreeWidget::edit(const QModelIndex &index, EditTrigger trigger, QEvent *event)
236{
237 if (m_readOnly) {
238 return false;
239 }
240
241 // accept edit only for color buttons in column 1 and reset in column 2
242 if (!index.parent().isValid() || index.column() < 1) {
243 return QTreeWidget::edit(index, trigger, event);
244 }
245
246 bool accept = false;
247 if (event && event->type() == QEvent::KeyPress) {
248 QKeyEvent *ke = static_cast<QKeyEvent *>(event);
249 accept = (ke->key() == Qt::Key_Space); // allow Space to edit
250 }
251
252 switch (trigger) {
256 accept = true;
257 break;
258 default:
259 break;
260 }
261
262 if (accept) {
263 KateColorTreeItem *item = static_cast<KateColorTreeItem *>(itemFromIndex(index));
264 const QColor color = item->useDefaultColor() ? item->defaultColor() : item->color();
265
266 if (index.column() == 1) {
267 const QColor selectedColor = QColorDialog::getColor(color, this, QString(), QColorDialog::ShowAlphaChannel);
268
269 if (selectedColor.isValid()) {
270 item->setUseDefaultColor(false);
271 item->setColor(selectedColor);
272 viewport()->update();
273 Q_EMIT changed();
274 }
275 } else if (index.column() == 2 && !item->useDefaultColor()) {
276 item->setUseDefaultColor(true);
277 viewport()->update();
278 Q_EMIT changed();
279 }
280
281 return false;
282 }
283 return QTreeWidget::edit(index, trigger, event);
284}
285
286void KateColorTreeWidget::drawBranches(QPainter *painter, const QRect &rect, const QModelIndex &index) const
287{
288 Q_UNUSED(painter)
289 Q_UNUSED(rect)
290 Q_UNUSED(index)
291}
292
293void KateColorTreeWidget::selectDefaults()
294{
295 bool somethingChanged = false;
296
297 // use default colors for all selected items
298 for (int a = 0; a < topLevelItemCount(); ++a) {
300 for (int b = 0; b < top->childCount(); ++b) {
301 KateColorTreeItem *it = static_cast<KateColorTreeItem *>(top->child(b));
302 Q_ASSERT(it);
303 if (!it->useDefaultColor()) {
304 it->setUseDefaultColor(true);
305 somethingChanged = true;
306 }
307 }
308 }
309
310 if (somethingChanged) {
311 viewport()->update();
312 Q_EMIT changed();
313 }
314}
315
316void KateColorTreeWidget::addColorItem(const KateColorItem &colorItem)
317{
318 QTreeWidgetItem *categoryItem = nullptr;
319 for (int i = 0; i < topLevelItemCount(); ++i) {
320 if (topLevelItem(i)->text(0) == colorItem.category) {
321 categoryItem = topLevelItem(i);
322 break;
323 }
324 }
325
326 if (!categoryItem) {
327 categoryItem = new QTreeWidgetItem();
328 categoryItem->setText(0, colorItem.category);
329 addTopLevelItem(categoryItem);
330 expandItem(categoryItem);
331 }
332
333 new KateColorTreeItem(colorItem, categoryItem);
334
336}
337
338void KateColorTreeWidget::addColorItems(const QList<KateColorItem> &colorItems)
339{
340 for (const KateColorItem &item : colorItems) {
341 addColorItem(item);
342 }
343}
344
345QList<KateColorItem> KateColorTreeWidget::colorItems() const
346{
348 for (int a = 0; a < topLevelItemCount(); ++a) {
350 for (int b = 0; b < top->childCount(); ++b) {
351 KateColorTreeItem *item = static_cast<KateColorTreeItem *>(top->child(b));
352 Q_ASSERT(item);
353 items.append(item->colorItem());
354 }
355 }
356 return items;
357}
358
359QColor KateColorTreeWidget::findColor(const QString &key) const
360{
361 for (int a = 0; a < topLevelItemCount(); ++a) {
363 for (int b = 0; b < top->childCount(); ++b) {
364 KateColorTreeItem *item = static_cast<KateColorTreeItem *>(top->child(b));
365 if (item->key() == key) {
366 if (item->useDefaultColor()) {
367 return item->defaultColor();
368 } else {
369 return item->color();
370 }
371 }
372 }
373 }
374 return QColor();
375}
376
377bool KateColorTreeWidget::readOnly() const
378{
379 return m_readOnly;
380}
381
382void KateColorTreeWidget::setReadOnly(bool readOnly)
383{
384 m_readOnly = readOnly;
385}
386
387#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)
QString text(int column) const const
QStyle * style() const const
void update()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:15:44 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.