bump product version to 6.4.0.3
[LibreOffice.git] / cui / source / dialogs / colorpicker.cxx
blobbddca8e8ca81c83944678db03ffa26ec4478a895
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/beans/XPropertyAccess.hpp>
23 #include <com/sun/star/lang/XInitialization.hpp>
24 #include <com/sun/star/lang/XServiceInfo.hpp>
25 #include <com/sun/star/awt/XWindow.hpp>
26 #include <cppuhelper/compbase.hxx>
27 #include <cppuhelper/supportsservice.hxx>
28 #include <cppuhelper/basemutex.hxx>
29 #include <vcl/customweld.hxx>
30 #include <vcl/event.hxx>
31 #include <vcl/svapp.hxx>
32 #include <vcl/virdev.hxx>
33 #include <vcl/weld.hxx>
34 #include <svx/hexcolorcontrol.hxx>
35 #include <basegfx/color/bcolortools.hxx>
36 #include <colorpicker.hxx>
37 #include <cmath>
38 #include <o3tl/typed_flags_set.hxx>
40 using namespace ::com::sun::star::uno;
41 using namespace ::com::sun::star::lang;
42 using namespace ::com::sun::star::ui::dialogs;
43 using namespace ::com::sun::star::beans;
44 using namespace ::basegfx;
46 enum class UpdateFlags
48 NONE = 0x00,
49 RGB = 0x01,
50 CMYK = 0x02,
51 HSB = 0x04,
52 ColorChooser = 0x08,
53 ColorSlider = 0x10,
54 Hex = 0x20,
55 All = 0x3f,
57 namespace o3tl {
58 template<> struct typed_flags<UpdateFlags> : is_typed_flags<UpdateFlags, 0x3f> {};
62 namespace cui
65 enum class ColorComponent {
66 Red,
67 Green,
68 Blue,
69 Hue,
70 Saturation,
71 Brightness,
72 Cyan,
73 Yellow,
74 Magenta,
75 Key,
79 // color space conversion helpers
81 static void RGBtoHSV( double dR, double dG, double dB, double& dH, double& dS, double& dV )
83 BColor result = basegfx::utils::rgb2hsv( BColor( dR, dG, dB ) );
85 dH = result.getX();
86 dS = result.getY();
87 dV = result.getZ();
90 static void HSVtoRGB(double dH, double dS, double dV, double& dR, double& dG, double& dB )
92 BColor result = basegfx::utils::hsv2rgb( BColor( dH, dS, dV ) );
94 dR = result.getRed();
95 dG = result.getGreen();
96 dB = result.getBlue();
99 // CMYK values from 0 to 1
100 static void CMYKtoRGB( double fCyan, double fMagenta, double fYellow, double fKey, double& dR, double& dG, double& dB )
102 fCyan = (fCyan * ( 1.0 - fKey )) + fKey;
103 fMagenta = (fMagenta * ( 1.0 - fKey )) + fKey;
104 fYellow = (fYellow * ( 1.0 - fKey )) + fKey;
106 dR = std::max( std::min( ( 1.0 - fCyan ), 1.0), 0.0 );
107 dG = std::max( std::min( ( 1.0 - fMagenta ), 1.0), 0.0 );
108 dB = std::max( std::min( ( 1.0 - fYellow ), 1.0), 0.0 );
111 // CMY results from 0 to 1
112 static void RGBtoCMYK( double dR, double dG, double dB, double& fCyan, double& fMagenta, double& fYellow, double& fKey )
114 fCyan = 1 - dR;
115 fMagenta = 1 - dG;
116 fYellow = 1 - dB;
118 //CMYK and CMY values from 0 to 1
119 fKey = 1.0;
120 if( fCyan < fKey ) fKey = fCyan;
121 if( fMagenta < fKey ) fKey = fMagenta;
122 if( fYellow < fKey ) fKey = fYellow;
124 if( fKey >= 1.0 )
126 //Black
127 fCyan = 0.0;
128 fMagenta = 0.0;
129 fYellow = 0.0;
131 else
133 fCyan = ( fCyan - fKey ) / ( 1.0 - fKey );
134 fMagenta = ( fMagenta - fKey ) / ( 1.0 - fKey );
135 fYellow = ( fYellow - fKey ) / ( 1.0 - fKey );
139 class ColorPreviewControl : public weld::CustomWidgetController
141 private:
142 Color m_aColor;
144 virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) override;
145 public:
146 ColorPreviewControl()
150 virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override
152 CustomWidgetController::SetDrawingArea(pDrawingArea);
153 pDrawingArea->set_size_request(pDrawingArea->get_approximate_digit_width() * 10,
154 pDrawingArea->get_text_height() * 2);
157 void SetColor(const Color& rCol)
159 if (rCol != m_aColor)
161 m_aColor = rCol;
162 Invalidate();
167 void ColorPreviewControl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
169 rRenderContext.SetFillColor(m_aColor);
170 rRenderContext.SetLineColor(m_aColor);
171 rRenderContext.DrawRect(tools::Rectangle(Point(0, 0), GetOutputSizePixel()));
174 enum ColorMode { HUE, SATURATION, BRIGHTNESS, RED, GREEN, BLUE };
175 const ColorMode DefaultMode = HUE;
177 class ColorFieldControl : public weld::CustomWidgetController
179 public:
180 ColorFieldControl()
181 : meMode( DefaultMode )
182 , mdX( -1.0 )
183 , mdY( -1.0 )
184 , mbMouseCaptured(false)
188 virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override
190 CustomWidgetController::SetDrawingArea(pDrawingArea);
191 pDrawingArea->set_size_request(pDrawingArea->get_approximate_digit_width() * 40,
192 pDrawingArea->get_text_height() * 10);
195 virtual ~ColorFieldControl() override
197 mxBitmap.disposeAndClear();
200 virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override;
201 virtual void Resize() override;
202 virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
203 virtual bool MouseMove(const MouseEvent& rMEvt) override;
204 virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
206 void UpdateBitmap();
207 void ShowPosition( const Point& rPos, bool bUpdate );
208 void UpdatePosition();
209 void Modify();
211 void SetValues(Color aColor, ColorMode eMode, double x, double y);
212 double GetX() const { return mdX;}
213 double GetY() const { return mdY;}
215 void SetModifyHdl(const Link<ColorFieldControl&,void>& rLink) { maModifyHdl = rLink; }
217 private:
218 ColorMode meMode;
219 Color maColor;
220 double mdX;
221 double mdY;
222 bool mbMouseCaptured;
223 Point maPosition;
224 VclPtr<VirtualDevice> mxBitmap;
225 Link<ColorFieldControl&,void> maModifyHdl;
226 std::vector<sal_uInt8> maRGB_Horiz;
227 std::vector<sal_uInt16> maGrad_Horiz;
228 std::vector<sal_uInt16> maPercent_Horiz;
229 std::vector<sal_uInt8> maRGB_Vert;
230 std::vector<sal_uInt16> maPercent_Vert;
233 void ColorFieldControl::UpdateBitmap()
235 const Size aSize(GetOutputSizePixel());
237 if (mxBitmap && mxBitmap->GetOutputSizePixel() != aSize)
238 mxBitmap.disposeAndClear();
240 const sal_Int32 nWidth = aSize.Width();
241 const sal_Int32 nHeight = aSize.Height();
243 if (nWidth == 0 || nHeight == 0)
244 return;
246 if (!mxBitmap)
248 mxBitmap = VclPtr<VirtualDevice>::Create();
249 mxBitmap->SetOutputSizePixel(aSize);
251 maRGB_Horiz.resize( nWidth );
252 maGrad_Horiz.resize( nWidth );
253 maPercent_Horiz.resize( nWidth );
255 sal_uInt8* pRGB = maRGB_Horiz.data();
256 sal_uInt16* pGrad = maGrad_Horiz.data();
257 sal_uInt16* pPercent = maPercent_Horiz.data();
259 for( sal_Int32 x = 0; x < nWidth; x++ )
261 *pRGB++ = static_cast<sal_uInt8>((x * 256) / nWidth);
262 *pGrad++ = static_cast<sal_uInt16>((x * 359) / nWidth);
263 *pPercent++ = static_cast<sal_uInt16>((x * 100) / nWidth);
266 maRGB_Vert.resize(nHeight);
267 maPercent_Vert.resize(nHeight);
269 pRGB = maRGB_Vert.data();
270 pPercent = maPercent_Vert.data();
272 sal_Int32 y = nHeight;
273 while (y--)
275 *pRGB++ = static_cast<sal_uInt8>((y * 256) / nHeight);
276 *pPercent++ = static_cast<sal_uInt16>((y * 100) / nHeight);
280 sal_uInt8* pRGB_Horiz = maRGB_Horiz.data();
281 sal_uInt16* pGrad_Horiz = maGrad_Horiz.data();
282 sal_uInt16* pPercent_Horiz = maPercent_Horiz.data();
283 sal_uInt8* pRGB_Vert = maRGB_Vert.data();
284 sal_uInt16* pPercent_Vert = maPercent_Vert.data();
286 Color aBitmapColor(maColor);
288 sal_uInt16 nHue, nSat, nBri;
289 maColor.RGBtoHSB(nHue, nSat, nBri);
291 // this has been unlooped for performance reason, please do not merge back!
293 sal_uInt16 y = nHeight,x;
295 switch(meMode)
297 case HUE:
298 while (y--)
300 nBri = pPercent_Vert[y];
301 x = nWidth;
302 while (x--)
304 nSat = pPercent_Horiz[x];
305 mxBitmap->DrawPixel(Point(x,y), Color::HSBtoRGB(nHue, nSat, nBri));
308 break;
309 case SATURATION:
310 while (y--)
312 nBri = pPercent_Vert[y];
313 x = nWidth;
314 while (x--)
316 nHue = pGrad_Horiz[x];
317 mxBitmap->DrawPixel(Point(x,y), Color::HSBtoRGB(nHue, nSat, nBri));
320 break;
321 case BRIGHTNESS:
322 while (y--)
324 nSat = pPercent_Vert[y];
325 x = nWidth;
326 while (x--)
328 nHue = pGrad_Horiz[x];
329 mxBitmap->DrawPixel(Point(x,y), Color::HSBtoRGB(nHue, nSat, nBri));
332 break;
333 case RED:
334 while (y--)
336 aBitmapColor.SetGreen(pRGB_Vert[y]);
337 x = nWidth;
338 while (x--)
340 aBitmapColor.SetBlue(pRGB_Horiz[x]);
341 mxBitmap->DrawPixel(Point(x,y), aBitmapColor);
344 break;
345 case GREEN:
346 while (y--)
348 aBitmapColor.SetRed(pRGB_Vert[y]);
349 x = nWidth;
350 while (x--)
352 aBitmapColor.SetBlue(pRGB_Horiz[x]);
353 mxBitmap->DrawPixel(Point(x,y), aBitmapColor);
356 break;
357 case BLUE:
358 while (y--)
360 aBitmapColor.SetGreen(pRGB_Vert[y]);
361 x = nWidth;
362 while (x--)
364 aBitmapColor.SetRed(pRGB_Horiz[x]);
365 mxBitmap->DrawPixel(Point(x,y), aBitmapColor);
368 break;
372 void ColorFieldControl::ShowPosition( const Point& rPos, bool bUpdate )
374 if (!mxBitmap)
376 UpdateBitmap();
377 Invalidate();
380 if (!mxBitmap)
381 return;
383 const Size aSize(mxBitmap->GetOutputSizePixel());
385 long nX = rPos.X();
386 long nY = rPos.Y();
387 if (nX < 0)
388 nX = 0;
389 else if (nX >= aSize.Width())
390 nX = aSize.Width() - 1;
392 if (nY < 0)
393 nY = 0;
394 else if (nY >= aSize.Height())
395 nY = aSize.Height() - 1;
397 Point aPos = maPosition;
398 maPosition.setX( nX - 5 );
399 maPosition.setY( nY - 5 );
400 Invalidate(tools::Rectangle(aPos, Size(11, 11)));
401 Invalidate(tools::Rectangle(maPosition, Size(11, 11)));
403 if (bUpdate)
405 mdX = double(nX) / double(aSize.Width() - 1.0);
406 mdY = double(aSize.Height() - 1.0 - nY) / double(aSize.Height() - 1.0);
408 maColor = mxBitmap->GetPixel(Point(nX, nY));
412 bool ColorFieldControl::MouseButtonDown(const MouseEvent& rMEvt)
414 CaptureMouse();
415 mbMouseCaptured = true;
416 ShowPosition(rMEvt.GetPosPixel(), true);
417 Modify();
418 return true;
421 bool ColorFieldControl::MouseMove(const MouseEvent& rMEvt)
423 if (mbMouseCaptured)
425 ShowPosition(rMEvt.GetPosPixel(), true);
426 Modify();
428 return true;
431 bool ColorFieldControl::MouseButtonUp(const MouseEvent&)
433 ReleaseMouse();
434 mbMouseCaptured = false;
435 return true;
438 void ColorFieldControl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
440 if (!mxBitmap)
441 UpdateBitmap();
443 if (mxBitmap)
445 Size aSize(GetOutputSizePixel());
446 rRenderContext.DrawOutDev(Point(0, 0), aSize, Point(0, 0), aSize, *mxBitmap);
449 // draw circle around current color
450 if (maColor.IsDark())
451 rRenderContext.SetLineColor( COL_WHITE );
452 else
453 rRenderContext.SetLineColor( COL_BLACK );
455 rRenderContext.SetFillColor();
457 rRenderContext.DrawEllipse(::tools::Rectangle(maPosition, Size(11, 11)));
460 void ColorFieldControl::Resize()
462 CustomWidgetController::Resize();
463 UpdateBitmap();
464 UpdatePosition();
467 void ColorFieldControl::Modify()
469 maModifyHdl.Call( *this );
472 void ColorFieldControl::SetValues( Color aColor, ColorMode eMode, double x, double y )
474 bool bUpdateBitmap = (maColor!= aColor) || (meMode != eMode);
475 if( bUpdateBitmap || (mdX != x) || (mdY != y) )
477 maColor = aColor;
478 meMode = eMode;
479 mdX = x;
480 mdY = y;
482 if (bUpdateBitmap)
483 UpdateBitmap();
484 UpdatePosition();
485 if (bUpdateBitmap)
486 Invalidate();
490 void ColorFieldControl::UpdatePosition()
492 Size aSize(GetOutputSizePixel());
493 ShowPosition(Point(static_cast<long>(mdX * aSize.Width()), static_cast<long>((1.0 - mdY) * aSize.Height())), false);
496 class ColorSliderControl : public weld::CustomWidgetController
498 public:
499 ColorSliderControl();
500 virtual ~ColorSliderControl() override;
502 virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
504 virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
505 virtual bool MouseMove(const MouseEvent& rMEvt) override;
506 virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
507 virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) override;
508 virtual void Resize() override;
510 void UpdateBitmap();
511 void ChangePosition( long nY );
512 void Modify();
514 void SetValue( const Color& rColor, ColorMode eMode, double dValue );
515 double GetValue() const { return mdValue; }
517 void SetModifyHdl( const Link<ColorSliderControl&,void>& rLink ) { maModifyHdl = rLink; }
519 sal_Int16 GetLevel() const { return mnLevel; }
521 private:
522 Link<ColorSliderControl&,void> maModifyHdl;
523 Color maColor;
524 ColorMode meMode;
525 VclPtr<VirtualDevice> mxBitmap;
526 sal_Int16 mnLevel;
527 double mdValue;
530 ColorSliderControl::ColorSliderControl()
531 : meMode( DefaultMode )
532 , mnLevel( 0 )
533 , mdValue( -1.0 )
537 void ColorSliderControl::SetDrawingArea(weld::DrawingArea* pDrawingArea)
539 CustomWidgetController::SetDrawingArea(pDrawingArea);
540 pDrawingArea->set_size_request(pDrawingArea->get_approximate_digit_width() * 3, -1);
543 ColorSliderControl::~ColorSliderControl()
545 mxBitmap.disposeAndClear();
548 void ColorSliderControl::UpdateBitmap()
550 Size aSize(1, GetOutputSizePixel().Height());
552 if (mxBitmap && mxBitmap->GetOutputSizePixel() != aSize)
553 mxBitmap.disposeAndClear();
555 if (!mxBitmap)
557 mxBitmap = VclPtr<VirtualDevice>::Create();
558 mxBitmap->SetOutputSizePixel(aSize);
561 const long nY = aSize.Height() - 1;
563 Color aBitmapColor(maColor);
565 sal_uInt16 nHue, nSat, nBri;
566 maColor.RGBtoHSB(nHue, nSat, nBri);
568 // this has been unlooped for performance reason, please do not merge back!
570 switch (meMode)
572 case HUE:
573 nSat = 100;
574 nBri = 100;
575 for (long y = 0; y <= nY; y++)
577 nHue = static_cast<sal_uInt16>((359 * y) / nY);
578 mxBitmap->DrawPixel(Point(0, nY - y), Color::HSBtoRGB(nHue, nSat, nBri));
580 break;
582 case SATURATION:
583 nBri = std::max(sal_uInt16(32), nBri);
584 for (long y = 0; y <= nY; y++)
586 nSat = static_cast<sal_uInt16>((100 * y) / nY);
587 mxBitmap->DrawPixel(Point(0, nY - y), Color::HSBtoRGB(nHue, nSat, nBri));
589 break;
591 case BRIGHTNESS:
592 for (long y = 0; y <= nY; y++)
594 nBri = static_cast<sal_uInt16>((100 * y) / nY);
595 mxBitmap->DrawPixel(Point(0, nY - y), Color::HSBtoRGB(nHue, nSat, nBri));
597 break;
599 case RED:
600 for (long y = 0; y <= nY; y++)
602 aBitmapColor.SetRed(sal_uInt8((long(255) * y) / nY));
603 mxBitmap->DrawPixel(Point(0, nY - y), aBitmapColor);
605 break;
607 case GREEN:
608 for (long y = 0; y <= nY; y++)
610 aBitmapColor.SetGreen(sal_uInt8((long(255) * y) / nY));
611 mxBitmap->DrawPixel(Point(0, nY - y), aBitmapColor);
613 break;
615 case BLUE:
616 for (long y = 0; y <= nY; y++)
618 aBitmapColor.SetBlue(sal_uInt8((long(255) * y) / nY));
619 mxBitmap->DrawPixel(Point(0, nY - y), aBitmapColor);
621 break;
625 void ColorSliderControl::ChangePosition(long nY)
627 const long nHeight = GetOutputSizePixel().Height() - 1;
629 if (nY < 0)
630 nY = 0;
631 else if (nY > nHeight)
632 nY = nHeight;
634 mnLevel = nY;
635 mdValue = double(nHeight - nY) / double(nHeight);
638 bool ColorSliderControl::MouseButtonDown(const MouseEvent& rMEvt)
640 CaptureMouse();
641 ChangePosition(rMEvt.GetPosPixel().Y());
642 Modify();
643 return true;
646 bool ColorSliderControl::MouseMove(const MouseEvent& rMEvt)
648 if (IsMouseCaptured())
650 ChangePosition(rMEvt.GetPosPixel().Y());
651 Modify();
653 return true;
656 bool ColorSliderControl::MouseButtonUp(const MouseEvent&)
658 ReleaseMouse();
659 return true;
662 void ColorSliderControl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
664 if (!mxBitmap)
665 UpdateBitmap();
667 const Size aSize(GetOutputSizePixel());
669 Point aPos;
670 int x = aSize.Width();
671 while (x--)
673 rRenderContext.DrawOutDev(aPos, aSize, Point(0,0), aSize, *mxBitmap);
674 aPos.AdjustX(1);
678 void ColorSliderControl::Resize()
680 CustomWidgetController::Resize();
681 UpdateBitmap();
684 void ColorSliderControl::Modify()
686 maModifyHdl.Call(*this);
689 void ColorSliderControl::SetValue(const Color& rColor, ColorMode eMode, double dValue)
691 bool bUpdateBitmap = (rColor != maColor) || (eMode != meMode);
692 if( bUpdateBitmap || (mdValue != dValue))
694 maColor = rColor;
695 mdValue = dValue;
696 mnLevel = static_cast<sal_Int16>((1.0-dValue) * GetOutputSizePixel().Height());
697 meMode = eMode;
698 if (bUpdateBitmap)
699 UpdateBitmap();
700 Invalidate();
704 class ColorPickerDialog : public weld::GenericDialogController
706 private:
707 ColorFieldControl m_aColorField;
708 ColorSliderControl m_aColorSlider;
709 ColorPreviewControl m_aColorPreview;
710 ColorPreviewControl m_aColorPrevious;
712 std::unique_ptr<weld::CustomWeld> m_xColorField;
713 std::unique_ptr<weld::CustomWeld> m_xColorSlider;
714 std::unique_ptr<weld::CustomWeld> m_xColorPreview;
715 std::unique_ptr<weld::CustomWeld> m_xColorPrevious;
717 std::unique_ptr<weld::Widget> m_xFISliderLeft;
718 std::unique_ptr<weld::Widget> m_xFISliderRight;
719 std::unique_ptr<weld::RadioButton> m_xRBRed;
720 std::unique_ptr<weld::RadioButton> m_xRBGreen;
721 std::unique_ptr<weld::RadioButton> m_xRBBlue;
722 std::unique_ptr<weld::RadioButton> m_xRBHue;
723 std::unique_ptr<weld::RadioButton> m_xRBSaturation;
724 std::unique_ptr<weld::RadioButton> m_xRBBrightness;
726 std::unique_ptr<weld::SpinButton> m_xMFRed;
727 std::unique_ptr<weld::SpinButton> m_xMFGreen;
728 std::unique_ptr<weld::SpinButton> m_xMFBlue;
729 std::unique_ptr<weld::HexColorControl> m_xEDHex;
731 std::unique_ptr<weld::MetricSpinButton> m_xMFHue;
732 std::unique_ptr<weld::MetricSpinButton> m_xMFSaturation;
733 std::unique_ptr<weld::MetricSpinButton> m_xMFBrightness;
735 std::unique_ptr<weld::MetricSpinButton> m_xMFCyan;
736 std::unique_ptr<weld::MetricSpinButton> m_xMFMagenta;
737 std::unique_ptr<weld::MetricSpinButton> m_xMFYellow;
738 std::unique_ptr<weld::MetricSpinButton> m_xMFKey;
740 public:
741 ColorPickerDialog(weld::Window* pParent, Color nColor, sal_Int16 nMode);
743 void update_color(UpdateFlags n = UpdateFlags::All);
745 DECL_LINK(ColorFieldControlModifydl, ColorFieldControl&, void);
746 DECL_LINK(ColorSliderControlModifyHdl, ColorSliderControl&, void);
747 DECL_LINK(ColorModifyMetricHdl, weld::MetricSpinButton&, void);
748 DECL_LINK(ColorModifySpinHdl, weld::SpinButton&, void);
749 DECL_LINK(ColorModifyEditHdl, weld::Entry&, void);
750 DECL_LINK(ModeModifyHdl, weld::ToggleButton&, void);
752 Color GetColor() const;
754 void setColorComponent(ColorComponent nComp, double dValue);
756 private:
757 ColorMode meMode;
759 double mdRed, mdGreen, mdBlue;
760 double mdHue, mdSat, mdBri;
761 double mdCyan, mdMagenta, mdYellow, mdKey;
764 ColorPickerDialog::ColorPickerDialog(weld::Window* pParent, Color nColor, sal_Int16 nDialogMode)
765 : GenericDialogController(pParent, "cui/ui/colorpickerdialog.ui", "ColorPicker")
766 , m_xColorField(new weld::CustomWeld(*m_xBuilder, "colorField", m_aColorField))
767 , m_xColorSlider(new weld::CustomWeld(*m_xBuilder, "colorSlider", m_aColorSlider))
768 , m_xColorPreview(new weld::CustomWeld(*m_xBuilder, "preview", m_aColorPreview))
769 , m_xColorPrevious(new weld::CustomWeld(*m_xBuilder, "previous", m_aColorPrevious))
770 , m_xFISliderLeft(m_xBuilder->weld_widget("leftImage"))
771 , m_xFISliderRight(m_xBuilder->weld_widget("rightImage"))
772 , m_xRBRed(m_xBuilder->weld_radio_button("redRadiobutton"))
773 , m_xRBGreen(m_xBuilder->weld_radio_button("greenRadiobutton"))
774 , m_xRBBlue(m_xBuilder->weld_radio_button("blueRadiobutton"))
775 , m_xRBHue(m_xBuilder->weld_radio_button("hueRadiobutton"))
776 , m_xRBSaturation(m_xBuilder->weld_radio_button("satRadiobutton"))
777 , m_xRBBrightness(m_xBuilder->weld_radio_button("brightRadiobutton"))
778 , m_xMFRed(m_xBuilder->weld_spin_button("redSpinbutton"))
779 , m_xMFGreen(m_xBuilder->weld_spin_button("greenSpinbutton"))
780 , m_xMFBlue(m_xBuilder->weld_spin_button("blueSpinbutton"))
781 , m_xEDHex(new weld::HexColorControl(m_xBuilder->weld_entry("hexEntry")))
782 , m_xMFHue(m_xBuilder->weld_metric_spin_button("hueSpinbutton", FieldUnit::DEGREE))
783 , m_xMFSaturation(m_xBuilder->weld_metric_spin_button("satSpinbutton", FieldUnit::PERCENT))
784 , m_xMFBrightness(m_xBuilder->weld_metric_spin_button("brightSpinbutton", FieldUnit::PERCENT))
785 , m_xMFCyan(m_xBuilder->weld_metric_spin_button("cyanSpinbutton", FieldUnit::PERCENT))
786 , m_xMFMagenta(m_xBuilder->weld_metric_spin_button("magSpinbutton", FieldUnit::PERCENT))
787 , m_xMFYellow(m_xBuilder->weld_metric_spin_button("yellowSpinbutton", FieldUnit::PERCENT))
788 , m_xMFKey(m_xBuilder->weld_metric_spin_button("keySpinbutton", FieldUnit::PERCENT))
789 , meMode( DefaultMode )
791 m_aColorField.SetModifyHdl( LINK( this, ColorPickerDialog, ColorFieldControlModifydl ) );
792 m_aColorSlider.SetModifyHdl( LINK( this, ColorPickerDialog, ColorSliderControlModifyHdl ) );
794 int nMargin = (m_xFISliderLeft->get_preferred_size().Height() + 1) / 2;
795 m_xColorSlider->set_margin_top(nMargin);
796 m_xColorSlider->set_margin_bottom(nMargin);
798 Link<weld::MetricSpinButton&,void> aLink3( LINK( this, ColorPickerDialog, ColorModifyMetricHdl ) );
799 m_xMFCyan->connect_value_changed( aLink3 );
800 m_xMFMagenta->connect_value_changed( aLink3 );
801 m_xMFYellow->connect_value_changed( aLink3 );
802 m_xMFKey->connect_value_changed( aLink3 );
804 m_xMFHue->connect_value_changed( aLink3 );
805 m_xMFSaturation->connect_value_changed( aLink3 );
806 m_xMFBrightness->connect_value_changed( aLink3 );
808 Link<weld::SpinButton&,void> aLink4(LINK(this, ColorPickerDialog, ColorModifySpinHdl));
809 m_xMFRed->connect_value_changed(aLink4);
810 m_xMFGreen->connect_value_changed(aLink4);
811 m_xMFBlue->connect_value_changed(aLink4);
813 m_xEDHex->connect_changed(LINK(this, ColorPickerDialog, ColorModifyEditHdl));
815 Link<weld::ToggleButton&,void> aLink2 = LINK( this, ColorPickerDialog, ModeModifyHdl );
816 m_xRBRed->connect_toggled( aLink2 );
817 m_xRBGreen->connect_toggled( aLink2 );
818 m_xRBBlue->connect_toggled( aLink2 );
819 m_xRBHue->connect_toggled( aLink2 );
820 m_xRBSaturation->connect_toggled( aLink2 );
821 m_xRBBrightness->connect_toggled( aLink2 );
823 Color aColor(nColor);
825 // modify
826 if (nDialogMode == 2)
828 m_aColorPrevious.SetColor(aColor);
829 m_xColorPrevious->show();
832 mdRed = static_cast<double>(aColor.GetRed()) / 255.0;
833 mdGreen = static_cast<double>(aColor.GetGreen()) / 255.0;
834 mdBlue = static_cast<double>(aColor.GetBlue()) / 255.0;
836 RGBtoHSV( mdRed, mdGreen, mdBlue, mdHue, mdSat, mdBri );
837 RGBtoCMYK( mdRed, mdGreen, mdBlue, mdCyan, mdMagenta, mdYellow, mdKey );
839 update_color();
842 static int toInt( double dValue, double dRange )
844 return static_cast< int >( std::floor((dValue * dRange) + 0.5 ) );
847 Color ColorPickerDialog::GetColor() const
849 return Color( toInt(mdRed,255.0), toInt(mdGreen,255.0), toInt(mdBlue,255.0) );
852 void ColorPickerDialog::update_color( UpdateFlags n )
854 sal_uInt8 nRed = toInt(mdRed,255.0);
855 sal_uInt8 nGreen = toInt(mdGreen,255.0);
856 sal_uInt8 nBlue = toInt(mdBlue,255.0);
858 Color aColor(nRed, nGreen, nBlue);
860 if (n & UpdateFlags::RGB) // update RGB
862 m_xMFRed->set_value(nRed);
863 m_xMFGreen->set_value(nGreen);
864 m_xMFBlue->set_value(nBlue);
867 if (n & UpdateFlags::CMYK) // update CMYK
869 m_xMFCyan->set_value(toInt(mdCyan, 100.0), FieldUnit::PERCENT);
870 m_xMFMagenta->set_value(toInt(mdMagenta, 100.0), FieldUnit::PERCENT);
871 m_xMFYellow->set_value(toInt(mdYellow, 100.0), FieldUnit::PERCENT);
872 m_xMFKey->set_value(toInt(mdKey, 100.0), FieldUnit::PERCENT);
875 if (n & UpdateFlags::HSB ) // update HSB
877 m_xMFHue->set_value(toInt(mdHue, 1.0), FieldUnit::DEGREE);
878 m_xMFSaturation->set_value(toInt( mdSat, 100.0), FieldUnit::PERCENT);
879 m_xMFBrightness->set_value(toInt( mdBri, 100.0), FieldUnit::PERCENT);
882 if (n & UpdateFlags::ColorChooser ) // update Color Chooser 1
884 switch( meMode )
886 case HUE:
887 m_aColorField.SetValues(aColor, meMode, mdSat, mdBri);
888 break;
889 case SATURATION:
890 m_aColorField.SetValues(aColor, meMode, mdHue / 360.0, mdBri);
891 break;
892 case BRIGHTNESS:
893 m_aColorField.SetValues(aColor, meMode, mdHue / 360.0, mdSat);
894 break;
895 case RED:
896 m_aColorField.SetValues(aColor, meMode, mdBlue, mdGreen);
897 break;
898 case GREEN:
899 m_aColorField.SetValues(aColor, meMode, mdBlue, mdRed);
900 break;
901 case BLUE:
902 m_aColorField.SetValues(aColor, meMode, mdRed, mdGreen);
903 break;
907 if (n & UpdateFlags::ColorSlider) // update Color Chooser 2
909 switch (meMode)
911 case HUE:
912 m_aColorSlider.SetValue(aColor, meMode, mdHue / 360.0);
913 break;
914 case SATURATION:
915 m_aColorSlider.SetValue(aColor, meMode, mdSat);
916 break;
917 case BRIGHTNESS:
918 m_aColorSlider.SetValue(aColor, meMode, mdBri);
919 break;
920 case RED:
921 m_aColorSlider.SetValue(aColor, meMode, mdRed);
922 break;
923 case GREEN:
924 m_aColorSlider.SetValue(aColor, meMode, mdGreen);
925 break;
926 case BLUE:
927 m_aColorSlider.SetValue(aColor, meMode, mdBlue);
928 break;
932 if (n & UpdateFlags::Hex) // update hex
934 m_xFISliderLeft->set_margin_top(m_aColorSlider.GetLevel());
935 m_xFISliderRight->set_margin_top(m_aColorSlider.GetLevel());
936 m_xEDHex->SetColor(aColor);
938 m_aColorPreview.SetColor(aColor);
941 IMPL_LINK_NOARG(ColorPickerDialog, ColorFieldControlModifydl, ColorFieldControl&, void)
943 double x = m_aColorField.GetX();
944 double y = m_aColorField.GetY();
946 switch( meMode )
948 case HUE:
949 mdSat = x;
950 setColorComponent( ColorComponent::Brightness, y );
951 break;
952 case SATURATION:
953 mdHue = x * 360.0;
954 setColorComponent( ColorComponent::Brightness, y );
955 break;
956 case BRIGHTNESS:
957 mdHue = x * 360.0;
958 setColorComponent( ColorComponent::Saturation, y );
959 break;
960 case RED:
961 mdBlue = x;
962 setColorComponent( ColorComponent::Green, y );
963 break;
964 case GREEN:
965 mdBlue = x;
966 setColorComponent( ColorComponent::Red, y );
967 break;
968 case BLUE:
969 mdRed = x;
970 setColorComponent( ColorComponent::Green, y );
971 break;
974 update_color(UpdateFlags::All & ~UpdateFlags::ColorChooser);
977 IMPL_LINK_NOARG(ColorPickerDialog, ColorSliderControlModifyHdl, ColorSliderControl&, void)
979 double dValue = m_aColorSlider.GetValue();
980 switch (meMode)
982 case HUE:
983 setColorComponent( ColorComponent::Hue, dValue * 360.0 );
984 break;
985 case SATURATION:
986 setColorComponent( ColorComponent::Saturation, dValue );
987 break;
988 case BRIGHTNESS:
989 setColorComponent( ColorComponent::Brightness, dValue );
990 break;
991 case RED:
992 setColorComponent( ColorComponent::Red, dValue );
993 break;
994 case GREEN:
995 setColorComponent( ColorComponent::Green, dValue );
996 break;
997 case BLUE:
998 setColorComponent( ColorComponent::Blue, dValue );
999 break;
1002 update_color(UpdateFlags::All & ~UpdateFlags::ColorSlider);
1005 IMPL_LINK(ColorPickerDialog, ColorModifyMetricHdl, weld::MetricSpinButton&, rEdit, void)
1007 UpdateFlags n = UpdateFlags::NONE;
1009 if (&rEdit == m_xMFHue.get())
1011 setColorComponent( ColorComponent::Hue, static_cast<double>(m_xMFHue->get_value(FieldUnit::DEGREE)) );
1012 n = UpdateFlags::All & ~UpdateFlags::HSB;
1014 else if (&rEdit == m_xMFSaturation.get())
1016 setColorComponent( ColorComponent::Saturation, static_cast<double>(m_xMFSaturation->get_value(FieldUnit::PERCENT)) / 100.0 );
1017 n = UpdateFlags::All & ~UpdateFlags::HSB;
1019 else if (&rEdit == m_xMFBrightness.get())
1021 setColorComponent( ColorComponent::Brightness, static_cast<double>(m_xMFBrightness->get_value(FieldUnit::PERCENT)) / 100.0 );
1022 n = UpdateFlags::All & ~UpdateFlags::HSB;
1024 else if (&rEdit == m_xMFCyan.get())
1026 setColorComponent( ColorComponent::Cyan, static_cast<double>(m_xMFCyan->get_value(FieldUnit::PERCENT)) / 100.0 );
1027 n = UpdateFlags::All & ~UpdateFlags::CMYK;
1029 else if (&rEdit == m_xMFMagenta.get())
1031 setColorComponent( ColorComponent::Magenta, static_cast<double>(m_xMFMagenta->get_value(FieldUnit::PERCENT)) / 100.0 );
1032 n = UpdateFlags::All & ~UpdateFlags::CMYK;
1034 else if (&rEdit == m_xMFYellow.get())
1036 setColorComponent( ColorComponent::Yellow, static_cast<double>(m_xMFYellow->get_value(FieldUnit::PERCENT)) / 100.0 );
1037 n = UpdateFlags::All & ~UpdateFlags::CMYK;
1039 else if (&rEdit == m_xMFKey.get())
1041 setColorComponent( ColorComponent::Key, static_cast<double>(m_xMFKey->get_value(FieldUnit::PERCENT)) / 100.0 );
1042 n = UpdateFlags::All & ~UpdateFlags::CMYK;
1045 if (n != UpdateFlags::NONE)
1046 update_color(n);
1049 IMPL_LINK_NOARG(ColorPickerDialog, ColorModifyEditHdl, weld::Entry&, void)
1051 UpdateFlags n = UpdateFlags::NONE;
1053 Color aColor = m_xEDHex->GetColor();
1055 if (aColor != Color(0xffffffff) && aColor != GetColor())
1057 mdRed = static_cast<double>(aColor.GetRed()) / 255.0;
1058 mdGreen = static_cast<double>(aColor.GetGreen()) / 255.0;
1059 mdBlue = static_cast<double>(aColor.GetBlue()) / 255.0;
1061 RGBtoHSV( mdRed, mdGreen, mdBlue, mdHue, mdSat, mdBri );
1062 RGBtoCMYK( mdRed, mdGreen, mdBlue, mdCyan, mdMagenta, mdYellow, mdKey );
1063 n = UpdateFlags::All & ~UpdateFlags::Hex;
1066 if (n != UpdateFlags::NONE)
1067 update_color(n);
1070 IMPL_LINK(ColorPickerDialog, ColorModifySpinHdl, weld::SpinButton&, rEdit, void)
1072 UpdateFlags n = UpdateFlags::NONE;
1074 if (&rEdit == m_xMFRed.get())
1076 setColorComponent( ColorComponent::Red, static_cast<double>(m_xMFRed->get_value()) / 255.0 );
1077 n = UpdateFlags::All & ~UpdateFlags::RGB;
1079 else if (&rEdit == m_xMFGreen.get())
1081 setColorComponent( ColorComponent::Green, static_cast<double>(m_xMFGreen->get_value()) / 255.0 );
1082 n = UpdateFlags::All & ~UpdateFlags::RGB;
1084 else if (&rEdit == m_xMFBlue.get())
1086 setColorComponent( ColorComponent::Blue, static_cast<double>(m_xMFBlue->get_value()) / 255.0 );
1087 n = UpdateFlags::All & ~UpdateFlags::RGB;
1090 if (n != UpdateFlags::NONE)
1091 update_color(n);
1095 IMPL_LINK_NOARG(ColorPickerDialog, ModeModifyHdl, weld::ToggleButton&, void)
1097 ColorMode eMode = HUE;
1099 if (m_xRBRed->get_active())
1101 eMode = RED;
1103 else if (m_xRBGreen->get_active())
1105 eMode = GREEN;
1107 else if (m_xRBBlue->get_active())
1109 eMode = BLUE;
1111 else if (m_xRBSaturation->get_active())
1113 eMode = SATURATION;
1115 else if (m_xRBBrightness->get_active())
1117 eMode = BRIGHTNESS;
1120 if (meMode != eMode)
1122 meMode = eMode;
1123 update_color(UpdateFlags::ColorChooser | UpdateFlags::ColorSlider);
1127 void ColorPickerDialog::setColorComponent( ColorComponent nComp, double dValue )
1129 switch( nComp )
1131 case ColorComponent::Red:
1132 mdRed = dValue;
1133 break;
1134 case ColorComponent::Green:
1135 mdGreen = dValue;
1136 break;
1137 case ColorComponent::Blue:
1138 mdBlue = dValue;
1139 break;
1140 case ColorComponent::Hue:
1141 mdHue = dValue;
1142 break;
1143 case ColorComponent::Saturation:
1144 mdSat = dValue;
1145 break;
1146 case ColorComponent::Brightness:
1147 mdBri = dValue;
1148 break;
1149 case ColorComponent::Cyan:
1150 mdCyan = dValue;
1151 break;
1152 case ColorComponent::Yellow:
1153 mdYellow = dValue;
1154 break;
1155 case ColorComponent::Magenta:
1156 mdMagenta = dValue;
1157 break;
1158 case ColorComponent::Key:
1159 mdKey = dValue;
1160 break;
1163 if (nComp == ColorComponent::Red || nComp == ColorComponent::Green || nComp == ColorComponent::Blue)
1165 RGBtoHSV( mdRed, mdGreen, mdBlue, mdHue, mdSat, mdBri );
1166 RGBtoCMYK( mdRed, mdGreen, mdBlue, mdCyan, mdMagenta, mdYellow, mdKey );
1168 else if (nComp == ColorComponent::Hue || nComp == ColorComponent::Saturation || nComp == ColorComponent::Brightness)
1170 HSVtoRGB( mdHue, mdSat, mdBri, mdRed, mdGreen, mdBlue );
1171 RGBtoCMYK( mdRed, mdGreen, mdBlue, mdCyan, mdMagenta, mdYellow, mdKey );
1173 else
1175 CMYKtoRGB( mdCyan, mdMagenta, mdYellow, mdKey, mdRed, mdGreen, mdBlue );
1176 RGBtoHSV( mdRed, mdGreen, mdBlue, mdHue, mdSat, mdBri );
1180 typedef ::cppu::WeakComponentImplHelper< XServiceInfo, XExecutableDialog, XInitialization, XPropertyAccess > ColorPickerBase;
1182 class ColorPicker : protected ::cppu::BaseMutex, // Struct for right initialization of mutex member! Must be first of baseclasses.
1183 public ColorPickerBase
1185 public:
1186 explicit ColorPicker();
1188 // XInitialization
1189 virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override;
1191 // XInitialization
1192 virtual OUString SAL_CALL getImplementationName( ) override;
1193 virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
1194 virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
1196 // XPropertyAccess
1197 virtual Sequence< PropertyValue > SAL_CALL getPropertyValues( ) override;
1198 virtual void SAL_CALL setPropertyValues( const Sequence< PropertyValue >& aProps ) override;
1200 // XExecutableDialog
1201 virtual void SAL_CALL setTitle( const OUString& aTitle ) override;
1202 virtual sal_Int16 SAL_CALL execute( ) override;
1204 private:
1205 Color mnColor;
1206 sal_Int16 mnMode;
1207 Reference<css::awt::XWindow> mxParent;
1210 OUString ColorPicker_getImplementationName()
1212 return "com.sun.star.cui.ColorPicker";
1215 Reference< XInterface > ColorPicker_createInstance( Reference< XComponentContext > const & )
1217 return static_cast<XWeak*>( new ColorPicker );
1220 Sequence< OUString > ColorPicker_getSupportedServiceNames()
1222 Sequence< OUString > seq { "com.sun.star.ui.dialogs.ColorPicker" };
1223 return seq;
1226 static const OUStringLiteral gsColorKey( "Color" );
1227 static const OUStringLiteral gsModeKey( "Mode" );
1229 ColorPicker::ColorPicker()
1230 : ColorPickerBase( m_aMutex )
1231 , mnColor( 0 )
1232 , mnMode( 0 )
1236 // XInitialization
1237 void SAL_CALL ColorPicker::initialize( const Sequence< Any >& aArguments )
1239 if( aArguments.getLength() == 1 )
1241 aArguments[0] >>= mxParent;
1245 // XInitialization
1246 OUString SAL_CALL ColorPicker::getImplementationName( )
1248 return ColorPicker_getImplementationName();
1251 sal_Bool SAL_CALL ColorPicker::supportsService( const OUString& sServiceName )
1253 return cppu::supportsService(this, sServiceName);
1256 Sequence< OUString > SAL_CALL ColorPicker::getSupportedServiceNames( )
1258 return ColorPicker_getSupportedServiceNames();
1261 // XPropertyAccess
1262 Sequence< PropertyValue > SAL_CALL ColorPicker::getPropertyValues( )
1264 Sequence< PropertyValue > props(1);
1265 props[0].Name = gsColorKey;
1266 props[0].Value <<= mnColor;
1267 return props;
1270 void SAL_CALL ColorPicker::setPropertyValues( const Sequence< PropertyValue >& aProps )
1272 for( sal_Int32 n = 0; n < aProps.getLength(); n++ )
1274 if( aProps[n].Name == gsColorKey )
1276 aProps[n].Value >>= mnColor;
1278 else if( aProps[n].Name == gsModeKey )
1280 aProps[n].Value >>= mnMode;
1285 // XExecutableDialog
1286 void SAL_CALL ColorPicker::setTitle( const OUString& )
1290 sal_Int16 SAL_CALL ColorPicker::execute()
1292 std::unique_ptr<ColorPickerDialog> xDlg(new ColorPickerDialog(Application::GetFrameWeld(mxParent), mnColor, mnMode));
1293 sal_Int16 ret = xDlg->run();
1294 if (ret)
1295 mnColor = xDlg->GetColor();
1296 return ret;
1301 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */