1use crate::color::*;
20use crate::custom_data::OptionalExtraHTMLData;
21use crate::images::URLImage;
22use crate::rendering::{HTMLCanvas, HTMLDrawable};
23use cotis_defaults::render_commands::render_t_list::{IsRenderList, RenderTList};
24use cotis_defaults::render_commands::*;
25
26impl<T: HTMLDrawable, L: IsRenderList + HTMLDrawable> HTMLDrawable for RenderTList<T, L> {
27 fn draw(self, canvas: &mut HTMLCanvas) {
28 match self {
29 RenderTList::Type(t) => {
30 t.draw(canvas);
31 }
32 RenderTList::List(l) => {
33 l.draw(canvas);
34 }
35 }
36 }
37}
38
39impl<T: HTMLDrawable> HTMLDrawable for RenderTList<T, ()> {
40 fn draw(self, canvas: &mut HTMLCanvas) {
41 match self {
42 RenderTList::Type(t) => t.draw(canvas),
43 RenderTList::List(()) => {}
44 }
45 }
46}
47
48impl<'a, ExtraData: OptionalExtraHTMLData> HTMLDrawable for Rectangle<'a, ExtraData> {
49 fn draw(self, canvas: &mut HTMLCanvas) {
50 let extra_data = match self.info.extra_data {
51 None => Default::default(),
52 Some(extra) => extra.as_ref().extra_html_data().unwrap_or_default(),
53 };
54 canvas.ensure_command_element(
55 self.info.id,
56 extra_data.tag.as_json_str(),
57 extra_data.extra_style.as_deref(),
58 );
59 let bg = rectangle_fill_css(&self.color);
60 canvas
61 .current_element_css_push(&format!(
62 "position: absolute; left: {}px; top: {}px; width: {}px; height: {}px",
63 self.info.bounding_box.x,
64 self.info.bounding_box.y,
65 self.info.bounding_box.width,
66 self.info.bounding_box.height
67 ))
68 .current_element_css_push(&format!("background-color: {}", bg))
69 .current_element_css_push(&format!(
70 "border-radius: {}px {}px {}px {}px",
71 self.corner_radii.top_left,
72 self.corner_radii.top_right,
73 self.corner_radii.bottom_right,
74 self.corner_radii.bottom_left
75 ))
76 .current_element_css_push("box-sizing: border-box; pointer-events: auto");
77 }
78}
79
80impl<'a, ExtraData: OptionalExtraHTMLData> HTMLDrawable for Border<'a, ExtraData> {
81 fn draw(self, canvas: &mut HTMLCanvas) {
82 let extra_data = match self.info.extra_data {
83 None => Default::default(),
84 Some(extra) => extra.as_ref().extra_html_data().unwrap_or_default(),
85 };
86 canvas.ensure_command_element(
87 self.info.id,
88 extra_data.tag.as_json_str(),
89 extra_data.extra_style.as_deref(),
90 );
91 let border_color = color_css(&self.color);
92 let bb = self.info.bounding_box;
93 canvas
94 .current_element_css_push(&format!(
95 "position: absolute; left: {}px; top: {}px; width: {}px; height: {}px",
96 bb.x, bb.y, bb.width, bb.height
97 ))
98 .current_element_css_push(&format!(
99 "border-top: {}px solid {}",
100 self.width.top, border_color
101 ))
102 .current_element_css_push(&format!(
103 "border-right: {}px solid {}",
104 self.width.right, border_color
105 ))
106 .current_element_css_push(&format!(
107 "border-bottom: {}px solid {}",
108 self.width.bottom, border_color
109 ))
110 .current_element_css_push(&format!(
111 "border-left: {}px solid {}",
112 self.width.left, border_color
113 ))
114 .current_element_css_push(&format!(
115 "border-radius: {}px {}px {}px {}px",
116 self.corner_radii.top_left,
117 self.corner_radii.top_right,
118 self.corner_radii.bottom_right,
119 self.corner_radii.bottom_left
120 ))
121 .current_element_css_push("box-sizing: border-box; pointer-events: auto");
122 }
123}
124
125impl<'a, ExtraData: OptionalExtraHTMLData> HTMLDrawable for ClipStart<'a, ExtraData> {
126 fn draw(self, canvas: &mut HTMLCanvas) {
127 let bb = self.info.bounding_box;
128 canvas.push_scissor(
129 self.info.id,
130 bb.x,
131 bb.y,
132 bb.width,
133 bb.height,
134 self.corner_radii,
135 );
136 }
137}
138
139impl HTMLDrawable for ClipEnd {
140 fn draw(self, canvas: &mut HTMLCanvas) {
141 canvas.pop_scissor();
142 }
143}
144
145impl<'a, ExtraData: OptionalExtraHTMLData> HTMLDrawable for Text<'a, ExtraData> {
146 fn draw(self, canvas: &mut HTMLCanvas) {
147 let extra_data = match self.info.extra_data {
148 None => Default::default(),
149 Some(extra) => extra.as_ref().extra_html_data().unwrap_or_default(),
150 };
151 canvas.ensure_command_element(
152 self.info.id,
153 extra_data.tag.as_json_str(),
154 extra_data.extra_style.as_deref(),
155 );
156 let text_color = text_color_css(&self.color);
157 let font_size = self.font_size * 1.0;
158 let line_height = if self.line_height > 0.0 {
159 self.line_height
160 } else {
161 1.2
162 };
163 let bb = self.info.bounding_box;
164 canvas.set_text_content(self.text.as_ref().to_string());
165 canvas
166 .current_element_css_push(&format!(
167 "position: absolute; left: {}px; top: {}px; width: {}px; height: {}px",
168 bb.x, bb.y, bb.width, bb.height
169 ))
170 .current_element_css_push(&format!(
171 "font-family: font{}; font-size: {}px; line-height: {}; letter-spacing: {}px",
172 self.font_id, font_size, line_height, self.letter_spacing
173 ))
174 .current_element_css_push(&format!("color: {}", text_color))
175 .current_element_css_push("display: flex; align-items: flex-start")
176 .current_element_css_push(
177 "white-space: pre-wrap; word-break: break-word; overflow-wrap: anywhere",
178 )
179 .current_element_css_push("overflow: hidden; box-sizing: border-box")
180 .current_element_css_push("pointer-events: auto; user-select: text");
181 }
182}
183
184impl<'a, ImageData: URLImage, ExtraData: OptionalExtraHTMLData> HTMLDrawable
185 for Image<'a, ImageData, ExtraData>
186{
187 fn draw(self, canvas: &mut HTMLCanvas) {
188 let extra_data = match self.info.extra_data {
189 None => Default::default(),
190 Some(extra) => extra.as_ref().extra_html_data().unwrap_or_default(),
191 };
192 canvas.ensure_command_element(
193 self.info.id,
194 extra_data.tag.as_json_str(),
195 extra_data.extra_style.as_deref(),
196 );
197 let url = self.data.as_ref().url();
198 let bg = image_background_css(&self.background_color);
199 let bb = self.info.bounding_box;
200 canvas
201 .current_element_css_push(&format!(
202 "position: absolute; left: {}px; top: {}px; width: {}px; height: {}px",
203 bb.x, bb.y, bb.width, bb.height
204 ))
205 .current_element_css_push(&format!("background-color: {}", bg))
206 .current_element_css_push(&format!("background-image: url(\"{}\")", url))
207 .current_element_css_push("background-size: 100% 100%; background-repeat: no-repeat")
208 .current_element_css_push("background-position: center; display: block")
209 .current_element_css_push(&format!(
210 "border-radius: {}px {}px {}px {}px",
211 self.corner_radii.top_left,
212 self.corner_radii.top_right,
213 self.corner_radii.bottom_right,
214 self.corner_radii.bottom_left
215 ))
216 .current_element_css_push("pointer-events: auto");
217 }
218}