Skip to content

Commit 50cc6b2

Browse files
committed
feat(gui): add rule for cache children style
1 parent ebf843f commit 50cc6b2

9 files changed

+292
-124
lines changed

include/LCUI/gui/css_library.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ typedef struct LCUI_SelectorRec_ {
176176
int rank; /**< 权值,决定优先级 */
177177
int batch_num; /**< 批次号 */
178178
int length; /**< 选择器结点长度 */
179-
unsigned int hash; /**< 哈希值 */
179+
unsigned hash; /**< 哈希值 */
180180
LCUI_SelectorNode *nodes; /**< 选择器结点列表 */
181181
} LCUI_SelectorRec, *LCUI_Selector;
182182

include/LCUI/gui/widget_base.h

+22-3
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ typedef enum LCUI_WidgetState {
124124

125125
typedef struct LCUI_WidgetRec_* LCUI_Widget;
126126
typedef struct LCUI_WidgetPrototypeRec_ *LCUI_WidgetPrototype;
127+
typedef struct LCUI_WidgetTaskContextRec_ *LCUI_WidgetTaskContext;
127128
typedef const struct LCUI_WidgetPrototypeRec_ *LCUI_WidgetPrototypeC;
128129

129130
typedef void(*LCUI_WidgetFunction)(LCUI_Widget);
@@ -159,11 +160,21 @@ typedef struct LCUI_WidgetData_ {
159160
} LCUI_WidgetData;
160161

161162
typedef struct LCUI_WidgetTaskContextRec_ {
162-
LCUI_Selector selector;
163-
LCUI_Widget widget;
164-
} LCUI_WidgetTaskContextRec, *LCUI_WidgetTaskContext;
163+
Dict *style_cache;
164+
unsigned style_hash;
165+
LCUI_WidgetTaskContext parent;
166+
} LCUI_WidgetTaskContextRec;
165167

