Auto close and auto fill options for vector brush (#197)
* Auto close and auto fill for vector brush * Fix undo * Make frame range work * Fix visual glitch * Fix crash * Add auto group to vector brush
This commit is contained in:
parent
f90b1577b8
commit
80fcee15eb
7 changed files with 159 additions and 27 deletions
|
@ -164,6 +164,7 @@ int TVectorImage::addStroke(TStroke *stroke, bool discardPoints,
|
||||||
while (
|
while (
|
||||||
m_imp->m_insideGroup.isParentOf(m_imp->m_strokes[k]->m_groupId)) {
|
m_imp->m_insideGroup.isParentOf(m_imp->m_strokes[k]->m_groupId)) {
|
||||||
k--;
|
k--;
|
||||||
|
if (k < 0) break;
|
||||||
}
|
}
|
||||||
m_imp->insertStrokeAt(
|
m_imp->insertStrokeAt(
|
||||||
new VIStroke(stroke, m_imp->m_strokes[i]->m_groupId), k + 1);
|
new VIStroke(stroke, m_imp->m_strokes[i]->m_groupId), k + 1);
|
||||||
|
|
|
@ -530,7 +530,8 @@ class BrushToolOptionsBox final : public ToolOptionsBox {
|
||||||
ToolOptionPopupButton *m_joinStyleCombo;
|
ToolOptionPopupButton *m_joinStyleCombo;
|
||||||
ToolOptionIntSlider *m_miterField;
|
ToolOptionIntSlider *m_miterField;
|
||||||
ToolOptionCombo *m_presetCombo;
|
ToolOptionCombo *m_presetCombo;
|
||||||
ToolOptionCheckbox *m_snapCheckbox, *m_drawOrderCheckbox;
|
ToolOptionCheckbox *m_snapCheckbox, *m_drawOrderCheckbox,
|
||||||
|
*m_autoCloseCheckbox, *m_autoGroupCheckbox, *m_autoFillCheckbox;
|
||||||
ToolOptionCombo *m_snapSensitivityCombo;
|
ToolOptionCombo *m_snapSensitivityCombo;
|
||||||
QPushButton *m_addPresetButton;
|
QPushButton *m_addPresetButton;
|
||||||
QPushButton *m_removePresetButton;
|
QPushButton *m_removePresetButton;
|
||||||
|
|
|
@ -1894,6 +1894,12 @@ BrushToolOptionsBox::BrushToolOptionsBox(QWidget *parent, TTool *tool,
|
||||||
if (tool && tool->getProperties(1)) tool->getProperties(1)->accept(builder);
|
if (tool && tool->getProperties(1)) tool->getProperties(1)->accept(builder);
|
||||||
m_drawOrderCheckbox =
|
m_drawOrderCheckbox =
|
||||||
dynamic_cast<ToolOptionCheckbox *>(m_controls.value("Draw Under"));
|
dynamic_cast<ToolOptionCheckbox *>(m_controls.value("Draw Under"));
|
||||||
|
m_autoCloseCheckbox =
|
||||||
|
dynamic_cast<ToolOptionCheckbox *>(m_controls.value("Auto Close"));
|
||||||
|
m_autoGroupCheckbox =
|
||||||
|
dynamic_cast<ToolOptionCheckbox *>(m_controls.value("Auto Group"));
|
||||||
|
m_autoFillCheckbox =
|
||||||
|
dynamic_cast<ToolOptionCheckbox *>(m_controls.value("Auto Fill"));
|
||||||
m_snapCheckbox =
|
m_snapCheckbox =
|
||||||
dynamic_cast<ToolOptionCheckbox *>(m_controls.value("Snap"));
|
dynamic_cast<ToolOptionCheckbox *>(m_controls.value("Snap"));
|
||||||
m_snapSensitivityCombo =
|
m_snapSensitivityCombo =
|
||||||
|
|
|
@ -1119,11 +1119,12 @@ void ToolUtils::UndoPencil::redo() const {
|
||||||
QMutexLocker sl(image->getMutex());
|
QMutexLocker sl(image->getMutex());
|
||||||
TStroke *stroke = new TStroke(*m_stroke);
|
TStroke *stroke = new TStroke(*m_stroke);
|
||||||
stroke->setId(m_strokeId);
|
stroke->setId(m_strokeId);
|
||||||
image->addStroke(stroke, true, m_sendToBack);
|
int addedStrokeIndex = image->addStroke(stroke, true, m_sendToBack);
|
||||||
if (image->isComputedRegionAlmostOnce()) image->findRegions();
|
if (image->isComputedRegionAlmostOnce()) image->findRegions();
|
||||||
|
|
||||||
if (m_autogroup && stroke->isSelfLoop()) {
|
if (m_autogroup && stroke->isSelfLoop()) {
|
||||||
int index = image->getStrokeCount() - 1;
|
int index = image->getStrokeCount() - 1;
|
||||||
|
if (m_sendToBack) index = addedStrokeIndex;
|
||||||
image->group(index, 1);
|
image->group(index, 1);
|
||||||
if (m_autofill) {
|
if (m_autofill) {
|
||||||
// to avoid filling other strokes, I enter into the new stroke group
|
// to avoid filling other strokes, I enter into the new stroke group
|
||||||
|
|
|
@ -63,6 +63,9 @@ TEnv::IntVar V_VectorBrushFrameRange("VectorBrushFrameRange", 0);
|
||||||
TEnv::IntVar V_VectorBrushSnap("VectorBrushSnap", 0);
|
TEnv::IntVar V_VectorBrushSnap("VectorBrushSnap", 0);
|
||||||
TEnv::IntVar V_VectorBrushSnapSensitivity("VectorBrushSnapSensitivity", 0);
|
TEnv::IntVar V_VectorBrushSnapSensitivity("VectorBrushSnapSensitivity", 0);
|
||||||
TEnv::IntVar V_VectorBrushDrawBehind("VectorBrushDrawBehind", 0);
|
TEnv::IntVar V_VectorBrushDrawBehind("VectorBrushDrawBehind", 0);
|
||||||
|
TEnv::IntVar V_VectorBrushAutoClose("VectorBrushAutoClose", 0);
|
||||||
|
TEnv::IntVar V_VectorBrushAutoFill("VectorBrushAutoFill", 0);
|
||||||
|
TEnv::IntVar V_VectorBrushAutoGroup("VectorBrushAutoGroup", 0);
|
||||||
TEnv::StringVar V_VectorBrushPreset("VectorBrushPreset", "<custom>");
|
TEnv::StringVar V_VectorBrushPreset("VectorBrushPreset", "<custom>");
|
||||||
|
|
||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
|
@ -370,6 +373,7 @@ static void addStroke(TTool::Application *application, const TVectorImageP &vi,
|
||||||
}
|
}
|
||||||
TFrameId id = application->getCurrentTool()->getTool()->getCurrentFid();
|
TFrameId id = application->getCurrentTool()->getTool()->getCurrentFid();
|
||||||
if (id == TFrameId::NO_FRAME && fid != TFrameId::NO_FRAME) id = fid;
|
if (id == TFrameId::NO_FRAME && fid != TFrameId::NO_FRAME) id = fid;
|
||||||
|
int addedStrokeIndex = -1;
|
||||||
if (!corners.empty()) {
|
if (!corners.empty()) {
|
||||||
if (breakAngles)
|
if (breakAngles)
|
||||||
split(stroke, corners, strokes);
|
split(stroke, corners, strokes);
|
||||||
|
@ -384,8 +388,8 @@ static void addStroke(TTool::Application *application, const TVectorImageP &vi,
|
||||||
new std::vector<TFilledRegionInf>;
|
new std::vector<TFilledRegionInf>;
|
||||||
ImageUtils::getFillingInformationOverlappingArea(vi, *fillInformation,
|
ImageUtils::getFillingInformationOverlappingArea(vi, *fillInformation,
|
||||||
stroke->getBBox());
|
stroke->getBBox());
|
||||||
TStroke *str = new TStroke(*strokes[i]);
|
TStroke *str = new TStroke(*strokes[i]);
|
||||||
vi->addStroke(str, true, sendToBack);
|
addedStrokeIndex = vi->addStroke(str, true, sendToBack);
|
||||||
TUndoManager::manager()->add(
|
TUndoManager::manager()->add(
|
||||||
new UndoPencil(str, fillInformation, sl, id, frameCreated,
|
new UndoPencil(str, fillInformation, sl, id, frameCreated,
|
||||||
levelCreated, autoGroup, autoFill, sendToBack));
|
levelCreated, autoGroup, autoFill, sendToBack));
|
||||||
|
@ -396,15 +400,16 @@ static void addStroke(TTool::Application *application, const TVectorImageP &vi,
|
||||||
new std::vector<TFilledRegionInf>;
|
new std::vector<TFilledRegionInf>;
|
||||||
ImageUtils::getFillingInformationOverlappingArea(vi, *fillInformation,
|
ImageUtils::getFillingInformationOverlappingArea(vi, *fillInformation,
|
||||||
stroke->getBBox());
|
stroke->getBBox());
|
||||||
TStroke *str = new TStroke(*stroke);
|
TStroke *str = new TStroke(*stroke);
|
||||||
vi->addStroke(str, true, sendToBack);
|
addedStrokeIndex = vi->addStroke(str, true, sendToBack);
|
||||||
TUndoManager::manager()->add(
|
TUndoManager::manager()->add(
|
||||||
new UndoPencil(str, fillInformation, sl, id, frameCreated, levelCreated,
|
new UndoPencil(str, fillInformation, sl, id, frameCreated, levelCreated,
|
||||||
autoGroup, autoFill, sendToBack));
|
autoGroup, autoFill, sendToBack));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (autoGroup && stroke->isSelfLoop()) {
|
if (autoGroup && stroke->isSelfLoop()) {
|
||||||
int index = vi->getStrokeCount() - 1;
|
int index = vi->getStrokeCount() - 1;
|
||||||
|
if (sendToBack) index = addedStrokeIndex;
|
||||||
vi->group(index, 1);
|
vi->group(index, 1);
|
||||||
if (autoFill) {
|
if (autoFill) {
|
||||||
// to avoid filling other strokes, I enter into the new stroke group
|
// to avoid filling other strokes, I enter into the new stroke group
|
||||||
|
@ -522,6 +527,9 @@ ToonzVectorBrushTool::ToonzVectorBrushTool(std::string name, int targetType)
|
||||||
, m_snap("Snap", false)
|
, m_snap("Snap", false)
|
||||||
, m_snapSensitivity("Sensitivity:")
|
, m_snapSensitivity("Sensitivity:")
|
||||||
, m_sendToBack("Draw Under", false)
|
, m_sendToBack("Draw Under", false)
|
||||||
|
, m_autoClose("Auto Close", false)
|
||||||
|
, m_autoGroup("Auto Group", false)
|
||||||
|
, m_autoFill("Auto Fill", false)
|
||||||
, m_targetType(targetType)
|
, m_targetType(targetType)
|
||||||
, m_workingFrameId(TFrameId()) {
|
, m_workingFrameId(TFrameId()) {
|
||||||
bind(targetType);
|
bind(targetType);
|
||||||
|
@ -534,6 +542,15 @@ ToonzVectorBrushTool::ToonzVectorBrushTool(std::string name, int targetType)
|
||||||
m_prop[0].bind(m_breakAngles);
|
m_prop[0].bind(m_breakAngles);
|
||||||
m_prop[0].bind(m_pressure);
|
m_prop[0].bind(m_pressure);
|
||||||
|
|
||||||
|
m_prop[0].bind(m_autoClose);
|
||||||
|
m_autoClose.setId("AutoClose");
|
||||||
|
|
||||||
|
m_prop[0].bind(m_autoGroup);
|
||||||
|
m_autoGroup.setId("AutoGroup");
|
||||||
|
|
||||||
|
m_prop[0].bind(m_autoFill);
|
||||||
|
m_autoFill.setId("AutoFill");
|
||||||
|
|
||||||
m_prop[0].bind(m_sendToBack);
|
m_prop[0].bind(m_sendToBack);
|
||||||
m_sendToBack.setId("DrawUnder");
|
m_sendToBack.setId("DrawUnder");
|
||||||
|
|
||||||
|
@ -618,6 +635,9 @@ void ToonzVectorBrushTool::updateTranslation() {
|
||||||
m_joinStyle.setItemUIName(ROUNDJ_WSTR, tr("Round join"));
|
m_joinStyle.setItemUIName(ROUNDJ_WSTR, tr("Round join"));
|
||||||
m_joinStyle.setItemUIName(BEVEL_WSTR, tr("Bevel join"));
|
m_joinStyle.setItemUIName(BEVEL_WSTR, tr("Bevel join"));
|
||||||
m_sendToBack.setQStringName(tr("Draw Under"));
|
m_sendToBack.setQStringName(tr("Draw Under"));
|
||||||
|
m_autoClose.setQStringName(tr("Auto Close"));
|
||||||
|
m_autoFill.setQStringName(tr("Auto Fill"));
|
||||||
|
m_autoGroup.setQStringName(tr("Auto Group"));
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------
|
||||||
|
@ -1140,6 +1160,7 @@ void ToonzVectorBrushTool::leftButtonUp(const TPointD &pos,
|
||||||
stroke->insertControlPoints(0.5);
|
stroke->insertControlPoints(0.5);
|
||||||
if (m_frameRange.getIndex()) {
|
if (m_frameRange.getIndex()) {
|
||||||
if (m_firstFrameId == -1) {
|
if (m_firstFrameId == -1) {
|
||||||
|
if (m_autoClose.getValue()) stroke->setSelfLoop(true);
|
||||||
m_firstStroke = new TStroke(*stroke);
|
m_firstStroke = new TStroke(*stroke);
|
||||||
m_firstFrameId = getFrameId();
|
m_firstFrameId = getFrameId();
|
||||||
TTool::Application *application = TTool::getApplication();
|
TTool::Application *application = TTool::getApplication();
|
||||||
|
@ -1158,8 +1179,10 @@ void ToonzVectorBrushTool::leftButtonUp(const TPointD &pos,
|
||||||
delete m_firstStroke;
|
delete m_firstStroke;
|
||||||
m_firstStroke = 0;
|
m_firstStroke = 0;
|
||||||
}
|
}
|
||||||
|
if (m_autoClose.getValue()) stroke->setSelfLoop(true);
|
||||||
m_firstStroke = new TStroke(*stroke);
|
m_firstStroke = new TStroke(*stroke);
|
||||||
m_rangeTrack = m_track;
|
if (m_autoClose.getValue()) m_firstStroke->setSelfLoop(true);
|
||||||
|
m_rangeTrack = m_track;
|
||||||
} else {
|
} else {
|
||||||
TFrameId currentId = getFrameId();
|
TFrameId currentId = getFrameId();
|
||||||
int curCol = 0, curFrame = 0;
|
int curCol = 0, curFrame = 0;
|
||||||
|
@ -1168,10 +1191,13 @@ void ToonzVectorBrushTool::leftButtonUp(const TPointD &pos,
|
||||||
curCol = application->getCurrentColumn()->getColumnIndex();
|
curCol = application->getCurrentColumn()->getColumnIndex();
|
||||||
curFrame = application->getCurrentFrame()->getFrame();
|
curFrame = application->getCurrentFrame()->getFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_autoClose.getValue()) stroke->setSelfLoop(true);
|
||||||
bool success = doFrameRangeStrokes(
|
bool success = doFrameRangeStrokes(
|
||||||
m_firstFrameId, m_firstStroke, getFrameId(), stroke,
|
m_firstFrameId, m_firstStroke, getFrameId(), stroke,
|
||||||
m_frameRange.getIndex(), m_breakAngles.getValue(), false, false,
|
m_frameRange.getIndex(), m_breakAngles.getValue(),
|
||||||
m_firstFrameRange, true, true, m_sendToBack.getValue() > 0);
|
m_autoGroup.getValue(), m_autoFill.getValue(), m_firstFrameRange,
|
||||||
|
true, true, m_sendToBack.getValue() > 0);
|
||||||
if (e.isCtrlPressed() && e.isAltPressed() && e.isShiftPressed()) {
|
if (e.isCtrlPressed() && e.isAltPressed() && e.isShiftPressed()) {
|
||||||
if (application) {
|
if (application) {
|
||||||
if (m_firstFrameId > currentId) {
|
if (m_firstFrameId > currentId) {
|
||||||
|
@ -1208,17 +1234,18 @@ void ToonzVectorBrushTool::leftButtonUp(const TPointD &pos,
|
||||||
stroke->setSelfLoop(true);
|
stroke->setSelfLoop(true);
|
||||||
m_snapSelf = false;
|
m_snapSelf = false;
|
||||||
}
|
}
|
||||||
// bool m_sendToBack =
|
|
||||||
// e.isAltPressed() && e.isShiftPressed() && !e.isCtrlPressed();
|
if (m_autoClose.getValue()) stroke->setSelfLoop(true);
|
||||||
//#ifdef Q_OS_WIN
|
//#ifdef Q_OS_WIN
|
||||||
// m_sendToBack = (GetKeyState(VK_CAPITAL) & 0x0001);
|
// m_sendToBack = (GetKeyState(VK_CAPITAL) & 0x0001);
|
||||||
//#endif
|
//#endif
|
||||||
addStrokeToImage(getApplication(), vi, stroke, m_breakAngles.getValue(),
|
addStrokeToImage(getApplication(), vi, stroke, m_breakAngles.getValue(),
|
||||||
false, false, m_isFrameCreated, m_isLevelCreated, 0,
|
m_autoGroup.getValue(), m_autoFill.getValue(),
|
||||||
TFrameId::NO_FRAME, m_sendToBack.getValue() > 0);
|
m_isFrameCreated, m_isLevelCreated, 0, TFrameId::NO_FRAME,
|
||||||
|
m_sendToBack.getValue() > 0);
|
||||||
TRectD bbox = stroke->getBBox().enlarge(2) + m_track.getModifiedRegion();
|
TRectD bbox = stroke->getBBox().enlarge(2) + m_track.getModifiedRegion();
|
||||||
|
|
||||||
invalidate(); // should use bbox?
|
invalidate();
|
||||||
|
|
||||||
if ((Preferences::instance()->getGuidedDrawingType() == 1 ||
|
if ((Preferences::instance()->getGuidedDrawingType() == 1 ||
|
||||||
Preferences::instance()->getGuidedDrawingType() == 2) &&
|
Preferences::instance()->getGuidedDrawingType() == 2) &&
|
||||||
|
@ -1226,8 +1253,9 @@ void ToonzVectorBrushTool::leftButtonUp(const TPointD &pos,
|
||||||
int fidx = getApplication()->getCurrentFrame()->getFrameIndex();
|
int fidx = getApplication()->getCurrentFrame()->getFrameIndex();
|
||||||
TFrameId fId = getFrameId();
|
TFrameId fId = getFrameId();
|
||||||
|
|
||||||
doGuidedAutoInbetween(fId, vi, stroke, m_breakAngles.getValue(), false,
|
doGuidedAutoInbetween(fId, vi, stroke, m_breakAngles.getValue(),
|
||||||
false, false, m_sendToBack.getValue() > 0);
|
m_autoGroup.getValue(), m_autoFill.getValue(),
|
||||||
|
false, m_sendToBack.getValue() > 0);
|
||||||
|
|
||||||
if (getApplication()->getCurrentFrame()->isEditingScene())
|
if (getApplication()->getCurrentFrame()->isEditingScene())
|
||||||
getApplication()->getCurrentFrame()->setFrame(fidx);
|
getApplication()->getCurrentFrame()->setFrame(fidx);
|
||||||
|
@ -1246,6 +1274,7 @@ void ToonzVectorBrushTool::leftButtonUp(const TPointD &pos,
|
||||||
bool ToonzVectorBrushTool::keyDown(QKeyEvent *event) {
|
bool ToonzVectorBrushTool::keyDown(QKeyEvent *event) {
|
||||||
if (event->key() == Qt::Key_Escape) {
|
if (event->key() == Qt::Key_Escape) {
|
||||||
resetFrameRange();
|
resetFrameRange();
|
||||||
|
invalidate();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1264,8 +1293,9 @@ bool ToonzVectorBrushTool::doFrameRangeStrokes(
|
||||||
TVectorImageP firstImage = new TVectorImage();
|
TVectorImageP firstImage = new TVectorImage();
|
||||||
TVectorImageP lastImage = new TVectorImage();
|
TVectorImageP lastImage = new TVectorImage();
|
||||||
|
|
||||||
*first = *firstStroke;
|
*first = *firstStroke;
|
||||||
*last = *lastStroke;
|
*last = *lastStroke;
|
||||||
|
|
||||||
bool swapped = false;
|
bool swapped = false;
|
||||||
if (firstFrameId > lastFrameId) {
|
if (firstFrameId > lastFrameId) {
|
||||||
std::swap(firstFrameId, lastFrameId);
|
std::swap(firstFrameId, lastFrameId);
|
||||||
|
@ -1274,6 +1304,11 @@ bool ToonzVectorBrushTool::doFrameRangeStrokes(
|
||||||
swapped = true;
|
swapped = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_autoClose.getValue()) {
|
||||||
|
first->setSelfLoop(true);
|
||||||
|
last->setSelfLoop(true);
|
||||||
|
}
|
||||||
|
|
||||||
firstImage->addStroke(first, false, sendToBack);
|
firstImage->addStroke(first, false, sendToBack);
|
||||||
lastImage->addStroke(last, false, sendToBack);
|
lastImage->addStroke(last, false, sendToBack);
|
||||||
assert(firstFrameId <= lastFrameId);
|
assert(firstFrameId <= lastFrameId);
|
||||||
|
@ -1337,6 +1372,7 @@ bool ToonzVectorBrushTool::doFrameRangeStrokes(
|
||||||
assert(lastImage->getStrokeCount() == 1);
|
assert(lastImage->getStrokeCount() == 1);
|
||||||
TVectorImageP vi = TInbetween(firstImage, lastImage).tween(s);
|
TVectorImageP vi = TInbetween(firstImage, lastImage).tween(s);
|
||||||
assert(vi->getStrokeCount() == 1);
|
assert(vi->getStrokeCount() == 1);
|
||||||
|
if (m_autoClose.getValue()) vi->getStroke(0)->setSelfLoop(true);
|
||||||
addStrokeToImage(getApplication(), img, vi->getStroke(0), breakAngles,
|
addStrokeToImage(getApplication(), img, vi->getStroke(0), breakAngles,
|
||||||
autoGroup, autoFill, m_isFrameCreated, m_isLevelCreated,
|
autoGroup, autoFill, m_isFrameCreated, m_isLevelCreated,
|
||||||
sl, fid, sendToBack);
|
sl, fid, sendToBack);
|
||||||
|
@ -1894,7 +1930,64 @@ bool ToonzVectorBrushTool::onPropertyChanged(std::string propertyName) {
|
||||||
if (index == 0) resetFrameRange();
|
if (index == 0) resetFrameRange();
|
||||||
} else if (propertyName == m_sendToBack.getName()) {
|
} else if (propertyName == m_sendToBack.getName()) {
|
||||||
V_VectorBrushDrawBehind = m_sendToBack.getValue();
|
V_VectorBrushDrawBehind = m_sendToBack.getValue();
|
||||||
} else if (propertyName == m_snap.getName()) {
|
}
|
||||||
|
|
||||||
|
else if (propertyName == m_autoClose.getName()) {
|
||||||
|
if (!m_autoClose.getValue()) {
|
||||||
|
m_autoFill.setValue(false);
|
||||||
|
m_autoGroup.setValue(false);
|
||||||
|
V_VectorBrushAutoFill = 0;
|
||||||
|
V_VectorBrushAutoGroup = 0;
|
||||||
|
// this is ugly: it's needed to refresh the GUI of the toolbar after
|
||||||
|
// having set to false the autofill...
|
||||||
|
TTool::getApplication()->getCurrentTool()->setTool(
|
||||||
|
""); // necessary, otherwise next setTool is ignored...
|
||||||
|
TTool::getApplication()->getCurrentTool()->setTool(
|
||||||
|
QString::fromStdString(getName()));
|
||||||
|
}
|
||||||
|
V_VectorBrushAutoClose = m_autoClose.getValue();
|
||||||
|
} else if (propertyName == m_autoGroup.getName()) {
|
||||||
|
// We need close turned on if on,
|
||||||
|
// We need autofill off if off.
|
||||||
|
if (m_autoGroup.getValue()) {
|
||||||
|
m_autoClose.setValue(true);
|
||||||
|
V_VectorBrushAutoClose = 1;
|
||||||
|
// this is ugly: it's needed to refresh the GUI of the toolbar after
|
||||||
|
// having set to false the autofill...
|
||||||
|
TTool::getApplication()->getCurrentTool()->setTool(
|
||||||
|
""); // necessary, otherwise next setTool is ignored...
|
||||||
|
TTool::getApplication()->getCurrentTool()->setTool(
|
||||||
|
QString::fromStdString(getName()));
|
||||||
|
}
|
||||||
|
if (!m_autoGroup.getValue() && m_autoFill.getValue()) {
|
||||||
|
m_autoFill.setValue(false);
|
||||||
|
V_VectorBrushAutoFill = 0;
|
||||||
|
// this is ugly: it's needed to refresh the GUI of the toolbar after
|
||||||
|
// having set to false the autofill...
|
||||||
|
TTool::getApplication()->getCurrentTool()->setTool(
|
||||||
|
""); // necessary, otherwise next setTool is ignored...
|
||||||
|
TTool::getApplication()->getCurrentTool()->setTool(
|
||||||
|
QString::fromStdString(getName()));
|
||||||
|
}
|
||||||
|
V_VectorBrushAutoGroup = m_autoGroup.getValue();
|
||||||
|
} else if (propertyName == m_autoFill.getName()) {
|
||||||
|
// we need close and group on
|
||||||
|
if (m_autoFill.getValue()) {
|
||||||
|
m_autoClose.setValue(true);
|
||||||
|
m_autoGroup.setValue(true);
|
||||||
|
V_VectorBrushAutoClose = 1;
|
||||||
|
V_VectorBrushAutoGroup = 1;
|
||||||
|
// this is ugly: it's needed to refresh the GUI of the toolbar after
|
||||||
|
// having set to false the autofill...
|
||||||
|
TTool::getApplication()->getCurrentTool()->setTool(
|
||||||
|
""); // necessary, otherwise next setTool is ignored...
|
||||||
|
TTool::getApplication()->getCurrentTool()->setTool(
|
||||||
|
QString::fromStdString(getName()));
|
||||||
|
}
|
||||||
|
V_VectorBrushAutoFill = m_autoFill.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (propertyName == m_snap.getName()) {
|
||||||
V_VectorBrushSnap = m_snap.getValue();
|
V_VectorBrushSnap = m_snap.getValue();
|
||||||
} else if (propertyName == m_snapSensitivity.getName()) {
|
} else if (propertyName == m_snapSensitivity.getName()) {
|
||||||
int index = m_snapSensitivity.getIndex();
|
int index = m_snapSensitivity.getIndex();
|
||||||
|
@ -2035,6 +2128,20 @@ void ToonzVectorBrushTool::loadLastBrush() {
|
||||||
m_snap.setValue(V_VectorBrushSnap);
|
m_snap.setValue(V_VectorBrushSnap);
|
||||||
m_snapSensitivity.setIndex(V_VectorBrushSnapSensitivity);
|
m_snapSensitivity.setIndex(V_VectorBrushSnapSensitivity);
|
||||||
m_sendToBack.setValue(V_VectorBrushDrawBehind);
|
m_sendToBack.setValue(V_VectorBrushDrawBehind);
|
||||||
|
m_autoClose.setValue(V_VectorBrushAutoClose);
|
||||||
|
m_autoFill.setValue(V_VectorBrushAutoFill);
|
||||||
|
if (m_autoFill.getValue() && !m_autoClose.getValue()) {
|
||||||
|
m_autoClose.setValue(true);
|
||||||
|
V_VectorBrushAutoClose = 1;
|
||||||
|
}
|
||||||
|
if (m_autoFill.getValue() && !m_autoGroup.getValue()) {
|
||||||
|
m_autoGroup.setValue(true);
|
||||||
|
V_VectorBrushAutoGroup = 1;
|
||||||
|
}
|
||||||
|
if (m_autoGroup.getValue() && !m_autoClose.getValue()) {
|
||||||
|
m_autoClose.setValue(true);
|
||||||
|
V_VectorBrushAutoClose = 1;
|
||||||
|
}
|
||||||
switch (V_VectorBrushSnapSensitivity) {
|
switch (V_VectorBrushSnapSensitivity) {
|
||||||
case 0:
|
case 0:
|
||||||
m_minDistance2 = SNAPPING_LOW;
|
m_minDistance2 = SNAPPING_LOW;
|
||||||
|
|
|
@ -155,6 +155,9 @@ protected:
|
||||||
TBoolProperty m_pressure;
|
TBoolProperty m_pressure;
|
||||||
TBoolProperty m_snap;
|
TBoolProperty m_snap;
|
||||||
TBoolProperty m_sendToBack;
|
TBoolProperty m_sendToBack;
|
||||||
|
TBoolProperty m_autoFill;
|
||||||
|
TBoolProperty m_autoClose;
|
||||||
|
TBoolProperty m_autoGroup;
|
||||||
TEnumProperty m_frameRange;
|
TEnumProperty m_frameRange;
|
||||||
TEnumProperty m_snapSensitivity;
|
TEnumProperty m_snapSensitivity;
|
||||||
TEnumProperty m_capStyle;
|
TEnumProperty m_capStyle;
|
||||||
|
@ -203,7 +206,6 @@ protected:
|
||||||
//! substitution.
|
//! substitution.
|
||||||
m_firstTime, m_isPath, m_presetsLoaded, m_firstFrameRange;
|
m_firstTime, m_isPath, m_presetsLoaded, m_firstFrameRange;
|
||||||
|
|
||||||
|
|
||||||
TFrameId m_workingFrameId;
|
TFrameId m_workingFrameId;
|
||||||
|
|
||||||
TPointD m_lastDragPos; //!< Position where mouse was last dragged.
|
TPointD m_lastDragPos; //!< Position where mouse was last dragged.
|
||||||
|
|
|
@ -119,6 +119,7 @@ void StrokeGenerator::drawFragments(int first, int last) {
|
||||||
TThickPoint a;
|
TThickPoint a;
|
||||||
TThickPoint b;
|
TThickPoint b;
|
||||||
TThickPoint c;
|
TThickPoint c;
|
||||||
|
TThickPoint tempThickPoint;
|
||||||
TPointD v;
|
TPointD v;
|
||||||
|
|
||||||
// If drawing a straight line, a stroke can have only two points
|
// If drawing a straight line, a stroke can have only two points
|
||||||
|
@ -161,11 +162,21 @@ void StrokeGenerator::drawFragments(int first, int last) {
|
||||||
if (c.thick == 0) c.thick = 0.1;
|
if (c.thick == 0) c.thick = 0.1;
|
||||||
}
|
}
|
||||||
if (i - 1 == 0) {
|
if (i - 1 == 0) {
|
||||||
v = a.thick * normalize(rotate90(b - a));
|
tempThickPoint = rotate90(b - a);
|
||||||
|
if (std::abs(tempThickPoint.x) == 0.0 &&
|
||||||
|
std::abs(tempThickPoint.y == 0.0)) {
|
||||||
|
v = a.thick * tempThickPoint;
|
||||||
|
} else
|
||||||
|
v = a.thick * normalize(tempThickPoint);
|
||||||
m_p0 = a + v;
|
m_p0 = a + v;
|
||||||
m_p1 = a - v;
|
m_p1 = a - v;
|
||||||
}
|
}
|
||||||
v = b.thick * normalize(rotate90(c - a));
|
tempThickPoint = rotate90(c - a);
|
||||||
|
if (std::abs(tempThickPoint.x) == 0.0 &&
|
||||||
|
std::abs(tempThickPoint.y == 0.0)) {
|
||||||
|
v = b.thick * tempThickPoint;
|
||||||
|
} else
|
||||||
|
v = b.thick * normalize(tempThickPoint);
|
||||||
TPointD p0 = b + v;
|
TPointD p0 = b + v;
|
||||||
TPointD p1 = b - v;
|
TPointD p1 = b - v;
|
||||||
glBegin(GL_POLYGON);
|
glBegin(GL_POLYGON);
|
||||||
|
@ -184,8 +195,11 @@ void StrokeGenerator::drawFragments(int first, int last) {
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
if (last < 2) return;
|
if (last < 2) return;
|
||||||
v = m_points[last].thick *
|
tempThickPoint = rotate90(m_points[last] - m_points[last - 1]);
|
||||||
normalize(rotate90(m_points[last] - m_points[last - 1]));
|
if (std::abs(tempThickPoint.x) == 0.0 && std::abs(tempThickPoint.y == 0.0)) {
|
||||||
|
v = m_points[last].thick * tempThickPoint;
|
||||||
|
} else
|
||||||
|
v = m_points[last].thick * normalize(tempThickPoint);
|
||||||
TPointD p0 = m_points[last] + v;
|
TPointD p0 = m_points[last] + v;
|
||||||
TPointD p1 = m_points[last] - v;
|
TPointD p1 = m_points[last] - v;
|
||||||
glBegin(GL_POLYGON);
|
glBegin(GL_POLYGON);
|
||||||
|
@ -222,7 +236,7 @@ void StrokeGenerator::drawLastFragments() {
|
||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
|
|
||||||
void StrokeGenerator::drawAllFragments() {
|
void StrokeGenerator::drawAllFragments() {
|
||||||
if (m_points.empty()) return;
|
if (m_points.empty() || m_points.size() == 0) return;
|
||||||
|
|
||||||
int n = m_points.size();
|
int n = m_points.size();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
Loading…
Reference in a new issue