1 /**
2  * @file lv_led.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_led.h"
10 #if LV_USE_LED != 0
11 
12 #include "../lv_themes/lv_theme.h"
13 #include "../lv_draw/lv_draw.h"
14 
15 /*********************
16  *      DEFINES
17  *********************/
18 #define LV_LED_WIDTH_DEF (LV_DPI / 3)
19 #define LV_LED_HEIGHT_DEF (LV_DPI / 3)
20 #define LV_LED_BRIGHT_OFF 100
21 #define LV_LED_BRIGHT_ON 255
22 
23 /**********************
24  *      TYPEDEFS
25  **********************/
26 
27 /**********************
28  *  STATIC PROTOTYPES
29  **********************/
30 static bool lv_led_design(lv_obj_t * led, const lv_area_t * mask, lv_design_mode_t mode);
31 static lv_res_t lv_led_signal(lv_obj_t * led, lv_signal_t sign, void * param);
32 
33 /**********************
34  *  STATIC VARIABLES
35  **********************/
36 static lv_design_cb_t ancestor_design_f;
37 static lv_signal_cb_t ancestor_signal;
38 
39 /**********************
40  *      MACROS
41  **********************/
42 
43 /**********************
44  *   GLOBAL FUNCTIONS
45  **********************/
46 
47 /**
48  * Create a led objects
49  * @param par pointer to an object, it will be the parent of the new led
50  * @param copy pointer to a led object, if not NULL then the new object will be copied from it
51  * @return pointer to the created led
52  */
lv_led_create(lv_obj_t * par,const lv_obj_t * copy)53 lv_obj_t * lv_led_create(lv_obj_t * par, const lv_obj_t * copy)
54 {
55     LV_LOG_TRACE("led create started");
56 
57     /*Create the ancestor basic object*/
58     lv_obj_t * new_led = lv_obj_create(par, copy);
59     lv_mem_assert(new_led);
60     if(new_led == NULL) return NULL;
61 
62     if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_cb(new_led);
63     if(ancestor_design_f == NULL) ancestor_design_f = lv_obj_get_design_cb(new_led);
64 
65     /*Allocate the object type specific extended data*/
66     lv_led_ext_t * ext = lv_obj_allocate_ext_attr(new_led, sizeof(lv_led_ext_t));
67     lv_mem_assert(ext);
68     if(ext == NULL) return NULL;
69 
70     ext->bright = LV_LED_BRIGHT_ON;
71 
72     lv_obj_set_signal_cb(new_led, lv_led_signal);
73     lv_obj_set_design_cb(new_led, lv_led_design);
74 
75     /*Init the new led object*/
76     if(copy == NULL) {
77         lv_obj_set_size(new_led, LV_LED_WIDTH_DEF, LV_LED_HEIGHT_DEF);
78 
79         /*Set the default styles*/
80         lv_theme_t * th = lv_theme_get_current();
81         if(th) {
82             lv_led_set_style(new_led, LV_LED_STYLE_MAIN, th->style.led);
83         } else {
84             lv_led_set_style(new_led, LV_LED_STYLE_MAIN, &lv_style_pretty_color);
85         }
86     }
87     /*Copy an existing object*/
88     else {
89         lv_led_ext_t * copy_ext = lv_obj_get_ext_attr(copy);
90         ext->bright             = copy_ext->bright;
91 
92         /*Refresh the style with new signal function*/
93         lv_obj_refresh_style(new_led);
94     }
95 
96     LV_LOG_INFO("led created");
97 
98     return new_led;
99 }
100 
101 /*=====================
102  * Setter functions
103  *====================*/
104 
105 /**
106  * Set the brightness of a LED object
107  * @param led pointer to a LED object
108  * @param bright 0 (max. dark) ... 255 (max. light)
109  */
lv_led_set_bright(lv_obj_t * led,uint8_t bright)110 void lv_led_set_bright(lv_obj_t * led, uint8_t bright)
111 {
112     /*Set the brightness*/
113     lv_led_ext_t * ext = lv_obj_get_ext_attr(led);
114     if(ext->bright == bright) return;
115 
116     ext->bright = bright;
117 
118     /*Invalidate the object there fore it will be redrawn*/
119     lv_obj_invalidate(led);
120 }
121 
122 /**
123  * Light on a LED
124  * @param led pointer to a LED object
125  */
lv_led_on(lv_obj_t * led)126 void lv_led_on(lv_obj_t * led)
127 {
128     lv_led_set_bright(led, LV_LED_BRIGHT_ON);
129 }
130 
131 /**
132  * Light off a LED
133  * @param led pointer to a LED object
134  */
lv_led_off(lv_obj_t * led)135 void lv_led_off(lv_obj_t * led)
136 {
137     lv_led_set_bright(led, LV_LED_BRIGHT_OFF);
138 }
139 
140 /**
141  * Toggle the state of a LED
142  * @param led pointer to a LED object
143  */
lv_led_toggle(lv_obj_t * led)144 void lv_led_toggle(lv_obj_t * led)
145 {
146     uint8_t bright = lv_led_get_bright(led);
147     if(bright > (LV_LED_BRIGHT_OFF + LV_LED_BRIGHT_ON) >> 1)
148         lv_led_off(led);
149     else
150         lv_led_on(led);
151 }
152 
153 /*=====================
154  * Getter functions
155  *====================*/
156 
157 /**
158  * Get the brightness of a LEd object
159  * @param led pointer to LED object
160  * @return bright 0 (max. dark) ... 255 (max. light)
161  */
lv_led_get_bright(const lv_obj_t * led)162 uint8_t lv_led_get_bright(const lv_obj_t * led)
163 {
164     lv_led_ext_t * ext = lv_obj_get_ext_attr(led);
165     return ext->bright;
166 }
167 
168 /**********************
169  *   STATIC FUNCTIONS
170  **********************/
171 
172 /**
173  * Handle the drawing related tasks of the leds
174  * @param led pointer to an object
175  * @param mask the object will be drawn only in this area
176  * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area
177  *                                  (return 'true' if yes)
178  *             LV_DESIGN_DRAW: draw the object (always return 'true')
179  *             LV_DESIGN_DRAW_POST: drawing after every children are drawn
180  * @param return true/false, depends on 'mode'
181  */
lv_led_design(lv_obj_t * led,const lv_area_t * mask,lv_design_mode_t mode)182 static bool lv_led_design(lv_obj_t * led, const lv_area_t * mask, lv_design_mode_t mode)
183 {
184     if(mode == LV_DESIGN_COVER_CHK) {
185         /*Return false if the object is not covers the mask area*/
186         return ancestor_design_f(led, mask, mode);
187     } else if(mode == LV_DESIGN_DRAW_MAIN) {
188         /*Make darker colors in a temporary style according to the brightness*/
189         lv_led_ext_t * ext       = lv_obj_get_ext_attr(led);
190         const lv_style_t * style = lv_obj_get_style(led);
191 
192         /* Store the real pointer because of 'lv_group'
193          * If the object is in focus 'lv_obj_get_style()' will give a pointer to tmp style
194          * and to the real object style. It is important because of style change tricks below*/
195         const lv_style_t * style_ori_p = led->style_p;
196 
197         /*Create a temporal style*/
198         lv_style_t leds_tmp;
199         memcpy(&leds_tmp, style, sizeof(leds_tmp));
200 
201         /*Mix. the color with black proportionally with brightness*/
202         leds_tmp.body.main_color   = lv_color_mix(leds_tmp.body.main_color, LV_COLOR_BLACK, ext->bright);
203         leds_tmp.body.grad_color   = lv_color_mix(leds_tmp.body.grad_color, LV_COLOR_BLACK, ext->bright);
204         leds_tmp.body.border.color = lv_color_mix(leds_tmp.body.border.color, LV_COLOR_BLACK, ext->bright);
205 
206         /*Set the current swidth according to brightness proportionally between LV_LED_BRIGHT_OFF
207          * and LV_LED_BRIGHT_ON*/
208         uint16_t bright_tmp = ext->bright;
209         leds_tmp.body.shadow.width =
210             ((bright_tmp - LV_LED_BRIGHT_OFF) * style->body.shadow.width) / (LV_LED_BRIGHT_ON - LV_LED_BRIGHT_OFF);
211 
212         led->style_p = &leds_tmp;
213         ancestor_design_f(led, mask, mode);
214         led->style_p = style_ori_p; /*Restore the ORIGINAL style pointer*/
215     }
216     return true;
217 }
218 
219 /**
220  * Signal function of the led
221  * @param led pointer to a led object
222  * @param sign a signal type from lv_signal_t enum
223  * @param param pointer to a signal specific variable
224  * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted
225  */
lv_led_signal(lv_obj_t * led,lv_signal_t sign,void * param)226 static lv_res_t lv_led_signal(lv_obj_t * led, lv_signal_t sign, void * param)
227 {
228     lv_res_t res;
229 
230     /* Include the ancient signal function */
231     res = ancestor_signal(led, sign, param);
232     if(res != LV_RES_OK) return res;
233 
234     if(sign == LV_SIGNAL_GET_TYPE) {
235         lv_obj_type_t * buf = param;
236         uint8_t i;
237         for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/
238             if(buf->type[i] == NULL) break;
239         }
240         buf->type[i] = "lv_led";
241     }
242 
243     return res;
244 }
245 #endif
246