166168
typedef struct LCUI_WidgetRulesRec_ {
169+
/**
170+
* Cache the stylesheets of children to improve the query speed of
171+
* the stylesheet.
172+
* If this rule is enabled, we recommend that you manually call
173+
* Widget_GenerateHash() to generate a hash value for the children
174+
* of the widget.
175+
*/
176+
LCUI_BOOL cache_children_style;
177+
167178
/** Refresh the style of all child widgets if the status has changed */
168179
LCUI_BOOL ignore_status_change;
169180

@@ -185,6 +196,7 @@ typedef struct LCUI_WidgetRulesRec_ {
185196

186197
typedef struct LCUI_WidgetRulesDataRec_ {
187198
LCUI_WidgetRulesRec rules;
199+
Dict *style_cache;
188200
size_t default_max_update_count;
189201
size_t current_index;
190202
} LCUI_WidgetRulesDataRec, *LCUI_WidgetRulesData;
@@ -203,6 +215,7 @@ typedef struct LCUI_WidgetAttributeRec_ {
203215

204216
/** 部件结构 */
205217
typedef struct LCUI_WidgetRec_ {
218+
unsigned hash; /**< 哈希值 */
206219
LCUI_WidgetState state; /**< 状态 */
207220
float x, y; /**< 当前坐标(由 origin 计算而来) */
208221
float origin_x, origin_y; /**< 当前布局下计算出的坐标 */
@@ -401,6 +414,12 @@ LCUI_API void Widget_SetTitleW(LCUI_Widget w, const wchar_t *title);
401414
/** 为部件添加状态 */
402415
LCUI_API void Widget_AddState(LCUI_Widget w, LCUI_WidgetState state);
403416

417+
/** Generate a hash for a widget to identify it and siblings */
418+
LCUI_API void Widget_GenerateSelfHash(LCUI_Widget w);
419+
420+
/** Generate hash values for a widget and its children */
421+
LCUI_API void Widget_GenerateHash(LCUI_Widget w);
422+
404423
/** Set widget updating rules */
405424
LCUI_API int Widget_SetRules(LCUI_Widget w, const LCUI_WidgetRulesRec *rules);
406425

src/gui/widget_base.c

+53-3
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ static void Widget_Init(LCUI_Widget widget)
107107
{
108108
ZEROSET(widget, LCUI_Widget);
109109
widget->state = LCUI_WSTATE_CREATED;
110-
widget->trigger = EventTrigger();
111110
widget->style = StyleSheet();
112111
widget->computed_style.opacity = 1.0;
113112
widget->computed_style.visible = TRUE;
@@ -271,12 +270,62 @@ void Widget_SetTitleW(LCUI_Widget w, const wchar_t *title)
271270
Widget_AddTask(w, LCUI_WTASK_TITLE);
272271
}
273272

273+
void Widget_GenerateSelfHash(LCUI_Widget widget)
274+
{
275+
int i;
276+
unsigned hash = 1080;
277+
LCUI_Widget w;
278+
279+
for (w = widget; w; w = w->parent) {
280+
if (w != widget) {
281+
hash = strhash(hash, " ");
282+
}
283+
if (w->type) {
284+
hash = strhash(hash, w->type);
285+
} else {
286+
hash = strhash(hash, "*");
287+
}
288+
if (w->id) {
289+
hash = strhash(hash, "#");
290+
hash = strhash(hash, w->id);
291+
}
292+
if (w->classes) {
293+
for (i = 0; w->classes[i]; ++i) {
294+
hash = strhash(hash, ".");
295+
hash = strhash(hash, w->classes[i]);
296+
}
297+
}
298+
if (w->status) {
299+
for (i = 0; w->status[i]; ++i) {
300+
hash = strhash(hash, ":");
301+
hash = strhash(hash, w->status[i]);
302+
}
303+
}
304+
if (w->rules && w->rules->cache_children_style) {
305+
break;
306+
}
307+
}
308+
widget->hash = hash;
309+
}
310+
311+
void Widget_GenerateHash(LCUI_Widget w)
312+
{
313+
LinkedListNode *node;
314+
315+
Widget_GenerateSelfHash(w);
316+
for (LinkedList_Each(node, &w->children_show)) {
317+
Widget_GenerateHash(node->data);
318+
}
319+
}
320+
274321
int Widget_SetRules(LCUI_Widget w, const LCUI_WidgetRulesRec *rules)
275322
{
276323
LCUI_WidgetRulesData data;
277324

278-
if (w->rules) {
279-
free(w->rules);
325+
data = (LCUI_WidgetRulesData)w->rules;
326+
if (data) {
327+
Dict_Release(data->style_cache);
328+
free(data);
280329
w->rules = NULL;
281330
}
282331
if (!rules) {
@@ -288,6 +337,7 @@ int Widget_SetRules(LCUI_Widget w, const LCUI_WidgetRulesRec *rules)
288337
}
289338
data->rules = *rules;
290339
data->current_index = 0;
340+
data->style_cache = NULL;
291341
data->default_max_update_count = 2048;
292342
w->rules = (LCUI_WidgetRules)data;
293343
return 0;

src/gui/widget_class.c

+5
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ static int Widget_HandleClassesChange(LCUI_Widget w, const char *name)
5454
if (w->rules && w->rules->ignore_classes_change) {
5555
return 0;
5656
}
57+
/* If widget is not ready, indicate that the style of the children has
58+
* been marked needs to be refreshed */
59+
if (w->state < LCUI_WSTATE_READY) {
60+
return 1;
61+
}
5762
if (Widget_GetChildrenStyleChanges(w, 0, name) > 0) {
5863
Widget_MarkChildrenRefreshByClasses(w);
5964
return 1;

src/gui/widget_event.c

+20-10
Original file line numberDiff line numberDiff line change
@@ -246,9 +246,11 @@ static void WidgetEventTranslator(LCUI_Event e, LCUI_WidgetEventPack pack)
246246
handler->func(w, &pack->event, pack->data);
247247
while (!pack->event.cancel_bubble && w->parent) {
248248
w = w->parent;
249-
pack->widget = w;
250-
/** 向父级部件冒泡传递事件 */
251-
EventTrigger_Trigger(w->trigger, e->type, pack);
249+
if (w->trigger) {
250+
pack->widget = w;
251+
/** 向父级部件冒泡传递事件 */
252+
EventTrigger_Trigger(w->trigger, e->type, pack);
253+
}
252254
}
253255
}
254256

@@ -434,6 +436,9 @@ int Widget_BindEventById(LCUI_Widget widget, int event_id,
434436
handler->func = func;
435437
handler->data = data;
436438
handler->destroy_data = destroy_data;
439+
if (!widget->trigger) {
440+
widget->trigger = EventTrigger();
441+
}
437442
return EventTrigger_Bind(widget->trigger, event_id,
438443
(LCUI_EventFunc)WidgetEventTranslator, handler,
439444
DestroyWidgetEventHandler);
@@ -507,9 +512,6 @@ static int Widget_TriggerEventEx(LCUI_Widget widget, LCUI_WidgetEventPack pack)
507512
{
508513
LCUI_WidgetEvent e = &pack->event;
509514

510-
if (!widget->trigger) {
511-
return -1;
512-
}
513515
pack->widget = widget;
514516
switch (e->type) {
515517
case LCUI_WEVENT_CLICK:
@@ -522,7 +524,8 @@ static int Widget_TriggerEventEx(LCUI_Widget widget, LCUI_WidgetEventPack pack)
522524
break;
523525
}
524526
default:
525-
if (0 < EventTrigger_Trigger(widget->trigger, e->type, pack)) {
527+
if (widget->trigger && 0 <
528+
EventTrigger_Trigger(widget->trigger, e->type, pack)) {
526529
return 0;
527530
}
528531
if (!widget->parent || e->cancel_bubble) {
@@ -534,7 +537,8 @@ static int Widget_TriggerEventEx(LCUI_Widget widget, LCUI_WidgetEventPack pack)
534537
if (!widget->parent || e->cancel_bubble) {
535538
return -1;
536539
}
537-
while (widget->computed_style.pointer_events == SV_NONE) {
540+
while (widget->trigger &&
541+
widget->computed_style.pointer_events == SV_NONE) {
538542
LCUI_Widget w;
539543
LCUI_BOOL is_pointer_event = TRUE;
540544
int pointer_x, pointer_y;
@@ -587,6 +591,7 @@ LCUI_BOOL Widget_PostEvent(LCUI_Widget widget, LCUI_WidgetEvent ev, void *data,
587591
LCUI_Event sys_ev;
588592
LCUI_TaskRec task;
589593
LCUI_WidgetEventPack pack;
594+
590595
if (widget->state == LCUI_WSTATE_DELETED) {
591596
return FALSE;
592597
}
@@ -620,6 +625,7 @@ LCUI_BOOL Widget_PostEvent(LCUI_Widget widget, LCUI_WidgetEvent ev, void *data,
620625
int Widget_TriggerEvent(LCUI_Widget widget, LCUI_WidgetEvent e, void *data)
621626
{
622627
LCUI_WidgetEventPackRec pack;
628+
623629
if (!e->target) {
624630
e->target = widget;
625631
}
@@ -1203,6 +1209,7 @@ int Widget_PostSurfaceEvent(LCUI_Widget w, int event_type, LCUI_BOOL sync_props)
12031209
int *data;
12041210
LCUI_WidgetEventRec e = { 0 };
12051211
LCUI_Widget root = LCUIWidget_GetRoot();
1212+
12061213
if (w->parent != root && w != root) {
12071214
return -1;
12081215
}
@@ -1221,13 +1228,16 @@ int Widget_PostSurfaceEvent(LCUI_Widget w, int event_type, LCUI_BOOL sync_props)
12211228
void Widget_DestroyEventTrigger(LCUI_Widget w)
12221229
{
12231230
LCUI_WidgetEventRec e = { LCUI_WEVENT_DESTROY, 0 };
1231+
12241232
Widget_TriggerEvent(w, &e, NULL);
12251233
Widget_ReleaseMouseCapture(w);
12261234
Widget_ReleaseTouchCapture(w, -1);
12271235
Widget_StopEventPropagation(w);
12281236
LCUIWidget_ClearEventTarget(w);
1229-
EventTrigger_Destroy(w->trigger);
1230-
w->trigger = NULL;
1237+
if (w->trigger) {
1238+
EventTrigger_Destroy(w->trigger);
1239+
w->trigger = NULL;
1240+
}
12311241
}
12321242

12331243
static void BindSysEvent(int e, LCUI_SysEventFunc func)

src/gui/widget_status.c

+4
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ static void Widget_MarkChildrenRefreshByStatus(LCUI_Widget w)
5252
static int Widget_HandleStatusChange(LCUI_Widget w, const char *name)
5353
{
5454
Widget_UpdateStyle(w, TRUE);
55+
if (w->state < LCUI_WSTATE_READY) {
56+
return 1;
57+
}
5558
if (w->rules && w->rules->ignore_status_change) {
5659
return 0;
5760
}
@@ -94,6 +97,7 @@ int Widget_RemoveStatus(LCUI_Widget w, const char *status_name)
9497
void Widget_UpdateStatus(LCUI_Widget widget)
9598
{
9699
LCUI_Widget child;
100+
97101
if (!widget->parent) {
98102
return;
99103
}

0 commit comments

Comments
 (0)