|
|
@ -1,28 +1,55 @@
|
|
|
|
use glium::Display;
|
|
|
|
use glium::Display;
|
|
|
|
use imgui::Ui;
|
|
|
|
use imgui::{Ui, MouseButton};
|
|
|
|
use imgui::color::ImColor32;
|
|
|
|
use imgui::color::ImColor32;
|
|
|
|
|
|
|
|
use imgui::draw_list::DrawListMut;
|
|
|
|
|
|
|
|
|
|
|
|
use crate::ui_generic::drag_area::DragArea;
|
|
|
|
use crate::ui_generic::drag_area::{DragArea, DragAreaMut};
|
|
|
|
use crate::storage::Storage;
|
|
|
|
use crate::storage::Storage;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const MIN_SCALE: f32 = 0.05;
|
|
|
|
|
|
|
|
const MAX_SCALE: f32 = 2.0;
|
|
|
|
|
|
|
|
|
|
|
|
const KF_CHAN_HEIGHT: f32 = 20.0;
|
|
|
|
const KF_CHAN_HEIGHT: f32 = 20.0;
|
|
|
|
const KF_CHAN_TITLE_DEFAULT_COLOR: ImColor32 =
|
|
|
|
const KF_CHAN_TITLE_BAR_WIDTH: f32 = 200.0;
|
|
|
|
|
|
|
|
const TS_BAR_HEIGHT: f32 = 20.0;
|
|
|
|
|
|
|
|
const TS_TICK_LINE_DIST: f32 = 5.0;
|
|
|
|
|
|
|
|
const TS_TICK_LINE_HEIGHT: f32 = 4.0;
|
|
|
|
|
|
|
|
const TS_TICK_LINE_TALL_HEIGHT: f32 = 18.0;
|
|
|
|
|
|
|
|
const KF_CHAN_TITLE_DEFAULT_FILL: ImColor32 =
|
|
|
|
ImColor32::from_rgb(38, 38, 38);
|
|
|
|
ImColor32::from_rgb(38, 38, 38);
|
|
|
|
const KF_CHAN_TITLE_HOVER_COLOR: ImColor32 =
|
|
|
|
const KF_CHAN_TITLE_HOVER_FILL: ImColor32 =
|
|
|
|
ImColor32::from_rgb(79, 79, 79);
|
|
|
|
ImColor32::from_rgb(79, 79, 79);
|
|
|
|
const KF_CHAN_CONTENT_DEFAULT_COLOR: ImColor32 =
|
|
|
|
const KF_CHAN_CONTENT_DEFAULT_FILL: ImColor32 =
|
|
|
|
ImColor32::from_rgb(16, 16, 16);
|
|
|
|
ImColor32::from_rgb(16, 16, 16);
|
|
|
|
const KF_CHAN_CONTENT_HOVER_COLOR: ImColor32 =
|
|
|
|
const KF_CHAN_CONTENT_HOVER_FILL: ImColor32 =
|
|
|
|
ImColor32::from_rgb(54, 54, 54);
|
|
|
|
ImColor32::from_rgb(54, 54, 54);
|
|
|
|
|
|
|
|
const TS_BAR_BG_FILL: ImColor32 =
|
|
|
|
|
|
|
|
ImColor32::from_rgb(10, 10, 10);
|
|
|
|
|
|
|
|
const TS_TRACKER_RECT_FILL: ImColor32 =
|
|
|
|
|
|
|
|
ImColor32::from_rgba(237, 66, 69, 60);
|
|
|
|
|
|
|
|
const TS_TRACKER_HDL_FILL: ImColor32 =
|
|
|
|
|
|
|
|
ImColor32::from_rgb(237, 66, 69);
|
|
|
|
|
|
|
|
|
|
|
|
pub struct KeyframeEditor {
|
|
|
|
pub struct KeyframeEditor {
|
|
|
|
pub drag_area: DragArea
|
|
|
|
pub drag_area: DragArea,
|
|
|
|
|
|
|
|
pub first_timestamp_in_view: i64,
|
|
|
|
|
|
|
|
pub scale: f32,
|
|
|
|
|
|
|
|
pub ts_bar_active: bool
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct KeyframeEditorMut {
|
|
|
|
|
|
|
|
pub first_timestamp_in_view: i64,
|
|
|
|
|
|
|
|
pub scale: f32,
|
|
|
|
|
|
|
|
pub ts_bar_active: bool
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl KeyframeEditor {
|
|
|
|
impl KeyframeEditor {
|
|
|
|
pub fn new(size: [f32; 2]) -> KeyframeEditor {
|
|
|
|
pub fn new(size: [f32; 2]) -> KeyframeEditor {
|
|
|
|
KeyframeEditor {
|
|
|
|
KeyframeEditor {
|
|
|
|
drag_area: DragArea::new(size, [0.0, 0.0])
|
|
|
|
drag_area: DragArea::new(size, [0.0, 0.0]),
|
|
|
|
|
|
|
|
first_timestamp_in_view: 0,
|
|
|
|
|
|
|
|
scale: 1.0,
|
|
|
|
|
|
|
|
ts_bar_active: false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -32,122 +59,316 @@ impl KeyframeEditor {
|
|
|
|
display: &Display,
|
|
|
|
display: &Display,
|
|
|
|
storage: &mut Storage
|
|
|
|
storage: &mut Storage
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
|
|
|
|
let mut k = KeyframeEditorMut {
|
|
|
|
|
|
|
|
first_timestamp_in_view: self.first_timestamp_in_view,
|
|
|
|
|
|
|
|
scale: self.scale,
|
|
|
|
|
|
|
|
ts_bar_active: self.ts_bar_active
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
self.drag_area.build(
|
|
|
|
self.drag_area.build(
|
|
|
|
&ui,
|
|
|
|
&ui,
|
|
|
|
&display.gl_window().window(),
|
|
|
|
&display.gl_window().window(),
|
|
|
|
|draw_list, area_min, area_max, offset| {
|
|
|
|
|d| {
|
|
|
|
let mouse_y = ui.io().mouse_pos[1];
|
|
|
|
KeyframeEditor::build_drag_area_contents(
|
|
|
|
|
|
|
|
ui,
|
|
|
|
|
|
|
|
storage,
|
|
|
|
|
|
|
|
&mut k,
|
|
|
|
|
|
|
|
d
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.first_timestamp_in_view = k.first_timestamp_in_view;
|
|
|
|
|
|
|
|
self.scale = k.scale;
|
|
|
|
|
|
|
|
self.ts_bar_active = k.ts_bar_active;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn build_drag_area_contents(
|
|
|
|
|
|
|
|
ui: &Ui,
|
|
|
|
|
|
|
|
storage: &mut Storage,
|
|
|
|
|
|
|
|
k: &mut KeyframeEditorMut,
|
|
|
|
|
|
|
|
mut d: DragAreaMut
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
// Establish ia = inner area
|
|
|
|
|
|
|
|
let ia_min = [d.area_min[0] + 1.0, d.area_min[1] + 1.0];
|
|
|
|
|
|
|
|
let ia_max = [d.area_max[0] - 1.0, d.area_max[1] - 1.0];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// No keyframes text
|
|
|
|
|
|
|
|
if storage.keyframe_channels.len() == 0 {
|
|
|
|
|
|
|
|
let text = "no keyframes to show.";
|
|
|
|
|
|
|
|
let text_size = ui.calc_text_size(text);
|
|
|
|
|
|
|
|
let text_pos: [f32; 2] = [
|
|
|
|
|
|
|
|
(ia_max[0] - ia_min[0]) / 2.0 + (text_size[0] / 2.0),
|
|
|
|
|
|
|
|
(ia_max[1] - ia_min[1]) / 2.0 + (text_size[1] / 2.0)
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
d.draw_list.add_text(text_pos, KF_CHAN_TITLE_HOVER_FILL, text);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Movement processing
|
|
|
|
|
|
|
|
let mouse_pos = ui.io().mouse_pos;
|
|
|
|
|
|
|
|
let scaled_ts_dist = TS_TICK_LINE_DIST * k.scale;
|
|
|
|
|
|
|
|
if ui.is_item_hovered() {
|
|
|
|
|
|
|
|
let wheel = ui.io().mouse_wheel;
|
|
|
|
|
|
|
|
let ctrl = ui.io().key_ctrl;
|
|
|
|
|
|
|
|
let shift = ui.io().key_shift;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ctrl {
|
|
|
|
|
|
|
|
k.scale += wheel * 0.05;
|
|
|
|
|
|
|
|
if k.scale < MIN_SCALE {
|
|
|
|
|
|
|
|
k.scale = MIN_SCALE
|
|
|
|
|
|
|
|
} else if k.scale > MAX_SCALE {
|
|
|
|
|
|
|
|
k.scale = MAX_SCALE
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
} else if shift {
|
|
|
|
|
|
|
|
let inverse_scale = MAX_SCALE - k.scale;
|
|
|
|
|
|
|
|
d.offset[0] -= wheel * scaled_ts_dist * inverse_scale;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
d.offset[1] += wheel * 10.0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if d.offset[1] > 0.0 {
|
|
|
|
|
|
|
|
d.offset[1] = 0.0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if d.offset[0] > 0.0 {
|
|
|
|
|
|
|
|
d.offset[0] = 0.0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
k.first_timestamp_in_view =
|
|
|
|
|
|
|
|
(-d.offset[0] / scaled_ts_dist) as i64;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let origin = [ia_min[0] + d.offset[0], ia_min[1] + d.offset[1]];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Draw each keyframe channel
|
|
|
|
|
|
|
|
let mut chan_y: f32 = origin[1] + TS_BAR_HEIGHT;
|
|
|
|
|
|
|
|
let mut next_chan_y: f32 = chan_y + KF_CHAN_HEIGHT;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (idx, chan) in storage.keyframe_channels.iter().enumerate() {
|
|
|
|
|
|
|
|
// Determine colors
|
|
|
|
|
|
|
|
let title_bg: ImColor32;
|
|
|
|
|
|
|
|
let content_bg: ImColor32;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if mouse_pos[1] <= next_chan_y && mouse_pos[1] > chan_y {
|
|
|
|
|
|
|
|
content_bg = KF_CHAN_CONTENT_HOVER_FILL;
|
|
|
|
|
|
|
|
title_bg = KF_CHAN_TITLE_HOVER_FILL;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
content_bg = KF_CHAN_CONTENT_DEFAULT_FILL;
|
|
|
|
|
|
|
|
title_bg = KF_CHAN_TITLE_DEFAULT_FILL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Draw keyframe channel title bar and text
|
|
|
|
|
|
|
|
let chan_title_start = [ia_min[0], chan_y];
|
|
|
|
|
|
|
|
let chan_title_end = [
|
|
|
|
|
|
|
|
ia_min[0] + KF_CHAN_TITLE_BAR_WIDTH,
|
|
|
|
|
|
|
|
next_chan_y - 1.0
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
d.draw_list
|
|
|
|
|
|
|
|
.add_rect(chan_title_start, chan_title_end, title_bg)
|
|
|
|
|
|
|
|
.filled(true)
|
|
|
|
|
|
|
|
.thickness(0.0)
|
|
|
|
|
|
|
|
.build();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let title_pos = [
|
|
|
|
|
|
|
|
chan_title_start[0] + 3.0,
|
|
|
|
|
|
|
|
chan_title_start[1] + 3.0
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
d.draw_list.add_text(
|
|
|
|
|
|
|
|
title_pos,
|
|
|
|
|
|
|
|
ImColor32::WHITE,
|
|
|
|
|
|
|
|
String::from(&chan.name)
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
let origin: [f32; 2];
|
|
|
|
// Draw keyframe content bar
|
|
|
|
|
|
|
|
let chan_content_end = [ia_max[0], chan_title_start[1]];
|
|
|
|
|
|
|
|
|
|
|
|
if storage.keyframe_channels.len() == 0 {
|
|
|
|
d.draw_list
|
|
|
|
let text_pos: [f32; 2] = [
|
|
|
|
.add_rect(chan_title_end, chan_content_end, content_bg)
|
|
|
|
area_min[0] + (area_max[0] - area_min[0]) / 2.0 - 50.0,
|
|
|
|
.filled(true)
|
|
|
|
area_min[1] + (area_max[1] - area_min[1]) / 2.0 - 2.5
|
|
|
|
.thickness(0.0)
|
|
|
|
];
|
|
|
|
.build();
|
|
|
|
|
|
|
|
|
|
|
|
draw_list.add_text(
|
|
|
|
// Draw keyframe channel border line
|
|
|
|
text_pos,
|
|
|
|
if idx < storage.keyframe_channels.len() - 1 {
|
|
|
|
KF_CHAN_TITLE_HOVER_COLOR,
|
|
|
|
let border_start = [chan_title_start[0], next_chan_y];
|
|
|
|
"No keyframes to show."
|
|
|
|
let border_end = [ia_max[0], next_chan_y];
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
d.draw_list
|
|
|
|
|
|
|
|
.add_line(border_start, border_end, title_bg)
|
|
|
|
|
|
|
|
.build();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
chan_y += KF_CHAN_HEIGHT;
|
|
|
|
|
|
|
|
next_chan_y += KF_CHAN_HEIGHT;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Draw time marker bar
|
|
|
|
|
|
|
|
let ts_bar_start = [
|
|
|
|
|
|
|
|
ia_min[0] + KF_CHAN_TITLE_BAR_WIDTH,
|
|
|
|
|
|
|
|
ia_min[1]
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let ts_bar_end = [
|
|
|
|
|
|
|
|
ia_max[0],
|
|
|
|
|
|
|
|
ia_min[1] + TS_BAR_HEIGHT
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
d.draw_list
|
|
|
|
|
|
|
|
.add_rect(
|
|
|
|
|
|
|
|
ts_bar_start,
|
|
|
|
|
|
|
|
ts_bar_end,
|
|
|
|
|
|
|
|
TS_BAR_BG_FILL
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
.filled(true)
|
|
|
|
|
|
|
|
.thickness(0.0)
|
|
|
|
|
|
|
|
.build();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Process interactivity for timestamp bar
|
|
|
|
|
|
|
|
let ts_bar_button_size = [
|
|
|
|
|
|
|
|
ts_bar_end[0] - ts_bar_start[0],
|
|
|
|
|
|
|
|
ts_bar_end[1] - ts_bar_start[1]
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let ts_bar_hovered =
|
|
|
|
|
|
|
|
ts_bar_start[0] <= mouse_pos[0]
|
|
|
|
|
|
|
|
&& ts_bar_end[0] >= mouse_pos[0]
|
|
|
|
|
|
|
|
&& ts_bar_start[1] <= mouse_pos[1]
|
|
|
|
|
|
|
|
&& ts_bar_end[1] >= mouse_pos[1];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let lmb_down = ui.is_mouse_down(MouseButton::Left);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if !k.ts_bar_active && lmb_down && ts_bar_hovered {
|
|
|
|
|
|
|
|
k.ts_bar_active = true;
|
|
|
|
|
|
|
|
} else if k.ts_bar_active && !lmb_down {
|
|
|
|
|
|
|
|
k.ts_bar_active = false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if k.ts_bar_active {
|
|
|
|
|
|
|
|
let new_ts = k.first_timestamp_in_view
|
|
|
|
|
|
|
|
+ (
|
|
|
|
|
|
|
|
(mouse_pos[0] - ts_bar_start[0])
|
|
|
|
|
|
|
|
/ scaled_ts_dist
|
|
|
|
|
|
|
|
) as i64;
|
|
|
|
|
|
|
|
if new_ts >= 0 {
|
|
|
|
|
|
|
|
storage.timestamp = new_ts;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
storage.timestamp = 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Draw time marker ticks and numbers
|
|
|
|
|
|
|
|
let mut ts_x = ts_bar_start[0];
|
|
|
|
|
|
|
|
let mut timestamp_inc = k.first_timestamp_in_view;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while ts_x < ia_max[0] {
|
|
|
|
|
|
|
|
let is_10_mult = timestamp_inc % 10 == 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let line_start = [ts_x, ts_bar_end[1]];
|
|
|
|
|
|
|
|
let line_end = [
|
|
|
|
|
|
|
|
ts_x,
|
|
|
|
|
|
|
|
if is_10_mult {
|
|
|
|
|
|
|
|
ts_bar_end[1] - TS_TICK_LINE_TALL_HEIGHT
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
ts_bar_end[1] - TS_TICK_LINE_HEIGHT
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
d.draw_list
|
|
|
|
|
|
|
|
.add_line(line_start, line_end, KF_CHAN_TITLE_HOVER_FILL)
|
|
|
|
|
|
|
|
.build();
|
|
|
|
|
|
|
|
|
|
|
|
let origin = [
|
|
|
|
if is_10_mult {
|
|
|
|
area_min[0] + offset[0],
|
|
|
|
let text = format!("{}", timestamp_inc);
|
|
|
|
area_min[1] + offset[1]
|
|
|
|
let text_pos = [
|
|
|
|
|
|
|
|
ts_x + 2.0,
|
|
|
|
|
|
|
|
ts_bar_end[1] - TS_TICK_LINE_TALL_HEIGHT
|
|
|
|
];
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
let mut chan_y: f32 = 1.0;
|
|
|
|
d.draw_list.add_text(
|
|
|
|
let mut next_chan_y: f32 = chan_y + KF_CHAN_HEIGHT;
|
|
|
|
text_pos,
|
|
|
|
|
|
|
|
KF_CHAN_TITLE_HOVER_FILL,
|
|
|
|
for (idx, chan) in storage.keyframe_channels.iter().enumerate() {
|
|
|
|
text
|
|
|
|
let title_bg: ImColor32;
|
|
|
|
);
|
|
|
|
let content_bg: ImColor32;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
|
|
|
(mouse_y < origin[1] + next_chan_y) &&
|
|
|
|
|
|
|
|
(mouse_y > origin[1] + chan_y)
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
content_bg = KF_CHAN_CONTENT_HOVER_COLOR;
|
|
|
|
|
|
|
|
title_bg = KF_CHAN_TITLE_HOVER_COLOR;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
content_bg = KF_CHAN_CONTENT_DEFAULT_COLOR;
|
|
|
|
|
|
|
|
title_bg = KF_CHAN_TITLE_DEFAULT_COLOR;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let chan_title_start: [f32; 2] = [
|
|
|
|
|
|
|
|
origin[0] + 1.0,
|
|
|
|
|
|
|
|
origin[1] + chan_y + 1.0
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let chan_title_end: [f32; 2] = [
|
|
|
|
|
|
|
|
origin[0] + 100.0,
|
|
|
|
|
|
|
|
origin[1] + next_chan_y + 1.0
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
draw_list
|
|
|
|
|
|
|
|
.add_rect(
|
|
|
|
|
|
|
|
chan_title_start,
|
|
|
|
|
|
|
|
chan_title_end,
|
|
|
|
|
|
|
|
title_bg
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
.filled(true)
|
|
|
|
|
|
|
|
.thickness(0.0)
|
|
|
|
|
|
|
|
.build();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let title_pos: [f32; 2] = [
|
|
|
|
|
|
|
|
origin[0] + 1.0 + 3.0,
|
|
|
|
|
|
|
|
origin[1] + chan_y + 2.0
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
draw_list.add_text(
|
|
|
|
|
|
|
|
title_pos,
|
|
|
|
|
|
|
|
ImColor32::WHITE,
|
|
|
|
|
|
|
|
String::from(&chan.name)
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let chan_content_end: [f32; 2] = [
|
|
|
|
|
|
|
|
area_max[0],
|
|
|
|
|
|
|
|
chan_title_start[1]
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
draw_list
|
|
|
|
|
|
|
|
.add_rect(
|
|
|
|
|
|
|
|
chan_title_end,
|
|
|
|
|
|
|
|
chan_content_end,
|
|
|
|
|
|
|
|
content_bg
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
.filled(true)
|
|
|
|
|
|
|
|
.thickness(0.0)
|
|
|
|
|
|
|
|
.build();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if true {
|
|
|
|
|
|
|
|
let border_start = [
|
|
|
|
|
|
|
|
origin[0],
|
|
|
|
|
|
|
|
origin[1] + next_chan_y
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let border_end = [
|
|
|
|
|
|
|
|
area_max[0],
|
|
|
|
|
|
|
|
origin[1] + next_chan_y
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
draw_list
|
|
|
|
|
|
|
|
.add_line(
|
|
|
|
|
|
|
|
border_start,
|
|
|
|
|
|
|
|
border_end,
|
|
|
|
|
|
|
|
title_bg
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
.build();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
chan_y += KF_CHAN_HEIGHT;
|
|
|
|
|
|
|
|
next_chan_y += KF_CHAN_HEIGHT;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
timestamp_inc += 1;
|
|
|
|
|
|
|
|
ts_x += TS_TICK_LINE_DIST * k.scale;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if storage.timestamp >= k.first_timestamp_in_view {
|
|
|
|
|
|
|
|
// Draw timestamp tracker rect
|
|
|
|
|
|
|
|
let current_ts_offset =
|
|
|
|
|
|
|
|
storage.timestamp - k.first_timestamp_in_view;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let ts_rect_start = [
|
|
|
|
|
|
|
|
ts_bar_start[0]
|
|
|
|
|
|
|
|
+ (scaled_ts_dist * current_ts_offset as f32),
|
|
|
|
|
|
|
|
ts_bar_end[1]
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let ts_rect_end = [
|
|
|
|
|
|
|
|
ts_rect_start[0] + scaled_ts_dist,
|
|
|
|
|
|
|
|
chan_y
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
d.draw_list
|
|
|
|
|
|
|
|
.add_rect(
|
|
|
|
|
|
|
|
ts_rect_start,
|
|
|
|
|
|
|
|
ts_rect_end,
|
|
|
|
|
|
|
|
TS_TRACKER_RECT_FILL
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
.filled(true)
|
|
|
|
|
|
|
|
.thickness(0.0)
|
|
|
|
|
|
|
|
.build();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Draw timestamp tracker handle thingy
|
|
|
|
|
|
|
|
let text = format!("{}", storage.timestamp);
|
|
|
|
|
|
|
|
let text_width = ui.calc_text_size(&text)[0];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let ts_hdl_p1 = [ts_rect_start[0], ia_min[1]];
|
|
|
|
|
|
|
|
let ts_hdl_p2 = [
|
|
|
|
|
|
|
|
ts_rect_start[0] + text_width + 6.0,
|
|
|
|
|
|
|
|
ts_bar_end[1]
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
d.draw_list
|
|
|
|
|
|
|
|
.add_rect(
|
|
|
|
|
|
|
|
ts_hdl_p1,
|
|
|
|
|
|
|
|
ts_hdl_p2,
|
|
|
|
|
|
|
|
TS_TRACKER_HDL_FILL
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
.rounding(3.0)
|
|
|
|
|
|
|
|
.round_top_left(true)
|
|
|
|
|
|
|
|
.round_top_right(true)
|
|
|
|
|
|
|
|
.round_bot_right(true)
|
|
|
|
|
|
|
|
.round_bot_left(false)
|
|
|
|
|
|
|
|
.filled(true)
|
|
|
|
|
|
|
|
.thickness(0.0)
|
|
|
|
|
|
|
|
.build();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let ts_hdl_text_pos = [
|
|
|
|
|
|
|
|
ts_rect_start[0] + 3.0,
|
|
|
|
|
|
|
|
ts_bar_end[1] - TS_TICK_LINE_TALL_HEIGHT
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
d.draw_list.add_text(
|
|
|
|
|
|
|
|
ts_hdl_text_pos,
|
|
|
|
|
|
|
|
ImColor32::WHITE,
|
|
|
|
|
|
|
|
text
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Draw scale text
|
|
|
|
|
|
|
|
let scale_text_pos = [ia_max[0] - 100.0, ia_max[1] - 50.0];
|
|
|
|
|
|
|
|
d.draw_list.add_text(
|
|
|
|
|
|
|
|
scale_text_pos,
|
|
|
|
|
|
|
|
KF_CHAN_TITLE_HOVER_FILL,
|
|
|
|
|
|
|
|
format!("{:.2}x scale", k.scale)
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|