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
->GetItemPool().FreezeIdRanges();
125 pModel
->SetScaleUnit(aMap100
.GetMapUnit());
126 pModel
->SetDefaultFontHeight( 500 );
128 pPage
= new SdrPage( *pModel
);
130 pPage
->SetSize( aGraphSize
);
131 pPage
->SetBorder( 0, 0, 0, 0 );
132 pModel
->InsertPage( pPage
.get() );
133 pModel
->SetChanged( false );
136 pView
.reset(new GraphCtrlView(*pModel
, this));
137 pView
->SetWorkArea( tools::Rectangle( Point(), aGraphSize
) );
138 pView
->EnableExtendedMouseEventDispatcher( true );
139 pView
->ShowSdrPage(pView
->GetModel().GetPage(0));
140 pView
->SetFrameDragSingles();
141 pView
->SetMarkedPointsSmooth( SdrPathSmoothKind::Symmetric
);
142 pView
->SetEditMode();
144 // #i72889# set needed flags
145 pView
->SetPagePaintingAllowed(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 if ( pView
->IsAction() )
313 else if ( pView
->AreObjectsMarked() )
315 pView
->UnmarkAllObj();
327 if( !aCode
.IsMod1() && !aCode
.IsMod2() )
329 bool bForward
= !aCode
.IsShift();
330 // select next object
331 if ( ! pView
->MarkNextObj( bForward
))
333 // At first or last object. Cycle to the other end
335 pView
->UnmarkAllObj();
336 pView
->MarkNextObj (bForward
);
340 else if(aCode
.IsMod1())
342 // select next handle
343 const SdrHdlList
& rHdlList
= pView
->GetHdlList();
344 bool bForward(!aCode
.IsShift());
346 const_cast<SdrHdlList
&>(rHdlList
).TravelFocusHdl(bForward
);
357 if ( aCode
.IsMod1() )
360 pView
->UnmarkAllObj();
361 pView
->MarkNextObj();
370 if ( aCode
.IsMod1() )
372 pView
->UnmarkAllObj();
373 pView
->MarkNextObj(true);
388 if (aCode
.GetCode() == KEY_UP
)
394 else if (aCode
.GetCode() == KEY_DOWN
)
400 else if (aCode
.GetCode() == KEY_LEFT
)
406 else if (aCode
.GetCode() == KEY_RIGHT
)
413 if (pView
->AreObjectsMarked() && !aCode
.IsMod1() )
417 // move in 1 pixel distance
418 Size aLogicSizeOnePixel
= rDevice
.PixelToLogic(Size(1,1));
419 nX
*= aLogicSizeOnePixel
.Width();
420 nY
*= aLogicSizeOnePixel
.Height();
424 // old, fixed move distance
430 const SdrHdlList
& rHdlList
= pView
->GetHdlList();
431 SdrHdl
* pHdl
= rHdlList
.GetFocusHdl();
435 // restrict movement to WorkArea
436 const tools::Rectangle
& rWorkArea
= pView
->GetWorkArea();
438 if(!rWorkArea
.IsEmpty())
440 tools::Rectangle
aMarkRect(pView
->GetMarkedObjRect());
441 aMarkRect
.Move(nX
, nY
);
443 if(!aMarkRect
.Contains(rWorkArea
))
445 if(aMarkRect
.Left() < rWorkArea
.Left())
447 nX
+= rWorkArea
.Left() - aMarkRect
.Left();
450 if(aMarkRect
.Right() > rWorkArea
.Right())
452 nX
-= aMarkRect
.Right() - rWorkArea
.Right();
455 if(aMarkRect
.Top() < rWorkArea
.Top())
457 nY
+= rWorkArea
.Top() - aMarkRect
.Top();
460 if(aMarkRect
.Bottom() > rWorkArea
.Bottom())
462 nY
-= aMarkRect
.Bottom() - rWorkArea
.Bottom();
467 // no handle selected
468 if(0 != nX
|| 0 != nY
)
470 pView
->MoveAllMarked(Size(nX
, nY
));
475 // move handle with index nHandleIndex
478 // now move the Handle (nX, nY)
479 Point
aStartPoint(pHdl
->GetPos());
480 Point
aEndPoint(pHdl
->GetPos() + Point(nX
, nY
));
481 const SdrDragStat
& rDragStat
= pView
->GetDragStat();
484 pView
->BegDragObj(aStartPoint
, nullptr, pHdl
, 0);
486 if(pView
->IsDragObj())
488 bool bWasNoSnap
= rDragStat
.IsNoSnap();
489 bool bWasSnapEnabled
= pView
->IsSnapEnabled();
491 // switch snapping off
493 const_cast<SdrDragStat
&>(rDragStat
).SetNoSnap();
495 pView
->SetSnapEnabled(false);
497 pView
->MovAction(aEndPoint
);
502 const_cast<SdrDragStat
&>(rDragStat
).SetNoSnap(bWasNoSnap
);
504 pView
->SetSnapEnabled(bWasSnapEnabled
);
516 const SdrHdlList
& rHdlList
= pView
->GetHdlList();
517 SdrHdl
* pHdl
= rHdlList
.GetFocusHdl();
521 if(pHdl
->GetKind() == SdrHdlKind::Poly
)
523 // rescue ID of point with focus
524 sal_uInt32
nPol(pHdl
->GetPolyNum());
525 sal_uInt32
nPnt(pHdl
->GetPointNum());
527 if(pView
->IsPointMarked(*pHdl
))
529 if(rKEvt
.GetKeyCode().IsShift())
531 pView
->UnmarkPoint(*pHdl
);
536 if(!rKEvt
.GetKeyCode().IsShift())
538 pView
->UnmarkAllPoints();
541 pView
->MarkPoint(*pHdl
);
544 if(nullptr == rHdlList
.GetFocusHdl())
546 // restore point with focus
547 SdrHdl
* pNewOne
= nullptr;
549 for(size_t a
= 0; !pNewOne
&& a
< rHdlList
.GetHdlCount(); ++a
)
551 SdrHdl
* pAct
= rHdlList
.GetHdl(a
);
554 && pAct
->GetKind() == SdrHdlKind::Poly
555 && pAct
->GetPolyNum() == nPol
556 && pAct
->GetPointNum() == nPnt
)
564 const_cast<SdrHdlList
&>(rHdlList
).SetFocusHdl(pNewOne
);
586 bool GraphCtrl::MouseButtonDown( const MouseEvent
& rMEvt
)
588 if ( mbSdrMode
&& ( rMEvt
.GetClicks() < 2 ) )
590 OutputDevice
& rDevice
= GetDrawingArea()->get_ref_device();
592 const Point
aLogPt( rDevice
.PixelToLogic( rMEvt
.GetPosPixel() ) );
594 if ( !tools::Rectangle( Point(), aGraphSize
).Contains( aLogPt
) && !pView
->IsEditMode() )
595 weld::CustomWidgetController::MouseButtonDown( rMEvt
);
598 // Get Focus for key inputs
604 SdrHitKind eHit
= pView
->PickAnything( rMEvt
, SdrMouseEventKind::BUTTONDOWN
, aVEvt
);
606 if ( nPolyEdit
== SID_BEZIER_INSERT
&& eHit
== SdrHitKind::MarkedObject
)
607 pView
->BegInsObjPoint( aLogPt
, rMEvt
.IsMod1());
609 pView
->MouseButtonDown( rMEvt
, &rDevice
);
612 pView
->MouseButtonDown( rMEvt
, &rDevice
);
615 SdrObject
* pCreateObj
= pView
->GetCreateObj();
617 // We want to realize the insert
618 if ( pCreateObj
&& !pCreateObj
->GetUserCall() )
619 pCreateObj
->SetUserCall( pUserCall
.get() );
621 SetPointer( pView
->GetPreferredPointer( aLogPt
, &rDevice
) );
624 weld::CustomWidgetController::MouseButtonDown( rMEvt
);
631 bool GraphCtrl::MouseMove(const MouseEvent
& rMEvt
)
633 OutputDevice
& rDevice
= GetDrawingArea()->get_ref_device();
634 const Point
aLogPos( rDevice
.PixelToLogic( rMEvt
.GetPosPixel() ) );
638 pView
->MouseMove( rMEvt
, &rDevice
);
640 if( ( SID_BEZIER_INSERT
== nPolyEdit
) &&
641 !pView
->PickHandle( aLogPos
) &&
642 !pView
->IsInsObjPoint() )
644 SetPointer( PointerStyle::Cross
);
647 SetPointer( pView
->GetPreferredPointer( aLogPos
, &rDevice
) );
650 weld::CustomWidgetController::MouseButtonUp( rMEvt
);
652 if ( aMousePosLink
.IsSet() )
654 if ( tools::Rectangle( Point(), aGraphSize
).Contains( aLogPos
) )
659 aMousePosLink
.Call( this );
667 bool GraphCtrl::MouseButtonUp(const MouseEvent
& rMEvt
)
671 OutputDevice
& rDevice
= GetDrawingArea()->get_ref_device();
673 if ( pView
->IsInsObjPoint() )
674 pView
->EndInsObjPoint( SdrCreateCmd::ForceEnd
);
676 pView
->MouseButtonUp( rMEvt
, &rDevice
);
679 SetPointer( pView
->GetPreferredPointer( rDevice
.PixelToLogic( rMEvt
.GetPosPixel() ), &rDevice
) );
682 weld::CustomWidgetController::MouseButtonUp( rMEvt
);
689 SdrObject
* GraphCtrl::GetSelectedSdrObject() const
691 SdrObject
* pSdrObj
= nullptr;
695 const SdrMarkList
& rMarkList
= pView
->GetMarkedObjectList();
697 if ( rMarkList
.GetMarkCount() == 1 )
698 pSdrObj
= rMarkList
.GetMark( 0 )->GetMarkedSdrObj();
704 void GraphCtrl::SetEditMode( const bool _bEditMode
)
708 bEditMode
= _bEditMode
;
709 pView
->SetEditMode( bEditMode
);
710 eObjKind
= SdrObjKind::NONE
;
711 pView
->SetCurrentObj(eObjKind
);
719 void GraphCtrl::SetPolyEditMode( const sal_uInt16 _nPolyEdit
)
721 if ( mbSdrMode
&& ( _nPolyEdit
!= nPolyEdit
) )
723 nPolyEdit
= _nPolyEdit
;
724 pView
->SetFrameDragSingles( nPolyEdit
== 0 );
732 void GraphCtrl::SetObjKind( const SdrObjKind _eObjKind
)
737 pView
->SetEditMode( bEditMode
);
738 eObjKind
= _eObjKind
;
739 pView
->SetCurrentObj(eObjKind
);
742 eObjKind
= SdrObjKind::NONE
;
747 IMPL_LINK_NOARG(GraphCtrl
, UpdateHdl
, Timer
*, void)
749 mbInIdleUpdate
= true;
750 aUpdateLink
.Call( this );
751 mbInIdleUpdate
= false;
754 void GraphCtrl::QueueIdleUpdate()
762 class WeldOverlayManager final
: public sdr::overlay::OverlayManager
764 weld::CustomWidgetController
& m_rGraphCtrl
;
767 WeldOverlayManager(weld::CustomWidgetController
& rGraphCtrl
, OutputDevice
& rDevice
)
768 : OverlayManager(rDevice
)
769 , m_rGraphCtrl(rGraphCtrl
)
773 // invalidate the given range at local OutputDevice
774 virtual void invalidateRange(const basegfx::B2DRange
& rRange
) override
776 tools::Rectangle
aInvalidateRectangle(RangeToInvalidateRectangle(rRange
));
777 m_rGraphCtrl
.Invalidate(aInvalidateRectangle
);
782 rtl::Reference
<sdr::overlay::OverlayManager
> GraphCtrlView::CreateOverlayManager(OutputDevice
& rDevice
) const
784 assert(&rDevice
== &rGraphCtrl
.GetDrawingArea()->get_ref_device());
785 if (rDevice
.GetOutDevType() == OUTDEV_VIRDEV
)
787 rtl::Reference
<sdr::overlay::OverlayManager
> xOverlayManager(new WeldOverlayManager(rGraphCtrl
, rDevice
));
788 InitOverlayManager(xOverlayManager
);
789 return xOverlayManager
;
791 return SdrView::CreateOverlayManager(rDevice
);
794 void GraphCtrlView::InvalidateOneWin(OutputDevice
& rDevice
)
796 assert(&rDevice
== &rGraphCtrl
.GetDrawingArea()->get_ref_device());
797 if (rDevice
.GetOutDevType() == OUTDEV_VIRDEV
)
799 rGraphCtrl
.Invalidate();
802 SdrView::InvalidateOneWin(rDevice
);
805 void GraphCtrlView::InvalidateOneWin(OutputDevice
& rDevice
, const tools::Rectangle
& rArea
)
807 assert(&rDevice
== &rGraphCtrl
.GetDrawingArea()->get_ref_device());
808 if (rDevice
.GetOutDevType() == OUTDEV_VIRDEV
)
810 rGraphCtrl
.Invalidate(rArea
);
813 SdrView::InvalidateOneWin(rDevice
, rArea
);
816 GraphCtrlView::~GraphCtrlView()
818 // turn SetOutputToWindow back off again before
819 // turning back into our baseclass during dtoring
820 const sal_uInt32
nWindowCount(PaintWindowCount());
821 for (sal_uInt32
nWinNum(0); nWinNum
< nWindowCount
; nWinNum
++)
823 SdrPaintWindow
* pPaintWindow
= GetPaintWindow(nWinNum
);
824 pPaintWindow
->SetOutputToWindow(false);
828 Point
GraphCtrl::GetPositionInDialog() const
830 int x
, y
, width
, height
;
831 if (GetDrawingArea()->get_extents_relative_to(*mpDialog
, x
, y
, width
, height
))
836 css::uno::Reference
< css::accessibility::XAccessible
> GraphCtrl::CreateAccessible()
838 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
839 if(mpAccContext
== nullptr )
841 // Disable accessibility if no model/view data available
843 mpAccContext
= new SvxGraphCtrlAccessibleContext(*this);
849 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */