diff options
Diffstat (limited to '')
-rw-r--r-- | cui/source/dialogs/colorpicker.cxx | 1363 |
1 files changed, 1363 insertions, 0 deletions
diff --git a/cui/source/dialogs/colorpicker.cxx b/cui/source/dialogs/colorpicker.cxx new file mode 100644 index 000000000..341cf5bf0 --- /dev/null +++ b/cui/source/dialogs/colorpicker.cxx @@ -0,0 +1,1363 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp> +#include <com/sun/star/ui/dialogs/XAsynchronousExecutableDialog.hpp> +#include <com/sun/star/beans/XPropertyAccess.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/awt/XWindow.hpp> + +#include <comphelper/propertyvalue.hxx> +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/basemutex.hxx> +#include <vcl/customweld.hxx> +#include <vcl/event.hxx> +#include <vcl/svapp.hxx> +#include <vcl/virdev.hxx> +#include <vcl/weld.hxx> +#include <sfx2/basedlgs.hxx> +#include <svx/hexcolorcontrol.hxx> +#include <basegfx/color/bcolortools.hxx> +#include <cmath> +#include <o3tl/typed_flags_set.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::ui::dialogs; +using namespace ::com::sun::star::beans; +using namespace ::basegfx; + +namespace { + +enum class UpdateFlags +{ + NONE = 0x00, + RGB = 0x01, + CMYK = 0x02, + HSB = 0x04, + ColorChooser = 0x08, + ColorSlider = 0x10, + Hex = 0x20, + All = 0x3f, +}; + +} + +namespace o3tl { + template<> struct typed_flags<UpdateFlags> : is_typed_flags<UpdateFlags, 0x3f> {}; +} + + +namespace cui +{ + +namespace { + +enum class ColorComponent { + Red, + Green, + Blue, + Hue, + Saturation, + Brightness, + Cyan, + Yellow, + Magenta, + Key, +}; + +} + +// color space conversion helpers + +static void RGBtoHSV( double dR, double dG, double dB, double& dH, double& dS, double& dV ) +{ + BColor result = basegfx::utils::rgb2hsv( BColor( dR, dG, dB ) ); + + dH = result.getX(); + dS = result.getY(); + dV = result.getZ(); +} + +static void HSVtoRGB(double dH, double dS, double dV, double& dR, double& dG, double& dB ) +{ + BColor result = basegfx::utils::hsv2rgb( BColor( dH, dS, dV ) ); + + dR = result.getRed(); + dG = result.getGreen(); + dB = result.getBlue(); +} + +// CMYK values from 0 to 1 +static void CMYKtoRGB( double fCyan, double fMagenta, double fYellow, double fKey, double& dR, double& dG, double& dB ) +{ + fCyan = (fCyan * ( 1.0 - fKey )) + fKey; + fMagenta = (fMagenta * ( 1.0 - fKey )) + fKey; + fYellow = (fYellow * ( 1.0 - fKey )) + fKey; + + dR = std::clamp( 1.0 - fCyan, 0.0, 1.0 ); + dG = std::clamp( 1.0 - fMagenta, 0.0, 1.0 ); + dB = std::clamp( 1.0 - fYellow, 0.0, 1.0 ); +} + +// CMY results from 0 to 1 +static void RGBtoCMYK( double dR, double dG, double dB, double& fCyan, double& fMagenta, double& fYellow, double& fKey ) +{ + fCyan = 1 - dR; + fMagenta = 1 - dG; + fYellow = 1 - dB; + + //CMYK and CMY values from 0 to 1 + fKey = 1.0; + if( fCyan < fKey ) fKey = fCyan; + if( fMagenta < fKey ) fKey = fMagenta; + if( fYellow < fKey ) fKey = fYellow; + + if( fKey >= 1.0 ) + { + //Black + fCyan = 0.0; + fMagenta = 0.0; + fYellow = 0.0; + } + else + { + fCyan = ( fCyan - fKey ) / ( 1.0 - fKey ); + fMagenta = ( fMagenta - fKey ) / ( 1.0 - fKey ); + fYellow = ( fYellow - fKey ) / ( 1.0 - fKey ); + } +} + +namespace { + +class ColorPreviewControl : public weld::CustomWidgetController +{ +private: + Color m_aColor; + + virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) override; +public: + ColorPreviewControl() + { + } + + virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override + { + CustomWidgetController::SetDrawingArea(pDrawingArea); + pDrawingArea->set_size_request(pDrawingArea->get_approximate_digit_width() * 10, + pDrawingArea->get_text_height() * 2); + } + + void SetColor(const Color& rCol) + { + if (rCol != m_aColor) + { + m_aColor = rCol; + Invalidate(); + } + } +}; + +} + +void ColorPreviewControl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) +{ + rRenderContext.SetFillColor(m_aColor); + rRenderContext.SetLineColor(m_aColor); + rRenderContext.DrawRect(tools::Rectangle(Point(0, 0), GetOutputSizePixel())); +} + +namespace { + +enum ColorMode { HUE, SATURATION, BRIGHTNESS, RED, GREEN, BLUE }; + +} + +const ColorMode DefaultMode = HUE; + +namespace { + +class ColorFieldControl : public weld::CustomWidgetController +{ +public: + ColorFieldControl() + : meMode( DefaultMode ) + , mnBaseValue(USHRT_MAX) + , mdX( -1.0 ) + , mdY( -1.0 ) + , mbMouseCaptured(false) + { + } + + virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override + { + CustomWidgetController::SetDrawingArea(pDrawingArea); + pDrawingArea->set_size_request(pDrawingArea->get_approximate_digit_width() * 40, + pDrawingArea->get_text_height() * 10); + } + + virtual ~ColorFieldControl() override + { + mxBitmap.disposeAndClear(); + } + + virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override; + virtual void Resize() override; + virtual bool MouseButtonDown(const MouseEvent& rMEvt) override; + virtual bool MouseMove(const MouseEvent& rMEvt) override; + virtual bool MouseButtonUp(const MouseEvent& rMEvt) override; + + void UpdateBitmap(); + void ShowPosition( const Point& rPos, bool bUpdate ); + void UpdatePosition(); + void Modify(); + + void SetValues(sal_uInt16 nBaseValue, ColorMode eMode, double x, double y); + double GetX() const { return mdX;} + double GetY() const { return mdY;} + + void SetModifyHdl(const Link<ColorFieldControl&,void>& rLink) { maModifyHdl = rLink; } + +private: + ColorMode meMode; + sal_uInt16 mnBaseValue; + double mdX; + double mdY; + bool mbMouseCaptured; + Point maPosition; + VclPtr<VirtualDevice> mxBitmap; + Link<ColorFieldControl&,void> maModifyHdl; + std::vector<sal_uInt8> maRGB_Horiz; + std::vector<sal_uInt16> maGrad_Horiz; + std::vector<sal_uInt16> maPercent_Horiz; + std::vector<sal_uInt8> maRGB_Vert; + std::vector<sal_uInt16> maPercent_Vert; +}; + +} + +void ColorFieldControl::UpdateBitmap() +{ + const Size aSize(GetOutputSizePixel()); + + if (mxBitmap && mxBitmap->GetOutputSizePixel() != aSize) + mxBitmap.disposeAndClear(); + + const sal_Int32 nWidth = aSize.Width(); + const sal_Int32 nHeight = aSize.Height(); + + if (nWidth == 0 || nHeight == 0) + return; + + if (!mxBitmap) + { + mxBitmap = VclPtr<VirtualDevice>::Create(); + mxBitmap->SetOutputSizePixel(aSize); + + maRGB_Horiz.resize( nWidth ); + maGrad_Horiz.resize( nWidth ); + maPercent_Horiz.resize( nWidth ); + + sal_uInt8* pRGB = maRGB_Horiz.data(); + sal_uInt16* pGrad = maGrad_Horiz.data(); + sal_uInt16* pPercent = maPercent_Horiz.data(); + + for( sal_Int32 x = 0; x < nWidth; x++ ) + { + *pRGB++ = static_cast<sal_uInt8>((x * 256) / nWidth); + *pGrad++ = static_cast<sal_uInt16>((x * 359) / nWidth); + *pPercent++ = static_cast<sal_uInt16>((x * 100) / nWidth); + } + + maRGB_Vert.resize(nHeight); + maPercent_Vert.resize(nHeight); + + pRGB = maRGB_Vert.data(); + pPercent = maPercent_Vert.data(); + + sal_Int32 y = nHeight; + while (y--) + { + *pRGB++ = static_cast<sal_uInt8>((y * 256) / nHeight); + *pPercent++ = static_cast<sal_uInt16>((y * 100) / nHeight); + } + } + + sal_uInt8* pRGB_Horiz = maRGB_Horiz.data(); + sal_uInt16* pGrad_Horiz = maGrad_Horiz.data(); + sal_uInt16* pPercent_Horiz = maPercent_Horiz.data(); + sal_uInt8* pRGB_Vert = maRGB_Vert.data(); + sal_uInt16* pPercent_Vert = maPercent_Vert.data(); + + // this has been unlooped for performance reason, please do not merge back! + + sal_uInt16 y = nHeight,x; + + switch(meMode) + { + case HUE: + while (y--) + { + sal_uInt16 nBri = pPercent_Vert[y]; + x = nWidth; + while (x--) + { + sal_uInt16 nSat = pPercent_Horiz[x]; + mxBitmap->DrawPixel(Point(x,y), Color::HSBtoRGB(mnBaseValue, nSat, nBri)); + } + } + break; + case SATURATION: + while (y--) + { + sal_uInt16 nBri = pPercent_Vert[y]; + x = nWidth; + while (x--) + { + sal_uInt16 nHue = pGrad_Horiz[x]; + mxBitmap->DrawPixel(Point(x,y), Color::HSBtoRGB(nHue, mnBaseValue, nBri)); + } + } + break; + case BRIGHTNESS: + while (y--) + { + sal_uInt16 nSat = pPercent_Vert[y]; + x = nWidth; + while (x--) + { + sal_uInt16 nHue = pGrad_Horiz[x]; + mxBitmap->DrawPixel(Point(x,y), Color::HSBtoRGB(nHue, nSat, mnBaseValue)); + } + } + break; + case RED: + { + Color aBitmapColor; + aBitmapColor.SetRed(mnBaseValue); + while (y--) + { + aBitmapColor.SetGreen(pRGB_Vert[y]); + x = nWidth; + while (x--) + { + aBitmapColor.SetBlue(pRGB_Horiz[x]); + mxBitmap->DrawPixel(Point(x,y), aBitmapColor); + } + } + break; + } + case GREEN: + { + Color aBitmapColor; + aBitmapColor.SetGreen(mnBaseValue); + while (y--) + { + aBitmapColor.SetRed(pRGB_Vert[y]); + x = nWidth; + while (x--) + { + aBitmapColor.SetBlue(pRGB_Horiz[x]); + mxBitmap->DrawPixel(Point(x,y), aBitmapColor); + } + } + break; + } + case BLUE: + { + Color aBitmapColor; + aBitmapColor.SetBlue(mnBaseValue); + while (y--) + { + aBitmapColor.SetGreen(pRGB_Vert[y]); + x = nWidth; + while (x--) + { + aBitmapColor.SetRed(pRGB_Horiz[x]); + mxBitmap->DrawPixel(Point(x,y), aBitmapColor); + } + } + break; + } + } +} + +constexpr int nCenterOffset = 5; + +void ColorFieldControl::ShowPosition( const Point& rPos, bool bUpdate ) +{ + if (!mxBitmap) + { + UpdateBitmap(); + Invalidate(); + } + + if (!mxBitmap) + return; + + const Size aSize(mxBitmap->GetOutputSizePixel()); + + tools::Long nX = rPos.X(); + tools::Long nY = rPos.Y(); + if (nX < 0) + nX = 0; + else if (nX >= aSize.Width()) + nX = aSize.Width() - 1; + + if (nY < 0) + nY = 0; + else if (nY >= aSize.Height()) + nY = aSize.Height() - 1; + + Point aPos = maPosition; + maPosition.setX( nX - nCenterOffset ); + maPosition.setY( nY - nCenterOffset ); + Invalidate(tools::Rectangle(aPos, Size(11, 11))); + Invalidate(tools::Rectangle(maPosition, Size(11, 11))); + + if (bUpdate) + { + mdX = double(nX) / double(aSize.Width() - 1.0); + mdY = double(aSize.Height() - 1.0 - nY) / double(aSize.Height() - 1.0); + } +} + +bool ColorFieldControl::MouseButtonDown(const MouseEvent& rMEvt) +{ + CaptureMouse(); + mbMouseCaptured = true; + ShowPosition(rMEvt.GetPosPixel(), true); + Modify(); + return true; +} + +bool ColorFieldControl::MouseMove(const MouseEvent& rMEvt) +{ + if (mbMouseCaptured) + { + ShowPosition(rMEvt.GetPosPixel(), true); + Modify(); + } + return true; +} + +bool ColorFieldControl::MouseButtonUp(const MouseEvent&) +{ + ReleaseMouse(); + mbMouseCaptured = false; + return true; +} + +void ColorFieldControl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) +{ + if (!mxBitmap) + UpdateBitmap(); + + if (!mxBitmap) + return; + + Size aSize(GetOutputSizePixel()); + rRenderContext.DrawOutDev(Point(0, 0), aSize, Point(0, 0), aSize, *mxBitmap); + + // draw circle around current color + Point aPos(maPosition.X() + nCenterOffset, maPosition.Y() + nCenterOffset); + Color aColor = mxBitmap->GetPixel(aPos); + if (aColor.IsDark()) + rRenderContext.SetLineColor(COL_WHITE); + else + rRenderContext.SetLineColor(COL_BLACK); + + rRenderContext.SetFillColor(); + rRenderContext.DrawEllipse(::tools::Rectangle(maPosition, Size(11, 11))); +} + +void ColorFieldControl::Resize() +{ + CustomWidgetController::Resize(); + UpdateBitmap(); + UpdatePosition(); +} + +void ColorFieldControl::Modify() +{ + maModifyHdl.Call( *this ); +} + +void ColorFieldControl::SetValues(sal_uInt16 nBaseValue, ColorMode eMode, double x, double y) +{ + bool bUpdateBitmap = (mnBaseValue != nBaseValue) || (meMode != eMode); + if (!bUpdateBitmap && mdX == x && mdY == y) + return; + + mnBaseValue = nBaseValue; + meMode = eMode; + mdX = x; + mdY = y; + + if (bUpdateBitmap) + UpdateBitmap(); + UpdatePosition(); + if (bUpdateBitmap) + Invalidate(); +} + +void ColorFieldControl::UpdatePosition() +{ + Size aSize(GetOutputSizePixel()); + ShowPosition(Point(static_cast<tools::Long>(mdX * aSize.Width()), static_cast<tools::Long>((1.0 - mdY) * aSize.Height())), false); +} + +namespace { + +class ColorSliderControl : public weld::CustomWidgetController +{ +public: + ColorSliderControl(); + virtual ~ColorSliderControl() override; + + virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override; + + virtual bool MouseButtonDown(const MouseEvent& rMEvt) override; + virtual bool MouseMove(const MouseEvent& rMEvt) override; + virtual bool MouseButtonUp(const MouseEvent& rMEvt) override; + virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) override; + virtual void Resize() override; + + void UpdateBitmap(); + void ChangePosition( tools::Long nY ); + void Modify(); + + void SetValue( const Color& rColor, ColorMode eMode, double dValue ); + double GetValue() const { return mdValue; } + + void SetModifyHdl( const Link<ColorSliderControl&,void>& rLink ) { maModifyHdl = rLink; } + + sal_Int16 GetLevel() const { return mnLevel; } + +private: + Link<ColorSliderControl&,void> maModifyHdl; + Color maColor; + ColorMode meMode; + VclPtr<VirtualDevice> mxBitmap; + sal_Int16 mnLevel; + double mdValue; +}; + +} + +ColorSliderControl::ColorSliderControl() + : meMode( DefaultMode ) + , mnLevel( 0 ) + , mdValue( -1.0 ) +{ +} + +void ColorSliderControl::SetDrawingArea(weld::DrawingArea* pDrawingArea) +{ + CustomWidgetController::SetDrawingArea(pDrawingArea); + pDrawingArea->set_size_request(pDrawingArea->get_approximate_digit_width() * 3, -1); +} + +ColorSliderControl::~ColorSliderControl() +{ + mxBitmap.disposeAndClear(); +} + +void ColorSliderControl::UpdateBitmap() +{ + Size aSize(1, GetOutputSizePixel().Height()); + + if (mxBitmap && mxBitmap->GetOutputSizePixel() != aSize) + mxBitmap.disposeAndClear(); + + if (!mxBitmap) + { + mxBitmap = VclPtr<VirtualDevice>::Create(); + mxBitmap->SetOutputSizePixel(aSize); + } + + const tools::Long nY = aSize.Height() - 1; + + Color aBitmapColor(maColor); + + sal_uInt16 nHue, nSat, nBri; + maColor.RGBtoHSB(nHue, nSat, nBri); + + // this has been unlooped for performance reason, please do not merge back! + + switch (meMode) + { + case HUE: + nSat = 100; + nBri = 100; + for (tools::Long y = 0; y <= nY; y++) + { + nHue = static_cast<sal_uInt16>((359 * y) / nY); + mxBitmap->DrawPixel(Point(0, nY - y), Color::HSBtoRGB(nHue, nSat, nBri)); + } + break; + + case SATURATION: + nBri = std::max(sal_uInt16(32), nBri); + for (tools::Long y = 0; y <= nY; y++) + { + nSat = static_cast<sal_uInt16>((100 * y) / nY); + mxBitmap->DrawPixel(Point(0, nY - y), Color::HSBtoRGB(nHue, nSat, nBri)); + } + break; + + case BRIGHTNESS: + for (tools::Long y = 0; y <= nY; y++) + { + nBri = static_cast<sal_uInt16>((100 * y) / nY); + mxBitmap->DrawPixel(Point(0, nY - y), Color::HSBtoRGB(nHue, nSat, nBri)); + } + break; + + case RED: + for (tools::Long y = 0; y <= nY; y++) + { + aBitmapColor.SetRed(sal_uInt8((tools::Long(255) * y) / nY)); + mxBitmap->DrawPixel(Point(0, nY - y), aBitmapColor); + } + break; + + case GREEN: + for (tools::Long y = 0; y <= nY; y++) + { + aBitmapColor.SetGreen(sal_uInt8((tools::Long(255) * y) / nY)); + mxBitmap->DrawPixel(Point(0, nY - y), aBitmapColor); + } + break; + + case BLUE: + for (tools::Long y = 0; y <= nY; y++) + { + aBitmapColor.SetBlue(sal_uInt8((tools::Long(255) * y) / nY)); + mxBitmap->DrawPixel(Point(0, nY - y), aBitmapColor); + } + break; + } +} + +void ColorSliderControl::ChangePosition(tools::Long nY) +{ + const tools::Long nHeight = GetOutputSizePixel().Height() - 1; + + if (nY < 0) + nY = 0; + else if (nY > nHeight) + nY = nHeight; + + mnLevel = nY; + mdValue = double(nHeight - nY) / double(nHeight); +} + +bool ColorSliderControl::MouseButtonDown(const MouseEvent& rMEvt) +{ + CaptureMouse(); + ChangePosition(rMEvt.GetPosPixel().Y()); + Modify(); + return true; +} + +bool ColorSliderControl::MouseMove(const MouseEvent& rMEvt) +{ + if (IsMouseCaptured()) + { + ChangePosition(rMEvt.GetPosPixel().Y()); + Modify(); + } + return true; +} + +bool ColorSliderControl::MouseButtonUp(const MouseEvent&) +{ + ReleaseMouse(); + return true; +} + +void ColorSliderControl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) +{ + if (!mxBitmap) + UpdateBitmap(); + + const Size aSize(GetOutputSizePixel()); + + Point aPos; + int x = aSize.Width(); + while (x--) + { + rRenderContext.DrawOutDev(aPos, aSize, Point(0,0), aSize, *mxBitmap); + aPos.AdjustX(1); + } +} + +void ColorSliderControl::Resize() +{ + CustomWidgetController::Resize(); + UpdateBitmap(); +} + +void ColorSliderControl::Modify() +{ + maModifyHdl.Call(*this); +} + +void ColorSliderControl::SetValue(const Color& rColor, ColorMode eMode, double dValue) +{ + bool bUpdateBitmap = (rColor != maColor) || (eMode != meMode); + if( bUpdateBitmap || (mdValue != dValue)) + { + maColor = rColor; + mdValue = dValue; + mnLevel = static_cast<sal_Int16>((1.0-dValue) * GetOutputSizePixel().Height()); + meMode = eMode; + if (bUpdateBitmap) + UpdateBitmap(); + Invalidate(); + } +} + +namespace { + +class ColorPickerDialog : public SfxDialogController +{ +private: + ColorFieldControl m_aColorField; + ColorSliderControl m_aColorSlider; + ColorPreviewControl m_aColorPreview; + ColorPreviewControl m_aColorPrevious; + + std::unique_ptr<weld::CustomWeld> m_xColorField; + std::unique_ptr<weld::CustomWeld> m_xColorSlider; + std::unique_ptr<weld::CustomWeld> m_xColorPreview; + std::unique_ptr<weld::CustomWeld> m_xColorPrevious; + + std::unique_ptr<weld::Widget> m_xFISliderLeft; + std::unique_ptr<weld::Widget> m_xFISliderRight; + std::unique_ptr<weld::RadioButton> m_xRBRed; + std::unique_ptr<weld::RadioButton> m_xRBGreen; + std::unique_ptr<weld::RadioButton> m_xRBBlue; + std::unique_ptr<weld::RadioButton> m_xRBHue; + std::unique_ptr<weld::RadioButton> m_xRBSaturation; + std::unique_ptr<weld::RadioButton> m_xRBBrightness; + + std::unique_ptr<weld::SpinButton> m_xMFRed; + std::unique_ptr<weld::SpinButton> m_xMFGreen; + std::unique_ptr<weld::SpinButton> m_xMFBlue; + std::unique_ptr<weld::HexColorControl> m_xEDHex; + + std::unique_ptr<weld::MetricSpinButton> m_xMFHue; + std::unique_ptr<weld::MetricSpinButton> m_xMFSaturation; + std::unique_ptr<weld::MetricSpinButton> m_xMFBrightness; + + std::unique_ptr<weld::MetricSpinButton> m_xMFCyan; + std::unique_ptr<weld::MetricSpinButton> m_xMFMagenta; + std::unique_ptr<weld::MetricSpinButton> m_xMFYellow; + std::unique_ptr<weld::MetricSpinButton> m_xMFKey; + +public: + ColorPickerDialog(weld::Window* pParent, Color nColor, sal_Int16 nMode); + + void update_color(UpdateFlags n = UpdateFlags::All); + + DECL_LINK(ColorFieldControlModifydl, ColorFieldControl&, void); + DECL_LINK(ColorSliderControlModifyHdl, ColorSliderControl&, void); + DECL_LINK(ColorModifyMetricHdl, weld::MetricSpinButton&, void); + DECL_LINK(ColorModifySpinHdl, weld::SpinButton&, void); + DECL_LINK(ColorModifyEditHdl, weld::Entry&, void); + DECL_LINK(ModeModifyHdl, weld::Toggleable&, void); + + Color GetColor() const; + + void setColorComponent(ColorComponent nComp, double dValue); + +private: + ColorMode meMode; + + double mdRed, mdGreen, mdBlue; + double mdHue, mdSat, mdBri; + double mdCyan, mdMagenta, mdYellow, mdKey; +}; + +} + +ColorPickerDialog::ColorPickerDialog(weld::Window* pParent, Color nColor, sal_Int16 nDialogMode) + : SfxDialogController(pParent, "cui/ui/colorpickerdialog.ui", "ColorPicker") + , m_xColorField(new weld::CustomWeld(*m_xBuilder, "colorField", m_aColorField)) + , m_xColorSlider(new weld::CustomWeld(*m_xBuilder, "colorSlider", m_aColorSlider)) + , m_xColorPreview(new weld::CustomWeld(*m_xBuilder, "preview", m_aColorPreview)) + , m_xColorPrevious(new weld::CustomWeld(*m_xBuilder, "previous", m_aColorPrevious)) + , m_xFISliderLeft(m_xBuilder->weld_widget("leftImage")) + , m_xFISliderRight(m_xBuilder->weld_widget("rightImage")) + , m_xRBRed(m_xBuilder->weld_radio_button("redRadiobutton")) + , m_xRBGreen(m_xBuilder->weld_radio_button("greenRadiobutton")) + , m_xRBBlue(m_xBuilder->weld_radio_button("blueRadiobutton")) + , m_xRBHue(m_xBuilder->weld_radio_button("hueRadiobutton")) + , m_xRBSaturation(m_xBuilder->weld_radio_button("satRadiobutton")) + , m_xRBBrightness(m_xBuilder->weld_radio_button("brightRadiobutton")) + , m_xMFRed(m_xBuilder->weld_spin_button("redSpinbutton")) + , m_xMFGreen(m_xBuilder->weld_spin_button("greenSpinbutton")) + , m_xMFBlue(m_xBuilder->weld_spin_button("blueSpinbutton")) + , m_xEDHex(new weld::HexColorControl(m_xBuilder->weld_entry("hexEntry"))) + , m_xMFHue(m_xBuilder->weld_metric_spin_button("hueSpinbutton", FieldUnit::DEGREE)) + , m_xMFSaturation(m_xBuilder->weld_metric_spin_button("satSpinbutton", FieldUnit::PERCENT)) + , m_xMFBrightness(m_xBuilder->weld_metric_spin_button("brightSpinbutton", FieldUnit::PERCENT)) + , m_xMFCyan(m_xBuilder->weld_metric_spin_button("cyanSpinbutton", FieldUnit::PERCENT)) + , m_xMFMagenta(m_xBuilder->weld_metric_spin_button("magSpinbutton", FieldUnit::PERCENT)) + , m_xMFYellow(m_xBuilder->weld_metric_spin_button("yellowSpinbutton", FieldUnit::PERCENT)) + , m_xMFKey(m_xBuilder->weld_metric_spin_button("keySpinbutton", FieldUnit::PERCENT)) + , meMode( DefaultMode ) +{ + m_aColorField.SetModifyHdl( LINK( this, ColorPickerDialog, ColorFieldControlModifydl ) ); + m_aColorSlider.SetModifyHdl( LINK( this, ColorPickerDialog, ColorSliderControlModifyHdl ) ); + + int nMargin = (m_xFISliderLeft->get_preferred_size().Height() + 1) / 2; + m_xColorSlider->set_margin_top(nMargin); + m_xColorSlider->set_margin_bottom(nMargin); + + Link<weld::MetricSpinButton&,void> aLink3( LINK( this, ColorPickerDialog, ColorModifyMetricHdl ) ); + m_xMFCyan->connect_value_changed( aLink3 ); + m_xMFMagenta->connect_value_changed( aLink3 ); + m_xMFYellow->connect_value_changed( aLink3 ); + m_xMFKey->connect_value_changed( aLink3 ); + + m_xMFHue->connect_value_changed( aLink3 ); + m_xMFSaturation->connect_value_changed( aLink3 ); + m_xMFBrightness->connect_value_changed( aLink3 ); + + Link<weld::SpinButton&,void> aLink4(LINK(this, ColorPickerDialog, ColorModifySpinHdl)); + m_xMFRed->connect_value_changed(aLink4); + m_xMFGreen->connect_value_changed(aLink4); + m_xMFBlue->connect_value_changed(aLink4); + + m_xEDHex->connect_changed(LINK(this, ColorPickerDialog, ColorModifyEditHdl)); + + Link<weld::Toggleable&,void> aLink2 = LINK( this, ColorPickerDialog, ModeModifyHdl ); + m_xRBRed->connect_toggled( aLink2 ); + m_xRBGreen->connect_toggled( aLink2 ); + m_xRBBlue->connect_toggled( aLink2 ); + m_xRBHue->connect_toggled( aLink2 ); + m_xRBSaturation->connect_toggled( aLink2 ); + m_xRBBrightness->connect_toggled( aLink2 ); + + Color aColor(nColor); + + // modify + if (nDialogMode == 2) + { + m_aColorPrevious.SetColor(aColor); + m_xColorPrevious->show(); + } + + mdRed = static_cast<double>(aColor.GetRed()) / 255.0; + mdGreen = static_cast<double>(aColor.GetGreen()) / 255.0; + mdBlue = static_cast<double>(aColor.GetBlue()) / 255.0; + + RGBtoHSV( mdRed, mdGreen, mdBlue, mdHue, mdSat, mdBri ); + RGBtoCMYK( mdRed, mdGreen, mdBlue, mdCyan, mdMagenta, mdYellow, mdKey ); + + update_color(); +} + +static int toInt( double dValue, double dRange ) +{ + return static_cast< int >( std::floor((dValue * dRange) + 0.5 ) ); +} + +Color ColorPickerDialog::GetColor() const +{ + return Color( toInt(mdRed,255.0), toInt(mdGreen,255.0), toInt(mdBlue,255.0) ); +} + +void ColorPickerDialog::update_color( UpdateFlags n ) +{ + sal_uInt8 nRed = toInt(mdRed,255.0); + sal_uInt8 nGreen = toInt(mdGreen,255.0); + sal_uInt8 nBlue = toInt(mdBlue,255.0); + + sal_uInt16 nHue = toInt(mdHue, 1.0); + sal_uInt16 nSat = toInt(mdSat, 100.0); + sal_uInt16 nBri = toInt(mdBri, 100.0); + + if (n & UpdateFlags::RGB) // update RGB + { + m_xMFRed->set_value(nRed); + m_xMFGreen->set_value(nGreen); + m_xMFBlue->set_value(nBlue); + } + + if (n & UpdateFlags::CMYK) // update CMYK + { + m_xMFCyan->set_value(toInt(mdCyan, 100.0), FieldUnit::PERCENT); + m_xMFMagenta->set_value(toInt(mdMagenta, 100.0), FieldUnit::PERCENT); + m_xMFYellow->set_value(toInt(mdYellow, 100.0), FieldUnit::PERCENT); + m_xMFKey->set_value(toInt(mdKey, 100.0), FieldUnit::PERCENT); + } + + if (n & UpdateFlags::HSB ) // update HSB + { + m_xMFHue->set_value(nHue, FieldUnit::DEGREE); + m_xMFSaturation->set_value(nSat, FieldUnit::PERCENT); + m_xMFBrightness->set_value(nBri, FieldUnit::PERCENT); + } + + if (n & UpdateFlags::ColorChooser ) // update Color Chooser 1 + { + switch( meMode ) + { + case HUE: + m_aColorField.SetValues(nHue, meMode, mdSat, mdBri); + break; + case SATURATION: + m_aColorField.SetValues(nSat, meMode, mdHue / 360.0, mdBri); + break; + case BRIGHTNESS: + m_aColorField.SetValues(nBri, meMode, mdHue / 360.0, mdSat); + break; + case RED: + m_aColorField.SetValues(nRed, meMode, mdBlue, mdGreen); + break; + case GREEN: + m_aColorField.SetValues(nGreen, meMode, mdBlue, mdRed); + break; + case BLUE: + m_aColorField.SetValues(nBlue, meMode, mdRed, mdGreen); + break; + } + } + + Color aColor(nRed, nGreen, nBlue); + + if (n & UpdateFlags::ColorSlider) // update Color Chooser 2 + { + switch (meMode) + { + case HUE: + m_aColorSlider.SetValue(aColor, meMode, mdHue / 360.0); + break; + case SATURATION: + m_aColorSlider.SetValue(aColor, meMode, mdSat); + break; + case BRIGHTNESS: + m_aColorSlider.SetValue(aColor, meMode, mdBri); + break; + case RED: + m_aColorSlider.SetValue(aColor, meMode, mdRed); + break; + case GREEN: + m_aColorSlider.SetValue(aColor, meMode, mdGreen); + break; + case BLUE: + m_aColorSlider.SetValue(aColor, meMode, mdBlue); + break; + } + } + + if (n & UpdateFlags::Hex) // update hex + { + m_xFISliderLeft->set_margin_top(m_aColorSlider.GetLevel()); + m_xFISliderRight->set_margin_top(m_aColorSlider.GetLevel()); + m_xEDHex->SetColor(aColor); + } + m_aColorPreview.SetColor(aColor); +} + +IMPL_LINK_NOARG(ColorPickerDialog, ColorFieldControlModifydl, ColorFieldControl&, void) +{ + double x = m_aColorField.GetX(); + double y = m_aColorField.GetY(); + + switch( meMode ) + { + case HUE: + mdSat = x; + setColorComponent( ColorComponent::Brightness, y ); + break; + case SATURATION: + mdHue = x * 360.0; + setColorComponent( ColorComponent::Brightness, y ); + break; + case BRIGHTNESS: + mdHue = x * 360.0; + setColorComponent( ColorComponent::Saturation, y ); + break; + case RED: + mdBlue = x; + setColorComponent( ColorComponent::Green, y ); + break; + case GREEN: + mdBlue = x; + setColorComponent( ColorComponent::Red, y ); + break; + case BLUE: + mdRed = x; + setColorComponent( ColorComponent::Green, y ); + break; + } + + update_color(UpdateFlags::All & ~UpdateFlags::ColorChooser); +} + +IMPL_LINK_NOARG(ColorPickerDialog, ColorSliderControlModifyHdl, ColorSliderControl&, void) +{ + double dValue = m_aColorSlider.GetValue(); + switch (meMode) + { + case HUE: + setColorComponent( ColorComponent::Hue, dValue * 360.0 ); + break; + case SATURATION: + setColorComponent( ColorComponent::Saturation, dValue ); + break; + case BRIGHTNESS: + setColorComponent( ColorComponent::Brightness, dValue ); + break; + case RED: + setColorComponent( ColorComponent::Red, dValue ); + break; + case GREEN: + setColorComponent( ColorComponent::Green, dValue ); + break; + case BLUE: + setColorComponent( ColorComponent::Blue, dValue ); + break; + } + + update_color(UpdateFlags::All & ~UpdateFlags::ColorSlider); +} + +IMPL_LINK(ColorPickerDialog, ColorModifyMetricHdl, weld::MetricSpinButton&, rEdit, void) +{ + UpdateFlags n = UpdateFlags::NONE; + + if (&rEdit == m_xMFHue.get()) + { + setColorComponent( ColorComponent::Hue, static_cast<double>(m_xMFHue->get_value(FieldUnit::DEGREE)) ); + n = UpdateFlags::All & ~UpdateFlags::HSB; + } + else if (&rEdit == m_xMFSaturation.get()) + { + setColorComponent( ColorComponent::Saturation, static_cast<double>(m_xMFSaturation->get_value(FieldUnit::PERCENT)) / 100.0 ); + n = UpdateFlags::All & ~UpdateFlags::HSB; + } + else if (&rEdit == m_xMFBrightness.get()) + { + setColorComponent( ColorComponent::Brightness, static_cast<double>(m_xMFBrightness->get_value(FieldUnit::PERCENT)) / 100.0 ); + n = UpdateFlags::All & ~UpdateFlags::HSB; + } + else if (&rEdit == m_xMFCyan.get()) + { + setColorComponent( ColorComponent::Cyan, static_cast<double>(m_xMFCyan->get_value(FieldUnit::PERCENT)) / 100.0 ); + n = UpdateFlags::All & ~UpdateFlags::CMYK; + } + else if (&rEdit == m_xMFMagenta.get()) + { + setColorComponent( ColorComponent::Magenta, static_cast<double>(m_xMFMagenta->get_value(FieldUnit::PERCENT)) / 100.0 ); + n = UpdateFlags::All & ~UpdateFlags::CMYK; + } + else if (&rEdit == m_xMFYellow.get()) + { + setColorComponent( ColorComponent::Yellow, static_cast<double>(m_xMFYellow->get_value(FieldUnit::PERCENT)) / 100.0 ); + n = UpdateFlags::All & ~UpdateFlags::CMYK; + } + else if (&rEdit == m_xMFKey.get()) + { + setColorComponent( ColorComponent::Key, static_cast<double>(m_xMFKey->get_value(FieldUnit::PERCENT)) / 100.0 ); + n = UpdateFlags::All & ~UpdateFlags::CMYK; + } + + if (n != UpdateFlags::NONE) + update_color(n); +} + +IMPL_LINK_NOARG(ColorPickerDialog, ColorModifyEditHdl, weld::Entry&, void) +{ + UpdateFlags n = UpdateFlags::NONE; + + Color aColor = m_xEDHex->GetColor(); + + if (aColor != COL_AUTO && aColor != GetColor()) + { + mdRed = static_cast<double>(aColor.GetRed()) / 255.0; + mdGreen = static_cast<double>(aColor.GetGreen()) / 255.0; + mdBlue = static_cast<double>(aColor.GetBlue()) / 255.0; + + RGBtoHSV( mdRed, mdGreen, mdBlue, mdHue, mdSat, mdBri ); + RGBtoCMYK( mdRed, mdGreen, mdBlue, mdCyan, mdMagenta, mdYellow, mdKey ); + n = UpdateFlags::All & ~UpdateFlags::Hex; + } + + if (n != UpdateFlags::NONE) + update_color(n); +} + +IMPL_LINK(ColorPickerDialog, ColorModifySpinHdl, weld::SpinButton&, rEdit, void) +{ + UpdateFlags n = UpdateFlags::NONE; + + if (&rEdit == m_xMFRed.get()) + { + setColorComponent( ColorComponent::Red, static_cast<double>(m_xMFRed->get_value()) / 255.0 ); + n = UpdateFlags::All & ~UpdateFlags::RGB; + } + else if (&rEdit == m_xMFGreen.get()) + { + setColorComponent( ColorComponent::Green, static_cast<double>(m_xMFGreen->get_value()) / 255.0 ); + n = UpdateFlags::All & ~UpdateFlags::RGB; + } + else if (&rEdit == m_xMFBlue.get()) + { + setColorComponent( ColorComponent::Blue, static_cast<double>(m_xMFBlue->get_value()) / 255.0 ); + n = UpdateFlags::All & ~UpdateFlags::RGB; + } + + if (n != UpdateFlags::NONE) + update_color(n); +} + + +IMPL_LINK_NOARG(ColorPickerDialog, ModeModifyHdl, weld::Toggleable&, void) +{ + ColorMode eMode = HUE; + + if (m_xRBRed->get_active()) + { + eMode = RED; + } + else if (m_xRBGreen->get_active()) + { + eMode = GREEN; + } + else if (m_xRBBlue->get_active()) + { + eMode = BLUE; + } + else if (m_xRBSaturation->get_active()) + { + eMode = SATURATION; + } + else if (m_xRBBrightness->get_active()) + { + eMode = BRIGHTNESS; + } + + if (meMode != eMode) + { + meMode = eMode; + update_color(UpdateFlags::ColorChooser | UpdateFlags::ColorSlider); + } +} + +void ColorPickerDialog::setColorComponent( ColorComponent nComp, double dValue ) +{ + switch( nComp ) + { + case ColorComponent::Red: + mdRed = dValue; + break; + case ColorComponent::Green: + mdGreen = dValue; + break; + case ColorComponent::Blue: + mdBlue = dValue; + break; + case ColorComponent::Hue: + mdHue = dValue; + break; + case ColorComponent::Saturation: + mdSat = dValue; + break; + case ColorComponent::Brightness: + mdBri = dValue; + break; + case ColorComponent::Cyan: + mdCyan = dValue; + break; + case ColorComponent::Yellow: + mdYellow = dValue; + break; + case ColorComponent::Magenta: + mdMagenta = dValue; + break; + case ColorComponent::Key: + mdKey = dValue; + break; + } + + if (nComp == ColorComponent::Red || nComp == ColorComponent::Green || nComp == ColorComponent::Blue) + { + RGBtoHSV( mdRed, mdGreen, mdBlue, mdHue, mdSat, mdBri ); + RGBtoCMYK( mdRed, mdGreen, mdBlue, mdCyan, mdMagenta, mdYellow, mdKey ); + } + else if (nComp == ColorComponent::Hue || nComp == ColorComponent::Saturation || nComp == ColorComponent::Brightness) + { + HSVtoRGB( mdHue, mdSat, mdBri, mdRed, mdGreen, mdBlue ); + RGBtoCMYK( mdRed, mdGreen, mdBlue, mdCyan, mdMagenta, mdYellow, mdKey ); + } + else + { + CMYKtoRGB( mdCyan, mdMagenta, mdYellow, mdKey, mdRed, mdGreen, mdBlue ); + RGBtoHSV( mdRed, mdGreen, mdBlue, mdHue, mdSat, mdBri ); + } +} + +typedef ::cppu::WeakComponentImplHelper< XServiceInfo, XExecutableDialog, XAsynchronousExecutableDialog, XInitialization, XPropertyAccess > ColorPickerBase; + +namespace { + +class ColorPicker : protected ::cppu::BaseMutex, // Struct for right initialization of mutex member! Must be first of baseclasses. + public ColorPickerBase +{ +public: + explicit ColorPicker(); + + // XInitialization + virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override; + + // XInitialization + virtual OUString SAL_CALL getImplementationName( ) override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + // XPropertyAccess + virtual Sequence< PropertyValue > SAL_CALL getPropertyValues( ) override; + virtual void SAL_CALL setPropertyValues( const Sequence< PropertyValue >& aProps ) override; + + // XExecutableDialog + virtual void SAL_CALL setTitle( const OUString& aTitle ) override; + virtual sal_Int16 SAL_CALL execute( ) override; + + // XAsynchronousExecutableDialog + virtual void SAL_CALL setDialogTitle( const OUString& aTitle ) override; + virtual void SAL_CALL startExecuteModal( const css::uno::Reference< css::ui::dialogs::XDialogClosedListener >& xListener ) override; + +private: + Color mnColor; + sal_Int16 mnMode; + Reference<css::awt::XWindow> mxParent; +}; + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_cui_ColorPicker_get_implementation( + css::uno::XComponentContext*, css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire( new ColorPicker ); +} + + +constexpr OUStringLiteral gsColorKey( u"Color" ); +constexpr OUStringLiteral gsModeKey( u"Mode" ); + +ColorPicker::ColorPicker() + : ColorPickerBase( m_aMutex ) + , mnColor( 0 ) + , mnMode( 0 ) +{ +} + +// XInitialization +void SAL_CALL ColorPicker::initialize( const Sequence< Any >& aArguments ) +{ + if( aArguments.getLength() == 1 ) + { + aArguments[0] >>= mxParent; + } +} + +// XInitialization +OUString SAL_CALL ColorPicker::getImplementationName( ) +{ + return "com.sun.star.cui.ColorPicker"; +} + +sal_Bool SAL_CALL ColorPicker::supportsService( const OUString& sServiceName ) +{ + return cppu::supportsService(this, sServiceName); +} + +Sequence< OUString > SAL_CALL ColorPicker::getSupportedServiceNames( ) +{ + return { "com.sun.star.ui.dialogs.ColorPicker", + "com.sun.star.ui.dialogs.AsynchronousColorPicker" }; +} + +// XPropertyAccess +Sequence< PropertyValue > SAL_CALL ColorPicker::getPropertyValues( ) +{ + Sequence< PropertyValue > props{ comphelper::makePropertyValue(gsColorKey, mnColor) }; + return props; +} + +void SAL_CALL ColorPicker::setPropertyValues( const Sequence< PropertyValue >& aProps ) +{ + for ( const PropertyValue& rProp : aProps ) + { + if( rProp.Name == gsColorKey ) + { + rProp.Value >>= mnColor; + } + else if( rProp.Name == gsModeKey ) + { + rProp.Value >>= mnMode; + } + } +} + +// XExecutableDialog +void SAL_CALL ColorPicker::setTitle( const OUString& ) +{ +} + +sal_Int16 SAL_CALL ColorPicker::execute() +{ + std::unique_ptr<ColorPickerDialog> xDlg(new ColorPickerDialog(Application::GetFrameWeld(mxParent), mnColor, mnMode)); + sal_Int16 ret = xDlg->run(); + if (ret) + mnColor = xDlg->GetColor(); + return ret; +} + +// XAsynchronousExecutableDialog +void SAL_CALL ColorPicker::setDialogTitle( const OUString& ) +{ +} + +void SAL_CALL ColorPicker::startExecuteModal( const css::uno::Reference< css::ui::dialogs::XDialogClosedListener >& xListener ) +{ + std::shared_ptr<ColorPickerDialog> xDlg = std::make_shared<ColorPickerDialog>(Application::GetFrameWeld(mxParent), mnColor, mnMode); + weld::DialogController::runAsync(xDlg, [this, xDlg, xListener] (sal_Int32 nResult) { + if (nResult) + mnColor = xDlg->GetColor(); + + sal_Int16 nRet = static_cast<sal_Int16>(nResult); + css::ui::dialogs::DialogClosedEvent aEvent( *this, nRet ); + xListener->dialogClosed( aEvent ); + }); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |