simple-render 0.2.0

a simple immediate mode wayland ui renderer inspired by clay
Documentation
use super::*;
use crate::animation::Animation;
use std::sync::mpsc::{self, Receiver, SendError, Sender};

pub type Result<T> = std::result::Result<T, Box<dyn Error>>;

pub type RenderSender = calloop_channel::Sender<RenderCommand>;
pub type RenderReceiver = calloop_channel::Channel<RenderCommand>;
pub type RenderSendError = SendError<RenderCommand>;

pub fn channel() -> (RenderSender, RenderReceiver) {
    calloop_channel::channel()
}

pub fn controller() -> (RenderController, RenderReceiver) {
    let (sender, receiver) = channel();
    (RenderController::new(sender), receiver)
}

#[derive(Clone)]
pub struct RenderController {
    sender: RenderSender,
}

impl RenderController {
    pub fn new(sender: RenderSender) -> Self {
        Self { sender }
    }

    pub fn sender(&self) -> &RenderSender {
        &self.sender
    }

    pub fn into_sender(self) -> RenderSender {
        self.sender
    }

    pub fn send(&self, command: RenderCommand) -> std::result::Result<(), RenderSendError> {
        self.sender.send(command)
    }

    pub fn redraw(&self) -> std::result::Result<(), RenderSendError> {
        self.send(RenderCommand::Redraw)
    }

    pub fn resize(&self, width: u32, height: u32) -> std::result::Result<(), RenderSendError> {
        self.send(RenderCommand::Resize { width, height })
    }

    pub fn set_margins(&self, margins: Margins) -> std::result::Result<(), RenderSendError> {
        self.send(RenderCommand::SetMargins(margins))
    }

    pub fn set_anchor(&self, anchor: Anchor) -> std::result::Result<(), RenderSendError> {
        self.send(RenderCommand::SetAnchor(anchor))
    }

    pub fn create_surface(
        &self,
        id: SurfaceId,
        options: LayerOptions,
    ) -> std::result::Result<(), RenderSendError> {
        self.send(RenderCommand::CreateSurface { id, options })
    }

    pub fn destroy_surface(&self, id: SurfaceId) -> std::result::Result<(), RenderSendError> {
        self.send(RenderCommand::DestroySurface { id })
    }

    pub fn redraw_surface(&self, id: SurfaceId) -> std::result::Result<(), RenderSendError> {
        self.send(RenderCommand::RedrawSurface { id })
    }

    pub fn resize_surface(
        &self,
        id: SurfaceId,
        width: u32,
        height: u32,
    ) -> std::result::Result<(), RenderSendError> {
        self.send(RenderCommand::ResizeSurface { id, width, height })
    }

    pub fn set_surface_margins(
        &self,
        id: SurfaceId,
        margins: Margins,
    ) -> std::result::Result<(), RenderSendError> {
        self.send(RenderCommand::SetSurfaceMargins { id, margins })
    }

    pub fn set_surface_anchor(
        &self,
        id: SurfaceId,
        anchor: Anchor,
    ) -> std::result::Result<(), RenderSendError> {
        self.send(RenderCommand::SetSurfaceAnchor { id, anchor })
    }

    pub fn set_surface_layer(
        &self,
        id: SurfaceId,
        layer: Layer,
    ) -> std::result::Result<(), RenderSendError> {
        self.send(RenderCommand::SetSurfaceLayer { id, layer })
    }

    pub fn animate_surface_margins(
        &self,
        id: SurfaceId,
        to: Margins,
        animation: Animation,
        destroy_on_complete: bool,
    ) -> std::result::Result<(), RenderSendError> {
        self.send(RenderCommand::AnimateSurfaceMargins {
            id,
            to,
            animation,
            destroy_on_complete,
        })
    }

    pub fn animate_surface_size(
        &self,
        id: SurfaceId,
        width: u32,
        height: u32,
        animation: Animation,
        destroy_on_complete: bool,
    ) -> std::result::Result<(), RenderSendError> {
        self.send(RenderCommand::AnimateSurfaceSize {
            id,
            width,
            height,
            animation,
            destroy_on_complete,
        })
    }

    pub fn cancel_surface_animation(
        &self,
        id: SurfaceId,
    ) -> std::result::Result<(), RenderSendError> {
        self.send(RenderCommand::CancelSurfaceAnimation { id })
    }

    pub fn request_outputs(
        &self,
    ) -> std::result::Result<Receiver<Vec<RenderOutput>>, RenderSendError> {
        let (reply, receiver) = mpsc::channel();
        self.send(RenderCommand::RequestOutputs { reply })?;
        Ok(receiver)
    }

    pub fn request_surface_state(
        &self,
        id: SurfaceId,
    ) -> std::result::Result<Receiver<Option<RenderSurfaceState>>, RenderSendError> {
        let (reply, receiver) = mpsc::channel();
        self.send(RenderCommand::RequestSurfaceState { id, reply })?;
        Ok(receiver)
    }

