File indexing completed on 2024-05-19 04:29:05
0001 /* This file is part of the KDE project 0002 * SPDX-FileCopyrightText: 2008 Boudewijn Rempt <boud@valdyas.org> 0003 * SPDX-FileCopyrightText: 2011 Silvio Heinrich <plassy@web.de> 0004 * 0005 * SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "kis_paintop_settings_widget.h" 0009 #include "kis_paintop_option.h" 0010 #include "kis_paintop_options_model.h" 0011 0012 #include <QHBoxLayout> 0013 #include <QList> 0014 #include <QStackedWidget> 0015 #include <QVBoxLayout> 0016 #include <QPainter> 0017 #include <QStyleOptionViewItem> 0018 #include <QMenu> 0019 #include <QAction> 0020 #include <QShowEvent> 0021 0022 #include <brushengine/kis_paintop_preset.h> 0023 #include <kis_cmb_composite.h> 0024 #include <kis_categorized_item_delegate.h> 0025 #include <brushengine/kis_locked_properties_server.h> 0026 #include <brushengine/kis_locked_properties_proxy.h> 0027 #include <brushengine/kis_locked_properties.h> 0028 #include <brushengine/kis_paintop_lod_limitations.h> 0029 0030 #include <lager/constant.hpp> 0031 #include <KisLager.h> 0032 0033 0034 struct KisPaintOpSettingsWidget::Private 0035 { 0036 Private() 0037 { 0038 } 0039 0040 QList<KisPaintOpOption*> paintOpOptions; 0041 KisCategorizedListView* optionsList; 0042 KisPaintOpOptionListModel* model; 0043 QStackedWidget* optionsStack; 0044 std::optional<lager::reader<KisPaintopLodLimitations>> lodLimitations; 0045 }; 0046 0047 KisPaintOpSettingsWidget::KisPaintOpSettingsWidget(QWidget * parent) 0048 : KisPaintOpConfigWidget(parent) 0049 , m_d(new Private()) 0050 { 0051 setObjectName("KisPaintOpPresetsWidget"); 0052 0053 m_d->model = new KisPaintOpOptionListModel(this); 0054 m_d->optionsList = new KisCategorizedListView(this); 0055 m_d->optionsList->setModel(m_d->model); 0056 m_d->optionsList->setItemDelegate(new KisCategorizedItemDelegate(m_d->optionsList)); 0057 m_d->optionsList->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); 0058 m_d->optionsList->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 0059 0060 QSizePolicy policy = QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); 0061 m_d->optionsList->setSizePolicy(policy); 0062 0063 m_d->optionsList->setMinimumWidth(160); // this should be just big enough to show all of the setting names 0064 0065 m_d->optionsStack = new QStackedWidget(this); 0066 policy = QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); 0067 m_d->optionsStack->setSizePolicy(policy); 0068 0069 QHBoxLayout* layout = new QHBoxLayout(this); 0070 layout->addWidget(m_d->optionsList); 0071 layout->addWidget(m_d->optionsStack); 0072 0073 layout->setStretch(0, 0); 0074 layout->setStretch(1, 1); 0075 0076 m_saveLockedOption = false; 0077 0078 connect(m_d->optionsList, SIGNAL(activated(QModelIndex)), this, SLOT(changePage(QModelIndex))); 0079 connect(m_d->optionsList, SIGNAL(clicked(QModelIndex)), this, SLOT(changePage(QModelIndex))); 0080 connect(m_d->optionsList, SIGNAL(rightClickedMenuDropSettingsTriggered()), this, SLOT(slotLockPropertiesDrop())); 0081 connect(m_d->optionsList, SIGNAL(rightClickedMenuSaveSettingsTriggered()), this, SLOT(slotLockPropertiesSave())); 0082 connect(m_d->optionsList, SIGNAL(sigEntryChecked(QModelIndex)), this, SLOT(slotEntryChecked(QModelIndex))); 0083 connect (m_d->optionsList, SIGNAL(lockAreaTriggered(QModelIndex)), this, SLOT(lockProperties(QModelIndex))); 0084 0085 // allow the list viewport to be responsive to input release events 0086 m_d->optionsList->viewport()->installEventFilter(this); 0087 } 0088 0089 0090 KisPaintOpSettingsWidget::~KisPaintOpSettingsWidget() 0091 { 0092 qDeleteAll(m_d->paintOpOptions); 0093 delete m_d; 0094 } 0095 0096 void KisPaintOpSettingsWidget::addPaintOpOption(KisPaintOpOption *option) 0097 { 0098 addPaintOpOption(option, option->category()); 0099 } 0100 0101 void KisPaintOpSettingsWidget::addPaintOpOption(KisPaintOpOption *option, KisPaintOpOption::PaintopCategory category) 0102 { 0103 addPaintOpOption(option, m_d->model->categoryName(category)); 0104 } 0105 0106 void KisPaintOpSettingsWidget::addPaintOpOption(KisPaintOpOption *option, QString category) 0107 { 0108 if (!option->configurationPage()) return; 0109 m_d->model->addPaintOpOption(option, m_d->optionsStack->count(), option->label(), category); 0110 connect(option, SIGNAL(sigSettingChanged()), SIGNAL(sigConfigurationItemChanged())); 0111 m_d->optionsStack->addWidget(option->configurationPage()); 0112 m_d->paintOpOptions << option; 0113 0114 m_d->lodLimitations = 0115 kislager::fold_optional_cursors(std::bit_or{}, m_d->lodLimitations, 0116 option->effectiveLodLimitations()); 0117 } 0118 0119 void KisPaintOpSettingsWidget::setConfiguration(const KisPropertiesConfigurationSP config) 0120 { 0121 Q_ASSERT(!config->getString("paintop").isEmpty()); 0122 KisLockedPropertiesProxySP propertiesProxy = KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(config); 0123 int indexcount = 0; 0124 Q_FOREACH (KisPaintOpOption* option, m_d->paintOpOptions) { 0125 option->startReadOptionSetting(propertiesProxy); 0126 0127 KisLockedPropertiesServer::instance()->setPropertiesFromLocked(false); 0128 KisOptionInfo info; 0129 info.option = option; 0130 info.index = indexcount; 0131 0132 m_d->model->categoriesMapper()->itemFromRow(m_d->model->indexOf(info).row())->setLocked(option->isLocked()); 0133 m_d->model->categoriesMapper()->itemFromRow(m_d->model->indexOf(info).row())->setLockable(true); 0134 m_d->model->signalDataChanged(m_d->model->indexOf(info)); 0135 indexcount++; 0136 } 0137 } 0138 0139 void KisPaintOpSettingsWidget::writeConfiguration(KisPropertiesConfigurationSP config) const 0140 { 0141 KisLockedPropertiesProxySP propertiesProxy = KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(config); 0142 Q_FOREACH (const KisPaintOpOption* option, m_d->paintOpOptions) { 0143 option->startWriteOptionSetting(propertiesProxy); 0144 } 0145 } 0146 0147 KisPaintopLodLimitations KisPaintOpSettingsWidget::lodLimitations() const 0148 { 0149 KisPaintopLodLimitations l; 0150 0151 Q_FOREACH (const KisPaintOpOption* option, m_d->paintOpOptions) { 0152 if (option->isCheckable() && !option->isChecked()) continue; 0153 option->lodLimitations(&l); 0154 } 0155 0156 return l; 0157 } 0158 0159 lager::reader<KisPaintopLodLimitations> KisPaintOpSettingsWidget::lodLimitationsReader() const 0160 { 0161 return m_d->lodLimitations.value_or(lager::make_constant(KisPaintopLodLimitations())); 0162 } 0163 0164 lager::reader<qreal> KisPaintOpSettingsWidget::effectiveBrushSize() const 0165 { 0166 return lager::make_constant(1.0); 0167 } 0168 0169 void KisPaintOpSettingsWidget::setImage(KisImageWSP image) 0170 { 0171 KisPaintOpConfigWidget::setImage(image); 0172 0173 Q_FOREACH (KisPaintOpOption* option, m_d->paintOpOptions) { 0174 option->setImage(image); 0175 } 0176 } 0177 0178 void KisPaintOpSettingsWidget::setNode(KisNodeWSP node) 0179 { 0180 KisPaintOpConfigWidget::setNode(node); 0181 0182 Q_FOREACH (KisPaintOpOption* option, m_d->paintOpOptions) { 0183 option->setNode(node); 0184 } 0185 } 0186 0187 void KisPaintOpSettingsWidget::setResourcesInterface(KisResourcesInterfaceSP resourcesInterface) 0188 { 0189 KisPaintOpConfigWidget::setResourcesInterface(resourcesInterface); 0190 0191 Q_FOREACH (KisPaintOpOption* option, m_d->paintOpOptions) { 0192 option->setResourcesInterface(resourcesInterface); 0193 } 0194 } 0195 0196 void KisPaintOpSettingsWidget::setCanvasResourcesInterface(KoCanvasResourcesInterfaceSP canvasResourcesInterface) 0197 { 0198 KisPaintOpConfigWidget::setCanvasResourcesInterface(canvasResourcesInterface); 0199 0200 Q_FOREACH (KisPaintOpOption* option, m_d->paintOpOptions) { 0201 option->setCanvasResourcesInterface(canvasResourcesInterface); 0202 } 0203 } 0204 0205 void KisPaintOpSettingsWidget::changePage(const QModelIndex& index) 0206 { 0207 KisOptionInfo info; 0208 QPalette palette; 0209 palette.setColor(QPalette::Base, QColor(255,200,200)); 0210 palette.setColor(QPalette::Text, Qt::black); 0211 0212 if(m_d->model->entryAt(info, index)) { 0213 m_d->optionsStack->setCurrentIndex(info.index); 0214 } 0215 0216 notifyPageChanged(); 0217 } 0218 0219 void KisPaintOpSettingsWidget::notifyPageChanged() 0220 { 0221 } 0222 0223 void KisPaintOpSettingsWidget::lockProperties(const QModelIndex& index) 0224 { 0225 KisOptionInfo info; 0226 if (m_d->model->entryAt(info, index)) { 0227 m_d->optionsList->setCurrentIndex(index); 0228 KisPropertiesConfigurationSP p = new KisPropertiesConfiguration(); 0229 info.option->startWriteOptionSetting(p); 0230 0231 if (!info.option->isLocked()){ 0232 KisLockedPropertiesServer::instance()->addToLockedProperties(p); 0233 info.option->setLocked(true); 0234 m_d->model->categoriesMapper()->itemFromRow(index.row())->setLocked(true); 0235 m_d->model->signalDataChanged(index); 0236 0237 } 0238 else { 0239 KisLockedPropertiesServer::instance()->removeFromLockedProperties(p); 0240 info.option->setLocked(false); 0241 m_d->model->categoriesMapper()->itemFromRow(index.row())->setLocked(false); 0242 m_d->model->signalDataChanged(index); 0243 0244 if (m_saveLockedOption){ 0245 emit sigSaveLockedConfig(p); 0246 } 0247 else { 0248 emit sigDropLockedConfig(p); 0249 } 0250 m_saveLockedOption = false; 0251 } 0252 } 0253 } 0254 void KisPaintOpSettingsWidget::slotLockPropertiesDrop() 0255 { 0256 m_saveLockedOption = false; 0257 lockProperties(m_d->optionsList->currentIndex()); 0258 } 0259 void KisPaintOpSettingsWidget::slotLockPropertiesSave() 0260 { 0261 m_saveLockedOption = true; 0262 lockProperties(m_d->optionsList->currentIndex()); 0263 } 0264 void KisPaintOpSettingsWidget::slotEntryChecked(const QModelIndex &index) 0265 { 0266 Q_UNUSED(index); 0267 emit sigConfigurationItemChanged(); 0268 } 0269 0270 bool KisPaintOpSettingsWidget::eventFilter(QObject *obj, QEvent *event) 0271 { 0272 if (event->type() == (QEvent::MouseButtonRelease) || event->type() == QEvent::TabletRelease) { 0273 // bit of a hack to properly work with the KisCategorizedListView type: 0274 // get the mouse position and utilize indexAt() instead of currentIndex() to 0275 // ensure the pages don't swap back and forth if the user repeatedly clicks 0276 // another option's checkbox too quickly 0277 const QMouseEvent* mevent = static_cast<const QMouseEvent*>(event); 0278 QModelIndex index = m_d->optionsList->indexAt(mevent->pos()); 0279 changePage(index); 0280 event->accept(); 0281 } 0282 0283 return QObject::eventFilter(obj, event); 0284 }