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