use std::{sync::Arc, time::Duration}; use anyhow::Context; use glam::{Affine3A, Quat, Vec3, vec3}; use wgui::{ components::button::ComponentButton, event::{CallbackDataCommon, EventAlterables}, i18n::Translation, parser::{Fetchable, parse_color_hex}, renderer_vk::text::custom_glyph::{CustomGlyphContent, CustomGlyphData}, taffy, widget::{ image::WidgetImage, label::WidgetLabel, rectangle::WidgetRectangle, sprite::WidgetSprite, }, }; use wlx_common::windowing::OverlayWindowState; use crate::{ backend::task::ModifyPanelCommand, gui::{ panel::{GuiPanel, NewGuiPanelParams}, timer::GuiTimer, }, state::AppState, windowing::{ backend::OverlayEventData, window::{OverlayCategory, OverlayWindowConfig}, }, }; struct CustomPanelState {} pub fn create_custom(app: &mut AppState, name: Arc) -> Option { let params = NewGuiPanelParams { external_xml: true, ..NewGuiPanelParams::default() }; let mut panel = GuiPanel::new_from_template(app, &format!("gui/{name}.xml"), CustomPanelState {}, params) .inspect_err(|e| log::warn!("Error creating '{name}': {e:?}")) .ok()?; panel .update_layout() .inspect_err(|e| log::warn!("Error layouting '{name}': {e:?}")) .ok()?; panel .timers .push(GuiTimer::new(Duration::from_millis(100), 0)); let scale = panel.layout.content_size.x / 40.0 * 0.05; panel.on_notify = Some(Box::new({ let name = name.clone(); move |panel, app, event_data| { let OverlayEventData::CustomCommand { element, command } = event_data else { return Ok(()); }; if let Err(e) = apply_custom_command(panel, app, &element, &command) { log::warn!("Could not apply {command:?} on {name}/{element}: {e:?}"); }; Ok(()) } })); Some(OverlayWindowConfig { name, category: OverlayCategory::Panel, default_state: OverlayWindowState { interactable: true, grabbable: true, transform: Affine3A::from_scale_rotation_translation( Vec3::ONE * scale, Quat::IDENTITY, vec3(0.0, 0.0, -0.5), ), ..OverlayWindowState::default() }, ..OverlayWindowConfig::from_backend(Box::new(panel)) }) } fn apply_custom_command( panel: &mut GuiPanel, app: &mut AppState, element: &str, command: &ModifyPanelCommand, ) -> anyhow::Result<()> { let mut alterables = EventAlterables::default(); let mut com = CallbackDataCommon { alterables: &mut alterables, state: &panel.layout.state, }; match command { ModifyPanelCommand::SetText(text) => { if let Ok(mut label) = panel .parser_state .fetch_widget_as::(&panel.layout.state, element) { label.set_text(&mut com, Translation::from_raw_text(text)); } else if let Ok(button) = panel .parser_state .fetch_component_as::(&element) { button.set_text(&mut com, Translation::from_raw_text(text)); } else { anyhow::bail!("No