1 /**
2 * @file lv_line.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "lv_line.h"
10
11 #if LV_USE_LINE != 0
12 #include "../misc/lv_assert.h"
13 #include "../draw/lv_draw.h"
14 #include "../misc/lv_math.h"
15 #include <stdbool.h>
16 #include <stdint.h>
17 #include <string.h>
18
19 /*********************
20 * DEFINES
21 *********************/
22 #define MY_CLASS &lv_line_class
23
24 /**********************
25 * TYPEDEFS
26 **********************/
27
28 /**********************
29 * STATIC PROTOTYPES
30 **********************/
31 static void lv_line_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
32 static void lv_line_event(const lv_obj_class_t * class_p, lv_event_t * e);
33
34 /**********************
35 * STATIC VARIABLES
36 **********************/
37 const lv_obj_class_t lv_line_class = {
38 .constructor_cb = lv_line_constructor,
39 .event_cb = lv_line_event,
40 .width_def = LV_SIZE_CONTENT,
41 .height_def = LV_SIZE_CONTENT,
42 .instance_size = sizeof(lv_line_t),
43 .base_class = &lv_obj_class
44 };
45
46 /**********************
47 * MACROS
48 **********************/
49
50 /**********************
51 * GLOBAL FUNCTIONS
52 **********************/
53
lv_line_create(lv_obj_t * parent)54 lv_obj_t * lv_line_create(lv_obj_t * parent)
55 {
56 LV_LOG_INFO("begin");
57 lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
58 lv_obj_class_init_obj(obj);
59 return obj;
60 }
61
62 /*=====================
63 * Setter functions
64 *====================*/
65
lv_line_set_points(lv_obj_t * obj,const lv_point_t points[],uint16_t point_num)66 void lv_line_set_points(lv_obj_t * obj, const lv_point_t points[], uint16_t point_num)
67 {
68 LV_ASSERT_OBJ(obj, MY_CLASS);
69
70 lv_line_t * line = (lv_line_t *)obj;
71 line->point_array = points;
72 line->point_num = point_num;
73
74 lv_obj_refresh_self_size(obj);
75
76 lv_obj_invalidate(obj);
77 }
78
lv_line_set_y_invert(lv_obj_t * obj,bool en)79 void lv_line_set_y_invert(lv_obj_t * obj, bool en)
80 {
81 LV_ASSERT_OBJ(obj, MY_CLASS);
82
83 lv_line_t * line = (lv_line_t *)obj;
84 if(line->y_inv == en) return;
85
86 line->y_inv = en ? 1U : 0U;
87
88 lv_obj_invalidate(obj);
89 }
90
91 /*=====================
92 * Getter functions
93 *====================*/
94
lv_line_get_y_invert(const lv_obj_t * obj)95 bool lv_line_get_y_invert(const lv_obj_t * obj)
96 {
97 LV_ASSERT_OBJ(obj, MY_CLASS);
98
99 lv_line_t * line = (lv_line_t *)obj;
100
101 return line->y_inv == 1U;
102 }
103
104 /**********************
105 * STATIC FUNCTIONS
106 **********************/
107
lv_line_constructor(const lv_obj_class_t * class_p,lv_obj_t * obj)108 static void lv_line_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
109 {
110 LV_UNUSED(class_p);
111 LV_TRACE_OBJ_CREATE("begin");
112
113 lv_line_t * line = (lv_line_t *)obj;
114
115 line->point_num = 0;
116 line->point_array = NULL;
117 line->y_inv = 0;
118
119 lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICKABLE);
120
121 LV_TRACE_OBJ_CREATE("finished");
122 }
123
lv_line_event(const lv_obj_class_t * class_p,lv_event_t * e)124 static void lv_line_event(const lv_obj_class_t * class_p, lv_event_t * e)
125 {
126 LV_UNUSED(class_p);
127
128 lv_res_t res;
129
130 /*Call the ancestor's event handler*/
131 res = lv_obj_event_base(MY_CLASS, e);
132 if(res != LV_RES_OK) return;
133
134 lv_event_code_t code = lv_event_get_code(e);
135 lv_obj_t * obj = lv_event_get_target(e);
136
137 if(code == LV_EVENT_REFR_EXT_DRAW_SIZE) {
138 /*The corner of the skew lines is out of the intended area*/
139 lv_coord_t line_width = lv_obj_get_style_line_width(obj, LV_PART_MAIN);
140 lv_coord_t * s = lv_event_get_param(e);
141 if(*s < line_width) *s = line_width;
142 }
143 else if(code == LV_EVENT_GET_SELF_SIZE) {
144 lv_line_t * line = (lv_line_t *)obj;
145
146 if(line->point_num == 0 || line->point_array == NULL) return;
147
148 lv_point_t * p = lv_event_get_param(e);
149 lv_coord_t w = 0;
150 lv_coord_t h = 0;
151
152 uint16_t i;
153 for(i = 0; i < line->point_num; i++) {
154 w = LV_MAX(line->point_array[i].x, w);
155 h = LV_MAX(line->point_array[i].y, h);
156 }
157
158 lv_coord_t line_width = lv_obj_get_style_line_width(obj, LV_PART_MAIN);
159 w += line_width;
160 h += line_width;
161 p->x = w;
162 p->y = h;
163 }
164 else if(code == LV_EVENT_DRAW_MAIN) {
165 lv_line_t * line = (lv_line_t *)obj;
166 lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e);
167
168 if(line->point_num == 0 || line->point_array == NULL) return;
169
170 lv_area_t area;
171 lv_obj_get_coords(obj, &area);
172 lv_coord_t x_ofs = area.x1 - lv_obj_get_scroll_x(obj);
173 lv_coord_t y_ofs = area.y1 - lv_obj_get_scroll_y(obj);
174 lv_coord_t h = lv_obj_get_height(obj);
175
176 lv_draw_line_dsc_t line_dsc;
177 lv_draw_line_dsc_init(&line_dsc);
178 lv_obj_init_draw_line_dsc(obj, LV_PART_MAIN, &line_dsc);
179
180 /*Read all points and draw the lines*/
181 uint16_t i;
182 for(i = 0; i < line->point_num - 1; i++) {
183 lv_point_t p1;
184 lv_point_t p2;
185 p1.x = line->point_array[i].x + x_ofs;
186 p2.x = line->point_array[i + 1].x + x_ofs;
187
188 if(line->y_inv == 0) {
189 p1.y = line->point_array[i].y + y_ofs;
190 p2.y = line->point_array[i + 1].y + y_ofs;
191 }
192 else {
193 p1.y = h - line->point_array[i].y + y_ofs;
194 p2.y = h - line->point_array[i + 1].y + y_ofs;
195 }
196 lv_draw_line(draw_ctx, &line_dsc, &p1, &p2);
197 line_dsc.round_start = 0; /*Draw the rounding only on the end points after the first line*/
198 }
199 }
200 }
201 #endif
202