Skip to content

Instantly share code, notes, and snippets.

@haudan
Created June 1, 2017 08:47
Show Gist options
  • Save haudan/64dd018eb7e0fc587d2a337230b3a51d to your computer and use it in GitHub Desktop.
Save haudan/64dd018eb7e0fc587d2a337230b3a51d to your computer and use it in GitHub Desktop.
Rust GUI core concept
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