sw/inc/PostItMgr.hxx | 6 +- sw/source/uibase/docvw/PostItMgr.cxx | 60 +++++++++++++++++++++----- sw/source/uibase/docvw/edtwin.cxx | 79 +++++++++++++++++++++++++++++++++-- sw/source/uibase/inc/edtwin.hxx | 6 ++ sw/source/uibase/inc/swruler.hxx | 4 + sw/source/uibase/misc/swruler.cxx | 33 +++++++++++++- 6 files changed, 169 insertions(+), 19 deletions(-)
New commits: commit 25399d65d4d6f2217c4389ec82d35ccbce0c6f3e Author: Rafael Lima <rafael.palma.l...@gmail.com> AuthorDate: Sun Sep 8 15:12:51 2024 +0200 Commit: Rafael Lima <rafael.palma.l...@gmail.com> CommitDate: Fri Sep 27 19:44:17 2024 +0200 tdf#162855 Draw a guide line while resizing the comment sidebar This patch draws a guide line while the user is dragging the comment sidebar edge, to provide a better feedback of the size that will be applied. Thanks to Jim Raykowski for his comments and contributions. It should be noted that he authored much of this patch. Change-Id: I08d4761a25c021c3ddda563a70fc0324000e4e62 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173017 Tested-by: Jenkins Reviewed-by: Jim Raykowski <rayk...@gmail.com> Reviewed-by: Rafael Lima <rafael.palma.l...@gmail.com> diff --git a/sw/inc/PostItMgr.hxx b/sw/inc/PostItMgr.hxx index 05cc25baa032..30ae1296b62f 100644 --- a/sw/inc/PostItMgr.hxx +++ b/sw/inc/PostItMgr.hxx @@ -67,7 +67,7 @@ struct SwPostItPageItem tools::Long lOffset; SwRect mPageRect; std::vector<SwSidebarItem*> mvSidebarItems; - SwPostItPageItem(): bScrollbar(false), eSidebarPosition( sw::sidebarwindows::SidebarPosition::RIGHT ), lOffset(0) + SwPostItPageItem(): bScrollbar(false), eSidebarPosition( sw::sidebarwindows::SidebarPosition::NONE ), lOffset(0) { } }; @@ -155,7 +155,7 @@ class SAL_DLLPUBLIC_RTTI SwPostItMgr final : public SfxListener, bool ShowScrollbar(const tools::ULong aPage) const; bool HasNotes() const ; bool ShowNotes() const; - void SetSidebarWidth(Point aPoint); + void SetSidebarWidth(const Point& rPointLogic); tools::Rectangle GetSidebarRect(const Point& rPointLogic); tools::ULong GetSidebarWidth(bool bPx = false) const; tools::ULong GetSidebarBorderWidth(bool bPx = false) const; @@ -252,6 +252,8 @@ class SAL_DLLPUBLIC_RTTI SwPostItMgr final : public SfxListener, void DrawNotesForPage(OutputDevice *pOutDev, sal_uInt32 nPage); void PaintTile(OutputDevice& rRenderContext); + + sw::sidebarwindows::SidebarPosition GetSidebarPos(const Point& rPointLogic); }; #endif diff --git a/sw/source/uibase/docvw/PostItMgr.cxx b/sw/source/uibase/docvw/PostItMgr.cxx index c50ffd06485a..03e2b9db6997 100644 --- a/sw/source/uibase/docvw/PostItMgr.cxx +++ b/sw/source/uibase/docvw/PostItMgr.cxx @@ -81,6 +81,7 @@ #include <annotsh.hxx> #include <swabstdlg.hxx> +#include <pagefrm.hxx> #include <memory> // distance between Anchor Y and initial note position @@ -2134,8 +2135,7 @@ tools::Rectangle SwPostItMgr::GetSidebarRect(const Point& rPointLogic) if (!nPageNum) return tools::Rectangle(); - OSL_ENSURE(mPages.size() > nPageNum - 1, "SwPostitMgr:: page container size wrong"); - return mPages[nPageNum - 1]->eSidebarPosition == sw::sidebarwindows::SidebarPosition::LEFT + return GetSidebarPos(rPointLogic) == sw::sidebarwindows::SidebarPosition::LEFT ? tools::Rectangle( Point(aPageFrame.Left() - GetSidebarWidth() - GetSidebarBorderWidth(), aPageFrame.Top()), @@ -2149,13 +2149,23 @@ bool SwPostItMgr::IsHitSidebarDragArea(const Point& rPointPx) { if (!HasNotes() || !ShowNotes()) return false; - const Point aPoint = mpEditWin->PixelToLogic(rPointPx); - tools::Rectangle aDragArea(GetSidebarRect(aPoint)); - aDragArea.SetPos(Point(aDragArea.TopRight().X() - 50, aDragArea.TopRight().Y())); + + const Point aPointLogic = mpEditWin->PixelToLogic(rPointPx); + sw::sidebarwindows::SidebarPosition eSidebarPosition = GetSidebarPos(aPointLogic); + if (eSidebarPosition == sw::sidebarwindows::SidebarPosition::NONE) + return false; + + tools::Rectangle aDragArea(GetSidebarRect(aPointLogic)); + aDragArea.SetTop(aPointLogic.Y()); + if (eSidebarPosition == sw::sidebarwindows::SidebarPosition::RIGHT) + aDragArea.SetPos(Point(aDragArea.Right() - 50, aDragArea.Top())); + else + aDragArea.SetPos(Point(aDragArea.Left() - 50, aDragArea.Top())); + Size aS(aDragArea.GetSize()); aS.setWidth(100); aDragArea.SetSize(aS); - return aDragArea.Contains(aPoint); + return aDragArea.Contains(aPointLogic); } tools::Rectangle SwPostItMgr::GetBottomScrollRect(const tools::ULong aPage) const @@ -2271,12 +2281,28 @@ bool SwPostItMgr::HasNotes() const return !mvPostItFields.empty(); } -void SwPostItMgr::SetSidebarWidth(Point aMousePos) +void SwPostItMgr::SetSidebarWidth(const Point& rPointLogic) { - sal_uInt16 nZoom = mpWrtShell->GetViewOptions()->GetZoom(); - tools::Long nPxWidth - = aMousePos.X() - mpEditWin->LogicToPixel(GetSidebarRect(aMousePos).TopLeft()).X(); - double nFactor = static_cast<double>(nPxWidth) / static_cast<double>(nZoom); + tools::Rectangle nSidebarRect = GetSidebarRect(rPointLogic); + if (nSidebarRect.IsEmpty()) + return; + + sw::sidebarwindows::SidebarPosition eSidebarPosition = GetSidebarPos(rPointLogic); + if (eSidebarPosition == sw::sidebarwindows::SidebarPosition::NONE) + return; + + // Calculate the width to be applied in logic units + tools::Long nLogicWidth; + if (eSidebarPosition == sw::sidebarwindows::SidebarPosition::RIGHT) + nLogicWidth = rPointLogic.X() - nSidebarRect.Left(); + else + nLogicWidth = nSidebarRect.Right() - rPointLogic.X(); + + // The zoom level is conveniently used as reference to define the minimum width + const sal_uInt16 nZoom = mpWrtShell->GetViewOptions()->GetZoom(); + double nFactor = static_cast<double>(mpEditWin->LogicToPixel(Point(nLogicWidth, 0)).X()) + / static_cast<double>(nZoom); + // The width may vary from 1x to 8x the zoom factor nFactor = std::clamp(nFactor, 1.0, 8.0); std::shared_ptr<comphelper::ConfigurationChanges> xChanges( comphelper::ConfigurationChanges::create()); @@ -2286,6 +2312,7 @@ void SwPostItMgr::SetSidebarWidth(Point aMousePos) // tdf#159146 After resizing the sidebar the layout and the ruler needs to be updated mpWrtShell->InvalidateLayout(true); mpView->GetHRuler().Invalidate(); + mpView->InvalidateRulerPos(); LayoutPostIts(); } @@ -2682,4 +2709,15 @@ void SwPostItMgr::UpdateResolvedStatus(const sw::annotation::SwAnnotationWin* to } } +sw::sidebarwindows::SidebarPosition SwPostItMgr::GetSidebarPos(const Point& rPointLogic) +{ + if (const SwRootFrame* pLayout = mpWrtShell->GetLayout()) + { + const SwPageFrame* pPageFrame = pLayout->GetPageAtPos(rPointLogic, nullptr, true); + if (pPageFrame) + return pPageFrame->SidebarPosition(); + } + return sw::sidebarwindows::SidebarPosition::NONE; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/uibase/docvw/edtwin.cxx b/sw/source/uibase/docvw/edtwin.cxx index daf39ec6446b..71ef81ca9d24 100644 --- a/sw/source/uibase/docvw/edtwin.cxx +++ b/sw/source/uibase/docvw/edtwin.cxx @@ -163,6 +163,9 @@ using namespace ::com::sun::star; */ static bool g_bInputLanguageSwitched = false; +// Used to draw the guide line while resizing the comment sidebar width +static tools::Rectangle aLastCommentSidebarPos; + // Usually in MouseButtonUp a selection is revoked when the selection is // not currently being pulled open. Unfortunately in MouseButtonDown there // is being selected at double/triple click. That selection is completely @@ -2992,9 +2995,11 @@ void SwEditWin::MouseButtonDown(const MouseEvent& _rMEvt) } } - if (m_rView.GetPostItMgr()->IsHitSidebarDragArea(aMEvt.GetPosPixel())) + if (aMEvt.GetButtons() == MOUSE_LEFT && m_rView.GetPostItMgr()->IsHitSidebarDragArea(aMEvt.GetPosPixel())) { mbIsDragSidebar = true; + // Capture mouse to keep tracking even if the mouse leaves the document window + CaptureMouse(); return; } @@ -4000,6 +4005,14 @@ void SwEditWin::MouseButtonDown(const MouseEvent& _rMEvt) } else if (MOUSE_RIGHT == aMEvt.GetButtons()) { + // If right-click while dragging to resize the comment width, stop resizing + if (mbIsDragSidebar) + { + ReleaseCommentGuideLine(); + ReleaseMouse(); + return; + } + if (rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton() && aMEvt.GetModifier() == KEY_MOD1) { @@ -4129,12 +4142,19 @@ void SwEditWin::MouseMove(const MouseEvent& _rMEvt) return; } } + if (m_rView.GetPostItMgr()->IsHitSidebarDragArea(rMEvt.GetPosPixel())) { SetPointer(PointerStyle::HSizeBar); return; } + if (mbIsDragSidebar) + { + DrawCommentGuideLine(rMEvt.GetPosPixel()); + return; + } + //ignore key modifiers for format paintbrush { bool bExecFormatPaintbrush = m_pApplyTempl && m_pApplyTempl->m_pFormatClipboard @@ -4688,8 +4708,10 @@ void SwEditWin::MouseButtonUp(const MouseEvent& rMEvt) if (mbIsDragSidebar) { - m_rView.GetPostItMgr()->SetSidebarWidth(rMEvt.GetPosPixel()); - mbIsDragSidebar = false; + SetSidebarWidth(rMEvt.GetPosPixel()); + // While dragging the mouse is captured, so we need to release it here + ReleaseMouse(); + ReleaseCommentGuideLine(); return; } @@ -6302,6 +6324,57 @@ void SwEditWin::SelectMenuPosition(SwWrtShell& rSh, const Point& rMousePos ) } } +void SwEditWin::DrawCommentGuideLine(Point aPointPixel) +{ + const Point aPointLogic = PixelToLogic(aPointPixel); + + sw::sidebarwindows::SidebarPosition eSidebarPosition + = m_rView.GetPostItMgr()->GetSidebarPos(aPointLogic); + if (eSidebarPosition == sw::sidebarwindows::SidebarPosition::NONE) // should never happen + return; + + tools::Long nPosX; + sal_uInt16 nZoom = m_rView.GetWrtShell().GetViewOptions()->GetZoom(); + if (eSidebarPosition == sw::sidebarwindows::SidebarPosition::RIGHT) + { + tools::Long nSidebarRectLeft + = LogicToPixel(m_rView.GetPostItMgr()->GetSidebarRect(aPointLogic).TopLeft()).X(); + tools::Long nPxWidth = aPointPixel.X() - nSidebarRectLeft; + nPosX = nSidebarRectLeft + std::clamp<tools::Long>(nPxWidth, 1 * nZoom, 8 * nZoom); + } + else + { + tools::Long nSidebarRectRight + = LogicToPixel(m_rView.GetPostItMgr()->GetSidebarRect(aPointLogic).TopRight()).X(); + tools::Long nPxWidth = nSidebarRectRight - aPointPixel.X(); + nPosX = nSidebarRectRight - std::clamp<tools::Long>(nPxWidth, 1 * nZoom, 8 * nZoom); + } + + + // We need two InvertTracking calls here to "erase" the previous and draw the new position at each mouse move + InvertTracking(aLastCommentSidebarPos, ShowTrackFlags::Clip | ShowTrackFlags::Split); + const tools::Long nHeight = GetOutDev()->GetOutputSizePixel().Height(); + aLastCommentSidebarPos + = tools::Rectangle(PixelToLogic(Point(nPosX, 0)), PixelToLogic(Point(nPosX, nHeight))); + InvertTracking(aLastCommentSidebarPos, ShowTrackFlags::Clip | ShowTrackFlags::Split); +} + +void SwEditWin::ReleaseCommentGuideLine() +{ + InvertTracking(aLastCommentSidebarPos, ShowTrackFlags::Clip | ShowTrackFlags::Split); + aLastCommentSidebarPos = tools::Rectangle(); + mbIsDragSidebar = false; +} + +void SwEditWin::SetSidebarWidth(const Point& rPointPixel) +{ + if (aLastCommentSidebarPos.IsEmpty()) + return; + // aLastCommentSidebarPos right and left positions are the same so either can be used here + m_rView.GetPostItMgr()->SetSidebarWidth( + Point(aLastCommentSidebarPos.Right(), PixelToLogic(rPointPixel).Y())); +} + static SfxShell* lcl_GetTextShellFromDispatcher( SwView const & rView ) { // determine Shell diff --git a/sw/source/uibase/inc/edtwin.hxx b/sw/source/uibase/inc/edtwin.hxx index ac6bbaeeeeff..53e7ddf16568 100644 --- a/sw/source/uibase/inc/edtwin.hxx +++ b/sw/source/uibase/inc/edtwin.hxx @@ -298,6 +298,12 @@ public: void ToggleOutlineContentVisibility(const size_t nOutlinePos, const bool bSubs); virtual FactoryFunction GetUITestFactory() const override; + + // Draws a guide line at the specified position + void DrawCommentGuideLine(Point aPointPixel); + // Stops drawing the guide line + void ReleaseCommentGuideLine(); + void SetSidebarWidth(const Point& rPointPixel); }; extern bool g_bModePushed; diff --git a/sw/source/uibase/inc/swruler.hxx b/sw/source/uibase/inc/swruler.hxx index 6a9b9f27e92d..13435972a1f3 100644 --- a/sw/source/uibase/inc/swruler.hxx +++ b/sw/source/uibase/inc/swruler.hxx @@ -14,6 +14,8 @@ #include <vcl/timer.hxx> #include <vcl/virdev.hxx> +#include <SidebarWindowsTypes.hxx> + class SwViewShell; class View; namespace vcl { class Window; } @@ -81,6 +83,8 @@ private: */ virtual void Update() override; + sw::sidebarwindows::SidebarPosition GetSidebarPosition(); + tools::Rectangle GetDragArea(); /** diff --git a/sw/source/uibase/misc/swruler.cxx b/sw/source/uibase/misc/swruler.cxx index 2551bf1dc03e..4d6f5e5e64c2 100644 --- a/sw/source/uibase/misc/swruler.cxx +++ b/sw/source/uibase/misc/swruler.cxx @@ -16,6 +16,7 @@ #include <edtwin.hxx> #include <PostItMgr.hxx> #include <view.hxx> +#include <wrtsh.hxx> #include <cmdid.h> #include <sfx2/request.hxx> #include <vcl/commandevent.hxx> @@ -106,6 +107,13 @@ void SwCommentRuler::dispose() SvxRuler::dispose(); } +sw::sidebarwindows::SidebarPosition SwCommentRuler::GetSidebarPosition() +{ + if (SwPostItMgr* pPostItMgr = mpViewShell->GetPostItMgr()) + return pPostItMgr->GetSidebarPos(mpSwWin->GetView().GetWrtShell().GetCursorDocPos()); + return sw::sidebarwindows::SidebarPosition::NONE; +} + void SwCommentRuler::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) { if (comphelper::LibreOfficeKit::isActive()) @@ -200,7 +208,10 @@ void SwCommentRuler::Command(const CommandEvent& rCEvt) void SwCommentRuler::MouseMove(const MouseEvent& rMEvt) { if (mbIsDrag) + { + mpSwWin->DrawCommentGuideLine(rMEvt.GetPosPixel()); return; + } SvxRuler::MouseMove(rMEvt); if (!mpViewShell->GetPostItMgr() || !mpViewShell->GetPostItMgr()->HasNotes()) @@ -221,6 +232,15 @@ void SwCommentRuler::MouseMove(const MouseEvent& rMEvt) void SwCommentRuler::MouseButtonDown(const MouseEvent& rMEvt) { + // If right-click while dragging to resize the comment width, stop resizing + if (mbIsDrag && rMEvt.GetButtons() == MOUSE_RIGHT) + { + ReleaseMouse(); + mpSwWin->ReleaseCommentGuideLine(); + mbIsDrag = false; + return; + } + Point aMousePos = rMEvt.GetPosPixel(); if (!rMEvt.IsLeft() || IsTracking() || (!GetCommentControlRegion().Contains(aMousePos) && !GetDragArea().Contains(aMousePos))) @@ -232,6 +252,7 @@ void SwCommentRuler::MouseButtonDown(const MouseEvent& rMEvt) if (GetDragArea().Contains(aMousePos)) { mbIsDrag = true; + CaptureMouse(); } else { @@ -254,7 +275,10 @@ void SwCommentRuler::MouseButtonUp(const MouseEvent& rMEvt) SvxRuler::MouseButtonUp(rMEvt); return; } - mpViewShell->GetPostItMgr()->SetSidebarWidth(rMEvt.GetPosPixel()); + + mpSwWin->SetSidebarWidth(rMEvt.GetPosPixel()); + ReleaseMouse(); + mpSwWin->ReleaseCommentGuideLine(); mbIsDrag = false; Invalidate(); } @@ -280,7 +304,10 @@ void SwCommentRuler::UpdateCommentHelpText() tools::Rectangle SwCommentRuler::GetDragArea() { tools::Rectangle base(GetCommentControlRegion()); - base.Move(Size(base.GetWidth() - 5, 0)); + if (GetSidebarPosition() == sw::sidebarwindows::SidebarPosition::LEFT) + base.Move(-5, 0); + else + base.Move(Size(base.GetWidth() - 5, 0)); base.SetWidth(10); return base; } @@ -300,7 +327,7 @@ tools::Rectangle SwCommentRuler::GetCommentControlRegion() //FIXME When the page width is larger then screen, the ruler is misplaced by one pixel tools::Long nLeft = GetPageOffset(); - if (GetTextRTL()) + if (GetSidebarPosition() == sw::sidebarwindows::SidebarPosition::LEFT) nLeft += GetBorderOffset() - nSidebarWidth; else nLeft += GetWinOffset() + mpSwWin->LogicToPixel(Size(GetPageWidth(), 0)).Width();