add widget_visible_in_scroll_view

This commit is contained in:
lixianjing 2024-06-13 17:40:32 +08:00
parent 365825839e
commit 48f4ea7bdb
6 changed files with 153 additions and 27 deletions

View File

@ -29,6 +29,7 @@ widget_t* scroll_view = NULL;
#define SCROLL_BAR_H_WIDGT_NAME "bar_h"
#define SCROLL_BAR_V_WIDGT_NAME "bar_v"
#define BUTTON_SET_FOCUSE_STRING "focused:"
#define BUTTON_SET_PROP_VISIBLE_REVEAL_IN_SCROLL_STRING "set_prop:"
static int32_t scroll_bar_value_to_scroll_view_offset_y(scroll_bar_t* scroll_bar,
scroll_view_t* sv) {
@ -94,6 +95,16 @@ static ret_t on_set_focuse_item(void* ctx, event_t* e) {
return RET_OK;
}
static ret_t on_set_visible_reveal_in_scroll(void* ctx, event_t* e) {
const char* name = (const char*)ctx;
if (name != NULL) {
widget_set_prop_str(scroll_view, WIDGET_PROP_VISIBLE_REVEAL_IN_SCROLL, name);
}
return RET_OK;
}
static ret_t scroll_view_offset_changed(void* ctx, event_t* e) {
scroll_view_t* sv = SCROLL_VIEW(scroll_view);
scroll_bar_t* scroll_bar_h = SCROLL_BAR(bar_h);
@ -133,6 +144,9 @@ static ret_t install_one(void* ctx, const void* iter) {
if (strstr(name, BUTTON_SET_FOCUSE_STRING) != NULL) {
widget_on(widget, EVT_CLICK, on_set_focuse_item,
(void*)(name + tk_strlen(BUTTON_SET_FOCUSE_STRING)));
} else if (strstr(name, BUTTON_SET_PROP_VISIBLE_REVEAL_IN_SCROLL_STRING) != NULL) {
widget_on(widget, EVT_CLICK, on_set_visible_reveal_in_scroll,
(void*)(name + tk_strlen(BUTTON_SET_PROP_VISIBLE_REVEAL_IN_SCROLL_STRING)));
} else if (tk_str_eq(name, SCROLL_BAR_H_WIDGT_NAME)) {
bar_h = widget;
widget_on(widget, EVT_VALUE_CHANGED, scroll_bar_value_changed, widget);

View File

@ -1,7 +1,7 @@
<window anim_hint="htranslate">
<view x="0" y="0" w="100%" h="70%">
<view x="0" y="0" w="100%" h="60%">
<scroll_view x="10%" y="10%" w="80%" h="80%" xoffset="0" yoffset="0" recursive="true" style.normal.border_color="#ff0000" >
<view x="1" y="1" w="30" h="30" style.normal.border_color="#0000ff" >
<view x="1" y="1" w="30" h="30" style.normal.border_color="#0000ff" style.normal.bg_color="red" >
<image image="earth" name="earth1" x="0" y="0" w="24" h="24"/>
</view>
<view x="1" y="100" w="30" h="30" style.normal.border_color="#0000ff">
@ -15,7 +15,7 @@
</view>
<view x="1" y="400" w="60" h="60" style.normal.border_color="#0000ff">
<view x="0" y="5" w="50" h="50" style.normal.border_color="#ff00ff">
<image image="earth" name="earth2" x="0" y="b" w="24" h="24"/>
<image image="earth" name="earth2" x="0" y="b" w="24" h="24" style.normal.bg_color="red"/>
</view>
</view>
<view x="100" y="100" w="30" h="30" style.normal.border_color="#0000ff">
@ -31,19 +31,26 @@
<image image="earth" x="0" y="0" w="24" h="24"/>
</view>
<view x="400" y="400" w="60" h="60" style.normal.border_color="#0000ff">
<image image="earth" name="earth3" x="0" y="0" w="24" h="24"/>
<image image="earth" name="earth3" x="0" y="0" w="24" h="24" style.normal.bg_color="red"/>
</view>
<view x="200" y="400" w="30" h="30" style.normal.border_color="#0000ff">
<image image="earth" name="earth4" x="60" y="60" w="24" h="24"/>
<image image="earth" name="earth4" x="60" y="60" w="24" h="24" style.normal.bg_color="red"/>
</view>
</scroll_view>
<scroll_bar_d name="bar_h" x="10%" y="b" w="80%" h="10%" value="0"/>
<scroll_bar_d name="bar_v" x="r" y="10%" w="10%" h="80%" value="0"/>
</view>
<view x="0" y="b" w="100%" h="30%" children_layout="default(c=2,r=4,m=5,s=5)" >
<view style:border_color="red" x="0" y="60%" w="100%" h="15%" children_layout="default(c=2,r=2,m=5,s=5)" >
<button name="focused:earth1" text="earth1" />
<button name="focused:earth2" text="earth2" />
<button name="focused:earth3" text="earth3" />
<button name="focused:earth4" text="earth4" />
</view>
<view style:border_color="red" x="0" y="75%" w="100%" h="25%" children_layout="default(c=2,r=3,m=5,s=5)" >
<button name="set_prop:default" text="default" />
<button name="set_prop:in_center" text="in_center" />
<button name="set_prop:in_center_if_outside_viewport" text="in_center_outside" />
<button name="set_prop:at_top" text="at_top" />
<button name="set_prop:no_operation" text="no_operation" />
</view>
</window>

View File

@ -2,6 +2,7 @@
2024/06/13
* 去掉不必要的参数有效性检查(感谢朝泽提供补丁)
* 增加滚动控件的子控件可视滚动属性(感谢智明提供补丁)
2024/06/12
* 修复中文输入法在输入超过15位拼音后多余的字符会直接输入到编辑框的bug(感谢泽武提供补丁)

View File

@ -48,6 +48,7 @@
#include "base/assets_manager.h"
#include "blend/image_g2d.h"
#include "base/style_const.h"
#include "base/widget_visible_in_scroll_view.inc"
ret_t widget_focus_up(widget_t* widget);
ret_t widget_focus_down(widget_t* widget);
@ -4125,39 +4126,29 @@ static ret_t widget_ensure_visible_in_scroll_view(widget_t* scroll_view, widget_
int32_t oy = 0;
int32_t old_ox = 0;
int32_t old_oy = 0;
rect_t r, r_visable;
int32_t max_w = 0;
int32_t max_h = 0;
rect_t r;
widget_visible_reveal_in_scroll_func_t func;
return_value_if_fail(widget != NULL && scroll_view != NULL, RET_BAD_PARAMS);
memset(&p, 0x0, sizeof(point_t));
widget_to_screen_ex(widget, scroll_view, &p);
r = rect_init(p.x, p.y, widget->w, widget->h);
func = widget_get_visible_reveal_in_scroll_func(scroll_view);
ox = widget_get_prop_int(scroll_view, WIDGET_PROP_XOFFSET, 0);
oy = widget_get_prop_int(scroll_view, WIDGET_PROP_YOFFSET, 0);
old_ox = ox;
old_oy = oy;
r_visable = rect_init(ox, oy, scroll_view->w, scroll_view->h);
if (rect_has_intersect(&r, &r_visable)) {
return RET_OK;
}
func(&r, ox, oy, scroll_view->w, scroll_view->h, &ox, &oy);
if (oy > r.y) {
oy = r.y;
}
if (ox > r.x) {
ox = r.x;
}
if ((r.y + r.h) > (oy + scroll_view->h)) {
oy = r.y + r.h - scroll_view->h;
}
if ((r.x + r.w) > (ox + scroll_view->w)) {
ox = r.x + r.w - scroll_view->w;
}
max_w = widget_get_prop_int(scroll_view, WIDGET_PROP_VIRTUAL_W, scroll_view->w);
max_h = widget_get_prop_int(scroll_view, WIDGET_PROP_VIRTUAL_H, scroll_view->h);
ox = tk_min(ox, max_w - scroll_view->w);
oy = tk_min(oy, max_h - scroll_view->h);
if (ox != old_ox) {
widget_set_prop_int(scroll_view, WIDGET_PROP_XOFFSET, ox);
}

View File

@ -335,6 +335,12 @@ BEGIN_C_DECLS
*/
#define WIDGET_PROP_ELLIPSES "ellipses"
/**
* @const WIDGET_PROP_VISIBLE_REVEAL_IN_SCROLL
* widget_ensure_visible_in_viewport
*/
#define WIDGET_PROP_VISIBLE_REVEAL_IN_SCROLL "visible_reveal_in_scroll"
/**
* @const WIDGET_PROP_TEXT
*

View File

@ -0,0 +1,107 @@

#define WIDGET_VISIBLE_REVEAL_IN_SCROLL_TYPE_DEFAULT "default"
#define WIDGET_VISIBLE_REVEAL_IN_SCROLL_TYPE_IN_CENTER "in_center"
#define WIDGET_VISIBLE_REVEAL_IN_SCROLL_TYPE_IN_CENTER_IF_OUTSIDE_VIEWPORT "in_center_if_outside_viewport"
#define WIDGET_VISIBLE_REVEAL_IN_SCROLL_TYPE_AT_TOP "at_top"
#define WIDGET_VISIBLE_REVEAL_IN_SCROLL_TYPE_NO_OPERATION "no_operation"
typedef ret_t (*widget_visible_reveal_in_scroll_func_t)(const rect_t* r, xy_t ox, xy_t oy, wh_t scroll_w, wh_t scroll_h, xy_t* new_ox, xy_t* new_oy);
/**
* 调整到最近的可视位置,即块已在可视区域内,如果显示区域比滚动区域还要大,则不做任何操作,否则选择最短的路径移到到可视区域。
*/
static ret_t widget_visible_reveal_in_scroll_by_default(const rect_t* r, xy_t ox, xy_t oy, wh_t scroll_w, wh_t scroll_h, xy_t* new_ox, xy_t* new_oy) {
return_value_if_fail(r != NULL && new_ox != NULL && new_oy != NULL, RET_BAD_PARAMS);
if (oy > r->y) {
oy = r->y;
}
if ((r->y + r->h) > (oy + scroll_h)) {
oy = r->y + r->h - scroll_h;
}
if (ox > r->x) {
ox = r->x;
}
if ((r->x + r->w) > (ox + scroll_w)) {
ox = r->x + r->w - scroll_w;
}
*new_ox = tk_max(ox, 0);
*new_oy = tk_max(oy, 0);
return RET_OK;
}
/**
* 调整到可视区域的中心,比如块没有在可视区域的中心(即使已在可视区域内),则调整到中心。
*/
static ret_t widget_visible_reveal_in_scroll_by_in_center(const rect_t* r, xy_t ox, xy_t oy, wh_t scroll_w, wh_t scroll_h, xy_t* new_ox, xy_t* new_oy) {
return_value_if_fail(r != NULL && new_ox != NULL && new_oy != NULL, RET_BAD_PARAMS);
(void)ox;
(void)oy;
*new_ox = r->x + (r->w - scroll_w) / 2;
*new_oy = r->y + (r->h - scroll_h) / 2;
*new_ox = tk_max(*new_ox, 0);
*new_oy = tk_max(*new_oy, 0);
return RET_OK;
}
/**
* 如果在可视区域之外,则调整到可视区域的中心;否则,不做任何操作。
*/
static ret_t widget_visible_reveal_in_scroll_by_in_center_if_outside_viewport(const rect_t* r, xy_t ox, xy_t oy, wh_t scroll_w, wh_t scroll_h, xy_t* new_ox, xy_t* new_oy) {
rect_t rect1;
return_value_if_fail(r != NULL && new_ox != NULL && new_oy != NULL, RET_BAD_PARAMS);
rect1 = rect_init(ox, oy, scroll_w, scroll_h);
if (rect_has_intersect(&rect1, r)) {
*new_ox = ox;
*new_oy = oy;
return RET_OK;
} else {
return widget_visible_reveal_in_scroll_by_in_center(r, ox, oy, scroll_w, scroll_h, new_ox, new_oy);
}
}
/**
* 调整到可视区域的顶端,比如块没有在可视区域的顶端(即使已在可视区域内),则调整到顶端。
*/
static ret_t widget_visible_reveal_in_scroll_by_at_top(const rect_t* r, xy_t ox, xy_t oy, wh_t scroll_w, wh_t scroll_h, xy_t* new_ox, xy_t* new_oy) {
return_value_if_fail(r != NULL && new_ox != NULL && new_oy != NULL, RET_BAD_PARAMS);
(void)scroll_w;
(void)scroll_h;
*new_ox = r->x;
*new_oy = r->y;
return RET_OK;
}
/* 不做任何处理 */
static ret_t widget_visible_reveal_in_scroll_by_no_operation(const rect_t* r, xy_t ox, xy_t oy, wh_t scroll_w, wh_t scroll_h, xy_t* new_ox, xy_t* new_oy) {
return_value_if_fail(r != NULL && new_ox != NULL && new_oy != NULL, RET_BAD_PARAMS);
*new_ox = ox;
*new_oy = oy;
return RET_OK;
}
static widget_visible_reveal_in_scroll_func_t widget_get_visible_reveal_in_scroll_func(widget_t* scroll_view) {
const char* str = widget_get_prop_str(scroll_view, WIDGET_PROP_VISIBLE_REVEAL_IN_SCROLL, NULL);
if (str != NULL) {
if (tk_stricmp(str, WIDGET_VISIBLE_REVEAL_IN_SCROLL_TYPE_DEFAULT) == 0) {
return widget_visible_reveal_in_scroll_by_default;
} else if (tk_stricmp(str, WIDGET_VISIBLE_REVEAL_IN_SCROLL_TYPE_IN_CENTER) == 0) {
return widget_visible_reveal_in_scroll_by_in_center;
} else if (tk_stricmp(str, WIDGET_VISIBLE_REVEAL_IN_SCROLL_TYPE_IN_CENTER_IF_OUTSIDE_VIEWPORT) == 0) {
return widget_visible_reveal_in_scroll_by_in_center_if_outside_viewport;
} else if (tk_stricmp(str, WIDGET_VISIBLE_REVEAL_IN_SCROLL_TYPE_AT_TOP) == 0) {
return widget_visible_reveal_in_scroll_by_at_top;
} else if (tk_stricmp(str, WIDGET_VISIBLE_REVEAL_IN_SCROLL_TYPE_NO_OPERATION) == 0) {
return widget_visible_reveal_in_scroll_by_no_operation;
}
}
return widget_visible_reveal_in_scroll_by_default;
}