sync(SDK): 增量同步主仓 M6.37–M6.39 至公开 SDK 仓
sdk/: - 同步 meow_ui_widget/input/gfx/lazygrid/audio/media/img 等源码与头 (SDK 默认列表/容器控件默认 MD3 — meow_list_set_container 可回退; 全局 App 内底部上滑回桌面 — meow_ui_input_is_home_swipe 系统保留手势; LazyGrid/LazyColumn/LazyRow MD3 化;叠加让位自抑改 app_id 判定; DSD 音频格式等) - 新增独立模块源码 meow_img_color / meow_lyric / meow_lyric_view 及对应宿主 test_*.c - 保留公开仓自包含适配:vendored meow_font.c/meow_font.h/meow_notif.h 不动; build_sdk.sh 自包含版本不动;meow_ui_gfx.c 仅改 meow_font.h include 路径; meow_ui_internal.h 去除 FreeType 内部声明 - meow_ipc.h 同步到主仓 launcher 版本(含 AUDIO_FMT_DOP/媒体歌词/蓝牙输出协议) - 不含 FreeType 矢量字 meow_ft_*(需 freetype vendor,公开仓以位图 meow_font 自包含);不含 mipsel 二进制 / .o / .a / 固件 / 密钥 / devdocs examples/hello/: - 新增 ui/demo/sdk2/sdk2.c;build_hello.sh 纳入该文件(保持自包含) docs / README / .gitignore: - docs/MEOW_APP_SDK.md 补 §12.5(默认 MD3 容器 + 底部上滑回桌面 + 两个新 API) - README 能力清单补「默认 MD3 容器」与「底部上滑回桌面」 - .gitignore 补新增宿主测试二进制 验证:sdk/meow_ui.a 与 examples/hello/hello 交叉编译均 0 warning;工作区无生成物。
This commit is contained in:
1 parent
a1687486bc
commit
c0396e40ce
45 files changed
+4665
-175
No files matched your search
+195
-66
@@ -116,6 +116,7 @@ struct meow_widget {
|
||||
int show_icon; /* 1=画左图标/缩略图(默认 1) */
|
||||
int show_right;/* 1=画右尾件(默认 1) */
|
||||
char empty_text[64]; /* 空态占位文案(首字符 0=不画) */
|
||||
int container; /* MD3 容器模式(默认 renderer):1=行=surfaceContainer 圆角卡+空隙 (P0) */
|
||||
|
||||
/* §5.5 左滑删除(列表行横向手势:滑动偏移/删除动画/回弹;calloc 归零,安全)。
|
||||
* 手势由 App 在 on_touch_move 喂(swipe_begin/move/end);横向小位移判 swipe、纵向滚动优先;
|
||||
@@ -141,6 +142,12 @@ static uint32_t widget_fg(const meow_widget *w, const meow_theme *th, uint32_t d
|
||||
{ (void)th; return (w->opts_used && w->opts.fg) ? w->opts.fg : def; }
|
||||
static int widget_radius(const meow_widget *w, int def)
|
||||
{ return (w->opts_used && w->opts.radius >= 0) ? w->opts.radius : def; }
|
||||
/* MD3 全形按钮圆角 = 胶囊(全高一半);opts.radius 显式优先(P1 shape 对齐,替代硬编码 10)。 */
|
||||
static int widget_btn_radius(const meow_widget *w)
|
||||
{
|
||||
if (w->opts_used && w->opts.radius >= 0) return w->opts.radius;
|
||||
return MEOW_SHAPE_FULL(w->h);
|
||||
}
|
||||
static int widget_pady(const meow_widget *w)
|
||||
{ return (w->opts_used && w->opts.pad_y > 0) ? w->opts.pad_y : 0; }
|
||||
|
||||
@@ -400,6 +407,10 @@ meow_widget *meow_list_create(int x, int y, int w, int h, int count,
|
||||
t->owner = meow_ui_activity_active();
|
||||
t->state = MEOW_WS_ENABLED;
|
||||
t->count = count; t->src = src; t->ctx = ctx; t->sel = 0;
|
||||
/* M6.37 P1:SDK 默认列表(meow_list_create / meow_lazycolumn_create / meow_lazyrow_create,皆 W_LIST)
|
||||
* 走 MD3 容器模式——每项=surfaceContainer 圆角卡 + 项间空隙 + 去分隔线 + 卡内 tonal 选中/按压,
|
||||
* 与 meow_listview 容器同范式(全局统一)。需扁平的宿主可显式 meow_list_set_container(w,0) 回退。 */
|
||||
t->container = 1;
|
||||
meow_draw_widget_register(t);
|
||||
return t;
|
||||
}
|
||||
@@ -1007,6 +1018,17 @@ int meow_list_tap_at(meow_widget *w, int x, int y)
|
||||
return idx;
|
||||
}
|
||||
|
||||
/* MD3 容器模式(W_LIST 共用,§5.5/§5.8.6):0=扁平满宽项+分隔线(回退);1=每项外套 surfaceContainer
|
||||
* 圆角卡+项间空隙(去分隔线),选中=primaryContainer/按压=primary α26(卡内 tonal)。
|
||||
* 覆盖 meow_list_create / meow_lazycolumn_create / meow_lazyrow_create。返回 0=成功;无效=负值。 */
|
||||
int meow_list_set_container(meow_widget *w, int on)
|
||||
{
|
||||
if (!w || w->type != W_LIST) return -1;
|
||||
w->container = on ? 1 : 0;
|
||||
meow_gfx_mark_dirty(w->x, w->y, w->w, w->h);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ============================================================ */
|
||||
/* §5.5 结构化列表(W_LISTVIEW):行=图标+标题+副标题+右侧操作+选中
|
||||
* ------------------------------------------------------------
|
||||
@@ -1017,6 +1039,11 @@ int meow_list_tap_at(meow_widget *w, int x, int y)
|
||||
#define MEOW_LISTV_ICON 24 /* 图标盒尺寸(px) */
|
||||
#define MEOW_LISTV_PAD 16 /* 行内左右 padding(px) */
|
||||
#define MEOW_LISTV_SUB_GAP 2 /* 标题与副标题间隙(px) */
|
||||
/* MD3 容器模式(P0):行=surfaceContainer 圆角卡 + 行间空隙(去分隔线);卡图元与主界面/
|
||||
* ncm 歌单同手法(main_menu.c:639 / playlist.c)。卡在行高内上下对称内缩(行中心=卡中心)。 */
|
||||
#define MEOW_LISTV_CARD_MARGIN 8 /* 卡横向外边距(px) */
|
||||
#define MEOW_LISTV_CARD_GAP 8 /* 卡纵向间隙(px) */
|
||||
#define MEOW_LISTV_CARD_RADIUS 12 /* 卡圆角(px,12dp) */
|
||||
|
||||
/* meow_ui_img_scaled 弱引用:W_LISTVIEW 的 MEOW_LIST_ICON_IMG 分支用它绘制图片图标。
|
||||
* 弱引用让「只用内置符号图标、不解码图片」的 App 不被牵连进 meow_ui_img.o/stb_image.o
|
||||
@@ -1179,6 +1206,9 @@ meow_widget *meow_listview_create(int x, int y, int w, int h, int count,
|
||||
t->sel = -1; t->item_h = 56; t->scroll = 0; t->swipe_idx = -1;
|
||||
t->sel_mode = (mode >= MEOW_LIST_SEL_NONE && mode <= MEOW_LIST_SEL_MULTI) ? mode : MEOW_LIST_SEL_NONE;
|
||||
t->lines = 2; t->show_icon = 1; t->show_right = 1; /* 默认双行富 item + 图标 + 右尾件(src2 布局不变) */
|
||||
t->container = 1; /* M6.37 P1:SDK 默认列表走 MD3 容器模式——行=surfaceContainer 圆角卡 + 空隙 + 去分隔线 + 卡内 tonal 选中,
|
||||
* 让 hello 示例 / files 及一切用 SDK 默认 renderer 的 App 开箱即 MD3(用户 2026-09-04 反馈默认仍扁平)。
|
||||
* 需扁平的宿主可显式 meow_listview_set_container(lv,0) 回退(test_meow_ui_widgets 即用它锁扁平基线)。 */
|
||||
if (t->sel_mode == MEOW_LIST_SEL_MULTI && t->count > 0) {
|
||||
t->sel_bits_n = (t->count + 31) / 32;
|
||||
t->sel_bits = (uint32_t *)calloc((size_t)t->sel_bits_n, sizeof(uint32_t));
|
||||
@@ -1395,6 +1425,14 @@ int meow_listview_set_item_draw(meow_widget *w, meow_listview_draw_fn draw,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int meow_listview_set_container(meow_widget *w, int on)
|
||||
{
|
||||
if (!w || w->type != W_LISTVIEW) return -1;
|
||||
w->container = on ? 1 : 0;
|
||||
meow_gfx_mark_dirty(w->x, w->y, w->w, w->h);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int meow_listview_set_empty_text(meow_widget *w, const char *text)
|
||||
{
|
||||
if (!w || w->type != W_LISTVIEW) return -1;
|
||||
@@ -1631,7 +1669,7 @@ void meow_widget_draw(meow_widget *w)
|
||||
uint32_t bg;
|
||||
if (fill) bg = (hold) ? state_tint(base, th, 24) : (press ? state_tint(base, th, 12) : base);
|
||||
else bg = 0;
|
||||
int r = widget_radius(w, 10);
|
||||
int r = widget_btn_radius(w);
|
||||
if (fill) meow_gfx_fill_round(w->x, w->y, w->w, w->h, r, bg);
|
||||
else if (press) meow_ui_fill_rect_alpha(w->x, w->y, w->w, w->h, th->primary, 12); /* transparent ripple */
|
||||
/* 内容区受 pad 垂直内缩(水平居中文本,pad_x 不影响中心) */
|
||||
@@ -1693,17 +1731,25 @@ void meow_widget_draw(meow_widget *w)
|
||||
break;
|
||||
}
|
||||
case W_SWITCH: {
|
||||
uint32_t bg = w->on ? th->primary : th->onSurfaceVariant;
|
||||
/* MD3(P3):on-track=primary;off-track=surfaceContainerHighest(原 onSurfaceVariant 过暗);
|
||||
* on-thumb=onPrimary;off-thumb=surface + outline(原恒白)。 */
|
||||
uint32_t bg = w->on ? th->primary : th->surfaceContainerHighest;
|
||||
meow_gfx_fill_round(w->x, w->y, w->w, w->h, w->h / 2, bg);
|
||||
int knob_r = w->h / 2 - 3;
|
||||
int kx = w->on ? w->x + w->w - knob_r * 2 - 3 : w->x + 3;
|
||||
meow_gfx_fill_round(kx, w->y + 3, knob_r * 2, knob_r * 2, knob_r, 0xFFFFFF);
|
||||
uint32_t knob = w->on ? th->onPrimary : th->surface; /* off-thumb 表面色 */
|
||||
meow_gfx_fill_round(kx, w->y + 3, knob_r * 2, knob_r * 2, knob_r, knob);
|
||||
if (!w->on) meow_ui_draw_rect_round(kx, w->y + 3, knob_r * 2, knob_r * 2, knob_r, th->outline);
|
||||
if (disabled) meow_gfx_fill_round_alpha(w->x, w->y, w->w, w->h, w->h / 2, th->onSurface, 90);
|
||||
break;
|
||||
}
|
||||
case W_LIST: {
|
||||
/* §5.8.6 列表容器(LazyColumn/LazyRow):只画可见项(虚拟化)+ 滚动偏移。
|
||||
* 纵向=行高 item_h(默认 44,兼容既有 meow_list_create);横向=LazyRow(列宽=item_h)。 */
|
||||
* 纵向=行高 item_h(默认 44,兼容既有 meow_list_create);横向=LazyRow(列宽=item_h)。
|
||||
* MD3 容器模式(w->container=1,默认):每项外套 surfaceContainer 圆角卡(12dp)+ 项间空隙
|
||||
* (去分隔线),选中=primaryContainer/按压=primary α26(卡内 tonal),与 meow_listview 容器同范式;
|
||||
* 卡在项内交叉轴内缩 MEOW_LISTV_CARD_MARGIN、滚动轴对称内缩 MEOW_LISTV_CARD_GAP(行中心=卡中心)。
|
||||
* 非容器(meow_list_set_container(0) 回退):满幅扁平行 + primary 选中 + onSurfaceVariant 分隔线。 */
|
||||
int pad = 16;
|
||||
int item = list_item(w);
|
||||
int vp = w->horizontal ? w->w : w->h;
|
||||
@@ -1720,36 +1766,70 @@ void meow_widget_draw(meow_widget *w)
|
||||
* 画到视口外 → 标脏并上屏 → 标题栏/底部残留脏区,P3)。 */
|
||||
int vx0 = w->x, vy0 = w->y, vx1 = w->x + w->w, vy1 = w->y + w->h;
|
||||
int thh = meow_ui_text_height(th->font_body);
|
||||
int cm = w->container ? MEOW_LISTV_CARD_MARGIN : 0; /* 卡交叉轴内缩(纵向=水平→横向=垂直) */
|
||||
int cgap = w->container ? MEOW_LISTV_CARD_GAP : 0; /* 卡滚动轴对称内缩(去分隔线、留空隙) */
|
||||
for (int i = first; i < last; i++) {
|
||||
char label[64] = "";
|
||||
if (!w->src || !w->src(i, label, (int)sizeof label, w->ctx)) continue;
|
||||
int pos = i * item - off; /* 相对容器起点的可视位置 */
|
||||
int sel = (i == w->sel);
|
||||
if (w->horizontal) {
|
||||
int rx = w->x + pos;
|
||||
if (rx >= vx1) break; /* 完全在右缘外 */
|
||||
if (rx + item <= vx0) continue; /* 完全在左缘外(滚出残余) */
|
||||
int cl = rx > vx0 ? rx : vx0; /* 可见左界 */
|
||||
int cr = (rx + item) < vx1 ? (rx + item) : vx1; /* 可见右界 */
|
||||
if (i == w->sel) meow_ui_fill_rect(cl, w->y, cr - cl, w->h, th->primary);
|
||||
uint32_t col = (i == w->sel) ? 0xFFFFFF : th->onSurface;
|
||||
int ctop = w->y + cm; /* 卡顶(交叉轴内缩) */
|
||||
int chh = w->h - 2 * cm; /* 卡高 */
|
||||
int clft = rx + cgap / 2; /* 卡左(滚动轴对称内缩) */
|
||||
int cwid = item - cgap; /* 卡宽 */
|
||||
int press = meow_input_touch_down() &&
|
||||
meow_input_touch_x() >= rx && meow_input_touch_x() < rx + item &&
|
||||
meow_input_touch_y() >= w->y && meow_input_touch_y() < w->y + w->h;
|
||||
if (w->container) {
|
||||
meow_gfx_fill_round(clft, ctop, cwid, chh, MEOW_LISTV_CARD_RADIUS, th->surfaceContainer);
|
||||
if (sel) meow_gfx_fill_round(clft, ctop, cwid, chh, MEOW_LISTV_CARD_RADIUS, th->primaryContainer);
|
||||
else if (press) meow_gfx_fill_round_alpha(clft, ctop, cwid, chh, MEOW_LISTV_CARD_RADIUS, th->primary, 26);
|
||||
} else {
|
||||
if (sel) meow_ui_fill_rect(cl, w->y, cr - cl, w->h, th->primary);
|
||||
}
|
||||
uint32_t col = sel ? (w->container ? th->onPrimaryContainer : 0xFFFFFF) : th->onSurface;
|
||||
int ty = w->y + (w->h - thh) / 2;
|
||||
if (rx >= vx0 && rx + item <= vx1) /* 仅整项可见才画文本(防泄漏) */
|
||||
meow_ui_text_center(rx + item / 2, ty, label, th->font_body, col);
|
||||
int sxp = rx + item - 1; /* 分隔线:仅当落在可见区 */
|
||||
if (sxp >= cl && sxp < cr) meow_ui_fill_rect(sxp, w->y, 1, w->h, th->onSurfaceVariant);
|
||||
if (!w->container) { /* 非容器才画分隔线(容器模式去冗余) */
|
||||
int sxp = rx + item - 1; /* 分隔线:仅当落在可见区 */
|
||||
if (sxp >= cl && sxp < cr) meow_ui_fill_rect(sxp, w->y, 1, w->h, th->onSurfaceVariant);
|
||||
}
|
||||
} else {
|
||||
int ry = w->y + pos;
|
||||
if (ry >= vy1) break; /* 完全在底缘外 */
|
||||
if (ry + item <= vy0) continue; /* 完全在顶缘外(滚出残余) */
|
||||
int cl = ry > vy0 ? ry : vy0; /* 可见顶界 */
|
||||
int cr = (ry + item) < vy1 ? (ry + item) : vy1; /* 可见底界 */
|
||||
if (i == w->sel) meow_ui_fill_rect(w->x, cl, w->w, cr - cl, th->primary);
|
||||
uint32_t col = (i == w->sel) ? 0xFFFFFF : th->onSurface;
|
||||
int clft = w->x + cm; /* 卡左(交叉轴内缩) */
|
||||
int cwid = w->w - 2 * cm; /* 卡宽 */
|
||||
int ctop = ry + cgap / 2; /* 卡顶(滚动轴对称内缩) */
|
||||
int chh = item - cgap; /* 卡高 */
|
||||
int press = meow_input_touch_down() &&
|
||||
meow_input_touch_x() >= w->x && meow_input_touch_x() < w->x + w->w &&
|
||||
meow_input_touch_y() >= ry && meow_input_touch_y() < ry + item;
|
||||
if (w->container) {
|
||||
meow_gfx_fill_round(clft, ctop, cwid, chh, MEOW_LISTV_CARD_RADIUS, th->surfaceContainer);
|
||||
if (sel) meow_gfx_fill_round(clft, ctop, cwid, chh, MEOW_LISTV_CARD_RADIUS, th->primaryContainer);
|
||||
else if (press) meow_gfx_fill_round_alpha(clft, ctop, cwid, chh, MEOW_LISTV_CARD_RADIUS, th->primary, 26);
|
||||
} else {
|
||||
if (sel) meow_ui_fill_rect(w->x, cl, w->w, cr - cl, th->primary);
|
||||
}
|
||||
uint32_t col = sel ? (w->container ? th->onPrimaryContainer : 0xFFFFFF) : th->onSurface;
|
||||
int txx = (w->container ? clft : w->x) + pad; /* 卡内文本左缘 */
|
||||
int ty = ry + (item - thh) / 2;
|
||||
if (ty >= vy0 && ty + thh <= vy1) /* 文本不越界才画(防标题/底部泄漏) */
|
||||
meow_ui_text(w->x + pad, ty, label, th->font_body, col);
|
||||
int sy = ry + item - 1; /* 分隔线:仅当落在可见区 */
|
||||
if (sy >= cl && sy < cr) meow_ui_fill_rect(w->x, sy, w->w, 1, th->onSurfaceVariant);
|
||||
meow_ui_text(txx, ty, label, th->font_body, col);
|
||||
if (!w->container) { /* 非容器才画分隔线(容器模式去冗余) */
|
||||
int sy = ry + item - 1; /* 分隔线:仅当落在可见区 */
|
||||
if (sy >= cl && sy < cr) meow_ui_fill_rect(w->x, sy, w->w, 1, th->onSurfaceVariant);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (disabled) meow_ui_fill_rect_alpha(w->x, w->y, w->w, w->h, th->onSurface, 90);
|
||||
@@ -1777,11 +1857,16 @@ void meow_widget_draw(meow_widget *w)
|
||||
int vx0 = w->x, vy0 = w->y, vy1 = w->y + w->h;
|
||||
int thh = meow_ui_text_height(th->font_body);
|
||||
int pad = MEOW_LISTV_PAD, isz = MEOW_LISTV_ICON;
|
||||
int text_x = vx0 + pad + ((w->show_icon) ? (isz + pad) : 0); /* 无图标则无图标间隙 */
|
||||
int op_start = (w->show_right) ? (vx0 + (w->w * 2 / 3)) /* 行右 1/3 = 操作区 */
|
||||
: (vx0 + w->w - pad);
|
||||
/* 容器模式(P0):行=surfaceContainer 圆角卡,卡横向内缩 cm;内容左缘/操作区/可用宽
|
||||
* 都在卡内计算(非容器 cm=0 → 与既有行为逐字一致)。 */
|
||||
int cm = w->container ? MEOW_LISTV_CARD_MARGIN : 0;
|
||||
int cw = w->w - 2 * cm; /* 内容/卡宽 */
|
||||
int cx0 = vx0 + cm; /* 内容左缘(卡内) */
|
||||
int text_x = cx0 + pad + ((w->show_icon) ? (isz + pad) : 0); /* 无图标则无图标间隙 */
|
||||
int op_start = (w->show_right) ? (cx0 + (cw * 2 / 3)) /* 行右 1/3 = 操作区 */
|
||||
: (cx0 + cw - pad);
|
||||
int text_maxw = (w->show_right) ? (op_start - pad - text_x) /* 标题/副标题可用宽(不压操作区) */
|
||||
: ((vx0 + w->w - pad) - text_x);
|
||||
: ((cx0 + cw - pad) - text_x);
|
||||
if (text_maxw < 8) text_maxw = 8;
|
||||
|
||||
/* 空态占位(§5.5):count==0 且设了 empty_text → 视口内居中画文案。 */
|
||||
@@ -1841,26 +1926,36 @@ void meow_widget_draw(meow_widget *w)
|
||||
meow_str("common.delete"), th->font_body, th->onError);
|
||||
shift = w->swipe_dx;
|
||||
}
|
||||
int rlx = vx0 + shift; /* 行内容左移后的 x */
|
||||
int rlx = (w->container ? cx0 : vx0) + shift; /* 行内容/卡左缘(随行左移) */
|
||||
int rtx = text_x + shift; /* 文本 x(随行左移) */
|
||||
int rop = op_start + shift; /* 操作区分界 x */
|
||||
int card_y = ry + MEOW_LISTV_CARD_GAP / 2; /* 容器模式:卡顶(行内对称内缩) */
|
||||
int card_h = item - MEOW_LISTV_CARD_GAP;
|
||||
|
||||
if (it->section) { /* 段头占位行(非粘性):surfaceContainerHigh 底 + primary 段名 */
|
||||
meow_ui_fill_rect(rlx, cl, w->w, cr - cl, th->surfaceContainerHigh);
|
||||
if (it->section) { /* 段头占位行(非粘性):容器=surface 上的 primary 段标签;非容器=surfaceContainerHigh 底 */
|
||||
if (!w->container) meow_ui_fill_rect(rlx, cl, w->w, cr - cl, th->surfaceContainerHigh);
|
||||
int sty = ry + (item - thh) / 2;
|
||||
if (it->title && sty >= vy0 && sty + thh <= vy1)
|
||||
listv_text_trunc(rtx, sty, it->title, text_maxw, th->font_body, th->primary);
|
||||
int sy = ry + item - 1;
|
||||
if (sy >= cl && sy < cr)
|
||||
meow_ui_fill_rect(rlx, sy, w->w, 1, th->outlineVariant);
|
||||
if (!it->enabled)
|
||||
meow_ui_fill_rect_alpha(rlx, cl, w->w, cr - cl, th->onSurface, 90);
|
||||
if (!w->container) {
|
||||
int sy = ry + item - 1;
|
||||
if (sy >= cl && sy < cr)
|
||||
meow_ui_fill_rect(rlx, sy, w->w, 1, th->outlineVariant);
|
||||
if (!it->enabled)
|
||||
meow_ui_fill_rect_alpha(rlx, cl, w->w, cr - cl, th->onSurface, 90);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 选中/按压背景(primaryContainer / 半透明主题色按压层) */
|
||||
if (sel) meow_ui_fill_rect(rlx, cl, w->w, cr - cl, th->primaryContainer);
|
||||
else if (press) meow_ui_fill_rect_alpha(rlx, cl, w->w, cr - cl, th->primary, 26);
|
||||
/* 选中/按压背景(容器=卡内 tonal;非容器=满幅实心,原行为) */
|
||||
if (w->container) {
|
||||
meow_gfx_fill_round(rlx, card_y, cw, card_h, MEOW_LISTV_CARD_RADIUS, th->surfaceContainer);
|
||||
if (sel) meow_gfx_fill_round(rlx, card_y, cw, card_h, MEOW_LISTV_CARD_RADIUS, th->primaryContainer);
|
||||
else if (press) meow_gfx_fill_round_alpha(rlx, card_y, cw, card_h, MEOW_LISTV_CARD_RADIUS, th->primary, 26);
|
||||
} else {
|
||||
if (sel) meow_ui_fill_rect(rlx, cl, w->w, cr - cl, th->primaryContainer);
|
||||
else if (press) meow_ui_fill_rect_alpha(rlx, cl, w->w, cr - cl, th->primary, 26);
|
||||
}
|
||||
uint32_t textcol = sel ? th->onPrimaryContainer : th->onSurface;
|
||||
uint32_t subcol = sel ? th->onPrimaryContainer : th->onSurfaceVariant;
|
||||
|
||||
@@ -1890,19 +1985,25 @@ void meow_widget_draw(meow_widget *w)
|
||||
|
||||
/* 右尾件(show_right=1:箭头/开关/复选/⋯) */
|
||||
if (w->show_right && it->right != MEOW_LIST_RIGHT_NONE) {
|
||||
int ax = rlx + w->w - pad - 24; /* 右缘动作槽(约 24px) */
|
||||
int ax = (cx0 + cw - pad - 24) + shift; /* 右缘动作槽(约 24px;容器=卡内右缘) */
|
||||
if (ax >= rop)
|
||||
listv_draw_right(th, ax, ry, item, it->right, it->on, subcol);
|
||||
}
|
||||
|
||||
/* 分隔线(仅落在可见带内才画) */
|
||||
int sy = ry + item - 1;
|
||||
if (sy >= cl && sy < cr)
|
||||
meow_ui_fill_rect(rlx, sy, w->w, 1, th->outlineVariant);
|
||||
/* 分隔线(仅非容器画;容器模式去冗余分隔线,行间用空隙替代) */
|
||||
if (!w->container) {
|
||||
int sy = ry + item - 1;
|
||||
if (sy >= cl && sy < cr)
|
||||
meow_ui_fill_rect(rlx, sy, w->w, 1, th->outlineVariant);
|
||||
}
|
||||
|
||||
/* 禁用行整体变淡(§5.5/§5.8.3 enabled=0 → 变暗) */
|
||||
if (!it->enabled)
|
||||
meow_ui_fill_rect_alpha(rlx, cl, w->w, cr - cl, th->onSurface, 90);
|
||||
/* 禁用行整体变淡(§5.5/§5.8.3 enabled=0 → 变暗;容器=卡内淡) */
|
||||
if (!it->enabled) {
|
||||
if (w->container)
|
||||
meow_gfx_fill_round_alpha(rlx, card_y, cw, card_h, MEOW_LISTV_CARD_RADIUS, th->onSurface, 90);
|
||||
else
|
||||
meow_ui_fill_rect_alpha(rlx, cl, w->w, cr - cl, th->onSurface, 90);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -1918,10 +2019,13 @@ void meow_widget_draw(meow_widget *w)
|
||||
int cl = ry > vy0 ? ry : vy0; /* 可见顶界(裁剪用) */
|
||||
int cr = (ry + item) < vy1 ? (ry + item) : vy1; /* 可见底界 */
|
||||
int sel = (i == w->sel);
|
||||
int press = meow_input_touch_down() &&
|
||||
meow_input_touch_x() >= vx0 && meow_input_touch_x() < vx0 + w->w &&
|
||||
meow_input_touch_y() >= ry && meow_input_touch_y() < ry + item;
|
||||
uint32_t textcol = sel ? th->onPrimaryContainer : th->onSurface;
|
||||
uint32_t subcol = sel ? th->onPrimaryContainer : th->onSurfaceVariant;
|
||||
/* 左滑删除(M7.3):本行被滑动 → 右露删除区 + 行 x 左移。非滑动行 shift=0 → 输出不变。 */
|
||||
int shift = 0, rlx = vx0, rtx = text_x, rop = op_start;
|
||||
int shift = 0, rlx = (w->container ? cx0 : vx0), rtx = text_x, rop = op_start;
|
||||
if (w->swipe_active && w->swipe_idx == i && w->swipe_dx < 0) {
|
||||
meow_ui_fill_rect(vx0 + w->w + w->swipe_dx, ry, -w->swipe_dx, item, th->error);
|
||||
int thh2 = meow_ui_text_height(th->font_body);
|
||||
@@ -1929,9 +2033,19 @@ void meow_widget_draw(meow_widget *w)
|
||||
if (dly >= vy0 && dly + thh2 <= vy1)
|
||||
meow_ui_text_center(vx0 + w->w + w->swipe_dx + (-w->swipe_dx) / 2, dly,
|
||||
meow_str("common.delete"), th->font_body, th->onError);
|
||||
shift = w->swipe_dx; rlx = vx0 + shift; rtx = text_x + shift; rop = op_start + shift;
|
||||
shift = w->swipe_dx; rlx = (w->container ? cx0 : vx0) + shift;
|
||||
rtx = text_x + shift; rop = op_start + shift;
|
||||
}
|
||||
int card_y = ry + MEOW_LISTV_CARD_GAP / 2;
|
||||
int card_h = item - MEOW_LISTV_CARD_GAP;
|
||||
if (w->container) {
|
||||
meow_gfx_fill_round(rlx, card_y, cw, card_h, MEOW_LISTV_CARD_RADIUS, th->surfaceContainer);
|
||||
if (sel) meow_gfx_fill_round(rlx, card_y, cw, card_h, MEOW_LISTV_CARD_RADIUS, th->primaryContainer);
|
||||
else if (press) meow_gfx_fill_round_alpha(rlx, card_y, cw, card_h, MEOW_LISTV_CARD_RADIUS, th->primary, 26);
|
||||
} else {
|
||||
if (sel) meow_ui_fill_rect(rlx, cl, w->w, cr - cl, th->primaryContainer);
|
||||
else if (press) meow_ui_fill_rect_alpha(rlx, cl, w->w, cr - cl, th->primary, 26);
|
||||
}
|
||||
if (sel) meow_ui_fill_rect(rlx, cl, w->w, cr - cl, th->primaryContainer);
|
||||
|
||||
/* 图标(左) */
|
||||
uint32_t iccol = sel ? th->onPrimaryContainer
|
||||
@@ -1958,19 +2072,25 @@ void meow_widget_draw(meow_widget *w)
|
||||
|
||||
/* 右侧操作区 */
|
||||
if (it.right != MEOW_LIST_RIGHT_NONE) {
|
||||
int ax = rlx + w->w - pad - 24; /* 右缘动作槽(约 24px) */
|
||||
int ax = (cx0 + cw - pad - 24) + shift; /* 右缘动作槽(约 24px;容器=卡内右缘) */
|
||||
if (ax >= rop)
|
||||
listv_draw_right(th, ax, ry, item, it.right, it.on, subcol);
|
||||
}
|
||||
|
||||
/* 分隔线(仅落在可见带内才画) */
|
||||
int sy = ry + item - 1;
|
||||
if (sy >= cl && sy < cr)
|
||||
meow_ui_fill_rect(rlx, sy, w->w, 1, th->outlineVariant);
|
||||
/* 分隔线(仅非容器画;容器模式去冗余分隔线,行间用空隙替代) */
|
||||
if (!w->container) {
|
||||
int sy = ry + item - 1;
|
||||
if (sy >= cl && sy < cr)
|
||||
meow_ui_fill_rect(rlx, sy, w->w, 1, th->outlineVariant);
|
||||
}
|
||||
|
||||
/* 禁用行整体变淡(§5.5/§5.8.3 enabled=0 → 变暗) */
|
||||
if (!it.enabled)
|
||||
meow_ui_fill_rect_alpha(rlx, cl, w->w, cr - cl, th->onSurface, 90);
|
||||
/* 禁用行整体变淡(§5.5/§5.8.3 enabled=0 → 变暗;容器=卡内淡) */
|
||||
if (!it.enabled) {
|
||||
if (w->container)
|
||||
meow_gfx_fill_round_alpha(rlx, card_y, cw, card_h, MEOW_LISTV_CARD_RADIUS, th->onSurface, 90);
|
||||
else
|
||||
meow_ui_fill_rect_alpha(rlx, cl, w->w, cr - cl, th->onSurface, 90);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (disabled) meow_ui_fill_rect_alpha(w->x, w->y, w->w, w->h, th->onSurface, 90);
|
||||
@@ -1988,7 +2108,7 @@ void meow_widget_draw(meow_widget *w)
|
||||
break;
|
||||
case W_TEXTFIELD: {
|
||||
/* MD3 输入框:圆角外框(surfaceContainerLowest 底 + outline 描边;focused=primary 2px)+ 提示/文本 + 光标。 */
|
||||
int r = widget_radius(w, 8);
|
||||
int r = widget_radius(w, MEOW_SHAPE_SMALL);
|
||||
int focused = (w->state & MEOW_WS_FOCUSED) != 0;
|
||||
meow_gfx_fill_round(w->x, w->y, w->w, w->h, r, th->surfaceContainerLowest);
|
||||
uint32_t bcol = focused ? th->primary : th->outline;
|
||||
@@ -2045,55 +2165,63 @@ void meow_widget_draw(meow_widget *w)
|
||||
break;
|
||||
}
|
||||
case W_CHECKBOX: {
|
||||
/* MD3(P3):视觉字 24dp 于控件矩形内居中(触摸目标不变);修正原 34 视觉过大。 */
|
||||
int sel = (w->state & MEOW_WS_SELECTED) != 0;
|
||||
int sz = w->w;
|
||||
int r = widget_radius(w, 4);
|
||||
int sz = 24;
|
||||
if (w->w < sz) sz = w->w; /* 控件小于视觉尺寸时跟随 */
|
||||
int bx = w->x + (w->w - sz) / 2, by = w->y + (w->h - sz) / 2;
|
||||
int r = widget_radius(w, MEOW_SHAPE_EXTRASMALL);
|
||||
if (sel) {
|
||||
meow_gfx_fill_round(w->x, w->y, sz, sz, r, th->primary);
|
||||
int ax = w->x + 9, ay1 = w->y + 17, ay2 = w->y + 23, bx = w->x + 15, cx = w->x + 25, cy = w->y + 11;
|
||||
meow_gfx_line(ax, ay1, bx, ay2, 3, th->onPrimary);
|
||||
meow_gfx_line(bx, ay2, cx, cy, 3, th->onPrimary);
|
||||
meow_gfx_fill_round(bx, by, sz, sz, r, th->primary);
|
||||
int ax = bx + 7, ay1 = by + 13, ay2 = by + 17, b2 = bx + 11, cx = bx + 18, cy = by + 7;
|
||||
meow_gfx_line(ax, ay1, b2, ay2, 2, th->onPrimary);
|
||||
meow_gfx_line(b2, ay2, cx, cy, 2, th->onPrimary);
|
||||
} else {
|
||||
meow_ui_draw_rect_round(w->x, w->y, sz, sz, r, th->outline);
|
||||
meow_ui_draw_rect_round(bx, by, sz, sz, r, th->outline);
|
||||
}
|
||||
if (w->state & MEOW_WS_FOCUSED) meow_ui_draw_rect_round(w->x, w->y, sz, sz, r, th->primary);
|
||||
if (disabled) meow_gfx_fill_round_alpha(w->x, w->y, sz, sz, r, th->onSurface, 90);
|
||||
if (w->state & MEOW_WS_FOCUSED) meow_ui_draw_rect_round(bx, by, sz, sz, r, th->primary);
|
||||
if (disabled) meow_gfx_fill_round_alpha(bx, by, sz, sz, r, th->onSurface, 90);
|
||||
break;
|
||||
}
|
||||
case W_RADIO: {
|
||||
/* MD3(P3):视觉 20dp(环半径 10)于控件内居中;原环半径 12 略大。 */
|
||||
int sel = (w->state & MEOW_WS_SELECTED) != 0;
|
||||
int ccx = w->x + w->w / 2, ccy = w->y + w->h / 2;
|
||||
meow_gfx_ring_arc(ccx, ccy, 12, 2, 0, 360, sel ? th->primary : th->outline);
|
||||
if (sel) meow_gfx_fill_circle(ccx, ccy, 6, th->primary);
|
||||
meow_gfx_ring_arc(ccx, ccy, 10, 2, 0, 360, sel ? th->primary : th->outline);
|
||||
if (sel) meow_gfx_fill_circle(ccx, ccy, 5, th->primary);
|
||||
if (disabled) meow_gfx_fill_round_alpha(w->x, w->y, w->w, w->h, w->w / 2, th->onSurface, 90);
|
||||
break;
|
||||
}
|
||||
case W_PROGRESS: {
|
||||
/* 批5b:轨道/填充可由 opts 覆盖(opts.bg=轨道、opts.fg=填充);opts 未设则回主题默认
|
||||
* (surfaceVariant/primary)——兼容既有调用(如 hello demo、现在播放页取色后回退默认)。 */
|
||||
uint32_t track = widget_bg(w, th, th->surfaceVariant);
|
||||
uint32_t fill = widget_fg(w, th, th->primary);
|
||||
if (w->variant == 1) { /* 圆形(几何 = 整圆像素外接框;由此解回圆心/半径) */
|
||||
int thk = MEOW_PROGRESS_ARC_THK;
|
||||
int m = MEOW_PROGRESS_ARC_MARGIN;
|
||||
int ccx = w->x + w->w / 2, ccy = w->y + w->h / 2;
|
||||
int rr = w->w / 2 - m; /* 与 create 一致:回到调用方传入的半径 r */
|
||||
if (rr <= 0) break;
|
||||
meow_gfx_ring_arc(ccx, ccy, rr, thk, 0, 360, th->surfaceVariant);
|
||||
meow_gfx_ring_arc(ccx, ccy, rr, thk, 0, 360, track);
|
||||
if (w->value < 0) { /* 不定:按时间推进一段弧(App 在 on_tick 里重绘驱动) */
|
||||
int start = (int)((meow_ui_time_ms() / 30) % 360);
|
||||
meow_gfx_ring_arc(ccx, ccy, rr, thk, start - 90, 90, th->primary);
|
||||
meow_gfx_ring_arc(ccx, ccy, rr, thk, start - 90, 90, fill);
|
||||
} else if (w->value > 0) {
|
||||
int sweep = w->value * 360 / 100;
|
||||
if (sweep > 0) meow_gfx_ring_arc(ccx, ccy, rr, thk, -90, sweep, th->primary);
|
||||
if (sweep > 0) meow_gfx_ring_arc(ccx, ccy, rr, thk, -90, sweep, fill);
|
||||
}
|
||||
} else { /* 线性 */
|
||||
int thk = w->h > 0 ? w->h : 4;
|
||||
int yy = w->y + w->h / 2 - thk / 2;
|
||||
meow_ui_fill_rect(w->x, yy, w->w, thk, th->surfaceVariant);
|
||||
meow_ui_fill_rect(w->x, yy, w->w, thk, track);
|
||||
if (w->value < 0) { /* 不定:移动块 */
|
||||
int fw = w->w / 3;
|
||||
int pos = (int)((meow_ui_time_ms() / 12) % (w->w + fw)) - fw;
|
||||
meow_ui_fill_rect(w->x + pos, yy, fw, thk, th->primary);
|
||||
meow_ui_fill_rect(w->x + pos, yy, fw, thk, fill);
|
||||
} else if (w->value > 0) {
|
||||
int fw = w->value * w->w / 100;
|
||||
if (fw > 0) meow_ui_fill_rect(w->x, yy, fw, thk, th->primary);
|
||||
if (fw > 0) meow_ui_fill_rect(w->x, yy, fw, thk, fill);
|
||||
}
|
||||
}
|
||||
if (disabled) meow_ui_fill_rect_alpha(w->x, w->y, w->w, w->h, th->onSurface, 90);
|
||||
@@ -2150,7 +2278,8 @@ void meow_widget_draw(meow_widget *w)
|
||||
for (int i = 0; i < w->nitems; i++) {
|
||||
int ix = w->x + i * iw;
|
||||
int sel = (i == w->selected);
|
||||
if (sel) meow_gfx_fill_round(ix + iw / 2 - 24, w->y + 8, 48, 22, 11, th->secondaryContainer);
|
||||
if (sel) /* MD3 active pill 64×32(原 48×22 偏小);垂直居中于栏 */
|
||||
meow_gfx_fill_round(ix + iw / 2 - 32, w->y + (w->h - 32) / 2, 64, 32, 16, th->secondaryContainer);
|
||||
uint32_t col = sel ? th->onSecondaryContainer : th->onSurfaceVariant;
|
||||
meow_ui_text_center(ix + iw / 2, ay, w->items[i], th->font_body, col);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user