1use std::fmt;
2
3use ggez::{graphics, Context, GameResult};
4
5use crate::ChessGui;
6
7#[derive(Copy, Clone, Eq, PartialEq, Default, Debug)]
9pub enum Align {
10 Left,
11 Right,
12 #[default]
13 Center,
14}
15
16#[derive(Copy, Clone)]
18pub struct Button {
19 pub id: &'static str,
21 enable: bool,
22 rect: graphics::Rect,
23 image_path: Option<&'static str>,
24 color: graphics::Color,
25 text: &'static str,
26 align: Align,
27 func: Option<fn(&mut ChessGui)>,
28}
29
30impl Button {
31 #[allow(clippy::too_many_arguments)]
33 pub fn new(
34 id: &'static str,
35 enable: bool,
36 rect: graphics::Rect,
37 color: graphics::Color,
38 text: &'static str,
39 align: Align,
40 func: Option<fn(&mut ChessGui)>,
41 ) -> Self {
42 Button {
43 id,
44 enable,
45 rect,
46 image_path: None,
47 color,
48 text,
49 align,
50 func,
51 }
52 }
53
54 pub fn is_enable(&self) -> bool {
56 self.enable
57 }
58
59 pub fn enable(&mut self) {
61 self.enable = true;
62 }
63
64 pub fn disable(&mut self) {
66 self.enable = false;
67 }
68
69 pub fn set_image(&mut self, path: Option<&'static str>) -> Self {
71 self.image_path = path;
72 *self
73 }
74
75 pub fn contains(&self, x: f32, y: f32) -> bool {
77 self.rect.contains([x, y])
78 }
79
80 pub fn draw(&self, ctx: &mut Context, font_path: &str, font_scale: f32) -> GameResult {
82 if self.enable {
83 if self.image_path.is_some() {
84 self.draw_image(ctx)?;
85 } else {
86 self.draw_rect(ctx)?;
87 self.draw_text(ctx, font_path, font_scale)?;
88 }
89 }
90 Ok(())
91 }
92
93 fn draw_rect(&self, ctx: &mut Context) -> GameResult {
95 let mesh = graphics::MeshBuilder::new()
96 .rectangle(graphics::DrawMode::stroke(3.0), self.rect, self.color)?
97 .build(ctx)?;
98 graphics::draw(ctx, &mesh, graphics::DrawParam::default())?;
99 Ok(())
100 }
101
102 fn draw_text(&self, ctx: &mut Context, font_path: &str, font_scale: f32) -> GameResult {
104 let font = graphics::Font::new(ctx, font_path)?;
105 let text = graphics::Text::new((self.text, font, font_scale));
106 let dest_point = match self.align {
107 Align::Left => [self.rect.x, self.rect.y],
108 Align::Right => [
109 self.rect.x + self.rect.w - text.width(ctx),
110 self.rect.y + self.rect.h - text.height(ctx),
111 ],
112 Align::Center => [
113 self.rect.x + (self.rect.w - text.width(ctx)) / 2.0,
114 self.rect.y + (self.rect.h - text.height(ctx)) / 2.0,
115 ],
116 };
117 graphics::draw(ctx, &text, (dest_point, self.color))?;
118 Ok(())
119 }
120
121 fn draw_image(&self, ctx: &mut Context) -> GameResult {
123 let image = graphics::Image::new(ctx, self.image_path.unwrap()).expect("Image load error");
124 let image_scale = [
125 self.rect.w / image.width() as f32,
126 self.rect.h / image.height() as f32,
127 ];
128 let dp = graphics::DrawParam::new()
129 .dest(self.rect.point())
130 .scale(image_scale);
131 graphics::draw(ctx, &image, dp)?;
132 Ok(())
133 }
134
135 pub fn clicked(&self, chess_gui: &mut ChessGui) {
137 if self.enable {
138 if let Some(func) = self.func {
139 func(chess_gui);
140 }
141 }
142 }
143}
144
145impl fmt::Display for Button {
146 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
147 write!(f, "{}", self.id)
148 }
149}
150
151impl fmt::Debug for Button {
152 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153 write!(f, "{}", self.id)
154 }
155}