svx/source/tbxctrls/tbcontrl.cxx | 423 ++++++++++++++++++++------------- svx/uiconfig/ui/floatingframeborder.ui | 34 +- svx/uiconfig/ui/floatinglinestyle.ui | 2 3 files changed, 286 insertions(+), 173 deletions(-)
New commits: commit 4a12a5eea4e24072f5675bbfd66bbebfa8f5f7a4 Author: Parth Raiyani <[email protected]> AuthorDate: Fri Dec 26 16:50:29 2025 +0530 Commit: Szymon Kłos <[email protected]> CommitDate: Mon Dec 29 10:06:06 2025 +0100 Replaces ValueSet with IconView for floating frame border and line style Border Frame: - Update the UI layout to use GtkIconView with better configuration options - Handle 'Shift to overwrite borders' case using mouse and keyboard events - Add support for tooltips and single-click activation. - Remove obsolete code related to ValueSet Border Line Style: - Used existing floatinglinestyle.ui for border line style instead of floatingframeborder.ui - Add support tooltips and single-click activation - Modified existing LineListBox logic to use IconView instead of ValueSet Change-Id: If00d97400baee7e47bee32c9497853e005202752 Signed-off-by: Parth Raiyani <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/194687 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Szymon Kłos <[email protected]> diff --git a/svx/source/tbxctrls/tbcontrl.cxx b/svx/source/tbxctrls/tbcontrl.cxx index 32a0ad942715..3d1fa2f92ff4 100644 --- a/svx/source/tbxctrls/tbcontrl.cxx +++ b/svx/source/tbxctrls/tbcontrl.cxx @@ -459,28 +459,6 @@ public: } }; - -// SelectHdl needs the Modifiers, get them in MouseButtonUp -class SvxFrmValueSet_Impl final : public ValueSet -{ -private: - sal_uInt16 nModifier; - - virtual bool MouseButtonUp(const MouseEvent& rMEvt) override - { - nModifier = rMEvt.GetModifier(); - return ValueSet::MouseButtonUp(rMEvt); - } - -public: - SvxFrmValueSet_Impl() - : ValueSet(nullptr) - , nModifier(0) - { - } - sal_uInt16 GetModifier() const {return nModifier;} -}; - } namespace { @@ -491,25 +469,31 @@ class SvxFrameWindow_Impl final : public WeldToolbarPopup { private: rtl::Reference<SvxFrameToolBoxControl> mxControl; - std::unique_ptr<SvxFrmValueSet_Impl> mxFrameSet; - std::unique_ptr<weld::CustomWeld> mxFrameSetWin; + std::unique_ptr<weld::IconView> mxFrameIV; std::vector<std::pair<BitmapEx, OUString>> aImgVec; bool bParagraphMode; bool m_bIsWriter; bool m_bIsCalc; + sal_uInt16 nModifier; void InitImageList(); - void CalcSizeValueSet(); - DECL_LINK( SelectHdl, ValueSet*, void ); + DECL_LINK( SelectHdl, weld::IconView&, bool ); + DECL_LINK( MousePressHdl, const MouseEvent&, bool ); + DECL_LINK( MouseReleaseHdl, const MouseEvent&, bool ); + DECL_LINK(KeyPressHdl, const KeyEvent&, bool); + DECL_LINK(QueryTooltipHdl, const weld::TreeIter&, OUString); + OUString GetBorderTypeTooltip(sal_uInt16 nBorderType) const; + void SetDiagonalDownBorder(const SvxLineItem& dDownLineItem); void SetDiagonalUpBorder(const SvxLineItem& dUpLineItem); + static VclPtr<VirtualDevice> GetVirtualDevice(BitmapEx aPreviewBitmap); public: SvxFrameWindow_Impl(SvxFrameToolBoxControl* pControl, weld::Widget* pParent); virtual void GrabFocus() override { - mxFrameSet->GrabFocus(); + mxFrameIV->grab_focus(); } virtual void statusChanged( const css::frame::FeatureStateEvent& rEvent ) override; @@ -533,7 +517,7 @@ private: virtual VclPtr<vcl::Window> createVclPopupWindow( vcl::Window* pParent ) override; }; - class LineListBox final : public ValueSet + class LineListBox final { public: typedef Color (*ColorFunc)(Color); @@ -542,11 +526,9 @@ private: LineListBox(); /** Set the width in Twips */ - Size SetWidth( tools::Long nWidth ) + void SetWidth( tools::Long nWidth ) { - tools::Long nOldWidth = m_nWidth; m_nWidth = nWidth; - return UpdateEntries( nOldWidth ); } void SetNone( const OUString& sNone ) @@ -563,22 +545,25 @@ private: SvxBorderLineStyle GetEntryStyle( sal_Int32 nPos ) const; - SvxBorderLineStyle GetSelectEntryStyle() const; + SvxBorderLineStyle GetSelectEntryStyle(std::u16string_view sId) const; + + void UpdateEntries( weld::IconView& rIconView ); + ImpLineListData* getBorderLineData(sal_Int32 nId); void SetSourceUnit( FieldUnit eNewUnit ) { eSourceUnit = eNewUnit; } const Color& GetColor() const { return aColor; } + OUString m_sNone; - virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override; private: - void ImpGetLine(tools::Long nLine1, tools::Long nLine2, tools::Long nDistance, + void ImpGetLine(const Size& rPreviewSize, tools::Long nLine1, tools::Long nLine2, tools::Long nDistance, Color nColor1, Color nColor2, Color nColorDist, SvxBorderLineStyle nStyle, BitmapEx& rBmp); void UpdatePaintLineColor(); // returns sal_True if maPaintCol has changed - Size UpdateEntries( tools::Long nOldWidth ); + static VclPtr<VirtualDevice> GetVirtualDevice(Image pImage); sal_Int32 GetStylePos( sal_Int32 nListPos, tools::Long nWidth ); const Color& GetPaintColor() const @@ -595,36 +580,34 @@ private: std::vector<std::unique_ptr<ImpLineListData>> m_vLineList; tools::Long m_nWidth; - OUString m_sNone; ScopedVclPtr<VirtualDevice> aVirDev; - Size aTxtSize; Color const aColor; Color maPaintCol; FieldUnit eSourceUnit; }; - SvxBorderLineStyle LineListBox::GetSelectEntryStyle() const + SvxBorderLineStyle LineListBox::GetSelectEntryStyle(std::u16string_view sId) const { - SvxBorderLineStyle nStyle = SvxBorderLineStyle::SOLID; - size_t nPos = GetSelectItemPos(); - if (nPos != VALUESET_ITEM_NOTFOUND) - { - if (!m_sNone.isEmpty()) - --nPos; - nStyle = GetEntryStyle( nPos ); - } + if (sId.empty()) + return SvxBorderLineStyle::NONE; - return nStyle; + sal_Int32 nId = o3tl::toInt32(sId); + if (nId == 0) + return SvxBorderLineStyle::NONE; + + return GetEntryStyle(nId - 1); } - void LineListBox::ImpGetLine( tools::Long nLine1, tools::Long nLine2, tools::Long nDistance, + Size getPreviewSize(const weld::Widget& rControl) + { + return Size(rControl.get_approximate_digit_width() * 15, rControl.get_text_height()); + } + + void LineListBox::ImpGetLine( const Size& rPreviewSize, tools::Long nLine1, tools::Long nLine2, tools::Long nDistance, Color aColor1, Color aColor2, Color aColorDist, SvxBorderLineStyle nStyle, BitmapEx& rBmp ) { - auto nMinWidth = GetDrawingArea()->get_ref_device().approximate_digit_width() * COMBO_WIDTH_IN_CHARS; - Size aSize(nMinWidth, aTxtSize.Height()); - aSize.AdjustWidth( -(aTxtSize.Width()) ); - aSize.AdjustWidth( -6 ); + Size aSize(rPreviewSize); // SourceUnit to Twips if ( eSourceUnit == FieldUnit::POINT ) @@ -677,8 +660,7 @@ private: } LineListBox::LineListBox() - : ValueSet(nullptr) - , m_nWidth( 5 ) + : m_nWidth( 5 ) , aVirDev(VclPtr<VirtualDevice>::Create()) , aColor(Application::GetSettings().GetStyleSettings().GetWindowTextColor()) , maPaintCol(COL_BLACK) @@ -688,18 +670,6 @@ private: aVirDev->SetMapMode( MapMode( MapUnit::MapTwip ) ); } - void LineListBox::SetDrawingArea(weld::DrawingArea* pDrawingArea) - { - ValueSet::SetDrawingArea(pDrawingArea); - - OutputDevice& rDevice = pDrawingArea->get_ref_device(); - - aTxtSize.setWidth( rDevice.approximate_digit_width() ); - aTxtSize.setHeight( rDevice.GetTextHeight() ); - - UpdatePaintLineColor(); - } - sal_Int32 LineListBox::GetStylePos( sal_Int32 nListPos, tools::Long nWidth ) { sal_Int32 nPos = -1; @@ -749,57 +719,92 @@ private: maPaintCol = aNewCol; } - Size LineListBox::UpdateEntries( tools::Long nOldWidth ) + ImpLineListData* LineListBox::getBorderLineData(sal_Int32 nId) + { + SvxBorderLineStyle eStyle = static_cast<SvxBorderLineStyle>(nId); + + for (auto& pData : m_vLineList) + { + if (pData->GetStyle() == eStyle) + return pData.get(); + } + + return nullptr; + } + + VclPtr<VirtualDevice> LineListBox::GetVirtualDevice(Image pImage) { - Size aSize; + constexpr tools::Long nMarginTopBottom = 5; + constexpr tools::Long nMarginLeftRight = 2; + + BitmapEx aPreviewBitmap = pImage.GetBitmapEx(); + Size aBmpSize = aPreviewBitmap.GetSizePixel(); + + Size aVDSize( + aBmpSize.Width() + 2 * nMarginLeftRight, + aBmpSize.Height() + 2 * nMarginTopBottom + ); + VclPtr<VirtualDevice> pVDev = VclPtr<VirtualDevice>::Create(); + pVDev->SetOutputSizePixel(aVDSize); + + Point aDrawPos(nMarginLeftRight, nMarginTopBottom); + pVDev->DrawBitmapEx(aDrawPos, aPreviewBitmap); + return pVDev; + } + + void LineListBox::UpdateEntries( weld::IconView& rIconView ) + { UpdatePaintLineColor( ); - sal_Int32 nSelEntry = GetSelectItemPos(); - sal_Int32 nTypePos = GetStylePos( nSelEntry, nOldWidth ); + OUString sCurrentSelectedId = rIconView.get_selected_id(); // Remove the old entries - Clear(); + rIconView.clear(); - sal_uInt16 nId(1); + sal_uInt16 nPos = 0; // Add the new entries based on the defined width if (!m_sNone.isEmpty()) - InsertItem(nId++, Image(), m_sNone); + { + Size aPreviewSize = getPreviewSize(rIconView); + VclPtr<VirtualDevice> pVDevNone = GetVirtualDevice(Image()); + pVDevNone->SetOutputSizePixel(aPreviewSize); + rIconView.append("0", m_sNone, pVDevNone.get()); + + if (sCurrentSelectedId == "0") + rIconView.select(nPos); + nPos++; + } - sal_uInt16 n = 0; - sal_uInt16 nCount = m_vLineList.size( ); - while ( n < nCount ) + for (size_t n = 0; n < m_vLineList.size(); ++n) { auto& pData = m_vLineList[ n ]; if ( pData->GetMinWidth() <= m_nWidth ) { BitmapEx aBmp; - ImpGetLine( pData->GetLine1ForWidth( m_nWidth ), + Size aPreviewSize = getPreviewSize(rIconView); + ImpGetLine(aPreviewSize, + pData->GetLine1ForWidth( m_nWidth ), pData->GetLine2ForWidth( m_nWidth ), pData->GetDistForWidth( m_nWidth ), - GetColorLine1( GetItemCount( ) ), - GetColorLine2( GetItemCount( ) ), - GetColorDist( GetItemCount( ) ), + GetColorLine1( n ), + GetColorLine2( n ), + GetColorDist( n ), pData->GetStyle(), aBmp ); - InsertItem(nId, Image(aBmp), SvtLineListBox::GetLineStyleName(pData->GetStyle())); - Size aBmpSize = aBmp.GetSizePixel(); - if (aBmpSize.Width() > aSize.Width()) - aSize.setWidth(aBmpSize.getWidth()); - if (aBmpSize.Height() > aSize.Height()) - aSize.setHeight(aBmpSize.getHeight()); - if ( n == nTypePos ) - SelectItem(nId); - } - else if ( n == nTypePos ) - SetNoSelection(); - n++; - ++nId; - } - Invalidate(); + VclPtr<VirtualDevice> pVDev = GetVirtualDevice(Image(aBmp)); + OUString sStyleName = SvtLineListBox::GetLineStyleName(pData->GetStyle()); + + OUString sId = OUString::number(n + 1); + rIconView.append(sId, sStyleName, pVDev.get()); - return aSize; + if (sCurrentSelectedId == sId) + rIconView.select(nPos); + + nPos++; + } + } } Color LineListBox::GetColorLine1( sal_Int32 nPos ) @@ -839,16 +844,17 @@ class SvxLineWindow_Impl final : public WeldToolbarPopup private: rtl::Reference<SvxFrameToolBoxControl> m_xControl; std::unique_ptr<LineListBox> m_xLineStyleLb; - std::unique_ptr<weld::CustomWeld> m_xLineStyleLbWin; + std::unique_ptr<weld::IconView> m_xLineStyleIV; bool m_bIsWriter; - DECL_LINK( SelectHdl, ValueSet*, void ); + DECL_LINK( SelectHdl, weld::IconView&, bool ); + DECL_LINK( QueryTooltipHdl, const weld::TreeIter&, OUString ); public: SvxLineWindow_Impl(SvxFrameToolBoxControl* pControl, weld::Widget* pParent); virtual void GrabFocus() override { - m_xLineStyleLb->GrabFocus(); + m_xLineStyleIV->grab_focus(); } }; @@ -2549,11 +2555,11 @@ Color ColorStatus::GetColor() SvxFrameWindow_Impl::SvxFrameWindow_Impl(SvxFrameToolBoxControl* pControl, weld::Widget* pParent) : WeldToolbarPopup(pControl->getFrameInterface(), pParent, u"svx/ui/floatingframeborder.ui"_ustr, u"FloatingFrameBorder"_ustr) , mxControl(pControl) - , mxFrameSet(new SvxFrmValueSet_Impl) - , mxFrameSetWin(new weld::CustomWeld(*m_xBuilder, u"valueset"_ustr, *mxFrameSet)) + , mxFrameIV(m_xBuilder->weld_icon_view(u"iconview_borders"_ustr)) , bParagraphMode(false) , m_bIsWriter(false) , m_bIsCalc(false) + , nModifier(0) { // check whether the document is Writer or not @@ -2564,7 +2570,6 @@ SvxFrameWindow_Impl::SvxFrameWindow_Impl(SvxFrameToolBoxControl* pControl, weld: m_bIsCalc = xSI->supportsService(u"com.sun.star.sheet.SpreadsheetDocument"_ustr); } - mxFrameSet->SetStyle(WB_ITEMBORDER | WB_DOUBLEBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT); AddStatusListener(u".uno:BorderReducedMode"_ustr); InitImageList(); @@ -2583,23 +2588,36 @@ SvxFrameWindow_Impl::SvxFrameWindow_Impl(SvxFrameToolBoxControl* pControl, weld: // Therefore, Calc uses 10 border types while // Writer uses 8 of them - for a single cell. for ( i=1; i < (m_bIsCalc ? 11 : 9); i++ ) - mxFrameSet->InsertItem(i, Image(aImgVec[i-1].first), aImgVec[i-1].second); + { + VclPtr<VirtualDevice> pVDev = GetVirtualDevice(aImgVec[i-1].first); + mxFrameIV->append(OUString::number(i), aImgVec[i-1].second, pVDev.get()); + } //bParagraphMode should have been set in StateChanged if ( !bParagraphMode ) // when multiple cell selected: // Writer has 12 border types and Calc has 15 of them. for ( i = (m_bIsCalc ? 11 : 9); i < (m_bIsCalc ? 16 : 13); i++ ) - mxFrameSet->InsertItem(i, Image(aImgVec[i-1].first), aImgVec[i-1].second); + { + VclPtr<VirtualDevice> pVDev = GetVirtualDevice(aImgVec[i-1].first); + mxFrameIV->append(OUString::number(i), aImgVec[i-1].second, pVDev.get()); + } - // adjust frame column for Writer - sal_uInt16 colCount = m_bIsWriter ? 4 : 5; - mxFrameSet->SetColCount( colCount ); - mxFrameSet->SetSelectHdl( LINK( this, SvxFrameWindow_Impl, SelectHdl ) ); - CalcSizeValueSet(); + mxFrameIV->connect_mouse_press(LINK(this, SvxFrameWindow_Impl, MousePressHdl)); + mxFrameIV->connect_mouse_release(LINK(this, SvxFrameWindow_Impl, MouseReleaseHdl)); + mxFrameIV->connect_key_press(LINK(this, SvxFrameWindow_Impl, KeyPressHdl)); + mxFrameIV->connect_item_activated( LINK( this, SvxFrameWindow_Impl, SelectHdl ) ); + + // Avoid LibreOffice Kit crash: tooltip handlers cause segfault during JSDialog + // serialization when popup widgets are destroyed/recreated + // Tooltip event binding is not needed for LibreOffice Kit + if (!comphelper::LibreOfficeKit::isActive()) + { + mxFrameIV->connect_query_tooltip(LINK(this, SvxFrameWindow_Impl, QueryTooltipHdl)); + } - mxFrameSet->SetHelpId( HID_POPUP_FRAME ); - mxFrameSet->SetAccessibleName( SvxResId(RID_SVXSTR_FRAME) ); + mxFrameIV->set_help_id( HID_POPUP_FRAME ); + mxFrameIV->set_accessible_name( SvxResId(RID_SVXSTR_FRAME) ); } namespace { @@ -2624,8 +2642,12 @@ namespace o3tl { // By default unset lines remain unchanged. // Via Shift unset lines are reset -IMPL_LINK_NOARG(SvxFrameWindow_Impl, SelectHdl, ValueSet*, void) +IMPL_LINK_NOARG(SvxFrameWindow_Impl, SelectHdl, weld::IconView&, bool) { + OUString sId = mxFrameIV->get_selected_id(); + if (sId.isEmpty()) + return false; + SvxBoxItem aBorderOuter( SID_ATTR_BORDER_OUTER ); SvxBoxInfoItem aBorderInner( SID_ATTR_BORDER_INNER ); SvxBorderLine theDefLine; @@ -2644,8 +2666,7 @@ IMPL_LINK_NOARG(SvxFrameWindow_Impl, SelectHdl, ValueSet*, void) *pRight = nullptr, *pTop = nullptr, *pBottom = nullptr; - sal_uInt16 nSel = mxFrameSet->GetSelectedItemId(); - sal_uInt16 nModifier = mxFrameSet->GetModifier(); + sal_uInt16 nSel = sId.toUInt32(); FrmValidFlags nValidFlags = FrmValidFlags::NONE; // tdf#48622, tdf#145828 use correct default to create intended 0.75pt @@ -2776,15 +2797,89 @@ IMPL_LINK_NOARG(SvxFrameWindow_Impl, SelectHdl, ValueSet*, void) } // coverity[ check_after_deref : FALSE] - if (mxFrameSet) + if (mxFrameIV) { /* #i33380# Moved the following line above the Dispatch() call. 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. */ - mxFrameSet->SetNoSelection(); + mxFrameIV->unselect_all(); } mxControl->EndPopupMode(); + return true; +} + +IMPL_LINK(SvxFrameWindow_Impl, MousePressHdl, const MouseEvent&, rMEvt, bool) +{ + nModifier = rMEvt.GetModifier(); + return false; +} + +IMPL_LINK(SvxFrameWindow_Impl, MouseReleaseHdl, const MouseEvent&, rMEvt, bool) +{ + nModifier = rMEvt.GetModifier(); + + if (rMEvt.IsLeft() && rMEvt.GetModifier() == KEY_SHIFT) + { + OUString sId = mxFrameIV->get_selected_id(); + if (!sId.isEmpty()) + SelectHdl(*mxFrameIV); + + return true; + } + return false; +} + +IMPL_LINK(SvxFrameWindow_Impl, KeyPressHdl, const KeyEvent&, rKEvt, bool) +{ + nModifier = rKEvt.GetKeyCode().GetModifier(); + + if (rKEvt.GetKeyCode().GetCode() == KEY_RETURN || + rKEvt.GetKeyCode().GetCode() == KEY_SPACE) + { + OUString sId = mxFrameIV->get_selected_id(); + if (!sId.isEmpty()) + SelectHdl(*mxFrameIV); + + return true; + } + return false; +} + +VclPtr<VirtualDevice> SvxFrameWindow_Impl::GetVirtualDevice(BitmapEx aPreviewBitmap) +{ + VclPtr<VirtualDevice> pVDev = VclPtr<VirtualDevice>::Create(); + const Point aNull(0, 0); + if (pVDev->GetDPIScaleFactor() > 1) + aPreviewBitmap.Scale(pVDev->GetDPIScaleFactor(), pVDev->GetDPIScaleFactor()); + const Size aSize(aPreviewBitmap.GetSizePixel()); + pVDev->SetOutputSizePixel(aSize); + pVDev->DrawBitmapEx(aNull, aPreviewBitmap); + + return pVDev; +} + +IMPL_LINK(SvxFrameWindow_Impl, QueryTooltipHdl, const weld::TreeIter&, iter, OUString) +{ + const OUString sId = mxFrameIV->get_id(iter); + + if (!sId.isEmpty()) + { + sal_uInt16 nBorderType = sId.toUInt32(); + return GetBorderTypeTooltip(nBorderType); + } + + return OUString(); +} + +OUString SvxFrameWindow_Impl::GetBorderTypeTooltip(sal_uInt16 nBorderType) const +{ + if (nBorderType > 0 && nBorderType <= aImgVec.size()) + { + return aImgVec[nBorderType - 1].second; + } + + return OUString(); } void SvxFrameWindow_Impl::SetDiagonalDownBorder(const SvxLineItem& dDownLineItem) @@ -2818,42 +2913,28 @@ void SvxFrameWindow_Impl::statusChanged( const css::frame::FeatureStateEvent& rE bParagraphMode = bValue; //initial calls mustn't insert or remove elements - if(!mxFrameSet->GetItemCount()) + if(mxFrameIV->n_children() == 0) return; // set 12 border types for Writer, otherwise 15 for Calc. - bool bTableMode = ( mxFrameSet->GetItemCount() == static_cast<size_t>(m_bIsCalc ? 15 : 12) ); - bool bResize = false; + bool bTableMode = ( mxFrameIV->n_children() == (m_bIsCalc ? 15 : 12) ); if ( bTableMode && bParagraphMode ) { for ( sal_uInt16 i = (m_bIsWriter ? 9 : 11); i < (m_bIsWriter ? 13 : 16); i++ ) - mxFrameSet->RemoveItem(i); - bResize = true; + mxFrameIV->remove(i - 1); } else if ( !bTableMode && !bParagraphMode ) { for ( sal_uInt16 i = (m_bIsWriter ? 9 : 11); i < (m_bIsWriter ? 13 : 16); i++ ) - mxFrameSet->InsertItem(i, Image(aImgVec[i-1].first), aImgVec[i-1].second); - bResize = true; - } - - if ( bResize ) - { - CalcSizeValueSet(); + { + VclPtr<VirtualDevice> pVDev = GetVirtualDevice(aImgVec[i-1].first); + OUString sId = OUString::number(i); + mxFrameIV->insert(i - 1, &aImgVec[i-1].second, &sId, pVDev.get(), nullptr); + } } } -void SvxFrameWindow_Impl::CalcSizeValueSet() -{ - weld::DrawingArea* pDrawingArea = mxFrameSet->GetDrawingArea(); - const OutputDevice& rDevice = pDrawingArea->get_ref_device(); - Size aItemSize( 20 * rDevice.GetDPIScaleFactor(), 20 * rDevice.GetDPIScaleFactor() ); - Size aSize = mxFrameSet->CalcWindowSizePixel( aItemSize ); - pDrawingArea->set_size_request(aSize.Width(), aSize.Height()); - mxFrameSet->SetOutputSizePixel(aSize); -} - void SvxFrameWindow_Impl::InitImageList() { if (!m_bIsCalc) @@ -2911,10 +2992,10 @@ static Color lcl_mediumColor( Color aMain, Color /*aDefault*/ ) } SvxLineWindow_Impl::SvxLineWindow_Impl(SvxFrameToolBoxControl* pControl, weld::Widget* pParent) - : WeldToolbarPopup(pControl->getFrameInterface(), pParent, u"svx/ui/floatingframeborder.ui"_ustr, u"FloatingFrameBorder"_ustr) + : WeldToolbarPopup(pControl->getFrameInterface(), pParent, u"svx/ui/floatinglinestyle.ui"_ustr, u"FloatingLineStyle"_ustr) , m_xControl(pControl) , m_xLineStyleLb(new LineListBox) - , m_xLineStyleLbWin(new weld::CustomWeld(*m_xBuilder, u"valueset"_ustr, *m_xLineStyleLb)) + , m_xLineStyleIV(m_xBuilder->weld_icon_view(u"floating_line_style_iconview"_ustr)) , m_bIsWriter(false) { try @@ -2927,8 +3008,6 @@ SvxLineWindow_Impl::SvxLineWindow_Impl(SvxFrameToolBoxControl* pControl, weld::W { } - m_xLineStyleLb->SetStyle( WinBits(WB_FLATVALUESET | WB_ITEMBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT | WB_TABSTOP) ); - m_xLineStyleLb->SetSourceUnit( FieldUnit::TWIP ); m_xLineStyleLb->SetNone( comphelper::LibreOfficeKit::isActive() ? SvxResId(RID_SVXSTR_INVISIBLE) :SvxResId(RID_SVXSTR_NONE) ); @@ -2959,33 +3038,40 @@ SvxLineWindow_Impl::SvxLineWindow_Impl(SvxFrameToolBoxControl* pControl, weld::W &SvxBorderLine::lightColor, &SvxBorderLine::darkColor ); m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::INSET ), SvxBorderLineStyle::INSET, 10, &SvxBorderLine::darkColor, &SvxBorderLine::lightColor ); - Size aSize = m_xLineStyleLb->SetWidth( 20 ); // 1pt by default + m_xLineStyleLb->SetWidth( 20 ); // 1pt by default + m_xLineStyleLb->UpdateEntries( *m_xLineStyleIV ); - m_xLineStyleLb->SetSelectHdl( LINK( this, SvxLineWindow_Impl, SelectHdl ) ); + m_xLineStyleIV->connect_item_activated( LINK( this, SvxLineWindow_Impl, SelectHdl ) ); - m_xContainer->set_help_id(HID_POPUP_LINE); + // Avoid LibreOffice Kit crash: tooltip handlers cause segfault during JSDialog + // serialization when popup widgets are destroyed/recreated during character formatting resets. + // Tooltip event binding is not needed for LibreOffice Kit + if (!comphelper::LibreOfficeKit::isActive()) + { + m_xLineStyleIV->connect_query_tooltip(LINK(this, SvxLineWindow_Impl, QueryTooltipHdl)); + } - aSize.AdjustWidth(6); - aSize.AdjustHeight(6); - aSize = m_xLineStyleLb->CalcWindowSizePixel(aSize); - m_xLineStyleLb->GetDrawingArea()->set_size_request(aSize.Width(), aSize.Height()); - m_xLineStyleLb->SetOutputSizePixel(aSize); + m_xContainer->set_help_id(HID_POPUP_LINE); } -IMPL_LINK_NOARG(SvxLineWindow_Impl, SelectHdl, ValueSet*, void) +IMPL_LINK_NOARG(SvxLineWindow_Impl, SelectHdl, weld::IconView&, bool) { - SvxLineItem aLineItem( SID_FRAME_LINESTYLE ); - SvxBorderLineStyle nStyle = m_xLineStyleLb->GetSelectEntryStyle(); + OUString sSelectedId = m_xLineStyleIV->get_selected_id(); - if ( m_xLineStyleLb->GetSelectItemPos( ) > 0 ) + SvxLineItem aLineItem( SID_FRAME_LINESTYLE ); + if (sSelectedId.isEmpty() || sSelectedId == "0") { - SvxBorderLine aTmp; - aTmp.SetBorderLineStyle( nStyle ); - aTmp.SetWidth( SvxBorderLineWidth::Thin ); // TODO Make it depend on a width field - aLineItem.SetLine( &aTmp ); + aLineItem.SetLine(nullptr); } else - aLineItem.SetLine( nullptr ); + { + SvxBorderLineStyle nStyle = m_xLineStyleLb->GetSelectEntryStyle(sSelectedId); + + SvxBorderLine aTmp; + aTmp.SetBorderLineStyle(nStyle); + aTmp.SetWidth(SvxBorderLineWidth::Thin); // TODO Make it depend on a width field + aLineItem.SetLine(&aTmp); + } Any a; aLineItem.QueryValue( a, m_bIsWriter ? CONVERT_TWIPS : 0 ); @@ -2994,6 +3080,25 @@ IMPL_LINK_NOARG(SvxLineWindow_Impl, SelectHdl, ValueSet*, void) m_xControl->dispatchCommand( u".uno:LineStyle"_ustr, aArgs ); m_xControl->EndPopupMode(); + + return true; +} + +IMPL_LINK(SvxLineWindow_Impl, QueryTooltipHdl, const weld::TreeIter&, rIter, OUString) +{ + OUString sId = m_xLineStyleIV->get_id(rIter); + if (sId.isEmpty()) + return OUString(); + + if (sId == "0") + return m_xLineStyleLb->m_sNone; + + sal_Int32 nId = sId.toUInt32() - 1; + ImpLineListData* pData = m_xLineStyleLb->getBorderLineData(nId); + if (pData) + return SvtLineListBox::GetLineStyleName(pData->GetStyle()); + + return OUString(); } SfxStyleControllerItem_Impl::SfxStyleControllerItem_Impl( diff --git a/svx/uiconfig/ui/floatingframeborder.ui b/svx/uiconfig/ui/floatingframeborder.ui index e86cf1c0aea2..0966641582c4 100644 --- a/svx/uiconfig/ui/floatingframeborder.ui +++ b/svx/uiconfig/ui/floatingframeborder.ui @@ -2,6 +2,14 @@ <!-- Generated with glade 3.38.2 --> <interface domain="svx"> <requires lib="gtk+" version="3.20"/> + <object class="GtkTreeStore" id="borders_liststore"> + <columns> + <!-- column-name pixbuf --> + <column type="GdkPixbuf"/> + <!-- column-name id --> + <column type="gchararray"/> + </columns> + </object> <object class="GtkPopover" id="FloatingFrameBorder"> <property name="can-focus">False</property> <property name="no-show-all">True</property> @@ -14,27 +22,27 @@ <property name="orientation">vertical</property> <property name="spacing">6</property> <child> - <object class="GtkScrolledWindow" id="valuesetwin"> + <object class="GtkScrolledWindow"> <property name="visible">True</property> <property name="can-focus">True</property> <property name="hexpand">True</property> - <property name="vexpand">True</property> + <property name="vexpand">False</property> <property name="hscrollbar-policy">never</property> <property name="vscrollbar-policy">never</property> + <property name="width-request">180</property> + <property name="height-request">100</property> <property name="shadow-type">in</property> <child> - <object class="GtkViewport"> + <object class="GtkIconView" id="iconview_borders"> <property name="visible">True</property> - <property name="can-focus">False</property> - <child> - <object class="GtkDrawingArea" id="valueset"> - <property name="visible">True</property> - <property name="can-focus">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> - <property name="hexpand">True</property> - <property name="vexpand">True</property> - </object> - </child> + <property name="can-focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="model">borders_liststore</property> + <property name="pixbuf-column">0</property> + <property name="selection-mode">single</property> + <property name="columns">4</property> + <property name="activate-on-single-click">True</property> </object> </child> </object> diff --git a/svx/uiconfig/ui/floatinglinestyle.ui b/svx/uiconfig/ui/floatinglinestyle.ui index 9f394c2f7a74..4a4c96fee229 100644 --- a/svx/uiconfig/ui/floatinglinestyle.ui +++ b/svx/uiconfig/ui/floatinglinestyle.ui @@ -30,7 +30,7 @@ <property name="hscrollbar-policy">never</property> <property name="vscrollbar-policy">always</property> <property name="shadow_type">in</property> - <property name="height-request">264</property> + <property name="height-request">280</property> <child> <object class="GtkIconView" id="floating_line_style_iconview"> <property name="visible">True</property>
