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"