~comcloudway/little_town

22adb12345b5c9f0bd6d1965cee91cb773633705 — Jakob Meier 1 year, 8 months ago a0f7f5c
Moved components into separate file
6 files changed, 629 insertions(+), 408 deletions(-)

D src/draw.rs
A src/ui/centered_text.rs
A src/ui/item_frame.rs
A src/ui/mod.rs
A src/ui/selectable_text.rs
A src/ui/text_button.rs
D src/draw.rs => src/draw.rs +0 -408
@@ 1,408 0,0 @@
use macroquad::prelude::*;
use crate::textures::AssetStore;

/// A UI item that can be rendered
pub trait Widget {
    /// Message types returned from the event loop
    type Event;
    /// Callback used to redraw the component
    async fn draw(&self, assets: &AssetStore);
    /// Callback used to perform background tasks
    /// e.g. keyboard input
    /// NOTE: this is currently not being run asynchronously
    /// when running large operations, spawn a separate thread
    fn ev_loop(&mut self) -> Self::Event;
    // returns the width and height of the widget
    fn get_dimensions(&self) -> (f32, f32);
}

/// UI Widget
/// used to draw centered text
pub struct CenteredText {
    /// middle of widget (along the x axis)
    /// set in percent of the display width
    x: f32,
    /// middle of widget (along the y axis)
    /// set in percent of the display height
    y: f32,
    /// the text to draw
    text: String,
    /// custom font size to use
    /// default is 60
    font_size: Option<u16>,
    /// the font to use
    /// defaults to macroquad default font
    font: Option<Font>,
    /// text color
    /// defaults to white
    color: Option<Color>
}
impl CenteredText {
    /// create new centered-text widget
    pub fn new(text: &str, x: f32, y: f32) -> Self {
        Self {
            x,
            y,
            text: text.to_string(),
            font_size: None,
            font: None,
            color: None
        }
    }
    /// changes the text of the widget
    pub fn set_text(self, text: &str) -> Self {
        Self {
            text: text.to_string(),
            ..self
        }
    }
    /// sets the font size
    pub fn with_font_size(self, font_size: u16) -> Self {
        Self {
            font_size: Some(font_size),
            ..self
        }
    }
    /// sets the font
    pub fn with_font(self, font: Font) -> Self {
        Self {
            font: Some(font),
            ..self
        }
    }
    /// sets a custom color
    pub fn with_color(self, color: Color) -> Self {
        Self {
            color: Some(color),
            ..self
        }
    }
}
impl Widget for CenteredText {
    type Event = bool;
    async fn draw(&self, assets: &AssetStore) {
        let (x,y) = (screen_width() * self.x, screen_height() * self.y);

        let mut title_params = TextParams {
            font_size: self.font_size.unwrap_or(60),
            color: self.color.unwrap_or(WHITE),
            ..Default::default()
        };
        if let Some(font) = self.font {
            title_params.font = font;
        }
        let title_center = get_text_center(
            &self.text,
            self.font,
            self.font_size.unwrap_or(60),
            1.0,
            0.0);
        draw_text_ex(
            &self.text,
            x - title_center.x,
            y- title_center.y,
            title_params);
    }
    fn ev_loop(&mut self) -> Self::Event {
        true
    }
    fn get_dimensions(&self) -> (f32, f32) {
        let text_dim: TextDimensions = measure_text(
            &self.text,
            self.font,
            self.font_size.unwrap_or(60),
            1.0);
        (text_dim.width, text_dim.height)
    }
}

