1 #if LV_BUILD_TEST
2 #include "../lvgl.h"
3 #include "../../lvgl_private.h"
4
5 #include "unity/unity.h"
6
7 #include "lv_test_indev.h"
8
9 static lv_obj_t * g_active_screen = NULL;
10 static lv_obj_t * g_bar = NULL;
11
setUp(void)12 void setUp(void)
13 {
14 g_active_screen = lv_screen_active();
15 g_bar = lv_bar_create(g_active_screen);
16 }
17
tearDown(void)18 void tearDown(void)
19 {
20 lv_obj_clean(g_active_screen);
21 }
22
test_bar_should_have_valid_default_attributes(void)23 void test_bar_should_have_valid_default_attributes(void)
24 {
25 TEST_ASSERT_EQUAL(0, lv_bar_get_min_value(g_bar));
26 TEST_ASSERT_EQUAL(100, lv_bar_get_max_value(g_bar));
27 TEST_ASSERT_EQUAL(LV_BAR_MODE_NORMAL, lv_bar_get_mode(g_bar));
28 }
29
30 /*
31 * Bar has two parts, main and indicator, coordinates of the latter are
32 * calculated based on:
33 * - Bar size
34 * - Bar (main part) padding
35 * - Bar value
36 * - Bar coordinates
37 * - Bar base direction
38 * See Boxing model in docs for reference.
39 *
40 * Bar properties assumed:
41 * - mode: LV_BAR_MODE_NORMAL
42 * - min value: 0
43 * - max value: 100
44 * - base direction: LTR
45 */
test_bar_should_update_indicator_right_coordinate_based_on_bar_value(void)46 void test_bar_should_update_indicator_right_coordinate_based_on_bar_value(void)
47 {
48 lv_bar_t * bar_ptr = (lv_bar_t *) g_bar;
49
50 static lv_style_t bar_style;
51
52 const int32_t style_padding = 5u;
53 const int32_t bar_width = 200u;
54 const int32_t bar_height = 20u;
55 int32_t bar_value = 10u;
56
57 lv_style_init(&bar_style);
58 lv_style_set_pad_all(&bar_style, style_padding);
59
60 /* Setup new style */
61 lv_obj_remove_style_all(g_bar);
62 lv_obj_add_style(g_bar, &bar_style, LV_PART_MAIN);
63
64 /* Set properties */
65 lv_obj_set_size(g_bar, bar_width, bar_height);
66 lv_bar_set_value(g_bar, bar_value, LV_ANIM_OFF);
67
68 /* FIXME: Remove wait */
69 lv_test_indev_wait(50);
70
71 int32_t actual_coord = lv_area_get_width(&bar_ptr->indic_area);
72
73 /* Calculate bar indicator right coordinate, using rule of 3 */
74 int32_t bar_max_value = lv_bar_get_max_value(g_bar);
75 int32_t indicator_part_width = lv_obj_get_content_width(g_bar);
76
77 int32_t expected_coord = (bar_value * indicator_part_width) / bar_max_value;
78 /* NOTE: Add 1 to calculation because the coordinates start at 0 */
79 expected_coord += 1;
80
81 TEST_ASSERT_EQUAL_INT32(expected_coord, actual_coord);
82 }
83
84 /*
85 * Bar has two parts, main and indicator, coordinates of the latter are
86 * calculated based on:
87 * - Bar size
88 * - Bar (main part) padding
89 * - Bar value
90 * - Bar coordinates
91 * - Bar base direction
92 * See Boxing model in docs for reference.
93 *
94 * Bar properties assumed:
95 * - mode: LV_BAR_MODE_NORMAL
96 * - min value: 0
97 * - max value: 100
98 */
test_bar_rtl_should_update_indicator_left_coordinate_based_on_bar_value(void)99 void test_bar_rtl_should_update_indicator_left_coordinate_based_on_bar_value(void)
100 {
101 lv_bar_t * bar_ptr = (lv_bar_t *) g_bar;
102
103 static lv_style_t bar_style;
104
105 const int32_t style_padding = 5u;
106 const int32_t bar_width = 200u;
107 const int32_t bar_height = 20u;
108 int32_t bar_value = 10u;
109
110 lv_style_init(&bar_style);
111 lv_style_set_pad_all(&bar_style, style_padding);
112
113 /* Setup new style */
114 lv_obj_remove_style_all(g_bar);
115 lv_obj_add_style(g_bar, &bar_style, LV_PART_MAIN);
116
117 /* Set properties */
118 lv_obj_set_size(g_bar, bar_width, bar_height);
119 lv_bar_set_value(g_bar, bar_value, LV_ANIM_OFF);
120 lv_obj_set_style_base_dir(g_bar, LV_BASE_DIR_RTL, 0);
121
122 /* FIXME: Remove wait */
123 lv_test_indev_wait(50);
124
125 int32_t actual_coord = bar_ptr->indic_area.x1;
126
127 /* Calculate current indicator width */
128 int32_t bar_max_value = lv_bar_get_max_value(g_bar);
129 int32_t indicator_part_width = lv_obj_get_content_width(g_bar);
130 int32_t right_padding = lv_obj_get_style_pad_right(g_bar, LV_PART_MAIN);
131 int32_t indicator_width = (bar_value * indicator_part_width) / bar_max_value;
132
133 int32_t expected_coord = (bar_width - right_padding) - indicator_width;
134 expected_coord -= 1;
135
136 TEST_ASSERT_EQUAL_INT32(expected_coord, actual_coord);
137 }
138
test_bar_normal(void)139 void test_bar_normal(void)
140 {
141 int32_t w = 300;
142 int32_t h = 40;
143 int32_t h_gap = 20;
144 int32_t w_gap = 20;
145 int32_t y = h_gap;
146 int32_t x = w_gap;
147 lv_color_t bg_color = lv_color_black();
148 lv_color_t indic_color = lv_color_hex(0x0000FF);
149
150 lv_obj_t * screen = lv_obj_create(lv_screen_active());
151 lv_obj_remove_style_all(screen);
152 lv_obj_set_size(screen, 800, 480);
153 lv_obj_center(screen);
154 lv_obj_set_style_bg_color(screen, lv_color_white(), 0);
155 lv_obj_set_style_bg_opa(screen, LV_OPA_100, 0);
156 lv_obj_set_style_pad_all(screen, 0, 0);
157
158 lv_obj_t * test_bar = lv_bar_create(screen);
159 lv_obj_set_style_radius(test_bar, 100, 0);
160 lv_obj_set_style_radius(test_bar, 100, LV_PART_MAIN);
161 lv_obj_set_style_bg_opa(test_bar, LV_OPA_30, LV_PART_MAIN);
162 lv_obj_set_style_bg_color(test_bar, bg_color, LV_PART_MAIN);
163 lv_obj_set_style_bg_color(test_bar, indic_color, LV_PART_INDICATOR);
164 lv_bar_set_range(test_bar, 0, 100);
165 lv_bar_set_value(test_bar, 30, LV_ANIM_OFF);
166 lv_obj_set_size(test_bar, w, h);
167 lv_obj_align(test_bar, LV_ALIGN_TOP_LEFT, x, y);
168 y += h + h_gap;
169
170 test_bar = lv_bar_create(screen);
171 lv_obj_set_style_radius(test_bar, 100, 0);
172 lv_obj_set_style_radius(test_bar, 100, LV_PART_MAIN);
173 lv_obj_set_style_bg_opa(test_bar, LV_OPA_30, LV_PART_MAIN);
174 lv_obj_set_style_bg_color(test_bar, bg_color, LV_PART_MAIN);
175 lv_obj_set_style_bg_color(test_bar, indic_color, LV_PART_INDICATOR);
176 lv_bar_set_range(test_bar, 0, 100);
177 lv_bar_set_value(test_bar, 30, LV_ANIM_OFF);
178 lv_obj_set_size(test_bar, w, h);
179 lv_obj_align(test_bar, LV_ALIGN_TOP_LEFT, x, y);
180 lv_obj_set_style_base_dir(test_bar, LV_BASE_DIR_RTL, 0);
181 y += h + h_gap;
182
183 x = 150;
184 test_bar = lv_bar_create(screen);
185 lv_obj_set_style_radius(test_bar, 100, 0);
186 lv_obj_set_style_radius(test_bar, 100, LV_PART_MAIN);
187 lv_obj_set_style_bg_opa(test_bar, LV_OPA_30, LV_PART_MAIN);
188 lv_obj_set_style_bg_color(test_bar, bg_color, LV_PART_MAIN);
189 lv_obj_set_style_bg_color(test_bar, indic_color, LV_PART_INDICATOR);
190 lv_bar_set_range(test_bar, 0, 100);
191 lv_bar_set_value(test_bar, 30, LV_ANIM_OFF);
192 lv_obj_set_size(test_bar, h, w);
193 lv_obj_align(test_bar, LV_ALIGN_TOP_LEFT, x, y);
194 x += h + w_gap;
195
196 test_bar = lv_bar_create(screen);
197 lv_obj_set_style_radius(test_bar, 100, 0);
198 lv_obj_set_style_radius(test_bar, 100, LV_PART_MAIN);
199 lv_obj_set_style_bg_opa(test_bar, LV_OPA_30, LV_PART_MAIN);
200 lv_obj_set_style_bg_color(test_bar, bg_color, LV_PART_MAIN);
201 lv_obj_set_style_bg_color(test_bar, indic_color, LV_PART_INDICATOR);
202 lv_bar_set_range(test_bar, 100, 0);
203 lv_bar_set_value(test_bar, 30, LV_ANIM_OFF);
204 lv_obj_set_size(test_bar, h, w);
205 lv_obj_align(test_bar, LV_ALIGN_TOP_LEFT, x, y);
206 TEST_ASSERT_EQUAL_SCREENSHOT("widgets/bar_1.png");
207 }
208
test_bar_indicator_area_should_get_smaller_when_padding_is_increased(void)209 void test_bar_indicator_area_should_get_smaller_when_padding_is_increased(void)
210 {
211 lv_bar_t * bar_ptr = (lv_bar_t *) g_bar;
212
213 const int32_t style_padding = 10u;
214 static lv_style_t bar_style;
215
216 int32_t new_height = 0u;
217 int32_t new_width = 0u;
218 int32_t original_height = 0u;
219 int32_t original_width = 0u;
220
221 lv_bar_set_value(g_bar, 50, LV_ANIM_OFF);
222 lv_test_indev_wait(50);
223
224 original_width = lv_area_get_width(&bar_ptr->indic_area);
225 original_height = lv_area_get_height(&bar_ptr->indic_area);
226
227 /* Setup new padding */
228 lv_style_init(&bar_style);
229 lv_style_set_pad_all(&bar_style, style_padding);
230 lv_obj_set_size(g_bar, 100, 50);
231
232 /* Apply new style */
233 lv_obj_remove_style_all(g_bar);
234 lv_obj_add_style(g_bar, &bar_style, LV_PART_MAIN);
235
236 /* Notify LVGL of style change */
237 lv_obj_report_style_change(&bar_style);
238 lv_test_indev_wait(50);
239
240 new_height = lv_area_get_height(&bar_ptr->indic_area);
241 new_width = lv_area_get_width(&bar_ptr->indic_area);
242
243 TEST_ASSERT_LESS_THAN_INT32(original_height, new_height);
244 TEST_ASSERT_LESS_THAN_INT32(original_width, new_width);
245 }
246
test_bar_start_value_should_only_change_when_in_range_mode(void)247 void test_bar_start_value_should_only_change_when_in_range_mode(void)
248 {
249 int32_t new_start_value = 20u;
250
251 lv_bar_set_value(g_bar, 90, LV_ANIM_OFF);
252 lv_bar_set_start_value(g_bar, new_start_value, LV_ANIM_OFF);
253
254 /* Start value shouldn't be updated when not in RANGE mode */
255 TEST_ASSERT_EQUAL_INT32(0u, lv_bar_get_start_value(g_bar));
256
257 /* Set bar in RANGE mode so we can edit the start value */
258 lv_bar_set_mode(g_bar, LV_BAR_MODE_RANGE);
259 lv_bar_set_start_value(g_bar, new_start_value, LV_ANIM_OFF);
260
261 TEST_ASSERT_EQUAL_INT32(new_start_value, lv_bar_get_start_value(g_bar));
262 }
263
test_bar_start_value_should_be_smaller_than_current_value_in_range_mode(void)264 void test_bar_start_value_should_be_smaller_than_current_value_in_range_mode(void)
265 {
266 /* Set bar in RANGE mode so we can edit the start value */
267 lv_bar_set_mode(g_bar, LV_BAR_MODE_RANGE);
268 lv_bar_set_value(g_bar, 50, LV_ANIM_OFF);
269 lv_bar_set_start_value(g_bar, 100u, LV_ANIM_OFF);
270
271 TEST_ASSERT_EQUAL_INT32(lv_bar_get_value(g_bar), lv_bar_get_start_value(g_bar));
272 }
273
test_bar_current_value_should_be_truncated_to_max_value_when_exceeds_it(void)274 void test_bar_current_value_should_be_truncated_to_max_value_when_exceeds_it(void)
275 {
276 int32_t max_value = lv_bar_get_max_value(g_bar);
277 int32_t new_value = max_value + 1u;
278
279 lv_bar_set_value(g_bar, new_value, LV_ANIM_OFF);
280 TEST_ASSERT_EQUAL_INT32(max_value, lv_bar_get_value(g_bar));
281 }
282
test_bar_current_value_should_be_truncated_to_min_value_when_it_is_below_it(void)283 void test_bar_current_value_should_be_truncated_to_min_value_when_it_is_below_it(void)
284 {
285 int32_t min_value = lv_bar_get_min_value(g_bar);
286 int32_t new_value = min_value - 1u;
287
288 lv_bar_set_value(g_bar, new_value, LV_ANIM_OFF);
289 TEST_ASSERT_EQUAL_INT32(min_value, lv_bar_get_value(g_bar));
290 }
291
292 /** When in symmetrical mode, the bar indicator has to be drawn towards the min
293 * range value. Requires a negative min range value and a positive max range
294 * value.
295 *
296 * Bar properties assumed:
297 * - base direction: LTR
298 */
test_bar_indicator_should_be_drawn_towards_the_min_range_side_after_setting_a_more_negative_value(void)299 void test_bar_indicator_should_be_drawn_towards_the_min_range_side_after_setting_a_more_negative_value(void)
300 {
301 lv_bar_t * bar_ptr = (lv_bar_t *) g_bar;
302
303 /* Setup bar properties */
304 lv_obj_set_size(g_bar, 100, 50);
305 lv_bar_set_mode(g_bar, LV_BAR_MODE_SYMMETRICAL);
306 lv_bar_set_range(g_bar, -100, 100);
307
308 /* Set bar value to 1, so it gets drawn at the middle of the bar */
309 lv_bar_set_value(g_bar, 1, LV_ANIM_OFF);
310 lv_test_indev_wait(50);
311
312 int32_t original_pos = bar_ptr->indic_area.x1;
313
314 /* Set bar to a more negative value */
315 lv_bar_set_value(g_bar, -50, LV_ANIM_OFF);
316 lv_test_indev_wait(50);
317
318 int32_t final_pos = bar_ptr->indic_area.x1;
319
320 TEST_ASSERT_LESS_THAN(original_pos, final_pos);
321 }
322
styled_bar_create(bool ver,int32_t start_value,int32_t end_value,lv_grad_dir_t grad_dir,int32_t bg_radius,int32_t indic_radius,int32_t bg_pad)323 static lv_obj_t * styled_bar_create(bool ver, int32_t start_value, int32_t end_value, lv_grad_dir_t grad_dir,
324 int32_t bg_radius, int32_t indic_radius, int32_t bg_pad)
325 {
326 lv_obj_t * bar = lv_bar_create(lv_screen_active());
327 if(ver) lv_obj_set_size(bar, 20, 100);
328 else lv_obj_set_size(bar, 100, 20);
329 lv_bar_set_range(bar, 0, 100);
330 lv_bar_set_mode(bar, LV_BAR_MODE_RANGE);
331 lv_bar_set_value(bar, end_value, LV_ANIM_OFF);
332 lv_bar_set_start_value(bar, start_value, LV_ANIM_OFF);
333
334 lv_obj_set_style_bg_opa(bar, 255, LV_PART_MAIN);
335 lv_obj_set_style_bg_color(bar, lv_color_hex3(0x0ff), LV_PART_MAIN);
336 lv_obj_set_style_radius(bar, bg_radius, LV_PART_MAIN);
337 lv_obj_set_style_pad_all(bar, bg_pad, LV_PART_MAIN);
338
339 lv_obj_set_style_bg_opa(bar, LV_OPA_70, LV_PART_INDICATOR);
340 lv_obj_set_style_bg_color(bar, lv_color_hex3(0xf0f), LV_PART_INDICATOR);
341 lv_obj_set_style_bg_grad_color(bar, lv_color_hex3(0x8f8), LV_PART_INDICATOR);
342 lv_obj_set_style_bg_grad_dir(bar, grad_dir, LV_PART_INDICATOR);
343
344 lv_obj_set_style_border_width(bar, 2, LV_PART_INDICATOR);
345 lv_obj_set_style_border_color(bar, lv_color_hex3(0x0f0), LV_PART_INDICATOR);
346 lv_obj_set_style_border_opa(bar, LV_OPA_70, LV_PART_INDICATOR);
347 lv_obj_set_style_outline_width(bar, 2, LV_PART_INDICATOR);
348 lv_obj_set_style_outline_pad(bar, 4, LV_PART_INDICATOR);
349 lv_obj_set_style_outline_color(bar, lv_color_hex3(0xff0), LV_PART_INDICATOR);
350 lv_obj_set_style_outline_opa(bar, LV_OPA_70, LV_PART_INDICATOR);
351 lv_obj_set_style_shadow_width(bar, 20, LV_PART_INDICATOR);
352 lv_obj_set_style_shadow_spread(bar, 5, LV_PART_INDICATOR);
353 lv_obj_set_style_shadow_color(bar, lv_color_hex3(0xf00), LV_PART_INDICATOR);
354 lv_obj_set_style_shadow_opa(bar, LV_OPA_70, LV_PART_INDICATOR);
355 lv_obj_set_style_radius(bar, indic_radius, LV_PART_INDICATOR);
356
357 return bar;
358 }
359
render_test_screen_create(bool ver,lv_grad_dir_t grad_dir,const char * ref_img_path)360 static void render_test_screen_create(bool ver, lv_grad_dir_t grad_dir, const char * ref_img_path)
361 {
362 lv_obj_t * active_screen = lv_screen_active();
363 lv_obj_clean(active_screen);
364
365 lv_obj_set_flex_flow(active_screen, ver ? LV_FLEX_FLOW_ROW_WRAP : LV_FLEX_FLOW_COLUMN_WRAP);
366 lv_obj_set_flex_align(active_screen, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_SPACE_EVENLY);
367 lv_obj_set_style_pad_row(active_screen, 17, 0);
368 lv_obj_set_style_pad_column(active_screen, 12, 0);
369 lv_obj_set_style_pad_all(active_screen, 15, 0);
370
371 int32_t bar_values[6][2] = {{0, 5}, {0, 50}, {0, 95}, {5, 100}, {95, 100}, {20, 90}};
372 int32_t bg_radius[2] = {0, 15};
373 int32_t indic_radius[2] = {0, 15};
374 int32_t bg_pad[3] = {-5, 0, 5};
375
376 uint32_t pad;
377 for(pad = 0; pad < 3; pad++) {
378 uint32_t indic_r;
379 for(indic_r = 0; indic_r < 2; indic_r++) {
380 uint32_t bg_r;
381 for(bg_r = 0; bg_r < 2; bg_r++) {
382 uint32_t v;
383 for(v = 0; v < 6; v++) {
384 styled_bar_create(ver, bar_values[v][0], bar_values[v][1], grad_dir, bg_radius[bg_r], indic_radius[indic_r],
385 bg_pad[pad]);
386 }
387 }
388 }
389 }
390
391 TEST_ASSERT_EQUAL_SCREENSHOT(ref_img_path);
392 }
393
test_bar_render_corner(void)394 void test_bar_render_corner(void)
395 {
396 render_test_screen_create(false, LV_GRAD_DIR_NONE, "widgets/bar_corner_1.png");
397 render_test_screen_create(false, LV_GRAD_DIR_HOR, "widgets/bar_corner_2.png");
398 render_test_screen_create(false, LV_GRAD_DIR_VER, "widgets/bar_corner_3.png");
399 render_test_screen_create(true, LV_GRAD_DIR_NONE, "widgets/bar_corner_4.png");
400 render_test_screen_create(true, LV_GRAD_DIR_HOR, "widgets/bar_corner_5.png");
401 render_test_screen_create(true, LV_GRAD_DIR_VER, "widgets/bar_corner_6.png");
402 }
403
404
bar_create_orientation(lv_bar_orientation_t orientation,int32_t w,int32_t h)405 static lv_obj_t * bar_create_orientation(lv_bar_orientation_t orientation, int32_t w, int32_t h)
406 {
407 lv_obj_t * bar = lv_bar_create(g_active_screen);
408 lv_bar_set_orientation(bar, orientation);
409 lv_obj_set_size(bar, w, h);
410 lv_bar_set_value(bar, 30, LV_ANIM_OFF);
411
412 return bar;
413
414 }
415
test_bar_orientation(void)416 void test_bar_orientation(void)
417 {
418 lv_obj_clean(g_active_screen);
419
420 lv_obj_set_flex_flow(g_active_screen, LV_FLEX_FLOW_ROW_WRAP);
421
422 lv_obj_t * label;
423
424 label = lv_label_create(g_active_screen);
425 lv_label_set_text(label, "Auto");
426 lv_obj_set_width(label, lv_pct(100));
427
428 bar_create_orientation(LV_BAR_ORIENTATION_AUTO, 100, 20);
429 bar_create_orientation(LV_BAR_ORIENTATION_AUTO, 20, 100);
430 bar_create_orientation(LV_BAR_ORIENTATION_AUTO, 100, 100);
431
432 label = lv_label_create(g_active_screen);
433 lv_label_set_text(label, "Vertical");
434 lv_obj_set_width(label, lv_pct(100));
435
436 bar_create_orientation(LV_BAR_ORIENTATION_VERTICAL, 100, 20);
437 bar_create_orientation(LV_BAR_ORIENTATION_VERTICAL, 20, 100);
438 bar_create_orientation(LV_BAR_ORIENTATION_VERTICAL, 100, 100);
439
440 label = lv_label_create(g_active_screen);
441 lv_label_set_text(label, "Horizontal");
442 lv_obj_set_width(label, lv_pct(100));
443
444 bar_create_orientation(LV_BAR_ORIENTATION_HORIZONTAL, 100, 20);
445 bar_create_orientation(LV_BAR_ORIENTATION_HORIZONTAL, 20, 100);
446 bar_create_orientation(LV_BAR_ORIENTATION_HORIZONTAL, 100, 100);
447
448 TEST_ASSERT_EQUAL_SCREENSHOT("widgets/bar_2.png");
449 }
450
451 #endif
452