File indexing completed on 2024-05-26 04:26:20
0001 /* This file is part of the KDE project 0002 * SPDX-FileCopyrightText: 2006 Jan Hambrecht <jaham@gmx.net> 0003 * SPDX-FileCopyrightText: 2006, 2007 Thorsten Zachmann <zachmann@kde.org> 0004 * 0005 * SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "KoSubpathJoinCommand.h" 0009 #include <klocalizedstring.h> 0010 #include "kis_assert.h" 0011 #include "KoPathMergeUtils.h" 0012 0013 0014 KoSubpathJoinCommand::KoSubpathJoinCommand(const KoPathPointData &pointData1, const KoPathPointData &pointData2, KUndo2Command *parent) 0015 : KUndo2Command(parent) 0016 , m_pointData1(pointData1) 0017 , m_pointData2(pointData2) 0018 , m_splitIndex(KoPathPointIndex(-1, -1)) 0019 , m_oldProperties1(KoPathPoint::Normal) 0020 , m_oldProperties2(KoPathPoint::Normal) 0021 , m_reverse(0) 0022 { 0023 KIS_ASSERT(m_pointData1.pathShape == m_pointData2.pathShape); 0024 KoPathShape * pathShape = m_pointData1.pathShape; 0025 KIS_ASSERT(!pathShape->isClosedSubpath(m_pointData1.pointIndex.first)); 0026 KIS_ASSERT(m_pointData1.pointIndex.second == 0 || 0027 m_pointData1.pointIndex.second == pathShape->subpathPointCount(m_pointData1.pointIndex.first) - 1); 0028 KIS_ASSERT(!pathShape->isClosedSubpath(m_pointData2.pointIndex.first)); 0029 KIS_ASSERT(m_pointData2.pointIndex.second == 0 || 0030 m_pointData2.pointIndex.second == pathShape->subpathPointCount(m_pointData2.pointIndex.first) - 1); 0031 //TODO check that points are not the same 0032 0033 if (m_pointData2 < m_pointData1) { 0034 std::swap(m_pointData1, m_pointData2); 0035 } 0036 0037 if (!closeSubpathMode()) { 0038 if (m_pointData1.pointIndex.second == 0 && 0039 pathShape->subpathPointCount(m_pointData1.pointIndex.first) > 1) 0040 m_reverse |= ReverseFirst; 0041 if (m_pointData2.pointIndex.second != 0) 0042 m_reverse |= ReverseSecond; 0043 setText(kundo2_i18n("Join subpaths")); 0044 } else { 0045 setText(kundo2_i18n("Close subpath")); 0046 } 0047 0048 KoPathPoint * point1 = pathShape->pointByIndex(m_pointData1.pointIndex); 0049 KoPathPoint * point2 = pathShape->pointByIndex(m_pointData2.pointIndex); 0050 0051 m_savedControlPoint1 = KritaUtils::fetchControlPoint(point1, m_reverse & ReverseFirst); 0052 m_savedControlPoint2 = KritaUtils::fetchControlPoint(point2, !(m_reverse & ReverseSecond)); 0053 0054 m_oldProperties1 = point1->properties(); 0055 m_oldProperties2 = point2->properties(); 0056 } 0057 0058 KoSubpathJoinCommand::~KoSubpathJoinCommand() 0059 { 0060 } 0061 0062 0063 0064 void KoSubpathJoinCommand::redo() 0065 { 0066 KUndo2Command::redo(); 0067 KoPathShape * pathShape = m_pointData1.pathShape; 0068 0069 KoPathPoint * point1 = pathShape->pointByIndex(m_pointData1.pointIndex); 0070 KoPathPoint * point2 = pathShape->pointByIndex(m_pointData2.pointIndex); 0071 0072 KIS_SAFE_ASSERT_RECOVER_RETURN(point1); 0073 KIS_SAFE_ASSERT_RECOVER_RETURN(point2); 0074 0075 // if the endpoint has a control point create a control point for the new segment to be 0076 // at the symmetric position to the exiting one 0077 0078 if (closeSubpathMode()) { 0079 KritaUtils::makeSymmetric(point1, false); 0080 KritaUtils::makeSymmetric(point2, true); 0081 } else { 0082 KritaUtils::makeSymmetric(point1, !(m_reverse & ReverseFirst)); 0083 KritaUtils::makeSymmetric(point2, m_reverse & ReverseSecond); 0084 } 0085 0086 if (closeSubpathMode()) { 0087 pathShape->closeSubpath(m_pointData1.pointIndex); 0088 } else { 0089 if (m_reverse & ReverseFirst) { 0090 pathShape->reverseSubpath(m_pointData1.pointIndex.first); 0091 } 0092 if (m_reverse & ReverseSecond) { 0093 pathShape->reverseSubpath(m_pointData2.pointIndex.first); 0094 } 0095 pathShape->moveSubpath(m_pointData2.pointIndex.first, m_pointData1.pointIndex.first + 1); 0096 m_splitIndex = m_pointData1.pointIndex; 0097 m_splitIndex.second = pathShape->subpathPointCount(m_pointData1.pointIndex.first) - 1; 0098 pathShape->join(m_pointData1.pointIndex.first); 0099 } 0100 0101 QList<KoPathPointIndex> pointIndexes; 0102 pointIndexes << pathShape->pathPointIndex(point1); 0103 pointIndexes << pathShape->pathPointIndex(point2); 0104 pathShape->recommendPointSelectionChange(pointIndexes); 0105 0106 pathShape->normalize(); 0107 pathShape->update(); 0108 } 0109 0110 void KoSubpathJoinCommand::undo() 0111 { 0112 KUndo2Command::undo(); 0113 KoPathShape * pathShape = m_pointData1.pathShape; 0114 pathShape->update(); 0115 0116 if (closeSubpathMode()) { 0117 pathShape->openSubpath(m_pointData1.pointIndex); 0118 } else { 0119 pathShape->breakAfter(m_splitIndex); 0120 pathShape->moveSubpath(m_pointData1.pointIndex.first + 1, m_pointData2.pointIndex.first); 0121 0122 if (m_reverse & ReverseSecond) { 0123 pathShape->reverseSubpath(m_pointData2.pointIndex.first); 0124 } 0125 if (m_reverse & ReverseFirst) { 0126 pathShape->reverseSubpath(m_pointData1.pointIndex.first); 0127 } 0128 } 0129 KoPathPoint * point1 = pathShape->pointByIndex(m_pointData1.pointIndex); 0130 KoPathPoint * point2 = pathShape->pointByIndex(m_pointData2.pointIndex); 0131 0132 KIS_SAFE_ASSERT_RECOVER_RETURN(point1); 0133 KIS_SAFE_ASSERT_RECOVER_RETURN(point2); 0134 0135 // restore the old end points 0136 if (closeSubpathMode()) { 0137 KritaUtils::restoreControlPoint(point1, true, m_savedControlPoint1); 0138 KritaUtils::restoreControlPoint(point2, false, m_savedControlPoint2); 0139 } else { 0140 KritaUtils::restoreControlPoint(point1, m_reverse & ReverseFirst, m_savedControlPoint1); 0141 KritaUtils::restoreControlPoint(point2, !(m_reverse & ReverseSecond), m_savedControlPoint2); 0142 } 0143 0144 point1->setProperties(m_oldProperties1); 0145 point2->setProperties(m_oldProperties2); 0146 0147 QList<KoPathPointIndex> pointIndexes; 0148 pointIndexes << pathShape->pathPointIndex(point1); 0149 pointIndexes << pathShape->pathPointIndex(point2); 0150 pathShape->recommendPointSelectionChange(pointIndexes); 0151 0152 pathShape->normalize(); 0153 pathShape->update(); 0154 } 0155 0156 bool KoSubpathJoinCommand::closeSubpathMode() const 0157 { 0158 return m_pointData1.pointIndex.first == m_pointData2.pointIndex.first; 0159 } 0160