tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / cui / source / dialogs / colorpicker.cxx
blob6ca351c883d41194d986bb469d1e0253c54270a5
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/uno/XComponentContext.hpp>
21 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
22 #include <com/sun/star/ui/dialogs/XAsynchronousExecutableDialog.hpp>
23 #include <com/sun/star/beans/XPropertyAccess.hpp>
24 #include <com/sun/star/lang/XInitialization.hpp>
25 #include <com/sun/star/lang/XServiceInfo.hpp>
26 #include <com/sun/star/awt/XWindow.hpp>
28 #include <comphelper/propertyvalue.hxx>
29 #include <comphelper/compbase.hxx>
30 #include <cppuhelper/supportsservice.hxx>
31 #include <vcl/customweld.hxx>
32 #include <vcl/event.hxx>
33 #include <vcl/svapp.hxx>
34 #include <vcl/virdev.hxx>
35 #include <vcl/weld.hxx>
36 #include <sfx2/basedlgs.hxx>
37 #include <svx/hexcolorcontrol.hxx>
38 #include <basegfx/color/bcolortools.hxx>
39 #include <cmath>
40 #include <o3tl/typed_flags_set.hxx>
42 using namespace ::com::sun::star::uno;
43 using namespace ::com::sun::star::lang;
44 using namespace ::com::sun::star::ui::dialogs;
45 using namespace ::com::sun::star::beans;
46 using namespace ::basegfx;
48 namespace {
50 enum class UpdateFlags
52 NONE = 0x00,
53 RGB = 0x01,
54 CMYK = 0x02,
55 HSB = 0x04,
56 ColorChooser = 0x08,
57 ColorSlider = 0x10,
58 Hex = 0x20,
59 All = 0x3f,
64 namespace o3tl {
65 template<> struct typed_flags<UpdateFlags> : is_typed_flags<UpdateFlags, 0x3f> {};
69 namespace cui
72 namespace {
74 enum class ColorComponent {
75 Red,
76 Green,
77 Blue,
78 Hue,
79 Saturation,
80 Brightness,
81 Cyan,
82 Yellow,
83 Magenta,
84 Key,
89 // color space conversion helpers
91 static void RGBtoHSV( double dR, double dG, double dB, double& dH, double& dS, double& dV )
93 BColor result = basegfx::utils::rgb2hsv( BColor( dR, dG, dB ) );
95 dH = result.getX();
96 dS = result.getY();
97 dV = result.getZ();
100 static void HSVtoRGB(double dH, double dS, double dV, double& dR, double& dG, double& dB )
102 BColor result = basegfx::utils::hsv2rgb( BColor( dH, dS, dV ) );
104 dR = result.getRed();
105 dG = result.getGreen();
106 dB = result.getBlue();
109 // CMYK values from 0 to 1
110 static void CMYKtoRGB( double fCyan, double fMagenta, double fYellow, double fKey, double& dR, double& dG, double& dB )
112 fCyan = (fCyan * ( 1.0 - fKey )) + fKey;
113 fMagenta = (fMagenta * ( 1.0 - fKey )) + fKey;
114 fYellow = (fYellow * ( 1.0 - fKey )) + fKey;
116 dR = std::clamp( 1.0 - fCyan, 0.0, 1.0 );
117 dG = std::clamp( 1.0 - fMagenta, 0.0, 1.0 );
118 dB = std::clamp( 1.0 - fYellow, 0.0, 1.0 );
121 // CMY results from 0 to 1
122 static void RGBtoCMYK( double dR, double dG, double dB, double& fCyan, double& fMagenta, double& fYellow, double& fKey )
124 fCyan = 1 - dR;
125 fMagenta = 1 - dG;
126 fYellow = 1 - dB;
128 //CMYK and CMY values from 0 to 1
129 fKey = 1.0;
130 if( fCyan < fKey ) fKey = fCyan;
131 if( fMagenta < fKey ) fKey = fMagenta;
132 if( fYellow < fKey ) fKey = fYellow;
134 if( fKey >= 1.0 )
136 //Black
137 fCyan = 0.0;
138 fMagenta = 0.0;
139 fYellow = 0.0;
141 else
143 fCyan = ( fCyan - fKey ) / ( 1.0 - fKey );
144 fMagenta = ( fMagenta - fKey ) / ( 1.0 - fKey );
145 fYellow = ( fYellow - fKey ) / ( 1.0 - fKey );
149 namespace {
151 class ColorPreviewControl : public weld::CustomWidgetController
153 private:
154 Color m_aColor;
156 virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) override;
157 public:
158 ColorPreviewControl()
162 virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override
164 CustomWidgetController::SetDrawingArea(pDrawingArea);
165 pDrawingArea->set_size_request(pDrawingArea->get_approximate_digit_width() * 10,
166 pDrawingArea->get_text_height() * 2);
169 void SetColor(const Color& rCol)
171 if (rCol != m_aColor)
173 m_aColor = rCol;
174 Invalidate();
181 void ColorPreviewControl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
183 rRenderContext.SetFillColor(m_aColor);
184 rRenderContext.SetLineColor(m_aColor);
185 rRenderContext.DrawRect(tools::Rectangle(Point(0, 0), GetOutputSizePixel()));
188 namespace {
190 enum ColorMode { HUE, SATURATION, BRIGHTNESS, RED, GREEN, BLUE };
194 const ColorMode DefaultMode = HUE;
196 namespace {
198 class ColorFieldControl : public weld::CustomWidgetController
200 public:
201 ColorFieldControl()
202 : meMode( DefaultMode )
203 , mnBaseValue(USHRT_MAX)
204 , mdX( -1.0 )
205 , mdY( -1.0 )
206 , mbMouseCaptured(false)
210 virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override
212 CustomWidgetController::SetDrawingArea(pDrawingArea);
213 pDrawingArea->set_size_request(pDrawingArea->get_approximate_digit_width() * 40,
214 pDrawingArea->get_text_height() * 10);
217 virtual ~ColorFieldControl() override
219 mxBitmap.disposeAndClear();
222 virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override;
223 virtual void Resize() override;
224 virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
225 virtual bool MouseMove(const MouseEvent& rMEvt) override;
226 virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
228 void UpdateBitmap();
229 void ShowPosition( const Point& rPos, bool bUpdate );
230 void UpdatePosition();
231 void Modify();
233 void SetValues(sal_uInt16 nBaseValue, ColorMode eMode, double x, double y);
234 double GetX() const { return mdX;}
235 double GetY() const { return mdY;}
237 void SetModifyHdl(const Link<ColorFieldControl&,void>& rLink) { maModifyHdl = rLink; }
239 private:
240 ColorMode meMode;
241 sal_uInt16 mnBaseValue;
242 double mdX;
243 double mdY;
244 bool mbMouseCaptured;
245 Point maPosition;
246 VclPtr<VirtualDevice> mxBitmap;
247 Link<ColorFieldControl&,void> maModifyHdl;
248 std::vector<sal_uInt8> maRGB_Horiz;
249 std::vector<sal_uInt16> maGrad_Horiz;
250 std::vector<sal_uInt16> maPercent_Horiz;
251 std::vector<sal_uInt8> maRGB_Vert;
252 std::vector<sal_uInt16> maPercent_Vert;
257 void ColorFieldControl::UpdateBitmap()
259 const Size aSize(GetOutputSizePixel());
261 if (mxBitmap && mxBitmap->GetOutputSizePixel() != aSize)
262 mxBitmap.disposeAndClear();
264 const sal_Int32 nWidth = aSize.Width();
265 const sal_Int32 nHeight = aSize.Height();
267 if (nWidth == 0 || nHeight == 0)
268 return;
270 if (!mxBitmap)
272 mxBitmap = VclPtr<VirtualDevice>::Create();
273 mxBitmap->SetOutputSizePixel(aSize);
275 maRGB_Horiz.resize( nWidth );
276 maGrad_Horiz.resize( nWidth );
277 maPercent_Horiz.resize( nWidth );
279 sal_uInt8* pRGB = maRGB_Horiz.data();
280 sal_uInt16* pGrad = maGrad_Horiz.data();
281 sal_uInt16* pPercent = maPercent_Horiz.data();
283 for( sal_Int32 x = 0; x < nWidth; x++ )
285 *pRGB++ = static_cast<sal_uInt8>((x * 256) / nWidth);
286 *pGrad++ = static_cast<sal_uInt16>((x * 359) / nWidth);
287 *pPercent++ = static_cast<sal_uInt16>((x * 100) / nWidth);
290 maRGB_Vert.resize(nHeight);
291 maPercent_Vert.resize(nHeight);
293 pRGB = maRGB_Vert.data();
294 pPercent = maPercent_Vert.data();
296 sal_Int32 y = nHeight;
297 while (y--)
299 *pRGB++ = static_cast<sal_uInt8>((y * 256) / nHeight);
300 *pPercent++ = static_cast<sal_uInt16>((y * 100) / nHeight);
304 sal_uInt8* pRGB_Horiz = maRGB_Horiz.data();
305 sal_uInt16* pGrad_Horiz = maGrad_Horiz.data();
306 sal_uInt16* pPercent_Horiz = maPercent_Horiz.data();
307 sal_uInt8* pRGB_Vert = maRGB_Vert.data();
308 sal_uInt16* pPercent_Vert = maPercent_Vert.data();
310 // this has been unlooped for performance reason, please do not merge back!
312 sal_uInt16 y = nHeight,x;
314 switch(meMode)
316 case HUE:
317 while (y--)
319 sal_uInt16 nBri = pPercent_Vert[y];
320 x = nWidth;
321 while (x--)
323 sal_uInt16 nSat = pPercent_Horiz[x];
324 mxBitmap->DrawPixel(Point(x,y), Color::HSBtoRGB(mnBaseValue, nSat, nBri));
327 break;
328 case SATURATION:
329 while (y--)
331 sal_uInt16 nBri = pPercent_Vert[y];
332 x = nWidth;
333 while (x--)
335 sal_uInt16 nHue = pGrad_Horiz[x];
336 mxBitmap->DrawPixel(Point(x,y), Color::HSBtoRGB(nHue, mnBaseValue, nBri));
339 break;
340 case BRIGHTNESS:
341 while (y--)
343 sal_uInt16 nSat = pPercent_Vert[y];
344 x = nWidth;
345 while (x--)
347 sal_uInt16 nHue = pGrad_Horiz[x];
348 mxBitmap->DrawPixel(Point(x,y), Color::HSBtoRGB(nHue, nSat, mnBaseValue));
351 break;
352 case RED:
354 Color aBitmapColor;
355 aBitmapColor.SetRed(mnBaseValue);
356 while (y--)
358 aBitmapColor.SetGreen(pRGB_Vert[y]);
359 x = nWidth;
360 while (x--)
362 aBitmapColor.SetBlue(pRGB_Horiz[x]);
363 mxBitmap->DrawPixel(Point(x,y), aBitmapColor);
366 break;
368 case GREEN:
370 Color aBitmapColor;
371 aBitmapColor.SetGreen(mnBaseValue);
372 while (y--)
374 aBitmapColor.SetRed(pRGB_Vert[y]);
375 x = nWidth;
376 while (x--)
378 aBitmapColor.SetBlue(pRGB_Horiz[x]);
379 mxBitmap->DrawPixel(Point(x,y), aBitmapColor);
382 break;
384 case BLUE:
386 Color aBitmapColor;
387 aBitmapColor.SetBlue(mnBaseValue);
388 while (y--)
390 aBitmapColor.SetGreen(pRGB_Vert[y]);
391 x = nWidth;
392 while (x--)
394 aBitmapColor.SetRed(pRGB_Horiz[x]);
395 mxBitmap->DrawPixel(Point(x,y), aBitmapColor);
398 break;
403 constexpr int nCenterOffset = 5;
405 void ColorFieldControl::ShowPosition( const Point& rPos, bool bUpdate )
407 if (!mxBitmap)
409 UpdateBitmap();
410 Invalidate();
413 if (!mxBitmap)
414 return;
416 const Size aSize(mxBitmap->GetOutputSizePixel());
418 tools::Long nX = rPos.X();
419 tools::Long nY = rPos.Y();
420 if (nX < 0)
421 nX = 0;
422 else if (nX >= aSize.Width())
423 nX = aSize.Width() - 1;
425 if (nY < 0)
426 nY = 0;
427 else if (nY >= aSize.Height())
428 nY = aSize.Height() - 1;
430 Point aPos = maPosition;
431 maPosition.setX( nX - nCenterOffset );
432 maPosition.setY( nY - nCenterOffset );
433 Invalidate(tools::Rectangle(aPos, Size(11, 11)));
434 Invalidate(tools::Rectangle(maPosition, Size(11, 11)));
436 if (bUpdate)
438 mdX = double(nX) / double(aSize.Width() - 1.0);
439 mdY = double(aSize.Height() - 1.0 - nY) / double(aSize.Height() - 1.0);
443 bool ColorFieldControl::MouseButtonDown(const MouseEvent& rMEvt)
445 CaptureMouse();
446 mbMouseCaptured = true;
447 ShowPosition(rMEvt.GetPosPixel(), true);
448 Modify();
449 return true;
452 bool ColorFieldControl::MouseMove(const MouseEvent& rMEvt)
454 if (mbMouseCaptured)
456 ShowPosition(rMEvt.GetPosPixel(), true);
457 Modify();
459 return true;
462 bool ColorFieldControl::MouseButtonUp(const MouseEvent&)
464 ReleaseMouse();
465 mbMouseCaptured = false;
466 return true;
469 void ColorFieldControl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
471 if (!mxBitmap)
472 UpdateBitmap();
474 if (!mxBitmap)
475 return;
477 Size aSize(GetOutputSizePixel());
478 rRenderContext.DrawOutDev(Point(0, 0), aSize, Point(0, 0), aSize, *mxBitmap);
480 // draw circle around current color
481 Point aPos(maPosition.X() + nCenterOffset, maPosition.Y() + nCenterOffset);
482 Color aColor = mxBitmap->GetPixel(aPos);
483 if (aColor.IsDark())
484 rRenderContext.SetLineColor(COL_WHITE);
485 else
486 rRenderContext.SetLineColor(COL_BLACK);
488 rRenderContext.SetFillColor();
489 rRenderContext.DrawEllipse(::tools::Rectangle(maPosition, Size(11, 11)));
492 void ColorFieldControl::Resize()
494 CustomWidgetController::Resize();
495 UpdateBitmap();
496 UpdatePosition();
499 void ColorFieldControl::Modify()
501 maModifyHdl.Call( *this );
504 void ColorFieldControl::SetValues(sal_uInt16 nBaseValue, ColorMode eMode, double x, double y)
506 bool bUpdateBitmap = (mnBaseValue != nBaseValue) || (meMode != eMode);
507 if (!bUpdateBitmap && mdX == x && mdY == y)
508 return;
510 mnBaseValue = nBaseValue;
511 meMode = eMode;
512 mdX = x;
513 mdY = y;
515 if (bUpdateBitmap)
516 UpdateBitmap();
517 UpdatePosition();
518 if (bUpdateBitmap)
519 Invalidate();
522 void ColorFieldControl::UpdatePosition()
524 Size aSize(GetOutputSizePixel());
525 ShowPosition(Point(static_cast<tools::Long>(mdX * aSize.Width()), static_cast<tools::Long>((1.0 - mdY) * aSize.Height())), false);
528 namespace {
530 class ColorSliderControl : public weld::CustomWidgetController
532 public:
533 ColorSliderControl();
534 virtual ~ColorSliderControl() override;
536 virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
538 virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
539 virtual bool MouseMove(const MouseEvent& rMEvt) override;
540 virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
541 virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) override;
542 virtual void Resize() override;
544 void UpdateBitmap();
545 void ChangePosition( tools::Long nY );
546 void Modify();
548 void SetValue( const Color& rColor, ColorMode eMode, double dValue );
549 double GetValue() const { return mdValue; }
551 void SetModifyHdl( const Link<ColorSliderControl&,void>& rLink ) { maModifyHdl = rLink; }
553 sal_Int16 GetLevel() const { return mnLevel; }
555 private:
556 Link<ColorSliderControl&,void> maModifyHdl;
557 Color maColor;
558 ColorMode meMode;
559 VclPtr<VirtualDevice> mxBitmap;
560 sal_Int16 mnLevel;
561 double mdValue;
566 ColorSliderControl::ColorSliderControl()
567 : meMode( DefaultMode )
568 , mnLevel( 0 )
569 , mdValue( -1.0 )
573 void ColorSliderControl::SetDrawingArea(weld::DrawingArea* pDrawingArea)
575 CustomWidgetController::SetDrawingArea(pDrawingArea);
576 pDrawingArea->set_size_request(pDrawingArea->get_approximate_digit_width() * 3, -1);
579 ColorSliderControl::~ColorSliderControl()
581 mxBitmap.disposeAndClear();
584 void ColorSliderControl::UpdateBitmap()
586 Size aSize(1, GetOutputSizePixel().Height());
588 if (mxBitmap && mxBitmap->GetOutputSizePixel() != aSize)
589 mxBitmap.disposeAndClear();
591 if (!mxBitmap)
593 mxBitmap = VclPtr<VirtualDevice>::Create();
594 mxBitmap->SetOutputSizePixel(aSize);
597 const tools::Long nY = aSize.Height() - 1;
599 Color aBitmapColor(maColor);
601 sal_uInt16 nHue, nSat, nBri;
602 maColor.RGBtoHSB(nHue, nSat, nBri);
604 // this has been unlooped for performance reason, please do not merge back!
606 switch (meMode)
608 case HUE:
609 nSat = 100;
610 nBri = 100;
611 for (tools::Long y = 0; y <= nY; y++)
613 nHue = static_cast<sal_uInt16>((359 * y) / nY);
614 mxBitmap->DrawPixel(Point(0, nY - y), Color::HSBtoRGB(nHue, nSat, nBri));
616 break;
618 case SATURATION:
619 nBri = std::max(sal_uInt16(32), nBri);
620 for (tools::Long y = 0; y <= nY; y++)
622 nSat = static_cast<sal_uInt16>((100 * y) / nY);
623 mxBitmap->DrawPixel(Point(0, nY - y), Color::HSBtoRGB(nHue, nSat, nBri));
625 break;
627 case BRIGHTNESS:
628 for (tools::Long y = 0; y <= nY; y++)
630 nBri = static_cast<sal_uInt16>((100 * y) / nY);
631 mxBitmap->DrawPixel(Point(0, nY - y), Color::HSBtoRGB(nHue, nSat, nBri));
633 break;
635 case RED:
636 for (tools::Long y = 0; y <= nY; y++)
638 aBitmapColor.SetRed(sal_uInt8((tools::Long(255) * y) / nY));
639 mxBitmap->DrawPixel(Point(0, nY - y), aBitmapColor);
641 break;
643 case GREEN:
644 for (tools::Long y = 0; y <= nY; y++)
646 aBitmapColor.SetGreen(sal_uInt8((tools::Long(255) * y) / nY));
647 mxBitmap->DrawPixel(Point(0, nY - y), aBitmapColor);
649 break;
651 case BLUE:
652 for (tools::Long y = 0; y <= nY; y++)
654 aBitmapColor.SetBlue(sal_uInt8((tools::Long(255) * y) / nY));
655 mxBitmap->DrawPixel(Point(0, nY - y), aBitmapColor);
657 break;
661 void ColorSliderControl::ChangePosition(tools::Long nY)
663 const tools::Long nHeight = GetOutputSizePixel().Height() - 1;
665 if (nY < 0)
666 nY = 0;
667 else if (nY > nHeight)
668 nY = nHeight;
670 mnLevel = nY;
671 mdValue = double(nHeight - nY) / double(nHeight);
674 bool ColorSliderControl::MouseButtonDown(const MouseEvent& rMEvt)
676 CaptureMouse();
677 ChangePosition(rMEvt.GetPosPixel().Y());
678 Modify();
679 return true;
682 bool ColorSliderControl::MouseMove(const MouseEvent& rMEvt)
684 if (IsMouseCaptured())
686 ChangePosition(rMEvt.GetPosPixel().Y());
687 Modify();
689 return true;
692 bool ColorSliderControl::MouseButtonUp(const MouseEvent&)
694 ReleaseMouse();
695 return true;
698 void ColorSliderControl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
700 if (!mxBitmap)
701 UpdateBitmap();
703 const Size aSize(GetOutputSizePixel());
705 Point aPos;
706 int x = aSize.Width();
707 while (x--)
709 rRenderContext.DrawOutDev(aPos, aSize, Point(0,0), aSize, *mxBitmap);
710 aPos.AdjustX(1);
714 void ColorSliderControl::Resize()
716 CustomWidgetController::Resize();
717 UpdateBitmap();
720 void ColorSliderControl::Modify()
722 maModifyHdl.Call(*this);
725 void ColorSliderControl::SetValue(const Color& rColor, ColorMode eMode, double dValue)
727 bool bUpdateBitmap = (rColor != maColor) || (eMode != meMode);
728 if( bUpdateBitmap || (mdValue != dValue))
730 maColor = rColor;
731 mdValue = dValue;
732 mnLevel = static_cast<sal_Int16>((1.0-dValue) * GetOutputSizePixel().Height());
733 meMode = eMode;
734 if (bUpdateBitmap)
735 UpdateBitmap();
736 Invalidate();
740 namespace {
742 class ColorPickerDialog : public SfxDialogController
744 private:
745 ColorFieldControl m_aColorField;
746 ColorSliderControl m_aColorSlider;
747 ColorPreviewControl m_aColorPreview;
748 ColorPreviewControl m_aColorPrevious;
750 std::unique_ptr<weld::CustomWeld> m_xColorField;
751 std::unique_ptr<weld::CustomWeld> m_xColorSlider;
752 std::unique_ptr<weld::CustomWeld> m_xColorPreview;
753 std::unique_ptr<weld::CustomWeld> m_xColorPrevious;
755 std::unique_ptr<weld::Widget> m_xFISliderLeft;
756 std::unique_ptr<weld::Widget> m_xFISliderRight;
757 std::unique_ptr<weld::RadioButton> m_xRBRed;
758 std::unique_ptr<weld::RadioButton> m_xRBGreen;
759 std::unique_ptr<weld::RadioButton> m_xRBBlue;
760 std::unique_ptr<weld::RadioButton> m_xRBHue;
761 std::unique_ptr<weld::RadioButton> m_xRBSaturation;
762 std::unique_ptr<weld::RadioButton> m_xRBBrightness;
764 std::unique_ptr<weld::SpinButton> m_xMFRed;
765 std::unique_ptr<weld::SpinButton> m_xMFGreen;
766 std::unique_ptr<weld::SpinButton> m_xMFBlue;
767 std::unique_ptr<weld::HexColorControl> m_xEDHex;
769 std::unique_ptr<weld::MetricSpinButton> m_xMFHue;
770 std::unique_ptr<weld::MetricSpinButton> m_xMFSaturation;
771 std::unique_ptr<weld::MetricSpinButton> m_xMFBrightness;
773 std::unique_ptr<weld::MetricSpinButton> m_xMFCyan;
774 std::unique_ptr<weld::MetricSpinButton> m_xMFMagenta;
775 std::unique_ptr<weld::MetricSpinButton> m_xMFYellow;
776 std::unique_ptr<weld::MetricSpinButton> m_xMFKey;
778 public:
779 ColorPickerDialog(weld::Window* pParent, Color nColor, sal_Int16 nMode);
781 void update_color(UpdateFlags n = UpdateFlags::All);
783 DECL_LINK(ColorFieldControlModifydl, ColorFieldControl&, void);
784 DECL_LINK(ColorSliderControlModifyHdl, ColorSliderControl&, void);
785 DECL_LINK(ColorModifyMetricHdl, weld::MetricSpinButton&, void);
786 DECL_LINK(ColorModifySpinHdl, weld::SpinButton&, void);
787 DECL_LINK(ColorModifyEditHdl, weld::Entry&, void);
788 DECL_LINK(ModeModifyHdl, weld::Toggleable&, void);
790 Color GetColor() const;
792 void setColorComponent(ColorComponent nComp, double dValue);
794 private:
795 ColorMode meMode;
797 double mdRed, mdGreen, mdBlue;
798 double mdHue, mdSat, mdBri;
799 double mdCyan, mdMagenta, mdYellow, mdKey;
804 ColorPickerDialog::ColorPickerDialog(weld::Window* pParent, Color nColor, sal_Int16 nDialogMode)
805 : SfxDialogController(pParent, u"cui/ui/colorpickerdialog.ui"_ustr, u"ColorPicker"_ustr)
806 , m_xColorField(new weld::CustomWeld(*m_xBuilder, u"colorField"_ustr, m_aColorField))
807 , m_xColorSlider(new weld::CustomWeld(*m_xBuilder, u"colorSlider"_ustr, m_aColorSlider))
808 , m_xColorPreview(new weld::CustomWeld(*m_xBuilder, u"preview"_ustr, m_aColorPreview))
809 , m_xColorPrevious(new weld::CustomWeld(*m_xBuilder, u"previous"_ustr, m_aColorPrevious))
810 , m_xFISliderLeft(m_xBuilder->weld_widget(u"leftImage"_ustr))
811 , m_xFISliderRight(m_xBuilder->weld_widget(u"rightImage"_ustr))
812 , m_xRBRed(m_xBuilder->weld_radio_button(u"redRadiobutton"_ustr))
813 , m_xRBGreen(m_xBuilder->weld_radio_button(u"greenRadiobutton"_ustr))
814 , m_xRBBlue(m_xBuilder->weld_radio_button(u"blueRadiobutton"_ustr))
815 , m_xRBHue(m_xBuilder->weld_radio_button(u"hueRadiobutton"_ustr))
816 , m_xRBSaturation(m_xBuilder->weld_radio_button(u"satRadiobutton"_ustr))
817 , m_xRBBrightness(m_xBuilder->weld_radio_button(u"brightRadiobutton"_ustr))
818 , m_xMFRed(m_xBuilder->weld_spin_button(u"redSpinbutton"_ustr))
819 , m_xMFGreen(m_xBuilder->weld_spin_button(u"greenSpinbutton"_ustr))
820 , m_xMFBlue(m_xBuilder->weld_spin_button(u"blueSpinbutton"_ustr))
821 , m_xEDHex(new weld::HexColorControl(m_xBuilder->weld_entry(u"hexEntry"_ustr)))
822 , m_xMFHue(m_xBuilder->weld_metric_spin_button(u"hueSpinbutton"_ustr, FieldUnit::DEGREE))
823 , m_xMFSaturation(m_xBuilder->weld_metric_spin_button(u"satSpinbutton"_ustr, FieldUnit::PERCENT))
824 , m_xMFBrightness(m_xBuilder->weld_metric_spin_button(u"brightSpinbutton"_ustr, FieldUnit::PERCENT))
825 , m_xMFCyan(m_xBuilder->weld_metric_spin_button(u"cyanSpinbutton"_ustr, FieldUnit::PERCENT))
826 , m_xMFMagenta(m_xBuilder->weld_metric_spin_button(u"magSpinbutton"_ustr, FieldUnit::PERCENT))
827 , m_xMFYellow(m_xBuilder->weld_metric_spin_button(u"yellowSpinbutton"_ustr, FieldUnit::PERCENT))
828 , m_xMFKey(m_xBuilder->weld_metric_spin_button(u"keySpinbutton"_ustr, FieldUnit::PERCENT))
829 , meMode( DefaultMode )
831 m_aColorField.SetModifyHdl( LINK( this, ColorPickerDialog, ColorFieldControlModifydl ) );
832 m_aColorSlider.SetModifyHdl( LINK( this, ColorPickerDialog, ColorSliderControlModifyHdl ) );
834 int nMargin = (m_xFISliderLeft->get_preferred_size().Height() + 1) / 2;
835 m_xColorSlider->set_margin_top(nMargin);
836 m_xColorSlider->set_margin_bottom(nMargin);
838 Link<weld::MetricSpinButton&,void> aLink3( LINK( this, ColorPickerDialog, ColorModifyMetricHdl ) );
839 m_xMFCyan->connect_value_changed( aLink3 );
840 m_xMFMagenta->connect_value_changed( aLink3 );
841 m_xMFYellow->connect_value_changed( aLink3 );
842 m_xMFKey->connect_value_changed( aLink3 );
844 m_xMFHue->connect_value_changed( aLink3 );
845 m_xMFSaturation->connect_value_changed( aLink3 );
846 m_xMFBrightness->connect_value_changed( aLink3 );
848 Link<weld::SpinButton&,void> aLink4(LINK(this, ColorPickerDialog, ColorModifySpinHdl));
849 m_xMFRed->connect_value_changed(aLink4);
850 m_xMFGreen->connect_value_changed(aLink4);
851 m_xMFBlue->connect_value_changed(aLink4);
853 m_xEDHex->connect_changed(LINK(this, ColorPickerDialog, ColorModifyEditHdl));
855 Link<weld::Toggleable&,void> aLink2 = LINK( this, ColorPickerDialog, ModeModifyHdl );
856 m_xRBRed->connect_toggled( aLink2 );
857 m_xRBGreen->connect_toggled( aLink2 );
858 m_xRBBlue->connect_toggled( aLink2 );
859 m_xRBHue->connect_toggled( aLink2 );
860 m_xRBSaturation->connect_toggled( aLink2 );
861 m_xRBBrightness->connect_toggled( aLink2 );
863 Color aColor(nColor);
865 // modify
866 if (nDialogMode == 2)
868 m_aColorPrevious.SetColor(aColor);
869 m_xColorPrevious->show();
872 mdRed = static_cast<double>(aColor.GetRed()) / 255.0;
873 mdGreen = static_cast<double>(aColor.GetGreen()) / 255.0;
874 mdBlue = static_cast<double>(aColor.GetBlue()) / 255.0;
876 RGBtoHSV( mdRed, mdGreen, mdBlue, mdHue, mdSat, mdBri );
877 RGBtoCMYK( mdRed, mdGreen, mdBlue, mdCyan, mdMagenta, mdYellow, mdKey );
879 update_color();
882 static int toInt( double dValue, double dRange )
884 return static_cast< int >( std::floor((dValue * dRange) + 0.5 ) );
887 Color ColorPickerDialog::GetColor() const
889 return Color( toInt(mdRed,255.0), toInt(mdGreen,255.0), toInt(mdBlue,255.0) );
892 void ColorPickerDialog::update_color( UpdateFlags n )
894 sal_uInt8 nRed = toInt(mdRed,255.0);
895 sal_uInt8 nGreen = toInt(mdGreen,255.0);
896 sal_uInt8 nBlue = toInt(mdBlue,255.0);
898 sal_uInt16 nHue = toInt(mdHue, 1.0);
899 sal_uInt16 nSat = toInt(mdSat, 100.0);
900 sal_uInt16 nBri = toInt(mdBri, 100.0);
902 if (n & UpdateFlags::RGB) // update RGB
904 m_xMFRed->set_value(nRed);
905 m_xMFGreen->set_value(nGreen);
906 m_xMFBlue->set_value(nBlue);
909 if (n & UpdateFlags::CMYK) // update CMYK
911 m_xMFCyan->set_value(toInt(mdCyan, 100.0), FieldUnit::PERCENT);
912 m_xMFMagenta->set_value(toInt(mdMagenta, 100.0), FieldUnit::PERCENT);
913 m_xMFYellow->set_value(toInt(mdYellow, 100.0), FieldUnit::PERCENT);
914 m_xMFKey->set_value(toInt(mdKey, 100.0), FieldUnit::PERCENT);
917 if (n & UpdateFlags::HSB ) // update HSB
919 m_xMFHue->set_value(nHue, FieldUnit::DEGREE);
920 m_xMFSaturation->set_value(nSat, FieldUnit::PERCENT);
921 m_xMFBrightness->set_value(nBri, FieldUnit::PERCENT);
924 if (n & UpdateFlags::ColorChooser ) // update Color Chooser 1
926 switch( meMode )
928 case HUE:
929 m_aColorField.SetValues(nHue, meMode, mdSat, mdBri);
930 break;
931 case SATURATION:
932 m_aColorField.SetValues(nSat, meMode, mdHue / 360.0, mdBri);
933 break;
934 case BRIGHTNESS:
935 m_aColorField.SetValues(nBri, meMode, mdHue / 360.0, mdSat);
936 break;
937 case RED:
938 m_aColorField.SetValues(nRed, meMode, mdBlue, mdGreen);
939 break;
940 case GREEN:
941 m_aColorField.SetValues(nGreen, meMode, mdBlue, mdRed);
942 break;
943 case BLUE:
944 m_aColorField.SetValues(nBlue, meMode, mdRed, mdGreen);
945 break;
949 Color aColor(nRed, nGreen, nBlue);
951 if (n & UpdateFlags::ColorSlider) // update Color Chooser 2
953 switch (meMode)
955 case HUE:
956 m_aColorSlider.SetValue(aColor, meMode, mdHue / 360.0);
957 break;
958 case SATURATION:
959 m_aColorSlider.SetValue(aColor, meMode, mdSat);
960 break;
961 case BRIGHTNESS:
962 m_aColorSlider.SetValue(aColor, meMode, mdBri);
963 break;
964 case RED:
965 m_aColorSlider.SetValue(aColor, meMode, mdRed);
966 break;
967 case GREEN:
968 m_aColorSlider.SetValue(aColor, meMode, mdGreen);
969 break;
970 case BLUE:
971 m_aColorSlider.SetValue(aColor, meMode, mdBlue);
972 break;
976 if (n & UpdateFlags::Hex) // update hex
978 m_xFISliderLeft->set_margin_top(m_aColorSlider.GetLevel());
979 m_xFISliderRight->set_margin_top(m_aColorSlider.GetLevel());
980 m_xEDHex->SetColor(aColor);
982 m_aColorPreview.SetColor(aColor);
985 IMPL_LINK_NOARG(ColorPickerDialog, ColorFieldControlModifydl, ColorFieldControl&, void)
987 double x = m_aColorField.GetX();
988 double y = m_aColorField.GetY();
990 switch( meMode )
992 case HUE:
993 mdSat = x;
994 setColorComponent( ColorComponent::Brightness, y );
995 break;
996 case SATURATION:
997 mdHue = x * 360.0;
998 setColorComponent( ColorComponent::Brightness, y );
999 break;
1000 case BRIGHTNESS:
1001 mdHue = x * 360.0;
1002 setColorComponent( ColorComponent::Saturation, y );
1003 break;
1004 case RED:
1005 mdBlue = x;
1006 setColorComponent( ColorComponent::Green, y );
1007 break;
1008 case GREEN:
1009 mdBlue = x;
1010 setColorComponent( ColorComponent::Red, y );
1011 break;
1012 case BLUE:
1013 mdRed = x;
1014 setColorComponent( ColorComponent::Green, y );
1015 break;
1018 update_color(UpdateFlags::All & ~UpdateFlags::ColorChooser);
1021 IMPL_LINK_NOARG(ColorPickerDialog, ColorSliderControlModifyHdl, ColorSliderControl&, void)
1023 double dValue = m_aColorSlider.GetValue();
1024 switch (meMode)
1026 case HUE:
1027 setColorComponent( ColorComponent::Hue, dValue * 360.0 );
1028 break;
1029 case SATURATION:
1030 setColorComponent( ColorComponent::Saturation, dValue );
1031 break;
1032 case BRIGHTNESS:
1033 setColorComponent( ColorComponent::Brightness, dValue );
1034 break;
1035 case RED:
1036 setColorComponent( ColorComponent::Red, dValue );
1037 break;
1038 case GREEN:
1039 setColorComponent( ColorComponent::Green, dValue );
1040 break;
1041 case BLUE:
1042 setColorComponent( ColorComponent::Blue, dValue );
1043 break;
1046 update_color(UpdateFlags::All & ~UpdateFlags::ColorSlider);
1049 IMPL_LINK(ColorPickerDialog, ColorModifyMetricHdl, weld::MetricSpinButton&, rEdit, void)
1051 UpdateFlags n = UpdateFlags::NONE;
1053 if (&rEdit == m_xMFHue.get())
1055 setColorComponent( ColorComponent::Hue, static_cast<double>(m_xMFHue->get_value(FieldUnit::DEGREE)) );
1056 n = UpdateFlags::All & ~UpdateFlags::HSB;
1058 else if (&rEdit == m_xMFSaturation.get())
1060 setColorComponent( ColorComponent::Saturation, static_cast<double>(m_xMFSaturation->get_value(FieldUnit::PERCENT)) / 100.0 );
1061 n = UpdateFlags::All & ~UpdateFlags::HSB;
1063 else if (&rEdit == m_xMFBrightness.get())
1065 setColorComponent( ColorComponent::Brightness, static_cast<double>(m_xMFBrightness->get_value(FieldUnit::PERCENT)) / 100.0 );
1066 n = UpdateFlags::All & ~UpdateFlags::HSB;
1068 else if (&rEdit == m_xMFCyan.get())
1070 setColorComponent( ColorComponent::Cyan, static_cast<double>(m_xMFCyan->get_value(FieldUnit::PERCENT)) / 100.0 );
1071 n = UpdateFlags::All & ~UpdateFlags::CMYK;
1073 else if (&rEdit == m_xMFMagenta.get())
1075 setColorComponent( ColorComponent::Magenta, static_cast<double>(m_xMFMagenta->get_value(FieldUnit::PERCENT)) / 100.0 );
1076 n = UpdateFlags::All & ~UpdateFlags::CMYK;
1078 else if (&rEdit == m_xMFYellow.get())
1080 setColorComponent( ColorComponent::Yellow, static_cast<double>(m_xMFYellow->get_value(FieldUnit::PERCENT)) / 100.0 );
1081 n = UpdateFlags::All & ~UpdateFlags::CMYK;
1083 else if (&rEdit == m_xMFKey.get())
1085 setColorComponent( ColorComponent::Key, static_cast<double>(m_xMFKey->get_value(FieldUnit::PERCENT)) / 100.0 );
1086 n = UpdateFlags::All & ~UpdateFlags::CMYK;
1089 if (n != UpdateFlags::NONE)
1090 update_color(n);
1093 IMPL_LINK_NOARG(ColorPickerDialog, ColorModifyEditHdl, weld::Entry&, void)
1095 UpdateFlags n = UpdateFlags::NONE;
1097 Color aColor = m_xEDHex->GetColor();
1099 if (aColor != COL_AUTO && aColor != GetColor())
1101 mdRed = static_cast<double>(aColor.GetRed()) / 255.0;
1102 mdGreen = static_cast<double>(aColor.GetGreen()) / 255.0;
1103 mdBlue = static_cast<double>(aColor.GetBlue()) / 255.0;
1105 RGBtoHSV( mdRed, mdGreen, mdBlue, mdHue, mdSat, mdBri );
1106 RGBtoCMYK( mdRed, mdGreen, mdBlue, mdCyan, mdMagenta, mdYellow, mdKey );
1107 n = UpdateFlags::All & ~UpdateFlags::Hex;
1110 if (n != UpdateFlags::NONE)
1111 update_color(n);
1114 IMPL_LINK(ColorPickerDialog, ColorModifySpinHdl, weld::SpinButton&, rEdit, void)
1116 UpdateFlags n = UpdateFlags::NONE;
1118 if (&rEdit == m_xMFRed.get())
1120 setColorComponent( ColorComponent::Red, static_cast<double>(m_xMFRed->get_value()) / 255.0 );
1121 n = UpdateFlags::All & ~UpdateFlags::RGB;
1123 else if (&rEdit == m_xMFGreen.get())
1125 setColorComponent( ColorComponent::Green, static_cast<double>(m_xMFGreen->get_value()) / 255.0 );
1126 n = UpdateFlags::All & ~UpdateFlags::RGB;
1128 else if (&rEdit == m_xMFBlue.get())
1130 setColorComponent( ColorComponent::Blue, static_cast<double>(m_xMFBlue->get_value()) / 255.0 );
1131 n = UpdateFlags::All & ~UpdateFlags::RGB;
1134 if (n != UpdateFlags::NONE)
1135 update_color(n);
1139 IMPL_LINK_NOARG(ColorPickerDialog, ModeModifyHdl, weld::Toggleable&, void)
1141 ColorMode eMode = HUE;
1143 if (m_xRBRed->get_active())
1145 eMode = RED;
1147 else if (m_xRBGreen->get_active())
1149 eMode = GREEN;
1151 else if (m_xRBBlue->get_active())
1153 eMode = BLUE;
1155 else if (m_xRBSaturation->get_active())
1157 eMode = SATURATION;
1159 else if (m_xRBBrightness->get_active())
1161 eMode = BRIGHTNESS;
1164 if (meMode != eMode)
1166 meMode = eMode;
1167 update_color(UpdateFlags::ColorChooser | UpdateFlags::ColorSlider);
1171 void ColorPickerDialog::setColorComponent( ColorComponent nComp, double dValue )
1173 switch( nComp )
1175 case ColorComponent::Red:
1176 mdRed = dValue;
1177 break;
1178 case ColorComponent::Green:
1179 mdGreen = dValue;
1180 break;
1181 case ColorComponent::Blue:
1182 mdBlue = dValue;
1183 break;
1184 case ColorComponent::Hue:
1185 mdHue = dValue;
1186 break;
1187 case ColorComponent::Saturation:
1188 mdSat = dValue;
1189 break;
1190 case ColorComponent::Brightness:
1191 mdBri = dValue;
1192 break;
1193 case ColorComponent::Cyan:
1194 mdCyan = dValue;
1195 break;
1196 case ColorComponent::Yellow:
1197 mdYellow = dValue;
1198 break;
1199 case ColorComponent::Magenta:
1200 mdMagenta = dValue;
1201 break;
1202 case ColorComponent::Key:
1203 mdKey = dValue;
1204 break;
1207 if (nComp == ColorComponent::Red || nComp == ColorComponent::Green || nComp == ColorComponent::Blue)
1209 RGBtoHSV( mdRed, mdGreen, mdBlue, mdHue, mdSat, mdBri );
1210 RGBtoCMYK( mdRed, mdGreen, mdBlue, mdCyan, mdMagenta, mdYellow, mdKey );
1212 else if (nComp == ColorComponent::Hue || nComp == ColorComponent::Saturation || nComp == ColorComponent::Brightness)
1214 HSVtoRGB( mdHue, mdSat, mdBri, mdRed, mdGreen, mdBlue );
1215 RGBtoCMYK( mdRed, mdGreen, mdBlue, mdCyan, mdMagenta, mdYellow, mdKey );
1217 else
1219 CMYKtoRGB( mdCyan, mdMagenta, mdYellow, mdKey, mdRed, mdGreen, mdBlue );
1220 RGBtoHSV( mdRed, mdGreen, mdBlue, mdHue, mdSat, mdBri );
1224 typedef ::comphelper::WeakComponentImplHelper< XServiceInfo, XExecutableDialog, XAsynchronousExecutableDialog, XInitialization, XPropertyAccess > ColorPickerBase;
1226 namespace {
1228 class ColorPicker : public ColorPickerBase
1230 public:
1231 explicit ColorPicker();
1233 // XInitialization
1234 virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override;
1236 // XInitialization
1237 virtual OUString SAL_CALL getImplementationName( ) override;
1238 virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
1239 virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
1241 // XPropertyAccess
1242 virtual Sequence< PropertyValue > SAL_CALL getPropertyValues( ) override;
1243 virtual void SAL_CALL setPropertyValues( const Sequence< PropertyValue >& aProps ) override;
1245 // XExecutableDialog
1246 virtual void SAL_CALL setTitle( const OUString& aTitle ) override;
1247 virtual sal_Int16 SAL_CALL execute( ) override;
1249 // XAsynchronousExecutableDialog
1250 virtual void SAL_CALL setDialogTitle( const OUString& aTitle ) override;
1251 virtual void SAL_CALL startExecuteModal( const css::uno::Reference< css::ui::dialogs::XDialogClosedListener >& xListener ) override;
1253 private:
1254 Color mnColor;
1255 sal_Int16 mnMode;
1256 Reference<css::awt::XWindow> mxParent;
1261 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
1262 com_sun_star_cui_ColorPicker_get_implementation(
1263 css::uno::XComponentContext*, css::uno::Sequence<css::uno::Any> const&)
1265 return cppu::acquire( new ColorPicker );
1269 constexpr OUString gsColorKey( u"Color"_ustr );
1270 constexpr OUStringLiteral gsModeKey( u"Mode" );
1272 ColorPicker::ColorPicker()
1273 : mnColor( 0 )
1274 , mnMode( 0 )
1278 // XInitialization
1279 void SAL_CALL ColorPicker::initialize( const Sequence< Any >& aArguments )
1281 if( aArguments.getLength() == 1 )
1283 aArguments[0] >>= mxParent;
1287 // XInitialization
1288 OUString SAL_CALL ColorPicker::getImplementationName( )
1290 return u"com.sun.star.cui.ColorPicker"_ustr;
1293 sal_Bool SAL_CALL ColorPicker::supportsService( const OUString& sServiceName )
1295 return cppu::supportsService(this, sServiceName);
1298 Sequence< OUString > SAL_CALL ColorPicker::getSupportedServiceNames( )
1300 return { u"com.sun.star.ui.dialogs.ColorPicker"_ustr,
1301 u"com.sun.star.ui.dialogs.AsynchronousColorPicker"_ustr };
1304 // XPropertyAccess
1305 Sequence< PropertyValue > SAL_CALL ColorPicker::getPropertyValues( )
1307 Sequence< PropertyValue > props{ comphelper::makePropertyValue(gsColorKey, mnColor) };
1308 return props;
1311 void SAL_CALL ColorPicker::setPropertyValues( const Sequence< PropertyValue >& aProps )
1313 for ( const PropertyValue& rProp : aProps )
1315 if( rProp.Name == gsColorKey )
1317 rProp.Value >>= mnColor;
1319 else if( rProp.Name == gsModeKey )
1321 rProp.Value >>= mnMode;
1326 // XExecutableDialog
1327 void SAL_CALL ColorPicker::setTitle( const OUString& )
1331 sal_Int16 SAL_CALL ColorPicker::execute()
1333 std::unique_ptr<ColorPickerDialog> xDlg(new ColorPickerDialog(Application::GetFrameWeld(mxParent), mnColor, mnMode));
1334 sal_Int16 ret = xDlg->run();
1335 if (ret)
1336 mnColor = xDlg->GetColor();
1337 return ret;
1340 // XAsynchronousExecutableDialog
1341 void SAL_CALL ColorPicker::setDialogTitle( const OUString& )
1345 void SAL_CALL ColorPicker::startExecuteModal( const css::uno::Reference< css::ui::dialogs::XDialogClosedListener >& xListener )
1347 std::shared_ptr<ColorPickerDialog> xDlg = std::make_shared<ColorPickerDialog>(Application::GetFrameWeld(mxParent), mnColor, mnMode);
1348 rtl::Reference<ColorPicker> xThis(this);
1349 weld::DialogController::runAsync(xDlg, [xThis=std::move(xThis), xDlg, xListener] (sal_Int32 nResult) {
1350 if (nResult)
1351 xThis->mnColor = xDlg->GetColor();
1353 sal_Int16 nRet = static_cast<sal_Int16>(nResult);
1354 css::ui::dialogs::DialogClosedEvent aEvent( *xThis, nRet );
1355 xListener->dialogClosed( aEvent );
1361 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */