diff --git a/libs/widgets/KisDlgInternalColorSelector.cpp b/libs/widgets/KisDlgInternalColorSelector.cpp index e57a44952f..4281ca0549 100644 --- a/libs/widgets/KisDlgInternalColorSelector.cpp +++ b/libs/widgets/KisDlgInternalColorSelector.cpp @@ -1,359 +1,357 @@ /* * Copyright (C) Wolthera van Hovell tot Westerflier , (C) 2016 * * 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 #include #include #include #include #include #include #include #include "KoColorSpaceRegistry.h" #include #include #include #include #include #include #include "kis_signal_compressor.h" #include "KoColorDisplayRendererInterface.h" #include "kis_spinbox_color_selector.h" #include "KisDlgInternalColorSelector.h" #include "ui_WdgDlgInternalColorSelector.h" #include "kis_config_notifier.h" #include "kis_color_input.h" #include "kis_icon_utils.h" #include "KisSqueezedComboBox.h" #include "ui_WdgDlgInternalColorSelector.h" std::function KisDlgInternalColorSelector::s_screenColorPickerFactory = 0; struct KisDlgInternalColorSelector::Private { bool allowUpdates = true; KoColor currentColor; KoColor previousColor; KoColor sRGB = KoColor(KoColorSpaceRegistry::instance()->rgb8()); const KoColorSpace *currentColorSpace; bool lockUsedCS = false; bool chooseAlpha = false; KisSignalCompressor *compressColorChanges; const KoColorDisplayRendererInterface *displayRenderer; KisHexColorInput *hexColorInput = 0; KisPaletteModel *paletteModel = 0; KisPaletteListWidget *paletteChooser = 0; KisScreenColorPickerBase *screenColorPicker = 0; }; KisDlgInternalColorSelector::KisDlgInternalColorSelector(QWidget *parent, KoColor color, Config config, const QString &caption, const KoColorDisplayRendererInterface *displayRenderer) - : KisPopover(parent, KisPopover::DOWN) + : KisPopover(parent, KisPopover::RIGHT) , m_d(new Private) { setModal(config.modal); setFocusPolicy(Qt::ClickFocus); QWidget *panelContents = new QWidget(this); m_ui = new Ui_WdgDlgInternalColorSelector(); m_ui->setupUi(panelContents); this->layout()->addWidget(panelContents); setWindowTitle(caption); setHeaderText(caption); - connect(this, &KisDlgInternalColorSelector::close, this, &KisDlgInternalColorSelector::accept); - m_d->currentColor = color; m_d->currentColorSpace = m_d->currentColor.colorSpace(); m_d->displayRenderer = displayRenderer; m_ui->spinboxselector->slotSetColor(color); connect(m_ui->spinboxselector, SIGNAL(sigNewColor(KoColor)), this, SLOT(slotColorUpdated(KoColor))); m_ui->visualSelector->slotSetColor(color); m_ui->visualSelector->setDisplayRenderer(displayRenderer); m_ui->visualSelector->setConfig(false, config.modal); if (config.visualColorSelector) { connect(m_ui->visualSelector, SIGNAL(sigNewColor(KoColor)), this, SLOT(slotColorUpdated(KoColor))); connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), m_ui->visualSelector, SLOT(configurationChanged())); } else { m_ui->visualSelector->hide(); } m_d->paletteChooser = new KisPaletteListWidget(panelContents); m_d->paletteModel = new KisPaletteModel(panelContents); m_ui->bnPaletteChooser->setIcon(KisIconUtils::loadIcon("hi16-palette_library")); m_ui->paletteBox->setPaletteModel(m_d->paletteModel); m_ui->paletteBox->setDisplayRenderer(displayRenderer); m_ui->cmbNameList->setCompanionView(m_ui->paletteBox); connect(m_d->paletteChooser, SIGNAL(sigPaletteSelected(KoColorSet*)), this, SLOT(slotChangePalette(KoColorSet*))); connect(m_ui->cmbNameList, SIGNAL(sigColorSelected(KoColor)), SLOT(slotColorUpdated(KoColor))); // For some bizare reason, the modal dialog doesn't like having the colorset set, so let's not. if (config.paletteBox) { //TODO: Add disable signal as well. Might be not necessary...? KConfigGroup cfg(KSharedConfig::openConfig()->group("")); QString paletteName = cfg.readEntry("internal_selector_active_color_set", QString()); KoResourceServer* rServer = KoResourceServerProvider::instance()->paletteServer(); KoColorSet *savedPal = rServer->resourceByName(paletteName); if (savedPal) { this->slotChangePalette(savedPal); } else { if (rServer->resources().count()) { savedPal = rServer->resources().first(); if (savedPal) { this->slotChangePalette(savedPal); } } } connect(m_ui->paletteBox, SIGNAL(sigColorSelected(KoColor)), this, SLOT(slotColorUpdated(KoColor))); m_ui->bnPaletteChooser->setPopupWidget(m_d->paletteChooser); } else { m_ui->paletteBox->setEnabled(false); m_ui->cmbNameList->setEnabled(false); m_ui->bnPaletteChooser->setEnabled(false); } if (config.prevNextButtons) { m_ui->currentColor->setColor(m_d->currentColor); m_ui->currentColor->setDisplayRenderer(displayRenderer); m_ui->previousColor->setColor(m_d->currentColor); m_ui->previousColor->setDisplayRenderer(displayRenderer); connect(m_ui->previousColor, SIGNAL(triggered(KoColorPatch*)), SLOT(slotSetColorFromPatch(KoColorPatch*))); } else { m_ui->currentColor->hide(); m_ui->previousColor->hide(); } if (config.hexInput) { m_d->sRGB.fromKoColor(m_d->currentColor); m_d->hexColorInput = new KisHexColorInput(panelContents, &m_d->sRGB); m_d->hexColorInput->update(); connect(m_d->hexColorInput, SIGNAL(updated()), SLOT(slotSetColorFromHex())); m_ui->rightPane->addWidget(m_d->hexColorInput); m_d->hexColorInput->setToolTip(i18n("This is a hexcode input, for webcolors. It can only get colors in the sRGB space.")); } // KisScreenColorPicker is in the kritaui module, so dependency inversion is used to access it. m_ui->screenColorPickerWidget->setLayout(new QHBoxLayout(m_ui->screenColorPickerWidget)); if (s_screenColorPickerFactory) { m_d->screenColorPicker = s_screenColorPickerFactory(m_ui->screenColorPickerWidget); m_ui->screenColorPickerWidget->layout()->addWidget(m_d->screenColorPicker); if (config.screenColorPicker) { connect(m_d->screenColorPicker, SIGNAL(sigNewColorPicked(KoColor)),this, SLOT(slotColorUpdated(KoColor))); } else { m_d->screenColorPicker->hide(); } } m_d->compressColorChanges = new KisSignalCompressor(100 /* ms */, KisSignalCompressor::POSTPONE, this); connect(m_d->compressColorChanges, SIGNAL(timeout()), this, SLOT(endUpdateWithNewColor())); connect(this, SIGNAL(finished(int)), SLOT(slotFinishUp())); } KisDlgInternalColorSelector::~KisDlgInternalColorSelector() { delete m_ui; } void KisDlgInternalColorSelector::slotColorUpdated(KoColor newColor) { // not-so-nice solution: if someone calls this slot directly and that code was // triggered by our compressor signal, our compressor is technically the sender()! if (sender() == m_d->compressColorChanges) { return; } // Do not accept external updates while a color update emit is pending; // Note: Assumes external updates only come from parent(), a separate slot might be better if (m_d->allowUpdates || (QObject::sender() && QObject::sender() != this->parent())) { // Enforce palette colors KConfigGroup group(KSharedConfig::openConfig(), ""); if (group.readEntry("colorsettings/forcepalettecolors", false)) { newColor = m_ui->paletteBox->closestColor(newColor); } if (m_d->lockUsedCS){ newColor.convertTo(m_d->currentColorSpace); m_d->currentColor = newColor; } else { m_d->currentColor = newColor; } updateAllElements(QObject::sender()); } } void KisDlgInternalColorSelector::slotSetColorFromPatch(KoColorPatch *patch) { slotColorUpdated(patch->color()); } void KisDlgInternalColorSelector::colorSpaceChanged(const KoColorSpace *cs) { if (cs == m_d->currentColorSpace) { return; } m_d->currentColorSpace = KoColorSpaceRegistry::instance()->colorSpace(cs->colorModelId().id(), cs->colorDepthId().id(), cs->profile()); m_ui->spinboxselector->slotSetColorSpace(m_d->currentColorSpace); m_ui->visualSelector->slotsetColorSpace(m_d->currentColorSpace); } void KisDlgInternalColorSelector::lockUsedColorSpace(const KoColorSpace *cs) { colorSpaceChanged(cs); if (m_d->currentColor.colorSpace() != m_d->currentColorSpace) { m_d->currentColor.convertTo(m_d->currentColorSpace); } m_d->lockUsedCS = true; } void KisDlgInternalColorSelector::setDisplayRenderer(const KoColorDisplayRendererInterface *displayRenderer) { if (displayRenderer) { m_d->displayRenderer = displayRenderer; m_ui->visualSelector->setDisplayRenderer(displayRenderer); m_ui->currentColor->setDisplayRenderer(displayRenderer); m_ui->previousColor->setDisplayRenderer(displayRenderer); m_ui->paletteBox->setDisplayRenderer(displayRenderer); } else { m_d->displayRenderer = KoDumbColorDisplayRenderer::instance(); } } KoColor KisDlgInternalColorSelector::getModalColorDialog(const KoColor color, QWidget* parent, QString caption, QPoint position) { Config config = Config(); KisDlgInternalColorSelector dialog(parent, color, config, caption); dialog.setPreviousColor(color); dialog.setOrigin(position); dialog.exec(); return dialog.getCurrentColor(); } KoColor KisDlgInternalColorSelector::getCurrentColor() { return m_d->currentColor; } void KisDlgInternalColorSelector::chooseAlpha(bool chooseAlpha) { m_d->chooseAlpha = chooseAlpha; } void KisDlgInternalColorSelector::slotConfigurationChanged() { //m_d->canvas->displayColorConverter()-> //slotColorSpaceChanged(m_d->canvas->image()->colorSpace()); } void KisDlgInternalColorSelector::setPreviousColor(KoColor c) { m_d->previousColor = c; } void KisDlgInternalColorSelector::reject() { slotColorUpdated(m_d->previousColor); QDialog::reject(); } void KisDlgInternalColorSelector::updateAllElements(QObject *source) { //update everything!!! if (source != m_ui->spinboxselector) { m_ui->spinboxselector->slotSetColor(m_d->currentColor); } if (source != m_ui->visualSelector) { m_ui->visualSelector->slotSetColor(m_d->currentColor); } if (source != m_d->hexColorInput) { m_d->sRGB.fromKoColor(m_d->currentColor); m_d->hexColorInput->update(); } if (source != m_ui->paletteBox) { m_ui->paletteBox->selectClosestColor(m_d->currentColor); } m_ui->previousColor->setColor(m_d->previousColor); m_ui->currentColor->setColor(m_d->currentColor); if (source && source != this->parent()) { m_d->allowUpdates = false; m_d->compressColorChanges->start(); } if (m_d->screenColorPicker) { m_d->screenColorPicker->updateIcons(); } } void KisDlgInternalColorSelector::endUpdateWithNewColor() { emit signalForegroundColorChosen(m_d->currentColor); m_d->allowUpdates = true; } void KisDlgInternalColorSelector::focusInEvent(QFocusEvent *) { //setPreviousColor(); } void KisDlgInternalColorSelector::slotFinishUp() { setPreviousColor(m_d->currentColor); KConfigGroup cfg(KSharedConfig::openConfig()->group("")); if (m_d->paletteModel) { if (m_d->paletteModel->colorSet()) { cfg.writeEntry("internal_selector_active_color_set", m_d->paletteModel->colorSet()->name()); } } } void KisDlgInternalColorSelector::slotSetColorFromHex() { slotColorUpdated(m_d->sRGB); } void KisDlgInternalColorSelector::slotChangePalette(KoColorSet *set) { if (!set) { return; } m_d->paletteModel->setPalette(set); } void KisDlgInternalColorSelector::showEvent(QShowEvent *event) { updateAllElements(0); QDialog::showEvent(event); } diff --git a/libs/widgetutils/KisPopover.cpp b/libs/widgetutils/KisPopover.cpp index 9dd6d4dcb0..a7afd46a27 100644 --- a/libs/widgetutils/KisPopover.cpp +++ b/libs/widgetutils/KisPopover.cpp @@ -1,140 +1,178 @@ #include "KisPopover.h" #include #include #include #include #include #include #include #include #include #include #include "kis_icon_utils.h" KisPopover::KisPopover(QWidget *parent) : QDialog(parent, Qt::FramelessWindowHint | Qt::Popup) { setModal(false); setMinimumSize(250, 50); QVBoxLayout* layout = new QVBoxLayout; setLayout(layout); QToolBar* toolbar = new QToolBar; denyAction = toolbar->addAction(KisIconUtils::loadIcon("edit-undo"), "Revert"); denyAction->connect(denyAction, &QAction::triggered, this, &KisPopover::reject); header = new QLabel(""); header->setAlignment(Qt::AlignCenter); header->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); toolbar->addWidget(header); acceptAction = toolbar->addAction(KisIconUtils::loadIcon("go-next"), "Apply"); acceptAction->connect(acceptAction, &QAction::triggered, this, &KisPopover::accept); layout->addWidget(toolbar); //TEMP -- Color settings only necessary to visualize. There should be better ways to handle the visualization. QPalette pal = palette(); QColor color = pal.color(QPalette::Window); QBrush brush(color.lighter(120)); pal.setBrush(QPalette::Window, brush); setPalette(pal); connect(this, &KisPopover::originChanged, this, &KisPopover::recalculatePosition); connect(this, &KisPopover::unfoldDirectionChanged, this, &KisPopover::recalculatePosition); + connect(this, &KisPopover::windowTitleChanged, this, &KisPopover::setHeaderText); } KisPopover::KisPopover(QWidget *parent, UnfoldDirections directions) : KisPopover(parent) { this->unfoldingDirection = directions; } KisPopover::~KisPopover() { } QPointer KisPopover::create(QWidget* parent, QPoint pos){ QSize windowSize = parent->size(); UnfoldDirections bestUnfoldDirection = discernBestUnfoldDirection(windowSize, pos); return KisPopover::create(parent, pos, bestUnfoldDirection); } QPointer KisPopover::create(QWidget* parent, QPoint pos, UnfoldDirections directions = UnfoldDirection::NONE){ KisPopover* popover = new KisPopover(parent); popover->setOrigin(pos); popover->setUnfoldDirection(directions); popover->setAttribute(Qt::WA_DeleteOnClose); //todo: perhaps use a smart pointer instead to try to have better auto clean situations? return popover; } KisPopover::UnfoldDirections KisPopover::discernBestUnfoldDirection(QSize mainWindowSize, QPoint desiredOpenPosition){ return UnfoldDirection::DOWN; } void KisPopover::setAcceptable(bool state){ if (acceptAction != nullptr){ acceptAction->setVisible(state); } } void KisPopover::setCancelable(bool state){ if (denyAction != nullptr){ denyAction->setVisible(state); } } void KisPopover::setHeaderText(QString title){ if (header != nullptr){ header->setText(title); } } void KisPopover::setUnfoldDirection(KisPopover::UnfoldDirections directions){ this->unfoldingDirection = directions; emit unfoldDirectionChanged(); } void KisPopover::setOrigin( QPoint newOrigin ){ this->origin = newOrigin; emit originChanged(); } void KisPopover::resizeEvent(QResizeEvent *revent){ QRect windowSize = this->rect(); const int stemHeight = 15; const int stemWidth = stemHeight * 2; QPolygon renderPolygon; switch (this->unfoldingDirection) { case UnfoldDirection::DOWN: - setStyleSheet(QString("KisPopover { margin-top: %1px; }").arg(stemHeight)); + //setStyleSheet(QString("KisPopover { margin-top: %1px; }").arg(stemHeight)); renderPolygon << QPoint(windowSize.x(), windowSize.y() + stemHeight) << QPoint(windowSize.x() + windowSize.width()/2 - stemWidth/2, windowSize.y() + stemHeight) << QPoint(windowSize.x() + windowSize.width()/2, windowSize.y()) << QPoint(windowSize.x() + windowSize.width()/2 + stemWidth/2, windowSize.y() + stemHeight) << QPoint(windowSize.x() + windowSize.width(), windowSize.y() + stemHeight) << QPoint(windowSize.x() + windowSize.width(), windowSize.y() + windowSize.height() ) << QPoint(windowSize.x(), windowSize.y() + windowSize.height()); break; + case UnfoldDirection::UP: + //setStyleSheet(QString("KisPopover { margin-bottom: %1px; }").arg(stemHeight)); + renderPolygon << QPoint(windowSize.x(), windowSize.y()) + << QPoint(windowSize.x() + windowSize.width(), windowSize.y()) + << QPoint(windowSize.x() + windowSize.width(), windowSize.y() + windowSize.height() - stemHeight ) + << QPoint(windowSize.x() + windowSize.width()/2 + stemWidth/2, windowSize.y() + windowSize.height() - stemHeight) + << QPoint(windowSize.x() + windowSize.width()/2, windowSize.y() + windowSize.height()) + << QPoint(windowSize.x() + windowSize.width()/2 - stemWidth/2, windowSize.y() + windowSize.height() - stemHeight) + << QPoint(windowSize.x(), windowSize.y() + windowSize.height() - stemHeight); + break; + case UnfoldDirection::LEFT: + //setStyleSheet(QString("KisPopover { margin-right: %1px; }").arg(stemHeight)); + renderPolygon << QPoint(windowSize.x(), windowSize.y()) + << QPoint(windowSize.x() + windowSize.width()-stemHeight, windowSize.y()) + << QPoint(windowSize.x() + windowSize.width()-stemHeight, windowSize.y() + windowSize.height()/2 - stemWidth/2) + << QPoint(windowSize.x() + windowSize.width(), windowSize.y() + windowSize.height()/2) + << QPoint(windowSize.x() + windowSize.width()-stemHeight, windowSize.y() + windowSize.height()/2 + stemWidth/2) + << QPoint(windowSize.x() + windowSize.width()-stemHeight, windowSize.y() + windowSize.height() ) + << QPoint(windowSize.x(), windowSize.y() + windowSize.height()); + break; + case UnfoldDirection::RIGHT: + renderPolygon << QPoint(windowSize.x() + stemHeight, windowSize.y()) + << QPoint(windowSize.x() + windowSize.width(), windowSize.y()) + << QPoint(windowSize.x() + windowSize.width(), windowSize.y() + windowSize.height()) + << QPoint(windowSize.x() + stemHeight, windowSize.y() + windowSize.height()) + << QPoint(windowSize.x() + stemHeight, windowSize.y() + windowSize.height()/2 + stemWidth/2) + << QPoint(windowSize.x(), windowSize.y() + windowSize.height()/2) + << QPoint(windowSize.x() + stemHeight, windowSize.y() + windowSize.height()/2 - stemWidth/2); + break; default: renderPolygon = QPolygon(windowSize); break; } QRegion mask(renderPolygon); setMask(mask); emit recalculatePosition(); } void KisPopover::recalculatePosition(){ QPoint offset = QPoint(); switch(this->unfoldingDirection) { case UnfoldDirection::DOWN: offset.setX( -1 * this->size().width() / 2 ); break; + case UnfoldDirection::UP: + offset.setX(-1 * this->size().width() / 2); + offset.setY(-1 * this->size().height()); + case UnfoldDirection::LEFT: + offset.setX(-1 * this->size().width()); + offset.setY( -1 * this->size().height() / 2); + case UnfoldDirection::RIGHT: + offset.setY(-1 * this->size().height() / 2); default: break; } this->move(this->origin + offset); } diff --git a/libs/widgetutils/KisPopover.h b/libs/widgetutils/KisPopover.h index 242c7d991e..2f5c160c0e 100644 --- a/libs/widgetutils/KisPopover.h +++ b/libs/widgetutils/KisPopover.h @@ -1,61 +1,60 @@ #ifndef KPOPOVER_H #define KPOPOVER_H #include "kritawidgetutils_export.h" #include #include #include #include +#include class KRITAWIDGETUTILS_EXPORT KisPopover : public QDialog { Q_OBJECT public: enum UnfoldDirection { NONE = 0, UP = 1 << 0, DOWN = 1 << 1, LEFT = 1 << 2, RIGHT = 1 << 3 }; Q_DECLARE_FLAGS(UnfoldDirections, UnfoldDirection); private: - UnfoldDirections unfoldingDirection = UnfoldDirection::DOWN; + UnfoldDirections unfoldingDirection = UnfoldDirection::UP; QPointer acceptAction; QPointer denyAction; QPointer header; QPoint origin; public: KisPopover(QWidget *parent); KisPopover(QWidget *parent, UnfoldDirections directions); ~KisPopover(); static QPointer create(QWidget* mainWindow, QPoint pos); static QPointer create(QWidget* mainWindow, QPoint pos, UnfoldDirections directions); static UnfoldDirections discernBestUnfoldDirection(QSize mainWindowSize, QPoint desiredOpenPosition); - //QPoint calculateBubbleOffset(QPoint origin); - void setAcceptable(bool state); void setCancelable(bool state); void setHeaderText(QString description); void setUnfoldDirection(UnfoldDirections directions); void setOrigin( QPoint newOrigin ); protected: void resizeEvent(QResizeEvent* revent) override; Q_SIGNALS: void originChanged(); void unfoldDirectionChanged(); protected Q_SLOTS: void recalculatePosition(); }; Q_DECLARE_OPERATORS_FOR_FLAGS(KisPopover::UnfoldDirections) #endif // KPOPOVER_H