use super::*; pub struct CustomWidget<'a> { pub position: &'a mut Aabb2, // Hidden pub animation_time: &'a mut f32, // state pub sense: &'a mut geng::ui::Sense, // Helper hidden state for interaction pub change: RefCell<&'a mut Option>, // Result of interaction is optionally a change that was made pub assets: &'a Assets, pub ratio: f32, hover_at: &'a mut Option, } impl<'a> CustomWidget<'a> { pub fn new(cx: &'a geng::ui::Controller, assets: &'a Assets, ratio: f32) -> Self { Self { position: cx.get_state_with(|| Aabb2::point(vec2::ZERO)), // Specify default value for hidden state animation_time: cx.get_state(), sense: cx.get_state(), // Or just use Default trait hover_at: cx.get_state(), change: RefCell::new(cx.get_state()), assets, ratio, } } // We had a RefCell so that this method doesn't need a mut reference to self pub fn get_change(&self) -> Option { self.change.borrow_mut().take() } } impl geng::ui::Widget for CustomWidget<'_> { fn calc_constraints( &mut self, _children: &geng::ui::ConstraintsContext, ) -> geng::ui::Constraints { geng::ui::Constraints { min_size: vec2(100.0, 100.0), flex: vec2(0.0, 0.0), } } // If using Sense helper this method must be added fn sense(&mut self) -> Option<&mut geng::ui::Sense> { Some(self.sense) } fn update(&mut self, delta_time: f64) { #![allow(unused_variables)] } fn draw(&mut self, cx: &mut geng::ui::DrawContext) { *self.position = cx.position.map(|x| x as f32); // Update hidden state to remember our widget's position #[derive(ugli::Vertex)] struct Vertex { a_pos: vec2, } ugli::draw( cx.framebuffer, &self.assets.shader, ugli::DrawMode::TriangleFan, &ugli::VertexBuffer::new_dynamic( cx.draw2d.ugli(), vec![ Vertex { a_pos: vec2(0.0, 0.0), }, Vertex { a_pos: vec2(1.0, 0.0), }, Vertex { a_pos: vec2(1.0, 1.0), }, Vertex { a_pos: vec2(0.0, 1.0), }, ], ), ( ugli::uniforms! { u_texture: &self.assets.texture, u_pos: cx.position.bottom_left().map(|x| x as f32), u_size: cx.position.size().map(|x| x as f32), u_ratio: self.ratio, }, geng::PixelPerfectCamera.uniforms(cx.framebuffer.size().map(|x| x as f32)), ), ugli::DrawParameters { blend_mode: Some(ugli::BlendMode::straight_alpha()), ..default() }, ); } fn handle_event(&mut self, event: &geng::Event) { // Use helper to determine if we should process interactions if let geng::Event::CursorMove { position } = event { *self.hover_at = Some( ((position.y as f32 - self.position.min.y) / self.position.height().max(0.1)) .clamp(0.0, 1.0), ); } if self.sense.is_captured() { if let geng::Event::MousePress { .. } | geng::Event::CursorMove { .. } = event { if let Some(new_value) = *self.hover_at { **self.change.borrow_mut() = Some(new_value); } } } } }