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