Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tools/tool.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzTools includes
Toshihiro Shimizu 890ddd
#include "tools/toolcommandids.h"
Toshihiro Shimizu 890ddd
#include "tools/toolhandle.h"
Toshihiro Shimizu 890ddd
#include "tools/cursors.h"
Toshihiro Shimizu 890ddd
#include "tools/tooloptions.h"
shun-iwasawa 536025
#include "tools/toolutils.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzQt includes
Toshihiro Shimizu 890ddd
#include "toonzqt/icongenerator.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzLib includes
Toshihiro Shimizu 890ddd
#include "toonzqt/menubarcommand.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshsimplelevel.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshleveltypes.h"
Toshihiro Shimizu 890ddd
#include "toonz/levelproperties.h"
Toshihiro Shimizu 890ddd
#include "toonz/toonzscene.h"
Toshihiro Shimizu 890ddd
#include "toonz/sceneproperties.h"
Toshihiro Shimizu 890ddd
#include "toonz/preferences.h"
Toshihiro Shimizu 890ddd
#include "toonz/tscenehandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/txsheethandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/tframehandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/tcolumnhandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/tobjecthandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/tpalettehandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshlevelhandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshcell.h"
Toshihiro Shimizu 890ddd
#include "toonz/tstageobject.h"
Toshihiro Shimizu 890ddd
#include "toonz/tstageobjectspline.h"
Toshihiro Shimizu 890ddd
#include "toonz/tstageobjecttree.h"
Toshihiro Shimizu 890ddd
#include "toonz/dpiscale.h"
Toshihiro Shimizu 890ddd
#include "toonz/palettecontroller.h"
manongjohn 40a40e
#include "toonz/tonionskinmaskhandle.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzCore includes
Toshihiro Shimizu 890ddd
#include "tvectorimage.h"
Toshihiro Shimizu 890ddd
#include "timagecache.h"
Toshihiro Shimizu 890ddd
#include "tstroke.h"
Toshihiro Shimizu 890ddd
#include "tcolorstyles.h"
Toshihiro Shimizu 890ddd
#include "ttoonzimage.h"
Toshihiro Shimizu 890ddd
#include "trasterimage.h"
manongjohn 40a40e
#include "strokeselection.h"
manongjohn 40a40e
#include "tundo.h"
manongjohn 40a40e
manongjohn 40a40e
#include "toonzvectorbrushtool.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//*****************************************************************************************
Toshihiro Shimizu 890ddd
//    Local namespace
Toshihiro Shimizu 890ddd
//*****************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Global variables
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
typedef std::pair<std::string, ttool::tooltargettype=""> ToolKey;</std::string,>
Toshihiro Shimizu 890ddd
typedef std::map<toolkey, *="" ttool=""> ToolTable;</toolkey,>
Toshihiro Shimizu 890ddd
ToolTable *toolTable = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
std::set<std::string> *toolNames = 0;</std::string>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Local classes
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
struct DummyTool final : public TTool {
Shinya Kitaoka 473e70
  ToolType getToolType() const override {
Shinya Kitaoka 120a6e
    return TTool::LevelReadTool;
Shinya Kitaoka 120a6e
  }  // Test level type
Shinya Kitaoka 120a6e
  ToolTargetType getTargetType() const {
Shinya Kitaoka 120a6e
    return TTool::NoTarget;
Shinya Kitaoka 120a6e
  }  // Works on nothing
Shinya Kitaoka 473e70
  int getCursorId() const override {
Shinya Kitaoka 120a6e
    return ToolCursor::ForbiddenCursor;
Shinya Kitaoka 120a6e
  }  // Forbids everything
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  DummyTool() : TTool("T_Dummy") {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} theDummyTool;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class ToolSelector {
Shinya Kitaoka 120a6e
  std::string m_toolName;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  ToolSelector(std::string toolName) : m_toolName(toolName) {}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void selectTool() {
Shinya Kitaoka 120a6e
    TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
    if (app) app->getCurrentTool()->setTool(QString::fromStdString(m_toolName));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Local functions
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFrameId getNewFrameId(TXshSimpleLevel *sl, int row) {
Shinya Kitaoka 120a6e
  TFrameId fid(row + 1);
Shinya Kitaoka 120a6e
  if (sl->isFid(fid)) {
Shinya Kitaoka 120a6e
    fid = TFrameId(fid.getNumber(), 'a');
Shinya Kitaoka 120a6e
    while (fid.getLetter() < 'z' && sl->isFid(fid))
Shinya Kitaoka 120a6e
      fid = TFrameId(fid.getNumber(), fid.getLetter() + 1);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return fid;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
shun-iwasawa 536025
TFrameId getDesiredFId(TXshCellColumn *column, int r0, TXshSimpleLevel *sl,
shun-iwasawa 536025
                       int row, TFrameId &maxFId) {
shun-iwasawa 536025
  // search upper cells in the current column and return the next fids to be
shun-iwasawa 536025
  // inserted if the maximum fid has no suffix it returns next number, otherwise
shun-iwasawa 536025
  // returns next suffix.
shun-iwasawa 536025
  maxFId = TFrameId(0);
shun-iwasawa 536025
  // in case inserting a new frame on the top
shun-iwasawa 536025
  if (row <= r0) return TFrameId(1);
shun-iwasawa 536025
  TFrameId neighborFId;
shun-iwasawa 536025
  for (int r = row - 1; r >= r0; r--) {
shun-iwasawa 536025
    if (sl != column->getCell(r).getSimpleLevel()) continue;
shun-iwasawa 536025
    TFrameId tmpFId = column->getCell(r).getFrameId();
shun-iwasawa 536025
    if (neighborFId.isEmptyFrame()) neighborFId = tmpFId;
shun-iwasawa 536025
    if (maxFId < tmpFId) maxFId = tmpFId;
shun-iwasawa 536025
  }
shun-iwasawa 536025
  if (maxFId.getLetter() && maxFId.getLetter() < 'z' && maxFId == neighborFId)
shun-iwasawa 536025
    return TFrameId(maxFId.getNumber(), maxFId.getLetter() + 1);
shun-iwasawa 536025
  else
shun-iwasawa 536025
    return TFrameId(maxFId.getNumber() + 1);
shun-iwasawa 536025
}
shun-iwasawa 536025
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//*****************************************************************************************
Toshihiro Shimizu 890ddd
//    TTool  static members
Toshihiro Shimizu 890ddd
//*****************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TTool::Application *TTool::m_application   = 0;
Toshihiro Shimizu 890ddd
std::set<tframeid> TTool::m_selectedFrames = std::set<tframeid>();</tframeid></tframeid>
Shinya Kitaoka 120a6e
bool TTool::m_isLevelCreated               = false;
Shinya Kitaoka 120a6e
bool TTool::m_isFrameCreated               = false;
shun-iwasawa 536025
bool TTool::m_isLevelRenumbererd           = false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// m_cellsData
Toshihiro Shimizu 890ddd
// brutto brutto. fix quick & dirty del baco #6213 (undo con animation sheet)
Toshihiro Shimizu 890ddd
// bisogna ripensare la logica degli undo e del touchImage
Toshihiro Shimizu 890ddd
// m_cellsData viene inizializzato nel touchImage() in modalita' animation sheet
Shinya Kitaoka 120a6e
// contiene una o due terne che rappresentano range di celle (dell'xsheet)
Shinya Kitaoka 120a6e
// modificate dall'inserimento
Toshihiro Shimizu 890ddd
// di un nuovo frame: [r0,r1,type].
Toshihiro Shimizu 890ddd
// type = 0 : vecchio (cella[r0-1]) => nuovo
Toshihiro Shimizu 890ddd
// type = 1 : vuoto => vecchio (cella[r0-1])
Toshihiro Shimizu 890ddd
// type = 2 : vuoto => nuovo
Shinya Kitaoka 120a6e
// cfr. il codice di TTool::touchImage()
Shinya Kitaoka 120a6e
// ToolUtils::TToolUndo::removeLevelAndFrameIfNeeded()
Toshihiro Shimizu 890ddd
shun-iwasawa 536025
std::vector<ttool::cellops> TTool::m_cellsData;</ttool::cellops>
shun-iwasawa 536025
std::vector<tframeid> TTool::m_oldFids;</tframeid>
shun-iwasawa 536025
std::vector<tframeid> TTool::m_newFids;</tframeid>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//*****************************************************************************************
Toshihiro Shimizu 890ddd
//    TTool  implementation
Toshihiro Shimizu 890ddd
//*****************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 3bfa54
TTool::TTool(std::string name)
Shinya Kitaoka 120a6e
    : m_name(name)
Shinya Kitaoka 120a6e
    , m_viewer(0)
Shinya Kitaoka 120a6e
    , m_targetType(NoTarget)
Shinya Kitaoka 120a6e
    , m_enabled(true)
Shinya Kitaoka 120a6e
    , m_active(false)
Shinya Kitaoka 120a6e
    , m_picking(false) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TTool *TTool::getTool(std::string toolName, ToolTargetType targetType) {
Shinya Kitaoka 120a6e
  if (!toolTable) return 0;
Shinya Kitaoka 120a6e
  ToolTable::iterator it =
Shinya Kitaoka 120a6e
      toolTable->find(std::make_pair(toolName, targetType));
Shinya Kitaoka 120a6e
  if (it == toolTable->end()) return 0;
Shinya Kitaoka 120a6e
  return it->second;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TTool::bind(int targetType) {
Shinya Kitaoka 120a6e
  m_targetType = targetType;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!toolTable) toolTable = new ToolTable();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!toolNames) toolNames = new std::set<std::string>();</std::string>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::string name = getName();
Shinya Kitaoka 120a6e
  if (toolNames->count(name) == 0) {
Shinya Kitaoka 120a6e
    toolNames->insert(name);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Initialize with the dummy tool
Shinya Kitaoka 120a6e
    toolTable->insert(
Shinya Kitaoka 120a6e
        std::make_pair(std::make_pair(name, ToonzImage), &theDummyTool));
Shinya Kitaoka 120a6e
    toolTable->insert(
Shinya Kitaoka 120a6e
        std::make_pair(std::make_pair(name, VectorImage), &theDummyTool));
Shinya Kitaoka 120a6e
    toolTable->insert(
Shinya Kitaoka 120a6e
        std::make_pair(std::make_pair(name, RasterImage), &theDummyTool));
Shinya Kitaoka 120a6e
    toolTable->insert(
Shinya Kitaoka 120a6e
        std::make_pair(std::make_pair(name, MeshImage), &theDummyTool));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    ToolSelector *toolSelector = new ToolSelector(name);
Shinya Kitaoka 120a6e
    CommandManager::instance()->setHandler(
Shinya Kitaoka 120a6e
        name.c_str(), new CommandHandlerHelper<toolselector>(</toolselector>
Shinya Kitaoka 120a6e
                          toolSelector, &ToolSelector::selectTool));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (targetType & ToonzImage)
Shinya Kitaoka 120a6e
    (*toolTable)[std::make_pair(name, ToonzImage)] = this;
Shinya Kitaoka 120a6e
  if (targetType & VectorImage)
Shinya Kitaoka 120a6e
    (*toolTable)[std::make_pair(name, VectorImage)] = this;
Shinya Kitaoka 120a6e
  if (targetType & RasterImage)
Shinya Kitaoka 120a6e
    (*toolTable)[std::make_pair(name, RasterImage)] = this;
Shinya Kitaoka 120a6e
  if (targetType & MeshImage)
Shinya Kitaoka 120a6e
    (*toolTable)[std::make_pair(name, MeshImage)] = this;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
ToolOptionsBox *TTool::createOptionsBox() {
Shinya Kitaoka 120a6e
  TPaletteHandle *currPalette =
Shinya Kitaoka 120a6e
      m_application->getPaletteController()->getCurrentLevelPalette();
Shinya Kitaoka 120a6e
  ToolHandle *currTool = m_application->getCurrentTool();
Shinya Kitaoka 120a6e
  return new GenericToolOptionsBox(0, this, currPalette, 0, currTool);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
double TTool::getPixelSize() const {
Shinya Kitaoka 120a6e
  return m_viewer ? m_viewer->getPixelSize() : 1.0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TXshCell TTool::getImageCell() {
Shinya Kitaoka 120a6e
  assert(m_application);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TXshCell result;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TFrameHandle *currentFrame    = m_application->getCurrentFrame();
Shinya Kitaoka 120a6e
  TXshLevelHandle *currentLevel = m_application->getCurrentLevel();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (currentFrame->isEditingLevel()) {
Shinya Kitaoka 120a6e
    if (TXshLevel *xl = currentLevel->getLevel()) {
Shinya Kitaoka 120a6e
      if (TXshSimpleLevel *sl = xl->getSimpleLevel()) {
Shinya Kitaoka 120a6e
        result.m_level   = xl;
Shinya Kitaoka 120a6e
        result.m_frameId = currentFrame->getFid();
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    if (TXsheet *xsh = m_application->getCurrentXsheet()->getXsheet()) {
Shinya Kitaoka 120a6e
      if (!m_application->getCurrentObject()->isSpline()) {
Shinya Kitaoka 120a6e
        int row = currentFrame->getFrame();
Shinya Kitaoka 120a6e
        int col = m_application->getCurrentColumn()->getColumnIndex();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        result = xsh->getCell(row, col);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return result;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TImage *TTool::getImage(bool toBeModified, int subsampling) {
Shinya Kitaoka 120a6e
  assert(m_application);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_application->getCurrentFrame()->isPlaying())
Shinya Kitaoka 120a6e
    toBeModified =
Shinya Kitaoka 120a6e
        false;  // In playback mode, you are not going to modify images
Shinya Kitaoka 120a6e
                // Probably useless - tools are disabled when playing...
Shinya Kitaoka 120a6e
  const TXshCell &cell = getImageCell();
Shinya Kitaoka 120a6e
  if (cell.isEmpty()) {
Shinya Kitaoka 120a6e
    TObjectHandle *currentObject = m_application->getCurrentObject();
Shinya Kitaoka 120a6e
    return currentObject->isSpline() ? currentObject->getSplineImage()
Shinya Kitaoka 120a6e
                                     : (TImage *)0;
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    return cell.getImage(toBeModified, subsampling).getPointer();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TImage *TTool::touchImage() {
Shinya Kitaoka 120a6e
  if (!m_application) return 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_cellsData.clear();
shun-iwasawa 536025
  m_oldFids.clear();
shun-iwasawa 536025
  m_newFids.clear();
Shinya Kitaoka 120a6e
shun-iwasawa 536025
  m_isLevelCreated     = false;
shun-iwasawa 536025
  m_isFrameCreated     = false;
shun-iwasawa 536025
  m_isLevelRenumbererd = false;
shun-iwasawa 536025
  Preferences *pref    = Preferences::instance();
Shinya Kitaoka 120a6e
shun-iwasawa 536025
  bool isAutoCreateEnabled        = pref->isAutoCreateEnabled();
shun-iwasawa 536025
  bool animationSheetEnabled      = pref->isAnimationSheetEnabled();
shun-iwasawa 536025
  bool isAutoStretchEnabled       = pref->isAutoStretchEnabled();
shun-iwasawa 536025
  bool isAutoRenumberEnabled      = pref->isAutorenumberEnabled();
shun-iwasawa 536025
  bool isCreateInHoldCellsEnabled = pref->isCreationInHoldCellsEnabled();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TFrameHandle *currentFrame    = m_application->getCurrentFrame();
Shinya Kitaoka 120a6e
  TXshLevelHandle *currentLevel = m_application->getCurrentLevel();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (currentFrame->isEditingLevel()) {
Shinya Kitaoka 120a6e
    // Editing level
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // no level => return 0
Shinya Kitaoka 120a6e
    TXshLevel *xl = currentLevel->getLevel();
Shinya Kitaoka 120a6e
    if (!xl) return 0;
Shinya Kitaoka 120a6e
    TXshSimpleLevel *sl = xl->getSimpleLevel();
Shinya Kitaoka 120a6e
    if (!sl || sl->isEmpty()) return 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TFrameId fid = currentFrame->getFid();
Shinya Kitaoka 120a6e
    TImageP img  = sl->getFrame(fid, true);
Shinya Kitaoka 120a6e
    if (!img) {
Shinya Kitaoka 120a6e
      // no drawing found
Shinya Kitaoka 120a6e
      if (sl->isSubsequence() || sl->isReadOnly() || !isAutoCreateEnabled)
Shinya Kitaoka 120a6e
        return 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // create a new drawing
Shinya Kitaoka 120a6e
      img = sl->createEmptyFrame();
Shinya Kitaoka 120a6e
      sl->setFrame(fid, img);
Shinya Kitaoka 120a6e
      currentLevel->notifyLevelChange();
Shinya Kitaoka 120a6e
      m_isFrameCreated = true;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    return img.getPointer();
shun-iwasawa 536025
  }
Shinya Kitaoka 120a6e
shun-iwasawa 536025
  //- - - - editing xsheet case starts here - - - -
Shinya Kitaoka 120a6e
shun-iwasawa 536025
  if (m_application->getCurrentObject()->isSpline()) return 0;
Shinya Kitaoka 120a6e
shun-iwasawa 536025
  TSceneHandle *currentScene = m_application->getCurrentScene();
shun-iwasawa 536025
  ToonzScene *scene          = currentScene->getScene();
shun-iwasawa 536025
  int row                    = currentFrame->getFrame();
shun-iwasawa 536025
  int col = m_application->getCurrentColumn()->getColumnIndex();
shun-iwasawa 536025
  if (col < 0) return 0;
shun-iwasawa 536025
shun-iwasawa 536025
  TXsheetHandle *currentXsheet = m_application->getCurrentXsheet();
shun-iwasawa 536025
  TXsheet *xsh                 = currentXsheet->getXsheet();
shun-iwasawa 536025
  if (!xsh) return 0;
shun-iwasawa 536025
shun-iwasawa 536025
  TXshCell cell       = xsh->getCell(row, col);
shun-iwasawa 536025
  TXshSimpleLevel *sl = cell.getSimpleLevel();
shun-iwasawa 536025
shun-iwasawa 536025
  if (sl) {
shun-iwasawa 536025
    // current cell is not empty
shun-iwasawa 536025
    if (isCreateInHoldCellsEnabled && row > 0 &&
shun-iwasawa 536025
        xsh->getCell(row - 1, col) == xsh->getCell(row, col)) {
shun-iwasawa 536025
      // CreateInHoldCells is enabled and the current cell is a "hold".
shun-iwasawa 536025
      // We must create a new drawing.
shun-iwasawa 536025
      // measure the hold length (starting from the current row) : r0-r1
shun-iwasawa 536025
      int r0 = row, r1 = row;
shun-iwasawa 536025
      if (isAutoStretchEnabled)
shun-iwasawa 536025
        while (xsh->getCell(r1 + 1, col) == cell) r1++;
shun-iwasawa 536025
      // find the proper frameid (possibly addisng suffix, in order to avoid a
shun-iwasawa 536025
      // fid already used)
shun-iwasawa 536025
      // find the proper frameid
shun-iwasawa 536025
      TFrameId fid;
shun-iwasawa 536025
      TXshCellColumn *column = xsh->getColumn(col)->getCellColumn();
shun-iwasawa 536025
      if (isAutoRenumberEnabled && column) {
shun-iwasawa 536025
        TFrameId maxFid;
shun-iwasawa 536025
        if (animationSheetEnabled) {
shun-iwasawa 536025
          fid    = TFrameId(row + 1);
shun-iwasawa 536025
          maxFid = TFrameId(row);
shun-iwasawa 536025
        } else {
shun-iwasawa 536025
          int r_begin, r_end;
shun-iwasawa 536025
          column->getRange(r_begin, r_end);
shun-iwasawa 536025
          fid = getDesiredFId(column, r_begin, sl, row, maxFid);
shun-iwasawa 536025
        }
shun-iwasawa 536025
        // renumber fids
shun-iwasawa 536025
        sl->getFids(m_oldFids);
shun-iwasawa 536025
        m_isLevelRenumbererd = ToolUtils::renumberForInsertFId(
shun-iwasawa 536025
            sl, fid, maxFid, scene->getTopXsheet());
shun-iwasawa 536025
        if (m_isLevelRenumbererd) sl->getFids(m_newFids);
shun-iwasawa 536025
      } else
shun-iwasawa 536025
        fid = (animationSheetEnabled) ? getNewFrameId(sl, row)
shun-iwasawa 536025
                                      : sl->index2fid(sl->getFrameCount());
shun-iwasawa 536025
      // create the new drawing
shun-iwasawa 536025
      TImageP img      = sl->createEmptyFrame();
shun-iwasawa 536025
      m_isFrameCreated = true;
shun-iwasawa 536025
      // insert the drawing in the level
shun-iwasawa 536025
      sl->setFrame(fid, img);
shun-iwasawa 536025
      // update the cell
shun-iwasawa 536025
      cell = TXshCell(sl, fid);
shun-iwasawa 536025
      // update the xsheet (change the current cell and possibly all the
shun-iwasawa 536025
      // following "hold")
shun-iwasawa 536025
      for (int r = r0; r <= r1; r++) xsh->setCell(r, col, cell);
shun-iwasawa 536025
      // notify
shun-iwasawa 536025
      currentXsheet->notifyXsheetChanged();
shun-iwasawa 536025
      currentScene->notifyCastChange();
shun-iwasawa 536025
      currentLevel->notifyLevelChange();
shun-iwasawa 536025
      m_cellsData.push_back({r0, r1, CellOps::ExistingToNew});
shun-iwasawa 536025
    }
shun-iwasawa 536025
    // if the level does not contain a frame in the current cell
shun-iwasawa 536025
    // (i.e. drawing on the cell with red numbers)
shun-iwasawa 536025
    else if (!sl->isFid(cell.getFrameId())) {
shun-iwasawa 536025
      // no drawing found
shun-iwasawa 536025
      if (sl->isSubsequence() || sl->isReadOnly() || !isAutoCreateEnabled)
shun-iwasawa 536025
        return 0;
shun-iwasawa 536025
      // create a new drawing
shun-iwasawa 536025
      TImageP img = sl->createEmptyFrame();
shun-iwasawa 536025
      sl->setFrame(cell.getFrameId(), img);
shun-iwasawa 536025
      currentXsheet->notifyXsheetChanged();
shun-iwasawa 536025
      currentLevel->notifyLevelChange();
shun-iwasawa 536025
      m_isFrameCreated = true;
shun-iwasawa 536025
      return img.getPointer();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
shun-iwasawa 536025
    // we've found the image. return it.
shun-iwasawa 536025
    return cell.getImage(true).getPointer();
shun-iwasawa 536025
  }
shun-iwasawa 536025
shun-iwasawa 536025
  // current cell is empty.
shun-iwasawa 536025
  if (!isAutoCreateEnabled) return 0;
shun-iwasawa 536025
shun-iwasawa 536025
  // get the column range
shun-iwasawa 536025
  int r0, r1;
shun-iwasawa 536025
  xsh->getCellRange(col, r0, r1);
shun-iwasawa 536025
  // in case the column is not empty
shun-iwasawa 536025
  if (r0 <= r1) {
shun-iwasawa 536025
    // We must create a new drawing in the column level and possibly add "holds"
shun-iwasawa 536025
shun-iwasawa 536025
    // find the last not-empty cell before the current one (a) and the first
shun-iwasawa 536025
    // after (b)
shun-iwasawa 536025
    int a = row - 1, b = row + 1;
shun-iwasawa 536025
    while (a >= r0 && xsh->getCell(a, col).isEmpty()) a--;
shun-iwasawa 536025
    while (b <= r1 && xsh->getCell(b, col).isEmpty()) b++;
shun-iwasawa 536025
shun-iwasawa 536025
    // find the level we must attach to
shun-iwasawa 536025
    if (a >= r0) {
shun-iwasawa 536025
      // there is a not-empty cell before the current one
shun-iwasawa 536025
      sl = xsh->getCell(a, col).getSimpleLevel();
shun-iwasawa 536025
    } else if (b <= r1) {
shun-iwasawa 536025
      sl = xsh->getCell(b, col).getSimpleLevel();
shun-iwasawa 536025
    }
shun-iwasawa 536025
    if (sl && !sl->isSubsequence() && !sl->isReadOnly()) {
shun-iwasawa 536025
      // note: sl should be always !=0 (the column is not empty)
shun-iwasawa 536025
      // if - for some reason - it is == 0 or it is not editable,
shun-iwasawa 536025
      // then we skip to empty-column behaviour
shun-iwasawa 536025
shun-iwasawa 536025
      // create the drawing
shun-iwasawa 536025
      // find the proper frameid
shun-iwasawa 536025
      TFrameId fid;
shun-iwasawa 536025
      TXshCellColumn *column = xsh->getColumn(col)->getCellColumn();
shun-iwasawa 536025
      if (isAutoRenumberEnabled && column) {
shun-iwasawa 536025
        TFrameId maxFid(row);
shun-iwasawa 536025
        fid = (animationSheetEnabled)
shun-iwasawa 536025
                  ? TFrameId(row + 1)
shun-iwasawa 536025
                  : getDesiredFId(column, r0, sl, row, maxFid);
shun-iwasawa 536025
        sl->getFids(m_oldFids);
shun-iwasawa 536025
        m_isLevelRenumbererd = ToolUtils::renumberForInsertFId(
shun-iwasawa 536025
            sl, fid, maxFid, scene->getTopXsheet());
shun-iwasawa 536025
        if (m_isLevelRenumbererd) sl->getFids(m_newFids);
shun-iwasawa 536025
      } else
shun-iwasawa 536025
        fid = (animationSheetEnabled) ? getNewFrameId(sl, row)
shun-iwasawa 536025
                                      : sl->index2fid(sl->getFrameCount());
shun-iwasawa 536025
      // create the new drawing
shun-iwasawa 536025
      TImageP img      = sl->createEmptyFrame();
shun-iwasawa 536025
      m_isFrameCreated = true;
shun-iwasawa 536025
      // insert the drawing in the level
shun-iwasawa 536025
      sl->setFrame(fid, img);
shun-iwasawa 536025
      // update the cell
shun-iwasawa 536025
      cell = TXshCell(sl, fid);
shun-iwasawa 536025
      xsh->setCell(row, col, cell);
shun-iwasawa 536025
shun-iwasawa 536025
      // create holds
shun-iwasawa 536025
      if (!isAutoStretchEnabled) {
shun-iwasawa 536025
        m_cellsData.push_back({row, row, CellOps::BlankToNew});
shun-iwasawa 536025
      } else {
shun-iwasawa 536025
        if (a >= r0) {
shun-iwasawa 536025
          // create a hold before : [a+1, row-1]
shun-iwasawa 536025
          TXshCell aCell = xsh->getCell(a, col);
shun-iwasawa 536025
          for (int i = a + 1; i < row; i++) xsh->setCell(i, col, aCell);
shun-iwasawa 536025
          m_cellsData.push_back({a + 1, row - 1, CellOps::BlankToExisting});
shun-iwasawa 536025
shun-iwasawa 536025
          if (b <= r1 && xsh->getCell(b, col).getSimpleLevel() == sl) {
shun-iwasawa 536025
            // create also a hold after
Shinya Kitaoka 120a6e
            for (int i = row + 1; i < b; i++) xsh->setCell(i, col, cell);
shun-iwasawa 536025
            m_cellsData.push_back({row, b - 1, CellOps::BlankToNew});
shun-iwasawa 536025
          } else {
shun-iwasawa 536025
            m_cellsData.push_back({row, row, CellOps::BlankToNew});
Shinya Kitaoka 120a6e
          }
shun-iwasawa 536025
        } else if (b <= r1) {
shun-iwasawa 536025
          // create a hold after
shun-iwasawa 536025
          for (int i = row + 1; i < b; i++) xsh->setCell(i, col, cell);
shun-iwasawa 536025
          m_cellsData.push_back({row, b - 1, CellOps::BlankToNew});
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      // notify & return
Shinya Kitaoka 120a6e
      currentXsheet->notifyXsheetChanged();
Shinya Kitaoka 120a6e
      currentScene->notifyCastChange();
Shinya Kitaoka 120a6e
      currentLevel->notifyLevelChange();
Shinya Kitaoka 120a6e
      return cell.getImage(true).getPointer();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
shun-iwasawa 536025
shun-iwasawa 536025
  // - - - - empty column case starts here - - - -
shun-iwasawa 536025
  // autoCreate is enabled: we must create a new level
shun-iwasawa 536025
  int levelType    = pref->getDefLevelType();
shun-iwasawa 536025
  TXshLevel *xl    = scene->createNewLevel(levelType);
shun-iwasawa 536025
  sl               = xl->getSimpleLevel();
shun-iwasawa 536025
  m_isLevelCreated = true;
shun-iwasawa 536025
shun-iwasawa 536025
  // create the drawing
shun-iwasawa 536025
  TFrameId fid = animationSheetEnabled ? getNewFrameId(sl, row) : TFrameId(1);
shun-iwasawa 536025
  TImageP img  = sl->createEmptyFrame();
shun-iwasawa 536025
  m_isFrameCreated = true;
shun-iwasawa 536025
  sl->setFrame(fid, img);
shun-iwasawa 536025
  cell = TXshCell(sl, fid);
shun-iwasawa 536025
  xsh->setCell(row, col, cell);
shun-iwasawa 536025
  m_cellsData.push_back({row, row, CellOps::BlankToNew});  // vuoto => nuovo
shun-iwasawa 536025
  currentXsheet->notifyXsheetChanged();
shun-iwasawa 536025
  currentScene->notifyCastChange();
shun-iwasawa 536025
  currentLevel->notifyLevelChange();
shun-iwasawa 536025
  return img.getPointer();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TTool::updateToolsPropertiesTranslation() {
Shinya Kitaoka 120a6e
  ToolTable::iterator tt, tEnd(toolTable->end());
Shinya Kitaoka 120a6e
  for (tt = toolTable->begin(); tt != tEnd; ++tt)
Shinya Kitaoka 120a6e
    tt->second->updateTranslation();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TTool::invalidate(const TRectD &rect) {
Shinya Kitaoka 120a6e
  if (m_viewer) {
Shinya Kitaoka 120a6e
    if (rect.isEmpty())
Shinya Kitaoka 120a6e
      m_viewer->GLInvalidateAll();
Shinya Kitaoka 120a6e
    else {
Shinya Kitaoka 120a6e
      TPointD dpiScale(1, 1);
Shinya Kitaoka 120a6e
      TXshSimpleLevel *sl =
Shinya Kitaoka 120a6e
          getApplication()->getCurrentLevel()->getSimpleLevel();
Shinya Kitaoka 120a6e
      if (sl) dpiScale = getCurrentDpiScale(sl, getCurrentFid());
Shinya Kitaoka 120a6e
      m_viewer->GLInvalidateRect(getCurrentColumnMatrix() *
Shinya Kitaoka 120a6e
                                 TScale(dpiScale.x, dpiScale.y) * rect);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
shun_iwasawa bc352c
int TTool::pick(const TPointD &p) {
Shinya Kitaoka 120a6e
  if (!m_viewer) return 0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_picking = true;
Shinya Kitaoka 120a6e
  int ret   = m_viewer->pick(p);
Shinya Kitaoka 120a6e
  m_picking = false;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return ret;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TXsheet *TTool::getXsheet() const {
Shinya Kitaoka 120a6e
  if (!m_application) return 0;
Shinya Kitaoka 120a6e
  return m_application->getCurrentXsheet()->getXsheet();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int TTool::getFrame() {
Shinya Kitaoka 120a6e
  if (!m_application) return 0;
Shinya Kitaoka 120a6e
  return m_application->getCurrentFrame()->getFrame();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int TTool::getColumnIndex() {
Shinya Kitaoka 120a6e
  if (!m_application) return 0;
Shinya Kitaoka 120a6e
  return m_application->getCurrentColumn()->getColumnIndex();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TStageObjectId TTool::getObjectId() {
Shinya Kitaoka 120a6e
  if (!m_application) return TStageObjectId();
Shinya Kitaoka 120a6e
  return m_application->getCurrentObject()->getObjectId();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TTool::Application *TTool::getApplication() {
Shinya Kitaoka 120a6e
  if (m_application == 0)
Shinya Kitaoka 120a6e
    assert(!"you MUST call the TTool::setApplication function in the main of the program!");
Shinya Kitaoka 120a6e
  return m_application;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*! Notify change of current image: update icon and notify level change.
Toshihiro Shimizu 890ddd
    If current object is a spline commit spline chenged.
Toshihiro Shimizu 890ddd
    If current mode is EditingLevel touch current frame.
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
void TTool::notifyImageChanged() {
Shinya Kitaoka 120a6e
  onImageChanged();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!m_application) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_application->getCurrentScene()->setDirtyFlag(true);
Shinya Kitaoka 120a6e
  if (m_application->getCurrentFrame()->isEditingLevel()) {
Shinya Kitaoka 120a6e
    TXshLevel *xl = m_application->getCurrentLevel()->getLevel();
Shinya Kitaoka 120a6e
    if (!xl) return;
Shinya Kitaoka 120a6e
    TXshSimpleLevel *sl = xl->getSimpleLevel();
Shinya Kitaoka 120a6e
    if (!sl) return;
Shinya Kitaoka 120a6e
    TFrameId fid = m_application->getCurrentFrame()->getFid();
Shinya Kitaoka 120a6e
    sl->touchFrame(fid);
Shinya Kitaoka 120a6e
    // sl->setDirtyFlag(true);
Shinya Kitaoka 120a6e
    IconGenerator::instance()->invalidate(sl, fid);
Shinya Kitaoka 120a6e
    IconGenerator::instance()->invalidateSceneIcon();
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    TXsheet *xsh = m_application->getCurrentXsheet()->getXsheet();
Shinya Kitaoka 120a6e
    if (!xsh) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TObjectHandle *currentObject = m_application->getCurrentObject();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (currentObject->isSpline()) {
Shinya Kitaoka 120a6e
      m_application->getCurrentObject()->commitSplineChanges();
Shinya Kitaoka 120a6e
      TStageObject *pegbar = xsh->getStageObject(currentObject->getObjectId());
Shinya Kitaoka 120a6e
      IconGenerator::instance()->invalidate(pegbar->getSpline());
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      int row = m_application->getCurrentFrame()->getFrame();
Shinya Kitaoka 120a6e
      int col = m_application->getCurrentColumn()->getColumnIndex();
Shinya Kitaoka 120a6e
      if (col < 0) return;
Shinya Kitaoka 120a6e
      TXshCell cell       = xsh->getCell(row, col);
Shinya Kitaoka 120a6e
      TXshSimpleLevel *sl = cell.getSimpleLevel();
Shinya Kitaoka 120a6e
      if (sl) {
Shinya Kitaoka 120a6e
        IconGenerator::instance()->invalidate(sl, cell.m_frameId);
Shinya Kitaoka 120a6e
        sl->touchFrame(cell.m_frameId);
Shinya Kitaoka 120a6e
        IconGenerator::instance()->invalidateSceneIcon();
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  m_application->getCurrentLevel()->notifyLevelChange();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*! Notify change of image in \b fid: update icon and notify level change.
shun-iwasawa d40c36
 */
Shinya Kitaoka 120a6e
void TTool::notifyImageChanged(const TFrameId &fid) {
Shinya Kitaoka 120a6e
  onImageChanged();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!m_application) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_application->getCurrentScene()->setDirtyFlag(true);
Shinya Kitaoka 120a6e
  if (m_application->getCurrentFrame()->isEditingLevel()) {
Shinya Kitaoka 120a6e
    TXshLevel *xl = m_application->getCurrentLevel()->getLevel();
Shinya Kitaoka 120a6e
    if (!xl) return;
Shinya Kitaoka 120a6e
    TXshSimpleLevel *sl = xl->getSimpleLevel();
Shinya Kitaoka 120a6e
    if (!sl) return;
Shinya Kitaoka 120a6e
    sl->setDirtyFlag(true);
Shinya Kitaoka 120a6e
    IconGenerator::instance()->invalidate(sl, fid);
Shinya Kitaoka 120a6e
    IconGenerator::instance()->invalidateSceneIcon();
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    int row = m_application->getCurrentFrame()->getFrame();
Shinya Kitaoka 120a6e
    int col = m_application->getCurrentColumn()->getColumnIndex();
Shinya Kitaoka 120a6e
    if (col < 0) return;
Shinya Kitaoka 120a6e
    TXsheet *xsh = m_application->getCurrentXsheet()->getXsheet();
Shinya Kitaoka 120a6e
    if (!xsh) return;
Shinya Kitaoka 120a6e
    TXshCell cell       = xsh->getCell(row, col);
Shinya Kitaoka 120a6e
    TXshSimpleLevel *sl = cell.getSimpleLevel();
Shinya Kitaoka 120a6e
    if (sl) {
Shinya Kitaoka 120a6e
      IconGenerator::instance()->invalidate(sl, fid);
Shinya Kitaoka 120a6e
      IconGenerator::instance()->invalidateSceneIcon();
Shinya Kitaoka 120a6e
      sl->setDirtyFlag(true);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  m_application->getCurrentLevel()->notifyLevelChange();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFrameId TTool::getCurrentFid() const {
Shinya Kitaoka 120a6e
  if (!m_application) return TFrameId();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TFrameHandle *fh = m_application->getCurrentFrame();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (fh->isEditingLevel()) return fh->getFid();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int row = m_application->getCurrentFrame()->getFrame();
Shinya Kitaoka 120a6e
  int col = m_application->getCurrentColumn()->getColumnIndex();
Shinya Kitaoka 120a6e
  TXshCell cell =
Shinya Kitaoka 120a6e
      m_application->getCurrentXsheet()->getXsheet()->getCell(row, col);
Shinya Kitaoka 120a6e
  if (cell.isEmpty()) return TFrameId::NO_FRAME;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return cell.getFrameId();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TAffine TTool::getCurrentColumnMatrix() const {
Shinya Kitaoka 120a6e
  return getColumnMatrix(m_application->getCurrentColumn()->getColumnIndex());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TAffine TTool::getCurrentColumnParentMatrix() const {
Shinya Kitaoka 120a6e
  if (!m_application) return TAffine();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TFrameHandle *fh = m_application->getCurrentFrame();
Shinya Kitaoka 120a6e
  if (fh->isEditingLevel()) return TAffine();
Shinya Kitaoka 120a6e
  int frame       = fh->getFrame();
Shinya Kitaoka 120a6e
  int columnIndex = m_application->getCurrentColumn()->getColumnIndex();
Shinya Kitaoka 120a6e
  TXsheet *xsh    = m_application->getCurrentXsheet()->getXsheet();
Shinya Kitaoka 120a6e
  TStageObjectId parentId =
Shinya Kitaoka 120a6e
      xsh->getStageObjectParent(TStageObjectId::ColumnId(columnIndex));
Shinya Kitaoka 120a6e
  return xsh->getPlacement(parentId, frame);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TAffine TTool::getCurrentObjectParentMatrix() const {
Shinya Kitaoka 120a6e
  if (!m_application) return TAffine();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_application->getCurrentXsheet()->getXsheet();
Shinya Kitaoka 120a6e
  int frame    = m_application->getCurrentFrame()->getFrame();
Shinya Kitaoka 120a6e
  TStageObjectId currentObjectId =
Shinya Kitaoka 120a6e
      m_application->getCurrentObject()->getObjectId();
Shinya Kitaoka 120a6e
  if (currentObjectId == TStageObjectId::NoneId) return TAffine();
Shinya Kitaoka 120a6e
  TStageObjectId parentId = xsh->getStageObjectParent(currentObjectId);
Shinya Kitaoka 120a6e
  if (parentId == TStageObjectId::NoneId)
Shinya Kitaoka 120a6e
    return TAffine();
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    return xsh->getPlacement(parentId, frame);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TAffine TTool::getColumnMatrix(int columnIndex) const {
Shinya Kitaoka 120a6e
  if (!m_application) return TAffine();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TFrameHandle *fh = m_application->getCurrentFrame();
Shinya Kitaoka 120a6e
  if (fh->isEditingLevel()) return TAffine();
shun-iwasawa 555106
  int frame    = fh->getFrame();
shun-iwasawa 555106
  TXsheet *xsh = m_application->getCurrentXsheet()->getXsheet();
shun-iwasawa 555106
  TStageObjectId columnObjId =
shun-iwasawa 555106
      (columnIndex >= 0)
shun-iwasawa 555106
          ? TStageObjectId::ColumnId(columnIndex)
shun-iwasawa 555106
          : TStageObjectId::CameraId(xsh->getCameraColumnIndex());
shun-iwasawa 555106
  TAffine columnPlacement = xsh->getPlacement(columnObjId, frame);
shun-iwasawa 555106
  double columnZ          = xsh->getZ(columnObjId, frame);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TStageObjectId cameraId = xsh->getStageObjectTree()->getCurrentCameraId();
Shinya Kitaoka 120a6e
  TStageObject *camera    = xsh->getStageObject(cameraId);
Shinya Kitaoka 120a6e
  TAffine cameraPlacement = camera->getPlacement(frame);
Shinya Kitaoka 120a6e
  double cameraZ          = camera->getZ(frame);
Shinya Kitaoka 120a6e
shun-iwasawa 555106
  TStageObject *object = xsh->getStageObject(columnObjId);
Shinya Kitaoka 120a6e
  TAffine placement;
Shinya Kitaoka 120a6e
  TStageObject::perspective(placement, cameraPlacement, cameraZ,
Shinya Kitaoka 120a6e
                            columnPlacement, columnZ,
Shinya Kitaoka 120a6e
                            object->getGlobalNoScaleZ());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return placement;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TAffine TTool::getCurrentObjectParentMatrix2() const {
Shinya Kitaoka 120a6e
  TTool::Application *app = m_application;
Shinya Kitaoka 120a6e
  TFrameHandle *fh        = app->getCurrentFrame();
Shinya Kitaoka 120a6e
  if (fh->isEditingLevel()) return TAffine();
Shinya Kitaoka 120a6e
  int frame               = fh->getFrame();
Shinya Kitaoka 120a6e
  TXsheet *xsh            = app->getCurrentXsheet()->getXsheet();
Shinya Kitaoka 120a6e
  TStageObjectId id       = app->getCurrentObject()->getObjectId();
Shinya Kitaoka 120a6e
  double objZ             = xsh->getZ(id, frame);
Shinya Kitaoka 120a6e
  TStageObjectId parentId = xsh->getStageObjectParent(id);
Shinya Kitaoka 120a6e
  if (parentId == TStageObjectId::NoneId) return TAffine();
Shinya Kitaoka 120a6e
  id                   = parentId;
Shinya Kitaoka 120a6e
  TAffine objPlacement = xsh->getPlacement(id, frame);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TStageObjectId cameraId = xsh->getStageObjectTree()->getCurrentCameraId();
Shinya Kitaoka 120a6e
  TStageObject *camera    = xsh->getStageObject(cameraId);
Shinya Kitaoka 120a6e
  TAffine cameraPlacement = camera->getPlacement(frame);
Shinya Kitaoka 120a6e
  double cameraZ          = camera->getZ(frame);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TAffine placement;
Shinya Kitaoka 120a6e
  TStageObject::perspective(placement, cameraPlacement, cameraZ, objPlacement,
Shinya Kitaoka 120a6e
                            objZ, 0);
Shinya Kitaoka 120a6e
  return placement;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TTool::updateMatrix() {
Shinya Kitaoka 120a6e
  assert(m_application);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_application->getCurrentObject()->isSpline())
Shinya Kitaoka 120a6e
    setMatrix(getCurrentObjectParentMatrix2());
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    setMatrix(getCurrentColumnMatrix());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TTool::resetInputMethod() {
Shinya Kitaoka 120a6e
  if (m_viewer) m_viewer->resetInputMethod();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TTool::isColumnLocked(int columnIndex) const {
Shinya Kitaoka 120a6e
  if (columnIndex < 0) return false;
Shinya Kitaoka 120a6e
  TXsheet *xsh       = getXsheet();
Shinya Kitaoka 120a6e
  TXshColumn *column = xsh->getColumn(columnIndex);
manongjohn 6939a3
  if (!column) return false;
Shinya Kitaoka 120a6e
  return column->isLocked();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QString TTool::updateEnabled() {
manongjohn b30686
  int rowIndex    = m_application->getCurrentFrame()->getFrame();
manongjohn b30686
  int columnIndex = m_application->getCurrentColumn()->getColumnIndex();
manongjohn b30686
manongjohn b30686
  return updateEnabled(rowIndex, columnIndex);
manongjohn b30686
}
manongjohn b30686
manongjohn b30686
QString TTool::updateEnabled(int rowIndex, int columnIndex) {
Shinya Kitaoka 120a6e
  // Disable every tool during playback
Shinya Kitaoka 120a6e
  if (m_application->getCurrentFrame()->isPlaying())
Shinya Kitaoka 120a6e
    return (enable(false), QString());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Release Generic tools at once
Shinya Kitaoka 120a6e
  int toolType   = getToolType();
Shinya Kitaoka 120a6e
  int targetType = getTargetType();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (toolType == TTool::GenericTool) return (enable(true), QString());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Retrieve vars and view modes
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_application->getCurrentXsheet()->getXsheet();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TXshColumn *column = (columnIndex >= 0) ? xsh->getColumn(columnIndex) : 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TXshLevel *xl       = m_application->getCurrentLevel()->getLevel();
Shinya Kitaoka 120a6e
  TXshSimpleLevel *sl = xl ? xl->getSimpleLevel() : 0;
Shinya Kitaoka 120a6e
  int levelType       = sl ? sl->getType() : NO_XSHLEVEL;
Shinya Kitaoka 120a6e
manongjohn 8a942e
  // If not in Level editor, let's use our current cell from the xsheet to
manongjohn 8a942e
  // find the nearest level before it
manongjohn f3163f
  if (levelType == NO_XSHLEVEL &&
manongjohn f3163f
      !m_application->getCurrentFrame()->isEditingLevel()) {
manongjohn 8a942e
    TXshCell cell = xsh->getCell(rowIndex, columnIndex);
manongjohn 8a942e
    xl            = cell.isEmpty() ? 0 : (TXshLevel *)(&cell.m_level);
manongjohn 8a942e
    sl            = cell.isEmpty() ? 0 : cell.getSimpleLevel();
manongjohn 8a942e
    levelType     = cell.isEmpty() ? NO_XSHLEVEL : cell.m_level->getType();
manongjohn 8a942e
  }
Shinya Kitaoka 120a6e
shun-iwasawa 536025
  if (Preferences::instance()->isAutoCreateEnabled()) {
manongjohn 5f9599
    // If not in Level editor, let's use our current cell from the xsheet to
manongjohn 5f9599
    // find the nearest level before it
manongjohn 5f9599
    if (levelType == NO_XSHLEVEL &&
manongjohn 5f9599
        !m_application->getCurrentFrame()->isEditingLevel()) {
manongjohn 5f9599
      int r0, r1;
manongjohn 5f9599
      xsh->getCellRange(columnIndex, r0, r1);
manongjohn 5f9599
      for (int r = std::min(r1, rowIndex); r > r0; r--) {
manongjohn 5f9599
        TXshCell cell = xsh->getCell(r, columnIndex);
manongjohn 5f9599
        if (cell.isEmpty()) continue;
manongjohn 5f9599
        xl        = (TXshLevel *)(&cell.m_level);
manongjohn 5f9599
        sl        = cell.getSimpleLevel();
manongjohn 5f9599
        levelType = cell.m_level->getType();
manongjohn 5f9599
        break;
manongjohn 5f9599
      }
manongjohn 5f9599
    }
manongjohn 5f9599
manongjohn 5f9599
    // If the current tool does not match the current type, check for
manongjohn 5f9599
    // a version of the same tool that does
manongjohn 5f9599
    {
manongjohn 5f9599
      TTool *tool = this;
manongjohn 5f9599
manongjohn 5f9599
      if ((levelType == PLI_XSHLEVEL) && !(targetType & VectorImage))
manongjohn 5f9599
        tool = TTool::getTool(m_name, VectorImage);
manongjohn 5f9599
      else if ((levelType == TZP_XSHLEVEL) && !(targetType & ToonzImage))
manongjohn 5f9599
        tool = TTool::getTool(m_name, ToonzImage);
manongjohn 5f9599
      else if ((levelType == OVL_XSHLEVEL) && !(targetType & RasterImage))
manongjohn 5f9599
        tool = TTool::getTool(m_name, RasterImage);
manongjohn 5f9599
      else if ((levelType == MESH_XSHLEVEL) && !(targetType & MeshImage))
manongjohn 5f9599
        tool = TTool::getTool(m_name, MeshImage);
manongjohn 5f9599
manongjohn 5f9599
      if (tool && tool != this && tool->getTargetType() != TTool::NoTarget)
manongjohn 5f9599
        return tool->updateEnabled();
manongjohn 5f9599
    }
manongjohn 5f9599
  }
manongjohn 5f9599
Shinya Kitaoka 120a6e
  bool spline = m_application->getCurrentObject()->isSpline();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool filmstrip = m_application->getCurrentFrame()->isEditingLevel();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  /*-- MultiLayerStylePickerONのときは、現状に関わらず使用可能 --*/
Shinya Kitaoka 120a6e
  if (m_name == T_StylePicker &&
Shinya Kitaoka 120a6e
      Preferences::instance()->isMultiLayerStylePickerEnabled())
Shinya Kitaoka 120a6e
    return (enable(true), QString());
Shinya Kitaoka 120a6e
John Dancel 421acd
  // Check against camera column
manongjohn 9bce81
  if (!filmstrip && columnIndex < 0 && (targetType & TTool::EmptyTarget) &&
John Dancel 421acd
      (m_name == T_Type || m_name == T_Geometric || m_name == T_Brush))
John Dancel 421acd
    return (enable(false), QString());
John Dancel 421acd
shun-iwasawa d40c36
  // In case of Animate Tool
shun-iwasawa d40c36
  if (m_name == T_Edit && !filmstrip) {
shun-iwasawa d40c36
    // if an object other than column is selected, then enable the tool
shun-iwasawa d40c36
    // regardless of the current column state
shun-iwasawa d40c36
    if (!m_application->getCurrentObject()->getObjectId().isColumn())
shun-iwasawa d40c36
      return (enable(true), QString());
shun-iwasawa d40c36
    // if a column object is selected, switch the inspected column to it
shun-iwasawa d40c36
    column = xsh->getColumn(
shun-iwasawa d40c36
        m_application->getCurrentObject()->getObjectId().getIndex());
shun-iwasawa d40c36
  }
shun-iwasawa d40c36
manongjohn 281291
  bool isZeraryCol =
manongjohn 281291
      column ? (column->getZeraryFxColumn() ? true : false) : false;
manongjohn 281291
  bool isPaletteCol =
manongjohn 281291
      column ? (column->getPaletteColumn() ? true : false) : false;
manongjohn 281291
  bool isMeshCol = column ? (column->getMeshColumn() ? true : false) : false;
manongjohn 281291
shun-iwasawa 036853
  // Check against splines
shun-iwasawa 036853
  if (spline && (toolType & TTool::LevelTool)) {
shun-iwasawa 036853
    return (targetType & Splines)
shun-iwasawa 036853
               ? (enable(true), QString())
shun-iwasawa 036853
               : (enable(false), QObject::tr("The current tool cannot be "
shun-iwasawa 036853
                                             "used to edit a motion path."));
shun-iwasawa 036853
  }
shun-iwasawa 036853
Shinya Kitaoka 120a6e
  // Check against unplaced columns (not in filmstrip mode)
Shinya Kitaoka 120a6e
  if (column && !filmstrip) {
manongjohn 6939a3
    if (column->isLocked() && m_name != T_Selection)
Shinya Kitaoka 120a6e
      return (enable(false), QObject::tr("The current column is locked."));
Shinya Kitaoka 120a6e
Jeremy Bullock 3b3466
    else if (!column->isCamstandVisible())
Jeremy Bullock 3b3466
      return (enable(false), QObject::tr("The current column is hidden."));
Jeremy Bullock 3b3466
Shinya Kitaoka 120a6e
    else if (column->getSoundColumn())
Shinya Kitaoka 120a6e
      return (enable(false),
Shinya Kitaoka 120a6e
              QObject::tr("It is not possible to edit the audio column."));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    else if (column->getSoundTextColumn())
Jeremy Bullock 3b3466
      return (
Jeremy Bullock 3b3466
          enable(false),
Jeremy Bullock 3b3466
          QObject::tr(
Jeremy Bullock 3b3466
              "Note columns can only be edited in the xsheet or timeline."));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (toolType == TTool::ColumnTool) {
Shinya Kitaoka 120a6e
      // Check column target
Shinya Kitaoka 120a6e
      if (column->getLevelColumn() && !(targetType & LevelColumns))
Shinya Kitaoka 120a6e
        return (
Shinya Kitaoka 120a6e
            enable(false),
Shinya Kitaoka 120a6e
            QObject::tr("The current tool cannot be used on a Level column."));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (column->getMeshColumn() && !(targetType & MeshColumns))
Shinya Kitaoka 120a6e
        return (
Shinya Kitaoka 120a6e
            enable(false),
Shinya Kitaoka 120a6e
            QObject::tr("The current tool cannot be used on a Mesh column."));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Check column tools
Shinya Kitaoka 120a6e
  if (toolType == TTool::ColumnTool) {
Shinya Kitaoka 120a6e
    if (filmstrip)
Shinya Kitaoka 120a6e
      return (
Shinya Kitaoka 120a6e
          enable(false),
Shinya Kitaoka 120a6e
          QObject::tr("The current tool cannot be used in Level Strip mode."));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if ((!column || column->isEmpty()) && !(targetType & TTool::EmptyTarget))
Shinya Kitaoka 120a6e
      return (enable(false), QString());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Check LevelRead & LevelWrite tools
Shinya Kitaoka 120a6e
  if (toolType & TTool::LevelTool) {
Shinya Kitaoka 120a6e
    // Check against empty levels
Shinya Kitaoka 120a6e
    if (!xl)
manongjohn 281291
      return ((targetType & EmptyTarget) && !isZeraryCol && !isPaletteCol &&
manongjohn 281291
              !isMeshCol)
manongjohn 281291
                 ? (enable(true), QString())
manongjohn 281291
                 : (enable(false), QString());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Check against simple-level-edness
Shinya Kitaoka 120a6e
    if (!sl)
Shinya Kitaoka 120a6e
      return (enable(false),
Shinya Kitaoka 120a6e
              QObject::tr("The current level is not editable."));  // Does it
Shinya Kitaoka 120a6e
                                                                   // happen at
Shinya Kitaoka 120a6e
                                                                   // all btw?
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Check against level types
Shinya Kitaoka 120a6e
    {
Shinya Kitaoka 120a6e
      if ((levelType == PLI_XSHLEVEL) && !(targetType & VectorImage))
Shinya Kitaoka 120a6e
        return (
Shinya Kitaoka 120a6e
            enable(false),
Shinya Kitaoka 120a6e
            QObject::tr("The current tool cannot be used on a Vector Level."));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if ((levelType == TZP_XSHLEVEL) && !(targetType & ToonzImage))
Shinya Kitaoka 120a6e
        return (
Shinya Kitaoka 120a6e
            enable(false),
Shinya Kitaoka 120a6e
            QObject::tr("The current tool cannot be used on a Toonz Level."));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if ((levelType == OVL_XSHLEVEL) && !(targetType & RasterImage))
Shinya Kitaoka 120a6e
        return (
Shinya Kitaoka 120a6e
            enable(false),
Shinya Kitaoka 120a6e
            QObject::tr("The current tool cannot be used on a Raster Level."));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if ((levelType == MESH_XSHLEVEL) && !(targetType & MeshImage))
Shinya Kitaoka 120a6e
        return (
Shinya Kitaoka 120a6e
            enable(false),
Shinya Kitaoka 120a6e
            QObject::tr("The current tool cannot be used on a Mesh Level."));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Check against impossibly traceable movements on the column
shun-iwasawa 555106
    if ((levelType & LEVELCOLUMN_XSHLEVEL) && !filmstrip && columnIndex >= 0) {
shun-iwasawa 555106
      TStageObject *obj =
shun-iwasawa 555106
          xsh->getStageObject(TStageObjectId::ColumnId(columnIndex));
Shinya Kitaoka 120a6e
      // Test for Mesh-deformed levels
Shinya Kitaoka 120a6e
      const TStageObjectId &parentId = obj->getParent();
Shinya Kitaoka 120a6e
      if (parentId.isColumn() && obj->getParentHandle()[0] != 'H') {
Shinya Kitaoka 120a6e
        TXshSimpleLevel *parentSl =
Shinya Kitaoka 120a6e
            xsh->getCell(rowIndex, parentId.getIndex()).getSimpleLevel();
manongjohn 6939a3
        if (parentSl && parentSl->getType() == MESH_XSHLEVEL &&
manongjohn 6939a3
            m_name != T_Selection)
Shinya Kitaoka 120a6e
          return (
Shinya Kitaoka 120a6e
              enable(false),
Shinya Kitaoka 120a6e
              QObject::tr(
Shinya Kitaoka 120a6e
                  "The current tool cannot be used on a mesh-deformed level"));
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Check TTool::ImageType tools
manongjohn 6939a3
    if (toolType == TTool::LevelWriteTool && m_name != T_Selection) {
Shinya Kitaoka 120a6e
      // Check level against read-only status
John Dancel 862914
      if (sl->isFrameReadOnly(getCurrentFid()))
John Dancel 862914
        return (enable(false),
John Dancel 862914
                QObject::tr(
John Dancel 862914
                    "The current frame is locked: any editing is forbidden."));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // Check level type write support
Shinya Kitaoka 120a6e
      if (sl->getPath().getType() ==
Shinya Kitaoka 120a6e
              "psd" ||  // We don't have the API to write psd files
manongjohn f2da01
          sl->getPath().getType() == "gif" ||
manongjohn f2da01
          sl->getPath().getType() == "mp4" ||
manongjohn f2da01
          sl->getPath().getType() == "webm" ||
manongjohn 6939a3
          sl->is16BitChannelLevel() ||  // Inherited by previous
manongjohn 6939a3
                                        // implementation.
Shinya Kitaoka 120a6e
                                        // Could be fixed?
Shinya Kitaoka 120a6e
          sl->getProperties()->getBpp() ==
Shinya Kitaoka 120a6e
              1)  // Black & White images. Again, could be fixed?
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        return (enable(false),
Shinya Kitaoka 120a6e
                QObject::tr("The current level is not editable."));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return (enable(true), QString());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TTool::setSelectedFrames(const std::set<tframeid> &selectedFrames) {</tframeid>
Shinya Kitaoka 120a6e
  m_selectedFrames = selectedFrames;
Shinya Kitaoka 120a6e
  onSelectedFramesChanged();
Toshihiro Shimizu 890ddd
}
manongjohn 40a40e
manongjohn 40a40e
//-------------------------------------------------------------------------------------------------------------
manongjohn 40a40e
manongjohn 40a40e
void TTool::Viewer::getGuidedFrameIdx(int *backIdx, int *frontIdx) {
manongjohn 233fcf
  if (!Preferences::instance()->isGuidedDrawingEnabled()) return;
manongjohn 233fcf
manongjohn 40a40e
  OnionSkinMask osMask =
manongjohn 40a40e
      m_application->getCurrentOnionSkin()->getOnionSkinMask();
manongjohn 40a40e
manongjohn 40a40e
  if (!osMask.isEnabled() || osMask.isEmpty()) return;
manongjohn 40a40e
manongjohn 40a40e
  TFrameHandle *currentFrame = getApplication()->getCurrentFrame();
manongjohn 40a40e
manongjohn 40a40e
  int cidx     = currentFrame->getFrameIndex();
manongjohn 40a40e
  int mosBack  = 0;
manongjohn 40a40e
  int mosFront = 0;
manongjohn 40a40e
  int mosCount = osMask.getMosCount();
manongjohn 40a40e
  int fosBack  = -1;
manongjohn 40a40e
  int fosFront = -1;
manongjohn 40a40e
  int fosCount = osMask.getFosCount();
manongjohn 40a40e
manongjohn 40a40e
  // Find onion-skinned drawing that is being used for guided auto inbetween
manongjohn 233fcf
  if (Preferences::instance()->getGuidedDrawingType() == 1) {
manongjohn 40a40e
    // Get closest moving unionskin
manongjohn 40a40e
    for (int i = 0; i < mosCount; i++) {
manongjohn 40a40e
      int cmos = osMask.getMos(i);
manongjohn 40a40e
      if (cmos == 0) continue;  // skip current
manongjohn 40a40e
      if (cmos < 0 && (!mosBack || cmos > mosBack)) mosBack    = cmos;
manongjohn 40a40e
      if (cmos > 0 && (!mosFront || cmos < mosFront)) mosFront = cmos;
manongjohn 40a40e
    }
manongjohn 40a40e
    if (mosBack) *backIdx   = mosBack + cidx;
manongjohn 40a40e
    if (mosFront) *frontIdx = mosFront + cidx;
manongjohn 40a40e
manongjohn 40a40e
    // Get closest fixed onionskin
manongjohn 40a40e
    for (int i = 0; i < fosCount; i++) {
manongjohn 40a40e
      int cfos = osMask.getFos(i);
manongjohn 40a40e
      if (cfos == cidx) continue;  // skip current
manongjohn 40a40e
      if (cfos < cidx && (fosBack == -1 || cfos > fosBack)) fosBack    = cfos;
manongjohn 40a40e
      if (cfos > cidx && (fosFront == -1 || cfos < fosFront)) fosFront = cfos;
manongjohn 40a40e
    }
manongjohn 40a40e
manongjohn 40a40e
    if (*backIdx == -1)
manongjohn 40a40e
      *backIdx = fosBack;
manongjohn 40a40e
    else if (fosBack != -1)
manongjohn 40a40e
      *backIdx = std::max(*backIdx, fosBack);
manongjohn 40a40e
    if (*frontIdx == -1)
manongjohn 40a40e
      *frontIdx = fosFront;
manongjohn 40a40e
    else if (fosFront != -1)
manongjohn 40a40e
      *frontIdx = std::min(*frontIdx, fosFront);
manongjohn 233fcf
  } else if (Preferences::instance()->getGuidedDrawingType() ==
manongjohn 40a40e
             2) {  // Furthest drawing
manongjohn 40a40e
                   // Get moving unionskin
manongjohn 40a40e
    for (int i = 0; i < mosCount; i++) {
manongjohn 40a40e
      int cmos = osMask.getMos(i);
manongjohn 40a40e
      if (cmos == 0) continue;  // skip current
manongjohn 40a40e
      if (cmos < 0 && (!mosBack || cmos < mosBack)) mosBack    = cmos;
manongjohn 40a40e
      if (cmos > 0 && (!mosFront || cmos > mosFront)) mosFront = cmos;
manongjohn 40a40e
    }
manongjohn 40a40e
    if (mosBack) *backIdx   = mosBack + cidx;
manongjohn 40a40e
    if (mosFront) *frontIdx = mosFront + cidx;
manongjohn 40a40e
manongjohn 40a40e
    // Get fixed onionskin
manongjohn 40a40e
    for (int i = 0; i < fosCount; i++) {
manongjohn 40a40e
      int cfos = osMask.getFos(i);
manongjohn 40a40e
      if (cfos == cidx) continue;  // skip current
manongjohn 40a40e
      if (cfos < cidx && (fosBack == -1 || cfos < fosBack)) fosBack    = cfos;
manongjohn 40a40e
      if (cfos > cidx && (fosFront == -1 || cfos > fosFront)) fosFront = cfos;
manongjohn 40a40e
    }
manongjohn 40a40e
manongjohn 40a40e
    if (*backIdx == -1)
manongjohn 40a40e
      *backIdx = fosBack;
manongjohn 40a40e
    else if (fosBack != -1)
manongjohn 40a40e
      *backIdx = std::min(*backIdx, fosBack);
manongjohn 40a40e
    if (*frontIdx == -1)
manongjohn 40a40e
      *frontIdx = fosFront;
manongjohn 40a40e
    else if (fosFront != -1)
manongjohn 40a40e
      *frontIdx = std::max(*frontIdx, fosFront);
manongjohn 40a40e
  }
manongjohn 40a40e
}
manongjohn 40a40e
manongjohn 40a40e
//-------------------------------------------------------------------------------------------------------------
manongjohn 40a40e
manongjohn 40a40e
void TTool::Viewer::doPickGuideStroke(const TPointD &pos) {
manongjohn 40a40e
  int pickerMode = getGuidedStrokePickerMode();
manongjohn 40a40e
manongjohn 40a40e
  if (!pickerMode) return;
manongjohn 40a40e
manongjohn 40a40e
  if (pickerMode >= -2 && pickerMode <= 2) setGuidedStrokePickerMode(0);
manongjohn 40a40e
manongjohn 40a40e
  int osBack  = -1;
manongjohn 40a40e
  int osFront = -1;
manongjohn 40a40e
  int os      = -1;
manongjohn 40a40e
manongjohn 40a40e
  getGuidedFrameIdx(&osBack, &osFront);
manongjohn 40a40e
manongjohn 40a40e
  if (pickerMode < 0)  // Previous Frame
manongjohn 40a40e
    os = osBack;
manongjohn 40a40e
  else if (pickerMode > 0)  // Next Frame
manongjohn 40a40e
    os = osFront;
manongjohn 40a40e
manongjohn 40a40e
  TFrameId fid;
manongjohn 40a40e
  TFrameHandle *currentFrame = getApplication()->getCurrentFrame();
manongjohn 40a40e
  TXshSimpleLevel *sl =
manongjohn 40a40e
      getApplication()->getCurrentLevel()->getLevel()->getSimpleLevel();
manongjohn 40a40e
  if (!sl) return;
manongjohn 40a40e
manongjohn 40a40e
  if (currentFrame->isEditingScene()) {
manongjohn 40a40e
    TXsheet *xsh = getApplication()->getCurrentXsheet()->getXsheet();
manongjohn 40a40e
    int col      = getApplication()->getCurrentColumn()->getColumnIndex();
manongjohn 40a40e
    if (xsh && col >= 0) {
manongjohn 40a40e
      TXshCell cell            = xsh->getCell(os, col);
manongjohn 40a40e
      if (!cell.isEmpty()) fid = cell.getFrameId();
manongjohn 40a40e
    }
manongjohn 40a40e
  } else
manongjohn 40a40e
    fid = sl->getFrameId(os);
manongjohn 40a40e
manongjohn 40a40e
  if (fid.isEmptyFrame()) return;
manongjohn 40a40e
manongjohn 40a40e
  TVectorImageP fvi = sl->getFrame(fid, false);
manongjohn 40a40e
  if (!fvi) return;
manongjohn 40a40e
manongjohn 40a40e
  UINT index;
manongjohn 40a40e
  double t, dist2 = 0;
manongjohn 40a40e
  double pixelSize = getPixelSize();
manongjohn 40a40e
  TAffine aff      = getViewMatrix();
manongjohn 40a40e
  double maxDist   = 5 * pixelSize;
manongjohn 40a40e
  double maxDist2  = maxDist * maxDist;
manongjohn 40a40e
  double checkDist = maxDist2 * 4;
manongjohn 40a40e
  TStroke *strokeRef;
manongjohn 40a40e
  if (fvi->getNearestStroke(pos, t, index, dist2)) {
manongjohn 40a40e
    strokeRef          = fvi->getStroke(index);
manongjohn 40a40e
    TThickPoint cursor = strokeRef->getThickPoint(t);
manongjohn 40a40e
    double len         = cursor.thick * pixelSize * sqrt(aff.det());
manongjohn 40a40e
    checkDist          = std::max(checkDist, (len * len));
manongjohn 40a40e
  }
manongjohn 40a40e
manongjohn 40a40e
  if (dist2 >= checkDist)
manongjohn 40a40e
    index = -1;
manongjohn 40a40e
  else {
manongjohn 40a40e
    if (pickerMode < 0)  // Previous Frame
manongjohn 40a40e
      setGuidedBackStroke(index);
manongjohn 40a40e
    else if (pickerMode > 0)  // Next Frame
manongjohn 40a40e
      setGuidedFrontStroke(index);
manongjohn 40a40e
  }
manongjohn 40a40e
manongjohn 40a40e
  if (pickerMode <= -2) {
manongjohn 40a40e
    if (index != -1) setGuidedStrokePickerMode(pickerMode * -1);
manongjohn 40a40e
  } else if (pickerMode >= 2) {
manongjohn 40a40e
    if (pickerMode >= 3 && index != -1) {
manongjohn 40a40e
      TTool *tool = TTool::getTool(T_Brush, TTool::ToolTargetType::VectorImage);
manongjohn 40a40e
      ToonzVectorBrushTool *vbTool = (ToonzVectorBrushTool *)tool;
manongjohn 40a40e
      if (vbTool) {
manongjohn 40a40e
        vbTool->setViewer(this);
manongjohn 40a40e
        vbTool->doGuidedAutoInbetween(fid, fvi, strokeRef, false, false, false,
manongjohn 40a40e
                                      false);
manongjohn 40a40e
      }
manongjohn 40a40e
manongjohn 40a40e
      setGuidedStrokePickerMode(pickerMode * -1);
manongjohn 40a40e
    }
manongjohn 40a40e
  }
manongjohn 40a40e
}
manongjohn 40a40e
manongjohn 40a40e
//-------------------------------------------------------------------------------------------------------------
manongjohn 40a40e
manongjohn 40a40e
void TTool::tweenSelectedGuideStrokes() {
manongjohn 40a40e
  if (!getViewer() || !m_application) return;
manongjohn 40a40e
manongjohn 40a40e
  TXshSimpleLevel *sl =
manongjohn 40a40e
      m_application->getCurrentLevel()->getLevel()->getSimpleLevel();
manongjohn 40a40e
  if (!sl) return;
manongjohn 40a40e
manongjohn 40a40e
  int backIdx = -1, frontIdx = -1;
manongjohn 40a40e
manongjohn 40a40e
  getViewer()->getGuidedFrameIdx(&backIdx, &frontIdx);
manongjohn 40a40e
manongjohn 40a40e
  if (backIdx == -1 || frontIdx == -1) return;
manongjohn 40a40e
manongjohn 40a40e
  TFrameHandle *currentFrame = getApplication()->getCurrentFrame();
manongjohn 40a40e
  int row                    = currentFrame->getFrameIndex();
manongjohn 40a40e
  TFrameId bFid, cFid, fFid;
manongjohn 40a40e
manongjohn 40a40e
  cFid = getCurrentFid();
manongjohn 40a40e
  if (cFid.isEmptyFrame()) return;
manongjohn 40a40e
manongjohn 40a40e
  TVectorImageP cvi = sl->getFrame(cFid, false);
manongjohn 40a40e
  if (!cvi) return;
manongjohn 40a40e
manongjohn 40a40e
  int cStrokeCount = cvi->getStrokeCount();
manongjohn 40a40e
manongjohn 40a40e
  if (currentFrame->isEditingScene()) {
manongjohn 40a40e
    TXsheet *xsh = m_application->getCurrentXsheet()->getXsheet();
manongjohn 40a40e
    int col      = m_application->getCurrentColumn()->getColumnIndex();
manongjohn 40a40e
    if (xsh && col >= 0) {
manongjohn 40a40e
      TXshCell cell             = xsh->getCell(backIdx, col);
manongjohn 40a40e
      if (!cell.isEmpty()) bFid = cell.getFrameId();
manongjohn 40a40e
      cell                      = xsh->getCell(frontIdx, col);
manongjohn 40a40e
      if (!cell.isEmpty()) fFid = cell.getFrameId();
manongjohn 40a40e
    }
manongjohn 40a40e
  } else {
manongjohn 40a40e
    bFid = sl->getFrameId(backIdx);
manongjohn 40a40e
    fFid = sl->getFrameId(frontIdx);
manongjohn 40a40e
  }
manongjohn 40a40e
  if (bFid.isEmptyFrame() || fFid.isEmptyFrame()) return;
manongjohn 40a40e
manongjohn 40a40e
  TVectorImageP bvi = sl->getFrame(bFid, false);
manongjohn 40a40e
  TVectorImageP fvi = sl->getFrame(fFid, false);
manongjohn 40a40e
manongjohn 40a40e
  if (!bvi || !fvi) return;
manongjohn 40a40e
manongjohn 40a40e
  int bStrokeCount = bvi->getStrokeCount();
manongjohn 40a40e
  int fStrokeCount = fvi->getStrokeCount();
manongjohn 40a40e
manongjohn 40a40e
  if (!bStrokeCount || !fStrokeCount) return;
manongjohn 40a40e
manongjohn 40a40e
  int bStrokeIdx = getViewer()->getGuidedBackStroke() != -1
manongjohn 40a40e
                       ? getViewer()->getGuidedBackStroke()
manongjohn 40a40e
                       : cStrokeCount;
manongjohn 40a40e
  int fStrokeIdx = getViewer()->getGuidedFrontStroke() != -1
manongjohn 40a40e
                       ? getViewer()->getGuidedFrontStroke()
manongjohn 40a40e
                       : cStrokeCount;
manongjohn 40a40e
manongjohn 40a40e
  if (bStrokeIdx >= bStrokeCount || fStrokeIdx >= fStrokeCount) return;
manongjohn 40a40e
manongjohn 40a40e
  TStroke *bStroke = bvi->getStroke(bStrokeIdx);
manongjohn 40a40e
  TStroke *fStroke = fvi->getStroke(fStrokeIdx);
manongjohn 40a40e
manongjohn 40a40e
  if (!bStroke || !fStroke) return;
manongjohn 40a40e
manongjohn 40a40e
  TTool *tool = TTool::getTool(T_Brush, TTool::ToolTargetType::VectorImage);
manongjohn 40a40e
  ToonzVectorBrushTool *vbTool = (ToonzVectorBrushTool *)tool;
manongjohn 40a40e
  if (vbTool) {
manongjohn 40a40e
    vbTool->setViewer(m_viewer);
manongjohn 40a40e
    vbTool->doFrameRangeStrokes(
manongjohn 40a40e
        bFid, bStroke, fFid, fStroke,
manongjohn 40a40e
        Preferences::instance()->getGuidedInterpolation(), false, false, false,
manongjohn 40a40e
        false, false, true);
manongjohn 40a40e
  }
manongjohn 40a40e
}
manongjohn 40a40e
manongjohn 40a40e
//-------------------------------------------------------------------------------------------------------------
manongjohn 40a40e
manongjohn 40a40e
void TTool::tweenGuideStrokeToSelected() {
manongjohn 40a40e
  if (!getViewer() || !m_application) return;
manongjohn 40a40e
manongjohn 40a40e
  TXshSimpleLevel *sl =
manongjohn 40a40e
      m_application->getCurrentLevel()->getLevel()->getSimpleLevel();
manongjohn 40a40e
  if (!sl) return;
manongjohn 40a40e
manongjohn 40a40e
  int backIdx = -1, frontIdx = -1;
manongjohn 40a40e
manongjohn 40a40e
  getViewer()->getGuidedFrameIdx(&backIdx, &frontIdx);
manongjohn 40a40e
manongjohn 40a40e
  TFrameHandle *currentFrame = getApplication()->getCurrentFrame();
manongjohn 40a40e
  int row                    = currentFrame->getFrameIndex();
manongjohn 40a40e
  TFrameId bFid, cFid, fFid;
manongjohn 40a40e
  TVectorImageP bvi, cvi, fvi;
manongjohn 40a40e
manongjohn 40a40e
  cFid = getCurrentFid();
manongjohn 40a40e
  if (cFid.isEmptyFrame()) return;
manongjohn 40a40e
manongjohn 40a40e
  cvi = sl->getFrame(cFid, false);
manongjohn 40a40e
  if (!cvi) return;
manongjohn 40a40e
manongjohn 40a40e
  int cStrokeCount = cvi->getStrokeCount();
manongjohn 40a40e
  if (!cStrokeCount) return;
manongjohn 40a40e
manongjohn 40a40e
  StrokeSelection *strokeSelection =
manongjohn 40a40e
      dynamic_cast<strokeselection *="">(getSelection());</strokeselection>
manongjohn 40a40e
  if (!strokeSelection || strokeSelection->isEmpty()) return;
manongjohn 40a40e
  const std::set<int> &selectedStrokeIdxs = strokeSelection->getSelection();</int>
manongjohn 40a40e
  const std::set<int>::iterator it        = selectedStrokeIdxs.begin();</int>
manongjohn 40a40e
  int cStrokeIdx                          = *it;
manongjohn 40a40e
manongjohn 40a40e
  TStroke *cStroke = cvi->getStroke(cStrokeIdx);
manongjohn 40a40e
  if (!cStroke) return;
manongjohn 40a40e
manongjohn 40a40e
  if (backIdx != -1) {
manongjohn 40a40e
    if (currentFrame->isEditingScene()) {
manongjohn 40a40e
      TXsheet *xsh = m_application->getCurrentXsheet()->getXsheet();
manongjohn 40a40e
      int col      = m_application->getCurrentColumn()->getColumnIndex();
manongjohn 40a40e
      if (xsh && col >= 0) {
manongjohn 40a40e
        TXshCell cell             = xsh->getCell(backIdx, col);
manongjohn 40a40e
        if (!cell.isEmpty()) bFid = cell.getFrameId();
manongjohn 40a40e
      }
manongjohn 40a40e
    } else
manongjohn 40a40e
      bFid = sl->getFrameId(backIdx);
manongjohn 40a40e
manongjohn 40a40e
    if (!bFid.isEmptyFrame()) bvi = sl->getFrame(bFid, false);
manongjohn 40a40e
  }
manongjohn 40a40e
manongjohn 40a40e
  if (frontIdx != -1) {
manongjohn 40a40e
    if (currentFrame->isEditingScene()) {
manongjohn 40a40e
      TXsheet *xsh = m_application->getCurrentXsheet()->getXsheet();
manongjohn 40a40e
      int col      = m_application->getCurrentColumn()->getColumnIndex();
manongjohn 40a40e
      if (xsh && col >= 0) {
manongjohn 40a40e
        TXshCell cell             = xsh->getCell(frontIdx, col);
manongjohn 40a40e
        if (!cell.isEmpty()) fFid = cell.getFrameId();
manongjohn 40a40e
      }
manongjohn 40a40e
    } else
manongjohn 40a40e
      fFid = sl->getFrameId(frontIdx);
manongjohn 40a40e
manongjohn 40a40e
    if (!fFid.isEmptyFrame()) fvi = sl->getFrame(fFid, false);
manongjohn 40a40e
  }
manongjohn 40a40e
manongjohn 40a40e
  if (!bvi && !fvi) return;
manongjohn 40a40e
manongjohn 40a40e
  int bStrokeCount = bvi ? bvi->getStrokeCount() : 0;
manongjohn 40a40e
  int fStrokeCount = fvi ? fvi->getStrokeCount() : 0;
manongjohn 40a40e
manongjohn 40a40e
  if (!bStrokeCount && !fStrokeCount) return;
manongjohn 40a40e
manongjohn 40a40e
  int bStrokeIdx = getViewer()->getGuidedBackStroke() != -1
manongjohn 40a40e
                       ? getViewer()->getGuidedBackStroke()
manongjohn 40a40e
                       : cStrokeCount;
manongjohn 40a40e
  int fStrokeIdx = getViewer()->getGuidedFrontStroke() != -1
manongjohn 40a40e
                       ? getViewer()->getGuidedFrontStroke()
manongjohn 40a40e
                       : cStrokeCount;
manongjohn 40a40e
manongjohn 40a40e
  if ((bStrokeCount && bStrokeIdx >= bStrokeCount) ||
manongjohn 40a40e
      (fStrokeCount && fStrokeIdx >= fStrokeCount))
manongjohn 40a40e
    return;
manongjohn 40a40e
manongjohn 40a40e
  TStroke *bStroke = bvi ? bvi->getStroke(bStrokeIdx) : 0;
manongjohn 40a40e
  TStroke *fStroke = fvi ? fvi->getStroke(fStrokeIdx) : 0;
manongjohn 40a40e
manongjohn 40a40e
  if (!bStroke && !fStroke) return;
manongjohn 40a40e
manongjohn 40a40e
  TTool *tool = TTool::getTool(T_Brush, TTool::ToolTargetType::VectorImage);
manongjohn 40a40e
  ToonzVectorBrushTool *vbTool = (ToonzVectorBrushTool *)tool;
manongjohn 40a40e
  if (vbTool) {
manongjohn 40a40e
    vbTool->setViewer(m_viewer);
manongjohn 40a40e
    TUndoManager::manager()->beginBlock();
manongjohn 40a40e
    if (bStroke)
manongjohn 40a40e
      vbTool->doFrameRangeStrokes(
manongjohn 40a40e
          bFid, bStroke, cFid, cStroke,
manongjohn 40a40e
          Preferences::instance()->getGuidedInterpolation(), false, false,
manongjohn 40a40e
          false, false, false, false);
manongjohn 40a40e
    if (fStroke)
manongjohn 40a40e
      vbTool->doFrameRangeStrokes(
manongjohn 40a40e
          cFid, cStroke, fFid, fStroke,
manongjohn 40a40e
          Preferences::instance()->getGuidedInterpolation(), false, false,
manongjohn 40a40e
          false, false, false, false);
manongjohn 40a40e
    TUndoManager::manager()->endBlock();
manongjohn 40a40e
  }
manongjohn 40a40e
}
manongjohn 233fcf
manongjohn 233fcf
//-------------------------------------------------------------------------------------------------------------
manongjohn 233fcf
manongjohn 233fcf
void TTool::flipGuideStrokeDirection(int mode) {
manongjohn 233fcf
  if (!mode) return;
manongjohn 233fcf
manongjohn 233fcf
  TXshSimpleLevel *sl =
manongjohn 233fcf
      m_application->getCurrentLevel()->getLevel()->getSimpleLevel();
manongjohn 233fcf
  if (!sl) return;
manongjohn 233fcf
manongjohn 233fcf
  int osBack  = -1;
manongjohn 233fcf
  int osFront = -1;
manongjohn 233fcf
  int os      = -1;
manongjohn 233fcf
  int strokeIdx;
manongjohn 233fcf
manongjohn 233fcf
  getViewer()->getGuidedFrameIdx(&osBack, &osFront);
manongjohn 233fcf
manongjohn 233fcf
  if (mode < 0) {  // Previous Frame
manongjohn 233fcf
    os        = osBack;
manongjohn 233fcf
    strokeIdx = getViewer()->getGuidedBackStroke();
manongjohn 233fcf
  } else if (mode > 0) {  // Next Frame
manongjohn 233fcf
    os        = osFront;
manongjohn 233fcf
    strokeIdx = getViewer()->getGuidedFrontStroke();
manongjohn 233fcf
  }
manongjohn 233fcf
manongjohn 233fcf
  if (os < 0) return;
manongjohn 233fcf
manongjohn 233fcf
  TFrameHandle *currentFrame = getApplication()->getCurrentFrame();
manongjohn 233fcf
  int row                    = currentFrame->getFrameIndex();
manongjohn 233fcf
  TFrameId cFid              = getCurrentFid();
manongjohn 233fcf
  if (cFid.isEmptyFrame()) return;
manongjohn 233fcf
manongjohn 233fcf
  TVectorImageP cvi = sl->getFrame(cFid, false);
manongjohn 233fcf
  if (!cvi) return;
manongjohn 233fcf
manongjohn 233fcf
  int cStrokeCount = cvi->getStrokeCount();
manongjohn 233fcf
manongjohn 233fcf
  TFrameId fid;
manongjohn 233fcf
  if (currentFrame->isEditingScene()) {
manongjohn 233fcf
    TXsheet *xsh = getApplication()->getCurrentXsheet()->getXsheet();
manongjohn 233fcf
    int col      = getApplication()->getCurrentColumn()->getColumnIndex();
manongjohn 233fcf
    if (xsh && col >= 0) {
manongjohn 233fcf
      TXshCell cell            = xsh->getCell(os, col);
manongjohn 233fcf
      if (!cell.isEmpty()) fid = cell.getFrameId();
manongjohn 233fcf
    }
manongjohn 233fcf
  } else
manongjohn 233fcf
    fid = sl->getFrameId(os);
manongjohn 233fcf
manongjohn 233fcf
  if (fid.isEmptyFrame()) return;
manongjohn 233fcf
manongjohn 233fcf
  TVectorImageP vi = sl->getFrame(fid, false);
manongjohn 233fcf
  if (!vi) return;
manongjohn 233fcf
manongjohn 233fcf
  int strokeCount = vi->getStrokeCount();
manongjohn 233fcf
  if (!strokeCount) return;
manongjohn 233fcf
manongjohn 233fcf
  if (strokeIdx == -1) strokeIdx = cStrokeCount;
manongjohn 233fcf
manongjohn 233fcf
  if (strokeIdx >= strokeCount) return;
manongjohn 233fcf
manongjohn 233fcf
  TStroke *stroke = vi->getStroke(strokeIdx);
manongjohn 233fcf
  if (!stroke) return;
manongjohn 233fcf
manongjohn 233fcf
  stroke->changeDirection();
manongjohn bf1e21
  sl->setDirtyFlag(true);
manongjohn 233fcf
  getViewer()->invalidateAll();
manongjohn bf1e21
  m_application->getCurrentLevel()->notifyLevelChange();
manongjohn 233fcf
}