pojienie 0149f4
#include "tenv.h"
pojienie 0149f4
#include "tproperty.h"
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
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
pojienie 0149f4
TEnv::IntVar SnapAtIntersection("CutterToolSnapAtIntersection", 0);
pojienie 0149f4
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
pojienie 86e7f3
  int m_lockedStrokeIndex;
pojienie 86e7f3
pojienie 0149f4
  TPropertyGroup m_prop;
pojienie 0149f4
  TBoolProperty m_snapAtIntersection;
pojienie 0149f4
Shinya Kitaoka 120a6e
  CutterTool()
Shinya Kitaoka 120a6e
      : TTool("T_Cutter")
Shinya Kitaoka 120a6e
      , m_mouseDown(false)
pojienie 0149f4
      , m_cursorId(ToolCursor::CutterCursor)
pojienie 0149f4
      , m_snapAtIntersection("Snap At Intersection", false) {
Shinya Kitaoka 120a6e
    bind(TTool::VectorImage);
pojienie 0149f4
    m_prop.bind(m_snapAtIntersection);
pojienie 0149f4
    m_snapAtIntersection.setId("Snap");
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
pojienie 75ef2c
  double getNearestSnapAtIntersection(TStroke *selfStroke, double w) {
pojienie 75ef2c
    TVectorImageP vi = TImageP(getImage(false));
pojienie 75ef2c
    if (!vi) {
pojienie 75ef2c
      return w;
pojienie 75ef2c
    }
pojienie 75ef2c
pojienie 75ef2c
    std::vector<doublepair> intersections;</doublepair>
pojienie 75ef2c
    int i, strokeNumber = vi->getStrokeCount();
pojienie 75ef2c
    double diff;
pojienie 75ef2c
    double nearestW = 1000;
pojienie 75ef2c
    double minDiff  = 1000;
pojienie 75ef2c
pojienie 75ef2c
    // check self intersection first
pojienie 75ef2c
    intersect(selfStroke, selfStroke, intersections, false);
pojienie 75ef2c
    for (auto &intersection : intersections) {
pojienie 75ef2c
      if (areAlmostEqual(intersection.first, 0, 1e-6)) {
pojienie 75ef2c
        continue;
pojienie 75ef2c
      }
pojienie 75ef2c
      if (areAlmostEqual(intersection.second, 1, 1e-6)) {
pojienie 75ef2c
        continue;
pojienie 75ef2c
      }
pojienie 75ef2c
Rozhuk Ivan 823a31
      diff = std::abs(intersection.first - w);
pojienie 75ef2c
      if (diff < minDiff) {
pojienie 75ef2c
        minDiff  = diff;
pojienie 75ef2c
        nearestW = intersection.first;
pojienie 75ef2c
      }
pojienie 75ef2c
Rozhuk Ivan 823a31
      diff = std::abs(intersection.second - w);
pojienie 75ef2c
      if (diff < minDiff) {
pojienie 75ef2c
        minDiff  = diff;
pojienie 75ef2c
        nearestW = intersection.second;
pojienie 75ef2c
      }
pojienie 75ef2c
pojienie 75ef2c
      if (selfStroke->isSelfLoop()) {
Rozhuk Ivan 823a31
        diff = std::abs(1 - intersection.first) + w;
pojienie 75ef2c
        if (diff < minDiff) {
pojienie 75ef2c
          minDiff  = diff;
pojienie 75ef2c
          nearestW = intersection.first;
pojienie 75ef2c
        }
pojienie 75ef2c
Rozhuk Ivan 823a31
        diff = intersection.first + std::abs(1 - w);
pojienie 75ef2c
        if (diff < minDiff) {
pojienie 75ef2c
          minDiff  = diff;
pojienie 75ef2c
          nearestW = intersection.first;
pojienie 75ef2c
        }
pojienie 75ef2c
Rozhuk Ivan 823a31
        diff = std::abs(1 - intersection.second) + w;
pojienie 75ef2c
        if (diff < minDiff) {
pojienie 75ef2c
          minDiff  = diff;
pojienie 75ef2c
          nearestW = intersection.second;
pojienie 75ef2c
        }
pojienie 75ef2c
Rozhuk Ivan 823a31
        diff = intersection.second + std::abs(1 - w);
pojienie 75ef2c
        if (diff < minDiff) {
pojienie 75ef2c
          minDiff  = diff;
pojienie 75ef2c
          nearestW = intersection.second;
pojienie 75ef2c
        }
pojienie 75ef2c
      }
pojienie 75ef2c
    }
pojienie 75ef2c
pojienie 75ef2c
    for (i = 0; i < strokeNumber; ++i) {
pojienie 75ef2c
      TStroke *stroke = vi->getStroke(i);
pojienie 75ef2c
      if (stroke == selfStroke) {
pojienie 75ef2c
        continue;
pojienie 75ef2c
      }
pojienie 75ef2c
pojienie 75ef2c
      intersect(selfStroke, stroke, intersections, false);
pojienie 75ef2c
      for (auto &intersection : intersections) {
Rozhuk Ivan 823a31
        diff = std::abs(intersection.first - w);
pojienie 75ef2c
        if (diff < minDiff) {
pojienie 75ef2c
          minDiff  = diff;
pojienie 75ef2c
          nearestW = intersection.first;
pojienie 75ef2c
        }
pojienie 75ef2c
pojienie 75ef2c
        if (selfStroke->isSelfLoop()) {
Rozhuk Ivan 823a31
          diff = std::abs(1 - intersection.first) + w;
pojienie 75ef2c
          if (diff < minDiff) {
pojienie 75ef2c
            minDiff  = diff;
pojienie 75ef2c
            nearestW = intersection.first;
pojienie 75ef2c
          }
pojienie 75ef2c
Rozhuk Ivan 823a31
          diff = intersection.first + std::abs(1 - w);
pojienie 75ef2c
          if (diff < minDiff) {
pojienie 75ef2c
            minDiff  = diff;
pojienie 75ef2c
            nearestW = intersection.first;
pojienie 75ef2c
          }
pojienie 75ef2c
        }
pojienie 75ef2c
      }
pojienie 75ef2c
    }
pojienie 75ef2c
pojienie 75ef2c
    if (nearestW >= 0 && nearestW <= 1) {
pojienie 75ef2c
      return nearestW;
pojienie 75ef2c
    }
pojienie 75ef2c
    return w;
pojienie 75ef2c
  }
pojienie 75ef2c
pojienie 86e7f3
  void leftButtonDown(const TPointD &pos, const TMouseEvent &e) override {
manongjohn 40a40e
    if (getViewer() && getViewer()->getGuidedStrokePickerMode()) {
manongjohn 40a40e
      getViewer()->doPickGuideStroke(pos);
manongjohn 40a40e
      return;
manongjohn 40a40e
    }
manongjohn 40a40e
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
pojienie 86e7f3
    if (getNearestStrokeWithLock(pos, pW, strokeIndex, dist,
pojienie 86e7f3
                                 e.isCtrlPressed()) &&
pojienie 86e7f3
        pW >= 0 && 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
pojienie 75ef2c
      if (m_snapAtIntersection.getValue()) {
pojienie 75ef2c
        w = getNearestSnapAtIntersection(strokeRef, w);
pojienie 75ef2c
      }
pojienie 75ef2c
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
pojienie 86e7f3
    if (getNearestStrokeWithLock(pos, pW, stroke, dist, e.isCtrlPressed())) {
Shinya Kitaoka 120a6e
      TStroke *strokeRef = vi->getStroke(stroke);
pojienie 75ef2c
pojienie 75ef2c
      if (m_snapAtIntersection.getValue()) {
pojienie 75ef2c
        pW = getNearestSnapAtIntersection(strokeRef, pW);
pojienie 75ef2c
      }
pojienie 75ef2c
pojienie 75ef2c
      m_speed  = strokeRef->getSpeed(pW);
pojienie 75ef2c
      m_cursor = strokeRef->getThickPoint(pW);
pojienie 75ef2c
      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
pojienie 0149f4
  void onActivate() override {
pojienie 0149f4
    m_snapAtIntersection.setValue(SnapAtIntersection ? 1 : 0);
pojienie 0149f4
  }
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
manongjohn 40a40e
  int getCursorId() const override {
manongjohn 40a40e
    if (m_viewer && m_viewer->getGuidedStrokePickerMode())
manongjohn 40a40e
      return m_viewer->getGuidedStrokePickerCursor();
manongjohn 40a40e
    return m_cursorId;
manongjohn 40a40e
  }
Toshihiro Shimizu 890ddd
pojienie 0149f4
  void updateTranslation() override {
pojienie 0149f4
    m_snapAtIntersection.setQStringName(QObject::tr("Snap At Intersection"));
pojienie 0149f4
  }
pojienie 0149f4
pojienie 0149f4
  TPropertyGroup *getProperties(int targetType) override { return &m_prop; }
pojienie 0149f4
pojienie 0149f4
  bool onPropertyChanged(std::string propertyName) override {
pojienie 0149f4
    SnapAtIntersection = (int)(m_snapAtIntersection.getValue());
pojienie 0149f4
    return true;
pojienie 0149f4
  }
pojienie 0149f4
pojienie 86e7f3
  bool getNearestStrokeWithLock(const TPointD &p, double &outW,
pojienie 86e7f3
                                UINT &strokeIndex, double &dist2, bool lock) {
pojienie 86e7f3
    TVectorImageP vi = TImageP(getImage(false));
pojienie 86e7f3
    if (!vi) return false;
pojienie 86e7f3
pojienie 86e7f3
    if (m_lockedStrokeIndex >= vi->getStrokeCount()) {
pojienie 86e7f3
      m_lockedStrokeIndex = -1;
pojienie 86e7f3
    }
pojienie 86e7f3
pojienie 86e7f3
    if (lock && m_lockedStrokeIndex >= 0) {
pojienie 86e7f3
      TStroke *stroke = vi->getStroke(m_lockedStrokeIndex);
pojienie 86e7f3
      strokeIndex     = m_lockedStrokeIndex;
pojienie 86e7f3
      return stroke->getNearestW(p, outW, dist2);
pojienie 86e7f3
    }
pojienie 86e7f3
pojienie 86e7f3
    UINT index;
pojienie 86e7f3
    if (vi->getNearestStroke(p, outW, index, dist2)) {
pojienie 86e7f3
      m_lockedStrokeIndex = index;
pojienie 86e7f3
      strokeIndex         = index;
pojienie 86e7f3
      return true;
pojienie 86e7f3
    }
pojienie 86e7f3
pojienie 86e7f3
    return false;
pojienie 86e7f3
  }
pojienie 86e7f3
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;}