Created
June 1, 2017 08:47
-
-
Save haudan/64dd018eb7e0fc587d2a337230b3a51d to your computer and use it in GitHub Desktop.
Rust GUI core concept
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
enum MouseButton { | |
Left, | |
Middle, | |
Right, | |
} | |
enum UiEvent { | |
MouseMove(i32, i32), | |
MouseClicked(i32, i32, MouseButton), | |
} | |
impl UiEvent { | |
fn position(&self) -> Option<(i32, i32)> { | |
use UiEvent::*; | |
match *self { | |
MouseMove(x, y) => Some((x, y)), | |
MouseClicked(x, y, ..) => Some((x, y)), | |
_ => None, | |
} | |
} | |
} | |
#[derive(Clone, Copy)] | |
struct Bbox { | |
min: (i32, i32), | |
max: (i32, i32), | |
} | |
impl Bbox { | |
fn new(min: (i32, i32), max: (i32, i32)) -> Self { | |
Bbox { min: min, max: max } | |
} | |
fn with_size(origin: (i32, i32), size: (i32, i32)) -> Self { | |
Bbox::new(origin, (origin.0 + size.0, origin.1 + size.1)) | |
} | |
fn size(&self) -> (i32, i32) { | |
let ((min_x, min_y), (max_x, max_y)) = (self.min, self.max); | |
(max_x - min_x, max_y - min_y) | |
} | |
fn contains_point(&self, point: (i32, i32)) -> bool { | |
let ((min_x, min_y), (max_x, max_y), (px, py)) = (self.min, self.max, point); | |
px >= min_x && px <= max_x && py >= min_y && py <= max_y | |
} | |
fn absolute_to(&self, abs_to: Bbox) -> Bbox { | |
let min = (self.min.0 + abs_to.min.0, self.min.1 + abs_to.min.1); | |
let max = (self.max.0 + abs_to.max.0, self.max.1 + abs_to.max.1); | |
Bbox::new(min, max) | |
} | |
} | |
trait Widget { | |
fn bbox(&self) -> Bbox; | |
fn handle_event(&mut self, event: UiEvent); | |
fn draw(&mut self); | |
} | |
struct ButtonWidget; | |
impl Widget for ButtonWidget { | |
fn bbox(&self) -> Bbox { | |
Bbox::new((10, 10), (200, 20)) | |
} | |
fn handle_event(&mut self, event: UiEvent) { | |
match event { | |
UiEvent::MouseClicked(_, _, MouseButton::Left) => println!("Button clicked!"), | |
_ => {} | |
} | |
} | |
fn draw(&mut self) { | |
println!("Drawing button"); | |
} | |
} | |
struct Window { | |
title: String, | |
bbox: Bbox, | |
widgets: Vec<Box<Widget>>, | |
} | |
impl Window { | |
fn handle_event(&mut self, event: UiEvent) { | |
if let Some(p) = event.position() { | |
let self_bbox = self.bbox; | |
if let Some(widget) = self.widgets | |
.iter_mut() | |
.filter(|w| w.bbox().absolute_to(self_bbox).contains_point(p)) | |
.next() { | |
widget.handle_event(event); | |
} | |
} | |
} | |
} | |
struct WindowManager { | |
windows: Vec<Window>, | |
} | |
impl WindowManager { | |
fn handle_event(&mut self, event: UiEvent) { | |
if let Some(p) = event.position() { | |
if let Some(window) = self.windows | |
.iter_mut() | |
.filter(|w| w.bbox.contains_point(p)) | |
.next() { | |
println!("Passing event onto window `{}`.", window.title); | |
window.handle_event(event); | |
} else { | |
println!("No window found at {:?} to handle the event.", p); | |
} | |
} | |
} | |
} | |
fn main() { | |
let mut manager = WindowManager { windows: Vec::new() }; | |
let mut window = Window { | |
title: "Main Window".to_owned(), | |
bbox: Bbox::with_size((100, 100), (640, 480)), | |
widgets: Vec::new(), | |
}; | |
let button = ButtonWidget; | |
window.widgets.push(Box::new(button)); | |
manager.windows.push(window); | |
manager.handle_event(UiEvent::MouseClicked(300, 300, MouseButton::Left)); | |
manager.handle_event(UiEvent::MouseClicked(15, 15, MouseButton::Left)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment