Merge pull request #6872 from Marmare314/envelope_contextmenu

Multiple selection in envelope editor
This commit is contained in:
Robert Müller 2023-07-28 11:11:02 +00:00 committed by GitHub
commit 8b209f036e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 592 additions and 270 deletions

View file

@ -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");
}
} }
} }

View file

@ -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);

View file

@ -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)