Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / svx / source / svdraw / svdmrkv1.cxx
blob9c732262bcc901266770f20a04be8a94ace8a279
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 .
21 #include <svx/svdmrkv.hxx>
22 #include <svx/svdpagv.hxx>
23 #include <osl/diagnose.h>
26 // Point Selection
29 bool SdrMarkView::HasMarkablePoints() const
31 ForceUndirtyMrkPnt();
32 bool bRet=false;
33 if (!ImpIsFrameHandles()) {
34 const size_t nMarkCount=GetMarkedObjectCount();
35 if (nMarkCount<=static_cast<size_t>(mnFrameHandlesLimit)) {
36 for (size_t nMarkNum=0; nMarkNum<nMarkCount && !bRet; ++nMarkNum) {
37 const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
38 const SdrObject* pObj=pM->GetMarkedSdrObj();
39 bRet=pObj->IsPolyObj();
43 return bRet;
46 sal_Int32 SdrMarkView::GetMarkablePointCount() const
48 ForceUndirtyMrkPnt();
49 sal_Int32 nCount=0;
50 if (!ImpIsFrameHandles()) {
51 const size_t nMarkCount=GetMarkedObjectCount();
52 if (nMarkCount<=static_cast<size_t>(mnFrameHandlesLimit)) {
53 for (size_t nMarkNum=0; nMarkNum<nMarkCount; ++nMarkNum) {
54 const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
55 const SdrObject* pObj=pM->GetMarkedSdrObj();
56 if (pObj->IsPolyObj()) {
57 nCount+=pObj->GetPointCount();
62 return nCount;
65 bool SdrMarkView::HasMarkedPoints() const
67 ForceUndirtyMrkPnt();
68 bool bRet=false;
69 if (!ImpIsFrameHandles()) {
70 const size_t nMarkCount=GetMarkedObjectCount();
71 if (nMarkCount<=static_cast<size_t>(mnFrameHandlesLimit)) {
72 for (size_t nMarkNum=0; nMarkNum<nMarkCount && !bRet; ++nMarkNum) {
73 const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
74 const SdrUShortCont& rPts = pM->GetMarkedPoints();
75 bRet = !rPts.empty();
79 return bRet;
82 bool SdrMarkView::IsPointMarkable(const SdrHdl& rHdl) const
84 return !ImpIsFrameHandles() && !rHdl.IsPlusHdl() && rHdl.GetKind()!=SdrHdlKind::Glue && rHdl.GetKind()!=SdrHdlKind::SmartTag && rHdl.GetObj()!=nullptr && rHdl.GetObj()->IsPolyObj();
87 bool SdrMarkView::MarkPointHelper(SdrHdl* pHdl, SdrMark* pMark, bool bUnmark)
89 return ImpMarkPoint( pHdl, pMark, bUnmark );
92 bool SdrMarkView::ImpMarkPoint(SdrHdl* pHdl, SdrMark* pMark, bool bUnmark)
94 if (pHdl==nullptr || pHdl->IsPlusHdl() || pHdl->GetKind()==SdrHdlKind::Glue)
95 return false;
97 if (pHdl->IsSelected() != bUnmark)
98 return false;
100 SdrObject* pObj=pHdl->GetObj();
101 if (pObj==nullptr || !pObj->IsPolyObj())
102 return false;
104 if (pMark==nullptr)
106 const size_t nMarkNum=TryToFindMarkedObject(pObj);
107 if (nMarkNum==SAL_MAX_SIZE)
108 return false;
109 pMark=GetSdrMarkByIndex(nMarkNum);
111 const sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
112 SdrUShortCont& rPts=pMark->GetMarkedPoints();
113 if (!bUnmark)
115 rPts.insert(static_cast<sal_uInt16>(nHdlNum));
117 else
119 SdrUShortCont::const_iterator it = rPts.find( static_cast<sal_uInt16>(nHdlNum) );
120 if (it != rPts.end())
122 rPts.erase(it);
124 else
126 return false; // error case!
130 pHdl->SetSelected(!bUnmark);
131 if (!mbPlusHdlAlways)
133 if (!bUnmark)
135 SdrHdlList plusList(nullptr);
136 pObj->AddToPlusHdlList(plusList, *pHdl);
137 sal_uInt32 nCount(plusList.GetHdlCount());
138 for (sal_uInt32 i=0; i<nCount; i++)
140 SdrHdl* pPlusHdl=plusList.GetHdl(i);
141 pPlusHdl->SetObj(pObj);
142 pPlusHdl->SetPageView(pMark->GetPageView());
143 pPlusHdl->SetPlusHdl(true);
145 plusList.MoveTo(maHdlList);
147 else
149 for (size_t i = maHdlList.GetHdlCount(); i>0;)
151 --i;
152 SdrHdl* pPlusHdl=maHdlList.GetHdl(i);
153 if (pPlusHdl->IsPlusHdl() && pPlusHdl->GetSourceHdlNum()==nHdlNum)
155 maHdlList.RemoveHdl(i);
161 maHdlList.Sort();
163 return true;
167 bool SdrMarkView::MarkPoint(SdrHdl& rHdl, bool bUnmark)
169 ForceUndirtyMrkPnt();
170 bool bRet=false;
171 const SdrObject* pObj=rHdl.GetObj();
172 if (IsPointMarkable(rHdl) && rHdl.IsSelected()==bUnmark) {
173 const size_t nMarkNum=TryToFindMarkedObject(pObj);
174 if (nMarkNum!=SAL_MAX_SIZE) {
175 SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
176 if (ImpMarkPoint(&rHdl,pM,bUnmark)) {
177 MarkListHasChanged();
178 bRet=true;
183 return bRet;
186 bool SdrMarkView::MarkPoints(const tools::Rectangle* pRect, bool bUnmark)
188 ForceUndirtyMrkPnt();
189 bool bChgd=false;
190 SortMarkedObjects();
191 const SdrObject* pObj0=nullptr;
192 const SdrPageView* pPV0=nullptr;
193 SdrMark* pM=nullptr;
194 maHdlList.Sort();
195 const size_t nHdlCnt=maHdlList.GetHdlCount();
196 for (size_t nHdlNum=nHdlCnt; nHdlNum>0;) {
197 --nHdlNum;
198 SdrHdl* pHdl=maHdlList.GetHdl(nHdlNum);
199 if (IsPointMarkable(*pHdl) && pHdl->IsSelected()==bUnmark) {
200 const SdrObject* pObj=pHdl->GetObj();
201 const SdrPageView* pPV=pHdl->GetPageView();
202 if (pObj!=pObj0 || pPV!=pPV0 || pM==nullptr) { // This section is for optimization,
203 const size_t nMarkNum=TryToFindMarkedObject(pObj); // so ImpMarkPoint() doesn't always
204 if (nMarkNum!=SAL_MAX_SIZE) { // have to search the object in the MarkList.
205 pM=GetSdrMarkByIndex(nMarkNum);
206 pObj0=pObj;
207 pPV0=pPV;
208 } else {
209 #ifdef DBG_UTIL
210 if (pObj->IsInserted()) {
211 OSL_FAIL("SdrMarkView::MarkPoints(const Rectangle* pRect): Selected object not found.");
213 #endif
214 pM=nullptr;
217 Point aPos(pHdl->GetPos());
218 if (pM!=nullptr && (pRect==nullptr || pRect->Contains(aPos))) {
219 if (ImpMarkPoint(pHdl,pM,bUnmark)) bChgd=true;
223 if (bChgd) {
224 MarkListHasChanged();
227 return bChgd;
230 void SdrMarkView::MarkNextPoint()
232 ForceUndirtyMrkPnt();
233 SortMarkedObjects();
236 const tools::Rectangle& SdrMarkView::GetMarkedPointsRect() const
238 ForceUndirtyMrkPnt();
239 if (mbMarkedPointsRectsDirty) ImpSetPointsRects();
240 return maMarkedPointsRect;
243 void SdrMarkView::SetPlusHandlesAlwaysVisible(bool bOn)
244 { // TODO: Optimize HandlePaint!
245 ForceUndirtyMrkPnt();
246 if (bOn!=mbPlusHdlAlways) {
247 mbPlusHdlAlways=bOn;
248 SetMarkHandles(nullptr);
249 MarkListHasChanged();
254 // ImpSetPointsRects() is for PolyPoints and GluePoints!
257 void SdrMarkView::ImpSetPointsRects() const
259 tools::Rectangle aPnts;
260 tools::Rectangle aGlue;
261 const size_t nHdlCnt=maHdlList.GetHdlCount();
262 for (size_t nHdlNum=0; nHdlNum<nHdlCnt; ++nHdlNum) {
263 const SdrHdl* pHdl=maHdlList.GetHdl(nHdlNum);
264 SdrHdlKind eKind=pHdl->GetKind();
265 if ((eKind==SdrHdlKind::Poly && pHdl->IsSelected()) || eKind==SdrHdlKind::Glue) {
266 Point aPt(pHdl->GetPos());
267 tools::Rectangle& rR=eKind==SdrHdlKind::Glue ? aGlue : aPnts;
268 if (rR.IsEmpty()) {
269 rR=tools::Rectangle(aPt,aPt);
270 } else {
271 if (aPt.X()<rR.Left ()) rR.SetLeft(aPt.X() );
272 if (aPt.X()>rR.Right ()) rR.SetRight(aPt.X() );
273 if (aPt.Y()<rR.Top ()) rR.SetTop(aPt.Y() );
274 if (aPt.Y()>rR.Bottom()) rR.SetBottom(aPt.Y() );
278 const_cast<SdrMarkView*>(this)->maMarkedPointsRect=aPnts;
279 const_cast<SdrMarkView*>(this)->maMarkedGluePointsRect=aGlue;
280 const_cast<SdrMarkView*>(this)->mbMarkedPointsRectsDirty=false;
284 // UndirtyMrkPnt() is for PolyPoints and GluePoints!
287 void SdrMarkView::UndirtyMrkPnt() const
289 bool bChg=false;
290 const size_t nMarkCount=GetMarkedObjectCount();
291 for (size_t nMarkNum=0; nMarkNum<nMarkCount; ++nMarkNum) {
292 SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
293 const SdrObject* pObj=pM->GetMarkedSdrObj();
294 // PolyPoints
296 SdrUShortCont& rPts = pM->GetMarkedPoints();
297 if (pObj->IsPolyObj()) {
298 // Remove invalid selected points, that is, all
299 // entries above the number of points in the object.
300 sal_uInt32 nMax(pObj->GetPointCount());
302 SdrUShortCont::const_iterator it = rPts.lower_bound(nMax);
303 if( it != rPts.end() )
305 rPts.erase(it, rPts.end());
306 bChg = true;
309 else
311 if (!rPts.empty())
313 // only fail *if* there are marked points
314 OSL_FAIL("SdrMarkView::UndirtyMrkPnt(): Selected points on an object that is not a PolyObj!");
315 rPts.clear();
316 bChg = true;
321 // GluePoints
323 SdrUShortCont& rPts = pM->GetMarkedGluePoints();
324 const SdrGluePointList* pGPL=pObj->GetGluePointList();
325 if (pGPL!=nullptr) {
326 // Remove invalid selected gluepoints, that is, all entries
327 // (IDs) that aren't contained in the GluePointList of the
328 // object
329 for(SdrUShortCont::const_iterator it = rPts.begin(); it != rPts.end(); )
331 sal_uInt16 nId=*it;
332 if (pGPL->FindGluePoint(nId)==SDRGLUEPOINT_NOTFOUND) {
333 it = rPts.erase(it);
334 bChg=true;
336 else
337 ++it;
339 } else {
340 if (!rPts.empty()) {
341 rPts.clear(); // object doesn't have any gluepoints (any more)
342 bChg=true;
347 if (bChg) const_cast<SdrMarkView*>(this)->mbMarkedPointsRectsDirty=true;
348 const_cast<SdrMarkView*>(this)->mbMrkPntDirty=false;
352 bool SdrMarkView::HasMarkableGluePoints() const
354 bool bRet=false;
355 if (IsGluePointEditMode()) {
356 ForceUndirtyMrkPnt();
357 const size_t nMarkCount=GetMarkedObjectCount();
358 for (size_t nMarkNum=0; nMarkNum<nMarkCount && !bRet; ++nMarkNum) {
359 const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
360 const SdrObject* pObj=pM->GetMarkedSdrObj();
361 const SdrGluePointList* pGPL=pObj->GetGluePointList();
363 // #i38892#
364 if(pGPL && pGPL->GetCount())
366 for(sal_uInt16 a(0); !bRet && a < pGPL->GetCount(); a++)
368 if((*pGPL)[a].IsUserDefined())
370 bRet = true;
376 return bRet;
379 bool SdrMarkView::HasMarkedGluePoints() const
381 ForceUndirtyMrkPnt();
382 bool bRet=false;
383 const size_t nMarkCount=GetMarkedObjectCount();
384 for (size_t nMarkNum=0; nMarkNum<nMarkCount && !bRet; ++nMarkNum) {
385 const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
386 const SdrUShortCont& rPts = pM->GetMarkedGluePoints();
387 bRet = !rPts.empty();
389 return bRet;
392 bool SdrMarkView::MarkGluePoints(const tools::Rectangle* pRect, bool bUnmark)
394 if (!IsGluePointEditMode() && !bUnmark) return false;
395 ForceUndirtyMrkPnt();
396 bool bChgd=false;
397 SortMarkedObjects();
398 const size_t nMarkCount=GetMarkedObjectCount();
399 for (size_t nMarkNum=0; nMarkNum<nMarkCount; ++nMarkNum) {
400 SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
401 const SdrObject* pObj=pM->GetMarkedSdrObj();
402 const SdrGluePointList* pGPL=pObj->GetGluePointList();
403 SdrUShortCont& rPts = pM->GetMarkedGluePoints();
404 if (bUnmark && pRect==nullptr) { // UnmarkAll
405 if (!rPts.empty()) {
406 rPts.clear();
407 bChgd=true;
409 } else {
410 if (pGPL!=nullptr) {
411 sal_uInt16 nGluePointCnt=pGPL->GetCount();
412 for (sal_uInt16 nGPNum=0; nGPNum<nGluePointCnt; nGPNum++) {
413 const SdrGluePoint& rGP=(*pGPL)[nGPNum];
415 // #i38892#
416 if(rGP.IsUserDefined())
418 Point aPos(rGP.GetAbsolutePos(*pObj));
419 if (pRect==nullptr || pRect->Contains(aPos)) {
420 bool bContains = rPts.find( rGP.GetId() ) != rPts.end();
421 if (!bUnmark && !bContains) {
422 bChgd=true;
423 rPts.insert(rGP.GetId());
425 if (bUnmark && bContains) {
426 bChgd=true;
427 rPts.erase(rGP.GetId());
435 if (bChgd) {
436 AdjustMarkHdl();
437 MarkListHasChanged();
439 return bChgd;
442 bool SdrMarkView::PickGluePoint(const Point& rPnt, SdrObject*& rpObj, sal_uInt16& rnId, SdrPageView*& rpPV) const
444 rpObj=nullptr; rpPV=nullptr; rnId=0;
445 if (!IsGluePointEditMode()) return false;
446 OutputDevice* pOut=mpActualOutDev.get();
447 if (pOut==nullptr) pOut=GetFirstOutputDevice();
448 if (pOut==nullptr) return false;
449 SortMarkedObjects();
450 const size_t nMarkCount=GetMarkedObjectCount();
451 size_t nMarkNum=nMarkCount;
452 while (nMarkNum>0) {
453 nMarkNum--;
454 const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
455 SdrObject* pObj=pM->GetMarkedSdrObj();
456 SdrPageView* pPV=pM->GetPageView();
457 const SdrGluePointList* pGPL=pObj->GetGluePointList();
458 if (pGPL!=nullptr) {
459 sal_uInt16 nNum=pGPL->HitTest(rPnt,*pOut,pObj);
460 if (nNum!=SDRGLUEPOINT_NOTFOUND)
462 // #i38892#
463 const SdrGluePoint& rCandidate = (*pGPL)[nNum];
465 if(rCandidate.IsUserDefined())
467 rpObj=pObj;
468 rnId=(*pGPL)[nNum].GetId();
469 rpPV=pPV;
470 return true;
475 return false;
478 bool SdrMarkView::MarkGluePoint(const SdrObject* pObj, sal_uInt16 nId, bool bUnmark)
480 if (!IsGluePointEditMode()) return false;
481 ForceUndirtyMrkPnt();
482 bool bChgd=false;
483 if (pObj!=nullptr) {
484 const size_t nMarkPos=TryToFindMarkedObject(pObj);
485 if (nMarkPos!=SAL_MAX_SIZE) {
486 SdrMark* pM=GetSdrMarkByIndex(nMarkPos);
487 SdrUShortCont& rPts = pM->GetMarkedGluePoints();
488 bool bContains = rPts.find( nId ) != rPts.end();
489 if (!bUnmark && !bContains) {
490 bChgd=true;
491 rPts.insert(nId);
493 if (bUnmark && bContains) {
494 bChgd=true;
495 rPts.erase(nId);
497 } else {
498 // TODO: implement implicit selection of objects
501 if (bChgd) {
502 AdjustMarkHdl();
503 MarkListHasChanged();
505 return bChgd;
508 bool SdrMarkView::IsGluePointMarked(const SdrObject* pObj, sal_uInt16 nId) const
510 ForceUndirtyMrkPnt();
511 bool bRet=false;
512 const size_t nPos=TryToFindMarkedObject(pObj); // casting to NonConst
513 if (nPos!=SAL_MAX_SIZE) {
514 const SdrMark* pM=GetSdrMarkByIndex(nPos);
515 const SdrUShortCont& rPts = pM->GetMarkedGluePoints();
516 bRet = rPts.find( nId ) != rPts.end();
518 return bRet;
521 SdrHdl* SdrMarkView::GetGluePointHdl(const SdrObject* pObj, sal_uInt16 nId) const
523 ForceUndirtyMrkPnt();
524 const size_t nHdlCnt=maHdlList.GetHdlCount();
525 for (size_t nHdlNum=0; nHdlNum<nHdlCnt; ++nHdlNum) {
526 SdrHdl* pHdl=maHdlList.GetHdl(nHdlNum);
527 if (pHdl->GetObj()==pObj &&
528 pHdl->GetKind()==SdrHdlKind::Glue &&
529 pHdl->GetObjHdlNum()==nId ) return pHdl;
531 return nullptr;
534 void SdrMarkView::MarkNextGluePoint()
536 ForceUndirtyMrkPnt();
537 SortMarkedObjects();
540 const tools::Rectangle& SdrMarkView::GetMarkedGluePointsRect() const
542 ForceUndirtyMrkPnt();
543 if (mbMarkedPointsRectsDirty) ImpSetPointsRects();
544 return maMarkedGluePointsRect;
547 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */