sdext: adapt xpdfwrapper to poppler 24.12
[LibreOffice.git] / svx / source / svdraw / svdview.cxx
blob3fac4208e6bce8d7450af8097345f8ddabe14b8b
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 <editeng/outlobj.hxx>
22 #include <svx/strings.hrc>
23 #include <svx/dialmgr.hxx>
24 #include <svx/svdpagv.hxx>
25 #include <svx/svdmrkv.hxx>
26 #include <svx/svdedxv.hxx>
27 #include <svx/svdobj.hxx>
28 #include <svx/svdopath.hxx>
29 #include <svx/svdograf.hxx>
30 #include <svx/svdomedia.hxx>
31 #include <svx/svdetc.hxx>
33 #include <svx/sdr/table/tablecontroller.hxx>
34 #include <svx/svdoutl.hxx>
35 #include <svx/svdview.hxx>
36 #include <editeng/flditem.hxx>
37 #include <svx/svddrgmt.hxx>
38 #include <svx/svdotable.hxx>
39 #include <tools/debug.hxx>
40 #include <svx/sdr/overlay/overlaypolypolygon.hxx>
41 #include <svx/sdr/overlay/overlaymanager.hxx>
42 #include <svx/sdrpaintwindow.hxx>
43 #include <svx/sdrpagewindow.hxx>
44 #include <svx/sdrhittesthelper.hxx>
45 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
46 #include <drawinglayer/primitive2d/texthierarchyprimitive2d.hxx>
47 #include <svx/sdr/contact/objectcontactofpageview.hxx>
48 #include <sal/log.hxx>
49 #include <vcl/ptrstyle.hxx>
50 #include <vcl/window.hxx>
51 #include <comphelper/lok.hxx>
54 SdrViewEvent::SdrViewEvent()
55 : mpHdl(nullptr),
56 mpObj(nullptr),
57 mpRootObj(nullptr),
58 mpPV(nullptr),
59 mpURLField(nullptr),
60 meHit(SdrHitKind::NONE),
61 meEvent(SdrEventKind::NONE),
62 mnMouseClicks(0),
63 mnMouseMode(MouseEventModifiers::NONE),
64 mnMouseCode(0),
65 mnHlplIdx(0),
66 mnGlueId(0),
67 mbMouseDown(false),
68 mbMouseUp(false),
69 mbIsAction(false),
70 mbIsTextEdit(false),
71 mbAddMark(false),
72 mbUnmark(false),
73 mbPrevNextMark(false),
74 mbMarkPrev(false)
78 // helper class for all D&D overlays
80 void SdrDropMarkerOverlay::ImplCreateOverlays(
81 const SdrView& rView,
82 const basegfx::B2DPolyPolygon& rLinePolyPolygon)
84 for(sal_uInt32 a(0); a < rView.PaintWindowCount(); a++)
86 SdrPaintWindow* pCandidate = rView.GetPaintWindow(a);
87 const rtl::Reference< sdr::overlay::OverlayManager >& xTargetOverlay = pCandidate->GetOverlayManager();
89 if (xTargetOverlay.is())
91 std::unique_ptr<sdr::overlay::OverlayPolyPolygonStripedAndFilled> pNew(new sdr::overlay::OverlayPolyPolygonStripedAndFilled(
92 rLinePolyPolygon));
94 xTargetOverlay->add(*pNew);
95 maObjects.append(std::move(pNew));
100 SdrDropMarkerOverlay::SdrDropMarkerOverlay(const SdrView& rView, const SdrObject& rObject)
102 ImplCreateOverlays(
103 rView,
104 rObject.TakeXorPoly());
107 SdrDropMarkerOverlay::SdrDropMarkerOverlay(const SdrView& rView, const tools::Rectangle& rRectangle)
109 basegfx::B2DPolygon aB2DPolygon;
111 aB2DPolygon.append(basegfx::B2DPoint(rRectangle.Left(), rRectangle.Top()));
112 aB2DPolygon.append(basegfx::B2DPoint(rRectangle.Right(), rRectangle.Top()));
113 aB2DPolygon.append(basegfx::B2DPoint(rRectangle.Right(), rRectangle.Bottom()));
114 aB2DPolygon.append(basegfx::B2DPoint(rRectangle.Left(), rRectangle.Bottom()));
115 aB2DPolygon.setClosed(true);
117 ImplCreateOverlays(
118 rView,
119 basegfx::B2DPolyPolygon(aB2DPolygon));
122 SdrDropMarkerOverlay::SdrDropMarkerOverlay(const SdrView& rView, const Point& rStart, const Point& rEnd)
124 basegfx::B2DPolygon aB2DPolygon;
126 aB2DPolygon.append(basegfx::B2DPoint(rStart.X(), rStart.Y()));
127 aB2DPolygon.append(basegfx::B2DPoint(rEnd.X(), rEnd.Y()));
128 aB2DPolygon.setClosed(true);
130 ImplCreateOverlays(
131 rView,
132 basegfx::B2DPolyPolygon(aB2DPolygon));
135 SdrDropMarkerOverlay::~SdrDropMarkerOverlay()
137 // The OverlayObjects are cleared using the destructor of OverlayObjectList.
138 // That destructor calls clear() at the list which removes all objects from the
139 // OverlayManager and deletes them.
142 SdrView::SdrView(
143 SdrModel& rSdrModel,
144 OutputDevice* pOut)
145 : SdrCreateView(rSdrModel, pOut),
146 mbNoExtendedMouseDispatcher(false),
147 mbNoExtendedKeyDispatcher(false),
148 mbMasterPagePaintCaching(false)
152 SdrView::~SdrView()
156 bool SdrView::KeyInput(const KeyEvent& rKEvt, vcl::Window* pWin)
158 SetActualWin(pWin ? pWin->GetOutDev() : nullptr);
159 bool bRet = SdrCreateView::KeyInput(rKEvt,pWin);
160 if (!bRet && !IsExtendedKeyInputDispatcherEnabled()) {
161 bRet = true;
162 switch (rKEvt.GetKeyCode().GetFullFunction()) {
163 case KeyFuncType::DELETE: DeleteMarked(); break;
164 case KeyFuncType::UNDO: GetModel().Undo(); break;
165 case KeyFuncType::REDO: GetModel().Redo(); break;
166 default: {
167 switch (rKEvt.GetKeyCode().GetFullCode()) {
168 case KEY_ESCAPE: {
169 if (IsTextEdit()) SdrEndTextEdit();
170 if (IsAction()) BrkAction();
171 if (pWin!=nullptr) pWin->ReleaseMouse();
172 } break;
173 case KEY_DELETE: DeleteMarked(); break;
174 case KEY_UNDO: case KEY_BACKSPACE+KEY_MOD2: GetModel().Undo(); break;
175 case KEY_BACKSPACE+KEY_MOD2+KEY_SHIFT: GetModel().Redo(); break;
176 case KEY_REPEAT: case KEY_BACKSPACE+KEY_MOD2+KEY_MOD1: GetModel().Repeat(*this); break;
177 case KEY_MOD1+KEY_A: MarkAll(); break;
178 default: bRet=false;
179 } // switch
181 } // switch
182 if (bRet && pWin!=nullptr) {
183 pWin->SetPointer(GetPreferredPointer(
184 pWin->PixelToLogic(pWin->ScreenToOutputPixel( pWin->GetPointerPosPixel() ) ),
185 pWin->GetOutDev(),
186 rKEvt.GetKeyCode().GetModifier()));
189 return bRet;
192 bool SdrView::MouseButtonDown(const MouseEvent& rMEvt, OutputDevice* pWin)
194 SetActualWin(pWin);
195 if (rMEvt.IsLeft()) maDragStat.SetMouseDown(true);
196 bool bRet = SdrCreateView::MouseButtonDown(rMEvt,pWin);
197 if (!bRet && !IsExtendedMouseEventDispatcherEnabled()) {
198 SdrViewEvent aVEvt;
199 PickAnything(rMEvt,SdrMouseEventKind::BUTTONDOWN,aVEvt);
200 bRet = DoMouseEvent(aVEvt);
202 return bRet;
205 bool SdrView::MouseButtonUp(const MouseEvent& rMEvt, OutputDevice* pWin)
207 SetActualWin(pWin);
208 if (rMEvt.IsLeft()) maDragStat.SetMouseDown(false);
209 bool bAction = IsAction();
210 bool bRet = !bAction && SdrCreateView::MouseButtonUp(rMEvt,pWin);
211 if (!bRet && !IsExtendedMouseEventDispatcherEnabled()) {
212 SdrViewEvent aVEvt;
213 PickAnything(rMEvt,SdrMouseEventKind::BUTTONUP,aVEvt);
214 bRet = DoMouseEvent(aVEvt);
216 return bRet;
219 bool SdrView::MouseMove(const MouseEvent& rMEvt, OutputDevice* pWin)
221 SetActualWin(pWin);
222 maDragStat.SetMouseDown(rMEvt.IsLeft());
223 bool bRet = SdrCreateView::MouseMove(rMEvt,pWin);
224 if (!IsExtendedMouseEventDispatcherEnabled() && !IsTextEditInSelectionMode()) {
225 SdrViewEvent aVEvt;
226 PickAnything(rMEvt,SdrMouseEventKind::MOVE,aVEvt);
227 if (DoMouseEvent(aVEvt)) bRet=true;
230 return bRet;
233 bool SdrView::Command(const CommandEvent& rCEvt, vcl::Window* pWin)
235 SetActualWin(pWin->GetOutDev());
236 bool bRet = SdrCreateView::Command(rCEvt,pWin);
237 return bRet;
240 void SdrView::GetAttributes(SfxItemSet& rTargetSet, bool bOnlyHardAttr) const
242 SdrCreateView::GetAttributes(rTargetSet, bOnlyHardAttr);
245 SdrHitKind SdrView::PickAnything(const MouseEvent& rMEvt, SdrMouseEventKind nEventKind, SdrViewEvent& rVEvt) const
247 rVEvt.mbMouseDown = nEventKind==SdrMouseEventKind::BUTTONDOWN;
248 rVEvt.mbMouseUp = nEventKind==SdrMouseEventKind::BUTTONUP;
249 rVEvt.mnMouseClicks = rMEvt.GetClicks();
250 rVEvt.mnMouseMode = rMEvt.GetMode();
251 rVEvt.mnMouseCode = rMEvt.GetButtons() | rMEvt.GetModifier();
252 const OutputDevice* pOut=mpActualOutDev;
253 if (pOut==nullptr)
255 pOut = GetFirstOutputDevice();
257 Point aPnt(rMEvt.GetPosPixel());
258 if (pOut!=nullptr) aPnt=pOut->PixelToLogic(aPnt);
260 if (mbNegativeX)
262 // Shape's x coordinates are all negated,
263 // Hence negate mouse event's x coord to match.
264 aPnt.setX(-aPnt.X());
267 rVEvt.maLogicPos = aPnt;
268 return PickAnything(aPnt,rVEvt);
271 // Dragging with the Mouse (Move)
272 // Example when creating a rectangle: MouseDown has to happen without a ModKey,
273 // else we usually force a selection (see below).
274 // When pressing Shift, Ctrl and Alt at the same time while doing a MouseMove,
275 // a centered, not snapped square is created.
276 // The dual allocation of Ortho and Shift won't usually create a problem, as the
277 // two functions are in most cases mutually exclusive. Only shearing (the kind
278 // that happens when contorting, not when rotating) can use both functions at
279 // the same time. To get around this, the user can use e. g. help lines.
280 #define MODKEY_NoSnap bCtrl /* temporarily disable snapping */
281 #define MODKEY_Ortho bShift /* ortho */
282 #define MODKEY_Center bAlt /* create/resize centeredly */
283 #define MODKEY_AngleSnap bShift
284 #define MODKEY_CopyDrag bCtrl /* drag and copy */
286 // click somewhere (MouseDown)
287 #define MODKEY_PolyPoly bAlt /* new Poly at InsPt and at Create */
288 #define MODKEY_MultiMark bShift /* MarkObj without doing UnmarkAll first */
289 #define MODKEY_Unmark bAlt /* deselect with a dragged frame */
290 #define MODKEY_ForceMark bCtrl /* force dragging a frame, even if there's an object at cursor position */
291 #define MODKEY_DeepMark bAlt /* MarkNextObj */
292 #define MODKEY_DeepBackw bShift /* MarkNextObj but backwards */
294 SdrHitKind SdrView::PickAnything(const Point& rLogicPos, SdrViewEvent& rVEvt) const
296 const OutputDevice* pOut=mpActualOutDev;
297 if (pOut==nullptr)
299 pOut = GetFirstOutputDevice();
302 // #i73628# Use a non-changeable copy of he logic position
303 const Point aLocalLogicPosition(rLogicPos);
305 bool bEditMode=IsEditMode();
306 bool bPointMode=bEditMode && HasMarkablePoints();
307 bool bGluePointMode=IsGluePointEditMode();
308 bool bInsPolyPt=bPointMode && IsInsObjPointMode() && IsInsObjPointPossible();
309 bool bInsGluePt=bGluePointMode && IsInsGluePointMode() && IsInsGluePointPossible();
310 bool bIsTextEdit=IsTextEdit();
311 bool bTextEditHit=IsTextEditHit(aLocalLogicPosition);
312 bool bTextEditSel=IsTextEditInSelectionMode();
313 bool bShift = (rVEvt.mnMouseCode & KEY_SHIFT) != 0;
314 bool bCtrl = (rVEvt.mnMouseCode & KEY_MOD1) != 0;
315 bool bAlt = (rVEvt.mnMouseCode & KEY_MOD2) != 0;
316 SdrHitKind eHit=SdrHitKind::NONE;
317 SdrHdl* pHdl=pOut!=nullptr && !bTextEditSel ? PickHandle(aLocalLogicPosition) : nullptr;
318 SdrPageView* pPV=nullptr;
319 SdrObject* pObj=nullptr;
320 SdrObject* pHitObj=nullptr;
321 bool bHitPassDirect=true;
322 sal_uInt16 nHlplIdx=0;
323 sal_uInt16 nGlueId=0;
324 if (bTextEditHit || bTextEditSel)
326 eHit=SdrHitKind::TextEdit;
328 else if (pHdl!=nullptr)
330 eHit=SdrHitKind::Handle; // handle is hit: highest priority
332 else if (bEditMode && IsHlplVisible() && IsHlplFront() && pOut!=nullptr && PickHelpLine(aLocalLogicPosition,mnHitTolLog,*pOut,nHlplIdx,pPV))
334 eHit=SdrHitKind::HelpLine; // help line in the foreground hit: can be moved now
336 else if (bGluePointMode && PickGluePoint(aLocalLogicPosition,pObj,nGlueId,pPV))
338 eHit=SdrHitKind::Gluepoint; // deselected gluepoint hit
340 else if ((pHitObj = PickObj(aLocalLogicPosition,mnHitTolLog,pPV,SdrSearchOptions::DEEP|SdrSearchOptions::MARKED,&pObj,&bHitPassDirect)))
342 eHit=SdrHitKind::MarkedObject;
343 sdr::table::SdrTableObj* pTableObj = dynamic_cast< sdr::table::SdrTableObj* >( pObj );
344 if( pTableObj )
346 sal_Int32 nX = 0, nY = 0;
347 switch( pTableObj->CheckTableHit( aLocalLogicPosition, nX, nY ) )
349 case sdr::table::TableHitKind::Cell:
350 eHit = SdrHitKind::Cell;
351 break;
352 case sdr::table::TableHitKind::CellTextArea:
353 eHit = SdrHitKind::TextEditObj;
354 break;
355 default:
356 break;
360 else if ((pHitObj = PickObj(aLocalLogicPosition,mnHitTolLog,pPV,SdrSearchOptions::DEEP|SdrSearchOptions::ALSOONMASTER|SdrSearchOptions::WHOLEPAGE,&pObj,&bHitPassDirect)))
362 // MasterPages and WholePage for Macro and URL
363 eHit=SdrHitKind::UnmarkedObject;
364 sdr::table::SdrTableObj* pTableObj = dynamic_cast< sdr::table::SdrTableObj* >( pObj );
365 if( pTableObj )
367 sal_Int32 nX = 0, nY = 0;
368 switch( pTableObj->CheckTableHit( aLocalLogicPosition, nX, nY, mnHitTolLog ) )
370 case sdr::table::TableHitKind::Cell:
371 eHit = SdrHitKind::Cell;
372 break;
373 case sdr::table::TableHitKind::CellTextArea:
374 // Keep state on UnmarkedObject to allow the below
375 // 'check for URL field' to be executed, else popups
376 // for e.g. URL links when hoovering and clicking
377 // them will not work. Tried several other changes,
378 // but this one safely keeps existing behaviour as-is.
379 // Except for the LOK. LOK doesn't have hoovering popup
380 // feature.
381 eHit = comphelper::LibreOfficeKit::isActive() ? SdrHitKind::TextEditObj : SdrHitKind::UnmarkedObject;
382 break;
383 default:
384 break;
388 else if (bEditMode && IsHlplVisible() && !IsHlplFront() && pOut!=nullptr && PickHelpLine(aLocalLogicPosition,mnHitTolLog,*pOut,nHlplIdx,pPV))
390 eHit=SdrHitKind::HelpLine; // help line in foreground hit: can be moved now
392 if (eHit==SdrHitKind::UnmarkedObject)
394 bool bRoot=pObj->HasMacro();
395 bool bDeep=pObj!=pHitObj && pHitObj->HasMacro();
396 bool bMid=false; // Have we hit upon a grouped group with a macro?
397 SdrObject* pMidObj=nullptr;
398 if (pObj!=pHitObj)
400 SdrObject* pObjTmp=pHitObj->getParentSdrObjectFromSdrObject();
401 if (pObjTmp==pObj) pObjTmp=nullptr;
402 while (pObjTmp!=nullptr)
404 if (pObjTmp->HasMacro())
406 bMid=true;
407 pMidObj=pObjTmp;
409 pObjTmp=pObjTmp->getParentSdrObjectFromSdrObject();
410 if (pObjTmp==pObj) pObjTmp=nullptr;
414 if (bDeep || bMid || bRoot)
416 SdrObjMacroHitRec aHitRec;
417 aHitRec.aPos=aLocalLogicPosition;
418 aHitRec.nTol=mnHitTolLog;
419 aHitRec.pVisiLayer=&pPV->GetVisibleLayers();
420 aHitRec.pPageView=pPV;
421 if (bDeep) bDeep=pHitObj->IsMacroHit(aHitRec);
422 if (bMid ) bMid =pMidObj->IsMacroHit(aHitRec);
423 if (bRoot) bRoot=pObj->IsMacroHit(aHitRec);
424 if (bRoot || bMid || bDeep)
426 // Priorities: 1. Root, 2. Mid, 3. Deep
427 rVEvt.mpRootObj = pObj;
428 if (!bRoot) pObj=pMidObj;
429 if (!bRoot && !bMid) pObj=pHitObj;
430 eHit=SdrHitKind::Macro;
434 // check for URL field
435 if (eHit==SdrHitKind::UnmarkedObject)
437 SdrTextObj* pTextObj=DynCastSdrTextObj( pHitObj );
438 if (pTextObj!=nullptr && pTextObj->HasText())
440 // use the primitive-based HitTest which is more accurate anyways. It
441 // will correctly handle rotated/mirrored/sheared/scaled text and can
442 // now return a HitContainer containing the primitive hierarchy of the
443 // primitive that triggered the hit. The first entry is that primitive,
444 // the others are the full stack of primitives leading to that one which
445 // includes grouping primitives (like TextHierarchyPrimitives we deed here)
446 // but also all decomposed ones which lead to the creation of that primitive
447 drawinglayer::primitive2d::Primitive2DContainer aHitContainer;
448 const bool bTEHit(pPV && SdrObjectPrimitiveHit(*pTextObj, aLocalLogicPosition, {0, 0}, *pPV, &pPV->GetVisibleLayers(), true, &aHitContainer));
450 if (bTEHit && !aHitContainer.empty())
452 // search for TextHierarchyFieldPrimitive2D which contains the needed information
453 // about a possible URLField
454 const drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D* pTextHierarchyFieldPrimitive2D = nullptr;
456 for (const drawinglayer::primitive2d::Primitive2DReference& xReference : aHitContainer)
458 auto pBasePrimitive = xReference.get();
459 if (pBasePrimitive && pBasePrimitive->getPrimitive2DID() == PRIMITIVE2D_ID_TEXTHIERARCHYFIELDPRIMITIVE2D)
461 pTextHierarchyFieldPrimitive2D = static_cast<const drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D*>(pBasePrimitive);
462 break;
466 if (nullptr != pTextHierarchyFieldPrimitive2D)
468 if (drawinglayer::primitive2d::FieldType::FIELD_TYPE_URL == pTextHierarchyFieldPrimitive2D->getType())
470 // problem with the old code is that a *pointer* to an instance of
471 // SvxURLField is set in the Event which is per se not good since that
472 // data comes from a temporary EditEngine's data and could vanish any
473 // moment. Have to replace for now with a static instance that gets
474 // filled/initialized from the original data held in the TextHierarchyField-
475 // Primitive2D (see impTextBreakupHandler::impCheckFieldPrimitive).
476 // Unfortunately things like 'TargetFrame' are still used in Calc, so this
477 // can currently not get replaced. For the future the Name/Value vector or
478 // the TextHierarchyFieldPrimitive2D itself should/will be used for handling
479 // that data
480 static SvxURLField aSvxURLField;
482 aSvxURLField.SetURL(pTextHierarchyFieldPrimitive2D->getValue(u"URL"_ustr));
483 aSvxURLField.SetRepresentation(pTextHierarchyFieldPrimitive2D->getValue(u"Representation"_ustr));
484 aSvxURLField.SetTargetFrame(pTextHierarchyFieldPrimitive2D->getValue(u"TargetFrame"_ustr));
485 const OUString aFormat(pTextHierarchyFieldPrimitive2D->getValue(u"SvxURLFormat"_ustr));
487 if (!aFormat.isEmpty())
489 aSvxURLField.SetFormat(static_cast<SvxURLFormat>(aFormat.toInt32()));
492 // set HitKind and pointer to local static instance in the Event
493 // to comply to old stuff
494 eHit = SdrHitKind::UrlField;
495 rVEvt.mpURLField = &aSvxURLField;
500 if (eHit==SdrHitKind::UnmarkedObject && !pHitObj->getHyperlink().isEmpty())
502 static SvxURLField aSvxURLField;
503 aSvxURLField.SetURL(pHitObj->getHyperlink());
504 rVEvt.mpURLField = &aSvxURLField;
505 eHit = SdrHitKind::UrlField;
509 if (bHitPassDirect &&
510 (eHit==SdrHitKind::MarkedObject || eHit==SdrHitKind::UnmarkedObject) &&
511 (IsTextTool() || (IsEditMode() && IsQuickTextEditMode())) && pHitObj->HasTextEdit())
513 auto pTextObj = DynCastSdrTextObj(pHitObj);
515 // Around the TextEditArea there's a border to select without going into text edit mode.
516 tools::Rectangle aBoundRect;
517 // Force to SnapRect when Fontwork
518 if (pTextObj && pTextObj->IsFontwork())
519 aBoundRect = pHitObj->GetSnapRect();
520 else if (pTextObj && !pTextObj->GetGeoStat().m_nRotationAngle
521 && !pTextObj->GetGeoStat().m_nShearAngle)
523 pTextObj->TakeTextEditArea(nullptr, nullptr, &aBoundRect, nullptr);
525 else
526 aBoundRect = pHitObj->GetCurrentBoundRect();
528 sal_Int32 nTolerance(mnHitTolLog);
529 bool bBoundRectHit(false);
531 if(pOut)
533 nTolerance = pOut->PixelToLogic(Size(2, 0)).Width();
536 if( (aLocalLogicPosition.X() >= aBoundRect.Left() - nTolerance && aLocalLogicPosition.X() <= aBoundRect.Left() + nTolerance)
537 || (aLocalLogicPosition.X() >= aBoundRect.Right() - nTolerance && aLocalLogicPosition.X() <= aBoundRect.Right() + nTolerance)
538 || (aLocalLogicPosition.Y() >= aBoundRect.Top() - nTolerance && aLocalLogicPosition.Y() <= aBoundRect.Top() + nTolerance)
539 || (aLocalLogicPosition.Y() >= aBoundRect.Bottom() - nTolerance && aLocalLogicPosition.Y() <= aBoundRect.Bottom() + nTolerance))
541 bBoundRectHit = true;
544 if(!bBoundRectHit && aBoundRect.Contains(aLocalLogicPosition))
546 bool bTEHit(pPV
547 && SdrObjectPrimitiveHit(*pHitObj, aLocalLogicPosition, { 2000.0, 0.0 },
548 *pPV, &pPV->GetVisibleLayers(), true));
550 // TextEdit attached to an object in a locked layer
551 if (bTEHit && pPV->GetLockedLayers().IsSet(pHitObj->GetLayer()))
553 bTEHit=false;
556 if (bTEHit)
558 rVEvt.mpRootObj=pObj;
559 pObj=pHitObj;
560 eHit=SdrHitKind::TextEditObj;
564 if (!bHitPassDirect && eHit==SdrHitKind::UnmarkedObject) {
565 eHit=SdrHitKind::NONE;
566 pObj=nullptr;
567 pPV=nullptr;
569 bool bMouseLeft = (rVEvt.mnMouseCode & MOUSE_LEFT) != 0;
570 bool bMouseRight = (rVEvt.mnMouseCode & MOUSE_RIGHT) != 0;
571 bool bMouseDown = rVEvt.mbMouseDown;
572 bool bMouseUp = rVEvt.mbMouseUp;
573 SdrEventKind eEvent=SdrEventKind::NONE;
574 bool bIsAction=IsAction();
576 if (bIsAction)
578 if (bMouseDown)
580 if (bMouseRight) eEvent=SdrEventKind::BackAction;
582 else if (bMouseUp)
584 if (bMouseLeft)
586 eEvent=SdrEventKind::EndAction;
587 if (IsDragObj())
589 eEvent=SdrEventKind::EndDrag;
591 else if (IsCreateObj() || IsInsObjPoint())
593 eEvent=IsCreateObj() ? SdrEventKind::EndCreate : SdrEventKind::EndInsertObjPoint;
595 else if (IsMarking())
597 eEvent=SdrEventKind::EndMark;
598 if (!maDragStat.IsMinMoved())
600 eEvent=SdrEventKind::BrkMark;
601 rVEvt.mbAddMark = MODKEY_MultiMark;
606 else
608 eEvent=SdrEventKind::MoveAction;
611 else if (eHit==SdrHitKind::TextEdit)
613 eEvent=SdrEventKind::TextEdit;
615 else if (bMouseDown && bMouseLeft)
617 if (rVEvt.mnMouseClicks == 2 && rVEvt.mnMouseCode == MOUSE_LEFT && pObj!=nullptr && pHitObj!=nullptr && pHitObj->HasTextEdit() && eHit==SdrHitKind::MarkedObject)
619 rVEvt.mpRootObj = pObj;
620 pObj=pHitObj;
621 eEvent=SdrEventKind::BeginTextEdit;
623 else if (MODKEY_ForceMark && eHit!=SdrHitKind::UrlField)
625 eEvent=SdrEventKind::BeginMark; // AddMark,Unmark */
627 else if (eHit==SdrHitKind::HelpLine)
629 eEvent=SdrEventKind::BeginDragHelpline; // nothing, actually
631 else if (eHit==SdrHitKind::Gluepoint)
633 eEvent=SdrEventKind::MarkGluePoint; // AddMark+Drag
634 rVEvt.mbAddMark = MODKEY_MultiMark || MODKEY_DeepMark; // if not hit with Deep
636 else if (eHit==SdrHitKind::Handle)
638 eEvent=SdrEventKind::BeginDragObj; // Mark+Drag,AddMark+Drag,DeepMark+Drag,Unmark
639 bool bGlue=pHdl->GetKind()==SdrHdlKind::Glue;
640 bool bPoly=!bGlue && IsPointMarkable(*pHdl);
641 bool bMarked=bGlue || (bPoly && pHdl->IsSelected());
642 if (bGlue || bPoly)
644 eEvent=bGlue ? SdrEventKind::MarkGluePoint : SdrEventKind::MarkPoint;
645 if (MODKEY_DeepMark)
647 rVEvt.mbAddMark = true;
648 rVEvt.mbPrevNextMark = true;
649 rVEvt.mbMarkPrev = MODKEY_DeepBackw;
651 else if (MODKEY_MultiMark)
653 rVEvt.mbAddMark = true;
654 rVEvt.mbUnmark = bMarked; // Toggle
655 if (bGlue)
657 pObj=pHdl->GetObj();
658 nGlueId=static_cast<sal_uInt16>(pHdl->GetObjHdlNum());
661 else if (bMarked)
663 eEvent=SdrEventKind::BeginDragObj; // don't change MarkState, only change Drag
667 else if (bInsPolyPt && (MODKEY_PolyPoly || (!MODKEY_MultiMark && !MODKEY_DeepMark)))
669 eEvent=SdrEventKind::BeginInsertObjPoint;
671 else if (bInsGluePt && !MODKEY_MultiMark && !MODKEY_DeepMark)
673 eEvent=SdrEventKind::BeginInsertGluePoint;
675 else if (eHit==SdrHitKind::TextEditObj)
677 eEvent=SdrEventKind::BeginTextEdit; // AddMark+Drag,DeepMark+Drag,Unmark
678 if (MODKEY_MultiMark || MODKEY_DeepMark)
679 { // if not hit with Deep
680 eEvent=SdrEventKind::MarkObj;
683 else if (eHit==SdrHitKind::Macro)
685 eEvent=SdrEventKind::BeginMacroObj; // AddMark+Drag
686 if (MODKEY_MultiMark || MODKEY_DeepMark)
687 { // if not hit with Deep
688 eEvent=SdrEventKind::MarkObj;
691 else if (eHit==SdrHitKind::UrlField)
693 eEvent=SdrEventKind::ExecuteUrl; // AddMark+Drag
694 if (MODKEY_MultiMark || MODKEY_DeepMark)
695 { // if not hit with Deep
696 eEvent=SdrEventKind::MarkObj;
699 else if (eHit==SdrHitKind::MarkedObject)
701 eEvent=SdrEventKind::BeginDragObj; // DeepMark+Drag,Unmark
703 if (MODKEY_MultiMark || MODKEY_DeepMark)
704 { // if not hit with Deep
705 eEvent=SdrEventKind::MarkObj;
708 else if (IsCreateMode())
710 eEvent=SdrEventKind::BeginCreateObj; // nothing, actually
712 else if (eHit==SdrHitKind::UnmarkedObject)
714 eEvent=SdrEventKind::MarkObj; // AddMark+Drag
716 else
718 eEvent=SdrEventKind::BeginMark;
721 if (eEvent==SdrEventKind::MarkObj)
723 rVEvt.mbAddMark = MODKEY_MultiMark || MODKEY_DeepMark; // if not hit with Deep
724 rVEvt.mbPrevNextMark = MODKEY_DeepMark;
725 rVEvt.mbMarkPrev = MODKEY_DeepMark && MODKEY_DeepBackw;
727 if (eEvent==SdrEventKind::BeginMark)
729 rVEvt.mbAddMark = MODKEY_MultiMark;
730 rVEvt.mbUnmark = MODKEY_Unmark;
733 rVEvt.mbIsAction = bIsAction;
734 rVEvt.mbIsTextEdit = bIsTextEdit;
735 rVEvt.maLogicPos = aLocalLogicPosition;
736 rVEvt.mpHdl = pHdl;
737 rVEvt.mpObj = pObj;
738 if (rVEvt.mpRootObj == nullptr)
739 rVEvt.mpRootObj = pObj;
740 rVEvt.mpPV = pPV;
741 rVEvt.mnHlplIdx = nHlplIdx;
742 rVEvt.mnGlueId = nGlueId;
743 rVEvt.meHit = eHit;
744 rVEvt.meEvent = eEvent;
745 #ifdef DGB_UTIL
746 if (rVEvt.mpRootObj != nullptr)
748 if (rVEvt.mpRootObj->getParentSdrObjListFromSdrObject() != rVEvt.mpPV->GetObjList())
750 OSL_FAIL("SdrView::PickAnything(): pRootObj->getParentSdrObjListFromSdrObject()!=pPV->GetObjList() !");
753 #endif
754 return eHit;
757 bool SdrView::DoMouseEvent(const SdrViewEvent& rVEvt)
759 bool bRet=false;
760 SdrHitKind eHit = rVEvt.meHit;
761 Point aLogicPos(rVEvt.maLogicPos);
763 bool bShift = (rVEvt.mnMouseCode & KEY_SHIFT) != 0;
764 bool bCtrl = (rVEvt.mnMouseCode & KEY_MOD1) != 0;
765 bool bAlt = (rVEvt.mnMouseCode & KEY_MOD2) != 0;
766 bool bMouseLeft = (rVEvt.mnMouseCode & MOUSE_LEFT) != 0;
767 bool bMouseDown = rVEvt.mbMouseDown;
768 bool bMouseUp = rVEvt.mbMouseUp;
769 if (bMouseDown) {
770 if (bMouseLeft) maDragStat.SetMouseDown(true);
771 } else if (bMouseUp) {
772 if (bMouseLeft) maDragStat.SetMouseDown(false);
773 } else { // else, MouseMove
774 maDragStat.SetMouseDown(bMouseLeft);
777 #ifdef MODKEY_NoSnap
778 SetSnapEnabled(!MODKEY_NoSnap);
779 #endif
780 #ifdef MODKEY_Ortho
781 SetOrtho(MODKEY_Ortho!=IsOrthoDesired());
782 #endif
783 #ifdef MODKEY_AngleSnap
784 SetAngleSnapEnabled(MODKEY_AngleSnap);
785 #endif
786 #ifdef MODKEY_CopyDrag
787 SetDragWithCopy(MODKEY_CopyDrag);
788 #endif
789 #ifdef MODKEY_Center
790 SetCreate1stPointAsCenter(MODKEY_Center);
791 SetResizeAtCenter(MODKEY_Center);
792 SetCrookAtCenter(MODKEY_Center);
793 #endif
794 if (bMouseLeft && bMouseDown && rVEvt.mbIsTextEdit && (eHit==SdrHitKind::UnmarkedObject || eHit==SdrHitKind::NONE)) {
795 SdrEndTextEdit(); // User has clicked beneath object, exit edit mode.
796 // pHdl is invalid, then, that shouldn't matter, though, as we expect
797 // pHdl==NULL (because of eHit).
799 switch (rVEvt.meEvent)
801 case SdrEventKind::NONE: bRet=false; break;
802 case SdrEventKind::TextEdit: bRet=false; break; // Events handled by the OutlinerView are not taken into account here.
803 case SdrEventKind::MoveAction: MovAction(aLogicPos); bRet=true; break;
804 case SdrEventKind::EndAction: EndAction(); bRet=true; break;
805 case SdrEventKind::BackAction: BckAction(); bRet=true; break;
806 case SdrEventKind::EndMark : EndAction(); bRet=true; break;
807 case SdrEventKind::BrkMark : {
808 BrkAction();
809 if (!MarkObj(aLogicPos, mnHitTolLog, rVEvt.mbAddMark))
811 // No object hit. Do the following:
812 // 1. deselect any selected gluepoints
813 // 2. deselect any selected polygon points
814 // 3. deselect any selected objects
815 if (!rVEvt.mbAddMark) UnmarkAll();
817 bRet=true;
818 } break;
819 case SdrEventKind::EndCreate: { // if necessary, MarkObj
820 SdrCreateCmd eCmd=SdrCreateCmd::NextPoint;
821 if (MODKEY_PolyPoly) eCmd=SdrCreateCmd::NextObject;
822 if (rVEvt.mnMouseClicks > 1) eCmd=SdrCreateCmd::ForceEnd;
823 if (!EndCreateObj(eCmd)) { // Don't evaluate event for Create? -> Select
824 if (eHit==SdrHitKind::UnmarkedObject || eHit==SdrHitKind::TextEdit) {
825 MarkObj(rVEvt.mpRootObj, rVEvt.mpPV);
826 if (eHit==SdrHitKind::TextEdit)
828 bool bRet2(mpActualOutDev && OUTDEV_WINDOW == mpActualOutDev->GetOutDevType() &&
829 SdrBeginTextEdit(rVEvt.mpObj, rVEvt.mpPV, mpActualOutDev->GetOwnerWindow()));
831 if(bRet2)
833 MouseEvent aMEvt(mpActualOutDev->LogicToPixel(aLogicPos), 1,
834 rVEvt.mnMouseMode,rVEvt.mnMouseCode,rVEvt.mnMouseCode);
836 OutlinerView* pOLV=GetTextEditOutlinerView();
837 if (pOLV!=nullptr) {
838 pOLV->MouseButtonDown(aMEvt); // event for the Outliner, but without double-click
839 pOLV->MouseButtonUp(aMEvt); // event for the Outliner, but without double-click
843 bRet=true; // object is selected and (if necessary) TextEdit is started
844 } else bRet=false; // canceled Create, nothing else
845 } else bRet=true; // return true for EndCreate
846 } break;
847 case SdrEventKind::EndDrag: {
848 bRet=EndDragObj(IsDragWithCopy());
849 ForceMarkedObjToAnotherPage(); // TODO: Undo+bracing missing!
850 } break;
851 case SdrEventKind::MarkObj: { // + (if applicable) BegDrag
852 if (!rVEvt.mbAddMark) UnmarkAllObj();
853 bool bUnmark = rVEvt.mbUnmark;
854 if (rVEvt.mbPrevNextMark) {
855 bRet=MarkNextObj(aLogicPos, mnHitTolLog, rVEvt.mbMarkPrev);
856 } else {
857 const SdrMarkList& rMarkList = GetMarkedObjectList();
858 rMarkList.ForceSort();
859 const size_t nCount0=rMarkList.GetMarkCount();
860 bRet=MarkObj(aLogicPos, mnHitTolLog, rVEvt.mbAddMark);
861 rMarkList.ForceSort();
862 const size_t nCount1=rMarkList.GetMarkCount();
863 bUnmark=nCount1<nCount0;
865 if (!bUnmark) {
866 BegDragObj(aLogicPos,nullptr,nullptr,mnMinMovLog);
867 bRet=true;
869 } break;
870 case SdrEventKind::MarkPoint: { // + (if applicable) BegDrag
871 if (!rVEvt.mbAddMark) UnmarkAllPoints();
872 if (rVEvt.mbPrevNextMark) {
873 MarkNextPoint();
874 bRet=false;
875 } else {
876 bRet = MarkPoint(*rVEvt.mpHdl, rVEvt.mbUnmark);
878 if (!rVEvt.mbUnmark && !rVEvt.mbPrevNextMark) {
879 BegDragObj(aLogicPos, nullptr, rVEvt.mpHdl, mnMinMovLog);
880 bRet=true;
882 } break;
883 case SdrEventKind::MarkGluePoint: { // + (if applicable) BegDrag
884 if (!rVEvt.mbAddMark) UnmarkAllGluePoints();
885 if (rVEvt.mbPrevNextMark) {
886 MarkNextGluePoint();
887 bRet=false;
888 } else {
889 bRet=MarkGluePoint(rVEvt.mpObj,rVEvt.mnGlueId,rVEvt.mbUnmark);
891 if (!rVEvt.mbUnmark && !rVEvt.mbPrevNextMark) {
892 SdrHdl* pHdl = GetGluePointHdl(rVEvt.mpObj, rVEvt.mnGlueId);
893 BegDragObj(aLogicPos,nullptr,pHdl,mnMinMovLog);
894 bRet=true;
896 } break;
897 case SdrEventKind::BeginMark: bRet = BegMark(aLogicPos,rVEvt.mbAddMark,rVEvt.mbUnmark); break;
898 case SdrEventKind::BeginInsertObjPoint: bRet = BegInsObjPoint(aLogicPos, MODKEY_PolyPoly); break;
899 case SdrEventKind::EndInsertObjPoint: {
900 SdrCreateCmd eCmd=SdrCreateCmd::NextPoint;
901 if (MODKEY_PolyPoly) eCmd=SdrCreateCmd::NextObject;
902 if (rVEvt.mnMouseClicks > 1) eCmd = SdrCreateCmd::ForceEnd;
903 EndInsObjPoint(eCmd);
904 bRet=true;
905 } break;
906 case SdrEventKind::BeginInsertGluePoint: bRet=BegInsGluePoint(aLogicPos); break;
907 case SdrEventKind::BeginDragHelpline: bRet = BegDragHelpLine(rVEvt.mnHlplIdx,rVEvt.mpPV); break;
908 case SdrEventKind::BeginDragObj: bRet=BegDragObj(aLogicPos, nullptr, rVEvt.mpHdl, mnMinMovLog); break;
909 case SdrEventKind::BeginCreateObj: {
910 if (mnCurrentInvent==SdrInventor::Default && mnCurrentIdent==SdrObjKind::Caption) {
911 tools::Long nHgt=SdrEngineDefaults::GetFontHeight();
912 bRet=BegCreateCaptionObj(aLogicPos,Size(5*nHgt,2*nHgt));
913 } else bRet=BegCreateObj(aLogicPos);
914 } break;
915 case SdrEventKind::BeginMacroObj: {
916 BegMacroObj(aLogicPos, mnHitTolLog, rVEvt.mpObj, rVEvt.mpPV, mpActualOutDev->GetOwnerWindow());
917 bRet=false;
918 } break;
919 case SdrEventKind::BeginTextEdit: {
920 if (!IsObjMarked(rVEvt.mpObj)) {
921 UnmarkAllObj();
922 MarkObj(rVEvt.mpRootObj,rVEvt.mpPV);
925 bRet = mpActualOutDev && OUTDEV_WINDOW == mpActualOutDev->GetOutDevType()&&
926 SdrBeginTextEdit(rVEvt.mpObj, rVEvt.mpPV, mpActualOutDev->GetOwnerWindow());
928 if(bRet)
930 MouseEvent aMEvt(mpActualOutDev->LogicToPixel(aLogicPos),
931 1, rVEvt.mnMouseMode, rVEvt.mnMouseCode, rVEvt.mnMouseCode);
932 OutlinerView* pOLV=GetTextEditOutlinerView();
933 if (pOLV!=nullptr) pOLV->MouseButtonDown(aMEvt); // event for the Outliner, but without double-click
935 } break;
936 default: break;
937 } // switch
938 if (bRet && mpActualOutDev && mpActualOutDev->GetOutDevType()==OUTDEV_WINDOW) {
939 vcl::Window* pWin=mpActualOutDev->GetOwnerWindow();
940 // left mouse button pressed?
941 bool bLeftDown = (rVEvt.mnMouseCode & MOUSE_LEFT) != 0 && rVEvt.mbMouseDown;
942 // left mouse button released?
943 bool bLeftUp = (rVEvt.mnMouseCode & MOUSE_LEFT) != 0 && rVEvt.mbMouseUp;
944 // left mouse button pressed or held?
945 bool bLeftDown1=(rVEvt.mnMouseCode & MOUSE_LEFT) != 0 && !rVEvt.mbMouseUp;
946 pWin->SetPointer(GetPreferredPointer(rVEvt.maLogicPos, pWin->GetOutDev(),
947 rVEvt.mnMouseCode & (KEY_SHIFT|KEY_MOD1|KEY_MOD2),bLeftDown1));
948 bool bAction=IsAction();
949 if (bLeftDown && bAction)
950 pWin->CaptureMouse();
951 else if (bLeftUp || (rVEvt.mbIsAction && !bAction))
952 pWin->ReleaseMouse();
954 return bRet;
957 PointerStyle SdrView::GetPreferredPointer(const Point& rMousePos, const OutputDevice* pOut, sal_uInt16 nModifier, bool bLeftDown) const
959 // Actions
960 if (IsCreateObj())
962 return mpCurrentCreate->GetCreatePointer();
964 if (mpCurrentSdrDragMethod)
966 return mpCurrentSdrDragMethod->GetSdrDragPointer();
968 if (IsMarkObj() || IsMarkPoints() || IsMarkGluePoints() || IsSetPageOrg()) return PointerStyle::Arrow;
969 if (IsDragHelpLine()) return GetDraggedHelpLinePointer();
970 if (IsMacroObj()) {
971 SdrObjMacroHitRec aHitRec;
972 aHitRec.aPos=pOut->LogicToPixel(rMousePos);
973 aHitRec.nTol=m_nMacroTol;
974 aHitRec.pVisiLayer=&m_pMacroPV->GetVisibleLayers();
975 aHitRec.pPageView=m_pMacroPV;
976 return m_pMacroObj->GetMacroPointer(aHitRec);
979 // TextEdit, ObjEdit, Macro
980 if (IsTextEdit() && (IsTextEditInSelectionMode() || IsTextEditHit(rMousePos)))
982 if(!pOut || IsTextEditInSelectionMode())
984 if (mpTextEditOutliner->IsVertical())
985 return PointerStyle::TextVertical;
986 else
987 return PointerStyle::Text;
989 // Outliner should return something here...
990 Point aPos(pOut->LogicToPixel(rMousePos));
991 PointerStyle aPointer(mpTextEditOutlinerView->GetPointer(aPos));
992 if (aPointer==PointerStyle::Arrow)
994 if (mpTextEditOutliner->IsVertical())
995 aPointer = PointerStyle::TextVertical;
996 else
997 aPointer = PointerStyle::Text;
999 return aPointer;
1002 SdrViewEvent aVEvt;
1003 aVEvt.mnMouseCode = (nModifier&(KEY_SHIFT|KEY_MOD1|KEY_MOD2))|MOUSE_LEFT; // to see what would happen on MouseLeftDown
1004 aVEvt.mbMouseDown = !bLeftDown; // What if ..?
1005 aVEvt.mbMouseUp = bLeftDown; // What if ..?
1006 if (pOut!=nullptr)
1007 const_cast<SdrView*>(this)->SetActualWin(pOut);
1008 SdrHitKind eHit=PickAnything(rMousePos,aVEvt);
1009 SdrEventKind eEvent = aVEvt.meEvent;
1010 switch (eEvent)
1012 case SdrEventKind::BeginCreateObj:
1013 return maCurrentCreatePointer;
1014 case SdrEventKind::MarkObj:
1015 return PointerStyle::Move;
1016 case SdrEventKind::BeginMark:
1017 return PointerStyle::Arrow;
1018 case SdrEventKind::MarkPoint:
1019 case SdrEventKind::MarkGluePoint:
1020 return PointerStyle::MovePoint;
1021 case SdrEventKind::BeginInsertObjPoint:
1022 case SdrEventKind::BeginInsertGluePoint:
1023 return PointerStyle::Cross;
1024 case SdrEventKind::ExecuteUrl:
1025 return PointerStyle::RefHand;
1026 case SdrEventKind::BeginMacroObj:
1028 SdrObjMacroHitRec aHitRec;
1029 aHitRec.aPos = aVEvt.maLogicPos;
1030 aHitRec.nTol=mnHitTolLog;
1031 aHitRec.pVisiLayer = &aVEvt.mpPV->GetVisibleLayers();
1032 aHitRec.pPageView = aVEvt.mpPV;
1033 return aVEvt.mpObj->GetMacroPointer(aHitRec);
1035 default: break;
1036 } // switch
1038 switch(eHit)
1040 case SdrHitKind::Cell:
1041 return PointerStyle::Arrow;
1042 case SdrHitKind::HelpLine :
1043 return aVEvt.mpPV->GetHelpLines()[aVEvt.mnHlplIdx].GetPointer();
1044 case SdrHitKind::Gluepoint:
1045 return PointerStyle::MovePoint;
1046 case SdrHitKind::TextEdit :
1047 case SdrHitKind::TextEditObj:
1049 SdrTextObj* pText = DynCastSdrTextObj(aVEvt.mpObj);
1050 if(pText && pText->HasText())
1052 OutlinerParaObject* pParaObj = pText->GetOutlinerParaObject();
1053 if(pParaObj && pParaObj->IsEffectivelyVertical())
1054 return PointerStyle::TextVertical;
1056 return PointerStyle::Text;
1058 default: break;
1061 bool bMarkHit=eHit==SdrHitKind::MarkedObject;
1062 SdrHdl* pHdl = aVEvt.mpHdl;
1063 // now check the pointers for dragging
1064 if (pHdl!=nullptr || bMarkHit) {
1065 SdrHdlKind eHdl= pHdl!=nullptr ? pHdl->GetKind() : SdrHdlKind::Move;
1066 bool bCorner=pHdl!=nullptr && pHdl->IsCornerHdl();
1067 bool bVertex=pHdl!=nullptr && pHdl->IsVertexHdl();
1068 bool bMov=eHdl==SdrHdlKind::Move;
1069 if (bMov && (meDragMode==SdrDragMode::Move || meDragMode==SdrDragMode::Resize || mbMarkedHitMovesAlways)) {
1070 if (!IsMoveAllowed()) return PointerStyle::Arrow; // because double click or drag & drop is possible
1071 return PointerStyle::Move;
1073 switch (meDragMode) {
1074 case SdrDragMode::Rotate: {
1075 if ((bCorner || bMov) && !IsRotateAllowed(true))
1076 return PointerStyle::NotAllowed;
1078 // are 3D objects selected?
1079 bool b3DObjSelected = false;
1080 const SdrMarkList& rMarkList = GetMarkedObjectList();
1081 for (size_t a=0; !b3DObjSelected && a<rMarkList.GetMarkCount(); ++a) {
1082 SdrObject* pObj = rMarkList.GetMark(a)->GetMarkedSdrObj();
1083 if(DynCastE3dObject(pObj))
1084 b3DObjSelected = true;
1086 // If we have a 3D object, go on despite !IsShearAllowed,
1087 // because then we have a rotation instead of a shear.
1088 if (bVertex && !IsShearAllowed() && !b3DObjSelected)
1089 return PointerStyle::NotAllowed;
1090 if (bMov)
1091 return PointerStyle::Rotate;
1092 } break;
1093 case SdrDragMode::Shear: {
1094 if (bCorner) {
1095 if (!IsDistortAllowed(true) && !IsDistortAllowed()) return PointerStyle::NotAllowed;
1096 else return PointerStyle::RefHand;
1098 if (bVertex && !IsShearAllowed()) return PointerStyle::NotAllowed;
1099 if (bMov) {
1100 if (!IsMoveAllowed()) return PointerStyle::Arrow; // because double click or drag & drop is possible
1101 return PointerStyle::Move;
1103 } break;
1104 case SdrDragMode::Mirror: {
1105 if (bCorner || bVertex || bMov) {
1106 SdrHdl* pH1=maHdlList.GetHdl(SdrHdlKind::Ref1);
1107 SdrHdl* pH2=maHdlList.GetHdl(SdrHdlKind::Ref2);
1108 bool b90=false;
1109 bool b45=false;
1110 if (pH1!=nullptr && pH2!=nullptr) {
1111 Point aDif = pH2->GetPos()-pH1->GetPos();
1112 b90=(aDif.X()==0) || aDif.Y()==0;
1113 b45=b90 || (std::abs(aDif.X())==std::abs(aDif.Y()));
1115 bool bNo=false;
1116 if (!IsMirrorAllowed(true,true)) bNo=true; // any mirroring is forbidden
1117 if (!IsMirrorAllowed() && !b45) bNo=true; // mirroring freely is forbidden
1118 if (!IsMirrorAllowed(true) && !b90) bNo=true; // mirroring horizontally/vertically is allowed
1119 if (bNo) return PointerStyle::NotAllowed;
1120 if (b90) {
1121 return PointerStyle::Mirror;
1123 return PointerStyle::Mirror;
1125 } break;
1127 case SdrDragMode::Transparence:
1129 if(!IsTransparenceAllowed())
1130 return PointerStyle::NotAllowed;
1132 return PointerStyle::RefHand;
1135 case SdrDragMode::Gradient:
1137 if(!IsGradientAllowed())
1138 return PointerStyle::NotAllowed;
1140 return PointerStyle::RefHand;
1143 case SdrDragMode::Crook: {
1144 if (bCorner || bVertex || bMov) {
1145 if (!IsCrookAllowed(true) && !IsCrookAllowed()) return PointerStyle::NotAllowed;
1146 return PointerStyle::Crook;
1148 break;
1151 case SdrDragMode::Crop:
1153 return PointerStyle::Crop;
1156 default: {
1157 if ((bCorner || bVertex) && !IsResizeAllowed(true)) return PointerStyle::NotAllowed;
1160 if (pHdl!=nullptr) return pHdl->GetPointer();
1161 if (bMov) {
1162 if (!IsMoveAllowed()) return PointerStyle::Arrow; // because double click or drag & drop is possible
1163 return PointerStyle::Move;
1166 if (meEditMode==SdrViewEditMode::Create) return maCurrentCreatePointer;
1167 return PointerStyle::Arrow;
1170 constexpr OUString STR_NOTHING = u"nothing"_ustr;
1171 OUString SdrView::GetStatusText()
1173 OUString aName;
1174 OUString aStr = STR_NOTHING;
1176 if (mpCurrentCreate!=nullptr)
1178 aStr=mpCurrentCreate->getSpecialDragComment(maDragStat);
1180 if(aStr.isEmpty())
1182 aName = mpCurrentCreate->TakeObjNameSingul();
1183 aStr = SvxResId(STR_ViewCreateObj);
1186 else if (mpCurrentSdrDragMethod)
1188 if (mbInsPolyPoint || IsInsertGluePoint())
1190 aStr=maInsPointUndoStr;
1192 else
1194 if (maDragStat.IsMinMoved())
1196 SAL_INFO(
1197 "svx.svdraw",
1198 "(" << this << ") " << mpCurrentSdrDragMethod.get());
1199 aStr = mpCurrentSdrDragMethod->GetSdrDragComment();
1203 else if(IsMarkObj())
1205 const SdrMarkList& rMarkList = GetMarkedObjectList();
1206 if(rMarkList.GetMarkCount() != 0)
1208 aStr = SvxResId(STR_ViewMarkMoreObjs);
1210 else
1212 aStr = SvxResId(STR_ViewMarkObjs);
1215 else if(IsMarkPoints())
1217 if(HasMarkedPoints())
1219 aStr = SvxResId(STR_ViewMarkMorePoints);
1221 else
1223 aStr = SvxResId(STR_ViewMarkPoints);
1225 } else if (IsMarkGluePoints())
1227 if(HasMarkedGluePoints())
1229 aStr = SvxResId(STR_ViewMarkMoreGluePoints);
1231 else
1233 aStr = SvxResId(STR_ViewMarkGluePoints);
1236 else if (IsTextEdit() && mpTextEditOutlinerView != nullptr) {
1237 aStr=SvxResId(STR_ViewTextEdit); // "TextEdit - Row y, Column x";
1238 ESelection aSel(mpTextEditOutlinerView->GetSelection());
1239 tools::Long nPar = aSel.end.nPara, nLin = 0, nCol = aSel.end.nIndex;
1240 if (aSel.end.nPara>0) {
1241 for (sal_Int32 nParaNum=0; nParaNum<aSel.end.nPara; nParaNum++) {
1242 nLin += mpTextEditOutliner->GetLineCount(nParaNum);
1245 // A little imperfection:
1246 // At the end of a line of any multi-line paragraph, we display the
1247 // position of the next line of the same paragraph, if there is one.
1248 sal_uInt16 nParaLine = 0;
1249 sal_Int32 nParaLineCount = mpTextEditOutliner->GetLineCount(aSel.end.nPara);
1250 bool bBrk = false;
1251 while (!bBrk)
1253 sal_uInt16 nLen = mpTextEditOutliner->GetLineLen(aSel.end.nPara, nParaLine);
1254 bool bLastLine = (nParaLine == nParaLineCount - 1);
1255 if (nCol>nLen || (!bLastLine && nCol == nLen))
1257 nCol -= nLen;
1258 nLin++;
1259 nParaLine++;
1261 else
1262 bBrk = true;
1264 if (nLen == 0)
1265 bBrk = true; // to be sure
1268 aStr = aStr.replaceFirst("%1", OUString::number(nPar + 1));
1269 aStr = aStr.replaceFirst("%2", OUString::number(nLin + 1));
1270 aStr = aStr.replaceFirst("%3", OUString::number(nCol + 1));
1272 #ifdef DBG_UTIL
1273 aStr += ", Level " + OUString::number(mpTextEditOutliner->GetDepth( aSel.end.nPara ));
1274 #endif
1277 if(aStr == STR_NOTHING)
1279 const SdrMarkList& rMarkList = GetMarkedObjectList();
1280 if (rMarkList.GetMarkCount() != 0) {
1281 aStr = ImpGetDescriptionString(STR_ViewMarked);
1282 if (IsGluePointEditMode()) {
1283 if (HasMarkedGluePoints()) {
1284 aStr = ImpGetDescriptionString(STR_ViewMarked, ImpGetDescriptionOptions::GLUEPOINTS);
1286 } else {
1287 if (HasMarkedPoints()) {
1288 aStr = ImpGetDescriptionString(STR_ViewMarked, ImpGetDescriptionOptions::POINTS);
1291 } else {
1292 aStr.clear();
1295 else if(!aName.isEmpty())
1297 aStr = aStr.replaceFirst("%1", aName);
1300 if(!aStr.isEmpty())
1302 // capitalize first letter
1303 aStr = aStr.replaceAt(0, 1, OUString(aStr[0]).toAsciiUpperCase());
1305 return aStr;
1308 SdrViewContext SdrView::GetContext() const
1310 if( IsGluePointEditMode() )
1311 return SdrViewContext::GluePointEdit;
1313 const SdrMarkList& rMarkList = GetMarkedObjectList();
1314 const size_t nMarkCount = rMarkList.GetMarkCount();
1316 if( HasMarkablePoints() && !IsFrameHandles() )
1318 bool bPath=true;
1319 for( size_t nMarkNum = 0; nMarkNum < nMarkCount && bPath; ++nMarkNum )
1320 if (dynamic_cast<const SdrPathObj*>(rMarkList.GetMark(nMarkNum)->GetMarkedSdrObj()) == nullptr)
1321 bPath=false;
1323 if( bPath )
1324 return SdrViewContext::PointEdit;
1327 if( rMarkList.GetMarkCount() )
1329 bool bGraf = true, bMedia = true, bTable = true;
1331 for( size_t nMarkNum = 0; nMarkNum < nMarkCount && ( bGraf || bMedia ); ++nMarkNum )
1333 const SdrObject* pMarkObj = rMarkList.GetMark(nMarkNum)->GetMarkedSdrObj();
1334 DBG_ASSERT( pMarkObj, "SdrView::GetContext(), null pointer in mark list!" );
1336 if( !pMarkObj )
1337 continue;
1339 if( dynamic_cast<const SdrGrafObj*>( pMarkObj) == nullptr )
1340 bGraf = false;
1342 if( dynamic_cast<const SdrMediaObj*>( pMarkObj) == nullptr )
1343 bMedia = false;
1345 if( dynamic_cast<const sdr::table::SdrTableObj* >( pMarkObj ) == nullptr )
1346 bTable = false;
1349 if( bGraf )
1350 return SdrViewContext::Graphic;
1351 else if( bMedia )
1352 return SdrViewContext::Media;
1353 else if( bTable )
1354 return SdrViewContext::Table;
1357 return SdrViewContext::Standard;
1360 void SdrView::MarkAll()
1362 if (IsTextEdit()) {
1363 GetTextEditOutlinerView()->SetSelection(ESelection::All());
1364 } else if (IsGluePointEditMode()) MarkAllGluePoints();
1365 else if (HasMarkablePoints()) MarkAllPoints();
1366 else {
1367 // check for table
1368 bool bMarkAll = true;
1369 const SdrMarkList& rMarkList = GetMarkedObjectList();
1370 if (rMarkList.GetMarkCount() == 1)
1372 const SdrObject* pObj(rMarkList.GetMark(0)->GetMarkedSdrObj());
1373 SdrView* pView = this;
1374 if (pObj && (pObj->GetObjInventor() == SdrInventor::Default)
1375 && (pObj->GetObjIdentifier() == SdrObjKind::Table))
1377 mxSelectionController.clear();
1378 mxSelectionController = sdr::table::CreateTableController(
1379 *pView, static_cast<const sdr::table::SdrTableObj&>(*pObj),
1380 mxLastSelectionController);
1382 if (mxSelectionController.is())
1384 mxLastSelectionController.clear();
1385 mxSelectionController->onSelectAll();
1386 bMarkAll = false;
1390 if ( bMarkAll )
1391 MarkAllObj();
1395 void SdrView::UnmarkAll()
1397 if (IsTextEdit()) {
1398 ESelection eSel=GetTextEditOutlinerView()->GetSelection();
1399 eSel.CollapseToEnd();
1400 GetTextEditOutlinerView()->SetSelection(eSel);
1401 } else if (HasMarkedGluePoints()) UnmarkAllGluePoints();
1402 else if (HasMarkedPoints()) UnmarkAllPoints(); // Marked, not Markable!
1403 else UnmarkAllObj();
1406 const tools::Rectangle& SdrView::GetMarkedRect() const
1408 if (IsGluePointEditMode() && HasMarkedGluePoints()) {
1409 return GetMarkedGluePointsRect();
1411 if (HasMarkedPoints()) {
1412 return GetMarkedPointsRect();
1414 return GetMarkedObjRect();
1417 void SdrView::DeleteMarked()
1419 if (IsTextEdit())
1421 SdrObjEditView::KeyInput(KeyEvent(0, vcl::KeyCode(KeyFuncType::DELETE)), mpTextEditWin);
1423 else
1425 if( mxSelectionController.is() && mxSelectionController->DeleteMarked() )
1427 // action already performed by current selection controller, do nothing
1429 else if (IsGluePointEditMode() && HasMarkedGluePoints())
1431 DeleteMarkedGluePoints();
1433 else if (GetContext()==SdrViewContext::PointEdit && HasMarkedPoints())
1435 DeleteMarkedPoints();
1437 else
1439 DeleteMarkedObj();
1444 bool SdrView::BegMark(const Point& rPnt, bool bAddMark, bool bUnmark)
1446 if (bUnmark) bAddMark=true;
1447 if (IsGluePointEditMode()) {
1448 if (!bAddMark) UnmarkAllGluePoints();
1449 return BegMarkGluePoints(rPnt,bUnmark);
1450 } else if (HasMarkablePoints()) {
1451 if (!bAddMark) UnmarkAllPoints();
1452 return BegMarkPoints(rPnt,bUnmark);
1453 } else {
1454 if (!bAddMark) UnmarkAllObj();
1455 BegMarkObj(rPnt,bUnmark);
1456 return true;
1460 bool SdrView::MoveShapeHandle(const sal_uInt32 handleNum, const Point& aEndPoint, const sal_Int32 aObjectOrdNum)
1462 if (GetHdlList().IsMoveOutside())
1463 return false;
1465 const SdrMarkList& rMarkList = GetMarkedObjectList();
1466 if (!rMarkList.GetMarkCount())
1467 return false;
1469 SdrHdl * pHdl = GetHdlList().GetHdl(handleNum);
1470 if (pHdl == nullptr)
1471 return false;
1473 SdrDragStat& rDragStat = const_cast<SdrDragStat&>(GetDragStat());
1474 // start dragging
1475 BegDragObj(pHdl->GetPos(), nullptr, pHdl, 0);
1476 if (!IsDragObj())
1477 return false;
1479 bool bWasNoSnap = rDragStat.IsNoSnap();
1480 bool bWasSnapEnabled = IsSnapEnabled();
1482 // switch snapping off
1483 if(!bWasNoSnap)
1484 rDragStat.SetNoSnap();
1485 if(bWasSnapEnabled)
1486 SetSnapEnabled(false);
1488 if (aObjectOrdNum != -1)
1490 rDragStat.GetGlueOptions().objectOrdNum = aObjectOrdNum;
1492 MovDragObj(aEndPoint);
1493 EndDragObj();
1495 // Clear Glue Options
1496 rDragStat.GetGlueOptions().objectOrdNum = -1;
1498 if (!bWasNoSnap)
1499 rDragStat.SetNoSnap(bWasNoSnap);
1500 if (bWasSnapEnabled)
1501 SetSnapEnabled(bWasSnapEnabled);
1503 return true;
1506 void SdrView::SetMasterPagePaintCaching(bool bOn)
1508 if(mbMasterPagePaintCaching == bOn)
1509 return;
1511 mbMasterPagePaintCaching = bOn;
1513 // reset at all SdrPageWindows
1514 SdrPageView* pPageView = GetSdrPageView();
1516 if(!pPageView)
1517 return;
1519 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1521 SdrPageWindow* pPageWindow = pPageView->GetPageWindow(b);
1522 assert(pPageWindow && "SdrView::SetMasterPagePaintCaching: Corrupt SdrPageWindow list (!)");
1524 // force deletion of ObjectContact, so at re-display all VOCs
1525 // will be re-created with updated flag setting
1526 pPageWindow->ResetObjectContact();
1529 // force redraw of this view
1530 pPageView->InvalidateAllWin();
1533 // Default ObjectContact is ObjectContactOfPageView
1534 sdr::contact::ObjectContact* SdrView::createViewSpecificObjectContact(
1535 SdrPageWindow& rPageWindow,
1536 const char* pDebugName) const
1538 return new sdr::contact::ObjectContactOfPageView(rPageWindow, pDebugName);
1541 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */