include/svtools/toolbarmenu.hxx | 30 + include/svx/colorbox.hxx | 61 +++ include/svx/colorwindow.hxx | 57 +++ include/vcl/customweld.hxx | 2 include/vcl/menubtn.hxx | 2 include/vcl/virdev.hxx | 2 include/vcl/weld.hxx | 35 +- solenv/sanitizers/ui/svx.suppr | 4 svtools/source/control/toolbarmenu.cxx | 30 + svtools/source/control/valueset.cxx | 2 svx/UIConfig_svx.mk | 1 svx/source/tbxctrls/tbcontrl.cxx | 442 +++++++++++++++++++++++++++- svx/uiconfig/ui/colorwindow.ui | 47 ++ svx/uiconfig/ui/oldcolorwindow.ui | 180 +++++++++++ sw/qa/uitest/writer_tests/watermark.py | 4 sw/source/uibase/app/docsh2.cxx | 7 sw/source/uibase/dialog/watermarkdialog.cxx | 66 +--- sw/source/uibase/inc/watermarkdialog.hxx | 23 - sw/uiconfig/swriter/ui/watermarkdialog.ui | 48 ++- vcl/headless/svpinst.cxx | 2 vcl/inc/headless/svpinst.hxx | 2 vcl/source/app/salvtables.cxx | 48 +++ vcl/source/control/menubtn.cxx | 34 ++ vcl/source/window/builder.cxx | 9 vcl/unx/gtk3/gtk3gtkinst.cxx | 356 +++++++++++++++++++--- 25 files changed, 1325 insertions(+), 169 deletions(-)
New commits: commit bf1e097c16f9dd672ea43234cbe0eb64c82fd37e Author: Caolán McNamara <caol...@redhat.com> Date: Tue Jun 19 16:40:38 2018 +0100 weld SwWatermarkDialog Change-Id: Iff3ddfb4dd75088e39ea7675b085f1bbde2c2045 Reviewed-on: https://gerrit.libreoffice.org/56414 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmik...@collabora.co.uk> diff --git a/include/svtools/toolbarmenu.hxx b/include/svtools/toolbarmenu.hxx index 5372c719892e..352a7d6368d5 100644 --- a/include/svtools/toolbarmenu.hxx +++ b/include/svtools/toolbarmenu.hxx @@ -21,6 +21,7 @@ #define INCLUDED_SVTOOLS_TOOLBARMENU_HXX #include <svtools/svtdllapi.h> +#include <svtools/framestatuslistener.hxx> #include <com/sun/star/frame/FeatureStateEvent.hpp> #include <com/sun/star/lang/XMultiServiceFactory.hpp> @@ -36,17 +37,33 @@ #include <vcl/dockwin.hxx> class ValueSet; -namespace svt { class FrameStatusListener; } namespace svtools { class ToolbarMenuEntry; struct ToolbarMenu_Impl; -class SVT_DLLPUBLIC ToolbarPopup : public DockingWindow +class SVT_DLLPUBLIC ToolbarPopupBase { friend class ToolbarPopupStatusListener; public: + ToolbarPopupBase(const css::uno::Reference<css::frame::XFrame>& rFrame); + virtual ~ToolbarPopupBase(); + +protected: + void AddStatusListener( const OUString& rCommandURL ); + + // Forwarded from XStatusListener (subclasses must override this one to get the status updates): + /// @throws css::uno::RuntimeException + virtual void statusChanged(const css::frame::FeatureStateEvent& Event ); + + css::uno::Reference<css::frame::XFrame> mxFrame; + rtl::Reference<svt::FrameStatusListener> mxStatusListener; +}; + +class SVT_DLLPUBLIC ToolbarPopup : public DockingWindow, public ToolbarPopupBase +{ +public: ToolbarPopup(const css::uno::Reference<css::frame::XFrame>& rFrame, vcl::Window* pParentWindow, WinBits nBits ); @@ -57,20 +74,11 @@ public: virtual void dispose() override; protected: - void AddStatusListener( const OUString& rCommandURL ); - bool IsInPopupMode(); void EndPopupMode(); - // Forwarded from XStatusListener (subclasses must override this one to get the status updates): - /// @throws css::uno::RuntimeException - virtual void statusChanged(const css::frame::FeatureStateEvent& Event ); - - css::uno::Reference< css::frame::XFrame > mxFrame; private: void init(); - - rtl::Reference< svt::FrameStatusListener > mxStatusListener; }; class SVT_DLLPUBLIC ToolbarMenu : public ToolbarPopup diff --git a/include/svx/colorbox.hxx b/include/svx/colorbox.hxx index 8ffbc12db77f..cb7c5e820128 100644 --- a/include/svx/colorbox.hxx +++ b/include/svx/colorbox.hxx @@ -12,10 +12,12 @@ #include <memory> #include <vcl/menubtn.hxx> +#include <vcl/weld.hxx> #include <svx/colorwindow.hxx> #include <sfx2/controlwrapper.hxx> class SvxColorListBox; +class ColorListBox; class SvxListBoxColorWrapper { @@ -78,6 +80,65 @@ public: DECL_LINK(WindowEventListener, VclWindowEvent&, void); }; +class ListBoxColorWrapper +{ +public: + ListBoxColorWrapper(ColorListBox* pControl); + void operator()(const OUString& rCommand, const NamedColor& rColor); + void dispose(); +private: + ColorListBox* mpControl; +}; + +class SVX_DLLPUBLIC ColorListBox +{ +private: + friend class ListBoxColorWrapper; + std::unique_ptr<ColorWindow> m_xColorWindow; + std::unique_ptr<weld::MenuButton> m_xButton; + weld::Window* m_pTopLevel; + Link<ColorListBox&, void> m_aSelectedLink; + ListBoxColorWrapper m_aColorWrapper; + Color m_aAutoDisplayColor; + Color m_aSaveColor; + NamedColor m_aSelectedColor; + sal_uInt16 m_nSlotId; + bool m_bShowNoneButton; + std::shared_ptr<PaletteManager> m_xPaletteManager; + BorderColorStatus m_aBorderColorStatus; + + void Selected(const NamedColor& rNamedColor); + void createColorWindow(); + void LockWidthRequest(); + ColorWindow* getColorWindow() const; +public: + ColorListBox(weld::MenuButton* pControl, weld::Window* pWindow); + ~ColorListBox(); + + void SetSelectHdl(const Link<ColorListBox&, void>& rLink) + { + m_aSelectedLink = rLink; + } + + void SetSlotId(sal_uInt16 nSlotId, bool bShowNoneButton = false); + + Color const & GetSelectEntryColor() const { return m_aSelectedColor.first; } + NamedColor const & GetSelectedEntry() const { return m_aSelectedColor; } + + void SelectEntry(const NamedColor& rColor); + void SelectEntry(const Color& rColor); + + void SetNoSelection() { getColorWindow()->SetNoSelection(); } + bool IsNoSelection() const { return getColorWindow()->IsNoSelection(); } + + void SetAutoDisplayColor(const Color &rColor) { m_aAutoDisplayColor = rColor; } + void ShowPreview(const NamedColor &rColor); + void EnsurePaletteManager(); + + void SaveValue() { m_aSaveColor = GetSelectEntryColor(); } + bool IsValueChangedFromSaved() const { return m_aSaveColor != GetSelectEntryColor(); } +}; + /** A wrapper for SvxColorListBox. */ class SVX_DLLPUBLIC SvxColorListBoxWrapper : public sfx::SingleControlWrapper<SvxColorListBox, Color> diff --git a/include/svx/colorwindow.hxx b/include/svx/colorwindow.hxx index 16fb45da4ff3..118c69217aa8 100644 --- a/include/svx/colorwindow.hxx +++ b/include/svx/colorwindow.hxx @@ -109,6 +109,63 @@ public: void SetSelectedHdl( const Link<const NamedColor&, void>& rLink ) { maSelectedLink = rLink; } }; +class SVX_DLLPUBLIC ColorWindow : public svtools::ToolbarPopupBase +{ +private: + std::unique_ptr<weld::Builder> m_xBuilder; + + const sal_uInt16 theSlotId; + OUString maCommand; + weld::Window* mpParentWindow; + weld::MenuButton* mpMenuButton; + std::shared_ptr<PaletteManager> mxPaletteManager; + BorderColorStatus& mrBorderColorStatus; + ColorSelectFunction maColorSelectFunction; + + std::unique_ptr<ColorValueSet> mxColorSet; + std::unique_ptr<ColorValueSet> mxRecentColorSet; + std::unique_ptr<weld::Container> mxTopLevel; + std::unique_ptr<weld::ComboBoxText> mxPaletteListBox; + std::unique_ptr<weld::Button> mxButtonAutoColor; + std::unique_ptr<weld::Button> mxButtonNoneColor; + std::unique_ptr<weld::Button> mxButtonPicker; + std::unique_ptr<weld::Widget> mxAutomaticSeparator; + std::unique_ptr<weld::CustomWeld> mxColorSetWin; + std::unique_ptr<weld::CustomWeld> mxRecentColorSetWin; + + Link<const NamedColor&, void> maSelectedLink; + DECL_LINK(SelectHdl, SvtValueSet*, void); + DECL_LINK(SelectPaletteHdl, weld::ComboBoxText&, void); + DECL_LINK(AutoColorClickHdl, weld::Button&, void); + DECL_LINK(OpenPickerClickHdl, weld::Button&, void); + + static bool SelectValueSetEntry(ColorValueSet* pColorSet, const Color& rColor); + static NamedColor GetSelectEntryColor(SvtValueSet const * pColorSet); + NamedColor GetAutoColor() const; + +public: + ColorWindow(const OUString& rCommand, + std::shared_ptr<PaletteManager> const & rPaletteManager, + BorderColorStatus& rBorderColorStatus, + sal_uInt16 nSlotId, + const css::uno::Reference< css::frame::XFrame >& rFrame, + weld::Window* pParentWindow, weld::MenuButton* pMenuButton, + ColorSelectFunction const& rColorSelectFunction); + weld::Container* GetWidget() { return mxTopLevel.get(); } + virtual ~ColorWindow() override; + void ShowNoneButton(); + void StartSelection(); + void SetNoSelection(); + bool IsNoSelection() const; + void SelectEntry(const NamedColor& rColor); + void SelectEntry(const Color& rColor); + NamedColor GetSelectEntryColor() const; + + virtual void statusChanged( const css::frame::FeatureStateEvent& rEvent ) override; + + void SetSelectedHdl( const Link<const NamedColor&, void>& rLink ) { maSelectedLink = rLink; } +}; + #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/vcl/customweld.hxx b/include/vcl/customweld.hxx index 622b20c256c5..c191b91ebf2b 100644 --- a/include/vcl/customweld.hxx +++ b/include/vcl/customweld.hxx @@ -61,6 +61,8 @@ public: bool IsMouseCaptured() const { return m_pDrawingArea->has_grab(); } void EnableRTL(bool bEnable) { m_pDrawingArea->set_direction(bEnable); } void ReleaseMouse() { m_pDrawingArea->grab_remove(); } + void SetHelpId(const OString& rHelpId) { m_pDrawingArea->set_help_id(rHelpId); } + void SetAccessibleName(const OUString& rName) { m_pDrawingArea->set_accessible_name(rName); } void set_size_request(int nWidth, int nHeight) { m_pDrawingArea->set_size_request(nWidth, nHeight); diff --git a/include/vcl/menubtn.hxx b/include/vcl/menubtn.hxx index 99ddf2bdb1e2..b5c1e226a372 100644 --- a/include/vcl/menubtn.hxx +++ b/include/vcl/menubtn.hxx @@ -64,6 +64,8 @@ public: virtual void Select(); void ExecuteMenu(); + bool MenuShown() const; + void CancelMenu(); //if false then the whole button launches the menu //if true, then the button has a separator diff --git a/include/vcl/virdev.hxx b/include/vcl/virdev.hxx index 98647fa4b766..06121aca050a 100644 --- a/include/vcl/virdev.hxx +++ b/include/vcl/virdev.hxx @@ -34,7 +34,7 @@ class VCL_DLLPUBLIC VirtualDevice : public OutputDevice friend class Application; friend class ::OutputDevice; friend class Printer; - friend cairo_surface_t* get_underlying_cairo_suface(VirtualDevice&); + friend cairo_surface_t* get_underlying_cairo_surface(VirtualDevice&); public: // reference device modes for different compatibility levels enum class RefDevMode { NONE = 0, diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx index 07360e8a43e5..39ee0c867886 100644 --- a/include/vcl/weld.hxx +++ b/include/vcl/weld.hxx @@ -45,6 +45,8 @@ public: virtual bool is_visible() const = 0; //if this widget visibility and all parents is true virtual void grab_focus() = 0; virtual bool has_focus() const = 0; + virtual void set_has_default(bool has_default) = 0; + virtual bool get_has_default() const = 0; virtual void show() = 0; virtual void hide() = 0; void show(bool bShow) @@ -364,27 +366,13 @@ protected: public: virtual void set_label(const OUString& rText) = 0; + virtual void set_image(VirtualDevice& rDevice) = 0; virtual OUString get_label() const = 0; void clicked() { signal_clicked(); } void connect_clicked(const Link<Button&, void>& rLink) { m_aClickHdl = rLink; } }; -class VCL_DLLPUBLIC MenuButton : virtual public Button -{ -protected: - Link<const OString&, void> m_aSelectHdl; - - void signal_selected(const OString& rIdent) { m_aSelectHdl.Call(rIdent); } - -public: - void connect_selected(const Link<const OString&, void>& rLink) { m_aSelectHdl = rLink; } - virtual void set_item_active(const OString& rIdent, bool bActive) = 0; - virtual void set_item_label(const OString& rIdent, const OUString& rLabel) = 0; - virtual void set_item_help_id(const OString& rIdent, const OString& rHelpId) = 0; - virtual OString get_item_help_id(const OString& rIdent) const = 0; -}; - class VCL_DLLPUBLIC ToggleButton : virtual public Button { protected: @@ -434,6 +422,23 @@ public: virtual void connect_toggled(const Link<ToggleButton&, void>& rLink) { m_aToggleHdl = rLink; } }; +class VCL_DLLPUBLIC MenuButton : virtual public ToggleButton +{ +protected: + Link<const OString&, void> m_aSelectHdl; + + void signal_selected(const OString& rIdent) { m_aSelectHdl.Call(rIdent); } + +public: + void connect_selected(const Link<const OString&, void>& rLink) { m_aSelectHdl = rLink; } + virtual void set_item_active(const OString& rIdent, bool bActive) = 0; + virtual void set_item_label(const OString& rIdent, const OUString& rLabel) = 0; + virtual void set_item_help_id(const OString& rIdent, const OString& rHelpId) = 0; + virtual OString get_item_help_id(const OString& rIdent) const = 0; + + virtual void set_popover(weld::Widget* pPopover) = 0; +}; + class VCL_DLLPUBLIC CheckButton : virtual public ToggleButton { }; diff --git a/solenv/sanitizers/ui/svx.suppr b/solenv/sanitizers/ui/svx.suppr index f1ef208e2ea1..083c4d4974c4 100644 --- a/solenv/sanitizers/ui/svx.suppr +++ b/solenv/sanitizers/ui/svx.suppr @@ -5,7 +5,6 @@ svx/uiconfig/ui/chinesedictionary.ui://GtkLabel[@id='mappingft'] orphan-label svx/uiconfig/ui/chinesedictionary.ui://GtkEntry[@id='mapping'] no-labelled-by svx/uiconfig/ui/chinesedictionary.ui://GtkLabel[@id='propertyft'] orphan-label svx/uiconfig/ui/colorwindow.ui://GtkButton[@id='auto_color_button'] button-no-label -svx/uiconfig/ui/colorwindow.ui://GtkLabel[@id='label1'] orphan-label svx/uiconfig/ui/compressgraphicdialog.ui://GtkScale[@id='scale-quality'] no-labelled-by svx/uiconfig/ui/compressgraphicdialog.ui://GtkSpinButton[@id='spin-quality'] no-labelled-by svx/uiconfig/ui/compressgraphicdialog.ui://GtkScale[@id='scale-compression'] no-labelled-by @@ -20,6 +19,9 @@ svx/uiconfig/ui/mediaplayback.ui://GtkLabel[@id='label3'] orphan-label svx/uiconfig/ui/mediaplayback.ui://GtkScale[@id='timeslider'] no-labelled-by svx/uiconfig/ui/mediaplayback.ui://GtkEntry[@id='timeedit:border'] no-labelled-by svx/uiconfig/ui/mediaplayback.ui://GtkScale[@id='volumeslider'] no-labelled-by +svx/uiconfig/ui/oldcolorwindow.ui://GtkButton[@id='auto_color_button'] button-no-label +svx/uiconfig/ui/oldcolorwindow.ui://GtkComboBox[@id='palette_listbox'] no-labelled-by +svx/uiconfig/ui/oldcolorwindow.ui://GtkLabel[@id='label1'] orphan-label svx/uiconfig/ui/paralinespacingcontrol.ui://GtkSpinButton[@id='percent_box:0%'] no-labelled-by svx/uiconfig/ui/paralinespacingcontrol.ui://GtkSpinButton[@id='metric_box:0.00cm'] no-labelled-by svx/uiconfig/ui/redlinefilterpage.ui://GtkCheckButton[@id='comment'] missing-labelled-by diff --git a/svtools/source/control/toolbarmenu.cxx b/svtools/source/control/toolbarmenu.cxx index dd94ed5fd8f3..b64c0b788442 100644 --- a/svtools/source/control/toolbarmenu.cxx +++ b/svtools/source/control/toolbarmenu.cxx @@ -1393,18 +1393,18 @@ class ToolbarPopupStatusListener : public svt::FrameStatusListener { public: ToolbarPopupStatusListener( const css::uno::Reference< css::frame::XFrame >& xFrame, - ToolbarPopup& rToolbarPopup ); + ToolbarPopupBase& rToolbarPopup ); virtual void SAL_CALL dispose() override; virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& Event ) override; - VclPtr<ToolbarPopup> mpPopup; + ToolbarPopupBase* mpPopup; }; ToolbarPopupStatusListener::ToolbarPopupStatusListener( const css::uno::Reference< css::frame::XFrame >& xFrame, - ToolbarPopup& rToolbarPopup ) + ToolbarPopupBase& rToolbarPopup ) : svt::FrameStatusListener( ::comphelper::getProcessComponentContext(), xFrame ) , mpPopup( &rToolbarPopup ) { @@ -1413,7 +1413,7 @@ ToolbarPopupStatusListener::ToolbarPopupStatusListener( void SAL_CALL ToolbarPopupStatusListener::dispose() { - mpPopup.clear(); + mpPopup = nullptr; svt::FrameStatusListener::dispose(); } @@ -1424,9 +1424,23 @@ void SAL_CALL ToolbarPopupStatusListener::statusChanged( const css::frame::Featu mpPopup->statusChanged( Event ); } +ToolbarPopupBase::ToolbarPopupBase(const css::uno::Reference<css::frame::XFrame>& rFrame) + : mxFrame(rFrame) +{ +} + +ToolbarPopupBase::~ToolbarPopupBase() +{ + if (mxStatusListener.is()) + { + mxStatusListener->dispose(); + mxStatusListener.clear(); + } +} + ToolbarPopup::ToolbarPopup( const css::uno::Reference<css::frame::XFrame>& rFrame, vcl::Window* pParentWindow, WinBits nBits ) : DockingWindow(pParentWindow, nBits) - , mxFrame( rFrame ) + , ToolbarPopupBase(rFrame) { init(); } @@ -1434,7 +1448,7 @@ ToolbarPopup::ToolbarPopup( const css::uno::Reference<css::frame::XFrame>& rFram ToolbarPopup::ToolbarPopup( const css::uno::Reference<css::frame::XFrame>& rFrame, vcl::Window* pParentWindow, const OString& rID, const OUString& rUIXMLDescription ) : DockingWindow(pParentWindow, rID, rUIXMLDescription, rFrame) - , mxFrame( rFrame ) + , ToolbarPopupBase(rFrame) { init(); } @@ -1467,7 +1481,7 @@ void ToolbarPopup::dispose() DockingWindow::dispose(); } -void ToolbarPopup::AddStatusListener( const OUString& rCommandURL ) +void ToolbarPopupBase::AddStatusListener( const OUString& rCommandURL ) { if( !mxStatusListener.is() ) mxStatusListener.set( new ToolbarPopupStatusListener( mxFrame, *this ) ); @@ -1475,7 +1489,7 @@ void ToolbarPopup::AddStatusListener( const OUString& rCommandURL ) mxStatusListener->addStatusListener( rCommandURL ); } -void ToolbarPopup::statusChanged( const css::frame::FeatureStateEvent& /*Event*/ ) +void ToolbarPopupBase::statusChanged( const css::frame::FeatureStateEvent& /*Event*/ ) { } diff --git a/svtools/source/control/valueset.cxx b/svtools/source/control/valueset.cxx index 23f8c82eb9c7..18fc943df835 100644 --- a/svtools/source/control/valueset.cxx +++ b/svtools/source/control/valueset.cxx @@ -2936,7 +2936,7 @@ void SvtValueSet::SetStyle(WinBits nStyle) if (nStyle != mnStyle) { mnStyle = nStyle; - mbFormat = false; + mbFormat = true; Invalidate(); } } diff --git a/svx/UIConfig_svx.mk b/svx/UIConfig_svx.mk index 441f2ca83208..a7cb36f70587 100644 --- a/svx/UIConfig_svx.mk +++ b/svx/UIConfig_svx.mk @@ -60,6 +60,7 @@ $(eval $(call gb_UIConfig_add_uifiles,svx,\ svx/uiconfig/ui/linkwarndialog \ svx/uiconfig/ui/mediaplayback \ svx/uiconfig/ui/namespacedialog \ + svx/uiconfig/ui/oldcolorwindow \ svx/uiconfig/ui/optgridpage \ svx/uiconfig/ui/paralinespacingcontrol \ svx/uiconfig/ui/paralrspacing \ diff --git a/svx/source/tbxctrls/tbcontrl.cxx b/svx/source/tbxctrls/tbcontrl.cxx index b9533fdc7dd4..94a4860fbb72 100644 --- a/svx/source/tbxctrls/tbcontrl.cxx +++ b/svx/source/tbxctrls/tbcontrl.cxx @@ -1260,7 +1260,7 @@ SvxColorWindow::SvxColorWindow(const OUString& rCommand, bool bReuseParentForPicker, std::function<void(const OUString&, const NamedColor&)> const & aFunction): - ToolbarPopup( rFrame, pParentWindow, "palette_popup_window", "svx/ui/colorwindow.ui" ), + ToolbarPopup( rFrame, pParentWindow, "palette_popup_window", "svx/ui/oldcolorwindow.ui" ), theSlotId( nSlotId ), maCommand( rCommand ), mxParentWindow(pParentWindow), @@ -1364,16 +1364,132 @@ SvxColorWindow::SvxColorWindow(const OUString& rCommand, } } +ColorWindow::ColorWindow(const OUString& rCommand, + std::shared_ptr<PaletteManager> const & rPaletteManager, + BorderColorStatus& rBorderColorStatus, + sal_uInt16 nSlotId, + const Reference< XFrame >& rFrame, + weld::Window* pParentWindow, + weld::MenuButton* pMenuButton, + std::function<void(const OUString&, const NamedColor&)> const & aFunction) + : ToolbarPopupBase(rFrame) + , m_xBuilder(Application::CreateBuilder(pMenuButton, "svx/ui/colorwindow.ui")) + , theSlotId(nSlotId) + , maCommand(rCommand) + , mpParentWindow(pParentWindow) + , mpMenuButton(pMenuButton) + , mxPaletteManager(rPaletteManager) + , mrBorderColorStatus(rBorderColorStatus) + , maColorSelectFunction(aFunction) + , mxColorSet(new ColorValueSet(m_xBuilder->weld_scrolled_window("colorsetwin"))) + , mxRecentColorSet(new ColorValueSet(nullptr)) + , mxTopLevel(m_xBuilder->weld_container("palette_popup_window")) + , mxPaletteListBox(m_xBuilder->weld_combo_box_text("palette_listbox")) + , mxButtonAutoColor(m_xBuilder->weld_button("auto_color_button")) + , mxButtonNoneColor(m_xBuilder->weld_button("none_color_button")) + , mxButtonPicker(m_xBuilder->weld_button("color_picker_button")) + , mxAutomaticSeparator(m_xBuilder->weld_widget("separator4")) + , mxColorSetWin(new weld::CustomWeld(*m_xBuilder, "colorset", *mxColorSet)) + , mxRecentColorSetWin(new weld::CustomWeld(*m_xBuilder, "recent_colorset", *mxRecentColorSet)) +{ + mxColorSet->SetStyle( WinBits(WB_FLATVALUESET | WB_ITEMBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT | WB_TABSTOP) ); + mxRecentColorSet->SetStyle( WinBits(WB_FLATVALUESET | WB_ITEMBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT | WB_TABSTOP) ); + + switch ( theSlotId ) + { + case SID_ATTR_CHAR_COLOR_BACKGROUND: + case SID_BACKGROUND_COLOR: + case SID_ATTR_CHAR_BACK_COLOR: + { + mxButtonAutoColor->set_label( SvxResId( RID_SVXSTR_NOFILL ) ); + break; + } + case SID_AUTHOR_COLOR: + { + mxButtonAutoColor->set_label( SvxResId( RID_SVXSTR_BY_AUTHOR ) ); + break; + } + case SID_BMPMASK_COLOR: + { + mxButtonAutoColor->set_label( SvxResId( RID_SVXSTR_TRANSPARENT ) ); + break; + } + case SID_ATTR_CHAR_COLOR: + case SID_ATTR_CHAR_COLOR2: + case SID_EXTRUSION_3D_COLOR: + { + mxButtonAutoColor->set_label(EditResId(RID_SVXSTR_AUTOMATIC)); + break; + } + case SID_FM_CTL_PROPERTIES: + { + mxButtonAutoColor->set_label( SvxResId( RID_SVXSTR_DEFAULT ) ); + break; + } + default: + { + mxButtonAutoColor->hide(); + mxAutomaticSeparator->hide(); + break; + } + } + + mxPaletteListBox->connect_changed(LINK(this, ColorWindow, SelectPaletteHdl)); + std::vector<OUString> aPaletteList = mxPaletteManager->GetPaletteList(); + for (std::vector<OUString>::iterator it = aPaletteList.begin(); it != aPaletteList.end(); ++it) + mxPaletteListBox->append_text(*it); + OUString aPaletteName( officecfg::Office::Common::UserColors::PaletteName::get() ); + mxPaletteListBox->set_active_text(aPaletteName); + const int nSelectedEntry(mxPaletteListBox->get_active()); + if (nSelectedEntry != -1) + mxPaletteManager->SetPalette(nSelectedEntry); + + mxButtonAutoColor->connect_clicked(LINK(this, ColorWindow, AutoColorClickHdl)); + mxButtonNoneColor->connect_clicked(LINK(this, ColorWindow, AutoColorClickHdl)); + mxButtonPicker->connect_clicked(LINK(this, ColorWindow, OpenPickerClickHdl)); + + mxColorSet->SetSelectHdl(LINK( this, ColorWindow, SelectHdl)); + mxRecentColorSet->SetSelectHdl(LINK( this, ColorWindow, SelectHdl)); + mxTopLevel->set_help_id(HID_POPUP_COLOR); + mxColorSet->SetHelpId(HID_POPUP_COLOR_CTRL); + + mxPaletteManager->ReloadColorSet(*mxColorSet); + const sal_uInt32 nMaxItems(SvxColorValueSet::getMaxRowCount() * SvxColorValueSet::getColumnCount()); + Size aSize = mxColorSet->layoutAllVisible(nMaxItems); + mxColorSet->set_size_request(aSize.Width(), aSize.Height()); + + mxPaletteManager->ReloadRecentColorSet(*mxRecentColorSet); + aSize = mxRecentColorSet->layoutAllVisible(mxPaletteManager->GetRecentColorCount()); + mxRecentColorSet->set_size_request(aSize.Width(), aSize.Height()); + + AddStatusListener( ".uno:ColorTableState" ); + AddStatusListener( maCommand ); + if ( maCommand == ".uno:FrameLineColor" ) + { + AddStatusListener( ".uno:BorderTLBR" ); + AddStatusListener( ".uno:BorderBLTR" ); + } +} + void SvxColorWindow::ShowNoneButton() { mpButtonNoneColor->Show(); } +void ColorWindow::ShowNoneButton() +{ + mxButtonNoneColor->show(); +} + SvxColorWindow::~SvxColorWindow() { disposeOnce(); } +ColorWindow::~ColorWindow() +{ +} + void SvxColorWindow::dispose() { mpColorSet.clear(); @@ -1400,6 +1516,13 @@ NamedColor SvxColorWindow::GetSelectEntryColor(ValueSet const * pColorSet) return std::make_pair(aColor, sColorName); } +NamedColor ColorWindow::GetSelectEntryColor(SvtValueSet const * pColorSet) +{ + Color aColor = pColorSet->GetItemColor(pColorSet->GetSelectedItemId()); + OUString sColorName = pColorSet->GetItemText(pColorSet->GetSelectedItemId()); + return std::make_pair(aColor, sColorName); +} + namespace { NamedColor GetAutoColor(sal_uInt16 nSlotId) @@ -1455,6 +1578,17 @@ NamedColor SvxColorWindow::GetSelectEntryColor() const return GetAutoColor(); } +NamedColor ColorWindow::GetSelectEntryColor() const +{ + if (!mxColorSet->IsNoSelection()) + return GetSelectEntryColor(mxColorSet.get()); + if (!mxRecentColorSet->IsNoSelection()) + return GetSelectEntryColor(mxRecentColorSet.get()); + if (mxButtonNoneColor->get_has_default()) + return GetNoneColor(); + return GetAutoColor(); +} + IMPL_LINK(SvxColorWindow, SelectHdl, ValueSet*, pColorSet, void) { VclPtr<SvxColorWindow> xThis(this); @@ -1480,6 +1614,29 @@ IMPL_LINK(SvxColorWindow, SelectHdl, ValueSet*, pColorSet, void) maColorSelectFunction(maCommand, aNamedColor); } +IMPL_LINK(ColorWindow, SelectHdl, SvtValueSet*, pColorSet, void) +{ + NamedColor aNamedColor = GetSelectEntryColor(pColorSet); + /* #i33380# DR 2004-09-03 Moved the following line above the Dispatch() calls. + This instance may be deleted in the meantime (i.e. when a dialog is opened + while in Dispatch()), accessing members will crash in this case. */ + pColorSet->SetNoSelection(); + + if (pColorSet != mxRecentColorSet.get()) + { + mxPaletteManager->AddRecentColor(aNamedColor.first, aNamedColor.second); + if (!mpMenuButton->get_active()) + mxPaletteManager->ReloadRecentColorSet(*mxRecentColorSet); + } + + if (mpMenuButton->get_active()) + mpMenuButton->set_active(false); + + maSelectedLink.Call(aNamedColor); + + maColorSelectFunction(maCommand, aNamedColor); +} + IMPL_LINK_NOARG(SvxColorWindow, SelectPaletteHdl, ListBox&, void) { sal_Int32 nPos = mpPaletteListBox->GetSelectedEntryPos(); @@ -1488,11 +1645,24 @@ IMPL_LINK_NOARG(SvxColorWindow, SelectPaletteHdl, ListBox&, void) mpColorSet->layoutToGivenHeight(mpColorSet->GetSizePixel().Height(), mxPaletteManager->GetColorCount()); } +IMPL_LINK_NOARG(ColorWindow, SelectPaletteHdl, weld::ComboBoxText&, void) +{ + int nPos = mxPaletteListBox->get_active(); + mxPaletteManager->SetPalette( nPos ); + mxPaletteManager->ReloadColorSet(*mxColorSet); + mxColorSet->layoutToGivenHeight(mxColorSet->GetOutputSizePixel().Height(), mxPaletteManager->GetColorCount()); +} + NamedColor SvxColorWindow::GetAutoColor() const { return ::GetAutoColor(theSlotId); } +NamedColor ColorWindow::GetAutoColor() const +{ + return ::GetAutoColor(theSlotId); +} + IMPL_LINK(SvxColorWindow, AutoColorClickHdl, Button*, pButton, void) { VclPtr<SvxColorWindow> xThis(this); @@ -1509,6 +1679,20 @@ IMPL_LINK(SvxColorWindow, AutoColorClickHdl, Button*, pButton, void) maColorSelectFunction(maCommand, aNamedColor); } +IMPL_LINK(ColorWindow, AutoColorClickHdl, weld::Button&, rButton, void) +{ + NamedColor aNamedColor = &rButton == mxButtonAutoColor.get() ? GetAutoColor() : GetNoneColor(); + + mxRecentColorSet->SetNoSelection(); + + if (mpMenuButton->get_active()) + mpMenuButton->set_active(false); + + maSelectedLink.Call(aNamedColor); + + maColorSelectFunction(maCommand, aNamedColor); +} + IMPL_LINK_NOARG(SvxColorWindow, OpenPickerClickHdl, Button*, void) { VclPtr<SvxColorWindow> xThis(this); @@ -1529,6 +1713,13 @@ IMPL_LINK_NOARG(SvxColorWindow, OpenPickerClickHdl, Button*, void) mxPaletteManager->PopupColorPicker(pParentFrame, maCommand, GetSelectEntryColor().first); } +IMPL_LINK_NOARG(ColorWindow, OpenPickerClickHdl, weld::Button&, void) +{ + if (mpMenuButton->get_active()) + mpMenuButton->set_active(false); + mxPaletteManager->PopupColorPicker(mpParentWindow, maCommand, GetSelectEntryColor().first); +} + void SvxColorWindow::StartSelection() { mpColorSet->StartSelection(); @@ -1543,6 +1734,14 @@ void SvxColorWindow::SetNoSelection() mpButtonNoneColor->set_property("has-default", "false"); } +void ColorWindow::SetNoSelection() +{ + mxColorSet->SetNoSelection(); + mxRecentColorSet->SetNoSelection(); + mxButtonAutoColor->set_has_default(false); + mxButtonNoneColor->set_has_default(false); +} + bool SvxColorWindow::IsNoSelection() const { if (!mpColorSet->IsNoSelection()) @@ -1552,6 +1751,15 @@ bool SvxColorWindow::IsNoSelection() const return !mpButtonAutoColor->IsVisible() && !mpButtonNoneColor->IsVisible(); } +bool ColorWindow::IsNoSelection() const +{ + if (!mxColorSet->IsNoSelection()) + return false; + if (!mxRecentColorSet->IsNoSelection()) + return false; + return !mxButtonAutoColor->get_visible() && !mxButtonNoneColor->get_visible(); +} + void SvxColorWindow::statusChanged( const css::frame::FeatureStateEvent& rEvent ) { if (rEvent.FeatureURL.Complete == ".uno:ColorTableState") @@ -1581,6 +1789,35 @@ void SvxColorWindow::statusChanged( const css::frame::FeatureStateEvent& rEvent } } +void ColorWindow::statusChanged( const css::frame::FeatureStateEvent& rEvent ) +{ + if (rEvent.FeatureURL.Complete == ".uno:ColorTableState") + { + if (rEvent.IsEnabled && mxPaletteManager->GetPalette() == 0) + { + mxPaletteManager->ReloadColorSet(*mxColorSet); + mxColorSet->layoutToGivenHeight(mxColorSet->GetOutputSizePixel().Height(), mxPaletteManager->GetColorCount()); + } + } + else + { + Color aColor(COL_TRANSPARENT); + + if (mrBorderColorStatus.statusChanged(rEvent)) + { + aColor = mrBorderColorStatus.GetColor(); + } + else if (rEvent.IsEnabled) + { + sal_Int32 nValue; + if (rEvent.State >>= nValue) + aColor = Color(nValue); + } + + SelectEntry(aColor); + } +} + bool SvxColorWindow::SelectValueSetEntry(SvxColorValueSet* pColorSet, const Color& rColor) { for (size_t i = 1; i <= pColorSet->GetItemCount(); ++i) @@ -1594,6 +1831,19 @@ bool SvxColorWindow::SelectValueSetEntry(SvxColorValueSet* pColorSet, const Colo return false; } +bool ColorWindow::SelectValueSetEntry(ColorValueSet* pColorSet, const Color& rColor) +{ + for (size_t i = 1; i <= pColorSet->GetItemCount(); ++i) + { + if (rColor == pColorSet->GetItemColor(i)) + { + pColorSet->SelectItem(i); + return true; + } + } + return false; +} + void SvxColorWindow::SelectEntry(const NamedColor& rNamedColor) { SetNoSelection(); @@ -1635,6 +1885,47 @@ void SvxColorWindow::SelectEntry(const Color& rColor) SvxColorWindow::SelectEntry(std::make_pair(rColor, sColorName)); } +void ColorWindow::SelectEntry(const NamedColor& rNamedColor) +{ + SetNoSelection(); + + const Color &rColor = rNamedColor.first; + + if (mxButtonNoneColor->get_visible() && (rColor == COL_TRANSPARENT || rColor == COL_AUTO)) + { + mxButtonAutoColor->set_has_default(true); + return; + } + + if (mxButtonNoneColor->get_visible() && rColor == COL_NONE_COLOR) + { + mxButtonNoneColor->set_has_default(true); + return; + } + + // try current palette + bool bFoundColor = SelectValueSetEntry(mxColorSet.get(), rColor); + // try recently used + if (!bFoundColor) + bFoundColor = SelectValueSetEntry(mxRecentColorSet.get(), rColor); + // if its not there, add it there now to the end of the recently used + // so its available somewhere handy, but not without trashing the + // whole recently used + if (!bFoundColor) + { + const OUString& rColorName = rNamedColor.second; + mxPaletteManager->AddRecentColor(rColor, rColorName, false); + mxPaletteManager->ReloadRecentColorSet(*mxRecentColorSet); + SelectValueSetEntry(mxRecentColorSet.get(), rColor); + } +} + +void ColorWindow::SelectEntry(const Color& rColor) +{ + OUString sColorName = ("#" + rColor.AsRGBHexString().toAsciiUpperCase()); + ColorWindow::SelectEntry(std::make_pair(rColor, sColorName)); +} + BorderColorStatus::BorderColorStatus() : maColor( COL_TRANSPARENT ), maTLBRColor( COL_TRANSPARENT ), @@ -3273,6 +3564,16 @@ void SvxListBoxColorWrapper::dispose() mxControl.clear(); } +ListBoxColorWrapper::ListBoxColorWrapper(ColorListBox* pControl) + : mpControl(pControl) +{ +} + +void ListBoxColorWrapper::operator()(const OUString& /*rCommand*/, const NamedColor& rColor) +{ + mpControl->Selected(rColor); +} + SvxColorListBox::SvxColorListBox(vcl::Window* pParent, WinBits nStyle) : MenuButton(pParent, nStyle) , m_aColorWrapper(this) @@ -3295,6 +3596,15 @@ void SvxColorListBox::EnsurePaletteManager() } } +void ColorListBox::EnsurePaletteManager() +{ + if (!m_xPaletteManager) + { + m_xPaletteManager.reset(new PaletteManager); + m_xPaletteManager->SetColorSelectFunction(std::ref(m_aColorWrapper)); + } +} + void SvxColorListBox::SetSlotId(sal_uInt16 nSlotId, bool bShowNoneButton) { m_nSlotId = nSlotId; @@ -3453,6 +3763,136 @@ void SvxColorListBox::SelectEntry(const Color& rColor) ShowPreview(m_aSelectedColor); } +ColorListBox::ColorListBox(weld::MenuButton* pControl, weld::Window* pTopLevel) + : m_xButton(pControl) + , m_pTopLevel(pTopLevel) + , m_aColorWrapper(this) + , m_aAutoDisplayColor(Application::GetSettings().GetStyleSettings().GetDialogColor()) + , m_nSlotId(0) + , m_bShowNoneButton(false) +{ + m_aSelectedColor = GetAutoColor(m_nSlotId); + LockWidthRequest(); + ShowPreview(m_aSelectedColor); +} + +ColorListBox::~ColorListBox() +{ +} + +ColorWindow* ColorListBox::getColorWindow() const +{ + if (!m_xColorWindow) + const_cast<ColorListBox*>(this)->createColorWindow(); + return m_xColorWindow.get(); +} + +void ColorListBox::createColorWindow() +{ + const SfxViewFrame* pViewFrame = SfxViewFrame::Current(); + const SfxFrame* pFrame = pViewFrame ? &pViewFrame->GetFrame() : nullptr; + css::uno::Reference<css::frame::XFrame> xFrame(pFrame ? pFrame->GetFrameInterface() : uno::Reference<css::frame::XFrame>()); + + EnsurePaletteManager(); + + m_xColorWindow.reset(new ColorWindow( + OUString() /*m_aCommandURL*/, + m_xPaletteManager, + m_aBorderColorStatus, + m_nSlotId, + xFrame, + m_pTopLevel, + m_xButton.get(), + m_aColorWrapper)); + + SetNoSelection(); + if (m_bShowNoneButton) + m_xColorWindow->ShowNoneButton(); + m_xButton->set_popover(m_xColorWindow->GetWidget()); + m_xColorWindow->SelectEntry(m_aSelectedColor); +} + +void ColorListBox::SelectEntry(const NamedColor& rColor) +{ + if (rColor.second.trim().isEmpty()) + { + SelectEntry(rColor.first); + return; + } + ColorWindow* pColorWindow = getColorWindow(); + pColorWindow->SelectEntry(rColor); + m_aSelectedColor = pColorWindow->GetSelectEntryColor(); + ShowPreview(m_aSelectedColor); +} + +void ColorListBox::SelectEntry(const Color& rColor) +{ + ColorWindow* pColorWindow = getColorWindow(); + pColorWindow->SelectEntry(rColor); + m_aSelectedColor = pColorWindow->GetSelectEntryColor(); + ShowPreview(m_aSelectedColor); +} + +void ColorListBox::Selected(const NamedColor& rColor) +{ + ShowPreview(rColor); + m_aSelectedColor = rColor; + if (m_aSelectedLink.IsSet()) + m_aSelectedLink.Call(*this); +} + +//to avoid the box resizing every time the color is changed to +//the optimal size of the individual color, get the longest +//standard color and stick with that as the size for all +void ColorListBox::LockWidthRequest() +{ + NamedColor aLongestColor; + long nMaxStandardColorTextWidth = 0; + XColorListRef const xColorTable = XColorList::CreateStdColorList(); + for (long i = 0; i != xColorTable->Count(); ++i) + { + XColorEntry& rEntry = *xColorTable->GetColor(i); + auto nColorTextWidth = m_xButton->get_pixel_size(rEntry.GetName()).Width(); + if (nColorTextWidth > nMaxStandardColorTextWidth) + { + nMaxStandardColorTextWidth = nColorTextWidth; + aLongestColor.second = rEntry.GetName(); + } + } + ShowPreview(aLongestColor); + m_xButton->set_size_request(m_xButton->get_preferred_size().Width(), -1); +} + +void ColorListBox::ShowPreview(const NamedColor &rColor) +{ + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + Size aImageSize(rStyleSettings.GetListBoxPreviewDefaultPixelSize()); + + ScopedVclPtrInstance<VirtualDevice> xDevice; + xDevice->SetOutputSize(aImageSize); + const tools::Rectangle aRect(Point(0, 0), aImageSize); + if (m_bShowNoneButton && rColor.first == COL_NONE_COLOR) + { + const Color aW(COL_WHITE); + const Color aG(0xef, 0xef, 0xef); + xDevice->DrawCheckered(aRect.TopLeft(), aRect.GetSize(), 8, aW, aG); + xDevice->SetFillColor(); + } + else + { + if (rColor.first == COL_AUTO) + xDevice->SetFillColor(m_aAutoDisplayColor); + else + xDevice->SetFillColor(rColor.first); + } + + xDevice->SetLineColor(rStyleSettings.GetDisableColor()); + xDevice->DrawRect(aRect); + + m_xButton->set_image(*xDevice); + m_xButton->set_label(rColor.second); +} + SvxColorListBoxWrapper::SvxColorListBoxWrapper(SvxColorListBox& rListBox) : sfx::SingleControlWrapper<SvxColorListBox, Color>(rListBox) { diff --git a/svx/uiconfig/ui/colorwindow.ui b/svx/uiconfig/ui/colorwindow.ui index b123b10e36a2..1c2e815eba12 100644 --- a/svx/uiconfig/ui/colorwindow.ui +++ b/svx/uiconfig/ui/colorwindow.ui @@ -1,33 +1,32 @@ <?xml version="1.0" encoding="UTF-8"?> -<!-- Generated with glade 3.20.0 --> +<!-- Generated with glade 3.22.1 --> <interface domain="svx"> - <requires lib="gtk+" version="3.18"/> - <requires lib="LibreOffice" version="1.0"/> + <requires lib="gtk+" version="3.20"/> <object class="GtkImage" id="auto_icon"> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="pixbuf">cmd/sc_square_unfilled.png</property> + <property name="icon_name">cmd/sc_square_unfilled.png</property> </object> <object class="GtkImage" id="custom_color_icon"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="margin_right">6</property> <property name="xalign">0</property> - <property name="pixbuf">cmd/sc_colorsettings.png</property> + <property name="icon_name">cmd/sc_colorsettings.png</property> <property name="icon_size">1</property> </object> <object class="GtkImage" id="none_icon"> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="pixbuf">cmd/sc_square_unfilled.png</property> + <property name="icon_name">cmd/sc_square_unfilled.png</property> </object> - <object class="GtkWindow" id="palette_popup_window"> + <object class="GtkPopover" id="palette_popup_window"> <property name="can_focus">False</property> <property name="hexpand">True</property> <property name="vexpand">True</property> <property name="border_width">4</property> - <property name="resizable">False</property> - <property name="type_hint">dock</property> + <property name="position">bottom</property> + <property name="constrain_to">none</property> <child> <object class="GtkBox" id="box1"> <property name="visible">True</property> @@ -43,7 +42,9 @@ <object class="GtkButton" id="auto_color_button"> <property name="visible">True</property> <property name="can_focus">True</property> + <property name="can_default">True</property> <property name="receives_default">True</property> + <property name="no_show_all">True</property> <property name="image">auto_icon</property> <property name="relief">none</property> <property name="xalign">0</property> @@ -58,7 +59,9 @@ <object class="GtkButton" id="none_color_button"> <property name="label" translatable="yes" context="colorwindow|none_color_button">None</property> <property name="can_focus">True</property> + <property name="can_default">True</property> <property name="receives_default">True</property> + <property name="no_show_all">True</property> <property name="image">none_icon</property> <property name="relief">none</property> <property name="xalign">0</property> @@ -88,7 +91,7 @@ </packing> </child> <child> - <object class="GtkComboBox" id="palette_listbox"> + <object class="GtkComboBoxText" id="palette_listbox"> <property name="visible">True</property> <property name="can_focus">False</property> </object> @@ -99,10 +102,25 @@ </packing> </child> <child> - <object class="svxcorelo-SvxColorValueSet" id="colorset"> + <object class="GtkScrolledWindow" id="colorsetwin"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="receives_default">True</property> + <property name="hscrollbar_policy">never</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkViewport"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkDrawingArea" id="colorset"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property> + </object> + </child> + </object> + </child> </object> <packing> <property name="expand">False</property> @@ -126,6 +144,8 @@ <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes" context="colorwindow|label1">Recent</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">recent_colorset</property> <property name="xalign">0</property> </object> <packing> @@ -135,10 +155,11 @@ </packing> </child> <child> - <object class="svxcorelo-SvxColorValueSet" id="recent_colorset"> + <object class="GtkDrawingArea" id="recent_colorset"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> + <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property> </object> <packing> <property name="expand">False</property> diff --git a/svx/uiconfig/ui/oldcolorwindow.ui b/svx/uiconfig/ui/oldcolorwindow.ui new file mode 100644 index 000000000000..042fdd3cc71c --- /dev/null +++ b/svx/uiconfig/ui/oldcolorwindow.ui @@ -0,0 +1,180 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.20.0 --> +<interface domain="svx"> + <requires lib="gtk+" version="3.18"/> + <requires lib="LibreOffice" version="1.0"/> + <object class="GtkImage" id="auto_icon"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="pixbuf">cmd/sc_square_unfilled.png</property> + </object> + <object class="GtkImage" id="custom_color_icon"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="margin_right">6</property> + <property name="xalign">0</property> + <property name="pixbuf">cmd/sc_colorsettings.png</property> + <property name="icon_size">1</property> + </object> + <object class="GtkImage" id="none_icon"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="pixbuf">cmd/sc_square_unfilled.png</property> + </object> + <object class="GtkWindow" id="palette_popup_window"> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="border_width">4</property> + <property name="resizable">False</property> + <property name="type_hint">dock</property> + <child> + <object class="GtkBox" id="box1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">6</property> + <property name="homogeneous">True</property> + <child> + <object class="GtkButton" id="auto_color_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="image">auto_icon</property> + <property name="relief">none</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="none_color_button"> + <property name="label" translatable="yes" context="oldcolorwindow|none_color_button">None</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="image">none_icon</property> + <property name="relief">none</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkSeparator" id="separator4"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkComboBox" id="palette_listbox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="svxcorelo-SvxColorValueSet" id="colorset"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + <child> + <object class="GtkSeparator" id="separator1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">4</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes" context="oldcolorwindow|label1">Recent</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">5</property> + </packing> + </child> + <child> + <object class="svxcorelo-SvxColorValueSet" id="recent_colorset"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">7</property> + </packing> + </child> + <child> + <object class="GtkSeparator" id="separator3"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">8</property> + </packing> + </child> + <child> + <object class="GtkButton" id="color_picker_button"> + <property name="label" translatable="yes" context="oldcolorwindow|color_picker_button">Custom Color…</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="image">custom_color_icon</property> + <property name="relief">none</property> + <property name="xalign">0</property> + <property name="always_show_image">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">9</property> + </packing> + </child> + </object> + </child> + </object> +</interface> diff --git a/sw/qa/uitest/writer_tests/watermark.py b/sw/qa/uitest/writer_tests/watermark.py index d42f37bb2aff..c5b07ac2a494 100644 --- a/sw/qa/uitest/writer_tests/watermark.py +++ b/sw/qa/uitest/writer_tests/watermark.py @@ -40,8 +40,8 @@ class watermark(UITestCase): xTransparency = xDialog.getChild("Transparency") self.assertEqual(get_state_as_dict(xTextInput)["Text"], "Watermark") - self.assertEqual(get_state_as_dict(xAngle)["Text"], "46") - self.assertEqual(get_state_as_dict(xTransparency)["Text"], "51") + self.assertEqual(get_state_as_dict(xAngle)["Text"], "46°") + self.assertEqual(get_state_as_dict(xTransparency)["Text"], "51%") xCancBtn = xDialog.getChild("cancel") self.ui_test.close_dialog_through_button(xCancBtn) diff --git a/sw/source/uibase/app/docsh2.cxx b/sw/source/uibase/app/docsh2.cxx index 7f7df1db893e..07afee0fcd64 100644 --- a/sw/source/uibase/app/docsh2.cxx +++ b/sw/source/uibase/app/docsh2.cxx @@ -1225,10 +1225,11 @@ void SwDocShell::Execute(SfxRequest& rReq) } else { - SfxViewShell* pViewShell = GetView()? GetView(): SfxViewShell::Current(); + SfxViewShell* pViewShell = GetView() ? GetView() : SfxViewShell::Current(); SfxBindings& rBindings( pViewShell->GetViewFrame()->GetBindings() ); - VclPtr<SwWatermarkDialog> pDlg(VclPtr<SwWatermarkDialog>::Create(&GetView()->GetViewFrame()->GetWindow(), rBindings)); - pDlg->StartExecuteAsync([](sal_Int32 /*nResult*/){}); + std::shared_ptr<SwWatermarkDialog> xDlg(new SwWatermarkDialog(pViewShell->GetViewFrame()->GetWindow().GetFrameWeld(), + rBindings)); + weld::DialogController::runAsync(xDlg, [](sal_Int32 /*nResult*/){}); } } } diff --git a/sw/source/uibase/dialog/watermarkdialog.cxx b/sw/source/uibase/dialog/watermarkdialog.cxx index 1a61670945f0..f3fbdb2bd907 100644 --- a/sw/source/uibase/dialog/watermarkdialog.cxx +++ b/sw/source/uibase/dialog/watermarkdialog.cxx @@ -19,36 +19,21 @@ #include <sfx2/watermarkitem.hxx> #include <svtools/ctrltool.hxx> -SwWatermarkDialog::SwWatermarkDialog( vcl::Window* pParent, SfxBindings& rBindings ) -: ModelessDialog( pParent, "WatermarkDialog", "modules/swriter/ui/watermarkdialog.ui" ) -, m_rBindings( rBindings ) +SwWatermarkDialog::SwWatermarkDialog(weld::Window* pParent, SfxBindings& rBindings) + : GenericDialogController(pParent, "modules/swriter/ui/watermarkdialog.ui", "WatermarkDialog") + , m_rBindings(rBindings) + , m_xTextInput(m_xBuilder->weld_entry("TextInput")) + , m_xOKButton(m_xBuilder->weld_button("ok")) + , m_xFont(m_xBuilder->weld_combo_box_text("FontBox")) + , m_xAngle(m_xBuilder->weld_metric_spin_button("Angle", FUNIT_DEGREE)) + , m_xTransparency(m_xBuilder->weld_metric_spin_button("Transparency", FUNIT_PERCENT)) + , m_xColor(new ColorListBox(m_xBuilder->weld_menu_button("Color"), m_xDialog.get())) { - get( m_pTextInput, "TextInput" ); - get( m_pOKButton, "ok" ); - get( m_pFont, "FontBox" ); - get( m_pAngle, "Angle" ); - get( m_pTransparency, "Transparency" ); - get( m_pColor, "Color" ); - InitFields(); - Update(); } SwWatermarkDialog::~SwWatermarkDialog() { - disposeOnce(); -} - -void SwWatermarkDialog::dispose() -{ - m_pFont.clear(); - m_pAngle.clear(); - m_pTransparency.clear(); - m_pColor.clear(); - m_pTextInput.clear(); - m_pOKButton.clear(); - - ModelessDialog::dispose(); } void SwWatermarkDialog::InitFields() @@ -68,9 +53,14 @@ void SwWatermarkDialog::InitFields() pFontList = xFontList.get(); } - m_pFont->Fill( pFontList ); + sal_uInt16 nFontCount = pFontList->GetFontNameCount(); + for (sal_uInt16 i = 0; i < nFontCount; ++i) + { + const FontMetric& rFontMetric = pFontList->GetFontName(i); + m_xFont->append_text(rFontMetric.GetFamilyName()); + } - m_pOKButton->SetClickHdl( LINK( this, SwWatermarkDialog, OKButtonHdl ) ); + m_xOKButton->connect_clicked(LINK(this, SwWatermarkDialog, OKButtonHdl)); // Get watermark properties const SfxPoolItem* pItem; @@ -80,29 +70,29 @@ void SwWatermarkDialog::InitFields() { const SfxWatermarkItem* pWatermark = static_cast<const SfxWatermarkItem*>( pItem ); OUString sText = pWatermark->GetText(); - m_pTextInput->SetText( sText ); - m_pFont->SelectEntryPos( m_pFont->GetEntryPos( pWatermark->GetFont() ) ); - m_pAngle->SetValue( pWatermark->GetAngle() ); - m_pColor->SelectEntry( pWatermark->GetColor() ); - m_pTransparency->SetValue( pWatermark->GetTransparency() ); + m_xTextInput->set_text(sText); + m_xFont->set_entry_text(pWatermark->GetFont()); + m_xAngle->set_value(pWatermark->GetAngle(), FUNIT_DEGREE); + m_xColor->SelectEntry( pWatermark->GetColor() ); + m_xTransparency->set_value(pWatermark->GetTransparency(), FUNIT_PERCENT); } } -IMPL_LINK_NOARG( SwWatermarkDialog, OKButtonHdl, Button*, void ) +IMPL_LINK_NOARG(SwWatermarkDialog, OKButtonHdl, weld::Button&, void) { - OUString sText = m_pTextInput->GetText(); + OUString sText = m_xTextInput->get_text(); css::uno::Sequence<css::beans::PropertyValue> aPropertyValues( comphelper::InitPropertySequence( { { "Text", css::uno::makeAny( sText ) }, - { "Font", css::uno::makeAny( m_pFont->GetSelectedEntry() ) }, - { "Angle", css::uno::makeAny( static_cast<sal_Int16>( m_pAngle->GetValue() ) ) }, - { "Transparency", css::uno::makeAny( static_cast<sal_Int16>( m_pTransparency->GetValue() ) ) }, - { "Color", css::uno::makeAny( static_cast<sal_uInt32>( m_pColor->GetSelectEntryColor().GetRGBColor() ) ) } + { "Font", css::uno::makeAny( m_xFont->get_active_text() ) }, + { "Angle", css::uno::makeAny( static_cast<sal_Int16>( m_xAngle->get_value(FUNIT_DEGREE) ) ) }, + { "Transparency", css::uno::makeAny( static_cast<sal_Int16>( m_xTransparency->get_value(FUNIT_PERCENT) ) ) }, + { "Color", css::uno::makeAny( static_cast<sal_uInt32>( m_xColor->GetSelectEntryColor().GetRGBColor() ) ) } } ) ); comphelper::dispatchCommand( ".uno:Watermark", aPropertyValues ); - Close(); + m_xDialog->response(RET_OK); } /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/sw/source/uibase/inc/watermarkdialog.hxx b/sw/source/uibase/inc/watermarkdialog.hxx index b443fbce797d..68f7d3d40a5f 100644 --- a/sw/source/uibase/inc/watermarkdialog.hxx +++ b/sw/source/uibase/inc/watermarkdialog.hxx @@ -10,31 +10,28 @@ #define INCLUDED_SW_SOURCE_UIBASE_INC_WATERMARKDIALOG_HXX #include <sfx2/bindings.hxx> -#include <vcl/field.hxx> -#include <vcl/layout.hxx> -#include <svtools/ctrlbox.hxx> +#include <vcl/weld.hxx> #include <svx/colorbox.hxx> -class SwWatermarkDialog : public ModelessDialog +class SwWatermarkDialog : public weld::GenericDialogController { public: - SwWatermarkDialog( vcl::Window* pParent, SfxBindings& rBindings ); + SwWatermarkDialog(weld::Window* pParent, SfxBindings& rBindings); virtual ~SwWatermarkDialog() override; - virtual void dispose() override; void InitFields(); private: - DECL_LINK( OKButtonHdl, Button*, void ); + DECL_LINK(OKButtonHdl, weld::Button&, void); SfxBindings& m_rBindings; - VclPtr<Edit> m_pTextInput; - VclPtr<PushButton> m_pOKButton; - VclPtr<FontNameBox> m_pFont; - VclPtr<NumericField> m_pAngle; - VclPtr<NumericField> m_pTransparency; - VclPtr<SvxColorListBox> m_pColor; + std::unique_ptr<weld::Entry> m_xTextInput; + std::unique_ptr<weld::Button> m_xOKButton; + std::unique_ptr<weld::ComboBoxText> m_xFont; + std::unique_ptr<weld::MetricSpinButton> m_xAngle; + std::unique_ptr<weld::MetricSpinButton> m_xTransparency; + std::unique_ptr<ColorListBox> m_xColor; }; #endif diff --git a/sw/uiconfig/swriter/ui/watermarkdialog.ui b/sw/uiconfig/swriter/ui/watermarkdialog.ui index c52e67394d2a..60450a06b10d 100644 --- a/sw/uiconfig/swriter/ui/watermarkdialog.ui +++ b/sw/uiconfig/swriter/ui/watermarkdialog.ui @@ -1,8 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> -<!-- Generated with glade 3.20.0 --> +<!-- Generated with glade 3.22.1 --> <interface domain="sw"> <requires lib="gtk+" version="3.18"/> - <requires lib="LibreOffice" version="1.0"/> <object class="GtkAdjustment" id="angle_adj"> <property name="upper">359</property> <property name="step_increment">1</property> @@ -17,7 +16,13 @@ <property name="can_focus">False</property> <property name="border_width">6</property> <property name="title" translatable="yes" context="watermarkdialog|WatermarkDialog">Watermark</property> + <property name="modal">True</property> + <property name="default_width">0</property> + <property name="default_height">0</property> <property name="type_hint">dialog</property> + <child> + <placeholder/> + </child> <child internal-child="vbox"> <object class="GtkBox" id="dialog-vbox1"> <property name="can_focus">False</property> @@ -109,6 +114,7 @@ <property name="visible">True</property> <property name="can_focus">True</property> <property name="hexpand">True</property> + <property name="activates_default">True</property> </object> <packing> <property name="left_attach">1</property> @@ -116,16 +122,6 @@ </packing> </child> <child> - <object class="svtlo-FontNameBox" id="FontBox"> - <property name="visible">True</property> - <property name="can_focus">True</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">1</property> - </packing> - </child> - <child> <object class="GtkLabel" id="FontLabel"> <property name="visible">True</property> <property name="can_focus">False</property> @@ -167,6 +163,8 @@ <property name="can_focus">False</property> <property name="halign">end</property> <property name="label" translatable="yes" context="watermarkdialog|ColorLabel">Color</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">Color</property> </object> <packing> <property name="left_attach">0</property> @@ -177,6 +175,7 @@ <object class="GtkSpinButton" id="Angle"> <property name="visible">True</property> <property name="can_focus">True</property> + <property name="activates_default">True</property> <property name="adjustment">angle_adj</property> </object> <packing> @@ -188,6 +187,7 @@ <object class="GtkSpinButton" id="Transparency"> <property name="visible">True</property> <property name="can_focus">True</property> + <property name="activates_default">True</property> <property name="adjustment">transparenct_adj</property> <property name="value">50</property> </object> @@ -197,15 +197,37 @@ </packing> </child> <child> - <object class="svxcorelo-SvxColorListBox" id="Color"> + <object class="GtkMenuButton" id="Color"> <property name="visible">True</property> <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="xalign">0</property> + <child> + <placeholder/> + </child> </object> <packing> <property name="left_attach">1</property> <property name="top_attach">4</property> </packing> </child> + <child> + <object class="GtkComboBoxText" id="FontBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="has_entry">True</property> + <child internal-child="entry"> + <object class="GtkEntry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + </object> + </child> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">1</property> + </packing> + </child> </object> <packing> <property name="expand">True</property> diff --git a/vcl/headless/svpinst.cxx b/vcl/headless/svpinst.cxx index 48f799473b14..c3d96016f5f2 100644 --- a/vcl/headless/svpinst.cxx +++ b/vcl/headless/svpinst.cxx @@ -248,7 +248,7 @@ std::unique_ptr<SalVirtualDevice> SvpSalInstance::CreateVirtualDevice( SalGraphi return pNew; } -cairo_surface_t* get_underlying_cairo_suface(VirtualDevice& rDevice) +cairo_surface_t* get_underlying_cairo_surface(VirtualDevice& rDevice) { return static_cast<SvpSalVirtualDevice*>(rDevice.mpVirDev.get())->GetSurface(); } diff --git a/vcl/inc/headless/svpinst.hxx b/vcl/inc/headless/svpinst.hxx index 3ca4d204cb84..caecb14003d5 100644 --- a/vcl/inc/headless/svpinst.hxx +++ b/vcl/inc/headless/svpinst.hxx @@ -197,7 +197,7 @@ inline void SvpSalInstance::deregisterFrame( SalFrame* pFrame ) eraseFrame( pFrame ); } -VCL_DLLPUBLIC cairo_surface_t* get_underlying_cairo_suface(VirtualDevice& rDevice); +VCL_DLLPUBLIC cairo_surface_t* get_underlying_cairo_surface(VirtualDevice& rDevice); #endif // INCLUDED_VCL_INC_HEADLESS_SVPINST_HXX diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx index f17df42bd968..7f03aed3e6c2 100644 --- a/vcl/source/app/salvtables.cxx +++ b/vcl/source/app/salvtables.cxx @@ -234,6 +234,16 @@ public: return m_xWidget->HasFocus(); } + virtual void set_has_default(bool has_default) override + { + m_xWidget->set_property("has-default", OUString::boolean(has_default)); + } + + virtual bool get_has_default() const override + { + return m_xWidget->GetStyle() & WB_DEFBUTTON; + } + virtual void show() override { m_xWidget->Show(); @@ -962,6 +972,13 @@ public: m_xButton->SetText(rText); } + virtual void set_image(VirtualDevice& rDevice) override + { + BitmapEx aBitmap(rDevice.GetBitmap(Point(0, 0), rDevice.GetOutputSize())); + m_xButton->SetImageAlign(ImageAlign::Left); + m_xButton->SetModeImage(Image(aBitmap)); + } + virtual OUString get_label() const override { return m_xButton->GetText(); @@ -1009,6 +1026,31 @@ public: m_xMenuButton->SetSelectHdl(LINK(this, SalInstanceMenuButton, MenuSelectHdl)); } + virtual void set_active(bool active) override + { + if (active == get_active()) + return; + if (active) + m_xMenuButton->ExecuteMenu(); + else + m_xMenuButton->CancelMenu(); + } + + virtual bool get_active() const override + { + return m_xMenuButton->MenuShown(); + } + + virtual void set_inconsistent(bool /*inconsistent*/) override + { + //not available + } + + virtual bool get_inconsistent() const override + { + return false; + } + virtual void set_item_active(const OString& rIdent, bool bActive) override { PopupMenu* pMenu = m_xMenuButton->GetPopupMenu(); @@ -1033,6 +1075,12 @@ public: return pMenu->GetHelpId(pMenu->GetItemId(rIdent)); } + virtual void set_popover(weld::Widget* pPopover) override + { + SalInstanceWidget* pPopoverWidget = dynamic_cast<SalInstanceWidget*>(pPopover); + m_xMenuButton->SetPopover(pPopoverWidget ? pPopoverWidget->getWidget() : nullptr); + } + virtual ~SalInstanceMenuButton() override { m_xMenuButton->SetSelectHdl(Link<::MenuButton*, void>()); diff --git a/vcl/source/control/menubtn.cxx b/vcl/source/control/menubtn.cxx index 0b47bf8dfac8..edf0df728ba0 100644 --- a/vcl/source/control/menubtn.cxx +++ b/vcl/source/control/menubtn.cxx @@ -73,6 +73,40 @@ void MenuButton::ExecuteMenu() } } +void MenuButton::CancelMenu() +{ + if (!mpMenu && !mpFloatingWindow) + return; + + if (mpMenu) + { + mpMenu->EndExecute(); + } + else + { + if (mpFloatingWindow->GetType() == WindowType::FLOATINGWINDOW) + static_cast<FloatingWindow*>(mpFloatingWindow.get())->EndPopupMode(); + else + vcl::Window::GetDockingManager()->EndPopupMode(mpFloatingWindow); + } +} + +bool MenuButton::MenuShown() const +{ + if (!mpMenu && !mpFloatingWindow) + return false; + + if (mpMenu) + return PopupMenu::GetActivePopupMenu() == mpMenu; + else + { + if (mpFloatingWindow->GetType() == WindowType::FLOATINGWINDOW) + return static_cast<const FloatingWindow*>(mpFloatingWindow.get())->IsInPopupMode(); + else + return vcl::Window::GetDockingManager()->IsInPopupMode(mpFloatingWindow); + } +} + OString MenuButton::GetCurItemIdent() const { return (mnCurItemId && mpMenu) ? diff --git a/vcl/source/window/builder.cxx b/vcl/source/window/builder.cxx index b4adb2e33069..fa0f1dc4ef30 100644 --- a/vcl/source/window/builder.cxx +++ b/vcl/source/window/builder.cxx @@ -1502,8 +1502,8 @@ VclPtr<vcl::Window> VclBuilder::makeObject(vcl::Window *pParent, const OString & VclPtr<Button> xButton; xButton = extractStockAndBuildMenuButton(pParent, rMap); OUString sMenu = extractPopupMenu(rMap); - assert(!sMenu.isEmpty()); - m_pParserState->m_aButtonMenuMaps.emplace_back(id, sMenu); + if (!sMenu.isEmpty()) + m_pParserState->m_aButtonMenuMaps.emplace_back(id, sMenu); xButton->SetImageAlign(ImageAlign::Left); //default to left xButton->SetAccessibleRole(css::accessibility::AccessibleRole::BUTTON_MENU); setupFromActionName(xButton, rMap, m_xFrame); @@ -1880,6 +1880,11 @@ VclPtr<vcl::Window> VclBuilder::makeObject(vcl::Window *pParent, const OString & else xWindow = VclPtr<FloatingWindow>::Create(pParent, nBits|WB_MOVEABLE); } + else if (name == "GtkPopover") + { + WinBits nBits = extractDeferredBits(rMap); + xWindow = VclPtr<DockingWindow>::Create(pParent, nBits|WB_DOCKABLE|WB_MOVEABLE); + } else if (name == "GtkListBox") { WinBits nBits = extractDeferredBits(rMap); diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx index 1d2c8d272b83..e2bc52fc922a 100644 --- a/vcl/unx/gtk3/gtk3gtkinst.cxx +++ b/vcl/unx/gtk3/gtk3gtkinst.cxx @@ -1241,6 +1241,18 @@ public: return gtk_widget_has_focus(m_pWidget); } + virtual void set_has_default(bool has_default) override + { + g_object_set(G_OBJECT(m_pWidget), "has-default", has_default, nullptr); + } + + virtual bool get_has_default() const override + { + gboolean has_default(false); + g_object_get(G_OBJECT(m_pWidget), "has-default", &has_default, nullptr); + return has_default; + } + virtual void show() override { gtk_widget_show(m_pWidget); @@ -1587,6 +1599,8 @@ public: : m_pMenu(pMenu) , m_bTakeOwnership(bTakeOwnership) { + if (!m_pMenu) + return; gtk_container_foreach(GTK_CONTAINER(m_pMenu), collect, this); for (auto& a : m_aMap) g_signal_connect(a.second, "activate", G_CALLBACK(signalActivate), this); @@ -2715,6 +2729,13 @@ public: ::set_label(m_pButton, rText); } + virtual void set_image(VirtualDevice& rDevice) override + { + gtk_button_set_always_show_image(m_pButton, true); + gtk_button_set_image_position(m_pButton, GTK_POS_LEFT); + gtk_button_set_image(m_pButton, gtk_image_new_from_surface(get_underlying_cairo_surface(rDevice))); + } + virtual OUString get_label() const override { return ::get_label(m_pButton); @@ -2782,42 +2803,6 @@ bool GtkInstanceDialog::has_click_handler(int nResponse) return false; } -class GtkInstanceMenuButton : public GtkInstanceButton, public MenuHelper, public virtual weld::MenuButton -{ -public: - GtkInstanceMenuButton(GtkMenuButton* pMenuButton, bool bTakeOwnership) - : GtkInstanceButton(GTK_BUTTON(pMenuButton), bTakeOwnership) - , MenuHelper(gtk_menu_button_get_popup(pMenuButton), false) - { - } - - virtual void set_item_active(const OString& rIdent, bool bActive) override - { - MenuHelper::set_item_active(rIdent, bActive); - } - - virtual void set_item_label(const OString& rIdent, const OUString& rLabel) override - { - MenuHelper::set_item_label(rIdent, rLabel); - } - - virtual void set_item_help_id(const OString& rIdent, const OString& rHelpId) override - { - MenuHelper::set_item_help_id(rIdent, rHelpId); - } - - virtual OString get_item_help_id(const OString& rIdent) const override - { - return MenuHelper::get_item_help_id(rIdent); - } - - virtual void signal_activate(GtkMenuItem* pItem) override - { - const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pItem)); - signal_selected(OString(pStr, pStr ? strlen(pStr) : 0)); - } -}; - class GtkInstanceToggleButton : public GtkInstanceButton, public virtual weld::ToggleButton { private: @@ -2879,6 +2864,294 @@ public: } }; +class GtkInstanceMenuButton : public GtkInstanceToggleButton, public MenuHelper, public virtual weld::MenuButton +{ +private: + GtkMenuButton* m_pMenuButton; + GtkBox* m_pBox; + GtkImage* m_pImage; + GtkLabel* m_pLabel; + //popover cannot escape dialog under X so stick up own window instead + GtkWindow* m_pMenuHack; + GtkWidget* m_pPopover; + gulong m_nSignalId; + + static void signalToggled(GtkWidget*, gpointer widget) + { + GtkInstanceMenuButton* pThis = static_cast<GtkInstanceMenuButton*>(widget); + SolarMutexGuard aGuard; + pThis->toggle_menu(); + } + + void do_grab() + { + GdkDisplay *pDisplay = gtk_widget_get_display(GTK_WIDGET(m_pMenuHack)); +#if GTK_CHECK_VERSION(3, 20, 0) + if (gtk_check_version(3, 20, 0) == nullptr) + { + GdkSeat* pSeat = gdk_display_get_default_seat(pDisplay); + gdk_seat_grab(pSeat, gtk_widget_get_window(GTK_WIDGET(m_pMenuHack)), + GDK_SEAT_CAPABILITY_ALL, true, nullptr, nullptr, nullptr, nullptr); + return; + } +#endif + //else older gtk3 + const int nMask = (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK); + + GdkDeviceManager* pDeviceManager = gdk_display_get_device_manager(pDisplay); + GdkDevice* pPointer = gdk_device_manager_get_client_pointer(pDeviceManager); + gdk_device_grab(pPointer, gtk_widget_get_window(GTK_WIDGET(m_pMenuHack)), GDK_OWNERSHIP_NONE, + true, GdkEventMask(nMask), nullptr, gtk_get_current_event_time()); + } + + void do_ungrab() + { + GdkDisplay *pDisplay = gtk_widget_get_display(GTK_WIDGET(m_pMenuHack)); +#if GTK_CHECK_VERSION(3, 20, 0) + if (gtk_check_version(3, 20, 0) == nullptr) + { + GdkSeat* pSeat = gdk_display_get_default_seat(pDisplay); + gdk_seat_ungrab(pSeat); + return; + } +#endif + //else older gtk3 + GdkDeviceManager* pDeviceManager = gdk_display_get_device_manager(pDisplay); + GdkDevice* pPointer = gdk_device_manager_get_client_pointer(pDeviceManager); + gdk_device_ungrab(pPointer, gtk_get_current_event_time()); + } + + void toggle_menu() + { + if (!m_pMenuHack) + return; + if (!get_active()) + { + do_ungrab(); + + gtk_widget_hide(GTK_WIDGET(m_pMenuHack)); + //put contents back from where the came from + GtkWidget* pChild = gtk_bin_get_child(GTK_BIN(m_pMenuHack)); + g_object_ref(pChild); + gtk_container_remove(GTK_CONTAINER(m_pMenuHack), pChild); + gtk_container_add(GTK_CONTAINER(m_pPopover), pChild); + g_object_unref(pChild); + } + else + { + //steal popover contents and smuggle into toplevel display window + GtkWidget* pChild = gtk_bin_get_child(GTK_BIN(m_pPopover)); + g_object_ref(pChild); + gtk_container_remove(GTK_CONTAINER(m_pPopover), pChild); + gtk_container_add(GTK_CONTAINER(m_pMenuHack), pChild); + g_object_unref(pChild); + + //place the toplevel just below its launcher button + GtkWidget* pToplevel = gtk_widget_get_toplevel(GTK_WIDGET(m_pMenuButton)); + gint x, y, absx, absy; + gtk_widget_translate_coordinates(GTK_WIDGET(m_pMenuButton), pToplevel, 0, 0, &x, &y); + GdkWindow *pWindow = gtk_widget_get_window(pToplevel); + gdk_window_get_position(pWindow, &absx, &absy); + + gtk_window_group_add_window(gtk_window_get_group(GTK_WINDOW(pToplevel)), m_pMenuHack); + gtk_window_set_transient_for(m_pMenuHack, GTK_WINDOW(pToplevel)); + + gtk_widget_show_all(GTK_WIDGET(m_pMenuHack)); + gtk_window_move(m_pMenuHack, x + absx, y + absy + gtk_widget_get_allocated_height(GTK_WIDGET(m_pMenuButton))); + + gtk_widget_grab_focus(GTK_WIDGET(m_pMenuHack)); + + do_grab(); + } + } + + static void signalGrabBroken(GtkWidget*, GdkEventGrabBroken *pEvent, gpointer widget) + { + GtkInstanceMenuButton* pThis = static_cast<GtkInstanceMenuButton*>(widget); + pThis->grab_broken(pEvent); + } + + void grab_broken(GdkEventGrabBroken *event) + { + if (event->grab_window == nullptr) + { + set_active(false); + } + else + { + //try and regrab, so when we lose the grab to the menu of the color palette + //combobox we regain it so the color palette doesn't itself disappear on next + //click on the color palette combobox + do_grab(); + } + } + + static gboolean signalButtonRelease(GtkWidget* pWidget, GdkEventButton* pEvent, gpointer widget) + { + GtkInstanceMenuButton* pThis = static_cast<GtkInstanceMenuButton*>(widget); + return pThis->button_release(pWidget, pEvent); + } + + bool button_release(GtkWidget* pWidget, GdkEventButton* pEvent) + { + //we want to pop down if the button was released outside our popup + gdouble x = pEvent->x_root; + gdouble y = pEvent->y_root; + gint xoffset, yoffset; + gdk_window_get_root_origin(gtk_widget_get_window(pWidget), &xoffset, &yoffset); + + GtkAllocation alloc; + gtk_widget_get_allocation(pWidget, &alloc); + xoffset += alloc.x; + yoffset += alloc.y; + + gtk_widget_get_allocation(GTK_WIDGET(m_pMenuHack), &alloc); + gint x1 = alloc.x + xoffset; + gint y1 = alloc.y + yoffset; + gint x2 = x1 + alloc.width; + gint y2 = y1 + alloc.height; + + if (x > x1 && x < x2 && y > y1 && y < y2) + return false; + + set_active(false); + + return false; + } + + static gboolean keyPress(GtkWidget*, GdkEventKey* pEvent, gpointer widget) + { + GtkInstanceMenuButton* pThis = static_cast<GtkInstanceMenuButton*>(widget); + return pThis->key_press(pEvent); + } + + bool key_press(GdkEventKey* pEvent) + { + if (pEvent->keyval == GDK_KEY_Escape) + { + set_active(false); + return true; + } + return false; + } + +public: + GtkInstanceMenuButton(GtkMenuButton* pMenuButton, bool bTakeOwnership) + : GtkInstanceToggleButton(GTK_TOGGLE_BUTTON(pMenuButton), bTakeOwnership) + , MenuHelper(gtk_menu_button_get_popup(pMenuButton), false) + , m_pMenuButton(pMenuButton) + , m_pImage(nullptr) + , m_pMenuHack(nullptr) + , m_pPopover(nullptr) + , m_nSignalId(0) + { + //do it "manually" so we can have the dropdown image in GtkMenuButtons shown + //on the right at the same time as this image is shown on the left + OString sLabel(gtk_button_get_label(GTK_BUTTON(m_pMenuButton))); + GtkWidget* pChild = gtk_bin_get_child(GTK_BIN(m_pMenuButton)); + gtk_container_remove(GTK_CONTAINER(m_pMenuButton), pChild); + + m_pBox = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0)); + + m_pLabel = GTK_LABEL(gtk_label_new_with_mnemonic(sLabel.getStr())); + gtk_label_set_ellipsize(m_pLabel, PANGO_ELLIPSIZE_MIDDLE); + gtk_label_set_mnemonic_widget(m_pLabel, GTK_WIDGET(m_pMenuButton)); + gtk_box_pack_start(m_pBox, GTK_WIDGET(m_pLabel), false, false, 0); + + gtk_box_pack_end(m_pBox, gtk_image_new_from_icon_name ("pan-down-symbolic", GTK_ICON_SIZE_BUTTON), false, false, 0); + gtk_container_add(GTK_CONTAINER(m_pMenuButton), GTK_WIDGET(m_pBox)); + gtk_widget_show_all(GTK_WIDGET(m_pBox)); + +#if defined(GDK_WINDOWING_X11) + //under wayland a Popover will work to "escape" the parent dialog, not + //so under X, so come up with this hack to use a raw GtkWindow + GdkDisplay *pDisplay = gtk_widget_get_display(m_pWidget); + if (GDK_IS_X11_DISPLAY(pDisplay)) + { + m_pMenuHack = GTK_WINDOW(gtk_window_new(GTK_WINDOW_POPUP)); + gtk_window_set_type_hint(m_pMenuHack, GDK_WINDOW_TYPE_HINT_COMBO); + gtk_window_set_modal(m_pMenuHack, true); + gtk_window_set_resizable(m_pMenuHack, false); + m_nSignalId = g_signal_connect(GTK_TOGGLE_BUTTON(pMenuButton), "toggled", G_CALLBACK(signalToggled), this); + g_signal_connect(m_pMenuHack, "grab-broken-event", G_CALLBACK(signalGrabBroken), this); + g_signal_connect(m_pMenuHack, "button-release-event", G_CALLBACK(signalButtonRelease), this); + g_signal_connect(m_pMenuHack, "key-press-event", G_CALLBACK(keyPress), this); + } +#endif + } + + virtual void set_label(const OUString& rText) override + { + ::set_label(m_pLabel, rText); + } + + virtual void set_image(VirtualDevice& rDevice) override + { + if (!m_pImage) + { + m_pImage = GTK_IMAGE(gtk_image_new_from_surface(get_underlying_cairo_surface(rDevice))); + GtkStyleContext *pContext = gtk_widget_get_style_context(GTK_WIDGET(m_pMenuButton)); + gint nImageSpacing(0); + gtk_style_context_get_style(pContext, "image-spacing", &nImageSpacing, nullptr); + gtk_box_pack_start(m_pBox, GTK_WIDGET(m_pImage), false, false, nImageSpacing); + gtk_box_reorder_child(m_pBox, GTK_WIDGET(m_pImage), 0); + gtk_widget_show(GTK_WIDGET(m_pImage)); + } + else + gtk_image_set_from_surface(m_pImage, get_underlying_cairo_surface(rDevice)); + } + + virtual void set_item_active(const OString& rIdent, bool bActive) override + { + MenuHelper::set_item_active(rIdent, bActive); + } + + virtual void set_item_label(const OString& rIdent, const OUString& rLabel) override + { + MenuHelper::set_item_label(rIdent, rLabel); + } + + virtual void set_item_help_id(const OString& rIdent, const OString& rHelpId) override + { + MenuHelper::set_item_help_id(rIdent, rHelpId); + } + + virtual OString get_item_help_id(const OString& rIdent) const override + { + return MenuHelper::get_item_help_id(rIdent); + } + + virtual void signal_activate(GtkMenuItem* pItem) override + { + const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pItem)); + signal_selected(OString(pStr, pStr ? strlen(pStr) : 0)); + } + + virtual void set_popover(weld::Widget* pPopover) override + { + GtkInstanceWidget* pPopoverWidget = dynamic_cast<GtkInstanceWidget*>(pPopover); + m_pPopover = pPopoverWidget->getWidget(); + if (m_pMenuHack) + { + gtk_menu_button_set_popover(m_pMenuButton, gtk_popover_new(GTK_WIDGET(m_pMenuButton))); + } + else + { + gtk_menu_button_set_popover(m_pMenuButton, m_pPopover); + gtk_widget_show_all(m_pPopover); + } + } + + virtual ~GtkInstanceMenuButton() override + { + if (m_pMenuHack) + { + g_signal_handler_disconnect(m_pMenuButton, m_nSignalId); + gtk_widget_destroy(GTK_WIDGET(m_pMenuHack)); + } + } +}; + class GtkInstanceRadioButton : public GtkInstanceToggleButton, public virtual weld::RadioButton { public: @@ -3877,7 +4150,7 @@ private: void signal_size_allocate(guint nWidth, guint nHeight) { m_xDevice->SetOutputSizePixel(Size(nWidth, nHeight)); - m_pSurface = get_underlying_cairo_suface(*m_xDevice); + m_pSurface = get_underlying_cairo_surface(*m_xDevice); m_aSizeAllocateHdl.Call(Size(nWidth, nHeight)); } static void signalStyleUpdated(GtkWidget*, gpointer widget) @@ -4707,13 +4980,6 @@ private: } if (gtk_button_get_use_underline(pButton) && !gtk_button_get_use_stock(pButton)) m_aMnemonicButtons.push_back(pButton); - - if (GTK_IS_MENU_BUTTON(pWidget)) - { - gtk_button_set_image(pButton, gtk_image_new_from_icon_name ("pan-down-symbolic", GTK_ICON_SIZE_BUTTON)); - gtk_button_set_image_position(pButton, GTK_POS_RIGHT); - gtk_button_set_always_show_image(pButton, true); - } } else if (GTK_IS_LABEL(pWidget)) { @@ -4816,7 +5082,7 @@ public: //gtk impl emulate this by doing this implicitly at weld time void auto_add_parentless_widgets_to_container(GtkWidget* pWidget) { - if (gtk_widget_get_toplevel(pWidget) == pWidget) + if (gtk_widget_get_toplevel(pWidget) == pWidget && !GTK_IS_POPOVER(pWidget)) gtk_container_add(GTK_CONTAINER(m_pParentWidget), pWidget); } _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits