Header/Footer: Implemented the separator label as a Window
Had quite a hard time drawing the new windows at the correct position and find the proper VCL attributes. This new Window child class is using the WB_MOVEABLE and WB_OWNERDRAWDECORATION to workaround bugs in VCL.
This commit is contained in:
parent
68795fe0dc
commit
d004a81afc
4 changed files with 210 additions and 146 deletions
|
@ -127,6 +127,9 @@
|
|||
#include <basegfx/color/bcolortools.hxx>
|
||||
|
||||
#include <algorithm>
|
||||
#include <wrtsh.hxx>
|
||||
#include <edtwin.hxx>
|
||||
#include <view.hxx>
|
||||
|
||||
using namespace ::editeng;
|
||||
using namespace ::com::sun::star;
|
||||
|
@ -2796,6 +2799,14 @@ SwRootFrm::Paint(SwRect const& rRect, SwPrintData const*const pPrintData) const
|
|||
else
|
||||
SwRootFrm::bInPaint = bResetRootPaint = sal_True;
|
||||
|
||||
SwWrtShell* pWrtSh = dynamic_cast< SwWrtShell* >( pSh );
|
||||
if ( pWrtSh )
|
||||
{
|
||||
SwEditWin& rEditWin = pWrtSh->GetView().GetEditWin();
|
||||
rEditWin.ClearHeaderFooterControls( );
|
||||
}
|
||||
|
||||
|
||||
SwSavePaintStatics *pStatics = 0;
|
||||
if ( pGlobalShell )
|
||||
pStatics = new SwSavePaintStatics();
|
||||
|
@ -3303,45 +3314,17 @@ void SwLayoutFrm::Paint(SwRect const& rRect, SwPrintData const*const) const
|
|||
}
|
||||
|
||||
drawinglayer::primitive2d::Primitive2DSequence lcl_CreateHeaderFooterSeparatorPrimitives(
|
||||
OutputDevice* pOut, drawinglayer::processor2d::BaseProcessor2D* pProcessor,
|
||||
const SwPageFrm* pPageFrm, double nLabelRight, double nLineY,
|
||||
bool bHeader, const String& rStyleName, const SwFrm* pFrm )
|
||||
const SwPageFrm* pPageFrm, double nLineY )
|
||||
{
|
||||
// Adjust the Y-coordinate of the line to the header/footer box
|
||||
if ( pFrm )
|
||||
{
|
||||
const SwFrmFmt* pFmt = ((const SwLayoutFrm*)pFrm)->GetFmt();
|
||||
if ( bHeader )
|
||||
nLineY -= pFmt->GetULSpace().GetLower();
|
||||
else
|
||||
nLineY += pFmt->GetULSpace().GetUpper();
|
||||
}
|
||||
|
||||
drawinglayer::primitive2d::Primitive2DSequence aSeq( 3 );
|
||||
drawinglayer::primitive2d::Primitive2DSequence aSeq( 1 );
|
||||
|
||||
basegfx::B2DPoint aLeft ( pPageFrm->Frm().Left(), nLineY );
|
||||
basegfx::B2DPoint aRight( pPageFrm->Frm().Right(), nLineY );
|
||||
|
||||
// Compute the text to show
|
||||
String aText = SW_RESSTR( STR_HEADER );
|
||||
if ( !bHeader )
|
||||
aText = SW_RESSTR( STR_FOOTER );
|
||||
aText += rStyleName;
|
||||
|
||||
// Colors
|
||||
basegfx::BColor aLineColor = SwViewOption::GetHeaderFooterMarkColor().getBColor();
|
||||
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 );
|
||||
basegfx::BColor aFillColor = basegfx::tools::hsl2rgb( aHslLine );
|
||||
|
||||
// Only draw the dashed line for unexisting header / footers
|
||||
if ( !pFrm )
|
||||
{
|
||||
aSeq.realloc( 4 );
|
||||
|
||||
// Dashed line in twips
|
||||
|
@ -3361,84 +3344,17 @@ drawinglayer::primitive2d::Primitive2DSequence lcl_CreateHeaderFooterSeparatorPr
|
|||
drawinglayer::attribute::LineAttribute( aLineColor, 20.0 ),
|
||||
drawinglayer::attribute::StrokeAttribute( aStrokePattern ) );
|
||||
|
||||
aSeq[3] = drawinglayer::primitive2d::Primitive2DReference( pLine );
|
||||
}
|
||||
|
||||
const SwRect& rVisArea = pPageFrm->getRootFrm()->GetCurrShell()->VisArea();
|
||||
double nVisRight = rVisArea.Right();
|
||||
|
||||
// Compute the text primitive
|
||||
basegfx::B2DVector aFontSize;
|
||||
|
||||
Font aFont = pOut->GetSettings().GetStyleSettings().GetAppFont();
|
||||
aFont.SetHeight( 8 * 20 ); // 8pt to twips
|
||||
|
||||
// Compute the text width
|
||||
const Font& rOldFont = pOut->GetFont();
|
||||
pOut->SetFont( aFont );
|
||||
double nTextWidth = pOut->GetTextWidth( aText );
|
||||
pOut->SetFont( rOldFont );
|
||||
|
||||
drawinglayer::attribute::FontAttribute aFontAttr = drawinglayer::primitive2d::getFontAttributeFromVclFont(
|
||||
aFontSize, aFont, false, false );
|
||||
|
||||
FontMetric aFontMetric = pOut->GetFontMetric( aFont );
|
||||
|
||||
double nTextOffsetY = aFontMetric.GetHeight() - aFontMetric.GetDescent() + 70.0;
|
||||
if ( !bHeader )
|
||||
nTextOffsetY = - aFontMetric.GetDescent() - 70.0;
|
||||
basegfx::B2DHomMatrix aTextMatrix( basegfx::tools::createScaleTranslateB2DHomMatrix(
|
||||
aFontSize.getX(), aFontSize.getY(),
|
||||
std::min( nLabelRight, nVisRight ) - nTextWidth - 80.0, nLineY + nTextOffsetY ) );
|
||||
|
||||
|
||||
drawinglayer::primitive2d::TextSimplePortionPrimitive2D * pText =
|
||||
new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
|
||||
aTextMatrix,
|
||||
aText, 0, aText.Len(),
|
||||
std::vector< double >(),
|
||||
aFontAttr,
|
||||
lang::Locale(),
|
||||
aLineColor );
|
||||
aSeq[2] = drawinglayer::primitive2d::Primitive2DReference( pText );
|
||||
basegfx::B2DRange aTextRange = pText->getB2DRange( pProcessor->getViewInformation2D() );
|
||||
|
||||
// Draw the polygon around the flag
|
||||
basegfx::B2DPolygon aFlagPolygon;
|
||||
basegfx::B2DVector aFlagVector( 0, 1 );
|
||||
|
||||
double nFlagHeight = aTextRange.getMaxY() - nLineY + 60.0;
|
||||
|
||||
if ( !bHeader )
|
||||
{
|
||||
aFlagVector = - aFlagVector;
|
||||
nFlagHeight = nLineY - aTextRange.getMinY() + 60.0;
|
||||
}
|
||||
basegfx::B2DPoint aStartPt( aTextRange.getMinX() - 60.0, nLineY );
|
||||
aFlagPolygon.append( aStartPt );
|
||||
basegfx::B2DPoint aNextPt = aStartPt + aFlagVector * ( nFlagHeight );
|
||||
aFlagPolygon.append( aNextPt );
|
||||
aNextPt += ( aTextRange.getWidth() + 120.0 ) * basegfx::B2DVector( 1, 0 );
|
||||
aFlagPolygon.append( aNextPt );
|
||||
aNextPt.setY( nLineY );
|
||||
aFlagPolygon.append( aNextPt );
|
||||
|
||||
// Compute the flag background color primitive
|
||||
aSeq[0] = drawinglayer::primitive2d::Primitive2DReference(
|
||||
new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
|
||||
basegfx::B2DPolyPolygon( aFlagPolygon ),
|
||||
aFillColor ) );
|
||||
|
||||
drawinglayer::primitive2d::PolygonHairlinePrimitive2D * pBoxLine =
|
||||
new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
|
||||
aFlagPolygon, aLineColor );
|
||||
aSeq[1] = drawinglayer::primitive2d::Primitive2DReference( pBoxLine );
|
||||
|
||||
aSeq[0] = drawinglayer::primitive2d::Primitive2DReference( pLine );
|
||||
return aSeq;
|
||||
}
|
||||
|
||||
void SwPageFrm::PaintDecorators( OutputDevice *pOut ) const
|
||||
{
|
||||
SwWrtShell* pWrtSh = dynamic_cast< SwWrtShell* >( pGlobalShell );
|
||||
if ( pWrtSh )
|
||||
{
|
||||
SwEditWin& rEditWin = pWrtSh->GetView().GetEditWin();
|
||||
|
||||
const SwLayoutFrm* pBody = FindBodyCont();
|
||||
if ( pBody )
|
||||
{
|
||||
|
@ -3449,7 +3365,10 @@ void SwPageFrm::PaintDecorators( OutputDevice *pOut ) const
|
|||
!pGlobalShell->IsPreView() &&
|
||||
pGlobalShell->IsHeaderFooterEdit( ) )
|
||||
{
|
||||
const String aStyleName = GetPageDesc()->GetName();
|
||||
const rtl::OUString& rStyleName = GetPageDesc()->GetName();
|
||||
rtl::OUString aHeaderText = ResId::toString( SW_RES( STR_HEADER ) );
|
||||
sal_Int32 nPos = aHeaderText.lastIndexOf( rtl::OUString::createFromAscii( "%1" ) );
|
||||
aHeaderText = aHeaderText.replaceAt( nPos, 2, rStyleName );
|
||||
drawinglayer::processor2d::BaseProcessor2D* pProcessor = CreateProcessor2D();
|
||||
|
||||
// Header
|
||||
|
@ -3457,10 +3376,19 @@ void SwPageFrm::PaintDecorators( OutputDevice *pOut ) const
|
|||
if ( !pHeaderFrm->IsHeaderFrm() )
|
||||
pHeaderFrm = NULL;
|
||||
|
||||
double nLabelRight = aBodyRect.Right();
|
||||
const SwRect& rVisArea = pGlobalShell->VisArea();
|
||||
long nXOff = std::min( aBodyRect.Right(), rVisArea.Right() );
|
||||
|
||||
// FIXME there are cases where the label isn't show but should be
|
||||
if ( rVisArea.IsInside( Point( rVisArea.Left(), pHeaderFrm->Frm().Bottom() ) ) )
|
||||
{
|
||||
long nOutputYOff = pHeaderFrm->Frm().Bottom();
|
||||
Point nOutputOff = rEditWin.LogicToPixel( Point( nXOff, nOutputYOff ) );
|
||||
rEditWin.AddHeaderFooterControl( aHeaderText, true, nOutputOff );
|
||||
}
|
||||
|
||||
pProcessor->process( lcl_CreateHeaderFooterSeparatorPrimitives(
|
||||
pOut, pProcessor, this, nLabelRight,
|
||||
double( aBodyRect.Top() ), true, aStyleName, pHeaderFrm ) );
|
||||
this, double( aBodyRect.Top() ) ) );
|
||||
|
||||
// Footer
|
||||
const SwFrm* pFooterFrm = Lower();
|
||||
|
@ -3469,14 +3397,26 @@ void SwPageFrm::PaintDecorators( OutputDevice *pOut ) const
|
|||
if ( !pFooterFrm->IsFooterFrm() )
|
||||
pFooterFrm = NULL;
|
||||
|
||||
rtl::OUString aFooterText = ResId::toString( SW_RES( STR_FOOTER ) );
|
||||
nPos = aFooterText.lastIndexOf( rtl::OUString::createFromAscii( "%1" ) );
|
||||
aFooterText = aFooterText.replaceAt( nPos, 2, rStyleName );
|
||||
|
||||
// FIXME there are cases where the label isn't show but should be
|
||||
if ( rVisArea.IsInside( Point( rVisArea.Left(), pFooterFrm->Frm().Top() ) ) )
|
||||
{
|
||||
long nOutputYOff = pFooterFrm->Frm().Top();
|
||||
Point nOutputOff = rEditWin.LogicToPixel( Point( nXOff, nOutputYOff ) );
|
||||
rEditWin.AddHeaderFooterControl( aFooterText, false, nOutputOff );
|
||||
}
|
||||
|
||||
pProcessor->process( lcl_CreateHeaderFooterSeparatorPrimitives(
|
||||
pOut, pProcessor, this, nLabelRight,
|
||||
double( aBodyRect.Bottom() ), false, aStyleName, pFooterFrm ) );
|
||||
this, double( aBodyRect.Bottom() ) ) );
|
||||
|
||||
delete pProcessor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** FlyFrm::IsBackgroundTransparent - for feature #99657#
|
||||
|
||||
|
|
|
@ -412,12 +412,12 @@ String STR_EMPTYPAGE
|
|||
|
||||
String STR_HEADER
|
||||
{
|
||||
Text [ en-US ] = "Header: " ;
|
||||
Text [ en-US ] = "Header (%1)" ;
|
||||
};
|
||||
|
||||
String STR_FOOTER
|
||||
{
|
||||
Text [ en-US ] = "Footer: " ;
|
||||
Text [ en-US ] = "Footer (%1)" ;
|
||||
};
|
||||
|
||||
QueryBox MSG_CLPBRD_CLEAR
|
||||
|
|
|
@ -74,6 +74,8 @@
|
|||
#include <editeng/postitem.hxx>
|
||||
#include <editeng/protitem.hxx>
|
||||
#include <unotools/charclass.hxx>
|
||||
#include <basegfx/color/bcolortools.hxx>
|
||||
#include <basegfx/polygon/b2dpolygon.hxx>
|
||||
|
||||
#include <editeng/acorrcfg.hxx>
|
||||
#include <SwSmartTagMgr.hxx>
|
||||
|
@ -5677,4 +5679,104 @@ Selection SwEditWin::GetSurroundingTextSelection() const
|
|||
}
|
||||
}
|
||||
|
||||
#define TEXT_PADDING 7
|
||||
#define BOX_DISTANCE 10
|
||||
|
||||
// the WB_MOVABLE flag is used here to avoid the window to appear on all desktops (on linux)
|
||||
// and the WB_OWNERDRAWDECORATION prevents the system to draw the window decorations.
|
||||
//
|
||||
SwHeaderFooterControl::SwHeaderFooterControl( Window* pParent, const rtl::OUString& sLabel, bool bHeader, Point aOffset, Size aPosOffset ) :
|
||||
FloatingWindow( pParent, WB_SYSTEMWINDOW | WB_NOBORDER | WB_NOSHADOW | WB_MOVEABLE | WB_OWNERDRAWDECORATION ),
|
||||
m_sText( sLabel ),
|
||||
m_bIsHeader( bHeader ),
|
||||
m_aPosOffset( aPosOffset )
|
||||
{
|
||||
// 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 ) );
|
||||
|
||||
// Compute the position & size of the window
|
||||
Rectangle aTextRect;
|
||||
GetTextBoundRect( aTextRect, String( sLabel ) );
|
||||
Rectangle aTextPxRect = LogicToPixel( aTextRect );
|
||||
|
||||
Size aParentSize = pParent->GetSizePixel();
|
||||
|
||||
Size aBoxSize ( aTextPxRect.GetWidth() + TEXT_PADDING * 2,
|
||||
aTextPxRect.GetHeight() + TEXT_PADDING * 2 );
|
||||
|
||||
long nYFooterOff = 0;
|
||||
if ( !bHeader )
|
||||
nYFooterOff = aBoxSize.Height();
|
||||
|
||||
Point aBoxPos( m_aPosOffset.Width() + aOffset.X() - aBoxSize.Width() - BOX_DISTANCE,
|
||||
m_aPosOffset.Height() + aOffset.Y() - nYFooterOff );
|
||||
|
||||
// Set the position & Size of the window
|
||||
SetPosSizePixel( aBoxPos, aBoxSize );
|
||||
|
||||
// TODO Add the list_add.png picture
|
||||
}
|
||||
|
||||
void SwHeaderFooterControl::Paint( const Rectangle& rRect )
|
||||
{
|
||||
// Colors
|
||||
basegfx::BColor aLineColor = SwViewOption::GetHeaderFooterMarkColor().getBColor();
|
||||
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 );
|
||||
basegfx::BColor aFillColor = basegfx::tools::hsl2rgb( aHslLine );
|
||||
|
||||
// Draw the background rect
|
||||
SetFillColor( Color ( aFillColor ) );
|
||||
SetLineColor( Color ( aFillColor ) );
|
||||
DrawRect( rRect );
|
||||
|
||||
// Draw the lines around the rect
|
||||
SetLineColor( Color( aLineColor ) );
|
||||
basegfx::B2DPolygon aPolygon;
|
||||
aPolygon.append( basegfx::B2DPoint( rRect.Left(), rRect.Top() ) );
|
||||
aPolygon.append( basegfx::B2DPoint( rRect.Left(), rRect.Bottom() ) );
|
||||
DrawPolyLine( aPolygon, 1.0 );
|
||||
|
||||
aPolygon.clear();
|
||||
aPolygon.append( basegfx::B2DPoint( rRect.Right(), rRect.Top() ) );
|
||||
aPolygon.append( basegfx::B2DPoint( rRect.Right(), rRect.Bottom() ) );
|
||||
DrawPolyLine( aPolygon, 1.0 );
|
||||
|
||||
long nYLine = rRect.Bottom();
|
||||
if ( !m_bIsHeader )
|
||||
nYLine = rRect.Top();
|
||||
aPolygon.clear();
|
||||
aPolygon.append( basegfx::B2DPoint( rRect.Left(), nYLine ) );
|
||||
aPolygon.append( basegfx::B2DPoint( rRect.Right(), nYLine ) );
|
||||
DrawPolyLine( aPolygon, 1.0 );
|
||||
|
||||
|
||||
// Draw the text
|
||||
SetTextColor( Color( aLineColor ) );
|
||||
DrawText( Point( rRect.Left() + TEXT_PADDING, rRect.Top() + TEXT_PADDING ),
|
||||
String( m_sText ) );
|
||||
}
|
||||
|
||||
void SwEditWin::AddHeaderFooterControl( const rtl::OUString& sLabel, bool bHeader, Point aOffset )
|
||||
{
|
||||
SwHeaderFooterControl::Pointer pNewControl( new SwHeaderFooterControl( this, sLabel, bHeader, aOffset,
|
||||
Size( GetOutOffXPixel(), GetOutOffYPixel() ) ) );
|
||||
pNewControl->Show( );
|
||||
aHeadFootControls.push_back( pNewControl );
|
||||
}
|
||||
|
||||
void SwEditWin::ClearHeaderFooterControls( )
|
||||
{
|
||||
aHeadFootControls.clear();
|
||||
}
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
|
|
@ -32,12 +32,15 @@
|
|||
#include <tools/link.hxx>
|
||||
#include <vcl/timer.hxx>
|
||||
#include <vcl/window.hxx>
|
||||
#include <vcl/floatwin.hxx>
|
||||
#include <svtools/transfer.hxx>
|
||||
#include <swevent.hxx>
|
||||
|
||||
#define _SVSTDARR_STRINGSISORTDTOR
|
||||
#include <svl/svstdarr.hxx>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
class SwWrtShell;
|
||||
class SwView;
|
||||
class SwRect;
|
||||
|
@ -57,6 +60,20 @@ class SdrDropMarkerOverlay;
|
|||
Description: input window
|
||||
--------------------------------------------------------------------*/
|
||||
|
||||
class SwHeaderFooterControl : public FloatingWindow
|
||||
{
|
||||
const rtl::OUString m_sText;
|
||||
bool m_bIsHeader;
|
||||
Size m_aPosOffset;
|
||||
|
||||
public:
|
||||
SwHeaderFooterControl( Window* pParent, const rtl::OUString& sLabel, bool bHeader, Point aOffset, Size aOffsetPos );
|
||||
|
||||
virtual void Paint( const Rectangle& rRect );
|
||||
|
||||
typedef boost::shared_ptr< SwHeaderFooterControl > Pointer;
|
||||
};
|
||||
|
||||
class SwEditWin: public Window,
|
||||
public DropTargetHelper, public DragSourceHelper
|
||||
{
|
||||
|
@ -146,6 +163,8 @@ friend void PageNumNotify( ViewShell* pVwSh,
|
|||
sal_uInt16 nKS_NUMDOWN_Count; // #i23725#
|
||||
sal_uInt16 nKS_NUMINDENTINC_Count;
|
||||
|
||||
std::vector< SwHeaderFooterControl::Pointer > aHeadFootControls;
|
||||
|
||||
void LeaveArea(const Point &);
|
||||
void JustifyAreaTimer();
|
||||
inline void EnterArea();
|
||||
|
@ -299,6 +318,9 @@ public:
|
|||
void SetUseInputLanguage( sal_Bool bNew );
|
||||
sal_Bool IsUseInputLanguage() const { return bUseInputLanguage; }
|
||||
|
||||
void AddHeaderFooterControl( const rtl::OUString& sLabel, bool bHeader, Point aOffset );
|
||||
void ClearHeaderFooterControls( );
|
||||
|
||||
SwEditWin(Window *pParent, SwView &);
|
||||
virtual ~SwEditWin();
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue