diff --git a/libs/ui/widgets/kis_color_label_button.cpp b/libs/ui/widgets/kis_color_label_button.cpp index 525e5236c4..8615e34059 100644 --- a/libs/ui/widgets/kis_color_label_button.cpp +++ b/libs/ui/widgets/kis_color_label_button.cpp @@ -1,182 +1,247 @@ /* * Copyright (c) 2020 Eoin O'Neill * Copyright (c) 2020 Emmet O'Neill * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_color_label_button.h" #include #include #include #include "kis_global.h" #include "kis_debug.h" #include "krita_container_utils.h" struct KisColorLabelButton::Private { - QColor color; + const QColor m_color; + const uint m_sizeSquared; + + Private(QColor color, uint sizeSquared) + : m_color(color) + , m_sizeSquared(sizeSquared) + { + + } + + Private(const Private& rhs) + : m_color(rhs.m_color) + , m_sizeSquared(rhs.m_sizeSquared) + { + + } }; -KisColorLabelButton::KisColorLabelButton(QColor color, QWidget *parent) : QAbstractButton(parent), m_d(new Private()) +KisColorLabelButton::KisColorLabelButton(QColor color, uint sizeSquared, QWidget *parent) : QAbstractButton(parent), m_d(new Private(color, sizeSquared)) { setCheckable(true); setChecked(true); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - m_d->color = color; } KisColorLabelButton::~KisColorLabelButton() {} void KisColorLabelButton::paintEvent(QPaintEvent *event) { QWidget::paintEvent(event); QStylePainter painter(this); QStyleOption styleOption; styleOption.initFrom(this); if (isDown() || isChecked()){ styleOption.state |= QStyle::State_On; } // Draw fill.. QRect fillRect = kisGrowRect(rect(), -2); + QRect outlineRect = kisGrowRect(fillRect, -1); + + if (!isEnabled()) { + fillRect -= QMargins(sizeHint().width() / 4, sizeHint().height() / 4, sizeHint().width() / 4, sizeHint().height() / 4); + } else { + fillRect = kisGrowRect(fillRect, -3); + } + + fillRect.width(); - if (m_d->color.alpha() > 0) { - QColor fillColor = m_d->color; + if (m_d->m_color.alpha() > 0) { + QColor fillColor = m_d->m_color; - if (!isChecked()) { + if (!isChecked() || !isEnabled()) { fillColor.setAlpha(32); } - painter.fillRect(fillRect, fillColor); + QBrush brush = QBrush(fillColor); + painter.fillRect(fillRect, brush); + + if (isEnabled()) { + painter.setPen(QPen(m_d->m_color, 2)); + painter.drawRect(outlineRect); + } + } else { // draw an X for no color for the first item - const int shortestEdge = std::min(fillRect.width(), fillRect.height()); + /*const int shortestEdge = std::min(fillRect.width(), fillRect.height()); const int longestEdge = std::max(fillRect.width(), fillRect.height()); bool horizontalIsShortest = (shortestEdge == fillRect.width()); QRect srcRect = horizontalIsShortest ? fillRect.adjusted(0, (longestEdge / 2) - (shortestEdge / 2), 0, (shortestEdge / 2) - (longestEdge / 2)) : fillRect.adjusted((longestEdge / 2) - (shortestEdge / 2), 0, (shortestEdge / 2) - (longestEdge / 2), 0); QRect crossRect = kisGrowRect(srcRect, -1); QColor shade = styleOption.palette.text().color(); - - if (!isChecked()) { + if (!isChecked() || !isEnabled()) { shade.setAlpha(64); } - painter.setPen(QPen(shade, 2)); + QPen pen = QPen(shade, 2); + + painter.setPen(pen); painter.drawLine(crossRect.topLeft(), crossRect.bottomRight()); - painter.drawLine(crossRect.bottomLeft(), crossRect.topRight()); + painter.drawLine(crossRect.bottomLeft(), crossRect.topRight());*/ + + QColor white = QColor(255,255,255); + QColor grey = QColor(220,220,220); + QColor outlineColor = grey; + + + if (!isChecked() || !isEnabled()) { + white.setAlpha(32); + grey.setAlpha(32); + } + + QBrush whiteBrush = QBrush(white); + QBrush greyBrush = QBrush(grey); + + QRect upperLeftGrey = fillRect - QMargins(0, 0, fillRect.size().width() / 2, fillRect.size().height() /2); + QRect lowerRightGrey = fillRect - QMargins(fillRect.size().width() / 2, fillRect.size().height() / 2, 0, 0); + painter.fillRect(fillRect, whiteBrush); + painter.fillRect(upperLeftGrey, greyBrush); + painter.fillRect(lowerRightGrey, greyBrush); + + if (isEnabled()) { + painter.setPen(QPen(outlineColor, 2)); + painter.drawRect(outlineRect); + } + } } QSize KisColorLabelButton::sizeHint() const { - return QSize(32,32); + return QSize(m_d->m_sizeSquared,m_d->m_sizeSquared); } void KisColorLabelButton::nextCheckState() { KisColorLabelFilterGroup* colorLabelButtonGroup = dynamic_cast(group()); if (colorLabelButtonGroup && (colorLabelButtonGroup->countCheckedViableButtons() > 1 || !isChecked())) { setChecked(!isChecked()); } else { setChecked(isChecked()); } } KisColorLabelFilterGroup::KisColorLabelFilterGroup(QObject *parent) : QButtonGroup(parent) { } KisColorLabelFilterGroup::~KisColorLabelFilterGroup() { } QList KisColorLabelFilterGroup::viableButtons() const { QList viableButtons; Q_FOREACH( int index, viableColorLabels ) { viableButtons.append(button(index)); } return viableButtons; } void KisColorLabelFilterGroup::setViableLabels(QSet &labels) { - hideAll(); + setAllVisibility(false); + disableAll(); QSet removed = viableColorLabels.subtract(labels); viableColorLabels = labels; if (viableColorLabels.count() > 1) { + setAllVisibility(true); Q_FOREACH( int index, viableColorLabels) { if (button(index)) { - button(index)->setVisible(true); + button(index)->setEnabled(true); } } } Q_FOREACH( int index, removed ) { button(index)->setChecked(true); } } QSet KisColorLabelFilterGroup::getActiveLabels() const { QSet checkedLabels = QSet(); Q_FOREACH( int index, viableColorLabels ) { if (button(index)->isChecked()) { checkedLabels.insert(index); } } return checkedLabels.count() == viableColorLabels.count() ? QSet() : checkedLabels; } QList KisColorLabelFilterGroup::checkedViableButtons() const { QList checkedButtons = viableButtons(); KritaUtils::filterContainer(checkedButtons, [](QAbstractButton* btn){ return (btn->isChecked()); }); return checkedButtons; } int KisColorLabelFilterGroup::countCheckedViableButtons() const { return checkedViableButtons().count(); } int KisColorLabelFilterGroup::countViableButtons() const { return viableColorLabels.count(); } void KisColorLabelFilterGroup::reset() { Q_FOREACH( QAbstractButton* btn, viableButtons() ) { btn->setChecked(true); } } -void KisColorLabelFilterGroup::hideAll() { +void KisColorLabelFilterGroup::disableAll() { + Q_FOREACH( QAbstractButton* btn, buttons() ) { + btn->setDisabled(true); + } +} + +void KisColorLabelFilterGroup::setAllVisibility(const bool vis) +{ Q_FOREACH( QAbstractButton* btn, buttons() ) { - btn->setVisible(false); + btn->setVisible(vis); } } diff --git a/libs/ui/widgets/kis_color_label_button.h b/libs/ui/widgets/kis_color_label_button.h index e10de45ebf..e5f275e7ec 100644 --- a/libs/ui/widgets/kis_color_label_button.h +++ b/libs/ui/widgets/kis_color_label_button.h @@ -1,69 +1,69 @@ /* * Copyright (c) 2020 Eoin O'Neill * Copyright (c) 2020 Emmet O'Neill * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KISCOLORLABELBUTTON_H #define KISCOLORLABELBUTTON_H #include #include #include #include "kritaui_export.h" class KRITAUI_EXPORT KisColorLabelButton : public QAbstractButton { Q_OBJECT public: - KisColorLabelButton(QColor color, QWidget *parent = nullptr); + KisColorLabelButton(QColor color, uint sizeSquared = 32, QWidget *parent = nullptr); ~KisColorLabelButton(); void paintEvent(QPaintEvent* event) override; QSize sizeHint() const override; virtual void nextCheckState() override; private: struct Private; const QScopedPointer m_d; }; class KRITAUI_EXPORT KisColorLabelFilterGroup : public QButtonGroup { Q_OBJECT public: KisColorLabelFilterGroup(QObject* parent); ~KisColorLabelFilterGroup(); QList viableButtons() const; void setViableLabels(QSet &buttons); QSet getActiveLabels() const; QList checkedViableButtons() const; int countCheckedViableButtons() const; int countViableButtons() const; void reset(); private: - void hideAll(); - + void disableAll(); + void setAllVisibility(const bool vis); QSet viableColorLabels; }; #endif // KISCOLORLABELBUTTON_H diff --git a/libs/ui/widgets/kis_layer_filter_widget.cpp b/libs/ui/widgets/kis_layer_filter_widget.cpp index 7030cb63d5..88e5d6c9bc 100644 --- a/libs/ui/widgets/kis_layer_filter_widget.cpp +++ b/libs/ui/widgets/kis_layer_filter_widget.cpp @@ -1,290 +1,289 @@ /* * Copyright (c) 2020 Eoin O'Neill * Copyright (c) 2020 Emmet O'Neill * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_layer_filter_widget.h" #include #include #include #include #include #include #include #include #include #include #include "kis_debug.h" #include "kis_node.h" #include "kis_global.h" #include "kis_color_label_button.h" #include "kis_color_label_selector_widget.h" #include "kis_node_view_color_scheme.h" KisLayerFilterWidget::KisLayerFilterWidget(QWidget *parent) : QWidget(parent) { QVBoxLayout *layout = new QVBoxLayout(this); setLayout(layout); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); textFilter = new QLineEdit(this); textFilter->setPlaceholderText(i18n("Filter by name...")); textFilter->setMinimumWidth(192); textFilter->setMinimumHeight(32); textFilter->setClearButtonEnabled(true); connect(textFilter, SIGNAL(textChanged(QString)), this, SIGNAL(filteringOptionsChanged())); KisNodeViewColorScheme colorScheme; QWidget* buttonContainer = new QWidget(this); buttonContainer->setToolTip(i18n("Filter by color label...")); buttonEventFilter = new EventFilter(buttonContainer); { QHBoxLayout *subLayout = new QHBoxLayout(buttonContainer); buttonContainer->setLayout(subLayout); subLayout->setContentsMargins(0,0,0,0); subLayout->setAlignment(Qt::AlignLeft); buttonGroup = new KisColorLabelFilterGroup(buttonContainer); buttonGroup->setExclusive(false); QVector colors = colorScheme.allColorLabels(); for (int id = 0; id < colors.count(); id++) { - KisColorLabelButton* btn = new KisColorLabelButton(colors[id], buttonContainer); + KisColorLabelButton* btn = new KisColorLabelButton(colors[id], 32, buttonContainer); buttonGroup->addButton(btn, id); - btn->setVisible(false); btn->installEventFilter(buttonEventFilter); subLayout->addWidget(btn); } connect(buttonGroup, SIGNAL(buttonToggled(int,bool)), this, SIGNAL(filteringOptionsChanged())); } resetButton = new QPushButton(i18n("Reset Filters"), this); resetButton->setMinimumHeight(32); connect(resetButton, &QPushButton::clicked, [this](){ this->reset(); }); layout->addWidget(textFilter); layout->addWidget(buttonContainer); layout->addWidget(resetButton); } void KisLayerFilterWidget::scanUsedColorLabels(KisNodeSP node, QSet &colorLabels) { if (node->parent()) { colorLabels.insert(node->colorLabelIndex()); } KisNodeSP child = node->firstChild(); while(child) { scanUsedColorLabels(child, colorLabels); child = child->nextSibling(); } } void KisLayerFilterWidget::updateColorLabels(KisNodeSP root) { QSet colorLabels; scanUsedColorLabels(root, colorLabels); buttonGroup->setViableLabels(colorLabels); } bool KisLayerFilterWidget::isCurrentlyFiltering() const { const bool isFilteringText = !textFilter->text().isEmpty(); const bool isFilteringColors = buttonGroup->getActiveLabels().count() > 0; return isFilteringText || isFilteringColors; } QSet KisLayerFilterWidget::getActiveColors() const { QSet activeColors = buttonGroup->getActiveLabels(); return activeColors; } QString KisLayerFilterWidget::getTextFilter() const { return textFilter->text(); } int KisLayerFilterWidget::getDesiredMinimumWidth() const { return qMax(textFilter->minimumWidth(), buttonGroup->countViableButtons() * 32); } int KisLayerFilterWidget::getDesiredMinimumHeight() const { QList viableButtons = buttonGroup->viableButtons(); if (viableButtons.count() > 1) { return viableButtons[0]->sizeHint().height() + textFilter->minimumHeight() + resetButton->minimumHeight(); } else { return textFilter->minimumHeight() + resetButton->minimumHeight(); } } void KisLayerFilterWidget::reset() { textFilter->clear(); buttonGroup->reset(); filteringOptionsChanged(); } QSize KisLayerFilterWidget::sizeHint() const { return QSize(getDesiredMinimumWidth(), getDesiredMinimumHeight()); } void KisLayerFilterWidget::showEvent(QShowEvent *show) { QMenu *parentMenu = dynamic_cast(parentWidget()); QScreen *screen = QGuiApplication::screenAt(parentMenu->mapToGlobal(parentMenu->pos())); if (parentMenu && screen) { const int widthBefore = parentMenu->width(); const int rightEdgeThreshold = 5; const bool onRightEdge = (parentMenu->pos().x() + parentMenu->width() + rightEdgeThreshold) > screen->geometry().width(); adjustSize(); QResizeEvent event = QResizeEvent(size(), parentMenu->size()); parentMenu->resize(size()); parentMenu->adjustSize(); qApp->sendEvent(parentMenu, &event); const int widthAfter = parentMenu->width(); if (onRightEdge) { if (widthAfter > widthBefore) { const QRect newGeo = kisEnsureInRect( parentMenu->geometry(), screen->geometry() ); const int xShift = newGeo.x() - parentMenu->pos().x(); parentMenu->move(parentMenu->pos().x() + xShift, parentMenu->pos().y() + 0); } else { const int xShift = widthBefore - widthAfter; parentMenu->move(parentMenu->pos().x() + xShift, parentMenu->pos().y() + 0); } } } QWidget::showEvent(show); } KisLayerFilterWidget::EventFilter::EventFilter(QWidget *buttonContainer, QObject* parent) : QObject(parent) { m_buttonContainer = buttonContainer; lastKnownMousePosition = QPoint(0,0); currentState = Idle; } bool KisLayerFilterWidget::EventFilter::eventFilter(QObject *obj, QEvent *event) { if (event->type() == QEvent::MouseButtonPress) { QMouseEvent* mouseEvent = static_cast(event); currentState = WaitingForDragLeave; lastKnownMousePosition = mouseEvent->globalPos(); return true; } else if (event->type() == QEvent::MouseButtonRelease) { QMouseEvent* mouseEvent = static_cast(event); QAbstractButton* startingButton = static_cast(obj); //If we never left, toggle the original button. if( currentState == WaitingForDragLeave ) { if ( startingButton->group() && (mouseEvent->modifiers() & Qt::SHIFT)) { KisColorLabelFilterGroup* const group = static_cast(startingButton->group()); const QList viableCheckedButtons = group->checkedViableButtons(); const int buttonsEnabled = viableCheckedButtons.count(); const bool shouldChangeIsolation = (buttonsEnabled == 1) && (viableCheckedButtons.first() == startingButton); const bool shouldIsolate = (buttonsEnabled != 1) || !shouldChangeIsolation; Q_FOREACH(QAbstractButton* otherBtn, group->viableButtons()) { if (otherBtn == startingButton){ startingButton->setChecked(true); } else { otherBtn->setChecked(!shouldIsolate); } } } else { startingButton->click(); } } currentState = Idle; lastKnownMousePosition = mouseEvent->globalPos(); return true; } else if (event->type() == QEvent::MouseMove) { if (currentState == WaitingForDragLeave) { QMouseEvent* mouseEvent = static_cast(event); QWidget* firstClicked = static_cast(obj); const QPointF localPosition = mouseEvent->localPos(); if (!firstClicked->rect().contains(localPosition.x(), localPosition.y())) { QAbstractButton* btn = static_cast(obj); btn->click(); checkSlideOverNeighborButtons(mouseEvent, btn); currentState = WaitingForDragEnter; } lastKnownMousePosition = mouseEvent->globalPos(); return true; } else if (currentState == WaitingForDragEnter) { QMouseEvent* mouseEvent = static_cast(event); QAbstractButton* startingButton = static_cast(obj); const QPoint currentPosition = mouseEvent->globalPos(); checkSlideOverNeighborButtons(mouseEvent, startingButton); lastKnownMousePosition = currentPosition; return true; } } return false; } void KisLayerFilterWidget::EventFilter::checkSlideOverNeighborButtons(QMouseEvent* mouseEvent, QAbstractButton* startingButton) { const QPoint currentPosition = mouseEvent->globalPos(); if (startingButton->group()) { QList allButtons = startingButton->group()->buttons(); Q_FOREACH(QAbstractButton* button, allButtons) { const QRect bounds = QRect(button->mapToGlobal(QPoint(0,0)), button->size()); const QPoint upperLeft = QPoint(qMin(lastKnownMousePosition.x(), currentPosition.x()), qMin(lastKnownMousePosition.y(), currentPosition.y())); const QPoint lowerRight = QPoint(qMax(lastKnownMousePosition.x(), currentPosition.x()), qMax(lastKnownMousePosition.y(), currentPosition.y())); const QRect mouseMovement = QRect(upperLeft, lowerRight); if( bounds.intersects(mouseMovement) && !bounds.contains(lastKnownMousePosition)) { button->click(); } } } }