123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 |
- use kahlo::prelude::*;
- use crate::{
- component::Component,
- input::MouseButton,
- layout::{LayoutNode, LayoutNodeAccess, LayoutNodeContainer, SizePolicy},
- ui::UIHandle,
- };
- use super::{Label, Widget};
- enum ButtonState {
- Idle,
- Hovered,
- Clicked,
- }
- pub struct Button<C: Component> {
- layout: LayoutNode,
- label: Label<C>,
- state: ButtonState,
- hook: Option<Box<dyn Fn() -> Option<C::Msg>>>,
- }
- impl<C: Component> Button<C> {
- pub fn new(uih: &UIHandle) -> Self {
- let mut layout = uih.new_layout_node();
- layout
- .set_width_policy(SizePolicy::expands(1))
- .set_height_policy(SizePolicy {
- minimum: uih.theme().ui_font_size as usize,
- desired: (uih.theme().ui_font_size * 1.5) as usize,
- slack_weight: 0,
- });
- Self {
- layout,
- label: Label::new(uih),
- state: ButtonState::Idle,
- hook: None,
- }
- }
- pub fn set_label(&mut self, label: &str) {
- self.label.set_text(label);
- }
- pub fn set_hook(&mut self, to: Box<dyn Fn() -> Option<C::Msg>>) {
- self.hook = Some(to);
- }
- }
- impl<C: Component> LayoutNodeContainer for Button<C> {
- fn layout_node(&self) -> &LayoutNode {
- &self.layout
- }
- fn layout_child(&self, ndx: usize) -> Option<LayoutNodeAccess<'_>> {
- if ndx == 0 {
- Some(self.label.layout_node())
- } else {
- None
- }
- }
- fn layout_child_count(&self) -> usize {
- 1
- }
- }
- impl<C: Component> Widget<C> for Button<C> {
- fn poll(
- &mut self,
- uih: &mut UIHandle,
- input_state: Option<&crate::input::InputState>,
- ) -> Vec<<C as Component>::Msg> {
- let mut result: Vec<<C as Component>::Msg> = vec![];
- if let (Some(istate), Some(area)) = (input_state, self.layout.render_area()) {
- if area.contains_inclusive(istate.mouse.pos) {
- println!("cursor on button");
- if istate.mouse.buttons.active(MouseButton::Left) {
- self.state = ButtonState::Clicked;
- } else if istate.mouse.released().active(MouseButton::Left) {
- self.state = ButtonState::Idle;
- result.extend(self.hook.as_ref().map(|v| v()).flatten().into_iter());
- } else {
- self.state = ButtonState::Hovered;
- }
- } else {
- self.state = ButtonState::Idle;
- }
- }
- result.extend(self.label.poll(uih, input_state).into_iter());
- result
- }
- fn layout_node(&self) -> LayoutNodeAccess {
- LayoutNodeAccess::new(self)
- }
- fn layout_node_mut(&mut self) -> &mut LayoutNode {
- &mut self.layout
- }
- fn render(&self, theme: &crate::theme::Theme, target: &mut kahlo::RgbaBitmap) {
- let colour = match self.state {
- ButtonState::Idle => theme.background,
- ButtonState::Hovered => theme.panel,
- ButtonState::Clicked => theme.foreground,
- };
- target.fill_region(self.layout.render_area().unwrap(), colour);
- self.label.render(theme, target);
- }
- }
|