Skip to content

Commit

Permalink
feat(gui): add support for custom widget update rules
Browse files Browse the repository at this point in the history
  • Loading branch information
lc-soft committed Mar 4, 2019
1 parent 3790fbd commit bdd1d1c
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 24 deletions.
35 changes: 35 additions & 0 deletions include/LCUI/gui/widget_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,37 @@ typedef struct LCUI_WidgetData_ {
LCUI_WidgetDataEntryRec *list;
} LCUI_WidgetData;

typedef struct LCUI_WidgetTaskContextRec_ {
LCUI_Selector selector;
LCUI_Widget widget;
} LCUI_WidgetTaskContextRec, *LCUI_WidgetTaskContext;

typedef struct LCUI_WidgetRulesRec_ {
/** Refresh the style of all child widgets if the status has changed */
LCUI_BOOL ignore_status_change;

/** Refresh the style of all child widgets if the classes has changed */
LCUI_BOOL ignore_classes_change;

/**
* Maximum number of children updated at each update
* values:
* -1 - Update all children at once
* 0 - Automatically calculates the appropriate maximum number
* N - Custom maximum number
*/
int max_update_children_count;

/** A callback function on update progress */
void (*on_update_progress)(LCUI_Widget, size_t);
} LCUI_WidgetRulesRec, *LCUI_WidgetRules;

typedef struct LCUI_WidgetRulesDataRec_ {
LCUI_WidgetRulesRec rules;
size_t default_max_update_count;
size_t current_index;
} LCUI_WidgetRulesDataRec, *LCUI_WidgetRulesData;

