#include "tools/tool.h" #include "tools/toolutils.h" #include "toonz/txsheethandle.h" #include "tools/toolhandle.h" #include "toonz/tframehandle.h" #include "toonz/tcolumnhandle.h" #include "toonz/txshlevelhandle.h" #include "tools/strokeselection.h" #include "tools/tool.h" #include "tmathutil.h" #include "tstroke.h" #include "tools/cursors.h" #include "tundo.h" #include "tvectorimage.h" #include "tthreadmessage.h" #include "toonzqt/imageutils.h" #include "toonzqt/tselectionhandle.h" #include "tgl.h" using namespace ToolUtils; //============================================================================= namespace { //============================================================================= // UndoCutter //----------------------------------------------------------------------------- class UndoCutter : public ToolUtils::TToolUndo { int m_newStrokeId1; int m_newStrokeId2; int m_pos; VIStroke *m_oldStroke; std::vector *m_fillInformation; std::vector *m_sortedWRanges; int m_row; int m_column; public: UndoCutter(TXshSimpleLevel *level, const TFrameId &frameId, VIStroke *oldStroke, int pos, int newStrokeId1, int newStrokeId2, std::vector *fillInformation, std::vector *sortedWRanges) : TToolUndo(level, frameId) , m_oldStroke(oldStroke) , m_newStrokeId1(newStrokeId1) , m_newStrokeId2(newStrokeId2) , m_pos(pos) , m_fillInformation(fillInformation) , m_sortedWRanges(sortedWRanges) { TTool::Application *app = TTool::getApplication(); if (app) { m_row = app->getCurrentFrame()->getFrame(); m_column = app->getCurrentColumn()->getColumnIndex(); } } ~UndoCutter() { deleteVIStroke(m_oldStroke); delete m_sortedWRanges; delete m_fillInformation; } void undo() const override { TTool::Application *app = TTool::getApplication(); if (!app) return; if (dynamic_cast( TTool::getApplication()->getCurrentSelection()->getSelection())) TTool::getApplication()->getCurrentSelection()->setSelection(0); if (app->getCurrentFrame()->isEditingScene()) { app->getCurrentColumn()->setColumnIndex(m_column); app->getCurrentFrame()->setFrame(m_row); } else app->getCurrentFrame()->setFid(m_frameId); TVectorImageP image = m_level->getFrame(m_frameId, true); assert(!!image); if (!image) return; QMutexLocker lock(image->getMutex()); VIStroke *stroke; stroke = image->getStrokeById(m_newStrokeId1); if (stroke) image->deleteStroke(stroke); stroke = image->getStrokeById(m_newStrokeId2); if (stroke) image->deleteStroke(stroke); stroke = cloneVIStroke(m_oldStroke); image->insertStrokeAt(stroke, m_pos); UINT size = m_fillInformation->size(); if (!size) { app->getCurrentXsheet()->notifyXsheetChanged(); notifyImageChanged(); return; } image->findRegions(); TRegion *reg; for (UINT i = 0; i < size; i++) { reg = image->getRegion((*m_fillInformation)[i].m_regionId); assert(reg); if (reg) reg->setStyle((*m_fillInformation)[i].m_styleId); } app->getCurrentXsheet()->notifyXsheetChanged(); notifyImageChanged(); } void redo() const override { TTool::Application *app = TTool::getApplication(); if (!app) return; if (app->getCurrentFrame()->isEditingScene()) { app->getCurrentColumn()->setColumnIndex(m_column); app->getCurrentFrame()->setFrame(m_row); } else app->getCurrentFrame()->setFid(m_frameId); TVectorImageP image = m_level->getFrame(m_frameId, true); assert(!!image); if (!image) return; QMutexLocker lock(image->getMutex()); bool isSelfLoop = image->getStroke(m_pos)->isSelfLoop(); image->splitStroke(m_pos, *m_sortedWRanges); image->getStroke(m_pos)->setId(m_newStrokeId1); if (!isSelfLoop && m_sortedWRanges->size() == 2) image->getStroke(m_pos + 1)->setId(m_newStrokeId2); app->getCurrentXsheet()->notifyXsheetChanged(); notifyImageChanged(); } int getSize() const override { return sizeof(*this) + m_fillInformation->capacity() * sizeof(TFilledRegionInf) + 500; } QString getToolName() override { return QString("Cutter Tool"); } }; //============================================================================= // CutterTool //----------------------------------------------------------------------------- class CutterTool : public TTool { public: bool m_mouseDown; TPointD m_vTan; TThickPoint m_cursor; TPointD m_speed; int m_cursorId; double m_pW; CutterTool() : TTool("T_Cutter") , m_mouseDown(false) , m_cursorId(ToolCursor::CutterCursor) { bind(TTool::VectorImage); } ToolType getToolType() const override { return TTool::LevelWriteTool; } void draw() override { // TAffine viewMatrix = getViewer()->getViewMatrix(); // glPushMatrix(); // tglMultMatrix(viewMatrix); const double pixelSize = getPixelSize(); double len = m_cursor.thick + 15 * pixelSize; if (m_speed != TPointD(0, 0)) { TPointD v = m_speed; TPointD p = (TPointD)m_cursor; v = rotate90(v); v = normalize(v); v = v * (len); tglColor(TPixelD(0.1, 0.9, 0.1)); tglDrawSegment(p - v, p + v); } // glPopMatrix(); } void leftButtonDown(const TPointD &pos, const TMouseEvent &) override { TVectorImageP vi = TImageP(getImage(true)); if (!vi) return; QMutexLocker sl(vi->getMutex()); double dist, pW; UINT strokeIndex; TStroke *strokeRef; if (vi->getNearestStroke(pos, pW, strokeIndex, dist) && pW >= 0 && pW <= 1) { double w; strokeRef = vi->getStroke(strokeIndex); double hitPointLen = strokeRef->getLength(pW); double totalLen = strokeRef->getLength(); double len = hitPointLen; if (!strokeRef->isSelfLoop()) { if (len < TConsts::epsilon) w = 0; else w = strokeRef->getParameterAtLength(len); if (len > totalLen - TConsts::epsilon) w = 1; else w = strokeRef->getParameterAtLength(len); } else { if (len < 0) len += totalLen; if (len > totalLen) len -= totalLen; w = strokeRef->getParameterAtLength(len); } std::vector *sortedWRanges = new std::vector; if (strokeRef->isSelfLoop()) { sortedWRanges->push_back(std::make_pair(0, w)); sortedWRanges->push_back(std::make_pair(w, 1)); } else { if (w == 0 || w == 1) sortedWRanges->push_back(std::make_pair(0, 1)); else { sortedWRanges->push_back(std::make_pair(0, w)); sortedWRanges->push_back(std::make_pair(w, 1)); } } std::vector *fillInformation = new std::vector; ImageUtils::getFillingInformationOverlappingArea(vi, *fillInformation, strokeRef->getBBox()); VIStroke *oldStroke = cloneVIStroke(vi->getVIStroke(strokeIndex)); bool isSelfLoop = vi->getStroke(strokeIndex)->isSelfLoop(); vi->splitStroke(strokeIndex, *sortedWRanges); TUndo *nundo; TXshSimpleLevel *sl = TTool::getApplication()->getCurrentLevel()->getSimpleLevel(); assert(sl); TFrameId id = getCurrentFid(); if (isSelfLoop || sortedWRanges->size() == 1) { nundo = new UndoCutter(sl, id, oldStroke, strokeIndex, vi->getStroke(strokeIndex)->getId(), -1, fillInformation, sortedWRanges); } else { assert(strokeIndex + 1 < vi->getStrokeCount()); nundo = new UndoCutter(sl, id, oldStroke, strokeIndex, vi->getStroke(strokeIndex)->getId(), vi->getStroke(strokeIndex + 1)->getId(), fillInformation, sortedWRanges); } TUndoManager::manager()->add(nundo); invalidate(); notifyImageChanged(); } invalidate(); } void mouseMove(const TPointD &pos, const TMouseEvent &e) override { TVectorImageP vi = TImageP(getImage(true)); if (!vi) { m_speed = TPointD(0, 0); return; } // select nearest stroke and finds its parameter double dist, pW; UINT stroke; if (vi->getNearestStroke(pos, pW, stroke, dist)) { TStroke *strokeRef = vi->getStroke(stroke); m_speed = strokeRef->getSpeed(pW); m_cursor = strokeRef->getThickPoint(pW); m_pW = pW; } else { m_speed = TPointD(0, 0); } invalidate(); } void onLeave() override { m_speed = TPointD(0, 0); } void onActivate() override {} void onEnter() override { if ((TVectorImageP)getImage(false)) m_cursorId = ToolCursor::CutterCursor; else m_cursorId = ToolCursor::CURSOR_NO; } int getCursorId() const override { return m_cursorId; } } cutterTool; //----------------------------------------------------------------------------- } // namespace //----------------------------------------------------------------------------- // TTool *getCutterTool() {return &cutterTool;}