summaryrefslogtreecommitdiff
path: root/sw/source/uibase/docvw/HeaderFooterWin.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/uibase/docvw/HeaderFooterWin.cxx')
-rw-r--r--sw/source/uibase/docvw/HeaderFooterWin.cxx520
1 files changed, 520 insertions, 0 deletions
diff --git a/sw/source/uibase/docvw/HeaderFooterWin.cxx b/sw/source/uibase/docvw/HeaderFooterWin.cxx
new file mode 100644
index 000000000000..b68c59a194d8
--- /dev/null
+++ b/sw/source/uibase/docvw/HeaderFooterWin.cxx
@@ -0,0 +1,520 @@
+/* -*- 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 <app.hrc>
+#include <docvw.hrc>
+#include <globals.hrc>
+#include <popup.hrc>
+#include <svtools/svtools.hrc>
+
+#include <cmdid.h>
+#include <DashedLine.hxx>
+#include <docsh.hxx>
+#include <edtwin.hxx>
+#include <fmthdft.hxx>
+#include <HeaderFooterWin.hxx>
+#include <pagedesc.hxx>
+#include <pagefrm.hxx>
+#include <SwRewriter.hxx>
+#include <view.hxx>
+#include <viewopt.hxx>
+#include <wrtsh.hxx>
+
+#include <basegfx/color/bcolortools.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/range/b2drectangle.hxx>
+#include <basegfx/vector/b2dsize.hxx>
+#include <drawinglayer/attribute/fillgradientattribute.hxx>
+#include <drawinglayer/attribute/fontattribute.hxx>
+#include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx>
+#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
+#include <drawinglayer/primitive2d/textprimitive2d.hxx>
+#include <editeng/boxitem.hxx>
+#include <svtools/svtresid.hxx>
+#include <svx/hdft.hxx>
+#include <drawinglayer/processor2d/processorfromoutputdevice.hxx>
+#include <vcl/decoview.hxx>
+#include <vcl/gradient.hxx>
+#include <vcl/menubtn.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+
+#define TEXT_PADDING 5
+#define BOX_DISTANCE 10
+#define BUTTON_WIDTH 18
+
+using namespace basegfx;
+using namespace basegfx::tools;
+using namespace drawinglayer::attribute;
+
+namespace
+{
+ static basegfx::BColor lcl_GetFillColor( basegfx::BColor aLineColor )
+ {
+ basegfx::BColor aHslLine = basegfx::tools::rgb2hsl( aLineColor );
+ double nLuminance = aHslLine.getZ() * 2.5;
+ if ( nLuminance == 0 )
+ nLuminance = 0.5;
+ else if ( nLuminance >= 1.0 )
+ nLuminance = aHslLine.getZ() * 0.4;
+ aHslLine.setZ( nLuminance );
+ return basegfx::tools::hsl2rgb( aHslLine );
+ }
+
+ static basegfx::BColor lcl_GetLighterGradientColor( basegfx::BColor aDarkColor )
+ {
+ basegfx::BColor aHslDark = basegfx::tools::rgb2hsl( aDarkColor );
+ double nLuminance = aHslDark.getZ() * 255 + 20;
+ aHslDark.setZ( nLuminance / 255.0 );
+ return basegfx::tools::hsl2rgb( aHslDark );
+ }
+
+ static B2DPolygon lcl_GetPolygon( const Rectangle& rRect, bool bHeader )
+ {
+ const double nRadius = 3;
+ const double nKappa((M_SQRT2 - 1.0) * 4.0 / 3.0);
+
+ B2DPolygon aPolygon;
+ aPolygon.append( B2DPoint( rRect.Left(), rRect.Top() ) );
+
+ {
+ B2DPoint aCorner( rRect.Left(), rRect.Bottom() );
+ B2DPoint aStart( rRect.Left(), rRect.Bottom() - nRadius );
+ B2DPoint aEnd( rRect.Left() + nRadius, rRect.Bottom() );
+ aPolygon.append( aStart );
+ aPolygon.appendBezierSegment(
+ interpolate( aStart, aCorner, nKappa ),
+ interpolate( aEnd, aCorner, nKappa ),
+ aEnd );
+ }
+
+ {
+ B2DPoint aCorner( rRect.Right(), rRect.Bottom() );
+ B2DPoint aStart( rRect.Right() - nRadius, rRect.Bottom() );
+ B2DPoint aEnd( rRect.Right(), rRect.Bottom() - nRadius );
+ aPolygon.append( aStart );
+ aPolygon.appendBezierSegment(
+ interpolate( aStart, aCorner, nKappa ),
+ interpolate( aEnd, aCorner, nKappa ),
+ aEnd );
+ }
+
+ aPolygon.append( B2DPoint( rRect.Right(), rRect.Top() ) );
+
+ if ( !bHeader )
+ {
+ B2DRectangle aBRect( rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom() );
+ B2DHomMatrix aRotation = createRotateAroundPoint(
+ aBRect.getCenterX(), aBRect.getCenterY(), M_PI );
+ aPolygon.transform( aRotation );
+ }
+
+ return aPolygon;
+ }
+}
+
+SwHeaderFooterWin::SwHeaderFooterWin( SwEditWin* pEditWin, const SwPageFrm* pPageFrm, bool bHeader ) :
+ MenuButton( pEditWin, WB_DIALOGCONTROL ),
+ SwFrameControl( pEditWin, pPageFrm ),
+ m_sLabel( ),
+ m_bIsHeader( bHeader ),
+ m_pPopupMenu( NULL ),
+ m_pLine( NULL ),
+ m_bIsAppearing( false ),
+ m_nFadeRate( 100 ),
+ m_aFadeTimer( )
+{
+ // Get the font and configure it
+ Font aFont = GetSettings().GetStyleSettings().GetToolFont();
+ SetZoomedPointFont( aFont );
+
+ // Use pixels for the rest of the drawing
+ SetMapMode( MapMode ( MAP_PIXEL ) );
+
+ // Create the line control
+ m_pLine = new SwDashedLine( GetEditWin(), &SwViewOption::GetHeaderFooterMarkColor );
+ m_pLine->SetZOrder( this, WINDOW_ZORDER_BEFOR );
+
+ // Create and set the PopupMenu
+ m_pPopupMenu = new PopupMenu( SW_RES( MN_HEADERFOOTER_BUTTON ) );
+
+ // Rewrite the menu entries' text
+ if ( m_bIsHeader )
+ {
+ m_pPopupMenu->SetItemText( FN_HEADERFOOTER_EDIT, SW_RESSTR( STR_FORMAT_HEADER ) );
+ m_pPopupMenu->SetItemText( FN_HEADERFOOTER_DELETE, SW_RESSTR( STR_DELETE_HEADER ) );
+ }
+ else
+ {
+ m_pPopupMenu->SetItemText( FN_HEADERFOOTER_EDIT, SW_RESSTR( STR_FORMAT_FOOTER ) );
+ m_pPopupMenu->SetItemText( FN_HEADERFOOTER_DELETE, SW_RESSTR( STR_DELETE_FOOTER ) );
+ }
+
+ SetPopupMenu( m_pPopupMenu );
+
+ m_aFadeTimer.SetTimeout( 50 );
+ m_aFadeTimer.SetTimeoutHdl( LINK( this, SwHeaderFooterWin, FadeHandler ) );
+}
+
+SwHeaderFooterWin::~SwHeaderFooterWin( )
+{
+ delete m_pPopupMenu;
+ delete m_pLine;
+}
+
+const SwPageFrm* SwHeaderFooterWin::GetPageFrame( )
+{
+ return static_cast< const SwPageFrm * >( GetFrame( ) );
+}
+
+void SwHeaderFooterWin::SetOffset( Point aOffset, long nXLineStart, long nXLineEnd )
+{
+ // Compute the text to show
+ m_sLabel = SW_RESSTR( STR_HEADER_TITLE );
+ if ( !m_bIsHeader )
+ m_sLabel = SW_RESSTR( STR_FOOTER_TITLE );
+ sal_Int32 nPos = m_sLabel.lastIndexOf( "%1" );
+ m_sLabel = m_sLabel.replaceAt( nPos, 2, GetPageFrame()->GetPageDesc()->GetName() );
+
+ // Compute the text size and get the box position & size from it
+ Rectangle aTextRect;
+ GetTextBoundRect( aTextRect, OUString( m_sLabel ) );
+ Rectangle aTextPxRect = LogicToPixel( aTextRect );
+ FontMetric aFontMetric = GetFontMetric( GetFont() );
+ Size aBoxSize ( aTextPxRect.GetWidth() + BUTTON_WIDTH + TEXT_PADDING * 2,
+ aFontMetric.GetLineHeight() + TEXT_PADDING * 2 );
+
+ long nYFooterOff = 0;
+ if ( !m_bIsHeader )
+ nYFooterOff = aBoxSize.Height();
+
+ Point aBoxPos( aOffset.X() - aBoxSize.Width() - BOX_DISTANCE,
+ aOffset.Y() - nYFooterOff );
+
+ if ( Application::GetSettings().GetLayoutRTL() )
+ {
+ aBoxPos.setX( aOffset.X() + BOX_DISTANCE );
+ }
+
+ // Set the position & Size of the window
+ SetPosSizePixel( aBoxPos, aBoxSize );
+
+ double nYLinePos = aBoxPos.Y();
+ if ( !m_bIsHeader )
+ nYLinePos += aBoxSize.Height();
+ Point aLinePos( nXLineStart, nYLinePos );
+ Size aLineSize( nXLineEnd - nXLineStart, 1 );
+ m_pLine->SetPosSizePixel( aLinePos, aLineSize );
+}
+
+void SwHeaderFooterWin::ShowAll( bool bShow )
+{
+ if ( !PopupMenu::IsInExecute() )
+ {
+ m_bIsAppearing = bShow;
+
+ if ( m_aFadeTimer.IsActive( ) )
+ m_aFadeTimer.Stop();
+ m_aFadeTimer.Start( );
+ }
+}
+
+bool SwHeaderFooterWin::Contains( const Point &rDocPt ) const
+{
+ Rectangle aRect( GetPosPixel(), GetSizePixel() );
+ if ( aRect.IsInside( rDocPt ) )
+ return true;
+
+ Rectangle aLineRect( m_pLine->GetPosPixel(), m_pLine->GetSizePixel() );
+ if ( aLineRect.IsInside( rDocPt ) )
+ return true;
+
+ return false;
+}
+
+void SwHeaderFooterWin::Paint( const Rectangle& )
+{
+ const Rectangle aRect( Rectangle( Point( 0, 0 ), PixelToLogic( GetSizePixel() ) ) );
+ drawinglayer::primitive2d::Primitive2DSequence aSeq( 3 );
+
+ B2DPolygon aPolygon = lcl_GetPolygon( aRect, m_bIsHeader );
+
+ // Colors
+ basegfx::BColor aLineColor = SwViewOption::GetHeaderFooterMarkColor().getBColor();
+ basegfx::BColor aFillColor = lcl_GetFillColor( aLineColor );
+ basegfx::BColor aLighterColor = lcl_GetLighterGradientColor( aFillColor );
+
+ const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
+ if ( rSettings.GetHighContrastMode() )
+ {
+ aFillColor = rSettings.GetDialogColor( ).getBColor();
+ aLineColor = rSettings.GetDialogTextColor( ).getBColor();
+
+ aSeq[0] = drawinglayer::primitive2d::Primitive2DReference( new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
+ B2DPolyPolygon( aPolygon ), aFillColor ) );
+ }
+ else
+ {
+ B2DRectangle aGradientRect( aRect.Left(), aRect.Top(), aRect.Right(), aRect.Bottom() );
+ double nAngle = M_PI;
+ if ( m_bIsHeader )
+ nAngle = 0;
+ FillGradientAttribute aFillAttrs( GRADIENTSTYLE_LINEAR, 0.0, 0.0, 0.0, nAngle,
+ aLighterColor, aFillColor, 10 );
+ aSeq[0] = drawinglayer::primitive2d::Primitive2DReference( new drawinglayer::primitive2d::FillGradientPrimitive2D(
+ aGradientRect, aFillAttrs ) );
+ }
+
+ // Create the border lines primitive
+ aSeq[1] = drawinglayer::primitive2d::Primitive2DReference( new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
+ aPolygon, aLineColor ) );
+
+ // Create the text primitive
+ B2DVector aFontSize;
+ FontAttribute aFontAttr = drawinglayer::primitive2d::getFontAttributeFromVclFont(
+ aFontSize, GetFont(), false, false );
+
+ FontMetric aFontMetric = GetFontMetric( GetFont() );
+ double nTextOffsetY = aFontMetric.GetAscent() + TEXT_PADDING;
+ Point aTextPos( TEXT_PADDING, nTextOffsetY );
+
+ basegfx::B2DHomMatrix aTextMatrix( createScaleTranslateB2DHomMatrix(
+ aFontSize.getX(), aFontSize.getY(),
+ double( aTextPos.X() ), double( aTextPos.Y() ) ) );
+
+ aSeq[2] = drawinglayer::primitive2d::Primitive2DReference( new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
+ aTextMatrix,
+ OUString( m_sLabel ), 0, m_sLabel.getLength(),
+ std::vector< double >( ),
+ aFontAttr,
+ com::sun::star::lang::Locale(),
+ aLineColor ) );
+
+ // Create the 'plus' or 'arrow' primitive
+ B2DRectangle aSignArea( B2DPoint( aRect.Right() - BUTTON_WIDTH, 0.0 ),
+ B2DSize( aRect.Right(), aRect.getHeight() ) );
+
+ B2DPolygon aSign;
+ if ( IsEmptyHeaderFooter( ) )
+ {
+ // Create the + polygon
+ double nLeft = aSignArea.getMinX() + TEXT_PADDING;
+ double nRight = aSignArea.getMaxX() - TEXT_PADDING;
+ double nHalfW = ( nRight - nLeft ) / 2.0;
+
+ double nTop = aSignArea.getCenterY() - nHalfW;
+ double nBottom = aSignArea.getCenterY() + nHalfW;
+
+ aSign.append( B2DPoint( nLeft, aSignArea.getCenterY() - 1.0 ) );
+ aSign.append( B2DPoint( aSignArea.getCenterX() - 1.0, aSignArea.getCenterY() - 1.0 ) );
+ aSign.append( B2DPoint( aSignArea.getCenterX() - 1.0, nTop ) );
+ aSign.append( B2DPoint( aSignArea.getCenterX() + 1.0, nTop ) );
+ aSign.append( B2DPoint( aSignArea.getCenterX() + 1.0, aSignArea.getCenterY() - 1.0 ) );
+ aSign.append( B2DPoint( nRight, aSignArea.getCenterY() - 1.0 ) );
+ aSign.append( B2DPoint( nRight, aSignArea.getCenterY() + 1.0 ) );
+ aSign.append( B2DPoint( aSignArea.getCenterX() + 1.0, aSignArea.getCenterY() + 1.0 ) );
+ aSign.append( B2DPoint( aSignArea.getCenterX() + 1.0, nBottom ) );
+ aSign.append( B2DPoint( aSignArea.getCenterX() - 1.0, nBottom ) );
+ aSign.append( B2DPoint( aSignArea.getCenterX() - 1.0, aSignArea.getCenterY() + 1.0 ) );
+ aSign.append( B2DPoint( nLeft, aSignArea.getCenterY() + 1.0 ) );
+ aSign.setClosed( true );
+ }
+ else
+ {
+ // Create the v polygon
+ B2DPoint aLeft( aSignArea.getMinX() + TEXT_PADDING, aSignArea.getCenterY() );
+ B2DPoint aRight( aSignArea.getMaxX() - TEXT_PADDING, aSignArea.getCenterY() );
+ B2DPoint aBottom( ( aLeft.getX() + aRight.getX() ) / 2.0, aLeft.getY() + 4.0 );
+ aSign.append( aLeft );
+ aSign.append( aRight );
+ aSign.append( aBottom );
+ aSign.setClosed( true );
+ }
+
+ BColor aSignColor = Color( COL_BLACK ).getBColor( );
+ if ( Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
+ aSignColor = Color( COL_WHITE ).getBColor( );
+
+ aSeq.realloc( aSeq.getLength() + 1 );
+ aSeq[ aSeq.getLength() - 1 ] = drawinglayer::primitive2d::Primitive2DReference( new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
+ B2DPolyPolygon( aSign ), aSignColor ) );
+
+ // Create the processor and process the primitives
+ const drawinglayer::geometry::ViewInformation2D aNewViewInfos;
+ drawinglayer::processor2d::BaseProcessor2D * pProcessor =
+ drawinglayer::processor2d::createBaseProcessor2DFromOutputDevice(
+ *this, aNewViewInfos );
+
+ // TODO Ghost it all if needed
+ drawinglayer::primitive2d::Primitive2DSequence aGhostedSeq( 1 );
+ double nFadeRate = double( m_nFadeRate ) / 100.0;
+ const basegfx::BColorModifierSharedPtr aBColorModifier(
+ new basegfx::BColorModifier_interpolate(
+ Color( COL_WHITE ).getBColor(),
+ 1.0 - nFadeRate));
+ aGhostedSeq[0] = drawinglayer::primitive2d::Primitive2DReference( new drawinglayer::primitive2d::ModifiedColorPrimitive2D(
+ aSeq, aBColorModifier ) );
+
+ pProcessor->process( aGhostedSeq );
+ delete pProcessor;
+}
+
+bool SwHeaderFooterWin::IsEmptyHeaderFooter( )
+{
+ bool bResult = true;
+
+ // Actually check it
+ const SwPageDesc* pDesc = GetPageFrame()->GetPageDesc();
+
+ bool const bFirst(GetPageFrame()->OnFirstPage());
+ const SwFrmFmt *const pFmt = (GetPageFrame()->OnRightPage())
+ ? pDesc->GetRightFmt(bFirst)
+ : pDesc->GetLeftFmt(bFirst);
+
+ if ( pFmt )
+ {
+ if ( m_bIsHeader )
+ bResult = !pFmt->GetHeader().IsActive();
+ else
+ bResult = !pFmt->GetFooter().IsActive();
+ }
+
+ return bResult;
+}
+
+void SwHeaderFooterWin::ExecuteCommand( sal_uInt16 nSlot )
+{
+ SwView& rView = GetEditWin()->GetView();
+ SwWrtShell& rSh = rView.GetWrtShell();
+
+ const OUString& rStyleName = GetPageFrame()->GetPageDesc()->GetName();
+ switch ( nSlot )
+ {
+ case FN_HEADERFOOTER_EDIT:
+ {
+ OString sPageId = m_bIsHeader ? OString("header") : OString("footer");
+ rView.GetDocShell()->FormatPage(rStyleName, sPageId, rSh);
+ }
+ break;
+ case FN_HEADERFOOTER_BORDERBACK:
+ {
+ const SwPageDesc* pDesc = GetPageFrame()->GetPageDesc();
+ const SwFrmFmt& rMaster = pDesc->GetMaster();
+ SwFrmFmt* pHFFmt = const_cast< SwFrmFmt* >( rMaster.GetFooter().GetFooterFmt() );
+ if ( m_bIsHeader )
+ pHFFmt = const_cast< SwFrmFmt* >( rMaster.GetHeader().GetHeaderFmt() );
+
+ SfxItemPool* pPool = pHFFmt->GetAttrSet().GetPool();
+ SfxItemSet aSet( *pPool,
+ RES_BACKGROUND, RES_BACKGROUND,
+ RES_BOX, RES_BOX,
+ SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER,
+ RES_SHADOW, RES_SHADOW, 0 );
+
+ aSet.Put( pHFFmt->GetAttrSet() );
+
+ // Create a box info item... needed by the dialog
+ SvxBoxInfoItem aBoxInfo( SID_ATTR_BORDER_INNER );
+ const SfxPoolItem *pBoxInfo;
+ if ( SFX_ITEM_SET == pHFFmt->GetAttrSet().GetItemState( SID_ATTR_BORDER_INNER,
+ true, &pBoxInfo) )
+ aBoxInfo = *(SvxBoxInfoItem*)pBoxInfo;
+
+ aBoxInfo.SetTable( false );
+ aBoxInfo.SetDist( true);
+ aBoxInfo.SetMinDist( false );
+ aBoxInfo.SetDefDist( MIN_BORDER_DIST );
+ aBoxInfo.SetValid( VALID_DISABLE );
+ aSet.Put( aBoxInfo );
+
+ if ( svx::ShowBorderBackgroundDlg( this, &aSet, true ) )
+ {
+ const SfxPoolItem* pItem;
+ if ( SFX_ITEM_SET == aSet.GetItemState( RES_BACKGROUND, false, &pItem ) ) {
+ pHFFmt->SetFmtAttr( *pItem );
+ rView.GetDocShell()->SetModified(true);
+ }
+
+ if ( SFX_ITEM_SET == aSet.GetItemState( RES_BOX, false, &pItem ) ) {
+ pHFFmt->SetFmtAttr( *pItem );
+ rView.GetDocShell()->SetModified(true);
+ }
+
+ if ( SFX_ITEM_SET == aSet.GetItemState( RES_SHADOW, false, &pItem ) ) {
+ pHFFmt->SetFmtAttr( *pItem );
+ rView.GetDocShell()->SetModified(true);
+ }
+ }
+ }
+ break;
+ case FN_HEADERFOOTER_DELETE:
+ {
+ rSh.ChangeHeaderOrFooter( rStyleName, m_bIsHeader, false, true );
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void SwHeaderFooterWin::SetReadonly( bool bReadonly )
+{
+ ShowAll( !bReadonly );
+}
+
+void SwHeaderFooterWin::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if ( IsEmptyHeaderFooter( ) )
+ {
+ SwView& rView = GetEditWin()->GetView();
+ SwWrtShell& rSh = rView.GetWrtShell();
+
+ const OUString& rStyleName = GetPageFrame()->GetPageDesc()->GetName();
+ rSh.ChangeHeaderOrFooter( rStyleName, m_bIsHeader, true, false );
+ }
+ else
+ MenuButton::MouseButtonDown( rMEvt );
+}
+
+void SwHeaderFooterWin::Select( )
+{
+ ExecuteCommand( GetCurItemId() );
+}
+
+IMPL_LINK_NOARG(SwHeaderFooterWin, FadeHandler)
+{
+ 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( true );
+ m_pLine->Show( true );
+ }
+ else if ( m_nFadeRate == 100 && IsVisible( ) )
+ {
+ Show( false );
+ m_pLine->Show( false );
+ }
+ else
+ Invalidate();
+
+ if ( IsVisible( ) && m_nFadeRate > 0 && m_nFadeRate < 100 )
+ m_aFadeTimer.Start();
+
+ return 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */