bump product version to 6.3.0.0.beta1
[LibreOffice.git] / cui / source / dialogs / colorpicker.cxx
blob4587f52660cccda74ceb44f848bc6e6781bb4a61
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/datatransfer/XTransferable.hpp>
26 #include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
27 #include <com/sun/star/awt/XWindow.hpp>
28 #include <cppuhelper/compbase.hxx>
29 #include <cppuhelper/supportsservice.hxx>
30 #include <cppuhelper/basemutex.hxx>
31 #include <vcl/customweld.hxx>
32 #include <vcl/bitmapaccess.hxx>
33 #include <vcl/event.hxx>
34 #include <vcl/svapp.hxx>
35 #include <vcl/virdev.hxx>
36 #include <vcl/weld.hxx>
37 #include <toolkit/helper/vclunohelper.hxx>
38 #include <sot/exchange.hxx>
39 #include <sot/formats.hxx>
40 #include <svx/hexcolorcontrol.hxx>
41 #include <sax/tools/converter.hxx>
42 #include <basegfx/color/bcolortools.hxx>
43 #include <colorpicker.hxx>
44 #include <bitmaps.hlst>
45 #include <cmath>
46 #include <limits>
47 #include <o3tl/typed_flags_set.hxx>
49 using namespace ::com::sun::star::uno;
50 using namespace ::com::sun::star::lang;
51 using namespace ::com::sun::star::ui::dialogs;
52 using namespace ::com::sun::star::beans;
53 using namespace ::basegfx;
55 enum class UpdateFlags
57 NONE = 0x00,
58 RGB = 0x01,
59 CMYK = 0x02,
60 HSB = 0x04,
61 ColorChooser = 0x08,
62 ColorSlider = 0x10,
63 Hex = 0x20,
64 All = 0x3f,
66 namespace o3tl {
67 template<> struct typed_flags<UpdateFlags> : is_typed_flags<UpdateFlags, 0x3f> {};
71 namespace cui
74 enum class ColorComponent {
75 Red,
76 Green,
77 Blue,
78 Hue,
79 Saturation,
80 Brightness,
81 Cyan,
82 Yellow,
83 Magenta,
84 Key,
88 // color space conversion helpers
90 static void RGBtoHSV( double dR, double dG, double dB, double& dH, double& dS, double& dV )
92 BColor result = basegfx::utils::rgb2hsv( BColor( dR, dG, dB ) );
94 dH = result.getX();
95 dS = result.getY();
96 dV = result.getZ();
99 static void HSVtoRGB(double dH, double dS, double dV, double& dR, double& dG, double& dB )
101 BColor result = basegfx::utils::hsv2rgb( BColor( dH, dS, dV ) );
103 dR = result.getRed();
104 dG = result.getGreen();
105 dB = result.getBlue();
108 // CMYK values from 0 to 1
109 static void CMYKtoRGB( double fCyan, double fMagenta, double fYellow, double fKey, double& dR, double& dG, double& dB )
111 fCyan = (fCyan * ( 1.0 - fKey )) + fKey;
112 fMagenta = (fMagenta * ( 1.0 - fKey )) + fKey;
113 fYellow = (fYellow * ( 1.0 - fKey )) + fKey;
115 dR = std::max( std::min( ( 1.0 - fCyan ), 1.0), 0.0 );
116 dG = std::max( std::min( ( 1.0 - fMagenta ), 1.0), 0.0 );
117 dB = std::max( std::min( ( 1.0 - fYellow ), 1.0), 0.0 );
120 // CMY results from 0 to 1
121 static void RGBtoCMYK( double dR, double dG, double dB, double& fCyan, double& fMagenta, double& fYellow, double& fKey )
123 fCyan = 1 - dR;
124 fMagenta = 1 - dG;
125 fYellow = 1 - dB;
127 //CMYK and CMY values from 0 to 1
128 fKey = 1.0;
129 if( fCyan < fKey ) fKey = fCyan;
130 if( fMagenta < fKey ) fKey = fMagenta;
131 if( fYellow < fKey ) fKey = fYellow;
133 if( fKey >= 1.0 )
135 //Black
136 fCyan = 0.0;
137 fMagenta = 0.0;
138 fYellow = 0.0;
140 else
142 fCyan = ( fCyan - fKey ) / ( 1.0 - fKey );
143 fMagenta = ( fMagenta - fKey ) / ( 1.0 - fKey );
144 fYellow = ( fYellow - fKey ) / ( 1.0 - fKey );
148 class ColorPreviewControl : public weld::CustomWidgetController
150 private:
151 Color m_aColor;
153 virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) override;
154 public:
155 ColorPreviewControl()
159 virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override
161 CustomWidgetController::SetDrawingArea(pDrawingArea);
162 pDrawingArea->set_size_request(pDrawingArea->get_approximate_digit_width() * 10,
163 pDrawingArea->get_text_height() * 2);
166 void SetColor(const Color& rCol)
168 if (rCol != m_aColor)
170 m_aColor = rCol;
171 Invalidate();
176 void ColorPreviewControl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
178 rRenderContext.SetFillColor(m_aColor);
179 rRenderContext.SetLineColor(m_aColor);
180 rRenderContext.DrawRect(tools::Rectangle(Point(0, 0), GetOutputSizePixel()));
183 enum ColorMode { HUE, SATURATION, BRIGHTNESS, RED, GREEN, BLUE };
184 const ColorMode DefaultMode = HUE;
186 class ColorFieldControl : public weld::CustomWidgetController
188 public:
189 ColorFieldControl()
190 : meMode( DefaultMode )
191 , mdX( -1.0 )
192 , mdY( -1.0 )
193 , mbMouseCaptured(false)
197 virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override
199 CustomWidgetController::SetDrawingArea(pDrawingArea);
200 pDrawingArea->set_size_request(pDrawingArea->get_approximate_digit_width() * 40,
201 pDrawingArea->get_text_height() * 10);
204 virtual ~ColorFieldControl() override
206 mxBitmap.disposeAndClear();
209 virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override;
210 virtual void Resize() override;
211 virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
212 virtual bool MouseMove(const MouseEvent& rMEvt) override;
213 virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
215 void UpdateBitmap();
216 void ShowPosition( const Point& rPos, bool bUpdate );
217 void UpdatePosition();
218 void Modify();
220 void SetValues(Color aColor, ColorMode eMode, double x, double y);
221 double GetX() { return mdX;}
222 double GetY() { return mdY;}
224 void SetModifyHdl(const Link<ColorFieldControl&,void>& rLink) { maModifyHdl = rLink; }
226 private:
227 ColorMode meMode;
228 Color maColor;
229 double mdX;
230 double mdY;
231 bool mbMouseCaptured;
232 Point maPosition;
233 VclPtr<VirtualDevice> mxBitmap;
234 Link<ColorFieldControl&,void> maModifyHdl;
235 std::vector<sal_uInt8> maRGB_Horiz;
236 std::vector<sal_uInt16> maGrad_Horiz;
237 std::vector<sal_uInt16> maPercent_Horiz;
238 std::vector<sal_uInt8> maRGB_Vert;
239 std::vector<sal_uInt16> maPercent_Vert;
242 void ColorFieldControl::UpdateBitmap()
244 const Size aSize(GetOutputSizePixel());
246 if (mxBitmap && mxBitmap->GetOutputSizePixel() != aSize)
247 mxBitmap.disposeAndClear();
249 const sal_Int32 nWidth = aSize.Width();
250 const sal_Int32 nHeight = aSize.Height();
252 if (nWidth == 0 || nHeight == 0)
253 return;
255 if (!mxBitmap)
257 mxBitmap = VclPtr<VirtualDevice>::Create();
258 mxBitmap->SetOutputSizePixel(aSize);
260 maRGB_Horiz.resize( nWidth );
261 maGrad_Horiz.resize( nWidth );
262 maPercent_Horiz.resize( nWidth );
264 sal_uInt8* pRGB = maRGB_Horiz.data();
265 sal_uInt16* pGrad = maGrad_Horiz.data();
266 sal_uInt16* pPercent = maPercent_Horiz.data();
268 for( sal_Int32 x = 0; x < nWidth; x++ )
270 *pRGB++ = static_cast<sal_uInt8>((x * 256) / nWidth);
271 *pGrad++ = static_cast<sal_uInt16>((x * 359) / nWidth);
272 *pPercent++ = static_cast<sal_uInt16>((x * 100) / nWidth);
275 maRGB_Vert.resize(nHeight);
276 maPercent_Vert.resize(nHeight);
278 pRGB = maRGB_Vert.data();
279 pPercent = maPercent_Vert.data();
281 sal_Int32 y = nHeight;
282 while (y--)
284 *pRGB++ = static_cast<sal_uInt8>((y * 256) / nHeight);
285 *pPercent++ = static_cast<sal_uInt16>((y * 100) / nHeight);
289 sal_uInt8* pRGB_Horiz = maRGB_Horiz.data();
290 sal_uInt16* pGrad_Horiz = maGrad_Horiz.data();
291 sal_uInt16* pPercent_Horiz = maPercent_Horiz.data();
292 sal_uInt8* pRGB_Vert = maRGB_Vert.data();
293 sal_uInt16* pPercent_Vert = maPercent_Vert.data();
295 Color aBitmapColor(maColor);
297 sal_uInt16 nHue, nSat, nBri;
298 maColor.RGBtoHSB(nHue, nSat, nBri);
300 // this has been unlooped for performance reason, please do not merge back!
302 sal_uInt16 y = nHeight,x;
304 switch(meMode)
306 case HUE:
307 while (y--)
309 nBri = pPercent_Vert[y];
310 x = nWidth;
311 while (x--)
313 nSat = pPercent_Horiz[x];
314 mxBitmap->DrawPixel(Point(x,y), Color::HSBtoRGB(nHue, nSat, nBri));
317 break;
318 case SATURATION:
319 while (y--)
321 nBri = pPercent_Vert[y];
322 x = nWidth;
323 while (x--)
325 nHue = pGrad_Horiz[x];
326 mxBitmap->DrawPixel(Point(x,y), Color::HSBtoRGB(nHue, nSat, nBri));
329 break;
330 case BRIGHTNESS:
331 while (y--)
333 nSat = pPercent_Vert[y];
334 x = nWidth;
335 while (x--)
337 nHue = pGrad_Horiz[x];
338 mxBitmap->DrawPixel(Point(x,y), Color::HSBtoRGB(nHue, nSat, nBri));
341 break;
342 case RED:
343 while (y--)
345 aBitmapColor.SetGreen(pRGB_Vert[y]);
346 x = nWidth;
347 while (x--)
349 aBitmapColor.SetBlue(pRGB_Horiz[x]);
350 mxBitmap->DrawPixel(Point(x,y), aBitmapColor);
353 break;
354 case GREEN:
355 while (y--)
357 aBitmapColor.SetRed(pRGB_Vert[y]);
358 x = nWidth;
359 while (x--)
361 aBitmapColor.SetBlue(pRGB_Horiz[x]);
362 mxBitmap->DrawPixel(Point(x,y), aBitmapColor);
365 break;
366 case BLUE:
367 while (y--)
369 aBitmapColor.SetGreen(pRGB_Vert[y]);
370 x = nWidth;
371 while (x--)
373 aBitmapColor.SetRed(pRGB_Horiz[x]);
374 mxBitmap->DrawPixel(Point(x,y), aBitmapColor);
377 break;
381 void ColorFieldControl::ShowPosition( const Point& rPos, bool bUpdate )
383 if (!mxBitmap)
385 UpdateBitmap();
386 Invalidate();
389 if (!mxBitmap)
390 return;
392 const Size aSize(mxBitmap->GetOutputSizePixel());
394 long nX = rPos.X();
395 long nY = rPos.Y();
396 if (nX < 0)
397 nX = 0;
398 else if (nX >= aSize.Width())
399 nX = aSize.Width() - 1;
401 if (nY < 0)
402 nY = 0;
403 else if (nY >= aSize.Height())
404 nY = aSize.Height() - 1;
406 Point aPos = maPosition;
407 maPosition.setX( nX - 5 );
408 maPosition.setY( nY - 5 );
409 Invalidate(tools::Rectangle(aPos, Size(11, 11)));
410 Invalidate(tools::Rectangle(maPosition, Size(11, 11)));
412 if (bUpdate)
414 mdX = double(nX) / double(aSize.Width() - 1.0);
415 mdY = double(aSize.Height() - 1.0 - nY) / double(aSize.Height() - 1.0);
417 maColor = mxBitmap->GetPixel(Point(nX, nY));
421 bool ColorFieldControl::MouseButtonDown(const MouseEvent& rMEvt)
423 CaptureMouse();
424 mbMouseCaptured = true;
425 ShowPosition(rMEvt.GetPosPixel(), true);
426 Modify();
427 return true;
430 bool ColorFieldControl::MouseMove(const MouseEvent& rMEvt)
432 if (mbMouseCaptured)
434 ShowPosition(rMEvt.GetPosPixel(), true);
435 Modify();
437 return true;
440 bool ColorFieldControl::MouseButtonUp(const MouseEvent&)
442 ReleaseMouse();
443 mbMouseCaptured = false;
444 return true;
447 void ColorFieldControl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
449 if (!mxBitmap)
450 UpdateBitmap();
452 if (mxBitmap)
454 Size aSize(GetOutputSizePixel());
455 rRenderContext.DrawOutDev(Point(0, 0), aSize, Point(0, 0), aSize, *mxBitmap);
458 // draw circle around current color
459 if (maColor.IsDark())
460 rRenderContext.SetLineColor( COL_WHITE );
461 else
462 rRenderContext.SetLineColor( COL_BLACK );
464 rRenderContext.SetFillColor();
466 rRenderContext.DrawEllipse(::tools::Rectangle(maPosition, Size(11, 11)));
469 void ColorFieldControl::Resize()
471 CustomWidgetController::Resize();
472 UpdateBitmap();
473 UpdatePosition();
476 void ColorFieldControl::Modify()
478 maModifyHdl.Call( *this );
481 void ColorFieldControl::SetValues( Color aColor, ColorMode eMode, double x, double y )
483 bool bUpdateBitmap = (maColor!= aColor) || (meMode != eMode);
484 if( bUpdateBitmap || (mdX != x) || (mdY != y) )
486 maColor = aColor;
487 meMode = eMode;
488 mdX = x;
489 mdY = y;
491 if (bUpdateBitmap)
492 UpdateBitmap();
493 UpdatePosition();
494 if (bUpdateBitmap)
495 Invalidate();
499 void ColorFieldControl::UpdatePosition()
501 Size aSize(GetOutputSizePixel());
502 ShowPosition(Point(static_cast<long>(mdX * aSize.Width()), static_cast<long>((1.0 - mdY) * aSize.Height())), false);
505 class ColorSliderControl : public weld::CustomWidgetController
507 public:
508 ColorSliderControl();
509 virtual ~ColorSliderControl() override;
511 virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
513 virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
514 virtual bool MouseMove(const MouseEvent& rMEvt) override;
515 virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
516 virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) override;
517 virtual void Resize() override;
519 void UpdateBitmap();
520 void ChangePosition( long nY );
521 void Modify();
523 void SetValue( const Color& rColor, ColorMode eMode, double dValue );
524 double GetValue() const { return mdValue; }
526 void SetModifyHdl( const Link<ColorSliderControl&,void>& rLink ) { maModifyHdl = rLink; }
528 sal_Int16 GetLevel() const { return mnLevel; }
530 private:
531 Link<ColorSliderControl&,void> maModifyHdl;
532 Color maColor;
533 ColorMode meMode;
534 VclPtr<VirtualDevice> mxBitmap;
535 sal_Int16 mnLevel;
536 double mdValue;
539 ColorSliderControl::ColorSliderControl()
540 : meMode( DefaultMode )
541 , mnLevel( 0 )
542 , mdValue( -1.0 )
546 void ColorSliderControl::SetDrawingArea(weld::DrawingArea* pDrawingArea)
548 CustomWidgetController::SetDrawingArea(pDrawingArea);
549 pDrawingArea->set_size_request(pDrawingArea->get_approximate_digit_width() * 3, -1);
552 ColorSliderControl::~ColorSliderControl()
554 mxBitmap.disposeAndClear();
557 void ColorSliderControl::UpdateBitmap()
559 Size aSize(1, GetOutputSizePixel().Height());
561 if (mxBitmap && mxBitmap->GetOutputSizePixel() != aSize)
562 mxBitmap.disposeAndClear();
564 if (!mxBitmap)
566 mxBitmap = VclPtr<VirtualDevice>::Create();
567 mxBitmap->SetOutputSizePixel(aSize);
570 const long nY = aSize.Height() - 1;
572 Color aBitmapColor(maColor);
574 sal_uInt16 nHue, nSat, nBri;
575 maColor.RGBtoHSB(nHue, nSat, nBri);
577 // this has been unlooped for performance reason, please do not merge back!
579 switch (meMode)
581 case HUE:
582 nSat = 100;
583 nBri = 100;
584 for (long y = 0; y <= nY; y++)
586 nHue = static_cast<sal_uInt16>((359 * y) / nY);
587 mxBitmap->DrawPixel(Point(0, nY - y), Color::HSBtoRGB(nHue, nSat, nBri));
589 break;
591 case SATURATION:
592 nBri = std::max(sal_uInt16(32), nBri);
593 for (long y = 0; y <= nY; y++)
595 nSat = static_cast<sal_uInt16>((100 * y) / nY);
596 mxBitmap->DrawPixel(Point(0, nY - y), Color::HSBtoRGB(nHue, nSat, nBri));
598 break;
600 case BRIGHTNESS:
601 for (long y = 0; y <= nY; y++)
603 nBri = static_cast<sal_uInt16>((100 * y) / nY);
604 mxBitmap->DrawPixel(Point(0, nY - y), Color::HSBtoRGB(nHue, nSat, nBri));
606 break;
608 case RED:
609 for (long y = 0; y <= nY; y++)
611 aBitmapColor.SetRed(sal_uInt8((long(255) * y) / nY));
612 mxBitmap->DrawPixel(Point(0, nY - y), aBitmapColor);
614 break;
616 case GREEN:
617 for (long y = 0; y <= nY; y++)
619 aBitmapColor.SetGreen(sal_uInt8((long(255) * y) / nY));
620 mxBitmap->DrawPixel(Point(0, nY - y), aBitmapColor);
622 break;
624 case BLUE:
625 for (long y = 0; y <= nY; y++)
627 aBitmapColor.SetBlue(sal_uInt8((long(255) * y) / nY));
628 mxBitmap->DrawPixel(Point(0, nY - y), aBitmapColor);
630 break;
634 void ColorSliderControl::ChangePosition(long nY)
636 const long nHeight = GetOutputSizePixel().Height() - 1;
638 if (nY < 0)
639 nY = 0;
640 else if (nY > nHeight)
641 nY = nHeight;
643 mnLevel = nY;
644 mdValue = double(nHeight - nY) / double(nHeight);
647 bool ColorSliderControl::MouseButtonDown(const MouseEvent& rMEvt)
649 CaptureMouse();
650 ChangePosition(rMEvt.GetPosPixel().Y());
651 Modify();
652 return true;
655 bool ColorSliderControl::MouseMove(const MouseEvent& rMEvt)
657 if (IsMouseCaptured())
659 ChangePosition(rMEvt.GetPosPixel().Y());
660 Modify();
662 return true;
665 bool ColorSliderControl::MouseButtonUp(const MouseEvent&)
667 ReleaseMouse();
668 return true;
671 void ColorSliderControl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
673 if (!mxBitmap)
674 UpdateBitmap();
676 const Size aSize(GetOutputSizePixel());
678 Point aPos;
679 int x = aSize.Width();
680 while (x--)
682 rRenderContext.DrawOutDev(aPos, aSize, Point(0,0), aSize, *mxBitmap);
683 aPos.AdjustX(1);
687 void ColorSliderControl::Resize()
689 CustomWidgetController::Resize();
690 UpdateBitmap();
693 void ColorSliderControl::Modify()
695 maModifyHdl.Call(*this);
698 void ColorSliderControl::SetValue(const Color& rColor, ColorMode eMode, double dValue)
700 bool bUpdateBitmap = (rColor != maColor) || (eMode != meMode);
701 if( bUpdateBitmap || (mdValue != dValue))
703 maColor = rColor;
704 mdValue = dValue;
705 mnLevel = static_cast<sal_Int16>((1.0-dValue) * GetOutputSizePixel().Height());
706 meMode = eMode;
707 if (bUpdateBitmap)
708 UpdateBitmap();
709 Invalidate();
713 class ColorPickerDialog : public weld::GenericDialogController
715 private:
716 ColorFieldControl m_aColorField;
717 ColorSliderControl m_aColorSlider;
718 ColorPreviewControl m_aColorPreview;
719 ColorPreviewControl m_aColorPrevious;
721 std::unique_ptr<weld::CustomWeld> m_xColorField;
722 std::unique_ptr<weld::CustomWeld> m_xColorSlider;
723 std::unique_ptr<weld::CustomWeld> m_xColorPreview;
724 std::unique_ptr<weld::CustomWeld> m_xColorPrevious;
726 std::unique_ptr<weld::Widget> m_xFISliderLeft;
727 std::unique_ptr<weld::Widget> m_xFISliderRight;
728 std::unique_ptr<weld::RadioButton> m_xRBRed;
729 std::unique_ptr<weld::RadioButton> m_xRBGreen;
730 std::unique_ptr<weld::RadioButton> m_xRBBlue;
731 std::unique_ptr<weld::RadioButton> m_xRBHue;
732 std::unique_ptr<weld::RadioButton> m_xRBSaturation;
733 std::unique_ptr<weld::RadioButton> m_xRBBrightness;
735 std::unique_ptr<weld::SpinButton> m_xMFRed;
736 std::unique_ptr<weld::SpinButton> m_xMFGreen;
737 std::unique_ptr<weld::SpinButton> m_xMFBlue;
738 std::unique_ptr<weld::HexColorControl> m_xEDHex;
740 std::unique_ptr<weld::MetricSpinButton> m_xMFHue;
741 std::unique_ptr<weld::MetricSpinButton> m_xMFSaturation;
742 std::unique_ptr<weld::MetricSpinButton> m_xMFBrightness;
744 std::unique_ptr<weld::MetricSpinButton> m_xMFCyan;
745 std::unique_ptr<weld::MetricSpinButton> m_xMFMagenta;
746 std::unique_ptr<weld::MetricSpinButton> m_xMFYellow;
747 std::unique_ptr<weld::MetricSpinButton> m_xMFKey;
749 public:
750 ColorPickerDialog(weld::Window* pParent, Color nColor, sal_Int16 nMode);
752 void update_color(UpdateFlags n = UpdateFlags::All);
754 DECL_LINK(ColorFieldControlModifydl, ColorFieldControl&, void);
755 DECL_LINK(ColorSliderControlModifyHdl, ColorSliderControl&, void);
756 DECL_LINK(ColorModifyMetricHdl, weld::MetricSpinButton&, void);
757 DECL_LINK(ColorModifySpinHdl, weld::SpinButton&, void);
758 DECL_LINK(ColorModifyEditHdl, weld::Entry&, void);
759 DECL_LINK(ModeModifyHdl, weld::ToggleButton&, void);
761 Color GetColor() const;
763 void setColorComponent(ColorComponent nComp, double dValue);
765 private:
766 ColorMode meMode;
768 double mdRed, mdGreen, mdBlue;
769 double mdHue, mdSat, mdBri;
770 double mdCyan, mdMagenta, mdYellow, mdKey;
773 ColorPickerDialog::ColorPickerDialog(weld::Window* pParent, Color nColor, sal_Int16 nDialogMode)
774 : GenericDialogController(pParent, "cui/ui/colorpickerdialog.ui", "ColorPicker")
775 , m_xColorField(new weld::CustomWeld(*m_xBuilder, "colorField", m_aColorField))
776 , m_xColorSlider(new weld::CustomWeld(*m_xBuilder, "colorSlider", m_aColorSlider))
777 , m_xColorPreview(new weld::CustomWeld(*m_xBuilder, "preview", m_aColorPreview))
778 , m_xColorPrevious(new weld::CustomWeld(*m_xBuilder, "previous", m_aColorPrevious))
779 , m_xFISliderLeft(m_xBuilder->weld_widget("leftImage"))
780 , m_xFISliderRight(m_xBuilder->weld_widget("rightImage"))
781 , m_xRBRed(m_xBuilder->weld_radio_button("redRadiobutton"))
782 , m_xRBGreen(m_xBuilder->weld_radio_button("greenRadiobutton"))
783 , m_xRBBlue(m_xBuilder->weld_radio_button("blueRadiobutton"))
784 , m_xRBHue(m_xBuilder->weld_radio_button("hueRadiobutton"))
785 , m_xRBSaturation(m_xBuilder->weld_radio_button("satRadiobutton"))
786 , m_xRBBrightness(m_xBuilder->weld_radio_button("brightRadiobutton"))
787 , m_xMFRed(m_xBuilder->weld_spin_button("redSpinbutton"))
788 , m_xMFGreen(m_xBuilder->weld_spin_button("greenSpinbutton"))
789 , m_xMFBlue(m_xBuilder->weld_spin_button("blueSpinbutton"))
790 , m_xEDHex(new weld::HexColorControl(m_xBuilder->weld_entry("hexEntry")))
791 , m_xMFHue(m_xBuilder->weld_metric_spin_button("hueSpinbutton", FieldUnit::DEGREE))
792 , m_xMFSaturation(m_xBuilder->weld_metric_spin_button("satSpinbutton", FieldUnit::PERCENT))
793 , m_xMFBrightness(m_xBuilder->weld_metric_spin_button("brightSpinbutton", FieldUnit::PERCENT))
794 , m_xMFCyan(m_xBuilder->weld_metric_spin_button("cyanSpinbutton", FieldUnit::PERCENT))
795 , m_xMFMagenta(m_xBuilder->weld_metric_spin_button("magSpinbutton", FieldUnit::PERCENT))
796 , m_xMFYellow(m_xBuilder->weld_metric_spin_button("yellowSpinbutton", FieldUnit::PERCENT))
797 , m_xMFKey(m_xBuilder->weld_metric_spin_button("keySpinbutton", FieldUnit::PERCENT))
798 , meMode( DefaultMode )
800 m_aColorField.SetModifyHdl( LINK( this, ColorPickerDialog, ColorFieldControlModifydl ) );
801 m_aColorSlider.SetModifyHdl( LINK( this, ColorPickerDialog, ColorSliderControlModifyHdl ) );
803 int nMargin = (m_xFISliderLeft->get_preferred_size().Height() + 1) / 2;
804 m_xColorSlider->set_margin_top(nMargin);
805 m_xColorSlider->set_margin_bottom(nMargin);
807 Link<weld::MetricSpinButton&,void> aLink3( LINK( this, ColorPickerDialog, ColorModifyMetricHdl ) );
808 m_xMFCyan->connect_value_changed( aLink3 );
809 m_xMFMagenta->connect_value_changed( aLink3 );
810 m_xMFYellow->connect_value_changed( aLink3 );
811 m_xMFKey->connect_value_changed( aLink3 );
813 m_xMFHue->connect_value_changed( aLink3 );
814 m_xMFSaturation->connect_value_changed( aLink3 );
815 m_xMFBrightness->connect_value_changed( aLink3 );
817 Link<weld::SpinButton&,void> aLink4(LINK(this, ColorPickerDialog, ColorModifySpinHdl));
818 m_xMFRed->connect_value_changed(aLink4);
819 m_xMFGreen->connect_value_changed(aLink4);
820 m_xMFBlue->connect_value_changed(aLink4);
822 m_xEDHex->connect_changed(LINK(this, ColorPickerDialog, ColorModifyEditHdl));
824 Link<weld::ToggleButton&,void> aLink2 = LINK( this, ColorPickerDialog, ModeModifyHdl );
825 m_xRBRed->connect_toggled( aLink2 );
826 m_xRBGreen->connect_toggled( aLink2 );
827 m_xRBBlue->connect_toggled( aLink2 );
828 m_xRBHue->connect_toggled( aLink2 );
829 m_xRBSaturation->connect_toggled( aLink2 );
830 m_xRBBrightness->connect_toggled( aLink2 );
832 Color aColor(nColor);
834 // modify
835 if (nDialogMode == 2)
837 m_aColorPrevious.SetColor(aColor);
838 m_xColorPrevious->show();
841 mdRed = static_cast<double>(aColor.GetRed()) / 255.0;
842 mdGreen = static_cast<double>(aColor.GetGreen()) / 255.0;
843 mdBlue = static_cast<double>(aColor.GetBlue()) / 255.0;
845 RGBtoHSV( mdRed, mdGreen, mdBlue, mdHue, mdSat, mdBri );
846 RGBtoCMYK( mdRed, mdGreen, mdBlue, mdCyan, mdMagenta, mdYellow, mdKey );
848 update_color();
851 static int toInt( double dValue, double dRange )
853 return static_cast< int >( std::floor((dValue * dRange) + 0.5 ) );
856 Color ColorPickerDialog::GetColor() const
858 return Color( toInt(mdRed,255.0), toInt(mdGreen,255.0), toInt(mdBlue,255.0) );
861 void ColorPickerDialog::update_color( UpdateFlags n )
863 sal_uInt8 nRed = toInt(mdRed,255.0);
864 sal_uInt8 nGreen = toInt(mdGreen,255.0);
865 sal_uInt8 nBlue = toInt(mdBlue,255.0);
867 Color aColor(nRed, nGreen, nBlue);
869 if (n & UpdateFlags::RGB) // update RGB
871 m_xMFRed->set_value(nRed);
872 m_xMFGreen->set_value(nGreen);
873 m_xMFBlue->set_value(nBlue);
876 if (n & UpdateFlags::CMYK) // update CMYK
878 m_xMFCyan->set_value(toInt(mdCyan, 100.0), FieldUnit::PERCENT);
879 m_xMFMagenta->set_value(toInt(mdMagenta, 100.0), FieldUnit::PERCENT);
880 m_xMFYellow->set_value(toInt(mdYellow, 100.0), FieldUnit::PERCENT);
881 m_xMFKey->set_value(toInt(mdKey, 100.0), FieldUnit::PERCENT);
884 if (n & UpdateFlags::HSB ) // update HSB
886 m_xMFHue->set_value(toInt(mdHue, 1.0), FieldUnit::DEGREE);
887 m_xMFSaturation->set_value(toInt( mdSat, 100.0), FieldUnit::PERCENT);
888 m_xMFBrightness->set_value(toInt( mdBri, 100.0), FieldUnit::PERCENT);
891 if (n & UpdateFlags::ColorChooser ) // update Color Chooser 1
893 switch( meMode )
895 case HUE:
896 m_aColorField.SetValues(aColor, meMode, mdSat, mdBri);
897 break;
898 case SATURATION:
899 m_aColorField.SetValues(aColor, meMode, mdHue / 360.0, mdBri);
900 break;
901 case BRIGHTNESS:
902 m_aColorField.SetValues(aColor, meMode, mdHue / 360.0, mdSat);
903 break;
904 case RED:
905 m_aColorField.SetValues(aColor, meMode, mdBlue, mdGreen);
906 break;
907 case GREEN:
908 m_aColorField.SetValues(aColor, meMode, mdBlue, mdRed);
909 break;
910 case BLUE:
911 m_aColorField.SetValues(aColor, meMode, mdRed, mdGreen);
912 break;
916 if (n & UpdateFlags::ColorSlider) // update Color Chooser 2
918 switch (meMode)
920 case HUE:
921 m_aColorSlider.SetValue(aColor, meMode, mdHue / 360.0);
922 break;
923 case SATURATION:
924 m_aColorSlider.SetValue(aColor, meMode, mdSat);
925 break;
926 case BRIGHTNESS:
927 m_aColorSlider.SetValue(aColor, meMode, mdBri);
928 break;
929 case RED:
930 m_aColorSlider.SetValue(aColor, meMode, mdRed);
931 break;
932 case GREEN:
933 m_aColorSlider.SetValue(aColor, meMode, mdGreen);
934 break;
935 case BLUE:
936 m_aColorSlider.SetValue(aColor, meMode, mdBlue);
937 break;
941 if (n & UpdateFlags::Hex) // update hex
943 m_xFISliderLeft->set_margin_top(m_aColorSlider.GetLevel());
944 m_xFISliderRight->set_margin_top(m_aColorSlider.GetLevel());
945 m_xEDHex->SetColor(aColor);
947 m_aColorPreview.SetColor(aColor);
950 IMPL_LINK_NOARG(ColorPickerDialog, ColorFieldControlModifydl, ColorFieldControl&, void)
952 double x = m_aColorField.GetX();
953 double y = m_aColorField.GetY();
955 switch( meMode )
957 case HUE:
958 mdSat = x;
959 setColorComponent( ColorComponent::Brightness, y );
960 break;
961 case SATURATION:
962 mdHue = x * 360.0;
963 setColorComponent( ColorComponent::Brightness, y );
964 break;
965 case BRIGHTNESS:
966 mdHue = x * 360.0;
967 setColorComponent( ColorComponent::Saturation, y );
968 break;
969 case RED:
970 mdBlue = x;
971 setColorComponent( ColorComponent::Green, y );
972 break;
973 case GREEN:
974 mdBlue = x;
975 setColorComponent( ColorComponent::Red, y );
976 break;
977 case BLUE:
978 mdRed = x;
979 setColorComponent( ColorComponent::Green, y );
980 break;
983 update_color(UpdateFlags::All & ~UpdateFlags::ColorChooser);
986 IMPL_LINK_NOARG(ColorPickerDialog, ColorSliderControlModifyHdl, ColorSliderControl&, void)
988 double dValue = m_aColorSlider.GetValue();
989 switch (meMode)
991 case HUE:
992 setColorComponent( ColorComponent::Hue, dValue * 360.0 );
993 break;
994 case SATURATION:
995 setColorComponent( ColorComponent::Saturation, dValue );
996 break;
997 case BRIGHTNESS:
998 setColorComponent( ColorComponent::Brightness, dValue );
999 break;
1000 case RED:
1001 setColorComponent( ColorComponent::Red, dValue );
1002 break;
1003 case GREEN:
1004 setColorComponent( ColorComponent::Green, dValue );
1005 break;
1006 case BLUE:
1007 setColorComponent( ColorComponent::Blue, dValue );
1008 break;
1011 update_color(UpdateFlags::All & ~UpdateFlags::ColorSlider);
1014 IMPL_LINK(ColorPickerDialog, ColorModifyMetricHdl, weld::MetricSpinButton&, rEdit, void)
1016 UpdateFlags n = UpdateFlags::NONE;
1018 if (&rEdit == m_xMFHue.get())
1020 setColorComponent( ColorComponent::Hue, static_cast<double>(m_xMFHue->get_value(FieldUnit::DEGREE)) );
1021 n = UpdateFlags::All & ~UpdateFlags::HSB;
1023 else if (&rEdit == m_xMFSaturation.get())
1025 setColorComponent( ColorComponent::Saturation, static_cast<double>(m_xMFSaturation->get_value(FieldUnit::PERCENT)) / 100.0 );
1026 n = UpdateFlags::All & ~UpdateFlags::HSB;
1028 else if (&rEdit == m_xMFBrightness.get())
1030 setColorComponent( ColorComponent::Brightness, static_cast<double>(m_xMFBrightness->get_value(FieldUnit::PERCENT)) / 100.0 );
1031 n = UpdateFlags::All & ~UpdateFlags::HSB;
1033 else if (&rEdit == m_xMFCyan.get())
1035 setColorComponent( ColorComponent::Cyan, static_cast<double>(m_xMFCyan->get_value(FieldUnit::PERCENT)) / 100.0 );
1036 n = UpdateFlags::All & ~UpdateFlags::CMYK;
1038 else if (&rEdit == m_xMFMagenta.get())
1040 setColorComponent( ColorComponent::Magenta, static_cast<double>(m_xMFMagenta->get_value(FieldUnit::PERCENT)) / 100.0 );
1041 n = UpdateFlags::All & ~UpdateFlags::CMYK;
1043 else if (&rEdit == m_xMFYellow.get())
1045 setColorComponent( ColorComponent::Yellow, static_cast<double>(m_xMFYellow->get_value(FieldUnit::PERCENT)) / 100.0 );
1046 n = UpdateFlags::All & ~UpdateFlags::CMYK;
1048 else if (&rEdit == m_xMFKey.get())
1050 setColorComponent( ColorComponent::Key, static_cast<double>(m_xMFKey->get_value(FieldUnit::PERCENT)) / 100.0 );
1051 n = UpdateFlags::All & ~UpdateFlags::CMYK;
1054 if (n != UpdateFlags::NONE)
1055 update_color(n);
1058 IMPL_LINK_NOARG(ColorPickerDialog, ColorModifyEditHdl, weld::Entry&, void)
1060 UpdateFlags n = UpdateFlags::NONE;
1062 Color aColor = m_xEDHex->GetColor();
1064 if (aColor != Color(0xffffffff) && aColor != GetColor())
1066 mdRed = static_cast<double>(aColor.GetRed()) / 255.0;
1067 mdGreen = static_cast<double>(aColor.GetGreen()) / 255.0;
1068 mdBlue = static_cast<double>(aColor.GetBlue()) / 255.0;
1070 RGBtoHSV( mdRed, mdGreen, mdBlue, mdHue, mdSat, mdBri );
1071 RGBtoCMYK( mdRed, mdGreen, mdBlue, mdCyan, mdMagenta, mdYellow, mdKey );
1072 n = UpdateFlags::All & ~UpdateFlags::Hex;
1075 if (n != UpdateFlags::NONE)
1076 update_color(n);
1079 IMPL_LINK(ColorPickerDialog, ColorModifySpinHdl, weld::SpinButton&, rEdit, void)
1081 UpdateFlags n = UpdateFlags::NONE;
1083 if (&rEdit == m_xMFRed.get())
1085 setColorComponent( ColorComponent::Red, static_cast<double>(m_xMFRed->get_value()) / 255.0 );
1086 n = UpdateFlags::All & ~UpdateFlags::RGB;
1088 else if (&rEdit == m_xMFGreen.get())
1090 setColorComponent( ColorComponent::Green, static_cast<double>(m_xMFGreen->get_value()) / 255.0 );
1091 n = UpdateFlags::All & ~UpdateFlags::RGB;
1093 else if (&rEdit == m_xMFBlue.get())
1095 setColorComponent( ColorComponent::Blue, static_cast<double>(m_xMFBlue->get_value()) / 255.0 );
1096 n = UpdateFlags::All & ~UpdateFlags::RGB;
1099 if (n != UpdateFlags::NONE)
1100 update_color(n);
1104 IMPL_LINK_NOARG(ColorPickerDialog, ModeModifyHdl, weld::ToggleButton&, void)
1106 ColorMode eMode = HUE;
1108 if (m_xRBRed->get_active())
1110 eMode = RED;
1112 else if (m_xRBGreen->get_active())
1114 eMode = GREEN;
1116 else if (m_xRBBlue->get_active())
1118 eMode = BLUE;
1120 else if (m_xRBSaturation->get_active())
1122 eMode = SATURATION;
1124 else if (m_xRBBrightness->get_active())
1126 eMode = BRIGHTNESS;
1129 if (meMode != eMode)
1131 meMode = eMode;
1132 update_color(UpdateFlags::ColorChooser | UpdateFlags::ColorSlider);
1136 void ColorPickerDialog::setColorComponent( ColorComponent nComp, double dValue )
1138 switch( nComp )
1140 case ColorComponent::Red:
1141 mdRed = dValue;
1142 break;
1143 case ColorComponent::Green:
1144 mdGreen = dValue;
1145 break;
1146 case ColorComponent::Blue:
1147 mdBlue = dValue;
1148 break;
1149 case ColorComponent::Hue:
1150 mdHue = dValue;
1151 break;
1152 case ColorComponent::Saturation:
1153 mdSat = dValue;
1154 break;
1155 case ColorComponent::Brightness:
1156 mdBri = dValue;
1157 break;
1158 case ColorComponent::Cyan:
1159 mdCyan = dValue;
1160 break;
1161 case ColorComponent::Yellow:
1162 mdYellow = dValue;
1163 break;
1164 case ColorComponent::Magenta:
1165 mdMagenta = dValue;
1166 break;
1167 case ColorComponent::Key:
1168 mdKey = dValue;
1169 break;
1172 if (nComp == ColorComponent::Red || nComp == ColorComponent::Green || nComp == ColorComponent::Blue)
1174 RGBtoHSV( mdRed, mdGreen, mdBlue, mdHue, mdSat, mdBri );
1175 RGBtoCMYK( mdRed, mdGreen, mdBlue, mdCyan, mdMagenta, mdYellow, mdKey );
1177 else if (nComp == ColorComponent::Hue || nComp == ColorComponent::Saturation || nComp == ColorComponent::Brightness)
1179 HSVtoRGB( mdHue, mdSat, mdBri, mdRed, mdGreen, mdBlue );
1180 RGBtoCMYK( mdRed, mdGreen, mdBlue, mdCyan, mdMagenta, mdYellow, mdKey );
1182 else
1184 CMYKtoRGB( mdCyan, mdMagenta, mdYellow, mdKey, mdRed, mdGreen, mdBlue );
1185 RGBtoHSV( mdRed, mdGreen, mdBlue, mdHue, mdSat, mdBri );
1189 typedef ::cppu::WeakComponentImplHelper< XServiceInfo, XExecutableDialog, XInitialization, XPropertyAccess > ColorPickerBase;
1191 class ColorPicker : protected ::cppu::BaseMutex, // Struct for right initialization of mutex member! Must be first of baseclasses.
1192 public ColorPickerBase
1194 public:
1195 explicit ColorPicker();
1197 // XInitialization
1198 virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override;
1200 // XInitialization
1201 virtual OUString SAL_CALL getImplementationName( ) override;
1202 virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
1203 virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
1205 // XPropertyAccess
1206 virtual Sequence< PropertyValue > SAL_CALL getPropertyValues( ) override;
1207 virtual void SAL_CALL setPropertyValues( const Sequence< PropertyValue >& aProps ) override;
1209 // XExecutableDialog
1210 virtual void SAL_CALL setTitle( const OUString& aTitle ) override;
1211 virtual sal_Int16 SAL_CALL execute( ) override;
1213 private:
1214 Color mnColor;
1215 sal_Int16 mnMode;
1216 Reference<css::awt::XWindow> mxParent;
1219 OUString ColorPicker_getImplementationName()
1221 return OUString( "com.sun.star.cui.ColorPicker" );
1224 Reference< XInterface > ColorPicker_createInstance( Reference< XComponentContext > const & )
1226 return static_cast<XWeak*>( new ColorPicker );
1229 Sequence< OUString > ColorPicker_getSupportedServiceNames()
1231 Sequence< OUString > seq { "com.sun.star.ui.dialogs.ColorPicker" };
1232 return seq;
1235 static const OUStringLiteral gsColorKey( "Color" );
1236 static const OUStringLiteral gsModeKey( "Mode" );
1238 ColorPicker::ColorPicker()
1239 : ColorPickerBase( m_aMutex )
1240 , mnColor( 0 )
1241 , mnMode( 0 )
1245 // XInitialization
1246 void SAL_CALL ColorPicker::initialize( const Sequence< Any >& aArguments )
1248 if( aArguments.getLength() == 1 )
1250 aArguments[0] >>= mxParent;
1254 // XInitialization
1255 OUString SAL_CALL ColorPicker::getImplementationName( )
1257 return ColorPicker_getImplementationName();
1260 sal_Bool SAL_CALL ColorPicker::supportsService( const OUString& sServiceName )
1262 return cppu::supportsService(this, sServiceName);
1265 Sequence< OUString > SAL_CALL ColorPicker::getSupportedServiceNames( )
1267 return ColorPicker_getSupportedServiceNames();
1270 // XPropertyAccess
1271 Sequence< PropertyValue > SAL_CALL ColorPicker::getPropertyValues( )
1273 Sequence< PropertyValue > props(1);
1274 props[0].Name = gsColorKey;
1275 props[0].Value <<= mnColor;
1276 return props;
1279 void SAL_CALL ColorPicker::setPropertyValues( const Sequence< PropertyValue >& aProps )
1281 for( sal_Int32 n = 0; n < aProps.getLength(); n++ )
1283 if( aProps[n].Name == gsColorKey )
1285 aProps[n].Value >>= mnColor;
1287 else if( aProps[n].Name == gsModeKey )
1289 aProps[n].Value >>= mnMode;
1294 // XExecutableDialog
1295 void SAL_CALL ColorPicker::setTitle( const OUString& )
1299 sal_Int16 SAL_CALL ColorPicker::execute()
1301 std::unique_ptr<ColorPickerDialog> xDlg(new ColorPickerDialog(Application::GetFrameWeld(mxParent), mnColor, mnMode));
1302 sal_Int16 ret = xDlg->run();
1303 if (ret)
1304 mnColor = xDlg->GetColor();
1305 return ret;
1310 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */