1
2
3 #include "vectorselectiontool.h"
4
5 // TnzTools includes
6 #include "tools/toolhandle.h"
7 #include "tools/imagegrouping.h"
8 #include "tools/cursors.h"
9
10 // TnzQt includes
11 #include "toonzqt/selectioncommandids.h"
12 #include "toonzqt/tselectionhandle.h"
13 #include "toonzqt/imageutils.h"
14
15 // TnzLib includes
16 #include "toonz/txsheethandle.h"
17 #include "toonz/txshlevelhandle.h"
18 #include "toonz/tobjecthandle.h"
19 #include "toonz/tstageobject.h"
20
21 // TnzBase includes
22 #include "tenv.h"
23
24 // TnzCore includes
25 #include "drawutil.h"
26
27 // boost includes
28 #include <boost/bind.hpp>
29
30 using namespace ToolUtils;
31 using namespace DragSelectionTool;
32
33 //********************************************************************************
34 // Global variables
35 //********************************************************************************
36
37 namespace {
38
39 VectorSelectionTool l_vectorSelectionTool(TTool::Vectors);
40 TEnv::IntVar l_strokeSelectConstantThickness("SelectionToolConstantThickness",
41 0);
42 TEnv::IntVar l_strokeSelectIncludeIntersection(
43 "SelectionToolIncludeIntersection", 0);
44
45 const int l_dragThreshold = 10; //!< Distance, in pixels, the user has to
46 //! move from a button press to trigger a
47 //! selection drag.
48 } // namespace
49
50 //********************************************************************************
51 // Local namespace stuff
52 //********************************************************************************
53
54 namespace {
55
getFourPointsFromVectorImage(const TVectorImageP & img,const std::set<int> & styleIds,double & maxThickness)56 FourPoints getFourPointsFromVectorImage(const TVectorImageP &img,
57 const std::set<int> &styleIds,
58 double &maxThickness) {
59 FourPoints p;
60
61 if (styleIds.empty()) {
62 p = img->getBBox();
63
64 for (UINT i = 0; i < img->getStrokeCount(); i++) {
65 TStroke *s = img->getStroke(i);
66
67 for (int j = 0; j < s->getControlPointCount(); j++) {
68 double thick = s->getControlPoint(j).thick;
69 if (maxThickness < thick) maxThickness = thick;
70 }
71 }
72 } else {
73 TRectD bbox;
74
75 for (UINT i = 0; i < img->getStrokeCount(); i++) {
76 TStroke *s = img->getStroke(i);
77 if (!styleIds.count(s->getStyle())) continue;
78
79 if (bbox.isEmpty())
80 bbox = s->getBBox();
81 else
82 bbox += s->getBBox();
83
84 for (int j = 0; j < s->getControlPointCount(); j++) {
85 double thick = s->getControlPoint(j).thick;
86 if (maxThickness < thick) maxThickness = thick;
87 }
88 }
89
90 p = bbox;
91 }
92
93 return p;
94 }
95
96 //-----------------------------------------------------------------------------
97
getStrokeIndexFromPos(UINT & index,const TVectorImageP & vi,const TPointD & pos,double pixelSize,TAffine aff)98 bool getStrokeIndexFromPos(UINT &index, const TVectorImageP &vi,
99 const TPointD &pos, double pixelSize, TAffine aff) {
100 if (!vi) return false;
101 double t, dist2 = 0;
102 double maxDist = 5 * pixelSize;
103 double maxDist2 = maxDist * maxDist;
104 double checkDist = maxDist2 * 4;
105
106 if (vi->getNearestStroke(pos, t, index, dist2)) {
107 TStroke *strokeRef = vi->getStroke(index);
108 TThickPoint cursor = strokeRef->getThickPoint(t);
109 double len = cursor.thick * pixelSize * sqrt(aff.det());
110 checkDist = std::max(checkDist, (len * len));
111 }
112
113 return (dist2 < checkDist);
114 }
115
116 //-----------------------------------------------------------------------------
117
currentOrNotSelected(const VectorSelectionTool & tool,const TFrameId & fid)118 static bool currentOrNotSelected(const VectorSelectionTool &tool,
119 const TFrameId &fid) {
120 return (tool.getCurrentFid() == fid ||
121 (tool.isSelectedFramesType() &&
122 tool.getSelectedFrames().count(fid) == 0));
123 }
124
125 //-----------------------------------------------------------------------------
126
notifySelectionChanged()127 inline void notifySelectionChanged() {
128 TTool::getApplication()->getCurrentSelection()->notifySelectionChanged();
129 }
130
131 } // namespace
132
133 //********************************************************************************
134 // VectorFreeDeformer implementation
135 //********************************************************************************
136
VectorFreeDeformer(TVectorImageP vi,std::set<int> strokeIndexes)137 VectorFreeDeformer::VectorFreeDeformer(TVectorImageP vi,
138 std::set<int> strokeIndexes)
139 : FreeDeformer()
140 , m_vi(vi)
141 , m_strokeIndexes(strokeIndexes)
142 , m_preserveThickness(false)
143 , m_computeRegion(false)
144 , m_flip(false) {
145 TRectD r;
146
147 std::set<int>::iterator it, iEnd = m_strokeIndexes.end();
148 for (it = m_strokeIndexes.begin(); it != iEnd; ++it) {
149 TStroke *stroke = m_vi->getStroke(*it);
150 r += stroke->getBBox();
151 m_originalStrokes.push_back(new TStroke(*stroke));
152 }
153
154 m_originalP00 = r.getP00();
155 m_originalP11 = r.getP11();
156 m_newPoints.push_back(m_originalP00);
157 m_newPoints.push_back(r.getP10());
158 m_newPoints.push_back(m_originalP11);
159 m_newPoints.push_back(r.getP01());
160 }
161
162 //-----------------------------------------------------------------------------
163
~VectorFreeDeformer()164 VectorFreeDeformer::~VectorFreeDeformer() {
165 clearPointerContainer(m_originalStrokes);
166 }
167
168 //-----------------------------------------------------------------------------
169
setPreserveThickness(bool preserveThickness)170 void VectorFreeDeformer::setPreserveThickness(bool preserveThickness) {
171 m_preserveThickness = preserveThickness;
172 }
173
174 //-----------------------------------------------------------------------------
175
setComputeRegion(bool computeRegion)176 void VectorFreeDeformer::setComputeRegion(bool computeRegion) {
177 m_computeRegion = computeRegion;
178 }
179
180 //-----------------------------------------------------------------------------
181
setFlip(bool flip)182 void VectorFreeDeformer::setFlip(bool flip) { m_flip = flip; }
183
184 //-----------------------------------------------------------------------------
185
setPoint(int index,const TPointD & p)186 void VectorFreeDeformer::setPoint(int index, const TPointD &p) {
187 m_newPoints[index] = p;
188 }
189
190 //-----------------------------------------------------------------------------
191
setPoints(const TPointD & p0,const TPointD & p1,const TPointD & p2,const TPointD & p3)192 void VectorFreeDeformer::setPoints(const TPointD &p0, const TPointD &p1,
193 const TPointD &p2, const TPointD &p3) {
194 m_newPoints[0] = p0;
195 m_newPoints[1] = p1;
196 m_newPoints[2] = p2;
197 m_newPoints[3] = p3;
198 }
199
200 //-----------------------------------------------------------------------------
201
deformRegions()202 void VectorFreeDeformer::deformRegions() {
203 if (m_strokeIndexes.empty() || !m_computeRegion) return;
204
205 std::vector<int> selectedIndexes(m_strokeIndexes.begin(),
206 m_strokeIndexes.end());
207
208 m_vi->notifyChangedStrokes(selectedIndexes, m_originalStrokes, m_flip);
209 m_computeRegion = false;
210 }
211
212 //-----------------------------------------------------------------------------
213
deformImage()214 void VectorFreeDeformer::deformImage() {
215 // debug
216 assert(m_strokeIndexes.size() == m_originalStrokes.size());
217
218 // release
219 if (m_strokeIndexes.size() != m_originalStrokes.size()) {
220 return;
221 }
222
223 QMutexLocker lock(m_vi->getMutex());
224
225 std::size_t i = 0;
226 for (auto it = m_strokeIndexes.begin(), end = m_strokeIndexes.end();
227 it != end; ++it) {
228 TStroke *stroke = m_vi->getStroke(*it);
229 TStroke *originalStroke = m_originalStrokes[i++];
230
231 assert(stroke->getControlPointCount() ==
232 originalStroke->getControlPointCount());
233 for (int j = 0, count = stroke->getControlPointCount(); j < count; ++j) {
234 TThickPoint p = deform(originalStroke->getControlPoint(j));
235 stroke->setControlPoint(j, p);
236 }
237 }
238
239 if (m_computeRegion) deformRegions();
240 }
241
242 //-----------------------------------------------------------------------------
243
deform(TThickPoint point)244 TThickPoint VectorFreeDeformer::deform(TThickPoint point) {
245 double vs = m_originalP11.x - m_originalP00.x;
246 double s = (vs == 0) ? 0 : (point.x - m_originalP00.x) / vs;
247 double vt = m_originalP11.y - m_originalP00.y;
248 double t = (vt == 0) ? 0 : (point.y - m_originalP00.y) / vt;
249 TPointD A = m_newPoints[0];
250 TPointD B = m_newPoints[1];
251 TPointD C = m_newPoints[2];
252 TPointD D = m_newPoints[3];
253 TPointD AD = (1 - t) * A + t * D;
254 TPointD BC = (1 - t) * B + t * C;
255 TPointD p = (1 - s) * AD + s * BC;
256
257 double thickness = point.thick;
258 if (!m_preserveThickness) {
259 double eps = 1.e-2;
260 TPointD p0x = TPointD(p.x - eps, p.x);
261 TPointD p1x = TPointD(p.x + eps, p.x);
262 TPointD p0y = TPointD(p.x, p.y - eps);
263 TPointD p1y = TPointD(p.x, p.y + eps);
264 m_preserveThickness = true;
265 TThickPoint newp0x = deform(p0x);
266 TThickPoint newp1x = deform(p1x);
267 TThickPoint newp0y = deform(p0y);
268 TThickPoint newp1y = deform(p1y);
269 m_preserveThickness = false;
270 double newA = fabs(cross(newp1x - newp0x, newp1y - newp0y));
271 double a = 4 * eps * eps;
272 thickness *= sqrt(newA / a);
273 }
274 return TThickPoint(p, thickness);
275 }
276
277 //********************************************************************************
278 // UndoChangeStrokes implementation
279 //********************************************************************************
280
UndoChangeStrokes(TXshSimpleLevel * level,const TFrameId & frameId,VectorSelectionTool * tool,const StrokeSelection & selection)281 DragSelectionTool::UndoChangeStrokes::UndoChangeStrokes(
282 TXshSimpleLevel *level, const TFrameId &frameId, VectorSelectionTool *tool,
283 const StrokeSelection &selection)
284 : ToolUtils::TToolUndo(level, frameId)
285 , m_tool(tool)
286 , m_selectionCount(tool->getSelectionCount()) // Not related to selection
287 , m_oldBBox(tool->getBBox())
288 , m_oldCenter(tool->getCenter())
289 , m_oldDeformValues(tool->m_deformValues)
290 , m_newDeformValues()
291 , m_flip(false) {
292 TVectorImageP vi = m_level->getFrame(m_frameId, false);
293 if (!vi) {
294 assert(vi);
295 return;
296 }
297
298 const StrokeSelection::IndexesContainer &indexes = selection.getSelection();
299 m_indexes.assign(indexes.begin(), indexes.end());
300
301 registerStrokes(true);
302 }
303
304 //-----------------------------------------------------------------------------
305
UndoChangeStrokes(TXshSimpleLevel * level,const TFrameId & frameId,VectorSelectionTool * tool,const LevelSelection & selection)306 DragSelectionTool::UndoChangeStrokes::UndoChangeStrokes(
307 TXshSimpleLevel *level, const TFrameId &frameId, VectorSelectionTool *tool,
308 const LevelSelection &selection)
309 : ToolUtils::TToolUndo(level, frameId)
310 , m_tool(tool)
311 , m_selectionCount(tool->getSelectionCount()) // Not related to selection
312 , m_oldBBox(tool->getBBox())
313 , m_oldCenter(tool->getCenter())
314 , m_oldDeformValues(tool->m_deformValues)
315 , m_newDeformValues()
316 , m_flip(false) {
317 TVectorImageP vi = m_level->getFrame(m_frameId, false);
318 if (!vi) {
319 assert(vi);
320 return;
321 }
322
323 m_indexes = getSelectedStrokes(*vi, selection);
324
325 registerStrokes(true);
326 }
327
328 //-----------------------------------------------------------------------------
329
~UndoChangeStrokes()330 DragSelectionTool::UndoChangeStrokes::~UndoChangeStrokes() {
331 clearPointerContainer(m_oldStrokes);
332 clearPointerContainer(m_newStrokes);
333 }
334
335 //-----------------------------------------------------------------------------
336
registerStrokes(bool beforeModify)337 void DragSelectionTool::UndoChangeStrokes::registerStrokes(bool beforeModify) {
338 TVectorImageP vi = m_level->getFrame(m_frameId, false);
339 if (!vi) {
340 assert(vi);
341 return;
342 }
343
344 std::vector<TStroke *> &strokes = beforeModify ? m_oldStrokes : m_newStrokes;
345
346 TRectD bbox;
347
348 int s, sCount = int(m_indexes.size());
349 for (s = 0; s != sCount; ++s) {
350 TStroke *stroke = vi->getStroke(m_indexes[s]);
351 bbox += stroke->getBBox();
352
353 strokes.push_back(new TStroke(*stroke));
354 }
355
356 if (beforeModify && !bbox.isEmpty()) {
357 ImageUtils::getFillingInformationOverlappingArea(vi, m_regionsData, bbox);
358 } else {
359 m_newBBox = m_tool->getBBox();
360 m_newCenter = m_tool->getCenter();
361 m_newDeformValues = m_tool->m_deformValues;
362 }
363 }
364
365 //-----------------------------------------------------------------------------
366
transform(const std::vector<TStroke * > & strokes,FourPoints bbox,TPointD center,DragSelectionTool::DeformValues deformValues) const367 void DragSelectionTool::UndoChangeStrokes::transform(
368 const std::vector<TStroke *> &strokes, FourPoints bbox, TPointD center,
369 DragSelectionTool::DeformValues deformValues) const {
370 TVectorImageP image = m_level->getFrame(m_frameId, true);
371 if (!image) {
372 assert(image);
373 return;
374 }
375
376 int s, sCount = int(m_indexes.size());
377 for (s = 0; s != sCount; ++s) {
378 int index = m_indexes[s];
379
380 TStroke *sourcesStroke = strokes[s], *stroke = image->getStroke(index);
381
382 int cp, cpCount = stroke->getControlPointCount();
383 for (cp = 0; cp != cpCount; ++cp)
384 stroke->setControlPoint(cp, sourcesStroke->getControlPoint(cp));
385 }
386
387 image->notifyChangedStrokes(m_indexes, strokes, m_flip);
388
389 if (!m_tool->isSelectionEmpty() &&
390 m_selectionCount == m_tool->getSelectionCount()) {
391 m_tool->setBBox(bbox);
392 m_tool->setCenter(center);
393 } else
394 m_tool->computeBBox();
395
396 m_tool->notifyImageChanged(m_frameId);
397 m_tool->m_deformValues = deformValues;
398 TTool::getApplication()->getCurrentXsheet()->notifyXsheetChanged();
399 TTool::getApplication()->getCurrentTool()->notifyToolChanged();
400 }
401
402 //-----------------------------------------------------------------------------
403
restoreRegions() const404 void DragSelectionTool::UndoChangeStrokes::restoreRegions() const {
405 TVectorImageP vi = m_level->getFrame(m_frameId, true);
406 if (!vi) {
407 assert(vi);
408 return;
409 }
410
411 ImageUtils::assignFillingInformation(*vi, m_regionsData);
412 }
413
414 //-----------------------------------------------------------------------------
415
undo() const416 void DragSelectionTool::UndoChangeStrokes::undo() const {
417 transform(m_oldStrokes, m_oldBBox, m_oldCenter, m_oldDeformValues);
418 restoreRegions();
419 }
420
421 //-----------------------------------------------------------------------------
422
redo() const423 void DragSelectionTool::UndoChangeStrokes::redo() const {
424 transform(m_newStrokes, m_newBBox, m_newCenter, m_newDeformValues);
425 }
426
427 //-----------------------------------------------------------------------------
428
getSize() const429 int DragSelectionTool::UndoChangeStrokes::getSize() const {
430 return sizeof(*this) + sizeof(*m_tool);
431 }
432
433 //=============================================================================
434 // UndoChangeOutlineStyle
435 //-----------------------------------------------------------------------------
436
437 class UndoChangeOutlineStyle final : public ToolUtils::TToolUndo {
438 std::vector<TStroke::OutlineOptions> m_oldOptions, m_newOptions;
439 FourPoints m_oldBBox, m_newBBox;
440 VectorSelectionTool *m_tool;
441 std::vector<int> m_indexes;
442 int m_selectionCount;
443
444 public:
445 UndoChangeOutlineStyle(TXshSimpleLevel *level, const TFrameId &frameId,
446 VectorSelectionTool *tool);
~UndoChangeOutlineStyle()447 ~UndoChangeOutlineStyle() {}
448 void registerStrokes(bool beforeModify = false);
449 void transform(const std::vector<TStroke::OutlineOptions> &options,
450 FourPoints bbox) const;
451 void undo() const override;
452 void redo() const override;
453 int getSize() const override;
454 };
455
456 //-----------------------------------------------------------------------------
457
UndoChangeOutlineStyle(TXshSimpleLevel * level,const TFrameId & frameId,VectorSelectionTool * tool)458 UndoChangeOutlineStyle::UndoChangeOutlineStyle(TXshSimpleLevel *level,
459 const TFrameId &frameId,
460 VectorSelectionTool *tool)
461 : ToolUtils::TToolUndo(level, frameId)
462 , m_tool(tool)
463 , m_oldBBox(tool->getBBox())
464 , m_selectionCount(tool->getSelectionCount()) {
465 TVectorImageP image = m_level->getFrame(m_frameId, false);
466 assert(!!image);
467 if (!image) return;
468 StrokeSelection *strokeSelection =
469 dynamic_cast<StrokeSelection *>(tool->getSelection());
470 int i;
471 for (i = 0; i < (int)image->getStrokeCount(); i++) {
472 if (!strokeSelection->isSelected(i) && !m_tool->isLevelType() &&
473 !m_tool->isSelectedFramesType())
474 continue;
475 m_indexes.push_back(i);
476 }
477 registerStrokes(true);
478 }
479
480 //-----------------------------------------------------------------------------
481
registerStrokes(bool beforeModify)482 void UndoChangeOutlineStyle::registerStrokes(bool beforeModify) {
483 TVectorImageP image = m_level->getFrame(m_frameId, false);
484 assert(!!image);
485 if (!image) return;
486 int i;
487 for (i = 0; i < (int)m_indexes.size(); i++) {
488 if (beforeModify)
489 m_oldOptions.push_back(image->getStroke(m_indexes[i])->outlineOptions());
490 else
491 m_newOptions.push_back(image->getStroke(m_indexes[i])->outlineOptions());
492 }
493 if (!beforeModify) m_newBBox = m_tool->getBBox();
494 }
495
496 //-----------------------------------------------------------------------------
497
transform(const std::vector<TStroke::OutlineOptions> & options,FourPoints bbox) const498 void UndoChangeOutlineStyle::transform(
499 const std::vector<TStroke::OutlineOptions> &options,
500 FourPoints bbox) const {
501 TVectorImageP image = m_level->getFrame(m_frameId, true);
502 assert(!!image);
503 if (!image) return;
504 int i;
505 for (i = 0; i < (int)m_indexes.size(); i++) {
506 int index = m_indexes[i];
507 image->getStroke(index)->outlineOptions() = options[i];
508 }
509 if (!m_tool->isSelectionEmpty() &&
510 m_selectionCount == m_tool->getSelectionCount())
511 m_tool->setBBox(bbox);
512 else
513 m_tool->computeBBox();
514 m_tool->notifyImageChanged(m_frameId);
515 TTool::getApplication()->getCurrentXsheet()->notifyXsheetChanged();
516 TTool::getApplication()->getCurrentTool()->notifyToolChanged();
517 }
518
519 //-----------------------------------------------------------------------------
520
undo() const521 void UndoChangeOutlineStyle::undo() const {
522 transform(m_oldOptions, m_oldBBox);
523 TTool::getApplication()->getCurrentTool()->notifyToolChanged();
524 }
525
526 //-----------------------------------------------------------------------------
527
redo() const528 void UndoChangeOutlineStyle::redo() const {
529 transform(m_newOptions, m_newBBox);
530 TTool::getApplication()->getCurrentTool()->notifyToolChanged();
531 }
532
533 //-----------------------------------------------------------------------------
534
getSize() const535 int UndoChangeOutlineStyle::getSize() const {
536 // NOTE: This is definitely wrong... sizeof(vector) DOES NOT correspond to its
537 // actual size - as it is internally allocated with new!!
538 return sizeof(*this) + sizeof(*m_tool);
539 }
540
541 //=============================================================================
542 // VectorDeformTool::VFDScopedBlock
543 //-----------------------------------------------------------------------------
544
545 struct VectorDeformTool::VFDScopedBlock //! Type bounding the scope of free
546 //! deformers in the tool.
547 {
VFDScopedBlockVectorDeformTool::VFDScopedBlock548 VFDScopedBlock(SelectionTool *tool) : m_tool(tool) {
549 m_tool->setNewFreeDeformer();
550 }
~VFDScopedBlockVectorDeformTool::VFDScopedBlock551 ~VFDScopedBlock() { m_tool->clearDeformers(); }
552
553 private:
554 SelectionTool *m_tool; //!< [\p external] Tool owning the deformers.
555 };
556
557 //=============================================================================
558 // VectorDeformTool
559 //-----------------------------------------------------------------------------
560
VectorDeformTool(VectorSelectionTool * tool)561 DragSelectionTool::VectorDeformTool::VectorDeformTool(VectorSelectionTool *tool)
562 : DeformTool(tool), m_undo() {
563 if (!TTool::getApplication()->getCurrentObject()->isSpline()) {
564 m_undo.reset(new UndoChangeStrokes(
565 TTool::getApplication()->getCurrentLevel()->getSimpleLevel(),
566 tool->getCurrentFid(), tool, tool->strokeSelection()));
567 }
568 }
569
570 //-----------------------------------------------------------------------------
571
~VectorDeformTool()572 DragSelectionTool::VectorDeformTool::~VectorDeformTool() {
573 // DO NOT REMOVE - DESTRUCTS TYPES INCOMPLETE IN THE HEADER
574 }
575
576 //-----------------------------------------------------------------------------
577
applyTransform(FourPoints bbox)578 void DragSelectionTool::VectorDeformTool::applyTransform(FourPoints bbox) {
579 SelectionTool *tool = getTool();
580
581 std::unique_ptr<VFDScopedBlock> localVfdScopedBlock;
582 if (!m_vfdScopedBlock) {
583 std::unique_ptr<VFDScopedBlock> &vfdScopedBlock =
584 m_isDragging ? m_vfdScopedBlock : localVfdScopedBlock;
585
586 vfdScopedBlock.reset(new VFDScopedBlock(tool));
587 }
588
589 VectorFreeDeformer *freeDeformer =
590 static_cast<VectorFreeDeformer *>(tool->getFreeDeformer());
591
592 const bool stayedTheSame = bbox.getP00() == freeDeformer->getPoint(0) &&
593 bbox.getP10() == freeDeformer->getPoint(1) &&
594 bbox.getP11() == freeDeformer->getPoint(2) &&
595 bbox.getP01() == freeDeformer->getPoint(3);
596
597 freeDeformer->setPoints(bbox.getP00(), bbox.getP10(), bbox.getP11(),
598 bbox.getP01());
599 freeDeformer->setComputeRegion(!m_isDragging);
600 freeDeformer->setPreserveThickness(tool->isConstantThickness());
601 freeDeformer->setFlip(isFlip());
602
603 if (!TTool::getApplication()->getCurrentObject()->isSpline() && m_undo)
604 m_undo->setFlip(isFlip());
605
606 freeDeformer->deformImage();
607
608 tool->invalidate();
609
610 if (!m_isDragging) tool->notifyImageChanged();
611
612 if (!stayedTheSame) tool->m_deformValues.m_isSelectionModified = true;
613
614 if (!m_isDragging && (tool->isLevelType() || tool->isSelectedFramesType()))
615 transformWholeLevel();
616 }
617
618 //-----------------------------------------------------------------------------
619
addTransformUndo()620 void DragSelectionTool::VectorDeformTool::addTransformUndo() {
621 if (TTool::getApplication()->getCurrentObject()->isSpline())
622 TUndoManager::manager()->add(
623 new UndoPath(getTool()
624 ->getXsheet()
625 ->getStageObject(getTool()->getObjectId())
626 ->getSpline()));
627 else if (m_undo) {
628 m_undo->registerStrokes();
629 TUndoManager::manager()->add(m_undo.release());
630 }
631 }
632
633 //-----------------------------------------------------------------------------
634
transformWholeLevel()635 void DragSelectionTool::VectorDeformTool::transformWholeLevel() {
636 VectorSelectionTool *tool = dynamic_cast<VectorSelectionTool *>(m_tool);
637 assert(tool);
638
639 assert(!tool->levelSelection().isEmpty());
640
641 TXshSimpleLevel *level =
642 TTool::getApplication()->getCurrentLevel()->getSimpleLevel();
643
644 std::vector<TFrameId> fids;
645 level->getFids(fids);
646
647 // Remove unwanted fids
648 fids.erase(std::remove_if(
649 fids.begin(), fids.end(),
650 boost::bind(::currentOrNotSelected, boost::cref(*tool), _1)),
651 fids.end());
652
653 TUndoManager::manager()->beginBlock();
654 {
655 addTransformUndo(); // For current frame
656
657 int f, fCount = int(fids.size());
658 for (f = 0; f != fCount; ++f) {
659 const TFrameId &fid = fids[f];
660 int t = f + 1; // Current frame's data is always at index 0
661 // The others are thus shifted by 1
662 // Skip nonselected frames
663 if (tool->getCurrentFid() == fid ||
664 (tool->isSelectedFramesType() &&
665 tool->getSelectedFrames().count(fid) == 0))
666 continue;
667
668 TVectorImageP vi = level->getFrame(fid, true);
669 if (!vi) continue;
670
671 std::unique_ptr<UndoChangeStrokes> undo(
672 new UndoChangeStrokes(level, fid, tool, tool->levelSelection()));
673
674 std::set<int> strokesIndices;
675
676 for (int s = 0; s < (int)vi->getStrokeCount(); ++s)
677 strokesIndices.insert(s);
678
679 FourPoints bbox = tool->getBBox(t);
680
681 VectorFreeDeformer *freeDeformer =
682 static_cast<VectorFreeDeformer *>(tool->getFreeDeformer(t));
683 freeDeformer->setPoints(bbox.getPoint(0), bbox.getPoint(1),
684 bbox.getPoint(2), bbox.getPoint(3));
685 freeDeformer->setComputeRegion(true);
686 freeDeformer->setPreserveThickness(tool->isConstantThickness());
687 freeDeformer->setFlip(isFlip());
688 freeDeformer->deformImage();
689
690 undo->registerStrokes();
691
692 TUndoManager::manager()->add(undo.release());
693 }
694 }
695 TUndoManager::manager()->endBlock();
696
697 // Finally, notify changed frames
698 std::for_each(fids.begin(), fids.end(),
699 boost::bind( // NOTE: current frame is not here - it should be,
700 &TTool::notifyImageChanged, m_tool,
701 _1)); // but it's currently unnecessary, in fact...
702
703 // notifyImageChanged(fid) must be invoked OUTSIDE of the loop - since it
704 // seems to imply notifyImageChanged()
705 // on CURRENT image - which seems wrong, but it's too low-level and I'm not
706 // changing it.
707 // This reasonably leads to computeBBox(), but bboxes are taken as INPUT to
708 // this transformation... >:(
709 }
710
711 //-----------------------------------------------------------------------------
712
isFlip()713 bool DragSelectionTool::VectorDeformTool::isFlip() {
714 TPointD scaleValue = getTool()->m_deformValues.m_scaleValue;
715 return m_startScaleValue.x * scaleValue.x < 0 ||
716 m_startScaleValue.y * scaleValue.y < 0;
717 }
718
719 //-----------------------------------------------------------------------------
720
leftButtonUp(const TPointD & pos,const TMouseEvent & e)721 void DragSelectionTool::VectorDeformTool::leftButtonUp(const TPointD &pos,
722 const TMouseEvent &e) {
723 std::unique_ptr<VFDScopedBlock> vfdScopedBlock(std::move(m_vfdScopedBlock));
724
725 SelectionTool *tool = getTool();
726 VectorFreeDeformer *deformer =
727 dynamic_cast<VectorFreeDeformer *>(tool->getFreeDeformer());
728 if (!deformer) return;
729
730 deformer->setComputeRegion(true);
731 deformer->setFlip(isFlip());
732 deformer->deformRegions();
733
734 if (!tool->isLevelType() && !tool->isSelectedFramesType())
735 addTransformUndo();
736 else
737 transformWholeLevel();
738
739 m_isDragging = false;
740
741 tool->notifyImageChanged();
742
743 VectorSelectionTool *selectionTool =
744 dynamic_cast<VectorSelectionTool *>(m_tool);
745 selectionTool->setResetCenter(true);
746 }
747
748 //=============================================================================
749 // VectorRotationTool
750 //-----------------------------------------------------------------------------
751
VectorRotationTool(VectorSelectionTool * tool)752 DragSelectionTool::VectorRotationTool::VectorRotationTool(
753 VectorSelectionTool *tool)
754 : VectorDeformTool(tool), m_rotation(new Rotation(this)) {}
755
756 //-----------------------------------------------------------------------------
757
transform(TAffine aff,double angle)758 void DragSelectionTool::VectorRotationTool::transform(TAffine aff,
759 double angle) {
760 SelectionTool *tool = getTool();
761 FourPoints newBbox(tool->getBBox() * aff);
762 TPointD center = m_rotation->getStartCenter();
763 int i;
764 for (i = 0; i < tool->getBBoxsCount(); i++) {
765 aff = TRotation(center, angle);
766 tool->setBBox(tool->getBBox(i) * aff, i);
767 }
768 applyTransform(newBbox);
769 }
770
771 //-----------------------------------------------------------------------------
772
leftButtonDrag(const TPointD & pos,const TMouseEvent & e)773 void DragSelectionTool::VectorRotationTool::leftButtonDrag(
774 const TPointD &pos, const TMouseEvent &e) {
775 VectorSelectionTool *tool = dynamic_cast<VectorSelectionTool *>(m_tool);
776 tool->setResetCenter(false);
777 m_rotation->leftButtonDrag(pos, e);
778 }
779
780 //-----------------------------------------------------------------------------
781
draw()782 void DragSelectionTool::VectorRotationTool::draw() { m_rotation->draw(); }
783
784 //=============================================================================
785 // VectorFreeDeformTool
786 //-----------------------------------------------------------------------------
787
VectorFreeDeformTool(VectorSelectionTool * tool)788 DragSelectionTool::VectorFreeDeformTool::VectorFreeDeformTool(
789 VectorSelectionTool *tool)
790 : VectorDeformTool(tool), m_freeDeform(new FreeDeform(this)) {}
791
792 //-----------------------------------------------------------------------------
793
leftButtonDrag(const TPointD & pos,const TMouseEvent & e)794 void DragSelectionTool::VectorFreeDeformTool::leftButtonDrag(
795 const TPointD &pos, const TMouseEvent &e) {
796 VectorSelectionTool *tool = dynamic_cast<VectorSelectionTool *>(m_tool);
797 tool->setResetCenter(false);
798 m_freeDeform->leftButtonDrag(pos, e);
799 }
800
801 //=============================================================================
802 // VectorMoveSelectionTool
803 //-----------------------------------------------------------------------------
804
VectorMoveSelectionTool(VectorSelectionTool * tool)805 DragSelectionTool::VectorMoveSelectionTool::VectorMoveSelectionTool(
806 VectorSelectionTool *tool)
807 : VectorDeformTool(tool), m_moveSelection(new MoveSelection(this)) {}
808
809 //-----------------------------------------------------------------------------
810
transform(TAffine aff)811 void DragSelectionTool::VectorMoveSelectionTool::transform(TAffine aff) {
812 SelectionTool *tool = getTool();
813 int i;
814 for (i = 0; i < (int)tool->getBBoxsCount(); i++)
815 tool->setBBox(tool->getBBox(i) * aff, i);
816 getTool()->setCenter(aff * tool->getCenter());
817 applyTransform(tool->getBBox());
818 }
819
820 //-----------------------------------------------------------------------------
821
leftButtonDown(const TPointD & pos,const TMouseEvent & e)822 void DragSelectionTool::VectorMoveSelectionTool::leftButtonDown(
823 const TPointD &pos, const TMouseEvent &e) {
824 m_moveSelection->leftButtonDown(pos, e);
825 VectorDeformTool::leftButtonDown(pos, e);
826 }
827
828 //-----------------------------------------------------------------------------
829
leftButtonDrag(const TPointD & pos,const TMouseEvent & e)830 void DragSelectionTool::VectorMoveSelectionTool::leftButtonDrag(
831 const TPointD &pos, const TMouseEvent &e) {
832 VectorSelectionTool *tool = dynamic_cast<VectorSelectionTool *>(m_tool);
833 tool->setResetCenter(false);
834 if (e.isCtrlPressed() ||
835 norm2(pos - getStartPos()) > l_dragThreshold * getTool()->getPixelSize())
836 m_moveSelection->leftButtonDrag(pos, e);
837 else // snap to the original position
838 m_moveSelection->leftButtonDrag(getStartPos(), e);
839 }
840
841 //=============================================================================
842 // VectorScaleTool
843 //-----------------------------------------------------------------------------
844
VectorScaleTool(VectorSelectionTool * tool,ScaleType type)845 DragSelectionTool::VectorScaleTool::VectorScaleTool(VectorSelectionTool *tool,
846 ScaleType type)
847 : VectorDeformTool(tool), m_scale(new Scale(this, type)) {}
848
849 //-----------------------------------------------------------------------------
850
transform(int index,TPointD newPos)851 TPointD DragSelectionTool::VectorScaleTool::transform(int index,
852 TPointD newPos) {
853 SelectionTool *tool = getTool();
854 TPointD scaleValue = tool->m_deformValues.m_scaleValue;
855
856 std::vector<FourPoints> startBboxs = m_scale->getStartBboxs();
857 TPointD center = m_scale->getStartCenter();
858 FourPoints bbox = m_scale->bboxScaleInCenter(index, startBboxs[0], newPos,
859 scaleValue, center, true);
860 if (bbox == startBboxs[0]) return scaleValue;
861
862 bool scaleInCenter = m_scale->scaleInCenter();
863 // Se non ho scalato rispetto al centro calcolo la posizione del nuovo centro
864 if (!scaleInCenter)
865 tool->setCenter(m_scale->getNewCenter(index, startBboxs[0], scaleValue));
866
867 if (tool->isLevelType() || tool->isSelectedFramesType()) {
868 int i;
869 for (i = 1; i < (int)tool->getBBoxsCount(); i++) {
870 FourPoints oldBbox = startBboxs[i];
871 TPointD frameCenter =
872 scaleInCenter ? center
873 : oldBbox.getPoint(getSymmetricPointIndex(index));
874 TPointD newp =
875 m_scale->getScaledPoint(index, oldBbox, scaleValue, frameCenter);
876 FourPoints newBbox = m_scale->bboxScaleInCenter(
877 index, oldBbox, newp, scaleValue, frameCenter, false);
878 tool->setBBox(newBbox, i);
879 if (!scaleInCenter)
880 tool->setCenter(m_scale->getNewCenter(index, oldBbox, scaleValue), i);
881 }
882 }
883 tool->setBBox(bbox);
884 applyTransform(bbox);
885 return scaleValue;
886 }
887
888 //-----------------------------------------------------------------------------
889
leftButtonDown(const TPointD & pos,const TMouseEvent & e)890 void DragSelectionTool::VectorScaleTool::leftButtonDown(const TPointD &pos,
891 const TMouseEvent &e) {
892 m_scale->leftButtonDown(pos, e);
893 VectorDeformTool::leftButtonDown(pos, e);
894 }
895
896 //-----------------------------------------------------------------------------
897
leftButtonDrag(const TPointD & pos,const TMouseEvent & e)898 void DragSelectionTool::VectorScaleTool::leftButtonDrag(const TPointD &pos,
899 const TMouseEvent &e) {
900 VectorSelectionTool *tool = dynamic_cast<VectorSelectionTool *>(m_tool);
901 tool->setResetCenter(false);
902 m_scale->leftButtonDrag(pos, e);
903 }
904
905 //=============================================================================
906 // VectorChangeThicknessTool
907 //-----------------------------------------------------------------------------
908
VectorChangeThicknessTool(VectorSelectionTool * tool)909 DragSelectionTool::VectorChangeThicknessTool::VectorChangeThicknessTool(
910 VectorSelectionTool *tool)
911 : DragTool(tool), m_curPos(), m_firstPos(), m_thicknessChange(0) {
912 TVectorImageP vi = tool->getImage(false);
913 assert(vi);
914
915 setStrokesThickness(*vi);
916
917 TXshSimpleLevel *level =
918 TTool::getApplication()->getCurrentLevel()->getSimpleLevel();
919 m_undo.reset(new UndoChangeStrokes(level, tool->getCurrentFid(), tool,
920 tool->strokeSelection()));
921 }
922
923 //-----------------------------------------------------------------------------
924
~VectorChangeThicknessTool()925 VectorChangeThicknessTool::~VectorChangeThicknessTool() {}
926
927 //-----------------------------------------------------------------------------
928
929 namespace {
930 namespace SetStrokeThickness {
931
932 using namespace DragSelectionTool;
933
934 struct Data {
935 VectorChangeThicknessTool &m_tool;
936 const TVectorImage &m_vi;
937 };
938 } // namespace SetStrokeThickness
939 } // namespace
940
setStrokesThickness(TVectorImage & vi)941 void DragSelectionTool::VectorChangeThicknessTool::setStrokesThickness(
942 TVectorImage &vi) {
943 struct locals {
944 static void setThickness(const SetStrokeThickness::Data &data, int s) {
945 const TStroke &stroke = *data.m_vi.getStroke(s);
946
947 std::vector<double> strokeThickness;
948
949 int cp, cpCount = stroke.getControlPointCount();
950 strokeThickness.reserve(cpCount);
951
952 for (cp = 0; cp != cpCount; ++cp)
953 strokeThickness.push_back(stroke.getControlPoint(cp).thick);
954
955 data.m_tool.m_strokesThickness[s] = strokeThickness;
956 }
957
958 }; // locals
959
960 SetStrokeThickness::Data data = {*this, vi};
961
962 VectorSelectionTool *vsTool = static_cast<VectorSelectionTool *>(m_tool);
963 const LevelSelection &levelSelection = vsTool->levelSelection();
964
965 if (levelSelection.isEmpty()) {
966 StrokeSelection *strokeSelection =
967 static_cast<StrokeSelection *>(m_tool->getSelection());
968 const std::set<int> &selectedStrokeIdxs = strokeSelection->getSelection();
969
970 std::for_each(selectedStrokeIdxs.begin(), selectedStrokeIdxs.end(),
971 boost::bind(locals::setThickness, boost::cref(data), _1));
972 } else {
973 std::vector<int> strokeIdxs = getSelectedStrokes(vi, levelSelection);
974
975 std::for_each(strokeIdxs.begin(), strokeIdxs.end(),
976 boost::bind(locals::setThickness, boost::cref(data), _1));
977 }
978 }
979
980 //-----------------------------------------------------------------------------
981
982 namespace {
983 namespace ChangeImageThickness {
984
985 using namespace DragSelectionTool;
986
987 struct Data {
988 VectorChangeThicknessTool &m_tool;
989 TVectorImage &m_vi;
990 double m_newThickness;
991 };
992 } // namespace ChangeImageThickness
993 } // namespace
994
changeImageThickness(TVectorImage & vi,double newThickness)995 void DragSelectionTool::VectorChangeThicknessTool::changeImageThickness(
996 TVectorImage &vi, double newThickness) {
997 struct locals {
998 static void changeThickness(const ChangeImageThickness::Data &data, int s) {
999 TStroke &stroke = *data.m_vi.getStroke(s);
1000
1001 for (int cp = 0; cp < (int)stroke.getControlPointCount(); ++cp) {
1002 double thickness =
1003 tcrop(data.m_tool.m_strokesThickness[s][cp] + data.m_newThickness,
1004 0.0, 255.0);
1005
1006 TThickPoint point(TPointD(stroke.getControlPoint(cp)), thickness);
1007
1008 stroke.setControlPoint(cp, point);
1009 }
1010 }
1011
1012 }; // locals
1013
1014 ChangeImageThickness::Data data = {*this, vi, newThickness};
1015
1016 VectorSelectionTool *vsTool = static_cast<VectorSelectionTool *>(getTool());
1017 const LevelSelection &levelSelection = vsTool->levelSelection();
1018
1019 if (levelSelection.isEmpty()) {
1020 StrokeSelection *strokeSelection =
1021 static_cast<StrokeSelection *>(m_tool->getSelection());
1022 const std::set<int> &selectedStrokeIdxs = strokeSelection->getSelection();
1023
1024 std::for_each(selectedStrokeIdxs.begin(), selectedStrokeIdxs.end(),
1025 boost::bind(locals::changeThickness, boost::ref(data), _1));
1026 } else {
1027 std::vector<int> strokeIdxs = getSelectedStrokes(vi, levelSelection);
1028
1029 std::for_each(strokeIdxs.begin(), strokeIdxs.end(),
1030 boost::bind(locals::changeThickness, boost::ref(data), _1));
1031 }
1032 }
1033
1034 //-----------------------------------------------------------------------------
1035
addUndo()1036 void DragSelectionTool::VectorChangeThicknessTool::addUndo() {
1037 TVectorImageP curVi = getTool()->getImage(true);
1038 if (!curVi) return;
1039
1040 m_undo->registerStrokes();
1041
1042 SelectionTool *tool = getTool();
1043 if (tool->isLevelType() || tool->isSelectedFramesType()) {
1044 VectorSelectionTool *vtool = dynamic_cast<VectorSelectionTool *>(tool);
1045 assert(vtool && !vtool->levelSelection().isEmpty());
1046
1047 TXshSimpleLevel *level =
1048 TTool::getApplication()->getCurrentLevel()->getSimpleLevel();
1049
1050 // Retrieve frames available in the level
1051 std::vector<TFrameId> fids;
1052 level->getFids(fids);
1053
1054 // Remove unwanted frames
1055 fids.erase(std::remove_if(fids.begin(), fids.end(),
1056 boost::bind(::currentOrNotSelected,
1057 boost::cref(*vtool), _1)),
1058 fids.end());
1059
1060 TUndoManager::manager()->beginBlock();
1061 {
1062 // Current frame added separately
1063 TUndoManager::manager()->add(m_undo.release()); // Inside an undo block
1064
1065 // Iterate remaining ones
1066 int f, fCount = int(fids.size());
1067 for (f = 0; f != fCount; ++f) {
1068 const TFrameId &fid = fids[f];
1069
1070 TVectorImageP vi = level->getFrame(fid, true);
1071 if (!vi) {
1072 assert(vi);
1073 continue;
1074 }
1075
1076 // Transform fid's selection
1077 std::unique_ptr<UndoChangeStrokes> undo(
1078 new UndoChangeStrokes(level, fid, vtool, vtool->levelSelection()));
1079
1080 setStrokesThickness(*vi);
1081 changeImageThickness(*vi, m_thicknessChange);
1082
1083 m_strokesThickness.clear();
1084 undo->registerStrokes();
1085
1086 TUndoManager::manager()->add(undo.release());
1087 }
1088 }
1089 TUndoManager::manager()->endBlock();
1090
1091 // Finally, notify changed frames
1092 std::for_each(fids.begin(), fids.end(),
1093 boost::bind( // NOTE: current frame is not here - it was
1094 &TTool::notifyImageChanged, m_tool,
1095 _1)); // aldready notified
1096 } else
1097 TUndoManager::manager()->add(m_undo.release()); // Outside any undo block
1098 }
1099
1100 //-----------------------------------------------------------------------------
1101
leftButtonDown(const TPointD & pos,const TMouseEvent & e)1102 void DragSelectionTool::VectorChangeThicknessTool::leftButtonDown(
1103 const TPointD &pos, const TMouseEvent &e) {
1104 m_curPos = pos;
1105 m_firstPos = pos;
1106 }
1107
1108 //-----------------------------------------------------------------------------
1109
leftButtonDrag(const TPointD & pos,const TMouseEvent & e)1110 void DragSelectionTool::VectorChangeThicknessTool::leftButtonDrag(
1111 const TPointD &pos, const TMouseEvent &e) {
1112 TAffine aff;
1113 TPointD delta = pos - m_curPos;
1114 TVectorImageP vi = getTool()->getImage(true);
1115 if (!vi) return;
1116 VectorSelectionTool *tool = dynamic_cast<VectorSelectionTool *>(m_tool);
1117 tool->setResetCenter(false);
1118 m_thicknessChange = (pos.y - m_firstPos.y) * 0.2;
1119 changeImageThickness(*vi, m_thicknessChange);
1120 getTool()->m_deformValues.m_maxSelectionThickness = m_thicknessChange;
1121 getTool()->computeBBox();
1122 getTool()->invalidate();
1123 m_curPos = pos;
1124 getTool()->notifyImageChanged();
1125 TTool::getApplication()->getCurrentTool()->notifyToolChanged();
1126 }
1127
1128 //-----------------------------------------------------------------------------
1129
leftButtonUp(const TPointD & pos,const TMouseEvent & e)1130 void DragSelectionTool::VectorChangeThicknessTool::leftButtonUp(
1131 const TPointD &pos, const TMouseEvent &e) {
1132 TVectorImageP curVi = getTool()->getImage(true);
1133 if (!curVi) return;
1134 addUndo();
1135 m_strokesThickness.clear();
1136 }
1137
1138 //=============================================================================
1139 namespace {
1140 //-----------------------------------------------------------------------------
1141
getGroupBBox(const TVectorImage & vi,int strokeIndex,TRectD & gBox)1142 bool getGroupBBox(const TVectorImage &vi, int strokeIndex, TRectD &gBox) {
1143 if (!vi.isStrokeGrouped(strokeIndex)) return false;
1144
1145 gBox = vi.getStroke(strokeIndex)->getBBox();
1146
1147 int s, sCount = int(vi.getStrokeCount());
1148 for (s = 0; s != sCount; ++s) {
1149 if (vi.sameGroup(s, strokeIndex)) gBox += vi.getStroke(s)->getBBox();
1150 }
1151
1152 return true;
1153 }
1154
1155 //=============================================================================
1156 // UndoEnterGroup
1157 //-----------------------------------------------------------------------------
1158
1159 class UndoEnterGroup final : public TUndo {
1160 int m_strokeIndex;
1161 TVectorImageP m_vi;
1162
1163 public:
UndoEnterGroup(TVectorImageP vi,int strokeIndex)1164 UndoEnterGroup(TVectorImageP vi, int strokeIndex)
1165 : m_vi(vi), m_strokeIndex(strokeIndex) {}
undo() const1166 void undo() const override {
1167 m_vi->exitGroup();
1168 TTool::getApplication()->getCurrentXsheet()->notifyXsheetChanged();
1169 }
redo() const1170 void redo() const override {
1171 m_vi->enterGroup(m_strokeIndex);
1172 TTool::getApplication()->getCurrentXsheet()->notifyXsheetChanged();
1173 }
getSize() const1174 int getSize() const override { return sizeof(*this); }
1175 };
1176
1177 //=============================================================================
1178 // UndoExitGroup
1179 //-----------------------------------------------------------------------------
1180
1181 class UndoExitGroup final : public TUndo {
1182 int m_strokeIndex;
1183 TVectorImageP m_vi;
1184
1185 public:
UndoExitGroup(TVectorImageP vi,int strokeIndex)1186 UndoExitGroup(TVectorImageP vi, int strokeIndex)
1187 : m_vi(vi), m_strokeIndex(strokeIndex) {}
undo() const1188 void undo() const override {
1189 m_vi->enterGroup(m_strokeIndex);
1190 TTool::getApplication()->getCurrentXsheet()->notifyXsheetChanged();
1191 }
redo() const1192 void redo() const override {
1193 m_vi->exitGroup();
1194 TTool::getApplication()->getCurrentXsheet()->notifyXsheetChanged();
1195 }
1196
getSize() const1197 int getSize() const override { return sizeof(*this); }
1198 };
1199
1200 } // namespace
1201
1202 //=============================================================================
1203 // VectorSelectionTool
1204 //-----------------------------------------------------------------------------
1205
VectorSelectionTool(int targetType)1206 VectorSelectionTool::VectorSelectionTool(int targetType)
1207 : SelectionTool(targetType)
1208 , m_selectionTarget("Mode:")
1209 , m_includeIntersection("Include Intersection", false)
1210 , m_constantThickness("Preserve Thickness", false)
1211 , m_levelSelection(m_strokeSelection)
1212 , m_capStyle("Cap")
1213 , m_joinStyle("Join")
1214 , m_miterJoinLimit("Miter:", 0, 100, 4)
1215 , m_selectionCount(0)
1216 , m_canEnterGroup(true)
1217 , m_resetCenter(true) {
1218 assert(targetType == TTool::Vectors);
1219 m_prop.bind(m_selectionTarget);
1220 m_prop.bind(m_includeIntersection);
1221 m_prop.bind(m_constantThickness);
1222
1223 m_selectionTarget.addValue(NORMAL_TYPE);
1224 m_selectionTarget.addValue(SELECTED_FRAMES_TYPE);
1225 m_selectionTarget.addValue(ALL_LEVEL_TYPE);
1226 m_selectionTarget.addValue(SAME_STYLE_TYPE);
1227 m_selectionTarget.addValue(STYLE_SELECTED_FRAMES_TYPE);
1228 m_selectionTarget.addValue(STYLE_LEVEL_TYPE);
1229 m_selectionTarget.addValue(BOUNDARY_TYPE);
1230 m_selectionTarget.addValue(BOUNDARY_SELECTED_FRAMES_TYPE);
1231 m_selectionTarget.addValue(BOUNDARY_LEVEL_TYPE);
1232
1233 m_strokeSelection.setView(this);
1234
1235 m_includeIntersection.setId("IncludeIntersection");
1236 m_constantThickness.setId("PreserveThickness");
1237 m_selectionTarget.setId("SelectionMode");
1238
1239 m_capStyle.addValue(BUTT_WSTR, QString::fromStdWString(BUTT_WSTR));
1240 m_capStyle.addValue(ROUNDC_WSTR, QString::fromStdWString(ROUNDC_WSTR));
1241 m_capStyle.addValue(PROJECTING_WSTR,
1242 QString::fromStdWString(PROJECTING_WSTR));
1243 m_capStyle.setId("Cap");
1244
1245 m_joinStyle.addValue(MITER_WSTR, QString::fromStdWString(MITER_WSTR));
1246 m_joinStyle.addValue(ROUNDJ_WSTR, QString::fromStdWString(ROUNDJ_WSTR));
1247 m_joinStyle.addValue(BEVEL_WSTR, QString::fromStdWString(BEVEL_WSTR));
1248 m_joinStyle.setId("Join");
1249
1250 m_miterJoinLimit.setId("Miter");
1251
1252 m_outlineProps.bind(m_capStyle);
1253 m_outlineProps.bind(m_joinStyle);
1254 m_outlineProps.bind(m_miterJoinLimit);
1255 }
1256
1257 //------------------------------------------------------------------------------
1258
setNewFreeDeformer()1259 void VectorSelectionTool::setNewFreeDeformer() {
1260 clearDeformers();
1261
1262 TVectorImageP vi =
1263 getImage(true); // BAD: Should not be done at tool creation...
1264 if (!vi) return;
1265
1266 // Current freeDeformer always at index 0
1267 m_freeDeformers.push_back(
1268 new VectorFreeDeformer(vi, m_strokeSelection.getSelection()));
1269
1270 if (isLevelType() || isSelectedFramesType()) {
1271 TXshSimpleLevel *level =
1272 TTool::getApplication()->getCurrentLevel()->getSimpleLevel();
1273
1274 // All SELECTED frames' subsequent freeDeformers are stored sequentially
1275 // after that
1276 std::vector<TFrameId> fids;
1277 level->getFids(fids);
1278
1279 fids.erase(std::remove_if(
1280 fids.begin(), fids.end(),
1281 boost::bind(::currentOrNotSelected, boost::cref(*this), _1)),
1282 fids.end());
1283
1284 std::vector<TFrameId>::iterator ft, fEnd = fids.end();
1285 for (ft = fids.begin(); ft != fEnd; ++ft) {
1286 if (TVectorImageP levelVi = level->getFrame(*ft, false)) {
1287 const std::vector<int> &selectedStrokeIdxs =
1288 ::getSelectedStrokes(*levelVi, m_levelSelection);
1289 std::set<int> strokesIndices(selectedStrokeIdxs.begin(),
1290 selectedStrokeIdxs.end());
1291
1292 m_freeDeformers.push_back(
1293 new VectorFreeDeformer(levelVi, strokesIndices));
1294 }
1295 }
1296 }
1297 }
1298
1299 //-----------------------------------------------------------------------------
1300
isLevelType() const1301 bool VectorSelectionTool::isLevelType() const {
1302 return m_levelSelection.framesMode() == LevelSelection::FRAMES_ALL;
1303 }
1304
1305 //-----------------------------------------------------------------------------
1306
isSelectedFramesType() const1307 bool VectorSelectionTool::isSelectedFramesType() const {
1308 return m_levelSelection.framesMode() == LevelSelection::FRAMES_SELECTED;
1309 }
1310
1311 //-----------------------------------------------------------------------------
1312
isSameStyleType() const1313 bool VectorSelectionTool::isSameStyleType() const {
1314 return m_levelSelection.filter() == LevelSelection::SELECTED_STYLES;
1315 }
1316
1317 //-----------------------------------------------------------------------------
1318
isModifiableSelectionType() const1319 bool VectorSelectionTool::isModifiableSelectionType() const {
1320 return (m_levelSelection.isEmpty() ||
1321 m_levelSelection.filter() == LevelSelection::SELECTED_STYLES);
1322 }
1323
1324 //-----------------------------------------------------------------------------
1325
updateTranslation()1326 void VectorSelectionTool::updateTranslation() {
1327 m_selectionTarget.setQStringName(tr("Mode:"));
1328 m_selectionTarget.setItemUIName(NORMAL_TYPE, tr("Standard"));
1329 m_selectionTarget.setItemUIName(SELECTED_FRAMES_TYPE, tr("Selected Frames"));
1330 m_selectionTarget.setItemUIName(ALL_LEVEL_TYPE, tr("Whole Level"));
1331 m_selectionTarget.setItemUIName(SAME_STYLE_TYPE, tr("Same Style"));
1332 m_selectionTarget.setItemUIName(STYLE_SELECTED_FRAMES_TYPE,
1333 tr("Same Style on Selected Frames"));
1334 m_selectionTarget.setItemUIName(STYLE_LEVEL_TYPE,
1335 tr("Same Style on Whole Level"));
1336 m_selectionTarget.setItemUIName(BOUNDARY_TYPE, tr("Boundary Strokes"));
1337 m_selectionTarget.setItemUIName(BOUNDARY_SELECTED_FRAMES_TYPE,
1338 tr("Boundaries on Selected Frames"));
1339 m_selectionTarget.setItemUIName(BOUNDARY_LEVEL_TYPE,
1340 tr("Boundaries on Whole Level"));
1341
1342 m_includeIntersection.setQStringName(tr("Include Intersection"));
1343 m_constantThickness.setQStringName(tr("Preserve Thickness"));
1344
1345 m_capStyle.setQStringName(tr("Cap"));
1346 m_capStyle.setItemUIName(BUTT_WSTR, tr("Butt cap"));
1347 m_capStyle.setItemUIName(ROUNDC_WSTR, tr("Round cap"));
1348 m_capStyle.setItemUIName(PROJECTING_WSTR, tr("Projecting cap"));
1349
1350 m_joinStyle.setQStringName(tr("Join"));
1351 m_joinStyle.setItemUIName(MITER_WSTR, tr("Miter join"));
1352 m_joinStyle.setItemUIName(ROUNDJ_WSTR, tr("Round join"));
1353 m_joinStyle.setItemUIName(BEVEL_WSTR, tr("Bevel join"));
1354
1355 m_miterJoinLimit.setQStringName(tr("Miter:"));
1356 SelectionTool::updateTranslation();
1357 }
1358
1359 //-----------------------------------------------------------------------------
1360
updateSelectionTarget()1361 void VectorSelectionTool::updateSelectionTarget() {
1362 // Make the correct selection current
1363 if (m_selectionTarget.getIndex() == NORMAL_TYPE_IDX) {
1364 std::set<int> selectedStrokes; // Retain previously selected strokes across
1365 selectedStrokes.swap(
1366 m_strokeSelection.getSelection()); // current selection change
1367
1368 m_strokeSelection.makeCurrent(); // Empties any (different) previously
1369 // current selection on its own
1370 selectedStrokes.swap(m_strokeSelection.getSelection());
1371 return;
1372 }
1373
1374 m_levelSelection.makeCurrent(); // Same here
1375
1376 // Choose frames mode
1377 LevelSelection::FramesMode framesMode;
1378 switch (m_selectionTarget.getIndex()) {
1379 case SAME_STYLE_TYPE_IDX:
1380 case BOUNDARY_TYPE_IDX:
1381 framesMode = LevelSelection::FRAMES_CURRENT;
1382 break;
1383
1384 case ALL_LEVEL_TYPE_IDX:
1385 case STYLE_LEVEL_TYPE_IDX:
1386 case BOUNDARY_LEVEL_TYPE_IDX:
1387 framesMode = LevelSelection::FRAMES_ALL;
1388 break;
1389
1390 case SELECTED_FRAMES_TYPE_IDX:
1391 case STYLE_SELECTED_FRAMES_TYPE_IDX:
1392 case BOUNDARY_SELECTED_FRAMES_TYPE_IDX:
1393 framesMode = LevelSelection::FRAMES_SELECTED;
1394 break;
1395 }
1396
1397 if (framesMode != m_levelSelection.framesMode()) clearSelectedStrokes();
1398
1399 m_levelSelection.framesMode() = framesMode;
1400
1401 // Choose filter
1402 LevelSelection::Filter filter;
1403 switch (m_selectionTarget.getIndex()) {
1404 case SELECTED_FRAMES_TYPE_IDX:
1405 case ALL_LEVEL_TYPE_IDX:
1406 filter = LevelSelection::WHOLE;
1407 selectedStyles().clear();
1408 break;
1409
1410 case SAME_STYLE_TYPE_IDX:
1411 case STYLE_SELECTED_FRAMES_TYPE_IDX:
1412 case STYLE_LEVEL_TYPE_IDX:
1413 filter = LevelSelection::SELECTED_STYLES;
1414 break;
1415
1416 case BOUNDARY_TYPE_IDX:
1417 case BOUNDARY_SELECTED_FRAMES_TYPE_IDX:
1418 case BOUNDARY_LEVEL_TYPE_IDX:
1419 filter = LevelSelection::BOUNDARY_STROKES;
1420 selectedStyles().clear();
1421 break;
1422 }
1423
1424 if (filter != m_levelSelection.filter()) clearSelectedStrokes();
1425
1426 m_levelSelection.filter() = filter;
1427 }
1428
1429 //-----------------------------------------------------------------------------
1430
finalizeSelection()1431 void VectorSelectionTool::finalizeSelection() {
1432 TVectorImageP vi = getImage(false);
1433 if (vi && !m_levelSelection.isEmpty()) {
1434 std::set<int> &selection = m_strokeSelection.getSelection();
1435 selection.clear();
1436
1437 // Apply base additive selection
1438 if (!isSelectedFramesType() || m_selectedFrames.count(getCurrentFid())) {
1439 // Apply filters
1440 std::vector<int> selectedStrokes =
1441 getSelectedStrokes(*vi, m_levelSelection);
1442 std::set<int>(selectedStrokes.begin(), selectedStrokes.end())
1443 .swap(selection);
1444 }
1445 }
1446
1447 computeBBox();
1448
1449 TTool::getApplication()
1450 ->getCurrentTool()
1451 ->notifyToolChanged(); // Refreshes toolbar values
1452 }
1453
1454 //-----------------------------------------------------------------------------
1455
clearSelectedStrokes()1456 void VectorSelectionTool::clearSelectedStrokes() {
1457 m_strokeSelection.selectNone();
1458 m_levelSelection.styles().clear();
1459 m_deformValues.reset();
1460 }
1461
1462 //-----------------------------------------------------------------------------
1463
modifySelectionOnClick(TImageP image,const TPointD & pos,const TMouseEvent & e)1464 void VectorSelectionTool::modifySelectionOnClick(TImageP image,
1465 const TPointD &pos,
1466 const TMouseEvent &e) {
1467 TVectorImageP vi = TVectorImageP(image);
1468 assert(m_strokeSelection.getImage() == vi);
1469
1470 if (!vi) return;
1471
1472 updateSelectionTarget(); // Make selection current. This is necessary in case
1473 // some other selection context made another selection current.
1474 m_firstPos = m_curPos = pos;
1475 m_selectingRect = FourPoints();
1476 m_selecting = false;
1477 m_justSelected = false;
1478
1479 updateAction(pos, e);
1480 if (m_what != Inside && m_what != Outside && m_what != ADD_SELECTION) return;
1481
1482 UINT index = 0;
1483 bool modifiableSel = isModifiableSelectionType(),
1484 strokeAtPos = getStrokeIndexFromPos(index, vi, pos, getPixelSize(),
1485 getViewer()->getViewMatrix()),
1486 addStroke = strokeAtPos && !m_strokeSelection.isSelected(index),
1487 toggleStroke = strokeAtPos && e.isShiftPressed();
1488
1489 m_selecting =
1490 (modifiableSel && !strokeAtPos // There must be no stroke under cursor
1491 && (e.isShiftPressed() // and either the user is explicitly performing
1492 // additional selection
1493 || (m_strokeSelectionType.getIndex() !=
1494 POLYLINE_SELECTION_IDX) // or the tool support immediate
1495 // selection on clear
1496 || m_strokeSelection
1497 .isEmpty())); // or the strokes list was already cleared
1498
1499 bool clearTargets = !(strokeAtPos || e.isShiftPressed() || m_selecting),
1500 clearSelection = (addStroke || !strokeAtPos) && !e.isShiftPressed(),
1501 selectionChanged = clearSelection;
1502
1503 assert(clearTargets ? clearSelection : true);
1504
1505 if (clearTargets) m_levelSelection.selectNone();
1506
1507 if (clearSelection) {
1508 m_strokeSelection.selectNone();
1509 selectedStyles().clear(); // Targets are preserved here
1510 }
1511
1512 if (strokeAtPos)
1513 selectionChanged = m_justSelected = selectStroke(index, toggleStroke);
1514
1515 if (selectionChanged) {
1516 m_deformValues.reset(); // Resets selection values shown in the toolbar
1517
1518 finalizeSelection();
1519 notifySelectionChanged();
1520
1521 invalidate();
1522 }
1523 }
1524
1525 //-----------------------------------------------------------------------------
1526
leftButtonDoubleClick(const TPointD & pos,const TMouseEvent & e)1527 void VectorSelectionTool::leftButtonDoubleClick(const TPointD &pos,
1528 const TMouseEvent &e) {
1529 TVectorImageP vi = getImage(false);
1530 if (!vi) return;
1531
1532 if (m_strokeSelectionType.getIndex() == POLYLINE_SELECTION_IDX &&
1533 !m_polyline.empty()) {
1534 closePolyline(pos);
1535 selectRegionVectorImage(m_includeIntersection.getValue());
1536
1537 m_selecting = false;
1538 invalidate();
1539
1540 return;
1541 }
1542
1543 int strokeIndex;
1544 if ((strokeIndex = vi->pickGroup(pos)) >= 0) {
1545 if (vi->canEnterGroup(strokeIndex) && m_canEnterGroup) {
1546 if (vi->enterGroup(strokeIndex)) {
1547 clearSelectedStrokes();
1548 TUndoManager::manager()->add(new UndoEnterGroup(vi, strokeIndex));
1549 }
1550 }
1551 } else if ((strokeIndex = vi->exitGroup()) >= 0)
1552 TUndoManager::manager()->add(new UndoExitGroup(vi, strokeIndex));
1553
1554 finalizeSelection();
1555 invalidate();
1556 }
1557
1558 //-----------------------------------------------------------------------------
1559
leftButtonDrag(const TPointD & pos,const TMouseEvent & e)1560 void VectorSelectionTool::leftButtonDrag(const TPointD &pos,
1561 const TMouseEvent &e) {
1562 if (m_dragTool) {
1563 if (!m_strokeSelection.isEditable()) return;
1564
1565 m_dragTool->leftButtonDrag(pos, e);
1566 return;
1567 }
1568
1569 TVectorImageP vi = getImage(false);
1570 if (!vi) return;
1571
1572 double pixelSize = getPixelSize();
1573 TTool::Application *app = TTool::getApplication();
1574 if (!app || m_justSelected || !m_selecting ||
1575 tdistance2(pos, m_curPos) < 9.0 * pixelSize * pixelSize)
1576 return;
1577
1578 m_curPos = pos;
1579
1580 if (m_strokeSelectionType.getIndex() == FREEHAND_SELECTION_IDX) {
1581 freehandDrag(pos);
1582 invalidate();
1583 } else if (m_strokeSelectionType.getIndex() == RECT_SELECTION_IDX) {
1584 bool selectOverlappingStroke = (m_firstPos.x > pos.x);
1585
1586 TRectD rect(m_firstPos, pos);
1587 m_selectingRect = rect;
1588
1589 std::set<int> oldSelection;
1590 if (m_shiftPressed) oldSelection = m_strokeSelection.getSelection();
1591
1592 clearSelectedStrokes();
1593
1594 QMutexLocker lock(vi->getMutex());
1595
1596 m_strokeSelection.setImage(vi); // >_< Shouldn't be done here...?
1597
1598 bool selectionChanged = false;
1599
1600 int s, sCount = vi->getStrokeCount();
1601 for (s = 0; s != sCount; ++s) {
1602 if (!vi->isEnteredGroupStroke(s)) continue;
1603
1604 TStroke *stroke = vi->getStroke(s);
1605
1606 if (m_strokeSelection.isSelected(s)) continue;
1607
1608 bool inSelection = selectOverlappingStroke
1609 ? rect.overlaps(stroke->getBBox())
1610 : rect.contains(stroke->getBBox());
1611
1612 if (inSelection || (m_shiftPressed && oldSelection.count(s)))
1613 selectionChanged = (selectStroke(s, false) || selectionChanged);
1614 }
1615
1616 if (selectionChanged) finalizeSelection();
1617
1618 invalidate();
1619 }
1620 }
1621
1622 //-----------------------------------------------------------------------------
1623
leftButtonDown(const TPointD & pos,const TMouseEvent & e)1624 void VectorSelectionTool::leftButtonDown(const TPointD &pos,
1625 const TMouseEvent &e) {
1626 if (getViewer() && getViewer()->getGuidedStrokePickerMode()) {
1627 getViewer()->doPickGuideStroke(pos);
1628 return;
1629 }
1630
1631 SelectionTool::leftButtonDown(pos, e);
1632 }
1633
1634 //-----------------------------------------------------------------------------
1635
leftButtonUp(const TPointD & pos,const TMouseEvent & e)1636 void VectorSelectionTool::leftButtonUp(const TPointD &pos,
1637 const TMouseEvent &e) {
1638 m_leftButtonMousePressed = false;
1639 m_shiftPressed = false;
1640
1641 if (m_dragTool) {
1642 if (!m_strokeSelection.isEditable()) {
1643 delete m_dragTool;
1644 m_dragTool = 0;
1645 return;
1646 }
1647
1648 m_dragTool->leftButtonUp(pos, e);
1649 delete m_dragTool;
1650 m_dragTool = 0;
1651 invalidate();
1652 return;
1653 }
1654
1655 if (!m_selecting) return;
1656
1657 // Complete selection
1658 TVectorImageP vi = getImage(false);
1659
1660 if (vi) {
1661 if (m_strokeSelectionType.getIndex() == RECT_SELECTION_IDX)
1662 notifySelectionChanged();
1663 else if (m_strokeSelectionType.getIndex() == FREEHAND_SELECTION_IDX) {
1664 QMutexLocker lock(vi->getMutex());
1665
1666 closeFreehand(pos);
1667
1668 if (m_stroke->getControlPointCount() > 3)
1669 selectRegionVectorImage(m_includeIntersection.getValue());
1670
1671 delete m_stroke; // >:(
1672 m_stroke = 0;
1673 m_track.clear();
1674 }
1675 }
1676
1677 m_selecting = false;
1678 m_justSelected = false;
1679 invalidate();
1680 }
1681
1682 //-----------------------------------------------------------------------------
1683
addContextMenuItems(QMenu * menu)1684 void VectorSelectionTool::addContextMenuItems(QMenu *menu) {
1685 menu->addAction(CommandManager::instance()->getAction(MI_RemoveEndpoints));
1686 menu->addSeparator();
1687
1688 m_strokeSelection.getGroupCommand()->addMenuItems(menu);
1689 }
1690
1691 //-----------------------------------------------------------------------------
1692
drawInLevelType(const TVectorImage & vi)1693 void VectorSelectionTool::drawInLevelType(const TVectorImage &vi) {
1694 glPushMatrix();
1695
1696 FourPoints bbox = getBBox();
1697 if (!bbox.isEmpty()) {
1698 TPixel32 frameColor(127, 127, 127);
1699 double pixelSize = getPixelSize();
1700
1701 drawFourPoints(bbox, TPixel32::Black, 0x5555, true);
1702 drawFourPoints(bbox.enlarge(pixelSize * (-4)), frameColor, 0xffff, true);
1703 drawFourPoints(bbox.enlarge(pixelSize * (-2)), frameColor, 0x8888, true);
1704
1705 drawCommandHandle(&vi);
1706 }
1707
1708 drawSelectedStrokes(vi);
1709
1710 if (m_selecting && !m_selectingRect.isEmpty()) drawRectSelection(&vi);
1711
1712 if (m_strokeSelectionType.getIndex() == POLYLINE_SELECTION_IDX)
1713 drawPolylineSelection();
1714
1715 glPopMatrix();
1716 }
1717
1718 //-----------------------------------------------------------------------------
1719
drawSelectedStrokes(const TVectorImage & vi)1720 void VectorSelectionTool::drawSelectedStrokes(const TVectorImage &vi) {
1721 glEnable(GL_LINE_STIPPLE);
1722
1723 double pixelSize = getPixelSize();
1724
1725 int s, sCount = vi.getStrokeCount();
1726 for (s = 0; s != sCount; ++s) {
1727 if (m_strokeSelection.isSelected(s)) {
1728 TStroke *stroke = vi.getStroke(s);
1729
1730 glLineStipple(1, 0xF0F0);
1731 tglColor(TPixel32::Black);
1732 drawStrokeCenterline(*stroke, pixelSize);
1733
1734 glLineStipple(1, 0x0F0F);
1735 tglColor(TPixel32::White);
1736 drawStrokeCenterline(*stroke, pixelSize);
1737 }
1738 }
1739
1740 glDisable(GL_LINE_STIPPLE);
1741 }
1742
1743 //-----------------------------------------------------------------------------
1744
drawGroup(const TVectorImage & vi)1745 void VectorSelectionTool::drawGroup(const TVectorImage &vi) {
1746 int s, sCount = vi.getStrokeCount();
1747 for (s = 0; s != sCount; ++s) {
1748 if (m_strokeSelection.isSelected(s)) {
1749 TRectD gBox;
1750 if (getGroupBBox(vi, s, gBox)) drawRect(gBox, TPixel::Blue, 0xffff);
1751 }
1752 }
1753 }
1754
1755 //-----------------------------------------------------------------------------
1756
draw()1757 void VectorSelectionTool::draw() {
1758 TVectorImageP vi = getImage(false);
1759 if (!vi) return;
1760
1761 if (isLevelType() || isSelectedFramesType()) {
1762 drawInLevelType(*vi);
1763 return;
1764 }
1765
1766 glPushMatrix();
1767
1768 if (m_strokeSelection.isEmpty()) // o_o WTF!?
1769 m_bboxs.clear(); //
1770
1771 // common draw
1772 if (getBBoxsCount() > 0) drawCommandHandle(vi.getPointer());
1773
1774 if (m_selecting && !m_selectingRect.isEmpty())
1775 drawRectSelection(vi.getPointer());
1776
1777 TRectD bbox = vi->getBBox();
1778 TPixel32 frameColor(140, 140, 140);
1779 tglColor(frameColor);
1780 drawRect(bbox, frameColor, 0x5555, true);
1781
1782 drawSelectedStrokes(*vi);
1783
1784 if (m_strokeSelectionType.getIndex() == POLYLINE_SELECTION_IDX)
1785 drawPolylineSelection();
1786 else if (m_strokeSelectionType.getIndex() == FREEHAND_SELECTION_IDX)
1787 drawFreehandSelection();
1788
1789 if (m_levelSelection.isEmpty()) drawGroup(*vi);
1790
1791 glPopMatrix();
1792 }
1793
1794 //-----------------------------------------------------------------------------
1795
getSelection()1796 TSelection *VectorSelectionTool::getSelection() {
1797 TImage *image = getImage(false);
1798 TVectorImageP vi = image;
1799 if (!vi) return 0;
1800
1801 return &m_strokeSelection;
1802 }
1803
1804 //-----------------------------------------------------------------------------
1805
isSelectionEmpty()1806 bool VectorSelectionTool::isSelectionEmpty() {
1807 TVectorImageP vi =
1808 getImage(false); // We want at least current image to be visible.
1809 if (!vi) // This is somewhat in line to preventing tool actions
1810 return true; // on non-visible levels.
1811
1812 return m_strokeSelection
1813 .isEmpty(); // Same here, something should be visibly selected.
1814 }
1815
1816 //-----------------------------------------------------------------------------
1817
computeBBox()1818 void VectorSelectionTool::computeBBox() {
1819 m_bboxs.clear();
1820 if (canResetCenter()) m_centers.clear();
1821
1822 TVectorImageP vi = getImage(false);
1823 if (!vi) return;
1824
1825 if (isLevelType() || isSelectedFramesType()) {
1826 double maxThickness = 0;
1827
1828 // Calculate current image's bbox - it is always the first one (index 0)
1829 if (vi && (isLevelType() || m_selectedFrames.count(getCurrentFid()) > 0)) {
1830 FourPoints bbox =
1831 getFourPointsFromVectorImage(vi, selectedStyles(), maxThickness);
1832
1833 m_bboxs.push_back(bbox);
1834 m_centers.push_back((bbox.getP00() + bbox.getP11()) * 0.5);
1835 }
1836
1837 // All subsequent SELECTED frames' bboxes come sequentially starting from 1
1838 if (TXshSimpleLevel *level =
1839 TTool::getApplication()->getCurrentLevel()->getSimpleLevel()) {
1840 std::vector<TFrameId> fids;
1841 level->getFids(fids);
1842
1843 for (int i = 0; i < (int)fids.size(); ++i) {
1844 if (getCurrentFid() == fids[i] ||
1845 (isSelectedFramesType() && m_selectedFrames.count(fids[i]) == 0))
1846 continue;
1847
1848 TVectorImageP vi = level->getFrame(fids[i], false);
1849 if (!vi) continue;
1850
1851 FourPoints p =
1852 getFourPointsFromVectorImage(vi, selectedStyles(), maxThickness);
1853
1854 m_bboxs.push_back(p);
1855 m_centers.push_back(0.5 * (p.getP00() + p.getP11()));
1856 m_deformValues.m_maxSelectionThickness = maxThickness;
1857 }
1858 }
1859 } else if (vi) {
1860 TRectD newBbox;
1861 double maxThickness = 0;
1862
1863 for (int i = 0; i < (int)vi->getStrokeCount(); i++) {
1864 TStroke *stroke = vi->getStroke(i);
1865
1866 if (m_strokeSelection.isSelected(i)) {
1867 newBbox += stroke->getBBox();
1868
1869 for (int j = 0; j < stroke->getControlPointCount(); j++) {
1870 double thick = stroke->getControlPoint(j).thick;
1871 if (maxThickness < thick) maxThickness = thick;
1872 }
1873 }
1874 }
1875
1876 m_deformValues.m_maxSelectionThickness = maxThickness;
1877 FourPoints bbox;
1878 bbox = newBbox;
1879 m_bboxs.push_back(bbox);
1880 if (canResetCenter())
1881 m_centers.push_back(0.5 * (bbox.getP11() + bbox.getP00()));
1882 }
1883
1884 ++m_selectionCount;
1885 }
1886
1887 //-----------------------------------------------------------------------------
1888
selectStroke(int index,bool toggle)1889 bool VectorSelectionTool::selectStroke(int index, bool toggle) {
1890 TVectorImageP vi = getImage(false);
1891 assert(vi);
1892 assert(m_strokeSelection.getImage() == vi);
1893
1894 if (!vi->isEnteredGroupStroke(index)) // If index is not in current group
1895 return false;
1896
1897 if (index < 0 || index >= int(vi->getStrokeCount())) // Should be asserted...
1898 return false;
1899
1900 bool wasSelected = m_strokeSelection.isSelected(index),
1901 selectState = !(wasSelected && toggle);
1902
1903 // (De)Select additional strokes related to ours
1904 std::set<int> &selectedStyles = this->selectedStyles();
1905
1906 if (isSameStyleType()) // Color selection
1907 {
1908 TStroke *refStroke = vi->getStroke(index);
1909 assert(refStroke);
1910
1911 int style = refStroke->getStyle();
1912
1913 if (selectState)
1914 selectedStyles.insert(style);
1915 else
1916 selectedStyles.erase(style);
1917 } else if (vi->isStrokeGrouped(index) &&
1918 vi->selectable(index)) // Group selection
1919 {
1920 int s, sCount = vi->getStrokeCount();
1921 for (s = 0; s != sCount; ++s) {
1922 if (vi->selectable(s) && vi->sameSubGroup(index, s))
1923 m_strokeSelection.select(s, selectState);
1924 }
1925 } else // Single stroke selection
1926 m_strokeSelection.select(index, selectState);
1927
1928 return (selectState != wasSelected);
1929 }
1930
1931 //-----------------------------------------------------------------------------
1932
onActivate()1933 void VectorSelectionTool::onActivate() {
1934 if (m_firstTime) {
1935 m_includeIntersection.setValue(l_strokeSelectIncludeIntersection ? 1 : 0);
1936 m_constantThickness.setValue(l_strokeSelectConstantThickness ? 1 : 0);
1937 m_strokeSelection.setSceneHandle(
1938 TTool::getApplication()->getCurrentScene());
1939 }
1940
1941 SelectionTool::onActivate();
1942 }
1943
1944 //-----------------------------------------------------------------------------
1945
onDeactivate()1946 void VectorSelectionTool::onDeactivate() {
1947 if (isLevelType()) return;
1948
1949 SelectionTool::onDeactivate();
1950 }
1951
1952 //-----------------------------------------------------------------------------
1953
doOnActivate()1954 void VectorSelectionTool::doOnActivate() {
1955 TVectorImageP vi = getImage(false);
1956 m_strokeSelection.setImage(vi);
1957
1958 updateSelectionTarget();
1959
1960 finalizeSelection();
1961 invalidate();
1962 }
1963
1964 //-----------------------------------------------------------------------------
1965
onImageChanged()1966 void VectorSelectionTool::onImageChanged() {
1967 TVectorImageP vi = getImage(false);
1968 TVectorImageP selectedImg = m_strokeSelection.getImage();
1969
1970 if (vi != selectedImg) {
1971 m_strokeSelection.selectNone();
1972 m_strokeSelection.setImage(vi);
1973
1974 if (!(vi && selectedImg) // Retain the styles selection ONLY
1975 || vi->getPalette() !=
1976 selectedImg->getPalette()) // if palettes still match
1977 selectedStyles().clear();
1978 } else {
1979 // Remove any eventual stroke index outside the valid range
1980 if (!m_strokeSelection.isEmpty()) {
1981 const std::set<int> &indexes = m_strokeSelection.getSelection();
1982 int strokesCount = selectedImg->getStrokeCount();
1983
1984 std::set<int>::const_iterator it;
1985 for (it = indexes.begin(); it != indexes.end(); ++it) {
1986 int index = *it;
1987
1988 if (index >= strokesCount) m_strokeSelection.select(index, false);
1989 }
1990 }
1991 }
1992
1993 finalizeSelection();
1994 }
1995
1996 //-----------------------------------------------------------------------------
1997
isDragging() const1998 bool VectorSelectionTool::isDragging() const {
1999 return m_enabled && m_leftButtonMousePressed;
2000 }
2001
2002 //-----------------------------------------------------------------------------
2003
doOnDeactivate()2004 void VectorSelectionTool::doOnDeactivate() {
2005 m_strokeSelection.selectNone();
2006 m_levelSelection.selectNone();
2007 m_deformValues.reset();
2008
2009 m_polyline.clear();
2010
2011 TTool::getApplication()->getCurrentSelection()->setSelection(0);
2012
2013 invalidate();
2014 }
2015
2016 //-----------------------------------------------------------------------------
2017
getProperties(int idx)2018 TPropertyGroup *VectorSelectionTool::getProperties(int idx) {
2019 switch (idx) {
2020 case 0:
2021 return &m_prop;
2022 case 1:
2023 return &m_outlineProps;
2024 default:
2025 return 0;
2026 };
2027 }
2028
2029 //-----------------------------------------------------------------------------
2030
onPropertyChanged(std::string propertyName)2031 bool VectorSelectionTool::onPropertyChanged(std::string propertyName) {
2032 if (!m_strokeSelection.isEditable()) return false;
2033
2034 if (SelectionTool::onPropertyChanged(propertyName)) return true;
2035
2036 if (propertyName == m_includeIntersection.getName())
2037 l_strokeSelectIncludeIntersection = (int)(m_includeIntersection.getValue());
2038 if (propertyName == m_constantThickness.getName())
2039 l_strokeSelectConstantThickness = (int)(m_constantThickness.getValue());
2040 else if (propertyName == m_selectionTarget.getName())
2041 doOnActivate();
2042 else if (propertyName == m_capStyle.getName()) {
2043 if (m_strokeSelection.isEmpty()) return true;
2044
2045 TXshSimpleLevel *level =
2046 TTool::getApplication()->getCurrentLevel()->getSimpleLevel();
2047 UndoChangeOutlineStyle *undo =
2048 new UndoChangeOutlineStyle(level, getCurrentFid(), this);
2049
2050 int newCapStyle = m_capStyle.getIndex();
2051
2052 TVectorImageP vi = m_strokeSelection.getImage();
2053
2054 const std::set<int> &indices = m_strokeSelection.getSelection();
2055
2056 std::set<int>::iterator it;
2057 for (it = indices.begin(); it != indices.end(); ++it) {
2058 TStroke *stroke = vi->getStroke(*it);
2059
2060 stroke->outlineOptions().m_capStyle =
2061 (TStroke::OutlineOptions::CapStyle)newCapStyle;
2062 stroke->invalidate();
2063 }
2064
2065 computeBBox();
2066 invalidate();
2067
2068 level->setDirtyFlag(true);
2069
2070 undo->registerStrokes();
2071 TUndoManager::manager()->add(undo);
2072
2073 notifyImageChanged();
2074 } else if (propertyName == m_joinStyle.getName()) {
2075 if (m_strokeSelection.isEmpty()) return true;
2076
2077 TXshSimpleLevel *level =
2078 TTool::getApplication()->getCurrentLevel()->getSimpleLevel();
2079 UndoChangeOutlineStyle *undo =
2080 new UndoChangeOutlineStyle(level, getCurrentFid(), this);
2081
2082 int newJoinStyle = m_joinStyle.getIndex();
2083
2084 TVectorImageP vi = m_strokeSelection.getImage();
2085
2086 const std::set<int> &indices = m_strokeSelection.getSelection();
2087
2088 std::set<int>::iterator it;
2089 for (it = indices.begin(); it != indices.end(); ++it) {
2090 TStroke *stroke = vi->getStroke(*it);
2091
2092 stroke->outlineOptions().m_joinStyle =
2093 (TStroke::OutlineOptions::JoinStyle)newJoinStyle;
2094 stroke->invalidate();
2095 }
2096
2097 computeBBox();
2098 invalidate();
2099
2100 level->setDirtyFlag(true);
2101
2102 undo->registerStrokes();
2103 TUndoManager::manager()->add(undo);
2104
2105 notifyImageChanged();
2106 } else if (propertyName == m_miterJoinLimit.getName()) {
2107 if (m_strokeSelection.isEmpty()) return true;
2108
2109 TXshSimpleLevel *level =
2110 TTool::getApplication()->getCurrentLevel()->getSimpleLevel();
2111 UndoChangeOutlineStyle *undo =
2112 new UndoChangeOutlineStyle(level, getCurrentFid(), this);
2113
2114 int upper = m_miterJoinLimit.getValue();
2115
2116 TVectorImageP vi = m_strokeSelection.getImage();
2117
2118 const std::set<int> &indices = m_strokeSelection.getSelection();
2119
2120 std::set<int>::iterator it;
2121 for (it = indices.begin(); it != indices.end(); ++it) {
2122 TStroke *stroke = vi->getStroke(*it);
2123
2124 stroke->outlineOptions().m_miterUpper = upper;
2125 stroke->invalidate();
2126 }
2127
2128 computeBBox();
2129 invalidate();
2130
2131 level->setDirtyFlag(true);
2132
2133 undo->registerStrokes();
2134 TUndoManager::manager()->add(undo);
2135
2136 notifyImageChanged();
2137 } else
2138 return false;
2139
2140 return true;
2141 }
2142
2143 //-----------------------------------------------------------------------------
2144
selectionOutlineStyle(int & capStyle,int & joinStyle)2145 void VectorSelectionTool::selectionOutlineStyle(int &capStyle, int &joinStyle) {
2146 // Check the selection's outline style group validity
2147 const std::set<int> &selection = m_strokeSelection.getSelection();
2148 if (selection.empty()) {
2149 capStyle = joinStyle = -1;
2150 return;
2151 }
2152
2153 TVectorImageP vi = m_strokeSelection.getImage();
2154 const TStroke::OutlineOptions &beginOptions =
2155 vi->getStroke(*selection.begin())->outlineOptions();
2156
2157 capStyle = beginOptions.m_capStyle;
2158 joinStyle = beginOptions.m_joinStyle;
2159
2160 std::set<int>::const_iterator it;
2161 for (it = selection.begin(); it != selection.end(); ++it) {
2162 const TStroke::OutlineOptions &options =
2163 vi->getStroke(*it)->outlineOptions();
2164
2165 if (capStyle != options.m_capStyle) capStyle = -1;
2166 if (joinStyle != options.m_joinStyle) joinStyle = -1;
2167 if (capStyle < 0 && joinStyle < 0) return;
2168 }
2169 }
2170
2171 //-----------------------------------------------------------------------------
2172
selectRegionVectorImage(bool includeIntersect)2173 void VectorSelectionTool::selectRegionVectorImage(bool includeIntersect) {
2174 if (!m_stroke) return;
2175
2176 TVectorImageP vi(getImage(false));
2177 if (!vi) return;
2178
2179 m_strokeSelection.setImage(vi);
2180
2181 TVectorImage selectImg;
2182 selectImg.addStroke(new TStroke(*m_stroke));
2183 selectImg.findRegions();
2184
2185 int sCount = int(vi->getStrokeCount()),
2186 rCount = int(selectImg.getRegionCount());
2187
2188 bool selectionChanged = false;
2189
2190 for (int s = 0; s != sCount; ++s) {
2191 TStroke *currentStroke = vi->getStroke(s);
2192
2193 for (int r = 0; r != rCount; ++r) {
2194 TRegion *region = selectImg.getRegion(r);
2195
2196 if (region->contains(*currentStroke, true))
2197 selectionChanged = selectStroke(s, false) || selectionChanged;
2198 }
2199
2200 if (includeIntersect) {
2201 std::vector<DoublePair> intersections;
2202 intersect(m_stroke, currentStroke, intersections, false);
2203 if (intersections.size() > 0) {
2204 selectionChanged = selectStroke(s, false) || selectionChanged;
2205 }
2206 }
2207 }
2208
2209 if (selectionChanged) {
2210 finalizeSelection();
2211 notifySelectionChanged();
2212 invalidate();
2213 }
2214 }
2215
2216 //-----------------------------------------------------------------------------
2217
updateAction(TPointD pos,const TMouseEvent & e)2218 void VectorSelectionTool::updateAction(TPointD pos, const TMouseEvent &e) {
2219 TImageP image = getImage(false);
2220 TVectorImageP vi = (TVectorImageP)image;
2221 if (!vi) return;
2222
2223 SelectionTool::updateAction(pos, e);
2224 if (m_what != Outside || m_cursorId != ToolCursor::StrokeSelectCursor) return;
2225
2226 if (!m_strokeSelection.isEditable()) return;
2227
2228 FourPoints bbox = getBBox();
2229 UINT index = 0;
2230
2231 if ((isLevelType() &&
2232 bbox.contains(pos)) // What about isSelectedFramesType()??
2233 || (getStrokeIndexFromPos(index, vi, pos, getPixelSize(),
2234 getViewer()->getViewMatrix()) &&
2235 m_strokeSelection.isSelected(index))) {
2236 m_what = Inside;
2237 m_cursorId =
2238 isLevelType() ? ToolCursor::LevelSelectCursor : ToolCursor::MoveCursor;
2239 }
2240 }
2241
2242 //-----------------------------------------------------------------------------
2243
onSelectedFramesChanged()2244 void VectorSelectionTool::onSelectedFramesChanged() {
2245 if (isSelectedFramesType()) // False also in case m_levelSelection is not
2246 // current
2247 finalizeSelection();
2248 }
2249