Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : */
9 :
10 : #include <globals.hrc>
11 : #include <popup.hrc>
12 : #include <utlui.hrc>
13 :
14 : #include <cmdid.h>
15 : #include <cntfrm.hxx>
16 : #include <DashedLine.hxx>
17 : #include <doc.hxx>
18 : #include <edtwin.hxx>
19 : #include <fmtpdsc.hxx>
20 : #include <IDocumentUndoRedo.hxx>
21 : #include <IDocumentContentOperations.hxx>
22 : #include <PageBreakWin.hxx>
23 : #include <pagefrm.hxx>
24 : #include <PostItMgr.hxx>
25 : #include <uiitems.hxx>
26 : #include <view.hxx>
27 : #include <viewopt.hxx>
28 : #include <wrtsh.hxx>
29 :
30 : #include <basegfx/color/bcolortools.hxx>
31 : #include <basegfx/matrix/b2dhommatrixtools.hxx>
32 : #include <basegfx/polygon/b2dpolygon.hxx>
33 : #include <basegfx/polygon/b2dpolygontools.hxx>
34 : #include <basegfx/range/b2drectangle.hxx>
35 : #include <drawinglayer/primitive2d/discretebitmapprimitive2d.hxx>
36 : #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
37 : #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
38 : #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
39 : #include <drawinglayer/processor2d/processorfromoutputdevice.hxx>
40 : #include <editeng/formatbreakitem.hxx>
41 : #include <sfx2/dispatch.hxx>
42 : #include <svl/stritem.hxx>
43 : #include <vcl/svapp.hxx>
44 : #include <vcl/settings.hxx>
45 : #include <boost/scoped_ptr.hpp>
46 :
47 : #define BUTTON_WIDTH 30
48 : #define BUTTON_HEIGHT 19
49 : #define ARROW_WIDTH 9
50 :
51 : using namespace basegfx;
52 : using namespace basegfx::tools;
53 :
54 : namespace
55 : {
56 856 : class SwBreakDashedLine : public SwDashedLine
57 : {
58 : private:
59 : SwPageBreakWin* m_pWin;
60 :
61 : public:
62 428 : SwBreakDashedLine( vcl::Window* pParent, Color& ( *pColorFn )(), SwPageBreakWin* pWin ) :
63 : SwDashedLine( pParent, pColorFn ),
64 428 : m_pWin( pWin ) {};
65 :
66 : virtual void MouseMove( const MouseEvent& rMEvt ) SAL_OVERRIDE;
67 : };
68 :
69 0 : void SwBreakDashedLine::MouseMove( const MouseEvent& rMEvt )
70 : {
71 0 : if ( rMEvt.IsLeaveWindow() )
72 : {
73 : // don't fade if we just move to the 'button'
74 0 : Point aEventPos( GetPosPixel() + rMEvt.GetPosPixel() );
75 0 : if ( !m_pWin->Contains( aEventPos ) || !m_pWin->IsVisible() )
76 0 : m_pWin->Fade( false );
77 : }
78 0 : else if ( !m_pWin->IsVisible() )
79 : {
80 0 : m_pWin->Fade( true );
81 : }
82 :
83 0 : if ( !rMEvt.IsSynthetic() && !m_pWin->IsVisible() )
84 : {
85 0 : Point* pPtr = new Point( rMEvt.GetPosPixel() );
86 0 : m_pWin->UpdatePosition( pPtr );
87 : }
88 0 : }
89 : }
90 :
91 428 : SwPageBreakWin::SwPageBreakWin( SwEditWin* pEditWin, const SwPageFrm* pPageFrm ) :
92 : MenuButton( pEditWin, WB_DIALOGCONTROL ),
93 : SwFrameControl( pEditWin, pPageFrm ),
94 : m_pPopupMenu( NULL ),
95 : m_pLine( NULL ),
96 : m_bIsAppearing( false ),
97 : m_nFadeRate( 100 ),
98 : m_nDelayAppearing( 0 ),
99 : m_bDestroyed( false ),
100 428 : m_pMousePt( NULL )
101 : {
102 : // Use pixels for the rest of the drawing
103 428 : SetMapMode( MapMode ( MAP_PIXEL ) );
104 :
105 : // Create the line control
106 428 : m_pLine = new SwBreakDashedLine( GetEditWin(), &SwViewOption::GetPageBreakColor, this );
107 :
108 : // Create the popup menu
109 428 : m_pPopupMenu = new PopupMenu( SW_RES( MN_PAGEBREAK_BUTTON ) );
110 428 : m_pPopupMenu->SetDeactivateHdl( LINK( this, SwPageBreakWin, HideHandler ) );
111 428 : SetPopupMenu( m_pPopupMenu );
112 :
113 428 : m_aFadeTimer.SetTimeout( 50 );
114 428 : m_aFadeTimer.SetTimeoutHdl( LINK( this, SwPageBreakWin, FadeHandler ) );
115 428 : }
116 :
117 1284 : SwPageBreakWin::~SwPageBreakWin( )
118 : {
119 428 : m_bDestroyed = true;
120 428 : m_aFadeTimer.Stop();
121 :
122 428 : delete m_pPopupMenu;
123 428 : delete m_pLine;
124 428 : delete m_pMousePt;
125 856 : }
126 :
127 0 : void SwPageBreakWin::Paint( const Rectangle& )
128 : {
129 0 : const Rectangle aRect( Rectangle( Point( 0, 0 ), PixelToLogic( GetSizePixel() ) ) );
130 :
131 : // Properly paint the control
132 0 : BColor aColor = SwViewOption::GetPageBreakColor().getBColor();
133 :
134 0 : BColor aHslLine = rgb2hsl( aColor );
135 0 : double nLuminance = aHslLine.getZ();
136 0 : nLuminance += ( 1.0 - nLuminance ) * 0.75;
137 0 : if ( aHslLine.getZ() > 0.7 )
138 0 : nLuminance = aHslLine.getZ() * 0.7;
139 0 : aHslLine.setZ( nLuminance );
140 0 : BColor aOtherColor = hsl2rgb( aHslLine );
141 :
142 0 : const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
143 0 : if ( rSettings.GetHighContrastMode( ) )
144 : {
145 0 : aColor = rSettings.GetDialogTextColor().getBColor();
146 0 : aOtherColor = rSettings.GetDialogColor( ).getBColor();
147 : }
148 :
149 0 : bool bRtl = Application::GetSettings().GetLayoutRTL();
150 :
151 0 : drawinglayer::primitive2d::Primitive2DSequence aSeq( 3 );
152 0 : B2DRectangle aBRect( double( aRect.Left() ), double( aRect.Top( ) ),
153 0 : double( aRect.Right() ), double( aRect.Bottom( ) ) );
154 0 : B2DPolygon aPolygon = createPolygonFromRect( aBRect, 3.0 / BUTTON_WIDTH, 3.0 / BUTTON_HEIGHT );
155 :
156 : // Create the polygon primitives
157 0 : aSeq[0] = Primitive2DReference( new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
158 0 : B2DPolyPolygon( aPolygon ), aOtherColor ) );
159 0 : aSeq[1] = Primitive2DReference( new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
160 0 : aPolygon, aColor ) );
161 :
162 : // Create the primitive for the image
163 0 : Image aImg( SW_RES( IMG_PAGE_BREAK ) );
164 0 : double nImgOfstX = 3.0;
165 0 : if ( bRtl )
166 0 : nImgOfstX = aRect.Right() - aImg.GetSizePixel().Width() - 3.0;
167 0 : aSeq[2] = Primitive2DReference( new drawinglayer::primitive2d::DiscreteBitmapPrimitive2D(
168 0 : aImg.GetBitmapEx(), B2DPoint( nImgOfstX, 1.0 ) ) );
169 :
170 0 : double nTop = double( aRect.getHeight() ) / 2.0;
171 0 : double nBottom = nTop + 4.0;
172 0 : double nLeft = aRect.getWidth( ) - ARROW_WIDTH - 6.0;
173 0 : if ( bRtl )
174 0 : nLeft = ARROW_WIDTH - 2.0;
175 0 : double nRight = nLeft + 8.0;
176 :
177 0 : B2DPolygon aTriangle;
178 0 : aTriangle.append( B2DPoint( nLeft, nTop ) );
179 0 : aTriangle.append( B2DPoint( nRight, nTop ) );
180 0 : aTriangle.append( B2DPoint( ( nLeft + nRight ) / 2.0, nBottom ) );
181 0 : aTriangle.setClosed( true );
182 :
183 0 : BColor aTriangleColor = Color( COL_BLACK ).getBColor( );
184 0 : if ( Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
185 0 : aTriangleColor = Color( COL_WHITE ).getBColor( );
186 :
187 0 : aSeq.realloc( aSeq.getLength() + 1 );
188 0 : aSeq[ aSeq.getLength() - 1 ] = Primitive2DReference( new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
189 0 : B2DPolyPolygon( aTriangle ), aTriangleColor ) );
190 :
191 0 : Primitive2DSequence aGhostedSeq( 1 );
192 0 : double nFadeRate = double( m_nFadeRate ) / 100.0;
193 : const basegfx::BColorModifierSharedPtr aBColorModifier(
194 : new basegfx::BColorModifier_interpolate(
195 : Color( COL_WHITE ).getBColor(),
196 0 : 1.0 - nFadeRate));
197 0 : aGhostedSeq[0] = Primitive2DReference( new drawinglayer::primitive2d::ModifiedColorPrimitive2D(
198 0 : aSeq, aBColorModifier ) );
199 :
200 : // Create the processor and process the primitives
201 0 : const drawinglayer::geometry::ViewInformation2D aNewViewInfos;
202 : boost::scoped_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(
203 : drawinglayer::processor2d::createBaseProcessor2DFromOutputDevice(
204 0 : *this, aNewViewInfos ));
205 :
206 0 : pProcessor->process( aGhostedSeq );
207 0 : }
208 :
209 0 : void SwPageBreakWin::Select( )
210 : {
211 0 : SwFrameControlPtr pThis = GetEditWin()->GetFrameControlsManager( ).GetControl( PageBreak, GetFrame() );
212 :
213 0 : switch( GetCurItemId( ) )
214 : {
215 : case FN_PAGEBREAK_EDIT:
216 : {
217 0 : const SwLayoutFrm* pBodyFrm = static_cast< const SwLayoutFrm* >( GetPageFrame()->Lower() );
218 0 : while ( pBodyFrm && !pBodyFrm->IsBodyFrm() )
219 0 : pBodyFrm = static_cast< const SwLayoutFrm* >( pBodyFrm->GetNext() );
220 :
221 0 : SwEditWin* pEditWin = GetEditWin();
222 :
223 0 : if ( pBodyFrm )
224 : {
225 0 : SwWrtShell& rSh = pEditWin->GetView().GetWrtShell();
226 0 : bool bOldLock = rSh.IsViewLocked();
227 0 : rSh.LockView( true );
228 :
229 0 : if ( pBodyFrm->Lower()->IsTabFrm() )
230 : {
231 0 : rSh.Push( );
232 0 : rSh.ClearMark();
233 :
234 0 : SwCntntFrm *pCnt = const_cast< SwCntntFrm* >( pBodyFrm->ContainsCntnt() );
235 0 : SwCntntNode* pNd = pCnt->GetNode();
236 0 : rSh.SetSelection( *pNd );
237 :
238 0 : SfxStringItem aItem(pEditWin->GetView().GetPool().GetWhich(FN_FORMAT_TABLE_DLG), "textflow");
239 0 : pEditWin->GetView().GetViewFrame()->GetDispatcher()->Execute(
240 0 : FN_FORMAT_TABLE_DLG, SfxCallMode::SYNCHRON|SfxCallMode::RECORD, &aItem, NULL );
241 :
242 0 : rSh.Pop( false );
243 : }
244 : else
245 : {
246 0 : SwCntntFrm *pCnt = const_cast< SwCntntFrm* >( pBodyFrm->ContainsCntnt() );
247 0 : SwCntntNode* pNd = pCnt->GetNode();
248 :
249 0 : SwPaM aPaM( *pNd );
250 0 : SwPaMItem aPaMItem( pEditWin->GetView().GetPool( ).GetWhich( FN_PARAM_PAM ), &aPaM );
251 0 : SfxStringItem aItem( pEditWin->GetView().GetPool( ).GetWhich( SID_PARA_DLG ), "textflow" );
252 0 : pEditWin->GetView().GetViewFrame()->GetDispatcher()->Execute(
253 0 : SID_PARA_DLG, SfxCallMode::SYNCHRON|SfxCallMode::RECORD, &aItem, &aPaMItem, NULL );
254 : }
255 0 : rSh.LockView( bOldLock );
256 0 : pEditWin->GrabFocus( );
257 : }
258 : }
259 0 : break;
260 : case FN_PAGEBREAK_DELETE:
261 : {
262 0 : const SwLayoutFrm* pBodyFrm = static_cast< const SwLayoutFrm* >( GetPageFrame()->Lower() );
263 0 : while ( pBodyFrm && !pBodyFrm->IsBodyFrm() )
264 0 : pBodyFrm = static_cast< const SwLayoutFrm* >( pBodyFrm->GetNext() );
265 :
266 0 : if ( pBodyFrm )
267 : {
268 0 : SwCntntFrm *pCnt = const_cast< SwCntntFrm* >( pBodyFrm->ContainsCntnt() );
269 0 : SwCntntNode* pNd = pCnt->GetNode();
270 :
271 0 : pNd->GetDoc()->GetIDocumentUndoRedo( ).StartUndo( UNDO_UI_DELETE_PAGE_BREAK, NULL );
272 :
273 0 : SfxItemSet aSet( GetEditWin()->GetView().GetWrtShell().GetAttrPool(),
274 : RES_PAGEDESC, RES_PAGEDESC,
275 : RES_BREAK, RES_BREAK,
276 0 : NULL );
277 0 : aSet.Put( SvxFmtBreakItem( SVX_BREAK_NONE, RES_BREAK ) );
278 0 : aSet.Put( SwFmtPageDesc( NULL ) );
279 :
280 0 : SwPaM aPaM( *pNd );
281 0 : pNd->GetDoc()->getIDocumentContentOperations().InsertItemSet( aPaM, aSet, nsSetAttrMode::SETATTR_DEFAULT );
282 :
283 0 : pNd->GetDoc()->GetIDocumentUndoRedo( ).EndUndo( UNDO_UI_DELETE_PAGE_BREAK, NULL );
284 : }
285 : }
286 0 : break;
287 : }
288 :
289 : // Only fade if there is more than this temporary shared pointer:
290 : // The main reference has been deleted due to a page break removal
291 0 : if ( pThis.use_count() > 1 )
292 0 : Fade( false );
293 0 : }
294 :
295 0 : void SwPageBreakWin::MouseMove( const MouseEvent& rMEvt )
296 : {
297 0 : if ( rMEvt.IsLeaveWindow() )
298 : {
299 : // don't fade if we just move to the 'line', or the popup menu is open
300 0 : Point aEventPos( rMEvt.GetPosPixel() + rMEvt.GetPosPixel() );
301 0 : if ( !Contains( aEventPos ) && !PopupMenu::IsInExecute() )
302 0 : Fade( false );
303 : }
304 0 : else if ( !IsVisible() )
305 0 : Fade( true );
306 0 : }
307 :
308 0 : void SwPageBreakWin::Activate( )
309 : {
310 0 : Fade( true );
311 0 : MenuButton::Activate();
312 0 : }
313 :
314 572 : void SwPageBreakWin::UpdatePosition( const Point* pEvtPt )
315 : {
316 572 : if ( pEvtPt != NULL )
317 : {
318 0 : if ( pEvtPt == m_pMousePt )
319 572 : return;
320 0 : delete m_pMousePt;
321 0 : m_pMousePt = pEvtPt;
322 : }
323 :
324 572 : const SwPageFrm* pPageFrm = GetPageFrame();
325 572 : const SwFrm* pPrevPage = pPageFrm;
326 616 : do
327 : {
328 616 : pPrevPage = pPrevPage->GetPrev();
329 : }
330 660 : while ( pPrevPage && ( ( pPrevPage->Frm().Top( ) == pPageFrm->Frm().Top( ) )
331 590 : || static_cast< const SwPageFrm* >( pPrevPage )->IsEmptyPage( ) ) );
332 :
333 572 : Rectangle aBoundRect = GetEditWin()->LogicToPixel( pPageFrm->GetBoundRect().SVRect() );
334 572 : Rectangle aFrmRect = GetEditWin()->LogicToPixel( pPageFrm->Frm().SVRect() );
335 :
336 572 : long nYLineOffset = ( aBoundRect.Top() + aFrmRect.Top() ) / 2;
337 572 : if ( pPrevPage )
338 : {
339 572 : Rectangle aPrevFrmRect = GetEditWin()->LogicToPixel( pPrevPage->Frm().SVRect() );
340 572 : nYLineOffset = ( aPrevFrmRect.Bottom() + aFrmRect.Top() ) / 2;
341 : }
342 :
343 : // Get the page + sidebar coords
344 572 : long nPgLeft = aFrmRect.Left();
345 572 : long nPgRight = aFrmRect.Right();
346 :
347 572 : unsigned long nSidebarWidth = 0;
348 572 : const SwPostItMgr* pPostItMngr = GetEditWin()->GetView().GetWrtShell().GetPostItMgr();
349 572 : if ( pPostItMngr && pPostItMngr->HasNotes() && pPostItMngr->ShowNotes() )
350 0 : nSidebarWidth = pPostItMngr->GetSidebarBorderWidth( true ) + pPostItMngr->GetSidebarWidth( true );
351 :
352 572 : if ( pPageFrm->SidebarPosition( ) == sw::sidebarwindows::SIDEBAR_LEFT )
353 6 : nPgLeft -= nSidebarWidth;
354 566 : else if ( pPageFrm->SidebarPosition( ) == sw::sidebarwindows::SIDEBAR_RIGHT )
355 566 : nPgRight += nSidebarWidth;
356 :
357 572 : Size aBtnSize( BUTTON_WIDTH + ARROW_WIDTH, BUTTON_HEIGHT );
358 :
359 : // Place the button on the left or right?
360 572 : Rectangle aVisArea = GetEditWin()->LogicToPixel( GetEditWin()->GetView().GetVisArea() );
361 :
362 572 : long nLineLeft = std::max( nPgLeft, aVisArea.Left() );
363 572 : long nLineRight = std::min( nPgRight, aVisArea.Right() );
364 572 : long nBtnLeft = nLineLeft;
365 :
366 572 : if ( m_pMousePt )
367 : {
368 0 : nBtnLeft = nLineLeft + m_pMousePt->X() - aBtnSize.getWidth() / 2;
369 :
370 0 : if ( nBtnLeft < nLineLeft )
371 0 : nBtnLeft = nLineLeft;
372 0 : else if ( ( nBtnLeft + aBtnSize.getWidth() ) > nLineRight )
373 0 : nBtnLeft = nLineRight - aBtnSize.getWidth();
374 : }
375 :
376 : // Set the button position
377 572 : Point aBtnPos( nBtnLeft, nYLineOffset - BUTTON_HEIGHT / 2 );
378 572 : SetPosSizePixel( aBtnPos, aBtnSize );
379 :
380 : // Set the line position
381 572 : Point aLinePos( nLineLeft, nYLineOffset - 5 );
382 572 : Size aLineSize( nLineRight - nLineLeft, 10 );
383 572 : m_pLine->SetPosSizePixel( aLinePos, aLineSize );
384 : }
385 :
386 1008 : void SwPageBreakWin::ShowAll( bool bShow )
387 : {
388 1008 : m_pLine->Show( bShow );
389 1008 : }
390 :
391 0 : bool SwPageBreakWin::Contains( const Point &rDocPt ) const
392 : {
393 0 : Rectangle aRect( GetPosPixel(), GetSizePixel() );
394 0 : if ( aRect.IsInside( rDocPt ) )
395 0 : return true;
396 :
397 0 : Rectangle aLineRect( m_pLine->GetPosPixel(), m_pLine->GetSizePixel() );
398 0 : if ( aLineRect.IsInside( rDocPt ) )
399 0 : return true;
400 :
401 0 : return false;
402 : }
403 :
404 572 : const SwPageFrm* SwPageBreakWin::GetPageFrame( )
405 : {
406 572 : return static_cast< const SwPageFrm * >( GetFrame( ) );
407 : }
408 :
409 428 : void SwPageBreakWin::SetReadonly( bool bReadonly )
410 : {
411 428 : ShowAll( !bReadonly );
412 428 : }
413 :
414 0 : void SwPageBreakWin::Fade( bool bFadeIn )
415 : {
416 0 : m_bIsAppearing = bFadeIn;
417 0 : if ( bFadeIn )
418 0 : m_nDelayAppearing = 0;
419 :
420 0 : if ( !m_bDestroyed && m_aFadeTimer.IsActive( ) )
421 0 : m_aFadeTimer.Stop();
422 0 : if ( !m_bDestroyed )
423 0 : m_aFadeTimer.Start( );
424 0 : }
425 :
426 0 : IMPL_LINK_NOARG(SwPageBreakWin, HideHandler)
427 : {
428 0 : Fade( false );
429 :
430 0 : return 0;
431 : }
432 :
433 0 : IMPL_LINK_NOARG(SwPageBreakWin, FadeHandler)
434 : {
435 0 : const int TICKS_BEFORE_WE_APPEAR = 10;
436 0 : if ( m_bIsAppearing && m_nDelayAppearing < TICKS_BEFORE_WE_APPEAR )
437 : {
438 0 : ++m_nDelayAppearing;
439 0 : m_aFadeTimer.Start();
440 0 : return 0;
441 : }
442 :
443 0 : if ( m_bIsAppearing && m_nFadeRate > 0 )
444 0 : m_nFadeRate -= 25;
445 0 : else if ( !m_bIsAppearing && m_nFadeRate < 100 )
446 0 : m_nFadeRate += 25;
447 :
448 0 : if ( m_nFadeRate != 100 && !IsVisible() )
449 0 : Show();
450 0 : else if ( m_nFadeRate == 100 && IsVisible( ) )
451 0 : Hide();
452 : else
453 : {
454 0 : UpdatePosition();
455 0 : Invalidate();
456 : }
457 :
458 0 : if ( IsVisible( ) && m_nFadeRate > 0 && m_nFadeRate < 100 )
459 0 : m_aFadeTimer.Start();
460 :
461 0 : return 0;
462 270 : }
463 :
464 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|