summaryrefslogtreecommitdiffstats
path: root/sw/source/uibase/docvw/PageBreakWin.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
commit940b4d1848e8c70ab7642901a68594e8016caffc (patch)
treeeb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /sw/source/uibase/docvw/PageBreakWin.cxx
parentInitial commit. (diff)
downloadlibreoffice-940b4d1848e8c70ab7642901a68594e8016caffc.tar.xz
libreoffice-940b4d1848e8c70ab7642901a68594e8016caffc.zip
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sw/source/uibase/docvw/PageBreakWin.cxx')
-rw-r--r--sw/source/uibase/docvw/PageBreakWin.cxx469
1 files changed, 469 insertions, 0 deletions
diff --git a/sw/source/uibase/docvw/PageBreakWin.cxx b/sw/source/uibase/docvw/PageBreakWin.cxx
new file mode 100644
index 000000000..84ebedb0e
--- /dev/null
+++ b/sw/source/uibase/docvw/PageBreakWin.cxx
@@ -0,0 +1,469 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <bitmaps.hlst>
+
+#include <cmdid.h>
+#include <cntfrm.hxx>
+#include <txtfrm.hxx>
+#include <notxtfrm.hxx>
+#include <ndtxt.hxx>
+#include <DashedLine.hxx>
+#include <doc.hxx>
+#include <edtwin.hxx>
+#include <fmtpdsc.hxx>
+#include <IDocumentUndoRedo.hxx>
+#include <IDocumentContentOperations.hxx>
+#include <PageBreakWin.hxx>
+#include <pagefrm.hxx>
+#include <PostItMgr.hxx>
+#include <FrameControlsManager.hxx>
+#include <uiitems.hxx>
+#include <view.hxx>
+#include <viewopt.hxx>
+#include <wrtsh.hxx>
+
+#include <basegfx/color/bcolortools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/range/b2drectangle.hxx>
+#include <drawinglayer/primitive2d/discretebitmapprimitive2d.hxx>
+#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonHairlinePrimitive2D.hxx>
+#include <drawinglayer/processor2d/baseprocessor2d.hxx>
+#include <drawinglayer/processor2d/processorfromoutputdevice.hxx>
+#include <editeng/formatbreakitem.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svl/stritem.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/event.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <memory>
+
+#define BUTTON_WIDTH 30
+#define BUTTON_HEIGHT 19
+#define ARROW_WIDTH 9
+
+using namespace basegfx;
+using namespace basegfx::utils;
+
+namespace
+{
+ class SwBreakDashedLine : public SwDashedLine
+ {
+ private:
+ VclPtr<SwPageBreakWin> m_pWin;
+
+ public:
+ SwBreakDashedLine( vcl::Window* pParent, Color& ( *pColorFn )(), SwPageBreakWin* pWin ) :
+ SwDashedLine( pParent, pColorFn ),
+ m_pWin( pWin ) {};
+ virtual ~SwBreakDashedLine() override { disposeOnce(); }
+ virtual void dispose() override { m_pWin.clear(); SwDashedLine::dispose(); }
+
+ virtual void MouseMove( const MouseEvent& rMEvt ) override;
+ };
+
+ void SwBreakDashedLine::MouseMove( const MouseEvent& rMEvt )
+ {
+ if ( rMEvt.IsLeaveWindow() )
+ {
+ // don't fade if we just move to the 'button'
+ Point aEventPos( GetPosPixel() + rMEvt.GetPosPixel() );
+ if ( !m_pWin->Contains( aEventPos ) || !m_pWin->IsVisible() )
+ m_pWin->Fade( false );
+ }
+ else if ( !m_pWin->IsVisible() )
+ {
+ m_pWin->Fade( true );
+ }
+
+ if ( !rMEvt.IsSynthetic() && !m_pWin->IsVisible() )
+ {
+ m_pWin->UpdatePosition( rMEvt.GetPosPixel() );
+ }
+ }
+}
+
+SwPageBreakWin::SwPageBreakWin( SwEditWin* pEditWin, const SwFrame *pFrame ) :
+ SwFrameMenuButtonBase( pEditWin, pFrame ),
+ m_aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "modules/swriter/ui/pagebreakmenu.ui", ""),
+ m_pPopupMenu(m_aBuilder.get_menu("menu")),
+ m_pLine( nullptr ),
+ m_bIsAppearing( false ),
+ m_nFadeRate( 100 ),
+ m_nDelayAppearing( 0 ),
+ m_bDestroyed( false )
+{
+ // Use pixels for the rest of the drawing
+ SetMapMode( MapMode ( MapUnit::MapPixel ) );
+
+ // Create the line control
+ m_pLine = VclPtr<SwBreakDashedLine>::Create( GetEditWin(), &SwViewOption::GetPageBreakColor, this );
+
+ // Set the popup menu
+ m_pPopupMenu->SetDeactivateHdl( LINK( this, SwPageBreakWin, HideHandler ) );
+ SetPopupMenu(m_pPopupMenu);
+
+ m_aFadeTimer.SetTimeout( 50 );
+ m_aFadeTimer.SetInvokeHandler( LINK( this, SwPageBreakWin, FadeHandler ) );
+}
+
+SwPageBreakWin::~SwPageBreakWin( )
+{
+ disposeOnce();
+}
+
+void SwPageBreakWin::dispose()
+{
+ m_bDestroyed = true;
+ m_aFadeTimer.Stop();
+
+ m_pLine.disposeAndClear();
+ m_pPopupMenu.clear();
+ m_aBuilder.disposeBuilder();
+
+ SwFrameMenuButtonBase::dispose();
+}
+
+void SwPageBreakWin::Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle&)
+{
+ const ::tools::Rectangle aRect(::tools::Rectangle(Point(0, 0), rRenderContext.PixelToLogic(GetSizePixel())));
+
+ // Properly paint the control
+ BColor aColor = SwViewOption::GetPageBreakColor().getBColor();
+
+ BColor aHslLine = rgb2hsl(aColor);
+ double nLuminance = aHslLine.getZ();
+ nLuminance += (1.0 - nLuminance) * 0.75;
+ if ( aHslLine.getZ() > 0.7 )
+ nLuminance = aHslLine.getZ() * 0.7;
+ aHslLine.setZ(nLuminance);
+ BColor aOtherColor = hsl2rgb(aHslLine);
+
+ const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
+ if (rSettings.GetHighContrastMode())
+ {
+ aColor = rSettings.GetDialogTextColor().getBColor();
+ aOtherColor = rSettings.GetDialogColor().getBColor();
+ }
+
+ bool bRtl = AllSettings::GetLayoutRTL();
+
+ drawinglayer::primitive2d::Primitive2DContainer aSeq(3);
+ B2DRectangle aBRect = vcl::unotools::b2DRectangleFromRectangle(aRect);
+ B2DPolygon aPolygon = createPolygonFromRect(aBRect, 3.0 / BUTTON_WIDTH, 3.0 / BUTTON_HEIGHT);
+
+ // Create the polygon primitives
+ aSeq[0].set(new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
+ B2DPolyPolygon(aPolygon), aOtherColor));
+ aSeq[1].set(new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
+ aPolygon, aColor));
+
+ // Create the primitive for the image
+ BitmapEx aBmpEx(RID_BMP_PAGE_BREAK);
+ double nImgOfstX = 3.0;
+ if (bRtl)
+ nImgOfstX = aRect.Right() - aBmpEx.GetSizePixel().Width() - 3.0;
+ aSeq[2].set(new drawinglayer::primitive2d::DiscreteBitmapPrimitive2D(
+ aBmpEx, B2DPoint(nImgOfstX, 1.0)));
+
+ double nTop = double(aRect.getHeight()) / 2.0;
+ double nBottom = nTop + 4.0;
+ double nLeft = aRect.getWidth() - ARROW_WIDTH - 6.0;
+ if (bRtl)
+ nLeft = ARROW_WIDTH - 2.0;
+ double nRight = nLeft + 8.0;
+
+ B2DPolygon aTriangle;
+ aTriangle.append(B2DPoint(nLeft, nTop));
+ aTriangle.append(B2DPoint(nRight, nTop));
+ aTriangle.append(B2DPoint((nLeft + nRight) / 2.0, nBottom));
+ aTriangle.setClosed(true);
+
+ BColor aTriangleColor = COL_BLACK.getBColor();
+ if (Application::GetSettings().GetStyleSettings().GetHighContrastMode())
+ aTriangleColor = COL_WHITE.getBColor();
+
+ aSeq.emplace_back();
+ aSeq.back().set( new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
+ B2DPolyPolygon(aTriangle), aTriangleColor));
+
+ drawinglayer::primitive2d::Primitive2DContainer aGhostedSeq(1);
+ double nFadeRate = double(m_nFadeRate) / 100.0;
+ const basegfx::BColorModifierSharedPtr aBColorModifier =
+ std::make_shared<basegfx::BColorModifier_interpolate>(COL_WHITE.getBColor(),
+ 1.0 - nFadeRate);
+ aGhostedSeq[0].set( new drawinglayer::primitive2d::ModifiedColorPrimitive2D(
+ aSeq, aBColorModifier));
+
+ // Create the processor and process the primitives
+ const drawinglayer::geometry::ViewInformation2D aNewViewInfos;
+ std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(
+ drawinglayer::processor2d::createBaseProcessor2DFromOutputDevice(rRenderContext, aNewViewInfos));
+
+ pProcessor->process(aGhostedSeq);
+}
+
+void SwPageBreakWin::Select()
+{
+ SwFrameControlPtr pThis = GetEditWin()->GetFrameControlsManager( ).GetControl( FrameControlType::PageBreak, GetFrame() );
+
+ OString sIdent = GetCurItemIdent();
+ if (sIdent == "edit")
+ {
+ const SwLayoutFrame* pBodyFrame = static_cast< const SwLayoutFrame* >( GetPageFrame()->Lower() );
+ while ( pBodyFrame && !pBodyFrame->IsBodyFrame() )
+ pBodyFrame = static_cast< const SwLayoutFrame* >( pBodyFrame->GetNext() );
+
+ SwEditWin* pEditWin = GetEditWin();
+
+ if ( pBodyFrame )
+ {
+ SwWrtShell& rSh = pEditWin->GetView().GetWrtShell();
+ bool bOldLock = rSh.IsViewLocked();
+ rSh.LockView( true );
+
+ if ( pBodyFrame->Lower()->IsTabFrame() )
+ {
+ rSh.Push( );
+ rSh.ClearMark();
+
+ SwContentFrame *pCnt = const_cast< SwContentFrame* >( pBodyFrame->ContainsContent() );
+ SwContentNode* pNd = pCnt->IsTextFrame()
+ ? static_cast<SwTextFrame*>(pCnt)->GetTextNodeFirst()
+ : static_cast<SwNoTextFrame*>(pCnt)->GetNode();
+ rSh.SetSelection( *pNd );
+
+ SfxStringItem aItem(pEditWin->GetView().GetPool().GetWhich(FN_FORMAT_TABLE_DLG), "textflow");
+ pEditWin->GetView().GetViewFrame()->GetDispatcher()->ExecuteList(
+ FN_FORMAT_TABLE_DLG,
+ SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
+ { &aItem });
+
+ rSh.Pop(SwCursorShell::PopMode::DeleteCurrent);
+ }
+ else
+ {
+ SwContentFrame *pCnt = const_cast< SwContentFrame* >( pBodyFrame->ContainsContent() );
+ SwContentNode* pNd = pCnt->IsTextFrame()
+ ? static_cast<SwTextFrame*>(pCnt)->GetTextNodeFirst()
+ : static_cast<SwNoTextFrame*>(pCnt)->GetNode();
+
+ SwPaM aPaM( *pNd );
+ SwPaMItem aPaMItem( pEditWin->GetView().GetPool( ).GetWhich( FN_PARAM_PAM ), &aPaM );
+ SfxStringItem aItem( pEditWin->GetView().GetPool( ).GetWhich( SID_PARA_DLG ), "textflow" );
+ pEditWin->GetView().GetViewFrame()->GetDispatcher()->ExecuteList(
+ SID_PARA_DLG,
+ SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
+ { &aItem, &aPaMItem });
+ }
+ rSh.LockView( bOldLock );
+ pEditWin->GrabFocus( );
+ }
+ }
+ else if (sIdent == "delete")
+ {
+ const SwLayoutFrame* pBodyFrame = static_cast< const SwLayoutFrame* >( GetPageFrame()->Lower() );
+ while ( pBodyFrame && !pBodyFrame->IsBodyFrame() )
+ pBodyFrame = static_cast< const SwLayoutFrame* >( pBodyFrame->GetNext() );
+
+ if ( pBodyFrame )
+ {
+
+ SwContentFrame *pCnt = const_cast< SwContentFrame* >( pBodyFrame->ContainsContent() );
+ SwContentNode* pNd = pCnt->IsTextFrame()
+ ? static_cast<SwTextFrame*>(pCnt)->GetTextNodeFirst()
+ : static_cast<SwNoTextFrame*>(pCnt)->GetNode();
+
+ pNd->GetDoc()->GetIDocumentUndoRedo( ).StartUndo( SwUndoId::UI_DELETE_PAGE_BREAK, nullptr );
+
+ SfxItemSet aSet(
+ GetEditWin()->GetView().GetWrtShell().GetAttrPool(),
+ svl::Items<RES_PAGEDESC, RES_BREAK>{});
+ aSet.Put( SvxFormatBreakItem( SvxBreak::NONE, RES_BREAK ) );
+ aSet.Put( SwFormatPageDesc( nullptr ) );
+
+ SwPaM aPaM( *pNd );
+ pNd->GetDoc()->getIDocumentContentOperations().InsertItemSet(
+ aPaM, aSet, SetAttrMode::DEFAULT, GetPageFrame()->getRootFrame());
+
+ pNd->GetDoc()->GetIDocumentUndoRedo( ).EndUndo( SwUndoId::UI_DELETE_PAGE_BREAK, nullptr );
+ }
+ }
+
+ // Only fade if there is more than this temporary shared pointer:
+ // The main reference has been deleted due to a page break removal
+ if ( pThis.use_count() > 1 )
+ Fade( false );
+}
+
+void SwPageBreakWin::MouseMove( const MouseEvent& rMEvt )
+{
+ if ( rMEvt.IsLeaveWindow() )
+ {
+ // don't fade if we just move to the 'line', or the popup menu is open
+ Point aEventPos( rMEvt.GetPosPixel() + rMEvt.GetPosPixel() );
+ if ( !Contains( aEventPos ) && !PopupMenu::IsInExecute() )
+ Fade( false );
+ }
+ else if ( !IsVisible() )
+ Fade( true );
+}
+
+void SwPageBreakWin::Activate( )
+{
+ Fade( true );
+ MenuButton::Activate();
+}
+
+void SwPageBreakWin::UpdatePosition(const std::optional<Point>& xEvtPt)
+{
+ if ( xEvtPt )
+ {
+ if ( xEvtPt == m_xMousePt )
+ return;
+ m_xMousePt = xEvtPt;
+ }
+
+ const SwPageFrame* pPageFrame = GetPageFrame();
+ const SwFrame* pPrevPage = pPageFrame;
+ do
+ {
+ pPrevPage = pPrevPage->GetPrev();
+ }
+ while ( pPrevPage && ( ( pPrevPage->getFrameArea().Top( ) == pPageFrame->getFrameArea().Top( ) )
+ || static_cast< const SwPageFrame* >( pPrevPage )->IsEmptyPage( ) ) );
+
+ ::tools::Rectangle aBoundRect = GetEditWin()->LogicToPixel( pPageFrame->GetBoundRect(GetEditWin()).SVRect() );
+ ::tools::Rectangle aFrameRect = GetEditWin()->LogicToPixel( pPageFrame->getFrameArea().SVRect() );
+
+ long nYLineOffset = ( aBoundRect.Top() + aFrameRect.Top() ) / 2;
+ if ( pPrevPage )
+ {
+ ::tools::Rectangle aPrevFrameRect = GetEditWin()->LogicToPixel( pPrevPage->getFrameArea().SVRect() );
+ nYLineOffset = ( aPrevFrameRect.Bottom() + aFrameRect.Top() ) / 2;
+ }
+
+ // Get the page + sidebar coords
+ long nPgLeft = aFrameRect.Left();
+ long nPgRight = aFrameRect.Right();
+
+ unsigned long nSidebarWidth = 0;
+ const SwPostItMgr* pPostItMngr = GetEditWin()->GetView().GetWrtShell().GetPostItMgr();
+ if ( pPostItMngr && pPostItMngr->HasNotes() && pPostItMngr->ShowNotes() )
+ nSidebarWidth = pPostItMngr->GetSidebarBorderWidth( true ) + pPostItMngr->GetSidebarWidth( true );
+
+ if ( pPageFrame->SidebarPosition( ) == sw::sidebarwindows::SidebarPosition::LEFT )
+ nPgLeft -= nSidebarWidth;
+ else if ( pPageFrame->SidebarPosition( ) == sw::sidebarwindows::SidebarPosition::RIGHT )
+ nPgRight += nSidebarWidth;
+
+ Size aBtnSize( BUTTON_WIDTH + ARROW_WIDTH, BUTTON_HEIGHT );
+
+ // Place the button on the left or right?
+ ::tools::Rectangle aVisArea = GetEditWin()->LogicToPixel( GetEditWin()->GetView().GetVisArea() );
+
+ long nLineLeft = std::max( nPgLeft, aVisArea.Left() );
+ long nLineRight = std::min( nPgRight, aVisArea.Right() );
+ long nBtnLeft = nLineLeft;
+
+ if ( m_xMousePt )
+ {
+ nBtnLeft = nLineLeft + m_xMousePt->X() - aBtnSize.getWidth() / 2;
+
+ if ( nBtnLeft < nLineLeft )
+ nBtnLeft = nLineLeft;
+ else if ( ( nBtnLeft + aBtnSize.getWidth() ) > nLineRight )
+ nBtnLeft = nLineRight - aBtnSize.getWidth();
+ }
+
+ // Set the button position
+ Point aBtnPos( nBtnLeft, nYLineOffset - BUTTON_HEIGHT / 2 );
+ SetPosSizePixel( aBtnPos, aBtnSize );
+
+ // Set the line position
+ Point aLinePos( nLineLeft, nYLineOffset - 5 );
+ Size aLineSize( nLineRight - nLineLeft, 10 );
+ m_pLine->SetPosSizePixel( aLinePos, aLineSize );
+}
+
+void SwPageBreakWin::ShowAll( bool bShow )
+{
+ m_pLine->Show( bShow );
+}
+
+bool SwPageBreakWin::Contains( const Point &rDocPt ) const
+{
+ ::tools::Rectangle aRect( GetPosPixel(), GetSizePixel() );
+ if ( aRect.IsInside( rDocPt ) )
+ return true;
+
+ ::tools::Rectangle aLineRect( m_pLine->GetPosPixel(), m_pLine->GetSizePixel() );
+ return aLineRect.IsInside( rDocPt );
+}
+
+void SwPageBreakWin::SetReadonly( bool bReadonly )
+{
+ ShowAll( !bReadonly );
+}
+
+void SwPageBreakWin::Fade( bool bFadeIn )
+{
+ m_bIsAppearing = bFadeIn;
+ if ( bFadeIn )
+ m_nDelayAppearing = 0;
+
+ if ( !m_bDestroyed && m_aFadeTimer.IsActive( ) )
+ m_aFadeTimer.Stop();
+ if ( !m_bDestroyed )
+ m_aFadeTimer.Start( );
+}
+
+IMPL_LINK_NOARG(SwPageBreakWin, HideHandler, Menu *, bool)
+{
+ Fade( false );
+
+ return false;
+}
+
+IMPL_LINK_NOARG(SwPageBreakWin, FadeHandler, Timer *, void)
+{
+ const int TICKS_BEFORE_WE_APPEAR = 10;
+ if ( m_bIsAppearing && m_nDelayAppearing < TICKS_BEFORE_WE_APPEAR )
+ {
+ ++m_nDelayAppearing;
+ m_aFadeTimer.Start();
+ return;
+ }
+
+ if ( m_bIsAppearing && m_nFadeRate > 0 )
+ m_nFadeRate -= 25;
+ else if ( !m_bIsAppearing && m_nFadeRate < 100 )
+ m_nFadeRate += 25;
+
+ if ( m_nFadeRate != 100 && !IsVisible() )
+ Show();
+ else if ( m_nFadeRate == 100 && IsVisible( ) )
+ Hide();
+ else
+ {
+ UpdatePosition();
+ Invalidate();
+ }
+
+ if (IsVisible( ) && m_nFadeRate > 0 && m_nFadeRate < 100)
+ m_aFadeTimer.Start();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */