#![allow(dead_code)]
#![allow(unused_macros)]
use std::ops::{Add, AddAssign};
use std::str;
use std::char;
use std::marker::PhantomData;
mod p {
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}
#[derive(Copy, Clone, Default, Debug)]
pub struct Coord {
pub x: f64,
pub y: f64
}
impl Coord {
pub fn scale(&self, factor: f64) -> Coord {
Coord {
x: self.x * factor,
y: self.y * factor,
}
}
}
impl Add for Coord {
type Output = Coord;
fn add (self, other: Coord) -> Coord {
Coord {
x: self.x + other.x,
y: self.y + other.y
}
}
}
impl AddAssign for Coord {
fn add_assign(&mut self, other: Coord) {
*self = Coord {
x: self.x + other.x,
y: self.y + other.y,
};
}
}
#[derive(Copy, Clone, Default, Debug)]
pub struct Size {
pub w: f64,
pub h: f64
}
impl Size {
pub fn scale(&self, factor: f64) -> Size {
Size {
w: self.w * factor,
h: self.h * factor
}
}
}
impl Add for Size {
type Output = Size;
fn add (self, other: Size) -> Size {
Size {
w: self.w + other.w,
h: self.h + other.h
}
}
}
#[derive(Copy, Clone, Default)]
pub struct EventContext {
pub pos: Coord,
pub pos_root: Coord,
pub time: f64
}
#[derive(Copy, Clone)]
pub enum SpecialKey {
Backspace,
Escape,
Delete,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
Left,
Up,
Right,
Down,
PageUp,
PageDown,
Home,
End,
Insert,
ShiftL,
ShiftR,
CtrlL,
CtrlR,
AltL,
AltR,
SuperL,
SuperR,
KeyMenu,
KeyCapsLock,
KeyScrollLock,
KeyNumLock,
KeyPrintScreen,
KeyPause,
None
}
impl From<p::PuglKey> for SpecialKey {
fn from (k: p::PuglKey) -> SpecialKey {
match k {
p::PuglKey_PUGL_KEY_BACKSPACE => SpecialKey::Backspace,
p::PuglKey_PUGL_KEY_ESCAPE => SpecialKey::Escape,
p::PuglKey_PUGL_KEY_DELETE => SpecialKey::Delete,
p::PuglKey_PUGL_KEY_F1 => SpecialKey::F1,
p::PuglKey_PUGL_KEY_F2 => SpecialKey::F2,
p::PuglKey_PUGL_KEY_F3 => SpecialKey::F3,
p::PuglKey_PUGL_KEY_F4 => SpecialKey::F4,
p::PuglKey_PUGL_KEY_F5 => SpecialKey::F5,
p::PuglKey_PUGL_KEY_F6 => SpecialKey::F6,
p::PuglKey_PUGL_KEY_F7 => SpecialKey::F7,
p::PuglKey_PUGL_KEY_F8 => SpecialKey::F8,
p::PuglKey_PUGL_KEY_F9 => SpecialKey::F9,
p::PuglKey_PUGL_KEY_F10 => SpecialKey::F10,
p::PuglKey_PUGL_KEY_F11 => SpecialKey::F11,
p::PuglKey_PUGL_KEY_F12 => SpecialKey::F12,
p::PuglKey_PUGL_KEY_LEFT => SpecialKey::Left,
p::PuglKey_PUGL_KEY_UP => SpecialKey::Up,
p::PuglKey_PUGL_KEY_RIGHT => SpecialKey::Right,
p::PuglKey_PUGL_KEY_DOWN => SpecialKey::Down,
p::PuglKey_PUGL_KEY_PAGE_UP => SpecialKey::PageUp,
p::PuglKey_PUGL_KEY_PAGE_DOWN => SpecialKey::PageDown,
p::PuglKey_PUGL_KEY_HOME => SpecialKey::Home,
p::PuglKey_PUGL_KEY_END => SpecialKey::End,
p::PuglKey_PUGL_KEY_INSERT => SpecialKey::Insert,
p::PuglKey_PUGL_KEY_SHIFT_L => SpecialKey::ShiftL,
p::PuglKey_PUGL_KEY_SHIFT_R => SpecialKey::ShiftR,
p::PuglKey_PUGL_KEY_CTRL_L => SpecialKey::CtrlL,
p::PuglKey_PUGL_KEY_ALT_L => SpecialKey::AltL,
p::PuglKey_PUGL_KEY_CTRL_R => SpecialKey::CtrlR,
p::PuglKey_PUGL_KEY_ALT_R => SpecialKey::AltR,
p::PuglKey_PUGL_KEY_SUPER_L => SpecialKey::SuperL,
p::PuglKey_PUGL_KEY_SUPER_R => SpecialKey::SuperR,
p::PuglKey_PUGL_KEY_MENU => SpecialKey::KeyMenu,
p::PuglKey_PUGL_KEY_CAPS_LOCK => SpecialKey::KeyCapsLock,
p::PuglKey_PUGL_KEY_SCROLL_LOCK => SpecialKey::KeyScrollLock,
p::PuglKey_PUGL_KEY_NUM_LOCK => SpecialKey::KeyNumLock,
p::PuglKey_PUGL_KEY_PRINT_SCREEN => SpecialKey::KeyPrintScreen,
p::PuglKey_PUGL_KEY_PAUSE => SpecialKey::KeyPause,
_ => SpecialKey::None
}
}
}
bitflags! {
pub struct Modifiers: u32 {
const NONE = 0;
const SHIFT = 1;
const CTRL = 2;
const ALT = 4;
const SUPER = 8;
}
}
type KeyCode = u32;
type Modifier = u32;
#[derive(Copy, Clone)]
pub enum KeyVal {
Character (char),
Special (SpecialKey)
}
#[derive(Copy, Clone)]
pub struct Key {
pub key: KeyVal,
pub modifiers: Modifier,
pub code: KeyCode
}
impl Key {
pub fn try_char(&self) -> Option<char> {
match self.key {
KeyVal::Character (c) => Some (c),
_ => None
}
}
}
impl From<p::PuglEventKey> for KeyVal {
fn from(ke: p::PuglEventKey) -> KeyVal {
match ke.key {
0 => KeyVal::Special (SpecialKey::from(ke.keycode)),
_ => KeyVal::Character (char::from_u32(ke.key).unwrap())
}
}
}
impl From<p::PuglEventKey> for Key {
fn from(ke: p::PuglEventKey) -> Key {
Key {
key: KeyVal::from (ke),
code: ke.keycode,
modifiers: ke.state
}
}
}
impl From<p::PuglEventKey> for EventContext {
fn from(ke: p::PuglEventKey) -> EventContext {
EventContext {
pos: Coord { x: ke.x, y: ke.y },
pos_root: Coord { x: ke.xRoot, y: ke.yRoot },
time: ke.time
}
}
}
#[derive(Copy, Clone, PartialEq)]
pub struct MouseButton {
pub num: u32,
pub modifiers: Modifier
}
impl From<p::PuglEventButton> for MouseButton {
fn from(be: p::PuglEventButton) -> MouseButton {
MouseButton {
num: be.button,
modifiers: be.state
}
}
}
impl From<p::PuglEventButton> for EventContext {
fn from(be: p::PuglEventButton) -> EventContext {
EventContext {
pos: Coord { x: be.x, y: be.y },
pos_root: Coord { x: be.xRoot, y: be.yRoot },
time: be.time
}
}
}
#[derive(Copy, Clone)]
pub struct MotionContext {
pub modifiers: Modifier,
pub is_hint: bool,
pub focus: bool
}
impl From<p::PuglEventMotion> for MotionContext {
fn from (me: p::PuglEventMotion) -> MotionContext {
MotionContext {
modifiers: me.state,
is_hint: me.isHint,
focus: me.focus
}
}
}
impl From<p::PuglEventMotion> for EventContext {
fn from (me: p::PuglEventMotion) -> EventContext {
EventContext {
pos: Coord { x: me.x, y: me.y },
pos_root: Coord { x: me.xRoot, y: me.yRoot },
time: me.time
}
}
}
#[derive(Copy, Clone)]
pub struct Scroll {
pub dx: f64,
pub dy: f64,
pub modifiers: Modifier
}
impl From<p::PuglEventScroll> for Scroll {
fn from (se: p::PuglEventScroll) -> Scroll {
Scroll {
dx: se.dx, dy: se.dy,
modifiers: se.state
}
}
}
impl From<p::PuglEventScroll> for EventContext {
fn from (se: p::PuglEventScroll) -> EventContext {
EventContext {
pos: Coord { x: se.x, y: se.y },
pos_root: Coord { x: se.xRoot, y: se.yRoot },
time: se.time
}
}
}
impl From<p::PuglEventConfigure> for Size {
fn from (ce: p::PuglEventConfigure) -> Size {
Size { w: ce.width, h: ce.height }
}
}
#[derive(Copy, Clone)]
pub struct ExposeArea {
pub pos: Coord,
pub size: Size,
pub count: i32
}
impl From<p::PuglEventExpose> for ExposeArea {
fn from(e: p::PuglEventExpose) -> ExposeArea {
ExposeArea {
pos: Coord { x: e.x, y: e.y },
size: Size { w: e.width, h: e.height },
count: e.count
}
}
}
#[derive(Copy, Clone)]
pub enum EventType {
KeyPress (Key),
KeyRelease (Key),
MouseButtonPress (MouseButton),
MouseButtonRelease (MouseButton),
MouseMove (MotionContext),
Scroll (Scroll)
}
#[derive(Copy, Clone)]
pub struct Event {
pub data: EventType,
pub context: EventContext
}
impl Event {
pub fn try_keypress(&self) -> Option<Key> {
match self.data {
EventType::KeyPress (k) => Some (k),
_ => None
}
}
pub fn pos(&self) -> Coord {
self.context.pos
}
pub fn scale_pos(self, scale_factor: f64) -> Event {
let mut ev = self;
ev.context.pos = self.context.pos.scale(scale_factor);
ev
}
pub fn pos_root(&self) -> Coord {
self.context.pos_root
}
}
#[derive(Copy, Clone)]
pub enum Cursor {
Arrow,
Caret,
CrossHair,
Hand,
No,
LeftRight,
UpDown
}
impl From<Cursor> for p::PuglCursor {
fn from(c: Cursor) -> p::PuglCursor {
match c {
Cursor::Arrow => p::PuglCursor_PUGL_CURSOR_ARROW,
Cursor::Caret => p::PuglCursor_PUGL_CURSOR_CARET,
Cursor::CrossHair => p::PuglCursor_PUGL_CURSOR_CROSSHAIR,
Cursor::Hand => p::PuglCursor_PUGL_CURSOR_HAND,
Cursor::No => p::PuglCursor_PUGL_CURSOR_NO,
Cursor::LeftRight => p::PuglCursor_PUGL_CURSOR_LEFT_RIGHT,
Cursor::UpDown => p::PuglCursor_PUGL_CURSOR_UP_DOWN,
}
}
}
pub type PuglViewFFI = *mut p::PuglView;
#[repr(u32)]
pub enum Status {
Success,
Failure,
UnknownError,
BadBackend,
BadParameter,
BackendFailed,
RegistrationFailed,
RealizeFailed,
SetFormatFailed,
CreateContextFailed,
UnsupportedType
}
impl From<p::PuglStatus> for Status {
fn from(ps: p::PuglStatus) -> Status {
match ps {
p::PuglStatus_PUGL_SUCCESS => Status::Success ,
p::PuglStatus_PUGL_FAILURE => Status::Failure ,
p::PuglStatus_PUGL_UNKNOWN_ERROR => Status::UnknownError ,
p::PuglStatus_PUGL_BAD_BACKEND => Status::BadBackend ,
p::PuglStatus_PUGL_BAD_PARAMETER => Status::BadParameter ,
p::PuglStatus_PUGL_BACKEND_FAILED => Status::BackendFailed ,
p::PuglStatus_PUGL_REGISTRATION_FAILED => Status::RegistrationFailed ,
p::PuglStatus_PUGL_REALIZE_FAILED => Status::RealizeFailed ,
p::PuglStatus_PUGL_SET_FORMAT_FAILED => Status::SetFormatFailed ,
p::PuglStatus_PUGL_CREATE_CONTEXT_FAILED => Status::CreateContextFailed ,
p::PuglStatus_PUGL_UNSUPPORTED_TYPE => Status::UnsupportedType,
_ => Status::UnsupportedType
}
}
}
pub trait PuglViewTrait {
fn event(&mut self, ev: Event) -> Status;
fn exposed (&mut self, _expose: &ExposeArea, cr: &cairo::Context);
fn resize (&mut self, size: Size);
fn close_request(&mut self);
fn focus_in(&mut self) -> Status { Status::Success }
fn focus_out(&mut self) -> Status { Status::Success }
fn set_view (&mut self, view: PuglViewFFI);
fn view (&self) -> PuglViewFFI;
fn world (&self) -> *mut p::PuglWorld {
unsafe { p::puglGetWorld(self.view() as *mut p::PuglView) }
}
fn post_redisplay (&self) -> Status {
unsafe { Status::from(p::puglPostRedisplay(self.view())) }
}
fn post_redisplay_rect(&self, pos: Coord, size: Size) -> Status {
let p_rect = p::PuglRect {
x: pos.x,
y: pos.y,
width: size.w,
height: size.h
};
unsafe { Status::from(p::puglPostRedisplayRect(self.view(), p_rect)) }
}
fn set_frame (&self, width: f64, height: f64) -> Status {
unsafe { Status::from(p::puglSetFrame(self.view(), p::PuglRect { x:0.0, y:0.0, width, height})) }
}
fn set_min_size (&self, width: i32, height: i32) -> Status {
unsafe { Status::from(p::puglSetMinSize(self.view(), width, height)) }
}
fn make_resizable(&self) -> Status {
unsafe { Status::from(p::puglSetViewHint(self.view(), p::PuglViewHint_PUGL_RESIZABLE, true as i32)) }
}
fn set_window_title (&self, title: &str) -> Status {
unsafe { Status::from(p::puglSetWindowTitle(self.view(), title.as_ptr() as *const i8)) }
}
fn show_window (&self) -> Status {
unsafe { Status::from(p::puglShowWindow(self.view())) }
}
fn set_cursor(&self, c: Cursor) -> Status {
unsafe { Status::from(p::puglSetCursor(self.view(), c.into())) }
}
fn update (&self, timeout: f64) -> Status {
unsafe { Status::from(p::puglUpdate(self.world(), timeout)) }
}
fn start_timer(&self, id: usize, timeout: f64) -> Status {
unsafe { Status::from(p::puglStartTimer(self.view(), id, timeout)) }
}
fn stop_timer(&self, id: usize) -> Status {
unsafe { Status::from(p::puglStopTimer(self.view(), id)) }
}
fn timer_event(&mut self, _id: usize) -> Status { Status::Success }
}
pub struct PuglView<T: PuglViewTrait> {
ui_type: std::marker::PhantomData<T>,
instance: *mut p::PuglView
}
unsafe extern "C"
fn event_handler<T: PuglViewTrait> (view_ptr: *mut p::PuglView, event_ptr: *const p::PuglEvent) -> p::PuglStatus {
let ev = *event_ptr;
let handle: &mut T = &mut *(p::puglGetHandle(view_ptr) as *mut T);
let event = match ev.type_ {
p::PuglEventType_PUGL_KEY_PRESS => {
Event { data: EventType::KeyPress(Key::from (ev.key)), context: EventContext::from (ev.key) }
},
p::PuglEventType_PUGL_KEY_RELEASE => {
Event { data: EventType::KeyRelease(Key::from (ev.key)), context: EventContext::from (ev.key) }
},
p::PuglEventType_PUGL_BUTTON_PRESS => {
Event { data: EventType::MouseButtonPress(MouseButton::from (ev.button)), context: EventContext::from (ev.button) }
},
p::PuglEventType_PUGL_BUTTON_RELEASE => {
Event { data: EventType::MouseButtonRelease(MouseButton::from (ev.button)), context: EventContext::from (ev.button) }
},
p::PuglEventType_PUGL_MOTION_NOTIFY => {
Event { data: EventType::MouseMove(MotionContext::from (ev.motion)), context: EventContext::from (ev.motion) }
},
p::PuglEventType_PUGL_SCROLL => {
Event { data: EventType::Scroll(Scroll::from (ev.scroll)), context: EventContext::from (ev.scroll) }
},
p::PuglEventType_PUGL_FOCUS_IN => {
return handle.focus_in() as p::PuglStatus
},
p::PuglEventType_PUGL_FOCUS_OUT => {
return handle.focus_out() as p::PuglStatus
},
p::PuglEventType_PUGL_TIMER => {
return handle.timer_event(ev.timer.id) as p::PuglStatus
}
p::PuglEventType_PUGL_CLOSE => {
handle.close_request ();
return p::PuglStatus_PUGL_SUCCESS
}
p::PuglEventType_PUGL_EXPOSE => {
let cr = cairo::Context::from_raw_borrow (p::puglGetContext(view_ptr) as *mut cairo_sys::cairo_t);
handle.exposed (&ExposeArea::from (ev.expose), &cr);
return p::PuglStatus_PUGL_SUCCESS
},
p::PuglEventType_PUGL_CONFIGURE => {
let size = Size::from (ev.configure);
handle.resize (size);
return p::PuglStatus_PUGL_SUCCESS
},
_ => { return p::PuglStatus_PUGL_SUCCESS }
};
handle.event (event) as p::PuglStatus
}
impl<T: PuglViewTrait> PuglView<T> {
pub fn make_view(mut handle: Box<T>, parent_window: *mut std::ffi::c_void) -> Box<Self> {
let view = Box::new(PuglView {
instance: unsafe {
p::puglNewView(p::puglNewWorld(p::PuglWorldType_PUGL_PROGRAM, 0))
},
ui_type: PhantomData
});
handle.set_view(view.instance);
let handle = Box::into_raw(handle) as *const T;
unsafe {
if !parent_window.is_null() {
println!("Parent window is {}", parent_window as usize);
p::puglSetParentWindow(view.instance, parent_window as usize);
}
p::puglSetHandle(view.instance, handle as p::PuglHandle);
p::puglSetEventFunc(view.instance, Some(event_handler::<T>));
p::puglSetBackend(view.instance, p::puglCairoBackend());
p::puglSetViewHint(view.instance, p::PuglViewHint_PUGL_IGNORE_KEY_REPEAT, true as i32);
}
view
}
pub fn handle(&mut self) -> &mut T {
unsafe {
&mut *(p::puglGetHandle(self.instance) as *mut T) as &mut T
}
}
pub fn view(&self) -> PuglViewFFI {
self.instance
}
pub fn native_window(&self) -> p::PuglNativeView {
unsafe { p::puglGetNativeWindow(self.view()) }
}
}
impl<T: PuglViewTrait> Drop for PuglView<T> {
fn drop(&mut self) {
unsafe {
let instance = self.instance as *mut p::PuglView;
let world = p::puglGetWorld(instance);
p::puglFreeView(instance);
p::puglFreeWorld(world);
};
}
}