tdf#130857 qt weld: Implement QtInstanceWidget::get_text_height
[LibreOffice.git] / sd / source / ui / func / fusel.cxx
blobbc2da0ced224dddca6ee6bded49fc1f5321b6f79
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 <fusel.hxx>
21 #include <svx/svddrgmt.hxx>
22 #include <svx/svdpagv.hxx>
23 #include <svx/svdogrp.hxx>
24 #include <svx/scene3d.hxx>
25 #include <vcl/imapobj.hxx>
26 #include <unotools/securityoptions.hxx>
27 #include <svx/svxids.hrc>
28 #include <svx/xfillit0.hxx>
29 #include <svx/ImageMapInfo.hxx>
30 #include <sfx2/viewfrm.hxx>
31 #include <svl/stritem.hxx>
32 #include <svl/intitem.hxx>
33 #include <sfx2/dispatch.hxx>
34 #include <sfx2/docfile.hxx>
35 #include <editeng/flditem.hxx>
37 #include <svx/svdotable.hxx>
39 #include <app.hrc>
41 #include <sdmod.hxx>
42 #include <DrawDocShell.hxx>
43 #include <stlpool.hxx>
44 #include <fudraw.hxx>
45 #include <ViewShell.hxx>
46 #include <ViewShellBase.hxx>
47 #include <FrameView.hxx>
48 #include <View.hxx>
49 #include <Window.hxx>
50 #include <drawdoc.hxx>
51 #include <DrawViewShell.hxx>
52 #include <ToolBarManager.hxx>
53 #include <Client.hxx>
54 #include <annotationmanager.hxx>
56 #include <svx/svdundo.hxx>
58 #include <svx/sdrhittesthelper.hxx>
59 #include <svx/diagram/IDiagramHelper.hxx>
60 #include <svx/annotation/ObjectAnnotationData.hxx>
62 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
63 #include <comphelper/lok.hxx>
65 using namespace ::com::sun::star;
67 namespace sd {
69 FuSelection::FuSelection (
70 ViewShell* pViewSh,
71 ::sd::Window* pWin,
72 ::sd::View* pView,
73 SdDrawDocument* pDoc,
74 SfxRequest& rReq)
75 : FuDraw(pViewSh, pWin, pView, pDoc, rReq),
76 bTempRotation(false),
77 bSelectionChanged(false),
78 pHdl(nullptr),
79 bSuppressChangesOfSelection(false),
80 bMirrorSide0(false),
81 nEditMode(SID_BEZIER_MOVE),
82 pWaterCanCandidate(nullptr)
83 //Add Shift+UP/DOWN/LEFT/RIGHT key to move the position of insert point,
84 //and SHIFT+ENTER key to decide the position and draw the new insert point
85 ,bBeginInsertPoint(false),
86 oldPoint(0,0)
87 ,bMovedToCenterPoint(false)
91 rtl::Reference<FuPoor> FuSelection::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
93 rtl::Reference<FuPoor> xFunc( new FuSelection( pViewSh, pWin, pView, pDoc, rReq ) );
94 xFunc->DoExecute(rReq);
95 return xFunc;
98 void FuSelection::DoExecute( SfxRequest& rReq )
100 FuDraw::DoExecute( rReq );
102 // Select object bar
103 SelectionHasChanged();
106 FuSelection::~FuSelection()
108 mpView->UnmarkAllPoints();
109 mpView->ResetCreationActive();
111 if ( mpView->GetDragMode() != SdrDragMode::Move )
113 mpView->SetDragMode(SdrDragMode::Move);
117 namespace {
118 bool lcl_followHyperlinkAllowed(const MouseEvent& rMEvt) {
119 if (!rMEvt.IsMod1() && SvtSecurityOptions::IsOptionSet(SvtSecurityOptions::EOption::CtrlClickHyperlink))
120 return false;
121 if (rMEvt.IsMod1() && !SvtSecurityOptions::IsOptionSet(SvtSecurityOptions::EOption::CtrlClickHyperlink))
122 return false;
123 return true;
127 bool FuSelection::MouseButtonDown(const MouseEvent& rMEvt)
129 pHdl = nullptr;
130 bool bReturn = FuDraw::MouseButtonDown(rMEvt);
131 bool bWaterCan = SdModule::get()->GetWaterCan();
132 const bool bReadOnly = mpDocSh->IsReadOnly();
133 // When the right mouse button is pressed then only select objects
134 // (and deselect others) as a preparation for showing the context
135 // menu.
136 const bool bSelectionOnly = rMEvt.IsRight();
138 bMBDown = true;
139 bSelectionChanged = false;
141 if ( mpView->IsAction() )
143 if ( rMEvt.IsRight() )
144 mpView->BckAction();
145 return true;
148 sal_uInt16 nDrgLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(mpView->GetDragThresholdPixels(),0)).Width() );
149 sal_uInt16 nHitLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(HITPIX,0)).Width() );
151 if (comphelper::LibreOfficeKit::isActive())
153 // When tiled rendering, we always work in logic units, use the non-pixel constants.
154 nDrgLog = DRGLOG;
155 nHitLog = HITLOG;
158 // The following code is executed for right clicks as well as for left
159 // clicks in order to modify the selection for the right button as a
160 // preparation for the context menu. The functions BegMarkObject() and
161 // BegDragObject(), however, are not called for right clicks because a)
162 // it makes no sense and b) to have IsAction() return sal_False when called
163 // from Command() which is a prerequisite for the context menu.
164 if ((rMEvt.IsLeft() || rMEvt.IsRight())
165 && !mpView->IsAction()
166 && (mpView->IsFrameDragSingles() || !mpView->HasMarkablePoints()))
168 /******************************************************************
169 * NO BEZIER_EDITOR
170 ******************************************************************/
171 mpWindow->CaptureMouse();
172 pHdl = mpView->PickHandle(aMDPos);
174 Degree100 nAngle0 = GetAngle(aMDPos - mpView->GetRef1());
175 nAngle0 -= 27000_deg100;
176 nAngle0 = NormAngle36000(nAngle0);
177 bMirrorSide0 = nAngle0 < 18000_deg100;
179 if (!pHdl && mpView->Is3DRotationCreationActive())
181 /******************************************************************
182 * If 3D-rotation bodies are about to be created,
183 * end creation now.
184 ******************************************************************/
185 bSuppressChangesOfSelection = true;
186 mpWindow->EnterWait();
187 mpView->End3DCreation();
188 bSuppressChangesOfSelection = false;
189 mpView->ResetCreationActive();
190 mpWindow->LeaveWait();
193 bool bTextEdit = false;
194 SdrViewEvent aVEvt;
195 SdrHitKind eHit = mpView->PickAnything(rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
197 if (eHit == SdrHitKind::TextEditObj && (mpViewShell->GetFrameView()->IsQuickEdit() || dynamic_cast< sdr::table::SdrTableObj* >(aVEvt.mpObj) != nullptr))
199 bTextEdit = true;
202 // When clicking into a URl field, also go to text edit mode (when not following the link)
203 if (!bTextEdit && eHit == SdrHitKind::UrlField && !rMEvt.IsMod2() && !lcl_followHyperlinkAllowed(rMEvt))
204 bTextEdit = true;
206 bool bPreventModify = mpDocSh->IsReadOnly();
207 if (bPreventModify && mpDocSh->GetSignPDFCertificate().is())
209 // If the just added signature line shape is selected, allow moving / resizing it.
210 bPreventModify = false;
213 if(!bTextEdit
214 && !bPreventModify
215 && ((mpView->IsMarkedHit(aMDPos, nHitLog) && !rMEvt.IsShift() && !rMEvt.IsMod2()) || pHdl != nullptr)
216 && (rMEvt.GetClicks() != 2)
219 if (!pHdl && mpView->Is3DRotationCreationActive())
221 // Switch between 3D-rotation body -> selection
222 mpView->ResetCreationActive();
224 else if (bWaterCan)
226 // Remember the selected object for proper handling in
227 // MouseButtonUp().
228 pWaterCanCandidate = pickObject (aMDPos);
230 else
232 // hit handle or marked object
233 bFirstMouseMove = true;
234 aDragTimer.Start();
237 if ( ! rMEvt.IsRight())
238 if (mpView->BegDragObj(aMDPos, nullptr, pHdl, nDrgLog))
239 mpView->GetDragMethod()->SetShiftPressed( rMEvt.IsShift() );
240 bReturn = true;
242 else
244 SdrPageView* pPV = nullptr;
245 SdrObject* pObj = !rMEvt.IsMod2() ? mpView->PickObj(aMDPos, mpView->getHitTolLog(), pPV, SdrSearchOptions::PICKMACRO) : nullptr;
246 if (pObj)
248 mpView->BegMacroObj(aMDPos, nHitLog, pObj, pPV, mpWindow);
249 bReturn = true;
251 else if ( bTextEdit )
253 SdrObjKind nSdrObjKind = aVEvt.mpObj->GetObjIdentifier();
255 if (aVEvt.mpObj->GetObjInventor() == SdrInventor::Default &&
256 (nSdrObjKind == SdrObjKind::Text ||
257 nSdrObjKind == SdrObjKind::TitleText ||
258 nSdrObjKind == SdrObjKind::OutlineText ||
259 !aVEvt.mpObj->IsEmptyPresObj()))
261 // Seamless Editing: branch to text input
262 if (!rMEvt.IsShift())
263 mpView->UnmarkAll();
265 SfxUInt16Item aItem(SID_TEXTEDIT, 1);
266 mpViewShell->GetViewFrame()->GetDispatcher()->
267 ExecuteList(SID_TEXTEDIT,
268 SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
269 { &aItem });
270 return bReturn; // CAUTION, due to the synchronous slot the object is deleted now
273 else if ( !rMEvt.IsMod2() && rMEvt.GetClicks() == 1 &&
274 aVEvt.meEvent == SdrEventKind::ExecuteUrl )
276 mpWindow->ReleaseMouse();
278 if (!aVEvt.mpURLField)
279 return true;
281 // If tiled rendering, let client handles URL execution and early returns.
282 if (comphelper::LibreOfficeKit::isActive())
284 SfxViewShell& rSfxViewShell = mpViewShell->GetViewShellBase();
285 rSfxViewShell.libreOfficeKitViewCallback(LOK_CALLBACK_HYPERLINK_CLICKED, aVEvt.mpURLField->GetURL().toUtf8());
286 return true;
289 if (!lcl_followHyperlinkAllowed(rMEvt))
290 return true;
292 SfxStringItem aStrItem(SID_FILE_NAME, aVEvt.mpURLField->GetURL());
293 SfxStringItem aReferer(SID_REFERER, mpDocSh->GetMedium()->GetName());
294 SfxBoolItem aBrowseItem( SID_BROWSE, true );
295 SfxViewFrame* pFrame = mpViewShell->GetViewFrame();
296 mpWindow->ReleaseMouse();
298 if (rMEvt.IsMod1())
300 // Open in new frame
301 pFrame->GetDispatcher()->ExecuteList(SID_OPENDOC,
302 SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
303 { &aStrItem, &aBrowseItem, &aReferer });
305 else
307 // Open in current frame
308 SfxFrameItem aFrameItem(SID_DOCFRAME, pFrame);
309 pFrame->GetDispatcher()->ExecuteList(SID_OPENDOC,
310 SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
311 { &aStrItem, &aFrameItem, &aBrowseItem, &aReferer });
314 bReturn = true;
316 else if(!rMEvt.IsMod2()
317 && dynamic_cast< const DrawViewShell *>( mpViewShell ) != nullptr
320 pObj = mpView->PickObj(aMDPos, mpView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER);
321 if (pObj)
323 // Handle ImageMap click when not just selecting
324 if (!bSelectionOnly)
326 if (lcl_followHyperlinkAllowed(rMEvt))
327 bReturn = HandleImageMapClick(pObj, aMDPos);
330 if (!bReturn
331 && (dynamic_cast<const SdrObjGroup*>(pObj) != nullptr
332 || DynCastE3dScene(pObj)))
334 if (rMEvt.GetClicks() == 1)
336 // Look into the group
337 pObj = mpView->PickObj(aMDPos, mpView->getHitTolLog(), pPV,
338 SdrSearchOptions::ALSOONMASTER
339 | SdrSearchOptions::DEEP);
340 if (pObj && lcl_followHyperlinkAllowed(rMEvt))
341 bReturn = HandleImageMapClick(pObj, aMDPos);
343 else if (!bReadOnly && rMEvt.GetClicks() == 2)
345 // New: double click on selected Group object
346 // enter group
347 if (!bSelectionOnly
348 && pObj->getSdrPageFromSdrObject() == pPV->GetPage())
349 bReturn = pPV->EnterGroup(pObj);
354 // #i71727# replaced else here with two possibilities, once the original else (!pObj)
355 // and also ignoring the found object when it's on a masterpage
356 if(!pObj || (pObj->getSdrPageFromSdrObject() && pObj->getSdrPageFromSdrObject()->IsMasterPage()))
358 if(mpView->IsGroupEntered() && 2 == rMEvt.GetClicks())
360 // New: double click on empty space/on obj on MasterPage, leave group
361 mpView->LeaveOneGroup();
362 bReturn = true;
367 if (!bReturn)
369 if (bWaterCan)
371 if ( ! (rMEvt.IsShift() || rMEvt.IsMod2()))
373 // Find the object under the current mouse position
374 // and store it for the MouseButtonUp() method to
375 // evaluate.
376 pWaterCanCandidate = pickObject (aMDPos);
379 else
381 bReturn = true;
382 bool bDeactivateOLE = false;
384 if ( !rMEvt.IsShift() && !rMEvt.IsMod2() )
386 OSL_ASSERT (mpViewShell->GetViewShell()!=nullptr);
387 Client* pIPClient = static_cast<Client*>(
388 mpViewShell->GetViewShell()->GetIPClient());
390 if (pIPClient && pIPClient->IsObjectInPlaceActive())
392 // OLE-object gets deactivated in subsequent UnmarkAll()
393 bDeactivateOLE = true;
396 mpView->UnmarkAll();
399 bool bMarked = false;
401 if ( !rMEvt.IsMod1() && !bDeactivateOLE)
403 if ( rMEvt.IsMod2() )
405 bMarked = mpView->MarkNextObj(aMDPos, nHitLog, rMEvt.IsShift() );
407 else
409 bool bToggle = false;
411 const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
412 if (rMEvt.IsShift() && rMarkList.GetMarkCount() > 1)
414 // No Toggle on single selection
415 bToggle = true;
418 bMarked = mpView->MarkObj(aMDPos, nHitLog, bToggle);
422 if( !bDeactivateOLE )
424 if ( !bReadOnly &&
425 bMarked &&
426 (!rMEvt.IsShift() || mpView->IsMarkedHit(aMDPos, nHitLog)))
428 /**********************************************************
429 * Move object
430 **********************************************************/
431 aDragTimer.Start();
433 pHdl=mpView->PickHandle(aMDPos);
434 if ( ! rMEvt.IsRight())
435 mpView->BegDragObj(aMDPos, nullptr, pHdl, nDrgLog);
437 else
439 /**********************************************************
440 * Select object
441 **********************************************************/
442 if ( ! rMEvt.IsRight())
443 mpView->BegMarkObj(aMDPos);
447 if( bMarked && bTempRotation && (nSlotId == SID_OBJECT_ROTATE) && !rMEvt.IsShift() && (rMEvt.GetClicks() != 2) )
449 nSlotId = SID_OBJECT_SELECT;
450 Activate();
456 else if ( !bReadOnly
457 && (rMEvt.IsLeft() || rMEvt.IsRight())
458 && !mpView->IsAction())
460 /**********************************************************************
461 * BEZIER-EDITOR
462 **********************************************************************/
463 mpWindow->CaptureMouse();
464 SdrViewEvent aVEvt;
465 SdrHitKind eHit = mpView->PickAnything(rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
467 if (eHit == SdrHitKind::Handle && aVEvt.mpHdl->GetKind() == SdrHdlKind::BezierWeight)
469 /******************************************************************
470 * Drag Handle
471 ******************************************************************/
472 if ( ! rMEvt.IsRight())
473 mpView->BegDragObj(aMDPos, nullptr, aVEvt.mpHdl, nDrgLog);
475 else if (eHit == SdrHitKind::MarkedObject && nEditMode == SID_BEZIER_INSERT)
477 /******************************************************************
478 * Insert gluepoint
479 ******************************************************************/
480 mpView->BegInsObjPoint(aMDPos, rMEvt.IsMod1());
482 else if (eHit == SdrHitKind::MarkedObject && rMEvt.IsMod1())
484 /******************************************************************
485 * Select gluepoint
486 ******************************************************************/
487 if (!rMEvt.IsShift())
488 mpView->UnmarkAllPoints();
490 if ( ! rMEvt.IsRight())
491 mpView->BegMarkPoints(aMDPos);
493 else if (eHit == SdrHitKind::MarkedObject && !rMEvt.IsShift() && !rMEvt.IsMod2())
495 /******************************************************************
496 * Move object
497 ******************************************************************/
498 if ( ! rMEvt.IsRight())
499 mpView->BegDragObj(aMDPos, nullptr, nullptr, nDrgLog);
501 else if (eHit == SdrHitKind::Handle)
503 /******************************************************************
504 * Select gluepoint
505 ******************************************************************/
506 if (!mpView->IsPointMarked(*aVEvt.mpHdl) || rMEvt.IsShift())
508 if (!rMEvt.IsShift())
510 mpView->UnmarkAllPoints();
511 pHdl = mpView->PickHandle(aMDPos);
513 else
515 if (mpView->IsPointMarked(*aVEvt.mpHdl))
517 mpView->UnmarkPoint(*aVEvt.mpHdl);
518 pHdl = nullptr;
520 else
522 pHdl = mpView->PickHandle(aMDPos);
526 if (pHdl)
528 mpView->MarkPoint(*pHdl);
529 if ( ! rMEvt.IsRight())
530 mpView->BegDragObj(aMDPos, nullptr, pHdl, nDrgLog);
534 else
536 // Point IS marked and NO shift is pressed. Start
537 // dragging of selected point(s)
538 pHdl = mpView->PickHandle(aMDPos);
539 if(pHdl && ! rMEvt.IsRight())
540 mpView->BegDragObj(aMDPos, nullptr, pHdl, nDrgLog);
543 else
545 /******************************************************************
546 * Select or drag object
547 ******************************************************************/
548 if (!rMEvt.IsShift() && !rMEvt.IsMod2() && eHit == SdrHitKind::UnmarkedObject)
550 mpView->UnmarkAllObj();
553 bool bMarked = false;
555 if (!rMEvt.IsMod1())
557 if (rMEvt.IsMod2())
559 bMarked = mpView->MarkNextObj(aMDPos, nHitLog, rMEvt.IsShift());
561 else
563 bMarked = mpView->MarkObj(aMDPos, nHitLog, rMEvt.IsShift());
567 const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
568 if (bMarked &&
569 (!rMEvt.IsShift() || eHit == SdrHitKind::MarkedObject))
571 // Move object
572 if ( ! rMEvt.IsRight())
573 mpView->BegDragObj(aMDPos, nullptr, aVEvt.mpHdl, nDrgLog);
575 else if (rMarkList.GetMarkCount() != 0)
577 /**************************************************************
578 * Select gluepoint
579 **************************************************************/
580 if (!rMEvt.IsShift())
581 mpView->UnmarkAllPoints();
583 if ( ! rMEvt.IsRight())
584 mpView->BegMarkPoints(aMDPos);
586 else
588 /**************************************************************
589 * Select object
590 **************************************************************/
591 if ( ! rMEvt.IsRight())
592 mpView->BegMarkObj(aMDPos);
595 ForcePointer(&rMEvt);
599 if (!bIsInDragMode)
601 ForcePointer(&rMEvt);
604 return bReturn;
607 bool FuSelection::MouseMove(const MouseEvent& rMEvt)
609 bool bReturn = FuDraw::MouseMove(rMEvt);
611 if (aDragTimer.IsActive())
613 if(bFirstMouseMove)
615 bFirstMouseMove = false;
617 else
619 aDragTimer.Stop();
623 if (mpView->IsAction())
625 Point aPix(rMEvt.GetPosPixel());
626 Point aPnt(mpWindow->PixelToLogic(aPix));
628 ForceScroll(aPix);
630 if (mpView->IsInsObjPoint())
632 mpView->MovInsObjPoint(aPnt);
634 else
636 mpView->MovAction(aPnt);
640 ForcePointer(&rMEvt);
642 return bReturn;
645 bool FuSelection::MouseButtonUp(const MouseEvent& rMEvt)
647 bool bReturn = false;
648 // When the right mouse button is pressed then only select objects
649 // (and deselect others) as a preparation for showing the context
650 // menu.
651 const bool bSelectionOnly = rMEvt.IsRight();
653 if (aDragTimer.IsActive() )
655 aDragTimer.Stop();
656 bIsInDragMode = false;
659 if( !mpView )
660 return false;
662 Point aPnt( mpWindow->PixelToLogic( rMEvt.GetPosPixel() ) );
663 sal_uInt16 nHitLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(HITPIX,0)).Width() );
664 sal_uInt16 nDrgLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(mpView->GetDragThresholdPixels(),0)).Width() );
666 bool bWasDragged = false;
667 if (mpView->IsFrameDragSingles() || !mpView->HasMarkablePoints())
669 /**********************************************************************
670 * NO BEZIER_EDITOR
671 **********************************************************************/
672 if ( mpView->IsDragObj() )
674 /******************************************************************
675 * Object was moved
676 ******************************************************************/
677 FrameView* pFrameView = mpViewShell->GetFrameView();
678 bool bDragWithCopy = (rMEvt.IsMod1() && pFrameView->IsDragWithCopy());
680 if (bDragWithCopy)
682 bDragWithCopy = !mpView->IsPresObjSelected(false);
685 mpView->SetDragWithCopy(bDragWithCopy);
686 bWasDragged = mpView->EndDragObj(mpView->IsDragWithCopy());
688 mpView->ForceMarkedToAnotherPage();
690 if (!rMEvt.IsShift() && !rMEvt.IsMod1() && !rMEvt.IsMod2() &&
691 !bSelectionChanged &&
692 std::abs(aPnt.X() - aMDPos.X()) < nDrgLog &&
693 std::abs(aPnt.Y() - aMDPos.Y()) < nDrgLog)
695 /*************************************************************
696 * If a user wants to click on an object in front of a marked
697 * one, he releases the mouse button immediately
698 **************************************************************/
699 SdrPageView* pPV;
700 SdrObject* pObj = mpView->PickObj(aMDPos, mpView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER | SdrSearchOptions::BEFOREMARK);
701 if (pObj && pPV->IsObjMarkable(pObj))
703 mpView->UnmarkAllObj();
704 mpView->MarkObj(pObj,pPV);
705 return true;
708 // check for single object selected
709 SdrObject* pSingleObj = nullptr;
711 const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
712 if (rMarkList.GetMarkCount()==1)
714 pSingleObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
717 // Check for click on svx::diagram::DiagramFrameHdl
718 // - if we hit a SdrHdl
719 // - if it was not moved
720 // - if single object is selected
721 // - and it is a Diagram
722 if(pHdl && !bWasDragged && nullptr != pSingleObj && pSingleObj->isDiagram())
724 svx::diagram::DiagramFrameHdl* pDiagramFrameHdl(dynamic_cast<svx::diagram::DiagramFrameHdl*>(pHdl));
725 if(nullptr != pDiagramFrameHdl)
727 // let the DiagramFrameHdl decide what to do
728 svx::diagram::DiagramFrameHdl::clicked(aPnt);
732 /**************************************************************
733 * Toggle between selection and rotation
734 **************************************************************/
735 if (nSlotId == SID_OBJECT_SELECT
736 && !comphelper::LibreOfficeKit::isActive()
737 && mpView->IsRotateAllowed()
739 && (rMEvt.GetClicks() != 2)
740 && (mpViewShell->GetFrameView()->IsClickChangeRotation()
741 || (pSingleObj
742 && pSingleObj->GetObjInventor()==SdrInventor::E3d))
743 && ! bSelectionOnly)
746 bTempRotation = true;
747 nSlotId = SID_OBJECT_ROTATE;
748 Activate();
750 else if (nSlotId == SID_OBJECT_ROTATE)
752 nSlotId = SID_OBJECT_SELECT;
753 Activate();
756 else if (nSlotId == SID_CONVERT_TO_3D_LATHE)
758 if (!pHdl)
760 bSuppressChangesOfSelection = true;
761 mpView->Start3DCreation();
762 bSuppressChangesOfSelection = false;
764 else if (pHdl->GetKind() != SdrHdlKind::MirrorAxis &&
765 pHdl->GetKind() != SdrHdlKind::Ref1 &&
766 pHdl->GetKind() != SdrHdlKind::Ref2 && mpView->Is3DRotationCreationActive())
768 /*********************************************************
769 * If 3D-rotation bodies are about to be created,
770 * end creation now
771 **********************************************************/
772 Degree100 nAngle1 = GetAngle(aPnt - mpView->GetRef1());
773 nAngle1 -= 27000_deg100;
774 nAngle1 = NormAngle36000(nAngle1);
775 bool bMirrorSide1 = nAngle1 < 18000_deg100;
777 if (bMirrorSide0 != bMirrorSide1)
779 bSuppressChangesOfSelection = true;
780 mpWindow->EnterWait();
781 mpView->End3DCreation();
782 bSuppressChangesOfSelection = false;
783 nSlotId = SID_OBJECT_SELECT;
784 mpWindow->LeaveWait();
785 Activate();
790 else if (rMEvt.IsMod1()
791 && !rMEvt.IsMod2()
792 && std::abs(aPnt.X() - aMDPos.X()) < nDrgLog
793 && std::abs(aPnt.Y() - aMDPos.Y()) < nDrgLog)
795 // Enter group
796 mpView->MarkObj(aPnt, nHitLog, rMEvt.IsShift(), rMEvt.IsMod1());
799 if (mpView->IsAction() )
801 mpView->EndAction();
804 if (SdModule::get()->GetWaterCan())
806 if( rMEvt.IsRight() )
808 // In watering-can mode, on press onto right mouse button, an undo is executed
809 mpViewShell->GetViewFrame()->GetDispatcher()->Execute( SID_UNDO, SfxCallMode::ASYNCHRON );
811 else if (pWaterCanCandidate != nullptr)
813 // Is the candidate object still under the mouse?
814 if (pickObject (aPnt) == pWaterCanCandidate)
816 SdStyleSheetPool* pPool = static_cast<SdStyleSheetPool*>(
817 mpDocSh->GetStyleSheetPool());
818 if (pPool != nullptr)
820 SfxStyleSheet* pStyleSheet = static_cast<SfxStyleSheet*>(
821 pPool->GetActualStyleSheet());
822 if (pStyleSheet != nullptr && mpView->IsUndoEnabled() )
824 // Added UNDOs for the WaterCan mode. This was never done in
825 // the past, thus it was missing all the time.
826 std::unique_ptr<SdrUndoAction> pUndoAttr = mpDoc->GetSdrUndoFactory().CreateUndoAttrObject(*pWaterCanCandidate, true, true);
827 mpView->BegUndo(pUndoAttr->GetComment());
828 mpView->AddUndo(mpDoc->GetSdrUndoFactory().CreateUndoGeoObject(*pWaterCanCandidate));
829 mpView->AddUndo(std::move(pUndoAttr));
831 pWaterCanCandidate->SetStyleSheet (pStyleSheet, false);
833 mpView->EndUndo();
838 // else when there has been no object under the mouse when the
839 // button was pressed then nothing happens even when there is
840 // one now.
843 sal_uInt16 nClicks = rMEvt.GetClicks();
845 if (nClicks == 2 && rMEvt.IsLeft() && bMBDown &&
846 !rMEvt.IsMod1() && !rMEvt.IsShift() )
848 DoubleClick(rMEvt);
851 bMBDown = false;
853 ForcePointer(&rMEvt);
854 pHdl = nullptr;
855 mpWindow->ReleaseMouse();
856 SdrObject* pSingleObj = nullptr;
857 const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
858 const size_t nMarkCount = rMarkList.GetMarkCount();
860 if (nMarkCount==1)
862 pSingleObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
865 if (!bWasDragged && pSingleObj && pSingleObj->isAnnotationObject() && rMEvt.IsLeft())
867 auto& pAnnotationData = pSingleObj->getAnnotationData();
868 if (pAnnotationData)
870 auto* pDrawViewShell = dynamic_cast<DrawViewShell*>(mpViewShell);
871 if (pDrawViewShell && pDrawViewShell->getAnnotationManagerPtr())
873 pDrawViewShell->getAnnotationManagerPtr()->SelectAnnotation(pAnnotationData->mxAnnotation);
875 pAnnotationData->openPopup();
877 return true;
880 if ( (nSlotId != SID_OBJECT_SELECT && nMarkCount==0) ||
881 ( mpView->GetDragMode() == SdrDragMode::Crook &&
882 !mpView->IsCrookAllowed( mpView->IsCrookNoContortion() ) ) ||
883 ( mpView->GetDragMode() == SdrDragMode::Shear &&
884 !mpView->IsShearAllowed() && !mpView->IsDistortAllowed() ) ||
885 ( nSlotId==SID_CONVERT_TO_3D_LATHE && pSingleObj &&
886 (pSingleObj->GetObjInventor() != SdrInventor::Default ||
887 pSingleObj->GetObjIdentifier() == SdrObjKind::Measure) ) )
889 bReturn = true;
890 ForcePointer(&rMEvt);
891 pHdl = nullptr;
892 mpWindow->ReleaseMouse();
893 FuDraw::MouseButtonUp(rMEvt);
894 mpViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::SYNCHRON);
895 return bReturn; // CAUTION, due to the synchronous slot, the object is deleted now.
898 FuDraw::MouseButtonUp(rMEvt);
900 else
902 /**********************************************************************
903 * BEZIER_EDITOR
904 **********************************************************************/
905 if ( mpView->IsAction() )
907 if ( mpView->IsInsObjPoint() )
909 mpView->EndInsObjPoint(SdrCreateCmd::ForceEnd);
911 else if ( mpView->IsDragObj() )
913 FrameView* pFrameView = mpViewShell->GetFrameView();
914 bool bDragWithCopy = (rMEvt.IsMod1() && pFrameView->IsDragWithCopy());
916 if (bDragWithCopy)
918 bDragWithCopy = !mpView->IsPresObjSelected(false);
921 mpView->SetDragWithCopy(bDragWithCopy);
922 mpView->EndDragObj( mpView->IsDragWithCopy() );
924 else
926 mpView->EndAction();
928 sal_uInt16 nDrgLog2 = sal_uInt16 ( mpWindow->PixelToLogic(Size(mpView->GetDragThresholdPixels(),0)).Width() );
929 Point aPos = mpWindow->PixelToLogic( rMEvt.GetPosPixel() );
931 if (std::abs(aMDPos.X() - aPos.X()) < nDrgLog2 &&
932 std::abs(aMDPos.Y() - aPos.Y()) < nDrgLog2 &&
933 !rMEvt.IsShift() && !rMEvt.IsMod2())
935 SdrViewEvent aVEvt;
936 SdrHitKind eHit = mpView->PickAnything(rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
938 if (eHit == SdrHitKind::NONE)
940 // Click on the same place - unselect
941 mpView->UnmarkAllObj();
946 else if (!rMEvt.IsShift() && rMEvt.IsMod1() && !rMEvt.IsMod2() &&
947 std::abs(aPnt.X() - aMDPos.X()) < nDrgLog &&
948 std::abs(aPnt.Y() - aMDPos.Y()) < nDrgLog)
950 // Enter group
951 mpView->MarkObj(aPnt, nHitLog, false, rMEvt.IsMod1());
954 ForcePointer(&rMEvt);
955 pHdl = nullptr;
956 mpWindow->ReleaseMouse();
958 FuDraw::MouseButtonUp(rMEvt);
961 return bReturn;
965 * Process keyboard input
966 * @returns sal_True if a KeyEvent is being processed, sal_False otherwise
968 bool FuSelection::KeyInput(const KeyEvent& rKEvt)
970 bool bReturn = false;
972 switch (rKEvt.GetKeyCode().GetCode())
974 case KEY_ESCAPE:
976 bReturn = FuSelection::cancel();
978 break;
979 //add keyboard operation for insert points in drawing curve
980 case KEY_UP:
981 case KEY_DOWN:
982 case KEY_LEFT:
983 case KEY_RIGHT:
985 if(rKEvt.GetKeyCode().IsShift()&&(nEditMode == SID_BEZIER_INSERT)){
986 ::tools::Long nX = 0;
987 ::tools::Long nY = 0;
988 sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
989 if (nCode == KEY_UP)
991 // scroll up
992 nX = 0;
993 nY =-1;
995 else if (nCode == KEY_DOWN)
997 // scroll down
998 nX = 0;
999 nY = 1;
1001 else if (nCode == KEY_LEFT)
1003 // scroll left
1004 nX =-1;
1005 nY = 0;
1007 else if (nCode == KEY_RIGHT)
1009 // scroll right
1010 nX = 1;
1011 nY = 0;
1014 Point centerPoint;
1015 ::tools::Rectangle rect = mpView->GetMarkedObjRect();
1016 centerPoint = mpWindow->LogicToPixel(rect.Center());
1017 Point aPoint = bMovedToCenterPoint? oldPoint:centerPoint;
1018 Point ePoint = aPoint + Point(nX,nY);
1019 mpWindow->SetPointerPosPixel(ePoint);
1020 //simulate mouse move action
1021 MouseEvent eMevt(ePoint, 1, MouseEventModifiers::DRAGMOVE, MOUSE_LEFT, 0);
1022 MouseMove(eMevt);
1023 oldPoint = ePoint;
1024 bMovedToCenterPoint = true;
1025 bReturn = true;
1028 break;
1029 case KEY_RETURN:
1030 if(rKEvt.GetKeyCode().IsShift()&&(nEditMode == SID_BEZIER_INSERT))
1032 if(!bBeginInsertPoint)
1034 //simulate mouse button down action
1035 MouseEvent aMevt(oldPoint, 1,
1036 MouseEventModifiers::SIMPLEMOVE | MouseEventModifiers::DRAGMOVE,
1037 MOUSE_LEFT, KEY_SHIFT);
1038 MouseButtonDown(aMevt);
1039 mpWindow->CaptureMouse();
1040 bBeginInsertPoint = true;
1042 else
1044 //simulate mouse button up action
1045 MouseEvent rMEvt(oldPoint, 1,
1046 MouseEventModifiers::SIMPLEMOVE | MouseEventModifiers::ENTERWINDOW,
1047 MOUSE_LEFT, KEY_SHIFT);
1048 MouseButtonUp(rMEvt);
1049 bBeginInsertPoint = false;
1051 bReturn= true;
1053 break;
1055 if (!bReturn)
1057 bReturn = FuDraw::KeyInput(rKEvt);
1059 const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
1060 if(rMarkList.GetMarkCount() == 0)
1062 mpView->ResetCreationActive();
1064 mpViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
1068 return bReturn;
1072 void FuSelection::Activate()
1074 SdrDragMode eMode;
1075 mpView->ResetCreationActive();
1076 mpView->SetEditMode(SdrViewEditMode::Edit);
1078 switch( nSlotId )
1080 case SID_OBJECT_ROTATE:
1082 eMode = SdrDragMode::Rotate;
1084 if ( mpView->GetDragMode() != eMode )
1085 mpView->SetDragMode(eMode);
1087 break;
1089 case SID_OBJECT_MIRROR:
1091 eMode = SdrDragMode::Mirror;
1093 if ( mpView->GetDragMode() != eMode )
1094 mpView->SetDragMode(eMode);
1096 break;
1098 case SID_OBJECT_CROP:
1100 eMode = SdrDragMode::Crop;
1102 if ( mpView->GetDragMode() != eMode )
1103 mpView->SetDragMode(eMode);
1105 break;
1107 case SID_OBJECT_TRANSPARENCE:
1109 eMode = SdrDragMode::Transparence;
1111 if ( mpView->GetDragMode() != eMode )
1112 mpView->SetDragMode(eMode);
1114 break;
1116 case SID_OBJECT_GRADIENT:
1118 eMode = SdrDragMode::Gradient;
1120 if ( mpView->GetDragMode() != eMode )
1121 mpView->SetDragMode(eMode);
1123 break;
1125 case SID_OBJECT_SHEAR:
1127 eMode = SdrDragMode::Shear;
1129 if ( mpView->GetDragMode() != eMode )
1130 mpView->SetDragMode(eMode);
1132 break;
1134 case SID_OBJECT_CROOK_ROTATE:
1136 eMode = SdrDragMode::Crook;
1138 if ( mpView->GetDragMode() != eMode )
1140 mpView->SetDragMode(eMode);
1141 mpView->SetCrookMode(SdrCrookMode::Rotate);
1144 break;
1146 case SID_OBJECT_CROOK_SLANT:
1148 eMode = SdrDragMode::Crook;
1150 if ( mpView->GetDragMode() != eMode )
1152 mpView->SetDragMode(eMode);
1153 mpView->SetCrookMode(SdrCrookMode::Slant);
1156 break;
1158 case SID_OBJECT_CROOK_STRETCH:
1160 eMode = SdrDragMode::Crook;
1162 if ( mpView->GetDragMode() != eMode )
1164 mpView->SetDragMode(eMode);
1165 mpView->SetCrookMode(SdrCrookMode::Stretch);
1168 break;
1170 case SID_CONVERT_TO_3D_LATHE:
1172 eMode = SdrDragMode::Mirror;
1173 bSuppressChangesOfSelection = true;
1175 if ( mpView->GetDragMode() != eMode )
1176 mpView->SetDragMode(eMode);
1178 if (!mpView->Is3DRotationCreationActive())
1179 mpView->Start3DCreation();
1181 bSuppressChangesOfSelection = false;
1183 break;
1185 default:
1187 eMode = SdrDragMode::Move;
1189 if ( mpView->GetDragMode() != eMode )
1190 mpView->SetDragMode(eMode);
1192 break;
1195 if (nSlotId != SID_OBJECT_ROTATE)
1197 bTempRotation = false;
1200 FuDraw::Activate();
1203 void FuSelection::SelectionHasChanged()
1205 bSelectionChanged = true;
1207 FuDraw::SelectionHasChanged();
1209 if (mpView->Is3DRotationCreationActive() && !bSuppressChangesOfSelection)
1211 // Switch rotation body -> selection
1212 mpView->ResetCreationActive();
1213 nSlotId = SID_OBJECT_SELECT;
1214 Activate();
1217 // Activate the right tool bar for the current context of the view.
1218 mpViewShell->GetViewShellBase().GetToolBarManager()->SelectionHasChanged(*mpViewShell, *mpView);
1222 * Set current bezier edit mode
1224 void FuSelection::SetEditMode(sal_uInt16 nMode)
1226 nEditMode = nMode;
1228 if (nEditMode == SID_BEZIER_INSERT)
1230 mpView->SetInsObjPointMode(true);
1232 else
1234 mpView->SetInsObjPointMode(false);
1237 ForcePointer();
1239 SfxBindings& rBindings = mpViewShell->GetViewFrame()->GetBindings();
1240 rBindings.Invalidate(SID_BEZIER_MOVE);
1241 rBindings.Invalidate(SID_BEZIER_INSERT);
1245 * Execute ImageMap interaction
1247 bool FuSelection::HandleImageMapClick(const SdrObject* pObj, const Point& rPos)
1249 bool bClosed = pObj->IsClosedObj();
1250 bool bFilled = false;
1252 if (bClosed)
1254 SfxItemSet aSet(mpDoc->GetPool());
1256 aSet.Put(pObj->GetMergedItemSet());
1258 const XFillStyleItem& rFillStyle = aSet.Get(XATTR_FILLSTYLE);
1259 bFilled = rFillStyle.GetValue() != drawing::FillStyle_NONE;
1262 const SdrLayerIDSet* pVisiLayer = &mpView->GetSdrPageView()->GetVisibleLayers();
1263 double fHitLog = mpWindow->PixelToLogic(Size(HITPIX, 0)).Width();
1264 const ::tools::Long n2HitLog = fHitLog * 2;
1265 Point aHitPosR(rPos);
1266 Point aHitPosL(rPos);
1267 Point aHitPosT(rPos);
1268 Point aHitPosB(rPos);
1270 aHitPosR.AdjustX(n2HitLog);
1271 aHitPosL.AdjustX(-n2HitLog);
1272 aHitPosT.AdjustY(n2HitLog);
1273 aHitPosB.AdjustY(-n2HitLog);
1275 if (!bClosed || !bFilled
1276 || (SdrObjectPrimitiveHit(*pObj, aHitPosR, {fHitLog, fHitLog}, *mpView->GetSdrPageView(), pVisiLayer,
1277 false)
1278 && SdrObjectPrimitiveHit(*pObj, aHitPosL, {fHitLog, fHitLog}, *mpView->GetSdrPageView(),
1279 pVisiLayer, false)
1280 && SdrObjectPrimitiveHit(*pObj, aHitPosT, {fHitLog, fHitLog}, *mpView->GetSdrPageView(),
1281 pVisiLayer, false)
1282 && SdrObjectPrimitiveHit(*pObj, aHitPosB, {fHitLog, fHitLog}, *mpView->GetSdrPageView(),
1283 pVisiLayer, false)))
1285 if (SvxIMapInfo::GetIMapInfo(pObj))
1287 const IMapObject* pIMapObj = SvxIMapInfo::GetHitIMapObject(pObj, rPos);
1289 if (pIMapObj && !pIMapObj->GetURL().isEmpty())
1291 // Jump to Document
1292 mpWindow->ReleaseMouse();
1293 SfxStringItem aStrItem(SID_FILE_NAME, pIMapObj->GetURL());
1294 SfxStringItem aReferer(SID_REFERER, mpDocSh->GetMedium()->GetName());
1295 SfxViewFrame* pFrame = mpViewShell->GetViewFrame();
1296 SfxFrameItem aFrameItem(SID_DOCFRAME, pFrame);
1297 SfxBoolItem aBrowseItem(SID_BROWSE, true);
1298 mpWindow->ReleaseMouse();
1299 pFrame->GetDispatcher()->ExecuteList(
1300 SID_OPENDOC, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
1301 { &aStrItem, &aFrameItem, &aBrowseItem, &aReferer });
1303 return true;
1308 return false;
1311 /** is called when the current function should be aborted. <p>
1312 This is used when a function gets a KEY_ESCAPE but can also
1313 be called directly.
1315 @returns true if an active function was aborted
1317 bool FuSelection::cancel()
1319 if (mpView->Is3DRotationCreationActive())
1321 mpView->ResetCreationActive();
1322 mpViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
1323 return true;
1325 else
1327 return false;
1331 SdrObject* FuSelection::pickObject (const Point& rTestPoint)
1333 SdrPageView* pPageView;
1334 sal_uInt16 nHitLog = sal_uInt16 (mpWindow->PixelToLogic(Size(HITPIX,0)).Width());
1335 return mpView->PickObj(rTestPoint, nHitLog, pPageView, SdrSearchOptions::PICKMARKABLE);
1338 void FuSelection::ForcePointer(const MouseEvent* pMEvt)
1340 if(bMovedToCenterPoint && !bBeginInsertPoint && pMEvt)
1342 MouseEvent aMEvt(pMEvt->GetPosPixel(), pMEvt->GetClicks(),
1343 pMEvt->GetMode(), pMEvt->GetButtons(), pMEvt->GetModifier() & ~KEY_SHIFT);
1344 FuDraw::ForcePointer(&aMEvt);
1346 else
1348 FuDraw::ForcePointer(pMEvt);
1352 } // end of namespace sd
1354 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */