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 <config_wasm_strip.h>
22 #include <svl/itempool.hxx>
23 #include <vcl/settings.hxx>
24 #include <vcl/ptrstyle.hxx>
25 #include <vcl/svapp.hxx>
27 #include <svx/graphctl.hxx>
28 #include <svx/sdr/overlay/overlaymanager.hxx>
29 #include <GraphCtlAccessibleContext.hxx>
30 #include <svx/svxids.hrc>
31 #include <svx/svdpage.hxx>
32 #include <svx/sdrpaintwindow.hxx>
34 void GraphCtrlUserCall::Changed( const SdrObject
& rObj
, SdrUserCallType eType
, const tools::Rectangle
& /*rOldBoundRect*/ )
38 case SdrUserCallType::MoveOnly
:
39 case SdrUserCallType::Resize
:
40 rWin
.SdrObjChanged( rObj
);
43 case SdrUserCallType::Inserted
:
44 rWin
.SdrObjCreated( rObj
);
50 rWin
.QueueIdleUpdate();
53 GraphCtrl::GraphCtrl(weld::Dialog
* pDialog
)
54 : aUpdateIdle("svx GraphCtrl Update")
55 , aMap100(MapUnit::Map100thMM
)
56 , eObjKind(SdrObjKind::NONE
)
60 , mbInIdleUpdate(false)
63 pUserCall
.reset(new GraphCtrlUserCall( *this ));
64 aUpdateIdle
.SetPriority( TaskPriority::LOWEST
);
65 aUpdateIdle
.SetInvokeHandler( LINK( this, GraphCtrl
, UpdateHdl
) );
69 void GraphCtrl::SetDrawingArea(weld::DrawingArea
* pDrawingArea
)
71 weld::CustomWidgetController::SetDrawingArea(pDrawingArea
);
75 GraphCtrl::~GraphCtrl()
79 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
80 if( mpAccContext
.is() )
82 mpAccContext
->disposing();
92 void GraphCtrl::SetSdrMode(bool bSdrMode
)
96 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
97 OutputDevice
& rDevice
= GetDrawingArea()->get_ref_device();
98 rDevice
.SetBackground( Wallpaper( rStyleSettings
.GetWindowColor() ) );
99 xVD
->SetBackground( Wallpaper( rStyleSettings
.GetWindowColor() ) );
100 rDevice
.SetMapMode( aMap100
);
101 xVD
->SetMapMode( aMap100
);
112 void GraphCtrl::InitSdrModel()
114 SolarMutexGuard aGuard
;
116 rtl::Reference
<SdrPage
> pPage
;
123 pModel
.reset(new SdrModel(nullptr, nullptr, true));
124 pModel
->SetScaleUnit(aMap100
.GetMapUnit());
125 pModel
->SetDefaultFontHeight( 500 );
127 pPage
= new SdrPage( *pModel
);
129 pPage
->SetSize( aGraphSize
);
130 pPage
->SetBorder( 0, 0, 0, 0 );
131 pModel
->InsertPage( pPage
.get() );
132 pModel
->SetChanged( false );
135 pView
.reset(new GraphCtrlView(*pModel
, this));
136 pView
->SetWorkArea( tools::Rectangle( Point(), aGraphSize
) );
137 pView
->EnableExtendedMouseEventDispatcher( true );
138 pView
->ShowSdrPage(pView
->GetModel().GetPage(0));
139 pView
->SetFrameDragSingles();
140 pView
->SetMarkedPointsSmooth( SdrPathSmoothKind::Symmetric
);
141 pView
->SetEditMode();
143 // #i72889# set needed flags
144 pView
->SetPageDecorationAllowed(false);
145 pView
->SetMasterPageVisualizationAllowed(false);
146 pView
->SetBufferedOutputAllowed(true);
147 pView
->SetBufferedOverlayAllowed(true);
149 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
150 // Tell the accessibility object about the changes.
151 if (mpAccContext
.is())
152 mpAccContext
->setModelAndView (pModel
.get(), pView
.get());
156 void GraphCtrl::SetGraphic( const Graphic
& rGraphic
, bool bNewModel
)
159 xVD
->SetOutputSizePixel(Size(0, 0)); //force redraw
161 if ( aGraphic
.GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel
)
162 aGraphSize
= Application::GetDefaultDevice()->PixelToLogic( aGraphic
.GetPrefSize(), aMap100
);
164 aGraphSize
= OutputDevice::LogicToLogic( aGraphic
.GetPrefSize(), aGraphic
.GetPrefMapMode(), aMap100
);
166 if ( mbSdrMode
&& bNewModel
)
169 aGraphSizeLink
.Call( this );
177 void GraphCtrl::GraphicToVD()
179 OutputDevice
& rDevice
= GetDrawingArea()->get_ref_device();
180 xVD
->SetOutputSizePixel(GetOutputSizePixel());
181 xVD
->SetBackground(rDevice
.GetBackground());
183 const bool bGraphicValid(GraphicType::NONE
!= aGraphic
.GetType());
185 aGraphic
.Draw(*xVD
, Point(), aGraphSize
);
188 void GraphCtrl::Resize()
190 weld::CustomWidgetController::Resize();
192 if (aGraphSize
.Width() && aGraphSize
.Height())
194 MapMode
aDisplayMap( aMap100
);
197 OutputDevice
& rDevice
= GetDrawingArea()->get_ref_device();
198 const Size aWinSize
= rDevice
.PixelToLogic( GetOutputSizePixel(), aDisplayMap
);
199 const tools::Long nWidth
= aWinSize
.Width();
200 const tools::Long nHeight
= aWinSize
.Height();
201 double fGrfWH
= static_cast<double>(aGraphSize
.Width()) / aGraphSize
.Height();
202 double fWinWH
= static_cast<double>(nWidth
) / nHeight
;
204 // Adapt Bitmap to Thumb size
205 if ( fGrfWH
< fWinWH
)
207 aNewSize
.setWidth( static_cast<tools::Long
>( static_cast<double>(nHeight
) * fGrfWH
) );
208 aNewSize
.setHeight( nHeight
);
212 aNewSize
.setWidth( nWidth
);
213 aNewSize
.setHeight( static_cast<tools::Long
>( static_cast<double>(nWidth
) / fGrfWH
) );
216 aNewPos
.setX( ( nWidth
- aNewSize
.Width() ) >> 1 );
217 aNewPos
.setY( ( nHeight
- aNewSize
.Height() ) >> 1 );
219 // Implementing MapMode for Engine
220 aDisplayMap
.SetScaleX( Fraction( aNewSize
.Width(), aGraphSize
.Width() ) );
221 aDisplayMap
.SetScaleY( Fraction( aNewSize
.Height(), aGraphSize
.Height() ) );
223 aDisplayMap
.SetOrigin( OutputDevice::LogicToLogic( aNewPos
, aMap100
, aDisplayMap
) );
224 rDevice
.SetMapMode( aDisplayMap
);
225 xVD
->SetMapMode( aDisplayMap
);
231 void GraphCtrl::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
)
233 // #i72889# used split repaint to be able to paint an own background
234 // even to the buffered view
235 const bool bGraphicValid(GraphicType::NONE
!= aGraphic
.GetType());
237 if (GetOutputSizePixel() != xVD
->GetOutputSizePixel())
242 SdrPaintWindow
* pPaintWindow
= pView
->BeginCompleteRedraw(&rRenderContext
);
243 pPaintWindow
->SetOutputToWindow(true);
247 vcl::RenderContext
& rTarget
= pPaintWindow
->GetTargetOutputDevice();
249 OutputDevice
& rDevice
= GetDrawingArea()->get_ref_device();
250 rTarget
.SetBackground(rDevice
.GetBackground());
253 rTarget
.DrawOutDev(Point(), xVD
->GetOutputSize(), Point(), xVD
->GetOutputSize(), *xVD
);
256 const vcl::Region
aRepaintRegion(rRect
);
257 pView
->DoCompleteRedraw(*pPaintWindow
, aRepaintRegion
);
258 pView
->EndCompleteRedraw(*pPaintWindow
, true);
262 // #i73381# in non-SdrMode, paint to local directly
263 rRenderContext
.DrawOutDev(rRect
.TopLeft(), rRect
.GetSize(),
264 rRect
.TopLeft(), rRect
.GetSize(),
269 void GraphCtrl::SdrObjChanged( const SdrObject
& )
274 void GraphCtrl::SdrObjCreated( const SdrObject
& )
279 void GraphCtrl::MarkListHasChanged()
284 bool GraphCtrl::KeyInput( const KeyEvent
& rKEvt
)
286 vcl::KeyCode
aCode( rKEvt
.GetKeyCode() );
289 OutputDevice
& rDevice
= GetDrawingArea()->get_ref_device();
291 switch ( aCode
.GetCode() )
298 pView
->DeleteMarked();
308 const SdrMarkList
& rMarkList
= pView
->GetMarkedObjectList();
309 if ( pView
->IsAction() )
314 else if ( rMarkList
.GetMarkCount() != 0 )
316 pView
->UnmarkAllObj();
328 if( !aCode
.IsMod1() && !aCode
.IsMod2() )
330 bool bForward
= !aCode
.IsShift();
331 // select next object
332 if ( ! pView
->MarkNextObj( bForward
))
334 // At first or last object. Cycle to the other end
336 pView
->UnmarkAllObj();
337 pView
->MarkNextObj (bForward
);
341 else if(aCode
.IsMod1())
343 // select next handle
344 const SdrHdlList
& rHdlList
= pView
->GetHdlList();
345 bool bForward(!aCode
.IsShift());
347 const_cast<SdrHdlList
&>(rHdlList
).TravelFocusHdl(bForward
);
358 if ( aCode
.IsMod1() )
361 pView
->UnmarkAllObj();
362 pView
->MarkNextObj();
371 if ( aCode
.IsMod1() )
373 pView
->UnmarkAllObj();
374 pView
->MarkNextObj(true);
389 if (aCode
.GetCode() == KEY_UP
)
395 else if (aCode
.GetCode() == KEY_DOWN
)
401 else if (aCode
.GetCode() == KEY_LEFT
)
407 else if (aCode
.GetCode() == KEY_RIGHT
)
414 const SdrMarkList
& rMarkList
= pView
->GetMarkedObjectList();
415 if (rMarkList
.GetMarkCount() != 0 && !aCode
.IsMod1() )
419 // move in 1 pixel distance
420 Size aLogicSizeOnePixel
= rDevice
.PixelToLogic(Size(1,1));
421 nX
*= aLogicSizeOnePixel
.Width();
422 nY
*= aLogicSizeOnePixel
.Height();
426 // old, fixed move distance
432 const SdrHdlList
& rHdlList
= pView
->GetHdlList();
433 SdrHdl
* pHdl
= rHdlList
.GetFocusHdl();
437 // restrict movement to WorkArea
438 const tools::Rectangle
& rWorkArea
= pView
->GetWorkArea();
440 if(!rWorkArea
.IsEmpty())
442 tools::Rectangle
aMarkRect(pView
->GetMarkedObjRect());
443 aMarkRect
.Move(nX
, nY
);
445 if(!aMarkRect
.Contains(rWorkArea
))
447 if(aMarkRect
.Left() < rWorkArea
.Left())
449 nX
+= rWorkArea
.Left() - aMarkRect
.Left();
452 if(aMarkRect
.Right() > rWorkArea
.Right())
454 nX
-= aMarkRect
.Right() - rWorkArea
.Right();
457 if(aMarkRect
.Top() < rWorkArea
.Top())
459 nY
+= rWorkArea
.Top() - aMarkRect
.Top();
462 if(aMarkRect
.Bottom() > rWorkArea
.Bottom())
464 nY
-= aMarkRect
.Bottom() - rWorkArea
.Bottom();
469 // no handle selected
470 if(0 != nX
|| 0 != nY
)
472 pView
->MoveAllMarked(Size(nX
, nY
));
477 // move handle with index nHandleIndex
480 // now move the Handle (nX, nY)
481 Point
aStartPoint(pHdl
->GetPos());
482 Point
aEndPoint(pHdl
->GetPos() + Point(nX
, nY
));
483 const SdrDragStat
& rDragStat
= pView
->GetDragStat();
486 pView
->BegDragObj(aStartPoint
, nullptr, pHdl
, 0);
488 if(pView
->IsDragObj())
490 bool bWasNoSnap
= rDragStat
.IsNoSnap();
491 bool bWasSnapEnabled
= pView
->IsSnapEnabled();
493 // switch snapping off
495 const_cast<SdrDragStat
&>(rDragStat
).SetNoSnap();
497 pView
->SetSnapEnabled(false);
499 pView
->MovAction(aEndPoint
);
504 const_cast<SdrDragStat
&>(rDragStat
).SetNoSnap(bWasNoSnap
);
506 pView
->SetSnapEnabled(bWasSnapEnabled
);
518 const SdrHdlList
& rHdlList
= pView
->GetHdlList();
519 SdrHdl
* pHdl
= rHdlList
.GetFocusHdl();
523 if(pHdl
->GetKind() == SdrHdlKind::Poly
)
525 // rescue ID of point with focus
526 sal_uInt32
nPol(pHdl
->GetPolyNum());
527 sal_uInt32
nPnt(pHdl
->GetPointNum());
529 if(pView
->IsPointMarked(*pHdl
))
531 if(rKEvt
.GetKeyCode().IsShift())
533 pView
->UnmarkPoint(*pHdl
);
538 if(!rKEvt
.GetKeyCode().IsShift())
540 pView
->UnmarkAllPoints();
543 pView
->MarkPoint(*pHdl
);
546 if(nullptr == rHdlList
.GetFocusHdl())
548 // restore point with focus
549 SdrHdl
* pNewOne
= nullptr;
551 for(size_t a
= 0; !pNewOne
&& a
< rHdlList
.GetHdlCount(); ++a
)
553 SdrHdl
* pAct
= rHdlList
.GetHdl(a
);
556 && pAct
->GetKind() == SdrHdlKind::Poly
557 && pAct
->GetPolyNum() == nPol
558 && pAct
->GetPointNum() == nPnt
)
566 const_cast<SdrHdlList
&>(rHdlList
).SetFocusHdl(pNewOne
);
588 bool GraphCtrl::MouseButtonDown( const MouseEvent
& rMEvt
)
590 if ( mbSdrMode
&& ( rMEvt
.GetClicks() < 2 ) )
592 OutputDevice
& rDevice
= GetDrawingArea()->get_ref_device();
594 const Point
aLogPt( rDevice
.PixelToLogic( rMEvt
.GetPosPixel() ) );
596 if ( !tools::Rectangle( Point(), aGraphSize
).Contains( aLogPt
) && !pView
->IsEditMode() )
597 weld::CustomWidgetController::MouseButtonDown( rMEvt
);
600 // Get Focus for key inputs
606 SdrHitKind eHit
= pView
->PickAnything( rMEvt
, SdrMouseEventKind::BUTTONDOWN
, aVEvt
);
608 if ( nPolyEdit
== SID_BEZIER_INSERT
&& eHit
== SdrHitKind::MarkedObject
)
609 pView
->BegInsObjPoint( aLogPt
, rMEvt
.IsMod1());
611 pView
->MouseButtonDown( rMEvt
, &rDevice
);
614 pView
->MouseButtonDown( rMEvt
, &rDevice
);
617 SdrObject
* pCreateObj
= pView
->GetCreateObj();
619 // We want to realize the insert
620 if ( pCreateObj
&& !pCreateObj
->GetUserCall() )
621 pCreateObj
->SetUserCall( pUserCall
.get() );
623 SetPointer( pView
->GetPreferredPointer( aLogPt
, &rDevice
) );
626 weld::CustomWidgetController::MouseButtonDown( rMEvt
);
633 bool GraphCtrl::MouseMove(const MouseEvent
& rMEvt
)
635 OutputDevice
& rDevice
= GetDrawingArea()->get_ref_device();
636 const Point
aLogPos( rDevice
.PixelToLogic( rMEvt
.GetPosPixel() ) );
640 pView
->MouseMove( rMEvt
, &rDevice
);
642 if( ( SID_BEZIER_INSERT
== nPolyEdit
) &&
643 !pView
->PickHandle( aLogPos
) &&
644 !pView
->IsInsObjPoint() )
646 SetPointer( PointerStyle::Cross
);
649 SetPointer( pView
->GetPreferredPointer( aLogPos
, &rDevice
) );
652 weld::CustomWidgetController::MouseButtonUp( rMEvt
);
654 if ( aMousePosLink
.IsSet() )
656 if ( tools::Rectangle( Point(), aGraphSize
).Contains( aLogPos
) )
661 aMousePosLink
.Call( this );
669 bool GraphCtrl::MouseButtonUp(const MouseEvent
& rMEvt
)
673 OutputDevice
& rDevice
= GetDrawingArea()->get_ref_device();
675 if ( pView
->IsInsObjPoint() )
676 pView
->EndInsObjPoint( SdrCreateCmd::ForceEnd
);
678 pView
->MouseButtonUp( rMEvt
, &rDevice
);
681 SetPointer( pView
->GetPreferredPointer( rDevice
.PixelToLogic( rMEvt
.GetPosPixel() ), &rDevice
) );
684 weld::CustomWidgetController::MouseButtonUp( rMEvt
);
691 SdrObject
* GraphCtrl::GetSelectedSdrObject() const
693 SdrObject
* pSdrObj
= nullptr;
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
);
712 eObjKind
= SdrObjKind::NONE
;
713 pView
->SetCurrentObj(eObjKind
);
721 void GraphCtrl::SetPolyEditMode( const sal_uInt16 _nPolyEdit
)
723 if ( mbSdrMode
&& ( _nPolyEdit
!= nPolyEdit
) )
725 nPolyEdit
= _nPolyEdit
;
726 pView
->SetFrameDragSingles( nPolyEdit
== 0 );
734 void GraphCtrl::SetObjKind( const SdrObjKind _eObjKind
)
739 pView
->SetEditMode( bEditMode
);
740 eObjKind
= _eObjKind
;
741 pView
->SetCurrentObj(eObjKind
);
744 eObjKind
= SdrObjKind::NONE
;
749 IMPL_LINK_NOARG(GraphCtrl
, UpdateHdl
, Timer
*, void)
751 mbInIdleUpdate
= true;
752 aUpdateLink
.Call( this );
753 mbInIdleUpdate
= false;
756 void GraphCtrl::QueueIdleUpdate()
764 class WeldOverlayManager final
: public sdr::overlay::OverlayManager
766 weld::CustomWidgetController
& m_rGraphCtrl
;
769 WeldOverlayManager(weld::CustomWidgetController
& rGraphCtrl
, OutputDevice
& rDevice
)
770 : OverlayManager(rDevice
)
771 , m_rGraphCtrl(rGraphCtrl
)
775 // invalidate the given range at local OutputDevice
776 virtual void invalidateRange(const basegfx::B2DRange
& rRange
) override
778 tools::Rectangle
aInvalidateRectangle(RangeToInvalidateRectangle(rRange
));
779 m_rGraphCtrl
.Invalidate(aInvalidateRectangle
);
784 rtl::Reference
<sdr::overlay::OverlayManager
> GraphCtrlView::CreateOverlayManager(OutputDevice
& rDevice
) const
786 assert(&rDevice
== &rGraphCtrl
.GetDrawingArea()->get_ref_device());
787 if (rDevice
.GetOutDevType() == OUTDEV_VIRDEV
)
789 rtl::Reference
<sdr::overlay::OverlayManager
> xOverlayManager(new WeldOverlayManager(rGraphCtrl
, rDevice
));
790 InitOverlayManager(xOverlayManager
);
791 return xOverlayManager
;
793 return SdrView::CreateOverlayManager(rDevice
);
796 void GraphCtrlView::InvalidateOneWin(OutputDevice
& rDevice
)
798 assert(&rDevice
== &rGraphCtrl
.GetDrawingArea()->get_ref_device());
799 if (rDevice
.GetOutDevType() == OUTDEV_VIRDEV
)
801 rGraphCtrl
.Invalidate();
804 SdrView::InvalidateOneWin(rDevice
);
807 void GraphCtrlView::InvalidateOneWin(OutputDevice
& rDevice
, const tools::Rectangle
& rArea
)
809 assert(&rDevice
== &rGraphCtrl
.GetDrawingArea()->get_ref_device());
810 if (rDevice
.GetOutDevType() == OUTDEV_VIRDEV
)
812 rGraphCtrl
.Invalidate(rArea
);
815 SdrView::InvalidateOneWin(rDevice
, rArea
);
818 GraphCtrlView::~GraphCtrlView()
820 // turn SetOutputToWindow back off again before
821 // turning back into our baseclass during dtoring
822 const sal_uInt32
nWindowCount(PaintWindowCount());
823 for (sal_uInt32
nWinNum(0); nWinNum
< nWindowCount
; nWinNum
++)
825 SdrPaintWindow
* pPaintWindow
= GetPaintWindow(nWinNum
);
826 pPaintWindow
->SetOutputToWindow(false);
830 Point
GraphCtrl::GetPositionInDialog() const
832 int x
, y
, width
, height
;
833 if (GetDrawingArea()->get_extents_relative_to(*mpDialog
, x
, y
, width
, height
))
838 css::uno::Reference
< css::accessibility::XAccessible
> GraphCtrl::CreateAccessible()
840 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
841 if(mpAccContext
== nullptr )
843 // Disable accessibility if no model/view data available
845 mpAccContext
= new SvxGraphCtrlAccessibleContext(*this);
851 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */