/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
// The OverlayObjects are cleared using the destructor of OverlayObjectList. // That destructor calls clear() at the list which removes all objects from the // OverlayManager and deletes them.
ImplMarkingOverlay::ImplMarkingOverlay(const SdrPaintView& rView, const basegfx::B2DPoint& rStartPos, bool bUnmarking)
: maSecondPosition(rStartPos),
mbUnmarking(bUnmarking)
{ if (comphelper::LibreOfficeKit::isActive()) return; // We do client-side object manipulation with the Kit API
// remember new position
maSecondPosition = rNewPosition;
}
}
class MarkingSelectionOverlay
{
sdr::overlay::OverlayObjectList maObjects; public:
MarkingSelectionOverlay(const SdrPaintView& rView, basegfx::B2DRectangle const& rSelection)
{ if (comphelper::LibreOfficeKit::isActive()) return; // We do client-side object manipulation with the Kit API
for (sal_uInt32 a(0); a < rView.PaintWindowCount(); a++)
{
SdrPaintWindow* pPaintWindow = rView.GetPaintWindow(a); const rtl::Reference<sdr::overlay::OverlayManager>& xTargetOverlay = pPaintWindow->GetOverlayManager();
if (xTargetOverlay.is())
{
basegfx::B2DPolyPolygon aPolyPoly(basegfx::utils::createPolygonFromRect(rSelection)); auto pNew = std::make_unique<sdr::overlay::OverlayPolyPolygon>(aPolyPoly, COL_GRAY, 0, COL_TRANSPARENT);
xTargetOverlay->add(*pNew);
maObjects.append(std::move(pNew));
}
}
}
};
class MarkingSubSelectionOverlay
{
sdr::overlay::OverlayObjectList maObjects;
public:
MarkingSubSelectionOverlay(const SdrPaintView& rView, std::vector<basegfx::B2DRectangle> const & rSelections)
{ if (comphelper::LibreOfficeKit::isActive()) return; // We do client-side object manipulation with the Kit API
for (sal_uInt32 a(0); a < rView.PaintWindowCount(); a++)
{
SdrPaintWindow* pCandidate = rView.GetPaintWindow(a); const rtl::Reference<sdr::overlay::OverlayManager>& xTargetOverlay = pCandidate->GetOverlayManager();
if (xTargetOverlay.is())
{ const Color aHighlightColor = SvtOptionsDrawinglayer::getHilightColor();
void SdrMarkView::ModelHasChanged()
{
SdrPaintView::ModelHasChanged();
GetMarkedObjectListWriteAccess().SetNameDirty();
mbMarkedObjRectDirty=true;
mbMarkedPointsRectsDirty=true; // Example: Obj is selected and maMarkedObjectList is sorted. // In another View 2, the ObjOrder is changed (e. g. MovToTop()) // Then we need to re-sort MarkList.
GetMarkedObjectListWriteAccess().SetUnsorted(); const SdrMarkList& rMarkList = GetMarkedObjectList();
rMarkList.ForceSort();
mbMrkPntDirty=true;
UndirtyMrkPnt();
SdrView* pV=static_cast<SdrView*>(this); if (!pV->IsDragObj() && !pV->IsInsObjPoint()) {
AdjustMarkHdl();
}
if (comphelper::LibreOfficeKit::isActive())
modelHasChangedLOKit();
}
//TODO: Is MarkedObjRect valid at this point?
tools::Rectangle aSelection(GetMarkedObjRect());
tools::Rectangle* pResultSelection; if (aSelection.IsEmpty())
pResultSelection = nullptr; else
{
sal_uInt32 nTotalPaintWindows = this->PaintWindowCount(); if (nTotalPaintWindows == 1)
{ const OutputDevice* pOut = this->GetFirstOutputDevice(); const vcl::Window* pWin = pOut ? pOut->GetOwnerWindow() : nullptr; if (pWin && pWin->IsChart())
{ if (SfxViewShell* pViewShell = GetSfxViewShell())
{ const vcl::Window* pViewShellWindow = pViewShell->GetEditWindowForActiveOLEObj(); if (pViewShellWindow && pViewShellWindow->IsAncestorOf(*pWin))
{
Point aOffsetPx = pWin->GetOffsetPixelFrom(*pViewShellWindow);
Point aLogicOffset = pWin->PixelToLogic(aOffsetPx);
aSelection.Move(aLogicOffset.getX(), aLogicOffset.getY());
}
}
}
}
// In case the map mode is in 100th MM, then need to convert the coordinates over to twips for LOK. if (mpMarkedPV)
{ if (OutputDevice* pOutputDevice = mpMarkedPV->GetView().GetFirstOutputDevice())
{ if (pOutputDevice->GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
aSelection = o3tl::convert(aSelection, o3tl::Length::mm100, o3tl::Length::twip);
}
}
pResultSelection = &aSelection;
if (mbNegativeX)
{ // Convert to positive X doc-coordinates
tools::Long nTmp = aSelection.Left();
aSelection.SetLeft(-aSelection.Right());
aSelection.SetRight(-nTmp);
}
}
if (SfxViewShell* pViewShell = GetSfxViewShell())
SfxLokHelper::notifyInvalidation(pViewShell, pResultSelection);
}
tools::Rectangle aSelection(rRect);
tools::Long nSignX = mbNegativeX ? -1 : 1; bool bIsChart = false;
Point addLogicOffset(0, 0); bool convertMapMode = false; if (!rRect.IsEmpty())
{
sal_uInt32 nTotalPaintWindows = this->PaintWindowCount(); if (nTotalPaintWindows == 1)
{ const OutputDevice* pOut = this->GetFirstOutputDevice(); const vcl::Window* pWin = pOut ? pOut->GetOwnerWindow() : nullptr; if (pWin && pWin->IsChart())
{
bIsChart = true; const vcl::Window* pViewShellWindow = GetSfxViewShell()->GetEditWindowForActiveOLEObj(); if (pViewShellWindow && pViewShellWindow->IsAncestorOf(*pWin))
{
Point aOffsetPx = pWin->GetOffsetPixelFrom(*pViewShellWindow); if (mbNegativeX && AllSettings::GetLayoutRTL())
{ // mbNegativeX is set only for Calc in RTL mode. // If global RTL flag is set, vcl-window X offset of chart window is // mirrored w.r.t parent window rectangle. This needs to be reverted.
aOffsetPx.setX(pViewShellWindow->GetOutOffXPixel() + pViewShellWindow->GetSizePixel().Width()
- pWin->GetOutOffXPixel() - pWin->GetSizePixel().Width());
}
Point aLogicOffset = pWin->PixelToLogic(aOffsetPx);
addLogicOffset = aLogicOffset;
aSelection.Move(aLogicOffset.getX(), aLogicOffset.getY());
}
}
}
}
if (!aSelection.IsEmpty())
{ // In case the map mode is in 100th MM, then need to convert the coordinates over to twips for LOK. if (mpMarkedPV)
{ if (OutputDevice* pOutputDevice = mpMarkedPV->GetView().GetFirstOutputDevice())
{ if (pOutputDevice->GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
{
aSelection = o3tl::convert(aSelection, o3tl::Length::mm100, o3tl::Length::twip);
convertMapMode = true;
}
}
}
// hide the text selection too if (pViewShell)
pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, ""_ostr);
}
const SdrMarkList& rMarkList = GetMarkedObjectList(); if (rMarkList.GetMarkCount())
{
SdrMark* pM = rMarkList.GetMark(0);
SdrObject* pO = pM->GetMarkedSdrObj();
Degree100 nRotAngle = pO->GetRotateAngle(); // true if we are dealing with a RotGrfFlyFrame // (SwVirtFlyDrawObj with a SwGrfNode) bool bWriterGraphic = pO->HasLimitedRotation();
if (mpMarkedObj && !pOtherShell)
{
OString innerTextInfo = CreateInnerTextRectString(); if (!innerTextInfo.isEmpty())
aExtraInfo.append("," + innerTextInfo);
}
// In core, the gridOffset is calculated based on the LogicRect's TopLeft coordinate // In online, we have the SnapRect and we calculate it based on its TopLeft coordinate // SnapRect's TopLeft and LogicRect's TopLeft match unless there is rotation // but the rotation is not applied to the LogicRect. Therefore, // what we calculate in online does not match with the core in case of the rotation. // Here we can send the correct gridOffset in the selection callback, this way // whether the shape is rotated or not, we will always have the correct gridOffset // Note that the gridOffset is calculated from the first selected obj
basegfx::B2DVector aGridOffset(0.0, 0.0); if(getPossibleGridOffsetForSdrObject(aGridOffset, rMarkList.GetMark(0)->GetMarkedSdrObj(), pPageView))
{
Point p(aGridOffset.getX(), aGridOffset.getY()); if (convertMapMode)
p = o3tl::convert(p, o3tl::Length::mm100, o3tl::Length::twip);
aExtraInfo.append(",\"gridOffsetX\":"
+ OString::number(nSignX * p.getX())
+ ",\"gridOffsetY\":"
+ OString::number(p.getY()));
}
if (meDragMode == SdrDragMode::Crop)
aExtraInfo.append(", \"isCropMode\": true");
std::u16string_view sDragMethod = lcl_getDragMethodServiceName(aValue); if (sDragMethod == u"PieSegmentDragging")
{ // old initial offset inside the CID returned by xSelectionSupplier->getSelection() // after a pie segment dragging; using SdrObject::GetName for getting a CID with the updated offset
aValue = pO->GetName();
std::u16string_view sDragParameters = lcl_getDragParameterString(aValue); if (!sDragParameters.empty())
{
aExtraInfo.append(", \"dragInfo\": { " "\"dragMethod\": \""
+ OUString(sDragMethod).toUtf8()
+ "\"");
// polygon approximating the pie segment or donut segment if (pViewShell && pO->GetObjIdentifier() == SdrObjKind::PathFill)
{ const basegfx::B2DPolyPolygon aPolyPolygon(pO->TakeXorPoly()); if (aPolyPolygon.count() == 1)
{ const basegfx::B2DPolygon& aPolygon = aPolyPolygon.getB2DPolygon(0); if (sal_uInt32 nPolySize = aPolygon.count())
{ const OutputDevice* pOut = this->GetFirstOutputDevice(); const vcl::Window* pWin = pOut ? pOut->GetOwnerWindow() : nullptr; const vcl::Window* pViewShellWindow = pViewShell->GetEditWindowForActiveOLEObj(); if (pWin && pViewShellWindow && pViewShellWindow->IsAncestorOf(*pWin))
{ // in the following code escaping sequences used inside raw literal strings // are for making them understandable by the JSON parser
Point aOffsetPx = pWin->GetOffsetPixelFrom(*pViewShellWindow);
Point aLogicOffset = pWin->PixelToLogic(aOffsetPx);
OString sPolygonElem("<polygon points=\\\""_ostr); for (sal_uInt32 nIndex = 0; nIndex < nPolySize; ++nIndex)
{ const basegfx::B2DPoint aB2Point = aPolygon.getB2DPoint(nIndex);
Point aPoint(aB2Point.getX(), aB2Point.getY());
aPoint.Move(aLogicOffset.getX(), aLogicOffset.getY()); if (mbNegativeX)
aPoint.setX(-aPoint.X()); if (nIndex > 0)
sPolygonElem += " ";
sPolygonElem += aPoint.toString();
}
sPolygonElem += R"elem(\" style=\"stroke: none; fill: rgb(114,159,207); fill-opacity: 0.8\"/>)elem";
if (bMediaObj && pOtherShell == nullptr)
{ // Add the URL only if we have a Media Object and // we are the selecting view.
SdrMediaObj* mediaObj = dynamic_cast<SdrMediaObj*>(mpMarkedObj); if (mediaObj)
aExtraInfo.append(", \"url\": \"" + mediaObj->getTempURL().toUtf8() + "\"");
}
if (pPage && getSdrModelFromSdrView().IsImpress())
{ // Send all objects' rectangles along with the selected object's information. // Other rectangles can be used for aligning the selected object referencing the others. // Replace curly braces with empty string in order to merge it with the resulting string.
OString objectRectangles = SdrObjList::GetObjectRectangles(*pPage).replaceAll("{"_ostr, ""_ostr).replaceAll("}"_ostr, ""_ostr);
aExtraInfo.append(", \"ObjectRectangles\": "_ostr + objectRectangles);
}
if (pOtherShell)
{ // Another shell wants to know about our existing // selection. if (pViewShell != pOtherShell)
SfxLokHelper::notifyOtherView(pViewShell, pOtherShell, LOK_CALLBACK_GRAPHIC_VIEW_SELECTION, "selection", sSelectionTextView);
} elseif (pViewShell)
{ // We have a new selection, so both pViewShell and the // other views want to know about it.
pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_GRAPHIC_SELECTION, sSelectionText);
// delete/clear all handles. This will always be done, even with areMarkHandlesHidden()
maHdlList.Clear();
maHdlList.SetRotateShear(meDragMode==SdrDragMode::Rotate);
maHdlList.SetDistortShear(meDragMode==SdrDragMode::Shear);
mpMarkedObj=nullptr;
mpMarkedPV=nullptr;
// are handles enabled at all? Create only then if(areMarkHandlesHidden()) return;
// There can be multiple mark views, but we're only interested in the one that has a window associated. constbool bTiledRendering = comphelper::LibreOfficeKit::isActive() && GetFirstOutputDevice() && GetFirstOutputDevice()->GetOutDevType() == OUTDEV_WINDOW;
// check if text edit or ole is active and handles need to be suppressed. This may be the case // when a single object is selected // Using a strict return statement is okay here; no handles means *no* handles. if (mpMarkedObj)
{ // formerly #i33755#: If TextEdit is active the EditEngine will directly paint // to the window, so suppress Overlay and handles completely; a text frame for // the active text edit will be painted by the repaint mechanism in // SdrObjEditView::ImpPaintOutlinerView in this case. This needs to be reworked // in the future // Also formerly #122142#: Pretty much the same for SdrCaptionObj's in calc. if(static_cast<SdrView*>(this)->IsTextEdit())
{ const SdrTextObj* pSdrTextObj = DynCastSdrTextObj(mpMarkedObj);
if (pSdrTextObj && pSdrTextObj->IsInEditMode())
{ if (!bTiledRendering) return;
}
}
// formerly #i118524#: if inplace activated OLE is selected, suppress handles const SdrOle2Obj* pSdrOle2Obj = dynamic_cast< const SdrOle2Obj* >(mpMarkedObj);
if (!bWdt0 && !bHgt0)
{
maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.BottomLeft(), SdrHdlKind::LowerLeft));
}
if (!bLimitedRotation && !bHgt0)
{
maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.BottomCenter(), SdrHdlKind::Lower));
}
if (!bWdt0 && !bHgt0)
{
maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.BottomRight(), SdrHdlKind::LowerRight));
}
}
}
// Diagram selection visualization support // Caution: CppunitTest_sd_tiledrendering shows that mpMarkedObj *can* actually be nullptr (!) if(nullptr != mpMarkedObj && mpMarkedObj->isDiagram())
{
mpMarkedObj->AddToHdlList(maHdlList);
}
const size_t nSiz1(maHdlList.GetHdlCount());
// moved setting the missing parameters at SdrHdl here from the // single loop above (bSingleTextObjMark), this was missing all // the time. Setting SdrObject is now required to correctly get // the View-Dependent evtl. GridOffset adapted for (size_t i=nSiz0; i<nSiz1; ++i)
{
SdrHdl* pHdl=maHdlList.GetHdl(i);
pHdl->SetObj(mpMarkedObj);
pHdl->SetPageView(mpMarkedPV);
pHdl->SetObjHdlNum(sal_uInt16(i-nSiz0));
}
}
} else
{ bool bDone(false);
// moved crop handling to non-frame part and the handle creation to SdrGrafObj if(1 == nMarkCount && mpMarkedObj && SdrDragMode::Crop == meDragMode)
{ // Default addCropHandles from SdrObject does nothing. When pMarkedObj is SdrGrafObj, previous // behaviour occurs (code in svx/source/svdraw/svdograf.cxx). When pMarkedObj is SwVirtFlyDrawObj // writer takes the responsibility of adding handles (code in sw/source/core/draw/dflyobj.cxx) const size_t nSiz0(maHdlList.GetHdlCount());
mpMarkedObj->addCropHandles(maHdlList); const size_t nSiz1(maHdlList.GetHdlCount());
// Was missing: Set infos at SdrCropHdl for (size_t i=nSiz0; i<nSiz1; ++i)
{
SdrHdl* pHdl=maHdlList.GetHdl(i);
pHdl->SetObj(mpMarkedObj);
pHdl->SetPageView(mpMarkedPV);
pHdl->SetObjHdlNum(sal_uInt16(i-nSiz0));
}
// GluePoint handles for (size_t nMarkNum=0; nMarkNum<nMarkCount; ++nMarkNum)
{ const SdrMark* pM=rMarkList.GetMark(nMarkNum);
SdrObject* pObj=pM->GetMarkedSdrObj(); const SdrGluePointList* pGPL=pObj->GetGluePointList(); if (!pGPL) continue;
SdrPageView* pPV=pM->GetPageView(); const SdrUShortCont& rMrkGlue=pM->GetMarkedGluePoints(); for (sal_uInt16 nId : rMrkGlue)
{ //nNum changed to nNumGP because already used in for loop
sal_uInt16 nNumGP=pGPL->FindGluePoint(nId); if (nNumGP!=SDRGLUEPOINT_NOTFOUND)
{ const SdrGluePoint& rGP=(*pGPL)[nNumGP];
Point aPos(rGP.GetAbsolutePos(*pObj));
std::unique_ptr<SdrHdl> pGlueHdl(new SdrHdl(aPos,SdrHdlKind::Glue));
pGlueHdl->SetObj(pObj);
pGlueHdl->SetPageView(pPV);
pGlueHdl->SetObjHdlNum(nId);
maHdlList.AddHdl(std::move(pGlueHdl));
}
}
}
// rotation point/axis of reflection if(!bLimitedRotation)
{
AddDragModeHdl(meDragMode);
}
// sort handles
maHdlList.Sort();
// add custom handles (used by other apps, e.g. AnchorPos)
AddCustomHdl();
// moved it here to access all the handles for callback. if (bTiledRendering && pViewShell)
{
SetMarkHandlesForLOKit(aRect, pOtherShell);
}
// try to restore focus handle index from remembered values if(!bSaveOldFocus) return;
for(size_t a = 0; a < maHdlList.GetHdlCount(); ++a)
{
SdrHdl* pCandidate = maHdlList.GetHdl(a);
void SdrMarkView::AddCustomHdl()
{ // add custom handles (used by other apps, e.g. AnchorPos)
}
void SdrMarkView::SetDragMode(SdrDragMode eMode)
{
SdrDragMode eMode0=meDragMode;
meDragMode=eMode; if (meDragMode==SdrDragMode::Resize) meDragMode=SdrDragMode::Move; if (meDragMode!=eMode0) {
ForceRefToMarked();
SetMarkHandles(nullptr);
{ const SdrMarkList& rMarkList = GetMarkedObjectList(); if (rMarkList.GetMarkCount() != 0) MarkListHasChanged();
}
}
}
void SdrMarkView::AddDragModeHdl(SdrDragMode eMode)
{ switch(eMode)
{ case SdrDragMode::Rotate:
{ // add rotation center
maHdlList.AddHdl(std::make_unique<SdrHdl>(maRef1, SdrHdlKind::Ref1)); break;
} case SdrDragMode::Mirror:
{ // add axis of reflection
std::unique_ptr<SdrHdl> pHdl3(new SdrHdl(maRef2, SdrHdlKind::Ref2));
std::unique_ptr<SdrHdl> pHdl2(new SdrHdl(maRef1, SdrHdlKind::Ref1));
std::unique_ptr<SdrHdl> pHdl1(new SdrHdlLine(*pHdl2, *pHdl3, SdrHdlKind::MirrorAxis));
pHdl1->SetObjHdlNum(1); // for sorting
pHdl2->SetObjHdlNum(2); // for sorting
pHdl3->SetObjHdlNum(3); // for sorting
maHdlList.AddHdl(std::move(pHdl1)); // line comes first, so it is the last in HitTest
maHdlList.AddHdl(std::move(pHdl2));
maHdlList.AddHdl(std::move(pHdl3));
// add undo to allow user to take back this step if (rModel.IsUndoEnabled())
{
rModel.BegUndo(SvxResId(SIP_XA_FILLTRANSPARENCE));
rModel.AddUndo(rModel.GetSdrUndoFactory().CreateUndoAttrObject(*pObj));
rModel.EndUndo();
}
if(eFillStyle == drawing::FillStyle_GRADIENT)
{ // set values and transform to vector set
GradTransVector aGradTransVector;
GradTransGradient aGradTransGradient;
Size aHdlSize(15, 15);
if (pOut!=nullptr && nMinLen>nOutHgt) nMinLen=nOutHgt; // TODO: maybe shorten this a little
if (pOut!=nullptr) { // now move completely into the visible area if (nY1<nOutMin) {
nY1=nOutMin; if (nY2<nY1+nMinLen) nY2=nY1+nMinLen;
} if (nY2>nOutMax) {
nY2=nOutMax; if (nY1>nY2-nMinLen) nY1=nY2-nMinLen;
}
}
const SdrMarkList& rMarkList = GetMarkedObjectList();
rMarkList.ForceSort(); const size_t nMarkCount=rMarkList.GetMarkCount();
size_t nChgMarkNum = SAL_MAX_SIZE; // number of the MarkEntry we want to replace
size_t nSearchObjNum = bPrev ? 0 : SAL_MAX_SIZE; if (nMarkCount!=0) {
nChgMarkNum=bPrev ? 0 : nMarkCount-1;
SdrMark* pM=rMarkList.GetMark(nChgMarkNum);
assert(pM != nullptr); if (pM->GetMarkedSdrObj() != nullptr)
nSearchObjNum = pM->GetMarkedSdrObj()->GetNavigationPosition();
}
SdrObject* pMarkObj=nullptr;
SdrObjList* pSearchObjList=pPageView->GetObjList(); const size_t nObjCount = pSearchObjList->GetObjCount(); if (nObjCount!=0) { if (nSearchObjNum>nObjCount) nSearchObjNum=nObjCount; while (pMarkObj==nullptr && ((!bPrev && nSearchObjNum>0) || (bPrev && nSearchObjNum<nObjCount)))
{ if (!bPrev)
nSearchObjNum--;
SdrObject* pSearchObj = pSearchObjList->GetObjectForNavigationPosition(nSearchObjNum); if (IsObjMarkable(pSearchObj,pPageView))
{ if (rMarkList.FindObject(pSearchObj)==SAL_MAX_SIZE)
{
pMarkObj=pSearchObj;
}
} if (bPrev) nSearchObjNum++;
}
}
if(!pMarkObj)
{ returnfalse;
}
if (nChgMarkNum!=SAL_MAX_SIZE)
{
GetMarkedObjectListWriteAccess().DeleteMark(nChgMarkNum);
}
MarkObj(pMarkObj,pPageView); // also calls MarkListHasChanged(), AdjustMarkHdl() returntrue;
}
bool SdrMarkView::MarkNextObj(const Point& rPnt, short nTol, bool bPrev)
{ const SdrMarkList& rMarkList = GetMarkedObjectList();
rMarkList.ForceSort();
nTol=ImpGetHitTolLogic(nTol,nullptr);
SdrMark* pTopMarkHit=nullptr;
SdrMark* pBtmMarkHit=nullptr;
size_t nTopMarkHit=0;
size_t nBtmMarkHit=0; // find topmost of the selected objects that is hit by rPnt const size_t nMarkCount=rMarkList.GetMarkCount(); for (size_t nm=nMarkCount; nm>0 && pTopMarkHit==nullptr;) {
--nm;
SdrMark* pM=rMarkList.GetMark(nm); if(CheckSingleSdrObjectHit(rPnt,sal_uInt16(nTol),pM->GetMarkedSdrObj(),pM->GetPageView(),SdrSearchOptions::NONE,nullptr))
{
pTopMarkHit=pM;
nTopMarkHit=nm;
}
} // nothing found, in this case, just select an object if (pTopMarkHit==nullptr) return MarkObj(rPnt,sal_uInt16(nTol));
SdrObject* pTopObjHit=pTopMarkHit->GetMarkedSdrObj();
SdrObjList* pObjList=pTopObjHit->getParentSdrObjListFromSdrObject();
SdrPageView* pPV=pTopMarkHit->GetPageView(); // find lowermost of the selected objects that is hit by rPnt // and is placed on the same PageView as pTopMarkHit for (size_t nm=0; nm<nMarkCount && pBtmMarkHit==nullptr; ++nm) {
SdrMark* pM=rMarkList.GetMark(nm);
SdrPageView* pPV2=pM->GetPageView(); if (pPV2==pPV && CheckSingleSdrObjectHit(rPnt,sal_uInt16(nTol),pM->GetMarkedSdrObj(),pPV2,SdrSearchOptions::NONE,nullptr))
{
pBtmMarkHit=pM;
nBtmMarkHit=nm;
}
} if (pBtmMarkHit==nullptr) { pBtmMarkHit=pTopMarkHit; nBtmMarkHit=nTopMarkHit; }
SdrObject* pBtmObjHit=pBtmMarkHit->GetMarkedSdrObj(); const size_t nObjCount = pObjList->GetObjCount();
if (CheckSingleSdrObjectHit(rPnt,sal_uInt16(nTol),pObj,pPV,SdrSearchOptions::TESTMARKABLE,nullptr))
{ if (rMarkList.FindObject(pObj)==SAL_MAX_SIZE) {
pFndObj=pObj;
} else { // TODO: for performance reasons set on to Top or Btm, if necessary
}
} if (bPrev) no++;
} if (pFndObj!=nullptr)
{
GetMarkedObjectListWriteAccess().DeleteMark(bPrev?nBtmMarkHit:nTopMarkHit);
GetMarkedObjectListWriteAccess().InsertEntry(SdrMark(pFndObj,pPV));
MarkListHasChanged();
AdjustMarkHdl();
} return pFndObj!=nullptr;
}
// add possible GridOffset to up-to-now view-independent BoundRect data
basegfx::B2DVector aGridOffset(0.0, 0.0); if(getPossibleGridOffsetForSdrObject(aGridOffset, pObj, pPV))
{
aRect += Point(
basegfx::fround<tools::Long>(aGridOffset.getX()),
basegfx::fround<tools::Long>(aGridOffset.getY()));
}
double nTol2(nTol);
// double tolerance for OLE, text frames and objects in // active text edit if(bOLE || bTXT || pObj==static_cast<const SdrObjEditView*>(this)->GetTextEditObject())
{
nTol2*=2;
}
aRect.expand(nTol2); // add 1 tolerance for all objects
if (aRect.Contains(rPnt))
{ if (!bCheckIfMarkable || IsObjMarkable(pObj,pPV))
{
SdrObjList* pOL=pObj->GetSubList();
if (pOL!=nullptr && pOL->GetObjCount()!=0)
{
SdrObject* pTmpObj; // adjustment hit point for virtual objects
Point aPnt( rPnt );
if ( auto pVirtObj = dynamic_cast<const SdrVirtObj*>( pObj) )
{
Point aOffset = pVirtObj->GetOffset();
aPnt.Move( -aOffset.X(), -aOffset.Y() );
}
// #i69171# pPV may still be NULL if there is no SDrPageView (!), e.g. when inserting // other files if(pPV)
{ constbool bMarkChg(GetMarkedObjectListWriteAccess().InsertPageView(*pPV));
void SdrMarkView::EnterMarkedGroup()
{ // We enter only the first group found (in only one PageView), because // PageView::EnterGroup calls an AdjustMarkHdl. // TODO: I'll have to prevent that via a flag.
SdrPageView* pPV = GetSdrPageView();
if(!pPV) return;
bool bEnter=false; const SdrMarkList& rMarkList = GetMarkedObjectList(); for (size_t nm = rMarkList.GetMarkCount(); nm > 0 && !bEnter;)
{
--nm;
SdrMark* pM=rMarkList.GetMark(nm); if (pM->GetPageView()==pPV) {
SdrObject* pObj=pM->GetMarkedSdrObj(); if (pObj->IsGroupObject()) { if (pPV->EnterGroup(pObj)) {
bEnter=true;
}
}
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.