1pub extern crate macroquad;
2use macroquad::prelude::*;
3pub mod button;
4pub mod column;
5pub mod row;
6pub mod text;
7
8use auto_impl::auto_impl;
9
10use self::row::Row;
11
12pub trait App {
13 fn tick(&mut self);
14}
15
16pub struct View {
18 pub geometry: Geometry,
20 child: Box<dyn Widget>,
22}
23
24impl Default for View {
25 fn default() -> Self {
26 View {
27 geometry: Geometry::new(Vector2::from(0, 0)),
28 child: Box::new(Row::new()),
29 }
30 }
31}
32
33impl View {
35 #[cfg(feature = "debug_draw")]
36 pub fn debug_draw(&self) {
37 draw_circle(0f32, 0f32, 20f32, RED);
38 draw_circle(screen_width(), 0f32, 20f32, RED);
39 draw_circle(0f32, screen_height(), 20f32, RED);
40 draw_circle(screen_width(), screen_height(), 20f32, RED);
41 }
42 pub fn draw(&self) {
43 #[cfg(feature = "debug_draw")]
44 self.debug_draw();
45 self.child.draw();
46 }
47
48 pub fn tick(&mut self) {
49 if self.child.get_build() || self.resized() {
51 self.build();
52 }
53 self.child.tick();
54 }
55
56 pub fn new<T: Widget + 'static>(child: T) -> View {
57 View {
58 geometry: Geometry {
59 top_left: Vector2 { x: 0f32, y: 0f32 },
60 top_left_curr: Vector2 { x: 0f32, y: 0f32 },
61 sides: Vector2 { x: 0f32, y: 0f32 },
62 abs_sides: Vector2 { x: 0f32, y: 0f32 },
63 margins: Directions2D {
64 top: 0f32,
65 bottom: 0f32,
66 left: 0f32,
67 right: 0f32,
68 },
69 abs_margins: Directions2D {
70 top: 0f32,
71 bottom: 0f32,
72 left: 0f32,
73 right: 0f32,
74 },
75 },
76 child: Box::new(child),
77 }
78 }
79
80 pub fn build(&mut self) {
81 self.geometry.abs_sides.x = screen_width();
82 self.geometry.abs_sides.y = screen_height();
83 self.geometry.top_left_curr = self.child.build(&self.geometry, None);
84 }
85
86 pub fn resized(&self) -> bool {
87 if screen_height() == self.geometry.abs_sides.y
88 && screen_width() == self.geometry.abs_sides.x
89 {
90 false
91 } else {
92 true
93 }
94 }
95}
96
97#[derive(Copy, Clone)]
99pub struct Vector2 {
100 pub x: f32,
101 pub y: f32,
102}
103
104impl Vector2 {
105 pub fn from(x: i32, y: i32) -> Self {
106 Vector2 {
107 x: x as f32,
108 y: y as f32,
109 }
110 }
111 pub fn new(x: f32, y: f32) -> Self {
112 Vector2 { x, y }
113 }
114}
115
116#[derive(Copy, Clone)]
118pub struct Directions2D {
119 pub top: f32,
120 pub bottom: f32,
121 pub left: f32,
122 pub right: f32,
123}
124
125impl Directions2D {
126 pub fn new(top: f32, bottom: f32, left: f32, right: f32) -> Self {
127 Directions2D {
128 top,
129 bottom,
130 left,
131 right,
132 }
133 }
134}
135
136pub struct Geometry {
138 pub sides: Vector2,
141
142 pub top_left: Vector2,
145
146 pub top_left_curr: Vector2,
148
149 pub abs_sides: Vector2,
151
152 pub margins: Directions2D,
154
155 pub abs_margins: Directions2D,
157}
158
159impl Geometry {
160 pub fn new(sides: Vector2) -> Self {
161 if sides.x < 0f32 || sides.y < 0f32 {
162 panic!("Widget has no geometry!");
163 } else {
164 Geometry {
165 top_left: Vector2::new(0f32, 0f32),
166 top_left_curr: Vector2::new(0f32, 0f32),
167 abs_sides: Vector2::new(0f32, 0f32),
168 sides,
169 margins: Directions2D::new(
170 (100f32 - sides.y) / 2f32,
171 (100f32 - sides.y) / 2f32,
172 (100f32 - sides.x) / 2f32,
173 (100f32 - sides.x) / 2f32,
174 ),
175 abs_margins: Directions2D::new(
176 (100f32 - sides.y) / 2f32,
177 (100f32 - sides.y) / 2f32,
178 (100f32 - sides.x) / 2f32,
179 (100f32 - sides.x) / 2f32,
180 ),
181 }
182 }
183 }
184}
185
186#[auto_impl(&mut)]
187pub trait Widget {
188 fn draw(&self);
189
190 fn build(&mut self, geometry: &Geometry, margin: Option<Directions2D>) -> Vector2;
198 fn tick(&mut self);
199
200 fn get_side(&self) -> Vector2;
202
203 fn get_id(&self) -> u16;
206
207 fn get_build(&self) -> bool;
210}