1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
use async_trait::async_trait;

use crate::axisalignedrectangle::AxisAlignedRectangle;
use crate::bakedexpression::BakedExpression;
use crate::context::Context;
use crate::element::{Element, ElementConfig};
use crate::render_buffer::RenderBuffer;
use crate::render_context::RenderContext;

#[derive(Debug)]
pub struct ScrollTextElement {
	name:         String,
	color:        u32,
	text:         BakedExpression,
	fontfile:     String,
	speed:        f32,
	size:         u32,
	bounding_box: AxisAlignedRectangle,
	offset:       f32,
}

impl ScrollTextElement {}

#[async_trait]
impl Element for ScrollTextElement {
	fn configure(&mut self, config: &ElementConfig) {
		self.color = config.get_u32_or("color", 0xffff00ff);
		self.text = config.get_bakedexpression_string("text", "");
		self.fontfile = config.get_path_or("font", "");
		self.speed = config.get_f32_or("speed", 0.0);
		self.size = config.get_u32_or("size", 20);

		let mut bb = AxisAlignedRectangle::new();

		bb.x = config.get_bakedexpression_empty("bounding_box_pos_x");
		bb.y = config.get_bakedexpression_empty("bounding_box_pos_y");
		bb.width = config.get_bakedexpression_empty("bounding_box_width");
		bb.height = config.get_bakedexpression_empty("bounding_box_height");

		self.bounding_box = bb;
	}

	fn shutdown(&mut self) {}

	async fn run(&mut self) -> anyhow::Result<()> {
		Ok(())
	}

	fn update(&mut self, context: &mut Context) {
		self.text.bake_string_or(context, "");
		self.offset -= self.speed * context.time_step() as f32;
		// :TODO: use calculated width of text instead of hardcoded values
		if self.offset < -600.0 {
			self.offset += 600.0 + 500.0;
		}

		// :TODO: bake with default
		self.bounding_box.bake(context);
	}

	fn render(&self, render_buffer: &mut RenderBuffer, render_context: &mut RenderContext) {
		//		dbg!(&self);
		match render_context.use_font(&self.fontfile) {
			// :TODO: handle error
			_ => {},
		};
		let pos_x = self.bounding_box.x.as_u32() as f32 + self.offset;

		match render_context.draw_text(
			render_buffer,
			&self.text.as_string(),
			pos_x as u32,
			self.bounding_box.y.as_u32(),
			self.bounding_box.width.as_u32(),
			self.bounding_box.height.as_u32(),
			&self.bounding_box,
			self.size, // :TODO: maybe move this to use font
			self.color,
		) {
			// :TODO: handle error
			_ => {},
		}
	}
	fn name(&self) -> &str {
		&self.name
	}
	fn set_name(&mut self, name: &str) {
		self.name = name.to_string();
	}

	fn element_type(&self) -> &str {
		"text"
	}
}

pub struct ScrollTextElementFactory {}

impl ScrollTextElementFactory {
	pub fn create() -> ScrollTextElement {
		ScrollTextElement {
			name:         "".to_string(),
			color:        0xff00ffff,
			text:         BakedExpression::from_str(""),
			fontfile:     "".to_string(),
			speed:        0.0,
			size:         20,
			bounding_box: AxisAlignedRectangle::new(),
			offset:       0.0,
		}
	}
}