lgui-core 0.2.2

Platform-neutral runtime and UI primitives for LGUI
Documentation
use std::sync::{Arc, RwLock};

use crate::{
    core::{Element, InputEvent, RenderCx},
    platform::dpi::ScalePreference,
};

use super::{WindowCommand, WindowId, WindowMode, WindowOptions};

type WindowCommandHandler = Arc<dyn Fn(WindowCommand) + Send + Sync>;

#[derive(Clone)]
pub struct WindowManager {
    inner: Arc<WindowManagerInner>,
}

struct WindowManagerInner {
    command: RwLock<Option<WindowCommandHandler>>,
}

impl WindowManager {
    pub(crate) fn new() -> Self {
        Self {
            inner: Arc::new(WindowManagerInner {
                command: RwLock::new(None),
            }),
        }
    }

    pub(crate) fn install(&self, command: impl Fn(WindowCommand) + Send + Sync + 'static) {
        *self.inner.command.write().expect("window manager poisoned") = Some(Arc::new(command));
    }

    pub fn show(
        &self,
        options: WindowOptions,
        view: impl for<'scope, 'context> Fn(&mut RenderCx<'scope, 'context>) -> Element
            + Send
            + Sync
            + 'static,
    ) -> bool {
        self.send(WindowCommand::Show {
            options,
            view: Arc::new(view),
        })
    }

    pub fn hide(&self, id: impl Into<WindowId>) -> bool {
        self.send(WindowCommand::Hide(id.into()))
    }

    pub fn toggle(
        &self,
        options: WindowOptions,
        view: impl for<'scope, 'context> Fn(&mut RenderCx<'scope, 'context>) -> Element
            + Send
            + Sync
            + 'static,
    ) -> bool {
        self.send(WindowCommand::Toggle {
            options,
            view: Arc::new(view),
        })
    }

    pub fn close(&self, id: impl Into<WindowId>) -> bool {
        self.send(WindowCommand::Close(id.into()))
    }

    pub fn request_close(&self, id: impl Into<WindowId>) -> bool {
        self.send(WindowCommand::RequestClose(id.into()))
    }

    pub fn minimize(&self, id: impl Into<WindowId>) -> bool {
        self.send(WindowCommand::Minimize(id.into()))
    }

    pub fn set_scale_preference(&self, preference: ScalePreference) -> bool {
        self.send(WindowCommand::SetScalePreference(preference))
    }

    pub fn set_mode(&self, id: impl Into<WindowId>, mode: WindowMode) -> bool {
        self.send(WindowCommand::SetMode {
            id: id.into(),
            mode,
        })
    }

    pub fn send_input(&self, id: impl Into<WindowId>, input: InputEvent) -> bool {
        self.send(WindowCommand::Input {
            id: id.into(),
            input,
        })
    }

    pub fn exit(&self) -> bool {
        self.send(WindowCommand::Exit)
    }

    fn send(&self, command: WindowCommand) -> bool {
        let handler = self
            .inner
            .command
            .read()
            .expect("window manager poisoned")
            .clone();
        let Some(handler) = handler else {
            return false;
        };
        handler(command);
        true
    }
}

impl PartialEq for WindowManager {
    fn eq(&self, other: &Self) -> bool {
        Arc::ptr_eq(&self.inner, &other.inner)
    }
}

#[derive(Clone)]
pub struct WindowHandle {
    id: WindowId,
    windows: WindowManager,
}

impl WindowHandle {
    pub(crate) fn new(id: WindowId, windows: WindowManager) -> Self {
        Self { id, windows }
    }

    pub fn id(&self) -> &WindowId {
        &self.id
    }

    pub fn close(&self) -> bool {
        self.windows.close(self.id.clone())
    }

    pub fn request_close(&self) -> bool {
        self.windows.request_close(self.id.clone())
    }

    pub fn minimize(&self) -> bool {
        self.windows.minimize(self.id.clone())
    }

    pub fn hide(&self) -> bool {
        self.windows.hide(self.id.clone())
    }

    pub fn set_mode(&self, mode: WindowMode) -> bool {
        self.windows.set_mode(self.id.clone(), mode)
    }
}