update credits
[LibreOffice.git] / svx / source / dialog / graphctl.cxx
blobc4fa12b4866735221369c52a7a000bb1ead1c85a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <unotools/syslocale.hxx>
24 #include <rtl/math.hxx>
25 #include <unotools/localedatawrapper.hxx>
26 #include <comphelper/processfactory.hxx>
27 #include <vcl/svapp.hxx>
28 #include <osl/mutex.hxx>
30 #include <svx/graphctl.hxx>
31 #include "GraphCtlAccessibleContext.hxx"
32 #include "svx/xoutbmp.hxx"
33 #include <svx/svxids.hrc>
34 #include <svx/svdpage.hxx>
36 // #i72889#
37 #include "svx/sdrpaintwindow.hxx"
39 void GraphCtrlUserCall::Changed( const SdrObject& rObj, SdrUserCallType eType, const Rectangle& /*rOldBoundRect*/ )
41 switch( eType )
43 case( SDRUSERCALL_MOVEONLY ):
44 case( SDRUSERCALL_RESIZE ):
45 rWin.SdrObjChanged( rObj );
46 break;
48 case( SDRUSERCALL_INSERTED ):
49 rWin.SdrObjCreated( rObj );
50 break;
52 default:
53 break;
57 GraphCtrl::GraphCtrl( Window* pParent, const ResId& rResId ) :
58 Control ( pParent, rResId ),
59 aMap100 ( MAP_100TH_MM ),
60 nWinStyle ( 0 ),
61 eObjKind ( OBJ_NONE ),
62 nPolyEdit ( 0 ),
63 bEditMode ( sal_False ),
64 bSdrMode ( sal_False ),
65 bAnim ( sal_False ),
66 mpAccContext ( NULL ),
67 pModel ( NULL ),
68 pView ( NULL )
70 pUserCall = new GraphCtrlUserCall( *this );
71 aUpdateTimer.SetTimeout( 500 );
72 aUpdateTimer.SetTimeoutHdl( LINK( this, GraphCtrl, UpdateHdl ) );
73 aUpdateTimer.Start();
74 EnableRTL( sal_False );
77 GraphCtrl::~GraphCtrl()
79 if( mpAccContext )
81 mpAccContext->disposing();
82 mpAccContext->release();
84 delete pView;
85 delete pModel;
86 delete pUserCall;
89 void GraphCtrl::SetWinStyle( WinBits nWinBits )
91 nWinStyle = nWinBits;
92 bAnim = ( nWinStyle & WB_ANIMATION ) == WB_ANIMATION;
93 bSdrMode = ( nWinStyle & WB_SDRMODE ) == WB_SDRMODE;
95 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
96 SetBackground( Wallpaper( rStyleSettings.GetWindowColor() ) );
97 SetMapMode( aMap100 );
99 delete pView;
100 pView = NULL;
102 delete pModel;
103 pModel = NULL;
105 if ( bSdrMode )
106 InitSdrModel();
109 void GraphCtrl::InitSdrModel()
111 SolarMutexGuard aGuard;
113 SdrPage* pPage;
115 // destroy old junk
116 delete pView;
117 delete pModel;
119 // Creating a Model
120 pModel = new SdrModel;
121 pModel->GetItemPool().FreezeIdRanges();
122 pModel->SetScaleUnit( aMap100.GetMapUnit() );
123 pModel->SetScaleFraction( Fraction( 1, 1 ) );
124 pModel->SetDefaultFontHeight( 500 );
126 pPage = new SdrPage( *pModel );
128 pPage->SetSize( aGraphSize );
129 pPage->SetBorder( 0, 0, 0, 0 );
130 pModel->InsertPage( pPage );
131 pModel->SetChanged( sal_False );
133 // Creating a View
134 pView = new GraphCtrlView( pModel, this );
135 pView->SetWorkArea( Rectangle( Point(), aGraphSize ) );
136 pView->EnableExtendedMouseEventDispatcher( sal_True );
137 pView->ShowSdrPage(pView->GetModel()->GetPage(0));
138 pView->SetFrameDragSingles( sal_True );
139 pView->SetMarkedPointsSmooth( SDRPATHSMOOTH_SYMMETRIC );
140 pView->SetEditMode( sal_True );
142 // #i72889# set neeeded flags
143 pView->SetPagePaintingAllowed(false);
144 pView->SetBufferedOutputAllowed(true);
145 pView->SetBufferedOverlayAllowed(true);
147 // Tell the accessibility object about the changes.
148 if (mpAccContext != NULL)
149 mpAccContext->setModelAndView (pModel, pView);
152 void GraphCtrl::SetGraphic( const Graphic& rGraphic, sal_Bool bNewModel )
154 // If possible we dither bitmaps for the display
155 if ( !bAnim && ( rGraphic.GetType() == GRAPHIC_BITMAP ) )
157 if ( rGraphic.IsTransparent() )
159 Bitmap aBmp( rGraphic.GetBitmap() );
161 DitherBitmap( aBmp );
162 aGraphic = Graphic( BitmapEx( aBmp, rGraphic.GetBitmapEx().GetMask() ) );
164 else
166 Bitmap aBmp( rGraphic.GetBitmap() );
167 DitherBitmap( aBmp );
168 aGraphic = aBmp;
171 else
172 aGraphic = rGraphic;
174 if ( aGraphic.GetPrefMapMode().GetMapUnit() == MAP_PIXEL )
175 aGraphSize = Application::GetDefaultDevice()->PixelToLogic( aGraphic.GetPrefSize(), aMap100 );
176 else
177 aGraphSize = OutputDevice::LogicToLogic( aGraphic.GetPrefSize(), aGraphic.GetPrefMapMode(), aMap100 );
179 if ( bSdrMode && bNewModel )
180 InitSdrModel();
182 if ( aGraphSizeLink.IsSet() )
183 aGraphSizeLink.Call( this );
185 Resize();
186 Invalidate();
189 void GraphCtrl::Resize()
191 Control::Resize();
193 if ( aGraphSize.Width() && aGraphSize.Height() )
195 MapMode aDisplayMap( aMap100 );
196 Point aNewPos;
197 Size aNewSize;
198 const Size aWinSize = PixelToLogic( GetOutputSizePixel(), aDisplayMap );
199 const long nWidth = aWinSize.Width();
200 const long nHeight = aWinSize.Height();
201 double fGrfWH = (double) aGraphSize.Width() / aGraphSize.Height();
202 double fWinWH = (double) nWidth / nHeight;
204 // Adapt Bitmap to Thumb size
205 if ( fGrfWH < fWinWH)
207 aNewSize.Width() = (long) ( (double) nHeight * fGrfWH );
208 aNewSize.Height()= nHeight;
210 else
212 aNewSize.Width() = nWidth;
213 aNewSize.Height()= (long) ( (double) nWidth / fGrfWH );
216 aNewPos.X() = ( nWidth - aNewSize.Width() ) >> 1;
217 aNewPos.Y() = ( 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( LogicToLogic( aNewPos, aMap100, aDisplayMap ) );
224 SetMapMode( aDisplayMap );
227 Invalidate();
230 void GraphCtrl::Paint( const Rectangle& rRect )
232 // #i72889# used splitted repaint to be able to paint an own background
233 // even to the buffered view
234 const bool bGraphicValid(GRAPHIC_NONE != aGraphic.GetType());
236 if(bSdrMode)
238 SdrPaintWindow* pPaintWindow = pView->BeginCompleteRedraw(this);
240 if(bGraphicValid)
242 OutputDevice& rTarget = pPaintWindow->GetTargetOutputDevice();
244 rTarget.SetBackground(GetBackground());
245 rTarget.Erase();
247 aGraphic.Draw(&rTarget, Point(), aGraphSize);
250 const Region aRepaintRegion(rRect);
251 pView->DoCompleteRedraw(*pPaintWindow, aRepaintRegion);
252 pView->EndCompleteRedraw(*pPaintWindow, true);
254 else
256 // #i73381# in non-SdrMode, paint to local directly
257 if(bGraphicValid)
259 aGraphic.Draw(this, Point(), aGraphSize);
264 void GraphCtrl::SdrObjChanged( const SdrObject& )
268 void GraphCtrl::SdrObjCreated( const SdrObject& )
272 void GraphCtrl::MarkListHasChanged()
274 if ( aMarkObjLink.IsSet() )
275 aMarkObjLink.Call( this );
278 void GraphCtrl::KeyInput( const KeyEvent& rKEvt )
280 KeyCode aCode( rKEvt.GetKeyCode() );
281 bool bProc = false;
283 switch ( aCode.GetCode() )
285 case KEY_DELETE:
286 case KEY_BACKSPACE:
288 if ( bSdrMode )
290 pView->DeleteMarked();
291 bProc = true;
292 if( !pView->AreObjectsMarked() )
293 GetParentDialog()->GrabFocusToFirstControl();
296 break;
298 case KEY_ESCAPE:
300 if ( bSdrMode )
302 if ( pView->IsAction() )
304 pView->BrkAction();
306 else if ( pView->AreObjectsMarked() )
308 const SdrHdlList& rHdlList = pView->GetHdlList();
309 SdrHdl* pHdl = rHdlList.GetFocusHdl();
311 if(pHdl)
313 ((SdrHdlList&)rHdlList).ResetFocusHdl();
315 else
317 GetParentDialog()->GrabFocusToFirstControl();
320 else
322 GetParentDialog()->GrabFocusToFirstControl();
324 bProc = true;
327 break;
329 case KEY_F11:
330 case KEY_TAB:
332 if( bSdrMode )
334 if( !aCode.IsMod1() && !aCode.IsMod2() )
336 bool bForward = !aCode.IsShift();
337 // select next object
338 if ( ! pView->MarkNextObj( bForward ))
340 // At first or last object. Cycle to the other end
341 // of the list.
342 pView->UnmarkAllObj();
343 pView->MarkNextObj (bForward);
345 bProc = true;
347 else if(aCode.IsMod1())
349 // select next handle
350 const SdrHdlList& rHdlList = pView->GetHdlList();
351 sal_Bool bForward(!aCode.IsShift());
353 ((SdrHdlList&)rHdlList).TravelFocusHdl(bForward);
355 bProc = true;
359 break;
361 case KEY_END:
364 if ( aCode.IsMod1() )
366 // mark last object
367 pView->UnmarkAllObj();
368 pView->MarkNextObj(sal_False);
370 bProc = true;
373 break;
375 case KEY_HOME:
377 if ( aCode.IsMod1() )
379 pView->UnmarkAllObj();
380 pView->MarkNextObj(sal_True);
382 bProc = true;
385 break;
387 case KEY_UP:
388 case KEY_DOWN:
389 case KEY_LEFT:
390 case KEY_RIGHT:
392 long nX = 0;
393 long nY = 0;
395 if (aCode.GetCode() == KEY_UP)
397 // Scroll up
398 nX = 0;
399 nY =-1;
401 else if (aCode.GetCode() == KEY_DOWN)
403 // Scroll down
404 nX = 0;
405 nY = 1;
407 else if (aCode.GetCode() == KEY_LEFT)
409 // Scroll left
410 nX =-1;
411 nY = 0;
413 else if (aCode.GetCode() == KEY_RIGHT)
415 // Scroll right
416 nX = 1;
417 nY = 0;
420 if (pView->AreObjectsMarked() && !aCode.IsMod1() )
422 if(aCode.IsMod2())
424 // move in 1 pixel distance
425 Size aLogicSizeOnePixel = PixelToLogic(Size(1,1));
426 nX *= aLogicSizeOnePixel.Width();
427 nY *= aLogicSizeOnePixel.Height();
429 else
431 // old, fixed move distance
432 nX *= 100;
433 nY *= 100;
436 // II
437 const SdrHdlList& rHdlList = pView->GetHdlList();
438 SdrHdl* pHdl = rHdlList.GetFocusHdl();
440 if(0L == pHdl)
442 // restrict movement to WorkArea
443 const Rectangle& rWorkArea = pView->GetWorkArea();
445 if(!rWorkArea.IsEmpty())
447 Rectangle aMarkRect(pView->GetMarkedObjRect());
448 aMarkRect.Move(nX, nY);
450 if(!aMarkRect.IsInside(rWorkArea))
452 if(aMarkRect.Left() < rWorkArea.Left())
454 nX += rWorkArea.Left() - aMarkRect.Left();
457 if(aMarkRect.Right() > rWorkArea.Right())
459 nX -= aMarkRect.Right() - rWorkArea.Right();
462 if(aMarkRect.Top() < rWorkArea.Top())
464 nY += rWorkArea.Top() - aMarkRect.Top();
467 if(aMarkRect.Bottom() > rWorkArea.Bottom())
469 nY -= aMarkRect.Bottom() - rWorkArea.Bottom();
474 // no handle selected
475 if(0 != nX || 0 != nY)
477 pView->MoveAllMarked(Size(nX, nY));
480 else
482 // move handle with index nHandleIndex
483 if(pHdl && (nX || nY))
485 // now move the Handle (nX, nY)
486 Point aStartPoint(pHdl->GetPos());
487 Point aEndPoint(pHdl->GetPos() + Point(nX, nY));
488 const SdrDragStat& rDragStat = pView->GetDragStat();
490 // start dragging
491 pView->BegDragObj(aStartPoint, 0, pHdl, 0);
493 if(pView->IsDragObj())
495 bool bWasNoSnap = rDragStat.IsNoSnap();
496 sal_Bool bWasSnapEnabled = pView->IsSnapEnabled();
498 // switch snapping off
499 if(!bWasNoSnap)
500 ((SdrDragStat&)rDragStat).SetNoSnap(sal_True);
501 if(bWasSnapEnabled)
502 pView->SetSnapEnabled(sal_False);
504 pView->MovAction(aEndPoint);
505 pView->EndDragObj();
507 // restore snap
508 if(!bWasNoSnap)
509 ((SdrDragStat&)rDragStat).SetNoSnap(bWasNoSnap);
510 if(bWasSnapEnabled)
511 pView->SetSnapEnabled(bWasSnapEnabled);
516 bProc = true;
519 break;
521 case KEY_SPACE:
523 const SdrHdlList& rHdlList = pView->GetHdlList();
524 SdrHdl* pHdl = rHdlList.GetFocusHdl();
526 if(pHdl)
528 if(pHdl->GetKind() == HDL_POLY)
530 // rescue ID of point with focus
531 sal_uInt32 nPol(pHdl->GetPolyNum());
532 sal_uInt32 nPnt(pHdl->GetPointNum());
534 if(pView->IsPointMarked(*pHdl))
536 if(rKEvt.GetKeyCode().IsShift())
538 pView->UnmarkPoint(*pHdl);
541 else
543 if(!rKEvt.GetKeyCode().IsShift())
545 pView->UnmarkAllPoints();
548 pView->MarkPoint(*pHdl);
551 if(0L == rHdlList.GetFocusHdl())
553 // restore point with focus
554 SdrHdl* pNewOne = 0L;
556 for(sal_uInt32 a(0); !pNewOne && a < rHdlList.GetHdlCount(); a++)
558 SdrHdl* pAct = rHdlList.GetHdl(a);
560 if(pAct
561 && pAct->GetKind() == HDL_POLY
562 && pAct->GetPolyNum() == nPol
563 && pAct->GetPointNum() == nPnt)
565 pNewOne = pAct;
569 if(pNewOne)
571 ((SdrHdlList&)rHdlList).SetFocusHdl(pNewOne);
575 bProc = true;
579 break;
581 default:
582 break;
585 if ( !bProc )
586 Control::KeyInput( rKEvt );
587 else
588 ReleaseMouse();
591 void GraphCtrl::MouseButtonDown( const MouseEvent& rMEvt )
593 if ( bSdrMode && ( rMEvt.GetClicks() < 2 ) )
595 const Point aLogPt( PixelToLogic( rMEvt.GetPosPixel() ) );
597 if ( !Rectangle( Point(), aGraphSize ).IsInside( aLogPt ) && !pView->IsEditMode() )
598 Control::MouseButtonDown( rMEvt );
599 else
601 // Get Focus for key inputs
602 GrabFocus();
604 if ( nPolyEdit )
606 SdrViewEvent aVEvt;
607 SdrHitKind eHit = pView->PickAnything( rMEvt, SDRMOUSEBUTTONDOWN, aVEvt );
609 if ( nPolyEdit == SID_BEZIER_INSERT && eHit == SDRHIT_MARKEDOBJECT )
610 pView->BegInsObjPoint( aLogPt, rMEvt.IsMod1());
611 else
612 pView->MouseButtonDown( rMEvt, this );
614 else
615 pView->MouseButtonDown( rMEvt, this );
618 SdrObject* pCreateObj = pView->GetCreateObj();
620 // We want to realize the insert
621 if ( pCreateObj && !pCreateObj->GetUserCall() )
622 pCreateObj->SetUserCall( pUserCall );
624 SetPointer( pView->GetPreferedPointer( aLogPt, this ) );
626 else
627 Control::MouseButtonDown( rMEvt );
630 void GraphCtrl::MouseMove(const MouseEvent& rMEvt)
632 const Point aLogPos( PixelToLogic( rMEvt.GetPosPixel() ) );
634 if ( bSdrMode )
636 pView->MouseMove( rMEvt, this );
638 if( ( SID_BEZIER_INSERT == nPolyEdit ) &&
639 !pView->PickHandle( aLogPos ) &&
640 !pView->IsInsObjPoint() )
642 SetPointer( POINTER_CROSS );
644 else
645 SetPointer( pView->GetPreferedPointer( aLogPos, this ) );
647 else
648 Control::MouseButtonUp( rMEvt );
650 if ( aMousePosLink.IsSet() )
652 if ( Rectangle( Point(), aGraphSize ).IsInside( aLogPos ) )
653 aMousePos = aLogPos;
654 else
655 aMousePos = Point();
657 aMousePosLink.Call( this );
661 void GraphCtrl::MouseButtonUp(const MouseEvent& rMEvt)
663 if ( bSdrMode )
665 if ( pView->IsInsObjPoint() )
666 pView->EndInsObjPoint( SDRCREATE_FORCEEND );
667 else
668 pView->MouseButtonUp( rMEvt, this );
670 ReleaseMouse();
671 SetPointer( pView->GetPreferedPointer( PixelToLogic( rMEvt.GetPosPixel() ), this ) );
673 else
674 Control::MouseButtonUp( rMEvt );
677 SdrObject* GraphCtrl::GetSelectedSdrObject() const
679 SdrObject* pSdrObj = NULL;
681 if ( bSdrMode )
683 const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
685 if ( rMarkList.GetMarkCount() == 1 )
686 pSdrObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
689 return pSdrObj;
692 void GraphCtrl::SetEditMode( const sal_Bool _bEditMode )
694 if ( bSdrMode )
696 bEditMode = _bEditMode;
697 pView->SetEditMode( bEditMode );
698 eObjKind = OBJ_NONE;
699 pView->SetCurrentObj( sal::static_int_cast< sal_uInt16 >( eObjKind ) );
701 else
702 bEditMode = sal_False;
705 void GraphCtrl::SetPolyEditMode( const sal_uInt16 _nPolyEdit )
707 if ( bSdrMode && ( _nPolyEdit != nPolyEdit ) )
709 nPolyEdit = _nPolyEdit;
710 pView->SetFrameDragSingles( nPolyEdit == 0 );
712 else
713 nPolyEdit = 0;
716 void GraphCtrl::SetObjKind( const SdrObjKind _eObjKind )
718 if ( bSdrMode )
720 bEditMode = sal_False;
721 pView->SetEditMode( bEditMode );
722 eObjKind = _eObjKind;
723 pView->SetCurrentObj( sal::static_int_cast< sal_uInt16 >( eObjKind ) );
725 else
726 eObjKind = OBJ_NONE;
729 IMPL_LINK( GraphCtrl, UpdateHdl, Timer*, pTimer )
731 if ( aUpdateLink.IsSet() )
732 aUpdateLink.Call( this );
734 pTimer->Start();
736 return 0L;
740 ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > GraphCtrl::CreateAccessible()
742 if( mpAccContext == NULL )
744 Window* pParent = GetParent();
746 DBG_ASSERT( pParent, "-GraphCtrl::CreateAccessible(): No Parent!" );
748 if( pParent )
750 ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > xAccParent( pParent->GetAccessible() );
752 // Disable accessibility if no model/view data available
753 if( pView &&
754 pModel &&
755 xAccParent.is() )
757 mpAccContext = new SvxGraphCtrlAccessibleContext( xAccParent, *this );
758 mpAccContext->acquire();
763 return mpAccContext;
766 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */