From 4a4b94ba2a513576248522714cf016f5508766db Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Sun, 22 May 2022 19:23:58 +0300 Subject: [PATCH] click events! soon there will be buttons! --- src/application.rs | 27 +++++++++++++- src/layout/position.rs | 4 ++ src/widget/column.rs | 75 ++++++++++++++++++++++++++++++++++++- src/widget/label.rs | 23 +++++++++++- src/widget/mod.rs | 20 +++++++++- src/widget/padding.rs | 29 ++++++++++++++- src/widget/row.rs | 75 ++++++++++++++++++++++++++++++++++++- src/window.rs | 84 ++++++++++++++++++++++++++++++++++-------- 8 files changed, 315 insertions(+), 22 deletions(-) diff --git a/src/application.rs b/src/application.rs index 28248ec..ed7de60 100755 --- a/src/application.rs +++ b/src/application.rs @@ -9,7 +9,7 @@ use std::cell::RefCell; use std::collections::HashMap; use std::rc::Rc; -use winit::event::{Event, WindowEvent as WinitWindowEvent}; +use winit::event::{Event, WindowEvent as WinitWindowEvent, ElementState}; use winit::event_loop::EventLoop; use winit::window::WindowId; use crate::context::Context; @@ -107,14 +107,39 @@ impl Application { emit_app_event!(self, ApplicationEvent::AllWindowsDestroyed); } } + Event::WindowEvent { window_id, event: WinitWindowEvent::Resized(size) } => self.windows.get_mut(&window_id).unwrap().resized(size), + + Event::WindowEvent { + window_id, + event: WinitWindowEvent::CursorMoved { + position, + .. + }, + } => self.windows.get_mut(&window_id).unwrap().cursor_moved(position), + + Event::WindowEvent { + window_id, + event: WinitWindowEvent::MouseInput { + state, + button, + .. + }, + } => match state { + ElementState::Pressed => self.windows + .get_mut(&window_id).unwrap().mouse_pressed(button), + ElementState::Released => self.windows + .get_mut(&window_id).unwrap().mouse_released(button), + } + Event::MainEventsCleared => { // determine if state changed and request redraw if needed // rinse and repeat for every window } + Event::RedrawRequested(window_id) => self.windows.get_mut(&window_id).unwrap().render(), diff --git a/src/layout/position.rs b/src/layout/position.rs index 90442d3..fc8ecb5 100755 --- a/src/layout/position.rs +++ b/src/layout/position.rs @@ -18,6 +18,10 @@ impl Position { pub fn new(x: u32, y: u32, width: u32, height: u32) -> Self { Position { x, y, width, height } } + + pub fn contains(&self, x: u32, y: u32) -> bool { + x >= self.x && y >= self.y && x < self.x + self.width && y < self.y + self.height + } pub fn x(&self) -> u32 { self.x diff --git a/src/widget/column.rs b/src/widget/column.rs index 2029091..a854568 100755 --- a/src/widget/column.rs +++ b/src/widget/column.rs @@ -6,8 +6,9 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use crate::{layout::position::Position, widget::Widget}; +use crate::{layout::position::Position, widget::Widget, window::Window}; use abletk_common::Renderer; +use winit::event::MouseButton; pub struct Column { widgets: Vec>, @@ -43,6 +44,78 @@ impl Widget for Column { Position::new(0, 0, width, height) } + + fn mouse_pressed(&mut self, + renderer: &mut Renderer, + window: &mut Window, + button: MouseButton, + x: u32, + y: u32, + ) { + let mut pos = Position::new(0, 0, 0, 0); + for widget in &mut self.widgets { + let widget_pos = widget.position(renderer); + pos = Position::new( + widget_pos.x(), + pos.y() + widget_pos.y(), + widget_pos.width(), + widget_pos.height(), + ); + + if pos.contains(x, y) { + widget.mouse_pressed( + renderer, + window, + button, + x - pos.x(), + y - pos.y(), + ); + } + + pos = Position::new( + pos.x(), + pos.y() + widget_pos.height(), + pos.width(), + pos.height(), + ) + } + } + + fn mouse_released(&mut self, + renderer: &mut Renderer, + window: &mut Window, + button: MouseButton, + x: u32, + y: u32, + ) { + let mut pos = Position::new(0, 0, 0, 0); + for widget in &mut self.widgets { + let widget_pos = widget.position(renderer); + pos = Position::new( + widget_pos.x(), + pos.y() + widget_pos.y(), + widget_pos.width(), + widget_pos.height(), + ); + + if pos.contains(x, y) { + widget.mouse_released( + renderer, + window, + button, + x - pos.x(), + y - pos.y(), + ); + } + + pos = Position::new( + pos.x(), + pos.y() + widget_pos.height(), + pos.width(), + pos.height(), + ) + } + } } impl Column { diff --git a/src/widget/label.rs b/src/widget/label.rs index 5434b9f..ce9cff1 100755 --- a/src/widget/label.rs +++ b/src/widget/label.rs @@ -7,7 +7,8 @@ */ use abletk_common::{Renderer, brush::Brush, color::Color, rgb}; -use crate::{widget::Widget, layout::position::Position}; +use winit::event::MouseButton; +use crate::{widget::Widget, layout::position::Position, window::Window}; pub struct Label { text: String, @@ -28,6 +29,26 @@ impl Widget for Label { let (width, height) = renderer.get_text_size(&self.text); Position::new(0, 0, width, height) } + + fn mouse_pressed(&mut self, + renderer: &mut Renderer, + window: &mut Window, + button: MouseButton, + x: u32, + y: u32, + ) { + eprintln!("Label::mouse_pressed {} {x}, {y}", self.text); + } + + fn mouse_released(&mut self, + renderer: &mut Renderer, + window: &mut Window, + button: MouseButton, + x: u32, + y: u32, + ) { + eprintln!("Label::mouse_released {} {x}, {y}", self.text); + } } impl Label { diff --git a/src/widget/mod.rs b/src/widget/mod.rs index 06a4534..0a69a9a 100755 --- a/src/widget/mod.rs +++ b/src/widget/mod.rs @@ -16,11 +16,29 @@ pub use column::*; pub use label::*; pub use padding::*; pub use row::*; +use winit::event::MouseButton; -use crate::layout::position::Position; +use crate::{layout::position::Position, window::Window}; pub trait Widget { fn draw(&self, renderer: &mut Renderer); + // fixme: don't pass renderer fn position(&self, renderer: &mut Renderer) -> Position; + + fn mouse_pressed(&mut self, + renderer: &mut Renderer, + window: &mut Window, + button: MouseButton, + x: u32, + y: u32, + ); + + fn mouse_released(&mut self, + renderer: &mut Renderer, + window: &mut Window, + button: MouseButton, + x: u32, + y: u32, + ); } diff --git a/src/widget/padding.rs b/src/widget/padding.rs index db3a1fb..c154e07 100755 --- a/src/widget/padding.rs +++ b/src/widget/padding.rs @@ -6,8 +6,9 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use crate::{layout::position::Position, widget::Widget}; +use crate::{layout::position::Position, widget::Widget, window::Window}; use abletk_common::Renderer; +use winit::event::MouseButton; pub struct Padding { widget: W, @@ -32,6 +33,32 @@ impl Widget for Padding { pos.height() + self.bottom, ) } + + fn mouse_pressed(&mut self, + renderer: &mut Renderer, + window: &mut Window, + button: MouseButton, + x: u32, + y: u32, + ) { + let pos = self.position(renderer); + if pos.contains(x, y) { + self.widget.mouse_pressed(renderer, window, button, x - pos.x(), y - pos.y()); + } + } + + fn mouse_released(&mut self, + renderer: &mut Renderer, + window: &mut Window, + button: MouseButton, + x: u32, + y: u32, + ) { + let pos = self.position(renderer); + if pos.contains(x, y) { + self.widget.mouse_released(renderer, window, button, x - pos.x(), y - pos.y()); + } + } } impl Padding { diff --git a/src/widget/row.rs b/src/widget/row.rs index a5dbc2f..828e6fd 100755 --- a/src/widget/row.rs +++ b/src/widget/row.rs @@ -6,8 +6,9 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use crate::{layout::position::Position, widget::Widget}; +use crate::{layout::position::Position, widget::Widget, window::Window}; use abletk_common::Renderer; +use winit::event::MouseButton; pub struct Row { widgets: Vec>, @@ -43,6 +44,78 @@ impl Widget for Row { Position::new(0, 0, width, height) } + + fn mouse_pressed(&mut self, + renderer: &mut Renderer, + window: &mut Window, + button: MouseButton, + x: u32, + y: u32, + ) { + let mut pos = Position::new(0, 0, 0, 0); + for widget in &mut self.widgets { + let widget_pos = widget.position(renderer); + pos = Position::new( + widget_pos.x() + pos.x(), + widget_pos.y(), + widget_pos.width(), + widget_pos.height(), + ); + + if pos.contains(x, y) { + widget.mouse_pressed( + renderer, + window, + button, + x - pos.x(), + y - pos.y(), + ); + } + + pos = Position::new( + pos.x() + widget_pos.width(), + pos.y(), + pos.width(), + pos.height(), + ); + } + } + + fn mouse_released(&mut self, + renderer: &mut Renderer, + window: &mut Window, + button: MouseButton, + x: u32, + y: u32, + ) { + let mut pos = Position::new(0, 0, 0, 0); + for widget in &mut self.widgets { + let widget_pos = widget.position(renderer); + pos = Position::new( + widget_pos.x() + pos.x(), + widget_pos.y(), + widget_pos.width(), + widget_pos.height(), + ); + + if pos.contains(x, y) { + widget.mouse_released( + renderer, + window, + button, + x - pos.x(), + y - pos.y(), + ); + } + + pos = Position::new( + pos.x() + widget_pos.width(), + pos.y(), + pos.width(), + pos.height(), + ); + } + } } impl Row { diff --git a/src/window.rs b/src/window.rs index 7a2af89..f42dc46 100755 --- a/src/window.rs +++ b/src/window.rs @@ -12,7 +12,7 @@ use std::rc::Rc; use raw_window_handle::HasRawWindowHandle; use winit::{ event_loop::EventLoopWindowTarget, - window::{Window as WinitWindow, WindowBuilder as WinitWindowBuilder}, + window::{Window as WinitWindow, WindowBuilder as WinitWindowBuilder}, dpi::PhysicalPosition, event::MouseButton, }; use winit::dpi::PhysicalSize; use winit::error::OsError; @@ -26,10 +26,11 @@ use crate::widget::Widget; pub struct Window { window: WinitWindow, events: HashMap>, - root: Box, + root: Option>, ctx: Rc>, - renderer: Renderer, + renderer: Option, background: Color, + cursor_pos: (u32, u32), } impl Window { @@ -58,12 +59,13 @@ impl Window { .build(event_loop)?; Ok(Self { - renderer: Renderer::new(window.raw_window_handle()), + renderer: Some(Renderer::new(window.raw_window_handle())), window, background, events, - root, + root: Some(root), ctx, + cursor_pos: (0, 0), }) } @@ -72,16 +74,14 @@ impl Window { } pub(crate) fn render(&mut self) { - let position = self.root.position(&mut self.renderer); - self.renderer.begin_draw(); - self.renderer.clear(self.background); - self.renderer.position_at(position.x(), position.y()); - self.root.draw(&mut self.renderer); - self.renderer.end_draw() - } - - pub fn set_always_on_top(&self, value: bool) { - self.window.set_always_on_top(value) + let root = self.root.as_ref().unwrap(); + let renderer = self.renderer.as_mut().unwrap(); + let position = root.position(renderer); + renderer.begin_draw(); + renderer.clear(self.background); + renderer.position_at(position.x(), position.y()); + root.draw(renderer); + renderer.end_draw() } pub fn focus(&self) { @@ -92,6 +92,10 @@ impl Window { self.window.request_redraw() } + pub fn set_always_on_top(&self, value: bool) { + self.window.set_always_on_top(value) + } + pub fn set_title + Into>(&mut self, title: S) { self.window.set_title(title.as_ref()) } @@ -109,12 +113,60 @@ impl Window { } } + pub(crate) fn cursor_moved(&mut self, pos: PhysicalPosition) { + self.cursor_pos = (pos.x as u32, pos.y as u32) + } + pub(crate) fn id(&self) -> WindowId { self.window.id() } + pub(crate) fn mouse_pressed(&mut self, button: MouseButton) { + if self.root + .as_ref() + .unwrap() + .position(self.renderer.as_mut().unwrap()) + .contains(self.cursor_pos.0, self.cursor_pos.1) + { + let mut root = self.root.take().unwrap(); + let mut renderer = self.renderer.take().unwrap(); + root.mouse_pressed( + &mut renderer, + self, + button, + self.cursor_pos.0, + self.cursor_pos.1, + ); + + self.root = Some(root); + self.renderer = Some(renderer); + } + } + + pub(crate) fn mouse_released(&mut self, button: MouseButton) { + if self.root + .as_ref() + .unwrap() + .position(self.renderer.as_mut().unwrap()) + .contains(self.cursor_pos.0, self.cursor_pos.1) + { + let mut root = self.root.take().unwrap(); + let mut renderer = self.renderer.take().unwrap(); + root.mouse_released( + &mut renderer, + self, + button, + self.cursor_pos.0, + self.cursor_pos.1, + ); + + self.root = Some(root); + self.renderer = Some(renderer); + } + } + pub(crate) fn resized(&mut self, size: PhysicalSize) { - self.renderer.resized(size.width, size.height); + self.renderer.as_mut().unwrap().resized(size.width, size.height); self.emit_event(Event::Resized) } }