summaryrefslogtreecommitdiff
path: root/my_imgui_widgets.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'my_imgui_widgets.cpp')
-rw-r--r--my_imgui_widgets.cpp1081
1 files changed, 1081 insertions, 0 deletions
diff --git a/my_imgui_widgets.cpp b/my_imgui_widgets.cpp
new file mode 100644
index 0000000..5a0ab55
--- /dev/null
+++ b/my_imgui_widgets.cpp
@@ -0,0 +1,1081 @@
+#include "imgui/imgui.h"
+#include "imgui_ops.h"
+
+// 0 for timeline keyframe, 1 for graph keyframe, 2 for left graph handle, 3 for right graph handle
+internal void
+ImGui_KeyframeDragging(project_data *File, project_state *State, ui *UI, property_channel *Property, int32 b, ImGuiIO io, int16 Type)
+{
+ keyframe *Keyframe = KeyframeLookupMemory(Property, b);
+ if (ImGui::IsItemActive()) {
+
+ if (!Keyframe->IsSelected && ImGui::IsItemActivated())
+ {
+ if (!io.KeyShift) {
+ temp_keyframe_list Bad = GetSelectedKeyframes(File);
+ for (int i = 0; i < Bad.Amount; i++)
+ Bad.SelectedKeyframe[i]->IsSelected = false;
+ }
+ Keyframe->IsSelected = true;
+ State->RecentSelectionType = selection_keyframe;
+ }
+ if (ImGui::IsMouseDragging(ImGuiMouseButton_Left, -1))
+ {
+ ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
+ if (Type == 0 || Type == 1)
+ {
+ UI->DraggingKeyframeThreshold += io.MouseDelta.x;
+ if (abs(UI->DraggingKeyframeThreshold) >= UI->TimelineZoom) {
+ int16 Increment = UI->DraggingKeyframeThreshold/UI->TimelineZoom;
+ // temp_keyframe_list Bad = GetSelectedKeyframes(File);
+ // for (int b = 0; b < Bad.Amount; b++) {
+ // keyframe *SelectedKeyframe = Bad.SelectedKeyframe[b];
+ if (!(Keyframe->FrameNumber == 0 && Increment == -1)) {
+ Keyframe->FrameNumber += Increment;
+ CheckKeyframeSort(Property, Increment, b);
+ // SortAndCacheKeyframeAtFrame(SelectedKeyframe->FrameNumber, &File.LayerPTR[i]->Property[a], &Cache);
+ ClampSurroundingKeyframeHandles(Property, b);
+ }
+ // }
+ UI->DraggingKeyframeThreshold += -1*Increment*UI->TimelineZoom;
+ State->UpdateFrame = true;
+ State->UpdateKeyframes = true;
+ // Cache.Frame[File.CurrentFrame].Cached = false;
+ }
+ }
+ if (Type != 0)
+ {
+ if (Type == 1)
+ {
+ real32 IncrementsPerPixel = (Property->LocalMaxVal.f - Property->LocalMinVal.f)/Property->GraphLength;
+ Keyframe->Value.f -= io.MouseDelta.y*IncrementsPerPixel;
+ CalculatePropertyMinMax(Property);
+ }
+ if (Type == 2)
+ {
+ Keyframe->TangentLeft.x += io.MouseDelta.x/UI->TimelineZoom;
+ Keyframe->TangentLeft.y -= io.MouseDelta.y;
+ ClampKeyframeHandles(Property, b, 0);
+ }
+ if (Type == 3)
+ {
+ Keyframe->TangentRight.x += io.MouseDelta.x/UI->TimelineZoom;
+ Keyframe->TangentRight.y -= io.MouseDelta.y;
+ ClampKeyframeHandles(Property, b, 1);
+ }
+ State->UpdateFrame = true;
+ State->UpdateKeyframes = true;
+ }
+ }
+ }
+}
+
+internal void
+ImGui_PropertiesPanel(project_data *File, project_state *State, ui *UI, memory *Memory)
+{
+ if (State->MostRecentlySelectedLayer > -1) {
+ project_layer *Layer = File->Layer[State->MostRecentlySelectedLayer];
+ char buf[256];
+ sprintf(buf, "Properties: %s###Properties", Layer->Name);
+ ImGui::Begin(buf);
+ if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows))
+ UI->FocusedWindow = focus_properties;
+ ImGui::Text("Transform");
+ for (int h = 0; h < AmountOf(Layer->Property); h++) {
+ property_channel *Property = &Layer->Property[h];
+ ImGui::PushID(Property);
+ if (ImGui::Button("K"))
+ ManualKeyframeInsertF(Property, Memory, File->CurrentFrame, Property->CurrentValue.f);
+ ImGui::SameLine();
+ if (ImGui::DragScalar(Property->Name, ImGuiDataType_Float, &Property->CurrentValue.f,
+ Property->ScrubVal.f, &Property->MinVal.f, &Property->MaxVal.f, "%f"))
+ {
+ State->UpdateFrame = true;
+ }
+ ImGui::PopID();
+ }
+ for (int h = 0; h < Layer->NumberOfEffects; h++) {
+ effect *Effect = Layer->Effect[h];
+ ImGui::Button("V"); ImGui::SameLine();
+ ImGui::Text(Effect->Name);
+ for (int i = 0; i < Effect->NumberOfProperties; i++) {
+ property_channel *Property = &Effect->Property[i];
+ ImGui::PushID(Property);
+ if (Property->VarType == type_real)
+ ImGui::DragScalar(Property->Name, ImGuiDataType_Float, &Property->CurrentValue.f, 0.005f, &Property->MaxVal.f, &Property->MaxVal.f, "%f");
+ if (Property->VarType == type_color)
+ if (ImGui::ColorEdit4("color 1", &Property->CurrentValue.f, ImGuiColorEditFlags_Float))
+ State->UpdateFrame = true;
+ if (Property->VarType == type_blendmode)
+ {
+ uint32 *item_current_idx = (uint32 *)&Property->CurrentValue.blendmode; // Here we store our selection data as an index.
+ if (ImGui::BeginListBox("Blend mode"))
+ {
+ for (int n = 0; n < IM_ARRAYSIZE(BlendmodeNames); n++)
+ {
+ const bool is_selected = (*item_current_idx == n);
+ if (ImGui::Selectable(BlendmodeNames[n], is_selected)) {
+ *item_current_idx = n;
+ State->UpdateFrame = true;
+ }
+
+ // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
+ if (is_selected)
+ ImGui::SetItemDefaultFocus();
+ }
+ ImGui::EndListBox();
+ }
+ }
+ ImGui::PopID();
+ }
+ }
+ } else {
+ char buf[256];
+ sprintf(buf, "Properties: empty###Properties");
+ ImGui::Begin(buf);
+ if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows))
+ UI->FocusedWindow = focus_properties;
+ }
+ ImGui::End();
+}
+
+internal v2
+CalculateAnchorPointUV(project_layer *Layer, pixel_buffer *Buffer);
+
+internal void
+ImGui_Viewport(project_data File, project_state *State, ui *UI, pixel_buffer CompBuffer,
+ ImGuiIO io, GLuint textureID)
+{
+ ImGui::Begin("Viewport");
+
+ if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows))
+ UI->FocusedWindow = focus_viewport;
+
+ // Primarily taken from the Custom Rendering section of the demo
+ ImVec2 ViewportMin = ImGui::GetCursorScreenPos();
+ ImVec2 ViewportScale = ImGui::GetContentRegionAvail();
+ ViewportScale.y -= ImGui::GetFontSize();
+ if (ViewportScale.x < 50.0f) ViewportScale.x = 50.0f;
+ if (ViewportScale.y < 50.0f) ViewportScale.y = 50.0f;
+ ImVec2 ViewportMax = ImVec2(ViewportMin.x + ViewportScale.x, ViewportMin.y + ViewportScale.y);
+
+ if (UI->Initializing) {
+ UI->CompZoom = ImVec2(CompBuffer.Width, CompBuffer.Height);
+ UI->CompPos = ImVec2(ViewportMin.x + ((ViewportMax.x - ViewportMin.x)/2 - UI->CompZoom.x/2),
+ ViewportMin.y + ((ViewportMax.y - ViewportMin.y)/2 - UI->CompZoom.y/2));
+ }
+
+ ImDrawList* draw_list = ImGui::GetWindowDrawList();
+ draw_list->AddRectFilled(ViewportMin, ViewportMax, IM_COL32(50, 50, 50, 255));
+ draw_list->AddRect(ViewportMin, ViewportMax, IM_COL32(255, 255, 255, 255));
+
+ ImGui::InvisibleButton("canvas", ViewportScale, ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight);
+ bool32 IsHovered = ImGui::IsItemHovered();
+ bool32 IsActive = ImGui::IsItemActive();
+ bool32 IsActivated = ImGui::IsItemActivated();
+
+
+ if (IsHovered && IsActivated && ImGui::IsMouseDown(ImGuiMouseButton_Left)) {
+ v2 LocalMousePos = (V2(io.MousePos) - V2(ViewportMin));
+ v2 LocalCompPos = V2(UI->CompPos) - V2(ViewportMin);
+ v2 MouseScreenUV = LocalMousePos - LocalCompPos;
+ UI->TempZoomRatio = MouseScreenUV / V2(UI->CompZoom); // AKA actual normalized UV of comp
+ if (!ImGui::IsKeyDown(ImGuiKey_Z)) {
+ for (int i = File.NumberOfLayers - 1; i >= 0; i--) {
+ if (!io.KeyShift) DeselectAllLayers(&File, State);
+ if (TestPointInLayer(File.Layer[i], &CompBuffer, UI->TempZoomRatio) && !File.Layer[i]->IsSelected)
+ {
+ SelectLayer(File.Layer[i], State, i);
+ break;
+ }
+ }
+ }
+ }
+
+ if (IsActive && ImGui::IsMouseDragging(ImGuiMouseButton_Right, -1.0f))
+ {
+ UI->CompPos.x += io.MouseDelta.x;
+ UI->CompPos.y += io.MouseDelta.y;
+ }
+ if (IsActive && ImGui::IsMouseDragging(ImGuiMouseButton_Left, -1.0f) && ImGui::IsKeyDown(ImGuiKey_Z))
+ {
+ real32 Distance = io.MouseDelta.x + io.MouseDelta.y;
+ UI->CompZoom.x += (Distance)*(real32)CompBuffer.Width/CompBuffer.Height;
+ UI->CompZoom.y += (Distance);
+ UI->CompPos.x -= ((Distance)*(real32)CompBuffer.Width/CompBuffer.Height)*UI->TempZoomRatio.x;
+ UI->CompPos.y -= Distance*UI->TempZoomRatio.y;
+ }
+
+ draw_list->PushClipRect(ViewportMin, ViewportMax, true);
+ draw_list->AddImage((void *)(intptr_t)textureID, ImVec2(UI->CompPos.x, UI->CompPos.y),
+ ImVec2(UI->CompPos.x + UI->CompZoom.x, UI->CompPos.y + UI->CompZoom.y));
+
+ if (State->MostRecentlySelectedLayer > -1) {
+ project_layer *Layer = File.Layer[State->MostRecentlySelectedLayer];
+ ImVec2 AUV = ImVec2(Layer->x.CurrentValue.f / CompBuffer.Width, Layer->y.CurrentValue.f / CompBuffer.Height);
+ ImVec2 ScreenAP = ImVec2(UI->CompPos.x + AUV.x * UI->CompZoom.x, UI->CompPos.y + AUV.y * UI->CompZoom.y);
+ draw_list->AddNgon(ScreenAP, 20, ImGui::GetColorU32(ImGuiCol_ScrollbarGrab), 8, 10.0f);
+ }
+
+ draw_list->PopClipRect();
+
+ ImGui::Text("%.1f", 100.0f * (UI->CompZoom.x / CompBuffer.Width));
+ if (State->MsgTime > 0) {
+ ImGui::SameLine();
+ ImGui::SetCursorPosX((ViewportScale.x / 5)*4);
+ ImGui::Text(State->Msg);
+ State->MsgTime--;
+ }
+
+ ImGui::End();
+}
+
+// 1 for left, 2 for right, 3 for both
+internal bool32
+ImGui_SlidingLayer(project_layer *Layer, real32 *DraggingThreshold, real32 Delta, int16 TimelineZoom, int16 Side)
+{
+ bool32 Result = 0;
+ if (ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left, -1))
+ {
+ ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW);
+ *DraggingThreshold += Delta;
+ if (abs(*DraggingThreshold) >= TimelineZoom) {
+ int16 Increment = *DraggingThreshold/TimelineZoom;
+
+ // TODO(fox): Properly handle the start and end points wrapping.
+
+ if (!(Increment < 0 && Layer->StartFrame == 0 && Side & 1))
+ {
+ if (Side & 1)
+ Layer->StartFrame += Increment;
+ if (Side & 2)
+ Layer->EndFrame += Increment;
+ if (Side == 3) {
+ IncrementKeyframesInLayer(Layer, Increment);
+ if (Layer->SourceType == source_video) {
+ video_source *Source = (video_source *)Layer->RenderInfo;
+ Source->VideoFrameOffset += Increment;
+ }
+ }
+ }
+ *DraggingThreshold += -1*Increment*TimelineZoom;
+ }
+ Result = 1;
+ }
+ return Result;
+}
+
+internal void
+AddSource(project_data *File, memory *Memory, char * = NULL);
+
+internal void
+ImGui_File(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO io)
+{
+ ImGui::Begin("Files");
+ ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
+ if (ImGui::Button("Add source")) {
+ AddSource(File, Memory);
+ }
+ for (int16 i = 0; i < File->NumberOfSources; i++) {
+ ImGui::PushID(i);
+ ImGui::InputText("##source", File->Source[i], STRING_SIZE);
+ ImGui::SameLine();
+ if (ImGui::Button("Create Layer")) {
+ CreateLayerFromSource(File, State, Memory, File->Source[i]);
+ }
+ ImGui::PopID();
+ }
+#if DEBUG
+ for (int i = 0; i < Debug.WatchedProperties; i++) {
+ if (Debug.DebugPropertyType[i] == d_float) {
+ ImGui::Text("%s: %f", Debug.String[i], Debug.Val[i].f);
+ } else if (Debug.DebugPropertyType[i] == d_int) {
+ ImGui::Text("%s: %i", Debug.String[i], Debug.Val[i].i);
+ } else if (Debug.DebugPropertyType[i] == d_uint) {
+ ImGui::Text("%s: %u", Debug.String[i], Debug.Val[i].u);
+ }
+ }
+#endif
+ ImGui::End();
+}
+
+
+internal void
+ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO io)
+{
+ ImVec2 FramePadding = ImGui::GetStyle().FramePadding;
+ ImVec2 ItemSpacing = ImGui::GetStyle().ItemSpacing;
+ ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); // makes setting up the layout easier
+ ImGui::Begin("Timeline", NULL);
+
+ if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows))
+ UI->FocusedWindow = focus_timeline;
+
+ real32 FontHeight = ImGui::GetFontSize();
+
+ ImVec2 WindowSize = ImGui::GetWindowSize();
+ if (WindowSize.x < 50.0f) WindowSize.x = 50.0f; // prevent crashing if the window gets too small
+ if (WindowSize.y < 50.0f) WindowSize.y = 50.0f; // (still crashes)
+
+ ImVec2 WindowMinAbs = ImGui::GetWindowPos();
+ ImVec2 WindowMaxAbs = WindowMinAbs + WindowSize;
+
+ ImVec2 ButtonSize = ImVec2(FontHeight*2, FontHeight*2);
+
+ real32 TopbarHeight = FontHeight*4;
+ ImVec2 TopbarMax = ImVec2(WindowMaxAbs.x, WindowMinAbs.y + TopbarHeight);
+
+ ImVec2 TimelineBorderPadding = ImVec2(FontHeight, FontHeight);
+
+ ImVec2 TopbarSize = ImVec2(WindowSize.x, TopbarHeight);
+ ImVec2 TopbarButtonSize = ImVec2(TopbarHeight, TopbarHeight);
+
+ // NOTE(fox): StartingPos values include X and Y scroll, primarily used for
+ // the keyframes/layers. Absolute doesn't include scroll, primarily used
+ // for the clip rects.
+
+ ImVec2 SidebarSize = ImVec2(UI->TimelineSplit, WindowSize.y - TopbarHeight);
+ ImVec2 SidebarSizeWithBorder = SidebarSize - TimelineBorderPadding*2;
+ ImVec2 SidebarAbsolutePos = WindowMinAbs + ImVec2(0, TopbarSize.y) + TimelineBorderPadding;
+ ImVec2 SidebarStartingPos = SidebarAbsolutePos + ImVec2(0, UI->ScrollYOffset);
+
+ ImVec2 TimelineSize = ImVec2(WindowSize.x - SidebarSize.x, SidebarSize.y);
+ ImVec2 TimelineSizeWithBorder = TimelineSize - TimelineBorderPadding*2;
+ ImVec2 TimelineAbsolutePos = WindowMinAbs + ImVec2(SidebarSize.x, TopbarSize.y) + TimelineBorderPadding;
+ ImVec2 TimelineStartingPos = SidebarStartingPos + ImVec2(SidebarSize.x + UI->ScrollXOffset, 0);
+
+ // Timeline and sidebar size including the padding between them
+ ImVec2 TimelineFullSize = TimelineSizeWithBorder + SidebarSizeWithBorder + ImVec2(TimelineBorderPadding.x*2, 0);
+
+ ImVec2 KeyframeSize = ImVec2(FontHeight, FontHeight);
+
+ ImVec2 PlayheadPos = ImVec2(TimelineStartingPos.x + UI->TimelineZoom * File->CurrentFrame, WindowMinAbs.y + TopbarSize.y/2);
+
+ // NOTE(fox): The InvisibleButton hitbox that handles mouse inputs on the
+ // graph occludes the hitbox that handles box drag selection, so I'm using
+ // this struct to carry over the state from the former to the latter.
+ imgui_buttonstate AnimationCurves = {};
+
+
+ if (UI->Initializing) {
+ UI->TimelineZoom = TimelineSizeWithBorder.x / (File->NumberOfFrames + 1);
+ }
+
+ ImDrawList* draw_list = ImGui::GetWindowDrawList();
+ draw_list->AddRectFilled(WindowMinAbs, WindowMaxAbs,
+ IM_COL32(255, 255, 255, 50));
+ draw_list->AddRectFilled(WindowMinAbs, TopbarMax,
+ IM_COL32(255, 255, 255, 50));
+
+
+ //
+
+
+ ImGui::BeginChild("Topbar", TopbarSize, true, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar);
+ ImGui::Button("V", TopbarButtonSize); ImGui::SameLine();
+ ImGui::Button("V", TopbarButtonSize); ImGui::SameLine();
+ ImGui::Button("V", TopbarButtonSize); ImGui::SameLine();
+
+ ImGui::SetCursorScreenPos(PlayheadPos);
+ ImGui::Button("P", ButtonSize);
+ if (ImGui::IsItemActive()) {
+ if (ImGui::IsMouseDragging(ImGuiMouseButton_Left, -1))
+ {
+ UI->DraggingKeyframeThreshold += io.MouseDelta.x;
+ if (abs(UI->DraggingKeyframeThreshold) >= UI->TimelineZoom) {
+ int16 Increment = UI->DraggingKeyframeThreshold/UI->TimelineZoom;
+ if (File->CurrentFrame <= 0 && Increment < File->StartFrame)
+ File->CurrentFrame = 0;
+ else if (File->CurrentFrame >= File->EndFrame && Increment > File->EndFrame) {
+ File->CurrentFrame = File->EndFrame;
+ } else {
+ File->CurrentFrame += Increment;
+ }
+ State->UpdateFrame = true;
+ State->UpdateKeyframes = true;
+ UI->DraggingKeyframeThreshold += -1*Increment*UI->TimelineZoom;
+ }
+ }
+ }
+
+ ImGui::EndChild();
+
+ ///
+
+ ImGui::BeginChild("Sidebar", SidebarSize, true, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar);
+
+ ImGui::SetCursorScreenPos(SidebarStartingPos);
+
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ItemSpacing);
+
+ ImGui::PushClipRect(SidebarAbsolutePos, SidebarAbsolutePos + SidebarSizeWithBorder, true);
+
+ for (int i = File->NumberOfLayers - 1; i >= 0; i--)
+ {
+ project_layer *Layer = File->Layer[i];
+ ImGui::PushID(i);
+
+ ImGui::SetCursorScreenPos(ImVec2(SidebarStartingPos.x, ImGui::GetCursorScreenPos().y));
+
+ draw_list->PushClipRect(SidebarAbsolutePos, SidebarAbsolutePos + TimelineFullSize, true);
+ if (Layer->IsSelected) {
+ real32 Y = ImGui::GetCursorScreenPos().y;
+ draw_list->AddRectFilled(ImVec2(SidebarAbsolutePos.x, Y),
+ ImVec2(TimelineAbsolutePos.x + TimelineSize.x, Y + FontHeight + FramePadding.y*2),
+ IM_COL32(255, 255, 255, 50));
+ }
+ draw_list->PopClipRect();
+
+ ImGui::Button("V"); ImGui::SameLine();
+ ImGui::Button("I"); ImGui::SameLine();
+ ImGui::Text(Layer->Name); ImGui::SameLine();
+
+ ImGui::SetCursorScreenPos(ImVec2(SidebarStartingPos.x, ImGui::GetCursorScreenPos().y));
+ ImGui::Button("##mover", ImVec2(SidebarSizeWithBorder.x, FontHeight + FramePadding.y*2));
+
+ // Layer dragging interaction
+
+ if (ImGui::IsItemActive()) {
+ if (ImGui::IsItemActivated() && !Layer->IsSelected)
+ {
+ if (!io.KeyShift) DeselectAllLayers(File, State);
+ SelectLayer(Layer, State, i);
+ }
+ if (ImGui::IsMouseDragging(ImGuiMouseButton_Left, -1) )
+ {
+ ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW);
+ UI->DraggingLayerThreshold -= io.MouseDelta.y;
+ real32 Threshold = FontHeight + FramePadding.y*2;
+ if (abs(UI->DraggingLayerThreshold) >= Threshold)
+ {
+ int16 Increment = UI->DraggingLayerThreshold/abs(UI->DraggingLayerThreshold);
+ MoveLayersByIncrement(File, State, Increment);
+ UI->DraggingLayerThreshold += -1*Increment*Threshold;
+ State->UpdateFrame = true;
+ // Cache.Frame[File->CurrentFrame].Cached = false;
+ }
+ }
+ }
+
+ // Properties gap
+
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, ItemSpacing.y * UI->KeyframeSpacing));
+ for (int a = 0; a < AmountOf(Layer->Property); a++) {
+ if (Layer->Property[a].IsToggled)
+ {
+ property_channel *Property = &Layer->Property[a];
+ ImGui::PushID(Property);
+ // if (Property->IsSelected) {
+ // real32 Y = ImGui::GetCursorScreenPos().y;
+ // draw_list->AddRectFilled(ImVec2(SidebarAbsolutePos.x, Y),
+ // ImVec2(TimelineAbsolutePos.x, Y + FontHeight + FramePadding.y*2),
+ // IM_COL32(100, 0, 255, 50));
+ // }
+ ImGui::SetCursorScreenPos(ImVec2(SidebarStartingPos.x, ImGui::GetCursorScreenPos().y));
+ ImGui::Text(Property->Name);
+ real32 YInit = ImGui::GetCursorScreenPos().y;
+ ImGui::SameLine();
+ if (ImGui::Button("K"))
+ ManualKeyframeInsertF(Property, Memory, File->CurrentFrame, Property->CurrentValue.f);
+ ImGui::SameLine();
+ if (ImGui::Button("G")) {
+ SwitchBool(Property->IsGraphToggled);
+ // TODO(fox): Make system to init things like these automatically?
+ if (!Property->GraphLength) {
+ Property->GraphLength = 150;
+ Property->GraphYOffset = (Property->GraphWindowHeight - Property->GraphLength)/2;
+ }
+ }
+ ImGui::SetCursorScreenPos(ImVec2(ImGui::GetCursorScreenPos().x, YInit));
+ if (Property->IsGraphToggled)
+ {
+ ImGui::Dummy(ImVec2(5, Property->GraphWindowHeight));
+ }
+ ImGui::PopID();
+ }
+ }
+ ImGui::PopStyleVar();
+
+ ImGui::PopID();
+ }
+
+ ImGui::PopClipRect();
+
+ /// Split size adjuster
+
+ ImGui::SetCursorScreenPos(ImVec2(WindowMinAbs.x + UI->TimelineSplit - TimelineBorderPadding.x, TimelineAbsolutePos.y));
+ ImGui::InvisibleButton("##SplitMove", ImVec2(TimelineBorderPadding.x, SidebarSizeWithBorder.y), ImGuiButtonFlags_MouseButtonLeft);
+ if (ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left, -1))
+ {
+ UI->TimelineSplit += io.MouseDelta.x;
+ }
+
+
+ ImGui::PopStyleVar();
+
+ ImGui::EndChild();
+ ImGui::SameLine();
+
+ ///
+
+ ImGui::BeginChild("Timeline", TimelineSize, true, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar);
+
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, ItemSpacing.y));
+
+ ImGui::SetCursorScreenPos(TimelineStartingPos);
+
+ ImGui::PushClipRect(TimelineAbsolutePos, TimelineAbsolutePos + TimelineSizeWithBorder, true);
+ draw_list->PushClipRect(TimelineAbsolutePos, TimelineAbsolutePos + TimelineSizeWithBorder, true);
+
+ for (int i = File->NumberOfLayers - 1; i >= 0; i--)
+ {
+ // The actual layer bars
+
+ project_layer *Layer = File->Layer[i];
+ ImGui::PushID(i);
+ uint16 LayerTLSpan = Layer->EndFrame - Layer->StartFrame;
+
+ // if (Layer->SourceType == video) {
+ // video_source *Source = (video_source *)Layer->RenderInfo;
+ // real32 XMin = TimelineMinX + UI->TimelineZoom*Source->VideoFrameOffset;
+ // // real32 YMin = StartingCursorPosAbs.y + (FontHeight + FramePadding.y*2 + ItemSpacing.y)*i;
+ // real32 YMin = ImGui::GetCursorScreenPos().y;
+ // draw_list->AddRect(ImVec2(WindowMin.x, YMin),
+ // ImVec2(WindowMaxAbs.x, YMin + FontHeight + FramePadding.y*2),
+ // IM_COL32(255, 255, 255, 50), 2);
+ // }
+
+ ImGui::SetCursorScreenPos(ImVec2(TimelineStartingPos.x + UI->TimelineZoom*Layer->StartFrame, ImGui::GetCursorScreenPos().y));
+ ImGui::Button("##leftbound", ImVec2(0.5 * UI->TimelineZoom, 0)); ImGui::SameLine();
+ if (ImGui::IsItemHovered()) {
+ ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW);
+ }
+ ImGui_SlidingLayer(Layer, &UI->DraggingKeyframeThreshold, io.MouseDelta.x, UI->TimelineZoom, 1);
+
+ ImGui::Button("##layer", ImVec2((LayerTLSpan * UI->TimelineZoom), 0)); ImGui::SameLine();
+ if (ImGui::IsItemClicked()) {
+ if (!io.KeyShift) DeselectAllLayers(File, State);
+ SelectLayer(Layer, State, i);
+ }
+ if (ImGui_SlidingLayer(Layer, &UI->DraggingLayerThreshold, io.MouseDelta.x, UI->TimelineZoom, 3)) {
+ // TODO(fox): This will be removed once video caching is implemented.
+ UI->TemporaryUpdateOverride = true;
+ }
+
+ ImGui::Button("##rightbound", ImVec2(0.5 * UI->TimelineZoom, 0));
+
+ if (ImGui::IsItemHovered()) {
+ ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW);
+ }
+ ImGui_SlidingLayer(Layer, &UI->DraggingKeyframeThreshold, io.MouseDelta.x, UI->TimelineZoom, 2);
+
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, ItemSpacing.y * UI->KeyframeSpacing));
+ ImGui::SetCursorPosY(ImGui::GetCursorPos().y + (ItemSpacing.y * UI->KeyframeSpacing / 2));
+
+ for (int a = 0; a < AmountOf(Layer->Property); a++) {
+ if (Layer->Property[a].IsToggled)
+ {
+ real32 InitialY = ImGui::GetCursorScreenPos().y;
+ ImGui::NewLine();
+ real32 NextY = ImGui::GetCursorScreenPos().y;
+
+ property_channel *Property = &Layer->Property[a];
+ ImGui::PushID(Property);
+
+ for (int b = 0; b < Layer->Property[a].NumberOfTotalKeyframes; b++) {
+ keyframe *Keyframe = KeyframeLookupMemory(Property, b);
+ real32 KeyframeOrigin = TimelineStartingPos.x + UI->TimelineZoom*Keyframe->FrameNumber;
+ ImVec2 KeyframePosition = ImVec2(KeyframeOrigin - FontHeight/2, InitialY);
+
+ ImGui::PushID(Keyframe);
+
+ ImGui::SetCursorScreenPos(KeyframePosition);
+
+ // sadly ImGui::Selectable doesn't work here
+ if (Keyframe->IsSelected)
+ ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetColorU32(ImGuiCol_ButtonHovered));
+
+ ImGui::Button("##keyframe", ImVec2(FontHeight, FontHeight));
+ ImGui::SameLine();
+
+ if (Keyframe->IsSelected)
+ ImGui::PopStyleColor();
+
+ if (UI->BoxSelectActive && UI->BoxStart.y < NextY) {
+ if (IsRectTouching(UI->BoxStart, UI->BoxEnd, KeyframePosition, KeyframePosition + KeyframeSize)) {
+ SelectKeyframe(File, Layer, Property, Keyframe);
+ State->RecentSelectionType = selection_keyframe;
+ } else if (!io.KeyShift) {
+ Keyframe->IsSelected = false;
+ }
+ }
+
+ ImGui_KeyframeDragging(File, State, UI, Property, b, io, 0);
+
+
+ ImGui::PopID();
+ }
+
+ ImGui::SetCursorScreenPos(ImVec2(ImGui::GetCursorScreenPos().x, NextY));
+
+ if (Property->IsGraphToggled)
+ {
+ uint16 GraphWindowHeight = File->Layer[i]->Property[a].GraphWindowHeight;
+ real32 GraphWindowLocalYMin = ImGui::GetCursorPosY();
+ ImDrawList* draw_list = ImGui::GetWindowDrawList();
+ real32 ScreenY = NextY;
+ ImVec2 MinPos = ImVec2(TimelineAbsolutePos.x, ScreenY);
+ ImVec2 MaxPos = ImVec2(TimelineAbsolutePos.x + TimelineSizeWithBorder.x, ScreenY + GraphWindowHeight);
+ draw_list->AddRectFilled(MinPos, MaxPos,
+ IM_COL32(00, 00, 30, 65));
+
+ draw_list->PushClipRect(MinPos, MaxPos, true);
+
+ ImVec2 LeftPos[2];
+ ImVec2 MidPos[2];
+ ImVec2 RightPos[2];
+ ImU32 col = ImGui::GetColorU32(ImGuiCol_ScrollbarGrab);
+
+ for (int b = 0; b < Property->NumberOfTotalKeyframes; b++) {
+ keyframe *Keyframe = KeyframeLookupMemory(Property, b);
+ // int32 Index = KeyframeMemoryToIndex(Property, b);
+
+ ImGui::PushID(Keyframe);
+
+ real32 MinVal = Property->LocalMinVal.f;
+ real32 MaxVal = Property->LocalMaxVal.f;
+
+ // Normalized ratio between the smallest and largest value
+ real32 HandleYRatio = (Keyframe->Value.f - MaxVal) / (MaxVal - MinVal);
+ real32 HandleYRatio_L = (Keyframe->Value.f + Keyframe->TangentLeft.y - MaxVal) / (MaxVal - MinVal);
+ real32 HandleYRatio_R = (Keyframe->Value.f + Keyframe->TangentRight.y - MaxVal) / (MaxVal - MinVal);
+
+ real32 LocalHandlePosX = UI->TimelineZoom*Keyframe->FrameNumber;
+ real32 LocalHandlePosX_L = LocalHandlePosX + UI->TimelineZoom*Keyframe->TangentLeft.x;
+ real32 LocalHandlePosX_R = LocalHandlePosX + UI->TimelineZoom*Keyframe->TangentRight.x;
+
+ real32 HandlePosX = TimelineStartingPos.x + LocalHandlePosX - FontHeight*0.5;
+ real32 HandlePosX_L = TimelineStartingPos.x + LocalHandlePosX_L - FontHeight*0.5;
+ real32 HandlePosX_R = TimelineStartingPos.x + LocalHandlePosX_R - FontHeight*0.5;
+
+ real32 LocalHandlePosY = HandleYRatio * Property->GraphLength;
+ real32 LocalHandlePosY_L = HandleYRatio_L * Property->GraphLength;
+ real32 LocalHandlePosY_R = HandleYRatio_R * Property->GraphLength;
+
+ real32 HandlePosY = MinPos.y - LocalHandlePosY + Property->GraphYOffset;
+ real32 HandlePosY_L = MinPos.y - LocalHandlePosY_L + Property->GraphYOffset;
+ real32 HandlePosY_R = MinPos.y - LocalHandlePosY_R + Property->GraphYOffset;
+
+ ImVec2 HandlePos = ImVec2(HandlePosX, HandlePosY);
+ ImVec2 HandlePos_L = ImVec2(HandlePosX_L, HandlePosY_L);
+ ImVec2 HandlePos_R = ImVec2(HandlePosX_R, HandlePosY_R);
+
+ if (UI->BoxSelectActive && UI->BoxStart.y >= NextY) {
+ if (IsRectTouching(UI->BoxStart, UI->BoxEnd, HandlePos, HandlePos + KeyframeSize)) {
+ Keyframe->IsSelected = true;
+ State->RecentSelectionType = selection_keyframe;
+ } else if (!io.KeyShift) {
+ Keyframe->IsSelected = false;
+ }
+ }
+
+ ImGui::PushStyleColor(ImGuiCol_Button, col);
+
+ ImGui::SetCursorScreenPos(ImVec2(HandlePosX - FontHeight*1.5, HandlePosY - FontHeight*1.5));
+ ImGui::Text("%.02f", Keyframe->Value.f);
+
+ ImGui::SetCursorScreenPos(ImVec2(HandlePosX - FontHeight*1.0, HandlePosY - FontHeight*1.0));
+ ImGui::InvisibleButton("##keyframepoint", ImVec2(FontHeight*2, FontHeight*2), ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight);
+
+ draw_list->AddRect(ImVec2(HandlePosX - FontHeight*0.5, HandlePosY - FontHeight*0.5),
+ ImVec2(HandlePosX + FontHeight*0.5, HandlePosY + FontHeight*0.5),
+ ImGui::GetColorU32(ImGuiCol_ButtonHovered));
+
+ ImGui_KeyframeDragging(File, State, UI, Property, b, io, 1);
+
+ if (Keyframe->IsSelected && Keyframe->Type == bezier) {
+
+ ImGui::SetCursorScreenPos(ImVec2(HandlePosX_L, HandlePosY_L));
+ draw_list->AddCircle(ImVec2(HandlePosX_L, HandlePosY_L), 2, col, 16, 1);
+ ImGui::Button("##keyframehandleleft", ImVec2(FontHeight, FontHeight));
+
+ ImGui_KeyframeDragging(File, State, UI, Property, b, io, 2);
+
+ ImGui::SetCursorScreenPos(ImVec2(HandlePosX_R, HandlePosY_R));
+ ImGui::Button("##keyframehandleright", ImVec2(FontHeight, FontHeight));
+
+ ImGui_KeyframeDragging(File, State, UI, Property, b, io, 3);
+
+ draw_list->AddLine(MidPos[b & 1], RightPos[b & 1], col, 1.0f);
+ draw_list->AddLine(MidPos[b & 1], LeftPos[b & 1], col, 1.0f);
+ }
+
+ ImGui::PopStyleColor();
+
+ ImGui::PopID();
+ }
+
+ // TODO(fox): Reformat this so it's all done in one loop.
+
+ for (int b = 0; b < Property->NumberOfTotalKeyframes; b++) {
+ keyframe *Keyframe = KeyframeLookupIndex(Property, b);
+
+ real32 MinVal = Property->LocalMinVal.f;
+ real32 MaxVal = Property->LocalMaxVal.f;
+
+ real32 HandleYRatio = (Keyframe->Value.f - MaxVal) / (MaxVal - MinVal);
+ real32 HandleYRatio_L = (Keyframe->Value.f + Keyframe->TangentLeft.y - MaxVal) / (MaxVal - MinVal);
+ real32 HandleYRatio_R = (Keyframe->Value.f + Keyframe->TangentRight.y - MaxVal) / (MaxVal - MinVal);
+
+ real32 LocalHandlePosX = UI->TimelineZoom*Keyframe->FrameNumber;
+ real32 LocalHandlePosX_L = LocalHandlePosX + UI->TimelineZoom*Keyframe->TangentLeft.x;
+ real32 LocalHandlePosX_R = LocalHandlePosX + UI->TimelineZoom*Keyframe->TangentRight.x;
+
+ real32 HandlePosX = TimelineStartingPos.x + LocalHandlePosX - FontHeight*0.5;
+ real32 HandlePosX_L = TimelineStartingPos.x + LocalHandlePosX_L - FontHeight*0.5;
+ real32 HandlePosX_R = TimelineStartingPos.x + LocalHandlePosX_R - FontHeight*0.5;
+
+ real32 LocalHandlePosY = HandleYRatio * Property->GraphLength;
+ real32 LocalHandlePosY_L = HandleYRatio_L * Property->GraphLength;
+ real32 LocalHandlePosY_R = HandleYRatio_R * Property->GraphLength;
+
+ real32 HandlePosY = MinPos.y - LocalHandlePosY + Property->GraphYOffset;
+ real32 HandlePosY_L = MinPos.y - LocalHandlePosY_L + Property->GraphYOffset;
+ real32 HandlePosY_R = MinPos.y - LocalHandlePosY_R + Property->GraphYOffset;
+
+ ImVec2 HandlePos = ImVec2(HandlePosX, HandlePosY);
+ ImVec2 HandlePos_L = ImVec2(HandlePosX_L, HandlePosY_L);
+ ImVec2 HandlePos_R = ImVec2(HandlePosX_R, HandlePosY_R);
+
+ MidPos[b & 1] = HandlePos;
+ LeftPos[b & 1] = HandlePos_L;
+ RightPos[b & 1] = HandlePos_R;
+
+ if (b != 0)
+ {
+ if (b & 1) {
+ if (Keyframe->Type == linear)
+ draw_list->AddLine(MidPos[0], MidPos[1], col, 1.0f);
+ else if (Keyframe->Type == bezier)
+ draw_list->AddBezierCubic(MidPos[0], RightPos[0], LeftPos[1], MidPos[1], col, 1.0f, 8);
+ } else {
+ if (Keyframe->Type == linear)
+ draw_list->AddLine(MidPos[1], MidPos[0], col, 1.0f);
+ else if (Keyframe->Type == bezier)
+ draw_list->AddBezierCubic(MidPos[1], RightPos[1], LeftPos[0], MidPos[0], col, 1.0f, 8);
+ }
+ }
+ }
+ // Horiziontal value lines
+
+ // uint32 LineColor = IM_COL32(200, 200, 200, 40);
+ // for (int i = 0; i < 10; i++) {
+ // real32 YPos = MinPos.y + (UI->TimelineZoom/2 * i) + 5;
+ // ImVec2 Min = ImVec2(TimelineStartingPos.x, YPos);
+ // ImVec2 Max = ImVec2(TimelineStartingPos.x + TimelineSize.x, YPos);
+ // draw_list->AddLine(Min, Max, LineColor);
+ // }
+
+ draw_list->PopClipRect();
+
+ ImGui::SetCursorScreenPos(ImVec2(MinPos.x, MinPos.y));
+ ImGui::Button("##SplitMove", ImVec2(TimelineBorderPadding.x, SidebarSizeWithBorder.y));
+ if (ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left, -1))
+ {
+ UI->TimelineSplit += io.MouseDelta.x;
+ }
+
+ ImGui::SetCursorScreenPos(ImVec2(MinPos.x, MinPos.y));
+ ImGui::InvisibleButton("AnimationCurves", ImVec2(TimelineSize.x - 20, GraphWindowHeight), ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight);
+ // NOTE(fox): I'm reusing this struct for the other
+ // channels, so I'm OR'ing it. Also persists across layers.
+ AnimationCurves.IsItemHovered |= ImGui::IsItemHovered();
+ AnimationCurves.IsItemActive |= ImGui::IsItemActive();
+ AnimationCurves.IsItemActivated |= ImGui::IsItemActivated();
+ AnimationCurves.IsItemDeactivated |= ImGui::IsItemDeactivated();
+ AnimationCurves.LeftClick |= ImGui::IsMouseDown(ImGuiMouseButton_Left);
+ AnimationCurves.RightClick |= ImGui::IsMouseDown(ImGuiMouseButton_Right);
+
+ if (AnimationCurves.IsItemHovered && AnimationCurves.IsItemActivated &&
+ ImGui::IsMouseDown(ImGuiMouseButton_Right)) {
+ real32 LocalMousePos = io.MousePos.y - MinPos.y - Property->GraphYOffset;
+ UI->TempZoomRatioGraph = LocalMousePos / Property->GraphLength;
+ }
+ // DebugWatchVar("LocalMousePos", &LocalMousePos, d_float);
+
+ if (AnimationCurves.IsItemActive && ImGui::IsMouseDragging(ImGuiMouseButton_Right, -1))
+ {
+ Property->GraphLength += io.MouseDelta.x;
+ Property->GraphYOffset -= io.MouseDelta.x*UI->TempZoomRatioGraph;
+ Property->GraphYOffset += io.MouseDelta.y;
+ }
+ }
+ ImGui::PopID();
+ }
+ }
+
+ ImGui::SetCursorPosY(ImGui::GetCursorPos().y - (ItemSpacing.y * UI->KeyframeSpacing / 2));
+ ImGui::PopStyleVar();
+
+ ImGui::PopID();
+ }
+
+ // Timeline frame ticks
+
+ ImGui::SetCursorScreenPos(TimelineStartingPos);
+ if (UI->TimelineZoom > 10) {
+ for (float x = 0; x < File->NumberOfFrames + 2; x += 1) {
+ uint32 LineColor = IM_COL32(200, 200, 200, 40);
+ ImVec2 Min = ImVec2(TimelineStartingPos.x + UI->TimelineZoom * x, TimelineStartingPos.y);
+ ImVec2 Max = ImVec2(Min.x + 2, WindowMaxAbs.y);
+ if (x == File->CurrentFrame) continue;
+ draw_list->AddLine(Min, Max, LineColor);
+ }
+ }
+
+
+
+ draw_list->PopClipRect();
+ ImGui::PopClipRect();
+
+ // Playhead line
+
+ uint32 LineColor = IM_COL32(200, 200, 200, 200);
+ ImVec2 Min = PlayheadPos;
+ ImVec2 Max = ImVec2(Min.x + 2, Min.y + TimelineSizeWithBorder.y + TopbarSize.y/2);
+ draw_list->AddLine(Min, Max, LineColor);
+
+ ImGui::PopStyleVar();
+
+ // General timeline interaction
+
+ ImGui::SetCursorScreenPos(TimelineAbsolutePos);
+ ImGui::InvisibleButton("TimelineMoving", TimelineSizeWithBorder, ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight);
+ bool32 IsHovered = ImGui::IsItemHovered();
+ bool32 IsActive = ImGui::IsItemActive();
+ bool32 IsItemActivated = ImGui::IsItemActivated();
+ bool32 IsItemDeactivated = ImGui::IsItemDeactivated();
+ bool32 LeftClick = ImGui::IsMouseDown(ImGuiMouseButton_Left);
+ bool32 RightClick = ImGui::IsMouseDown(ImGuiMouseButton_Right);
+
+ if (IsActive || AnimationCurves.IsItemActive) {
+ if (LeftClick) {
+ if (io.KeyCtrl && IsActive) {
+ real32 LocalMousePos = ImGui::GetMousePos().x - TimelineStartingPos.x;
+ real32 ZoomRatio = LocalMousePos / UI->TimelineZoom;
+ File->CurrentFrame = (int32)(ZoomRatio + 0.5);
+ State->UpdateFrame = true;
+ State->UpdateKeyframes = true;
+ } else {
+ if (IsItemActivated || AnimationCurves.IsItemActivated)
+ {
+ if (!io.KeyShift) {
+ // DeselectAllKeyframes(&State);
+ // DeselectAllLayers(File, State);
+ }
+ UI->BoxStart = ImGui::GetMousePos();
+ UI->BoxSelectActive = true;
+ }
+ if (ImGui::IsMouseDragging(ImGuiMouseButton_Left, -1) )
+ {
+ UI->BoxEnd = ImGui::GetMousePos();
+ draw_list->AddRectFilled(UI->BoxStart, UI->BoxEnd,
+ IM_COL32(0, 0, 200, 50));
+ }
+ }
+ // Timeline zooming interaction
+ } else if (RightClick && IsActive) {
+ if (IsItemActivated)
+ {
+ real32 LocalMousePos = io.MousePos.x - WindowMinAbs.x - UI->TimelineSplit;
+ UI->TempZoomRatioTimeline = LocalMousePos / TimelineSize.x;
+ }
+ if (ImGui::IsMouseDragging(ImGuiMouseButton_Right, -1) )
+ {
+ UI->TimelineZoom += io.MouseDelta.x;
+ ImGui::SetScrollX(ImGui::GetScrollMaxX() * UI->TempZoomRatioTimeline);
+ }
+ }
+ }
+ if (IsItemDeactivated || AnimationCurves.IsItemDeactivated) {
+ UI->BoxStart = {0, 0};
+ UI->BoxEnd = {0, 0};
+ UI->BoxSelectActive = false;
+ }
+
+ ImGui::EndChild();
+
+ ImGui::PopStyleVar(2);
+
+ if (IsRectTouching(WindowMinAbs, WindowMaxAbs, io.MousePos, io.MousePos + 1)) {
+ if (io.KeyCtrl && io.MouseWheel) {
+ real32 ZoomAmount = io.MouseWheel*8;
+ real32 LocalMousePos = ImGui::GetMousePos().x - TimelineStartingPos.x;
+ real32 ZoomRatio = LocalMousePos / UI->TimelineZoom;
+ UI->TimelineZoom += ZoomAmount;
+ UI->ScrollXOffset -= ZoomAmount*ZoomRatio;
+ } else {
+ UI->ScrollXOffset += io.MouseWheelH*8;
+ UI->ScrollYOffset += io.MouseWheel*8;
+ }
+ }
+
+
+
+ ImGui::End();
+}
+
+
+internal void
+ImGui_ProcessInputs(project_data *File, project_state *State, pixel_buffer *CompBuffer, memory *Memory, ui *UI, ImGuiIO io)
+{
+ if (io.KeysData[ImGuiKey_Q].Down)
+ State->IsRunning = false;
+
+ if (ImGui::IsKeyPressed(ImGuiKey_D)) {
+ IncrementFrame(File, -1);
+ State->UpdateFrame = true;
+ State->UpdateKeyframes = true;
+ }
+
+ if (ImGui::IsKeyPressed(ImGuiKey_F)) {
+ IncrementFrame(File, 1);
+ State->UpdateFrame = true;
+ State->UpdateKeyframes = true;
+ }
+
+
+ if (ImGui::IsKeyPressed(ImGuiKey_Space)) {
+ SwitchBool(State->IsPlaying);
+ }
+
+ if (State->IsPlaying && !IsRendering) {
+ IncrementFrame(File, 1);
+ State->UpdateFrame = true;
+ State->UpdateKeyframes = true;
+ }
+
+ if (ImGui::IsKeyPressed(ImGuiKey_R) && State->NumberOfSelectedLayers)
+ TransformsInteract(File, State, UI, sliding_rotation);
+ if (ImGui::IsKeyPressed(ImGuiKey_S) && State->NumberOfSelectedLayers)
+ TransformsInteract(File, State, UI, sliding_scale);
+ if (ImGui::IsKeyPressed(ImGuiKey_G) && State->NumberOfSelectedLayers)
+ TransformsInteract(File, State, UI, sliding_position);
+ if (ImGui::IsKeyPressed(ImGuiKey_A) && State->NumberOfSelectedLayers)
+ TransformsInteract(File, State, UI, sliding_anchorpoint);
+
+ if (ImGui::IsKeyPressed(ImGuiKey_Delete))
+ {
+ switch (State->RecentSelectionType)
+ {
+ case selection_none:
+ {
+ } break;
+ case selection_layer:
+ {
+ } break;
+ case selection_effect:
+ {
+ } break;
+ case selection_keyframe:
+ {
+ DeleteSelectedKeyframes(File, Memory);
+ State->UpdateKeyframes = true;
+ State->UpdateFrame = true;
+ } break;
+ }
+ }
+
+#if DEBUG
+ if (ImGui::IsKeyPressed(ImGuiKey_E)) {
+ SwitchBool(AVXEnabled);
+ State->UpdateFrame = true;
+ }
+ if (ImGui::IsKeyPressed(ImGuiKey_M))
+ {
+ Debug.Markers[Debug.MarkerIndex] = File->CurrentFrame;
+ Debug.MarkerIndex++;
+ }
+#endif
+
+ bool32 Ended = ImGui::IsMouseDown(ImGuiMouseButton_Left);
+ if (State->IsInteracting) {
+ ImVec2 MouseIncrement = io.MouseDelta * (ImVec2(CompBuffer->Width, CompBuffer->Height) / UI->CompZoom);
+ switch (State->TransformsHotkeyInteract)
+ {
+ case sliding_position:
+ {
+ InteractProperty(0, File, State, Ended, MouseIncrement.x, Memory);
+ InteractProperty(1, File, State, Ended, MouseIncrement.y, Memory);
+ } break;
+ case sliding_anchorpoint:
+ {
+ InteractProperty(2, File, State, Ended, MouseIncrement.x, Memory);
+ InteractProperty(3, File, State, Ended, MouseIncrement.y, Memory);
+ } break;
+ case sliding_rotation:
+ {
+ InteractProperty(4, File, State, Ended, MouseIncrement.x / 10.0, Memory);
+ } break;
+ case sliding_scale:
+ {
+ InteractProperty(5, File, State, Ended, MouseIncrement.x / 200.0, Memory);
+ } break;
+ }
+ }
+
+
+ if (!ImGui::IsMouseDown(ImGuiMouseButton_Left)) {
+ UI->DraggingLayerThreshold = 0;
+ UI->DraggingTimelineThreshold = 0;
+ UI->DraggingKeyframeThreshold = 0;
+ }
+}
+
+
+global_variable char ImGuiPrefs[] = "[Window][DockSpaceViewport_11111111]"
+"\nSize=3153,1837"
+"\nCollapsed=0"
+"\n"
+"\n[Window][Debug##Default]"
+"\nPos=60,60"
+"\nSize=400,400"
+"\nCollapsed=0"
+"\n"
+"\n[Window][Viewport]"
+"\nPos=528,0"
+"\nSize=2121,1208"
+"\nCollapsed=0"
+"\nDockId=0x00000005,0"
+"\n"
+"\n[Window][###Properties]"
+"\nSize=526,1208"
+"\nCollapsed=0"
+"\nDockId=0x00000003,0"
+"\n"
+"\n[Window][Timeline]"
+"\nPos=0,1210"
+"\nSize=3153,627"
+"\nCollapsed=0"
+"\nDockId=0x00000002,0"
+"\n"
+"\n[Window][Dear ImGui Demo]"
+"\nPos=1881,692"
+"\nSize=550,680"
+"\nCollapsed=0"
+"\n"
+"\n[Window][Files]"
+"\nPos=2651,0"
+"\nSize=502,1208"
+"\nCollapsed=0"
+"\nDockId=0x00000006,0"
+"\n"
+"\n[Docking][Data]"
+"\nDockSpace ID=0x8B93E3BD Pos=0,0 Size=3153,1837 Split=Y Selected=0x13926F0B"
+"\n DockNode ID=0x00000001 Parent=0x8B93E3BD SizeRef=3200,1171 Split=X Selected=0x13926F0B"
+"\n DockNode ID=0x00000003 Parent=0x00000001 SizeRef=526,1171 Selected=0xDBB8CEFA"
+"\n DockNode ID=0x00000004 Parent=0x00000001 SizeRef=2672,1171 Split=X Selected=0x13926F0B"
+"\n DockNode ID=0x00000005 Parent=0x00000004 SizeRef=2115,1171 CentralNode=1 Selected=0x13926F0B"
+"\n DockNode ID=0x00000006 Parent=0x00000004 SizeRef=502,1171 Selected=0x86FA2F90"
+"\n DockNode ID=0x00000002 Parent=0x8B93E3BD SizeRef=3200,627 HiddenTabBar=1 Selected=0x0F18B61B"
+"\n";