1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <svl/itempool.hxx>
21 #include <vcl/dialog.hxx>
22 #include <vcl/wrkwin.hxx>
23 #include <vcl/settings.hxx>
24 #include <vcl/builderfactory.hxx>
25 #include <unotools/syslocale.hxx>
26 #include <rtl/math.hxx>
27 #include <unotools/localedatawrapper.hxx>
28 #include <comphelper/processfactory.hxx>
29 #include <vcl/svapp.hxx>
30 #include <osl/mutex.hxx>
32 #include <svx/graphctl.hxx>
33 #include "GraphCtlAccessibleContext.hxx"
34 #include "svx/xoutbmp.hxx"
35 #include <svx/svxids.hrc>
36 #include <svx/svdpage.hxx>
37 #include "svx/sdrpaintwindow.hxx"
39 void GraphCtrlUserCall::Changed( const SdrObject
& rObj
, SdrUserCallType eType
, const Rectangle
& /*rOldBoundRect*/ )
43 case( SDRUSERCALL_MOVEONLY
):
44 case( SDRUSERCALL_RESIZE
):
45 rWin
.SdrObjChanged( rObj
);
48 case( SDRUSERCALL_INSERTED
):
49 rWin
.SdrObjCreated( rObj
);
57 GraphCtrl::GraphCtrl( vcl::Window
* pParent
, WinBits nStyle
) :
58 Control ( pParent
, nStyle
),
59 aMap100 ( MAP_100TH_MM
),
61 eObjKind ( OBJ_NONE
),
66 mpAccContext ( NULL
),
70 pUserCall
= new GraphCtrlUserCall( *this );
71 aUpdateIdle
.SetPriority( SchedulerPriority::LOWEST
);
72 aUpdateIdle
.SetIdleHdl( LINK( this, GraphCtrl
, UpdateHdl
) );
77 VCL_BUILDER_DECL_FACTORY(GraphCtrl
)
79 WinBits nWinStyle
= 0;
80 OString sBorder
= VclBuilder::extractCustomProperty(rMap
);
81 if (!sBorder
.isEmpty())
82 nWinStyle
|= WB_BORDER
;
83 rRet
= VclPtr
<GraphCtrl
>::Create(pParent
, nWinStyle
);
86 GraphCtrl::~GraphCtrl()
91 void GraphCtrl::dispose()
95 mpAccContext
->disposing();
96 mpAccContext
->release();
104 void GraphCtrl::SetWinStyle( WinBits nWinBits
)
106 nWinStyle
= nWinBits
;
107 bAnim
= ( nWinStyle
& WB_ANIMATION
) == WB_ANIMATION
;
108 bSdrMode
= ( nWinStyle
& WB_SDRMODE
) == WB_SDRMODE
;
110 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
111 SetBackground( Wallpaper( rStyleSettings
.GetWindowColor() ) );
112 SetMapMode( aMap100
);
124 void GraphCtrl::InitSdrModel()
126 SolarMutexGuard aGuard
;
135 pModel
= new SdrModel
;
136 pModel
->GetItemPool().FreezeIdRanges();
137 pModel
->SetScaleUnit( aMap100
.GetMapUnit() );
138 pModel
->SetScaleFraction( Fraction( 1, 1 ) );
139 pModel
->SetDefaultFontHeight( 500 );
141 pPage
= new SdrPage( *pModel
);
143 pPage
->SetSize( aGraphSize
);
144 pPage
->SetBorder( 0, 0, 0, 0 );
145 pModel
->InsertPage( pPage
);
146 pModel
->SetChanged( false );
149 pView
= new GraphCtrlView( pModel
, this );
150 pView
->SetWorkArea( Rectangle( Point(), aGraphSize
) );
151 pView
->EnableExtendedMouseEventDispatcher( true );
152 pView
->ShowSdrPage(pView
->GetModel()->GetPage(0));
153 pView
->SetFrameDragSingles( true );
154 pView
->SetMarkedPointsSmooth( SDRPATHSMOOTH_SYMMETRIC
);
155 pView
->SetEditMode( true );
157 // #i72889# set neeeded flags
158 pView
->SetPagePaintingAllowed(false);
159 pView
->SetBufferedOutputAllowed(true);
160 pView
->SetBufferedOverlayAllowed(true);
162 // Tell the accessibility object about the changes.
163 if (mpAccContext
!= NULL
)
164 mpAccContext
->setModelAndView (pModel
, pView
);
167 void GraphCtrl::SetGraphic( const Graphic
& rGraphic
, bool bNewModel
)
169 // If possible we dither bitmaps for the display
170 if ( !bAnim
&& ( rGraphic
.GetType() == GRAPHIC_BITMAP
) )
172 if ( rGraphic
.IsTransparent() )
174 Bitmap
aBmp( rGraphic
.GetBitmap() );
176 DitherBitmap( aBmp
);
177 aGraphic
= Graphic( BitmapEx( aBmp
, rGraphic
.GetBitmapEx().GetMask() ) );
181 Bitmap
aBmp( rGraphic
.GetBitmap() );
182 DitherBitmap( aBmp
);
189 if ( aGraphic
.GetPrefMapMode().GetMapUnit() == MAP_PIXEL
)
190 aGraphSize
= Application::GetDefaultDevice()->PixelToLogic( aGraphic
.GetPrefSize(), aMap100
);
192 aGraphSize
= OutputDevice::LogicToLogic( aGraphic
.GetPrefSize(), aGraphic
.GetPrefMapMode(), aMap100
);
194 if ( bSdrMode
&& bNewModel
)
197 if ( aGraphSizeLink
.IsSet() )
198 aGraphSizeLink
.Call( this );
204 void GraphCtrl::Resize()
208 if ( aGraphSize
.Width() && aGraphSize
.Height() )
210 MapMode
aDisplayMap( aMap100
);
213 const Size aWinSize
= PixelToLogic( GetOutputSizePixel(), aDisplayMap
);
214 const long nWidth
= aWinSize
.Width();
215 const long nHeight
= aWinSize
.Height();
216 double fGrfWH
= (double) aGraphSize
.Width() / aGraphSize
.Height();
217 double fWinWH
= (double) nWidth
/ nHeight
;
219 // Adapt Bitmap to Thumb size
220 if ( fGrfWH
< fWinWH
)
222 aNewSize
.Width() = (long) ( (double) nHeight
* fGrfWH
);
223 aNewSize
.Height()= nHeight
;
227 aNewSize
.Width() = nWidth
;
228 aNewSize
.Height()= (long) ( (double) nWidth
/ fGrfWH
);
231 aNewPos
.X() = ( nWidth
- aNewSize
.Width() ) >> 1;
232 aNewPos
.Y() = ( nHeight
- aNewSize
.Height() ) >> 1;
234 // Implementing MapMode for Engine
235 aDisplayMap
.SetScaleX( Fraction( aNewSize
.Width(), aGraphSize
.Width() ) );
236 aDisplayMap
.SetScaleY( Fraction( aNewSize
.Height(), aGraphSize
.Height() ) );
238 aDisplayMap
.SetOrigin( LogicToLogic( aNewPos
, aMap100
, aDisplayMap
) );
239 SetMapMode( aDisplayMap
);
245 void GraphCtrl::Paint( vcl::RenderContext
& rRenderContext
, const Rectangle
& rRect
)
247 // #i72889# used splitted repaint to be able to paint an own background
248 // even to the buffered view
249 const bool bGraphicValid(GRAPHIC_NONE
!= aGraphic
.GetType());
253 SdrPaintWindow
* pPaintWindow
= pView
->BeginCompleteRedraw(&rRenderContext
);
257 vcl::RenderContext
& rTarget
= pPaintWindow
->GetTargetOutputDevice();
259 rTarget
.SetBackground(GetBackground());
262 aGraphic
.Draw(&rTarget
, Point(), aGraphSize
);
265 const vcl::Region
aRepaintRegion(rRect
);
266 pView
->DoCompleteRedraw(*pPaintWindow
, aRepaintRegion
);
267 pView
->EndCompleteRedraw(*pPaintWindow
, true);
271 // #i73381# in non-SdrMode, paint to local directly
274 aGraphic
.Draw(&rRenderContext
, Point(), aGraphSize
);
279 void GraphCtrl::SdrObjChanged( const SdrObject
& )
283 void GraphCtrl::SdrObjCreated( const SdrObject
& )
287 void GraphCtrl::MarkListHasChanged()
289 if ( aMarkObjLink
.IsSet() )
290 aMarkObjLink
.Call( this );
293 void GraphCtrl::KeyInput( const KeyEvent
& rKEvt
)
295 vcl::KeyCode
aCode( rKEvt
.GetKeyCode() );
298 Dialog
* pDialog
= GetParentDialog();
300 switch ( aCode
.GetCode() )
307 pView
->DeleteMarked();
309 if (!pView
->AreObjectsMarked() && pDialog
)
310 pDialog
->GrabFocusToFirstControl();
319 bool bGrabFocusToFirstControl
= true;
320 if ( pView
->IsAction() )
323 bGrabFocusToFirstControl
= false;
325 else if ( pView
->AreObjectsMarked() )
327 const SdrHdlList
& rHdlList
= pView
->GetHdlList();
328 SdrHdl
* pHdl
= rHdlList
.GetFocusHdl();
332 ((SdrHdlList
&)rHdlList
).ResetFocusHdl();
333 bGrabFocusToFirstControl
= false;
336 if (bGrabFocusToFirstControl
&& pDialog
)
337 pDialog
->GrabFocusToFirstControl();
348 if( !aCode
.IsMod1() && !aCode
.IsMod2() )
350 bool bForward
= !aCode
.IsShift();
351 // select next object
352 if ( ! pView
->MarkNextObj( bForward
))
354 // At first or last object. Cycle to the other end
356 pView
->UnmarkAllObj();
357 pView
->MarkNextObj (bForward
);
361 else if(aCode
.IsMod1())
363 // select next handle
364 const SdrHdlList
& rHdlList
= pView
->GetHdlList();
365 bool bForward(!aCode
.IsShift());
367 ((SdrHdlList
&)rHdlList
).TravelFocusHdl(bForward
);
378 if ( aCode
.IsMod1() )
381 pView
->UnmarkAllObj();
382 pView
->MarkNextObj(false);
391 if ( aCode
.IsMod1() )
393 pView
->UnmarkAllObj();
394 pView
->MarkNextObj(true);
409 if (aCode
.GetCode() == KEY_UP
)
415 else if (aCode
.GetCode() == KEY_DOWN
)
421 else if (aCode
.GetCode() == KEY_LEFT
)
427 else if (aCode
.GetCode() == KEY_RIGHT
)
434 if (pView
->AreObjectsMarked() && !aCode
.IsMod1() )
438 // move in 1 pixel distance
439 Size aLogicSizeOnePixel
= PixelToLogic(Size(1,1));
440 nX
*= aLogicSizeOnePixel
.Width();
441 nY
*= aLogicSizeOnePixel
.Height();
445 // old, fixed move distance
451 const SdrHdlList
& rHdlList
= pView
->GetHdlList();
452 SdrHdl
* pHdl
= rHdlList
.GetFocusHdl();
456 // restrict movement to WorkArea
457 const Rectangle
& rWorkArea
= pView
->GetWorkArea();
459 if(!rWorkArea
.IsEmpty())
461 Rectangle
aMarkRect(pView
->GetMarkedObjRect());
462 aMarkRect
.Move(nX
, nY
);
464 if(!aMarkRect
.IsInside(rWorkArea
))
466 if(aMarkRect
.Left() < rWorkArea
.Left())
468 nX
+= rWorkArea
.Left() - aMarkRect
.Left();
471 if(aMarkRect
.Right() > rWorkArea
.Right())
473 nX
-= aMarkRect
.Right() - rWorkArea
.Right();
476 if(aMarkRect
.Top() < rWorkArea
.Top())
478 nY
+= rWorkArea
.Top() - aMarkRect
.Top();
481 if(aMarkRect
.Bottom() > rWorkArea
.Bottom())
483 nY
-= aMarkRect
.Bottom() - rWorkArea
.Bottom();
488 // no handle selected
489 if(0 != nX
|| 0 != nY
)
491 pView
->MoveAllMarked(Size(nX
, nY
));
496 // move handle with index nHandleIndex
497 if(pHdl
&& (nX
|| nY
))
499 // now move the Handle (nX, nY)
500 Point
aStartPoint(pHdl
->GetPos());
501 Point
aEndPoint(pHdl
->GetPos() + Point(nX
, nY
));
502 const SdrDragStat
& rDragStat
= pView
->GetDragStat();
505 pView
->BegDragObj(aStartPoint
, 0, pHdl
, 0);
507 if(pView
->IsDragObj())
509 bool bWasNoSnap
= rDragStat
.IsNoSnap();
510 bool bWasSnapEnabled
= pView
->IsSnapEnabled();
512 // switch snapping off
514 ((SdrDragStat
&)rDragStat
).SetNoSnap(true);
516 pView
->SetSnapEnabled(false);
518 pView
->MovAction(aEndPoint
);
523 ((SdrDragStat
&)rDragStat
).SetNoSnap(bWasNoSnap
);
525 pView
->SetSnapEnabled(bWasSnapEnabled
);
537 const SdrHdlList
& rHdlList
= pView
->GetHdlList();
538 SdrHdl
* pHdl
= rHdlList
.GetFocusHdl();
542 if(pHdl
->GetKind() == HDL_POLY
)
544 // rescue ID of point with focus
545 sal_uInt32
nPol(pHdl
->GetPolyNum());
546 sal_uInt32
nPnt(pHdl
->GetPointNum());
548 if(pView
->IsPointMarked(*pHdl
))
550 if(rKEvt
.GetKeyCode().IsShift())
552 pView
->UnmarkPoint(*pHdl
);
557 if(!rKEvt
.GetKeyCode().IsShift())
559 pView
->UnmarkAllPoints();
562 pView
->MarkPoint(*pHdl
);
565 if(0L == rHdlList
.GetFocusHdl())
567 // restore point with focus
568 SdrHdl
* pNewOne
= 0L;
570 for(size_t a
= 0; !pNewOne
&& a
< rHdlList
.GetHdlCount(); ++a
)
572 SdrHdl
* pAct
= rHdlList
.GetHdl(a
);
575 && pAct
->GetKind() == HDL_POLY
576 && pAct
->GetPolyNum() == nPol
577 && pAct
->GetPointNum() == nPnt
)
585 ((SdrHdlList
&)rHdlList
).SetFocusHdl(pNewOne
);
600 Control::KeyInput( rKEvt
);
605 void GraphCtrl::MouseButtonDown( const MouseEvent
& rMEvt
)
607 if ( bSdrMode
&& ( rMEvt
.GetClicks() < 2 ) )
609 const Point
aLogPt( PixelToLogic( rMEvt
.GetPosPixel() ) );
611 if ( !Rectangle( Point(), aGraphSize
).IsInside( aLogPt
) && !pView
->IsEditMode() )
612 Control::MouseButtonDown( rMEvt
);
615 // Get Focus for key inputs
621 SdrHitKind eHit
= pView
->PickAnything( rMEvt
, SdrMouseEventKind::BUTTONDOWN
, aVEvt
);
623 if ( nPolyEdit
== SID_BEZIER_INSERT
&& eHit
== SDRHIT_MARKEDOBJECT
)
624 pView
->BegInsObjPoint( aLogPt
, rMEvt
.IsMod1());
626 pView
->MouseButtonDown( rMEvt
, this );
629 pView
->MouseButtonDown( rMEvt
, this );
632 SdrObject
* pCreateObj
= pView
->GetCreateObj();
634 // We want to realize the insert
635 if ( pCreateObj
&& !pCreateObj
->GetUserCall() )
636 pCreateObj
->SetUserCall( pUserCall
);
638 SetPointer( pView
->GetPreferredPointer( aLogPt
, this ) );
641 Control::MouseButtonDown( rMEvt
);
644 void GraphCtrl::MouseMove(const MouseEvent
& rMEvt
)
646 const Point
aLogPos( PixelToLogic( rMEvt
.GetPosPixel() ) );
650 pView
->MouseMove( rMEvt
, this );
652 if( ( SID_BEZIER_INSERT
== nPolyEdit
) &&
653 !pView
->PickHandle( aLogPos
) &&
654 !pView
->IsInsObjPoint() )
656 SetPointer( PointerStyle::Cross
);
659 SetPointer( pView
->GetPreferredPointer( aLogPos
, this ) );
662 Control::MouseButtonUp( rMEvt
);
664 if ( aMousePosLink
.IsSet() )
666 if ( Rectangle( Point(), aGraphSize
).IsInside( aLogPos
) )
671 aMousePosLink
.Call( this );
675 void GraphCtrl::MouseButtonUp(const MouseEvent
& rMEvt
)
679 if ( pView
->IsInsObjPoint() )
680 pView
->EndInsObjPoint( SDRCREATE_FORCEEND
);
682 pView
->MouseButtonUp( rMEvt
, this );
685 SetPointer( pView
->GetPreferredPointer( PixelToLogic( rMEvt
.GetPosPixel() ), this ) );
688 Control::MouseButtonUp( rMEvt
);
691 SdrObject
* GraphCtrl::GetSelectedSdrObject() const
693 SdrObject
* pSdrObj
= NULL
;
697 const SdrMarkList
& rMarkList
= pView
->GetMarkedObjectList();
699 if ( rMarkList
.GetMarkCount() == 1 )
700 pSdrObj
= rMarkList
.GetMark( 0 )->GetMarkedSdrObj();
706 void GraphCtrl::SetEditMode( const bool _bEditMode
)
710 bEditMode
= _bEditMode
;
711 pView
->SetEditMode( bEditMode
);
713 pView
->SetCurrentObj( sal::static_int_cast
< sal_uInt16
>( eObjKind
) );
719 void GraphCtrl::SetPolyEditMode( const sal_uInt16 _nPolyEdit
)
721 if ( bSdrMode
&& ( _nPolyEdit
!= nPolyEdit
) )
723 nPolyEdit
= _nPolyEdit
;
724 pView
->SetFrameDragSingles( nPolyEdit
== 0 );
730 void GraphCtrl::SetObjKind( const SdrObjKind _eObjKind
)
735 pView
->SetEditMode( bEditMode
);
736 eObjKind
= _eObjKind
;
737 pView
->SetCurrentObj( sal::static_int_cast
< sal_uInt16
>( eObjKind
) );
743 IMPL_LINK_TYPED( GraphCtrl
, UpdateHdl
, Idle
*, pTimer
, void )
745 if ( aUpdateLink
.IsSet() )
746 aUpdateLink
.Call( this );
752 ::com::sun::star::uno::Reference
< ::com::sun::star::accessibility::XAccessible
> GraphCtrl::CreateAccessible()
754 if( mpAccContext
== NULL
)
756 vcl::Window
* pParent
= GetParent();
758 DBG_ASSERT( pParent
, "-GraphCtrl::CreateAccessible(): No Parent!" );
762 ::com::sun::star::uno::Reference
< ::com::sun::star::accessibility::XAccessible
> xAccParent( pParent
->GetAccessible() );
764 // Disable accessibility if no model/view data available
769 mpAccContext
= new SvxGraphCtrlAccessibleContext( xAccParent
, *this );
770 mpAccContext
->acquire();
778 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */