1 /* 2 * Copyright (c) 2007-2008 Cyrille Berger <cberger@cberger.net> 3 * Copyright (c) 2009 Boudewijn Rempt <boud@valdyas.org> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 * Boston, MA 02110-1301, USA. 19 */ 20 21 #include "kis_filter_selector_widget.h" 22 23 #include <QHeaderView> 24 #include <QTreeView> 25 #include <QLabel> 26 #include <QComboBox> 27 #include <QPushButton> 28 #include <QScrollArea> 29 #include <QLayout> 30 #include <QDialogButtonBox> 31 #include <QPlainTextEdit> 32 #include <QDomDocument> 33 #include <QDomElement> 34 35 #include "ui_wdgfilterselector.h" 36 37 #include <kis_layer.h> 38 #include <kis_paint_device.h> 39 #include <filter/kis_filter.h> 40 #include <kis_config_widget.h> 41 #include <filter/kis_filter_configuration.h> 42 #include "kis_default_bounds.h" 43 #include <KisKineticScroller.h> 44 45 // From krita/ui 46 #include "kis_bookmarked_configurations_editor.h" 47 #include "kis_bookmarked_filter_configurations_model.h" 48 #include "kis_filters_model.h" 49 #include "kis_config.h" 50 51 class ThumbnailBounds : public KisDefaultBounds { 52 public: ThumbnailBounds()53 ThumbnailBounds() : KisDefaultBounds() {} ~ThumbnailBounds()54 ~ThumbnailBounds() override {} 55 bounds() const56 QRect bounds() const override 57 { 58 return QRect(0, 0, 100, 100); 59 } 60 private: 61 Q_DISABLE_COPY(ThumbnailBounds) 62 }; 63 64 65 struct KisFilterSelectorWidget::Private { 66 QWidget *currentCentralWidget {0}; 67 KisConfigWidget *currentFilterConfigurationWidget {0}; 68 KisFilterSP currentFilter; 69 KisPaintDeviceSP paintDevice; 70 Ui_FilterSelector uiFilterSelector; 71 KisPaintDeviceSP thumb; 72 KisBookmarkedFilterConfigurationsModel *currentBookmarkedFilterConfigurationsModel {0}; 73 KisFiltersModel *filtersModel {}; 74 QGridLayout *widgetLayout {}; 75 KisViewManager *view{}; 76 bool showFilterGallery {true}; 77 bool usedForMask {false}; 78 }; 79 KisFilterSelectorWidget(QWidget * parent)80 KisFilterSelectorWidget::KisFilterSelectorWidget(QWidget* parent) 81 : d(new Private) 82 { 83 Q_UNUSED(parent); 84 setObjectName("KisFilterSelectorWidget"); 85 d->uiFilterSelector.setupUi(this); 86 87 d->widgetLayout = new QGridLayout(d->uiFilterSelector.centralWidgetHolder); 88 d->widgetLayout->setContentsMargins(0,0,0,0); 89 d->widgetLayout->setHorizontalSpacing(0); 90 91 showFilterGallery(false); 92 93 connect(d->uiFilterSelector.filtersSelector, SIGNAL(clicked(QModelIndex)), SLOT(setFilterIndex(QModelIndex))); 94 connect(d->uiFilterSelector.filtersSelector, SIGNAL(activated(QModelIndex)), SLOT(setFilterIndex(QModelIndex))); 95 96 connect(d->uiFilterSelector.comboBoxPresets, SIGNAL(activated(int)),SLOT(slotBookmarkedFilterConfigurationSelected(int))); 97 connect(d->uiFilterSelector.pushButtonEditPressets, SIGNAL(pressed()), SLOT(editConfigurations())); 98 connect(d->uiFilterSelector.btnXML, SIGNAL(clicked()), this, SLOT(showXMLdialog())); 99 100 KisConfig cfg(true); 101 d->uiFilterSelector.chkRememberPreset->setChecked(cfg.readEntry<bool>("filterdialog/rememberlastpreset", false)); 102 103 } 104 ~KisFilterSelectorWidget()105 KisFilterSelectorWidget::~KisFilterSelectorWidget() 106 { 107 KisConfig cfg(false); 108 cfg.writeEntry<bool>("filterdialog/rememberlastpreset", d->uiFilterSelector.chkRememberPreset->isChecked()); 109 delete d->filtersModel; 110 delete d->currentBookmarkedFilterConfigurationsModel; 111 delete d->currentCentralWidget; 112 delete d->widgetLayout; 113 delete d; 114 } 115 setView(KisViewManager * view)116 void KisFilterSelectorWidget::setView(KisViewManager *view) 117 { 118 d->view = view; 119 } 120 setPaintDevice(bool showAll,KisPaintDeviceSP _paintDevice)121 void KisFilterSelectorWidget::setPaintDevice(bool showAll, KisPaintDeviceSP _paintDevice) 122 { 123 if (!_paintDevice) return; 124 125 if (d->filtersModel) delete d->filtersModel; 126 127 d->usedForMask = !showAll; 128 d->paintDevice = _paintDevice; 129 d->thumb = d->paintDevice->createThumbnailDevice(100, 100); 130 d->thumb->setDefaultBounds(new ThumbnailBounds()); 131 d->filtersModel = new KisFiltersModel(showAll, d->thumb); 132 133 d->uiFilterSelector.filtersSelector->setFilterModel(d->filtersModel); 134 d->uiFilterSelector.filtersSelector->header()->setVisible(false); 135 136 KisConfig cfg(true); 137 QModelIndex idx = d->filtersModel->indexForFilter(cfg.readEntry<QString>("FilterSelector/LastUsedFilter", "levels")); 138 139 if (!idx.isValid()) { 140 idx = d->filtersModel->indexForFilter("levels"); 141 } 142 143 if (d->usedForMask && isFilterGalleryVisible()) { 144 d->uiFilterSelector.filtersSelector->activateFilter(idx); 145 } 146 147 } 148 showFilterGallery(bool visible)149 void KisFilterSelectorWidget::showFilterGallery(bool visible) 150 { 151 if (d->showFilterGallery == visible) { 152 return; 153 } 154 155 d->showFilterGallery = visible; 156 update(); 157 emit sigFilterGalleryToggled(visible); 158 emit sigSizeChanged(); 159 } 160 showXMLdialog()161 void KisFilterSelectorWidget::showXMLdialog() 162 { 163 if (currentFilter()->showConfigurationWidget()) { 164 QDialog *xmlDialog = new QDialog(qApp->activeWindow()); 165 xmlDialog->setMinimumWidth(500); 166 xmlDialog->setWindowTitle(i18n("Filter configuration XML")); 167 QVBoxLayout *xmllayout = new QVBoxLayout(xmlDialog); 168 QPlainTextEdit *text = new QPlainTextEdit(xmlDialog); 169 KisFilterConfigurationSP config = configuration(); 170 text->setPlainText(config->toXML()); 171 xmllayout->addWidget(text); 172 QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel, xmlDialog); 173 connect(buttons, SIGNAL(accepted()), xmlDialog, SLOT(accept())); 174 connect(buttons, SIGNAL(rejected()), xmlDialog, SLOT(reject())); 175 xmllayout->addWidget(buttons); 176 if (xmlDialog->exec()==QDialog::Accepted) { 177 QDomDocument doc; 178 doc.setContent(text->toPlainText()); 179 config->fromXML(doc.documentElement()); 180 if (config) { 181 d->currentFilterConfigurationWidget->setConfiguration(config); 182 } 183 } 184 } 185 } 186 isFilterGalleryVisible() const187 bool KisFilterSelectorWidget::isFilterGalleryVisible() const 188 { 189 return d->showFilterGallery; 190 } 191 currentFilter() const192 KisFilterSP KisFilterSelectorWidget::currentFilter() const 193 { 194 return d->currentFilter; 195 } 196 setFilter(KisFilterSP f,KisFilterConfigurationSP overrideDefaultConfig)197 void KisFilterSelectorWidget::setFilter(KisFilterSP f, KisFilterConfigurationSP overrideDefaultConfig) 198 { 199 Q_ASSERT(f); 200 Q_ASSERT(d->filtersModel); 201 setWindowTitle(f->name()); 202 dbgKrita << "setFilter: " << f; 203 d->currentFilter = f; 204 delete d->currentCentralWidget; 205 206 { 207 bool v = d->uiFilterSelector.filtersSelector->blockSignals(true); 208 d->uiFilterSelector.filtersSelector->setCurrentIndex(d->filtersModel->indexForFilter(f->id())); 209 d->uiFilterSelector.filtersSelector->blockSignals(v); 210 } 211 212 KisConfigWidget* widget = 213 d->currentFilter->createConfigurationWidget(d->uiFilterSelector.centralWidgetHolder, d->paintDevice, d->usedForMask); 214 215 if (!widget) { // No widget, so display a label instead 216 d->uiFilterSelector.comboBoxPresets->setEnabled(false); 217 d->uiFilterSelector.pushButtonEditPressets->setEnabled(false); 218 d->uiFilterSelector.btnXML->setEnabled(false); 219 220 d->currentFilterConfigurationWidget = 0; 221 d->currentCentralWidget = new QLabel(i18n("No configuration options"), 222 d->uiFilterSelector.centralWidgetHolder); 223 d->uiFilterSelector.scrollArea->setMinimumSize(d->currentCentralWidget->sizeHint()); 224 qobject_cast<QLabel*>(d->currentCentralWidget)->setAlignment(Qt::AlignCenter); 225 } else { 226 KisFilterConfigurationSP defaultConfiguration = 227 overrideDefaultConfig ? 228 overrideDefaultConfig : 229 d->currentFilter->defaultConfiguration(); 230 231 d->uiFilterSelector.comboBoxPresets->setEnabled(true); 232 d->uiFilterSelector.pushButtonEditPressets->setEnabled(true); 233 d->uiFilterSelector.btnXML->setEnabled(true); 234 235 d->currentFilterConfigurationWidget = widget; 236 d->currentCentralWidget = widget; 237 widget->layout()->setContentsMargins(0,0,0,0); 238 d->currentFilterConfigurationWidget->setView(d->view); 239 d->currentFilterConfigurationWidget->blockSignals(true); 240 d->currentFilterConfigurationWidget->setConfiguration(defaultConfiguration); 241 d->currentFilterConfigurationWidget->blockSignals(false); 242 d->uiFilterSelector.scrollArea->setContentsMargins(0,0,0,0); 243 d->uiFilterSelector.scrollArea->setMinimumWidth(widget->sizeHint().width() + 18); 244 connect(d->currentFilterConfigurationWidget, SIGNAL(sigConfigurationUpdated()), this, SIGNAL(configurationChanged())); 245 } 246 247 // Change the list of presets 248 delete d->currentBookmarkedFilterConfigurationsModel; 249 d->currentBookmarkedFilterConfigurationsModel = new KisBookmarkedFilterConfigurationsModel(d->thumb, f); 250 d->uiFilterSelector.comboBoxPresets->setModel(d->currentBookmarkedFilterConfigurationsModel); 251 252 // Add the widget to the layout 253 d->currentCentralWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); 254 d->widgetLayout->addWidget(d->currentCentralWidget, 0 , 0); 255 256 if (d->uiFilterSelector.chkRememberPreset->isChecked()) { 257 int lastBookmarkedFilterConfiguration = KisConfig(true).readEntry<int>("lastBookmarkedFilterConfiguration/" + f->id(), 0); 258 if (d->uiFilterSelector.comboBoxPresets->count() > lastBookmarkedFilterConfiguration) { 259 d->uiFilterSelector.comboBoxPresets->setCurrentIndex(lastBookmarkedFilterConfiguration); 260 slotBookmarkedFilterConfigurationSelected(lastBookmarkedFilterConfiguration); 261 } 262 } 263 264 update(); 265 } 266 setFilterIndex(const QModelIndex & idx)267 void KisFilterSelectorWidget::setFilterIndex(const QModelIndex& idx) 268 { 269 if (!idx.isValid()) return; 270 271 Q_ASSERT(d->filtersModel); 272 KisFilter* filter = const_cast<KisFilter*>(d->filtersModel->indexToFilter(idx)); 273 if (filter) { 274 setFilter(filter, 0); 275 } 276 else { 277 if (d->currentFilter) { 278 bool v = d->uiFilterSelector.filtersSelector->blockSignals(true); 279 QModelIndex idx = d->filtersModel->indexForFilter(d->currentFilter->id()); 280 d->uiFilterSelector.filtersSelector->setCurrentIndex(idx); 281 d->uiFilterSelector.filtersSelector->scrollTo(idx); 282 d->uiFilterSelector.filtersSelector->blockSignals(v); 283 } 284 } 285 286 slotBookMarkCurrentFilter(); 287 emit(configurationChanged()); 288 } 289 slotBookMarkCurrentFilter()290 void KisFilterSelectorWidget::slotBookMarkCurrentFilter() { 291 KisConfig cfg(false); 292 cfg.writeEntry<QString>("FilterSelector/LastUsedFilter", d->currentFilter->id()); 293 } 294 slotBookmarkedFilterConfigurationSelected(int index)295 void KisFilterSelectorWidget::slotBookmarkedFilterConfigurationSelected(int index) 296 { 297 if (d->currentFilterConfigurationWidget) { 298 QModelIndex modelIndex = d->currentBookmarkedFilterConfigurationsModel->index(index, 0); 299 KisFilterConfigurationSP config = d->currentBookmarkedFilterConfigurationsModel->configuration(modelIndex); 300 d->currentFilterConfigurationWidget->setConfiguration(config); 301 if (d->currentFilter && index != KisConfig(true).readEntry<int>("lastBookmarkedFilterConfiguration/" + d->currentFilter->id(), 0)) { 302 KisConfig(false).writeEntry<int>("lastBookmarkedFilterConfiguration/" + d->currentFilter->id(), index); 303 } 304 } 305 } 306 editConfigurations()307 void KisFilterSelectorWidget::editConfigurations() 308 { 309 KisSerializableConfigurationSP config = 310 d->currentFilterConfigurationWidget ? d->currentFilterConfigurationWidget->configuration() : 0; 311 KisBookmarkedConfigurationsEditor editor(this, d->currentBookmarkedFilterConfigurationsModel, config); 312 editor.exec(); 313 } 314 update()315 void KisFilterSelectorWidget::update() 316 { 317 d->uiFilterSelector.filtersSelector->setVisible(d->showFilterGallery); 318 if (d->showFilterGallery) { 319 setMinimumWidth(qMax(sizeHint().width(), 700)); 320 d->uiFilterSelector.scrollArea->setMinimumHeight(400); 321 setMinimumHeight(d->uiFilterSelector.verticalLayout->sizeHint().height()); 322 if (d->currentFilter) { 323 bool v = d->uiFilterSelector.filtersSelector->blockSignals(true); 324 d->uiFilterSelector.filtersSelector->setCurrentIndex(d->filtersModel->indexForFilter(d->currentFilter->id())); 325 d->uiFilterSelector.filtersSelector->blockSignals(v); 326 } 327 } 328 else { 329 if (d->currentCentralWidget) { 330 d->uiFilterSelector.scrollArea->setMinimumHeight(qMin(400, d->currentCentralWidget->sizeHint().height())); 331 } 332 setMinimumSize(d->uiFilterSelector.verticalLayout->sizeHint()); 333 } 334 } 335 configuration()336 KisFilterConfigurationSP KisFilterSelectorWidget::configuration() 337 { 338 if (d->currentFilterConfigurationWidget) { 339 KisFilterConfigurationSP config = dynamic_cast<KisFilterConfiguration*>(d->currentFilterConfigurationWidget->configuration().data()); 340 if (config) { 341 return config; 342 } 343 } else if (d->currentFilter) { 344 return d->currentFilter->defaultConfiguration(); 345 } 346 return 0; 347 348 } 349 setFilterModel(QAbstractItemModel * model)350 void KisFilterTree::setFilterModel(QAbstractItemModel *model) 351 { 352 m_model = model; 353 354 } 355 activateFilter(QModelIndex idx)356 void KisFilterTree::activateFilter(QModelIndex idx) 357 { 358 setModel(m_model); 359 selectionModel()->select(idx, QItemSelectionModel::SelectCurrent); 360 expand(idx); 361 scrollTo(idx); 362 emit activated(idx); 363 } 364 setVisible(bool visible)365 void KisFilterSelectorWidget::setVisible(bool visible) 366 { 367 QWidget::setVisible(visible); 368 if (visible) { 369 update(); 370 } 371 } 372 373