    pub fn exit(&self) -> std::result::Result<(), RenderSendError> {
        self.send(RenderCommand::Exit)
    }
}

#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SurfaceId(pub u64);

pub const DEFAULT_SURFACE_ID: SurfaceId = SurfaceId(0);

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RenderOutput {
    pub id: u32,
    pub name: Option<String>,
    pub description: Option<String>,
    pub make: String,
    pub model: String,
    pub logical_position: Option<(i32, i32)>,
    pub logical_size: Option<(i32, i32)>,
    pub scale_factor: i32,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RenderSurfaceState {
    pub id: SurfaceId,
    pub configured: bool,
    pub width: u32,
    pub height: u32,
    pub output: Option<OutputTarget>,
    pub layer: Layer,
    pub anchor: Anchor,
    pub margins: Margins,
    pub scale: u32,
    pub animating: bool,
    pub frame_pending: bool,
}

#[derive(Debug, Clone)]
pub enum RenderCommand {
    Redraw,
    Resize {
        width: u32,
        height: u32,
    },
    SetMargins(Margins),
    SetAnchor(Anchor),
    CreateSurface {
        id: SurfaceId,
        options: LayerOptions,
    },
    DestroySurface {
        id: SurfaceId,
    },
    RedrawSurface {
        id: SurfaceId,
    },
    ResizeSurface {
        id: SurfaceId,
        width: u32,
        height: u32,
    },
    SetSurfaceMargins {
        id: SurfaceId,
        margins: Margins,
    },
    SetSurfaceAnchor {
        id: SurfaceId,
        anchor: Anchor,
    },
    SetSurfaceLayer {
        id: SurfaceId,
        layer: Layer,
    },
    AnimateSurfaceMargins {
        id: SurfaceId,
        to: Margins,
        animation: Animation,
        destroy_on_complete: bool,
    },
    AnimateSurfaceSize {
        id: SurfaceId,
        width: u32,
        height: u32,
        animation: Animation,
        destroy_on_complete: bool,
    },
    CancelSurfaceAnimation {
        id: SurfaceId,
    },
    RequestOutputs {
        reply: Sender<Vec<RenderOutput>>,
    },
    RequestSurfaceState {
        id: SurfaceId,
        reply: Sender<Option<RenderSurfaceState>>,
    },
    Exit,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InputAction {
    Ignore,
    Redraw,
    Animate,
    Exit,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PointerButtonState {
    Pressed,
    Released,
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum PointerEventKind {
    Enter,
    Leave,
    Motion,
    Button {
        button: u32,
        state: PointerButtonState,
    },
    Axis {
        horizontal: PointerAxis,
        vertical: PointerAxis,
        source: Option<PointerAxisSource>,
    },
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub struct PointerAxis {
    pub absolute: f64,
    pub discrete: i32,
    pub stopped: bool,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PointerAxisSource {
    Wheel,
    Finger,
    Continuous,
    WheelTilt,
    Unknown,
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub struct PointerEvent {
    pub surface: SurfaceId,
    pub x: f64,
    pub y: f64,
    pub time: Option<u32>,
    pub serial: Option<u32>,
    pub kind: PointerEventKind,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FrameAction {
    Wait,
    Animate,
    Exit,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RenderContext {
    /// Surface width in logical pixels.
    pub width: u32,
    /// Surface height in logical pixels.
    pub height: u32,
    /// Integer Wayland buffer scale used for the current frame.
    pub scale: u32,
    /// Backing buffer width in physical pixels.
    pub buffer_width: u32,
    /// Backing buffer height in physical pixels.
    pub buffer_height: u32,
    pub frame_time: Option<u32>,
}

pub trait Renderer: 'static {
    fn draw(&mut self, canvas: &mut Canvas<'_>, context: RenderContext) -> FrameAction;

    fn draw_surface(
        &mut self,
        _: SurfaceId,
        canvas: &mut Canvas<'_>,
        context: RenderContext,
    ) -> FrameAction {
        self.draw(canvas, context)
    }

    fn closed(&mut self) {}

    fn closed_surface(&mut self, _: SurfaceId) {
        self.closed();
    }

    fn configured_surface(&mut self, _: SurfaceId, _: u32, _: u32) {}

    fn output_added(&mut self, _: RenderOutput) {}

    fn output_updated(&mut self, _: RenderOutput) {}

    fn output_removed(&mut self, _: RenderOutput) {}

    fn pointer_event(&mut self, _: PointerEvent) -> InputAction {
        InputAction::Ignore
    }
}

impl<F> Renderer for F
where
    F: for<'borrow, 'canvas> FnMut(&'borrow mut Canvas<'canvas>, RenderContext) -> FrameAction
        + 'static,
{
    fn draw(&mut self, canvas: &mut Canvas<'_>, context: RenderContext) -> FrameAction {
        self(canvas, context)
    }
}