Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_layer_filter_widget.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2020 Eoin O 'Neill <eoinoneill1991@gmail.com>
3 * SPDX-FileCopyrightText: 2020 Emmet O 'Neill <emmetoneill.pdx@gmail.com>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
8
9#include <QScreen>
10#include <QApplication>
11#include <QVBoxLayout>
12#include <QLineEdit>
13#include <QCompleter>
14#include <QEvent>
15#include <QMouseEvent>
16#include <QButtonGroup>
17#include <QPushButton>
18#include <QMenu>
19#include <QScreen>
20#include <QStylePainter>
21#include <QGraphicsDropShadowEffect>
22
23#include "kis_debug.h"
24#include "kis_node.h"
25#include "kis_global.h"
26#include "kis_icon_utils.h"
27
32
33#include "KisMouseClickEater.h"
35
36KisLayerFilterWidget::KisLayerFilterWidget(QWidget *parent) : QWidget(parent)
37{
38 QVBoxLayout *layout = new QVBoxLayout(this);
39 setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
40
42 textFilter->setPlaceholderText(i18n("Filter by name..."));
43 textFilter->setMinimumWidth(200);
44 textFilter->setMinimumHeight(28);
45 textFilter->setClearButtonEnabled(true);
46
47 connect(textFilter, SIGNAL(textChanged(QString)), this, SIGNAL(filteringOptionsChanged()));
48 connect(textFilter, &QLineEdit::returnPressed, [this]() {
49 QMenu* menu = dynamic_cast<QMenu*>(parentWidget());
50 if (menu) {
51 menu->close();
52 }
53 });
54
55 KisNodeViewColorScheme colorScheme;
56
57 QWidget* buttonContainer = new QWidget(this);
58 MouseClickIgnore* mouseEater = new MouseClickIgnore(this);
59 buttonContainer->setToolTip(i18n("Filter by color label..."));
60 buttonContainer->installEventFilter(mouseEater);
62 {
63 QHBoxLayout *subLayout = new QHBoxLayout(buttonContainer);
64 subLayout->setContentsMargins(0,0,0,0);
65 subLayout->setSpacing(2);
66 subLayout->setAlignment(Qt::AlignLeft);
67 buttonGroup = new KisColorLabelFilterGroup(buttonContainer);
68 buttonGroup->setExclusive(false);
69 QVector<QColor> colors = colorScheme.allColorLabels();
70
71 for (int id = 0; id < colors.count(); id++) {
72 KisColorLabelButton* btn = new KisColorLabelButton(colors[id], 22, buttonContainer);
73 buttonGroup->addButton(btn, id);
74 btn->installEventFilter(buttonEventFilter);
75 subLayout->addWidget(btn);
76 }
77
78 connect(buttonGroup, SIGNAL(idToggled(int,bool)), this, SIGNAL(filteringOptionsChanged()));
79 }
80
81 resetButton = new QPushButton(i18n("Reset Filters"), this);
82 resetButton->setMinimumHeight(28);
83 connect(resetButton, &QPushButton::clicked, [this](){
84 this->reset();
85 });
86
87
88 layout->addWidget(textFilter);
89 layout->addWidget(buttonContainer);
90 layout->addWidget(resetButton);
91}
92
93void KisLayerFilterWidget::scanUsedColorLabels(KisNodeSP node, QSet<int> &colorLabels)
94{
95 if (node->parent()) {
96 colorLabels.insert(node->colorLabelIndex());
97 }
98
99 KisNodeSP child = node->firstChild();
100 while(child) {
101 scanUsedColorLabels(child, colorLabels);
102 child = child->nextSibling();
103 }
104}
105
107{
108 QSet<int> colorLabels;
109
110 scanUsedColorLabels(root, colorLabels);
111 buttonGroup->setViableLabels(colorLabels);
112}
113
115{
116 const bool isFilteringText = hasTextFilter();
117 const bool isFilteringColors = buttonGroup->getActiveLabels().count() > 0;
118
119 return isFilteringText || isFilteringColors;
120}
121
123{
124 return !textFilter->text().isEmpty();
125}
126
128{
129 QSet<int> activeColors = buttonGroup->getActiveLabels();
130
131 return activeColors;
132}
133
135{
136 return textFilter->text();
137}
138
140 return qMax(textFilter->minimumWidth(), buttonGroup->countViableButtons() * 32);
141}
142
145 if (viableButtons.count() > 1) {
146 return viableButtons[0]->sizeHint().height() + textFilter->minimumHeight() + resetButton->minimumHeight();
147 } else {
148 return textFilter->minimumHeight() + resetButton->minimumHeight();
149 }
150}
151
158
163
165{
166 QMenu *parentMenu = dynamic_cast<QMenu*>(parentWidget());
167
168 if (parentMenu) {
169 const int widthBefore = parentMenu->width();
170 const int rightEdgeThreshold = 5;
171
172 //Fake resize event needs to be made to register change in widget menu size.
173 //Not doing this will cause QMenu to not resize properly!
174 resize(sizeHint());
175
176 adjustSize();
177 QResizeEvent event = QResizeEvent(sizeHint(), parentMenu->size());
178
179 parentMenu->resize(sizeHint());
180 parentMenu->adjustSize();
181 qApp->sendEvent(parentMenu, &event);
182 QScreen *screen = QGuiApplication::screenAt(parentMenu->mapToGlobal(parentMenu->pos()));
183 QRect screenGeometry = screen ? screen->geometry() : parentMenu->parentWidget()->window()->geometry();
184 const bool onRightEdge = (parentMenu->pos().x() + widthBefore + rightEdgeThreshold) > screenGeometry.width();
185 const int widthAfter = parentMenu->width();
186
187
188 if (onRightEdge) {
189 if (widthAfter > widthBefore) {
190 const QRect newGeo = kisEnsureInRect( parentMenu->geometry(), screenGeometry );
191 const int xShift = newGeo.x() - parentMenu->pos().x();
192 parentMenu->move(parentMenu->pos().x() + xShift, parentMenu->pos().y() + 0);
193 } else {
194 const int xShift = widthBefore - widthAfter;
195 parentMenu->move(parentMenu->pos().x() + xShift, parentMenu->pos().y() + 0);
196 }
197 }
198 }
199 QWidget::showEvent(show);
200}
201
203 : QToolButton(parent)
204{
205 m_textFilter = false;
207}
208
210 : QToolButton(rhs.parentWidget())
211 , m_textFilter(rhs.m_textFilter)
212 , m_selectedColors(rhs.m_selectedColors)
213{
214
215}
216
221
223{
224 m_textFilter = isTextFiltering;
225}
226
228{
229 KisNodeViewColorScheme colorScheme;
230 const bool validColorFilter = !(m_selectedColors.count() == 0 || m_selectedColors.count() == colorScheme.allColorLabels().count());
231
232 if (m_textFilter == false && !validColorFilter)
233 {
234 QToolButton::paintEvent(paintEvent);
235 }
236 else
237 {
238 QStylePainter paint(this);
239 QStyleOptionToolButton opt;
240 initStyleOption(&opt);
241 opt.icon = m_textFilter ? KisIconUtils::loadIcon("format-text-bold") : icon();
242 paint.drawComplexControl(QStyle::CC_ToolButton, opt);
243 const QSize halfIconSize = this->iconSize() / 2;
244 const QSize halfButtonSize = this->size() / 2;
245 const QRect editRect = kisGrowRect(QRect(QPoint(halfButtonSize.width() - halfIconSize.width(), halfButtonSize.height() - halfIconSize.height()),this->iconSize()), -1);
246 const int size = qMin(editRect.width(), editRect.height());
247
248 if( validColorFilter )
249 {
250 KisColorFilterCombo::paintColorPie(paint, opt.palette, m_selectedColors, editRect, size );
251 if (m_textFilter) {
252 if (!opt.icon.isNull()) {
253 QRadialGradient radGradient = QRadialGradient(editRect.center(), size);
254 QColor shadowTransparent = palette().shadow().color();
255 shadowTransparent.setAlpha(96);
256 radGradient.setColorAt(0.0f, shadowTransparent);
257 shadowTransparent.setAlpha(0);
258 radGradient.setColorAt(1.0f, shadowTransparent);
259 paint.setBrush(radGradient);
260 paint.setPen(Qt::NoPen);
261 paint.drawEllipse(editRect.center(), size, size);
262 opt.icon.paint(&paint, editRect);
263 }
264 }
265 }
266 }
267}
268
270 : QObject(parent)
271{
272}
273
274bool MouseClickIgnore::eventFilter(QObject *obj, QEvent *event)
275{
276 if (obj &&
277 (event->type() == QEvent::MouseButtonPress ||
278 event->type() == QEvent::MouseButtonDblClick ||
279 event->type() == QEvent::MouseButtonRelease)) {
280 event->setAccepted(true);
281 return true;
282 } else {
283 return false;
284 }
285}
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
int iconSize(qreal width, qreal height)
static void paintColorPie(QStylePainter &painter, const QPalette &palette, const QList< int > &selectedColors, const QRect &rect, const int &baseSize)
void setViableLabels(const QSet< int > &buttons)
QList< QAbstractButton * > viableButtons() const
void paintEvent(QPaintEvent *paintEvent) override
void setTextFilter(bool isTextFiltering)
KisLayerFilterWidgetToolButton(QWidget *parent=nullptr)
void setSelectedColors(QList< int > colors)
QSet< int > getActiveColors() const
class QPushButton * resetButton
class KisColorLabelMouseDragFilter * buttonEventFilter
class KisColorLabelFilterGroup * buttonGroup
static void scanUsedColorLabels(KisNodeSP node, QSet< int > &colorLabels)
void filteringOptionsChanged()
void showEvent(QShowEvent *show) override
void updateColorLabels(KisNodeSP root)
QSize sizeHint() const override
KisLayerFilterWidget(QWidget *parent=nullptr)
QVector< QColor > allColorLabels() const
bool eventFilter(QObject *obj, QEvent *event) override
MouseClickIgnore(QObject *parent=nullptr)
T kisGrowRect(const T &rect, U offset)
Definition kis_global.h:186
QRect kisEnsureInRect(QRect rc, const QRect &bounds)
Definition kis_global.h:267
QIcon loadIcon(const QString &name)
rgba palette[MAX_PALETTE]
Definition palette.c:35
int colorLabelIndex() const
KisNodeSP firstChild() const
Definition kis_node.cpp:361
KisNodeWSP parent
Definition kis_node.cpp:86
KisNodeSP nextSibling() const
Definition kis_node.cpp:408