Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "fullcolorbrushtool.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzTools includes
Toshihiro Shimizu 890ddd
#include "tools/tool.h"
Toshihiro Shimizu 890ddd
#include "tools/cursors.h"
Toshihiro Shimizu 890ddd
#include "tools/toolutils.h"
Toshihiro Shimizu 890ddd
#include "tools/toolhandle.h"
Toshihiro Shimizu 890ddd
#include "tools/tooloptions.h"
Toshihiro Shimizu 890ddd
bf1d82
#include "mypainttoonzbrush.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzQt includes
Toshihiro Shimizu 890ddd
#include "toonzqt/dvdialog.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzLib includes
Toshihiro Shimizu 890ddd
#include "toonz/tpalettehandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/txsheethandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshlevelhandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/tobjecthandle.h"
shun-iwasawa e1ab6d
#include "toonz/tframehandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/ttileset.h"
Toshihiro Shimizu 890ddd
#include "toonz/ttilesaver.h"
Toshihiro Shimizu 890ddd
#include "toonz/strokegenerator.h"
Toshihiro Shimizu 890ddd
#include "toonz/tstageobject.h"
Toshihiro Shimizu 890ddd
#include "toonz/palettecontroller.h"
bf1d82
#include "toonz/mypaintbrushstyle.h"
manongjohn 75da26
#include "toonz/preferences.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzCore includes
Toshihiro Shimizu 890ddd
#include "tgl.h"
Toshihiro Shimizu 890ddd
#include "tproperty.h"
Toshihiro Shimizu 890ddd
#include "trasterimage.h"
Toshihiro Shimizu 890ddd
#include "tenv.h"
Toshihiro Shimizu 890ddd
#include "tpalette.h"
Toshihiro Shimizu 890ddd
#include "trop.h"
Toshihiro Shimizu 890ddd
#include "tstream.h"
Toshihiro Shimizu 890ddd
#include "tstroke.h"
Toshihiro Shimizu 890ddd
#include "timagecache.h"
bf1d82
#include "tpixelutils.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Qt includes
Shinya Kitaoka 120a6e
#include <qcoreapplication>  // Qt translation support</qcoreapplication>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TEnv::IntVar FullcolorBrushMinSize("FullcolorBrushMinSize", 1);
Toshihiro Shimizu 890ddd
TEnv::IntVar FullcolorBrushMaxSize("FullcolorBrushMaxSize", 5);
Campbell Barton f49389
TEnv::IntVar FullcolorPressureSensitivity("FullcolorPressureSensitivity", 1);
Toshihiro Shimizu 890ddd
TEnv::DoubleVar FullcolorBrushHardness("FullcolorBrushHardness", 100);
Toshihiro Shimizu 890ddd
TEnv::DoubleVar FullcolorMinOpacity("FullcolorMinOpacity", 100);
Toshihiro Shimizu 890ddd
TEnv::DoubleVar FullcolorMaxOpacity("FullcolorMaxOpacity", 100);
bf1d82
TEnv::DoubleVar FullcolorModifierSize("FullcolorModifierSize", 0);
bf1d82
TEnv::DoubleVar FullcolorModifierOpacity("FullcolorModifierOpacity", 100);
572ed1
TEnv::IntVar FullcolorModifierEraser("FullcolorModifierEraser", 0);
572ed1
TEnv::IntVar FullcolorModifierLockAlpha("FullcolorModifierLockAlpha", 0);
9380d5
TEnv::IntVar FullcolorAssistants("FullcolorAssistants", 0);
manongjohn df5842
TEnv::StringVar FullcolorBrushPreset("FullcolorBrushPreset", "<custom>");</custom>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define CUSTOM_WSTR L"<custom>"</custom>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Shinya Kitaoka 120a6e
Shinya Kitaoka d1f6c4
class FullColorBrushUndo final : public ToolUtils::TFullColorRasterUndo {
Shinya Kitaoka 120a6e
  TPoint m_offset;
Shinya Kitaoka 120a6e
  QString m_id;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  FullColorBrushUndo(TTileSetFullColor *tileSet, TXshSimpleLevel *level,
Shinya Kitaoka 120a6e
                     const TFrameId &frameId, bool isFrameCreated,
Shinya Kitaoka 120a6e
                     const TRasterP &ras, const TPoint &offset)
Shinya Kitaoka 120a6e
      : ToolUtils::TFullColorRasterUndo(tileSet, level, frameId, isFrameCreated,
Shinya Kitaoka 120a6e
                                        false, 0)
Shinya Kitaoka 120a6e
      , m_offset(offset) {
Shinya Kitaoka 120a6e
    static int counter = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_id = QString("FullColorBrushUndo") + QString::number(counter++);
Shinya Kitaoka 120a6e
    TImageCache::instance()->add(m_id.toStdString(), TRasterImageP(ras));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ~FullColorBrushUndo() { TImageCache::instance()->remove(m_id); }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void redo() const override {
Shinya Kitaoka 120a6e
    insertLevelAndFrameIfNeeded();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TRasterImageP image = getImage();
Shinya Kitaoka 120a6e
    TRasterP ras        = image->getRaster();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TRasterImageP srcImg =
Shinya Kitaoka 120a6e
        TImageCache::instance()->get(m_id.toStdString(), false);
Shinya Kitaoka 120a6e
    ras->copy(srcImg->getRaster(), m_offset);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TTool::getApplication()->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) + ToolUtils::TFullColorRasterUndo::getSize();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  QString getToolName() override { return QString("Raster Brush Tool"); }
Shinya Kitaoka 473e70
  int getHistoryType() override { return HistoryType::BrushTool; }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
//    FullColor Brush Tool implementation
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 3bfa54
FullColorBrushTool::FullColorBrushTool(std::string name)
Shinya Kitaoka 120a6e
    : TTool(name)
shun-iwasawa 76d093
    , m_thickness("Size", 1, 1000, 1, 5, false)
Jeremy Bullock 01e454
    , m_pressure("Pressure", true)
Jeremy Bullock 01e454
    , m_opacity("Opacity", 0, 100, 100, 100, true)
Shinya Kitaoka 120a6e
    , m_hardness("Hardness:", 0, 100, 100)
bf1d82
    , m_modifierSize("ModifierSize", -3, 3, 0, true)
bf1d82
    , m_modifierOpacity("ModifierOpacity", 0, 100, 100, true)
572ed1
    , m_modifierEraser("ModifierEraser", false)
manongjohn 963976
    , m_modifierLockAlpha("Lock Alpha", false)
9380d5
    , m_assistants("Assistants", true)
Shinya Kitaoka 120a6e
    , m_preset("Preset:")
d8eddc
    , m_enabledPressure(false)
bf1d82
    , m_minCursorThick(0)
bf1d82
    , m_maxCursorThick(0)
Shinya Kitaoka 120a6e
    , m_tileSet(0)
Shinya Kitaoka 120a6e
    , m_tileSaver(0)
Shinya Kitaoka 120a6e
    , m_notifier(0)
Shinya Kitaoka 120a6e
    , m_presetsLoaded(false)
7a5892
    , m_firstTime(true)
7a5892
    , m_started(false) {
Shinya Kitaoka 120a6e
  bind(TTool::RasterImage | TTool::EmptyTarget);
shun-iwasawa ec85ad
  m_thickness.setNonLinearSlider();
shun-iwasawa ec85ad
shun-iwasawa ec85ad
  m_prop.bind(m_thickness);
shun-iwasawa ec85ad
  m_prop.bind(m_hardness);
shun-iwasawa ec85ad
  m_prop.bind(m_opacity);
shun-iwasawa ec85ad
  m_prop.bind(m_modifierSize);
shun-iwasawa ec85ad
  m_prop.bind(m_modifierOpacity);
shun-iwasawa ec85ad
  m_prop.bind(m_modifierEraser);
shun-iwasawa ec85ad
  m_prop.bind(m_modifierLockAlpha);
shun-iwasawa ec85ad
  m_prop.bind(m_pressure);
shun-iwasawa ec85ad
  m_prop.bind(m_assistants);
shun-iwasawa ec85ad
  m_prop.bind(m_preset);
Shinya Kitaoka 120a6e
d8eddc
  m_inputmanager.setHandler(this);
shun-iwasawa ec85ad
#ifndef NDEBUG
9f0c16
  m_modifierTest = new TModifierTest(5, 40);
shun-iwasawa ec85ad
#endif
shun-iwasawa ec85ad
  m_modifierLine         = new TModifierLine();
shun-iwasawa ec85ad
  m_modifierTangents     = new TModifierTangents();
shun-iwasawa ec85ad
  m_modifierAssistants   = new TModifierAssistants();
493cac
  m_modifierSegmentation = new TModifierSegmentation();
26ff80
shun-iwasawa ec85ad
  m_inputmanager.addModifier(
shun-iwasawa ec85ad
      TInputModifierP(m_modifierAssistants.getPointer()));
shun-iwasawa ec85ad
shun-iwasawa 76d093
  m_thickness.setNonLinearSlider();
Shinya Kitaoka 120a6e
  m_preset.setId("BrushPreset");
manongjohn 85ae4c
  m_modifierEraser.setId("RasterEraser");
manongjohn 85ae4c
  m_modifierLockAlpha.setId("LockAlpha");
manongjohn 85ae4c
  m_pressure.setId("PressureSensitivity");
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
ToolOptionsBox *FullColorBrushTool::createOptionsBox() {
Shinya Kitaoka 120a6e
  TPaletteHandle *currPalette =
Shinya Kitaoka 120a6e
      TTool::getApplication()->getPaletteController()->getCurrentLevelPalette();
Shinya Kitaoka 120a6e
  ToolHandle *currTool = TTool::getApplication()->getCurrentTool();
Shinya Kitaoka 120a6e
  return new BrushToolOptionsBox(0, this, currPalette, currTool);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FullColorBrushTool::onCanvasSizeChanged() {
Shinya Kitaoka 120a6e
  onDeactivate();
Shinya Kitaoka 120a6e
  setWorkAndBackupImages();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
bf1d82
void FullColorBrushTool::onColorStyleChanged() {
bf1d82
  getApplication()->getCurrentTool()->notifyToolChanged();
bf1d82
}
bf1d82
bf1d82
//---------------------------------------------------------------------------------------------------
bf1d82
Shinya Kitaoka 120a6e
void FullColorBrushTool::updateTranslation() {
Jeremy Bullock 01e454
  m_thickness.setQStringName(tr("Size"));
Jeremy Bullock 01e454
  m_pressure.setQStringName(tr("Pressure"));
Jeremy Bullock 01e454
  m_opacity.setQStringName(tr("Opacity"));
Shinya Kitaoka 120a6e
  m_hardness.setQStringName(tr("Hardness:"));
Shinya Kitaoka 120a6e
  m_preset.setQStringName(tr("Preset:"));
bf1d82
  m_modifierSize.setQStringName(tr("Size"));
bf1d82
  m_modifierOpacity.setQStringName(tr("Opacity"));
572ed1
  m_modifierEraser.setQStringName(tr("Eraser"));
572ed1
  m_modifierLockAlpha.setQStringName(tr("Lock Alpha"));
9380d5
  m_assistants.setQStringName(tr("Assistants"));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FullColorBrushTool::onActivate() {
Shinya Kitaoka 120a6e
  if (!m_notifier) m_notifier = new FullColorBrushToolNotifier(this);
shun-iwasawa ec85ad
  m_notifier->onActivate();
Shinya Kitaoka 120a6e
bf1d82
  updateCurrentStyle();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_firstTime) {
Shinya Kitaoka 120a6e
    m_firstTime = false;
manongjohn df5842
manongjohn df5842
    std::wstring wpreset =
manongjohn df5842
        QString::fromStdString(FullcolorBrushPreset.getValue()).toStdWString();
manongjohn df5842
    if (wpreset != CUSTOM_WSTR) {
manongjohn df5842
      initPresets();
manongjohn 8b8d41
      if (!m_preset.isValue(wpreset)) wpreset = CUSTOM_WSTR;
manongjohn df5842
      m_preset.setValue(wpreset);
manongjohn 8b8d41
      FullcolorBrushPreset = m_preset.getValueAsString();
manongjohn df5842
      loadPreset();
manongjohn df5842
    } else
manongjohn df5842
      loadLastBrush();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  setWorkAndBackupImages();
bf1d82
  onColorStyleChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FullColorBrushTool::onDeactivate() {
shun-iwasawa ec85ad
  if (m_notifier) m_notifier->onDeactivate();
shun-iwasawa ec85ad
d8eddc
  m_inputmanager.finishTracks();
Shinya Kitaoka 120a6e
  m_workRaster = TRaster32P();
Shinya Kitaoka 120a6e
  m_backUpRas  = TRasterP();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FullColorBrushTool::updateWorkAndBackupRasters(const TRect &rect) {
bf1d82
  if (rect.isEmpty()) return;
bf1d82
Shinya Kitaoka 120a6e
  TRasterImageP ri = TImageP(getImage(false, 1));
Shinya Kitaoka 120a6e
  if (!ri) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TRasterP ras = ri->getRaster();
Toshihiro Shimizu 890ddd
bf1d82
  const int denominator = 8;
shun_iwasawa e553fc
  TRect enlargedRect    = rect + m_lastRect;
shun_iwasawa e553fc
  int dx                = (enlargedRect.getLx() - 1) / denominator + 1;
shun_iwasawa e553fc
  int dy                = (enlargedRect.getLy() - 1) / denominator + 1;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_lastRect.isEmpty()) {
bf1d82
    enlargedRect.x0 -= dx;
bf1d82
    enlargedRect.y0 -= dy;
bf1d82
    enlargedRect.x1 += dx;
bf1d82
    enlargedRect.y1 += dy;
bf1d82
shun_iwasawa e553fc
    TRect _rect = enlargedRect * ras->getBounds();
bf1d82
    if (_rect.isEmpty()) return;
bf1d82
bf1d82
    m_workRaster->extract(_rect)->copy(ras->extract(_rect));
Shinya Kitaoka 120a6e
    m_backUpRas->extract(_rect)->copy(ras->extract(_rect));
bf1d82
  } else {
bf1d82
    if (enlargedRect.x0 < m_lastRect.x0) enlargedRect.x0 -= dx;
bf1d82
    if (enlargedRect.y0 < m_lastRect.y0) enlargedRect.y0 -= dy;
bf1d82
    if (enlargedRect.x1 > m_lastRect.x1) enlargedRect.x1 += dx;
bf1d82
    if (enlargedRect.y1 > m_lastRect.y1) enlargedRect.y1 += dy;
bf1d82
shun_iwasawa e553fc
    TRect _rect = enlargedRect * ras->getBounds();
bf1d82
    if (_rect.isEmpty()) return;
bf1d82
shun_iwasawa e553fc
    TRect _lastRect    = m_lastRect * ras->getBounds();
bf1d82
    QList<trect> rects = ToolUtils::splitRect(_rect, _lastRect);</trect>
bf1d82
    for (int i = 0; i < rects.size(); i++) {
bf1d82
      m_workRaster->extract(rects[i])->copy(ras->extract(rects[i]));
bf1d82
      m_backUpRas->extract(rects[i])->copy(ras->extract(rects[i]));
bf1d82
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
bf1d82
  m_lastRect = enlargedRect;
bf1d82
}
bf1d82
bf1d82
//--------------------------------------------------------------------------------------------------
bf1d82
shun_iwasawa e553fc
bool FullColorBrushTool::askRead(const TRect &rect) { return askWrite(rect); }
bf1d82
bf1d82
//--------------------------------------------------------------------------------------------------
bf1d82
bf1d82
bool FullColorBrushTool::askWrite(const TRect &rect) {
bf1d82
  if (rect.isEmpty()) return true;
bf1d82
  m_strokeRect += rect;
bf1d82
  m_strokeSegmentRect += rect;
bf1d82
  updateWorkAndBackupRasters(rect);
bf1d82
  m_tileSaver->save(rect);
bf1d82
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool FullColorBrushTool::preLeftButtonDown() {
d07d8b
  m_modifierAssistants->drawOnly = !FullcolorAssistants;
shun-iwasawa ec85ad
  m_inputmanager.drawPreview     = false;  //! m_modifierAssistants->drawOnly;
shun-iwasawa ec85ad
d8eddc
  m_inputmanager.clearModifiers();
shun-iwasawa ec85ad
  m_inputmanager.addModifier(TInputModifierP(m_modifierTangents.getPointer()));
shun-iwasawa ec85ad
  m_inputmanager.addModifier(
shun-iwasawa ec85ad
      TInputModifierP(m_modifierAssistants.getPointer()));
shun-iwasawa ec85ad
  m_inputmanager.addModifier(
shun-iwasawa ec85ad
      TInputModifierP(m_modifierSegmentation.getPointer()));
shun-iwasawa ec85ad
#ifndef NDEBUG
shun-iwasawa ec85ad
  m_inputmanager.addModifier(TInputModifierP(m_modifierTest.getPointer()));
shun-iwasawa ec85ad
#endif
shun-iwasawa ec85ad
Shinya Kitaoka 120a6e
  touchImage();
Toshihiro Shimizu 890ddd
shun-iwasawa e1ab6d
  if (m_isFrameCreated) {
shun-iwasawa e1ab6d
    setWorkAndBackupImages();
shun-iwasawa e1ab6d
    // When the xsheet frame is selected, whole viewer will be updated from
shun-iwasawa e1ab6d
    // SceneViewer::onXsheetChanged() on adding a new frame.
shun-iwasawa e1ab6d
    // We need to take care of a case when the level frame is selected.
shun-iwasawa e1ab6d
    if (m_application->getCurrentFrame()->isEditingLevel()) invalidate();
shun-iwasawa e1ab6d
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
shun-iwasawa ec85ad
void FullColorBrushTool::handleMouseEvent(MouseEventType type,
shun-iwasawa ec85ad
                                          const TPointD &pos,
shun-iwasawa ec85ad
                                          const TMouseEvent &e) {
d8eddc
  TTimerTicks t = TToolTimer::ticks();
shun-iwasawa ec85ad
  bool alt      = e.getModifiersMask() & TMouseEvent::ALT_KEY;
shun-iwasawa ec85ad
  bool shift    = e.getModifiersMask() & TMouseEvent::SHIFT_KEY;
shun-iwasawa ec85ad
  bool control  = e.getModifiersMask() & TMouseEvent::CTRL_KEY;
shun-iwasawa ec85ad
145ef4
  if (shift && type == ME_DOWN && e.button() == Qt::LeftButton && !m_started) {
26ff80
    m_modifierAssistants->drawOnly = true;
7a5892
    m_inputmanager.clearModifiers();
shun-iwasawa ec85ad
    m_inputmanager.addModifier(TInputModifierP(m_modifierLine.getPointer()));
shun-iwasawa ec85ad
    m_inputmanager.addModifier(
shun-iwasawa ec85ad
        TInputModifierP(m_modifierAssistants.getPointer()));
shun-iwasawa ec85ad
    m_inputmanager.addModifier(
shun-iwasawa ec85ad
        TInputModifierP(m_modifierSegmentation.getPointer()));
dba7b5
    m_inputmanager.drawPreview = true;
7a5892
  }
shun-iwasawa ec85ad
d8eddc
  if (alt != m_inputmanager.state.isKeyPressed(TKey::alt))
d8eddc
    m_inputmanager.keyEvent(alt, TKey::alt, t, nullptr);
d8eddc
  if (shift != m_inputmanager.state.isKeyPressed(TKey::shift))
d8eddc
    m_inputmanager.keyEvent(shift, TKey::shift, t, nullptr);
d8eddc
  if (control != m_inputmanager.state.isKeyPressed(TKey::control))
d8eddc
    m_inputmanager.keyEvent(control, TKey::control, t, nullptr);
shun-iwasawa ec85ad
d8eddc
  if (type == ME_MOVE) {
d8eddc
    THoverList hovers(1, pos);
d8eddc
    m_inputmanager.hoverEvent(hovers);
d8eddc
  } else {
shun-iwasawa ec85ad
    m_inputmanager.trackEvent(e.isTablet(), 0, pos,
shun-iwasawa ec85ad
                              e.isTablet() ? &e.m_pressure : nullptr, nullptr,
shun-iwasawa ec85ad
                              type == ME_UP, t);
d8eddc
    m_inputmanager.processTracks();
d8eddc
  }
d8eddc
}
d8eddc
d8eddc
//---------------------------------------------------------------------------------------------------
d8eddc
shun-iwasawa ec85ad
void FullColorBrushTool::leftButtonDown(const TPointD &pos,
shun-iwasawa ec85ad
                                        const TMouseEvent &e) {
shun-iwasawa ec85ad
  handleMouseEvent(ME_DOWN, pos, e);
shun-iwasawa ec85ad
}
shun-iwasawa ec85ad
void FullColorBrushTool::leftButtonDrag(const TPointD &pos,
shun-iwasawa ec85ad
                                        const TMouseEvent &e) {
shun-iwasawa ec85ad
  handleMouseEvent(ME_DRAG, pos, e);
shun-iwasawa ec85ad
}
shun-iwasawa ec85ad
void FullColorBrushTool::leftButtonUp(const TPointD &pos,
shun-iwasawa ec85ad
                                      const TMouseEvent &e) {
shun-iwasawa ec85ad
  handleMouseEvent(ME_UP, pos, e);
shun-iwasawa ec85ad
}
shun-iwasawa ec85ad
void FullColorBrushTool::mouseMove(const TPointD &pos, const TMouseEvent &e) {
shun-iwasawa ec85ad
  handleMouseEvent(ME_MOVE, pos, e);
shun-iwasawa ec85ad
}
d8eddc
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
shun-iwasawa ec85ad
void FullColorBrushTool::inputMouseMove(const TPointD &position,
shun-iwasawa ec85ad
                                        const TInputState &state) {
Shinya Kitaoka 120a6e
  struct Locals {
Shinya Kitaoka 120a6e
    FullColorBrushTool *m_this;
Toshihiro Shimizu 890ddd
c02b89
    void notify(TProperty &prop) {
Shinya Kitaoka 120a6e
      m_this->onPropertyChanged(prop.getName());
Shinya Kitaoka 120a6e
      TTool::getApplication()->getCurrentTool()->notifyToolChanged();
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    void addMinMax(TIntPairProperty &prop, double add) {
Shinya Kitaoka 120a6e
      const TIntPairProperty::Range &range = prop.getRange();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      TIntPairProperty::Value value = prop.getValue();
Shinya Kitaoka 120a6e
      value.second =
Shinya Kitaoka 120a6e
          tcrop<double>(value.second + add, range.first, range.second);</double>
Shinya Kitaoka 120a6e
      value.first = tcrop<double>(value.first + add, range.first, range.second);</double>
c02b89
      prop.setValue(value);
Toshihiro Shimizu 890ddd
c02b89
      notify(prop);
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Jeremy Bullock 01e454
    void addMinMaxSeparate(TIntPairProperty &prop, double min, double max) {
Jeremy Bullock 01e454
      if (min == 0.0 && max == 0.0) return;
Jeremy Bullock 01e454
      const TIntPairProperty::Range &range = prop.getRange();
Toshihiro Shimizu 890ddd
Jeremy Bullock 01e454
      TIntPairProperty::Value value = prop.getValue();
Jeremy Bullock 01e454
      value.first += min;
Jeremy Bullock 01e454
      value.second += max;
Jeremy Bullock 01e454
      if (value.first > value.second) value.first = value.second;
shun-iwasawa ec85ad
      value.first = tcrop<double>(value.first, range.first, range.second);</double>
c02b89
Jeremy Bullock 01e454
      value.second = tcrop<double>(value.second, range.first, range.second);</double>
c02b89
      prop.setValue(value);
Jeremy Bullock 01e454
c02b89
      notify(prop);
c02b89
    }
c02b89
c02b89
    void add(TDoubleProperty &prop, double x) {
c02b89
      if (x == 0.0) return;
c02b89
c02b89
      const TDoubleProperty::Range &range = prop.getRange();
shun-iwasawa ec85ad
      double value =
shun-iwasawa ec85ad
          tcrop<double>(prop.getValue() + x, range.first, range.second);</double>
c02b89
      prop.setValue(value);
c02b89
c02b89
      notify(prop);
Jeremy Bullock 01e454
    }
Jeremy Bullock 01e454
  } locals = {this};
Shinya Kitaoka d4642c
d8eddc
  if (state.isKeyPressed(TKey::control) && state.isKeyPressed(TKey::alt)) {
d8eddc
    const TPointD &diff = position - m_mousePos;
c02b89
    if (getBrushStyle()) {
shun-iwasawa ec85ad
      locals.add(m_modifierSize, 0.01 * diff.x);
c02b89
    } else {
shun-iwasawa ec85ad
      locals.addMinMaxSeparate(m_thickness, int(diff.x / 2), int(diff.y / 2));
c02b89
    }
Jeremy Bullock 01e454
  } else {
d8eddc
    m_brushPos = position;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
d8eddc
  m_mousePos = position;
Shinya Kitaoka 120a6e
  invalidate();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------------------------------------
00337d
7a5892
void FullColorBrushTool::inputSetBusy(bool busy) {
7a5892
  if (m_started == busy) return;
7a5892
  if (busy) {
7a5892
    // begin paint
7a5892
    TRasterImageP ri = (TRasterImageP)getImage(true);
shun-iwasawa ec85ad
    if (!ri) ri = (TRasterImageP)touchImage();
7a5892
    if (!ri) return;
7a5892
    TRasterP ras = ri->getRaster();
7a5892
7a5892
    if (!(m_workRaster && m_backUpRas)) setWorkAndBackupImages();
7a5892
    m_workRaster->lock();
7a5892
    m_tileSet   = new TTileSetFullColor(ras->getSize());
7a5892
    m_tileSaver = new TTileSaverFullColor(ras, m_tileSet);
7a5892
7a5892
    // update color here since the current style might be switched
7a5892
    // with numpad shortcut keys
7a5892
    updateCurrentStyle();
7a5892
  } else {
7a5892
    // end paint
7a5892
    if (TRasterImageP ri = (TRasterImageP)getImage(true)) {
7a5892
      TRasterP ras = ri->getRaster();
7a5892
7a5892
      m_lastRect.empty();
7a5892
      m_workRaster->unlock();
7a5892
7a5892
      if (m_tileSet->getTileCount() > 0) {
7a5892
        delete m_tileSaver;
7a5892
        TTool::Application *app   = TTool::getApplication();
7a5892
        TXshLevel *level          = app->getCurrentLevel()->getLevel();
7a5892
        TXshSimpleLevelP simLevel = level->getSimpleLevel();
7a5892
        TFrameId frameId          = getCurrentFid();
7a5892
        TRasterP subras           = ras->extract(m_strokeRect)->clone();
7a5892
        TUndoManager::manager()->add(new FullColorBrushUndo(
7a5892
            m_tileSet, simLevel.getPointer(), frameId, m_isFrameCreated, subras,
7a5892
            m_strokeRect.getP00()));
7a5892
      }
7a5892
7a5892
      notifyImageChanged();
7a5892
      m_strokeRect.empty();
7a5892
    }
7a5892
  }
7a5892
  m_started = busy;
7a5892
}
7a5892
7a5892
//-------------------------------------------------------------------------------------------------------------
7a5892
shun-iwasawa ec85ad
void FullColorBrushTool::inputPaintTrackPoint(const TTrackPoint &point,
shun-iwasawa ec85ad
                                              const TTrack &track,
shun-iwasawa ec85ad
                                              bool firstTrack) {
7a5892
  // get raster
7a5892
  if (!m_started || !getViewer()) return;
7a5892
  TRasterImageP ri = (TRasterImageP)getImage(true);
7a5892
  if (!ri) return;
shun-iwasawa ec85ad
  TRasterP ras      = ri->getRaster();
7a5892
  TPointD rasCenter = ras->getCenterD();
7a5892
7a5892
  // init brush
7a5892
  TrackHandler *handler;
7a5892
  if (track.size() == track.pointsAdded && !track.toolHandler && m_workRaster) {
7a5892
    mypaint::Brush mypaintBrush;
7a5892
    applyToonzBrushSettings(mypaintBrush);
7a5892
    handler = new TrackHandler(m_workRaster, *this, mypaintBrush);
7a5892
    handler->brush.beginStroke();
7a5892
    track.toolHandler = handler;
7a5892
  }
shun-iwasawa ec85ad
  handler = dynamic_cast<trackhandler *="">(track.toolHandler.getPointer());</trackhandler>
7a5892
  if (!handler) return;
7a5892
7a5892
  // paint stroke
7a5892
  m_strokeSegmentRect.empty();
shun-iwasawa ec85ad
  handler->brush.strokeTo(point.position + rasCenter,
shun-iwasawa ec85ad
                          m_enabledPressure ? point.pressure : 0.5, point.tilt,
shun-iwasawa ec85ad
                          point.time - track.previous().time);
shun-iwasawa ec85ad
  if (track.pointsAdded == 1 && track.finished()) handler->brush.endStroke();
7a5892
7a5892
  // update affected area
7a5892
  TRect updateRect = m_strokeSegmentRect * ras->getBounds();
7a5892
  if (!updateRect.isEmpty())
7a5892
    ras->extract(updateRect)->copy(m_workRaster->extract(updateRect));
7a5892
  TRectD invalidateRect = convert(m_strokeSegmentRect) - rasCenter;
7a5892
  if (firstTrack) {
7a5892
    TPointD thickOffset(m_maxCursorThick * 0.5, m_maxCursorThick * 0.5);
shun-iwasawa ec85ad
    invalidateRect +=
shun-iwasawa ec85ad
        TRectD(m_brushPos - thickOffset, m_brushPos + thickOffset);
shun-iwasawa ec85ad
    invalidateRect +=
shun-iwasawa ec85ad
        TRectD(point.position - thickOffset, point.position + thickOffset);
7a5892
    m_brushPos = m_mousePos = point.position;
7a5892
  }
7a5892
  invalidate(invalidateRect.enlarge(2.0));
7a5892
}
7a5892
7a5892
//-------------------------------------------------------------------------------------------------------------
7a5892
shun-iwasawa ec85ad
void FullColorBrushTool::inputInvalidateRect(const TRectD &bounds) {
shun-iwasawa ec85ad
  invalidate(bounds);
shun-iwasawa ec85ad
}
00337d
00337d
//-------------------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FullColorBrushTool::draw() {
Shinya Kitaoka 120a6e
  if (TRasterImageP ri = TRasterImageP(getImage(false))) {
manongjohn 75da26
    // If toggled off, don't draw brush outline
manongjohn 75da26
    if (!Preferences::instance()->isCursorOutlineEnabled()) return;
manongjohn 75da26
Shinya Kitaoka 120a6e
    TRasterP ras = ri->getRaster();
Toshihiro Shimizu 890ddd
shun_iwasawa e553fc
    double alpha       = 1.0;
bf1d82
    double alphaRadius = 3.0;
shun_iwasawa e553fc
    double pixelSize   = sqrt(tglGetPixelSize2());
bf1d82
bf1d82
    // circles with lesser radius looks more bold
bf1d82
    // to avoid these effect we'll reduce alpha for small radiuses
shun_iwasawa e553fc
    double minX     = m_minCursorThick / (alphaRadius * pixelSize);
shun_iwasawa e553fc
    double maxX     = m_maxCursorThick / (alphaRadius * pixelSize);
shun_iwasawa e553fc
    double minAlpha = alpha * (1.0 - 1.0 / (1.0 + minX));
shun_iwasawa e553fc
    double maxAlpha = alpha * (1.0 - 1.0 / (1.0 + maxX));
bf1d82
bf1d82
    glPushAttrib(GL_ALL_ATTRIB_BITS);
bf1d82
    tglEnableBlending();
bf1d82
    tglEnableLineSmooth(true, 0.5);
bf1d82
bf1d82
    if (m_minCursorThick < m_maxCursorThick - pixelSize) {
bf1d82
      glColor4d(1.0, 1.0, 1.0, minAlpha);
shun_iwasawa e553fc
      tglDrawCircle(m_brushPos, (m_minCursorThick + 1) * 0.5 - pixelSize);
bf1d82
      glColor4d(0.0, 0.0, 0.0, minAlpha);
shun_iwasawa e553fc
      tglDrawCircle(m_brushPos, (m_minCursorThick + 1) * 0.5);
bf1d82
    }
bf1d82
bf1d82
    glColor4d(1.0, 1.0, 1.0, maxAlpha);
shun_iwasawa e553fc
    tglDrawCircle(m_brushPos, (m_maxCursorThick + 1) * 0.5 - pixelSize);
bf1d82
    glColor4d(0.0, 0.0, 0.0, maxAlpha);
shun_iwasawa e553fc
    tglDrawCircle(m_brushPos, (m_maxCursorThick + 1) * 0.5);
Toshihiro Shimizu 890ddd
bf1d82
    glPopAttrib();
Shinya Kitaoka 120a6e
  }
c3c215
  m_inputmanager.draw();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
shun_iwasawa e553fc
void FullColorBrushTool::onEnter() { updateCurrentStyle(); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FullColorBrushTool::onLeave() {
bf1d82
  m_minCursorThick = 0;
bf1d82
  m_maxCursorThick = 0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TPropertyGroup *FullColorBrushTool::getProperties(int targetType) {
Shinya Kitaoka 120a6e
  if (!m_presetsLoaded) initPresets();
Shinya Kitaoka 120a6e
  return &m_prop;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FullColorBrushTool::onImageChanged() { setWorkAndBackupImages(); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FullColorBrushTool::setWorkAndBackupImages() {
Shinya Kitaoka 120a6e
  TRasterImageP ri = (TRasterImageP)getImage(false, 1);
Shinya Kitaoka 120a6e
  if (!ri) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TRasterP ras   = ri->getRaster();
Shinya Kitaoka 120a6e
  TDimension dim = ras->getSize();
Toshihiro Shimizu 890ddd
Jeremy Bullock 8c1a46
  if (!m_workRaster || m_workRaster->getLx() != dim.lx ||
Jeremy Bullock 8c1a46
      m_workRaster->getLy() != dim.ly)
Shinya Kitaoka 120a6e
    m_workRaster = TRaster32P(dim);
Toshihiro Shimizu 890ddd
Jeremy Bullock 8c1a46
  if (!m_backUpRas || m_backUpRas->getLx() != dim.lx ||
Jeremy Bullock 8c1a46
      m_backUpRas->getLy() != dim.ly ||
Shinya Kitaoka 120a6e
      m_backUpRas->getPixelSize() != ras->getPixelSize())
Shinya Kitaoka 120a6e
    m_backUpRas = ras->create(dim.lx, dim.ly);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_strokeRect.empty();
Shinya Kitaoka 120a6e
  m_lastRect.empty();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool FullColorBrushTool::onPropertyChanged(std::string propertyName) {
manongjohn 5a2268
  if (m_propertyUpdating) return true;
manongjohn 5a2268
manongjohn df5842
  updateCurrentStyle();
manongjohn df5842
manongjohn df5842
  if (propertyName == "Preset:") {
manongjohn df5842
    if (m_preset.getValue() != CUSTOM_WSTR)
manongjohn df5842
      loadPreset();
manongjohn df5842
    else  // Chose <custom>, go back to last saved brush settings</custom>
manongjohn df5842
      loadLastBrush();
manongjohn df5842
manongjohn df5842
    FullcolorBrushPreset = m_preset.getValueAsString();
manongjohn 5a2268
    m_propertyUpdating   = true;
manongjohn df5842
    getApplication()->getCurrentTool()->notifyToolChanged();
manongjohn 5a2268
    m_propertyUpdating = false;
manongjohn df5842
    return true;
manongjohn df5842
  }
manongjohn df5842
bf1d82
  FullcolorBrushMinSize        = m_thickness.getValue().first;
bf1d82
  FullcolorBrushMaxSize        = m_thickness.getValue().second;
Campbell Barton f49389
  FullcolorPressureSensitivity = m_pressure.getValue();
Shinya Kitaoka 120a6e
  FullcolorBrushHardness       = m_hardness.getValue();
Shinya Kitaoka 120a6e
  FullcolorMinOpacity          = m_opacity.getValue().first;
Shinya Kitaoka 120a6e
  FullcolorMaxOpacity          = m_opacity.getValue().second;
bf1d82
  FullcolorModifierSize        = m_modifierSize.getValue();
bf1d82
  FullcolorModifierOpacity     = m_modifierOpacity.getValue();
572ed1
  FullcolorModifierEraser      = m_modifierEraser.getValue() ? 1 : 0;
572ed1
  FullcolorModifierLockAlpha   = m_modifierLockAlpha.getValue() ? 1 : 0;
9380d5
  FullcolorAssistants          = m_assistants.getValue() ? 1 : 0;
bf1d82
Shinya Kitaoka 120a6e
  if (m_preset.getValue() != CUSTOM_WSTR) {
Shinya Kitaoka 120a6e
    m_preset.setValue(CUSTOM_WSTR);
manongjohn df5842
    FullcolorBrushPreset = m_preset.getValueAsString();
manongjohn 5a2268
    m_propertyUpdating   = true;
Shinya Kitaoka 120a6e
    getApplication()->getCurrentTool()->notifyToolChanged();
manongjohn 5a2268
    m_propertyUpdating = false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FullColorBrushTool::initPresets() {
Shinya Kitaoka 120a6e
  if (!m_presetsLoaded) {
Shinya Kitaoka 120a6e
    // If necessary, load the presets from file
Shinya Kitaoka 120a6e
    m_presetsLoaded = true;
Shinya Kitaoka 120a6e
    m_presetsManager.load(TEnv::getConfigDir() + "brush_raster.txt");
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Rebuild the presets property entries
Shinya Kitaoka 120a6e
  const std::set<brushdata> &presets = m_presetsManager.presets();</brushdata>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_preset.deleteAllValues();
Shinya Kitaoka 120a6e
  m_preset.addValue(CUSTOM_WSTR);
shun-iwasawa e87e08
  m_preset.setItemUIName(CUSTOM_WSTR, tr("<custom>"));</custom>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::set<brushdata>::const_iterator it, end = presets.end();</brushdata>
Shinya Kitaoka 120a6e
  for (it = presets.begin(); it != end; ++it) m_preset.addValue(it->m_name);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FullColorBrushTool::loadPreset() {
Shinya Kitaoka 120a6e
  const std::set<brushdata> &presets = m_presetsManager.presets();</brushdata>
Shinya Kitaoka 120a6e
  std::set<brushdata>::const_iterator it;</brushdata>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  it = presets.find(BrushData(m_preset.getValue()));
Shinya Kitaoka 120a6e
  if (it == presets.end()) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const BrushData &preset = *it;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  try  // Don't bother with RangeErrors
Shinya Kitaoka 120a6e
  {
shun-iwasawa ec85ad
    m_thickness.setValue(TIntPairProperty::Value(std::max((int)preset.m_min, 1),
shun-iwasawa ec85ad
                                                 (int)preset.m_max));
Shinya Kitaoka 120a6e
    m_hardness.setValue(preset.m_hardness, true);
Shinya Kitaoka 120a6e
    m_opacity.setValue(
Shinya Kitaoka 120a6e
        TDoublePairProperty::Value(preset.m_opacityMin, preset.m_opacityMax));
Shinya Kitaoka 120a6e
    m_pressure.setValue(preset.m_pressure);
bf1d82
    m_modifierSize.setValue(preset.m_modifierSize);
bf1d82
    m_modifierOpacity.setValue(preset.m_modifierOpacity);
572ed1
    m_modifierEraser.setValue(preset.m_modifierEraser);
572ed1
    m_modifierLockAlpha.setValue(preset.m_modifierLockAlpha);
9380d5
    m_assistants.setValue(preset.m_assistants);
Shinya Kitaoka 120a6e
  } catch (...) {
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FullColorBrushTool::addPreset(QString name) {
Shinya Kitaoka 120a6e
  // Build the preset
Shinya Kitaoka 120a6e
  BrushData preset(name.toStdWString());
Toshihiro Shimizu 890ddd
572ed1
  preset.m_min               = m_thickness.getValue().first;
572ed1
  preset.m_max               = m_thickness.getValue().second;
572ed1
  preset.m_hardness          = m_hardness.getValue();
572ed1
  preset.m_opacityMin        = m_opacity.getValue().first;
572ed1
  preset.m_opacityMax        = m_opacity.getValue().second;
572ed1
  preset.m_pressure          = m_pressure.getValue();
572ed1
  preset.m_modifierSize      = m_modifierSize.getValue();
572ed1
  preset.m_modifierOpacity   = m_modifierOpacity.getValue();
572ed1
  preset.m_modifierEraser    = m_modifierEraser.getValue();
572ed1
  preset.m_modifierLockAlpha = m_modifierLockAlpha.getValue();
9380d5
  preset.m_assistants        = m_assistants.getValue();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Pass the preset to the manager
Shinya Kitaoka 120a6e
  m_presetsManager.addPreset(preset);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Reinitialize the associated preset enum
Shinya Kitaoka 120a6e
  initPresets();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Set the value to the specified one
Shinya Kitaoka 120a6e
  m_preset.setValue(preset.m_name);
manongjohn 8b8d41
  FullcolorBrushPreset = m_preset.getValueAsString();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FullColorBrushTool::removePreset() {
Shinya Kitaoka 120a6e
  std::wstring name(m_preset.getValue());
Shinya Kitaoka 120a6e
  if (name == CUSTOM_WSTR) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_presetsManager.removePreset(name);
Shinya Kitaoka 120a6e
  initPresets();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // No parameter change, and set the preset value to custom
Shinya Kitaoka 120a6e
  m_preset.setValue(CUSTOM_WSTR);
manongjohn 8b8d41
  FullcolorBrushPreset = m_preset.getValueAsString();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
shun_iwasawa e3df22
//------------------------------------------------------------------
manongjohn df5842
manongjohn df5842
void FullColorBrushTool::loadLastBrush() {
manongjohn df5842
  m_thickness.setValue(
manongjohn df5842
      TIntPairProperty::Value(FullcolorBrushMinSize, FullcolorBrushMaxSize));
manongjohn df5842
  m_pressure.setValue(FullcolorPressureSensitivity ? 1 : 0);
manongjohn df5842
  m_opacity.setValue(
manongjohn df5842
      TDoublePairProperty::Value(FullcolorMinOpacity, FullcolorMaxOpacity));
manongjohn df5842
  m_hardness.setValue(FullcolorBrushHardness);
manongjohn df5842
  m_modifierSize.setValue(FullcolorModifierSize);
manongjohn df5842
  m_modifierOpacity.setValue(FullcolorModifierOpacity);
manongjohn df5842
  m_modifierEraser.setValue(FullcolorModifierEraser ? true : false);
manongjohn df5842
  m_modifierLockAlpha.setValue(FullcolorModifierLockAlpha ? true : false);
9380d5
  m_assistants.setValue(FullcolorAssistants ? true : false);
manongjohn df5842
}
manongjohn df5842
manongjohn df5842
//------------------------------------------------------------------
shun_iwasawa e3df22
bf1d82
void FullColorBrushTool::updateCurrentStyle() {
bf1d82
  m_currentColor = TPixel32::Black;
bf1d82
  if (TTool::Application *app = getApplication()) {
bf1d82
    if (app->getCurrentObject()->isSpline()) {
bf1d82
      m_currentColor = TPixel32::Red;
shun_iwasawa e553fc
    } else if (TPalette *plt = app->getCurrentPalette()->getPalette()) {
bf1d82
      int style               = app->getCurrentLevelStyleIndex();
bf1d82
      TColorStyle *colorStyle = plt->getStyle(style);
bf1d82
      m_currentColor          = colorStyle->getMainColor();
bf1d82
    }
shun_iwasawa e3df22
  }
shun_iwasawa e3df22
bf1d82
  int prevMinCursorThick = m_minCursorThick;
bf1d82
  int prevMaxCursorThick = m_maxCursorThick;
bf1d82
bf1d82
  m_enabledPressure = m_pressure.getValue();
bf1d82
  if (TMyPaintBrushStyle *brushStyle = getBrushStyle()) {
shun_iwasawa e553fc
    double radiusLog = brushStyle->getBrush().getBaseValue(
shun_iwasawa e553fc
                           MYPAINT_BRUSH_SETTING_RADIUS_LOGARITHMIC) +
shun_iwasawa e553fc
                       m_modifierSize.getValue() * log(2.0);
shun_iwasawa e553fc
    double radius    = exp(radiusLog);
shun_iwasawa e553fc
    m_minCursorThick = m_maxCursorThick = (int)round(2.0 * radius);
bf1d82
  } else {
bf1d82
    m_minCursorThick = std::max(m_thickness.getValue().first, 1);
shun_iwasawa e553fc
    m_maxCursorThick =
shun_iwasawa e553fc
        std::max(m_thickness.getValue().second, m_minCursorThick);
shun-iwasawa 76d093
    if (!m_enabledPressure) m_minCursorThick = m_maxCursorThick;
bf1d82
  }
bf1d82
shun-iwasawa 7b497a
  // if this function is called from onEnter(), the clipping rect will not be
shun-iwasawa 7b497a
  // set in order to update whole viewer.
shun-iwasawa 7b497a
  if (prevMinCursorThick == 0 && prevMaxCursorThick == 0) return;
shun-iwasawa 7b497a
shun_iwasawa e553fc
  if (m_minCursorThick != prevMinCursorThick ||
shun_iwasawa e553fc
      m_maxCursorThick != prevMaxCursorThick) {
shun_iwasawa e553fc
    TRectD rect(
shun_iwasawa e553fc
        m_brushPos - TPointD(m_maxCursorThick + 2, m_maxCursorThick + 2),
shun_iwasawa e553fc
        m_brushPos + TPointD(m_maxCursorThick + 2, m_maxCursorThick + 2));
bf1d82
    invalidate(rect);
bf1d82
  }
bf1d82
}
bf1d82
bf1d82
//------------------------------------------------------------------
bf1d82
shun_iwasawa e553fc
TMyPaintBrushStyle *FullColorBrushTool::getBrushStyle() {
bf1d82
  if (TTool::Application *app = getApplication())
shun_iwasawa e553fc
    return dynamic_cast<tmypaintbrushstyle *="">(app->getCurrentLevelStyle());</tmypaintbrushstyle>
bf1d82
  return 0;
shun_iwasawa e3df22
}
shun_iwasawa e3df22
bf1d82
//------------------------------------------------------------------
bf1d82
shun_iwasawa e553fc
void FullColorBrushTool::applyClassicToonzBrushSettings(
shun_iwasawa e553fc
    mypaint::Brush &mypaintBrush) {
shun_iwasawa e553fc
  const double precision       = 1e-5;
bf1d82
  const double hardnessOpacity = 0.1;
bf1d82
shun_iwasawa e553fc
  double minThickness = 0.5 * m_thickness.getValue().first;
shun_iwasawa e553fc
  double maxThickness = 0.5 * m_thickness.getValue().second;
shun_iwasawa e553fc
  double minOpacity   = 0.01 * m_opacity.getValue().first;
shun_iwasawa e553fc
  double maxOpacity   = 0.01 * m_opacity.getValue().second;
shun_iwasawa e553fc
  double hardness     = 0.01 * m_hardness.getValue();
bf1d82
shun_iwasawa e553fc
  TPixelD color = PixelConverter<tpixeld>::from(m_currentColor);</tpixeld>
shun_iwasawa e553fc
  double colorH = 0.0;
shun_iwasawa e553fc
  double colorS = 0.0;
shun_iwasawa e553fc
  double colorV = 0.0;
bf1d82
  RGB2HSV(color.r, color.g, color.b, &colorH, &colorS, &colorV);
bf1d82
bf1d82
  // avoid log(0)
shun_iwasawa e553fc
  if (minThickness < precision) minThickness = precision;
shun_iwasawa e553fc
  if (maxThickness < precision) maxThickness = precision;
bf1d82
bf1d82
  // tune hardness opacity for better visual softness
bf1d82
  hardness *= hardness;
shun_iwasawa e553fc
  double opacityAmplifier = 1.0 - hardnessOpacity + hardness * hardnessOpacity;
bf1d82
  minOpacity *= opacityAmplifier;
bf1d82
  maxOpacity *= opacityAmplifier;
bf1d82
bf1d82
  // reset
bf1d82
  mypaintBrush.fromDefaults();
bf1d82
  mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_OPAQUE_MULTIPLY, 1.0);
shun_iwasawa e553fc
  mypaintBrush.setMappingN(MYPAINT_BRUSH_SETTING_OPAQUE_MULTIPLY,
shun_iwasawa e553fc
                           MYPAINT_BRUSH_INPUT_PRESSURE, 0);
shun_iwasawa e553fc
shun_iwasawa e553fc
  mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_HARDNESS,
shun_iwasawa e553fc
                            0.5 * hardness + 0.5);
shun_iwasawa e553fc
  mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_COLOR_H, colorH / 360.0);
shun_iwasawa e553fc
  mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_COLOR_S, colorS);
shun_iwasawa e553fc
  mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_COLOR_V, colorV);
shun_iwasawa e553fc
  mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_DABS_PER_ACTUAL_RADIUS,
shun_iwasawa e553fc
                            5.0 + hardness * 10.0);
bf1d82
  mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_DABS_PER_BASIC_RADIUS, 0.0);
bf1d82
  mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_DABS_PER_SECOND, 0.0);
bf1d82
bf1d82
  // thickness may be dynamic
bf1d82
  if (minThickness + precision >= maxThickness) {
shun_iwasawa e553fc
    mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_RADIUS_LOGARITHMIC,
shun_iwasawa e553fc
                              log(maxThickness));
shun_iwasawa e553fc
    mypaintBrush.setMappingN(MYPAINT_BRUSH_SETTING_RADIUS_LOGARITHMIC,
shun_iwasawa e553fc
                             MYPAINT_BRUSH_INPUT_PRESSURE, 0);
bf1d82
  } else {
shun_iwasawa e553fc
    double minThicknessLog  = log(minThickness);
shun_iwasawa e553fc
    double maxThicknessLog  = log(maxThickness);
shun_iwasawa e553fc
    double baseThicknessLog = 0.5 * (minThicknessLog + maxThicknessLog);
shun_iwasawa e553fc
    mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_RADIUS_LOGARITHMIC,
shun_iwasawa e553fc
                              baseThicknessLog);
shun_iwasawa e553fc
    mypaintBrush.setMappingN(MYPAINT_BRUSH_SETTING_RADIUS_LOGARITHMIC,
shun_iwasawa e553fc
                             MYPAINT_BRUSH_INPUT_PRESSURE, 2);
shun_iwasawa e553fc
    mypaintBrush.setMappingPoint(MYPAINT_BRUSH_SETTING_RADIUS_LOGARITHMIC,
shun_iwasawa e553fc
                                 MYPAINT_BRUSH_INPUT_PRESSURE, 0, 0.0,
shun_iwasawa e553fc
                                 minThicknessLog - baseThicknessLog);
shun_iwasawa e553fc
    mypaintBrush.setMappingPoint(MYPAINT_BRUSH_SETTING_RADIUS_LOGARITHMIC,
shun_iwasawa e553fc
                                 MYPAINT_BRUSH_INPUT_PRESSURE, 1, 1.0,
shun_iwasawa e553fc
                                 maxThicknessLog - baseThicknessLog);
bf1d82
  }
bf1d82
bf1d82
  // opacity may be dynamic
bf1d82
  if (minOpacity + precision >= maxOpacity) {
bf1d82
    mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_OPAQUE, maxOpacity);
shun_iwasawa e553fc
    mypaintBrush.setMappingN(MYPAINT_BRUSH_SETTING_OPAQUE,
shun_iwasawa e553fc
                             MYPAINT_BRUSH_INPUT_PRESSURE, 0);
bf1d82
  } else {
bf1d82
    mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_OPAQUE, minOpacity);
shun_iwasawa e553fc
    mypaintBrush.setMappingN(MYPAINT_BRUSH_SETTING_OPAQUE,
shun_iwasawa e553fc
                             MYPAINT_BRUSH_INPUT_PRESSURE, 2);
shun_iwasawa e553fc
    mypaintBrush.setMappingPoint(MYPAINT_BRUSH_SETTING_OPAQUE,
shun_iwasawa e553fc
                                 MYPAINT_BRUSH_INPUT_PRESSURE, 0, 0.0, 0.0);
shun_iwasawa e553fc
    mypaintBrush.setMappingPoint(MYPAINT_BRUSH_SETTING_OPAQUE,
shun_iwasawa e553fc
                                 MYPAINT_BRUSH_INPUT_PRESSURE, 1, 1.0,
shun_iwasawa e553fc
                                 maxOpacity - minOpacity);
bf1d82
  }
manongjohn 963976
manongjohn 963976
  if (m_modifierLockAlpha.getValue()) {
manongjohn 963976
    mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_LOCK_ALPHA, 1.0);
manongjohn 963976
  }
bf1d82
}
bf1d82
bf1d82
void FullColorBrushTool::applyToonzBrushSettings(mypaint::Brush &mypaintBrush) {
bf1d82
  TMyPaintBrushStyle *mypaintStyle = getBrushStyle();
bf1d82
bf1d82
  if (mypaintStyle) {
bf1d82
    const double precision = 1e-5;
bf1d82
shun_iwasawa e553fc
    double modifierSize    = m_modifierSize.getValue() * log(2.0);
shun_iwasawa e553fc
    double modifierOpacity = 0.01 * m_modifierOpacity.getValue();
shun_iwasawa 9a4581
    bool modifierEraser    = m_modifierEraser.getValue();
shun_iwasawa 9a4581
    bool modifierLockAlpha = m_modifierLockAlpha.getValue();
bf1d82
shun_iwasawa e553fc
    TPixelD color = PixelConverter<tpixeld>::from(m_currentColor);</tpixeld>
shun_iwasawa e553fc
    double colorH = 0.0;
shun_iwasawa e553fc
    double colorS = 0.0;
shun_iwasawa e553fc
    double colorV = 0.0;
bf1d82
    RGB2HSV(color.r, color.g, color.b, &colorH, &colorS, &colorV);
bf1d82
bf1d82
    mypaintBrush.fromBrush(mypaintStyle->getBrush());
bf1d82
shun_iwasawa e553fc
    float baseSize =
shun_iwasawa e553fc
        mypaintBrush.getBaseValue(MYPAINT_BRUSH_SETTING_RADIUS_LOGARITHMIC);
bf1d82
    float baseOpacity = mypaintBrush.getBaseValue(MYPAINT_BRUSH_SETTING_OPAQUE);
bf1d82
shun_iwasawa e553fc
    mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_RADIUS_LOGARITHMIC,
shun_iwasawa e553fc
                              baseSize + modifierSize);
shun_iwasawa e553fc
    mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_OPAQUE,
shun_iwasawa e553fc
                              baseOpacity * modifierOpacity);
shun_iwasawa e553fc
    mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_COLOR_H, colorH / 360.0);
shun_iwasawa e553fc
    mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_COLOR_S, colorS);
shun_iwasawa e553fc
    mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_COLOR_V, colorV);
572ed1
572ed1
    if (modifierEraser) {
572ed1
      mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_ERASER, 1.0);
572ed1
      mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_LOCK_ALPHA, 0.0);
572ed1
    } else if (modifierLockAlpha) {
572ed1
      // lock-alpha already disables eraser
572ed1
      mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_LOCK_ALPHA, 1.0);
572ed1
    }
bf1d82
  } else {
bf1d82
    applyClassicToonzBrushSettings(mypaintBrush);
bf1d82
  }
bf1d82
}
bf1d82
Toshihiro Shimizu 890ddd
//==========================================================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
FullColorBrushToolNotifier::FullColorBrushToolNotifier(FullColorBrushTool *tool)
shun-iwasawa ec85ad
    : m_tool(tool) {}
shun-iwasawa ec85ad
shun-iwasawa ec85ad
//------------------------------------------------------------
shun-iwasawa ec85ad
shun-iwasawa ec85ad
void FullColorBrushToolNotifier::onActivate() {
bf1d82
  if (TTool::Application *app = m_tool->getApplication()) {
bf1d82
    if (TXshLevelHandle *levelHandle = app->getCurrentLevel()) {
bf1d82
      bool ret = connect(levelHandle, SIGNAL(xshCanvasSizeChanged()), this,
bf1d82
                         SLOT(onCanvasSizeChanged()));
bf1d82
      assert(ret);
bf1d82
    }
bf1d82
    if (TPaletteHandle *paletteHandle = app->getCurrentPalette()) {
shun-iwasawa ec85ad
      bool ret = connect(paletteHandle, SIGNAL(colorStyleChanged(bool)), this,
shun-iwasawa ec85ad
                         SLOT(onColorStyleChanged()));
shun-iwasawa ec85ad
      ret = ret && connect(paletteHandle, SIGNAL(colorStyleSwitched()), this,
shun-iwasawa ec85ad
                           SLOT(onColorStyleChanged()));
shun-iwasawa ec85ad
      ret = ret && connect(paletteHandle, SIGNAL(paletteSwitched()), this,
shun-iwasawa ec85ad
                           SLOT(onColorStyleChanged()));
bf1d82
      assert(ret);
shun-iwasawa ec85ad
    }
shun-iwasawa ec85ad
  }
shun-iwasawa ec85ad
}
shun-iwasawa ec85ad
shun-iwasawa ec85ad
//------------------------------------------------------------
shun-iwasawa ec85ad
shun-iwasawa ec85ad
void FullColorBrushToolNotifier::onDeactivate() {
shun-iwasawa ec85ad
  if (TTool::Application *app = m_tool->getApplication()) {
shun-iwasawa ec85ad
    if (TXshLevelHandle *levelHandle = app->getCurrentLevel()) {
shun-iwasawa ec85ad
      bool ret = disconnect(levelHandle, SIGNAL(xshCanvasSizeChanged()), this,
shun-iwasawa ec85ad
                            SLOT(onCanvasSizeChanged()));
bf1d82
      assert(ret);
shun-iwasawa ec85ad
    }
shun-iwasawa ec85ad
    if (TPaletteHandle *paletteHandle = app->getCurrentPalette()) {
shun-iwasawa ec85ad
      bool ret = disconnect(paletteHandle, SIGNAL(colorStyleChanged(bool)),
shun-iwasawa ec85ad
                            this, SLOT(onColorStyleChanged()));
shun-iwasawa ec85ad
      ret = ret && disconnect(paletteHandle, SIGNAL(colorStyleSwitched()), this,
shun-iwasawa ec85ad
                              SLOT(onColorStyleChanged()));
shun-iwasawa ec85ad
      ret = ret && disconnect(paletteHandle, SIGNAL(paletteSwitched()), this,
shun-iwasawa ec85ad
                              SLOT(onColorStyleChanged()));
c5aed0
      assert(ret);
bf1d82
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==========================================================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
FullColorBrushTool fullColorPencil("T_Brush");