Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzCore includes
Toshihiro Shimizu 890ddd
#include "tstroke.h"
Toshihiro Shimizu 890ddd
#include "tgl.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzBase includes
Toshihiro Shimizu 890ddd
#include "tenv.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzLib includes
Toshihiro Shimizu 890ddd
#include "toonz/tstageobjectcmd.h"
Toshihiro Shimizu 890ddd
#include "toonz/toonzimageutils.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshcolumn.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshsimplelevel.h"
Toshihiro Shimizu 890ddd
#include "toonz/tstageobjecttree.h"
Toshihiro Shimizu 890ddd
#include "toonz/tstageobjectspline.h"
Toshihiro Shimizu 890ddd
#include "toonz/toonzscene.h"
Toshihiro Shimizu 890ddd
#include "toonz/stage.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshcell.h"
Toshihiro Shimizu 890ddd
#include "toonz/dpiscale.h"
Toshihiro Shimizu 890ddd
#include "toonz/skeleton.h"
Toshihiro Shimizu 890ddd
#include "toonz/tscenehandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/tobjecthandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/tpinnedrangeset.h"
Toshihiro Shimizu 890ddd
#include "toonz/tframehandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/tcolumnhandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/txsheethandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/stageobjectutil.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzQt includes
Toshihiro Shimizu 890ddd
#include "toonzqt/selection.h"
Toshihiro Shimizu 890ddd
#include "toonzqt/selectioncommandids.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 "tw/keycodes.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Qt includes
Shinya Kitaoka 120a6e
#include <qcoreapplication>  // Qt translation support</qcoreapplication>
Toshihiro Shimizu 890ddd
#include <qpainter></qpainter>
Shinya Kitaoka 120a6e
#include <qglwidget>  // for QGLWidget::convertToGLFormat</qglwidget>
Toshihiro Shimizu 890ddd
#include <qpainterpath></qpainterpath>
Toshihiro Shimizu 890ddd
#include <qstring></qstring>
Toshihiro Shimizu 890ddd
#include <qimage></qimage>
Toshihiro Shimizu 890ddd
#include <qfont></qfont>
Toshihiro Shimizu 890ddd
#include <qfontmetrics></qfontmetrics>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "skeletonsubtools.h"
Toshihiro Shimizu 890ddd
#include "skeletontool.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
using namespace SkeletonSubtools;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TEnv::IntVar SkeletonGlobalKeyFrame("SkeletonToolGlobalKeyFrame", 0);
Toshihiro Shimizu 890ddd
TEnv::IntVar SkeletonInverseKinematics("SkeletonToolInverseKinematics", 0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define BUILD_SKELETON L"Build Skeleton"
Toshihiro Shimizu 890ddd
#define ANIMATE L"Animate"
Toshihiro Shimizu 890ddd
#define INVERSE_KINEMATICS L"Inverse Kinematics"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
const double alpha = 0.4;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
using SkeletonSubtools::HookData;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//============================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline std::string removeTrailingH(std::string handle) {
Shinya Kitaoka 120a6e
  if (handle.find("H") == 0)
Shinya Kitaoka 120a6e
    return handle.substr(1);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    return handle;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//============================================================
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
// util
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// return true iff column ancestorIndex is column descentIndex or its parent or
Shinya Kitaoka 120a6e
// the parent of the parent, etc.
Campbell Barton 8c6c57
static bool isAncestorOf(int ancestorIndex, int descendentIndex) {
Shinya Kitaoka 120a6e
  TStageObjectId ancestorId   = TStageObjectId::ColumnId(ancestorIndex);
Shinya Kitaoka 120a6e
  TStageObjectId descendentId = TStageObjectId::ColumnId(descendentIndex);
Shinya Kitaoka 120a6e
  TXsheet *xsh = TTool::getApplication()->getCurrentXsheet()->getXsheet();
Shinya Kitaoka 120a6e
  while (descendentId != ancestorId && descendentId.isColumn())
Shinya Kitaoka 120a6e
    descendentId = xsh->getStageObjectParent(descendentId);
Shinya Kitaoka 120a6e
  return descendentId == ancestorId;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
shun-iwasawa 27b0cf
static void getHooks(std::vector<hookdata> &hooks, TXsheet *xsh, int row,</hookdata>
shun-iwasawa 27b0cf
                     int col, TPointD dpiScale) {
Shinya Kitaoka 120a6e
  // nota. hook position is in the coordinate system of the parent object.
Shinya Kitaoka 120a6e
  // a inch is Stage::inch
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TXshCell cell = xsh->getCell(row, col);
Shinya Kitaoka 120a6e
  if (!cell.m_level) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TStageObjectId columnId = TStageObjectId::ColumnId(col);
Shinya Kitaoka 120a6e
  // handle is the current handle (pivot) of the column. It can be H1,H2,... or
Shinya Kitaoka 120a6e
  // A,B,C,...
Shinya Kitaoka 120a6e
  std::string handle =
Shinya Kitaoka 120a6e
      xsh->getStageObject(TStageObjectId::ColumnId(col))->getHandle();
Shinya Kitaoka 120a6e
  bool handleIsHook = handle.find("H") == 0;
Shinya Kitaoka 120a6e
  TAffine aff       = xsh->getPlacement(columnId, row);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // imageDpiAff represent the scale factor between the image and the camera
Shinya Kitaoka 120a6e
  // derived by dpi match (i.e. ignoring geometric transformation)
Shinya Kitaoka 120a6e
  // cameraPos = imageDpiAff * imagePos
Shinya Kitaoka 120a6e
  TAffine imageDpiAff;
Shinya Kitaoka 120a6e
  if (cell.m_level->getSimpleLevel())
Shinya Kitaoka 120a6e
    imageDpiAff =
Shinya Kitaoka 120a6e
        getDpiAffine(cell.m_level->getSimpleLevel(), cell.m_frameId, true);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // center (inches)
Shinya Kitaoka 120a6e
  TPointD center           = xsh->getCenter(columnId, row);  // getHooks
Shinya Kitaoka 120a6e
  if (handleIsHook) center = TPointD(0, 0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // add the hook #0 (i.e. the regular center)
Shinya Kitaoka 120a6e
  hooks.push_back(HookData(xsh, col, 0, aff * TScale(Stage::inch) * center));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // add the regular hooks
Shinya Kitaoka 120a6e
  HookSet *hookSet = cell.m_level->getHookSet();
Shinya Kitaoka 120a6e
  if (hookSet && hookSet->getHookCount() > 0) {
Shinya Kitaoka 120a6e
    for (int j = 0; j < hookSet->getHookCount(); j++) {
Shinya Kitaoka 120a6e
      Hook *hook = hookSet->getHook(j);
Shinya Kitaoka 120a6e
      if (hook && !hook->isEmpty()) {
Shinya Kitaoka 120a6e
        TPointD pos = hook->getAPos(cell.m_frameId);
Shinya Kitaoka 120a6e
        pos         = aff * imageDpiAff * pos;
Shinya Kitaoka 120a6e
        hooks.push_back(HookData(xsh, col, j + 1, pos));
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Campbell Barton 8c6c57
static void getConnectedColumns(std::set<int> &connectedColumns, TXsheet *xsh,</int>
Campbell Barton 8c6c57
                                int col) {
Shinya Kitaoka 120a6e
  TStageObjectId id;
Shinya Kitaoka 120a6e
  // insert col and all column ancestors
Shinya Kitaoka 120a6e
  id = TStageObjectId::ColumnId(col);
Shinya Kitaoka 120a6e
  do {
Shinya Kitaoka 120a6e
    connectedColumns.insert(id.getIndex());
Shinya Kitaoka 120a6e
    id = xsh->getStageObjectParent(id);
Shinya Kitaoka 120a6e
  } while (id.isColumn());
Shinya Kitaoka 120a6e
  // for each column
Shinya Kitaoka 120a6e
  for (int i = 0; i < xsh->getColumnCount(); i++) {
Shinya Kitaoka 120a6e
    id = TStageObjectId::ColumnId(i);
Shinya Kitaoka 120a6e
    std::vector<tstageobjectid> stack;</tstageobjectid>
Shinya Kitaoka 120a6e
    // find a column ancestor already connected; put all the column ancestors in
Shinya Kitaoka 120a6e
    // stack
Shinya Kitaoka 120a6e
    while (id.isColumn() && connectedColumns.count(id.getIndex()) == 0) {
Shinya Kitaoka 120a6e
      stack.push_back(id);
Shinya Kitaoka 120a6e
      id = xsh->getStageObjectParent(id);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (id.isColumn()) {
Shinya Kitaoka 120a6e
      // the stack is connected
Shinya Kitaoka 120a6e
      for (int j = 0; j < (int)stack.size(); j++)
Shinya Kitaoka 120a6e
        connectedColumns.insert(stack[j].getIndex());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Campbell Barton 8c6c57
static bool canShowBone(Skeleton::Bone *bone, TXsheet *xsh, int row) {
Shinya Kitaoka 120a6e
  TStageObjectId id = bone->getStageObject()->getId();
Shinya Kitaoka 120a6e
  if (!xsh->getCell(row, id.getIndex()).isEmpty() &&
Shinya Kitaoka 120a6e
      xsh->getColumn(id.getIndex())->isCamstandVisible())
Shinya Kitaoka 120a6e
    return true;
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < bone->getChildCount(); i++) {
Shinya Kitaoka 120a6e
    if (canShowBone(bone->getChild(i), xsh, row)) return true;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//============================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
HookData::HookData(TXsheet *xsh, int columnIndex, int hookId,
Shinya Kitaoka 120a6e
                   const TPointD &pos)
Shinya Kitaoka 120a6e
    : m_columnIndex(columnIndex)
Shinya Kitaoka 120a6e
    , m_hookId(hookId)
Shinya Kitaoka 120a6e
    , m_pos(pos)
Shinya Kitaoka 120a6e
    , m_isPivot(false) {
Shinya Kitaoka 120a6e
  std::string handle =
Shinya Kitaoka 120a6e
      xsh->getStageObject(TStageObjectId::ColumnId(columnIndex))->getHandle();
Shinya Kitaoka 120a6e
  if (m_hookId == 0) {
Shinya Kitaoka 120a6e
    // if the current handle is a hook the the hook#0 should be the default
Shinya Kitaoka 120a6e
    // center, i.e. B
Shinya Kitaoka 120a6e
    if (handle.find("H") == 0)
Shinya Kitaoka 120a6e
      m_name = "B";
Shinya Kitaoka 120a6e
    else {
Shinya Kitaoka 120a6e
      m_name    = handle;
Shinya Kitaoka 120a6e
      m_isPivot = true;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    m_name    = std::to_string(m_hookId);
Shinya Kitaoka 120a6e
    m_isPivot = "H" + m_name == handle;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//============================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
enum ToolDevice {
Shinya Kitaoka 120a6e
  TD_None        = -1,
Shinya Kitaoka 120a6e
  TD_Translation = 1,
Shinya Kitaoka 120a6e
  TD_Rotation,
Shinya Kitaoka 120a6e
  TD_Center,
Shinya Kitaoka 120a6e
  TD_ChangeParent,
Shinya Kitaoka 120a6e
  TD_ChangeDrawing,
Shinya Kitaoka 120a6e
  TD_IncrementDrawing,
Shinya Kitaoka 120a6e
  TD_DecrementDrawing,
Shinya Kitaoka 120a6e
  TD_InverseKinematics,
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TD_Hook            = 10000,
Shinya Kitaoka 120a6e
  TD_LockStageObject = 20000,
Shinya Kitaoka 120a6e
  TD_MagicLink       = 30000,
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TD_Test = 100000
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//============================================================
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
// SkeletonTool
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
SkeletonTool skeletonTool;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
SkeletonTool::SkeletonTool()
Shinya Kitaoka 120a6e
    : TTool("T_Skeleton")
Shinya Kitaoka 120a6e
    , m_active(false)
Shinya Kitaoka 120a6e
    , m_device(TD_None)
Shinya Kitaoka 120a6e
    , m_mode("Mode:")
Shinya Kitaoka 120a6e
    , m_showOnlyActiveSkeleton("Show Only Active Skeleton", false)
Shinya Kitaoka 120a6e
    , m_globalKeyframes("Global Key", false)
Shinya Kitaoka 120a6e
    , m_dragTool(0)
Shinya Kitaoka 120a6e
    , m_firstTime(true)
Shinya Kitaoka 120a6e
    , m_currentFrame(-1)
Shinya Kitaoka 120a6e
    , m_parentProbe()
Shinya Kitaoka 120a6e
    , m_parentProbeEnabled(false)
Shinya Kitaoka 120a6e
    , m_otherColumn(-1)
Shinya Kitaoka 120a6e
    , m_otherColumnBBoxAff()
Shinya Kitaoka 120a6e
    , m_otherColumnBBox()
Shinya Kitaoka 120a6e
    , m_labelPos(0, 0)
Shinya Kitaoka 120a6e
    , m_label("") {
Shinya Kitaoka 120a6e
  bind(TTool::CommonLevels);
Shinya Kitaoka 120a6e
  m_prop.bind(m_mode);
Shinya Kitaoka 120a6e
  m_prop.bind(m_globalKeyframes);
Shinya Kitaoka 120a6e
  m_prop.bind(m_showOnlyActiveSkeleton);
Shinya Kitaoka 120a6e
  m_mode.setId("SkeletonMode");
Shinya Kitaoka 120a6e
  m_globalKeyframes.setId("GlobalKey");
Shinya Kitaoka 120a6e
  m_showOnlyActiveSkeleton.setId("ShowOnlyActiveSkeleton");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_mode.addValue(BUILD_SKELETON);
Shinya Kitaoka 120a6e
  m_mode.addValue(ANIMATE);
Shinya Kitaoka 120a6e
  m_mode.addValue(INVERSE_KINEMATICS);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_commandHandler = new CommandHandler();
Shinya Kitaoka 120a6e
  m_commandHandler->setTempPinnedSet(&m_temporaryPinnedColumns);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
SkeletonTool::~SkeletonTool() { delete m_dragTool; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool SkeletonTool::onPropertyChanged(std::string propertyName) {
Shinya Kitaoka 120a6e
  SkeletonGlobalKeyFrame = (int)(m_globalKeyframes.getValue());
Shinya Kitaoka 120a6e
  // SkeletonInverseKinematics=(int)(m_ikEnabled.getValue());
Shinya Kitaoka 120a6e
  invalidate();
Shinya Kitaoka 120a6e
  return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool SkeletonTool::isGlobalKeyframesEnabled() const {
Shinya Kitaoka 120a6e
  return m_globalKeyframes.getValue();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SkeletonTool::updateTranslation() {
Shinya Kitaoka 120a6e
  // m_ikEnabled.setQStringName(tr("Inverse Kinematics"));
Shinya Kitaoka 120a6e
  m_showOnlyActiveSkeleton.setQStringName(tr("Show Only Active Skeleton"));
Shinya Kitaoka 120a6e
  m_globalKeyframes.setQStringName(tr("Global Key"));
Shinya Kitaoka 120a6e
  m_mode.setQStringName(tr("Mode:"));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool SkeletonTool::doesApply() const {
Shinya Kitaoka 120a6e
  TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
  TXsheet *xsh            = app->getCurrentXsheet()->getXsheet();
Shinya Kitaoka 120a6e
  assert(xsh);
Shinya Kitaoka 120a6e
  TStageObjectId objId = app->getCurrentObject()->getObjectId();
Shinya Kitaoka 120a6e
  if (objId.isColumn()) {
Shinya Kitaoka 120a6e
    TXshColumn *column = xsh->getColumn(objId.getIndex());
Shinya Kitaoka 120a6e
    if (column && column->getSoundColumn()) return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SkeletonTool::mouseMove(const TPointD &, const TMouseEvent &e) {
Shinya Kitaoka 120a6e
  int selectedDevice = pick(e.m_pos);
Shinya Kitaoka 120a6e
  if (selectedDevice != m_device) {
Shinya Kitaoka 120a6e
    m_device = selectedDevice;
Shinya Kitaoka 120a6e
    invalidate();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SkeletonTool::leftButtonDown(const TPointD &ppos, const TMouseEvent &e) {
Shinya Kitaoka 120a6e
  m_otherColumn        = -1;
Shinya Kitaoka 120a6e
  m_otherColumnBBox    = TRectD();
Shinya Kitaoka 120a6e
  m_otherColumnBBoxAff = TAffine();
Shinya Kitaoka 120a6e
  m_labelPos           = TPointD(0, 0);
Shinya Kitaoka 120a6e
  m_label              = "";
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TUndoManager::manager()->beginBlock();
Shinya Kitaoka 120a6e
  if (!doesApply()) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(m_dragTool == 0);
Shinya Kitaoka 120a6e
  m_dragTool = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
  int currentColumnIndex  = app->getCurrentColumn()->getColumnIndex();
Shinya Kitaoka 120a6e
  TXsheet *xsh            = app->getCurrentScene()->getScene()->getXsheet();
Shinya Kitaoka 120a6e
  TPointD pos             = ppos;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int selectedDevice = pick(e.m_pos);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // cambio drawing
Shinya Kitaoka 120a6e
  if (selectedDevice == TD_ChangeDrawing ||
Shinya Kitaoka 120a6e
      selectedDevice == TD_IncrementDrawing ||
Shinya Kitaoka 120a6e
      selectedDevice == TD_DecrementDrawing) {
Shinya Kitaoka 120a6e
    int d = 0;
Shinya Kitaoka 120a6e
    if (selectedDevice == TD_IncrementDrawing)
Shinya Kitaoka 120a6e
      d = 1;
Shinya Kitaoka 120a6e
    else if (selectedDevice == TD_DecrementDrawing)
Shinya Kitaoka 120a6e
      d        = -1;
Shinya Kitaoka 120a6e
    m_dragTool = new ChangeDrawingTool(this, d);
Shinya Kitaoka 120a6e
    m_dragTool->leftButtonDown(ppos, e);
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // click su un hook: attacca la colonna corrente tramite quell'hook
Shinya Kitaoka 120a6e
  if (TD_Hook <= selectedDevice && selectedDevice < TD_Hook + 50) {
Shinya Kitaoka 120a6e
    TXsheet *xsh         = app->getCurrentXsheet()->getXsheet();
Shinya Kitaoka 120a6e
    TStageObjectId objId = TStageObjectId::ColumnId(currentColumnIndex);
Shinya Kitaoka 120a6e
    TPointD p0           = getCurrentColumnMatrix() * TPointD(0, 0);
Shinya Kitaoka 120a6e
    HookData hook(xsh, currentColumnIndex, selectedDevice - TD_Hook, p0);
Shinya Kitaoka 120a6e
    TStageObjectCmd::setHandle(objId, hook.getHandle(),
Shinya Kitaoka 120a6e
                               app->getCurrentXsheet());
Shinya Kitaoka 120a6e
    app->getCurrentXsheet()->notifyXsheetChanged();
Shinya Kitaoka 120a6e
    invalidate();
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // magic link
Shinya Kitaoka 120a6e
  if (TD_MagicLink <= selectedDevice &&
Shinya Kitaoka 120a6e
      selectedDevice < TD_MagicLink + (int)m_magicLinks.size()) {
Shinya Kitaoka 120a6e
    magicLink(selectedDevice - TD_MagicLink);
Shinya Kitaoka 120a6e
    app->getCurrentXsheet()->notifyXsheetChanged();
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_device          = selectedDevice;
Shinya Kitaoka 120a6e
  bool justSelected = false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_device < 0) {
Shinya Kitaoka 120a6e
    // nessun gadget cliccato. Eventualmente seleziono la colonna
Shinya Kitaoka 120a6e
    std::vector<int> columnIndexes;</int>
Shinya Kitaoka 120a6e
    getViewer()->posToColumnIndexes(e.m_pos, columnIndexes, getPixelSize() * 5,
Shinya Kitaoka 120a6e
                                    false);
Shinya Kitaoka 120a6e
    if (!columnIndexes.empty()) {
Shinya Kitaoka 120a6e
      int columnIndex;
Shinya Kitaoka 120a6e
      columnIndex = columnIndexes.back();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (columnIndex >= 0 && columnIndex != currentColumnIndex) {
Shinya Kitaoka 120a6e
        if (!isColumnLocked(columnIndex)) {
Shinya Kitaoka 120a6e
          pos = getMatrix() * pos;
Shinya Kitaoka 120a6e
          app->getCurrentColumn()->setColumnIndex(columnIndex);
Shinya Kitaoka 120a6e
          updateMatrix();
Shinya Kitaoka 120a6e
          currentColumnIndex = columnIndex;
Shinya Kitaoka 120a6e
          justSelected       = true;
Shinya Kitaoka 120a6e
          pos                = getMatrix().inv() * pos;
Shinya Kitaoka 120a6e
        } else {
Shinya Kitaoka 120a6e
          m_label    = "Column is locked";
Shinya Kitaoka 120a6e
          m_labelPos = pos;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_device < 0) {
Shinya Kitaoka 120a6e
    if (m_mode.getValue() == INVERSE_KINEMATICS)
Shinya Kitaoka 120a6e
      m_device = TD_InverseKinematics;
Shinya Kitaoka 120a6e
    else if (m_mode.getValue() == ANIMATE)
Shinya Kitaoka 120a6e
      m_device = TD_Rotation;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // lock/unlock: modalita IK
Shinya Kitaoka 120a6e
  if (TD_LockStageObject <= m_device && m_device < TD_LockStageObject + 1000) {
Shinya Kitaoka 120a6e
    int columnIndex = m_device - TD_LockStageObject;
Shinya Kitaoka 120a6e
    int frame       = app->getCurrentFrame()->getFrame();
Shinya Kitaoka 120a6e
    togglePinnedStatus(columnIndex, frame, e.isShiftPressed());
Shinya Kitaoka 120a6e
    invalidate();
Shinya Kitaoka 120a6e
    m_dragTool = 0;
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  switch (m_device) {
Shinya Kitaoka 120a6e
  case TD_Center:
Shinya Kitaoka 120a6e
    m_dragTool = new DragCenterTool(this);
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case TD_Translation:
Shinya Kitaoka 120a6e
    m_dragTool = new DragPositionTool(this);
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case TD_Rotation:
Shinya Kitaoka 120a6e
    m_dragTool = new DragRotationTool(this, justSelected);
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case TD_ChangeParent:
Shinya Kitaoka 120a6e
    m_dragTool = new ParentChangeTool(this, getViewer());
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case TD_InverseKinematics: {
Shinya Kitaoka 120a6e
    Skeleton *skeleton = new Skeleton();
Shinya Kitaoka 120a6e
    buildSkeleton(*skeleton, currentColumnIndex);
Shinya Kitaoka 120a6e
    m_dragTool = new IKTool(this, getViewer(), skeleton, currentColumnIndex);
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_dragTool) {
Shinya Kitaoka 120a6e
    m_dragTool->leftButtonDown(pos, e);
Shinya Kitaoka 120a6e
    invalidate();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SkeletonTool::leftButtonDrag(const TPointD &pos, const TMouseEvent &e) {
Shinya Kitaoka 120a6e
  if (m_dragTool) {
Shinya Kitaoka 120a6e
    m_dragTool->leftButtonDrag(pos, e);
Shinya Kitaoka 120a6e
    invalidate();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SkeletonTool::leftButtonUp(const TPointD &pos, const TMouseEvent &e) {
Shinya Kitaoka 120a6e
  m_label    = "";
Shinya Kitaoka 120a6e
  m_labelPos = TPointD(0, 0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_dragTool) {
Shinya Kitaoka 120a6e
    m_dragTool->leftButtonUp(pos, e);
Shinya Kitaoka 120a6e
    delete m_dragTool;
Shinya Kitaoka 120a6e
    m_dragTool = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TTool::getApplication()->getCurrentXsheet()->notifyXsheetChanged();
Shinya Kitaoka 120a6e
    TTool::getApplication()->getCurrentObject()->notifyObjectIdChanged(
Shinya Kitaoka 120a6e
        false);  // Keyframes navigator reads this
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (m_device == TD_IncrementDrawing || m_device == TD_DecrementDrawing ||
Shinya Kitaoka 120a6e
      m_device == TD_ChangeDrawing)
Shinya Kitaoka 120a6e
    m_device = pick(e.m_pos);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    m_device = -1;
Shinya Kitaoka 120a6e
  invalidate();
Shinya Kitaoka 120a6e
  TUndoManager::manager()->endBlock();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool SkeletonTool::keyDown(int key, TUINT32 flags, const TPoint &pos) {
Shinya Kitaoka 120a6e
  ChangeDrawingTool tool(this, 0);
Shinya Kitaoka 120a6e
  if (key == TwConsts::TK_UpArrow)
Shinya Kitaoka 120a6e
    tool.changeDrawing(1);
Shinya Kitaoka 120a6e
  else if (key == TwConsts::TK_DownArrow)
Shinya Kitaoka 120a6e
    tool.changeDrawing(-1);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
  invalidate();
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class TogglePinnedStatusUndo final : public TUndo {
Shinya Kitaoka 120a6e
  SkeletonTool *m_tool;
Shinya Kitaoka 120a6e
  std::set<int> m_oldTemp, m_newTemp;</int>
Shinya Kitaoka 120a6e
  int m_columnIndex, m_oldColumnIndex;
Shinya Kitaoka 120a6e
  std::pair<int, int=""> m_newRange, m_oldRange;</int,>
Shinya Kitaoka 120a6e
  TAffine m_oldPlacement, m_newPlacement;
Shinya Kitaoka 120a6e
  std::vector<std::pair<tstageobjectid, tstageobject::keyframe="">> m_keyframes;</std::pair<tstageobjectid,>
Shinya Kitaoka 120a6e
  int m_frame;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  TogglePinnedStatusUndo(SkeletonTool *tool, int frame)
Shinya Kitaoka 120a6e
      : m_tool(tool)
Shinya Kitaoka 120a6e
      , m_oldTemp()
Shinya Kitaoka 120a6e
      , m_newTemp()
Shinya Kitaoka 120a6e
      , m_columnIndex(-1)
Shinya Kitaoka 120a6e
      , m_oldColumnIndex(-1)
Shinya Kitaoka 120a6e
      , m_newRange(0, -1)
Shinya Kitaoka 120a6e
      , m_oldRange(0, -1)
Shinya Kitaoka 120a6e
      , m_frame(frame) {}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void addBoneId(const TStageObjectId &id) {
Shinya Kitaoka 120a6e
    TStageObject *stageObject = getXsheet()->getStageObject(id);
Shinya Kitaoka 120a6e
    if (stageObject) {
Shinya Kitaoka 120a6e
      TStageObject::Keyframe k = stageObject->getKeyframe(m_frame);
Shinya Kitaoka 120a6e
      m_keyframes.push_back(std::make_pair(id, k));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void setOldRange(int columnIndex, int first, int second,
Shinya Kitaoka 120a6e
                   const TAffine &placement) {
Shinya Kitaoka 120a6e
    m_oldColumnIndex = columnIndex;
Shinya Kitaoka 120a6e
    m_oldRange       = std::make_pair(first, second);
Shinya Kitaoka 120a6e
    m_oldPlacement   = placement;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  void setNewRange(int columnIndex, int first, int second,
Shinya Kitaoka 120a6e
                   const TAffine &placement) {
Shinya Kitaoka 120a6e
    m_columnIndex  = columnIndex;
Shinya Kitaoka 120a6e
    m_newRange     = std::make_pair(first, second);
Shinya Kitaoka 120a6e
    m_newPlacement = placement;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  void setOldTemp(const std::set<int> &oldTemp) { m_oldTemp = oldTemp; }</int>
Shinya Kitaoka 120a6e
  void setNewTemp(const std::set<int> &newTemp) { m_newTemp = newTemp; }</int>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TStageObject *getStageObject(int columnIndex) const {
Shinya Kitaoka 120a6e
    return TTool::getApplication()
Shinya Kitaoka 120a6e
        ->getCurrentXsheet()
Shinya Kitaoka 120a6e
        ->getXsheet()
Shinya Kitaoka 120a6e
        ->getStageObject(TStageObjectId::ColumnId(columnIndex));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TPinnedRangeSet *getRangeSet(int columnIndex) const {
Shinya Kitaoka 120a6e
    return getStageObject(columnIndex)->getPinnedRangeSet();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TXsheet *getXsheet() const {
Shinya Kitaoka 120a6e
    return TTool::getApplication()->getCurrentXsheet()->getXsheet();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void notify() const {
Shinya Kitaoka 120a6e
    m_tool->invalidate();
Shinya Kitaoka 120a6e
    TXsheet *xsh         = getXsheet();
Shinya Kitaoka 120a6e
    int index            = m_columnIndex;
Shinya Kitaoka 120a6e
    if (index < 0) index = m_oldColumnIndex;
Shinya Kitaoka 120a6e
    if (index >= 0) {
Shinya Kitaoka 120a6e
      TStageObjectId id = TStageObjectId::ColumnId(index);
Shinya Kitaoka 120a6e
      TStageObjectId parentId;
Shinya Kitaoka 120a6e
      while (parentId = xsh->getStageObjectParent(id), parentId.isColumn())
Shinya Kitaoka 120a6e
        id = parentId;
Shinya Kitaoka 120a6e
      xsh->getStageObject(id)->invalidate();
Shinya Kitaoka 120a6e
      TTool::getApplication()->getCurrentXsheet()->notifyXsheetChanged();
Shinya Kitaoka 120a6e
      TTool::getApplication()->getCurrentObject()->notifyObjectIdChanged(false);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void undo() const override {
Shinya Kitaoka 120a6e
    m_tool->setTemporaryPinnedColumns(m_oldTemp);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (m_columnIndex >= 0)
Shinya Kitaoka 120a6e
      getRangeSet(m_columnIndex)
Shinya Kitaoka 120a6e
          ->removeRange(m_newRange.first, m_newRange.second);
Shinya Kitaoka 120a6e
    if (m_oldColumnIndex >= 0) {
Shinya Kitaoka 120a6e
      TPinnedRangeSet *rangeSet = getRangeSet(m_oldColumnIndex);
Shinya Kitaoka 120a6e
      rangeSet->setRange(m_oldRange.first, m_oldRange.second);
Shinya Kitaoka 120a6e
      rangeSet->setPlacement(m_oldPlacement);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    TXsheet *xsh = getXsheet();
Shinya Kitaoka 120a6e
    for (int i = 0; i < (int)m_keyframes.size(); i++) {
Shinya Kitaoka 120a6e
      TStageObject *stageObject =
Shinya Kitaoka 120a6e
          getXsheet()->getStageObject(m_keyframes[i].first);
Shinya Kitaoka 120a6e
      if (!stageObject) continue;
Shinya Kitaoka 120a6e
      stageObject->removeKeyframeWithoutUndo(m_frame);
Shinya Kitaoka 120a6e
      if (m_keyframes[i].second.m_isKeyframe)
Shinya Kitaoka 120a6e
        stageObject->setKeyframeWithoutUndo(m_frame, m_keyframes[i].second);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    notify();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void redo() const override {
Shinya Kitaoka 120a6e
    TXsheet *xsh = getXsheet();
Shinya Kitaoka 120a6e
    for (int i = 0; i < (int)m_keyframes.size(); i++) {
Shinya Kitaoka 120a6e
      TStageObject *stageObject =
Shinya Kitaoka 120a6e
          getXsheet()->getStageObject(m_keyframes[i].first);
Shinya Kitaoka 120a6e
      if (stageObject) stageObject->setKeyframeWithoutUndo(m_frame);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    m_tool->setTemporaryPinnedColumns(m_newTemp);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (m_oldColumnIndex >= 0)
Shinya Kitaoka 120a6e
      getRangeSet(m_oldColumnIndex)
Shinya Kitaoka 120a6e
          ->removeRange(m_oldRange.first, m_oldRange.second);
Shinya Kitaoka 120a6e
    if (m_columnIndex >= 0) {
Shinya Kitaoka 120a6e
      TPinnedRangeSet *rangeSet = getRangeSet(m_columnIndex);
Shinya Kitaoka 120a6e
      rangeSet->setRange(m_newRange.first, m_newRange.second);
Shinya Kitaoka 120a6e
      rangeSet->setPlacement(m_newPlacement);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    notify();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 473e70
  int getSize() const override { return sizeof *this; }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SkeletonTool::togglePinnedStatus(int columnIndex, int frame,
Shinya Kitaoka 120a6e
                                      bool shiftPressed) {
Shinya Kitaoka 120a6e
  Skeleton skeleton;
Shinya Kitaoka 120a6e
  buildSkeleton(skeleton, columnIndex);
Shinya Kitaoka 120a6e
  if (!skeleton.getRootBone() || !skeleton.getRootBone()->getStageObject())
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  Skeleton::Bone *bone = skeleton.getBoneByColumnIndex(columnIndex);
Shinya Kitaoka 120a6e
  assert(bone);
Shinya Kitaoka 120a6e
  if (!bone) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TogglePinnedStatusUndo *undo = new TogglePinnedStatusUndo(this, frame);
Shinya Kitaoka 120a6e
  for (int i = 0; i < skeleton.getBoneCount(); i++) {
Shinya Kitaoka 120a6e
    TStageObject *obj = skeleton.getBone(i)->getStageObject();
Shinya Kitaoka 120a6e
    if (obj) {
Shinya Kitaoka 120a6e
      undo->addBoneId(obj->getId());
Shinya Kitaoka 120a6e
      obj->setKeyframeWithoutUndo(frame);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  getApplication()->getCurrentXsheet()->notifyXsheetChanged();
Shinya Kitaoka 120a6e
  getApplication()->getCurrentObject()->notifyObjectIdChanged(false);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  undo->setOldTemp(m_temporaryPinnedColumns);
Shinya Kitaoka 120a6e
  bool isTemporaryPinned = m_temporaryPinnedColumns.count(columnIndex) > 0;
Shinya Kitaoka 120a6e
  if (shiftPressed || isTemporaryPinned) {
Shinya Kitaoka 120a6e
    if (isTemporaryPinned)
Shinya Kitaoka 120a6e
      m_temporaryPinnedColumns.erase(columnIndex);
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      m_temporaryPinnedColumns.insert(columnIndex);
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    TXsheet *xsh = TTool::getApplication()->getCurrentXsheet()->getXsheet();
Shinya Kitaoka 120a6e
    TAffine placement =
Shinya Kitaoka 120a6e
        xsh->getPlacement(bone->getStageObject()->getId(), frame);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TStageObjectId rootId = skeleton.getRootBone()->getStageObject()->getId();
Shinya Kitaoka 120a6e
    TAffine rootPlacement = xsh->getPlacement(rootId, frame);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    int pinnedStatus = bone->getPinnedStatus();
Shinya Kitaoka 120a6e
    if (pinnedStatus != Skeleton::Bone::PINNED) {
Shinya Kitaoka 120a6e
      int oldPinned = -1;
Shinya Kitaoka 120a6e
      for (int i = 0; i < skeleton.getBoneCount(); i++) {
Shinya Kitaoka 120a6e
        TStageObject *obj = skeleton.getBone(i)->getStageObject();
Shinya Kitaoka 120a6e
        if (obj->getPinnedRangeSet()->isPinned(frame)) {
Shinya Kitaoka 120a6e
          oldPinned = i;
Shinya Kitaoka 120a6e
          break;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      int lastFrame = 1000000;
Shinya Kitaoka 120a6e
      if (oldPinned >= 0) {
Shinya Kitaoka 120a6e
        assert(skeleton.getBone(oldPinned) != bone);
Shinya Kitaoka 120a6e
        TStageObject *obj = skeleton.getBone(oldPinned)->getStageObject();
Shinya Kitaoka 120a6e
        const TPinnedRangeSet::Range *range =
Shinya Kitaoka 120a6e
            obj->getPinnedRangeSet()->getRange(frame);
Shinya Kitaoka 120a6e
        assert(range && range->first <= frame && frame <= range->second);
Shinya Kitaoka 120a6e
        lastFrame                 = range->second;
Shinya Kitaoka 120a6e
        TPinnedRangeSet *rangeSet = obj->getPinnedRangeSet();
Shinya Kitaoka 120a6e
        rangeSet->removeRange(frame, range->second);
Shinya Kitaoka 120a6e
        obj->invalidate();
Shinya Kitaoka 120a6e
        undo->setOldRange(oldPinned, frame, range->second,
Shinya Kitaoka 120a6e
                          rangeSet->getPlacement());
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        for (int i = 0; i < skeleton.getBoneCount(); i++) {
Shinya Kitaoka 120a6e
          TStageObject *obj = skeleton.getBone(i)->getStageObject();
Shinya Kitaoka 120a6e
          const TPinnedRangeSet::Range *range =
Shinya Kitaoka 120a6e
              obj->getPinnedRangeSet()->getNextRange(frame);
Shinya Kitaoka 120a6e
          if (range) {
Shinya Kitaoka 120a6e
            assert(range->first > frame);
Shinya Kitaoka 120a6e
            if (range->first - 1 < lastFrame) lastFrame = range->first - 1;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      TStageObject *obj         = bone->getStageObject();
Shinya Kitaoka 120a6e
      TPinnedRangeSet *rangeSet = obj->getPinnedRangeSet();
Shinya Kitaoka 120a6e
      rangeSet->setRange(frame, lastFrame);
Shinya Kitaoka 120a6e
      if (frame == 0) {
Shinya Kitaoka 120a6e
        // this code should be moved elsewhere, possibly in the stageobject
Shinya Kitaoka 120a6e
        // implementation
Shinya Kitaoka 120a6e
        // the idea is to remove the normal
Shinya Kitaoka 120a6e
        TStageObject *rootObj = skeleton.getRootBone()->getStageObject();
Shinya Kitaoka 120a6e
        rootObj->setStatus(TStageObject::XY);
Shinya Kitaoka 120a6e
        placement = rootObj->getPlacement(0).inv() * placement;
Shinya Kitaoka 120a6e
        rootObj->setStatus(TStageObject::IK);
Shinya Kitaoka 120a6e
        rangeSet->setPlacement(placement);
Shinya Kitaoka 120a6e
        rootObj->invalidate();
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      undo->setNewRange(bone->getColumnIndex(), frame, lastFrame,
Shinya Kitaoka 120a6e
                        rangeSet->getPlacement());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  undo->setNewTemp(m_temporaryPinnedColumns);
Shinya Kitaoka 120a6e
  TUndoManager::manager()->add(undo);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SkeletonTool::drawSkeleton(const Skeleton &skeleton, int row) {
Shinya Kitaoka 120a6e
  bool buildingSkeleton = m_mode.getValue() == BUILD_SKELETON;
Shinya Kitaoka 120a6e
  bool ikEnabled        = m_mode.getValue() == INVERSE_KINEMATICS;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TXsheet *xsh = getXsheet();
Shinya Kitaoka 120a6e
  std::vector<int> showBoneIndex;</int>
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < skeleton.getBoneCount(); i++) {
Shinya Kitaoka 120a6e
    Skeleton::Bone *bone = skeleton.getBone(i);
Shinya Kitaoka 120a6e
    TStageObjectId id    = bone->getStageObject()->getId();
Shinya Kitaoka 120a6e
    bool canShow         = canShowBone(bone, xsh, row);
Shinya Kitaoka 120a6e
    if (!canShow) continue;
Shinya Kitaoka 120a6e
    showBoneIndex.push_back(i);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool changingParent = dynamic_cast<parentchangetool *="">(m_dragTool) != 0;</parentchangetool>
Shinya Kitaoka 120a6e
  TStageObjectId currentObjectId =
Shinya Kitaoka 120a6e
      TTool::getApplication()->getCurrentObject()->getObjectId();
Shinya Kitaoka 120a6e
  std::string currentHandle = xsh->getStageObject(currentObjectId)->getHandle();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (i = 0; i < (int)showBoneIndex.size(); i++) {
Shinya Kitaoka 120a6e
    Skeleton::Bone *bone = skeleton.getBone(showBoneIndex[i]);
Shinya Kitaoka 120a6e
    TStageObjectId id    = bone->getStageObject()->getId();
Shinya Kitaoka 120a6e
    bool isCurrent       = id == currentObjectId;
Shinya Kitaoka 120a6e
    if (isCurrent && buildingSkeleton && m_parentProbeEnabled) {
Shinya Kitaoka 120a6e
      if (!m_magicLinks.empty()) {
Shinya Kitaoka 120a6e
        drawBone(bone->getCenter(), m_magicLinks[0].m_h1.m_pos, false);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      drawBone(bone->getCenter(), m_parentProbe, true);
Shinya Kitaoka 120a6e
    } else if (ikEnabled) {
Shinya Kitaoka 120a6e
      if (bone->getParent())
Shinya Kitaoka 120a6e
        drawIKBone(bone->getCenter(), bone->getParent()->getCenter());
Shinya Kitaoka 120a6e
    } else if (bone->getParent() || isCurrent) {
Shinya Kitaoka 120a6e
      double pixelSize = getPixelSize();
Shinya Kitaoka 120a6e
      TPointD a        = bone->getCenter();
Shinya Kitaoka 120a6e
      TPointD b, pm;
Shinya Kitaoka 120a6e
      if (bone->getParent()) {
Shinya Kitaoka 120a6e
        b  = bone->getParent()->getCenter();
Shinya Kitaoka 120a6e
        pm = (a + b) * 0.5;
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        pm = b = a + TPointD(0, 60) * pixelSize;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      bool boneIsVisible = false;
Shinya Kitaoka 120a6e
      if (buildingSkeleton) {
Shinya Kitaoka 120a6e
        boneIsVisible = true;
Shinya Kitaoka 120a6e
        if (bone->isSelected())
Shinya Kitaoka 120a6e
          drawBone(a, b, true);
Shinya Kitaoka 120a6e
        else if (!m_showOnlyActiveSkeleton.getValue())
Shinya Kitaoka 120a6e
          drawBone(a, b, false);
Shinya Kitaoka 120a6e
        else
Shinya Kitaoka 120a6e
          boneIsVisible = false;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      if (boneIsVisible && isCurrent) {
Shinya Kitaoka 120a6e
        // draw change parent gadget
Shinya Kitaoka 120a6e
        double r = pixelSize * 5;
Shinya Kitaoka 120a6e
        if (isPicking()) {
Shinya Kitaoka 120a6e
          // int code = TD_ResetParent +
Shinya Kitaoka 120a6e
          // bone->getStageObject()->getId().getIndex();
Shinya Kitaoka 120a6e
          glPushName(TD_ChangeParent);
Shinya Kitaoka 120a6e
          tglDrawDisk(pm, r);
Shinya Kitaoka 120a6e
          glPopName();
Shinya Kitaoka 120a6e
        } else {
Shinya Kitaoka 120a6e
          if (m_device == TD_ChangeParent) {
Shinya Kitaoka 120a6e
            glColor4d(0.47 * alpha, 0.6 * alpha, 0.65 * alpha, alpha);
Shinya Kitaoka 120a6e
            r *= 1.5;
Shinya Kitaoka 120a6e
          } else
Shinya Kitaoka 120a6e
            glColor4d(0.37 * alpha, 0.5 * alpha, 0.55 * alpha, alpha);
Shinya Kitaoka 120a6e
          glRectd(pm.x - r, pm.y - r, pm.x + r, pm.y + r);
Shinya Kitaoka 120a6e
          glColor3d(0, 0, 0);
Shinya Kitaoka 120a6e
          tglDrawRect(pm.x - r, pm.y - r, pm.x + r, pm.y + r);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  for (i = 0; i < (int)showBoneIndex.size(); i++) {
Shinya Kitaoka 120a6e
    Skeleton::Bone *bone = skeleton.getBone(showBoneIndex[i]);
Shinya Kitaoka 120a6e
    if (!m_showOnlyActiveSkeleton.getValue() || bone->isSelected())
Shinya Kitaoka 120a6e
      drawJoint(bone->getCenter(),
Shinya Kitaoka 120a6e
                currentObjectId == bone->getStageObject()->getId() &&
Shinya Kitaoka 120a6e
                    currentHandle.find("H") != 0);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SkeletonTool::getImageBoundingBox(TRectD &bbox, TAffine &aff, int frame,
Shinya Kitaoka 120a6e
                                       int columnIndex) {
Shinya Kitaoka 120a6e
  TAffine columnAff =
Shinya Kitaoka 120a6e
      getXsheet()->getPlacement(TStageObjectId::ColumnId(columnIndex), frame);
Shinya Kitaoka 120a6e
  // TAffine affine = getColumnMatrix(columnIndex);
Shinya Kitaoka 120a6e
  TXshCell cell    = getXsheet()->getCell(frame, columnIndex);
Shinya Kitaoka 120a6e
  TImageP image    = cell.getImage(false);
Shinya Kitaoka 120a6e
  TToonzImageP ti  = image;
Shinya Kitaoka 120a6e
  TVectorImageP vi = image;
Shinya Kitaoka 120a6e
  if (ti) {
Shinya Kitaoka 120a6e
    TAffine imageDpiAff;
Shinya Kitaoka 120a6e
    if (cell.m_level->getSimpleLevel())
Shinya Kitaoka 120a6e
      imageDpiAff =
Shinya Kitaoka 120a6e
          getDpiAffine(cell.m_level->getSimpleLevel(), cell.m_frameId, true);
Shinya Kitaoka 120a6e
    aff  = columnAff * imageDpiAff;
Shinya Kitaoka 120a6e
    bbox = ToonzImageUtils::convertRasterToWorld(convert(ti->getBBox()), ti) *
Shinya Kitaoka 120a6e
           ti->getSubsampling();
Shinya Kitaoka 120a6e
    ToolUtils::drawRect(bbox * ti->getSubsampling(), TPixel32(200, 200, 200),
Shinya Kitaoka 120a6e
                        0x5555);
Shinya Kitaoka 120a6e
  } else if (vi) {
Shinya Kitaoka 120a6e
    bbox = vi->getBBox();
Shinya Kitaoka 120a6e
    aff  = columnAff;
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    bbox = TRectD();
Shinya Kitaoka 120a6e
    aff  = TAffine();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SkeletonTool::drawLevelBoundingBox(int frame, int columnIndex) {
Shinya Kitaoka 120a6e
  TAffine affine   = getCurrentColumnMatrix();
Shinya Kitaoka 120a6e
  TXshCell cell    = getXsheet()->getCell(frame, columnIndex);
Shinya Kitaoka 120a6e
  TImageP image    = cell.getImage(false);
Shinya Kitaoka 120a6e
  TToonzImageP ti  = image;
Shinya Kitaoka 120a6e
  TVectorImageP vi = image;
Shinya Kitaoka 120a6e
  glPushMatrix();
Shinya Kitaoka 120a6e
  if (affine != getMatrix()) tglMultMatrix(getMatrix().inv() * affine);
Shinya Kitaoka 120a6e
  if (ti) {
Shinya Kitaoka 120a6e
    TPointD dpiScale = getViewer()->getDpiScale();
Shinya Kitaoka 120a6e
    glScaled(dpiScale.x, dpiScale.y, 1);
Shinya Kitaoka 120a6e
    TRectD bbox =
Shinya Kitaoka 120a6e
        ToonzImageUtils::convertRasterToWorld(convert(ti->getBBox()), ti);
Shinya Kitaoka 120a6e
    ToolUtils::drawRect(bbox * ti->getSubsampling(), TPixel32(200, 200, 200),
Shinya Kitaoka 120a6e
                        0x5555);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (vi) {
Shinya Kitaoka 120a6e
    TRectD bbox = vi->getBBox();
Shinya Kitaoka 120a6e
    ToolUtils::drawRect(bbox, TPixel32(200, 200, 200), 0x5555);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  glPopMatrix();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SkeletonTool::drawIKJoint(const Skeleton::Bone *bone) {
Shinya Kitaoka 120a6e
  TPointD pos     = bone->getCenter();
Shinya Kitaoka 120a6e
  const double r0 = 6 * getPixelSize(), r1 = r0 / 3;
Shinya Kitaoka 120a6e
  int code = TD_LockStageObject + bone->getColumnIndex();
Shinya Kitaoka 120a6e
  glPushName(code);
Shinya Kitaoka 120a6e
  glColor3d(0.8, 0.5, 0.05);
Shinya Kitaoka 120a6e
  if (bone->getPinnedStatus() != Skeleton::Bone::FREE) {
Shinya Kitaoka 120a6e
    if (bone->getPinnedStatus() == Skeleton::Bone::TEMP_PINNED) {
Shinya Kitaoka 120a6e
      double r1 = r0 * 0.60;
Shinya Kitaoka 120a6e
      glColor3d(60.0 / 255.0, 250.0 / 255.0, 1.0);
Shinya Kitaoka 120a6e
      glRectd(pos.x - r0, pos.y - r0, pos.x + r0, pos.y + r0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      glColor3d(0.78, 0.62, 0);
Shinya Kitaoka 120a6e
      glRectd(pos.x - r1, pos.y - r1, pos.x + r1, pos.y + r1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      glColor3d(0.2, 0.1, 0.05);
Shinya Kitaoka 120a6e
      tglDrawRect(pos.x - r0, pos.y - r0, pos.x + r0, pos.y + r0);
Shinya Kitaoka 120a6e
      tglDrawRect(pos.x - r1, pos.y - r1, pos.x + r1, pos.y + r1);
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      glColor3d(0, 175.0 / 255.0, 1.0);
Shinya Kitaoka 120a6e
      glRectd(pos.x - r0, pos.y - r0, pos.x + r0, pos.y + r0);
Shinya Kitaoka 120a6e
      glColor3d(0.2, 0.1, 0.05);
Shinya Kitaoka 120a6e
      tglDrawRect(pos.x - r0, pos.y - r0, pos.x + r0, pos.y + r0);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    if (bone->isSelected())
Shinya Kitaoka 120a6e
      glColor3d(1, 0.78, 0.19);
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      glColor3d(0.78, 0.62, 0);
Shinya Kitaoka 120a6e
    tglDrawDisk(pos, r0);
Shinya Kitaoka 120a6e
    glColor3d(0.2, 0.1, 0.05);
Shinya Kitaoka 120a6e
    tglDrawCircle(pos, r0);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_device == code) {
Shinya Kitaoka 120a6e
    glColor3d(0.9, 0.1, 0.1);
Shinya Kitaoka 120a6e
    tglFillRect(pos.x - r1, pos.y - r1, pos.x + r1, pos.y + r1);
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    glColor3d(0.2, 0.1, 0.05);
Shinya Kitaoka 120a6e
    const double r3 = 2 * getPixelSize();
Shinya Kitaoka 120a6e
    tglDrawCircle(pos, r3);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  glPopName();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SkeletonTool::drawJoint(const TPointD &pos, bool current) {
Shinya Kitaoka 120a6e
  const double alpha = 0.8, ialpha = 1 - alpha;
Shinya Kitaoka 120a6e
  double r0 = 4 * getPixelSize();
Shinya Kitaoka 120a6e
  if (current) {
Shinya Kitaoka 120a6e
    glPushName(TD_Center);
Shinya Kitaoka 120a6e
    if (m_device == TD_Center) {
Shinya Kitaoka 120a6e
      glColor4d(0.9 * alpha, 0.8 * alpha, 0.2 * alpha, alpha);
Shinya Kitaoka 120a6e
      r0 *= 1.5;
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      glColor4d(((255.0 / 255.0) - ialpha) / alpha,
Shinya Kitaoka 120a6e
                ((200.0 / 255.0) - ialpha) / alpha,
Shinya Kitaoka 120a6e
                ((48.0 / 255.0) - ialpha) / alpha, alpha);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    tglDrawDisk(pos, r0);
Shinya Kitaoka 120a6e
    glColor3d(0.2, 0.1, 0.05);
Shinya Kitaoka 120a6e
    tglDrawCircle(pos, r0);
Shinya Kitaoka 120a6e
    glPopName();
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    // in build skeleton center is clickable, but only the current one
Shinya Kitaoka 120a6e
    if (m_mode.getValue() == BUILD_SKELETON)
Shinya Kitaoka 120a6e
      glColor4d(0.60 * alpha, 0.60 * alpha, 0.60 * alpha, alpha);
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      glColor4d(0.78 * alpha, 0.62 * alpha, 0 * alpha, alpha);
Shinya Kitaoka 120a6e
    tglDrawDisk(pos, r0);
Shinya Kitaoka 120a6e
    glColor3d(0.2, 0.1, 0.05);
Shinya Kitaoka 120a6e
    tglDrawCircle(pos, r0);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SkeletonTool::drawBone(const TPointD &a, const TPointD &b, bool selected) {
Shinya Kitaoka 120a6e
  const double alpha = 0.8;
Shinya Kitaoka 120a6e
  // se sono troppo vicini niente da fare
Shinya Kitaoka 120a6e
  TPointD delta = b - a;
Shinya Kitaoka 120a6e
  if (norm2(delta) < 0.001) return;
Shinya Kitaoka 120a6e
  TPointD u = getPixelSize() * 2.5 * normalize(rotate90(delta));
Shinya Kitaoka 120a6e
  if (selected)
Shinya Kitaoka 120a6e
    glColor4d(0.9 * alpha, 0.9 * alpha, 0.9 * alpha, alpha);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    glColor4d(0.58 * alpha, 0.58 * alpha, 0.58 * alpha, alpha);
Shinya Kitaoka 120a6e
  glBegin(GL_POLYGON);
Shinya Kitaoka 120a6e
  tglVertex(a + u);
Shinya Kitaoka 120a6e
  tglVertex(b);
Shinya Kitaoka 120a6e
  tglVertex(a - u);
Shinya Kitaoka 120a6e
  glEnd();
Shinya Kitaoka 120a6e
  glColor3d(0.2, 0.3, 0.35);
Shinya Kitaoka 120a6e
  glBegin(GL_LINE_STRIP);
Shinya Kitaoka 120a6e
  tglVertex(a + u);
Shinya Kitaoka 120a6e
  tglVertex(b);
Shinya Kitaoka 120a6e
  tglVertex(a - u);
Shinya Kitaoka 120a6e
  glEnd();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SkeletonTool::drawIKBone(const TPointD &a, const TPointD &b) {
Shinya Kitaoka 120a6e
  // se sono troppo vicini niente da fare
Shinya Kitaoka 120a6e
  TPointD delta = b - a;
Shinya Kitaoka 120a6e
  if (norm2(delta) < 0.001) return;
Shinya Kitaoka 120a6e
  TPointD u = getPixelSize() * 2.5 * normalize(rotate90(delta));
Shinya Kitaoka 120a6e
  glColor3d(0.58, 0.58, 0.58);
Shinya Kitaoka 120a6e
  glBegin(GL_POLYGON);
Shinya Kitaoka 120a6e
  tglVertex(a + u);
Shinya Kitaoka 120a6e
  tglVertex(b + u);
Shinya Kitaoka 120a6e
  tglVertex(b - u);
Shinya Kitaoka 120a6e
  tglVertex(a - u);
Shinya Kitaoka 120a6e
  glEnd();
Shinya Kitaoka 120a6e
  glColor3d(0.2, 0.3, 0.35);
Shinya Kitaoka 120a6e
  glBegin(GL_LINES);
Shinya Kitaoka 120a6e
  tglVertex(a + u);
Shinya Kitaoka 120a6e
  tglVertex(b + u);
Shinya Kitaoka 120a6e
  tglVertex(a - u);
Shinya Kitaoka 120a6e
  tglVertex(b - u);
Shinya Kitaoka 120a6e
  glEnd();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SkeletonTool::computeMagicLinks() {
Shinya Kitaoka 120a6e
  // TODO: spostare qui il calcolo dei magic link
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SkeletonTool::drawHooks() {
Shinya Kitaoka 120a6e
  // camera stand reference system
Shinya Kitaoka 120a6e
  // glColor3d(0,0,1);
Shinya Kitaoka 120a6e
  // tglDrawRect(3,3,97,97);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // glColor3d(0,1,1);
Shinya Kitaoka 120a6e
  // tglDrawRect(0,100,Stage::inch,110);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QTime time;
Shinya Kitaoka 120a6e
  time.start();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_magicLinks.clear();
Shinya Kitaoka 120a6e
  computeMagicLinks();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
  TXsheet *xsh            = app->getCurrentXsheet()->getXsheet();
Shinya Kitaoka 120a6e
  int row                 = app->getCurrentFrame()->getFrame();
Shinya Kitaoka 120a6e
  int col                 = app->getCurrentColumn()->getColumnIndex();
Shinya Kitaoka 120a6e
  TPointD dpiScale        = getViewer()->getDpiScale();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // glColor3d(1,0,1);
Shinya Kitaoka 120a6e
  // tglDrawRect(-100*dpiScale.x, -100*dpiScale.y, 0,0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // I should not show hooks of columns already connected with the current one
Shinya Kitaoka 120a6e
  // ("linking" to those hooks would create evil loops in the hierarchy)
Shinya Kitaoka 120a6e
  std::set<int> connectedColumns;</int>
Shinya Kitaoka 120a6e
  getConnectedColumns(connectedColumns, xsh, col);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::vector<hookdata> currentColumnHooks;</hookdata>
Shinya Kitaoka 120a6e
  std::vector<hookdata> otherColumnsHooks;</hookdata>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // fill currentColumnHooks
Shinya Kitaoka 120a6e
  // detect otherColumn (i.e. the active column during a click&drag operator
Shinya Kitaoka 120a6e
  int otherColumn = -1;
Shinya Kitaoka 120a6e
  if (m_parentProbeEnabled) {
Shinya Kitaoka 120a6e
    // qDebug("  parent probe enabled");
Shinya Kitaoka 120a6e
    // currentColumnHooks <- current column & current handle
Shinya Kitaoka 120a6e
    int hookId = 0;
Shinya Kitaoka 120a6e
    std::string handle =
Shinya Kitaoka 120a6e
        xsh->getStageObject(TStageObjectId::ColumnId(col))->getHandle();
Shinya Kitaoka 120a6e
    if (handle.find("H") == 0) {
Shinya Kitaoka 120a6e
      int j = 1;
Shinya Kitaoka 120a6e
      while (j < (int)handle.size() && '0' <= handle[j] && handle[j] <= '9') {
Shinya Kitaoka 120a6e
        hookId = hookId * 10 + (int)handle[j] - '0';
Shinya Kitaoka 120a6e
        j++;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    currentColumnHooks.push_back(HookData(xsh, col, hookId, m_parentProbe));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // otherColumn = "picked" column not connected
Shinya Kitaoka 120a6e
    TPoint parentProbePos = getViewer()->worldToPos(m_parentProbe);
Shinya Kitaoka 120a6e
    std::vector<int> indexes;</int>
Shinya Kitaoka 120a6e
    getViewer()->posToColumnIndexes(parentProbePos, indexes,
Shinya Kitaoka 120a6e
                                    getPixelSize() * 10, false);
Shinya Kitaoka 120a6e
    for (int i = (int)indexes.size() - 1; i >= 0; i--) {
Shinya Kitaoka 120a6e
      if (connectedColumns.count(indexes[i]) == 0) {
Shinya Kitaoka 120a6e
        otherColumn = indexes[i];
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    // if the mouse is not on a stroke, I'm using the "old" m_otherColumn, if
Shinya Kitaoka 120a6e
    // any.
Shinya Kitaoka 120a6e
    // (this is needed because of the hooks put inside of unfilled regions)
Shinya Kitaoka 120a6e
    if (otherColumn < 0 && m_otherColumn >= 0) {
Shinya Kitaoka 120a6e
      if (m_otherColumnBBox.contains(m_otherColumnBBoxAff.inv() *
Shinya Kitaoka 120a6e
                                     m_parentProbe))
Shinya Kitaoka 120a6e
        otherColumn = m_otherColumn;
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        m_otherColumn = -1;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    // parent probe not enabled: get all hooks of current column. other column =
Shinya Kitaoka 120a6e
    // -1
Shinya Kitaoka 120a6e
    getHooks(currentColumnHooks, xsh, row, col, TPointD(1, 1));  // dpiScale);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // other columns hooks <- all hooks of all unlinked columns
Shinya Kitaoka 120a6e
  for (int i = 0; i < xsh->getColumnCount(); i++)
Shinya Kitaoka 120a6e
    if (xsh->getColumn(i)->isCamstandVisible())
Shinya Kitaoka 120a6e
      if (connectedColumns.count(i) == 0)
Shinya Kitaoka 120a6e
        getHooks(otherColumnsHooks, xsh, row, i, TPointD(1, 1));  // dpiScale);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  /*
Shinya Kitaoka 120a6e
qDebug("  time=%dms", time.elapsed());
Shinya Kitaoka 120a6e
qDebug("  %d hooks (current column)", currentColumnHooks.size());
Shinya Kitaoka 120a6e
for(int i=0;i<(int)currentColumnHooks.size();i++)
Shinya Kitaoka 120a6e
qDebug("
Shinya Kitaoka 120a6e
%d,%d",currentColumnHooks[i].m_columnIndex,currentColumnHooks[i].m_hookId);
Shinya Kitaoka 120a6e
qDebug("  %d hooks (other columns)", otherColumnsHooks.size());
Shinya Kitaoka 120a6e
for(int i=0;i<(int)otherColumnsHooks.size();i++)
Shinya Kitaoka 120a6e
qDebug("
Shinya Kitaoka 120a6e
%d,%d",otherColumnsHooks[i].m_columnIndex,otherColumnsHooks[i].m_hookId);
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::vector<trectd> balloons;</trectd>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // draw current column hooks
Shinya Kitaoka 120a6e
  for (int i = 0; i < (int)currentColumnHooks.size(); i++) {
Shinya Kitaoka 120a6e
    const HookData &hook = currentColumnHooks[i];
Shinya Kitaoka 120a6e
    if (hook.m_name == "") continue;  // should not happen
Shinya Kitaoka 120a6e
    int code    = TD_Hook + hook.m_hookId;
Shinya Kitaoka 120a6e
    TPointD pos = hook.m_pos;
Shinya Kitaoka 120a6e
    ToolUtils::drawHook(pos, ToolUtils::OtherLevelHook);
Shinya Kitaoka 120a6e
    glPushName(code);
Shinya Kitaoka 120a6e
    TPixel32 color(200, 220, 205, 200);
Shinya Kitaoka 120a6e
    if (hook.m_isPivot)
Shinya Kitaoka 120a6e
      color = TPixel32(200, 200, 10, 200);
Shinya Kitaoka 120a6e
    else if (code == m_device)
Shinya Kitaoka 120a6e
      color = TPixel32(185, 255, 255);
Shinya Kitaoka 120a6e
    ToolUtils::drawBalloon(pos, hook.m_name, color, TPoint(20, 20), isPicking(),
Shinya Kitaoka 120a6e
                           &balloons);
Shinya Kitaoka 120a6e
    glPopName();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_parentProbeEnabled) {
Shinya Kitaoka 120a6e
    for (int i = 0; i < (int)otherColumnsHooks.size(); i++)
Shinya Kitaoka 120a6e
      ToolUtils::drawHook(otherColumnsHooks[i].m_pos,
Shinya Kitaoka 120a6e
                          ToolUtils::OtherLevelHook);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // search for magic links
Shinya Kitaoka 120a6e
  double minDist2       = 0;
Shinya Kitaoka 120a6e
  double snapRadius2    = 100 * getPixelSize() * getPixelSize();
Shinya Kitaoka 120a6e
  double snapRadius2bis = 100;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!m_parentProbeEnabled) {
Shinya Kitaoka 120a6e
    // "static" magic links: no parent probe
Shinya Kitaoka 120a6e
    for (int i = 0; i < (int)currentColumnHooks.size(); i++) {
Shinya Kitaoka 120a6e
      for (int j = 0; j < (int)otherColumnsHooks.size(); j++) {
Shinya Kitaoka 120a6e
        double dist2 =
Shinya Kitaoka 120a6e
            norm2(currentColumnHooks[i].m_pos - otherColumnsHooks[j].m_pos);
Shinya Kitaoka 120a6e
        if (currentColumnHooks[i].m_hookId == 0 ||
Shinya Kitaoka 120a6e
            otherColumnsHooks[j].m_hookId == 0)
Shinya Kitaoka 120a6e
          continue;
Shinya Kitaoka 120a6e
        if (dist2 < snapRadius2bis) {
Shinya Kitaoka 120a6e
          m_magicLinks.push_back(
Shinya Kitaoka 120a6e
              MagicLink(currentColumnHooks[i], otherColumnsHooks[j], dist2));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          qDebug("  magic link_a %d (%d,%d) %d (%d,%d); dist=%f", i,
Shinya Kitaoka 120a6e
                 currentColumnHooks[i].m_columnIndex,
Shinya Kitaoka 120a6e
                 currentColumnHooks[i].m_hookId, j,
Shinya Kitaoka 120a6e
                 otherColumnsHooks[j].m_columnIndex,
Shinya Kitaoka 120a6e
                 otherColumnsHooks[j].m_hookId, dist2);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_parentProbeEnabled) {
Shinya Kitaoka 120a6e
    // search for the closest hook of the picked column
Shinya Kitaoka 120a6e
    int i = -1, j = -1;
Shinya Kitaoka 120a6e
    double minDist2 = snapRadius2;
Shinya Kitaoka 120a6e
    for (i = 0; i < (int)otherColumnsHooks.size(); i++) {
Shinya Kitaoka 120a6e
      double dist2 = tdistance2(otherColumnsHooks[i].m_pos, m_parentProbe);
Shinya Kitaoka 120a6e
      if (dist2 < minDist2) {
Shinya Kitaoka 120a6e
        j           = i;
Shinya Kitaoka 120a6e
        minDist2    = dist2;
Shinya Kitaoka 120a6e
        otherColumn = otherColumnsHooks[i].m_columnIndex;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_parentProbeEnabled && otherColumn >= 0)  //  && m_magicLinks.empty()
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    // "dynamic" magic links: probing and picking a column
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // show image bounding box
Shinya Kitaoka 120a6e
    m_otherColumn = otherColumn;
Shinya Kitaoka 120a6e
    getImageBoundingBox(m_otherColumnBBox, m_otherColumnBBoxAff, row,
Shinya Kitaoka 120a6e
                        otherColumn);
Shinya Kitaoka 120a6e
    if (!m_otherColumnBBox.isEmpty()) {
Toshihiro Shimizu 890ddd
      glPushMatrix();
Shinya Kitaoka 120a6e
      tglMultMatrix(m_otherColumnBBoxAff);
Shinya Kitaoka 120a6e
      ToolUtils::drawRect(m_otherColumnBBox, TPixel32(188, 202, 191), 0xF0F0);
Shinya Kitaoka 120a6e
      // tglDrawRect(img->getBBox());
Toshihiro Shimizu 890ddd
      glPopMatrix();
Toshihiro Shimizu 890ddd
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    /*
Shinya Kitaoka 120a6e
TXshCell cell = xsh->getCell(row, otherColumn);
Shinya Kitaoka 120a6e
//TAffine aff = xsh->getPlacement(TStageObjectId::ColumnId(otherColumn),row);
Shinya Kitaoka 120a6e
//m_otherColumnAff = aff;
Shinya Kitaoka 120a6e
TImageP img = cell.getImage(false);
Shinya Kitaoka 120a6e
if(img)
Shinya Kitaoka 120a6e
{
Shinya Kitaoka 120a6e
getImageBoundingBox(m_otherColumnBBox, m_otherColumnBBoxAff, row, otherColumn);
Shinya Kitaoka 120a6e
//glColor3d(188.0/255.0, 202.0/255.0, 191.0/255.0);
Shinya Kitaoka 120a6e
glPushMatrix();
Shinya Kitaoka 120a6e
tglMultMatrix(aff * imageDpiAff);
Shinya Kitaoka 120a6e
ToolUtils::drawRect(img->getBBox(), TPixel32(188,202,191), 0xF0F0);
Shinya Kitaoka 120a6e
//tglDrawRect(img->getBBox());
Shinya Kitaoka 120a6e
glPopMatrix();
Shinya Kitaoka 120a6e
}
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
    // search for the closest hook of the picked column
Shinya Kitaoka 120a6e
    int i = -1, j = -1;
Shinya Kitaoka 120a6e
    double minDist2 = snapRadius2;
Shinya Kitaoka 120a6e
    for (i = 0; i < (int)otherColumnsHooks.size(); i++)
Shinya Kitaoka 120a6e
      if (otherColumnsHooks[i].m_columnIndex == otherColumn) {
Shinya Kitaoka 120a6e
        double dist2 = tdistance2(otherColumnsHooks[i].m_pos, m_parentProbe);
Shinya Kitaoka 120a6e
        if (j < 0)
Shinya Kitaoka 120a6e
          j = i;
Shinya Kitaoka 120a6e
        else if (dist2 < minDist2 || otherColumnsHooks[i].m_hookId == 0) {
Shinya Kitaoka 120a6e
          j        = i;
Shinya Kitaoka 120a6e
          minDist2 = dist2;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    // visualize a balloon for the closest hook
Shinya Kitaoka 120a6e
    if (0 <= j && j < (int)otherColumnsHooks.size()) {
Shinya Kitaoka 120a6e
      // I want to get a specific color when overlaying the label on white
Shinya Kitaoka 120a6e
      int alfa = 100, ialfa = 255 - alfa;
Shinya Kitaoka 120a6e
      TPixel32 color(255 * (188 - ialfa) / alfa, 255 * (202 - ialfa) / alfa,
Shinya Kitaoka 120a6e
                     255 * (191 - ialfa) / alfa, alfa);
Shinya Kitaoka 120a6e
      ToolUtils::drawBalloon(otherColumnsHooks[j].m_pos,
Shinya Kitaoka 120a6e
                             otherColumnsHooks[j].m_name,  // getHandle(),
Shinya Kitaoka 120a6e
                             color, TPoint(20, 20), false, &balloons);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      HookData baseHook = currentColumnHooks[0];
Shinya Kitaoka 120a6e
      baseHook.m_pos    = otherColumnsHooks[j].m_pos;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // this is also a magic link
Shinya Kitaoka 120a6e
      m_magicLinks.push_back(MagicLink(baseHook, otherColumnsHooks[j], 10000));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // visualize all the magic links
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int i = 0; i < (int)m_magicLinks.size(); i++) {
Shinya Kitaoka 120a6e
    const MagicLink &magicLink = m_magicLinks[i];
Shinya Kitaoka 120a6e
    const HookData &h1         = magicLink.m_h1;
Shinya Kitaoka 120a6e
    std::string name;
Shinya Kitaoka 120a6e
    name = (m_parentProbeEnabled ? "Linking " : "Link ") +
Shinya Kitaoka 120a6e
           removeTrailingH(magicLink.m_h0.getHandle()) + " to Col " +
Shinya Kitaoka 120a6e
           std::to_string(h1.m_columnIndex + 1) + "/" +
Shinya Kitaoka 120a6e
           removeTrailingH(h1.getHandle());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    int code = TD_MagicLink + i;
Shinya Kitaoka 120a6e
    glPushName(code);
Shinya Kitaoka 120a6e
    TPixel32 color(100, 255, 100, 100);
Shinya Kitaoka 120a6e
    if (code == m_device) color = TPixel32(185, 255, 255);
Shinya Kitaoka 120a6e
    ToolUtils::drawBalloon(magicLink.m_h0.m_pos, name, color, TPoint(20, -20),
Shinya Kitaoka 120a6e
                           isPicking(), &balloons);
Shinya Kitaoka 120a6e
    glPopName();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SkeletonTool::drawDrawingBrowser(const TXshCell &cell,
Shinya Kitaoka 120a6e
                                      const TPointD ¢er) {
Shinya Kitaoka 120a6e
  if (!cell.m_level || cell.m_level->getFrameCount() <= 1) return;
Shinya Kitaoka 120a6e
  double pixelSize = getPixelSize();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::string name = ::to_string(cell.m_level->getName()) + "." +
Shinya Kitaoka 120a6e
                     std::to_string(cell.m_frameId.getNumber());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QString qText = QString::fromStdString(name);
Shinya Kitaoka 120a6e
  QFont font("Arial", 10);  // ,QFont::Bold);
Shinya Kitaoka 120a6e
  QFontMetrics fm(font);
Shinya Kitaoka 120a6e
  QSize textSize   = fm.boundingRect(qText).size();
Shinya Kitaoka 120a6e
  int arrowHeight  = 10;
Shinya Kitaoka 120a6e
  int minTextWidth = 2 * arrowHeight + 5;
Shinya Kitaoka 120a6e
  if (textSize.width() < minTextWidth) textSize.setWidth(minTextWidth);
Shinya Kitaoka 120a6e
  QSize totalSize(textSize.width(), textSize.height() + 2 * arrowHeight);
Shinya Kitaoka 120a6e
  TPointD p = center + TPointD(30, -arrowHeight) * pixelSize;
Shinya Kitaoka 120a6e
  QRect textRect(0, arrowHeight, textSize.width(), textSize.height());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(glGetError() == 0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (isPicking()) {
Shinya Kitaoka 120a6e
    double x0 = p.x, x1 = p.x + totalSize.width() * pixelSize;
Shinya Kitaoka 120a6e
    double y0 = p.y, y3 = p.y + totalSize.height() * pixelSize;
Shinya Kitaoka 120a6e
    double y1 = y0 + arrowHeight * pixelSize;
Shinya Kitaoka 120a6e
    double y2 = y3 - arrowHeight * pixelSize;
Shinya Kitaoka 120a6e
    double x  = (x0 + x1) * 0.5;
Shinya Kitaoka 120a6e
    double d  = arrowHeight * pixelSize;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    glColor3d(0, 1, 0);
Shinya Kitaoka 120a6e
    glPushName(TD_ChangeDrawing);
Shinya Kitaoka 120a6e
    glRectd(x0, y1, x1, y2);
Shinya Kitaoka 120a6e
    glPopName();
Shinya Kitaoka 120a6e
    glPushName(TD_IncrementDrawing);
Shinya Kitaoka 120a6e
    glBegin(GL_POLYGON);
Shinya Kitaoka 120a6e
    glVertex2d(x, y0);
Shinya Kitaoka 120a6e
    glVertex2d(x + d, y0 + d);
Shinya Kitaoka 120a6e
    glVertex2d(x - d, y0 + d);
Shinya Kitaoka 120a6e
    glEnd();
Shinya Kitaoka 120a6e
    glPopName();
Shinya Kitaoka 120a6e
    glPushName(TD_DecrementDrawing);
Shinya Kitaoka 120a6e
    glBegin(GL_POLYGON);
Shinya Kitaoka 120a6e
    glVertex2d(x, y3);
Shinya Kitaoka 120a6e
    glVertex2d(x + d, y3 - d);
Shinya Kitaoka 120a6e
    glVertex2d(x - d, y3 - d);
Shinya Kitaoka 120a6e
    glEnd();
Shinya Kitaoka 120a6e
    glPopName();
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    assert(glGetError() == 0);
Shinya Kitaoka 120a6e
    bool active = m_device == TD_ChangeDrawing ||
Shinya Kitaoka 120a6e
                  m_device == TD_IncrementDrawing ||
Shinya Kitaoka 120a6e
                  m_device == TD_DecrementDrawing;
Shinya Kitaoka 120a6e
    QImage img(totalSize.width(), totalSize.height(), QImage::Format_ARGB32);
Shinya Kitaoka 120a6e
    img.fill(Qt::transparent);
Shinya Kitaoka 120a6e
    QPainter imgPainter(&img);
Shinya Kitaoka 120a6e
    imgPainter.setRenderHints(QPainter::Antialiasing |
Shinya Kitaoka 120a6e
                              QPainter::TextAntialiasing);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // imgPainter.setPen(Qt::black);
Shinya Kitaoka 120a6e
    // imgPainter.drawRect(0,0,totalSize.width(),totalSize.height());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    imgPainter.setPen(Qt::NoPen);
Shinya Kitaoka 120a6e
    imgPainter.setBrush(QColor(200, 200, 200, 200));
Shinya Kitaoka 120a6e
    imgPainter.drawRect(textRect);
Shinya Kitaoka 120a6e
    imgPainter.setPen(active ? Qt::red : Qt::black);
Shinya Kitaoka 120a6e
    imgPainter.setBrush(Qt::NoBrush);
Shinya Kitaoka 120a6e
    imgPainter.setFont(font);
Shinya Kitaoka 120a6e
    imgPainter.drawText(textRect, Qt::AlignCenter, qText);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (active) {
Shinya Kitaoka 120a6e
      int x = textRect.center().x();
Shinya Kitaoka 120a6e
      int d = arrowHeight - 4;
Shinya Kitaoka 120a6e
      int y = 0;
Shinya Kitaoka 120a6e
      QPainterPath upArrow;
Shinya Kitaoka 120a6e
      upArrow.moveTo(x, y);
Shinya Kitaoka 120a6e
      upArrow.lineTo(x + d, y + d);
Shinya Kitaoka 120a6e
      upArrow.lineTo(x - d, y + d);
Shinya Kitaoka 120a6e
      upArrow.lineTo(x, y);
Shinya Kitaoka 120a6e
      y = totalSize.height() - 1;
Shinya Kitaoka 120a6e
      QPainterPath dnArrow;
Shinya Kitaoka 120a6e
      dnArrow.moveTo(x, y);
Shinya Kitaoka 120a6e
      dnArrow.lineTo(x + d, y - d);
Shinya Kitaoka 120a6e
      dnArrow.lineTo(x - d, y - d);
Shinya Kitaoka 120a6e
      dnArrow.lineTo(x, y);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      imgPainter.setPen(Qt::NoPen);
Shinya Kitaoka 120a6e
      imgPainter.setBrush(m_device == TD_DecrementDrawing
Shinya Kitaoka 120a6e
                              ? QColor(255, 0, 0)
Shinya Kitaoka 120a6e
                              : QColor(200, 100, 100));
Shinya Kitaoka 120a6e
      imgPainter.drawPath(upArrow);
Shinya Kitaoka 120a6e
      imgPainter.setBrush(m_device == TD_IncrementDrawing
Shinya Kitaoka 120a6e
                              ? QColor(255, 0, 0)
Shinya Kitaoka 120a6e
                              : QColor(200, 100, 100));
Shinya Kitaoka 120a6e
      imgPainter.drawPath(dnArrow);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    QImage texture = QGLWidget::convertToGLFormat(img);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    glRasterPos2f(p.x, p.y);
Shinya Kitaoka 120a6e
    // glBitmap(0,0,0,0,  0,-size.height()+(y+delta.y),  NULL); //
Shinya Kitaoka 120a6e
    glEnable(GL_BLEND);
Shinya Kitaoka 120a6e
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Shinya Kitaoka 120a6e
    glDrawPixels(texture.width(), texture.height(), GL_RGBA, GL_UNSIGNED_BYTE,
Shinya Kitaoka 120a6e
                 texture.bits());
Shinya Kitaoka 120a6e
    glDisable(GL_BLEND);
Shinya Kitaoka 120a6e
    glColor3d(0, 0, 0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    assert(glGetError() == 0);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SkeletonTool::drawMainGadget(const TPointD ¢er) {
Shinya Kitaoka 120a6e
  assert(glGetError() == GL_NO_ERROR);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double r  = 10 * getPixelSize();
Shinya Kitaoka 120a6e
  double cx = center.x + r * 1.1;
Shinya Kitaoka 120a6e
  double cy = center.y - r * 1.1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  glColor3d(1, 0, 0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (isPicking()) {
Shinya Kitaoka 120a6e
    glPushName(TD_Translation);
Shinya Kitaoka 120a6e
    tglDrawDisk(TPointD(cx, cy), getPixelSize() * 9);
Shinya Kitaoka 120a6e
    glPopName();
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QImage img(19, 19, QImage::Format_ARGB32);
Shinya Kitaoka 120a6e
  img.fill(Qt::transparent);
Shinya Kitaoka 120a6e
  QPainter p(&img);
Shinya Kitaoka 120a6e
  // p.setRenderHints(QPainter::Antialiasing|QPainter::TextAntialiasing);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QPainterPath pp;
Shinya Kitaoka 120a6e
  int dx = 1, dy = 0;
Shinya Kitaoka 120a6e
  for (int i = 0; i < 4; i++) {
Shinya Kitaoka 120a6e
    int x = 9 + dx * 8;
Shinya Kitaoka 120a6e
    int y = 9 + dy * 8;
Shinya Kitaoka 120a6e
    pp.moveTo(9, 9);
Shinya Kitaoka 120a6e
    pp.lineTo(x, y);
Shinya Kitaoka 120a6e
    pp.lineTo(x - 2 * dx - 2 * dy, y - 2 * dy + 2 * dx);
Shinya Kitaoka 120a6e
    pp.moveTo(x, y);
Shinya Kitaoka 120a6e
    pp.lineTo(x - 2 * dx + 2 * dy, y - 2 * dy - 2 * dx);
Shinya Kitaoka 120a6e
    int d = dx;
Shinya Kitaoka 120a6e
    dx    = -dy;
Shinya Kitaoka 120a6e
    dy    = d;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  p.setPen(QPen(Qt::white, 3));
Shinya Kitaoka 120a6e
  p.drawPath(pp);
Shinya Kitaoka 120a6e
  p.setPen(Qt::black);
Shinya Kitaoka 120a6e
  p.drawPath(pp);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  p.setBrush(QColor(54, 213, 54));
Shinya Kitaoka 120a6e
  p.drawRect(6, 6, 6, 6);
Shinya Kitaoka 120a6e
  QImage texture = QGLWidget::convertToGLFormat(img);
Shinya Kitaoka 120a6e
  // texture.save("c:\\urka.png");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  glRasterPos2f(center.x + r * 1.1, center.y - r * 1.1);
Shinya Kitaoka 120a6e
  glBitmap(0, 0, 0, 0, -9, -9, NULL);
Shinya Kitaoka 120a6e
  glEnable(GL_BLEND);
Shinya Kitaoka 120a6e
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Shinya Kitaoka 120a6e
  glDrawPixels(texture.width(), texture.height(), GL_RGBA, GL_UNSIGNED_BYTE,
Shinya Kitaoka 120a6e
               texture.bits());
Shinya Kitaoka 120a6e
  glDisable(GL_BLEND);
Shinya Kitaoka 120a6e
  glColor3d(0, 0, 0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(glGetError() == GL_NO_ERROR);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SkeletonTool::draw() {
Shinya Kitaoka 120a6e
  // parent object reference system
Shinya Kitaoka 120a6e
  // glColor3d(1,0,0);
Shinya Kitaoka 120a6e
  // tglDrawRect(0,0,100,100);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_label != "")
Shinya Kitaoka 120a6e
    ToolUtils::drawBalloon(m_labelPos, m_label, TPixel32::Red, TPoint(20, -20),
Shinya Kitaoka 120a6e
                           false);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool ikEnabled = m_mode.getValue() == INVERSE_KINEMATICS;
Shinya Kitaoka 120a6e
  assert(glGetError() == GL_NO_ERROR);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // l'xsheet, oggetto (e relativo placement), frame corrente
Shinya Kitaoka 120a6e
  TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
  TXsheet *xsh            = getXsheet();
Shinya Kitaoka 120a6e
  assert(xsh);
Shinya Kitaoka 120a6e
  TStageObjectId objId = app->getCurrentObject()->getObjectId();
Shinya Kitaoka 120a6e
  // se l'oggetto corrente non e' una colonna non disegno nulla
Shinya Kitaoka 120a6e
  if (!objId.isColumn()) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TStageObject *pegbar = xsh->getStageObject(objId);
Shinya Kitaoka 120a6e
  int col              = objId.getIndex();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int frame = app->getCurrentFrame()->getFrame();
Shinya Kitaoka 120a6e
  if (m_currentFrame != frame) m_temporaryPinnedColumns.clear();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TAffine aff = getMatrix();
Shinya Kitaoka 120a6e
  // puo' suggere che il placement degeneri (es.: c'e' uno h-scale = 0%)
Shinya Kitaoka 120a6e
  if (fabs(aff.det()) < 0.00001) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // m_unit = getPixelSize() * sqrt(fabs(aff.det()));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!ikEnabled) drawLevelBoundingBox(frame, col);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  glPushMatrix();
Shinya Kitaoka 120a6e
  tglMultMatrix(aff.inv());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // camera stand reference system
Shinya Kitaoka 120a6e
  // glColor3d(0,1,0);
Shinya Kitaoka 120a6e
  // tglDrawRect(0,0,100,100);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool changingParent = dynamic_cast<parentchangetool *="">(m_dragTool) != 0;</parentchangetool>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // !changingParent &&
Shinya Kitaoka 120a6e
  if (m_mode.getValue() == BUILD_SKELETON &&
Shinya Kitaoka 120a6e
      !xsh->getStageObjectParent(objId).isColumn()) {
Shinya Kitaoka 120a6e
    if (!changingParent) drawHooks();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  Skeleton skeleton;
Shinya Kitaoka 120a6e
  buildSkeleton(skeleton, col);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  glEnable(GL_BLEND);
Shinya Kitaoka 120a6e
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Shinya Kitaoka 120a6e
  drawSkeleton(skeleton, frame);
Shinya Kitaoka 120a6e
  glDisable(GL_BLEND);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TXshCell cell            = xsh->getCell(frame, objId.getIndex());
Shinya Kitaoka 120a6e
  Skeleton::Bone *rootBone = skeleton.getRootBone();
Shinya Kitaoka 120a6e
  for (int i = 0; i < skeleton.getBoneCount(); i++) {
Shinya Kitaoka 120a6e
    Skeleton::Bone *bone     = skeleton.getBone(i);
Shinya Kitaoka 120a6e
    TStageObjectId currentId = bone->getStageObject()->getId();
Shinya Kitaoka 120a6e
    bool isCurrent           = (currentId == objId);
Shinya Kitaoka 120a6e
    TPointD pos              = bone->getCenter();
Shinya Kitaoka 120a6e
    if (isCurrent && m_mode.getValue() != BUILD_SKELETON) {
Shinya Kitaoka 120a6e
      drawDrawingBrowser(cell, pos);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    bool isActiveChain = bone->isSelected();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    glColor3d(0, 1, 0);
Shinya Kitaoka 120a6e
    if (ikEnabled) {
Shinya Kitaoka 120a6e
      drawIKJoint(bone);
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      TPointD pos = bone->getCenter();
Shinya Kitaoka 120a6e
      if (isCurrent && m_mode.getValue() == ANIMATE) {
Shinya Kitaoka 120a6e
        drawMainGadget(pos);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  m_currentFrame = frame;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_dragTool) m_dragTool->draw();
Shinya Kitaoka 120a6e
  glPopMatrix();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SkeletonTool::onActivate() {
Shinya Kitaoka 120a6e
  TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
  if (m_firstTime) {
Shinya Kitaoka 120a6e
    m_globalKeyframes.setValue(SkeletonGlobalKeyFrame ? 1 : 0);
Shinya Kitaoka 120a6e
    m_mode.setValue(BUILD_SKELETON);
Shinya Kitaoka 120a6e
    // m_ikEnabled.setValue(SkeletonInverseKinematics ? 1 : 0);
Shinya Kitaoka 120a6e
    m_firstTime = false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  TStageObjectId objId = app->getCurrentObject()->getObjectId();
Shinya Kitaoka 120a6e
  if (objId == TStageObjectId::NoneId) {
Shinya Kitaoka 120a6e
    int index = app->getCurrentColumn()->getColumnIndex();
Shinya Kitaoka 120a6e
    objId     = TStageObjectId::ColumnId(index);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  //  app->editStageObject(objId);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SkeletonTool::onDeactivate() {
Shinya Kitaoka 120a6e
  // m_selection.selectNone();
Shinya Kitaoka 120a6e
  // TSelection::setCurrent(0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
SkeletonSubtools::MagicLink SkeletonTool::getMagicLink(int index) const {
Shinya Kitaoka 120a6e
  assert(0 <= index && index < (int)m_magicLinks.size());
Shinya Kitaoka 120a6e
  return m_magicLinks[index];
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SkeletonTool::magicLink(int index) {
Shinya Kitaoka 120a6e
  if (index < 0 || index >= (int)m_magicLinks.size()) return;
Shinya Kitaoka 120a6e
  HookData h0             = m_magicLinks[index].m_h0;
Shinya Kitaoka 120a6e
  HookData h1             = m_magicLinks[index].m_h1;
Shinya Kitaoka 120a6e
  TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
  TXsheet *xsh            = app->getCurrentXsheet()->getXsheet();
Shinya Kitaoka 120a6e
  int columnIndex         = app->getCurrentColumn()->getColumnIndex();
Shinya Kitaoka 120a6e
  TStageObjectId id       = TStageObjectId::ColumnId(columnIndex);
Shinya Kitaoka 120a6e
  TStageObject *obj       = xsh->getStageObject(id);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int parentColumnIndex    = h1.m_columnIndex;
Shinya Kitaoka 120a6e
  TStageObjectId parentId  = TStageObjectId::ColumnId(parentColumnIndex);
Shinya Kitaoka 120a6e
  std::string parentHandle = h1.getHandle();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::string handle = "";
Shinya Kitaoka 120a6e
  if (h0.m_columnIndex < 0) {
Shinya Kitaoka 120a6e
    handle = obj->getHandle();
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    handle = h0.getHandle();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // TUndoManager *undoManager = TUndoManager::manager();
Shinya Kitaoka 120a6e
  // undoManager->beginBlock();
Shinya Kitaoka 120a6e
  TStageObjectCmd::setHandle(id, handle, app->getCurrentXsheet());
Shinya Kitaoka 120a6e
  TStageObjectCmd::setParent(id, parentId, parentHandle,
Shinya Kitaoka 120a6e
                             app->getCurrentXsheet());
Shinya Kitaoka 120a6e
  // undoManager->endBlock();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int SkeletonTool::getCursorId() const {
Shinya Kitaoka 120a6e
  switch (m_device) {
Shinya Kitaoka 120a6e
  case TD_None:
Shinya Kitaoka 120a6e
    if (m_mode.getValue() == BUILD_SKELETON)
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      return ToolCursor::RotCursor;
Shinya Kitaoka 120a6e
  case TD_Translation:
Shinya Kitaoka 120a6e
    return ToolCursor::MoveCursor;
Shinya Kitaoka 120a6e
  case TD_Rotation:
Shinya Kitaoka 120a6e
    return ToolCursor::RotCursor;
Shinya Kitaoka 120a6e
  default:
Shinya Kitaoka 120a6e
    return ToolCursor::StrokeSelectCursor;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return ToolCursor::StrokeSelectCursor;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SkeletonTool::addContextMenuItems(QMenu *menu) {
Shinya Kitaoka 120a6e
  bool ikEnabled = m_mode.getValue() == INVERSE_KINEMATICS;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (ikEnabled) {
Shinya Kitaoka 120a6e
    Skeleton *skeleton = new Skeleton();
Shinya Kitaoka 120a6e
    buildSkeleton(
Shinya Kitaoka 120a6e
        *skeleton,
Shinya Kitaoka 120a6e
        TTool::getApplication()->getCurrentColumn()->getColumnIndex());
Shinya Kitaoka 120a6e
    if (skeleton->hasPinnedRanges() || skeleton->isIKEnabled()) {
Shinya Kitaoka 120a6e
      m_commandHandler->setSkeleton(skeleton);
Shinya Kitaoka 120a6e
      QAction *rp = menu->addAction(tr("Reset Pinned Center"));
Shinya Kitaoka 120a6e
      menu->addSeparator();
Shinya Kitaoka 120a6e
      bool ret = QObject::connect(rp, SIGNAL(triggered()), m_commandHandler,
Shinya Kitaoka 120a6e
                                  SLOT(clearPinnedRanges()));
Shinya Kitaoka 120a6e
      assert(ret);
Shinya Kitaoka 120a6e
    } else
Shinya Kitaoka 120a6e
      delete skeleton;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SkeletonTool::buildSkeleton(Skeleton &skeleton, int columnIndex) {
Shinya Kitaoka 120a6e
  int frame = TTool::getApplication()->getCurrentFrame()->getFrame();
Shinya Kitaoka 120a6e
  skeleton.build(getXsheet(), frame, columnIndex, m_temporaryPinnedColumns);
Toshihiro Shimizu 890ddd
}