rx-editor 0.3.0

a modern, extensible pixel editor
Documentation
use crate::platform::{
    ControlFlow, InputState, Key, KeyboardInput, LogicalDelta, LogicalPosition, LogicalSize,
    ModifiersState, MouseButton, WindowEvent, WindowHint,
};

use winit;
// We only support desktop platforms.
use winit::platform::desktop::EventLoopExtDesktop;

use std::io;

///////////////////////////////////////////////////////////////////////////////

pub fn run<F, T>(mut win: Window<T>, mut events: Events, mut callback: F) -> T
where
    F: 'static + FnMut(&mut Window<T>, WindowEvent) -> ControlFlow<T>,
    T: Default,
{
    let mut exit = T::default();

    win.set_cursor_visible(false);

    events
        .handle
        .run_return(|event, _, control_flow| match event {
            winit::event::Event::WindowEvent { event, .. } => {
                if let ControlFlow::Exit(r) = callback(&mut win, event.into()) {
                    *control_flow = winit::event_loop::ControlFlow::Exit;
                    exit = r;
                }
            }
            winit::event::Event::EventsCleared => {
                if let ControlFlow::Exit(r) = callback(&mut win, WindowEvent::Ready) {
                    *control_flow = winit::event_loop::ControlFlow::Exit;
                    exit = r;
                }
            }
            _ => {
                *control_flow = winit::event_loop::ControlFlow::Poll;
            }
        });

    exit
}

pub struct Events {
    handle: winit::event_loop::EventLoop<()>,
}

pub struct Window<T> {
    pub handle: winit::window::Window,
    phantom: std::marker::PhantomData<T>,
}

impl<T> Window<T> {
    pub fn request_redraw(&self) {
        self.handle.request_redraw();
    }

    pub fn handle(&self) -> &winit::window::Window {
        &self.handle
    }

    pub fn set_cursor_visible(&mut self, visible: bool) {
        self.handle.set_cursor_visible(visible);
    }

    pub fn hidpi_factor(&self) -> f64 {
        self.handle.hidpi_factor()
    }

    pub fn size(&self) -> LogicalSize {
        let size = self.handle.inner_size();
        LogicalSize::new(size.width, size.height)
    }
}

pub fn init<T>(
    title: &str,
    w: u32,
    h: u32,
    hints: &[WindowHint],
) -> io::Result<(Window<T>, Events)> {
    let events = Events {
        handle: winit::event_loop::EventLoop::new(),
    };
    let mut resizable = true;
    let mut visible = true;

    for h in hints {
        match h {
            WindowHint::Resizable(r) => {
                resizable = *r;
            }
            WindowHint::Visible(v) => {
                visible = *v;
            }
        }
    }

    let handle = winit::window::WindowBuilder::new()
        .with_title(title)
        .with_inner_size(winit::dpi::LogicalSize::new(w as f64, h as f64))
        .with_resizable(resizable)
        .with_visible(visible)
        .build(&events.handle)
        .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;

    Ok((
        Window {
            handle,
            phantom: std::marker::PhantomData,
        },
        events,
    ))
}

impl From<winit::dpi::LogicalSize> for LogicalSize {
    #[inline]
    fn from(size: winit::dpi::LogicalSize) -> Self {
        Self::new(size.width, size.height)
    }
}

impl From<winit::event::MouseButton> for MouseButton {
    fn from(button: winit::event::MouseButton) -> Self {
        match button {
            winit::event::MouseButton::Left => MouseButton::Left,
            winit::event::MouseButton::Right => MouseButton::Right,
            winit::event::MouseButton::Middle => MouseButton::Middle,
            winit::event::MouseButton::Other(n) => MouseButton::Other(n),
        }
    }
}

impl From<winit::event::ElementState> for InputState {
    fn from(state: winit::event::ElementState) -> Self {
        match state {
            winit::event::ElementState::Pressed => InputState::Pressed,
            winit::event::ElementState::Released => InputState::Released,
        }
    }
}

impl From<winit::event::KeyboardInput> for KeyboardInput {
    fn from(input: winit::event::KeyboardInput) -> Self {
        Self {
            state: input.state.into(),
            key: input.virtual_keycode.map(Key::from),
            modifiers: input.modifiers.into(),
        }
    }
}

