File indexing completed on 2024-12-22 04:15:02
0001 /* 0002 * SPDX-FileCopyrightText: 2021 Mathias Wein <lynx.mw+kde@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-3.0-or-later 0005 */ 0006 0007 #include "WGActionManager.h" 0008 0009 #include "WGColorSelectorDock.h" 0010 #include "WGColorPatches.h" 0011 #include "WGColorPreviewToolTip.h" 0012 #include "WGConfigSelectorTypes.h" 0013 #include "WGMyPaintShadeSelector.h" 0014 #include "WGSelectorPopup.h" 0015 #include "WGSelectorWidgetBase.h" 0016 #include "WGShadeSelector.h" 0017 0018 #include <kis_action.h> 0019 #include <kis_action_manager.h> 0020 #include <kis_canvas2.h> 0021 #include <kis_canvas_resource_provider.h> 0022 #include <kis_display_color_converter.h> 0023 #include <kis_signal_compressor.h> 0024 #include <KisViewManager.h> 0025 #include <KisVisualColorSelector.h> 0026 0027 #include <QVector4D> 0028 0029 WGActionManager::WGActionManager(WGColorSelectorDock *parentDock) 0030 : QObject(parentDock) 0031 , m_docker(parentDock) 0032 , m_displayConfig(new WGSelectorDisplayConfig) 0033 , m_colorTooltip(new WGColorPreviewToolTip) 0034 , m_colorChangeCompressor(new KisSignalCompressor(100 /* ms */, KisSignalCompressor::POSTPONE, this)) 0035 , m_colorModel(new KisVisualColorModel) 0036 { 0037 m_lastUsedColor.setOpacity(quint8(0)); 0038 connect(m_colorChangeCompressor, SIGNAL(timeout()), SLOT(slotUpdateDocker())); 0039 connect(m_colorModel.data(), SIGNAL(sigChannelValuesChanged(QVector4D,quint32)), SLOT(slotChannelValuesChanged())); 0040 connect(WGConfig::notifier(), SIGNAL(configChanged()), SLOT(slotConfigChanged())); 0041 connect(WGConfig::notifier(), SIGNAL(selectorConfigChanged()), SLOT(slotSelectorConfigChanged())); 0042 slotConfigChanged(); 0043 } 0044 0045 WGActionManager::~WGActionManager() 0046 { 0047 delete m_colorSelectorPopup; 0048 delete m_shadeSelectorPopup; 0049 delete m_myPaintSelectorPopup; 0050 delete m_colorHistoryPopup; 0051 } 0052 0053 void WGActionManager::setCanvas(KisCanvas2 *canvas, KisCanvas2 *oldCanvas) 0054 { 0055 Q_UNUSED(oldCanvas); 0056 KisDisplayColorConverter *converter = canvas ? canvas->displayColorConverter() : 0; 0057 m_displayConfig->setDisplayConverter(converter); 0058 if (m_colorSelector) { 0059 m_colorSelector->setDisplayRenderer(m_displayConfig->displayConverter()->displayRendererInterface()); 0060 } 0061 } 0062 0063 void WGActionManager::registerActions(KisViewManager *viewManager) 0064 { 0065 KisActionManager *actionManager = viewManager->actionManager(); 0066 KisAction *action; 0067 action = actionManager->createAction("show_wg_color_selector"); 0068 connect(action, SIGNAL(triggered()), SLOT(slotShowColorSelectorPopup())); 0069 action = actionManager->createAction("show_wg_shade_selector"); 0070 connect(action, SIGNAL(triggered()), SLOT(slotShowShadeSelectorPopup())); 0071 action = actionManager->createAction("show_wg_mypaint_selector"); 0072 connect(action, SIGNAL(triggered()), SLOT(slotShowMyPaintSelectorPopup())); 0073 action = actionManager->createAction("show_wg_color_history"); 0074 connect(action, SIGNAL(triggered()), SLOT(slotShowColorHistoryPopup())); 0075 action = actionManager->createAction("wgcs_lighten_color"); 0076 connect(action, SIGNAL(triggered(bool)), SLOT(slotIncreaseLightness())); 0077 action = actionManager->createAction("wgcs_darken_color"); 0078 connect(action, SIGNAL(triggered(bool)), SLOT(slotDecreaseLightness())); 0079 action = actionManager->createAction("wgcs_increase_saturation"); 0080 connect(action, SIGNAL(triggered(bool)), SLOT(slotIncreaseSaturation())); 0081 action = actionManager->createAction("wgcs_decrease_saturation"); 0082 connect(action, SIGNAL(triggered(bool)), SLOT(slotDecreaseSaturation())); 0083 action = actionManager->createAction("wgcs_shift_hue_clockwise"); 0084 connect(action, SIGNAL(triggered(bool)), SLOT(slotShiftHueCW())); 0085 action = actionManager->createAction("wgcs_shift_hue_counterclockwise"); 0086 connect(action, SIGNAL(triggered(bool)), SLOT(slotShiftHueCCW())); 0087 } 0088 0089 void WGActionManager::setLastUsedColor(const KoColor &col) 0090 { 0091 m_lastUsedColor = col; 0092 } 0093 0094 void WGActionManager::updateWidgetSize(QWidget *widget, int size) 0095 { 0096 QSizePolicy hsp = widget->sizePolicy(); 0097 if (hsp.horizontalPolicy() != QSizePolicy::Fixed) { 0098 widget->setFixedWidth(size); 0099 } else { 0100 widget->setFixedWidth(QWIDGETSIZE_MAX); // looks weird, but that really resets min size to 0... 0101 } 0102 if (hsp.verticalPolicy() != QSizePolicy::Fixed) { 0103 widget->setFixedHeight(size); 0104 } else { 0105 widget->setFixedHeight(QWIDGETSIZE_MAX); 0106 } 0107 } 0108 0109 void WGActionManager::showPopup(WGSelectorPopup *popup) 0110 { 0111 // preparations 0112 m_isSynchronizing = true; 0113 if (m_currentPopup) { 0114 m_currentPopup->hide(); 0115 m_currentPopup = 0; 0116 } 0117 const KisVisualColorModel &dockerModel = m_docker->colorModel(); 0118 m_colorModel->copyState(dockerModel); 0119 m_colorTooltip->setLastUsedColor(m_displayConfig->displayConverter()->toQColor(m_lastUsedColor)); 0120 QColor baseCol = m_displayConfig->displayConverter()->toQColor(m_colorModel->currentColor()); 0121 m_colorTooltip->setCurrentColor(baseCol); 0122 m_colorTooltip->setPreviousColor(baseCol); 0123 m_isSynchronizing = false; 0124 0125 m_currentPopup = popup; 0126 popup->slotShowPopup(); 0127 m_colorTooltip->show(popup); 0128 } 0129 0130 void WGActionManager::loadColorSelectorSettings(WGConfig::Accessor &cfg) 0131 { 0132 m_colorSelector->setRenderMode(cfg.get(WGConfig::selectorRenderMode)); 0133 slotSelectorConfigChanged(); 0134 } 0135 0136 void WGActionManager::modifyHSX(int channel, float amount) 0137 { 0138 if (channel < 0 || channel > 2) { 0139 return; 0140 } 0141 if (m_docker->colorModel().isHSXModel()) { 0142 QVector4D channelValues = m_docker->colorModel().channelValues(); 0143 channelValues[channel] = qBound(0.0f, channelValues[channel] + amount, 1.0f); 0144 m_docker->setChannelValues(channelValues); 0145 } 0146 } 0147 0148 void WGActionManager::slotConfigChanged() 0149 { 0150 WGConfig::Accessor cfg; 0151 int popupSize = cfg.get(WGConfig::popupSize); 0152 bool proofColors = cfg.get(WGConfig::proofToPaintingColors); 0153 m_displayConfig->setPreviewInPaintingCS(proofColors); 0154 0155 if (m_colorSelector) { 0156 loadColorSelectorSettings(cfg); 0157 m_colorSelector->setProofColors(proofColors); 0158 updateWidgetSize(m_colorSelector, popupSize); 0159 } 0160 if (m_shadeSelector) { 0161 m_shadeSelector->updateSettings(); 0162 updateWidgetSize(m_shadeSelector, popupSize); 0163 } 0164 if (m_myPaintSelector) { 0165 m_myPaintSelector->updateSettings(); 0166 updateWidgetSize(m_myPaintSelector, popupSize); 0167 } 0168 if (m_colorHistoryPopup) { 0169 WGSelectorWidgetBase *selector = m_colorHistoryPopup->selectorWidget(); 0170 KIS_ASSERT(selector); 0171 selector->updateSettings(); 0172 updateWidgetSize(selector, popupSize); 0173 } 0174 } 0175 0176 void WGActionManager::slotSelectorConfigChanged() 0177 { 0178 if (m_colorSelector) { 0179 WGConfig::Accessor cfg; 0180 KisColorSelectorConfiguration selectorConf = cfg.colorSelectorConfiguration(); 0181 m_colorSelector->setConfiguration(&selectorConf); 0182 } 0183 } 0184 0185 void WGActionManager::slotPopupClosed(WGSelectorPopup *popup) 0186 { 0187 if (popup == m_currentPopup) { 0188 m_currentPopup = 0; 0189 m_colorTooltip->hide(); 0190 } 0191 } 0192 0193 void WGActionManager::slotShowColorSelectorPopup() 0194 { 0195 if (!m_colorSelectorPopup) { 0196 WGConfig::Accessor cfg; 0197 m_colorSelectorPopup = new WGSelectorPopup(); 0198 m_colorSelector = new KisVisualColorSelector(m_colorSelectorPopup, m_colorModel); 0199 m_colorSelector->setDisplayRenderer(m_displayConfig->displayConverter()->displayRendererInterface()); 0200 updateWidgetSize(m_colorSelector, cfg.get(WGConfig::popupSize)); 0201 m_colorSelectorPopup->setSelectorWidget(m_colorSelector); 0202 connect(m_colorSelectorPopup, SIGNAL(sigPopupClosed(WGSelectorPopup*)), 0203 SLOT(slotPopupClosed(WGSelectorPopup*))); 0204 connect(m_colorSelector, SIGNAL(sigInteraction(bool)), SLOT(slotColorInteraction(bool))); 0205 0206 loadColorSelectorSettings(cfg); 0207 } 0208 0209 // update gamut mask 0210 KisCanvas2 *canvas = qobject_cast<KisCanvas2*>(m_docker->observedCanvas()); 0211 if (canvas) { 0212 KisCanvasResourceProvider *resourceProvider = canvas->imageView()->resourceProvider(); 0213 if (resourceProvider->gamutMaskActive()) { 0214 m_colorSelector->slotGamutMaskChanged(resourceProvider->currentGamutMask()); 0215 } 0216 else { 0217 m_colorSelector->slotGamutMaskUnset(); 0218 } 0219 } 0220 0221 showPopup(m_colorSelectorPopup); 0222 } 0223 0224 void WGActionManager::slotShowShadeSelectorPopup() 0225 { 0226 if (!m_shadeSelectorPopup) { 0227 m_shadeSelectorPopup = new WGSelectorPopup(); 0228 m_shadeSelector = new WGShadeSelector(m_displayConfig, m_colorModel, m_shadeSelectorPopup); 0229 m_shadeSelector->updateSettings(); 0230 updateWidgetSize(m_shadeSelector, WGConfig::Accessor().get(WGConfig::popupSize)); 0231 m_shadeSelectorPopup->setSelectorWidget(m_shadeSelector); 0232 connect(m_shadeSelectorPopup, SIGNAL(sigPopupClosed(WGSelectorPopup*)), 0233 SLOT(slotPopupClosed(WGSelectorPopup*))); 0234 connect(m_shadeSelector, SIGNAL(sigColorInteraction(bool)), SLOT(slotColorInteraction(bool))); 0235 } 0236 0237 showPopup(m_shadeSelectorPopup); 0238 } 0239 0240 void WGActionManager::slotShowMyPaintSelectorPopup() 0241 { 0242 if (!m_myPaintSelectorPopup) { 0243 m_myPaintSelectorPopup = new WGSelectorPopup(); 0244 m_myPaintSelector = new WGMyPaintShadeSelector(m_displayConfig, m_myPaintSelectorPopup, 0245 WGSelectorWidgetBase::PopupMode); 0246 updateWidgetSize(m_myPaintSelector, WGConfig::Accessor().get(WGConfig::popupSize)); 0247 m_myPaintSelector->setModel(m_colorModel); 0248 m_myPaintSelectorPopup->setSelectorWidget(m_myPaintSelector); 0249 connect(m_myPaintSelectorPopup, SIGNAL(sigPopupClosed(WGSelectorPopup*)), 0250 SLOT(slotPopupClosed(WGSelectorPopup*))); 0251 connect(m_myPaintSelector, SIGNAL(sigColorInteraction(bool)), SLOT(slotColorInteraction(bool))); 0252 } 0253 0254 showPopup(m_myPaintSelectorPopup); 0255 } 0256 0257 void WGActionManager::slotShowColorHistoryPopup() 0258 { 0259 if (!m_colorHistoryPopup) { 0260 m_colorHistoryPopup = new WGSelectorPopup; 0261 WGColorPatches *history = new WGColorPatches(m_displayConfig, m_docker->colorHistory()); 0262 history->setUiMode(WGSelectorWidgetBase::PopupMode); 0263 history->setPreset(WGColorPatches::History); 0264 history->updateSettings(); 0265 updateWidgetSize(history, WGConfig::Accessor().get(WGConfig::popupSize)); 0266 m_colorHistoryPopup->setSelectorWidget(history); 0267 connect(m_colorHistoryPopup, SIGNAL(sigPopupClosed(WGSelectorPopup*)), 0268 SLOT(slotPopupClosed(WGSelectorPopup*))); 0269 connect(history, SIGNAL(sigColorInteraction(bool)), SLOT(slotColorPatchInteraction(bool))); 0270 connect(history, SIGNAL(sigColorChanged(KoColor)), SLOT(slotColorSelected(KoColor))); 0271 } 0272 showPopup(m_colorHistoryPopup); 0273 } 0274 0275 void WGActionManager::slotIncreaseLightness() 0276 { 0277 modifyHSX(2, 0.1f); 0278 } 0279 0280 void WGActionManager::slotDecreaseLightness() 0281 { 0282 modifyHSX(2, -0.1f); 0283 } 0284 0285 void WGActionManager::slotIncreaseSaturation() 0286 { 0287 modifyHSX(1, 0.1f); 0288 } 0289 0290 void WGActionManager::slotDecreaseSaturation() 0291 { 0292 modifyHSX(1, -0.1f); 0293 } 0294 0295 void WGActionManager::slotShiftHueCW() 0296 { 0297 modifyHSX(0, 0.1f); 0298 } 0299 0300 void WGActionManager::slotShiftHueCCW() 0301 { 0302 modifyHSX(0, -0.1f); 0303 } 0304 0305 void WGActionManager::slotChannelValuesChanged() 0306 { 0307 // FIXME: KoColorDisplayRendererInterface's displayConfigurationChanged() 0308 // signal (e.g. layer switches) makes the color model emit new channel values 0309 // and this would overwrite the color resources with outdated data! 0310 // so make sure a popup is actually active 0311 if (!m_isSynchronizing && m_currentPopup) { 0312 m_colorChangeCompressor->start(); 0313 QColor color = m_displayConfig->displayConverter()->toQColor(m_colorModel->currentColor()); 0314 m_colorTooltip->setCurrentColor(color); 0315 } 0316 } 0317 0318 void WGActionManager::slotColorInteraction(bool active) 0319 { 0320 if (active) { 0321 QColor baseCol = m_displayConfig->displayConverter()->toQColor(m_colorModel->currentColor()); 0322 m_colorTooltip->setCurrentColor(baseCol); 0323 m_colorTooltip->setPreviousColor(baseCol); 0324 } 0325 } 0326 0327 void WGActionManager::slotColorPatchInteraction(bool active) 0328 { 0329 KoCanvasBase *canvas = m_docker->observedCanvas(); 0330 if (active && canvas) { 0331 KoColor fgColor = canvas->resourceManager()->foregroundColor(); 0332 QColor baseCol = m_docker->displayColorConverter()->toQColor(fgColor); 0333 m_colorTooltip->setCurrentColor(baseCol); 0334 m_colorTooltip->setPreviousColor(baseCol); 0335 } 0336 } 0337 0338 /* Directly set canvas resource for color history, 0339 */ 0340 void WGActionManager::slotColorSelected(const KoColor &color) 0341 { 0342 // CAVEAT: currently, the color history does not allow background color setting 0343 if (!m_docker->observedCanvas()) { 0344 return; 0345 } 0346 m_docker->observedCanvas()->resourceManager()->setForegroundColor(color); 0347 QColor previewCol = m_docker->displayColorConverter()->toQColor(color); 0348 m_colorTooltip->setCurrentColor(previewCol); 0349 0350 } 0351 0352 void WGActionManager::slotUpdateDocker() 0353 { 0354 m_docker->setChannelValues(m_colorModel->channelValues()); 0355 }