/// A button event send from the Button widget ev-loop
/// i.e WideButton
pub enum ButtonEvent {
    /// nothing happened
    None,
    /// user clicked on button with left mouse button
    LeftClick,
    /// user clicked on button with right mouse button
    RightClick
}
/// UI Widget
/// a clickable button with text on it
pub struct TextButton {
    /// the text on the button
    text: String,
    /// middle of button (x axis)
    /// specified in perfect of screen width
    x: f32,
    /// middle of button (y-axis)
    /// specified in perfect of screen height
    y: f32,
    /// the font used to draw the text
    font: Option<Font>,
    /// custom font color
    font_color: Option<Color>,
    /// custom font size to use
    font_size: Option<u16>,
    /// true if mouse is over button
    hovered: bool
}
impl TextButton {
    /// creates a new text button widget
    pub fn new(text: &str, x: f32, y: f32) -> Self {
        Self {
            text: text.to_string(),
            x,
            y,
            font: None,
            font_color: None,
            font_size: None,
            hovered: false
        }
    }
    /// sets the custom font
    pub fn with_font(self, font: Font) -> Self {
        Self {
            font: Some(font),
            ..self
        }
    }
    /// sets the font color
    pub fn with_font_color(self, color: Color) -> Self {
        Self {
            font_color: Some(color),
            ..self
        }
    }
    /// sets the font size
    pub fn with_font_size(self, size: u16) -> Self {
        Self {
            font_size: Some(size),
            ..self
        }
    }
}
impl Widget for TextButton {
    type Event = ButtonEvent;
    fn get_dimensions(&self) -> (f32, f32) {
        let text_dim: TextDimensions = measure_text(
            &self.text,
            self.font,
            self.font_size.unwrap_or(60),
            1.0);
        (text_dim.width + 30.0, text_dim.height+20.0)
    }
    async fn draw(&self, assets: &AssetStore) {
        let (x,y) = (screen_width() * self.x, screen_height() * self.y);
        let (width, height) = self.get_dimensions();

        draw_texture_ex(
            if self.hovered { assets.ui.long_button.1 } else { assets.ui.long_button.0 },
            x - width / 2.0,
            y - height / 2.0,
            WHITE,
            DrawTextureParams {
                dest_size: Some(Vec2::new(width, height)),
                source: None,
                rotation: 0.0,
                flip_x: false,
                flip_y: false,
                pivot: None
            });

        let text_center = get_text_center(
            &self.text,
            self.font,
            self.font_size.unwrap_or(60),
            1.0,
            0.0);
        draw_text_ex(
            &self.text,
            x - text_center.x,
            y - text_center.y,
            TextParams {
                font_size: self.font_size.unwrap_or(60),
                color: self.font_color.unwrap_or(WHITE),
                ..Default::default()
            });
    }
    fn ev_loop(&mut self) -> Self::Event {
        self.hovered = false;

        let (width, height) = self.get_dimensions();

        let (mx, my) = mouse_position();
        let (x,y) = (screen_width() * self.x, screen_height() * self.y);

        if mx >= x - width/2.0 && mx <= x + width/2.0
            && my >= y - height/2.0 && my <= y + height/2.0 {
                self.hovered = true;

                if is_mouse_button_pressed(MouseButton::Left) {
                    return Self::Event::LeftClick;
                }
                if is_mouse_button_pressed(MouseButton::Right) {
                    return Self::Event::RightClick;
                }
            }


        Self::Event::None
    }
}


/// A widget similar to a button,
/// but it can be selected
/// and will stay selected
pub struct SelectableText {
    /// the text on the button
    text: String,
    /// middle of button (x axis)
    /// specified in perfect of screen width
    x: f32,
    /// middle of button (y-axis)
    /// specified in perfect of screen height
    y: f32,
    /// the font used to draw the text
    font: Option<Font>,
    /// custom font color
    /// defaults to white
    font_color: Option<Color>,
    /// custom font size to use
    font_size: Option<u16>,
    /// true if widget option is selected
    selected: bool,
    /// if the widget is visible or not
    visible: bool
}
impl SelectableText {
    /// creates a new text button widget
    pub fn new(text: &str, x: f32, y: f32) -> Self {
        Self {
            text: text.to_string(),
            x,
            y,
            font: None,
            font_color: None,
            font_size: None,
            selected: false,
            visible: true
        }
    }
    /// set the visibility
    pub fn with_visibility(self, vis: bool) -> Self {
        Self {
            visible: vis,
            ..self
        }
    }
    /// sets the custom font
    pub fn with_font(self, font: Font) -> Self {
        Self {
            font: Some(font),
            ..self
        }
    }
    /// sets the font color
    pub fn with_font_color(self, color: Color) -> Self {
        Self {
            font_color: Some(color),
            ..self
        }
    }
    /// sets the font size
    pub fn with_font_size(self, size: u16) -> Self {
        Self {
            font_size: Some(size),
            ..self
        }
    }
    /// selects or unselects the Widget
    pub fn set_selected(&mut self, state: bool) {
        self.selected = state;
    }
    /// updates the widget text
    pub fn set_text(&mut self, text: &str) {
        self.text = text.to_string();
    }
    /// updates the widget visibility
    pub fn set_visibility(&mut self, vis: bool) {
        self.visible = vis;
    }
}
impl Widget for SelectableText {
    type Event = ButtonEvent;
    fn get_dimensions(&self) -> (f32, f32) {
        let text_dim: TextDimensions = measure_text(
            &self.text,
            self.font,
            self.font_size.unwrap_or(60),
            1.0);
        (text_dim.width + 30.0, text_dim.height+20.0)
    }
    async fn draw(&self, assets: &AssetStore) {
        if !self.visible {
            return;
        }

        let (x,y) = (screen_width() * self.x, screen_height() * self.y);
        let (width, height) = self.get_dimensions();

        let mut bg = assets.ui.panel_brown.0;
        if self.selected {
            // draw blue background
            bg = assets.ui.panel_blue.0;
        }
        // draw background
        draw_texture_ex(
            bg,
            x - width/2.0,
            y - height/2.0,
            WHITE,
            DrawTextureParams {
                dest_size: Some(Vec2::new(width, height)),
                ..Default::default()
            }
        );

        let text_center = get_text_center(
            &self.text,
            self.font,
            self.font_size.unwrap_or(60),
            1.0,
            0.0);
        draw_text_ex(
            &self.text,
            x - text_center.x,
            y - text_center.y,
            TextParams {
                font_size: self.font_size.unwrap_or(60),
                color: self.font_color.unwrap_or(WHITE),
                ..Default::default()
            });
    }
    fn ev_loop(&mut self) -> Self::Event {
        if !self.visible {
            return Self::Event::None;
        }

        let (width, height) = self.get_dimensions();

        let (mx, my) = mouse_position();
        let (x,y) = (screen_width() * self.x, screen_height() * self.y);

        if mx >= x - width/2.0 && mx <= x + width/2.0
            && my >= y - height/2.0 && my <= y + height/2.0 {
                if is_mouse_button_pressed(MouseButton::Left) {
                    return Self::Event::LeftClick;
                }
                if is_mouse_button_pressed(MouseButton::Right) {
                    return Self::Event::RightClick;
                }
            }


        Self::Event::None

    }
}

A src/ui/centered_text.rs => src/ui/centered_text.rs +104 -0
@@ 0,0 1,104 @@
use macroquad::prelude::*;
use crate::textures::AssetStore;
use super::Widget;

/// UI Widget
/// used to draw centered text
pub struct CenteredText {
    /// middle of widget (along the x axis)
    /// set in percent of the display width
    x: f32,
    /// middle of widget (along the y axis)
    /// set in percent of the display height
    y: f32,
    /// the text to draw
    text: String,
    /// custom font size to use
    /// default is 60
    font_size: Option<u16>,
    /// the font to use
    /// defaults to macroquad default font
    font: Option<Font>,
    /// text color
    /// defaults to white
    color: Option<Color>
}
impl CenteredText {
    /// create new centered-text widget
    pub fn new(text: &str, x: f32, y: f32) -> Self {
        Self {
            x,
            y,
            text: text.to_string(),
            font_size: None,
            font: None,
            color: None
        }
    }
    /// sets the font size
    #[allow(dead_code)]
    pub fn with_font_size(self, font_size: u16) -> Self {
        Self {
            font_size: Some(font_size),
            ..self
        }
    }
    /// sets the font
    #[allow(dead_code)]
    pub fn with_font(self, font: Font) -> Self {
        Self {
            font: Some(font),
            ..self
        }
    }
    /// sets a custom color
    #[allow(dead_code)]
    pub fn with_color(self, color: Color) -> Self {
        Self {
            color: Some(color),
            ..self
        }
    }
    /// updates the text of this widget
    #[allow(dead_code)]
    pub fn set_text(&mut self, text: &str) {
        self.text = text.to_string();
    }
}
impl Widget for CenteredText {
    type Event = bool;
    async fn draw(&self, _assets: &AssetStore) {
        let (x,y) = (screen_width() * self.x, screen_height() * self.y);

        let mut title_params = TextParams {
            font_size: self.font_size.unwrap_or(60),
            color: self.color.unwrap_or(WHITE),
            ..Default::default()
        };
        if let Some(font) = self.font {
            title_params.font = font;
        }
        let title_center = get_text_center(
            &self.text,
            self.font,
            self.font_size.unwrap_or(60),
            1.0,
            0.0);
        draw_text_ex(
            &self.text,
            x - title_center.x,
            y- title_center.y,
            title_params);
    }
    fn ev_loop(&mut self) -> Self::Event {
        true
    }
    fn get_dimensions(&self) -> (f32, f32) {
        let text_dim: TextDimensions = measure_text(
            &self.text,
            self.font,
            self.font_size.unwrap_or(60),
            1.0);
        (text_dim.width, text_dim.height)
    }
}

A src/ui/item_frame.rs => src/ui/item_frame.rs +181 -0
@@ 0,0 1,181 @@
use macroquad::prelude::*;
use crate::textures::AssetStore;
use crate::game::blocks::Block;
use crate::game::types::Direction;
use super::{Widget, ButtonEvent, CenteredText};

pub struct ItemFrame {
    /// middle of button (x axis)
    /// specified in perfect of screen width
    x: f32,
    /// middle of button (y-axis)
    /// specified in perfect of screen height
    y: f32,
    /// the block shown in the frame
    block: Option<Block>,
    /// should contain the item amount (when not in sandbox mode)
    /// should be None in sandbox mode
    amount: Option<usize>,
    /// width/height of frame in
    /// percent of smallest display size
    size: f32,
    /// true if widget option is selected
    selected: bool,
    /// widget used to display count
    widget_amount: CenteredText,
    /// the direciton the block is facing
    direction: Direction
}
impl ItemFrame {
    type Event = ButtonEvent;
    /// creates a new widget
    pub fn new(x: f32, y:f32, size: f32) -> Self {
        Self {
            x,
            y,
            size,
            amount: None,
            selected: false,
            block: None,
            direction: Direction::North,
            widget_amount: CenteredText::new("", x, y)
                .with_font_size(30)
        }
    }
    /// adds a block to the item frame
    #[allow(dead_code)]
    pub fn with_block(self, block: Block, amount: Option<usize>) -> Self {
        let mut this = Self {
            block: Some(block),
            amount,
            ..self
        };
        if let Some(amount) = amount {
            this.widget_amount.set_text(&format!("{}", amount));
        } else {
            this.widget_amount.set_text("inf");
        }

        this
    }
    /// changes the block inside the frame
    #[allow(dead_code)]
    pub fn change_block(&mut self, block: Block, amount: Option<usize>) {
        self.block = Some(block);
        self.amount = amount;

        if let Some(amount) = amount {
            self.widget_amount.set_text(&format!("{}", amount));
        } else {
            self.widget_amount.set_text("inf");
        }
    }
    /// empties the item frame
    #[allow(dead_code)]
    pub fn empty(&mut self) {
        self.block = None;
        self.amount = None;
    }
    /// set widget selected state
    #[allow(dead_code)]
    pub fn set_selected(&mut self, state: bool) {
        self.selected = state;
    }
    /// update block, direction and amount in one go
    #[allow(dead_code)]
    pub fn update(&mut self, selected: &Option<Block>, direction: &Direction, amount: &Option<usize>) {
        if let Some(block) = selected {
            self.block = Some(block.clone());
            self.amount = Some(0);
            self.amount = *amount;
        } else {
            self.block = None;
            self.amount = None;
        }
        self.direction = direction.clone();
    }
}
impl Widget for ItemFrame {
    type Event = ButtonEvent;
    fn get_dimensions(&self) -> (f32, f32) {
        let smallest = if screen_width() < screen_height() { screen_width() } else { screen_height() };
        (self.size * smallest, self.size * smallest)
    }
    async fn draw(&self, assets: &AssetStore) {
        let (x,y) = (screen_width() * self.x, screen_height() * self.y);
        let (size, _) = self.get_dimensions();

        let mut bg = assets.ui.panel_brown.0;
        if self.selected {
            // selected block
            // draw blue background
            bg = assets.ui.panel_blue.0;
        }
        // draw background
        draw_texture_ex(
            bg,
            x - size/2.0,
            y - size/2.0,
            WHITE,
            DrawTextureParams {
                dest_size: Some(Vec2::new(size, size)),
                ..Default::default()
            }
        );

        // draw brown foreground
        {
            let scale = size/100.0;
            let dim = scale * 93.0;
            draw_texture_ex(
                assets.ui.panel_brown.1,
                x - dim/2.0,
                y - dim/2.0,
                WHITE,
                DrawTextureParams {
                    dest_size: Some(Vec2::new(dim, dim)),
                    ..Default::default()
                }
            );
        }

        if let Some(block) = &self.block {
            // draw block
            let width = size * 2.0/3.0;
            let height = (width * 352.0) / 256.0;
            draw_texture_ex(
                block.get_texture().await.get_dir(&self.direction),
                x - width / 2.0,
                y - (height * 238.0)/352.0,

                WHITE,
                DrawTextureParams {
                    dest_size: Some(Vec2::new(
                        width,
                        height)),
                    ..Default::default()
                }
            );
            // draw amount
            self.widget_amount.draw(&assets).await;
        }
    }
    fn ev_loop(&mut self) -> Self::Event {
        let (width, height) = self.get_dimensions();

        let (mx, my) = mouse_position();
        let (x,y) = (screen_width() * self.x, screen_height() * self.y);

        if mx >= x - width/2.0 && mx <= x + width/2.0
            && my >= y - height/2.0 && my <= y + height/2.0 {
                if is_mouse_button_pressed(MouseButton::Left) {
                    return Self::Event::LeftClick;
                }
                if is_mouse_button_pressed(MouseButton::Right) {
                    return Self::Event::RightClick;
                }
            }

        Self::Event::None
    }
}

A src/ui/mod.rs => src/ui/mod.rs +38 -0
@@ 0,0 1,38 @@
use macroquad::prelude::*;
use crate::textures::AssetStore;

mod centered_text;
mod item_frame;
mod selectable_text;
mod text_button;

pub use centered_text::CenteredText;
pub use item_frame::ItemFrame;
pub use selectable_text::SelectableText;
pub use text_button::TextButton;

/// A button event send from the Button widget ev-loop
/// i.e WideButton
pub enum ButtonEvent {
    /// nothing happened
    None,
    /// user clicked on button with left mouse button
    LeftClick,
    /// user clicked on button with right mouse button
    RightClick
}

/// A UI item that can be rendered
pub trait Widget {
    /// Message types returned from the event loop
    type Event;
    /// Callback used to redraw the component
    async fn draw(&self, assets: &AssetStore);
    /// Callback used to perform background tasks
    /// e.g. keyboard input
    /// NOTE: this is currently not being run asynchronously
    /// when running large operations, spawn a separate thread
    fn ev_loop(&mut self) -> Self::Event;
    // returns the width and height of the widget
    fn get_dimensions(&self) -> (f32, f32);
}

A src/ui/selectable_text.rs => src/ui/selectable_text.rs +171 -0
@@ 0,0 1,171 @@
use macroquad::prelude::*;
use crate::textures::AssetStore;
use super::{Widget, ButtonEvent};

/// A widget similar to a button,
/// but it can be selected
/// and will stay selected
pub struct SelectableText {
    /// the text on the button
    text: String,
    /// middle of button (x axis)
    /// specified in perfect of screen width
    x: f32,
    /// middle of button (y-axis)
    /// specified in perfect of screen height
    y: f32,
    /// the font used to draw the text
    font: Option<Font>,
    /// custom font color
    /// defaults to white
    font_color: Option<Color>,
    /// custom font size to use
    font_size: Option<u16>,
    /// true if widget option is selected
    selected: bool,
    /// if the widget is visible or not
    visible: bool
}
impl SelectableText {
    /// creates a new text button widget
    pub fn new(text: &str, x: f32, y: f32) -> Self {
        Self {
            text: text.to_string(),
            x,
            y,
            font: None,
            font_color: None,
            font_size: None,
            selected: false,
            visible: true
        }
    }
    /// set the visibility
    #[allow(dead_code)]
    pub fn with_visibility(self, vis: bool) -> Self {
        Self {
            visible: vis,
            ..self
        }
    }
    /// sets the custom font
    #[allow(dead_code)]
    pub fn with_font(self, font: Font) -> Self {
        Self {
            font: Some(font),
            ..self
        }
    }
    /// sets the font color
    #[allow(dead_code)]
    pub fn with_font_color(self, color: Color) -> Self {
        Self {
            font_color: Some(color),
            ..self
        }
    }
    /// sets the font size
    #[allow(dead_code)]
    pub fn with_font_size(self, size: u16) -> Self {
        Self {
            font_size: Some(size),
            ..self
        }
    }
    /// selects or unselects the Widget
    #[allow(dead_code)]
    pub fn set_selected(&mut self, state: bool) {
        self.selected = state;
    }
    /// updates the widget text
    #[allow(dead_code)]
    pub fn set_text(&mut self, text: &str) {
        self.text = text.to_string();
    }
    /// updates the widget visibility
    #[allow(dead_code)]
    pub fn set_visibility(&mut self, vis: bool) {
        self.visible = vis;
    }
    /// returns the text currently displayed on widget
    #[allow(dead_code)]
    pub fn get_text(&self) -> &str {
        &self.text
    }
}
impl Widget for SelectableText {
    type Event = ButtonEvent;
    fn get_dimensions(&self) -> (f32, f32) {
        let text_dim: TextDimensions = measure_text(
            &self.text,
            self.font,
            self.font_size.unwrap_or(60),
            1.0);
        (text_dim.width + 30.0, text_dim.height+20.0)
    }
    async fn draw(&self, assets: &AssetStore) {
        if !self.visible {
            return;
        }

        let (x,y) = (screen_width() * self.x, screen_height() * self.y);
        let (width, height) = self.get_dimensions();

        let mut bg = assets.ui.panel_brown.0;
        if self.selected {
            // draw blue background
            bg = assets.ui.panel_blue.0;
        }
        // draw background
        draw_texture_ex(
            bg,
            x - width/2.0,
            y - height/2.0,
            WHITE,
            DrawTextureParams {
                dest_size: Some(Vec2::new(width, height)),
                ..Default::default()
            }
        );

        let text_center = get_text_center(
            &self.text,
            self.font,
            self.font_size.unwrap_or(60),
            1.0,
            0.0);
        draw_text_ex(
            &self.text,
            x - text_center.x,
            y - text_center.y,
            TextParams {
                font_size: self.font_size.unwrap_or(60),
                color: self.font_color.unwrap_or(WHITE),
                ..Default::default()
            });
    }
    fn ev_loop(&mut self) -> Self::Event {
        if !self.visible {
            return Self::Event::None;
        }

        let (width, height) = self.get_dimensions();

        let (mx, my) = mouse_position();
        let (x,y) = (screen_width() * self.x, screen_height() * self.y);

        if mx >= x - width/2.0 && mx <= x + width/2.0
            && my >= y - height/2.0 && my <= y + height/2.0 {
                if is_mouse_button_pressed(MouseButton::Left) {
                    return Self::Event::LeftClick;
                }
                if is_mouse_button_pressed(MouseButton::Right) {
                    return Self::Event::RightClick;
                }
            }


        Self::Event::None

    }
}

A src/ui/text_button.rs => src/ui/text_button.rs +135 -0
@@ 0,0 1,135 @@
use macroquad::prelude::*;
use crate::textures::AssetStore;
use super::{Widget, ButtonEvent};

/// UI Widget
/// a clickable button with text on it
pub struct TextButton {
    /// the text on the button
    text: String,
    /// middle of button (x axis)
    /// specified in perfect of screen width
    x: f32,
    /// middle of button (y-axis)
    /// specified in perfect of screen height
    y: f32,
    /// the font used to draw the text
    font: Option<Font>,
    /// custom font color
    font_color: Option<Color>,
    /// custom font size to use
    font_size: Option<u16>,
    /// true if mouse is over button
    hovered: bool
}
impl TextButton {
    /// creates a new text button widget
    pub fn new(text: &str, x: f32, y: f32) -> Self {
        Self {
            text: text.to_string(),
            x,
            y,
            font: None,
            font_color: None,
            font_size: None,
            hovered: false
        }
    }
    /// sets the custom font
    #[allow(dead_code)]
    pub fn with_font(self, font: Font) -> Self {
        Self {
            font: Some(font),
            ..self
        }
    }
    /// sets the font color
    #[allow(dead_code)]
    pub fn with_font_color(self, color: Color) -> Self {
        Self {
            font_color: Some(color),
            ..self
        }
    }
    /// sets the font size
    #[allow(dead_code)]
    pub fn with_font_size(self, size: u16) -> Self {
        Self {
            font_size: Some(size),
            ..self
        }
    }
    /// updates the widget text
    #[allow(dead_code)]
    pub fn set_text(&mut self, text: &str) {
        self.text = text.to_string();
    }
}
impl Widget for TextButton {
    type Event = ButtonEvent;
    fn get_dimensions(&self) -> (f32, f32) {
        let text_dim: TextDimensions = measure_text(
            &self.text,
            self.font,
            self.font_size.unwrap_or(60),
            1.0);
        (text_dim.width + 30.0, text_dim.height+20.0)
    }
    async fn draw(&self, assets: &AssetStore) {
        let (x,y) = (screen_width() * self.x, screen_height() * self.y);
        let (width, height) = self.get_dimensions();

        draw_texture_ex(
            if self.hovered { assets.ui.long_button.1 } else { assets.ui.long_button.0 },
            x - width / 2.0,
            y - height / 2.0,
            WHITE,
            DrawTextureParams {
                dest_size: Some(Vec2::new(width, height)),
                source: None,
                rotation: 0.0,
                flip_x: false,
                flip_y: false,
                pivot: None
            });

        let text_center = get_text_center(
            &self.text,
            self.font,
            self.font_size.unwrap_or(60),
            1.0,
            0.0);
        draw_text_ex(
            &self.text,
            x - text_center.x,
            y - text_center.y,
            TextParams {
                font_size: self.font_size.unwrap_or(60),
                color: self.font_color.unwrap_or(WHITE),
                ..Default::default()
            });
    }
    fn ev_loop(&mut self) -> Self::Event {
        self.hovered = false;

        let (width, height) = self.get_dimensions();

        let (mx, my) = mouse_position();
        let (x,y) = (screen_width() * self.x, screen_height() * self.y);

        if mx >= x - width/2.0 && mx <= x + width/2.0
            && my >= y - height/2.0 && my <= y + height/2.0 {
                self.hovered = true;

                if is_mouse_button_pressed(MouseButton::Left) {
                    return Self::Event::LeftClick;
                }
                if is_mouse_button_pressed(MouseButton::Right) {
                    return Self::Event::RightClick;
                }
            }


        Self::Event::None
    }
}