use crate::prelude::*;
use crate::core::*;
use crate::core::builder::*;
use crate::backends::backend;
#[derive(Clone)]
pub struct Display {
pub(crate) handle: backend::Display,
pub(crate) context: Context,
pub(crate) frame: Rc<RefCell<Option<backend::Frame>>>,
pub(crate) input_data: Arc<RwLock<InputData>>,
pub(crate) fullscreen: Rc<RefCell<Option<Monitor>>>,
}
impl Debug for Display {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Display")
}
}
impl Display {
pub fn builder() -> DisplayBuilder {
DisplayBuilder::new()
}
pub fn set_title(self: &Self, title: &str) {
self.handle.set_title(title);
}
pub fn show(self: &Self) {
self.handle.show();
}
pub fn hide(self: &Self) {
self.handle.hide();
}
pub fn set_fullscreen(self: &Self, monitor: Option<Monitor>) -> Result<()> {
let target = if let Some(given_monitor) = monitor {
given_monitor
} else if let Some(default_monitor) = backend::MonitorIterator::new().next() {
Monitor::new(default_monitor)
} else {
return Err(Error::Failed);
};
if !self.handle.set_fullscreen(Some(target.clone())) {
self.handle.set_fullscreen(None);
Err(Error::FullscreenError("Failed to switch to fullscreen.".to_string()))
} else {
*self.fullscreen.borrow_mut() = Some(target);
Ok(())
}
}
pub fn set_windowed(self: &Self) {
self.handle.set_fullscreen(None);
*self.fullscreen.borrow_mut() = None;
}
pub fn toggle_fullscreen(self: &Self, monitor: Option<Monitor>) -> Result<()> {
if self.fullscreen.borrow().is_some() {
self.set_windowed();
Ok(())
} else {
self.set_fullscreen(monitor)
}
}
pub fn input(self: &Self) -> Input {
Input { input_data: self.input_data.clone() }
}
pub fn prepare_frame(self: &Self) {
if self.frame.borrow().is_some() {
panic!("Current frame needs to be swapped before a new frame can be prepared.");
}
*self.frame.borrow_mut() = Some(self.handle.draw());
}
pub fn clear_frame(self: &Self, color: Color) {
self.prepare_frame();
if let Some(ref mut frame) = self.frame.borrow_mut().as_mut() {
frame.clear(color);
} else {
panic!("Failed to prepare a frame for clear.");
}
}
pub fn swap_frame(self: &Self) {
let frame = mem::replace(&mut *self.frame.borrow_mut(), None);
if let Some(frame) = frame {
frame.finish();
} else {
panic!("No frame currently prepared, nothing to swap.");
}
}
pub fn grab_cursor(self: &Self) {
let mut input_data = self.input_data.write().unwrap();
if input_data.has_focus {
self.handle.set_cursor_state(CursorState::Grab);
}
input_data.cursor_grabbed = true;
}
pub fn hide_cursor(self: &Self) {
self.handle.set_cursor_state(CursorState::Hide);
self.input_data.write().unwrap().cursor_grabbed = false;
}
pub fn free_cursor(self: &Self) {
self.handle.set_cursor_state(CursorState::Normal);
self.input_data.write().unwrap().cursor_grabbed = false;
}
pub fn set_cursor_position(self: &Self, position: Point2<i32>) {
self.handle.set_cursor_position(position);
}
pub fn dimensions(self: &Self) -> Point2<u32> {
self.handle.framebuffer_dimensions()
}
pub fn monitors() -> Vec<Monitor> {
let iter = backend::MonitorIterator::new();
let mut result = Vec::<Monitor>::new();
for monitor in iter {
result.push(Monitor::new(monitor));
}
result
}
pub fn poll_events(self: &Self) -> &Self {
let mut input_data = self.input_data.write().unwrap();
input_data.reset();
self.handle.poll_events(|event| {
match event {
Event::KeyboardInput(key_id, down) => {
let currently_down = match input_data.key[key_id] {
InputState::Down | InputState::Pressed | InputState::Repeat => true,
_ => false
};
if !currently_down && down {
input_data.key[key_id] = InputState::Pressed;
} else if currently_down && !down {
input_data.key[key_id] = InputState::Released;
} else if currently_down && down {
input_data.key[key_id] = InputState::Repeat;
}
},
Event::MouseDelta(x, y) => {
input_data.mouse_delta = (x, y);
},
Event::MousePosition(x, y) => {
input_data.mouse = (x, y);
},
Event::MouseInput(button_id, down) => {
let currently_down = match input_data.button[button_id] {
InputState::Down | InputState::Pressed => true,
_ => false
};
if !currently_down && down {
input_data.button[button_id] = InputState::Pressed
} else if currently_down && !down {
input_data.button[button_id] = InputState::Released
}
},
Event::Focus => {
input_data.has_focus = true;
if input_data.cursor_grabbed {
self.handle.set_cursor_state(CursorState::Grab);
}
}
Event::Blur => {
input_data.has_focus = false;
self.handle.set_cursor_state(CursorState::Normal);
}
Event::Close => {
input_data.should_close = true;
}
}
});
input_data.dimensions = self.handle.window_dimensions().into();
self
}
pub fn was_closed(self: &Self) -> bool {
let mut input_data = self.input_data.write().unwrap();
let result = input_data.should_close;
input_data.should_close = false;
result
}
pub fn context(self: &Self) -> &Context {
&self.context
}
pub(crate) fn new(descriptor: DisplayBuilder) -> Result<Display> {
let context = if let Some(existing_context) = descriptor.context.clone() {
existing_context
} else {
Context::new()
};
let shared_gpu = descriptor.context.as_ref().and_then(|ctx| {
ctx.lock().backend_context.as_ref().map(|bc| bc.shared_gpu())
});
let fullscreen = descriptor.monitor.clone();
let display = backend::Display::new(descriptor, shared_gpu)?;
{
let mut context = context.lock();
if !context.has_primary_display() {
context.set_primary_display(&display);
}
}
Ok(Display {
handle : display,
context : context,
frame : Rc::new(RefCell::new(None)),
input_data : Arc::new(RwLock::new(InputData::new())),
fullscreen : Rc::new(RefCell::new(fullscreen)),
})
}
}
impl AsRenderTarget for Display {
fn as_render_target(self: &Self) -> RenderTarget {
RenderTarget::frame(&self.frame)
}
}
#[derive(Debug)]
pub enum CursorState {
Normal,
Hide,
Grab,
}
#[derive(Debug, PartialEq)]
pub enum Event {
KeyboardInput(usize, bool),
MouseInput(usize, bool),
MouseDelta(i32, i32),
MousePosition(i32, i32),
Focus,
Blur,
Close,
}