mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 10:08:18 +00:00
Merge pull request #6872 from Marmare314/envelope_contextmenu
Multiple selection in envelope editor
This commit is contained in:
commit
8b209f036e
|
@ -884,6 +884,109 @@ int CEditor::FindSelectedQuadPointIndex(int QuadIndex) const
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int CEditor::FindEnvPointIndex(int Index, int Channel) const
|
||||||
|
{
|
||||||
|
auto Iter = std::find(
|
||||||
|
m_vSelectedEnvelopePoints.begin(),
|
||||||
|
m_vSelectedEnvelopePoints.end(),
|
||||||
|
std::pair(Index, Channel));
|
||||||
|
|
||||||
|
if(Iter != m_vSelectedEnvelopePoints.end())
|
||||||
|
return Iter - m_vSelectedEnvelopePoints.begin();
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CEditor::SelectEnvPoint(int Index)
|
||||||
|
{
|
||||||
|
m_vSelectedEnvelopePoints.clear();
|
||||||
|
|
||||||
|
for(int c = 0; c < CEnvPoint::MAX_CHANNELS; c++)
|
||||||
|
m_vSelectedEnvelopePoints.emplace_back(Index, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CEditor::SelectEnvPoint(int Index, int Channel)
|
||||||
|
{
|
||||||
|
DeselectEnvPoints();
|
||||||
|
m_vSelectedEnvelopePoints.emplace_back(Index, Channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CEditor::ToggleEnvPoint(int Index, int Channel)
|
||||||
|
{
|
||||||
|
if(IsTangentSelected())
|
||||||
|
DeselectEnvPoints();
|
||||||
|
|
||||||
|
int ListIndex = FindEnvPointIndex(Index, Channel);
|
||||||
|
|
||||||
|
if(ListIndex >= 0)
|
||||||
|
{
|
||||||
|
m_vSelectedEnvelopePoints.erase(m_vSelectedEnvelopePoints.begin() + ListIndex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_vSelectedEnvelopePoints.emplace_back(Index, Channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CEditor::IsEnvPointSelected(int Index, int Channel) const
|
||||||
|
{
|
||||||
|
int ListIndex = FindEnvPointIndex(Index, Channel);
|
||||||
|
|
||||||
|
return ListIndex >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CEditor::IsEnvPointSelected(int Index) const
|
||||||
|
{
|
||||||
|
auto Iter = std::find_if(
|
||||||
|
m_vSelectedEnvelopePoints.begin(),
|
||||||
|
m_vSelectedEnvelopePoints.end(),
|
||||||
|
[&](auto pair) { return pair.first == Index; });
|
||||||
|
|
||||||
|
return Iter != m_vSelectedEnvelopePoints.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CEditor::DeselectEnvPoints()
|
||||||
|
{
|
||||||
|
m_vSelectedEnvelopePoints.clear();
|
||||||
|
m_SelectedTangentInPoint = std::pair(-1, -1);
|
||||||
|
m_SelectedTangentOutPoint = std::pair(-1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CEditor::SelectTangentOutPoint(int Index, int Channel)
|
||||||
|
{
|
||||||
|
DeselectEnvPoints();
|
||||||
|
m_SelectedTangentOutPoint = std::pair(Index, Channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CEditor::IsTangentOutPointSelected(int Index, int Channel) const
|
||||||
|
{
|
||||||
|
return m_SelectedTangentOutPoint == std::pair(Index, Channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CEditor::SelectTangentInPoint(int Index, int Channel)
|
||||||
|
{
|
||||||
|
DeselectEnvPoints();
|
||||||
|
m_SelectedTangentInPoint = std::pair(Index, Channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CEditor::IsTangentInPointSelected(int Index, int Channel) const
|
||||||
|
{
|
||||||
|
return m_SelectedTangentInPoint == std::pair(Index, Channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CEditor::IsTangentInSelected() const
|
||||||
|
{
|
||||||
|
return m_SelectedTangentInPoint != std::pair(-1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CEditor::IsTangentOutSelected() const
|
||||||
|
{
|
||||||
|
return m_SelectedTangentOutPoint != std::pair(-1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CEditor::IsTangentSelected() const
|
||||||
|
{
|
||||||
|
return IsTangentInSelected() || IsTangentOutSelected();
|
||||||
|
}
|
||||||
|
|
||||||
bool CEditor::CallbackOpenMap(const char *pFileName, int StorageType, void *pUser)
|
bool CEditor::CallbackOpenMap(const char *pFileName, int StorageType, void *pUser)
|
||||||
{
|
{
|
||||||
CEditor *pEditor = (CEditor *)pUser;
|
CEditor *pEditor = (CEditor *)pUser;
|
||||||
|
@ -2306,7 +2409,7 @@ void CEditor::DoQuadEnvelopes(const std::vector<CQuad> &vQuads, IGraphics::CText
|
||||||
float Rot = fx2f(apEnvelope[j]->m_vPoints[i].m_aValues[2]) / 360.0f * pi * 2;
|
float Rot = fx2f(apEnvelope[j]->m_vPoints[i].m_aValues[2]) / 360.0f * pi * 2;
|
||||||
|
|
||||||
// Set Colours
|
// Set Colours
|
||||||
float Alpha = (m_SelectedQuadEnvelope == vQuads[j].m_PosEnv && m_SelectedEnvelopePoint == (int)i) ? 0.65f : 0.35f;
|
float Alpha = (m_SelectedQuadEnvelope == vQuads[j].m_PosEnv && IsEnvPointSelected(i)) ? 0.65f : 0.35f;
|
||||||
IGraphics::CColorVertex aArray[4] = {
|
IGraphics::CColorVertex aArray[4] = {
|
||||||
IGraphics::CColorVertex(0, vQuads[j].m_aColors[0].r, vQuads[j].m_aColors[0].g, vQuads[j].m_aColors[0].b, Alpha),
|
IGraphics::CColorVertex(0, vQuads[j].m_aColors[0].r, vQuads[j].m_aColors[0].g, vQuads[j].m_aColors[0].b, Alpha),
|
||||||
IGraphics::CColorVertex(1, vQuads[j].m_aColors[1].r, vQuads[j].m_aColors[1].g, vQuads[j].m_aColors[1].b, Alpha),
|
IGraphics::CColorVertex(1, vQuads[j].m_aColors[1].r, vQuads[j].m_aColors[1].g, vQuads[j].m_aColors[1].b, Alpha),
|
||||||
|
@ -2452,7 +2555,7 @@ void CEditor::DoQuadEnvPoint(const CQuad *pQuad, int QIndex, int PIndex)
|
||||||
SelectQuad(QIndex);
|
SelectQuad(QIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_SelectedEnvelopePoint = PIndex;
|
SelectEnvPoint(PIndex);
|
||||||
m_SelectedQuadEnvelope = pQuad->m_PosEnv;
|
m_SelectedQuadEnvelope = pQuad->m_PosEnv;
|
||||||
|
|
||||||
UI()->SetActiveItem(pID);
|
UI()->SetActiveItem(pID);
|
||||||
|
@ -2462,7 +2565,7 @@ void CEditor::DoQuadEnvPoint(const CQuad *pQuad, int QIndex, int PIndex)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_SelectedEnvelopePoint = -1;
|
DeselectEnvPoints();
|
||||||
m_SelectedQuadEnvelope = -1;
|
m_SelectedQuadEnvelope = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5735,6 +5838,15 @@ void CEditor::RemoveTimeOffsetEnvelope(CEnvelope *pEnvelope)
|
||||||
m_OffsetEnvelopeX += fxt2f(TimeOffset) / m_ZoomEnvelopeX.GetZoom();
|
m_OffsetEnvelopeX += fxt2f(TimeOffset) / m_ZoomEnvelopeX.GetZoom();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static float ClampDelta(float Val, float Delta, float Min, float Max)
|
||||||
|
{
|
||||||
|
if(Val + Delta <= Min)
|
||||||
|
return Min - Val;
|
||||||
|
if(Val + Delta >= Max)
|
||||||
|
return Max - Val;
|
||||||
|
return Delta;
|
||||||
|
}
|
||||||
|
|
||||||
void CEditor::RenderEnvelopeEditor(CUIRect View)
|
void CEditor::RenderEnvelopeEditor(CUIRect View)
|
||||||
{
|
{
|
||||||
if(m_SelectedEnvelope < 0)
|
if(m_SelectedEnvelope < 0)
|
||||||
|
@ -5749,13 +5861,17 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
OP_NONE,
|
OP_NONE,
|
||||||
|
OP_SELECT,
|
||||||
OP_DRAG_POINT,
|
OP_DRAG_POINT,
|
||||||
OP_DRAG_POINT_X,
|
OP_DRAG_POINT_X,
|
||||||
OP_DRAG_POINT_Y
|
OP_DRAG_POINT_Y,
|
||||||
|
OP_CONTEXT_MENU
|
||||||
};
|
};
|
||||||
static int s_Operation = OP_NONE;
|
static int s_Operation = OP_NONE;
|
||||||
static float s_AccurateDragValueX = 0.0f;
|
static std::vector<float> s_vAccurateDragValuesX = {};
|
||||||
static float s_AccurateDragValueY = 0.0f;
|
static std::vector<float> s_vAccurateDragValuesY = {};
|
||||||
|
static float s_MouseXStart = 0.0f;
|
||||||
|
static float s_MouseYStart = 0.0f;
|
||||||
|
|
||||||
CUIRect ToolBar, CurveBar, ColorBar, DragBar;
|
CUIRect ToolBar, CurveBar, ColorBar, DragBar;
|
||||||
View.HSplitTop(30.0f, &DragBar, nullptr);
|
View.HSplitTop(30.0f, &DragBar, nullptr);
|
||||||
|
@ -6001,7 +6117,7 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
||||||
if(UI()->HotItem() == &s_EnvelopeEditorID)
|
if(UI()->HotItem() == &s_EnvelopeEditorID)
|
||||||
{
|
{
|
||||||
// do stuff
|
// do stuff
|
||||||
if(UI()->MouseButtonClicked(1))
|
if(UI()->MouseButton(0) && Input()->MouseDoubleClick())
|
||||||
{
|
{
|
||||||
// add point
|
// add point
|
||||||
float Time = ScreenToEnvelopeX(View, UI()->MouseX());
|
float Time = ScreenToEnvelopeX(View, UI()->MouseX());
|
||||||
|
@ -6039,15 +6155,12 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ShowEnvelopePreview = SHOWENV_SELECTED;
|
m_ShowEnvelopePreview = SHOWENV_SELECTED;
|
||||||
m_pTooltip = "Press right mouse button to create a new point. Use shift to change the zoom axis.";
|
m_pTooltip = "Double-click to create a new point. Use shift to change the zoom axis.";
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateZoomEnvelopeX(View);
|
UpdateZoomEnvelopeX(View);
|
||||||
UpdateZoomEnvelopeY(View);
|
UpdateZoomEnvelopeY(View);
|
||||||
|
|
||||||
// keep track of selected point to handle value/time text input
|
|
||||||
static const void *s_pSelectedPoint = nullptr;
|
|
||||||
|
|
||||||
// render tangents for bezier curves
|
// render tangents for bezier curves
|
||||||
{
|
{
|
||||||
UI()->ClipEnable(&View);
|
UI()->ClipEnable(&View);
|
||||||
|
@ -6069,7 +6182,7 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
||||||
float TangentX = EnvelopeToScreenX(View, fxt2f(pEnvelope->m_vPoints[i].m_Time + pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c]));
|
float TangentX = EnvelopeToScreenX(View, fxt2f(pEnvelope->m_vPoints[i].m_Time + pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c]));
|
||||||
float TangentY = EnvelopeToScreenY(View, fx2f(pEnvelope->m_vPoints[i].m_aValues[c] + pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaY[c]));
|
float TangentY = EnvelopeToScreenY(View, fx2f(pEnvelope->m_vPoints[i].m_aValues[c] + pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaY[c]));
|
||||||
|
|
||||||
if(s_pSelectedPoint == &pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c] || (m_SelectedQuadEnvelope == m_SelectedEnvelope && m_SelectedEnvelopePoint == i))
|
if(IsTangentOutPointSelected(i, c))
|
||||||
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.4f);
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.4f);
|
||||||
else
|
else
|
||||||
Graphics()->SetColor(aColors[c].r, aColors[c].g, aColors[c].b, 0.4f);
|
Graphics()->SetColor(aColors[c].r, aColors[c].g, aColors[c].b, 0.4f);
|
||||||
|
@ -6084,7 +6197,7 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
||||||
float TangentX = EnvelopeToScreenX(View, fxt2f(pEnvelope->m_vPoints[i].m_Time + pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX[c]));
|
float TangentX = EnvelopeToScreenX(View, fxt2f(pEnvelope->m_vPoints[i].m_Time + pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX[c]));
|
||||||
float TangentY = EnvelopeToScreenY(View, fx2f(pEnvelope->m_vPoints[i].m_aValues[c] + pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaY[c]));
|
float TangentY = EnvelopeToScreenY(View, fx2f(pEnvelope->m_vPoints[i].m_aValues[c] + pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaY[c]));
|
||||||
|
|
||||||
if(s_pSelectedPoint == &pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX[c] || (m_SelectedQuadEnvelope == m_SelectedEnvelope && m_SelectedEnvelopePoint == i))
|
if(IsTangentInPointSelected(i, c))
|
||||||
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.4f);
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.4f);
|
||||||
else
|
else
|
||||||
Graphics()->SetColor(aColors[c].r, aColors[c].g, aColors[c].b, 0.4f);
|
Graphics()->SetColor(aColors[c].r, aColors[c].g, aColors[c].b, 0.4f);
|
||||||
|
@ -6214,18 +6327,9 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
||||||
}
|
}
|
||||||
|
|
||||||
// render handles
|
// render handles
|
||||||
|
|
||||||
static CLineInputNumber s_CurValueInput;
|
|
||||||
static CLineInputNumber s_CurTimeInput;
|
|
||||||
|
|
||||||
if(CurrentEnvelopeSwitched)
|
if(CurrentEnvelopeSwitched)
|
||||||
{
|
{
|
||||||
s_pSelectedPoint = nullptr;
|
DeselectEnvPoints();
|
||||||
|
|
||||||
// update displayed text
|
|
||||||
s_CurValueInput.SetFloat(0.0f);
|
|
||||||
s_CurTimeInput.SetFloat(0.0f);
|
|
||||||
|
|
||||||
m_ResetZoomEnvelope = true;
|
m_ResetZoomEnvelope = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6255,87 +6359,146 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
||||||
if(UI()->MouseInside(&Final) && UI()->MouseInside(&View))
|
if(UI()->MouseInside(&Final) && UI()->MouseInside(&View))
|
||||||
UI()->SetHotItem(pID);
|
UI()->SetHotItem(pID);
|
||||||
|
|
||||||
float ColorMod = 1.0f;
|
if(IsEnvPointSelected(i, c))
|
||||||
|
{
|
||||||
|
Graphics()->SetColor(1, 1, 1, 1);
|
||||||
|
CUIRect Background = {
|
||||||
|
Final.x - 0.2f * Final.w,
|
||||||
|
Final.y - 0.2f * Final.h,
|
||||||
|
Final.w * 1.4f,
|
||||||
|
Final.h * 1.4f};
|
||||||
|
IGraphics::CQuadItem QuadItem(Background.x, Background.y, Background.w, Background.h);
|
||||||
|
Graphics()->QuadsDrawTL(&QuadItem, 1);
|
||||||
|
}
|
||||||
|
|
||||||
if(UI()->CheckActiveItem(pID))
|
if(UI()->CheckActiveItem(pID))
|
||||||
{
|
{
|
||||||
if(!UI()->MouseButton(0))
|
m_ShowEnvelopePreview = SHOWENV_SELECTED;
|
||||||
|
|
||||||
|
if(s_Operation == OP_SELECT)
|
||||||
{
|
{
|
||||||
m_SelectedQuadEnvelope = -1;
|
float dx = s_MouseXStart - UI()->MouseX();
|
||||||
m_SelectedEnvelopePoint = -1;
|
float dy = s_MouseYStart - UI()->MouseY();
|
||||||
|
|
||||||
s_Operation = OP_NONE;
|
if(dx * dx + dy * dy > 20.0f)
|
||||||
|
{
|
||||||
|
s_Operation = OP_DRAG_POINT;
|
||||||
|
|
||||||
UI()->SetActiveItem(nullptr);
|
if(!IsEnvPointSelected(i, c))
|
||||||
|
SelectEnvPoint(i, c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if(s_Operation == OP_DRAG_POINT || s_Operation == OP_DRAG_POINT_X || s_Operation == OP_DRAG_POINT_Y)
|
||||||
{
|
{
|
||||||
if(Input()->ShiftIsPressed())
|
if(Input()->ShiftIsPressed())
|
||||||
{
|
{
|
||||||
if(s_Operation == OP_NONE || s_Operation == OP_DRAG_POINT_Y)
|
if(s_Operation == OP_DRAG_POINT || s_Operation == OP_DRAG_POINT_Y)
|
||||||
{
|
{
|
||||||
s_Operation = OP_DRAG_POINT_X;
|
s_Operation = OP_DRAG_POINT_X;
|
||||||
s_AccurateDragValueX = pEnvelope->m_vPoints[i].m_Time;
|
s_vAccurateDragValuesX.clear();
|
||||||
|
for(auto [SelectedIndex, _] : m_vSelectedEnvelopePoints)
|
||||||
|
s_vAccurateDragValuesX.push_back(pEnvelope->m_vPoints[SelectedIndex].m_Time);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
float DeltaX = ScreenToEnvelopeDX(View, UI()->MouseDeltaX()) * (Input()->ModifierIsPressed() ? 50.0f : 1000.0f);
|
float DeltaX = ScreenToEnvelopeDX(View, UI()->MouseDeltaX()) * (Input()->ModifierIsPressed() ? 50.0f : 1000.0f);
|
||||||
s_AccurateDragValueX += DeltaX;
|
|
||||||
|
|
||||||
pEnvelope->m_vPoints[i].m_Time = std::round(s_AccurateDragValueX);
|
for(size_t k = 0; k < m_vSelectedEnvelopePoints.size(); k++)
|
||||||
if(i == 0 && pEnvelope->m_vPoints[i].m_Time != 0)
|
|
||||||
{
|
{
|
||||||
RemoveTimeOffsetEnvelope(pEnvelope);
|
int SelectedIndex = m_vSelectedEnvelopePoints[k].first;
|
||||||
s_AccurateDragValueX = 0.0f;
|
int BoundLow = f2fxt(ScreenToEnvelopeX(View, View.x));
|
||||||
}
|
int BoundHigh = f2fxt(ScreenToEnvelopeX(View, View.x + View.w));
|
||||||
if(i != 0 && pEnvelope->m_vPoints[i].m_Time < pEnvelope->m_vPoints[i - 1].m_Time)
|
for(int j = 0; j < SelectedIndex; j++)
|
||||||
{
|
{
|
||||||
pEnvelope->m_vPoints[i].m_Time = pEnvelope->m_vPoints[i - 1].m_Time + 1;
|
if(!IsEnvPointSelected(j))
|
||||||
s_AccurateDragValueX = pEnvelope->m_vPoints[i - 1].m_Time + 1;
|
BoundLow = maximum(pEnvelope->m_vPoints[j].m_Time + 1, BoundLow);
|
||||||
}
|
}
|
||||||
if(i < pEnvelope->m_vPoints.size() - 1 && pEnvelope->m_vPoints[i].m_Time > pEnvelope->m_vPoints[i + 1].m_Time)
|
for(int j = SelectedIndex + 1; j < (int)pEnvelope->m_vPoints.size(); j++)
|
||||||
{
|
{
|
||||||
pEnvelope->m_vPoints[i].m_Time = pEnvelope->m_vPoints[i + 1].m_Time - 1;
|
if(!IsEnvPointSelected(j))
|
||||||
s_AccurateDragValueX = pEnvelope->m_vPoints[i + 1].m_Time - 1;
|
BoundHigh = minimum(pEnvelope->m_vPoints[j].m_Time - 1, BoundHigh);
|
||||||
}
|
}
|
||||||
|
|
||||||
pEnvelope->m_vPoints[i].m_Time = clamp(pEnvelope->m_vPoints[i].m_Time, f2fxt(ScreenToEnvelopeX(View, View.x)), f2fxt(ScreenToEnvelopeX(View, View.x + View.w)));
|
DeltaX = ClampDelta(s_vAccurateDragValuesX[k], DeltaX, BoundLow, BoundHigh);
|
||||||
s_AccurateDragValueX = clamp<float>(s_AccurateDragValueX, f2fxt(ScreenToEnvelopeX(View, View.x)), f2fxt(ScreenToEnvelopeX(View, View.x + View.w)));
|
}
|
||||||
|
for(size_t k = 0; k < m_vSelectedEnvelopePoints.size(); k++)
|
||||||
|
{
|
||||||
|
int SelectedIndex = m_vSelectedEnvelopePoints[k].first;
|
||||||
|
s_vAccurateDragValuesX[k] += DeltaX;
|
||||||
|
pEnvelope->m_vPoints[SelectedIndex].m_Time = std::round(s_vAccurateDragValuesX[k]);
|
||||||
|
}
|
||||||
|
for(size_t k = 0; k < m_vSelectedEnvelopePoints.size(); k++)
|
||||||
|
{
|
||||||
|
int SelectedIndex = m_vSelectedEnvelopePoints[k].first;
|
||||||
|
if(SelectedIndex == 0 && pEnvelope->m_vPoints[SelectedIndex].m_Time != 0)
|
||||||
|
{
|
||||||
|
RemoveTimeOffsetEnvelope(pEnvelope);
|
||||||
|
float Offset = s_vAccurateDragValuesX[k];
|
||||||
|
for(auto &Value : s_vAccurateDragValuesX)
|
||||||
|
Value -= Offset;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(s_Operation == OP_NONE || s_Operation == OP_DRAG_POINT_X)
|
if(s_Operation == OP_DRAG_POINT || s_Operation == OP_DRAG_POINT_X)
|
||||||
{
|
{
|
||||||
s_Operation = OP_DRAG_POINT_Y;
|
s_Operation = OP_DRAG_POINT_Y;
|
||||||
s_AccurateDragValueY = pEnvelope->m_vPoints[i].m_aValues[c];
|
s_vAccurateDragValuesY.clear();
|
||||||
|
for(auto [SelectedIndex, SelectedChannel] : m_vSelectedEnvelopePoints)
|
||||||
|
s_vAccurateDragValuesY.push_back(pEnvelope->m_vPoints[SelectedIndex].m_aValues[SelectedChannel]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
float DeltaY = ScreenToEnvelopeDY(View, UI()->MouseDeltaY()) * (Input()->ModifierIsPressed() ? 51.2f : 1024.0f);
|
float DeltaY = ScreenToEnvelopeDY(View, UI()->MouseDeltaY()) * (Input()->ModifierIsPressed() ? 51.2f : 1024.0f);
|
||||||
s_AccurateDragValueY -= DeltaY;
|
for(size_t k = 0; k < m_vSelectedEnvelopePoints.size(); k++)
|
||||||
|
{
|
||||||
|
auto [SelectedIndex, SelectedChannel] = m_vSelectedEnvelopePoints[k];
|
||||||
|
s_vAccurateDragValuesY[k] -= DeltaY;
|
||||||
|
pEnvelope->m_vPoints[SelectedIndex].m_aValues[SelectedChannel] = std::round(s_vAccurateDragValuesY[k]);
|
||||||
|
|
||||||
pEnvelope->m_vPoints[i].m_aValues[c] = std::round(s_AccurateDragValueY);
|
if(pEnvelope->GetChannels() == 4)
|
||||||
if(pEnvelope->GetChannels() == 4)
|
{
|
||||||
{
|
pEnvelope->m_vPoints[i].m_aValues[c] = clamp(pEnvelope->m_vPoints[i].m_aValues[c], 0, 1024);
|
||||||
pEnvelope->m_vPoints[i].m_aValues[c] = clamp(pEnvelope->m_vPoints[i].m_aValues[c], 0, 1024);
|
s_vAccurateDragValuesY[k] = clamp<float>(s_vAccurateDragValuesY[k], 0, 1024);
|
||||||
s_AccurateDragValueY = clamp<float>(s_AccurateDragValueY, 0, 1024);
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pEnvelope->m_vPoints[i].m_aValues[c] = clamp(pEnvelope->m_vPoints[i].m_aValues[c], f2fx(ScreenToEnvelopeY(View, View.y + View.h)), f2fx(ScreenToEnvelopeY(View, View.y)));
|
|
||||||
s_AccurateDragValueY = clamp<float>(s_AccurateDragValueY, f2fx(ScreenToEnvelopeY(View, View.y + View.h)), f2fx(ScreenToEnvelopeY(View, View.y)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(s_Operation == OP_CONTEXT_MENU)
|
||||||
|
{
|
||||||
|
if(!UI()->MouseButton(1))
|
||||||
|
{
|
||||||
|
if(m_vSelectedEnvelopePoints.size() == 1)
|
||||||
|
{
|
||||||
|
m_UpdateEnvPointInfo = true;
|
||||||
|
static SPopupMenuId s_PopupEnvPointId;
|
||||||
|
UI()->DoPopupMenu(&s_PopupEnvPointId, UI()->MouseX(), UI()->MouseY(), 150, 56, this, PopupEnvPoint);
|
||||||
|
}
|
||||||
|
UI()->SetActiveItem(nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(!UI()->MouseButton(0))
|
||||||
|
{
|
||||||
|
UI()->SetActiveItem(nullptr);
|
||||||
|
m_SelectedQuadEnvelope = -1;
|
||||||
|
|
||||||
|
if(s_Operation == OP_SELECT)
|
||||||
|
{
|
||||||
|
if(Input()->ShiftIsPressed())
|
||||||
|
ToggleEnvPoint(i, c);
|
||||||
|
else
|
||||||
|
SelectEnvPoint(i, c);
|
||||||
|
}
|
||||||
|
|
||||||
m_SelectedQuadEnvelope = m_SelectedEnvelope;
|
|
||||||
m_ShowEnvelopePreview = SHOWENV_SELECTED;
|
|
||||||
m_SelectedEnvelopePoint = i;
|
|
||||||
m_Map.OnModify();
|
m_Map.OnModify();
|
||||||
}
|
}
|
||||||
|
|
||||||
ColorMod = 100.0f;
|
|
||||||
Graphics()->SetColor(1, 1, 1, 1);
|
Graphics()->SetColor(1, 1, 1, 1);
|
||||||
}
|
}
|
||||||
else if(UI()->HotItem() == pID)
|
else if(UI()->HotItem() == pID)
|
||||||
|
@ -6343,65 +6506,35 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
||||||
if(UI()->MouseButton(0))
|
if(UI()->MouseButton(0))
|
||||||
{
|
{
|
||||||
UI()->SetActiveItem(pID);
|
UI()->SetActiveItem(pID);
|
||||||
s_pSelectedPoint = pID;
|
s_Operation = OP_SELECT;
|
||||||
|
m_SelectedQuadEnvelope = m_SelectedEnvelope;
|
||||||
|
|
||||||
|
s_MouseXStart = UI()->MouseX();
|
||||||
|
s_MouseYStart = UI()->MouseY();
|
||||||
}
|
}
|
||||||
|
else if(UI()->MouseButtonClicked(1))
|
||||||
// remove point
|
|
||||||
if(UI()->MouseButtonClicked(1) && pEnvelope->m_vPoints.size() > 2)
|
|
||||||
{
|
{
|
||||||
if(s_pSelectedPoint == pID)
|
if(Input()->ShiftIsPressed())
|
||||||
{
|
{
|
||||||
s_pSelectedPoint = nullptr;
|
pEnvelope->m_vPoints.erase(pEnvelope->m_vPoints.begin() + i);
|
||||||
|
m_Map.OnModify();
|
||||||
// update displayed text
|
}
|
||||||
s_CurValueInput.SetFloat(0.0f);
|
else
|
||||||
s_CurTimeInput.SetFloat(0.0f);
|
{
|
||||||
|
s_Operation = OP_CONTEXT_MENU;
|
||||||
|
SelectEnvPoint(i, c);
|
||||||
|
UI()->SetActiveItem(pID);
|
||||||
}
|
}
|
||||||
|
|
||||||
pEnvelope->m_vPoints.erase(pEnvelope->m_vPoints.begin() + i);
|
|
||||||
m_Map.OnModify();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ShowEnvelopePreview = SHOWENV_SELECTED;
|
m_ShowEnvelopePreview = SHOWENV_SELECTED;
|
||||||
ColorMod = 100.0f;
|
Graphics()->SetColor(1, 1, 1, 1);
|
||||||
Graphics()->SetColor(1, 0.75f, 0.75f, 1);
|
m_pTooltip = "Envelope point. Left mouse to drag. Hold ctrl to be more precise. Hold shift to alter time. Shift + right-click to delete.";
|
||||||
m_pTooltip = "Envelope point. Left mouse to drag. Hold ctrl to be more precise. Hold shift to alter time point instead of value. Right click to delete.";
|
ms_pUiGotContext = pID;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(pID == s_pSelectedPoint && UI()->ConsumeHotkey(CUI::HOTKEY_ENTER))
|
|
||||||
{
|
|
||||||
if(i != 0)
|
|
||||||
{
|
|
||||||
pEnvelope->m_vPoints[i].m_Time = s_CurTimeInput.GetFloat() * 1000.0f;
|
|
||||||
|
|
||||||
if(pEnvelope->m_vPoints[i].m_Time < pEnvelope->m_vPoints[i - 1].m_Time)
|
|
||||||
pEnvelope->m_vPoints[i].m_Time = pEnvelope->m_vPoints[i - 1].m_Time + 1;
|
|
||||||
if(i + 1 != pEnvelope->m_vPoints.size() && pEnvelope->m_vPoints[i].m_Time > pEnvelope->m_vPoints[i + 1].m_Time)
|
|
||||||
pEnvelope->m_vPoints[i].m_Time = pEnvelope->m_vPoints[i + 1].m_Time - 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
pEnvelope->m_vPoints[i].m_Time = 0.0f;
|
|
||||||
|
|
||||||
s_CurTimeInput.SetFloat(pEnvelope->m_vPoints[i].m_Time / 1000.0f);
|
|
||||||
|
|
||||||
pEnvelope->m_vPoints[i].m_aValues[c] = f2fx(s_CurValueInput.GetFloat());
|
|
||||||
s_CurValueInput.SetFloat(fx2f(pEnvelope->m_vPoints[i].m_aValues[c]));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(UI()->CheckActiveItem(pID))
|
|
||||||
{
|
|
||||||
const int CurrentTime = pEnvelope->m_vPoints[i].m_Time;
|
|
||||||
const int CurrentValue = pEnvelope->m_vPoints[i].m_aValues[c];
|
|
||||||
|
|
||||||
// update displayed text
|
|
||||||
s_CurValueInput.SetFloat(fx2f(CurrentValue));
|
|
||||||
s_CurTimeInput.SetFloat(CurrentTime / 1000.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pID == s_pSelectedPoint || (m_SelectedQuadEnvelope == m_SelectedEnvelope && m_SelectedEnvelopePoint == (int)i))
|
|
||||||
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
|
||||||
else
|
else
|
||||||
Graphics()->SetColor(aColors[c].r * ColorMod, aColors[c].g * ColorMod, aColors[c].b * ColorMod, 1.0f);
|
Graphics()->SetColor(aColors[c].r, aColors[c].g, aColors[c].b, 1.0f);
|
||||||
|
|
||||||
IGraphics::CQuadItem QuadItem(Final.x, Final.y, Final.w, Final.h);
|
IGraphics::CQuadItem QuadItem(Final.x, Final.y, Final.w, Final.h);
|
||||||
Graphics()->QuadsDrawTL(&QuadItem, 1);
|
Graphics()->QuadsDrawTL(&QuadItem, 1);
|
||||||
}
|
}
|
||||||
|
@ -6420,99 +6553,123 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
||||||
Final.h = 4.0f;
|
Final.h = 4.0f;
|
||||||
|
|
||||||
// handle logic
|
// handle logic
|
||||||
bool Updated = false;
|
|
||||||
const void *pID = &pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c];
|
const void *pID = &pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c];
|
||||||
|
|
||||||
float ColorMod = 1.0f;
|
if(IsTangentOutPointSelected(i, c))
|
||||||
|
{
|
||||||
|
Graphics()->SetColor(1, 1, 1, 1);
|
||||||
|
IGraphics::CFreeformItem FreeformItem(
|
||||||
|
Final.x + Final.w / 2.0f,
|
||||||
|
Final.y - 1,
|
||||||
|
Final.x + Final.w / 2.0f,
|
||||||
|
Final.y - 1,
|
||||||
|
Final.x + Final.w + 1,
|
||||||
|
Final.y + Final.h + 1,
|
||||||
|
Final.x - 1,
|
||||||
|
Final.y + Final.h + 1);
|
||||||
|
Graphics()->QuadsDrawFreeform(&FreeformItem, 1);
|
||||||
|
}
|
||||||
|
|
||||||
if(UI()->MouseInside(&Final) && UI()->MouseInside(&View))
|
if(UI()->MouseInside(&Final) && UI()->MouseInside(&View))
|
||||||
UI()->SetHotItem(pID);
|
UI()->SetHotItem(pID);
|
||||||
|
|
||||||
if(UI()->CheckActiveItem(pID))
|
if(UI()->CheckActiveItem(pID))
|
||||||
{
|
{
|
||||||
if(!UI()->MouseButton(0))
|
m_ShowEnvelopePreview = SHOWENV_SELECTED;
|
||||||
{
|
|
||||||
m_SelectedQuadEnvelope = -1;
|
|
||||||
m_SelectedEnvelopePoint = -1;
|
|
||||||
|
|
||||||
s_Operation = OP_NONE;
|
if(s_Operation == OP_SELECT)
|
||||||
|
|
||||||
UI()->SetActiveItem(nullptr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
if(s_Operation == OP_NONE)
|
float dx = s_MouseXStart - UI()->MouseX();
|
||||||
|
float dy = s_MouseYStart - UI()->MouseY();
|
||||||
|
|
||||||
|
if(dx * dx + dy * dy > 20.0f)
|
||||||
{
|
{
|
||||||
s_Operation = OP_DRAG_POINT;
|
s_Operation = OP_DRAG_POINT;
|
||||||
s_AccurateDragValueX = pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c];
|
|
||||||
s_AccurateDragValueY = pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaY[c];
|
s_vAccurateDragValuesX = {static_cast<float>(pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c])};
|
||||||
|
s_vAccurateDragValuesY = {static_cast<float>(pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaY[c])};
|
||||||
|
|
||||||
|
if(!IsTangentOutPointSelected(i, c))
|
||||||
|
SelectTangentOutPoint(i, c);
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
|
||||||
|
if(s_Operation == OP_DRAG_POINT)
|
||||||
|
{
|
||||||
|
float DeltaX = ScreenToEnvelopeDX(View, UI()->MouseDeltaX()) * (Input()->ModifierIsPressed() ? 50.0f : 1000.0f);
|
||||||
|
float DeltaY = ScreenToEnvelopeDY(View, UI()->MouseDeltaY()) * (Input()->ModifierIsPressed() ? 51.2f : 1024.0f);
|
||||||
|
s_vAccurateDragValuesX[0] += DeltaX;
|
||||||
|
s_vAccurateDragValuesY[0] -= DeltaY;
|
||||||
|
|
||||||
|
pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c] = std::round(s_vAccurateDragValuesX[0]);
|
||||||
|
pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaY[c] = std::round(s_vAccurateDragValuesY[0]);
|
||||||
|
|
||||||
|
// clamp time value
|
||||||
|
pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c] = clamp<int>(pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c], 0, f2fxt(ScreenToEnvelopeX(View, View.x + View.w)) - pEnvelope->m_vPoints[i].m_Time);
|
||||||
|
s_vAccurateDragValuesX[0] = clamp<float>(s_vAccurateDragValuesX[0], 0, f2fxt(ScreenToEnvelopeX(View, View.x + View.w)) - pEnvelope->m_vPoints[i].m_Time);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(s_Operation == OP_CONTEXT_MENU)
|
||||||
|
{
|
||||||
|
if(!UI()->MouseButton(1))
|
||||||
{
|
{
|
||||||
float DeltaX = ScreenToEnvelopeDX(View, UI()->MouseDeltaX()) * (Input()->ModifierIsPressed() ? 50.0f : 1000.0f);
|
if(IsTangentOutPointSelected(i, c))
|
||||||
float DeltaY = ScreenToEnvelopeDY(View, UI()->MouseDeltaY()) * (Input()->ModifierIsPressed() ? 51.2f : 1024.0f);
|
{
|
||||||
s_AccurateDragValueX += DeltaX;
|
m_UpdateEnvPointInfo = true;
|
||||||
s_AccurateDragValueY -= DeltaY;
|
static SPopupMenuId s_PopupEnvPointId;
|
||||||
|
UI()->DoPopupMenu(&s_PopupEnvPointId, UI()->MouseX(), UI()->MouseY(), 150, 56, this, PopupEnvPoint);
|
||||||
pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c] = std::round(s_AccurateDragValueX);
|
}
|
||||||
pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaY[c] = std::round(s_AccurateDragValueY);
|
UI()->SetActiveItem(nullptr);
|
||||||
|
|
||||||
// clamp time value
|
|
||||||
pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c] = clamp<int>(pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c], 0, f2fxt(ScreenToEnvelopeX(View, View.x + View.w)) - pEnvelope->m_vPoints[i].m_Time);
|
|
||||||
s_AccurateDragValueX = clamp<float>(s_AccurateDragValueX, 0, f2fxt(ScreenToEnvelopeX(View, View.x + View.w)) - pEnvelope->m_vPoints[i].m_Time);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else if(!UI()->MouseButton(0))
|
||||||
|
{
|
||||||
|
UI()->SetActiveItem(nullptr);
|
||||||
|
m_SelectedQuadEnvelope = -1;
|
||||||
|
|
||||||
|
if(s_Operation == OP_SELECT)
|
||||||
|
SelectTangentOutPoint(i, c);
|
||||||
|
|
||||||
m_SelectedQuadEnvelope = m_SelectedEnvelope;
|
|
||||||
m_ShowEnvelopePreview = SHOWENV_SELECTED;
|
|
||||||
m_SelectedEnvelopePoint = i;
|
|
||||||
m_Map.OnModify();
|
m_Map.OnModify();
|
||||||
}
|
}
|
||||||
ColorMod = 100.0f;
|
|
||||||
|
Graphics()->SetColor(1, 1, 1, 1);
|
||||||
}
|
}
|
||||||
else if(UI()->HotItem() == pID)
|
else if(UI()->HotItem() == pID)
|
||||||
{
|
{
|
||||||
if(UI()->MouseButton(0))
|
if(UI()->MouseButton(0))
|
||||||
{
|
{
|
||||||
UI()->SetActiveItem(pID);
|
UI()->SetActiveItem(pID);
|
||||||
s_pSelectedPoint = pID;
|
s_Operation = OP_SELECT;
|
||||||
}
|
m_SelectedQuadEnvelope = m_SelectedEnvelope;
|
||||||
|
|
||||||
// reset
|
s_MouseXStart = UI()->MouseX();
|
||||||
if(UI()->MouseButtonClicked(1))
|
s_MouseYStart = UI()->MouseY();
|
||||||
|
}
|
||||||
|
else if(UI()->MouseButtonClicked(1))
|
||||||
{
|
{
|
||||||
UI()->SetActiveItem(pID);
|
if(Input()->ShiftIsPressed())
|
||||||
s_pSelectedPoint = pID;
|
{
|
||||||
mem_zero(pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX, sizeof(pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX));
|
SelectTangentOutPoint(i, c);
|
||||||
mem_zero(pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaY, sizeof(pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaY));
|
pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c] = 0.0f;
|
||||||
m_Map.OnModify();
|
pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaY[c] = 0.0f;
|
||||||
Updated = true;
|
m_Map.OnModify();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s_Operation = OP_CONTEXT_MENU;
|
||||||
|
SelectTangentOutPoint(i, c);
|
||||||
|
UI()->SetActiveItem(pID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ShowEnvelopePreview = SHOWENV_SELECTED;
|
m_ShowEnvelopePreview = SHOWENV_SELECTED;
|
||||||
ColorMod = 100.0f;
|
Graphics()->SetColor(1, 1, 1, 1);
|
||||||
m_pTooltip = "Bezier out-tangent. Left mouse to drag. Hold ctrl to be more precise. Right click to reset.";
|
m_pTooltip = "Bezier out-tangent. Left mouse to drag. Hold ctrl to be more precise. Shift + right-click to reset.";
|
||||||
|
ms_pUiGotContext = pID;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(pID == s_pSelectedPoint && UI()->ConsumeHotkey(CUI::HOTKEY_ENTER))
|
|
||||||
{
|
|
||||||
pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c] = clamp<int>(s_CurTimeInput.GetFloat() * 1000.0f - pEnvelope->m_vPoints[i].m_Time, 0, pEnvelope->m_vPoints[i + 1].m_Time - pEnvelope->m_vPoints[i].m_Time);
|
|
||||||
pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaY[c] = f2fx(s_CurValueInput.GetFloat()) - pEnvelope->m_vPoints[i].m_aValues[c];
|
|
||||||
Updated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(UI()->CheckActiveItem(pID) || Updated)
|
|
||||||
{
|
|
||||||
const int CurrentTime = pEnvelope->m_vPoints[i].m_Time + pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c];
|
|
||||||
const int CurrentValue = pEnvelope->m_vPoints[i].m_aValues[c] + pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaY[c];
|
|
||||||
|
|
||||||
// update displayed text
|
|
||||||
s_CurValueInput.SetFloat(fx2f(CurrentValue));
|
|
||||||
s_CurTimeInput.SetFloat(CurrentTime / 1000.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pID == s_pSelectedPoint || (m_SelectedQuadEnvelope == m_SelectedEnvelope && m_SelectedEnvelopePoint == (int)i))
|
|
||||||
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.5f);
|
|
||||||
else
|
else
|
||||||
Graphics()->SetColor(aColors[c].r * ColorMod, aColors[c].g * ColorMod, aColors[c].b * ColorMod, 0.5f);
|
Graphics()->SetColor(aColors[c].r, aColors[c].g, aColors[c].b, 1.0f);
|
||||||
|
|
||||||
// draw triangle
|
// draw triangle
|
||||||
IGraphics::CFreeformItem FreeformItem(Final.x + Final.w / 2.0f, Final.y, Final.x + Final.w / 2.0f, Final.y, Final.x + Final.w, Final.y + Final.h, Final.x, Final.y + Final.h);
|
IGraphics::CFreeformItem FreeformItem(Final.x + Final.w / 2.0f, Final.y, Final.x + Final.w / 2.0f, Final.y, Final.x + Final.w, Final.y + Final.h, Final.x, Final.y + Final.h);
|
||||||
|
@ -6531,99 +6688,123 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
||||||
Final.h = 4.0f;
|
Final.h = 4.0f;
|
||||||
|
|
||||||
// handle logic
|
// handle logic
|
||||||
bool Updated = false;
|
|
||||||
const void *pID = &pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX[c];
|
const void *pID = &pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX[c];
|
||||||
|
|
||||||
float ColorMod = 1.0f;
|
if(IsTangentInPointSelected(i, c))
|
||||||
|
{
|
||||||
|
Graphics()->SetColor(1, 1, 1, 1);
|
||||||
|
IGraphics::CFreeformItem FreeformItem(
|
||||||
|
Final.x + Final.w / 2.0f,
|
||||||
|
Final.y - 1,
|
||||||
|
Final.x + Final.w / 2.0f,
|
||||||
|
Final.y - 1,
|
||||||
|
Final.x + Final.w + 1,
|
||||||
|
Final.y + Final.h + 1,
|
||||||
|
Final.x - 1,
|
||||||
|
Final.y + Final.h + 1);
|
||||||
|
Graphics()->QuadsDrawFreeform(&FreeformItem, 1);
|
||||||
|
}
|
||||||
|
|
||||||
if(UI()->MouseInside(&Final) && UI()->MouseInside(&View))
|
if(UI()->MouseInside(&Final) && UI()->MouseInside(&View))
|
||||||
UI()->SetHotItem(pID);
|
UI()->SetHotItem(pID);
|
||||||
|
|
||||||
if(UI()->CheckActiveItem(pID))
|
if(UI()->CheckActiveItem(pID))
|
||||||
{
|
{
|
||||||
if(!UI()->MouseButton(0))
|
m_ShowEnvelopePreview = SHOWENV_SELECTED;
|
||||||
{
|
|
||||||
m_SelectedQuadEnvelope = -1;
|
|
||||||
m_SelectedEnvelopePoint = -1;
|
|
||||||
|
|
||||||
s_Operation = OP_NONE;
|
if(s_Operation == OP_SELECT)
|
||||||
|
|
||||||
UI()->SetActiveItem(nullptr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
if(s_Operation == OP_NONE)
|
float dx = s_MouseXStart - UI()->MouseX();
|
||||||
|
float dy = s_MouseYStart - UI()->MouseY();
|
||||||
|
|
||||||
|
if(dx * dx + dy * dy > 20.0f)
|
||||||
{
|
{
|
||||||
s_Operation = OP_DRAG_POINT;
|
s_Operation = OP_DRAG_POINT;
|
||||||
s_AccurateDragValueX = pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX[c];
|
|
||||||
s_AccurateDragValueY = pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaY[c];
|
s_vAccurateDragValuesX = {static_cast<float>(pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX[c])};
|
||||||
|
s_vAccurateDragValuesY = {static_cast<float>(pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaY[c])};
|
||||||
|
|
||||||
|
if(!IsTangentInPointSelected(i, c))
|
||||||
|
SelectTangentInPoint(i, c);
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
|
||||||
|
if(s_Operation == OP_DRAG_POINT)
|
||||||
|
{
|
||||||
|
float DeltaX = ScreenToEnvelopeDX(View, UI()->MouseDeltaX()) * (Input()->ModifierIsPressed() ? 50.0f : 1000.0f);
|
||||||
|
float DeltaY = ScreenToEnvelopeDY(View, UI()->MouseDeltaY()) * (Input()->ModifierIsPressed() ? 51.2f : 1024.0f);
|
||||||
|
s_vAccurateDragValuesX[0] += DeltaX;
|
||||||
|
s_vAccurateDragValuesY[0] -= DeltaY;
|
||||||
|
|
||||||
|
pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX[c] = std::round(s_vAccurateDragValuesX[0]);
|
||||||
|
pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaY[c] = std::round(s_vAccurateDragValuesY[0]);
|
||||||
|
|
||||||
|
// clamp time value
|
||||||
|
pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX[c] = clamp(pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX[c], f2fxt(ScreenToEnvelopeX(View, View.x)) - pEnvelope->m_vPoints[i].m_Time, 0);
|
||||||
|
s_vAccurateDragValuesX[0] = clamp<float>(s_vAccurateDragValuesX[0], f2fxt(ScreenToEnvelopeX(View, View.x)) - pEnvelope->m_vPoints[i].m_Time, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(s_Operation == OP_CONTEXT_MENU)
|
||||||
|
{
|
||||||
|
if(!UI()->MouseButton(1))
|
||||||
{
|
{
|
||||||
float DeltaX = ScreenToEnvelopeDX(View, UI()->MouseDeltaX()) * (Input()->ModifierIsPressed() ? 50.0f : 1000.0f);
|
if(IsTangentInPointSelected(i, c))
|
||||||
float DeltaY = ScreenToEnvelopeDY(View, UI()->MouseDeltaY()) * (Input()->ModifierIsPressed() ? 51.2f : 1024.0f);
|
{
|
||||||
s_AccurateDragValueX += DeltaX;
|
m_UpdateEnvPointInfo = true;
|
||||||
s_AccurateDragValueY -= DeltaY;
|
static SPopupMenuId s_PopupEnvPointId;
|
||||||
|
UI()->DoPopupMenu(&s_PopupEnvPointId, UI()->MouseX(), UI()->MouseY(), 150, 56, this, PopupEnvPoint);
|
||||||
pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX[c] = std::round(s_AccurateDragValueX);
|
}
|
||||||
pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaY[c] = std::round(s_AccurateDragValueY);
|
UI()->SetActiveItem(nullptr);
|
||||||
|
|
||||||
// clamp time value
|
|
||||||
pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX[c] = clamp(pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX[c], f2fxt(ScreenToEnvelopeX(View, View.x)) - pEnvelope->m_vPoints[i].m_Time, 0);
|
|
||||||
s_AccurateDragValueX = clamp<float>(s_AccurateDragValueX, f2fxt(ScreenToEnvelopeX(View, View.x)) - pEnvelope->m_vPoints[i].m_Time, 0);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else if(!UI()->MouseButton(0))
|
||||||
|
{
|
||||||
|
UI()->SetActiveItem(nullptr);
|
||||||
|
m_SelectedQuadEnvelope = -1;
|
||||||
|
|
||||||
|
if(s_Operation == OP_SELECT)
|
||||||
|
SelectTangentInPoint(i, c);
|
||||||
|
|
||||||
m_SelectedQuadEnvelope = m_SelectedEnvelope;
|
|
||||||
m_ShowEnvelopePreview = SHOWENV_SELECTED;
|
|
||||||
m_SelectedEnvelopePoint = i;
|
|
||||||
m_Map.OnModify();
|
m_Map.OnModify();
|
||||||
}
|
}
|
||||||
ColorMod = 100.0f;
|
|
||||||
|
Graphics()->SetColor(1, 1, 1, 1);
|
||||||
}
|
}
|
||||||
else if(UI()->HotItem() == pID)
|
else if(UI()->HotItem() == pID)
|
||||||
{
|
{
|
||||||
if(UI()->MouseButton(0))
|
if(UI()->MouseButton(0))
|
||||||
{
|
{
|
||||||
UI()->SetActiveItem(pID);
|
UI()->SetActiveItem(pID);
|
||||||
s_pSelectedPoint = pID;
|
s_Operation = OP_SELECT;
|
||||||
}
|
m_SelectedQuadEnvelope = m_SelectedEnvelope;
|
||||||
|
|
||||||
// reset
|
s_MouseXStart = UI()->MouseX();
|
||||||
if(UI()->MouseButtonClicked(1))
|
s_MouseYStart = UI()->MouseY();
|
||||||
|
}
|
||||||
|
else if(UI()->MouseButtonClicked(1))
|
||||||
{
|
{
|
||||||
UI()->SetActiveItem(pID);
|
if(Input()->ShiftIsPressed())
|
||||||
s_pSelectedPoint = pID;
|
{
|
||||||
mem_zero(pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX, sizeof(pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX));
|
SelectTangentInPoint(i, c);
|
||||||
mem_zero(pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaY, sizeof(pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaY));
|
pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX[c] = 0.0f;
|
||||||
m_Map.OnModify();
|
pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaY[c] = 0.0f;
|
||||||
Updated = true;
|
m_Map.OnModify();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s_Operation = OP_CONTEXT_MENU;
|
||||||
|
SelectTangentInPoint(i, c);
|
||||||
|
UI()->SetActiveItem(pID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ShowEnvelopePreview = SHOWENV_SELECTED;
|
m_ShowEnvelopePreview = SHOWENV_SELECTED;
|
||||||
ColorMod = 100.0f;
|
Graphics()->SetColor(1, 1, 1, 1);
|
||||||
m_pTooltip = "Bezier in-tangent. Left mouse to drag. Hold ctrl to be more precise. Right click to reset.";
|
m_pTooltip = "Bezier in-tangent. Left mouse to drag. Hold ctrl to be more precise. Shift + right-click to reset.";
|
||||||
|
ms_pUiGotContext = pID;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(pID == s_pSelectedPoint && UI()->ConsumeHotkey(CUI::HOTKEY_ENTER))
|
|
||||||
{
|
|
||||||
pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX[c] = clamp<int>(s_CurTimeInput.GetFloat() * 1000.0f - pEnvelope->m_vPoints[i].m_Time, -pEnvelope->m_vPoints[i].m_Time, 0);
|
|
||||||
pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaY[c] = f2fx(s_CurValueInput.GetFloat()) - pEnvelope->m_vPoints[i].m_aValues[c];
|
|
||||||
Updated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(UI()->CheckActiveItem(pID) || Updated)
|
|
||||||
{
|
|
||||||
const int CurrentTime = pEnvelope->m_vPoints[i].m_Time + pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX[c];
|
|
||||||
const int CurrentValue = pEnvelope->m_vPoints[i].m_aValues[c] + pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaY[c];
|
|
||||||
|
|
||||||
// update displayed text
|
|
||||||
s_CurValueInput.SetFloat(fx2f(CurrentValue));
|
|
||||||
s_CurTimeInput.SetFloat(CurrentTime / 1000.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pID == s_pSelectedPoint || (m_SelectedQuadEnvelope == m_SelectedEnvelope && m_SelectedEnvelopePoint == (int)i))
|
|
||||||
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.5f);
|
|
||||||
else
|
else
|
||||||
Graphics()->SetColor(aColors[c].r * ColorMod, aColors[c].g * ColorMod, aColors[c].b * ColorMod, 0.5f);
|
Graphics()->SetColor(aColors[c].r, aColors[c].g, aColors[c].b, 1.0f);
|
||||||
|
|
||||||
// draw triangle
|
// draw triangle
|
||||||
IGraphics::CFreeformItem FreeformItem(Final.x + Final.w / 2.0f, Final.y, Final.x + Final.w / 2.0f, Final.y, Final.x + Final.w, Final.y + Final.h, Final.x, Final.y + Final.h);
|
IGraphics::CFreeformItem FreeformItem(Final.x + Final.w / 2.0f, Final.y, Final.x + Final.w / 2.0f, Final.y, Final.x + Final.w, Final.y + Final.h, Final.x, Final.y + Final.h);
|
||||||
|
@ -6635,31 +6816,6 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
||||||
Graphics()->QuadsEnd();
|
Graphics()->QuadsEnd();
|
||||||
UI()->ClipDisable();
|
UI()->ClipDisable();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(s_pSelectedPoint != nullptr)
|
|
||||||
{
|
|
||||||
CUIRect ToolBar1;
|
|
||||||
CUIRect ToolBar2;
|
|
||||||
ToolBar.VSplitMid(&ToolBar1, &ToolBar2);
|
|
||||||
ToolBar1.VSplitRight(3.0f, &ToolBar1, nullptr);
|
|
||||||
ToolBar2.VSplitRight(3.0f, &ToolBar2, nullptr);
|
|
||||||
if(ToolBar.w > ToolBar.h * 21)
|
|
||||||
{
|
|
||||||
CUIRect Label1;
|
|
||||||
CUIRect Label2;
|
|
||||||
|
|
||||||
ToolBar1.VSplitMid(&Label1, &ToolBar1);
|
|
||||||
ToolBar2.VSplitMid(&Label2, &ToolBar2);
|
|
||||||
Label1.VSplitRight(3.0f, &Label1, nullptr);
|
|
||||||
Label2.VSplitRight(3.0f, &Label2, nullptr);
|
|
||||||
|
|
||||||
UI()->DoLabel(&Label1, "Value:", 10.0f, TEXTALIGN_MR);
|
|
||||||
UI()->DoLabel(&Label2, "Time (in s):", 10.0f, TEXTALIGN_MR);
|
|
||||||
}
|
|
||||||
|
|
||||||
DoEditBox(&s_CurValueInput, &ToolBar1, 10.0f, IGraphics::CORNER_ALL, "The value of the selected element");
|
|
||||||
DoEditBox(&s_CurTimeInput, &ToolBar2, 10.0f, IGraphics::CORNER_ALL, "The time of the selected element");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -947,7 +947,10 @@ public:
|
||||||
|
|
||||||
m_ShowEnvelopePreview = SHOWENV_NONE;
|
m_ShowEnvelopePreview = SHOWENV_NONE;
|
||||||
m_SelectedQuadEnvelope = -1;
|
m_SelectedQuadEnvelope = -1;
|
||||||
m_SelectedEnvelopePoint = -1;
|
m_vSelectedEnvelopePoints = {};
|
||||||
|
m_UpdateEnvPointInfo = false;
|
||||||
|
m_SelectedTangentInPoint = std::pair(-1, -1);
|
||||||
|
m_SelectedTangentOutPoint = std::pair(-1, -1);
|
||||||
|
|
||||||
m_QuadKnifeActive = false;
|
m_QuadKnifeActive = false;
|
||||||
m_QuadKnifeCount = 0;
|
m_QuadKnifeCount = 0;
|
||||||
|
@ -1041,6 +1044,21 @@ public:
|
||||||
int FindSelectedQuadIndex(int Index) const;
|
int FindSelectedQuadIndex(int Index) const;
|
||||||
int FindSelectedQuadPointIndex(int QuadIndex) const;
|
int FindSelectedQuadPointIndex(int QuadIndex) const;
|
||||||
|
|
||||||
|
int FindEnvPointIndex(int Index, int Channel) const;
|
||||||
|
void SelectEnvPoint(int Index);
|
||||||
|
void SelectEnvPoint(int Index, int Channel);
|
||||||
|
void ToggleEnvPoint(int Index, int Channel);
|
||||||
|
bool IsEnvPointSelected(int Index, int Channel) const;
|
||||||
|
bool IsEnvPointSelected(int Index) const;
|
||||||
|
void DeselectEnvPoints();
|
||||||
|
void SelectTangentOutPoint(int Index, int Channel);
|
||||||
|
bool IsTangentOutPointSelected(int Index, int Channel) const;
|
||||||
|
void SelectTangentInPoint(int Index, int Channel);
|
||||||
|
bool IsTangentInPointSelected(int Index, int Channel) const;
|
||||||
|
bool IsTangentInSelected() const;
|
||||||
|
bool IsTangentOutSelected() const;
|
||||||
|
bool IsTangentSelected() const;
|
||||||
|
|
||||||
int DoProperties(CUIRect *pToolbox, CProperty *pProps, int *pIDs, int *pNewVal, ColorRGBA Color = ColorRGBA(1, 1, 1, 0.5f));
|
int DoProperties(CUIRect *pToolbox, CProperty *pProps, int *pIDs, int *pNewVal, ColorRGBA Color = ColorRGBA(1, 1, 1, 0.5f));
|
||||||
|
|
||||||
int m_Mode;
|
int m_Mode;
|
||||||
|
@ -1270,11 +1288,14 @@ public:
|
||||||
int m_SelectedGroup;
|
int m_SelectedGroup;
|
||||||
std::vector<std::pair<int, int>> m_vSelectedQuadPoints;
|
std::vector<std::pair<int, int>> m_vSelectedQuadPoints;
|
||||||
int m_SelectedEnvelope;
|
int m_SelectedEnvelope;
|
||||||
int m_SelectedEnvelopePoint;
|
std::vector<std::pair<int, int>> m_vSelectedEnvelopePoints;
|
||||||
int m_SelectedQuadEnvelope;
|
int m_SelectedQuadEnvelope;
|
||||||
int m_SelectedImage;
|
int m_SelectedImage;
|
||||||
int m_SelectedSound;
|
int m_SelectedSound;
|
||||||
int m_SelectedSource;
|
int m_SelectedSource;
|
||||||
|
std::pair<int, int> m_SelectedTangentInPoint;
|
||||||
|
std::pair<int, int> m_SelectedTangentOutPoint;
|
||||||
|
bool m_UpdateEnvPointInfo;
|
||||||
|
|
||||||
std::vector<CQuad> m_vCopyBuffer;
|
std::vector<CQuad> m_vCopyBuffer;
|
||||||
|
|
||||||
|
@ -1346,6 +1367,7 @@ public:
|
||||||
static CUI::EPopupMenuFunctionResult PopupQuad(void *pContext, CUIRect View, bool Active);
|
static CUI::EPopupMenuFunctionResult PopupQuad(void *pContext, CUIRect View, bool Active);
|
||||||
static CUI::EPopupMenuFunctionResult PopupSource(void *pContext, CUIRect View, bool Active);
|
static CUI::EPopupMenuFunctionResult PopupSource(void *pContext, CUIRect View, bool Active);
|
||||||
static CUI::EPopupMenuFunctionResult PopupPoint(void *pContext, CUIRect View, bool Active);
|
static CUI::EPopupMenuFunctionResult PopupPoint(void *pContext, CUIRect View, bool Active);
|
||||||
|
static CUI::EPopupMenuFunctionResult PopupEnvPoint(void *pContext, CUIRect View, bool Active);
|
||||||
static CUI::EPopupMenuFunctionResult PopupImage(void *pContext, CUIRect View, bool Active);
|
static CUI::EPopupMenuFunctionResult PopupImage(void *pContext, CUIRect View, bool Active);
|
||||||
static CUI::EPopupMenuFunctionResult PopupSound(void *pContext, CUIRect View, bool Active);
|
static CUI::EPopupMenuFunctionResult PopupSound(void *pContext, CUIRect View, bool Active);
|
||||||
static CUI::EPopupMenuFunctionResult PopupNewFolder(void *pContext, CUIRect View, bool Active);
|
static CUI::EPopupMenuFunctionResult PopupNewFolder(void *pContext, CUIRect View, bool Active);
|
||||||
|
|
|
@ -1285,6 +1285,150 @@ CUI::EPopupMenuFunctionResult CEditor::PopupPoint(void *pContext, CUIRect View,
|
||||||
return CUI::POPUP_KEEP_OPEN;
|
return CUI::POPUP_KEEP_OPEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CUI::EPopupMenuFunctionResult CEditor::PopupEnvPoint(void *pContext, CUIRect View, bool Active)
|
||||||
|
{
|
||||||
|
CEditor *pEditor = static_cast<CEditor *>(pContext);
|
||||||
|
const float RowHeight = 12.0f;
|
||||||
|
CUIRect Row, Label, EditBox;
|
||||||
|
|
||||||
|
pEditor->m_ShowEnvelopePreview = SHOWENV_SELECTED;
|
||||||
|
|
||||||
|
static CLineInputNumber s_CurValueInput;
|
||||||
|
static CLineInputNumber s_CurTimeInput;
|
||||||
|
|
||||||
|
CEnvelope *pEnvelope = pEditor->m_Map.m_vpEnvelopes[pEditor->m_SelectedEnvelope];
|
||||||
|
if(pEditor->m_UpdateEnvPointInfo)
|
||||||
|
{
|
||||||
|
pEditor->m_UpdateEnvPointInfo = false;
|
||||||
|
|
||||||
|
int CurrentTime;
|
||||||
|
int CurrentValue;
|
||||||
|
if(pEditor->IsTangentInSelected())
|
||||||
|
{
|
||||||
|
auto [SelectedIndex, SelectedChannel] = pEditor->m_SelectedTangentInPoint;
|
||||||
|
|
||||||
|
CurrentTime = pEnvelope->m_vPoints[SelectedIndex].m_Time + pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aInTangentDeltaX[SelectedChannel];
|
||||||
|
CurrentValue = pEnvelope->m_vPoints[SelectedIndex].m_aValues[SelectedChannel] + pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aInTangentDeltaY[SelectedChannel];
|
||||||
|
}
|
||||||
|
else if(pEditor->IsTangentOutSelected())
|
||||||
|
{
|
||||||
|
auto [SelectedIndex, SelectedChannel] = pEditor->m_SelectedTangentOutPoint;
|
||||||
|
|
||||||
|
CurrentTime = pEnvelope->m_vPoints[SelectedIndex].m_Time + pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aOutTangentDeltaX[SelectedChannel];
|
||||||
|
CurrentValue = pEnvelope->m_vPoints[SelectedIndex].m_aValues[SelectedChannel] + pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aOutTangentDeltaY[SelectedChannel];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto [SelectedIndex, SelectedChannel] = pEditor->m_vSelectedEnvelopePoints.front();
|
||||||
|
|
||||||
|
CurrentTime = pEnvelope->m_vPoints[SelectedIndex].m_Time;
|
||||||
|
CurrentValue = pEnvelope->m_vPoints[SelectedIndex].m_aValues[SelectedChannel];
|
||||||
|
}
|
||||||
|
|
||||||
|
// update displayed text
|
||||||
|
s_CurValueInput.SetFloat(fx2f(CurrentValue));
|
||||||
|
s_CurTimeInput.SetFloat(CurrentTime / 1000.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
View.HSplitTop(RowHeight, &Row, &View);
|
||||||
|
Row.VSplitLeft(60.0f, &Label, &Row);
|
||||||
|
Row.VSplitLeft(10.0f, nullptr, &EditBox);
|
||||||
|
pEditor->UI()->DoLabel(&Label, "Value:", RowHeight - 2.0f, TEXTALIGN_LEFT);
|
||||||
|
pEditor->DoEditBox(&s_CurValueInput, &EditBox, RowHeight - 2.0f, IGraphics::CORNER_ALL, "The value of the selected envelope point");
|
||||||
|
|
||||||
|
View.HMargin(4.0f, &View);
|
||||||
|
View.HSplitTop(RowHeight, &Row, &View);
|
||||||
|
Row.VSplitLeft(60.0f, &Label, &Row);
|
||||||
|
Row.VSplitLeft(10.0f, nullptr, &EditBox);
|
||||||
|
pEditor->UI()->DoLabel(&Label, "Time (in s):", RowHeight - 2.0f, TEXTALIGN_LEFT);
|
||||||
|
pEditor->DoEditBox(&s_CurTimeInput, &EditBox, RowHeight - 2.0f, IGraphics::CORNER_ALL, "The time of the selected envelope point");
|
||||||
|
|
||||||
|
if(pEditor->Input()->KeyIsPressed(KEY_RETURN) || pEditor->Input()->KeyIsPressed(KEY_KP_ENTER))
|
||||||
|
{
|
||||||
|
float CurrentTime = s_CurTimeInput.GetFloat();
|
||||||
|
float CurrentValue = s_CurValueInput.GetFloat();
|
||||||
|
if(pEditor->IsTangentInSelected())
|
||||||
|
{
|
||||||
|
auto [SelectedIndex, SelectedChannel] = pEditor->m_SelectedTangentInPoint;
|
||||||
|
|
||||||
|
pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aInTangentDeltaX[SelectedChannel] = minimum<int>(CurrentTime * 1000.0f - pEnvelope->m_vPoints[SelectedIndex].m_Time, 0);
|
||||||
|
CurrentTime = (pEnvelope->m_vPoints[SelectedIndex].m_Time + pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aInTangentDeltaX[SelectedChannel]) / 1000.0f;
|
||||||
|
|
||||||
|
pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aInTangentDeltaY[SelectedChannel] = f2fx(CurrentValue) - pEnvelope->m_vPoints[SelectedIndex].m_aValues[SelectedChannel];
|
||||||
|
}
|
||||||
|
else if(pEditor->IsTangentOutSelected())
|
||||||
|
{
|
||||||
|
auto [SelectedIndex, SelectedChannel] = pEditor->m_SelectedTangentOutPoint;
|
||||||
|
|
||||||
|
pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aOutTangentDeltaX[SelectedChannel] = maximum<int>(CurrentTime * 1000.0f - pEnvelope->m_vPoints[SelectedIndex].m_Time, 0);
|
||||||
|
CurrentTime = (pEnvelope->m_vPoints[SelectedIndex].m_Time + pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aOutTangentDeltaX[SelectedChannel]) / 1000.0f;
|
||||||
|
|
||||||
|
pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aOutTangentDeltaY[SelectedChannel] = f2fx(CurrentValue) - pEnvelope->m_vPoints[SelectedIndex].m_aValues[SelectedChannel];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto [SelectedIndex, SelectedChannel] = pEditor->m_vSelectedEnvelopePoints.front();
|
||||||
|
|
||||||
|
pEnvelope->m_vPoints[SelectedIndex].m_aValues[SelectedChannel] = f2fx(CurrentValue);
|
||||||
|
if(SelectedIndex != 0)
|
||||||
|
{
|
||||||
|
pEnvelope->m_vPoints[SelectedIndex].m_Time = CurrentTime * 1000.0f;
|
||||||
|
|
||||||
|
if(pEnvelope->m_vPoints[SelectedIndex].m_Time < pEnvelope->m_vPoints[SelectedIndex - 1].m_Time)
|
||||||
|
pEnvelope->m_vPoints[SelectedIndex].m_Time = pEnvelope->m_vPoints[SelectedIndex - 1].m_Time + 1;
|
||||||
|
if(static_cast<size_t>(SelectedIndex) + 1 != pEnvelope->m_vPoints.size() && pEnvelope->m_vPoints[SelectedIndex].m_Time > pEnvelope->m_vPoints[SelectedIndex + 1].m_Time)
|
||||||
|
pEnvelope->m_vPoints[SelectedIndex].m_Time = pEnvelope->m_vPoints[SelectedIndex + 1].m_Time - 1;
|
||||||
|
|
||||||
|
CurrentTime = pEnvelope->m_vPoints[SelectedIndex].m_Time / 1000.0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CurrentTime = 0.0f;
|
||||||
|
pEnvelope->m_vPoints[SelectedIndex].m_Time = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s_CurTimeInput.SetFloat(static_cast<int>(CurrentTime * 1000.0f) / 1000.0f);
|
||||||
|
s_CurValueInput.SetFloat(fx2f(f2fx(CurrentValue)));
|
||||||
|
|
||||||
|
pEditor->m_Map.OnModify();
|
||||||
|
}
|
||||||
|
|
||||||
|
View.HMargin(6.0f, &View);
|
||||||
|
View.HSplitTop(RowHeight, &Row, &View);
|
||||||
|
static int s_DeleteButtonID = 0;
|
||||||
|
const char *pButtonText = pEditor->IsTangentSelected() ? "Reset" : "Delete";
|
||||||
|
const char *pTooltip = pEditor->IsTangentSelected() ? "Reset tangent point to default value." : "Delete current envelope point in all channels.";
|
||||||
|
if(pEditor->DoButton_Editor(&s_DeleteButtonID, pButtonText, 0, &Row, 0, pTooltip))
|
||||||
|
{
|
||||||
|
if(pEditor->IsTangentInSelected())
|
||||||
|
{
|
||||||
|
auto [SelectedIndex, SelectedChannel] = pEditor->m_SelectedTangentInPoint;
|
||||||
|
|
||||||
|
pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aInTangentDeltaX[SelectedChannel] = 0.0f;
|
||||||
|
pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aInTangentDeltaY[SelectedChannel] = 0.0f;
|
||||||
|
}
|
||||||
|
else if(pEditor->IsTangentOutSelected())
|
||||||
|
{
|
||||||
|
auto [SelectedIndex, SelectedChannel] = pEditor->m_SelectedTangentOutPoint;
|
||||||
|
|
||||||
|
pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aOutTangentDeltaX[SelectedChannel] = 0.0f;
|
||||||
|
pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aOutTangentDeltaY[SelectedChannel] = 0.0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto [SelectedIndex, SelectedChannel] = pEditor->m_vSelectedEnvelopePoints.front();
|
||||||
|
|
||||||
|
pEnvelope->m_vPoints.erase(pEnvelope->m_vPoints.begin() + SelectedIndex);
|
||||||
|
}
|
||||||
|
pEditor->m_Map.OnModify();
|
||||||
|
|
||||||
|
return CUI::POPUP_CLOSE_CURRENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CUI::POPUP_KEEP_OPEN;
|
||||||
|
}
|
||||||
|
|
||||||
static const auto &&gs_ModifyIndexDeleted = [](int DeletedIndex) {
|
static const auto &&gs_ModifyIndexDeleted = [](int DeletedIndex) {
|
||||||
return [DeletedIndex](int *pIndex) {
|
return [DeletedIndex](int *pIndex) {
|
||||||
if(*pIndex == DeletedIndex)
|
if(*pIndex == DeletedIndex)
|
||||||
|
|
Loading…
Reference in a new issue