diff --git a/toonz/sources/tnztools/bluredbrush.cpp b/toonz/sources/tnztools/bluredbrush.cpp
index 44f5214..61ee125 100644
--- a/toonz/sources/tnztools/bluredbrush.cpp
+++ b/toonz/sources/tnztools/bluredbrush.cpp
@@ -197,7 +197,14 @@ BluredBrush::~BluredBrush() {}
 
 //----------------------------------------------------------------------------------
 
-void BluredBrush::addPoint(const TThickPoint &p, double opacity) {
+void BluredBrush::addPoint(const TThickPoint &p, double opacity, bool keepDistance) {
+  if (keepDistance) {
+    double dist = norm2(p - m_lastPoint);
+    double d = 0.12 * m_lastPoint.thick;
+    if (dist < d*d)
+      return;
+  }
+  
   double radius      = p.thick * 0.5;
   double brushRadius = m_size * 0.5;
   double scaleFactor = radius / brushRadius;
diff --git a/toonz/sources/tnztools/bluredbrush.h b/toonz/sources/tnztools/bluredbrush.h
index 3f7a32c..650a001 100644
--- a/toonz/sources/tnztools/bluredbrush.h
+++ b/toonz/sources/tnztools/bluredbrush.h
@@ -34,7 +34,7 @@ public:
               bool doDynamicOpacity);
   ~BluredBrush();
 
-  void addPoint(const TThickPoint &p, double opacity);
+  void addPoint(const TThickPoint &p, double opacity, bool keepDistance = false);
   void addArc(const TThickPoint &pa, const TThickPoint &pb,
               const TThickPoint &pc, double opacityA, double opacityC);
   TRect getBoundFromPoints(const std::vector<TThickPoint> &points) const;
diff --git a/toonz/sources/tnztools/toonzrasterbrushtool.cpp b/toonz/sources/tnztools/toonzrasterbrushtool.cpp
index b10a4ef..2d30c40 100644
--- a/toonz/sources/tnztools/toonzrasterbrushtool.cpp
+++ b/toonz/sources/tnztools/toonzrasterbrushtool.cpp
@@ -6,7 +6,6 @@
 #include "tools/toolhandle.h"
 #include "tools/toolutils.h"
 #include "tools/tooloptions.h"
-#include "bluredbrush.h"
 
 // TnzQt includes
 #include "toonzqt/dvdialog.h"
@@ -21,7 +20,6 @@
 #include "toonz/txsheet.h"
 #include "toonz/tstageobject.h"
 #include "toonz/tstageobjectspline.h"
-#include "toonz/rasterstrokegenerator.h"
 #include "toonz/ttileset.h"
 #include "toonz/txshsimplelevel.h"
 #include "toonz/toonzimageutils.h"
@@ -884,7 +882,6 @@ ToonzRasterBrushTool::ToonzRasterBrushTool(std::string name, int targetType)
     , m_isPrompting(false)
     , m_firstTime(true)
     , m_presetsLoaded(false)
-    , m_workingFrameId(TFrameId())
     , m_notifier(0)
 {
   bind(targetType);
@@ -912,6 +909,18 @@ ToonzRasterBrushTool::ToonzRasterBrushTool(std::string name, int targetType)
   m_preset.addValue(CUSTOM_WSTR);
   m_pressure.setId("PressureSensitivity");
   m_modifierLockAlpha.setId("LockAlpha");
+
+  m_inputmanager.setHandler(this);
+#ifndef NDEBUG
+  m_modifierTest = new TModifierTest(5, 40);
+#endif
+  m_modifierLine         = new TModifierLine();
+  m_modifierTangents     = new TModifierTangents();
+  m_modifierAssistants   = new TModifierAssistants();
+  m_modifierSegmentation = new TModifierSegmentation();
+
+  m_inputmanager.addModifier(
+      TInputModifierP(m_modifierAssistants.getPointer()));
 }
 
 //-------------------------------------------------------------------------------------------------------
@@ -1110,70 +1119,6 @@ void ToonzRasterBrushTool::updateTranslation() {
 
 //---------------------------------------------------------------------------------------------------
 
-void ToonzRasterBrushTool::updateWorkAndBackupRasters(const TRect &rect) {
-  TToonzImageP ti = TImageP(getImage(false, 1));
-  if (!ti) return;
-
-  TRasterCM32P ras = ti->getRaster();
-
-  if (m_isMyPaintStyleSelected) {
-    const int denominator = 8;
-    TRect enlargedRect    = rect + m_painting.lastRect;
-    int dx                = (enlargedRect.getLx() - 1) / denominator + 1;
-    int dy                = (enlargedRect.getLy() - 1) / denominator + 1;
-
-    if (m_painting.lastRect.isEmpty()) {
-      enlargedRect.x0 -= dx;
-      enlargedRect.y0 -= dy;
-      enlargedRect.x1 += dx;
-      enlargedRect.y1 += dy;
-
-      TRect _rect = enlargedRect * ras->getBounds();
-      if (_rect.isEmpty()) return;
-
-      m_workRas->extract(_rect)->copy(ras->extract(_rect));
-      m_backupRas->extract(_rect)->copy(ras->extract(_rect));
-    } else {
-      if (enlargedRect.x0 < m_painting.lastRect.x0) enlargedRect.x0 -= dx;
-      if (enlargedRect.y0 < m_painting.lastRect.y0) enlargedRect.y0 -= dy;
-      if (enlargedRect.x1 > m_painting.lastRect.x1) enlargedRect.x1 += dx;
-      if (enlargedRect.y1 > m_painting.lastRect.y1) enlargedRect.y1 += dy;
-
-      TRect _rect = enlargedRect * ras->getBounds();
-      if (_rect.isEmpty()) return;
-
-      TRect _lastRect    = m_painting.lastRect * ras->getBounds();
-      QList<TRect> rects = ToolUtils::splitRect(_rect, _lastRect);
-      for (int i = 0; i < rects.size(); i++) {
-        m_workRas->extract(rects[i])->copy(ras->extract(rects[i]));
-        m_backupRas->extract(rects[i])->copy(ras->extract(rects[i]));
-      }
-    }
-
-    m_painting.lastRect = enlargedRect;
-    return;
-  }
-
-  TRect _rect     = rect * ras->getBounds();
-  TRect _lastRect = m_painting.lastRect * ras->getBounds();
-
-  if (_rect.isEmpty()) return;
-
-  if (m_painting.lastRect.isEmpty()) {
-    m_workRas->extract(_rect)->clear();
-    m_backupRas->extract(_rect)->copy(ras->extract(_rect));
-    return;
-  }
-
-  QList<TRect> rects = ToolUtils::splitRect(_rect, _lastRect);
-  for (int i = 0; i < rects.size(); i++) {
-    m_workRas->extract(rects[i])->clear();
-    m_backupRas->extract(rects[i])->copy(ras->extract(rects[i]));
-  }
-}
-
-//---------------------------------------------------------------------------------------------------
-
 void ToonzRasterBrushTool::onActivate() {
   if (!m_notifier) m_notifier = new ToonzRasterBrushToolNotifier(this);
 
@@ -1202,18 +1147,8 @@ void ToonzRasterBrushTool::onActivate() {
 //--------------------------------------------------------------------------------------------------
 
 void ToonzRasterBrushTool::onDeactivate() {
-  /*---
-   * ドラッグ中にツールが切り替わった場合に備え、onDeactivateにもMouseReleaseと同じ処理を行う
-   * ---*/
-  if (m_painting.tileSaver) {
-    bool isValid = m_enabled && m_painting.active;
-    m_enabled = false;
-    m_painting.active = false;
-    if (isValid) {
-      finishRasterBrush(m_mousePos,
-                        1); /*-- 最後のストロークの筆圧は1とする --*/
-    }
-  }
+  m_inputmanager.finishTracks();
+  m_enabled   = false;
   m_workRas   = TRaster32P();
   m_backupRas = TRasterCM32P();
 }
@@ -1226,7 +1161,6 @@ bool ToonzRasterBrushTool::askRead(const TRect &rect) { return askWrite(rect); }
 
 bool ToonzRasterBrushTool::askWrite(const TRect &rect) {
   if (rect.isEmpty()) return true;
-  m_painting.myPaint.strokeRect += rect;
   m_painting.myPaint.strokeSegmentRect += rect;
   updateWorkAndBackupRasters(rect);
   m_painting.tileSaver->save(rect);
@@ -1236,6 +1170,17 @@ bool ToonzRasterBrushTool::askWrite(const TRect &rect) {
 //--------------------------------------------------------------------------------------------------
 
 bool ToonzRasterBrushTool::preLeftButtonDown() {
+  m_modifierAssistants->drawOnly = true;
+  m_inputmanager.drawPreview     = false;  //! m_modifierAssistants->drawOnly;
+
+  m_inputmanager.clearModifiers();
+  m_inputmanager.addModifier(TInputModifierP(m_modifierTangents.getPointer()));
+  m_inputmanager.addModifier(TInputModifierP(m_modifierAssistants.getPointer()));
+  m_inputmanager.addModifier(TInputModifierP(m_modifierSegmentation.getPointer()));
+#ifndef NDEBUG
+  m_inputmanager.addModifier(TInputModifierP(m_modifierTest.getPointer()));
+#endif
+
   touchImage();
   if (m_isFrameCreated) {
     setWorkAndBackupImages();
@@ -1247,635 +1192,337 @@ bool ToonzRasterBrushTool::preLeftButtonDown() {
   return true;
 }
 
-//--------------------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------------------
 
-void ToonzRasterBrushTool::leftButtonDown(const TPointD &pos,
+void ToonzRasterBrushTool::handleMouseEvent(MouseEventType type,
+                                          const TPointD &pos,
                                           const TMouseEvent &e) {
-  TTool::Application *app = TTool::getApplication();
-  if (!app) return;
-
-  int col   = app->getCurrentColumn()->getColumnIndex();
-  m_enabled = col >= 0 || app->getCurrentFrame()->isEditingLevel();
-  // todo: gestire autoenable
-  if (!m_enabled) return;
-
-  m_painting.active = !!getImage(true);
-  if (!m_painting.active) m_painting.active = !!touchImage();
-  if (!m_painting.active) return;
-
-  // nel caso che il colore corrente sia un cleanup/studiopalette color
-  // oppure il colore di un colorfield
-  if (TColorStyle *cs = app->getCurrentLevelStyle()) {
-    m_painting.styleId = app->getCurrentLevelStyleIndex();
-    TRasterStyleFx *rfx = cs->getRasterStyleFx();
-    if (!cs->isStrokeStyle() && (!rfx || !rfx->isInkStyle()))
-        { m_painting.active = false; return; }
-  } else {
-    m_painting.styleId = 1;
-  }
-
-  TPointD centeredPos = getCenteredCursorPos(pos);
-  
-  // Modifier to do straight line
-  if (e.isShiftPressed()) {
-    m_painting.straight.isStraight = true;
-    m_painting.straight.firstPoint = pos;
-    m_painting.straight.lastPoint  = pos;
+  TTimerTicks t = TToolTimer::ticks();
+  bool alt      = e.getModifiersMask() & TMouseEvent::ALT_KEY;
+  bool shift    = e.getModifiersMask() & TMouseEvent::SHIFT_KEY;
+  bool control  = e.getModifiersMask() & TMouseEvent::CTRL_KEY;
+
+  if (shift && type == ME_DOWN && e.button() == Qt::LeftButton && !m_painting.active) {
+    m_modifierAssistants->drawOnly = true;
+    m_inputmanager.clearModifiers();
+    m_inputmanager.addModifier(TInputModifierP(m_modifierLine.getPointer()));
+    m_inputmanager.addModifier(TInputModifierP(m_modifierAssistants.getPointer()));
+    m_inputmanager.addModifier(TInputModifierP(m_modifierSegmentation.getPointer()));
+    m_inputmanager.drawPreview = true;
   }
 
-  double pressure;
-  if (m_isMyPaintStyleSelected)  // mypaint brush case
-    pressure = m_pressure.getValue() && e.isTablet() ? e.m_pressure : 0.5;
-  else
-    pressure = m_pressure.getValue() ? e.m_pressure : 1.0;
-
-  TImageP img = getImage(true);
-  TToonzImageP ri(img);
-  TRasterCM32P ras = ri->getRaster();
-  if (ras) {
-    TPointD rasCenter = ras->getCenterD();
-    m_painting.tileSet   = new TTileSetCM32(ras->getSize());
-    m_painting.tileSaver = new TTileSaverCM32(ras, m_painting.tileSet);
-    double maxThick   = m_rasThickness.getValue().second;
-    double thickness  = (m_pressure.getValue())
-                            ? computeThickness(pressure, m_rasThickness) * 2
-                            : maxThick;
-
-    /*--- ストロークの最初にMaxサイズの円が描かれてしまう不具合を防止する
-     * ---*/
-    if (m_pressure.getValue() && e.m_pressure == 1.0 && !m_painting.straight.isStraight)
-      thickness = m_rasThickness.getValue().first;
-
-    TPointD halfThick(maxThick * 0.5, maxThick * 0.5);
-    TRectD invalidateRect(centeredPos - halfThick, centeredPos + halfThick);
-    TPointD dpi;
-    ri->getDpi(dpi.x, dpi.y);
-    TRectD previousTipRect(m_brushPos - halfThick, m_brushPos + halfThick);
-    if (dpi.x > Stage::inch || dpi.y > Stage::inch)
-      previousTipRect *= dpi.x / Stage::inch;
-    invalidateRect += previousTipRect;
-
-    // if the drawOrder mode = "Palette Order",
-    // get styleId list which is above the current style in the palette
-    DrawOrder drawOrder = (DrawOrder)m_drawOrder.getIndex();
-    QSet<int> aboveStyleIds;
-    if (drawOrder == PaletteOrder) {
-      getAboveStyleIdSet(m_painting.styleId, ri->getPalette(), aboveStyleIds);
-    }
-
-    // mypaint brush case
-    if (m_isMyPaintStyleSelected) {
-      TPointD point(centeredPos + rasCenter);
-
-      updateCurrentStyle();
-      if (!(m_workRas && m_backupRas)) setWorkAndBackupImages();
-      m_workRas->lock();
-      mypaint::Brush mypaintBrush;
-      TMyPaintBrushStyle *mypaintStyle =
-          dynamic_cast<TMyPaintBrushStyle *>(app->getCurrentLevelStyle());
-      {  // applyToonzBrushSettings
-        mypaintBrush.fromBrush(mypaintStyle->getBrush());
-        double modifierSize = m_modifierSize.getValue() * log(2.0);
-        float baseSize =
-            mypaintBrush.getBaseValue(MYPAINT_BRUSH_SETTING_RADIUS_LOGARITHMIC);
-        mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_RADIUS_LOGARITHMIC,
-                                  baseSize + modifierSize);
-      }
-      m_painting.myPaint.brush = new MyPaintToonzBrush(m_workRas, *this, mypaintBrush);
-      m_painting.myPaint.strokeRect.empty();
-      m_painting.myPaint.strokeSegmentRect.empty();
-      m_painting.myPaint.brush->beginStroke();
-      m_painting.myPaint.brush->strokeTo(point, pressure, TPointD(), restartBrushTimer());
-      TRect updateRect = m_painting.myPaint.strokeSegmentRect * ras->getBounds();
-      if (!updateRect.isEmpty()) {
-        m_painting.myPaint.brush->updateDrawing( ri->getRaster(), m_backupRas, m_painting.myPaint.strokeRect,
-                                                 m_painting.styleId, m_modifierLockAlpha.getValue() );
-      }
-      m_painting.lastRect = m_painting.myPaint.strokeRect;
-
-      TPointD thickOffset(m_maxCursorThick * 0.5, m_maxCursorThick * 0.5);
-      invalidateRect = convert(m_painting.myPaint.strokeSegmentRect) - rasCenter;
-      invalidateRect +=
-          TRectD(centeredPos - thickOffset, centeredPos + thickOffset);
-      invalidateRect +=
-          TRectD(m_brushPos - thickOffset, m_brushPos + thickOffset);
-    } else if (m_hardness.getValue() == 100 || m_pencil.getValue()) {
-      m_painting.pencil.realPencil = m_pencil.getValue();
-      
-      /*-- Pencilモードでなく、Hardness=100 の場合のブラシサイズを1段階下げる
-       * --*/
-      if (!m_painting.pencil.realPencil && !m_painting.straight.isStraight) thickness -= 1.0;
-
-      TThickPoint thickPoint(centeredPos + convert(ras->getCenter()),
-                             thickness);
-      m_painting.pencil.brush = new RasterStrokeGenerator(
-          ras, BRUSH, NONE, m_painting.styleId, thickPoint, drawOrder != OverAll, 0,
-          m_modifierLockAlpha.getValue(), !m_painting.pencil.realPencil,
-          drawOrder == PaletteOrder);
-
-      if (drawOrder == PaletteOrder)
-        m_painting.pencil.brush->setAboveStyleIds(aboveStyleIds);
-
-      m_painting.tileSaver->save( m_painting.pencil.brush->getLastRect() );
-      if (!m_painting.straight.isStraight)
-        m_painting.pencil.brush->generateLastPieceOfStroke( m_painting.pencil.realPencil );
-
-      m_painting.smooth = m_smooth.getValue() > 0;
-      if (m_painting.smooth) {
-        std::vector<TThickPoint> pts;
-        m_painting.smoothStroke.beginStroke(m_smooth.getValue());
-        m_painting.smoothStroke.addPoint(thickPoint);
-        m_painting.smoothStroke.getSmoothPoints(pts);
-      }
-    } else {
-      m_painting.blured.points.clear();
-      TThickPoint point(centeredPos + rasCenter, thickness);
-      m_painting.blured.points.push_back(point);
-      m_painting.blured.brush = new BluredBrush(m_workRas, maxThick, m_brushPad, false);
-
-      if (drawOrder == PaletteOrder)
-        m_painting.blured.brush->setAboveStyleIds(aboveStyleIds);
-
-      TRect strokeRect = m_painting.blured.brush->getBoundFromPoints( m_painting.blured.points );
-      updateWorkAndBackupRasters(strokeRect);
-      m_painting.tileSaver->save(strokeRect);
-      m_painting.blured.brush->addPoint(point, 1);
-      if (!m_painting.straight.isStraight)
-        m_painting.blured.brush->updateDrawing( ri->getRaster(), m_backupRas, strokeRect,
-                                                m_painting.styleId, drawOrder,
-                                                m_modifierLockAlpha.getValue() );
-      m_painting.lastRect = strokeRect;
-
-      m_painting.smooth = m_smooth.getValue() > 0;
-      if (m_painting.smooth) {
-        std::vector<TThickPoint> pts;
-        m_painting.smoothStroke.beginStroke(m_smooth.getValue());
-        m_painting.smoothStroke.addPoint(point);
-        m_painting.smoothStroke.getSmoothPoints(pts);
-      }
-    }
-    /*-- 作業中のFidを登録 --*/
-    m_workingFrameId = getFrameId();
+  if (alt != m_inputmanager.state.isKeyPressed(TKey::alt))
+    m_inputmanager.keyEvent(alt, TKey::alt, t, nullptr);
+  if (shift != m_inputmanager.state.isKeyPressed(TKey::shift))
+    m_inputmanager.keyEvent(shift, TKey::shift, t, nullptr);
+  if (control != m_inputmanager.state.isKeyPressed(TKey::control))
+    m_inputmanager.keyEvent(control, TKey::control, t, nullptr);
 
-    invalidate(invalidateRect.enlarge(2));
+  if (type == ME_MOVE) {
+    THoverList hovers(1, pos);
+    m_inputmanager.hoverEvent(hovers);
+  } else {
+    m_inputmanager.trackEvent(e.isTablet(), 0, pos,
+                              e.isTablet() ? &e.m_pressure : nullptr, nullptr,
+                              type == ME_UP, t);
+    m_inputmanager.processTracks();
   }
-  // updating m_brushPos is needed to refresh viewer properly
-  m_mousePos = pos;
-  m_brushPos = getCenteredCursorPos(pos);
 }
 
-//-------------------------------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------------------
 
+void ToonzRasterBrushTool::leftButtonDown(const TPointD &pos,
+                                        const TMouseEvent &e) {
+  handleMouseEvent(ME_DOWN, pos, e);
+}
 void ToonzRasterBrushTool::leftButtonDrag(const TPointD &pos,
-                                          const TMouseEvent &e) {
-  TRectD invalidateRect;
-  m_painting.straight.lastPoint = pos;
-
-  if (!m_enabled || !m_painting.active) {
-    m_mousePos = pos;
-    m_brushPos = getCenteredCursorPos(pos);
-    return;
-  }
-
-  TPointD centeredPos = getCenteredCursorPos(m_painting.straight.lastPoint);
-
-  double pressure;
-  if (m_isMyPaintStyleSelected)  // mypaint brush case
-    pressure = m_pressure.getValue() && e.isTablet() ? e.m_pressure : 0.5;
-  else
-    pressure = m_pressure.getValue() ? e.m_pressure : 1.0;
-
-  TToonzImageP ti     = TImageP(getImage(true));
-  TPointD rasCenter   = ti->getRaster()->getCenterD();
-  double maxThickness = m_rasThickness.getValue().second;
-  double thickness    = (m_pressure.getValue())
-                            ? computeThickness(pressure, m_rasThickness) * 2
-                            : maxThickness;
+                                        const TMouseEvent &e) {
+  handleMouseEvent(ME_DRAG, pos, e);
+}
+void ToonzRasterBrushTool::leftButtonUp(const TPointD &pos,
+                                      const TMouseEvent &e) {
+  handleMouseEvent(ME_UP, pos, e);
+}
+void ToonzRasterBrushTool::mouseMove(const TPointD &pos, const TMouseEvent &e) {
+  handleMouseEvent(ME_MOVE, pos, e);
+}
 
-  if (m_painting.straight.maxPressure < pressure) m_painting.straight.maxPressure = pressure;
+//--------------------------------------------------------------------------------------------------
 
-  if (m_painting.straight.isStraight) {
-    invalidateRect = TRectD(m_painting.straight.firstPoint, m_painting.straight.lastPoint).enlarge(2);
-    if (e.isCtrlPressed()) {
-      double distance = (m_brushPos.x - m_maxCursorThick + 1) * 0.5;
-      TRectD brushRect =
-          TRectD(TPointD(m_brushPos.x - distance, m_brushPos.y - distance),
-                 TPointD(m_brushPos.x + distance, m_brushPos.y + distance));
-      invalidateRect += (brushRect);
-      double denominator = m_painting.straight.lastPoint.x - m_painting.straight.firstPoint.x;
-      if (denominator == 0) denominator == 0.001;
-      double slope = ((m_painting.straight.lastPoint.y - m_painting.straight.firstPoint.y) / denominator);
-      double angle = std::atan(slope) * (180 / 3.14159);
-      if (abs(angle) > 67.5)
-        m_painting.straight.lastPoint.x = m_painting.straight.firstPoint.x;
-      else if (abs(angle) < 22.5)
-        m_painting.straight.lastPoint.y = m_painting.straight.firstPoint.y;
-      else {
-        double xDistance = m_painting.straight.lastPoint.x - m_painting.straight.firstPoint.x;
-        double yDistance = m_painting.straight.lastPoint.y - m_painting.straight.firstPoint.y;
-        if (abs(xDistance) > abs(yDistance)) {
-          if (abs(yDistance) == yDistance)
-            m_painting.straight.lastPoint.y = m_painting.straight.firstPoint.y + abs(xDistance);
-          else
-            m_painting.straight.lastPoint.y = m_painting.straight.firstPoint.y - abs(xDistance);
-        } else {
-          if (abs(xDistance) == xDistance)
-            m_painting.straight.lastPoint.x = m_painting.straight.firstPoint.x + abs(yDistance);
-          else
-            m_painting.straight.lastPoint.x = m_painting.straight.firstPoint.x - abs(yDistance);
-        }
-      }
-    }
-    m_mousePos = pos;
-    m_brushPos = getCenteredCursorPos(pos);
-    invalidate(invalidateRect);
+void ToonzRasterBrushTool::inputSetBusy(bool busy) {
+  if (m_painting.active == busy)
     return;
-  }
-
-  if (m_painting.myPaint.brush) {
-    TRasterP ras = ti->getRaster();
-    TPointD point(centeredPos + rasCenter);
+  
+  if (busy) {
+    // begin painting
+    
+    TTool::Application *app = TTool::getApplication();
+    if (!app) return;
 
-    m_painting.myPaint.strokeSegmentRect.empty();
-    m_painting.myPaint.brush->strokeTo(point, pressure, TPointD(), restartBrushTimer());
-    TRect updateRect = m_painting.myPaint.strokeSegmentRect * ras->getBounds();
-    if (!updateRect.isEmpty()) {
-      m_painting.myPaint.brush->updateDrawing( ras, m_backupRas, m_painting.myPaint.strokeSegmentRect,
-                                               m_painting.styleId, m_modifierLockAlpha.getValue() );
-    }
-    m_painting.lastRect = m_painting.myPaint.strokeRect;
-
-    TPointD thickOffset(m_maxCursorThick * 0.5, m_maxCursorThick * 0.5);
-    invalidateRect = convert(m_painting.myPaint.strokeSegmentRect) - rasCenter;
-    invalidateRect +=
-        TRectD(centeredPos - thickOffset, centeredPos + thickOffset);
-    invalidateRect +=
-        TRectD(m_brushPos - thickOffset, m_brushPos + thickOffset);
-  } else
-  if (m_painting.pencil.brush) {
-    /*-- Pencilモードでなく、Hardness=100 の場合のブラシサイズを1段階下げる
-     * --*/
-    if (!m_painting.pencil.realPencil) thickness -= 1.0;
+    int col   = app->getCurrentColumn()->getColumnIndex();
+    m_enabled = col >= 0 || app->getCurrentFrame()->isEditingLevel();
+    // todo: gestire autoenable
+    if (!m_enabled) return;
 
-    TThickPoint thickPoint(centeredPos + rasCenter, thickness);
-    std::vector<TThickPoint> pts;
-    if (m_painting.smooth) {
-      pts.push_back(thickPoint);
+    m_painting.active = !!getImage(true);
+    if (!m_painting.active)
+      m_painting.active = !!touchImage();
+    if (!m_painting.active)
+      return;
+    
+    // nel caso che il colore corrente sia un cleanup/studiopalette color
+    // oppure il colore di un colorfield
+    updateCurrentStyle();
+    if (TColorStyle *cs = app->getCurrentLevelStyle()) {
+      m_painting.styleId = app->getCurrentLevelStyleIndex();
+      TRasterStyleFx *rfx = cs->getRasterStyleFx();
+      if (!cs->isStrokeStyle() && (!rfx || !rfx->isInkStyle()))
+          { m_painting.active = false; return; }
     } else {
-      m_painting.smoothStroke.addPoint(thickPoint);
-      m_painting.smoothStroke.getSmoothPoints(pts);
+      m_painting.styleId = 1;
     }
-    for (size_t i = 0; i < pts.size(); ++i) {
-      const TThickPoint &thickPoint = pts[i];
-      m_painting.pencil.brush->add( thickPoint);
-      m_painting.tileSaver->save( m_painting.pencil.brush->getLastRect() );
-      m_painting.pencil.brush->generateLastPieceOfStroke( m_painting.pencil.realPencil );
-      std::vector<TThickPoint> brushPoints = m_painting.pencil.brush->getPointsSequence();
-      int m                                = (int)brushPoints.size();
-      std::vector<TThickPoint> points;
-      if (m == 3) {
-        points.push_back(brushPoints[0]);
-        points.push_back(brushPoints[1]);
-      } else {
-        points.push_back(brushPoints[m - 4]);
-        points.push_back(brushPoints[m - 3]);
-        points.push_back(brushPoints[m - 2]);
-      }
-      invalidateRect += ToolUtils::getBounds(points, maxThickness) - rasCenter;
-    }
-  } else {
-    // antialiased brush
-    assert(m_painting.blured.brush);
-    assert(m_workRas.getPointer() && m_backupRas.getPointer());
-    TThickPoint thickPoint(centeredPos + rasCenter, thickness);
-    std::vector<TThickPoint> pts;
-    if (m_painting.smooth) {
-      pts.push_back(thickPoint);
+    
+    m_painting.frameId = getFrameId();
+
+    TImageP img = getImage(true);
+    TToonzImageP ri(img);
+    TRasterCM32P ras = ri->getRaster();
+    if (!ras)
+      { m_painting.active = false; return; }
+      
+    m_painting.tileSet   = new TTileSetCM32(ras->getSize());
+    m_painting.tileSaver = new TTileSaverCM32(ras, m_painting.tileSet);
+    m_painting.affectedRect.empty();
+    setWorkAndBackupImages();
+    
+    if (m_isMyPaintStyleSelected) {
+      // init myPaint drawing
+      
+      m_painting.myPaint.isActive = true;
+      m_painting.myPaint.strokeSegmentRect.empty();
+      
+      m_workRas->lock();
+      
+      // prepare base brush
+      if ( TMyPaintBrushStyle *mypaintStyle = dynamic_cast<TMyPaintBrushStyle *>(app->getCurrentLevelStyle()) )
+        m_painting.myPaint.baseBrush.fromBrush( mypaintStyle->getBrush() ); else
+          m_painting.myPaint.baseBrush.fromDefaults();
+      double modifierSize = m_modifierSize.getValue() * log(2.0);
+      float baseSize = m_painting.myPaint.baseBrush.getBaseValue( MYPAINT_BRUSH_SETTING_RADIUS_LOGARITHMIC );
+      m_painting.myPaint.baseBrush.setBaseValue( MYPAINT_BRUSH_SETTING_RADIUS_LOGARITHMIC, baseSize + modifierSize );
+    } else
+    if (m_hardness.getValue() == 100 || m_pencil.getValue()) {
+      // init pencil drawing
+      
+      m_painting.pencil.isActive = true;
+      m_painting.pencil.realPencil = m_pencil.getValue();
     } else {
-      m_painting.smoothStroke.addPoint(thickPoint);
-      m_painting.smoothStroke.getSmoothPoints(pts);
+      // init blured brush drawing (regular drawing)
+      
+      m_painting.blured.isActive = true;
     }
-    for (size_t i = 0; i < pts.size(); ++i) {
-      TThickPoint old = m_painting.blured.points.back();
-
-      const TThickPoint &point = pts[i];
-      TThickPoint mid((old + point) * 0.5, (point.thick + old.thick) * 0.5);
-      m_painting.blured.points.push_back(mid);
-      m_painting.blured.points.push_back(point);
-
-      TRect bbox;
-      int m = (int)m_painting.blured.points.size();
-      std::vector<TThickPoint> points;
-      if (m == 3) {
-        // ho appena cominciato. devo disegnare un segmento
-        TThickPoint pa = m_painting.blured.points.front();
-        points.push_back(pa);
-        points.push_back(mid);
-        bbox = m_painting.blured.brush->getBoundFromPoints(points);
-        updateWorkAndBackupRasters(bbox + m_painting.lastRect);
-        m_painting.tileSaver->save(bbox);
-        m_painting.blured.brush->addArc(pa, (mid + pa) * 0.5, mid, 1, 1);
-        m_painting.lastRect += bbox;
-      } else {
-        points.push_back(m_painting.blured.points[m - 4]);
-        points.push_back(old);
-        points.push_back(mid);
-        bbox = m_painting.blured.brush->getBoundFromPoints(points);
-        updateWorkAndBackupRasters(bbox + m_painting.lastRect);
-        m_painting.tileSaver->save(bbox);
-        m_painting.blured.brush->addArc( m_painting.blured.points[m - 4], old, mid, 1, 1 );
-        m_painting.lastRect += bbox;
-      }
-      invalidateRect += ToolUtils::getBounds(points, maxThickness) - rasCenter;
-
-      m_painting.blured.brush->updateDrawing( ti->getRaster(), m_backupRas, bbox,
-                                                    m_painting.styleId, m_drawOrder.getIndex(),
-                                                    m_modifierLockAlpha.getValue() );
+    
+  } else {
+    // finish painting
+    
+    if (m_painting.myPaint.isActive) {
+      // finish myPaint drawing
+      m_workRas->unlock();
     }
-  }
 
-  // clear & draw brush tip when drawing smooth stroke
-  if (m_painting.smooth) {
-    TPointD halfThick(m_maxThick * 0.5, m_maxThick * 0.5);
-    invalidateRect += TRectD(m_brushPos - halfThick, m_brushPos + halfThick);
-    invalidateRect += TRectD(centeredPos - halfThick, centeredPos + halfThick);
-  }
+    delete m_painting.tileSaver;
+    m_painting.tileSaver = nullptr;
 
-  m_mousePos = pos;
-  m_brushPos = getCenteredCursorPos(pos);
+    // add undo record
+    TFrameId frameId = m_painting.frameId.isEmptyFrame() ? getCurrentFid() : m_painting.frameId;
+    if (m_painting.tileSet->getTileCount() > 0) {
+      TTool::Application *app   = TTool::getApplication();
+      TXshLevel *level          = app->getCurrentLevel()->getLevel();
+      TXshSimpleLevelP simLevel = level->getSimpleLevel();
+      TRasterCM32P ras          = TToonzImageP( getImage(true) )->getRaster();
+      TRasterCM32P subras       = ras->extract(m_painting.affectedRect)->clone();
+      TUndoManager::manager()->add(new MyPaintBrushUndo(
+          m_painting.tileSet, simLevel.getPointer(), frameId, m_isFrameCreated,
+          m_isLevelCreated, subras, m_painting.affectedRect.getP00()));
+      // MyPaintBrushUndo will delete tileSet by it self
+    } else {
+      // delete tileSet here because MyPaintBrushUndo will not do it
+      delete m_painting.tileSet;
+    }
+    m_painting.tileSet = nullptr;
 
-  invalidate(invalidateRect.enlarge(2));
-}
+    /*-- 作業中のフレームをリセット --*/
+    m_painting.frameId = TFrameId();
 
-//---------------------------------------------------------------------------------------------------------------
 
-void ToonzRasterBrushTool::leftButtonUp(const TPointD &pos,
-                                        const TMouseEvent &e) {
-  bool isValid = m_enabled && m_painting.active;
-  m_enabled = false;
-  m_painting.active = false;
-  if (!isValid) {
-    return;
+    m_painting.myPaint.isActive = false;
+    m_painting.pencil.isActive = false;
+    m_painting.blured.isActive = false;
+    m_painting.active = false;
+    
+    /*-- FIdを指定して、描画中にフレームが動いても、
+      描画開始時のFidのサムネイルが更新されるようにする。--*/
+    notifyImageChanged(frameId);
+    ToolUtils::updateSaveBox();
   }
-  TPointD centeredPos;
-  if (m_painting.straight.isStraight)
-    centeredPos = getCenteredCursorPos(m_painting.straight.lastPoint);
-  else
-    centeredPos = getCenteredCursorPos(pos);
-
-  double pressure;
-  if (m_isMyPaintStyleSelected)  // mypaint brush case
-    pressure = m_pressure.getValue() && e.isTablet() ? e.m_pressure : 0.5;
-  else
-    pressure = m_pressure.getValue() ? e.m_pressure : 1.0;
-
-  if (m_painting.straight.isStraight && m_painting.straight.maxPressure > 0.0) pressure = m_painting.straight.maxPressure;
-
-  finishRasterBrush(centeredPos, pressure);
-  int tc = ToonzCheck::instance()->getChecks();
-  if (tc & ToonzCheck::eGap || tc & ToonzCheck::eAutoclose || m_painting.straight.isStraight)
-    invalidate();
-
-  m_painting.straight.isStraight  = false;
-  m_painting.straight.maxPressure = -1.0;
 }
 
-//---------------------------------------------------------------------------------------------------------------
-/*!
- * ドラッグ中にツールが切り替わった場合に備え、onDeactivate時とMouseRelease時にと同じ終了処理を行う
- */
-void ToonzRasterBrushTool::finishRasterBrush(const TPointD &pos,
-                                             double pressureVal) {
-  TToonzImageP ti = TImageP(getImage(true));
-
-  if (!ti) return;
+//--------------------------------------------------------------------------------------------------
 
-  TPointD rasCenter         = ti->getRaster()->getCenterD();
-  TTool::Application *app   = TTool::getApplication();
-  TXshLevel *level          = app->getCurrentLevel()->getLevel();
-  TXshSimpleLevelP simLevel = level->getSimpleLevel();
-
-  /*--
-   * 描画中にカレントフレームが変わっても、描画開始時のFidに対してUndoを記録する
-   * --*/
-  TFrameId frameId =
-      m_workingFrameId.isEmptyFrame() ? getCurrentFid() : m_workingFrameId;
-  if (m_painting.myPaint.brush) {
-    TRasterCM32P ras = ti->getRaster();
-    TPointD point(pos + rasCenter);
-    double pressure = m_pressure.getValue() ? pressureVal : 0.5;
+void ToonzRasterBrushTool::inputPaintTrackPoint(const TTrackPoint &point, const TTrack &track, bool firstTrack) {
+  if (!m_painting.active)
+    return;
+  
+  TImageP img = getImage(true);
+  TToonzImageP ri(img);
+  TRasterCM32P ras = ri->getRaster();
+  if (!ras)
+    return;
+  TPointD rasCenter = ras->getCenterD();
+  
 
+  TRectD invalidateRect;
+  bool firstPoint = track.size() == track.pointsAdded;
+  bool lastPoint  = track.pointsAdded == 1 && track.finished();
+  
+  // first point must be without handler, following points must be with handler
+  // other behaviour is possible bug and must be ignored
+  assert(firstPoint == !track.toolHandler);
+  if (firstPoint != !track.toolHandler)
+    return;
+  
+  if (m_painting.myPaint.isActive) {
+    // mypaint case
+    
+    // init brush
+    MyPaintStroke *handler;
+    if (firstPoint) {
+      handler = new MyPaintStroke(m_workRas, *this, m_painting.myPaint.baseBrush, false);
+      handler->brush.beginStroke();
+      track.toolHandler = handler;
+    }
+    handler = dynamic_cast<MyPaintStroke*>(track.toolHandler.getPointer());
+    if (!handler) return;
+    
+    // paint stroke
     m_painting.myPaint.strokeSegmentRect.empty();
-    m_painting.myPaint.brush->strokeTo(point, pressure, TPointD(), restartBrushTimer());
-    m_painting.myPaint.brush->endStroke();
+    handler->brush.strokeTo(point.position + rasCenter, point.pressure, point.tilt, point.time);
+    if (lastPoint)
+      handler->brush.endStroke();
+    
+    // update affected area
     TRect updateRect = m_painting.myPaint.strokeSegmentRect * ras->getBounds();
-    if (!updateRect.isEmpty()) {
-      m_painting.myPaint.brush->updateDrawing( ras, m_backupRas, m_painting.myPaint.strokeSegmentRect,
-                                               m_painting.styleId, m_modifierLockAlpha.getValue() );
-    }
-    TPointD thickOffset(m_maxCursorThick * 0.5,
-                        m_maxCursorThick * 0.5);  // TODO
-    TRectD invalidateRect = convert(m_painting.myPaint.strokeSegmentRect) - rasCenter;
-    invalidateRect += TRectD(pos - thickOffset, pos + thickOffset);
-    invalidate(invalidateRect.enlarge(2.0));
-
-    delete m_painting.myPaint.brush;
-    m_painting.myPaint.brush = nullptr;
-
-    m_painting.lastRect.empty();
-    m_workRas->unlock();
-
-    if (m_painting.tileSet->getTileCount() > 0) {
-      TRasterCM32P subras = ras->extract(m_painting.myPaint.strokeRect)->clone();
-      TUndoManager::manager()->add(new MyPaintBrushUndo(
-          m_painting.tileSet, simLevel.getPointer(), frameId, m_isFrameCreated,
-          m_isLevelCreated, subras, m_painting.myPaint.strokeRect.getP00()));
-    }
-
+    m_painting.affectedRect += updateRect;
+    if (!updateRect.isEmpty())
+      handler->brush.updateDrawing( ras, m_backupRas, m_painting.myPaint.strokeSegmentRect,
+                                    m_painting.styleId, m_modifierLockAlpha.getValue() );
+    
+    // determine invalidate rect
+    invalidateRect += convert(m_painting.myPaint.strokeSegmentRect) - rasCenter;
   } else
-  if (m_painting.pencil.brush) {
-    double thickness = m_pressure.getValue()
-                           ? computeThickness(pressureVal, m_rasThickness) * 2
-                           : m_rasThickness.getValue().second;
-
-    if (!m_painting.straight.isStraight) {
-      // ストロークの最初にMaxサイズの円が描かれてしまう不具合を防止する
-      if (m_pressure.getValue() && pressureVal == 1.0)
-        thickness = m_rasThickness.getValue().first;
-
-      // Pencilモードでなく、Hardness=100 の場合のブラシサイズを1段階下げる
-      if (!m_painting.pencil.realPencil) thickness -= 1.0;
-    }
-
-    TRectD invalidateRect;
-    TThickPoint thickPoint(pos + rasCenter, thickness);
-    std::vector<TThickPoint> pts;
-    if (m_painting.smooth || m_painting.straight.isStraight) {
-      pts.push_back(thickPoint);
-    } else {
-      m_painting.smoothStroke.addPoint(thickPoint);
-      m_painting.smoothStroke.endStroke();
-      m_painting.smoothStroke.getSmoothPoints(pts);
-    }
-    for (size_t i = 0; i < pts.size(); ++i) {
-      const TThickPoint &thickPoint = pts[i];
-      m_painting.pencil.brush->add( thickPoint );
-      m_painting.tileSaver->save( m_painting.pencil.brush->getLastRect( m_painting.straight.isStraight) );
-      m_painting.pencil.brush->generateLastPieceOfStroke(
-        m_painting.pencil.realPencil, true, m_painting.straight.isStraight);
-
-      std::vector<TThickPoint> brushPoints = m_painting.pencil.brush->getPointsSequence();
-      int m                                = (int)brushPoints.size();
-      std::vector<TThickPoint> points;
-      if (m_painting.straight.isStraight) {
-        points.push_back(brushPoints[0]);
-        points.push_back(brushPoints[2]);
-      } else if (m == 3) {
-        points.push_back(brushPoints[0]);
-        points.push_back(brushPoints[1]);
-      } else {
-        points.push_back(brushPoints[m - 4]);
-        points.push_back(brushPoints[m - 3]);
-        points.push_back(brushPoints[m - 2]);
+  if (m_painting.pencil.isActive) {
+    // pencil case
+    
+    // Pencilモードでなく、Hardness=100 の場合のブラシサイズを1段階下げる
+    double thickness = computeThickness(point.pressure, m_rasThickness)*2;
+    //if (!m_painting.pencil.realPencil && !m_painting.straight.isStraight)
+    //  thickness -= 1.0;
+    TThickPoint thickPoint(point.position + rasCenter, thickness);
+
+    // init brush
+    PencilStroke *handler;
+    if (firstPoint) {
+      DrawOrder drawOrder = (DrawOrder)m_drawOrder.getIndex();
+      handler = new PencilStroke( ras, BRUSH, NONE, m_painting.styleId, thickPoint, drawOrder != OverAll, 0,
+                                  m_modifierLockAlpha.getValue(), !m_painting.pencil.realPencil,
+                                  drawOrder == PaletteOrder );
+      
+      // if the drawOrder mode = "Palette Order",
+      // get styleId list which is above the current style in the palette
+      if (drawOrder == PaletteOrder) {
+        QSet<int> aboveStyleIds;
+        getAboveStyleIdSet(m_painting.styleId, ri->getPalette(), aboveStyleIds);
+        handler->brush.setAboveStyleIds(aboveStyleIds);
       }
-      double maxThickness = m_rasThickness.getValue().second;
-      invalidateRect += ToolUtils::getBounds(points, maxThickness) - rasCenter;
-    }
-    invalidate(invalidateRect.enlarge(2));
-
-    if (m_painting.tileSet->getTileCount() > 0) {
-      TUndoManager::manager()->add(new RasterBrushUndo(
-          m_painting.tileSet, m_painting.pencil.brush->getPointsSequence(),
-          m_painting.pencil.brush->getStyleId(), m_painting.pencil.brush->isSelective(),
-          simLevel.getPointer(), frameId, m_painting.pencil.realPencil, m_isFrameCreated,
-          m_isLevelCreated, m_painting.pencil.brush->isPaletteOrder(),
-          m_painting.pencil.brush->isAlphaLocked(), m_painting.straight.isStraight));
+      track.toolHandler = handler;
     }
-    delete m_painting.pencil.brush;
-    m_painting.pencil.brush = nullptr;
-  } else {
-    assert(m_painting.blured.brush);
-    double maxThickness = m_rasThickness.getValue().second;
-    double thickness    = (m_pressure.getValue())
-                              ? computeThickness(pressureVal, m_rasThickness) * 2
-                              : maxThickness;
-    TPointD rasCenter   = ti->getRaster()->getCenterD();
-    TRectD invalidateRect;
-    TThickPoint thickPoint(pos + rasCenter, thickness);
-    std::vector<TThickPoint> pts;
-    if (m_painting.smooth || m_painting.straight.isStraight) {
-      pts.push_back(thickPoint);
-    } else {
-      m_painting.smoothStroke.addPoint(thickPoint);
-      m_painting.smoothStroke.endStroke();
-      m_painting.smoothStroke.getSmoothPoints(pts);
-    }
-    // we need to skip the for-loop here if pts.size() == 0 or else
-    // (pts.size() - 1) becomes ULLONG_MAX since size_t is unsigned
-    if (pts.size() > 0) {
-      // this doesn't get run for a straight line
-      for (size_t i = 0; i < pts.size() - 1; ++i) {
-        TThickPoint old = m_painting.blured.points.back();
-
-        const TThickPoint &point = pts[i];
-        TThickPoint mid((old + point) * 0.5, (point.thick + old.thick) * 0.5);
-        m_painting.blured.points.push_back(mid);
-        m_painting.blured.points.push_back(point);
-
-        TRect bbox;
-        int m = (int)m_painting.blured.points.size();
-        std::vector<TThickPoint> points;
-        if (m == 3) {
-          // ho appena cominciato. devo disegnare un segmento
-          TThickPoint pa = m_painting.blured.points.front();
-          points.push_back(pa);
-          points.push_back(mid);
-          bbox = m_painting.blured.brush->getBoundFromPoints(points);
-          updateWorkAndBackupRasters(bbox + m_painting.lastRect);
-          m_painting.tileSaver->save(bbox);
-          m_painting.blured.brush->addArc(pa, (mid + pa) * 0.5, mid, 1, 1);
-          m_painting.lastRect += bbox;
-        } else {
-          points.push_back(m_painting.blured.points[m - 4]);
-          points.push_back(old);
-          points.push_back(mid);
-          bbox = m_painting.blured.brush->getBoundFromPoints(points);
-          updateWorkAndBackupRasters(bbox + m_painting.lastRect);
-          m_painting.tileSaver->save(bbox);
-          m_painting.blured.brush->addArc(m_painting.blured.points[m - 4], old, mid, 1, 1);
-          m_painting.lastRect += bbox;
-        }
-
-        invalidateRect +=
-            ToolUtils::getBounds(points, maxThickness) - rasCenter;
+    handler = dynamic_cast<PencilStroke*>(track.toolHandler.getPointer());
+    if (!handler) return;
+
+    // paint stroke
+    if (!firstPoint)
+      handler->brush.add(thickPoint);
+    
+    // update affected area
+    TRect strokeRect = handler->brush.getLastRect() * ras->getBounds();
+    m_painting.tileSaver->save( strokeRect );
+    m_painting.affectedRect += strokeRect;
+    handler->brush.generateLastPieceOfStroke( m_painting.pencil.realPencil );
+    
+    // determine invalidate rect
+    std::vector<TThickPoint> points = handler->brush.getPointsSequence();
+    int m = (int)points.size() - 3;
+    if (m > 0)
+      points.erase(points.begin(), points.begin() + m);
+    invalidateRect += ToolUtils::getBounds(points, m_rasThickness.getValue().second) - rasCenter;
+  } else
+  if (m_painting.blured.isActive) {
+    // blured brush case (aka regular brush)
 
-        m_painting.blured.brush->updateDrawing( ti->getRaster(), m_backupRas, bbox,
-                                                      m_painting.styleId, m_drawOrder.getIndex(),
-                                                      m_modifierLockAlpha.getValue() );
-      }
-      if (!m_painting.straight.isStraight && m_painting.blured.points.size() > 1) {
-        TThickPoint point = pts.back();
-        m_painting.blured.points.push_back(point);
-      }
-      int m = m_painting.blured.points.size();
-      std::vector<TThickPoint> points;
-      if (!m_painting.straight.isStraight && m_painting.blured.points.size() > 1) {
-        points.push_back( m_painting.blured.points[m - 3] );
-        points.push_back( m_painting.blured.points[m - 2] );
-        points.push_back( m_painting.blured.points[m - 1] );
-      } else {
-        const TThickPoint point = m_painting.blured.points[0];
-        TThickPoint mid((thickPoint + point) * 0.5,
-                        (point.thick + thickPoint.thick) * 0.5);
-        m_painting.blured.points.push_back(mid);
-        m_painting.blured.points.push_back(thickPoint);
-        points.push_back( m_painting.blured.points[0] );
-        points.push_back( m_painting.blured.points[1] );
-        points.push_back( m_painting.blured.points[2] );
+    double maxThick = m_rasThickness.getValue().second;
+    DrawOrder drawOrder = (DrawOrder)m_drawOrder.getIndex();
+    
+    // init brush
+    BluredStroke *handler;
+    if (firstPoint) {
+      handler = new BluredStroke(m_workRas, maxThick, m_brushPad, false);
+      // if the drawOrder mode = "Palette Order",
+      // get styleId list which is above the current style in the palette
+      if (drawOrder == PaletteOrder) {
+        QSet<int> aboveStyleIds;
+        getAboveStyleIdSet(m_painting.styleId, ri->getPalette(), aboveStyleIds);
+        handler->brush.setAboveStyleIds(aboveStyleIds);
       }
-      TRect bbox = m_painting.blured.brush->getBoundFromPoints(points);
-      updateWorkAndBackupRasters(bbox);
-      m_painting.tileSaver->save(bbox);
-      m_painting.blured.brush->addArc( points[0], points[1], points[2], 1, 1 );
-      m_painting.blured.brush->updateDrawing( ti->getRaster(), m_backupRas, bbox,
-                                                    m_painting.styleId, m_drawOrder.getIndex(),
-                                                    m_modifierLockAlpha.getValue() );
-
-      invalidateRect += ToolUtils::getBounds(points, maxThickness) - rasCenter;
-
-      m_painting.lastRect += bbox;
-    }
-    if (!invalidateRect.isEmpty()) invalidate(invalidateRect.enlarge(2));
-    m_painting.lastRect.empty();
-
-    delete m_painting.blured.brush;
-    m_painting.blured.brush = nullptr;
-
-    if (m_painting.tileSet->getTileCount() > 0) {
-      TUndoManager::manager()->add(new RasterBluredBrushUndo(
-          m_painting.tileSet, m_painting.blured.points, m_painting.styleId, (DrawOrder)m_drawOrder.getIndex(),
-          m_modifierLockAlpha.getValue(), simLevel.getPointer(), frameId,
-          m_rasThickness.getValue().second, m_hardness.getValue() * 0.01,
-          m_isFrameCreated, m_isLevelCreated, m_painting.straight.isStraight));
+      track.toolHandler = handler;
     }
+    handler = dynamic_cast<BluredStroke*>(track.toolHandler.getPointer());
+    if (!handler) return;
+
+    // paint stroke
+    double radius = computeThickness(point.pressure, m_rasThickness);
+    TThickPoint thickPoint(point.position + rasCenter, radius*2);
+    TRect strokeRect( tfloor(thickPoint.x - maxThick - 0.999),
+                      tfloor(thickPoint.y - maxThick - 0.999),
+                      tceil(thickPoint.x + maxThick + 0.999),
+                      tceil(thickPoint.y + maxThick + 0.999) );
+    strokeRect *= ras->getBounds();
+    m_painting.affectedRect += strokeRect;
+    updateWorkAndBackupRasters(m_painting.affectedRect);
+    m_painting.tileSaver->save(strokeRect);
+    handler->brush.addPoint(thickPoint, 1, !lastPoint);
+    handler->brush.updateDrawing( ras, m_backupRas, strokeRect,
+                                  m_painting.styleId, drawOrder,
+                                  m_modifierLockAlpha.getValue() );
+    
+    invalidateRect += convert(strokeRect) - rasCenter;
   }
-  delete m_painting.tileSaver;
-  m_painting.tileSaver = nullptr;
-
-  /*-- FIdを指定して、描画中にフレームが動いても、
-    描画開始時のFidのサムネイルが更新されるようにする。--*/
-  notifyImageChanged(frameId);
 
-  ToolUtils::updateSaveBox();
-
-  /*-- 作業中のフレームをリセット --*/
-  m_workingFrameId = TFrameId();
+  // invalidate rect
+  if (firstTrack) {
+    // for the first track we will paint cursor circle
+    // here we will invalidate rects for it
+    TPointD thickOffset(m_maxCursorThick*0.5, m_maxCursorThick*0.5);
+    invalidateRect += TRectD(m_brushPos - thickOffset, m_brushPos + thickOffset);
+    invalidateRect += TRectD(point.position - thickOffset, point.position + thickOffset);
+    m_brushPos = m_mousePos = point.position;
+  }
+  invalidate(invalidateRect.enlarge(2));
 }
+
 //---------------------------------------------------------------------------------------------------------------
-// 明日はここをMyPaintのときにカーソルを消せるように修正する!!!!!!
-void ToonzRasterBrushTool::mouseMove(const TPointD &pos, const TMouseEvent &e) {
-  qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
 
+// 明日はここをMyPaintのときにカーソルを消せるように修正する!!!!!!
+void ToonzRasterBrushTool::inputMouseMove(const TPointD &position, const TInputState &state) {
   struct Locals {
     ToonzRasterBrushTool *m_this;
 
@@ -1914,23 +1561,18 @@ void ToonzRasterBrushTool::mouseMove(const TPointD &pos, const TMouseEvent &e) {
 
   } locals = {this};
 
-  // if (e.isAltPressed() && !e.isCtrlPressed()) {
-  // const TPointD &diff = pos - m_mousePos;
-  // double add = (fabs(diff.x) > fabs(diff.y)) ? diff.x : diff.y;
-
-  // locals.addMinMax(
-  //  TToonzImageP(getImage(false, 1)) ? m_rasThickness : m_thickness, add);
-  //} else
-
   double thickness =
       (m_isMyPaintStyleSelected) ? (double)(m_maxCursorThick + 1) : m_maxThick;
   TPointD halfThick(thickness * 0.5, thickness * 0.5);
   TRectD invalidateRect(m_brushPos - halfThick, m_brushPos + halfThick);
 
-  if (e.isCtrlPressed() && e.isAltPressed() && !e.isShiftPressed() &&
-      Preferences::instance()->useCtrlAltToResizeBrushEnabled()) {
+  if ( Preferences::instance()->useCtrlAltToResizeBrushEnabled()
+    && state.isKeyPressed(TKey::control)
+    && state.isKeyPressed(TKey::alt)
+    && !state.isKeyPressed(TKey::shift) )
+  {
     // Resize the brush if CTRL+ALT is pressed and the preference is enabled.
-    const TPointD &diff = pos - m_mousePos;
+    const TPointD &diff = position - m_mousePos;
     double max          = diff.x / 2;
     double min          = diff.y / 2;
 
@@ -1941,10 +1583,10 @@ void ToonzRasterBrushTool::mouseMove(const TPointD &pos, const TMouseEvent &e) {
                              m_brushPos + TPointD(radius, radius));
 
   } else {
-    m_mousePos = pos;
-    m_brushPos = getCenteredCursorPos(pos);
+    m_mousePos = position;
+    m_brushPos = getCenteredCursorPos(position);
 
-    invalidateRect += TRectD(pos - halfThick, pos + halfThick);
+    invalidateRect += TRectD(position - halfThick, position + halfThick);
   }
 
   invalidate(invalidateRect.enlarge(2));
@@ -2005,21 +1647,16 @@ void ToonzRasterBrushTool::draw() {
     drawEmptyCircle(m_brushPos, tround(m_maxThick), true, true,
                     m_pencil.getValue());
   }
+  
+  m_inputmanager.draw();
 }
 
 //--------------------------------------------------------------------------------------------------------------
 
 void ToonzRasterBrushTool::onEnter() {
-  TImageP img = getImage(false);
-
   m_minThick = m_rasThickness.getValue().first;
   m_maxThick = m_rasThickness.getValue().second;
   updateCurrentStyle();
-
-  Application *app = getApplication();
-
-  m_painting.styleId = app->getCurrentLevelStyleIndex();
-  m_painting.active = img;
 }
 
 //----------------------------------------------------------------------------------------------------------
@@ -2043,7 +1680,6 @@ TPropertyGroup *ToonzRasterBrushTool::getProperties(int idx) {
 
 void ToonzRasterBrushTool::onImageChanged() {
   if (!isEnabled()) return;
-
   setWorkAndBackupImages();
 }
 
@@ -2055,22 +1691,57 @@ void ToonzRasterBrushTool::setWorkAndBackupImages() {
   TRasterP ras   = ti->getRaster();
   TDimension dim = ras->getSize();
 
-  double hardness = m_hardness.getValue() * 0.01;
-  if (!m_isMyPaintStyleSelected && hardness == 1.0 &&
-      ras->getPixelSize() == 4) {
-    m_workRas   = TRaster32P();
-    m_backupRas = TRasterCM32P();
+  if (!m_workRas || m_workRas->getLx() < dim.lx || m_workRas->getLy() < dim.ly)
+    m_workRas = TRaster32P(dim);
+  if (!m_backupRas || m_backupRas->getLx() < dim.lx || m_backupRas->getLy() < dim.ly)
+    m_backupRas = TRasterCM32P(dim);
+
+  m_workBackupRect.empty();
+}
+
+//---------------------------------------------------------------------------------------------------
+
+void ToonzRasterBrushTool::updateWorkAndBackupRasters(const TRect &rect) {
+  TToonzImageP ti = TImageP(getImage(false, 1));
+  if (!ti) return;
+  TRasterCM32P ras = ti->getRaster();
+
+  // work and backup rect will additionaly enlarged to 1/8 of it size
+  // in each affected direction to predict future possible enlargements in this direction
+  const int denominator = 8;
+  TRect enlargedRect    = rect + m_workBackupRect;
+  int dx                = (enlargedRect.getLx() - 1) / denominator + 1;
+  int dy                = (enlargedRect.getLy() - 1) / denominator + 1;
+
+  if (m_workBackupRect.isEmpty()) {
+    enlargedRect.x0 -= dx;
+    enlargedRect.y0 -= dy;
+    enlargedRect.x1 += dx;
+    enlargedRect.y1 += dy;
+
+    enlargedRect *= ras->getBounds();
+    if (enlargedRect.isEmpty()) return;
+
+    m_workRas->extract(enlargedRect)->copy(ras->extract(enlargedRect));
+    m_backupRas->extract(enlargedRect)->copy(ras->extract(enlargedRect));
   } else {
-    if (!m_workRas || m_workRas->getLx() > dim.lx ||
-        m_workRas->getLy() > dim.ly)
-      m_workRas = TRaster32P(dim);
-    if (!m_backupRas || m_backupRas->getLx() > dim.lx ||
-        m_backupRas->getLy() > dim.ly)
-      m_backupRas = TRasterCM32P(dim);
-
-    m_painting.myPaint.strokeRect.empty();
-    m_painting.lastRect.empty();
+    if (enlargedRect.x0 < m_workBackupRect.x0) enlargedRect.x0 -= dx;
+    if (enlargedRect.y0 < m_workBackupRect.y0) enlargedRect.y0 -= dy;
+    if (enlargedRect.x1 > m_workBackupRect.x1) enlargedRect.x1 += dx;
+    if (enlargedRect.y1 > m_workBackupRect.y1) enlargedRect.y1 += dy;
+
+    enlargedRect *= ras->getBounds();
+    if (enlargedRect.isEmpty()) return;
+
+    TRect lastRect     = m_workBackupRect * ras->getBounds();
+    QList<TRect> rects = ToolUtils::splitRect(enlargedRect, lastRect);
+    for (int i = 0; i < rects.size(); i++) {
+      m_workRas->extract(rects[i])->copy(ras->extract(rects[i]));
+      m_backupRas->extract(rects[i])->copy(ras->extract(rects[i]));
+    }
   }
+
+  m_workBackupRect = enlargedRect;
 }
 
 //------------------------------------------------------------------
@@ -2258,14 +1929,8 @@ bool ToonzRasterBrushTool::isPencilModeActive() {
 //------------------------------------------------------------------
 
 void ToonzRasterBrushTool::onColorStyleChanged() {
-  // in case the style switched while drawing
-  if (m_painting.tileSaver) {
-    bool isValid = m_enabled && m_painting.active;
-    m_enabled    = false;
-    if (isValid) {
-      finishRasterBrush(m_mousePos, 1);
-    }
-  }
+  m_inputmanager.finishTracks();
+  m_enabled = false;
 
   TTool::Application *app = getApplication();
   TMyPaintBrushStyle *mpbs =
diff --git a/toonz/sources/tnztools/toonzrasterbrushtool.h b/toonz/sources/tnztools/toonzrasterbrushtool.h
index 2b9875c..4f6ef26 100644
--- a/toonz/sources/tnztools/toonzrasterbrushtool.h
+++ b/toonz/sources/tnztools/toonzrasterbrushtool.h
@@ -3,15 +3,27 @@
 #ifndef TOONZRASTERBRUSHTOOL_H
 #define TOONZRASTERBRUSHTOOL_H
 
-#include "tgeometry.h"
-#include "tproperty.h"
-#include "trasterimage.h"
-#include "ttoonzimage.h"
-#include "tstroke.h"
-#include "toonz/strokegenerator.h"
-
-#include "tools/tool.h"
-#include "tools/cursors.h"
+#include <tgeometry.h>
+#include <tproperty.h>
+#include <trasterimage.h>
+#include <ttoonzimage.h>
+#include <tstroke.h>
+#include <toonz/strokegenerator.h>
+#include <toonz/rasterstrokegenerator.h>
+
+#include <tools/tool.h>
+#include <tools/cursors.h>
+
+#include <tools/inputmanager.h>
+#include <tools/modifiers/modifierline.h>
+#include <tools/modifiers/modifiertangents.h>
+#include <tools/modifiers/modifierassistants.h>
+#include <tools/modifiers/modifiersegmentation.h>
+#ifndef NDEBUG
+#include <tools/modifiers/modifiertest.h>
+#endif
+
+#include "bluredbrush.h"
 #include "mypainttoonzbrush.h"
 
 #include <QCoreApplication>
@@ -118,7 +130,9 @@ private:
 //   Toonz Raster Brush Tool declaration
 //************************************************************************
 
-class ToonzRasterBrushTool final : public TTool, public RasterController {
+class ToonzRasterBrushTool final : public TTool,
+                                   public RasterController,
+                                   public TInputHandler {
   Q_DECLARE_TR_FUNCTIONS(ToonzRasterBrushTool)
 
   void updateCurrentStyle();
@@ -142,6 +156,14 @@ public:
   void leftButtonUp(const TPointD &pos, const TMouseEvent &e) override;
   void mouseMove(const TPointD &pos, const TMouseEvent &e) override;
 
+  void inputMouseMove(const TPointD &position,
+                      const TInputState &state) override;
+  void inputSetBusy(bool busy) override;
+  void inputPaintTrackPoint(const TTrackPoint &point, const TTrack &track,
+                            bool firstTrack) override;
+  void inputInvalidateRect(const TRectD &bounds) override { invalidate(bounds); }
+  TTool *inputGetTool() override { return this; };
+
   void draw() override;
 
   void onEnter() override;
@@ -162,7 +184,6 @@ public:
 
   void loadLastBrush();
 
-  void finishRasterBrush(const TPointD &pos, double pressureVal);
   // return true if the pencil mode is active in the Brush / PaintBrush / Eraser
   // Tools.
   bool isPencilModeActive() override;
@@ -172,35 +193,86 @@ public:
   bool askWrite(const TRect &rect) override;
   bool isMyPaintStyleSelected() { return m_isMyPaintStyleSelected; }
 
+private:
+  enum MouseEventType { ME_DOWN, ME_DRAG, ME_UP, ME_MOVE };
+  void handleMouseEvent(MouseEventType type, const TPointD &pos,
+                        const TMouseEvent &e);
+
 protected:
-  struct Stroke {
-  } m_stroke;
+  TInputManager m_inputmanager;
+#ifndef NDEBUG
+  TSmartPointerT<TModifierTest> m_modifierTest;
+#endif
+  TSmartPointerT<TModifierLine> m_modifierLine;
+  TSmartPointerT<TModifierTangents> m_modifierTangents;
+  TSmartPointerT<TModifierAssistants> m_modifierAssistants;
+  TSmartPointerT<TModifierSegmentation> m_modifierSegmentation;
+
+  class MyPaintStroke: public TTrackToolHandler {
+  public:
+    MyPaintToonzBrush brush;
+    
+    inline MyPaintStroke(
+      const TRaster32P &ras,
+      RasterController &controller,
+      const mypaint::Brush &brush,
+      bool interpolation = false
+    ): 
+      brush(ras, controller, brush, interpolation)
+    { }
+  };
+  
+  class PencilStroke: public TTrackToolHandler {
+  public:
+    RasterStrokeGenerator brush;
+    
+    inline PencilStroke( const TRasterCM32P &raster, Tasks task,
+                         ColorType colorType, int styleId, const TThickPoint &p,
+                         bool selective, int selectedStyle, bool lockAlpha,
+                         bool keepAntialias, bool isPaletteOrder = false
+    ):
+      brush(raster, task, colorType, styleId, p, selective, selectedStyle, lockAlpha, keepAntialias, isPaletteOrder)
+    { }
+  };
+
+  class BluredStroke: public TTrackToolHandler {
+  public:
+    BluredBrush brush;
+    
+    inline BluredStroke( const TRaster32P &ras, int size,
+                         const QRadialGradient &gradient, bool doDynamicOpacity
+    ):
+      brush(ras, size, gradient, doDynamicOpacity)
+    { }
+  };
   
   struct Painting {
     // initial painting input
     bool active = false;
     int styleId = 0;
-    bool smooth;
+    bool smooth = false;
+    // 作業中のFrameIdをクリック時に保存し、マウスリリース時(Undoの登録時)に別のフレームに 移動していたときの不具合を修正する。
+    TFrameId frameId;
     
     // common variables
     TTileSetCM32 *tileSet = nullptr;
     TTileSaverCM32 *tileSaver = nullptr;
-    TRect lastRect;
+    TRect affectedRect;
+    
     SmoothStroke smoothStroke;
     
     struct Pencil {
-      RasterStrokeGenerator *brush = nullptr;
+      bool isActive = false;
       bool realPencil = false;
     } pencil;
     
     struct Blured {
-      BluredBrush *brush = nullptr;
-      std::vector<TThickPoint> points;
+      bool isActive = false;
     } blured;
     
     struct MyPaint {
-      MyPaintToonzBrush *brush = nullptr;
-      TRect strokeRect;
+      bool isActive = false;
+      mypaint::Brush baseBrush;
       TRect strokeSegmentRect;
     } myPaint;
     
@@ -236,6 +308,7 @@ protected:
 
   TRasterCM32P m_backupRas;
   TRaster32P m_workRas;
+  TRect m_workBackupRect;
 
   BrushPresetManager
       m_presetsManager;  //!< Manager for presets of this tool instance
@@ -245,11 +318,6 @@ protected:
                       //! substitution.
       m_firstTime, m_presetsLoaded;
 
-  /*---
-作業中のFrameIdをクリック時に保存し、マウスリリース時(Undoの登録時)に別のフレームに
-移動していたときの不具合を修正する。---*/
-  TFrameId m_workingFrameId;
-
   ToonzRasterBrushToolNotifier *m_notifier;
   bool m_isMyPaintStyleSelected    = false;
   QElapsedTimer m_brushTimer;