impl From<winit::event::WindowEvent> for WindowEvent {
    fn from(event: winit::event::WindowEvent) -> Self {
        use winit::event::WindowEvent as Winit;

        match event {
            Winit::Resized(size) => WindowEvent::Resized(size.into()),
            Winit::Destroyed => WindowEvent::Destroyed,
            Winit::CloseRequested => WindowEvent::CloseRequested,
            Winit::RedrawRequested => WindowEvent::RedrawRequested,
            Winit::Moved(pos) => WindowEvent::Moved(pos.into()),
            Winit::MouseInput {
                state,
                button,
                modifiers,
                ..
            } => WindowEvent::MouseInput {
                state: state.into(),
                button: button.into(),
                modifiers: modifiers.into(),
            },
            Winit::MouseWheel { delta, .. } => WindowEvent::MouseWheel {
                delta: delta.into(),
            },
            Winit::CursorLeft { .. } => WindowEvent::CursorLeft,
            Winit::CursorEntered { .. } => WindowEvent::CursorEntered,
            Winit::CursorMoved { position, .. } => WindowEvent::CursorMoved {
                position: position.into(),
            },
            Winit::ReceivedCharacter(c) => WindowEvent::ReceivedCharacter(c),
            Winit::KeyboardInput { input, .. } => WindowEvent::KeyboardInput(input.into()),
            Winit::Focused(b) => WindowEvent::Focused(b),
            Winit::HiDpiFactorChanged(n) => WindowEvent::HiDpiFactorChanged(n),

            _ => WindowEvent::Noop,
        }
    }
}

impl From<winit::event::VirtualKeyCode> for Key {
    fn from(k: winit::event::VirtualKeyCode) -> Self {
        use winit::event::VirtualKeyCode as Winit;

        match k {
            Winit::Key1 => Key::Num1,
            Winit::Key2 => Key::Num2,
            Winit::Key3 => Key::Num3,
            Winit::Key4 => Key::Num4,
            Winit::Key5 => Key::Num5,
            Winit::Key6 => Key::Num6,
            Winit::Key7 => Key::Num7,
            Winit::Key8 => Key::Num8,
            Winit::Key9 => Key::Num9,
            Winit::Key0 => Key::Num0,
            Winit::A => Key::A,
            Winit::B => Key::B,
            Winit::C => Key::C,
            Winit::D => Key::D,
            Winit::E => Key::E,
            Winit::F => Key::F,
            Winit::G => Key::G,
            Winit::H => Key::H,
            Winit::I => Key::I,
            Winit::J => Key::J,
            Winit::K => Key::K,
            Winit::L => Key::L,
            Winit::M => Key::M,
            Winit::N => Key::N,
            Winit::O => Key::O,
            Winit::P => Key::P,
            Winit::Q => Key::Q,
            Winit::R => Key::R,
            Winit::S => Key::S,
            Winit::T => Key::T,
            Winit::U => Key::U,
            Winit::V => Key::V,
            Winit::W => Key::W,
            Winit::X => Key::X,
            Winit::Y => Key::Y,
            Winit::Z => Key::Z,
            Winit::Escape => Key::Escape,
            Winit::Insert => Key::Insert,
            Winit::Home => Key::Home,
            Winit::Delete => Key::Delete,
            Winit::End => Key::End,
            Winit::PageDown => Key::PageDown,
            Winit::PageUp => Key::PageUp,
            Winit::Left => Key::Left,
            Winit::Up => Key::Up,
            Winit::Right => Key::Right,
            Winit::Down => Key::Down,
            Winit::Back => Key::Backspace,
            Winit::Return => Key::Return,
            Winit::Space => Key::Space,
            Winit::Caret => Key::Caret,
            Winit::Apostrophe => Key::Apostrophe,
            Winit::Backslash => Key::Backslash,
            Winit::Colon => Key::Colon,
            Winit::Comma => Key::Comma,
            Winit::Equals => Key::Equal,
            Winit::Grave => Key::Grave,
            Winit::LAlt => Key::Alt,
            Winit::LBracket => Key::LBracket,
            Winit::LControl => Key::Control,
            Winit::LShift => Key::Shift,
            Winit::Subtract => Key::Minus,
            Winit::Period => Key::Period,
            Winit::RAlt => Key::Alt,
            Winit::RBracket => Key::RBracket,
            Winit::RControl => Key::Control,
            Winit::RShift => Key::Shift,
            Winit::Semicolon => Key::Semicolon,
            Winit::Slash => Key::Slash,
            Winit::Tab => Key::Tab,
            _ => Key::Unknown,
        }
    }
}

impl From<winit::event::ModifiersState> for ModifiersState {
    fn from(mods: winit::event::ModifiersState) -> Self {
        Self {
            shift: mods.shift,
            ctrl: mods.ctrl,
            alt: mods.alt,
            meta: mods.logo,
        }
    }
}

impl From<winit::dpi::LogicalPosition> for LogicalPosition {
    fn from(pos: winit::dpi::LogicalPosition) -> Self {
        Self { x: pos.x, y: pos.y }
    }
}

impl From<winit::event::MouseScrollDelta> for LogicalDelta {
    fn from(delta: winit::event::MouseScrollDelta) -> Self {
        match delta {
            winit::event::MouseScrollDelta::LineDelta(x, y) => LogicalDelta {
                x: x as f64,
                y: y as f64,
            },
            winit::event::MouseScrollDelta::PixelDelta(pos) => LogicalDelta { x: pos.x, y: pos.y },
        }
    }
}