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