File indexing completed on 2025-02-02 04:22:09

0001 /*
0002  * SPDX-FileCopyrightText: 2008 Boudewijn Rempt <boud@valdyas.org>
0003  * SPDX-FileCopyrightText: 2014 Mohit Goyal <mohit.bits2011@gmail.com>
0004  *
0005  * SPDX-License-Identifier: GPL-2.0-or-later
0006  */
0007 #include "kis_brush_selection_widget.h"
0008 #include <QLayout>
0009 #include <QTabWidget>
0010 #include <QFrame>
0011 #include <QImage>
0012 #include <QPainter>
0013 #include <QBrush>
0014 #include <QColor>
0015 #include <QToolButton>
0016 #include <QButtonGroup>
0017 #include <QStackedWidget>
0018 
0019 #include <klocalizedstring.h>
0020 
0021 #include <widgets/kis_preset_chooser.h>
0022 #include <kis_image.h>
0023 #include <kis_fixed_paint_device.h>
0024 
0025 #include "kis_brush.h"
0026 #include "kis_auto_brush.h"
0027 #include "kis_imagepipe_brush.h"
0028 #include "kis_predefined_brush_chooser.h"
0029 #include "kis_auto_brush_widget.h"
0030 #include "kis_custom_brush_widget.h"
0031 #include "kis_clipboard_brush_widget.h"
0032 #include "kis_text_brush_chooser.h"
0033 #include "KisWidgetConnectionUtils.h"
0034 #include <KisZug.h>
0035 #include <KisLager.h>
0036 #include <lager/constant.hpp>
0037 
0038 using namespace KisBrushModel;
0039 using namespace KisWidgetConnectionUtils;
0040 
0041 QString calcPrecisionToolTip(int precisionLevel) {
0042     QString toolTip;
0043 
0044     KIS_SAFE_ASSERT_RECOVER_NOOP(precisionLevel >= 1);
0045     KIS_SAFE_ASSERT_RECOVER_NOOP(precisionLevel <= 5);
0046 
0047     switch (precisionLevel) {
0048     case 1:
0049         toolTip =
0050             i18n("Precision Level 1 (fastest)\n"
0051                  "Subpixel precision: disabled\n"
0052                  "Brush size precision: 5%\n"
0053                  "\n"
0054                  "Optimal for very big brushes");
0055         break;
0056     case 2:
0057         toolTip =
0058             i18n("Precision Level 2\n"
0059                  "Subpixel precision: disabled\n"
0060                  "Brush size precision: 1%\n"
0061                  "\n"
0062                  "Optimal for big brushes");
0063         break;
0064     case 3:
0065         toolTip =
0066             i18n("Precision Level 3\n"
0067                  "Subpixel precision: disabled\n"
0068                  "Brush size precision: exact");
0069         break;
0070     case 4:
0071         toolTip =
0072             i18n("Precision Level 4 (optimal)\n"
0073                  "Subpixel precision: 50%\n"
0074                  "Brush size precision: exact\n"
0075                  "\n"
0076                  "Gives up to 50% better performance in comparison to Level 5");
0077         break;
0078     case 5:
0079         toolTip =
0080             i18n("Precision Level 5 (best quality)\n"
0081                  "Subpixel precision: exact\n"
0082                  "Brush size precision: exact\n"
0083                  "\n"
0084                  "The slowest performance. Best quality.");
0085         break;
0086     }
0087     return toolTip;
0088 }
0089 
0090 class PrecisionModel : public QObject
0091 {
0092     Q_OBJECT
0093 
0094 public:
0095 
0096     PrecisionModel(lager::cursor<PrecisionData> source)
0097         : m_source(source),
0098           LAGER_QT(precisionLevel) {m_source[&PrecisionData::precisionLevel]},
0099           LAGER_QT(useAutoPrecision) {m_source[&PrecisionData::useAutoPrecision]},
0100           LAGER_QT(precisionToolTip) {LAGER_QT(precisionLevel).map(&calcPrecisionToolTip)}
0101     {
0102     }
0103 
0104     lager::cursor<PrecisionData> m_source;
0105 
0106     LAGER_QT_CURSOR(int, precisionLevel);
0107     LAGER_QT_CURSOR(bool, useAutoPrecision);
0108     LAGER_QT_READER(QString, precisionToolTip);
0109 };
0110 
0111 struct KisBrushSelectionWidget::Private
0112 {
0113     Private(lager::cursor<PrecisionData> precisionData)
0114         : model(precisionData)
0115     {
0116     }
0117 
0118     PrecisionModel model;
0119     lager::cursor<int> brushType;
0120 };
0121 
0122 KisBrushSelectionWidget::KisBrushSelectionWidget(int maxBrushSize,
0123                                                  KisAutoBrushModel *autoBrushModel,
0124                                                  KisPredefinedBrushModel *predefinedBrushModel,
0125                                                  KisTextBrushModel *textBrushModel,
0126                                                  lager::cursor<BrushType> brushType,
0127                                                  lager::cursor<PrecisionData> precisionData,
0128                                                  KisBrushOptionWidgetFlags flags,
0129                                                  QWidget *parent)
0130     : QWidget(parent)
0131     , m_currentBrushWidget(0)
0132     , m_d(new Private(precisionData))
0133 {
0134     uiWdgBrushChooser.setupUi(this);
0135 
0136     m_buttonGroup = new QButtonGroup(this);
0137     m_buttonGroup->setExclusive(true);
0138     m_layout = new QGridLayout(uiWdgBrushChooser.settingsFrame);
0139 
0140     m_stackedWidget = new QStackedWidget(this);
0141     m_layout->addWidget(m_stackedWidget);
0142 
0143     m_autoBrushWidget = new KisAutoBrushWidget(maxBrushSize, autoBrushModel, this, "autobrush");
0144     addChooser(i18nc("Autobrush Brush tip mode", "Auto"), m_autoBrushWidget, AUTOBRUSH, KoGroupButton::GroupLeft);
0145     m_predefinedBrushWidget = new KisPredefinedBrushChooser(maxBrushSize, predefinedBrushModel, this);
0146     addChooser(i18nc("Predefined Brush tip mode", "Predefined"), m_predefinedBrushWidget, PREDEFINEDBRUSH, KoGroupButton::GroupCenter);
0147 
0148     m_textBrushWidget = new KisTextBrushChooser(textBrushModel, this);
0149     addChooser(i18nc("Text Brush tip mode", "Text"), m_textBrushWidget, TEXTBRUSH, KoGroupButton::GroupRight);
0150 
0151     m_d->brushType = brushType.zoom(kislager::lenses::do_static_cast<BrushType, int>);
0152 
0153     m_d->brushType.bind([this](int value) {m_stackedWidget->setCurrentIndex(value); });
0154     m_d->brushType.bind([this](int value) {m_buttonGroup->button(value)->setChecked(true); });
0155     connect(m_buttonGroup, qOverload<int>(&QButtonGroup::buttonClicked),
0156             [this] (int id) {m_d->brushType.set(id);});
0157 
0158 
0159     Q_FOREACH (QWidget *widget, m_chooserMap.values()) {
0160         m_minimumSize = m_minimumSize.expandedTo(widget->sizeHint());
0161     }
0162 
0163 
0164     setCurrentWidget(m_autoBrushWidget);
0165 
0166     uiWdgBrushChooser.sliderPrecision->setRange(1, 5);
0167     uiWdgBrushChooser.sliderPrecision->setSingleStep(1);
0168     uiWdgBrushChooser.sliderPrecision->setPageStep(1);
0169 
0170 
0171     if (flags & KisBrushOptionWidgetFlag::SupportsPrecision) {
0172         connectControl(uiWdgBrushChooser.sliderPrecision, &m_d->model, "precisionLevel");
0173         connectControl(uiWdgBrushChooser.autoPrecisionCheckBox, &m_d->model, "useAutoPrecision");
0174         connect(&m_d->model, &PrecisionModel::precisionToolTipChanged,
0175                 uiWdgBrushChooser.sliderPrecision, &KisSliderSpinBox::setToolTip);
0176 
0177         connect(&m_d->model, &PrecisionModel::useAutoPrecisionChanged,
0178                 uiWdgBrushChooser.sliderPrecision, &KisSliderSpinBox::setDisabled);
0179         connect(&m_d->model, &PrecisionModel::useAutoPrecisionChanged,
0180                 uiWdgBrushChooser.lblPrecision, &KisSliderSpinBox::setDisabled);
0181     } else {
0182         uiWdgBrushChooser.sliderPrecision->setVisible(false);
0183         uiWdgBrushChooser.autoPrecisionCheckBox->setVisible(false);
0184         uiWdgBrushChooser.lblPrecision->setVisible(false);
0185     }
0186 }
0187 
0188 
0189 KisBrushSelectionWidget::~KisBrushSelectionWidget()
0190 {
0191 }
0192 
0193 KisBrushSP KisBrushSelectionWidget::brush() const
0194 {
0195     KisBrushSP theBrush;
0196 
0197     // Fallback to auto brush if no brush selected
0198     // Can happen if there is no predefined brush found
0199     if (!theBrush)
0200         theBrush = m_autoBrushWidget->brush();
0201 
0202     return theBrush;
0203 
0204 }
0205 void KisBrushSelectionWidget::setImage(KisImageWSP image)
0206 {
0207     m_predefinedBrushWidget->setImage(image);
0208 }
0209 
0210 void KisBrushSelectionWidget::hideOptions(const QStringList &options)
0211 {
0212     Q_FOREACH(const QString &option, options) {
0213         QStringList l = option.split("/");
0214         if (l.count() != 2) {
0215             continue;
0216         }
0217         QObject *o = 0;
0218         if (l[0] == "KisAutoBrushWidget") {
0219             o = m_autoBrushWidget->findChild<QObject*>(l[1]);
0220         }
0221         else if (l[0] == "KisBrushChooser") {
0222             o = m_predefinedBrushWidget->findChild<QObject*>(l[1]);
0223         }
0224         else if (l[0] == "KisTextBrushChooser") {
0225             o = m_textBrushWidget->findChild<QObject*>(l[1]);
0226         }
0227         else {
0228             qWarning() << "KisBrushSelectionWidget: Invalid option given to disable:" << option;
0229         }
0230 
0231         if (o) {
0232             QWidget *w = qobject_cast<QWidget*>(o);
0233             if (w) {
0234                 w->setVisible(false);
0235             }
0236             o = 0;
0237         }
0238     }
0239 }
0240 
0241 lager::reader<bool> KisBrushSelectionWidget::lightnessModeEnabled() const
0242 {
0243     return lager::with(m_d->brushType.xform(kiszug::map_equal<int>(Predefined)),
0244                        m_predefinedBrushWidget->lightnessModeEnabled())
0245             .map(std::logical_and{});
0246 }
0247 
0248 void KisBrushSelectionWidget::setCurrentWidget(QWidget* widget)
0249 {
0250     return;
0251 
0252     if (widget == m_currentBrushWidget) return;
0253 
0254     if (m_currentBrushWidget) {
0255         m_layout->removeWidget(m_currentBrushWidget);
0256         m_currentBrushWidget->setParent(this);
0257         m_currentBrushWidget->hide();
0258     }
0259     widget->setMinimumSize(m_minimumSize);
0260 
0261     m_currentBrushWidget = widget;
0262     m_layout->addWidget(widget);
0263 
0264     m_currentBrushWidget->show();
0265     m_buttonGroup->button(m_chooserMap.key(widget))->setChecked(true);
0266 }
0267 
0268 void KisBrushSelectionWidget::addChooser(const QString& text, QWidget* widget, int id, KoGroupButton::GroupPosition pos)
0269 {
0270     KoGroupButton *button = new KoGroupButton(this);
0271     button->setGroupPosition(pos);
0272     button->setText(text);
0273     button->setAutoRaise(false);
0274     button->setCheckable(true);
0275     uiWdgBrushChooser.brushChooserButtonLayout->addWidget(button);
0276     m_buttonGroup->addButton(button, id);
0277 
0278     m_stackedWidget->insertWidget(id, widget);
0279 }
0280 
0281 #include "kis_brush_selection_widget.moc"