use eframe::egui;
use egui::{Pos2, Rect, Vec2};
pub fn screen_to_local(screen_pos: Pos2, panel_rect: Rect) -> Vec2 {
Vec2::new(
screen_pos.x - panel_rect.min.x,
screen_pos.y - panel_rect.min.y,
)
}
pub fn local_to_screen(local_pos: Vec2, panel_rect: Rect) -> Pos2 {
Pos2::new(
local_pos.x + panel_rect.min.x,
local_pos.y + panel_rect.min.y,
)
}
pub fn is_in_panel(screen_pos: Pos2, panel_rect: Rect) -> bool {
panel_rect.contains(screen_pos)
}
pub fn screen_to_normalized(screen_pos: Pos2, panel_rect: Rect) -> Option<Vec2> {
if !panel_rect.contains(screen_pos) {
return None;
}
let local = screen_to_local(screen_pos, panel_rect);
Some(Vec2::new(
local.x / panel_rect.width(),
local.y / panel_rect.height(),
))
}
use crate::entities::Project;
use crate::core::event_bus::EventBus;
use crate::core::player::Player;
use crate::widgets::timeline::{
TimelineConfig, TimelineState, render_canvas, render_outline, render_toolbar,
};
use crate::widgets::viewport::shaders::Shaders;
pub fn render_timeline_panel(
ui: &mut egui::Ui,
player: &mut Player,
project: &Project,
shader_manager: &mut Shaders,
timeline_state: &mut TimelineState,
event_bus: &EventBus,
show_tooltips: bool,
layer_height: f32,
name_column_width: f32,
outline_top_offset: f32,
layout_names: &[String],
current_layout: &str,
timeline_hover_highlight: bool,
) -> (bool, crate::widgets::timeline::TimelineActions) {
let old_shader = shader_manager.current_shader.clone();
let mut timeline_actions = crate::widgets::timeline::TimelineActions::default();
let available_height = ui.available_height();
ui.vertical(|ui| {
ui.set_min_height(available_height);
ui.set_max_height(available_height);
if let Some(comp_uuid) = player.active_comp() {
if timeline_state
.last_comp_uuid
.map(|u| u != comp_uuid)
.unwrap_or(true)
{
timeline_state.pan_offset = 0.0;
timeline_state.last_comp_uuid = Some(comp_uuid);
}
if let Some(comp) = project.clone_comp(comp_uuid) {
let comp = ∁ let config = TimelineConfig::new(layer_height, name_column_width);
render_toolbar(ui, timeline_state, player.loop_enabled(), show_tooltips, layout_names, current_layout, |evt| event_bus.emit_boxed(evt));
ui.add_space(4.0);
let splitter_height = ui.available_height();
match timeline_state.view_mode {
crate::widgets::timeline::TimelineViewMode::Split => {
let saved_width = timeline_state.outline_width.max(400.0);
let outline_response = egui::SidePanel::left("timeline_outline")
.resizable(true)
.min_width(100.0)
.default_width(saved_width)
.frame(egui::Frame::NONE) .show_inside(ui, |ui| {
ui.set_height(splitter_height);
ui.set_max_height(splitter_height);
render_outline(
ui,
comp_uuid,
comp,
&config,
timeline_state,
timeline_state.view_mode,
outline_top_offset,
|evt| event_bus.emit_boxed(evt),
);
});
let new_width = outline_response.response.rect.width();
if (new_width - timeline_state.outline_width).abs() > 1.0
&& new_width >= 150.0
&& new_width != 100.0
&& new_width >= timeline_state.outline_width * 0.5 {
timeline_state.outline_width = new_width.max(400.0); }
egui::CentralPanel::default()
.frame(egui::Frame::NONE) .show_inside(ui, |ui| {
ui.set_height(splitter_height);
ui.set_max_height(splitter_height);
timeline_actions = render_canvas(
ui,
comp_uuid,
comp,
project,
&config,
timeline_state,
timeline_state.view_mode,
timeline_hover_highlight,
|evt| event_bus.emit_boxed(evt),
);
});
}
crate::widgets::timeline::TimelineViewMode::CanvasOnly => {
egui::CentralPanel::default()
.frame(egui::Frame::NONE)
.show_inside(ui, |ui| {
ui.set_height(splitter_height);
ui.set_max_height(splitter_height);
timeline_actions = render_canvas(
ui,
comp_uuid,
comp,
project,
&config,
timeline_state,
timeline_state.view_mode,
timeline_hover_highlight,
|evt| event_bus.emit_boxed(evt),
);
});
}
crate::widgets::timeline::TimelineViewMode::OutlineOnly => {
egui::CentralPanel::default()
.frame(egui::Frame::NONE)
.show_inside(ui, |ui| {
ui.set_height(splitter_height);
ui.set_max_height(splitter_height);
render_outline(
ui,
comp_uuid,
comp,
&config,
timeline_state,
timeline_state.view_mode,
outline_top_offset,
|evt| event_bus.emit_boxed(evt),
);
});
}
}
}
} else {
ui.centered_and_justified(|ui| {
ui.label("No active composition");
});
}
});
(
old_shader != shader_manager.current_shader,
timeline_actions,
)
}