use crate::fixture_editor::{APPLY_FILL, Draft, FixtureWindow};
use egui::emath::TSTransform;
use egui::{
Context, Event, Key, Modifiers, PointerButton, Pos2, RawInput, Rect, Shape, pos2, vec2,
};
use gled_model::asset::project::Project;
use gled_model::collection::Collections;
use gled_model::patching::Patch;
use gled_model::patching::definition::FixtureDefinition;
use gled_model::patching::fixture::{Fixture, FixtureId, LayoutPosition};
use gled_model::test_support::collections_with;
fn shows_apply(shape: &Shape) -> bool {
match shape {
Shape::Rect(rect) => {
let [r, g, b, _] = rect.fill.to_srgba_unmultiplied();
let [apply_r, apply_g, apply_b, _] = APPLY_FILL.to_array();
r.abs_diff(apply_r) <= 2 && g.abs_diff(apply_g) <= 2 && b.abs_diff(apply_b) <= 2
}
Shape::Vec(shapes) => shapes.iter().any(shows_apply),
_ => false,
}
}
pub(super) struct Session {
ctx: Context,
pub(super) window: FixtureWindow,
project: Option<Project>,
collections: Collections,
time: f64,
pub(super) left: FixtureId,
pub(super) right: FixtureId,
}
impl Session {
pub(super) fn new() -> Self {
Self::with_fixtures(0)
}
pub(super) fn with_fixtures(extra: usize) -> Self {
let (collections, ids) = collections_with(vec![
FixtureDefinition {
size_m: [4.0, 4.0, 0.1],
..Default::default()
},
FixtureDefinition {
size_m: [0.4, 0.4, 0.1],
..Default::default()
},
]);
let mut project = Project::default();
let mut fixture = |name: &str, definition, position| {
let mut fixture = Fixture::new(name);
fixture.definition = Some(definition);
project
.patch
.add_fixture(fixture, LayoutPosition::at(position))
};
let left = fixture("left", ids[0], pos2(700.0, 1000.0));
let right = fixture("right", ids[0], pos2(1300.0, 1000.0));
for index in 0..extra {
let (col, row) = (index % 25, index / 25);
let position = pos2(250.0 + col as f32 * 60.0, 1300.0 + row as f32 * 30.0);
fixture(&format!("small {index}"), ids[1], position);
}
let ctx = Context::default();
crate::style::apply(&ctx);
let mut window = FixtureWindow::default();
window.open();
let mut session = Self {
ctx,
window,
project: Some(project),
collections,
time: 0.0,
left,
right,
};
for _ in 0..3 {
session.frame(vec![]);
}
session
}
pub(super) fn frame(&mut self, events: Vec<Event>) -> bool {
self.time += 0.03;
let input = RawInput {
screen_rect: Some(Rect::from_min_size(Pos2::ZERO, vec2(1600.0, 1000.0))),
time: Some(self.time),
events,
..Default::default()
};
let Self {
window,
project,
collections,
..
} = self;
let mut output = self
.ctx
.run_ui(input, |ui| window.update(ui.ctx(), project, collections));
output.textures_delta.clear();
output
.shapes
.iter()
.any(|clipped| shows_apply(&clipped.shape))
}
fn to_screen(&self) -> TSTransform {
let layers: Vec<_> = self.ctx.memory(|memory| memory.layer_ids().collect());
layers
.into_iter()
.find_map(|layer| self.ctx.layer_transform_to_global(layer))
.expect("the canvas has a scene layer")
}
pub(super) fn on_screen(&self, id: FixtureId) -> Pos2 {
self.to_screen() * self.patch().topology.default_layout.members[&id].pos
}
pub(super) fn patch(&self) -> &Patch {
&self.draft().patch
}
pub(super) fn project(&self) -> &Project {
self.project.as_ref().expect("the session has a project")
}
pub(super) fn adopt(&mut self, patch: Patch) {
if let Some(project) = self.project.as_mut() {
project.patch = patch;
}
self.window.project_replaced();
self.frame(vec![]);
}
pub(super) fn apply(&mut self) {
let mut draft = self.window.draft.take().expect("the window has a draft");
let project = self.project.as_mut().expect("the session has a project");
self.window.apply(&mut draft, project);
self.window.draft = Some(draft);
}
pub(super) fn draft(&self) -> &Draft {
self.window.draft.as_ref().expect("the window has a draft")
}
pub(super) fn button(pos: Pos2, pressed: bool) -> Event {
Event::PointerButton {
pos,
button: PointerButton::Primary,
pressed,
modifiers: Modifiers::NONE,
}
}
pub(super) fn drag(&mut self, from: Pos2, to: Pos2, move_and_press_together: bool) {
if move_and_press_together {
self.frame(vec![Event::PointerMoved(from), Self::button(from, true)]);
} else {
self.frame(vec![Event::PointerMoved(from)]);
self.frame(vec![Self::button(from, true)]);
}
for step in 1..=20 {
let at = from + (to - from) * step as f32 / 20.0;
self.frame(vec![Event::PointerMoved(at)]);
}
self.frame(vec![Self::button(to, false)]);
self.frame(vec![Event::PointerMoved(to + vec2(1.0, 0.0))]);
self.frame(vec![]);
}
fn key(&mut self, modifiers: Modifiers, key: Key) {
let event = |pressed| Event::Key {
key,
physical_key: None,
pressed,
repeat: false,
modifiers,
};
self.frame(vec![Event::ModifiersChanged(modifiers), event(true)]);
self.frame(vec![event(false), Event::ModifiersChanged(Modifiers::NONE)]);
self.frame(vec![]);
}
pub(super) fn undo(&mut self) {
self.key(Modifiers::COMMAND, Key::Z);
}
pub(super) fn redo(&mut self) {
self.key(Modifiers::COMMAND | Modifiers::SHIFT, Key::Z);
}
pub(super) fn can_undo(&self) -> bool {
self.draft().undo.can_undo()
}
pub(super) fn can_redo(&self) -> bool {
self.draft().undo.can_redo()
}
}