1 /**
2  * @file lv_obj_class.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_obj_class_private.h"
10 #include "lv_obj_private.h"
11 #include "../themes/lv_theme.h"
12 #include "../display/lv_display.h"
13 #include "../display/lv_display_private.h"
14 #include "../stdlib/lv_string.h"
15 
16 /*********************
17  *      DEFINES
18  *********************/
19 #define MY_CLASS (&lv_obj_class)
20 
21 /**********************
22  *      TYPEDEFS
23  **********************/
24 
25 /**********************
26  *  GLOBAL PROTOTYPES
27  **********************/
28 
29 /**********************
30  *  STATIC PROTOTYPES
31  **********************/
32 static void lv_obj_construct(const lv_obj_class_t * class_p, lv_obj_t * obj);
33 static uint32_t get_instance_size(const lv_obj_class_t * class_p);
34 
35 /**********************
36  *  STATIC VARIABLES
37  **********************/
38 
39 /**********************
40  *      MACROS
41  **********************/
42 
43 /**********************
44  *   GLOBAL FUNCTIONS
45  **********************/
46 
lv_obj_class_create_obj(const lv_obj_class_t * class_p,lv_obj_t * parent)47 lv_obj_t * lv_obj_class_create_obj(const lv_obj_class_t * class_p, lv_obj_t * parent)
48 {
49     LV_TRACE_OBJ_CREATE("Creating object with %p class on %p parent", (void *)class_p, (void *)parent);
50     uint32_t s = get_instance_size(class_p);
51     lv_obj_t * obj = lv_malloc_zeroed(s);
52     if(obj == NULL) return NULL;
53     obj->class_p = class_p;
54     obj->parent = parent;
55 
56     /*Create a screen*/
57     if(parent == NULL) {
58         LV_TRACE_OBJ_CREATE("creating a screen");
59         lv_display_t * disp = lv_display_get_default();
60         if(!disp) {
61             LV_LOG_WARN("No display created yet. No place to assign the new screen");
62             lv_free(obj);
63             return NULL;
64         }
65 
66         if(disp->screens == NULL) {
67             disp->screen_cnt = 0;
68         }
69 
70         lv_obj_t ** screens = lv_realloc(disp->screens, sizeof(lv_obj_t *) * (disp->screen_cnt + 1));
71         LV_ASSERT_MALLOC(screens);
72         if(screens == NULL) {
73             lv_free(obj);
74             return NULL;
75         }
76 
77         disp->screen_cnt++;
78         disp->screens = screens;
79         disp->screens[disp->screen_cnt - 1] = obj;
80 
81         /*Set coordinates to full screen size*/
82         obj->coords.x1 = 0;
83         obj->coords.y1 = 0;
84         obj->coords.x2 = lv_display_get_horizontal_resolution(NULL) - 1;
85         obj->coords.y2 = lv_display_get_vertical_resolution(NULL) - 1;
86     }
87     /*Create a normal object*/
88     else {
89         LV_TRACE_OBJ_CREATE("creating normal object");
90         LV_ASSERT_OBJ(parent, MY_CLASS);
91         if(parent->spec_attr == NULL) {
92             lv_obj_allocate_spec_attr(parent);
93         }
94 
95         parent->spec_attr->child_cnt++;
96         parent->spec_attr->children = lv_realloc(parent->spec_attr->children,
97                                                  sizeof(lv_obj_t *) * parent->spec_attr->child_cnt);
98         parent->spec_attr->children[parent->spec_attr->child_cnt - 1] = obj;
99     }
100 
101     return obj;
102 }
103 
lv_obj_class_init_obj(lv_obj_t * obj)104 void lv_obj_class_init_obj(lv_obj_t * obj)
105 {
106     if(obj == NULL) return;
107 
108     lv_obj_mark_layout_as_dirty(obj);
109     lv_obj_enable_style_refresh(false);
110 
111     lv_theme_apply(obj);
112     lv_obj_construct(obj->class_p, obj);
113 
114     lv_obj_enable_style_refresh(true);
115     lv_obj_refresh_style(obj, LV_PART_ANY, LV_STYLE_PROP_ANY);
116 
117     lv_obj_refresh_self_size(obj);
118 
119     lv_group_t * def_group = lv_group_get_default();
120     if(def_group && lv_obj_is_group_def(obj)) {
121         lv_group_add_obj(def_group, obj);
122     }
123 
124     lv_obj_t * parent = lv_obj_get_parent(obj);
125     if(parent) {
126         /*Call the ancestor's event handler to the parent to notify it about the new child.
127          *Also triggers layout update*/
128         lv_obj_send_event(parent, LV_EVENT_CHILD_CHANGED, obj);
129         lv_obj_send_event(parent, LV_EVENT_CHILD_CREATED, obj);
130 
131         /*Invalidate the area if not screen created*/
132         lv_obj_invalidate(obj);
133     }
134 }
135 
lv_obj_destruct(lv_obj_t * obj)136 void lv_obj_destruct(lv_obj_t * obj)
137 {
138     if(obj->class_p->destructor_cb) obj->class_p->destructor_cb(obj->class_p, obj);
139 
140     if(obj->class_p->base_class) {
141         /*Don't let the descendant methods run during destructing the ancestor type*/
142         obj->class_p = obj->class_p->base_class;
143 
144         /*Call the base class's destructor too*/
145         lv_obj_destruct(obj);
146     }
147 }
148 
lv_obj_is_editable(lv_obj_t * obj)149 bool lv_obj_is_editable(lv_obj_t * obj)
150 {
151     const lv_obj_class_t * class_p = obj->class_p;
152 
153     /*Find a base in which editable is set*/
154     while(class_p && class_p->editable == LV_OBJ_CLASS_EDITABLE_INHERIT) class_p = class_p->base_class;
155 
156     if(class_p == NULL) return false;
157 
158     return class_p->editable == LV_OBJ_CLASS_EDITABLE_TRUE;
159 }
160 
lv_obj_is_group_def(lv_obj_t * obj)161 bool lv_obj_is_group_def(lv_obj_t * obj)
162 {
163     const lv_obj_class_t * class_p = obj->class_p;
164 
165     /*Find a base in which group_def is set*/
166     while(class_p && class_p->group_def == LV_OBJ_CLASS_GROUP_DEF_INHERIT) class_p = class_p->base_class;
167 
168     if(class_p == NULL) return false;
169 
170     return class_p->group_def == LV_OBJ_CLASS_GROUP_DEF_TRUE;
171 }
172 
173 /**********************
174  *   STATIC FUNCTIONS
175  **********************/
176 
lv_obj_construct(const lv_obj_class_t * class_p,lv_obj_t * obj)177 static void lv_obj_construct(const lv_obj_class_t * class_p, lv_obj_t * obj)
178 {
179     if(obj->class_p->base_class) {
180         const lv_obj_class_t * original_class_p = obj->class_p;
181 
182         /*Don't let the descendant methods run during constructing the ancestor type*/
183         obj->class_p = obj->class_p->base_class;
184 
185         /*Construct the base first*/
186         lv_obj_construct(class_p, obj);
187 
188         /*Restore the original class*/
189         obj->class_p = original_class_p;
190     }
191 
192     if(obj->class_p->constructor_cb) obj->class_p->constructor_cb(class_p, obj);
193 }
194 
get_instance_size(const lv_obj_class_t * class_p)195 static uint32_t get_instance_size(const lv_obj_class_t * class_p)
196 {
197     /*Find a base in which instance size is set*/
198     const lv_obj_class_t * base = class_p;
199     while(base && base->instance_size == 0) base = base->base_class;
200 
201     if(base == NULL) return 0;  /*Never happens: set at least in `lv_obj` class*/
202 
203     return base->instance_size;
204 }
205