shift and trace improvement (#2240)

This commit is contained in:
shun-iwasawa 2018-09-11 14:35:02 +09:00 committed by masafumi-inoue
parent e5a0a35b95
commit 1d5937a1fe
25 changed files with 559 additions and 192 deletions

View file

@ -607,7 +607,8 @@ public:
//! onionskins) //! onionskins)
//! (window coordinate, pixels, bottom-left origin) //! (window coordinate, pixels, bottom-left origin)
virtual int posToRow(const TPointD &p, double distance, virtual int posToRow(const TPointD &p, double distance,
bool includeInvisible = true) const = 0; bool includeInvisible = true,
bool currentColumnOnly = false) const = 0;
//! return pos in pixel, bottom-left origin //! return pos in pixel, bottom-left origin
virtual TPointD worldToPos(const TPointD &worldPos) const = 0; virtual TPointD worldToPos(const TPointD &worldPos) const = 0;

View file

@ -20,6 +20,7 @@
#include <QToolBar> #include <QToolBar>
#include <QMap> #include <QMap>
#include <QLabel> #include <QLabel>
#include <QRadioButton>
// STD includes // STD includes
#include <map> #include <map>
@ -678,15 +679,25 @@ protected slots:
class ShiftTraceToolOptionBox final : public ToolOptionsBox { class ShiftTraceToolOptionBox final : public ToolOptionsBox {
Q_OBJECT Q_OBJECT
QPushButton *m_resetPrevGhostBtn; QFrame *m_prevFrame, *m_afterFrame;
QPushButton *m_resetAfterGhostBtn; QRadioButton *m_prevRadioBtn, *m_afterRadioBtn;
QPushButton *m_resetPrevGhostBtn, *m_resetAfterGhostBtn;
TTool *m_tool;
void resetGhost(int index); void resetGhost(int index);
protected:
void showEvent(QShowEvent *);
void hideEvent(QShowEvent *);
public: public:
ShiftTraceToolOptionBox(QWidget *parent = 0); ShiftTraceToolOptionBox(QWidget *parent = 0, TTool *tool = 0);
void updateStatus() override;
protected slots: protected slots:
void onResetPrevGhostBtnPressed(); void onResetPrevGhostBtnPressed();
void onResetAfterGhostBtnPressed(); void onResetAfterGhostBtnPressed();
void onPrevRadioBtnClicked();
void onAfterRadioBtnClicked();
void updateColors();
}; };
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View file

@ -507,6 +507,11 @@ public:
} }
bool getOnionSkinDuringPlayback() { return m_onionSkinDuringPlayback; } bool getOnionSkinDuringPlayback() { return m_onionSkinDuringPlayback; }
void setOnionSkinDuringPlayback(bool on); void setOnionSkinDuringPlayback(bool on);
void useOnionColorsForShiftAndTraceGhosts(bool on);
bool areOnionColorsUsedForShiftAndTraceGhosts() const {
return m_useOnionColorsForShiftAndTraceGhosts;
}
// Transparency Check tab // Transparency Check tab
void setTranspCheckData(const TPixel &bg, const TPixel &ink, void setTranspCheckData(const TPixel &bg, const TPixel &ink,
@ -711,7 +716,8 @@ private:
TPixel32 m_currentColumnColor; TPixel32 m_currentColumnColor;
bool m_enableWinInk = false; bool m_enableWinInk = false;
bool m_useOnionColorsForShiftAndTraceGhosts = false;
private: private:
Preferences(); Preferences();

View file

@ -107,6 +107,8 @@ public:
static double m_firstBackOnionSkin; static double m_firstBackOnionSkin;
static double m_lastBackVisibleSkin; static double m_lastBackVisibleSkin;
static bool m_isShiftAndTraceEnabled;
TPixel32 m_filterColor; TPixel32 m_filterColor;
public: public:

View file

@ -289,6 +289,8 @@ class DVAPI Picker final : public Visitor {
TAffine m_viewAff; TAffine m_viewAff;
double m_minDist2; double m_minDist2;
int m_currentColumnIndex = -1;
public: public:
Picker(const TAffine &viewAff, const TPointD &p, Picker(const TAffine &viewAff, const TPointD &p,
const ImagePainter::VisualSettings &vs); const ImagePainter::VisualSettings &vs);
@ -304,6 +306,8 @@ public:
int getColumnIndex() const; int getColumnIndex() const;
void getColumnIndexes(std::vector<int> &indexes) const; void getColumnIndexes(std::vector<int> &indexes) const;
int getRow() const; int getRow() const;
void setCurrentColumnIndex(int index) { m_currentColumnIndex = index; }
}; };
//============================================================================= //=============================================================================

View file

@ -36,6 +36,7 @@ set(HEADERS ${MOC_HEADERS}
../include/tools/toolutils.h ../include/tools/toolutils.h
../include/tools/RGBpicker.h ../include/tools/RGBpicker.h
mypainttoonzbrush.h mypainttoonzbrush.h
shifttracetool.h
) )
set(SOURCES set(SOURCES
@ -96,6 +97,7 @@ set(SOURCES
fingertool.cpp fingertool.cpp
rulertool.cpp rulertool.cpp
mypainttoonzbrush.cpp mypainttoonzbrush.cpp
shifttracetool.cpp
) )
set(RESOURCES tnztools.qrc) set(RESOURCES tnztools.qrc)

View file

@ -4,7 +4,6 @@
#include "toonz/onionskinmask.h" #include "toonz/onionskinmask.h"
#include "toonz/tonionskinmaskhandle.h" #include "toonz/tonionskinmaskhandle.h"
#include "tools/cursors.h" #include "tools/cursors.h"
#include "tools/tool.h"
#include "timage.h" #include "timage.h"
#include "trasterimage.h" #include "trasterimage.h"
#include "ttoonzimage.h" #include "ttoonzimage.h"
@ -15,10 +14,10 @@
#include "toonz/tframehandle.h" #include "toonz/tframehandle.h"
#include "toonz/tcolumnhandle.h" #include "toonz/tcolumnhandle.h"
#include "toonz/txshlevelhandle.h" #include "toonz/txshlevelhandle.h"
#include "tools/toolhandle.h"
#include "toonz/txshsimplelevel.h" #include "toonz/txshsimplelevel.h"
#include "toonz/dpiscale.h" #include "toonz/dpiscale.h"
#include "toonz/stage.h" #include "toonz/stage.h"
#include "tapp.h"
#include "tpixel.h" #include "tpixel.h"
#include "toonzqt/menubarcommand.h" #include "toonzqt/menubarcommand.h"
@ -51,97 +50,6 @@ static bool circumCenter(TPointD &out, const TPointD &a, const TPointD &b,
//============================================================================= //=============================================================================
class ShiftTraceTool final : public TTool {
public:
enum CurveStatus {
NoCurve,
TwoPointsCurve, // just during the first click&drag
ThreePointsCurve
};
enum GadgetId {
NoGadget,
NoGadget_InBox,
CurveP0Gadget,
CurveP1Gadget,
CurvePmGadget,
MoveCenterGadget,
RotateGadget,
TranslateGadget,
ScaleGadget
};
inline bool isCurveGadget(GadgetId id) const {
return CurveP0Gadget <= id && id <= CurvePmGadget;
}
private:
TPointD m_oldPos, m_startPos;
int m_ghostIndex;
TPointD m_p0, m_p1, m_p2;
CurveStatus m_curveStatus;
GadgetId m_gadget;
GadgetId m_highlightedGadget;
TRectD m_box;
TAffine m_dpiAff;
int m_row[2];
TAffine m_aff[2];
TPointD m_center[2];
TAffine m_oldAff;
public:
ShiftTraceTool();
ToolType getToolType() const override { return GenericTool; }
void clearData();
void updateData();
void updateBox();
void updateCurveAffs();
void updateGhost();
void reset() override {
int ghostIndex = m_ghostIndex;
onActivate();
invalidate();
m_ghostIndex = ghostIndex;
}
void mouseMove(const TPointD &, const TMouseEvent &e) override;
void leftButtonDown(const TPointD &, const TMouseEvent &) override;
void leftButtonDrag(const TPointD &, const TMouseEvent &) override;
void leftButtonUp(const TPointD &, const TMouseEvent &) override;
void draw() override;
TAffine getGhostAff();
GadgetId getGadget(const TPointD &);
void drawDot(const TPointD &center, double r,
const TPixel32 &color = TPixel32::White);
void drawControlRect();
void drawCurve();
void onActivate() override {
m_ghostIndex = 0;
m_curveStatus = NoCurve;
clearData();
OnionSkinMask osm =
TApp::instance()->getCurrentOnionSkin()->getOnionSkinMask();
m_aff[0] = osm.getShiftTraceGhostAff(0);
m_aff[1] = osm.getShiftTraceGhostAff(1);
m_center[0] = osm.getShiftTraceGhostCenter(0);
m_center[1] = osm.getShiftTraceGhostCenter(1);
}
void onDeactivate() override {
QAction *action = CommandManager::instance()->getAction("MI_EditShift");
action->setChecked(false);
}
bool isEventAcceptable(QEvent *e) override;
int getCursorId() const override;
};
ShiftTraceTool::ShiftTraceTool() ShiftTraceTool::ShiftTraceTool()
: TTool("T_ShiftTrace") : TTool("T_ShiftTrace")
, m_ghostIndex(0) , m_ghostIndex(0)
@ -170,7 +78,7 @@ void ShiftTraceTool::updateBox() {
TImageP img; TImageP img;
TApp *app = TApp::instance(); TApplication *app = TTool::getApplication();
if (app->getCurrentFrame()->isEditingScene()) { if (app->getCurrentFrame()->isEditingScene()) {
int col = app->getCurrentColumn()->getColumnIndex(); int col = app->getCurrentColumn()->getColumnIndex();
int row = m_row[m_ghostIndex]; int row = m_row[m_ghostIndex];
@ -214,10 +122,9 @@ void ShiftTraceTool::updateData() {
m_box = TRectD(); m_box = TRectD();
for (int i = 0; i < 2; i++) m_row[i] = -1; for (int i = 0; i < 2; i++) m_row[i] = -1;
m_dpiAff = TAffine(); m_dpiAff = TAffine();
TApp *app = TApp::instance(); TApplication *app = TTool::getApplication();
OnionSkinMask osm = OnionSkinMask osm = app->getCurrentOnionSkin()->getOnionSkinMask();
TApp::instance()->getCurrentOnionSkin()->getOnionSkinMask();
int previousOffset = osm.getShiftTraceGhostFrameOffset(0); int previousOffset = osm.getShiftTraceGhostFrameOffset(0);
int forwardOffset = osm.getShiftTraceGhostFrameOffset(1); int forwardOffset = osm.getShiftTraceGhostFrameOffset(1);
// we must find the prev (m_row[0]) and next (m_row[1]) reference images // we must find the prev (m_row[0]) and next (m_row[1]) reference images
@ -284,12 +191,23 @@ void ShiftTraceTool::updateCurveAffs() {
void ShiftTraceTool::updateGhost() { void ShiftTraceTool::updateGhost() {
OnionSkinMask osm = OnionSkinMask osm =
TApp::instance()->getCurrentOnionSkin()->getOnionSkinMask(); TTool::getApplication()->getCurrentOnionSkin()->getOnionSkinMask();
osm.setShiftTraceGhostAff(0, m_aff[0]); osm.setShiftTraceGhostAff(0, m_aff[0]);
osm.setShiftTraceGhostAff(1, m_aff[1]); osm.setShiftTraceGhostAff(1, m_aff[1]);
osm.setShiftTraceGhostCenter(0, m_center[0]); osm.setShiftTraceGhostCenter(0, m_center[0]);
osm.setShiftTraceGhostCenter(1, m_center[1]); osm.setShiftTraceGhostCenter(1, m_center[1]);
TApp::instance()->getCurrentOnionSkin()->setOnionSkinMask(osm); TTool::getApplication()->getCurrentOnionSkin()->setOnionSkinMask(osm);
}
void ShiftTraceTool::reset() {
int ghostIndex = m_ghostIndex;
onActivate();
invalidate();
m_ghostIndex = ghostIndex;
TTool::getApplication()
->getCurrentTool()
->notifyToolChanged(); // Refreshes toolbar values
} }
TAffine ShiftTraceTool::getGhostAff() { TAffine ShiftTraceTool::getGhostAff() {
@ -417,6 +335,23 @@ void ShiftTraceTool::drawCurve() {
} }
} }
void ShiftTraceTool::onActivate() {
m_ghostIndex = 0;
m_curveStatus = NoCurve;
clearData();
OnionSkinMask osm =
TTool::getApplication()->getCurrentOnionSkin()->getOnionSkinMask();
m_aff[0] = osm.getShiftTraceGhostAff(0);
m_aff[1] = osm.getShiftTraceGhostAff(1);
m_center[0] = osm.getShiftTraceGhostCenter(0);
m_center[1] = osm.getShiftTraceGhostCenter(1);
}
void ShiftTraceTool::onDeactivate() {
QAction *action = CommandManager::instance()->getAction("MI_EditShift");
action->setChecked(false);
}
ShiftTraceTool::GadgetId ShiftTraceTool::getGadget(const TPointD &p) { ShiftTraceTool::GadgetId ShiftTraceTool::getGadget(const TPointD &p) {
std::vector<std::pair<TPointD, GadgetId>> gadgets; std::vector<std::pair<TPointD, GadgetId>> gadgets;
gadgets.push_back(std::make_pair(m_p0, CurveP0Gadget)); gadgets.push_back(std::make_pair(m_p0, CurveP0Gadget));
@ -505,6 +440,8 @@ void ShiftTraceTool::leftButtonDown(const TPointD &pos, const TMouseEvent &e) {
m_gadget = m_highlightedGadget; m_gadget = m_highlightedGadget;
m_oldPos = m_startPos = pos; m_oldPos = m_startPos = pos;
bool notify = false;
if (m_gadget == NoGadget || m_gadget == NoGadget_InBox) { if (m_gadget == NoGadget || m_gadget == NoGadget_InBox) {
if (!e.isCtrlPressed()) { if (!e.isCtrlPressed()) {
if (m_gadget == NoGadget_InBox) if (m_gadget == NoGadget_InBox)
@ -513,13 +450,13 @@ void ShiftTraceTool::leftButtonDown(const TPointD &pos, const TMouseEvent &e) {
m_gadget = RotateGadget; m_gadget = RotateGadget;
// m_curveStatus = NoCurve; // m_curveStatus = NoCurve;
} }
int row = getViewer()->posToRow(e.m_pos, 5 * getPixelSize(), false); int row = getViewer()->posToRow(e.m_pos, 5 * getPixelSize(), false, true);
if (row >= 0) { if (row >= 0) {
int index = -1; int index = -1;
TApp *app = TApp::instance(); TApplication *app = TTool::getApplication();
if (app->getCurrentFrame()->isEditingScene()) { if (app->getCurrentFrame()->isEditingScene()) {
int currentRow = getFrame(); int currentRow = getFrame();
if (m_row[0] >= 0 && row <= currentRow) if (m_row[0] >= 0 && row < currentRow)
index = 0; index = 0;
else if (m_row[1] >= 0 && row > currentRow) else if (m_row[1] >= 0 && row > currentRow)
index = 1; index = 1;
@ -535,12 +472,19 @@ void ShiftTraceTool::leftButtonDown(const TPointD &pos, const TMouseEvent &e) {
updateBox(); updateBox();
m_gadget = TranslateGadget; m_gadget = TranslateGadget;
m_highlightedGadget = TranslateGadget; m_highlightedGadget = TranslateGadget;
notify = true;
} }
} }
} }
m_oldAff = m_aff[m_ghostIndex]; m_oldAff = m_aff[m_ghostIndex];
invalidate(); invalidate();
if (notify) {
TTool::getApplication()
->getCurrentTool()
->notifyToolChanged(); // Refreshes toolbar values
}
} }
void ShiftTraceTool::leftButtonDrag(const TPointD &pos, const TMouseEvent &e) { void ShiftTraceTool::leftButtonDrag(const TPointD &pos, const TMouseEvent &e) {
@ -613,6 +557,10 @@ void ShiftTraceTool::leftButtonUp(const TPointD &pos, const TMouseEvent &) {
} }
m_gadget = NoGadget; m_gadget = NoGadget;
invalidate(); invalidate();
TTool::getApplication()
->getCurrentTool()
->notifyToolChanged(); // Refreshes toolbar values
} }
void ShiftTraceTool::draw() { void ShiftTraceTool::draw() {
@ -639,4 +587,17 @@ bool ShiftTraceTool::isEventAcceptable(QEvent *e) {
return (Qt::Key_F1 <= key && key <= Qt::Key_F3); return (Qt::Key_F1 <= key && key <= Qt::Key_F3);
} }
void ShiftTraceTool::onLeave() {
OnionSkinMask osm =
TTool::getApplication()->getCurrentOnionSkin()->getOnionSkinMask();
osm.clearGhostFlipKey();
TTool::getApplication()->getCurrentOnionSkin()->setOnionSkinMask(osm);
}
void ShiftTraceTool::setCurrentGhostIndex(int index) {
m_ghostIndex = index;
updateBox();
invalidate();
}
ShiftTraceTool shiftTraceTool; ShiftTraceTool shiftTraceTool;

View file

@ -0,0 +1,82 @@
#pragma once
#include "tools/tool.h"
class ShiftTraceTool final : public TTool {
public:
enum CurveStatus {
NoCurve,
TwoPointsCurve, // just during the first click&drag
ThreePointsCurve
};
enum GadgetId {
NoGadget,
NoGadget_InBox,
CurveP0Gadget,
CurveP1Gadget,
CurvePmGadget,
MoveCenterGadget,
RotateGadget,
TranslateGadget,
ScaleGadget
};
inline bool isCurveGadget(GadgetId id) const {
return CurveP0Gadget <= id && id <= CurvePmGadget;
}
private:
TPointD m_oldPos, m_startPos;
int m_ghostIndex;
TPointD m_p0, m_p1, m_p2;
CurveStatus m_curveStatus;
GadgetId m_gadget;
GadgetId m_highlightedGadget;
TRectD m_box;
TAffine m_dpiAff;
int m_row[2];
TAffine m_aff[2];
TPointD m_center[2];
TAffine m_oldAff;
public:
ShiftTraceTool();
ToolType getToolType() const override { return GenericTool; }
void clearData();
void updateData();
void updateBox();
void updateCurveAffs();
void updateGhost();
void reset() override;
void mouseMove(const TPointD &, const TMouseEvent &e) override;
void leftButtonDown(const TPointD &, const TMouseEvent &) override;
void leftButtonDrag(const TPointD &, const TMouseEvent &) override;
void leftButtonUp(const TPointD &, const TMouseEvent &) override;
void draw() override;
TAffine getGhostAff();
GadgetId getGadget(const TPointD &);
void drawDot(const TPointD &center, double r,
const TPixel32 &color = TPixel32::White);
void drawControlRect();
void drawCurve();
void onActivate() override;
void onDeactivate() override;
void onLeave() override;
bool isEventAcceptable(QEvent *e) override;
int getCursorId() const override;
int getCurrentGhostIndex() { return m_ghostIndex; }
void setCurrentGhostIndex(int index);
};

View file

@ -16,6 +16,7 @@
//#include "rgbpickertool.h" //#include "rgbpickertool.h"
#include "rulertool.h" #include "rulertool.h"
#include "shifttracetool.h"
// TnzQt includes // TnzQt includes
#include "toonzqt/dvdialog.h" #include "toonzqt/dvdialog.h"
@ -2501,24 +2502,58 @@ void StylePickerToolOptionsBox::updateRealTimePickLabel(const int ink,
// ShiftTraceToolOptionBox // ShiftTraceToolOptionBox
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
ShiftTraceToolOptionBox::ShiftTraceToolOptionBox(QWidget *parent) ShiftTraceToolOptionBox::ShiftTraceToolOptionBox(QWidget *parent, TTool *tool)
: ToolOptionsBox(parent) { : ToolOptionsBox(parent), m_tool(tool) {
setFrameStyle(QFrame::StyledPanel); setFrameStyle(QFrame::StyledPanel);
setFixedHeight(26); setFixedHeight(26);
m_resetPrevGhostBtn = m_prevFrame = new QFrame(this);
new QPushButton(tr("Reset Shift of Previous Drawing"), this); m_afterFrame = new QFrame(this);
m_resetAfterGhostBtn =
new QPushButton(tr("Reset Shift of Forward Drawing"), this);
m_resetPrevGhostBtn = new QPushButton(tr("Reset Previous"), this);
m_resetAfterGhostBtn = new QPushButton(tr("Reset Following"), this);
m_prevRadioBtn = new QRadioButton(tr("Previous Drawing"), this);
m_afterRadioBtn = new QRadioButton(tr("Following Drawing"), this);
m_prevFrame->setFixedSize(10, 21);
m_afterFrame->setFixedSize(10, 21);
m_layout->addWidget(m_prevFrame, 0);
m_layout->addWidget(m_prevRadioBtn, 0);
m_layout->addWidget(m_resetPrevGhostBtn, 0); m_layout->addWidget(m_resetPrevGhostBtn, 0);
m_layout->addWidget(new DVGui::Separator("", this, false));
m_layout->addWidget(m_afterFrame, 0);
m_layout->addWidget(m_afterRadioBtn, 0);
m_layout->addWidget(m_resetAfterGhostBtn, 0); m_layout->addWidget(m_resetAfterGhostBtn, 0);
m_layout->addStretch(1); m_layout->addStretch(1);
connect(m_resetPrevGhostBtn, SIGNAL(clicked()), this, connect(m_resetPrevGhostBtn, SIGNAL(clicked(bool)), this,
SLOT(onResetPrevGhostBtnPressed())); SLOT(onResetPrevGhostBtnPressed()));
connect(m_resetAfterGhostBtn, SIGNAL(clicked()), this, connect(m_resetAfterGhostBtn, SIGNAL(clicked(bool)), this,
SLOT(onResetAfterGhostBtnPressed())); SLOT(onResetAfterGhostBtnPressed()));
connect(m_prevRadioBtn, SIGNAL(clicked(bool)), this,
SLOT(onPrevRadioBtnClicked()));
connect(m_afterRadioBtn, SIGNAL(clicked(bool)), this,
SLOT(onAfterRadioBtnClicked()));
updateStatus();
}
void ShiftTraceToolOptionBox::showEvent(QShowEvent *) {
TTool::Application *app = TTool::getApplication();
connect(app->getCurrentOnionSkin(), SIGNAL(onionSkinMaskChanged()), this,
SLOT(updateColors()));
updateColors();
}
void ShiftTraceToolOptionBox::hideEvent(QShowEvent *) {
TTool::Application *app = TTool::getApplication();
disconnect(app->getCurrentOnionSkin(), SIGNAL(onionSkinMaskChanged()), this,
SLOT(updateColors()));
} }
void ShiftTraceToolOptionBox::resetGhost(int index) { void ShiftTraceToolOptionBox::resetGhost(int index) {
@ -2530,12 +2565,68 @@ void ShiftTraceToolOptionBox::resetGhost(int index) {
app->getCurrentOnionSkin()->notifyOnionSkinMaskChanged(); app->getCurrentOnionSkin()->notifyOnionSkinMaskChanged();
TTool *tool = app->getCurrentTool()->getTool(); TTool *tool = app->getCurrentTool()->getTool();
if (tool) tool->reset(); if (tool) tool->reset();
if (index == 0)
m_resetPrevGhostBtn->setDisabled(true);
else // index == 1
m_resetAfterGhostBtn->setDisabled(true);
} }
void ShiftTraceToolOptionBox::onResetPrevGhostBtnPressed() { resetGhost(0); } void ShiftTraceToolOptionBox::onResetPrevGhostBtnPressed() { resetGhost(0); }
void ShiftTraceToolOptionBox::onResetAfterGhostBtnPressed() { resetGhost(1); } void ShiftTraceToolOptionBox::onResetAfterGhostBtnPressed() { resetGhost(1); }
void ShiftTraceToolOptionBox::updateColors() {
TPixel front, back;
bool ink;
Preferences::instance()->getOnionData(front, back, ink);
m_prevFrame->setStyleSheet(QString("background:rgb(%1,%2,%3,255);")
.arg((int)back.r)
.arg((int)back.g)
.arg((int)back.b));
m_afterFrame->setStyleSheet(QString("background:rgb(%1,%2,%3,255);")
.arg((int)front.r)
.arg((int)front.g)
.arg((int)front.b));
}
void ShiftTraceToolOptionBox::updateStatus() {
TTool::Application *app = TTool::getApplication();
OnionSkinMask osm = app->getCurrentOnionSkin()->getOnionSkinMask();
if (osm.getShiftTraceGhostAff(0).isIdentity() &&
osm.getShiftTraceGhostCenter(0) == TPointD())
m_resetPrevGhostBtn->setDisabled(true);
else
m_resetPrevGhostBtn->setEnabled(true);
if (osm.getShiftTraceGhostAff(1).isIdentity() &&
osm.getShiftTraceGhostCenter(1) == TPointD())
m_resetAfterGhostBtn->setDisabled(true);
else
m_resetAfterGhostBtn->setEnabled(true);
// Check the ghost index
ShiftTraceTool *stTool = (ShiftTraceTool *)m_tool;
if (!stTool) return;
if (stTool->getCurrentGhostIndex() == 0)
m_prevRadioBtn->setChecked(true);
else // ghostIndex == 1
m_afterRadioBtn->setChecked(true);
}
void ShiftTraceToolOptionBox::onPrevRadioBtnClicked() {
ShiftTraceTool *stTool = (ShiftTraceTool *)m_tool;
if (!stTool) return;
stTool->setCurrentGhostIndex(0);
}
void ShiftTraceToolOptionBox::onAfterRadioBtnClicked() {
ShiftTraceTool *stTool = (ShiftTraceTool *)m_tool;
if (!stTool) return;
stTool->setCurrentGhostIndex(1);
}
//============================================================================= //=============================================================================
// ToolOptions // ToolOptions
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -2645,7 +2736,7 @@ void ToolOptions::onToolSwitched() {
panel = new StylePickerToolOptionsBox(0, tool, currPalette, currTool, panel = new StylePickerToolOptionsBox(0, tool, currPalette, currTool,
app->getPaletteController()); app->getPaletteController());
else if (tool->getName() == "T_ShiftTrace") else if (tool->getName() == "T_ShiftTrace")
panel = new ShiftTraceToolOptionBox(this); panel = new ShiftTraceToolOptionBox(this, tool);
else else
panel = tool->createOptionsBox(); // Only this line should remain out panel = tool->createOptionsBox(); // Only this line should remain out
// of that if/else monstrosity // of that if/else monstrosity

View file

@ -107,7 +107,6 @@ set(MOC_HEADERS
sceneviewerevents.h sceneviewerevents.h
scriptconsolepanel.h scriptconsolepanel.h
selectionutils.h selectionutils.h
shifttracetool.h
shortcutpopup.h shortcutpopup.h
soundtrackexport.h soundtrackexport.h
startuppopup.h startuppopup.h
@ -255,7 +254,6 @@ set(SOURCES
sceneviewercontextmenu.cpp sceneviewercontextmenu.cpp
scenesettingspopup.cpp scenesettingspopup.cpp
scriptconsolepanel.cpp scriptconsolepanel.cpp
shifttracetool.cpp
shortcutpopup.cpp shortcutpopup.cpp
soundtrackexport.cpp soundtrackexport.cpp
startuppopup.cpp startuppopup.cpp

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="レイヤー_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" width="24px" height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;stroke:#000000;stroke-miterlimit:10;}
.st1{fill:none;stroke:#000000;stroke-linecap:round;stroke-miterlimit:10;}
.st2{fill:none;stroke:#000000;stroke-width:3;stroke-linecap:round;stroke-miterlimit:10;}
.st3{fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-miterlimit:10;}
</style>
<path class="st0" d="M19.5,9.2c0-4.3-3.4-7.7-7.5-7.7S4.5,4.9,4.5,9.2c0,4.9,4.9,6.3,4.9,10.5c0,2,1.2,2.8,2.6,2.8
c1.5,0,2.6-0.8,2.6-2.8C14.6,15.5,19.5,14.1,19.5,9.2z"/>
<rect x="10" y="10.5" class="st1" width="4" height="7"/>
<g>
<line class="st2" x1="8.5" y1="18.5" x2="15.5" y2="18.5"/>
<line class="st3" x1="8.5" y1="18.5" x2="15.5" y2="18.5"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1 KiB

View file

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="レイヤー_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" width="24px" height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;stroke:#000000;stroke-miterlimit:10;}
.st1{fill:none;stroke:#000000;stroke-width:3;stroke-linecap:round;stroke-miterlimit:10;}
.st2{fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-miterlimit:10;}
.st3{fill:none;stroke:#000000;stroke-linecap:round;stroke-miterlimit:10;}
.st4{fill:none;stroke:#000000;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:10;}
.st5{fill:#FFFFFF;}
.st6{display:none;}
.st7{display:inline;fill:none;stroke:#000000;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:10;}
.st8{display:inline;fill:#FFFFFF;}
</style>
<path class="st0" d="M12.5,7c0-3-2.5-5.5-5.5-5.5S1.5,4,1.5,7c0,3.5,3.6,4.5,3.6,7.5c0,1.5,0.9,2,1.9,2c1.1,0,1.9-0.5,1.9-2
C8.9,11.5,12.5,10.5,12.5,7z"/>
<g>
<line class="st1" x1="4.5" y1="13.5" x2="9.5" y2="13.5"/>
<line class="st2" x1="4.5" y1="13.5" x2="9.5" y2="13.5"/>
</g>
<rect x="5.5" y="7.5" class="st3" width="3" height="5"/>
<line class="st1" x1="15.5" y1="10.5" x2="15.5" y2="20.5"/>
<line class="st1" x1="10.5" y1="15.5" x2="19.5" y2="15.5"/>
<polygon class="st4" points="17.5,20 13.5,20 15.5,22.5 "/>
<polygon class="st4" points="19.8,13.5 19.8,17.5 22.3,15.5 "/>
<polygon class="st4" points="13.5,11 17.5,11 15.5,8.5 "/>
<polygon class="st4" points="11,17.5 11,13.5 8.5,15.5 "/>
<polygon class="st5" points="19.8,13.5 19.8,17.5 22.3,15.5 "/>
<polygon class="st5" points="13.5,11 17.5,11 15.5,8.5 "/>
<polygon class="st5" points="11,17.5 11,13.5 8.5,15.5 "/>
<polygon class="st5" points="17.5,20 13.5,20 15.5,22.5 "/>
<line class="st2" x1="15.5" y1="10.5" x2="15.5" y2="20.5"/>
<line class="st2" x1="10.5" y1="15.5" x2="20.5" y2="15.5"/>
<g class="st6">
<polygon class="st7" points="13.7,9 16.1,9 15.5,12.6 "/>
<polygon class="st8" points="13.7,9 16.1,9 15.5,12.6 "/>
</g>
<g class="st6">
<polygon class="st7" points="17.3,22 14.9,22 15.5,18.5 "/>
<polygon class="st8" points="17.3,22 14.9,22 15.5,18.5 "/>
</g>
<g class="st6">
<polygon class="st7" points="20.2,10.7 21.4,12.8 18.1,14 "/>
<polygon class="st8" points="20.2,10.7 21.4,12.8 18.1,14 "/>
</g>
<g class="st6">
<polygon class="st7" points="10.8,20.3 9.6,18.2 13,17 "/>
<polygon class="st8" points="10.8,20.3 9.6,18.2 13,17 "/>
</g>
<g class="st6">
<polygon class="st7" points="9,13.8 10.2,11.8 13,14 "/>
<polygon class="st8" points="9,13.8 10.2,11.8 13,14 "/>
</g>
<g class="st6">
<polygon class="st7" points="22,17.2 20.8,19.3 18.1,17 "/>
<polygon class="st8" points="22,17.2 20.8,19.3 18.1,17 "/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="レイヤー_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" width="24px" height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;stroke:#000000;stroke-miterlimit:10;}
.st1{fill:none;stroke:#000000;stroke-width:3;stroke-linecap:round;stroke-miterlimit:10;}
.st2{fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-miterlimit:10;}
.st3{fill:none;stroke:#000000;stroke-linecap:round;stroke-miterlimit:10;}
.st4{display:none;fill:none;stroke:#000000;stroke-width:3;stroke-linecap:round;stroke-miterlimit:10;}
.st5{display:none;fill:none;stroke:#000000;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:10;}
.st6{display:none;fill:#FFFFFF;}
.st7{display:none;fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-miterlimit:10;}
.st8{fill:none;stroke:#000000;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:10;}
.st9{fill:#FFFFFF;}
</style>
<path class="st0" d="M12.5,7c0-3-2.5-5.5-5.5-5.5S1.5,4,1.5,7c0,3.5,3.6,4.5,3.6,7.5c0,1.5,0.9,2,1.9,2c1.1,0,1.9-0.5,1.9-2
C8.9,11.5,12.5,10.5,12.5,7z"/>
<g>
<line class="st1" x1="4.5" y1="13.5" x2="9.5" y2="13.5"/>
<line class="st2" x1="4.5" y1="13.5" x2="9.5" y2="13.5"/>
</g>
<rect x="5.5" y="7.5" class="st3" width="3" height="5"/>
<line class="st4" x1="13.5" y1="10.5" x2="13.5" y2="18.5"/>
<line class="st4" x1="10.5" y1="15.5" x2="16.5" y2="15.5"/>
<polygon class="st5" points="16.8,13.5 16.8,17.5 19.3,15.5 "/>
<polygon class="st5" points="11.5,11 15.5,11 13.5,8.5 "/>
<polygon class="st6" points="16.8,13.5 16.8,17.5 19.3,15.5 "/>
<polygon class="st6" points="11.5,11 15.5,11 13.5,8.5 "/>
<line class="st7" x1="13.5" y1="10.5" x2="13.5" y2="18.5"/>
<line class="st7" x1="10.5" y1="15.5" x2="17.5" y2="15.5"/>
<g>
<polygon class="st8" points="13.7,9 16.1,9 15.5,12.6 "/>
<polygon class="st9" points="13.7,9 16.1,9 15.5,12.6 "/>
</g>
<g>
<polygon class="st8" points="17.3,22 14.9,22 15.5,18.5 "/>
<polygon class="st9" points="17.3,22 14.9,22 15.5,18.5 "/>
</g>
<g>
<polygon class="st8" points="20.2,10.7 21.4,12.8 18.1,14 "/>
<polygon class="st9" points="20.2,10.7 21.4,12.8 18.1,14 "/>
</g>
<g>
<polygon class="st8" points="10.8,20.3 9.6,18.2 13,17 "/>
<polygon class="st9" points="10.8,20.3 9.6,18.2 13,17 "/>
</g>
<g>
<polygon class="st8" points="9,13.8 10.2,11.8 13,14 "/>
<polygon class="st9" points="9,13.8 10.2,11.8 13,14 "/>
</g>
<g>
<polygon class="st8" points="22,17.2 20.8,19.3 18.1,17 "/>
<polygon class="st9" points="22,17.2 20.8,19.3 18.1,17 "/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -1956,13 +1956,16 @@ void MainWindow::defineActions() {
MenuViewCommandType); MenuViewCommandType);
createToggle(MI_ACheck, tr("&Gap Check"), "", ACheckToggleAction ? 1 : 0, createToggle(MI_ACheck, tr("&Gap Check"), "", ACheckToggleAction ? 1 : 0,
MenuViewCommandType); MenuViewCommandType);
createToggle(MI_ShiftTrace, tr("Shift and Trace"), "", false, QAction* shiftTraceAction = createToggle(MI_ShiftTrace, tr("Shift and Trace"), "", false,
MenuViewCommandType); MenuViewCommandType);
createToggle(MI_EditShift, tr("Edit Shift"), "", false, MenuViewCommandType); shiftTraceAction->setIcon(QIcon(":Resources/shift_and_trace.svg"));
shiftTraceAction = createToggle(MI_EditShift, tr("Edit Shift"), "", false, MenuViewCommandType);
shiftTraceAction->setIcon(QIcon(":Resources/shift_and_trace_edit.svg"));
createToggle(MI_NoShift, tr("No Shift"), "", false, MenuViewCommandType); createToggle(MI_NoShift, tr("No Shift"), "", false, MenuViewCommandType);
CommandManager::instance()->enable(MI_EditShift, false); CommandManager::instance()->enable(MI_EditShift, false);
CommandManager::instance()->enable(MI_NoShift, false); CommandManager::instance()->enable(MI_NoShift, false);
createAction(MI_ResetShift, tr("Reset Shift"), "", MenuViewCommandType); shiftTraceAction = createAction(MI_ResetShift, tr("Reset Shift"), "", MenuViewCommandType);
shiftTraceAction->setIcon(QIcon(":Resources/shift_and_trace_reset.svg"));
if (QGLPixelBuffer::hasOpenGLPbuffers()) if (QGLPixelBuffer::hasOpenGLPbuffers())
createToggle(MI_RasterizePli, tr("&Visualize Vector As Raster"), "", createToggle(MI_RasterizePli, tr("&Visualize Vector As Raster"), "",

View file

@ -506,6 +506,7 @@ void PreferencesPopup::onOnionDataChanged(const TPixel32 &, bool isDragging) {
TApp::instance()->getCurrentScene()->notifySceneChanged(); TApp::instance()->getCurrentScene()->notifySceneChanged();
TApp::instance()->getCurrentLevel()->notifyLevelViewChange(); TApp::instance()->getCurrentLevel()->notifyLevelViewChange();
TApp::instance()->getCurrentOnionSkin()->notifyOnionSkinMaskChanged();
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -806,6 +807,12 @@ void PreferencesPopup::onOnionSkinDuringPlaybackChanged(int index) {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void PreferencesPopup::onOnionColorsForShiftAndTraceChanged(int index) {
m_pref->useOnionColorsForShiftAndTraceGhosts(index == Qt::Checked);
}
//-----------------------------------------------------------------------------
void PreferencesPopup::onGuidedDrawingStyleChanged(int index) { void PreferencesPopup::onGuidedDrawingStyleChanged(int index) {
m_pref->setAnimatedGuidedDrawing(index); m_pref->setAnimatedGuidedDrawing(index);
} }
@ -1533,9 +1540,11 @@ PreferencesPopup::PreferencesPopup()
m_onionSkinVisibility = new CheckBox(tr("Onion Skin ON")); m_onionSkinVisibility = new CheckBox(tr("Onion Skin ON"));
m_onionSkinDuringPlayback = m_onionSkinDuringPlayback =
new CheckBox(tr("Show Onion Skin During Playback")); new CheckBox(tr("Show Onion Skin During Playback"));
m_frontOnionColor = new ColorField(this, false, frontColor); m_frontOnionColor = new ColorField(this, false, frontColor);
m_backOnionColor = new ColorField(this, false, backColor); m_backOnionColor = new ColorField(this, false, backColor);
m_inksOnly = new DVGui::CheckBox(tr("Display Lines Only ")); m_useOnionColorsForShiftAndTraceCB = new CheckBox(
tr("Use Onion Skin Colors for Reference Drawings of Shift and Trace"));
m_inksOnly = new DVGui::CheckBox(tr("Display Lines Only "));
m_inksOnly->setChecked(onlyInks); m_inksOnly->setChecked(onlyInks);
int thickness = m_pref->getOnionPaperThickness(); int thickness = m_pref->getOnionPaperThickness();
@ -1898,6 +1907,8 @@ PreferencesPopup::PreferencesPopup()
m_onionSkinDuringPlayback->setChecked(m_pref->getOnionSkinDuringPlayback()); m_onionSkinDuringPlayback->setChecked(m_pref->getOnionSkinDuringPlayback());
m_frontOnionColor->setEnabled(m_pref->isOnionSkinEnabled()); m_frontOnionColor->setEnabled(m_pref->isOnionSkinEnabled());
m_backOnionColor->setEnabled(m_pref->isOnionSkinEnabled()); m_backOnionColor->setEnabled(m_pref->isOnionSkinEnabled());
m_useOnionColorsForShiftAndTraceCB->setChecked(
m_pref->areOnionColorsUsedForShiftAndTraceGhosts());
m_inksOnly->setEnabled(m_pref->isOnionSkinEnabled()); m_inksOnly->setEnabled(m_pref->isOnionSkinEnabled());
QStringList guidedDrawingStyles; QStringList guidedDrawingStyles;
guidedDrawingStyles << tr("Arrow Markers") << tr("Animated Guide"); guidedDrawingStyles << tr("Arrow Markers") << tr("Animated Guide");
@ -2558,6 +2569,8 @@ PreferencesPopup::PreferencesPopup()
onionLay->addWidget(m_inksOnly, 0, Qt::AlignLeft | Qt::AlignVCenter); onionLay->addWidget(m_inksOnly, 0, Qt::AlignLeft | Qt::AlignVCenter);
onionLay->addWidget(m_onionSkinDuringPlayback, 0, onionLay->addWidget(m_onionSkinDuringPlayback, 0,
Qt::AlignLeft | Qt::AlignVCenter); Qt::AlignLeft | Qt::AlignVCenter);
onionLay->addWidget(m_useOnionColorsForShiftAndTraceCB, 0,
Qt::AlignLeft | Qt::AlignVCenter);
QGridLayout *guidedDrawingLay = new QGridLayout(); QGridLayout *guidedDrawingLay = new QGridLayout();
{ {
guidedDrawingLay->addWidget(new QLabel(tr("Vector Guided Style:")), 0, guidedDrawingLay->addWidget(new QLabel(tr("Vector Guided Style:")), 0,
@ -2952,6 +2965,9 @@ PreferencesPopup::PreferencesPopup()
SLOT(onOnionSkinVisibilityChanged(int))); SLOT(onOnionSkinVisibilityChanged(int)));
ret = ret && connect(m_onionSkinDuringPlayback, SIGNAL(stateChanged(int)), ret = ret && connect(m_onionSkinDuringPlayback, SIGNAL(stateChanged(int)),
SLOT(onOnionSkinDuringPlaybackChanged(int))); SLOT(onOnionSkinDuringPlaybackChanged(int)));
ret = ret &&
connect(m_useOnionColorsForShiftAndTraceCB, SIGNAL(stateChanged(int)),
SLOT(onOnionColorsForShiftAndTraceChanged(int)));
ret = ret && connect(m_onionPaperThickness, SIGNAL(editingFinished()), ret = ret && connect(m_onionPaperThickness, SIGNAL(editingFinished()),
SLOT(onOnionPaperThicknessChanged())); SLOT(onOnionPaperThicknessChanged()));
ret = ret && connect(m_guidedDrawingStyle, SIGNAL(currentIndexChanged(int)), ret = ret && connect(m_guidedDrawingStyle, SIGNAL(currentIndexChanged(int)),

View file

@ -82,7 +82,8 @@ private:
*m_useHigherDpiOnVectorSimplifyCB, *m_keepFillOnVectorSimplifyCB, *m_useHigherDpiOnVectorSimplifyCB, *m_keepFillOnVectorSimplifyCB,
*m_newLevelToCameraSizeCB, *m_ignoreImageDpiCB, *m_newLevelToCameraSizeCB, *m_ignoreImageDpiCB,
*m_syncLevelRenumberWithXsheet, *m_downArrowInLevelStripCreatesNewFrame, *m_syncLevelRenumberWithXsheet, *m_downArrowInLevelStripCreatesNewFrame,
*m_enableAutoStretch, *m_enableWinInk; *m_enableAutoStretch, *m_enableWinInk,
*m_useOnionColorsForShiftAndTraceCB;
DVGui::FileField *m_customProjectRootFileField; DVGui::FileField *m_customProjectRootFileField;
@ -182,6 +183,7 @@ private slots:
void onReplaceAfterSaveLevelAsChanged(int index); void onReplaceAfterSaveLevelAsChanged(int index);
void onOnionSkinVisibilityChanged(int); void onOnionSkinVisibilityChanged(int);
void onOnionSkinDuringPlaybackChanged(int); void onOnionSkinDuringPlaybackChanged(int);
void onOnionColorsForShiftAndTraceChanged(int);
void onGuidedDrawingStyleChanged(int); void onGuidedDrawingStyleChanged(int);
void onActualPixelOnSceneModeChanged(int); void onActualPixelOnSceneModeChanged(int);
void onMultiLayerStylePickerChanged(int); void onMultiLayerStylePickerChanged(int);

View file

@ -2376,7 +2376,7 @@ includeInvisible);
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
int SceneViewer::posToRow(const TPointD &p, double distance, int SceneViewer::posToRow(const TPointD &p, double distance,
bool includeInvisible) const { bool includeInvisible, bool currentColumnOnly) const {
int oldRasterizePli = TXshSimpleLevel::m_rasterizePli; int oldRasterizePli = TXshSimpleLevel::m_rasterizePli;
TApp *app = TApp::instance(); TApp *app = TApp::instance();
OnionSkinMask osm = app->getCurrentOnionSkin()->getOnionSkinMask(); OnionSkinMask osm = app->getCurrentOnionSkin()->getOnionSkinMask();
@ -2405,6 +2405,8 @@ int SceneViewer::posToRow(const TPointD &p, double distance,
args.m_osm = &osm; args.m_osm = &osm;
args.m_onlyVisible = includeInvisible; args.m_onlyVisible = includeInvisible;
if (currentColumnOnly) picker.setCurrentColumnIndex(currentColumnIndex);
Stage::visit(picker, args); Stage::visit(picker, args);
} }
TXshSimpleLevel::m_rasterizePli = oldRasterizePli; TXshSimpleLevel::m_rasterizePli = oldRasterizePli;

View file

@ -370,8 +370,8 @@ protected:
//! return the row of the drawings intersecting point \b p (used with onion //! return the row of the drawings intersecting point \b p (used with onion
//! skins) //! skins)
//! (window coordinate, pixels, bottom-left origin) //! (window coordinate, pixels, bottom-left origin)
int posToRow(const TPointD &p, double distance, int posToRow(const TPointD &p, double distance, bool includeInvisible = true,
bool includeInvisible = true) const override; bool currentColumnOnly = false) const override;
void dragEnterEvent(QDragEnterEvent *event) override; void dragEnterEvent(QDragEnterEvent *event) override;
void dropEvent(QDropEvent *event) override; void dropEvent(QDropEvent *event) override;

View file

@ -365,6 +365,11 @@ void SceneViewer::onLeave() {
if (m_freezedStatus != NO_FREEZED) return; if (m_freezedStatus != NO_FREEZED) return;
TTool *tool = TApp::instance()->getCurrentTool()->getTool(); TTool *tool = TApp::instance()->getCurrentTool()->getTool();
if (tool && tool->isEnabled()) tool->onLeave(); if (tool && tool->isEnabled()) tool->onLeave();
// force reset the flipping of shift & trace
if (CommandManager::instance()->getAction(MI_ShiftTrace)->isChecked())
TTool::getTool("T_ShiftTrace", TTool::ToonzImage)->onLeave();
update(); update();
} }

View file

@ -1 +0,0 @@
#pragma once

View file

@ -465,5 +465,8 @@
<file>Resources/colorchiporder_upleft.svg</file> <file>Resources/colorchiporder_upleft.svg</file>
<file>Resources/timeline2xsheet.svg</file> <file>Resources/timeline2xsheet.svg</file>
<file>Resources/xsheet2timeline.svg</file> <file>Resources/xsheet2timeline.svg</file>
<file>Resources/shift_and_trace.svg</file>
<file>Resources/shift_and_trace_edit.svg</file>
<file>Resources/shift_and_trace_reset.svg</file>
</qresource> </qresource>
</RCC> </RCC>

View file

@ -344,7 +344,8 @@ Preferences::Preferences()
, m_cursorBrushStyle("Default") , m_cursorBrushStyle("Default")
, m_cursorOutlineEnabled(true) , m_cursorOutlineEnabled(true)
, m_currentColumnColor(TPixel::Black) , m_currentColumnColor(TPixel::Black)
, m_enableWinInk(false) { , m_enableWinInk(false)
, m_useOnionColorsForShiftAndTraceGhosts(false) {
TCamera camera; TCamera camera;
m_defLevelType = PLI_XSHLEVEL; m_defLevelType = PLI_XSHLEVEL;
m_defLevelWidth = camera.getSize().lx; m_defLevelWidth = camera.getSize().lx;
@ -620,6 +621,8 @@ Preferences::Preferences()
m_moveCurrentFrameByClickCellArea); m_moveCurrentFrameByClickCellArea);
getValue(*m_settings, "onionSkinEnabled", m_onionSkinEnabled); getValue(*m_settings, "onionSkinEnabled", m_onionSkinEnabled);
getValue(*m_settings, "onionSkinDuringPlayback", m_onionSkinDuringPlayback); getValue(*m_settings, "onionSkinDuringPlayback", m_onionSkinDuringPlayback);
getValue(*m_settings, "useOnionColorsForShiftAndTraceGhosts",
m_useOnionColorsForShiftAndTraceGhosts);
getValue(*m_settings, "multiLayerStylePickerEnabled", getValue(*m_settings, "multiLayerStylePickerEnabled",
m_multiLayerStylePickerEnabled); m_multiLayerStylePickerEnabled);
getValue(*m_settings, "showKeyframesOnXsheetCellArea", getValue(*m_settings, "showKeyframesOnXsheetCellArea",
@ -1107,6 +1110,13 @@ void Preferences::setOnionSkinDuringPlayback(bool on) {
//----------------------------------------------------------------- //-----------------------------------------------------------------
void Preferences::useOnionColorsForShiftAndTraceGhosts(bool on) {
m_useOnionColorsForShiftAndTraceGhosts = on;
m_settings->setValue("useOnionColorsForShiftAndTraceGhosts", on ? "1" : "0");
}
//-----------------------------------------------------------------
void Preferences::setShow0ThickLines(bool on) { void Preferences::setShow0ThickLines(bool on) {
m_show0ThickLines = on; m_show0ThickLines = on;
m_settings->setValue(s_show0ThickLines, s_bool[on]); m_settings->setValue(s_show0ThickLines, s_bool[on]);

View file

@ -418,9 +418,6 @@ void StageBuilder::addCell(PlayerSet &players, ToonzScene *scene, TXsheet *xsh,
} }
else { else {
if (m_shiftTraceGhostId != TRACED)
player.m_opacity =
UCHAR(255.0 * (1.0 - OnionSkinMask::getOnionSkinFade(1)));
int opacity = player.m_opacity; int opacity = player.m_opacity;
player.m_bingoOrder = 10; player.m_bingoOrder = 10;
if (m_onionSkinMask.getShiftTraceStatus() != if (m_onionSkinMask.getShiftTraceStatus() !=
@ -428,13 +425,15 @@ void StageBuilder::addCell(PlayerSet &players, ToonzScene *scene, TXsheet *xsh,
if (m_shiftTraceGhostId == FIRST_GHOST) { if (m_shiftTraceGhostId == FIRST_GHOST) {
player.m_opacity = 30; player.m_opacity = 30;
players.push_back(player); players.push_back(player);
player.m_opacity = opacity; player.m_opacity = opacity;
player.m_onionSkinDistance = -1;
player.m_placement = player.m_placement =
m_onionSkinMask.getShiftTraceGhostAff(0) * player.m_placement; m_onionSkinMask.getShiftTraceGhostAff(0) * player.m_placement;
} else if (m_shiftTraceGhostId == SECOND_GHOST) { } else if (m_shiftTraceGhostId == SECOND_GHOST) {
player.m_opacity = 30; player.m_opacity = 30;
players.push_back(player); players.push_back(player);
player.m_opacity = opacity; player.m_opacity = opacity;
player.m_onionSkinDistance = 1;
player.m_placement = player.m_placement =
m_onionSkinMask.getShiftTraceGhostAff(1) * player.m_placement; m_onionSkinMask.getShiftTraceGhostAff(1) * player.m_placement;
} }
@ -532,32 +531,46 @@ void StageBuilder::addCellWithOnionSkin(PlayerSet &players, ToonzScene *scene,
} }
}; // locals }; // locals
if (m_onionSkinMask.isShiftTraceEnabled() && col == m_currentColumnIndex) { if (m_onionSkinMask.isShiftTraceEnabled()) {
TXshCell cell = xsh->getCell(row, col); if (col == m_currentColumnIndex) {
TXshCell cell = xsh->getCell(row, col);
// First Ghost // First Ghost
int r; int r;
r = row + m_onionSkinMask.getShiftTraceGhostFrameOffset(0); r = row + m_onionSkinMask.getShiftTraceGhostFrameOffset(0);
if (r >= 0 && xsh->getCell(r, col) != cell && if (r >= 0 && xsh->getCell(r, col) != cell &&
(cell.getSimpleLevel() == 0 || (cell.getSimpleLevel() == 0 ||
xsh->getCell(r, col).getSimpleLevel() == cell.getSimpleLevel())) { xsh->getCell(r, col).getSimpleLevel() == cell.getSimpleLevel())) {
m_shiftTraceGhostId = FIRST_GHOST; m_shiftTraceGhostId = FIRST_GHOST;
addCell(players, scene, xsh, r, col, level); addCell(players, scene, xsh, r, col, level);
}
r = row + m_onionSkinMask.getShiftTraceGhostFrameOffset(1);
if (r >= 0 && xsh->getCell(r, col) != cell &&
(cell.getSimpleLevel() == 0 ||
xsh->getCell(r, col).getSimpleLevel() == cell.getSimpleLevel())) {
m_shiftTraceGhostId = SECOND_GHOST;
addCell(players, scene, xsh, r, col, level);
}
// draw current working frame
if (!cell.isEmpty()) {
m_shiftTraceGhostId = TRACED;
addCell(players, scene, xsh, row, col, level);
m_shiftTraceGhostId = NO_GHOST;
}
} }
// flip non-current columns as well
r = row + m_onionSkinMask.getShiftTraceGhostFrameOffset(1); else {
if (r >= 0 && xsh->getCell(r, col) != cell && int flipKey = m_onionSkinMask.getGhostFlipKey();
(cell.getSimpleLevel() == 0 || if (flipKey == Qt::Key_F1) {
xsh->getCell(r, col).getSimpleLevel() == cell.getSimpleLevel())) { int r = row + m_onionSkinMask.getShiftTraceGhostFrameOffset(0);
m_shiftTraceGhostId = SECOND_GHOST; addCell(players, scene, xsh, r, col, level);
addCell(players, scene, xsh, r, col, level); } else if (flipKey == Qt::Key_F3) {
} int r = row + m_onionSkinMask.getShiftTraceGhostFrameOffset(1);
addCell(players, scene, xsh, r, col, level);
// draw current working frame } else
if (!cell.isEmpty()) { addCell(players, scene, xsh, row, col, level);
m_shiftTraceGhostId = TRACED;
addCell(players, scene, xsh, row, col, level);
m_shiftTraceGhostId = NO_GHOST;
} }
} else if (locals::doStandardOnionSkin(this, xsh, level, col)) { } else if (locals::doStandardOnionSkin(this, xsh, level, col)) {
std::vector<int> rows; std::vector<int> rows;
@ -674,17 +687,14 @@ void StageBuilder::addSimpleLevelFrame(PlayerSet &players,
return; return;
} }
if (m_shiftTraceGhostId != TRACED)
player.m_opacity =
UCHAR(255.0 * (1.0 - OnionSkinMask::getOnionSkinFade(1)));
;
int opacity = player.m_opacity; int opacity = player.m_opacity;
player.m_bingoOrder = 10; player.m_bingoOrder = 10;
if (m_onionSkinMask.getShiftTraceStatus() != if (m_onionSkinMask.getShiftTraceStatus() !=
OnionSkinMask::ENABLED_WITHOUT_GHOST_MOVEMENTS) { OnionSkinMask::ENABLED_WITHOUT_GHOST_MOVEMENTS) {
player.m_opacity = 30; player.m_opacity = 30;
players.push_back(player); players.push_back(player);
player.m_opacity = opacity; player.m_opacity = opacity;
player.m_onionSkinDistance = (ghostIndex == 0) ? -1 : 1;
player.m_placement = m_onionSkinMask.getShiftTraceGhostAff(ghostIndex) * player.m_placement = m_onionSkinMask.getShiftTraceGhostAff(ghostIndex) *
player.m_placement; player.m_placement;
} }
@ -832,10 +842,11 @@ void Stage::visit(Visitor &visitor, const VisitArgs &args) {
sb.m_onionSkinMask = *osm; sb.m_onionSkinMask = *osm;
sb.m_currentFrameId = args.m_currentFrameId; sb.m_currentFrameId = args.m_currentFrameId;
sb.m_isGuidedDrawingEnabled = args.m_isGuidedDrawingEnabled; sb.m_isGuidedDrawingEnabled = args.m_isGuidedDrawingEnabled;
Player::m_onionSkinFrontSize = 0; Player::m_onionSkinFrontSize = 0;
Player::m_onionSkinBackSize = 0; Player::m_onionSkinBackSize = 0;
Player::m_firstBackOnionSkin = 0; Player::m_firstBackOnionSkin = 0;
Player::m_lastBackVisibleSkin = 0; Player::m_lastBackVisibleSkin = 0;
Player::m_isShiftAndTraceEnabled = osm->isShiftTraceEnabled();
sb.addFrame(sb.m_players, scene, xsh, row, 0, args.m_onlyVisible, sb.addFrame(sb.m_players, scene, xsh, row, 0, args.m_onlyVisible,
args.m_checkPreviewVisibility); args.m_checkPreviewVisibility);
@ -867,14 +878,15 @@ void Stage::visit(Visitor &visitor, TXshSimpleLevel *level, const TFrameId &fid,
const OnionSkinMask &osm, bool isPlaying, const OnionSkinMask &osm, bool isPlaying,
int isGuidedDrawingEnabled) { int isGuidedDrawingEnabled) {
StageBuilder sb; StageBuilder sb;
sb.m_vs = &visitor.m_vs; sb.m_vs = &visitor.m_vs;
sb.m_onionSkinMask = osm; sb.m_onionSkinMask = osm;
sb.m_currentFrameId = fid; sb.m_currentFrameId = fid;
sb.m_isGuidedDrawingEnabled = isGuidedDrawingEnabled; sb.m_isGuidedDrawingEnabled = isGuidedDrawingEnabled;
Player::m_onionSkinFrontSize = 0; Player::m_onionSkinFrontSize = 0;
Player::m_onionSkinBackSize = 0; Player::m_onionSkinBackSize = 0;
Player::m_firstBackOnionSkin = 0; Player::m_firstBackOnionSkin = 0;
Player::m_lastBackVisibleSkin = 0; Player::m_lastBackVisibleSkin = 0;
Player::m_isShiftAndTraceEnabled = osm.isShiftTraceEnabled();
sb.addSimpleLevelFrame(sb.m_players, level, fid); sb.addSimpleLevelFrame(sb.m_players, level, fid);
updateOnionSkinSize(sb.m_players); updateOnionSkinSize(sb.m_players);
sb.visit(sb.m_players, visitor, isPlaying); sb.visit(sb.m_players, visitor, isPlaying);

View file

@ -19,10 +19,11 @@ using namespace Stage;
// Stage::Player implementation // Stage::Player implementation
//***************************************************************************************** //*****************************************************************************************
double Player::m_onionSkinFrontSize = 0; double Player::m_onionSkinFrontSize = 0;
double Player::m_onionSkinBackSize = 0; double Player::m_onionSkinBackSize = 0;
double Player::m_firstBackOnionSkin = 0; double Player::m_firstBackOnionSkin = 0;
double Player::m_lastBackVisibleSkin = 0; double Player::m_lastBackVisibleSkin = 0;
bool Player::m_isShiftAndTraceEnabled = false;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View file

@ -49,6 +49,7 @@
#include "toonz/txshleveltypes.h" #include "toonz/txshleveltypes.h"
#include "imagebuilders.h" #include "imagebuilders.h"
#include "toonz/tframehandle.h" #include "toonz/tframehandle.h"
#include "toonz/preferences.h"
// Qt includes // Qt includes
#include <QImage> #include <QImage>
@ -228,6 +229,12 @@ void Picker::setDistance(double d) { m_minDist2 = d * d; }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void Picker::onImage(const Stage::Player &player) { void Picker::onImage(const Stage::Player &player) {
// if m_currentColumnIndex is other than the default value (-1),
// then pick only the current column.
if (m_currentColumnIndex != -1 &&
m_currentColumnIndex != player.m_ancestorColumnIndex)
return;
bool picked = false; bool picked = false;
TAffine aff = m_viewAff * player.m_placement; TAffine aff = m_viewAff * player.m_placement;
TPointD point = aff.inv() * m_point; TPointD point = aff.inv() * m_point;
@ -815,7 +822,9 @@ void RasterPainter::onVectorImage(TVectorImage *vi,
if (player.m_onionSkinDistance != c_noOnionSkin) { if (player.m_onionSkinDistance != c_noOnionSkin) {
TPixel32 frontOnionColor, backOnionColor; TPixel32 frontOnionColor, backOnionColor;
if (player.m_onionSkinDistance != 0) { if (player.m_onionSkinDistance != 0 &&
(!player.m_isShiftAndTraceEnabled ||
Preferences::instance()->areOnionColorsUsedForShiftAndTraceGhosts())) {
prefs.getOnionData(frontOnionColor, backOnionColor, inksOnly); prefs.getOnionData(frontOnionColor, backOnionColor, inksOnly);
bgColor = bgColor =
(player.m_onionSkinDistance < 0) ? backOnionColor : frontOnionColor; (player.m_onionSkinDistance < 0) ? backOnionColor : frontOnionColor;
@ -961,11 +970,17 @@ void RasterPainter::onRasterImage(TRasterImage *ri,
? 0.9 ? 0.9
: (1.0 - OnionSkinMask::getOnionSkinFade( : (1.0 - OnionSkinMask::getOnionSkinFade(
player.m_onionSkinDistance)); player.m_onionSkinDistance));
alpha = tcrop(tround(onionSkiFade * 255.0), 0, 255); alpha = tcrop(tround(onionSkiFade * 255.0), 0, 255);
onionMode = (player.m_onionSkinDistance > 0) if (player.m_isShiftAndTraceEnabled &&
? Node::eOnionSkinFront !Preferences::instance()->areOnionColorsUsedForShiftAndTraceGhosts())
: ((player.m_onionSkinDistance < 0) ? Node::eOnionSkinBack onionMode = Node::eOnionSkinNone;
: Node::eOnionSkinNone); else {
onionMode =
(player.m_onionSkinDistance > 0)
? Node::eOnionSkinFront
: ((player.m_onionSkinDistance < 0) ? Node::eOnionSkinBack
: Node::eOnionSkinNone);
}
} else if (player.m_opacity < 255) } else if (player.m_opacity < 255)
alpha = player.m_opacity; alpha = player.m_opacity;
TXshSimpleLevel *sl = player.m_sl; TXshSimpleLevel *sl = player.m_sl;
@ -1018,11 +1033,19 @@ void RasterPainter::onToonzImage(TToonzImage *ti, const Stage::Player &player) {
? 0.9 ? 0.9
: (1.0 - OnionSkinMask::getOnionSkinFade( : (1.0 - OnionSkinMask::getOnionSkinFade(
player.m_onionSkinDistance)); player.m_onionSkinDistance));
alpha = tcrop(tround(onionSkiFade * 255.0), 0, 255); alpha = tcrop(tround(onionSkiFade * 255.0), 0, 255);
onionMode = (player.m_onionSkinDistance > 0)
? Node::eOnionSkinFront if (player.m_isShiftAndTraceEnabled &&
: ((player.m_onionSkinDistance < 0) ? Node::eOnionSkinBack !Preferences::instance()->areOnionColorsUsedForShiftAndTraceGhosts())
: Node::eOnionSkinNone); onionMode = Node::eOnionSkinNone;
else {
onionMode =
(player.m_onionSkinDistance > 0)
? Node::eOnionSkinFront
: ((player.m_onionSkinDistance < 0) ? Node::eOnionSkinBack
: Node::eOnionSkinNone);
}
} else if (player.m_opacity < 255) } else if (player.m_opacity < 255)
alpha = player.m_opacity; alpha = player.m_opacity;