sdk(M7.0a): 视图事件接线 + IconButton + 主题色板导出/注入(launcher 重写基座前置)

M7 launcher 整体 MD3 重写的 SDK 基座补全(只动 patch_v2/sdk/):
- 缺口#7 meow_view 事件接线:meow_view_dispatch_event 接入 meow_ui_run 主循环
  (§6.4 分流之上,TAP/KEY/SWIPE/LONG_PRESS 先经 view 路由、命中即消费、未命中回落
  on_* —— 无 view 树/未命中完全向后兼容);meow_view_add_child 在父已进入时挂子视图
  立即进入(递归 children 修正);meow_view_sub_push/pop 标注废弃(设计定案 b 不做页内
  子导航栈)。
- 缺口#2 IconButton:meow_iconbtn_create —— sb_icons 位图 + 圆形命中 + 按压/按住态
  (实时,同 meow_btn)+ owner/enabled 闸门;电源菜单/播放控制/锁屏通用件。
- 缺口#6 SDK 半主题收口:meow_theme_export/meow_theme_inject(§8.1.5 色板导出/注入),
  launcher s_ui_theme() 将据此变读 SDK 的薄壳(launcher 侧改动不在此批)。
- 文档:MEOW_APP_SDK.md 补 meow_iconbtn_create + meow_theme_export/inject 说明。
- 验证:新增 test_meow_ui_iconbtn / test_meow_ui_theme_export / test_meow_ui_view_event
  全 PASS;全量 SDK 宿主回归(widgets/dispatch/box/anim/scroll/listvirt/str/ime/pinyin/
  overlay/notif/input_keys/p1p2p3/umbrella/ft)全 PASS;交叉 -Wall -Wextra 0 warning。

meow_ui.a md5: be24214e24faadba63577f3a98c2c9d1 -> 7fc83f7731cadb2f91df1c3ed7d3814f
This commit is contained in:
AskaEth committed 2026-09-02 16:50:40 +08:00
1 parent e67cc50afa
commit a8c51be1fc
12 files changed
+595 -11

No files matched your search

