use super::App;
use crate::{key_code::key_code, ui::project_edits::project_edits};
use gled_model::{
asset::{output_device::routing::OutputRoutings, project::Project},
input::key_code::KeyCode,
};
use gled_protocol::action::UiAction;
use gled_protocol::state::{ClientInput, EngineEvent, ServerSettings};
use std::collections::BTreeSet;
use std::sync::Arc;
#[derive(Debug, Default)]
pub(super) struct EngineSync {
project: Option<Project>,
compared_changes: u64,
edits_sent: bool,
routings: Arc<OutputRoutings>,
keys: Option<BTreeSet<KeyCode>>,
layout_generation: u64,
}
impl App {
pub(super) fn send_local_changes(&mut self) {
let patch_applied = self.windows.fixture_window.take_patch_applied();
let actions = project_edits(&self.sync.project, &self.project, patch_applied);
if !actions.is_empty() || self.sync.project.is_some() != self.project.is_some() {
self.sync.project = self.project.clone();
self.sync.edits_sent = true;
}
for action in actions {
action.enqueue();
}
if self.output_config.routings != self.sync.routings {
self.sync.routings = self.output_config.routings.clone();
UiAction::SetOutputRoutings(self.output_config.routings.clone()).enqueue();
}
}
pub(super) fn receive_engine_messages(&mut self) {
for message in self.connection.receive() {
self.model.apply(message);
}
if std::mem::take(&mut self.model.welcomed) {
self.connection.reset_sequence();
}
}
pub(super) fn receive_engine_state(&mut self) {
if !std::mem::take(&mut self.model.state_changed) || !self.model.replica.complete {
return;
}
let replica = std::mem::take(&mut self.model.replica);
let state = &replica.state;
self.project_id = state.project_id;
self.selected_scene_instance = state.selected_scene_instance;
if replica.applied_sequence >= self.connection.sent_sequence() {
self.selected_scene_effect_editor
.follow_engine(state.selected_scene_effect);
}
self.network_stats = (
f64::from(state.status.network_in),
f64::from(state.status.network_out),
);
self.blackout = state.blackout;
self.blackout_hold = state.blackout_hold;
self.midi_output_active = state.midi_output_active;
self.timing.update(state.beat, state.tap_count);
self.output_config.universes = state.output_config.universes.clone();
if replica.applied_sequence >= self.connection.sent_sequence() {
let may_differ =
replica.project_changes != self.sync.compared_changes || self.sync.edits_sent;
self.sync.compared_changes = replica.project_changes;
self.sync.edits_sent = false;
if (may_differ && state.project.as_deref() != self.sync.project.as_ref())
|| state.output_config.routings != self.sync.routings
{
if state.project.is_none() && self.project.is_some() {
self.windows.external_device_settings.close();
self.windows.output_routings.close();
self.windows.shortcuts.close();
}
self.project = state.project.as_deref().cloned();
self.sync.project = state.project.as_deref().cloned();
self.windows.fixture_window.project_replaced();
self.output_config.routings = state.output_config.routings.clone();
self.sync.routings = state.output_config.routings.clone();
}
}
if state.layout_generation != self.sync.layout_generation {
self.sync.layout_generation = state.layout_generation;
self.ui_preview.indices.request_rebuild();
}
self.model.replica = replica;
}
pub(crate) fn server_settings(&self) -> &ServerSettings {
&self.model.replica.state.status.settings
}
pub(crate) fn change_server_settings(&self, change: impl FnOnce(&mut ServerSettings)) {
let mut settings = self.server_settings().clone();
change(&mut settings);
ClientInput::SetServerSettings(settings).enqueue();
}
pub(super) fn handle_engine_events(&mut self) {
for event in std::mem::take(&mut self.model.events) {
match event {
EngineEvent::ShaderReloaded(animation) => {
self.thumbnails.invalidate(animation);
self.windows.scenes.invalidate_pipelines(animation);
}
EngineEvent::Error(error) => {
#[cfg(not(target_arch = "wasm32"))]
if let Err(err) = notify_rust::Notification::new()
.summary("Error")
.body(&error)
.icon("application-gled")
.show()
{
tracing::error!("Could not show notification: {err:?}");
}
self.windows.errors.entries.push(error);
}
}
}
}
pub(super) fn send_keys(&mut self, ctx: &egui::Context) {
if ctx.egui_wants_keyboard_input() {
return;
}
let keys: BTreeSet<KeyCode> =
ctx.input(|input| input.keys_down.iter().copied().map(key_code).collect());
if self.sync.keys.as_ref() != Some(&keys) {
self.sync.keys = Some(keys.clone());
ClientInput::Keys(keys).enqueue();
}
}
}