1 /**
2  * @file lv_xml_style.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "../../lvgl.h"
10 #if LV_USE_XML
11 
12 #include "lv_xml_base_types.h"
13 #include "lv_xml_parser.h"
14 #include "lv_xml_style.h"
15 #include "lv_xml_utils.h"
16 #include "lv_xml_component_private.h"
17 #include <string.h>
18 
19 /*********************
20  *      DEFINES
21  *********************/
22 #ifdef _MSC_VER
23     #define strtok_r strtok_s  // Use strtok_s as an equivalent to strtok_r in Visual Studio
24 #endif
25 
26 /**********************
27  *      TYPEDEFS
28  **********************/
29 
30 /**********************
31  *  STATIC PROTOTYPES
32  **********************/
33 
34 /**********************
35  *  STATIC VARIABLES
36  **********************/
37 
38 /**********************
39  *      MACROS
40  **********************/
41 
42 /*Expands to e.g.
43   if(lv_streq(name, "height")) lv_style_set_height(style, lv_xml_to_size(value));
44  */
45 #define SET_STYLE_IF(prop, value) if(lv_streq(name, #prop)) lv_style_set_##prop(style, value)
46 
47 /**********************
48  *   GLOBAL FUNCTIONS
49  **********************/
50 
lv_xml_style_state_to_enum(const char * txt)51 lv_state_t lv_xml_style_state_to_enum(const char * txt)
52 {
53     if(lv_streq("default", txt)) return LV_STATE_DEFAULT;
54     else if(lv_streq("pressed", txt)) return LV_STATE_PRESSED;
55     else if(lv_streq("checked", txt)) return LV_STATE_CHECKED;
56     else if(lv_streq("scrolled", txt)) return LV_STATE_SCROLLED;
57     else if(lv_streq("focused", txt)) return LV_STATE_FOCUSED;
58     else if(lv_streq("focus_key", txt)) return LV_STATE_FOCUS_KEY;
59     else if(lv_streq("edited", txt)) return LV_STATE_EDITED;
60     else if(lv_streq("hovered", txt)) return LV_STATE_HOVERED;
61     else if(lv_streq("disabled", txt)) return LV_STATE_DISABLED;
62 
63     return 0; /*Return 0 in lack of a better option. */
64 }
65 
lv_xml_style_part_to_enum(const char * txt)66 lv_part_t lv_xml_style_part_to_enum(const char * txt)
67 {
68     if(lv_streq("main", txt)) return LV_PART_MAIN;
69     else if(lv_streq("scrollbar", txt)) return LV_PART_SCROLLBAR;
70     else if(lv_streq("indicator", txt)) return LV_PART_INDICATOR;
71     else if(lv_streq("knob", txt)) return LV_PART_KNOB;
72     else if(lv_streq("selected", txt)) return LV_PART_SELECTED;
73     else if(lv_streq("items", txt)) return LV_PART_ITEMS;
74     else if(lv_streq("cursor", txt)) return LV_PART_CURSOR;
75 
76     return 0; /*Return 0 in lack of a better option. */
77 }
78 
lv_xml_style_register(lv_xml_component_ctx_t * ctx,const char ** attrs)79 void lv_xml_style_register(lv_xml_component_ctx_t * ctx, const char ** attrs)
80 {
81     const char * style_name =  lv_xml_get_value_of(attrs, "name");
82     if(style_name == NULL) {
83         LV_LOG_WARN("'name' is missing from a style");
84         return;
85     }
86     lv_xml_style_t * xml_style = lv_ll_ins_tail(&ctx->style_ll);
87     lv_style_t * style = &xml_style->style;
88     lv_style_init(style);
89     xml_style->name = lv_strdup(style_name);
90 
91     size_t long_name_len = lv_strlen(ctx->name) + 1 + lv_strlen(style_name) + 1;
92     xml_style->long_name = lv_malloc(long_name_len);
93     lv_snprintf((char *)xml_style->long_name, long_name_len, "%s.%s", ctx->name, style_name); /*E.g. my_button.style1*/
94 
95     for(int i = 0; attrs[i]; i += 2) {
96         const char * name = attrs[i];
97         const char * value = attrs[i + 1];
98         if(lv_streq(name, "name")) continue;
99         if(lv_streq(name, "help")) continue;
100 
101         if(value[0] == '#') {
102             const char * value_clean = &value[1];
103             lv_xml_const_t * c;
104             LV_LL_READ(&ctx->const_ll, c) {
105                 if(lv_streq(c->name, value_clean)) {
106                     value = c->value;
107                     break;
108                 }
109             }
110         }
111 
112 
113         SET_STYLE_IF(width, lv_xml_to_size(value));
114         else SET_STYLE_IF(height, lv_xml_to_size(value));
115         else SET_STYLE_IF(length, lv_xml_to_size(value));
116         else SET_STYLE_IF(radius, lv_xml_to_size(value));
117 
118         else SET_STYLE_IF(pad_left, lv_xml_atoi(value));
119         else SET_STYLE_IF(pad_right, lv_xml_atoi(value));
120         else SET_STYLE_IF(pad_top, lv_xml_atoi(value));
121         else SET_STYLE_IF(pad_bottom, lv_xml_atoi(value));
122         else SET_STYLE_IF(pad_hor, lv_xml_atoi(value));
123         else SET_STYLE_IF(pad_ver, lv_xml_atoi(value));
124         else SET_STYLE_IF(pad_all, lv_xml_atoi(value));
125         else SET_STYLE_IF(pad_row, lv_xml_atoi(value));
126         else SET_STYLE_IF(pad_column, lv_xml_atoi(value));
127         else SET_STYLE_IF(pad_gap, lv_xml_atoi(value));
128         else SET_STYLE_IF(pad_radial, lv_xml_atoi(value));
129 
130         else SET_STYLE_IF(margin_left, lv_xml_atoi(value));
131         else SET_STYLE_IF(margin_right, lv_xml_atoi(value));
132         else SET_STYLE_IF(margin_top, lv_xml_atoi(value));
133         else SET_STYLE_IF(margin_bottom, lv_xml_atoi(value));
134         else SET_STYLE_IF(margin_hor, lv_xml_atoi(value));
135         else SET_STYLE_IF(margin_ver, lv_xml_atoi(value));
136         else SET_STYLE_IF(margin_all, lv_xml_atoi(value));
137 
138         else SET_STYLE_IF(base_dir, lv_xml_base_dir_to_enum(value));
139         else SET_STYLE_IF(clip_corner, lv_xml_to_bool(value));
140 
141         else SET_STYLE_IF(bg_opa, lv_xml_to_opa(value));
142         else SET_STYLE_IF(bg_color, lv_xml_to_color(value));
143         else SET_STYLE_IF(bg_grad_dir, lv_xml_grad_dir_to_enum(value));
144         else SET_STYLE_IF(bg_grad_color, lv_xml_to_color(value));
145         else SET_STYLE_IF(bg_main_stop, lv_xml_atoi(value));
146         else SET_STYLE_IF(bg_grad_stop, lv_xml_atoi(value));
147 
148         else SET_STYLE_IF(bg_image_src, lv_xml_get_image(value));
149         else SET_STYLE_IF(bg_image_tiled, lv_xml_to_bool(value));
150         else SET_STYLE_IF(bg_image_recolor, lv_xml_to_color(value));
151         else SET_STYLE_IF(bg_image_recolor_opa, lv_xml_to_opa(value));
152 
153         else SET_STYLE_IF(border_color, lv_xml_to_color(value));
154         else SET_STYLE_IF(border_width, lv_xml_atoi(value));
155         else SET_STYLE_IF(border_opa, lv_xml_to_opa(value));
156         else SET_STYLE_IF(border_side, lv_xml_border_side_to_enum(value));
157         else SET_STYLE_IF(border_post, lv_xml_to_bool(value));
158 
159         else SET_STYLE_IF(outline_color, lv_xml_to_color(value));
160         else SET_STYLE_IF(outline_width, lv_xml_atoi(value));
161         else SET_STYLE_IF(outline_opa, lv_xml_to_opa(value));
162         else SET_STYLE_IF(outline_pad, lv_xml_atoi(value));
163 
164         else SET_STYLE_IF(shadow_width, lv_xml_atoi(value));
165         else SET_STYLE_IF(shadow_color, lv_xml_to_color(value));
166         else SET_STYLE_IF(shadow_offset_x, lv_xml_atoi(value));
167         else SET_STYLE_IF(shadow_offset_y, lv_xml_atoi(value));
168         else SET_STYLE_IF(shadow_spread, lv_xml_atoi(value));
169         else SET_STYLE_IF(shadow_opa, lv_xml_to_opa(value));
170 
171         else SET_STYLE_IF(text_color, lv_xml_to_color(value));
172         else SET_STYLE_IF(text_font, lv_xml_get_font(value));
173         else SET_STYLE_IF(text_opa, lv_xml_to_opa(value));
174         else SET_STYLE_IF(text_align, lv_xml_text_align_to_enum(value));
175         else SET_STYLE_IF(text_letter_space, lv_xml_atoi(value));
176         else SET_STYLE_IF(text_line_space, lv_xml_atoi(value));
177         else SET_STYLE_IF(text_decor, lv_xml_text_decor_to_enum(value));
178 
179         else SET_STYLE_IF(image_opa, lv_xml_to_opa(value));
180         else SET_STYLE_IF(image_recolor, lv_xml_to_color(value));
181         else SET_STYLE_IF(image_recolor_opa, lv_xml_to_opa(value));
182 
183         else SET_STYLE_IF(line_color, lv_xml_to_color(value));
184         else SET_STYLE_IF(line_opa, lv_xml_to_opa(value));
185         else SET_STYLE_IF(line_width, lv_xml_atoi(value));
186         else SET_STYLE_IF(line_dash_width, lv_xml_atoi(value));
187         else SET_STYLE_IF(line_dash_gap, lv_xml_atoi(value));
188         else SET_STYLE_IF(line_rounded, lv_xml_to_bool(value));
189 
190         else SET_STYLE_IF(arc_color, lv_xml_to_color(value));
191         else SET_STYLE_IF(arc_opa, lv_xml_to_opa(value));
192         else SET_STYLE_IF(arc_width, lv_xml_atoi(value));
193         else SET_STYLE_IF(arc_rounded, lv_xml_to_bool(value));
194         else SET_STYLE_IF(arc_image_src, lv_xml_get_image(value));
195 
196         else SET_STYLE_IF(opa, lv_xml_to_opa(value));
197         else SET_STYLE_IF(opa_layered, lv_xml_to_opa(value));
198         else SET_STYLE_IF(color_filter_opa, lv_xml_to_opa(value));
199         else SET_STYLE_IF(anim_duration, lv_xml_atoi(value));
200         else SET_STYLE_IF(blend_mode, lv_xml_blend_mode_to_enum(value));
201         else SET_STYLE_IF(transform_width, lv_xml_atoi(value));
202         else SET_STYLE_IF(transform_height, lv_xml_atoi(value));
203         else SET_STYLE_IF(translate_x, lv_xml_atoi(value));
204         else SET_STYLE_IF(translate_y, lv_xml_atoi(value));
205         else SET_STYLE_IF(translate_radial, lv_xml_atoi(value));
206         else SET_STYLE_IF(transform_scale_x, lv_xml_atoi(value));
207         else SET_STYLE_IF(transform_scale_y, lv_xml_atoi(value));
208         else SET_STYLE_IF(transform_rotation, lv_xml_atoi(value));
209         else SET_STYLE_IF(transform_pivot_x, lv_xml_atoi(value));
210         else SET_STYLE_IF(transform_pivot_y, lv_xml_atoi(value));
211         else SET_STYLE_IF(transform_skew_x, lv_xml_atoi(value));
212         else SET_STYLE_IF(bitmap_mask_src, lv_xml_get_image(value));
213         else SET_STYLE_IF(rotary_sensitivity, lv_xml_atoi(value));
214 
215         else SET_STYLE_IF(layout, lv_xml_layout_to_enum(value));
216 
217         else SET_STYLE_IF(flex_flow, lv_xml_flex_flow_to_enum(value));
218         else SET_STYLE_IF(flex_grow, lv_xml_atoi(value));
219         else SET_STYLE_IF(flex_main_place, lv_xml_flex_align_to_enum(value));
220         else SET_STYLE_IF(flex_cross_place, lv_xml_flex_align_to_enum(value));
221         else SET_STYLE_IF(flex_track_place, lv_xml_flex_align_to_enum(value));
222 
223         else SET_STYLE_IF(grid_column_align, lv_xml_grid_align_to_enum(value));
224         else SET_STYLE_IF(grid_row_align, lv_xml_grid_align_to_enum(value));
225         else SET_STYLE_IF(grid_cell_column_pos, lv_xml_atoi(value));
226         else SET_STYLE_IF(grid_cell_column_span, lv_xml_atoi(value));
227         else SET_STYLE_IF(grid_cell_x_align, lv_xml_grid_align_to_enum(value));
228         else SET_STYLE_IF(grid_cell_row_pos, lv_xml_atoi(value));
229         else SET_STYLE_IF(grid_cell_row_span, lv_xml_atoi(value));
230         else SET_STYLE_IF(grid_cell_y_align, lv_xml_grid_align_to_enum(value));
231         else {
232             LV_LOG_WARN("%s style property is not supported", name);
233         }
234     }
235 }
236 
lv_xml_style_string_process(char * txt,lv_style_selector_t * selector)237 const char * lv_xml_style_string_process(char * txt, lv_style_selector_t * selector)
238 {
239     *selector = 0;
240 
241     char * style_name = lv_xml_split_str(&txt, ':');
242     char * selector_str = lv_xml_split_str(&txt, ':');
243     while(selector_str != NULL) {
244         /* Handle different states and parts */
245         *selector |= lv_xml_style_state_to_enum(selector_str);
246         *selector |= lv_xml_style_part_to_enum(selector_str);
247 
248         /* Move to the next token */
249         selector_str = lv_xml_split_str(&txt, ':');
250     }
251 
252     return style_name;
253 }
254 
lv_xml_style_add_to_obj(lv_xml_parser_state_t * state,lv_obj_t * obj,const char * text)255 void lv_xml_style_add_to_obj(lv_xml_parser_state_t * state, lv_obj_t * obj, const char * text)
256 {
257     char * str = lv_strdup(text);
258     char * str_ori = str;
259 
260     /* Split the string based on space and colons */
261     char * onestyle_str = lv_xml_split_str(&str, ' ');
262     while(onestyle_str != NULL) {
263         /* Parse the parts and states after the space */
264         lv_style_selector_t selector = 0;
265         const char * style_name = lv_xml_style_string_process(onestyle_str, &selector);
266         if(style_name != NULL) {
267             lv_xml_style_t * xml_style = NULL;
268             /*Resolve parameters or just find the style*/
269             if(style_name[0] == '$') {
270                 /*E.g. `$pr_style` style name means use the value
271                  *coming from the parent's `pr_style` named attribute*/
272                 const char * name_clean = &style_name[1];
273                 const char * parent_style_name = lv_xml_get_value_of(state->parent_attrs, name_clean);
274                 if(parent_style_name) {
275                     xml_style = lv_xml_get_style_by_name(state->parent_ctx, parent_style_name);
276                 }
277             }
278             else {
279                 xml_style = lv_xml_get_style_by_name(&state->ctx, style_name);
280             }
281             if(xml_style) {
282                 /* Apply with the selector */
283                 lv_obj_add_style(obj, &xml_style->style, selector);
284             }
285         }
286         onestyle_str = lv_xml_split_str(&str, ' ');
287     }
288 
289     lv_free(str_ori);
290 }
291 
lv_xml_get_style_by_name(lv_xml_component_ctx_t * ctx,const char * style_name_raw)292 lv_xml_style_t * lv_xml_get_style_by_name(lv_xml_component_ctx_t * ctx, const char * style_name_raw)
293 {
294     const char * style_name = strrchr(style_name_raw, '.');
295 
296     if(style_name) {
297         char component_name[256];
298         size_t len = (size_t)(style_name - style_name_raw);
299         lv_memcpy(component_name, style_name_raw, len);
300         component_name[len] = '\0';
301         ctx = lv_xml_component_get_ctx(component_name);
302         style_name++; /*Skip the dot*/
303     }
304     else {
305         style_name = style_name_raw;
306     }
307 
308     lv_xml_style_t * xml_style;
309     LV_LL_READ(&ctx->style_ll, xml_style) {
310         if(lv_streq(xml_style->name, style_name)) return xml_style;
311     }
312 
313     LV_LOG_WARN("No style found with %s name", style_name_raw);
314 
315     return NULL;
316 }
317 
318 /**********************
319  *   STATIC FUNCTIONS
320  **********************/
321 
322 #endif /* LV_USE_XML */
323