diff --git a/tools/jotpluggler/internal.h b/tools/jotpluggler/internal.h index 22a5c1dd959450..35a16ada48c8a6 100644 --- a/tools/jotpluggler/internal.h +++ b/tools/jotpluggler/internal.h @@ -134,7 +134,8 @@ void clamp_shared_range(UiState *state, const AppSession &session); void reset_shared_range(UiState *state, const AppSession &session); void update_follow_range(UiState *state, const AppSession &session); void advance_playback(UiState *state, const AppSession &session); -void step_tracker(UiState *state, double direction); +void seek_tracker(UiState *state, const AppSession &session, double time_value); +void step_tracker(UiState *state, const AppSession &session, double direction); std::string dbc_combo_label(const AppSession &session); const char *log_selector_name(LogSelector selector); const char *log_selector_description(LogSelector selector); diff --git a/tools/jotpluggler/render.cc b/tools/jotpluggler/render.cc index 54f0c16cc394b9..70e97e3370751c 100644 --- a/tools/jotpluggler/render.cc +++ b/tools/jotpluggler/render.cc @@ -59,11 +59,15 @@ void render_layout(AppSession *session, UiState *state, bool show_camera_feed) { if (!ImGui::GetIO().WantTextInput && ctrl && ImGui::IsKeyPressed(ImGuiKey_F, false)) { state->open_find_signal = true; } - if (ImGui::IsKeyPressed(ImGuiKey_LeftArrow, false)) { - step_tracker(state, -1.0); - } - if (ImGui::IsKeyPressed(ImGuiKey_RightArrow, false)) { - step_tracker(state, 1.0); + if (!ImGui::GetIO().WantTextInput) { + const int left_steps = ImGui::GetKeyPressedAmount(ImGuiKey_LeftArrow, 0.18f, 0.03f); + const int right_steps = ImGui::GetKeyPressedAmount(ImGuiKey_RightArrow, 0.18f, 0.03f); + for (int i = 0; i < left_steps; ++i) { + step_tracker(state, *session, -1.0); + } + for (int i = 0; i < right_steps; ++i) { + step_tracker(state, *session, 1.0); + } } if (!ImGui::GetIO().WantTextInput && ImGui::IsKeyPressed(ImGuiKey_Space, false)) { state->playback_playing = !state->playback_playing; diff --git a/tools/jotpluggler/session.cc b/tools/jotpluggler/session.cc index 22dd7dd463873a..3630bf173451d7 100644 --- a/tools/jotpluggler/session.cc +++ b/tools/jotpluggler/session.cc @@ -265,12 +265,30 @@ void advance_playback(UiState *state, const AppSession &session) { } } -void step_tracker(UiState *state, double direction) { - if (!state->has_shared_range) { +void seek_tracker(UiState *state, const AppSession &session, double time_value) { + if (!state->has_shared_range || !session.route_data.has_time_range) { return; } - state->tracker_time += direction * std::max(0.001, state->playback_step); + + state->has_tracker_time = true; + state->follow_latest = false; + state->tracker_time = time_value; state->tracker_time = std::clamp(state->tracker_time, state->route_x_min, state->route_x_max); + + if (state->tracker_time < state->x_view_min || state->tracker_time > state->x_view_max) { + const double view_span = std::max(MIN_HORIZONTAL_ZOOM_SECONDS, state->x_view_max - state->x_view_min); + state->x_view_min = state->tracker_time - view_span * 0.5; + state->x_view_max = state->x_view_min + view_span; + clamp_shared_range(state, session); + } +} + +void step_tracker(UiState *state, const AppSession &session, double direction) { + if (!state->has_shared_range) { + return; + } + const double delta = direction * std::max(0.001, state->playback_step); + seek_tracker(state, session, state->tracker_time + delta); } const char *log_selector_name(LogSelector selector) { diff --git a/tools/jotpluggler/sidebar.cc b/tools/jotpluggler/sidebar.cc index c120b47908e6b1..9239d1881abedb 100644 --- a/tools/jotpluggler/sidebar.cc +++ b/tools/jotpluggler/sidebar.cc @@ -46,7 +46,6 @@ void draw_timeline_bar_contents(const AppSession &session, UiState *state, float ImGui::InvisibleButton("##timeline_button", size); const bool hovered = ImGui::IsItemHovered(); - const bool active = ImGui::IsItemActive(); const bool double_clicked = hovered && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left); ImDrawList *draw_list = ImGui::GetWindowDrawList(); @@ -85,6 +84,8 @@ void draw_timeline_bar_contents(const AppSession &session, UiState *state, float const float edge_grab = 4.0f; const float mouse_x = ImGui::GetIO().MousePos.x; const double mouse_time = timeline_x_to_time(mouse_x, route_min, route_max, bar_min.x, bar_max.x); + const bool left_down = ImGui::IsMouseDown(ImGuiMouseButton_Left); + const bool right_down = ImGui::IsMouseDown(ImGuiMouseButton_Right); if (double_clicked) { reset_timeline_view(state, session); } else if (hovered && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) { @@ -95,28 +96,34 @@ void draw_timeline_bar_contents(const AppSession &session, UiState *state, float state->timeline_drag_mode = TimelineDragMode::ResizeLeft; } else if (std::abs(mouse_x - vp_right) <= edge_grab) { state->timeline_drag_mode = TimelineDragMode::ResizeRight; - } else if (mouse_x >= vp_left && mouse_x <= vp_right) { - state->timeline_drag_mode = TimelineDragMode::PanViewport; } else { state->timeline_drag_mode = TimelineDragMode::ScrubCursor; - state->tracker_time = std::clamp(mouse_time, route_min, route_max); - state->has_tracker_time = true; + seek_tracker(state, session, mouse_time); } + } else if (hovered && ImGui::IsMouseClicked(ImGuiMouseButton_Right) && mouse_x >= vp_left && mouse_x <= vp_right) { + state->timeline_drag_anchor_time = mouse_time; + state->timeline_drag_anchor_x_min = state->x_view_min; + state->timeline_drag_anchor_x_max = state->x_view_max; + state->timeline_drag_mode = TimelineDragMode::PanViewport; } - if (!ImGui::IsMouseDown(ImGuiMouseButton_Left)) { + if (!left_down && !right_down) { state->timeline_drag_mode = TimelineDragMode::None; - } else if (active || state->timeline_drag_mode != TimelineDragMode::None) { + } else if (state->timeline_drag_mode != TimelineDragMode::None) { switch (state->timeline_drag_mode) { case TimelineDragMode::ScrubCursor: - state->tracker_time = std::clamp(mouse_time, route_min, route_max); - state->has_tracker_time = true; + if (left_down) { + seek_tracker(state, session, mouse_time); + } break; case TimelineDragMode::PanViewport: { - const double delta = mouse_time - state->timeline_drag_anchor_time; - state->x_view_min = state->timeline_drag_anchor_x_min + delta; - state->x_view_max = state->timeline_drag_anchor_x_max + delta; - clamp_shared_range(state, session); + if (right_down) { + const double delta = mouse_time - state->timeline_drag_anchor_time; + state->x_view_min = state->timeline_drag_anchor_x_min + delta; + state->x_view_max = state->timeline_drag_anchor_x_max + delta; + state->follow_latest = false; + clamp_shared_range(state, session); + } break; } case TimelineDragMode::ResizeLeft: