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