Skip to content

Commit

Permalink
Timeline arrow key navigation
Browse files Browse the repository at this point in the history
Add inital support for left and right arrow key navigation in the
timeline. It was necessary to turn off the default navigation as it was
interacting badly.

Signed-off-by: Thomas Wilshaw <thomaswilshaw@gmail.com>
  • Loading branch information
ThomasWilshaw committed Nov 29, 2024
1 parent 2039019 commit 12ebf08
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 2 deletions.
2 changes: 2 additions & 0 deletions app.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ struct AppState {
float track_height = 30.0f; // current track height (pixels)
otio::RationalTime playhead;
bool scroll_to_playhead = false; // temporary flag, only true until next frame
bool scroll_left = false; // temporary flag, only true until next frame
bool scroll_right = false; // temporary flag, only true until next frame
otio::TimeRange
playhead_limit; // min/max limit for moving the playhead, auto-calculated
float zebra_factor = 0.1; // opacity of the per-frame zebra stripes
Expand Down
2 changes: 1 addition & 1 deletion main_glfw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ int main(int argc, char** argv)
ImGui::CreateContext();
ImPlot::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
Expand Down
2 changes: 1 addition & 1 deletion main_win32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ int main(int argc, char** argv)
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
Expand Down
74 changes: 74 additions & 0 deletions timeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,23 @@ void DrawItem(
ImGui::BeginGroup();

ImGui::InvisibleButton("##Item", size);

// Don't skip invisible item if it is the item we have just selected
if (!ImGui::IsItemVisible()
&& appState.selected_object == item
&& (appState.scroll_left || appState.scroll_right)) {

otio::Item* selected_item = dynamic_cast<otio::Item*>(appState.selected_object);
if (appState.scroll_right) {
ImGui::SetScrollX( ImGui::GetScrollX() +
selected_item->range_in_parent().duration().to_seconds() * scale);
appState.scroll_right = false;
}
if (appState.scroll_left) {
ImGui::SetScrollX(selected_item->range_in_parent().start_time().to_seconds() * scale);
appState.scroll_left = false;
}
}
if (!ImGui::IsItemVisible()) {
// exit early if this item is off-screen
ImGui::EndGroup();
Expand Down Expand Up @@ -290,6 +307,24 @@ void DrawTransition(

ImVec2 p0 = ImGui::GetItemRectMin();
ImVec2 p1 = ImGui::GetItemRectMax();

// Don't skip invisible item if it is the item we have just selected
if (!ImGui::IsItemVisible()
&& appState.selected_object == transition
&& (appState.scroll_left || appState.scroll_right)) {

otio::Transition* selected_item = dynamic_cast<otio::Transition*>(appState.selected_object);
if (appState.scroll_right) {
ImGui::SetScrollX( ImGui::GetScrollX() +
selected_item->range_in_parent()->duration().to_seconds() * scale);
appState.scroll_right = false;
}
if (appState.scroll_left) {
ImGui::SetScrollX( selected_item->range_in_parent()->start_time().to_seconds() * scale);
appState.scroll_left = false;
}
}

if (!ImGui::IsRectVisible(p0, p1)) {
ImGui::EndGroup();
ImGui::PopID();
Expand Down Expand Up @@ -1490,6 +1525,45 @@ void DrawTimeline(otio::Timeline* timeline) {
appState.scroll_to_playhead = false;
}

if (ImGui::IsKeyPressed(ImGuiKey::ImGuiKey_RightArrow)) {
std::string selected_type = appState.selected_object->schema_name();
if (selected_type == "Clip" || selected_type == "Gap" || selected_type == "Transition") {
// Loop through selected items parent track to find the next item
auto parent = dynamic_cast<otio::Composable*>(appState.selected_object)->parent();
for(auto it = parent->children().begin(); it != parent->children().end(); it++ ){
// If last item then do nothing
if (std::next(it) == parent->children().end()) {
break;
}
if (*it == appState.selected_object) {
std::advance(it, 1);
SelectObject(*it);
appState.scroll_right = true;
break;
}
}
}
}
if (ImGui::IsKeyPressed(ImGuiKey::ImGuiKey_LeftArrow)) {
std::string selected_type = appState.selected_object->schema_name();
if (selected_type == "Clip" || selected_type == "Gap" || selected_type == "Transition") {
// Loop through selected items parent track to find the previous item
auto parent = dynamic_cast<otio::Composable*>(appState.selected_object)->parent();
for(auto it = parent->children().begin(); it != parent->children().end(); it++ ){
if (*it == appState.selected_object) {
// If first item do nothin
if (it == parent->children().begin()) {
break;
}
std::advance(it, -1);
SelectObject(*it);
appState.scroll_left = true;
break;
}
}
}
}

// This is helpful when debugging visibility performance optimization
// ImGui::SetTooltip("Tracks rendered: %d\nItems rendered: %d",
// __tracks_rendered, __items_rendered);
Expand Down

0 comments on commit 12ebf08

Please sign in to comment.