typedef struct LCUI_WidgetAttributeRec_ {
char *name;
struct {
Expand Down Expand Up @@ -197,6 +228,7 @@ typedef struct LCUI_WidgetRec_ {
LCUI_WidgetPrototypeC proto; /**< 原型 */
LCUI_EventTrigger trigger; /**< 事件触发器 */
LCUI_WidgetTaskBoxRec task; /**< 任务记录 */
LCUI_WidgetRules rules; /**< 更新部件时采用的规则 */
LCUI_BOOL event_blocked; /**< 是否阻止自己和子级部件的事件处理 */
LCUI_BOOL disabled; /**< 是否禁用 */
LinkedListNode node; /**< 在部件链表中的结点 */
Expand Down Expand Up @@ -369,6 +401,9 @@ LCUI_API void Widget_SetTitleW(LCUI_Widget w, const wchar_t *title);
/** 为部件添加状态 */
LCUI_API void Widget_AddState(LCUI_Widget w, LCUI_WidgetState state);

/** Set widget updating rules */
LCUI_API int Widget_SetRules(LCUI_Widget w, const LCUI_WidgetRulesRec *rules);

/** 计算部件的最大宽度 */
LCUI_API float Widget_ComputeMaxWidth(LCUI_Widget w);

Expand Down
4 changes: 2 additions & 2 deletions include/LCUI/gui/widget_style.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ LCUI_SelectorNode Widget_GetSelectorNode(LCUI_Widget w);
/** 获取选择器 */
LCUI_API LCUI_Selector Widget_GetSelector(LCUI_Widget w);

/** 处理子级部件样式变化 */
LCUI_API int Widget_HandleChildrenStyleChange(LCUI_Widget w, int type, const char *name);
/** 获取样式受到影响的子级部件数量 */
LCUI_API size_t Widget_GetChildrenStyleChanges(LCUI_Widget w, int type, const char *name);

#endif
23 changes: 23 additions & 0 deletions src/gui/widget_base.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ void Widget_ExecDestroy(LCUI_Widget w)
Widget_DestroyAttributes(w);
Widget_DestroyClasses(w);
Widget_DestroyStatus(w);
Widget_SetRules(w, NULL);
free(w);
}

Expand Down Expand Up @@ -270,6 +271,28 @@ void Widget_SetTitleW(LCUI_Widget w, const wchar_t *title)
Widget_AddTask(w, LCUI_WTASK_TITLE);
}

int Widget_SetRules(LCUI_Widget w, const LCUI_WidgetRulesRec *rules)
{
LCUI_WidgetRulesData data;

if (w->rules) {
free(w->rules);
w->rules = NULL;
}
if (!rules) {
return 0;
}
data = malloc(sizeof(LCUI_WidgetRulesDataRec));
if (!data) {
return -ENOMEM;
}
data->rules = *rules;
data->current_index = 0;
data->default_max_update_count = 2048;
w->rules = (LCUI_WidgetRules)data;
return 0;
}

void Widget_AddState(LCUI_Widget w, LCUI_WidgetState state)
{
/* 如果部件还处于未准备完毕的状态 */
Expand Down
34 changes: 29 additions & 5 deletions src/gui/widget_class.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,33 @@
#include <LCUI/gui/widget_base.h>
#include <LCUI/gui/widget_class.h>
#include <LCUI/gui/widget_style.h>
#include <LCUI/gui/widget_task.h>

static void Widget_MarkChildrenRefreshByClasses(LCUI_Widget w)
{
LinkedListNode *node;

if (w->rules && w->rules->ignore_classes_change) {
return;
}
Widget_AddTask(w, LCUI_WTASK_REFRESH_STYLE);
for (LinkedList_Each(node, &w->children)) {
Widget_MarkChildrenRefreshByClasses(node->data);
}
}

static int Widget_HandleClassesChange(LCUI_Widget w, const char *name)
{
Widget_UpdateStyle(w, TRUE);
if (w->rules && w->rules->ignore_classes_change) {
return 0;
}
if (Widget_GetChildrenStyleChanges(w, 0, name) > 0) {
Widget_MarkChildrenRefreshByClasses(w);
return 1;
}
return 0;
}

int Widget_AddClass(LCUI_Widget w, const char *class_name)
{
Expand All @@ -42,9 +69,7 @@ int Widget_AddClass(LCUI_Widget w, const char *class_name)
if (strlist_add(&w->classes, class_name) <= 0) {
return 0;
}
Widget_HandleChildrenStyleChange(w, 0, class_name);
Widget_UpdateStyle(w, TRUE);
return 1;
return Widget_HandleClassesChange(w, class_name);
}

LCUI_BOOL Widget_HasClass(LCUI_Widget w, const char *class_name)
Expand All @@ -58,9 +83,8 @@ LCUI_BOOL Widget_HasClass(LCUI_Widget w, const char *class_name)
int Widget_RemoveClass(LCUI_Widget w, const char *class_name)
{
if (strlist_has(w->classes, class_name)) {
Widget_HandleChildrenStyleChange(w, 0, class_name);
Widget_HandleClassesChange(w, class_name);
strlist_remove(&w->classes, class_name);
Widget_UpdateStyle(w, TRUE);
return 1;
}
return 0;
Expand Down
34 changes: 29 additions & 5 deletions src/gui/widget_status.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,35 @@
#include <LCUI/gui/widget_base.h>
#include <LCUI/gui/widget_status.h>
#include <LCUI/gui/widget_style.h>
#include <LCUI/gui/widget_task.h>
#include <LCUI/gui/widget_tree.h>

static void Widget_MarkChildrenRefreshByStatus(LCUI_Widget w)
{
LinkedListNode *node;

if (w->rules && w->rules->ignore_status_change) {
return;
}
Widget_AddTask(w, LCUI_WTASK_REFRESH_STYLE);
for (LinkedList_Each(node, &w->children)) {
Widget_MarkChildrenRefreshByStatus(node->data);
}
}

static int Widget_HandleStatusChange(LCUI_Widget w, const char *name)
{
Widget_UpdateStyle(w, TRUE);
if (w->rules && w->rules->ignore_status_change) {
return 0;
}
if (Widget_GetChildrenStyleChanges(w, 1, name) > 0) {
Widget_MarkChildrenRefreshByStatus(w);
return 1;
}
return 0;
}

int Widget_AddStatus(LCUI_Widget w, const char *status_name)
{
if (strlist_has(w->status, status_name)) {
Expand All @@ -43,9 +70,7 @@ int Widget_AddStatus(LCUI_Widget w, const char *status_name)
if (strlist_add(&w->status, status_name) <= 0) {
return 0;
}
Widget_HandleChildrenStyleChange(w, 1, status_name);
Widget_UpdateStyle(w, TRUE);
return 1;
return Widget_HandleStatusChange(w, status_name);
}

LCUI_BOOL Widget_HasStatus(LCUI_Widget w, const char *status_name)
Expand All @@ -59,9 +84,8 @@ LCUI_BOOL Widget_HasStatus(LCUI_Widget w, const char *status_name)
int Widget_RemoveStatus(LCUI_Widget w, const char *status_name)
{
if (strlist_has(w->status, status_name)) {
Widget_HandleChildrenStyleChange(w, 1, status_name);
Widget_HandleStatusChange(w, status_name);
strlist_remove(&w->status, status_name);
Widget_UpdateStyle(w, TRUE);
return 1;
}
return 0;
Expand Down
9 changes: 2 additions & 7 deletions src/gui/widget_style.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,17 +122,16 @@ LCUI_Selector Widget_GetSelector(LCUI_Widget w)
return s;
}

int Widget_HandleChildrenStyleChange(LCUI_Widget w, int type, const char *name)
size_t Widget_GetChildrenStyleChanges(LCUI_Widget w, int type, const char *name)
{
LCUI_Selector s;
LinkedList snames;
LinkedListNode *node;

size_t i, n, len;
int count = 0;
size_t count = 0;
char ch, *str, **names = NULL;

/* 选择相应的前缀 */
switch (type) {
case 0:
ch = '.';
Expand Down Expand Up @@ -181,10 +180,6 @@ int Widget_HandleChildrenStyleChange(LCUI_Widget w, int type, const char *name)
}
Selector_Delete(s);
LinkedList_Clear(&snames, free);
/* 若子部件的样式受到了影响,则标记子部件需要刷新 */
if (count > 0) {
Widget_AddTaskForChildren(w, LCUI_WTASK_REFRESH_STYLE);
}
for (i = 0; names[i]; ++i) {
free(names[i]);
}
Expand Down
61 changes: 56 additions & 5 deletions src/gui/widget_task.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/

#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <LCUI_Build.h>
Expand Down Expand Up @@ -186,15 +187,22 @@ void Widget_EndUpdate(LCUI_WidgetTaskContext ctx)
size_t Widget_UpdateWithContext(LCUI_Widget w, LCUI_WidgetTaskContext ctx)
{
int i;
size_t count = 0;
clock_t msec;
size_t total = 0, update_count = 0, count;

LCUI_BOOL *states;
LCUI_Widget child;
LCUI_WidgetTaskContext self_ctx;
LCUI_WidgetRulesData data;
LinkedListNode *node, *next;

if (!w->task.for_self && !w->task.for_children) {
return 0;
}
data = (LCUI_WidgetRulesData)w->rules;
if (data) {
msec = clock();
}
self_ctx = Widget_BeginUpdate(w, ctx);
if (w->task.for_self) {
w->task.for_self = FALSE;
Expand All @@ -214,7 +222,7 @@ size_t Widget_UpdateWithContext(LCUI_Widget w, LCUI_WidgetTaskContext ctx)
}
}
Widget_AddState(w, LCUI_WSTATE_UPDATED);
count += 1;
total += 1;
}
if (w->task.for_children) {
/* 如果子级部件中有待处理的部件,则递归进去 */
Expand All @@ -228,15 +236,58 @@ size_t Widget_UpdateWithContext(LCUI_Widget w, LCUI_WidgetTaskContext ctx)
*/
next = node->next;
/* 如果该级部件的任务需要留到下次再处理 */
count += Widget_UpdateWithContext(child, self_ctx);
count = Widget_UpdateWithContext(child, self_ctx);
if (child->task.for_self || child->task.for_children) {
w->task.for_children = TRUE;
}
total += count;
node = next;
if (!data) {
continue;
}
if (count > 0) {
data->current_index = max(data->current_index, child->index);
update_count += 1;
}
if (data->rules.max_update_children_count < 0) {
continue;
}
if (data->rules.max_update_children_count > 0) {
if (update_count >=
data->rules.max_update_children_count) {
w->task.for_children = TRUE;
break;
}
}
if (update_count < data->default_max_update_count) {
continue;
}
w->task.for_children = TRUE;
/*
* Conversion from:
* (1000 / LCUI_MAX_FRAMES_PER_SEC /
* ((clock() - start) / CLOCKS_PER_SEC * 1000 /
* update_count);
*/
msec = (clock() - msec);
if (msec < 1) {
data->default_max_update_count += 2048;
continue;
}
data->default_max_update_count =
update_count * CLOCKS_PER_SEC /
LCUI_MAX_FRAMES_PER_SEC / msec;
if (data->default_max_update_count < 1) {
data->default_max_update_count = 32;
}
break;
}
}
if (data && data->rules.on_update_progress) {
data->rules.on_update_progress(w, data->current_index);
}
Widget_EndUpdate(self_ctx);
return count;
return total;
}

size_t Widget_Update(LCUI_Widget w)
Expand All @@ -257,7 +308,7 @@ size_t LCUIWidget_Update(void)
self.update_count += 1;
}
root = LCUIWidget_GetRoot();
for (total = 0, i = 0; i < 5; ++i) {
for (total = 0, i = 0; i < 2; ++i) {
count = Widget_Update(root);
if (count < 1) {
break;
Expand Down

0 comments on commit bdd1d1c

Please sign in to comment.