1
0
Fork 0
libreoffice/svx/source/svdraw/svdmrkv1.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

563 lines
18 KiB
C++

/* -*- 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 .
*/
#include <svx/svdmrkv.hxx>
#include <svx/svdpagv.hxx>
#include <osl/diagnose.h>
// Point Selection
bool SdrMarkView::HasMarkablePoints() const
{
ForceUndirtyMrkPnt();
bool bRet=false;
if (!ImpIsFrameHandles()) {
const SdrMarkList& rMarkList = GetMarkedObjectList();
const size_t nMarkCount=rMarkList.GetMarkCount();
if (nMarkCount<=static_cast<size_t>(mnFrameHandlesLimit)) {
for (size_t nMarkNum=0; nMarkNum<nMarkCount && !bRet; ++nMarkNum) {
const SdrMark* pM=rMarkList.GetMark(nMarkNum);
const SdrObject* pObj=pM->GetMarkedSdrObj();
bRet=pObj->IsPolyObj();
}
}
}
return bRet;
}
sal_Int32 SdrMarkView::GetMarkablePointCount() const
{
ForceUndirtyMrkPnt();
sal_Int32 nCount=0;
if (!ImpIsFrameHandles()) {
const SdrMarkList& rMarkList = GetMarkedObjectList();
const size_t nMarkCount=rMarkList.GetMarkCount();
if (nMarkCount<=static_cast<size_t>(mnFrameHandlesLimit)) {
for (size_t nMarkNum=0; nMarkNum<nMarkCount; ++nMarkNum) {
const SdrMark* pM=rMarkList.GetMark(nMarkNum);
const SdrObject* pObj=pM->GetMarkedSdrObj();
if (pObj->IsPolyObj()) {
nCount+=pObj->GetPointCount();
}
}
}
}
return nCount;
}
bool SdrMarkView::HasMarkedPoints() const
{
ForceUndirtyMrkPnt();
bool bRet=false;
if (!ImpIsFrameHandles()) {
const SdrMarkList& rMarkList = GetMarkedObjectList();
const size_t nMarkCount=rMarkList.GetMarkCount();
if (nMarkCount<=static_cast<size_t>(mnFrameHandlesLimit)) {
for (size_t nMarkNum=0; nMarkNum<nMarkCount && !bRet; ++nMarkNum) {
const SdrMark* pM=rMarkList.GetMark(nMarkNum);
const SdrUShortCont& rPts = pM->GetMarkedPoints();
bRet = !rPts.empty();
}
}
}
return bRet;
}
bool SdrMarkView::IsPointMarkable(const SdrHdl& rHdl) const
{
return !ImpIsFrameHandles() && !rHdl.IsPlusHdl() && rHdl.GetKind()!=SdrHdlKind::Glue && rHdl.GetKind()!=SdrHdlKind::SmartTag && rHdl.GetObj()!=nullptr && rHdl.GetObj()->IsPolyObj();
}
bool SdrMarkView::MarkPointHelper(SdrHdl* pHdl, SdrMark* pMark, bool bUnmark)
{
return ImpMarkPoint( pHdl, pMark, bUnmark );
}
bool SdrMarkView::ImpMarkPoint(SdrHdl* pHdl, SdrMark* pMark, bool bUnmark)
{
if (pHdl==nullptr || pHdl->IsPlusHdl() || pHdl->GetKind()==SdrHdlKind::Glue)
return false;
if (pHdl->IsSelected() != bUnmark)
return false;
SdrObject* pObj=pHdl->GetObj();
if (pObj==nullptr || !pObj->IsPolyObj())
return false;
if (pMark==nullptr)
{
const SdrMarkList& rMarkList = GetMarkedObjectList();
const size_t nMarkNum=rMarkList.FindObject(pObj);
if (nMarkNum==SAL_MAX_SIZE)
return false;
pMark=rMarkList.GetMark(nMarkNum);
}
const sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
SdrUShortCont& rPts=pMark->GetMarkedPoints();
if (!bUnmark)
{
rPts.insert(static_cast<sal_uInt16>(nHdlNum));
}
else
{
SdrUShortCont::const_iterator it = rPts.find( static_cast<sal_uInt16>(nHdlNum) );
if (it != rPts.end())
{
rPts.erase(it);
}
else
{
return false; // error case!
}
}
pHdl->SetSelected(!bUnmark);
if (!mbPlusHdlAlways)
{
if (!bUnmark)
{
SdrHdlList plusList(nullptr);
pObj->AddToPlusHdlList(plusList, *pHdl);
sal_uInt32 nCount(plusList.GetHdlCount());
for (sal_uInt32 i=0; i<nCount; i++)
{
SdrHdl* pPlusHdl=plusList.GetHdl(i);
pPlusHdl->SetObj(pObj);
pPlusHdl->SetPageView(pMark->GetPageView());
pPlusHdl->SetPlusHdl(true);
}
plusList.MoveTo(maHdlList);
}
else
{
for (size_t i = maHdlList.GetHdlCount(); i>0;)
{
--i;
SdrHdl* pPlusHdl=maHdlList.GetHdl(i);
if (pPlusHdl->IsPlusHdl() && pPlusHdl->GetSourceHdlNum()==nHdlNum)
{
maHdlList.RemoveHdl(i);
}
}
}
}
maHdlList.Sort();
return true;
}
bool SdrMarkView::MarkPoint(SdrHdl& rHdl, bool bUnmark)
{
ForceUndirtyMrkPnt();
bool bRet=false;
const SdrObject* pObj=rHdl.GetObj();
if (IsPointMarkable(rHdl) && rHdl.IsSelected()==bUnmark) {
const SdrMarkList& rMarkList = GetMarkedObjectList();
const size_t nMarkNum=rMarkList.FindObject(pObj);
if (nMarkNum!=SAL_MAX_SIZE) {
SdrMark* pM=rMarkList.GetMark(nMarkNum);
if (ImpMarkPoint(&rHdl,pM,bUnmark)) {
MarkListHasChanged();
bRet=true;
}
}
}
return bRet;
}
bool SdrMarkView::MarkPoints(const tools::Rectangle* pRect, bool bUnmark)
{
ForceUndirtyMrkPnt();
bool bChgd=false;
const SdrMarkList& rMarkList = GetMarkedObjectList();
rMarkList.ForceSort();
const SdrObject* pObj0=nullptr;
const SdrPageView* pPV0=nullptr;
SdrMark* pM=nullptr;
maHdlList.Sort();
const size_t nHdlCnt=maHdlList.GetHdlCount();
for (size_t nHdlNum=nHdlCnt; nHdlNum>0;) {
--nHdlNum;
SdrHdl* pHdl=maHdlList.GetHdl(nHdlNum);
if (IsPointMarkable(*pHdl) && pHdl->IsSelected()==bUnmark) {
const SdrObject* pObj=pHdl->GetObj();
const SdrPageView* pPV=pHdl->GetPageView();
if (pObj!=pObj0 || pPV!=pPV0 || pM==nullptr) { // This section is for optimization,
const size_t nMarkNum=rMarkList.FindObject(pObj); // so ImpMarkPoint() doesn't always
if (nMarkNum!=SAL_MAX_SIZE) { // have to search the object in the MarkList.
pM=rMarkList.GetMark(nMarkNum);
pObj0=pObj;
pPV0=pPV;
} else {
#ifdef DBG_UTIL
assert(pObj);
if (pObj->IsInserted()) {
OSL_FAIL("SdrMarkView::MarkPoints(const Rectangle* pRect): Selected object not found.");
}
#endif
pM=nullptr;
}
}
Point aPos(pHdl->GetPos());
if (pM!=nullptr && (pRect==nullptr || pRect->Contains(aPos))) {
if (ImpMarkPoint(pHdl,pM,bUnmark)) bChgd=true;
}
}
}
if (bChgd) {
MarkListHasChanged();
}
return bChgd;
}
void SdrMarkView::MarkNextPoint()
{
ForceUndirtyMrkPnt();
const SdrMarkList& rMarkList = GetMarkedObjectList();
rMarkList.ForceSort();
}
const tools::Rectangle& SdrMarkView::GetMarkedPointsRect() const
{
ForceUndirtyMrkPnt();
if (mbMarkedPointsRectsDirty) ImpSetPointsRects();
return maMarkedPointsRect;
}
void SdrMarkView::SetPlusHandlesAlwaysVisible(bool bOn)
{ // TODO: Optimize HandlePaint!
ForceUndirtyMrkPnt();
if (bOn!=mbPlusHdlAlways) {
mbPlusHdlAlways=bOn;
SetMarkHandles(nullptr);
MarkListHasChanged();
}
}
// ImpSetPointsRects() is for PolyPoints and GluePoints!
void SdrMarkView::ImpSetPointsRects() const
{
tools::Rectangle aPnts;
tools::Rectangle aGlue;
const size_t nHdlCnt=maHdlList.GetHdlCount();
for (size_t nHdlNum=0; nHdlNum<nHdlCnt; ++nHdlNum) {
const SdrHdl* pHdl=maHdlList.GetHdl(nHdlNum);
SdrHdlKind eKind=pHdl->GetKind();
if ((eKind==SdrHdlKind::Poly && pHdl->IsSelected()) || eKind==SdrHdlKind::Glue) {
Point aPt(pHdl->GetPos());
tools::Rectangle& rR=eKind==SdrHdlKind::Glue ? aGlue : aPnts;
if (rR.IsEmpty()) {
rR=tools::Rectangle(aPt,aPt);
} else {
if (aPt.X()<rR.Left ()) rR.SetLeft(aPt.X() );
if (aPt.X()>rR.Right ()) rR.SetRight(aPt.X() );
if (aPt.Y()<rR.Top ()) rR.SetTop(aPt.Y() );
if (aPt.Y()>rR.Bottom()) rR.SetBottom(aPt.Y() );
}
}
}
const_cast<SdrMarkView*>(this)->maMarkedPointsRect=aPnts;
const_cast<SdrMarkView*>(this)->maMarkedGluePointsRect=aGlue;
const_cast<SdrMarkView*>(this)->mbMarkedPointsRectsDirty=false;
}
// UndirtyMrkPnt() is for PolyPoints and GluePoints!
void SdrMarkView::UndirtyMrkPnt() const
{
bool bChg=false;
const SdrMarkList& rMarkList = GetMarkedObjectList();
const size_t nMarkCount=rMarkList.GetMarkCount();
for (size_t nMarkNum=0; nMarkNum<nMarkCount; ++nMarkNum) {
SdrMark* pM=rMarkList.GetMark(nMarkNum);
const SdrObject* pObj=pM->GetMarkedSdrObj();
// PolyPoints
{
SdrUShortCont& rPts = pM->GetMarkedPoints();
if (pObj->IsPolyObj()) {
// Remove invalid selected points, that is, all
// entries above the number of points in the object.
sal_uInt32 nMax(pObj->GetPointCount());
SdrUShortCont::const_iterator it = rPts.lower_bound(nMax);
if( it != rPts.end() )
{
rPts.erase(it, rPts.end());
bChg = true;
}
}
else
{
if (!rPts.empty())
{
// only fail *if* there are marked points
OSL_FAIL("SdrMarkView::UndirtyMrkPnt(): Selected points on an object that is not a PolyObj!");
rPts.clear();
bChg = true;
}
}
}
// GluePoints
{
SdrUShortCont& rPts = pM->GetMarkedGluePoints();
const SdrGluePointList* pGPL=pObj->GetGluePointList();
if (pGPL!=nullptr) {
// Remove invalid selected gluepoints, that is, all entries
// (IDs) that aren't contained in the GluePointList of the
// object
for(SdrUShortCont::const_iterator it = rPts.begin(); it != rPts.end(); )
{
sal_uInt16 nId=*it;
if (pGPL->FindGluePoint(nId)==SDRGLUEPOINT_NOTFOUND) {
it = rPts.erase(it);
bChg=true;
}
else
++it;
}
} else {
if (!rPts.empty()) {
rPts.clear(); // object doesn't have any gluepoints (any more)
bChg=true;
}
}
}
}
if (bChg) const_cast<SdrMarkView*>(this)->mbMarkedPointsRectsDirty=true;
const_cast<SdrMarkView*>(this)->mbMrkPntDirty=false;
}
bool SdrMarkView::HasMarkableGluePoints() const
{
bool bRet=false;
if (IsGluePointEditMode()) {
ForceUndirtyMrkPnt();
const SdrMarkList& rMarkList = GetMarkedObjectList();
const size_t nMarkCount=rMarkList.GetMarkCount();
for (size_t nMarkNum=0; nMarkNum<nMarkCount && !bRet; ++nMarkNum) {
const SdrMark* pM=rMarkList.GetMark(nMarkNum);
const SdrObject* pObj=pM->GetMarkedSdrObj();
const SdrGluePointList* pGPL=pObj->GetGluePointList();
// #i38892#
if(pGPL && pGPL->GetCount())
{
for(sal_uInt16 a(0); !bRet && a < pGPL->GetCount(); a++)
{
if((*pGPL)[a].IsUserDefined())
{
bRet = true;
}
}
}
}
}
return bRet;
}
bool SdrMarkView::HasMarkedGluePoints() const
{
ForceUndirtyMrkPnt();
bool bRet=false;
const SdrMarkList& rMarkList = GetMarkedObjectList();
const size_t nMarkCount=rMarkList.GetMarkCount();
for (size_t nMarkNum=0; nMarkNum<nMarkCount && !bRet; ++nMarkNum) {
const SdrMark* pM=rMarkList.GetMark(nMarkNum);
const SdrUShortCont& rPts = pM->GetMarkedGluePoints();
bRet = !rPts.empty();
}
return bRet;
}
bool SdrMarkView::MarkGluePoints(const tools::Rectangle* pRect, bool bUnmark)
{
if (!IsGluePointEditMode() && !bUnmark) return false;
ForceUndirtyMrkPnt();
bool bChgd=false;
const SdrMarkList& rMarkList = GetMarkedObjectList();
rMarkList.ForceSort();
const size_t nMarkCount=rMarkList.GetMarkCount();
for (size_t nMarkNum=0; nMarkNum<nMarkCount; ++nMarkNum) {
SdrMark* pM=rMarkList.GetMark(nMarkNum);
const SdrObject* pObj=pM->GetMarkedSdrObj();
const SdrGluePointList* pGPL=pObj->GetGluePointList();
SdrUShortCont& rPts = pM->GetMarkedGluePoints();
if (bUnmark && pRect==nullptr) { // UnmarkAll
if (!rPts.empty()) {
rPts.clear();
bChgd=true;
}
} else {
if (pGPL!=nullptr) {
sal_uInt16 nGluePointCnt=pGPL->GetCount();
for (sal_uInt16 nGPNum=0; nGPNum<nGluePointCnt; nGPNum++) {
const SdrGluePoint& rGP=(*pGPL)[nGPNum];
// #i38892#
if(rGP.IsUserDefined())
{
Point aPos(rGP.GetAbsolutePos(*pObj));
if (pRect==nullptr || pRect->Contains(aPos)) {
bool bContains = rPts.find( rGP.GetId() ) != rPts.end();
if (!bUnmark && !bContains) {
bChgd=true;
rPts.insert(rGP.GetId());
}
if (bUnmark && bContains) {
bChgd=true;
rPts.erase(rGP.GetId());
}
}
}
}
}
}
}
if (bChgd) {
AdjustMarkHdl();
MarkListHasChanged();
}
return bChgd;
}
bool SdrMarkView::PickGluePoint(const Point& rPnt, SdrObject*& rpObj, sal_uInt16& rnId, SdrPageView*& rpPV) const
{
rpObj=nullptr; rpPV=nullptr; rnId=0;
if (!IsGluePointEditMode()) return false;
OutputDevice* pOut=mpActualOutDev.get();
if (pOut==nullptr) pOut=GetFirstOutputDevice();
if (pOut==nullptr) return false;
const SdrMarkList& rMarkList = GetMarkedObjectList();
rMarkList.ForceSort();
const size_t nMarkCount=rMarkList.GetMarkCount();
size_t nMarkNum=nMarkCount;
while (nMarkNum>0) {
nMarkNum--;
const SdrMark* pM=rMarkList.GetMark(nMarkNum);
SdrObject* pObj=pM->GetMarkedSdrObj();
SdrPageView* pPV=pM->GetPageView();
const SdrGluePointList* pGPL=pObj->GetGluePointList();
if (pGPL!=nullptr) {
sal_uInt16 nNum=pGPL->HitTest(rPnt,*pOut,pObj);
if (nNum!=SDRGLUEPOINT_NOTFOUND)
{
// #i38892#
const SdrGluePoint& rCandidate = (*pGPL)[nNum];
if(rCandidate.IsUserDefined())
{
rpObj=pObj;
rnId=(*pGPL)[nNum].GetId();
rpPV=pPV;
return true;
}
}
}
}
return false;
}
bool SdrMarkView::MarkGluePoint(const SdrObject* pObj, sal_uInt16 nId, bool bUnmark)
{
if (!IsGluePointEditMode()) return false;
ForceUndirtyMrkPnt();
bool bChgd=false;
if (pObj!=nullptr) {
const SdrMarkList& rMarkList = GetMarkedObjectList();
const size_t nMarkPos=rMarkList.FindObject(pObj);
if (nMarkPos!=SAL_MAX_SIZE) {
SdrMark* pM=rMarkList.GetMark(nMarkPos);
SdrUShortCont& rPts = pM->GetMarkedGluePoints();
bool bContains = rPts.find( nId ) != rPts.end();
if (!bUnmark && !bContains) {
bChgd=true;
rPts.insert(nId);
}
if (bUnmark && bContains) {
bChgd=true;
rPts.erase(nId);
}
} else {
// TODO: implement implicit selection of objects
}
}
if (bChgd) {
AdjustMarkHdl();
MarkListHasChanged();
}
return bChgd;
}
bool SdrMarkView::IsGluePointMarked(const SdrObject* pObj, sal_uInt16 nId) const
{
ForceUndirtyMrkPnt();
bool bRet=false;
const SdrMarkList& rMarkList = GetMarkedObjectList();
const size_t nPos=rMarkList.FindObject(pObj); // casting to NonConst
if (nPos!=SAL_MAX_SIZE) {
const SdrMark* pM=rMarkList.GetMark(nPos);
const SdrUShortCont& rPts = pM->GetMarkedGluePoints();
bRet = rPts.find( nId ) != rPts.end();
}
return bRet;
}
SdrHdl* SdrMarkView::GetGluePointHdl(const SdrObject* pObj, sal_uInt16 nId) const
{
ForceUndirtyMrkPnt();
const size_t nHdlCnt=maHdlList.GetHdlCount();
for (size_t nHdlNum=0; nHdlNum<nHdlCnt; ++nHdlNum) {
SdrHdl* pHdl=maHdlList.GetHdl(nHdlNum);
if (pHdl->GetObj()==pObj &&
pHdl->GetKind()==SdrHdlKind::Glue &&
pHdl->GetObjHdlNum()==nId ) return pHdl;
}
return nullptr;
}
void SdrMarkView::MarkNextGluePoint()
{
ForceUndirtyMrkPnt();
const SdrMarkList& rMarkList = GetMarkedObjectList();
rMarkList.ForceSort();
}
const tools::Rectangle& SdrMarkView::GetMarkedGluePointsRect() const
{
ForceUndirtyMrkPnt();
if (mbMarkedPointsRectsDirty) ImpSetPointsRects();
return maMarkedGluePointsRect;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */