Page Breaks: IsLeaveWindow() is unreliable, we do not need it here.
[LibreOffice.git] / sw / source / ui / docvw / PageBreakWin.cxx
blobff5050b3f826863595d1dc02f1752e079a7cc542
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * Version: MPL 1.1 / GPLv3+ / LGPLv3+
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License or as specified alternatively below. You may obtain a copy of
8 * the License at http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * Major Contributor(s):
16 * [ Copyright (C) 2011 SUSE <cbosdonnat@suse.com> (initial developer) ]
18 * All Rights Reserved.
20 * For minor contributions see the git repository.
22 * Alternatively, the contents of this file may be used under the terms of
23 * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
24 * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
25 * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
26 * instead of those above.
28 #include <globals.hrc>
29 #include <popup.hrc>
30 #include <utlui.hrc>
32 #include <cmdid.h>
33 #include <cntfrm.hxx>
34 #include <DashedLine.hxx>
35 #include <doc.hxx>
36 #include <edtwin.hxx>
37 #include <fmtpdsc.hxx>
38 #include <IDocumentUndoRedo.hxx>
39 #include <PageBreakWin.hxx>
40 #include <pagefrm.hxx>
41 #include <PostItMgr.hxx>
42 #include <uiitems.hxx>
43 #include <view.hxx>
44 #include <viewopt.hxx>
45 #include <wrtsh.hxx>
47 #include <basegfx/color/bcolortools.hxx>
48 #include <basegfx/matrix/b2dhommatrixtools.hxx>
49 #include <basegfx/polygon/b2dpolygon.hxx>
50 #include <basegfx/polygon/b2dpolygontools.hxx>
51 #include <basegfx/range/b2drectangle.hxx>
52 #include <drawinglayer/primitive2d/discretebitmapprimitive2d.hxx>
53 #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
54 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
55 #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
56 #include <editeng/brkitem.hxx>
57 #include <sfx2/dispatch.hxx>
58 #include <svx/sdr/contact/objectcontacttools.hxx>
59 #include <vcl/svapp.hxx>
61 #define BUTTON_WIDTH 30
62 #define BUTTON_HEIGHT 19
63 #define ARROW_WIDTH 9
65 using namespace basegfx;
66 using namespace basegfx::tools;
67 using namespace drawinglayer::primitive2d;
69 namespace
71 class SwBreakDashedLine : public SwDashedLine
73 private:
74 SwPageBreakWin* m_pWin;
76 public:
77 SwBreakDashedLine( Window* pParent, Color& ( *pColorFn )(), SwPageBreakWin* pWin ) :
78 SwDashedLine( pParent, pColorFn ),
79 m_pWin( pWin ) {};
81 virtual void MouseMove( const MouseEvent& rMEvt );
84 void SwBreakDashedLine::MouseMove( const MouseEvent& rMEvt )
86 Point aEventPos( GetPosPixel() + rMEvt.GetPosPixel() );
87 if ( !m_pWin->Contains( aEventPos ) )
88 m_pWin->Fade( false );
89 else if ( !m_pWin->IsVisible() )
90 m_pWin->Fade( true );
92 if ( !rMEvt.IsSynthetic() )
94 Point* pPtr = new Point( rMEvt.GetPosPixel() );
95 m_pWin->UpdatePosition( pPtr );
100 SwPageBreakWin::SwPageBreakWin( SwEditWin* pEditWin, const SwPageFrm* pPageFrm ) :
101 MenuButton( pEditWin, WB_DIALOGCONTROL ),
102 SwFrameControl( pEditWin, pPageFrm ),
103 m_pPopupMenu( NULL ),
104 m_pLine( NULL ),
105 m_bIsAppearing( false ),
106 m_nFadeRate( 100 ),
107 m_nDelayAppearing( 0 ),
108 m_bDestroyed( false ),
109 m_pMousePt( NULL )
111 // Use pixels for the rest of the drawing
112 SetMapMode( MapMode ( MAP_PIXEL ) );
114 // Create the line control
115 m_pLine = new SwBreakDashedLine( GetEditWin(), &SwViewOption::GetPageBreakColor, this );
117 // Create the popup menu
118 m_pPopupMenu = new PopupMenu( SW_RES( MN_PAGEBREAK_BUTTON ) );
119 m_pPopupMenu->SetDeactivateHdl( LINK( this, SwPageBreakWin, HideHandler ) );
120 SetPopupMenu( m_pPopupMenu );
122 m_aFadeTimer.SetTimeout( 50 );
123 m_aFadeTimer.SetTimeoutHdl( LINK( this, SwPageBreakWin, FadeHandler ) );
126 SwPageBreakWin::~SwPageBreakWin( )
128 m_bDestroyed = true;
129 m_aFadeTimer.Stop();
131 delete m_pPopupMenu;
132 delete m_pLine;
133 delete m_pMousePt;
136 void SwPageBreakWin::Paint( const Rectangle& )
138 const Rectangle aRect( Rectangle( Point( 0, 0 ), PixelToLogic( GetSizePixel() ) ) );
140 // Properly paint the control
141 BColor aColor = SwViewOption::GetPageBreakColor().getBColor();
143 BColor aHslLine = rgb2hsl( aColor );
144 double nLuminance = aHslLine.getZ();
145 nLuminance += ( 1.0 - nLuminance ) * 0.75;
146 if ( aHslLine.getZ() > 0.7 )
147 nLuminance = aHslLine.getZ() * 0.7;
148 aHslLine.setZ( nLuminance );
149 BColor aOtherColor = hsl2rgb( aHslLine );
151 const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
152 if ( rSettings.GetHighContrastMode( ) )
154 aColor = rSettings.GetDialogTextColor().getBColor();
155 aOtherColor = rSettings.GetDialogColor( ).getBColor();
158 bool bRtl = Application::GetSettings().GetLayoutRTL();
160 Primitive2DSequence aSeq( 3 );
161 B2DRectangle aBRect( double( aRect.Left() ), double( aRect.Top( ) ),
162 double( aRect.Right() ), double( aRect.Bottom( ) ) );
163 B2DPolygon aPolygon = createPolygonFromRect( aBRect, 3.0 / BUTTON_WIDTH, 3.0 / BUTTON_HEIGHT );
165 // Create the polygon primitives
166 aSeq[0] = Primitive2DReference( new PolyPolygonColorPrimitive2D(
167 B2DPolyPolygon( aPolygon ), aOtherColor ) );
168 aSeq[1] = Primitive2DReference( new PolygonHairlinePrimitive2D(
169 aPolygon, aColor ) );
171 // Create the primitive for the image
172 Image aImg( SW_RES( IMG_PAGE_BREAK ) );
173 double nImgOfstX = 3.0;
174 if ( bRtl )
175 nImgOfstX = aRect.Right() - aImg.GetSizePixel().Width() - 3.0;
176 aSeq[2] = Primitive2DReference( new DiscreteBitmapPrimitive2D(
177 aImg.GetBitmapEx(), B2DPoint( nImgOfstX, 1.0 ) ) );
179 // Paint the symbol if not readonly button
180 if ( IsEnabled() )
182 double nTop = double( aRect.getHeight() ) / 2.0;
183 double nBottom = nTop + 4.0;
184 double nLeft = aRect.getWidth( ) - ARROW_WIDTH - 6.0;
185 if ( bRtl )
186 nLeft = ARROW_WIDTH - 2.0;
187 double nRight = nLeft + 8.0;
189 B2DPolygon aTriangle;
190 aTriangle.append( B2DPoint( nLeft, nTop ) );
191 aTriangle.append( B2DPoint( nRight, nTop ) );
192 aTriangle.append( B2DPoint( ( nLeft + nRight ) / 2.0, nBottom ) );
193 aTriangle.setClosed( true );
195 BColor aTriangleColor = Color( COL_BLACK ).getBColor( );
196 if ( Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
197 aTriangleColor = Color( COL_WHITE ).getBColor( );
199 aSeq.realloc( aSeq.getLength() + 1 );
200 aSeq[ aSeq.getLength() - 1 ] = Primitive2DReference( new PolyPolygonColorPrimitive2D(
201 B2DPolyPolygon( aTriangle ), aTriangleColor ) );
204 Primitive2DSequence aGhostedSeq( 1 );
205 double nFadeRate = double( m_nFadeRate ) / 100.0;
206 aGhostedSeq[0] = Primitive2DReference( new ModifiedColorPrimitive2D(
207 aSeq, BColorModifier( Color( COL_WHITE ).getBColor(), 1.0 - nFadeRate, BCOLORMODIFYMODE_INTERPOLATE ) ) );
209 // Create the processor and process the primitives
210 const drawinglayer::geometry::ViewInformation2D aNewViewInfos;
211 drawinglayer::processor2d::BaseProcessor2D * pProcessor =
212 sdr::contact::createBaseProcessor2DFromOutputDevice(
213 *this, aNewViewInfos );
215 pProcessor->process( aGhostedSeq );
218 void SwPageBreakWin::Select( )
220 SwFrameControlPtr pThis = GetEditWin()->GetFrameControlsManager( ).GetControl( PageBreak, GetFrame() );
222 switch( GetCurItemId( ) )
224 case FN_PAGEBREAK_EDIT:
226 const SwLayoutFrm* pBodyFrm = static_cast< const SwLayoutFrm* >( GetPageFrame()->Lower() );
227 while ( pBodyFrm && !pBodyFrm->IsBodyFrm() )
228 pBodyFrm = static_cast< const SwLayoutFrm* >( pBodyFrm->GetNext() );
230 SwEditWin* pEditWin = GetEditWin();
232 if ( pBodyFrm )
234 SwWrtShell& rSh = pEditWin->GetView().GetWrtShell();
235 sal_Bool bOldLock = rSh.IsViewLocked();
236 rSh.LockView( sal_True );
238 if ( pBodyFrm->Lower()->IsTabFrm() )
240 rSh.Push( );
241 rSh.ClearMark();
243 SwCntntFrm *pCnt = const_cast< SwCntntFrm* >( pBodyFrm->ContainsCntnt() );
244 SwCntntNode* pNd = pCnt->GetNode();
245 rSh.SetSelection( *pNd );
247 SfxUInt16Item aItem( pEditWin->GetView().GetPool( ).GetWhich( FN_FORMAT_TABLE_DLG ), TP_TABLE_TEXTFLOW );
248 pEditWin->GetView().GetViewFrame()->GetDispatcher()->Execute(
249 FN_FORMAT_TABLE_DLG, SFX_CALLMODE_SYNCHRON|SFX_CALLMODE_RECORD, &aItem, NULL );
251 rSh.Pop( sal_False );
253 else
255 SwCntntFrm *pCnt = const_cast< SwCntntFrm* >( pBodyFrm->ContainsCntnt() );
256 SwCntntNode* pNd = pCnt->GetNode();
258 SwPaM aPaM( *pNd );
259 SwPaMItem aPaMItem( pEditWin->GetView().GetPool( ).GetWhich( FN_PARAM_PAM ), &aPaM );
260 SfxUInt16Item aItem( pEditWin->GetView().GetPool( ).GetWhich( SID_PARA_DLG ), TP_PARA_EXT );
261 pEditWin->GetView().GetViewFrame()->GetDispatcher()->Execute(
262 SID_PARA_DLG, SFX_CALLMODE_SYNCHRON|SFX_CALLMODE_RECORD, &aItem, &aPaMItem, NULL );
264 rSh.LockView( bOldLock );
265 pEditWin->GrabFocus( );
268 break;
269 case FN_PAGEBREAK_DELETE:
271 const SwLayoutFrm* pBodyFrm = static_cast< const SwLayoutFrm* >( GetPageFrame()->Lower() );
272 while ( pBodyFrm && !pBodyFrm->IsBodyFrm() )
273 pBodyFrm = static_cast< const SwLayoutFrm* >( pBodyFrm->GetNext() );
275 if ( pBodyFrm )
277 SwCntntFrm *pCnt = const_cast< SwCntntFrm* >( pBodyFrm->ContainsCntnt() );
278 SwCntntNode* pNd = pCnt->GetNode();
280 pNd->GetDoc()->GetIDocumentUndoRedo( ).StartUndo( UNDO_UI_DELETE_PAGE_BREAK, NULL );
282 SfxItemSet aSet( GetEditWin()->GetView().GetWrtShell().GetAttrPool(),
283 RES_PAGEDESC, RES_PAGEDESC,
284 RES_BREAK, RES_BREAK,
285 NULL );
286 aSet.Put( SvxFmtBreakItem( SVX_BREAK_NONE, RES_BREAK ) );
287 aSet.Put( SwFmtPageDesc( NULL ) );
289 SwPaM aPaM( *pNd );
290 pNd->GetDoc()->InsertItemSet( aPaM, aSet, nsSetAttrMode::SETATTR_DEFAULT );
292 pNd->GetDoc()->GetIDocumentUndoRedo( ).EndUndo( UNDO_UI_DELETE_PAGE_BREAK, NULL );
295 break;
298 // Only fade if there is more than this temporary shared pointer:
299 // The main reference has been deleted due to a page break removal
300 if ( pThis.use_count() > 1 )
301 Fade( false );
304 void SwPageBreakWin::MouseMove( const MouseEvent& rMEvt )
306 Point aEventPos( rMEvt.GetPosPixel() + rMEvt.GetPosPixel() );
307 if ( !Contains( aEventPos ) && !PopupMenu::IsInExecute() )
308 Fade( false );
309 else if ( !IsVisible() )
310 Fade( true );
313 void SwPageBreakWin::Activate( )
315 Fade( true );
316 MenuButton::Activate();
319 void SwPageBreakWin::UpdatePosition( const Point* pEvtPt )
321 if ( pEvtPt != NULL )
323 if ( pEvtPt == m_pMousePt )
324 return;
325 delete m_pMousePt;
326 m_pMousePt = pEvtPt;
329 const SwPageFrm* pPageFrm = GetPageFrame();
330 const SwFrm* pPrevPage = pPageFrm->GetPrev();
331 while ( pPrevPage && ( pPrevPage->Frm().Top( ) == pPageFrm->Frm().Top( ) ) )
332 pPrevPage = pPrevPage->GetPrev();
334 Rectangle aBoundRect = GetEditWin()->LogicToPixel( pPageFrm->GetBoundRect().SVRect() );
335 Rectangle aFrmRect = GetEditWin()->LogicToPixel( pPageFrm->Frm().SVRect() );
337 long nYLineOffset = ( aBoundRect.Top() + aFrmRect.Top() ) / 2;
338 if ( pPrevPage )
340 Rectangle aPrevFrmRect = GetEditWin()->LogicToPixel( pPrevPage->Frm().SVRect() );
341 nYLineOffset = ( aPrevFrmRect.Bottom() + aFrmRect.Top() ) / 2;
344 // Get the page + sidebar coords
345 long nPgLeft = aFrmRect.Left();
346 long nPgRight = aFrmRect.Right();
348 unsigned long nSidebarWidth = 0;
349 const SwPostItMgr* pPostItMngr = GetEditWin()->GetView().GetWrtShell().GetPostItMgr();
350 if ( pPostItMngr && pPostItMngr->HasNotes() && pPostItMngr->ShowNotes() )
351 nSidebarWidth = pPostItMngr->GetSidebarBorderWidth( true ) + pPostItMngr->GetSidebarWidth( true );
353 if ( pPageFrm->SidebarPosition( ) == sw::sidebarwindows::SIDEBAR_LEFT )
354 nPgLeft -= nSidebarWidth;
355 else if ( pPageFrm->SidebarPosition( ) == sw::sidebarwindows::SIDEBAR_RIGHT )
356 nPgRight += nSidebarWidth;
358 Size aBtnSize( BUTTON_WIDTH + ARROW_WIDTH, BUTTON_HEIGHT );
360 // Place the button on the left or right?
361 Rectangle aVisArea = GetEditWin()->LogicToPixel( GetEditWin()->GetView().GetVisArea() );
363 long nLineLeft = std::max( nPgLeft, aVisArea.Left() );
364 long nLineRight = std::min( nPgRight, aVisArea.Right() );
365 long nBtnLeft = nLineLeft;
367 if ( m_pMousePt )
369 nBtnLeft = nLineLeft + m_pMousePt->X() - aBtnSize.getWidth() / 2;
371 if ( nBtnLeft < nLineLeft )
372 nBtnLeft = nLineLeft;
373 else if ( ( nBtnLeft + aBtnSize.getWidth() ) > nLineRight )
374 nBtnLeft = nLineRight - aBtnSize.getWidth();
377 // Set the button position
378 Point aBtnPos( nBtnLeft, nYLineOffset - BUTTON_HEIGHT / 2 );
379 SetPosSizePixel( aBtnPos, aBtnSize );
381 // Set the line position
382 Point aLinePos( nLineLeft, nYLineOffset - 5 );
383 Size aLineSize( nLineRight - nLineLeft, 10 );
384 m_pLine->SetPosSizePixel( aLinePos, aLineSize );
387 void SwPageBreakWin::ShowAll( bool bShow )
389 m_pLine->Show( bShow );
392 bool SwPageBreakWin::Contains( const Point &rDocPt ) const
394 Rectangle aRect( GetPosPixel(), GetSizePixel() );
395 if ( aRect.IsInside( rDocPt ) )
396 return true;
398 Rectangle aLineRect( m_pLine->GetPosPixel(), m_pLine->GetSizePixel() );
399 if ( aLineRect.IsInside( rDocPt ) )
400 return true;
402 return false;
405 const SwPageFrm* SwPageBreakWin::GetPageFrame( )
407 return static_cast< const SwPageFrm * >( GetFrame( ) );
410 void SwPageBreakWin::SetReadonly( bool bReadonly )
412 Enable( !bReadonly );
415 void SwPageBreakWin::Fade( bool bFadeIn )
417 m_bIsAppearing = bFadeIn;
418 if ( bFadeIn )
419 m_nDelayAppearing = 0;
421 if ( !m_bDestroyed && m_aFadeTimer.IsActive( ) )
422 m_aFadeTimer.Stop();
423 if ( !m_bDestroyed )
424 m_aFadeTimer.Start( );
427 IMPL_LINK( SwPageBreakWin, HideHandler, void *, EMPTYARG )
429 Fade( false );
431 return 0;
434 IMPL_LINK( SwPageBreakWin, FadeHandler, Timer *, EMPTYARG )
436 const int TICKS_BEFORE_WE_APPEAR = 10;
437 if ( m_bIsAppearing && m_nDelayAppearing < TICKS_BEFORE_WE_APPEAR )
439 ++m_nDelayAppearing;
440 m_aFadeTimer.Start();
441 return 0;
444 if ( m_bIsAppearing && m_nFadeRate > 0 )
445 m_nFadeRate -= 25;
446 else if ( !m_bIsAppearing && m_nFadeRate < 100 )
447 m_nFadeRate += 25;
449 if ( m_nFadeRate != 100 && !IsVisible() )
450 Show();
451 else if ( m_nFadeRate == 100 && IsVisible( ) )
452 Hide();
453 else
455 UpdatePosition();
456 Invalidate();
459 if ( IsVisible( ) && m_nFadeRate > 0 && m_nFadeRate < 100 )
460 m_aFadeTimer.Start();
462 return 0;
465 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */