Krita Source Code Documentation
Loading...
Searching...
No Matches
WGSelectorConfigGrid.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2020 Mathias Wein <lynx.mw+kde@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-3.0-or-later
5 */
6
8
10
11#include "kis_debug.h"
12
13#include <QAction>
14#include <QActionGroup>
15#include <QEvent>
16#include <QGridLayout>
17#include <QIcon>
18#include <QPainter>
19#include <QString>
20#include <QTimer>
21#include <QToolButton>
22
23
24class SelectorConfigAction: public QAction
25{
26public:
27 explicit SelectorConfigAction(const KisColorSelectorConfiguration &cfg, QObject *parent)
28 : QAction(parent)
29 , m_config(cfg)
30 {
31 setCheckable(true);
32 }
34private:
36};
37
38WGSelectorConfigGrid::WGSelectorConfigGrid(QWidget *parent, bool multiSelect)
39 : QWidget(parent)
40 , m_layout(new QGridLayout(this))
41 , m_actionGroup(new QActionGroup(this))
42 , m_selector(new KisVisualColorSelector(this))
43{
44 m_actionGroup->setExclusive(!multiSelect);
45 connect(m_actionGroup, SIGNAL(triggered(QAction*)), SLOT(slotActionTriggered(QAction*)));
46
48 m_selector->setGeometry(0, 0, m_iconSize, m_iconSize - 2);
49 m_selector->setVisible(false);
50 m_selector->setEnabled(false);
52 m_selector->slotSetColor(KoColor(QColor(255, 0, 0), KoColorSpaceRegistry::instance()->rgb8()));
53}
54
56{
57 while (QLayoutItem *child = m_layout->takeAt(0)) {
58 delete child->widget();
59 delete child;
60 }
61 qDeleteAll(m_actionGroup->actions());
62}
63
65{
66 return (m_currentAction && m_currentAction != m_dummyAction) ? m_currentAction->icon() : QIcon();
67}
68
79
81{
83 const QList<QAction*> actions = m_actionGroup->actions();
84 for (QAction *action : actions) {
85 SelectorConfigAction *sa = dynamic_cast<SelectorConfigAction *>(action);
86 if (sa && sa->isChecked()) {
87 configurations.append(sa->configuration());
88 }
89 }
90 return configurations;
91}
92
94{
95 if (model != m_selector->selectorModel()->colorModel()) {
96 m_selector->selectorModel()->setRGBColorModel(model);
98 }
99}
100
102{
103 clear();
104 // exclusive action groups have no nice way to set none as checked, and
105 // ExclusiveOptional is not what we want either, so use a dummy action
106 m_dummyAction = new QAction("dummy", m_actionGroup);
107 m_dummyAction->setCheckable(true);
108 m_dummyAction->setChecked(true);
110
111 for (int i = 0; i < configurations.size(); i++) {
112 const KisColorSelectorConfiguration &config = configurations.at(i);
114 //action->setText(QString("TBD %1").arg(i));
115 action->setIcon(generateIcon(config, devicePixelRatioF(), true));
116
117 QToolButton *button = new QToolButton(this);
118 button->setAutoRaise(true);
119 button->setDefaultAction(action);
120 button->setIconSize(QSize(m_iconSize, m_iconSize));
121 m_layout->addWidget(button, i/m_columns, i%m_columns);
122 }
123}
124
126{
127 const QList<QAction*> actions = m_actionGroup->actions();
128 for (QAction *action : actions) {
129 SelectorConfigAction *sa = dynamic_cast<SelectorConfigAction *>(action);
130 if (sa && sa->configuration() == configuration) {
131 sa->setChecked(true);
132 m_currentAction = action;
133 return;
134 }
135 }
136 m_dummyAction->setChecked(true);
138}
139
140QIcon WGSelectorConfigGrid::generateIcon(const KisColorSelectorConfiguration &configuration, qreal pixelRatio, bool dualState) const
141{
142 QSize sz(m_selector->width() * pixelRatio, m_selector->height() * pixelRatio);
143 QPixmap pixmap(sz);
144 pixmap.setDevicePixelRatio(pixelRatio);
145 pixmap.fill(Qt::transparent);
146 m_selector->setConfiguration(&configuration);
147 QPoint offset(0, dualState ? 2 : 1);
148 m_selector->render(&pixmap, offset, QRegion(), RenderFlag::DrawChildren);
149 QIcon icon(pixmap);
150
151 if (!dualState) {
152 return icon;
153 }
154
155 // highlight bar for on-icon
156 QPainter painter(&pixmap);
157 painter.setRenderHint(QPainter::Antialiasing);
158 QBrush highlight(palette().brush(QPalette::Active, QPalette::Highlight));
159 painter.setPen(QPen(highlight, 2.0, Qt::SolidLine, Qt::RoundCap));
160 painter.drawLine(1, 1, m_iconSize-1, 1);
161 painter.end();
162 icon.addPixmap(pixmap, QIcon::Normal, QIcon::On);
163 return icon;
164}
165
167{
169 QVector<KCSC> configs;
170 configs.push_back(KCSC(KCSC::Triangle, KCSC::Ring, KCSC::SV, KCSC::H));
171 configs.push_back(KCSC(KCSC::Square, KCSC::Ring, KCSC::SV, KCSC::H));
172 configs.push_back(KCSC(KCSC::Wheel, KCSC::Slider, KCSC::VH, KCSC::hsvS));
173 configs.push_back(KCSC(KCSC::Wheel, KCSC::Slider, KCSC::hsvSH, KCSC::V));
174 configs.push_back(KCSC(KCSC::Square, KCSC::Slider, KCSC::SV, KCSC::H));
175 configs.push_back(KCSC(KCSC::Square, KCSC::Slider, KCSC::VH, KCSC::hsvS));
176 configs.push_back(KCSC(KCSC::Square, KCSC::Slider, KCSC::hsvSH, KCSC::V));
177 return configs;
178}
179
181{
182 bool handled = QWidget::event(event);
183 if (event->type() == QEvent::PaletteChange) {
184 // For some reason, Qt doesn't like if we recreate the icons from this
185 // even handler and randomly crashes somewhere after this function returns
186 QTimer::singleShot(0, this, &WGSelectorConfigGrid::updateIcons);
187 event->accept();
188 handled = true;
189 }
190 return handled;
191}
192
194{
195 // Unfortunately, exclusive QActionGroups don't filter out attempts to toggle
196 // an action that is already checked, so need to check ourselves if checked
197 // action really changed. Checking the hidden dummy also is a silent operation.
198 if (action == m_currentAction) {
199 return;
200 }
201 m_currentAction = action;
202 if (action != m_dummyAction) {
203 SelectorConfigAction *sa = dynamic_cast<SelectorConfigAction *>(action);
205
206 Q_EMIT sigConfigSelected(sa->configuration());
207 }
208}
209
211 const QList<QAction*> actions = m_actionGroup->actions();
212 for (QAction *action : actions) {
213 SelectorConfigAction *sa = dynamic_cast<SelectorConfigAction *>(action);
214 if (sa) {
215 sa->setIcon(generateIcon(sa->configuration(), devicePixelRatioF(), true));
216 }
217 }
218}
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
The KisVisualColorSelector class.
void slotSetColorSpace(const KoColorSpace *cs) override
void setConfiguration(const KisColorSelectorConfiguration *config)
Explicitly set the shape configuration. Accepts all valid combinations of Advanced Color Selector,...
void slotSetColor(const KoColor &c) override
KisVisualColorModelSP selectorModel() const
SelectorConfigAction(const KisColorSelectorConfiguration &cfg, QObject *parent)
KisColorSelectorConfiguration m_config
const KisColorSelectorConfiguration & configuration()
QVector< KisColorSelectorConfiguration > selectedConfigurations() const
KisColorSelectorConfiguration currentConfiguration() const
bool event(QEvent *event) override
void slotActionTriggered(QAction *action)
void setConfigurations(const QVector< KisColorSelectorConfiguration > &configurations)
QIcon generateIcon(const KisColorSelectorConfiguration &configuration, qreal pixelRatio=1.0, bool dualState=false) const
KisVisualColorSelector * m_selector
void setColorModel(KisVisualColorModel::ColorModel model)
WGSelectorConfigGrid(QWidget *parent=nullptr, bool multiSelect=false)
static QVector< KisColorSelectorConfiguration > hueBasedConfigurations()
void setChecked(const KisColorSelectorConfiguration &configuration)
void sigConfigSelected(const KisColorSelectorConfiguration &cfg)
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
QString button(const QWheelEvent &ev)
rgba palette[MAX_PALETTE]
Definition palette.c:35
static KoColorSpaceRegistry * instance()