From b60bcc8c1693e02fcf90f989745ce351f0b8385e Mon Sep 17 00:00:00 2001 From: xianjimli Date: Wed, 1 Jan 2020 08:50:00 +0800 Subject: [PATCH] optimize widget_clone --- docs/changes.md | 3 + src/base/children_layouter.c | 8 ++ src/base/children_layouter.h | 11 ++ src/base/self_layouter.c | 8 ++ src/base/self_layouter.h | 12 ++ src/base/widget.c | 127 ++++++++++-------- src/base/widget.h | 9 +- src/base/widget_vtable.c | 27 ++++ src/base/widget_vtable.h | 1 + .../scroll_view/children_layouter_list_view.c | 11 ++ src/layouters/children_layouter_default.c | 11 ++ src/layouters/self_layouter_default.c | 11 ++ src/layouters/self_layouter_menu.c | 11 ++ tests/button_test.cc | 15 ++- 14 files changed, 207 insertions(+), 58 deletions(-) diff --git a/docs/changes.md b/docs/changes.md index 6780b3a59..2b8d4a777 100644 --- a/docs/changes.md +++ b/docs/changes.md @@ -1,5 +1,8 @@ # 最新动态 +* 2020/01/01 + * 优化widget\_clone + * 2019/12/31 * 完善RichText(感谢尧燊提供补丁) diff --git a/src/base/children_layouter.c b/src/base/children_layouter.c index f0b14595c..6d0b2022e 100644 --- a/src/base/children_layouter.c +++ b/src/base/children_layouter.c @@ -113,6 +113,14 @@ ret_t children_layouter_destroy(children_layouter_t* layouter) { return layouter->vt->destroy(layouter); } +children_layouter_t* children_layouter_clone(children_layouter_t* layouter) { + if (layouter != NULL && layouter->vt != NULL && layouter->vt->clone != NULL) { + return layouter->vt->clone(layouter); + } + + return NULL; +} + #ifdef WITHOUT_LAYOUTER children_layouter_t* children_layouter_create(const char* params) { return NULL; diff --git a/src/base/children_layouter.h b/src/base/children_layouter.h index b0e29f537..45c25cc8a 100644 --- a/src/base/children_layouter.h +++ b/src/base/children_layouter.h @@ -41,6 +41,7 @@ typedef bool_t (*children_layouter_is_valid_t)(children_layouter_t* layouter); typedef ret_t (*children_layouter_destroy_t)(children_layouter_t* layouter); typedef children_layouter_t* (*children_layouter_create_t)(void); +typedef children_layouter_t* (*children_layouter_clone_t)(children_layouter_t* layouter); typedef struct _children_layouter_vtable_t { const char* type; @@ -49,6 +50,7 @@ typedef struct _children_layouter_vtable_t { children_layouter_is_valid_t is_valid; children_layouter_get_param_t get_param; children_layouter_set_param_t set_param; + children_layouter_clone_t clone; children_layouter_destroy_t destroy; } children_layouter_vtable_t; @@ -176,6 +178,15 @@ ret_t children_layouter_destroy(children_layouter_t* layouter); */ children_layouter_t* children_layouter_create(const char* params); +/** + * @method children_layouter_clone + * 克隆layouter对象。 + * @param {children_layouter_t*} layouter 被克隆的对象。 + * + * @return {children_layouter_t*} 返回layouter对象。 + */ +children_layouter_t* children_layouter_clone(children_layouter_t* layouter); + END_C_DECLS #endif /*TK_CHILDREN_LAYOUTER_H*/ diff --git a/src/base/self_layouter.c b/src/base/self_layouter.c index b3c0dab05..30c7d5dcc 100644 --- a/src/base/self_layouter.c +++ b/src/base/self_layouter.c @@ -99,6 +99,14 @@ ret_t self_layouter_destroy(self_layouter_t* layouter) { return layouter->vt->destroy(layouter); } +self_layouter_t* self_layouter_clone(self_layouter_t* layouter) { + if (layouter != NULL && layouter->vt != NULL && layouter->vt->clone != NULL) { + return layouter->vt->clone(layouter); + } + + return NULL; +} + #ifdef WITHOUT_LAYOUTER self_layouter_t* self_layouter_create(const char* params) { return NULL; diff --git a/src/base/self_layouter.h b/src/base/self_layouter.h index d65d3c3c7..eddcd8e7f 100644 --- a/src/base/self_layouter.h +++ b/src/base/self_layouter.h @@ -41,6 +41,7 @@ typedef ret_t (*self_layouter_set_param_t)(self_layouter_t* layouter, const char typedef ret_t (*self_layouter_destroy_t)(self_layouter_t* layouter); typedef self_layouter_t* (*self_layouter_create_t)(void); +typedef self_layouter_t* (*self_layouter_clone_t)(self_layouter_t* layouter); typedef struct _self_layouter_vtable_t { const char* type; @@ -48,6 +49,7 @@ typedef struct _self_layouter_vtable_t { self_layouter_layout_t layout; self_layouter_get_param_t get_param; self_layouter_set_param_t set_param; + self_layouter_clone_t clone; self_layouter_destroy_t destroy; } self_layouter_vtable_t; @@ -155,6 +157,16 @@ ret_t self_layouter_destroy(self_layouter_t* layouter); */ self_layouter_t* self_layouter_create(const char* params); +/** + * @method self_layouter_clone + * 克隆layouter对象。 + * + * @param {const char*} layouter 被克隆的对象。 + * + * @return {self_layouter_t*} 返回layouter对象。 + */ +self_layouter_t* self_layouter_clone(self_layouter_t* layouter); + END_C_DECLS #endif /*TK_SELF_LAYOUTER_H*/ diff --git a/src/base/widget.c b/src/base/widget.c index 45b893424..a74eec186 100644 --- a/src/base/widget.c +++ b/src/base/widget.c @@ -2900,50 +2900,6 @@ ret_t widget_prepare_text_style(widget_t* widget, canvas_t* c) { return RET_OK; } -static const char* const s_widget_persistent_props[] = {WIDGET_PROP_NAME, - WIDGET_PROP_STYLE, - WIDGET_PROP_TR_TEXT, - WIDGET_PROP_TEXT, - WIDGET_PROP_ANIMATION, - WIDGET_PROP_ENABLE, - WIDGET_PROP_VISIBLE, - WIDGET_PROP_FLOATING, - WIDGET_PROP_CHILDREN_LAYOUT, - WIDGET_PROP_SELF_LAYOUT, - WIDGET_PROP_OPACITY, - WIDGET_PROP_FOCUSED, - WIDGET_PROP_FEEDBACK, - WIDGET_PROP_FOCUSABLE, - WIDGET_PROP_WITH_FOCUS_STATE, - WIDGET_PROP_SENSITIVE, - NULL}; - -const char* const* widget_get_persistent_props(void) { - return s_widget_persistent_props; -} - -static ret_t widget_copy_props(widget_t* clone, widget_t* widget, const char* const* properties) { - if (properties != NULL) { - value_t v; - value_t defval; - uint32_t i = 0; - for (i = 0; properties[i] != NULL; i++) { - const char* prop = properties[i]; - if (widget_get_prop(widget, prop, &v) == RET_OK) { - if (widget_get_prop_default_value(widget, prop, &defval) == RET_OK) { - if (!value_equal(&v, &defval)) { - widget_set_prop(clone, prop, &v); - } - } else { - widget_set_prop(clone, prop, &v); - } - } - } - } - - return RET_OK; -} - static ret_t widget_copy_style(widget_t* clone, widget_t* widget) { if (style_is_mutable(widget->astyle) && style_mutable_cast(widget->astyle) != NULL) { if (!style_is_mutable(clone->astyle)) { @@ -2958,17 +2914,82 @@ static ret_t widget_copy_style(widget_t* clone, widget_t* widget) { return RET_OK; } -static ret_t widget_copy(widget_t* clone, widget_t* widget) { - clone->state = tk_strdup(widget->state); - clone->focused = widget->focused; - widget_copy_style(clone, widget); - widget_copy_props(clone, widget, s_widget_persistent_props); - widget_copy_props(clone, widget, widget->vt->clone_properties); +static const char* const s_widget_persistent_props[] = {WIDGET_PROP_NAME, + WIDGET_PROP_STYLE, + WIDGET_PROP_TR_TEXT, + WIDGET_PROP_TEXT, + WIDGET_PROP_ANIMATION, + WIDGET_PROP_ENABLE, + WIDGET_PROP_VISIBLE, + WIDGET_PROP_FLOATING, + WIDGET_PROP_CHILDREN_LAYOUT, + WIDGET_PROP_SELF_LAYOUT, + WIDGET_PROP_OPACITY, + WIDGET_PROP_FOCUSED, + WIDGET_PROP_FEEDBACK, + WIDGET_PROP_FOCUSABLE, + WIDGET_PROP_SENSITIVE, + WIDGET_PROP_WITH_FOCUS_STATE, + NULL}; - if (widget->custom_props) { - clone->custom_props = object_default_clone(OBJECT_DEFAULT(widget->custom_props)); +const char* const* widget_get_persistent_props(void) { + return s_widget_persistent_props; +} + +static ret_t widget_copy_base_props(widget_t* widget, widget_t* other) { + widget->state = tk_str_copy(widget->state, other->state); + widget->name = tk_str_copy(widget->name, other->name); + widget->style = tk_str_copy(widget->style, other->style); + widget->tr_text = tk_str_copy(widget->tr_text, other->tr_text); + + if (other->text.str != NULL) { + widget_set_text(widget, other->text.str); } + widget->enable = other->enable; + widget->visible = other->visible; + widget->floating = other->floating; + widget->opacity = other->opacity; + widget->focused = other->focused; + widget->feedback = other->feedback; + widget->focusable = other->focusable; + widget->sensitive = other->sensitive; + widget->with_focus_state = other->with_focus_state; + + if (other->animation != NULL && *(other->animation)) { + widget_set_animation(widget, other->animation); + } + + if (other->self_layout != NULL) { + widget->self_layout = self_layouter_clone(other->self_layout); + } + + if (other->children_layout != NULL) { + widget->children_layout = children_layouter_clone(other->children_layout); + } + + return RET_OK; +} + +static ret_t widget_copy(widget_t* widget, widget_t* other) { + return_value_if_fail(widget != NULL && other != NULL, RET_BAD_PARAMS); + return_value_if_fail(widget->vt == other->vt, RET_BAD_PARAMS); + + widget_copy_style(widget, other); + widget_copy_base_props(widget, other); + + if (widget->vt->on_copy != NULL) { + widget->vt->on_copy(widget, other); + } else { + widget_on_copy_default(widget, other); + } + + if (other->custom_props) { + widget->custom_props = object_default_clone(OBJECT_DEFAULT(other->custom_props)); + } + + widget_set_need_update_style(widget); + return RET_OK; } @@ -2977,11 +2998,9 @@ widget_t* widget_clone(widget_t* widget, widget_t* parent) { return_value_if_fail(widget != NULL && widget->vt != NULL && widget->vt->create != NULL, NULL); clone = widget->vt->create(parent, widget->x, widget->y, widget->w, widget->h); - TKMEM_FREE(clone->state); return_value_if_fail(clone != NULL, NULL); widget_copy(clone, widget); - widget_set_need_update_style(clone); WIDGET_FOR_EACH_CHILD_BEGIN(widget, iter, i) widget_clone(iter, clone); diff --git a/src/base/widget.h b/src/base/widget.h index a69cbd4b4..9d71b8ee5 100644 --- a/src/base/widget.h +++ b/src/base/widget.h @@ -72,6 +72,7 @@ typedef ret_t (*widget_on_layout_children_t)(widget_t* widget); typedef ret_t (*widget_get_prop_t)(widget_t* widget, const char* name, value_t* v); typedef ret_t (*widget_get_prop_default_value_t)(widget_t* widget, const char* name, value_t* v); typedef ret_t (*widget_set_prop_t)(widget_t* widget, const char* name, const value_t* v); +typedef ret_t (*widget_on_copy_t)(widget_t* widget, widget_t* other); typedef widget_t* (*widget_find_target_t)(widget_t* widget, xy_t x, xy_t y); typedef widget_t* (*widget_create_t)(widget_t* parent, xy_t x, xy_t y, wh_t w, wh_t h); typedef ret_t (*widget_on_destroy_t)(widget_t* widget); @@ -148,8 +149,12 @@ struct _widget_vtable_t { widget_create_t create; widget_get_prop_t get_prop; - widget_get_prop_default_value_t get_prop_default_value; widget_set_prop_t set_prop; + widget_invalidate_t invalidate; + widget_find_target_t find_target; + widget_get_prop_default_value_t get_prop_default_value; + + widget_on_copy_t on_copy; widget_on_keyup_t on_keyup; widget_on_keydown_t on_keydown; widget_on_wheel_t on_wheel; @@ -163,14 +168,12 @@ struct _widget_vtable_t { widget_on_pointer_move_t on_pointer_move; widget_on_pointer_up_t on_pointer_up; widget_on_layout_children_t on_layout_children; - widget_invalidate_t invalidate; widget_on_add_child_t on_add_child; widget_on_remove_child_t on_remove_child; widget_on_attach_parent_t on_attach_parent; widget_on_detach_parent_t on_detach_parent; widget_on_event_t on_event; widget_on_event_before_children_t on_event_before_children; - widget_find_target_t find_target; widget_on_destroy_t on_destroy; }; diff --git a/src/base/widget_vtable.c b/src/base/widget_vtable.c index f5abdc7fa..058981304 100644 --- a/src/base/widget_vtable.c +++ b/src/base/widget_vtable.c @@ -189,6 +189,32 @@ widget_t* widget_find_target_default(widget_t* widget, xy_t x, xy_t y) { return NULL; } +static ret_t widget_copy_props(widget_t* clone, widget_t* widget, const char* const* properties) { + if (properties != NULL) { + value_t v; + value_t defval; + uint32_t i = 0; + for (i = 0; properties[i] != NULL; i++) { + const char* prop = properties[i]; + if (widget_get_prop(widget, prop, &v) == RET_OK) { + if (widget_get_prop_default_value(widget, prop, &defval) == RET_OK) { + if (!value_equal(&v, &defval)) { + widget_set_prop(clone, prop, &v); + } + } else { + widget_set_prop(clone, prop, &v); + } + } + } + } + + return RET_OK; +} + +ret_t widget_on_copy_default(widget_t* widget, widget_t* other) { + return widget_copy_props(widget, other, widget->vt->clone_properties); +} + ret_t widget_on_destroy_default(widget_t* widget) { (void)widget; return RET_OK; @@ -203,6 +229,7 @@ ret_t widget_on_paint_null(widget_t* widget, canvas_t* c) { TK_DECL_VTABLE(widget) = {.size = sizeof(widget_t), .type = WIDGET_TYPE_NONE, .parent = NULL, + .on_copy = widget_on_copy_default, .invalidate = widget_invalidate_default, .on_event = widget_on_event_default, .on_paint_self = widget_on_paint_self_default, diff --git a/src/base/widget_vtable.h b/src/base/widget_vtable.h index 121fca7a5..96a8d6d0d 100644 --- a/src/base/widget_vtable.h +++ b/src/base/widget_vtable.h @@ -36,6 +36,7 @@ ret_t widget_on_click_default(widget_t* widget, pointer_event_t* e); ret_t widget_on_pointer_down_default(widget_t* widget, pointer_event_t* e); ret_t widget_on_pointer_move_default(widget_t* widget, pointer_event_t* e); ret_t widget_on_pointer_up_default(widget_t* widget, pointer_event_t* e); +ret_t widget_on_copy_default(widget_t* widget, widget_t* other); ret_t widget_get_prop_default(widget_t* widget, const char* name, value_t* v); ret_t widget_set_prop_default(widget_t* widget, const char* name, const value_t* v); widget_t* widget_find_target_default(widget_t* widget, xy_t x, xy_t y); diff --git a/src/ext_widgets/scroll_view/children_layouter_list_view.c b/src/ext_widgets/scroll_view/children_layouter_list_view.c index 39152c88d..b28f99f9e 100644 --- a/src/ext_widgets/scroll_view/children_layouter_list_view.c +++ b/src/ext_widgets/scroll_view/children_layouter_list_view.c @@ -359,8 +359,19 @@ static ret_t children_layouter_list_view_destroy(children_layouter_t* layouter) return RET_OK; } +static children_layouter_t* children_layouter_list_view_clone(children_layouter_t* layouter) { + children_layouter_list_view_t* l = TKMEM_ZALLOC(children_layouter_list_view_t); + + memcpy(l, layouter, sizeof(*l)); + str_init(&(l->layouter.params), 0); + str_set(&(l->layouter.params), layouter->params.str); + + return (children_layouter_t*)l; +} + static const children_layouter_vtable_t s_children_layouter_list_view_vtable = { .type = CHILDREN_LAYOUTER_LIST_VIEW, + .clone = children_layouter_list_view_clone, .to_string = children_layouter_list_view_to_string, .get_param = children_layouter_list_view_get_param, .set_param = children_layouter_list_view_set_param, diff --git a/src/layouters/children_layouter_default.c b/src/layouters/children_layouter_default.c index ce139a0dc..f0245c98d 100644 --- a/src/layouters/children_layouter_default.c +++ b/src/layouters/children_layouter_default.c @@ -420,8 +420,19 @@ static ret_t children_layouter_default_destroy(children_layouter_t* layouter) { return RET_OK; } +static children_layouter_t* children_layouter_default_clone(children_layouter_t* layouter) { + children_layouter_default_t* l = TKMEM_ZALLOC(children_layouter_default_t); + + memcpy(l, layouter, sizeof(*l)); + str_init(&(l->layouter.params), 0); + str_set(&(l->layouter.params), layouter->params.str); + + return (children_layouter_t*)l; +} + static const children_layouter_vtable_t s_children_layouter_default_vtable = { .type = "default", + .clone = children_layouter_default_clone, .to_string = children_layouter_default_to_string, .get_param = children_layouter_default_get_param, .set_param = children_layouter_default_set_param, diff --git a/src/layouters/self_layouter_default.c b/src/layouters/self_layouter_default.c index b072629ac..bc90ff4ef 100644 --- a/src/layouters/self_layouter_default.c +++ b/src/layouters/self_layouter_default.c @@ -385,8 +385,19 @@ static ret_t self_layouter_default_destroy(self_layouter_t* layouter) { return RET_OK; } +static self_layouter_t* self_layouter_default_clone(self_layouter_t* layouter) { + self_layouter_default_t* l = TKMEM_ZALLOC(self_layouter_default_t); + + memcpy(l, layouter, sizeof(*l)); + str_init(&(l->layouter.params), 0); + str_set(&(l->layouter.params), layouter->params.str); + + return (self_layouter_t*)l; +} + static const self_layouter_vtable_t s_self_layouter_default_vtable = { .type = "default", + .clone = self_layouter_default_clone, .to_string = self_layouter_default_to_string, .get_param = self_layouter_default_get_param, .set_param = self_layouter_default_set_param, diff --git a/src/layouters/self_layouter_menu.c b/src/layouters/self_layouter_menu.c index c7685ea8b..cd460a528 100644 --- a/src/layouters/self_layouter_menu.c +++ b/src/layouters/self_layouter_menu.c @@ -350,8 +350,19 @@ static ret_t self_layouter_menu_destroy(self_layouter_t* layouter) { return RET_OK; } +static self_layouter_t* self_layouter_menu_clone(self_layouter_t* layouter) { + self_layouter_menu_t* l = TKMEM_ZALLOC(self_layouter_menu_t); + + memcpy(l, layouter, sizeof(*l)); + str_init(&(l->layouter.params), 0); + str_set(&(l->layouter.params), layouter->params.str); + + return (self_layouter_t*)l; +} + static const self_layouter_vtable_t s_self_layouter_menu_vtable = { .type = "menu", + .clone = self_layouter_menu_clone, .get_param = self_layouter_menu_get_param, .set_param = self_layouter_menu_set_param, .layout = self_layouter_menu_layout, diff --git a/tests/button_test.cc b/tests/button_test.cc index 7d8cea33f..564434a3f 100644 --- a/tests/button_test.cc +++ b/tests/button_test.cc @@ -11,6 +11,7 @@ #include "base/window.h" #include "gtest/gtest.h" #include +#include "ui_loader/ui_serializer.h" TEST(Button, basic) { value_t v1; @@ -42,9 +43,10 @@ TEST(Button, basic) { TEST(Button, clone) { value_t v1; - + str_t str; widget_t* w1 = button_create(NULL, 10, 20, 30, 40); + str_init(&str, 0); value_set_int(&v1, 200); ASSERT_EQ(widget_set_prop(w1, WIDGET_PROP_REPEAT, &v1), RET_OK); widget_set_self_layout_params(w1, "1", "2", "3", "4"); @@ -54,9 +56,20 @@ TEST(Button, clone) { ASSERT_EQ(button_cast(w1), w1); widget_t* w2 = widget_clone(w1, NULL); + + log_debug("==================================\n"); + widget_to_xml(w1, &str); + log_debug("w1:%s\n", str.str); + + str_set(&str, ""); + widget_to_xml(w2, &str); + log_debug("w2:%s\n", str.str); + log_debug("==================================\n"); + ASSERT_EQ(widget_equal(w1, w2), TRUE); widget_destroy(w1); widget_destroy(w2); + str_reset(&str); } static ret_t button_on_click_to_remove_parent(void* ctx, event_t* e) {