blob: 844cb4cd17d5a0ecca28b47a364f136886995d60 [file] [log] [blame]
use avm_stats::{Plane, PlaneType, Spatial};
use egui::{vec2, Button, Checkbox, RichText, Ui};
use crate::app_state::AppState;
use crate::settings::{DistortionView, FrameSortOrder, MotionFieldColoring};
use crate::stream::{ChangeFrame, CurrentFrame};
use crate::views::RenderView;
use super::ViewMode;
const PLAYBACK_BUTTON_HEIGHT: f32 = 30.0;
const PLAYBACK_BUTTON_WIDTH: f32 = 30.0;
const PLAYBACK_BUTTON_FONT_SIZE: f32 = 18.0;
fn create_playback_button(icon: &str) -> Button {
Button::new(RichText::new(format!(" {icon} ")).size(PLAYBACK_BUTTON_FONT_SIZE))
.min_size(vec2(PLAYBACK_BUTTON_WIDTH, PLAYBACK_BUTTON_HEIGHT))
}
pub struct ControlsViewer;
impl RenderView for ControlsViewer {
fn title(&self) -> String {
"Controls".into()
}
fn render(&self, ui: &mut Ui, state: &mut AppState) -> anyhow::Result<()> {
ui.horizontal(|ui| {
ui.vertical(|ui| {
ui.label("View");
let frame_sort_options = [FrameSortOrder::Decode, FrameSortOrder::Display];
egui::ComboBox::from_label("Frame sort order")
.selected_text(format!("{:?}", state.settings.persistent.frame_sort_order))
.show_ui(ui, |ui| {
for &sort_option in frame_sort_options.iter() {
ui.selectable_value(
&mut state.settings.persistent.frame_sort_order,
sort_option,
format!("{sort_option:?}"),
);
}
});
ui.end_row();
let plane_options = [
PlaneType::Planar(Plane::Y),
PlaneType::Planar(Plane::U),
PlaneType::Planar(Plane::V),
PlaneType::Rgb,
];
egui::ComboBox::from_label("Plane view")
.selected_text(format!("{}", state.settings.sharable.current_plane))
.show_ui(ui, |ui| {
for &plane_option in plane_options.iter() {
ui.selectable_value(
&mut state.settings.sharable.current_plane,
plane_option,
format!("{plane_option}"),
);
}
});
ui.end_row();
ui.add_enabled(
state.settings.sharable.view_mode.view_settings().pixel_type.is_delta(),
egui::Checkbox::new(&mut state.settings.sharable.show_relative_delta, "Show relative delta"),
);
ui.end_row();
ui.checkbox(&mut state.settings.sharable.show_overlay, "Show overlay");
ui.end_row();
ui.checkbox(&mut state.settings.sharable.show_yuv, "Show YUV");
ui.end_row();
if ui.button("Reset Zoom").clicked() {
if let Some(frame) = state.stream.current_frame() {
state.settings.sharable.world_bounds = frame.rect();
}
}
});
if let Some(stream) = &mut state.stream {
ui.separator();
ui.vertical(|ui| {
ui.label("Playback");
ui.horizontal(|ui| {
let frame_sort_order: FrameSortOrder = state.settings.persistent.frame_sort_order;
if ui
.add(create_playback_button("⏮"))
.on_hover_text("Go to first frame")
.clicked()
{
stream.change_frame(ChangeFrame::first().order(frame_sort_order));
}
if ui
.add(create_playback_button("⏪"))
.on_hover_text("Go to previous frame")
.clicked()
{
stream.change_frame(ChangeFrame::prev().order(frame_sort_order));
}
let play_pause = if state.settings.playback.playback_running {
"⏸"
} else {
"▶"
};
if ui
.add(create_playback_button(play_pause))
.on_hover_text("Start/stop playback")
.clicked()
{
state.settings.playback.playback_running = !state.settings.playback.playback_running;
}
if ui
.add(create_playback_button("⏩"))
.on_hover_text("Go to next frame")
.clicked()
{
stream.change_frame(ChangeFrame::next().order(frame_sort_order));
}
if ui
.add(create_playback_button("⏭"))
.on_hover_text("Go to last frame")
.clicked()
{
stream.change_frame(ChangeFrame::last().order(frame_sort_order));
}
});
// TODO(comc): Re-enable after adding pause logic for pending loads.
// ui.checkbox(
// &mut state.settings.playback.show_loaded_frames_only,
// "Playback loaded frames only",
// );
ui.checkbox(&mut state.settings.playback.playback_loop, "Loop playback");
ui.label("Playback FPS:");
ui.add(egui::Slider::new(&mut state.settings.playback.playback_fps, 1.0..=60.0).step_by(1.0));
});
}
if state.settings.sharable.view_mode == ViewMode::Heatmap {
ui.separator();
ui.vertical(|ui| {
ui.label("Heatmap");
ui.checkbox(&mut state.settings.sharable.show_heatmap_legend, "Show Heatmap Legend");
ui.end_row();
ui.label("Histogram buckets");
ui.add(egui::Slider::new(
&mut state.settings.sharable.heatmap_settings.histogram_buckets,
4..=100,
));
ui.end_row();
ui.checkbox(
&mut state.settings.sharable.heatmap_histogram_log_scale,
"Histogram log scale",
);
ui.end_row();
ui.label("Symbol filter");
ui.text_edit_singleline(&mut state.settings.sharable.heatmap_settings.symbol_filter);
if ui.button("Recalculate heatmap").clicked() {
if let Some(stream) = &state.stream {
stream.images.clear_heatmaps();
}
}
});
}
if let ViewMode::Distortion(mut distortion_view) = state.settings.sharable.view_mode {
ui.separator();
ui.vertical(|ui| {
let distortion_view_options = [
DistortionView::Distortion,
DistortionView::Original,
DistortionView::Reconstruction,
];
egui::ComboBox::from_label("Displayed pixels")
.selected_text(distortion_view.name())
.show_ui(ui, |ui| {
for &distortion_view_option in distortion_view_options.iter() {
ui.selectable_value(
&mut distortion_view,
distortion_view_option,
distortion_view_option.name(),
);
}
});
ui.end_row();
});
state.settings.sharable.view_mode = ViewMode::Distortion(distortion_view);
}
if state.settings.sharable.view_mode == ViewMode::Motion {
ui.separator();
ui.vertical(|ui| {
ui.label("Motion");
ui.checkbox(&mut state.settings.sharable.motion_field.show, "Show motion field");
ui.end_row();
ui.checkbox(
&mut state.settings.sharable.motion_field.show_origin,
"Show motion vector origin",
);
ui.end_row();
ui.add_enabled(
state.settings.sharable.motion_field.show,
Checkbox::new(
&mut state.settings.sharable.motion_field.normalize,
"Normalize vector lengths",
),
);
ui.end_row();
ui.label("Motion vector scale:");
ui.add(egui::Slider::new(&mut state.settings.sharable.motion_field.scale, 0.1..=10.0).step_by(0.1));
let coloring_options = [
MotionFieldColoring::RefFrames,
MotionFieldColoring::PastFuture,
MotionFieldColoring::Monochrome,
];
egui::ComboBox::from_label("Coloring scheme")
.selected_text(state.settings.sharable.motion_field.coloring.name())
.show_ui(ui, |ui| {
for &coloring_option in coloring_options.iter() {
ui.selectable_value(
&mut state.settings.sharable.motion_field.coloring,
coloring_option,
coloring_option.name(),
);
}
});
ui.end_row();
ui.label("Granularity (in 4x4 units):");
ui.checkbox(&mut state.settings.sharable.motion_field.auto_granularity, "Automatic");
ui.add_enabled(
!state.settings.sharable.motion_field.auto_granularity,
egui::Slider::new(&mut state.settings.sharable.motion_field.granularity, 1..=32),
);
if let Some(frame) = state.stream.current_frame() {
if state.settings.sharable.motion_field.auto_granularity {
state.settings.sharable.motion_field.granularity = frame.height() as usize / 64;
}
}
ui.end_row();
});
}
});
Ok(())
}
}