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