1use crate::{
22 border::BorderBuilder,
23 button::ButtonBuilder,
24 core::{algebra::Vector2, color::Color, parking_lot::Mutex, pool::Handle},
25 decorator::DecoratorBuilder,
26 formatted_text::WrapMode,
27 grid::{Column, GridBuilder, Row},
28 image::ImageBuilder,
29 style::{resource::StyleResourceExt, Style},
30 text::TextBuilder,
31 vector_image::{Primitive, VectorImageBuilder},
32 widget::WidgetBuilder,
33 Brush, BuildContext, HorizontalAlignment, RcUiNodeHandle, Thickness, UiNode, VerticalAlignment,
34};
35use fyrox_texture::{
36 CompressionOptions, TextureImportOptions, TextureMinificationFilter, TextureResource,
37 TextureResourceExtension,
38};
39use std::sync::Arc;
40
41pub enum ArrowDirection {
42 Top,
43 Bottom,
44 Left,
45 Right,
46}
47
48pub fn make_arrow_primitives_non_uniform_size(
49 orientation: ArrowDirection,
50 width: f32,
51 height: f32,
52) -> Vec<Primitive> {
53 vec![match orientation {
54 ArrowDirection::Top => Primitive::Triangle {
55 points: [
56 Vector2::new(width * 0.5, 0.0),
57 Vector2::new(width, height),
58 Vector2::new(0.0, height),
59 ],
60 },
61 ArrowDirection::Bottom => Primitive::Triangle {
62 points: [
63 Vector2::new(0.0, 0.0),
64 Vector2::new(width, 0.0),
65 Vector2::new(width * 0.5, height),
66 ],
67 },
68 ArrowDirection::Right => Primitive::Triangle {
69 points: [
70 Vector2::new(0.0, 0.0),
71 Vector2::new(width, height * 0.5),
72 Vector2::new(0.0, height),
73 ],
74 },
75 ArrowDirection::Left => Primitive::Triangle {
76 points: [
77 Vector2::new(0.0, height * 0.5),
78 Vector2::new(width, 0.0),
79 Vector2::new(width, height),
80 ],
81 },
82 }]
83}
84
85pub fn make_arrow_primitives(orientation: ArrowDirection, size: f32) -> Vec<Primitive> {
86 make_arrow_primitives_non_uniform_size(orientation, size, size)
87}
88
89pub fn make_arrow_non_uniform_size(
90 ctx: &mut BuildContext,
91 orientation: ArrowDirection,
92 width: f32,
93 height: f32,
94) -> Handle<UiNode> {
95 VectorImageBuilder::new(
96 WidgetBuilder::new()
97 .with_foreground(ctx.style.property(Style::BRUSH_BRIGHT))
98 .with_width(width)
99 .with_height(height)
100 .with_horizontal_alignment(HorizontalAlignment::Center)
101 .with_vertical_alignment(VerticalAlignment::Center),
102 )
103 .with_primitives(make_arrow_primitives_non_uniform_size(
104 orientation,
105 width,
106 height,
107 ))
108 .build(ctx)
109}
110
111pub fn make_arrow(
112 ctx: &mut BuildContext,
113 orientation: ArrowDirection,
114 size: f32,
115) -> Handle<UiNode> {
116 make_arrow_non_uniform_size(ctx, orientation, size, size)
117}
118
119pub fn make_cross_primitive(size: f32, thickness: f32) -> Vec<Primitive> {
120 vec![
121 Primitive::Line {
122 begin: Vector2::new(0.0, 0.0),
123 end: Vector2::new(size, size),
124 thickness,
125 },
126 Primitive::Line {
127 begin: Vector2::new(size, 0.0),
128 end: Vector2::new(0.0, size),
129 thickness,
130 },
131 ]
132}
133
134pub fn make_cross(ctx: &mut BuildContext, size: f32, thickness: f32) -> Handle<UiNode> {
135 VectorImageBuilder::new(
136 WidgetBuilder::new()
137 .with_horizontal_alignment(HorizontalAlignment::Center)
138 .with_vertical_alignment(VerticalAlignment::Center)
139 .with_width(size)
140 .with_height(size)
141 .with_foreground(ctx.style.property(Style::BRUSH_BRIGHT)),
142 )
143 .with_primitives(make_cross_primitive(size, thickness))
144 .build(ctx)
145}
146
147pub fn make_simple_tooltip(ctx: &mut BuildContext, text: &str) -> RcUiNodeHandle {
148 let handle = BorderBuilder::new(
149 WidgetBuilder::new()
150 .with_visibility(false)
151 .with_hit_test_visibility(false)
152 .with_foreground(ctx.style.property(Style::BRUSH_DARKEST))
153 .with_background(Brush::Solid(Color::opaque(230, 230, 230)).into())
154 .with_max_size(Vector2::new(300.0, f32::INFINITY))
155 .with_child(
156 TextBuilder::new(
157 WidgetBuilder::new()
158 .with_margin(Thickness::uniform(2.0))
159 .with_foreground(ctx.style.property(Style::BRUSH_DARKER)),
160 )
161 .with_wrap(WrapMode::Word)
162 .with_text(text)
163 .build(ctx),
164 ),
165 )
166 .build(ctx);
167 RcUiNodeHandle::new(handle, ctx.sender())
168}
169
170pub fn make_dropdown_list_option_universal<T: Send + 'static>(
171 ctx: &mut BuildContext,
172 name: &str,
173 height: f32,
174 user_data: T,
175) -> Handle<UiNode> {
176 DecoratorBuilder::new(
177 BorderBuilder::new(
178 WidgetBuilder::new()
179 .with_height(height)
180 .with_user_data(Arc::new(Mutex::new(user_data)))
181 .with_child(
182 TextBuilder::new(WidgetBuilder::new())
183 .with_vertical_text_alignment(VerticalAlignment::Center)
184 .with_horizontal_text_alignment(HorizontalAlignment::Center)
185 .with_text(name)
186 .build(ctx),
187 ),
188 )
189 .with_corner_radius(4.0f32.into())
190 .with_pad_by_corner_radius(false),
191 )
192 .build(ctx)
193}
194
195pub fn make_dropdown_list_option(ctx: &mut BuildContext, name: &str) -> Handle<UiNode> {
196 DecoratorBuilder::new(
197 BorderBuilder::new(
198 WidgetBuilder::new().with_child(
199 TextBuilder::new(WidgetBuilder::new())
200 .with_vertical_text_alignment(VerticalAlignment::Center)
201 .with_horizontal_text_alignment(HorizontalAlignment::Center)
202 .with_text(name)
203 .build(ctx),
204 ),
205 )
206 .with_corner_radius(4.0f32.into())
207 .with_pad_by_corner_radius(false),
208 )
209 .build(ctx)
210}
211
212pub fn make_dropdown_list_option_with_height(
213 ctx: &mut BuildContext,
214 name: &str,
215 height: f32,
216) -> Handle<UiNode> {
217 DecoratorBuilder::new(
218 BorderBuilder::new(
219 WidgetBuilder::new().with_height(height).with_child(
220 TextBuilder::new(WidgetBuilder::new())
221 .with_vertical_text_alignment(VerticalAlignment::Center)
222 .with_horizontal_text_alignment(HorizontalAlignment::Center)
223 .with_text(name)
224 .build(ctx),
225 ),
226 )
227 .with_corner_radius(4.0f32.into())
228 .with_pad_by_corner_radius(false),
229 )
230 .build(ctx)
231}
232
233pub fn make_image_button_with_tooltip(
234 ctx: &mut BuildContext,
235 width: f32,
236 height: f32,
237 image: Option<TextureResource>,
238 tooltip: &str,
239 tab_index: Option<usize>,
240) -> Handle<UiNode> {
241 ButtonBuilder::new(
242 WidgetBuilder::new()
243 .with_tab_index(tab_index)
244 .with_tooltip(make_simple_tooltip(ctx, tooltip))
245 .with_margin(Thickness::uniform(1.0)),
246 )
247 .with_content(
248 ImageBuilder::new(
249 WidgetBuilder::new()
250 .with_background(ctx.style.property(Style::BRUSH_BRIGHTEST))
251 .with_margin(Thickness::uniform(2.0))
252 .with_width(width)
253 .with_height(height),
254 )
255 .with_opt_texture(image)
256 .build(ctx),
257 )
258 .build(ctx)
259}
260
261pub fn make_text_and_image_button_with_tooltip(
262 ctx: &mut BuildContext,
263 text: &str,
264 image_width: f32,
265 image_height: f32,
266 image: Option<TextureResource>,
267 tooltip: &str,
268 row: usize,
269 column: usize,
270 tab_index: Option<usize>,
271 color: Color,
272 font_size: f32,
273) -> Handle<UiNode> {
274 let margin = 2.0;
275 ButtonBuilder::new(
276 WidgetBuilder::new()
277 .on_row(row)
278 .on_column(column)
279 .with_tab_index(tab_index)
280 .with_tooltip(make_simple_tooltip(ctx, tooltip))
281 .with_margin(Thickness::uniform(1.0)),
282 )
283 .with_content(
284 GridBuilder::new(
285 WidgetBuilder::new()
286 .with_child(
287 ImageBuilder::new(
288 WidgetBuilder::new()
289 .on_row(0)
290 .on_column(0)
291 .with_background(Brush::Solid(color).into())
292 .with_margin(Thickness {
293 left: 2.0 * margin,
294 top: margin,
295 right: margin,
296 bottom: margin,
297 })
298 .with_width(image_width - 2.0 * margin)
299 .with_height(image_height - 2.0 * margin),
300 )
301 .with_opt_texture(image)
302 .build(ctx),
303 )
304 .with_child(
305 TextBuilder::new(
306 WidgetBuilder::new()
307 .on_row(0)
308 .on_column(1)
309 .with_vertical_alignment(VerticalAlignment::Center)
310 .with_horizontal_alignment(HorizontalAlignment::Center)
311 .with_margin(Thickness {
312 left: 4.0,
313 top: margin,
314 right: 8.0,
315 bottom: margin,
316 }),
317 )
318 .with_font_size(font_size.into())
319 .with_text(text)
320 .build(ctx),
321 ),
322 )
323 .add_column(Column::auto())
324 .add_column(Column::stretch())
325 .add_row(Row::stretch())
326 .build(ctx),
327 )
328 .build(ctx)
329}
330
331pub fn load_image(data: &[u8]) -> Option<TextureResource> {
332 TextureResource::load_from_memory(
333 Default::default(),
334 data,
335 TextureImportOptions::default()
336 .with_compression(CompressionOptions::NoCompression)
337 .with_minification_filter(TextureMinificationFilter::LinearMipMapLinear)
338 .with_lod_bias(-1.0),
339 )
340 .ok()
341}