+67 -4
View File
@@ -15,7 +15,8 @@ enum { W_BTN = 0, W_SLIDER = 1, W_SWITCH = 2, W_LIST = 3,
W_TEXTFIELD = 7, W_CARD = 8, W_DIVIDER = 9, W_BADGE = 10,
W_CHECKBOX = 11, W_RADIO = 12, W_PROGRESS = 13,
W_TOPAPPBAR = 14, W_NAVBAR = 15, W_TABBAR = 16, W_FAB = 17,
W_LISTVIEW = 18 }; /* §5.5 结构化列表(行=图标+标题+副标题+右侧操作+选中) */
W_LISTVIEW = 18, /* §5.5 结构化列表(行=图标+标题+副标题+右侧操作+选中) */
W_ICONBTN = 19 }; /* M7.0a 缺口#2:圆形/位图图标按钮(圆形命中 + 按压态) */
/* 布局子项数组上限(固定尺寸子项先做;超出静默拒收)。 */
#define MEOW_LAYOUT_MAX_CHILD 32
@@ -100,6 +101,8 @@ struct meow_widget {
meow_listview_tap_fn lv_tap_cb; /* 行点击回调(idx, op) */
void *lv_tap_ctx; /* 回调 ctx */
/* W_ICONBTN 位图图标:sb_icons[] 下标(= MEOW_ICON_* 或 SB_I_*;<0 画空位图,命中照常)。 */
int icon_id;
/* §5.5 虚拟化层(W_LISTVIEW 扩展:固定 item 池 + 多行渲染器 + 完全自绘 + 空态。
* calloc 归零,安全;vs_count/vs_bind 均非 NULL 才进入 pool 模式,src2 模式不受影响。) */
meow_listview_count_fn vs_count; /* 虚拟化总数回调(NULL=src2 模式) */
@@ -225,7 +228,9 @@ static int g_live_prev_hold = 0; /* 该按钮上次渲染是否为按住
static void live_btn_register(meow_widget *w)
{
if (!w || w->type != W_BTN) return;
if (!w) return;
/* M7.0a 缺口#2:IconButton 也是实时按压钮(同 meow_btn 的按压/按住即时重绘)。 */
if (w->type != W_BTN && w->type != W_ICONBTN) return;
for (int i = 0; i < g_live_btn_n; i++)
if (g_live_btns[i] == w) return;
if (g_live_btn_n < MEOW_LIVE_BTN_MAX) g_live_btns[g_live_btn_n++] = w;
@@ -246,6 +251,15 @@ static void live_btn_unregister(meow_widget *w)
/* 命中:返回坐标所在的「当前 active Activity」的最上层按钮(创建序 = 绘制序,最后者在上)。
* §6.1 ①:仅扫描 owner == 当前 active Activity 的按钮 —— 非 active Activity 的控件
* 绝不参与命中(根治 agent-119 遗留的「全屏页触摸到主页按钮位置 → 闪现 accent 底」)。 */
/* 圆形命中(IconButton;圆心=按钮中心、半径=size/2)。 */
static int iconbtn_circular_hit(const meow_widget *w, int x, int y)
{
int cx = w->x + w->w / 2, cy = w->y + w->h / 2;
int r = (w->w < w->h ? w->w : w->h) / 2;
int dx = x - cx, dy = y - cy;
return (dx * dx + dy * dy) <= (r * r);
}
static meow_widget *live_btn_hit(int x, int y)
{
int active = meow_ui_activity_active();
@@ -253,8 +267,12 @@ static meow_widget *live_btn_hit(int x, int y)
for (int i = 0; i < g_live_btn_n; i++) {
meow_widget *w = g_live_btns[i];
if (w->owner != active) continue; /* 非 active activity:跳过 */
if (x >= w->x && x < w->x + w->w && y >= w->y && y < w->y + w->h)
/* M7.0a 缺口#2:IconButton 按圆形命中(角部按下不点亮圆钮);其余按矩形。 */
if (w->type == W_ICONBTN) {
if (iconbtn_circular_hit(w, x, y)) r = w;
} else if (x >= w->x && x < w->x + w->w && y >= w->y && y < w->y + w->h) {
r = w; /* 越后创建越上:保留最后命中 */
}
}
return r;
}
@@ -540,6 +558,20 @@ int meow_btn_set_variant(meow_widget *w, int variant)
return 0;
}
/* ---- §5.8.6 M7.0a 缺口#2:IconButton(圆形/位图图标按钮)---- */
meow_widget *meow_iconbtn_create(int x, int y, int size, int icon_idx)
{
meow_widget *t = (meow_widget *)calloc(1, sizeof *t);
if (!t) return NULL;
t->type = W_ICONBTN; t->x = x; t->y = y; t->w = size; t->h = size;
t->owner = meow_ui_activity_active(); /* §6.1 ①:同既有控件绑当前 active Activity */
t->state = MEOW_WS_ENABLED;
t->icon_id = icon_idx;
live_btn_register(t); /* 实时按压/按住即时重绘(同 meow_btn,agent-119) */
meow_draw_widget_register(t); /* §6.2 自动注册(创建即注册,App 零调用) */
return t;
}
/* ---- TextField ---- */
meow_widget *meow_textfield_create(int x, int y, int w, int h, const char *placeholder,
char *buf, int maxlen, meow_ime_mode mode)
@@ -1374,9 +1406,11 @@ int meow_widget_hit(meow_widget *w, int x, int y)
if (w->owner != meow_ui_activity_active()) return 0;
/* §5.8.3:禁用不响应命中(也不进 pressed)。 */
if (widget_disabled(w)) return 0;
/* §5.8.1:自定义画布用 App 回调判定命中(可非矩形);其余矩形内含。 */
/* §5.8.1:自定义画布用 App 回调判定命中(可非矩形);IconButton 圆形命中;其余矩形内含。 */
if (w->type == W_CUSTOM)
return w->hit_cb ? w->hit_cb(w, x, y, w->ctx) : hit(w, x, y);
if (w->type == W_ICONBTN)
return iconbtn_circular_hit(w, x, y);
return hit(w, x, y);
}
int meow_btn_pressed(meow_widget *w)
@@ -1480,6 +1514,35 @@ void meow_widget_draw(meow_widget *w)
if (disabled) meow_gfx_fill_round_alpha(w->x, w->y, w->w, w->h, r, th->onSurface, 90);
break;
}
case W_ICONBTN: {
/* M7.0a 缺口#2:圆形底 + 位图图标 + 按压/按住状态层(实时)。
* 按压三路来源(同 meow_btn,agent-119):状态机 MEOW_WS_PRESSED / 实时触摸命中 /
* 位图取自 sb_icons[](meow_gfx_blit_icon_ink,只写像素不标顶栏脏区——控件矩形由
* 本 draw 的 clip + invalidation 管理);图标墨色 onSurface,选中/按住淡向底。 */
int live = meow_input_touch_down() &&
iconbtn_circular_hit(w, meow_input_touch_x(), meow_input_touch_y());
int press = (w->state & MEOW_WS_PRESSED) || live;
int hold = live && meow_input_touch_hold_ms() >= (unsigned)meow_ui_long_press_ms();
int disabled = widget_disabled(w);
if (disabled) press = 0;
int cx = w->x + w->w / 2, cy = w->y + w->h / 2;
int r = (w->w < w->h ? w->w : w->h) / 2;
int inkh = (w->h * 6) / 10; /* MD3 图标比:约 24/40 → 0.6*size */
if (inkh < 8) inkh = (w->h > 0) ? w->h : 8;
int selected = (w->state & MEOW_WS_SELECTED);
uint32_t base = selected ? th->primaryContainer : widget_bg(w, th, th->surfaceContainerLow);
uint32_t fgc = selected ? th->onPrimaryContainer : widget_fg(w, th, th->onSurface);
uint32_t bg = (hold) ? state_tint(base, th, 24)
: (press ? state_tint(base, th, 12) : base);
if (disabled) bg = state_tint(base, th, 38); /* 禁用变淡(圆形底直接变灰) */
if (w->state & MEOW_WS_FOCUSED) bg = state_tint(base, th, 8); /* 焦点浅提亮 */
meow_gfx_fill_circle(cx, cy, r, bg);
if (w->icon_id >= 0)
meow_gfx_blit_icon_ink(w->icon_id, cx - MEOW_SB_ICON_SIZE / 2, inkh, fgc, cy);
if (w->state & MEOW_WS_FOCUSED)
meow_gfx_ring_arc(cx, cy, r - 1, 2, 0, 360, th->primary); /* 焦点圆形描边 */
break;
}
case W_SLIDER: {
/* 语义色:轨道=onSurfaceVariant(dim)、填充=primary(accent)、滑块=fg(onSurface)。 */
int trace_y = w->y + w->h / 2 - 3;