887 lines
37 KiB
C
887 lines
37 KiB
C
/* pages.c — KATE 风格页面绘制(M0 自 main.c 平移)
|
||||
|
|
*
|
|||
|
|
* 包含:topbar / DASHBOARD / StatusBar / IDE / DESKTOP(含旧任务栏) /
|
|||
|
|
* CUSTOM / 任务视图 / 右键菜单。M2-M4 将按 Fluent 计划逐页替换:
|
|||
|
|
* topbar→删除、DASHBOARD→小组件、DESKTOP 任务栏→悬浮任务栏。
|
|||
|
|
*/
|
|||
|
|
#include "desktop.h"
|
|||
|
|
#include "zhfont.h" /* M2: 桌面图标中文标签 */
|
|||
|
|
|
|||
|
|
/* ============================================================
|
|||
|
|
* 顶栏(brand + WorkspaceSwitcher + PageSwitcher + PG 时钟)
|
|||
|
|
* ============================================================ */
|
|||
|
|
|
|||
|
|
void draw_topbar(void) {
|
|||
|
|
int W = (int)g_fb_w;
|
|||
|
|
du_fill_rect_gradient(&g_fb, 0, 0, W, KATE_TOPBAR_H,
|
|||
|
|
0xFF0A2840u, KS_BG_PRIMARY);
|
|||
|
|
du_divider_h(&g_fb, 0, KATE_TOPBAR_H, W, KS_BORDER);
|
|||
|
|
|
|||
|
|
int x = 12;
|
|||
|
|
int ty = (KATE_TOPBAR_H - (int)DU_ASCII_LINE_H) / 2 + 1;
|
|||
|
|
|
|||
|
|
/* brand:方块点 + DESHAB + brand-credit(对应 Kate "由 Deaicup 工作室制作") */
|
|||
|
|
du_fill_rect(&g_fb, x, KATE_TOPBAR_H / 2 - 3, 6, 6, KS_ACCENT);
|
|||
|
|
du_draw_string(&g_fb, "DESHAB", x + 12, ty, KS_ACCENT, 0, DU_ASCII_STEP + 2);
|
|||
|
|
x += 12 + 6 * ((int)DU_ASCII_STEP + 2) + 10;
|
|||
|
|
du_draw_string(&g_fb, "DEAICUP STUDIO", x, ty + 2, KS_ACCENT2, 0, DU_ASCII_STEP);
|
|||
|
|
x += 14 * (int)DU_ASCII_STEP + 14;
|
|||
|
|
|
|||
|
|
/* 分隔线 + 任务视图按钮(三横线图标) */
|
|||
|
|
du_divider_v(&g_fb, x - 6, 6, KATE_TOPBAR_H - 12, KS_BORDER);
|
|||
|
|
g_tvbtn_rect[0] = x; g_tvbtn_rect[1] = 5;
|
|||
|
|
g_tvbtn_rect[2] = 28; g_tvbtn_rect[3] = 24;
|
|||
|
|
{
|
|||
|
|
int hover = g_mouse_x >= x && g_mouse_x < x + 28 &&
|
|||
|
|
g_mouse_y >= 5 && g_mouse_y < 29;
|
|||
|
|
if (hover) du_fill_rect(&g_fb, x, 5, 28, 24, KS_ACCENT_DIM);
|
|||
|
|
du_rect_outline(&g_fb, x, 5, 28, 24, KS_BORDER, 1);
|
|||
|
|
du_fill_rect(&g_fb, x + 6, 11, 16, 2, KS_ACCENT);
|
|||
|
|
du_fill_rect(&g_fb, x + 6, 16, 16, 2, KS_ACCENT);
|
|||
|
|
du_fill_rect(&g_fb, x + 6, 21, 16, 2, KS_ACCENT);
|
|||
|
|
}
|
|||
|
|
x += 34;
|
|||
|
|
|
|||
|
|
/* 工作区按钮 "name|n" */
|
|||
|
|
for (int i = 0; i < g_ws_count; i++) {
|
|||
|
|
char label[24];
|
|||
|
|
kstrcpy(label, g_ws[i].name, 18);
|
|||
|
|
kstrcat(label, "|", 24);
|
|||
|
|
int cnt = ws_win_count(i);
|
|||
|
|
char cn[4];
|
|||
|
|
cn[0] = '0' + (char)(cnt % 10); cn[1] = 0;
|
|||
|
|
kstrcat(label, cn, 24);
|
|||
|
|
int bw = kstrlen(label) * (int)DU_ASCII_STEP + 16;
|
|||
|
|
int active = (i == g_ws_cur);
|
|||
|
|
int hover = g_mouse_x >= x && g_mouse_x < x + bw &&
|
|||
|
|
g_mouse_y >= 5 && g_mouse_y < 29;
|
|||
|
|
if (active) {
|
|||
|
|
du_fill_rect(&g_fb, x, 5, bw, 24, KS_ACCENT2);
|
|||
|
|
du_kate_glow_border(&g_fb, x, 5, bw, 24, KS_ACCENT2);
|
|||
|
|
} else if (hover) {
|
|||
|
|
du_fill_rect(&g_fb, x, 5, bw, 24, KS_ACCENT_DIM);
|
|||
|
|
}
|
|||
|
|
du_rect_outline(&g_fb, x, 5, bw, 24, active ? KS_ACCENT2 : KS_BORDER, 1);
|
|||
|
|
du_draw_string(&g_fb, label, x + 8, ty,
|
|||
|
|
active ? KS_TEXT_INVERT : KS_TEXT_DIM, 0, DU_ASCII_STEP);
|
|||
|
|
g_ws_rect[i][0] = x; g_ws_rect[i][1] = 5;
|
|||
|
|
g_ws_rect[i][2] = bw; g_ws_rect[i][3] = 24;
|
|||
|
|
x += bw + 6;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* ws-add "+" */
|
|||
|
|
g_wsadd_rect[0] = x; g_wsadd_rect[1] = 5;
|
|||
|
|
g_wsadd_rect[2] = 26; g_wsadd_rect[3] = 24;
|
|||
|
|
{
|
|||
|
|
int hover = g_mouse_x >= x && g_mouse_x < x + 26 &&
|
|||
|
|
g_mouse_y >= 5 && g_mouse_y < 29;
|
|||
|
|
if (hover) du_fill_rect(&g_fb, x, 5, 26, 24, KS_ACCENT_DIM);
|
|||
|
|
du_rect_outline(&g_fb, x, 5, 26, 24, KS_ACCENT2, 1);
|
|||
|
|
du_draw_string(&g_fb, "+", x + 7, ty - 1, KS_ACCENT2, 0, DU_ASCII_STEP);
|
|||
|
|
}
|
|||
|
|
x += 32;
|
|||
|
|
|
|||
|
|
/* 分隔线 */
|
|||
|
|
du_divider_v(&g_fb, x - 4, 6, KATE_TOPBAR_H - 12, KS_BORDER);
|
|||
|
|
x += 4;
|
|||
|
|
|
|||
|
|
/* 页面切换:精简按钮文字 */
|
|||
|
|
static const char *pg_names[3] = { "DASH", "IDE", "DESK" };
|
|||
|
|
for (int i = 0; i < 3; i++) {
|
|||
|
|
int bw = kstrlen(pg_names[i]) * (int)DU_ASCII_STEP + 24;
|
|||
|
|
int active = (g_page == i + 1);
|
|||
|
|
int hover = g_mouse_x >= x && g_mouse_x < x + bw &&
|
|||
|
|
g_mouse_y >= 5 && g_mouse_y < 29;
|
|||
|
|
if (active) {
|
|||
|
|
du_fill_rect(&g_fb, x, 5, bw, 24, KS_ACCENT);
|
|||
|
|
du_kate_glow_border(&g_fb, x, 5, bw, 24, KS_ACCENT);
|
|||
|
|
} else if (hover) {
|
|||
|
|
du_fill_rect(&g_fb, x, 5, bw, 24, KS_ACCENT_DIM);
|
|||
|
|
}
|
|||
|
|
du_rect_outline(&g_fb, x, 5, bw, 24, active ? KS_ACCENT : KS_BORDER, 1);
|
|||
|
|
du_draw_string(&g_fb, pg_names[i], x + 12, ty,
|
|||
|
|
active ? KS_TEXT_INVERT : KS_TEXT_DIM, 0, DU_ASCII_STEP);
|
|||
|
|
g_pg_rect[i][0] = x; g_pg_rect[i][1] = 5;
|
|||
|
|
g_pg_rect[i][2] = bw; g_pg_rect[i][3] = 24;
|
|||
|
|
x += bw + 8;
|
|||
|
|
}
|
|||
|
|
/* 自定义页 */
|
|||
|
|
for (int i = 0; i < g_cpage_count; i++) {
|
|||
|
|
char label[20];
|
|||
|
|
label[0] = '0' + (char)g_cpages[i].id;
|
|||
|
|
label[1] = '.'; label[2] = 0;
|
|||
|
|
kstrcat(label, g_cpages[i].name, 20);
|
|||
|
|
int bw = kstrlen(label) * (int)DU_ASCII_STEP + 28;
|
|||
|
|
int active = (g_page == g_cpages[i].id);
|
|||
|
|
int hover = g_mouse_x >= x && g_mouse_x < x + bw &&
|
|||
|
|
g_mouse_y >= 5 && g_mouse_y < 29;
|
|||
|
|
if (active) {
|
|||
|
|
du_fill_rect(&g_fb, x, 5, bw, 24, KS_ACCENT);
|
|||
|
|
} else if (hover) {
|
|||
|
|
du_fill_rect(&g_fb, x, 5, bw, 24, KS_ACCENT_DIM);
|
|||
|
|
}
|
|||
|
|
du_rect_outline(&g_fb, x, 5, bw, 24, active ? KS_ACCENT : KS_BORDER, 1);
|
|||
|
|
du_draw_string(&g_fb, label, x + 6, ty,
|
|||
|
|
active ? KS_TEXT_INVERT : KS_TEXT_DIM, 0, DU_ASCII_STEP);
|
|||
|
|
du_draw_string(&g_fb, "x", x + bw - 14, ty, KS_DANGER, 0, DU_ASCII_STEP);
|
|||
|
|
g_pg_rect[3 + i][0] = x; g_pg_rect[3 + i][1] = 5;
|
|||
|
|
g_pg_rect[3 + i][2] = bw; g_pg_rect[3 + i][3] = 24;
|
|||
|
|
g_pg_rm_rect[3 + i][0] = x + bw - 20; g_pg_rm_rect[3 + i][1] = 5;
|
|||
|
|
g_pg_rm_rect[3 + i][2] = 20; g_pg_rm_rect[3 + i][3] = 24;
|
|||
|
|
x += bw + 6;
|
|||
|
|
}
|
|||
|
|
/* pg-add "+" */
|
|||
|
|
if (g_cpage_count < MAX_CPAGES) {
|
|||
|
|
g_pgadd_rect[0] = x; g_pgadd_rect[1] = 5;
|
|||
|
|
g_pgadd_rect[2] = 26; g_pgadd_rect[3] = 24;
|
|||
|
|
int hover = g_mouse_x >= x && g_mouse_x < x + 26 &&
|
|||
|
|
g_mouse_y >= 5 && g_mouse_y < 29;
|
|||
|
|
if (hover) du_fill_rect(&g_fb, x, 5, 26, 24, KS_ACCENT_DIM);
|
|||
|
|
du_rect_outline(&g_fb, x, 5, 26, 24, KS_ACCENT2, 1);
|
|||
|
|
du_draw_string(&g_fb, "+", x + 7, ty - 1, KS_ACCENT2, 0, DU_ASCII_STEP);
|
|||
|
|
} else {
|
|||
|
|
g_pgadd_rect[2] = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 右侧:credit-top + PG 时钟(对应 Kate "© Deaicup Studio" + "PG n") */
|
|||
|
|
char pgclk[8];
|
|||
|
|
pgclk[0] = 'P'; pgclk[1] = 'G'; pgclk[2] = ' ';
|
|||
|
|
pgclk[3] = '0' + (char)(g_page % 10); pgclk[4] = 0;
|
|||
|
|
const char *credit = "(C) DEAICUP STUDIO";
|
|||
|
|
int cl = kstrlen(credit) + 1 + kstrlen(pgclk);
|
|||
|
|
du_draw_string(&g_fb, credit, W - 12 - cl * (int)DU_ASCII_STEP, ty,
|
|||
|
|
KS_TEXT_DIM, 0, DU_ASCII_STEP);
|
|||
|
|
du_draw_string(&g_fb, pgclk, W - 12 - kstrlen(pgclk) * (int)DU_ASCII_STEP, ty,
|
|||
|
|
KS_ACCENT2, 0, DU_ASCII_STEP);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* ============================================================
|
|||
|
|
* 滑块(VOL / BRIGHT)
|
|||
|
|
* ============================================================ */
|
|||
|
|
|
|||
|
|
static void draw_slider(int x, int y, int w, int val, int rect_out[4]) {
|
|||
|
|
du_fill_rect(&g_fb, x, y + 5, w, 3, KS_BG_TERTIARY);
|
|||
|
|
du_rect_outline(&g_fb, x, y + 4, w, 5, KS_BORDER, 1);
|
|||
|
|
int fw = w * val / 100;
|
|||
|
|
if (fw > 0) du_fill_rect(&g_fb, x, y + 5, fw, 3, KS_ACCENT);
|
|||
|
|
int kx = x + fw - 3;
|
|||
|
|
if (kx < x) kx = x;
|
|||
|
|
if (kx > x + w - 6) kx = x + w - 6;
|
|||
|
|
du_fill_rect(&g_fb, kx, y, 6, 13, KS_ACCENT);
|
|||
|
|
du_rect_outline(&g_fb, kx, y, 6, 13, KS_ACCENT, 1);
|
|||
|
|
rect_out[0] = x; rect_out[1] = y - 2;
|
|||
|
|
rect_out[2] = w; rect_out[3] = 17;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* ============================================================
|
|||
|
|
* 状态栏(DASHBOARD 底部 32px)
|
|||
|
|
* ============================================================ */
|
|||
|
|
|
|||
|
|
static void draw_statusbar_full(void) {
|
|||
|
|
int W = (int)g_fb_w;
|
|||
|
|
int y = (int)g_fb_h - KATE_STATUSBAR_H;
|
|||
|
|
du_fill_rect(&g_fb, 0, y, W, KATE_STATUSBAR_H, 0xFF051828u);
|
|||
|
|
du_divider_h(&g_fb, 0, y, W, KS_BORDER);
|
|||
|
|
|
|||
|
|
int x = 12;
|
|||
|
|
int ty = y + (KATE_STATUSBAR_H - (int)DU_ASCII_LINE_H) / 2 + 1;
|
|||
|
|
|
|||
|
|
/* 时钟(日期 · 秒级时间,accent2) */
|
|||
|
|
int yy, mo, dd, hh, mi, ss;
|
|||
|
|
rtc_read(&yy, &mo, &dd, &hh, &mi, &ss);
|
|||
|
|
char clk[32];
|
|||
|
|
int cp2 = 0;
|
|||
|
|
clk[cp2++] = '2'; clk[cp2++] = '0';
|
|||
|
|
clk[cp2++] = '0' + (char)(yy / 10); clk[cp2++] = '0' + (char)(yy % 10);
|
|||
|
|
clk[cp2++] = '-';
|
|||
|
|
clk[cp2++] = '0' + (char)(mo / 10); clk[cp2++] = '0' + (char)(mo % 10);
|
|||
|
|
clk[cp2++] = '-';
|
|||
|
|
clk[cp2++] = '0' + (char)(dd / 10); clk[cp2++] = '0' + (char)(dd % 10);
|
|||
|
|
clk[cp2++] = ' '; clk[cp2++] = '.'; clk[cp2++] = ' ';
|
|||
|
|
char hms[9];
|
|||
|
|
fmt_hms(hms, hh * 3600 + mi * 60 + ss);
|
|||
|
|
for (int i = 0; hms[i]; i++) clk[cp2++] = hms[i];
|
|||
|
|
clk[cp2] = 0;
|
|||
|
|
du_draw_string(&g_fb, clk, x, ty, KS_ACCENT2, 0, DU_ASCII_STEP);
|
|||
|
|
x += cp2 * (int)DU_ASCII_STEP + 18;
|
|||
|
|
|
|||
|
|
/* UP 计时 */
|
|||
|
|
{
|
|||
|
|
int up = hh * 3600 + mi * 60 + ss - g_rtc_boot_sec;
|
|||
|
|
if (up < 0) up += 86400;
|
|||
|
|
char upb[16];
|
|||
|
|
kstrcpy(upb, "UP ", 16);
|
|||
|
|
char uh[9];
|
|||
|
|
fmt_hms(uh, up);
|
|||
|
|
kstrcat(upb, uh, 16);
|
|||
|
|
du_draw_string(&g_fb, upb, x, ty, KS_TEXT_DIM, 0, DU_ASCII_STEP);
|
|||
|
|
x += kstrlen(upb) * (int)DU_ASCII_STEP + 18;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* VOL 滑块 */
|
|||
|
|
du_draw_string(&g_fb, "VOL", x, ty, KS_TEXT_DIM, 0, DU_ASCII_STEP);
|
|||
|
|
x += 3 * (int)DU_ASCII_STEP + 6;
|
|||
|
|
draw_slider(x, y + 9, 90, g_vol, g_vol_rect);
|
|||
|
|
x += 90 + 8;
|
|||
|
|
{
|
|||
|
|
char vb[6];
|
|||
|
|
vb[0] = '0' + (char)(g_vol / 100 % 10);
|
|||
|
|
vb[1] = '0' + (char)(g_vol / 10 % 10);
|
|||
|
|
vb[2] = '0' + (char)(g_vol % 10);
|
|||
|
|
vb[3] = '%'; vb[4] = 0;
|
|||
|
|
const char *vp = (g_vol >= 100) ? vb : (g_vol >= 10 ? vb + 1 : vb + 2);
|
|||
|
|
du_draw_string(&g_fb, vp, x, ty, KS_ACCENT2, 0, DU_ASCII_STEP);
|
|||
|
|
x += 4 * (int)DU_ASCII_STEP + 14;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* BRIGHT 滑块 */
|
|||
|
|
du_draw_string(&g_fb, "BRIGHT", x, ty, KS_TEXT_DIM, 0, DU_ASCII_STEP);
|
|||
|
|
x += 6 * (int)DU_ASCII_STEP + 6;
|
|||
|
|
draw_slider(x, y + 9, 90, g_bright, g_bri_rect);
|
|||
|
|
x += 90 + 8;
|
|||
|
|
{
|
|||
|
|
char vb[6];
|
|||
|
|
vb[0] = '0' + (char)(g_bright / 100 % 10);
|
|||
|
|
vb[1] = '0' + (char)(g_bright / 10 % 10);
|
|||
|
|
vb[2] = '0' + (char)(g_bright % 10);
|
|||
|
|
vb[3] = '%'; vb[4] = 0;
|
|||
|
|
const char *vp = (g_bright >= 100) ? vb : (g_bright >= 10 ? vb + 1 : vb + 2);
|
|||
|
|
du_draw_string(&g_fb, vp, x, ty, KS_ACCENT2, 0, DU_ASCII_STEP);
|
|||
|
|
x += 4 * (int)DU_ASCII_STEP + 14;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* BT / WIFI */
|
|||
|
|
du_draw_string(&g_fb, "BT OFF", x, ty, KS_TEXT_DIM, 0, DU_ASCII_STEP);
|
|||
|
|
x += 6 * (int)DU_ASCII_STEP + 14;
|
|||
|
|
du_draw_string(&g_fb, "WIFI --", x, ty, KS_TEXT_DIM, 0, DU_ASCII_STEP);
|
|||
|
|
|
|||
|
|
/* 右侧 hint */
|
|||
|
|
const char *hint = "Ctrl+Tab PAGE";
|
|||
|
|
du_draw_string(&g_fb, hint, W - 12 - kstrlen(hint) * (int)DU_ASCII_STEP, ty,
|
|||
|
|
KS_TEXT_DIM, 0, DU_ASCII_STEP);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* ============================================================
|
|||
|
|
* 页面绘制
|
|||
|
|
* ============================================================ */
|
|||
|
|
|
|||
|
|
static void draw_desktop_icons(void) {
|
|||
|
|
/* desktop-empty(Kate:无快捷方式提示) */
|
|||
|
|
if (g_icon_count == 0) {
|
|||
|
|
zh_draw_string(&g_fb, "桌面无快捷方式",
|
|||
|
|
KATE_ICON_PAD, KATE_TOPBAR_H + KATE_PAGE_PAD + KATE_ICON_PAD + 16,
|
|||
|
|
KS_TEXT_DIM, 0);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
for (int i = 0; i < g_icon_count; i++) {
|
|||
|
|
desktop_icon *ic = &g_icons[i];
|
|||
|
|
if (g_fluent) {
|
|||
|
|
/* M2 Fluent:图标 + 中文标签(zh 字库,缺失自动回退 ASCII) */
|
|||
|
|
du_kate_desktop_icon(&g_fb, ic->x, ic->y, "", ic->selected);
|
|||
|
|
int ix = ic->x + (KATE_ICON_W - KATE_ICON_IMG) / 2;
|
|||
|
|
int iy = ic->y + 10;
|
|||
|
|
draw_app_icon(&g_fb, ic->app_id, ix, iy);
|
|||
|
|
int lw = zh_string_width(ic->label, 0);
|
|||
|
|
zh_draw_string(&g_fb, ic->label,
|
|||
|
|
ic->x + (KATE_ICON_W - lw) / 2,
|
|||
|
|
ic->y + KATE_ICON_IMG + 16,
|
|||
|
|
ic->selected ? 0xFFFFFFFFu : 0xFFE8E8E8u, 0);
|
|||
|
|
} else {
|
|||
|
|
du_kate_desktop_icon(&g_fb, ic->x, ic->y, ic->label, ic->selected);
|
|||
|
|
int ix = ic->x + (KATE_ICON_W - KATE_ICON_IMG) / 2;
|
|||
|
|
int iy = ic->y + 10;
|
|||
|
|
draw_app_icon(&g_fb, ic->app_id, ix, iy);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* ---- 1·DASHBOARD ---- */
|
|||
|
|
static void dash_layout(void) {
|
|||
|
|
int top = KATE_TOPBAR_H, bot = (int)g_fb_h - KATE_STATUSBAR_H;
|
|||
|
|
int pad = 8, gap = 8;
|
|||
|
|
int avail_w = (int)g_fb_w - 2 * pad;
|
|||
|
|
int avail_h = bot - top - 2 * pad;
|
|||
|
|
int left_w = avail_w * 35 / 100; /* 终端面板:42%→35% */
|
|||
|
|
int right_x = pad + left_w + gap;
|
|||
|
|
int right_w = (int)g_fb_w - pad - right_x;
|
|||
|
|
int row_h = (avail_h - gap) / 2;
|
|||
|
|
|
|||
|
|
g_dash_rect[0][0] = pad; g_dash_rect[0][1] = top + pad;
|
|||
|
|
g_dash_rect[0][2] = left_w; g_dash_rect[0][3] = row_h;
|
|||
|
|
g_dash_rect[1][0] = pad; g_dash_rect[1][1] = top + pad + row_h + gap;
|
|||
|
|
g_dash_rect[1][2] = left_w; g_dash_rect[1][3] = row_h;
|
|||
|
|
g_dash_rect[2][0] = right_x; g_dash_rect[2][1] = top + pad;
|
|||
|
|
g_dash_rect[2][2] = right_w; g_dash_rect[2][3] = row_h;
|
|||
|
|
g_dash_rect[3][0] = right_x; g_dash_rect[3][1] = top + pad + row_h + gap;
|
|||
|
|
g_dash_rect[3][2] = right_w; g_dash_rect[3][3] = row_h;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void draw_dashboard(void) {
|
|||
|
|
dash_layout();
|
|||
|
|
const char *headers[4] = { "TERM-01", "TERM-02", 0, "FILES" };
|
|||
|
|
char ed_hdr[40];
|
|||
|
|
editor_state *ed = (editor_state *)ADDR_EDDASH;
|
|||
|
|
kstrcpy(ed_hdr, "EDITOR . ", 40);
|
|||
|
|
kstrcat(ed_hdr, ed->has_file ? ed->disp : "untitled", 40);
|
|||
|
|
headers[2] = ed_hdr;
|
|||
|
|
|
|||
|
|
for (int i = 0; i < 4; i++) {
|
|||
|
|
int x = g_dash_rect[i][0], y = g_dash_rect[i][1];
|
|||
|
|
int w = g_dash_rect[i][2], h = g_dash_rect[i][3];
|
|||
|
|
du_kate_panel(&g_fb, x, y, w, h, headers[i]);
|
|||
|
|
if (g_dash_focus == i) {
|
|||
|
|
du_rect_outline(&g_fb, x, y, w, h, KS_ACCENT, 2);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* EDITOR 头 SAVE 按钮(仅关联文件后可用) */
|
|||
|
|
{
|
|||
|
|
int ex = g_dash_rect[2][0], ey = g_dash_rect[2][1], ew = g_dash_rect[2][2];
|
|||
|
|
int bw = 52, bh = 18;
|
|||
|
|
int bx = ex + ew - bw - 6, by = ey + 3;
|
|||
|
|
g_save_rect[0] = bx; g_save_rect[1] = by;
|
|||
|
|
g_save_rect[2] = bw; g_save_rect[3] = bh;
|
|||
|
|
u32 fg = ed->has_file ? KS_ACCENT : KS_TEXT_DIM;
|
|||
|
|
int hover = ed->has_file &&
|
|||
|
|
g_mouse_x >= bx && g_mouse_x < bx + bw &&
|
|||
|
|
g_mouse_y >= by && g_mouse_y < by + bh;
|
|||
|
|
if (hover) du_fill_rect(&g_fb, bx, by, bw, bh, KS_ACCENT_DIM);
|
|||
|
|
du_rect_outline(&g_fb, bx, by, bw, bh, ed->has_file ? KS_BORDER : KS_BORDER_DIM, 1);
|
|||
|
|
du_draw_string(&g_fb, "SAVE", bx + 5, by + 1, fg, 0, DU_ASCII_STEP);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 面板内容 */
|
|||
|
|
bash_draw_to((bash_state *)ADDR_TERM1,
|
|||
|
|
g_dash_rect[0][0] + 2, g_dash_rect[0][1] + KATE_PANEL_HEADER_H + 2,
|
|||
|
|
g_dash_rect[0][2] - 4, g_dash_rect[0][3] - KATE_PANEL_HEADER_H - 4);
|
|||
|
|
|
|||
|
|
bash_draw_to((bash_state *)ADDR_TERM2,
|
|||
|
|
g_dash_rect[1][0] + 2, g_dash_rect[1][1] + KATE_PANEL_HEADER_H + 2,
|
|||
|
|
g_dash_rect[1][2] - 4, g_dash_rect[1][3] - KATE_PANEL_HEADER_H - 4);
|
|||
|
|
|
|||
|
|
editor_draw_to(ed,
|
|||
|
|
g_dash_rect[2][0] + 2, g_dash_rect[2][1] + KATE_PANEL_HEADER_H + 2,
|
|||
|
|
g_dash_rect[2][2] - 4, g_dash_rect[2][3] - KATE_PANEL_HEADER_H - 4);
|
|||
|
|
|
|||
|
|
/* FILES 面板内容 */
|
|||
|
|
{
|
|||
|
|
int fx = g_dash_rect[3][0] + 2, fy = g_dash_rect[3][1] + KATE_PANEL_HEADER_H + 2;
|
|||
|
|
int fw = g_dash_rect[3][2] - 4, fh = g_dash_rect[3][3] - KATE_PANEL_HEADER_H - 4;
|
|||
|
|
du_fill_rect(&g_fb, fx, fy, fw, fh, KS_BG_PRIMARY);
|
|||
|
|
|
|||
|
|
char path_buf[32];
|
|||
|
|
kstrcpy(path_buf, "FAT32:/USER (", 32);
|
|||
|
|
int pl = kstrlen(path_buf);
|
|||
|
|
if (g_file_count >= 10) path_buf[pl++] = '0' + (char)(g_file_count / 10);
|
|||
|
|
path_buf[pl++] = '0' + (char)(g_file_count % 10);
|
|||
|
|
path_buf[pl++] = ')'; path_buf[pl] = 0;
|
|||
|
|
du_draw_string(&g_fb, path_buf, fx + 8, fy + 3, KS_ACCENT, KS_BG_PRIMARY, DU_ASCII_STEP);
|
|||
|
|
du_divider_h(&g_fb, fx, fy + 22, fw, KS_BORDER);
|
|||
|
|
|
|||
|
|
int row_h = 22;
|
|||
|
|
int max_rows = (fh - 24) / row_h;
|
|||
|
|
for (int i = 0; i < g_file_count && i < max_rows; i++) {
|
|||
|
|
int ry = fy + 24 + i * row_h;
|
|||
|
|
if (i == g_file_sel) {
|
|||
|
|
du_fill_rect(&g_fb, fx, ry, fw, row_h, KS_ACCENT_DIM);
|
|||
|
|
}
|
|||
|
|
int hover = (g_mouse_x >= fx && g_mouse_x < fx + fw &&
|
|||
|
|
g_mouse_y >= ry && g_mouse_y < ry + row_h);
|
|||
|
|
if (hover && i != g_file_sel) {
|
|||
|
|
du_fill_rect(&g_fb, fx, ry, fw, row_h, KS_ACCENT_DIM);
|
|||
|
|
}
|
|||
|
|
u32 fg = (i == g_file_sel) ? KS_ACCENT : KS_TEXT_PRIMARY;
|
|||
|
|
du_draw_string(&g_fb, g_files[i].disp, fx + 8, ry + 2, fg, 0, DU_ASCII_STEP);
|
|||
|
|
char sz[12];
|
|||
|
|
u32 kb = g_files[i].size / 1024;
|
|||
|
|
int sp = 0;
|
|||
|
|
if (kb >= 100) { sz[sp++] = '0' + (char)(kb / 100 % 10); }
|
|||
|
|
if (kb >= 10) { sz[sp++] = '0' + (char)(kb / 10 % 10); }
|
|||
|
|
sz[sp++] = '0' + (char)(kb % 10);
|
|||
|
|
sz[sp++] = 'K'; sz[sp] = 0;
|
|||
|
|
du_draw_string(&g_fb, sz, fx + fw - sp * (int)DU_ASCII_STEP - 8, ry + 2,
|
|||
|
|
KS_TEXT_DIM, 0, DU_ASCII_STEP);
|
|||
|
|
}
|
|||
|
|
if (!g_files_loaded) {
|
|||
|
|
du_draw_string(&g_fb, "NO BLOCK DEVICE", fx + 8, fy + 28,
|
|||
|
|
KS_DANGER, KS_BG_PRIMARY, DU_ASCII_STEP);
|
|||
|
|
} else if (g_file_count == 0) {
|
|||
|
|
du_draw_string(&g_fb, "(empty)", fx + 8, fy + 28,
|
|||
|
|
KS_TEXT_DIM, KS_BG_PRIMARY, DU_ASCII_STEP);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
draw_statusbar_full();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* ---- 2·IDE ---- */
|
|||
|
|
void draw_ide(void) {
|
|||
|
|
int W = (int)g_fb_w;
|
|||
|
|
int top = KATE_TOPBAR_H;
|
|||
|
|
|
|||
|
|
/* ide-tabs(36px):dot + 实例标签 + "+ NEW IDE" + ide-hint(Kate 结构) */
|
|||
|
|
du_fill_rect(&g_fb, 0, top, W, 36, 0xFF051828u);
|
|||
|
|
du_divider_h(&g_fb, 0, top + 36, W, KS_BORDER);
|
|||
|
|
int x = 12;
|
|||
|
|
int ty = top + (36 - (int)DU_ASCII_LINE_H) / 2 + 1;
|
|||
|
|
|
|||
|
|
/* .dot(8×8 accent2 发光点) */
|
|||
|
|
du_fill_rect(&g_fb, x, top + 14, 8, 8, KS_ACCENT2);
|
|||
|
|
x += 16;
|
|||
|
|
|
|||
|
|
/* 实例标签(Kate .ide-tab):P7.4 动态标签 = 最近启动实例 DISPLAY 名 */
|
|||
|
|
{
|
|||
|
|
const char *label = g_ide_tab_label;
|
|||
|
|
int bw = kstrlen(label) * (int)DU_ASCII_STEP + 32;
|
|||
|
|
if (g_ide_attached) {
|
|||
|
|
du_fill_rect(&g_fb, x, top + 5, bw, 26, KS_ACCENT);
|
|||
|
|
du_kate_glow_border(&g_fb, x, top + 5, bw, 26, KS_ACCENT);
|
|||
|
|
}
|
|||
|
|
du_rect_outline(&g_fb, x, top + 5, bw, 26,
|
|||
|
|
g_ide_attached ? KS_ACCENT : KS_BORDER, 1);
|
|||
|
|
du_draw_string(&g_fb, label, x + 8, ty,
|
|||
|
|
g_ide_attached ? KS_TEXT_INVERT : KS_TEXT_DIM, 0, DU_ASCII_STEP);
|
|||
|
|
du_draw_string(&g_fb, "x", x + bw - 14, ty, KS_DANGER, 0, DU_ASCII_STEP);
|
|||
|
|
g_ide_tabx[0] = x + bw - 20; g_ide_tabx[1] = top + 5;
|
|||
|
|
g_ide_tabx[2] = 20; g_ide_tabx[3] = 26;
|
|||
|
|
x += bw + 8;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* "+ NEW IDE" 按钮(Kate .btn,透明底 + 边框 + accent 字) */
|
|||
|
|
{
|
|||
|
|
const char *nb = "+ NEW IDE";
|
|||
|
|
int bw = kstrlen(nb) * (int)DU_ASCII_STEP + 20;
|
|||
|
|
g_ide_new_rect[0] = x; g_ide_new_rect[1] = top + 7;
|
|||
|
|
g_ide_new_rect[2] = bw; g_ide_new_rect[3] = 22;
|
|||
|
|
int hover = g_mouse_x >= x && g_mouse_x < x + bw &&
|
|||
|
|
g_mouse_y >= top + 7 && g_mouse_y < top + 29;
|
|||
|
|
if (hover) du_fill_rect(&g_fb, x, top + 7, bw, 22, KS_ACCENT_DIM);
|
|||
|
|
du_rect_outline(&g_fb, x, top + 7, bw, 22, KS_BORDER, 1);
|
|||
|
|
du_draw_string(&g_fb, nb, x + 10, ty, KS_ACCENT, 0, DU_ASCII_STEP);
|
|||
|
|
x += bw + 8;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* ide-hint */
|
|||
|
|
du_draw_string(&g_fb, "CTRL+SHIFT+TAB CTX . x DETACH . DBL-CLICK HOST ATTACH",
|
|||
|
|
x + 8, ty + 1, KS_TEXT_DIM, 0, DU_ASCII_STEP);
|
|||
|
|
|
|||
|
|
/* page-credit(对应 Kate "由 Deaicup 工作室制作") */
|
|||
|
|
du_draw_string(&g_fb, "DEAICUP STUDIO",
|
|||
|
|
W - 12 - 14 * (int)DU_ASCII_STEP, ty + 1,
|
|||
|
|
KS_TEXT_DIM, 0, DU_ASCII_STEP);
|
|||
|
|
|
|||
|
|
/* ide-host(虚线,margin 8px) */
|
|||
|
|
int hx = 8, hy = top + 36 + 8;
|
|||
|
|
int hw = W - 16, hh = (int)g_fb_h - hy - 8;
|
|||
|
|
g_ide_host[0] = hx; g_ide_host[1] = hy;
|
|||
|
|
g_ide_host[2] = hw; g_ide_host[3] = hh;
|
|||
|
|
draw_dashed_rect(hx, hy, hw, hh, KS_BORDER);
|
|||
|
|
|
|||
|
|
if (g_ide_attached) {
|
|||
|
|
if (g_input_forward_enabled) {
|
|||
|
|
/* VSCode Phase 6 状态机:启动中探测 scanout 上线 → 运行中 */
|
|||
|
|
if (g_vscode_state == 1) {
|
|||
|
|
const struct linux_compat_scanout_info *si = ide_scanout_state();
|
|||
|
|
if (si && si->enabled) {
|
|||
|
|
g_vscode_state = 2;
|
|||
|
|
g_launch_phase = 6;
|
|||
|
|
g_so_full_repaint = 1; /* 上线首帧全量重绘 */
|
|||
|
|
/* P8.1: scanout 上线日志 + 耗时 */
|
|||
|
|
slog("[launch] phase 6: SCANOUT ONLINE");
|
|||
|
|
if (g_tsc_per_sec && g_launch_tsc) {
|
|||
|
|
u64 ms = (rdtsc() - g_launch_tsc) * 1000 / g_tsc_per_sec;
|
|||
|
|
slog_num("[launch] total launch time ms=", (int)ms);
|
|||
|
|
}
|
|||
|
|
{
|
|||
|
|
char sbuf[48];
|
|||
|
|
kstrcpy(sbuf, "scanout: ", 48);
|
|||
|
|
u32dec(si->width, sbuf + kstrlen(sbuf));
|
|||
|
|
kstrcat(sbuf, "x", 48);
|
|||
|
|
u32dec(si->height, sbuf + kstrlen(sbuf));
|
|||
|
|
slog(sbuf);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (g_vscode_state == 2) {
|
|||
|
|
/* 运行中:blit guest 合成帧 */
|
|||
|
|
blit_scanout_to_ide(hx + 2, hy + 2, hw - 4, hh - 4);
|
|||
|
|
} else {
|
|||
|
|
/* P8.1: 启动中--显示分阶段状态 + 详细信息 */
|
|||
|
|
du_fill_rect(&g_fb, hx + 2, hy + 2, hw - 4, hh - 4, 0xFF051828u);
|
|||
|
|
draw_centered(g_launch_status[0] ? g_launch_status :
|
|||
|
|
"STARTING VSCODE . . .",
|
|||
|
|
W / 2, hy + hh / 2 - 20, KS_TEXT_DIM, 0);
|
|||
|
|
/* 详细信息行(phase/exec_rc/pgrep/耗时) */
|
|||
|
|
{
|
|||
|
|
char dbuf[80];
|
|||
|
|
int dp = 0;
|
|||
|
|
kstrcpy(dbuf + dp, "PHASE:", 80); dp = kstrlen(dbuf);
|
|||
|
|
dp += u32dec((u32)g_launch_phase, dbuf + dp);
|
|||
|
|
if (g_launch_exec_rc != 0) {
|
|||
|
|
kstrcpy(dbuf + dp, " RC:", 80); dp = kstrlen(dbuf);
|
|||
|
|
dp += u32dec((u32)(g_launch_exec_rc < 0 ?
|
|||
|
|
(u32)(-g_launch_exec_rc) : (u32)g_launch_exec_rc),
|
|||
|
|
dbuf + dp);
|
|||
|
|
}
|
|||
|
|
if (g_launch_pgrep_rc >= 0) {
|
|||
|
|
kstrcpy(dbuf + dp, " PGREP:", 80); dp = kstrlen(dbuf);
|
|||
|
|
kstrcpy(dbuf + dp, g_launch_pgrep_rc == 0 ? "FOUND" : "MISSING",
|
|||
|
|
80);
|
|||
|
|
dp = kstrlen(dbuf);
|
|||
|
|
}
|
|||
|
|
if (g_tsc_per_sec && g_launch_tsc) {
|
|||
|
|
u64 ms = (rdtsc() - g_launch_tsc) * 1000 / g_tsc_per_sec;
|
|||
|
|
kstrcpy(dbuf + dp, " T:", 80); dp = kstrlen(dbuf);
|
|||
|
|
dp += u32dec((u32)ms, dbuf + dp);
|
|||
|
|
kstrcpy(dbuf + dp, "ms", 80);
|
|||
|
|
}
|
|||
|
|
draw_centered(dbuf, W / 2, hy + hh / 2 + 4, KS_TEXT_DIM, 0);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
editor_draw_to((editor_state *)ADDR_EDDASH, hx + 2, hy + 2, hw - 4, hh - 4);
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
/* embed-empty(Kate:未启动 VSCode 提示) */
|
|||
|
|
draw_centered("VSCODE NOT RUNNING . DOUBLE-CLICK OR + NEW IDE TO START",
|
|||
|
|
W / 2, hy + hh / 2 - 8, KS_TEXT_DIM, 0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* P7.9: 性能 profiling 叠加(IDE 页面左下角) */
|
|||
|
|
if (g_ide_attached && g_input_forward_enabled) {
|
|||
|
|
char buf[80];
|
|||
|
|
int p = 0;
|
|||
|
|
kstrcpy(buf + p, "FPS:", 80 - p); p = kstrlen(buf);
|
|||
|
|
p += u32dec((u32)g_prof_fps, buf + p);
|
|||
|
|
kstrcpy(buf + p, " BLT:", 80 - p); p = kstrlen(buf);
|
|||
|
|
p += u32dec((u32)g_prof_last_blit_us, buf + p);
|
|||
|
|
kstrcpy(buf + p, "us SKP:", 80 - p); p = kstrlen(buf);
|
|||
|
|
p += u32dec((u32)g_prof_blit_skip, buf + p);
|
|||
|
|
kstrcpy(buf + p, " FUL:", 80 - p); p = kstrlen(buf);
|
|||
|
|
p += u32dec((u32)g_prof_blit_full, buf + p);
|
|||
|
|
du_draw_string(&g_fb, buf, hx + 6, hy + hh - 16,
|
|||
|
|
KS_TEXT_DIM, 0, DU_ASCII_STEP);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* ---- 3·DESKTOP ---- */
|
|||
|
|
void draw_desktop_page(void) {
|
|||
|
|
/* 图标网格 */
|
|||
|
|
draw_desktop_icons();
|
|||
|
|
|
|||
|
|
/* 窗口(当前工作区,从底到顶) */
|
|||
|
|
for (int i = 0; i < g_win_count; i++) {
|
|||
|
|
desktop_window *w = &g_windows[i];
|
|||
|
|
if (w->minimized || !w->visible) continue;
|
|||
|
|
if (w->ws != g_ws_cur) continue;
|
|||
|
|
|
|||
|
|
draw_window_frame(w);
|
|||
|
|
|
|||
|
|
if (w->app_id >= 0 && w->app_id < g_app_count &&
|
|||
|
|
g_apps[w->app_id].on_draw && w->app_state) {
|
|||
|
|
app_ctx ctx;
|
|||
|
|
fill_app_ctx(&ctx, w);
|
|||
|
|
g_apps[w->app_id].on_draw(w->app_state, &ctx);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!g_fluent) { /* KATE 扫描线特效;Fluent 窗口干净背景 */
|
|||
|
|
du_kate_scanlines(&g_fb, w->x + 1, w->y + KATE_TITLEBAR_H,
|
|||
|
|
w->w - 2, w->h - KATE_TITLEBAR_H - 1);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* M2 Fluent:悬浮任务栏由 compositor(redraw_all_fluent)统一叠加,
|
|||
|
|
* 此处跳过旧 40px 任务栏。 */
|
|||
|
|
if (g_fluent) return;
|
|||
|
|
|
|||
|
|
/* 任务栏(40px,KATE 回退路径) */
|
|||
|
|
int W = (int)g_fb_w;
|
|||
|
|
int tb_y = (int)g_fb_h - KATE_TASKBAR_H;
|
|||
|
|
du_fill_rect_gradient(&g_fb, 0, tb_y, W, KATE_TASKBAR_H,
|
|||
|
|
0xFF0A2840u, KS_BG_PRIMARY);
|
|||
|
|
du_divider_h(&g_fb, 0, tb_y, W, KS_BORDER);
|
|||
|
|
|
|||
|
|
int x = 8;
|
|||
|
|
int ty = tb_y + (KATE_TASKBAR_H - (int)DU_ASCII_LINE_H) / 2 + 1;
|
|||
|
|
|
|||
|
|
/* tb-item per window(当前工作区) */
|
|||
|
|
for (int i = 0; i < g_win_count; i++) {
|
|||
|
|
desktop_window *w = &g_windows[i];
|
|||
|
|
if (!w->visible || w->ws != g_ws_cur) {
|
|||
|
|
g_tb_rect[i][2] = 0; g_tb_close_rect[i][2] = 0;
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
char t[16];
|
|||
|
|
int tl = 0;
|
|||
|
|
while (w->title[tl] && tl < 11) { t[tl] = w->title[tl]; tl++; }
|
|||
|
|
if (w->title[tl]) { t[tl-1] = '.'; t[tl] = '.'; tl++; }
|
|||
|
|
t[tl] = 0;
|
|||
|
|
int bw = tl * (int)DU_ASCII_STEP + 34;
|
|||
|
|
if (bw > 150) bw = 150;
|
|||
|
|
int active = w->focused;
|
|||
|
|
int hover = g_mouse_x >= x && g_mouse_x < x + bw &&
|
|||
|
|
g_mouse_y >= tb_y + 6 && g_mouse_y < tb_y + 34;
|
|||
|
|
if (active) du_fill_rect(&g_fb, x, tb_y + 6, bw, 28, KS_ACCENT_DIM);
|
|||
|
|
else if (hover) du_fill_rect(&g_fb, x, tb_y + 6, bw, 28, KS_ACCENT_DIM);
|
|||
|
|
du_rect_outline(&g_fb, x, tb_y + 6, bw, 28,
|
|||
|
|
active ? KS_ACCENT : KS_BORDER, 1);
|
|||
|
|
du_draw_string(&g_fb, t, x + 6, ty,
|
|||
|
|
active ? KS_ACCENT : KS_TEXT_PRIMARY, 0, DU_ASCII_STEP);
|
|||
|
|
du_draw_string(&g_fb, "x", x + bw - 14, ty, KS_TEXT_DIM, 0, DU_ASCII_STEP);
|
|||
|
|
g_tb_rect[i][0] = x; g_tb_rect[i][1] = tb_y + 6;
|
|||
|
|
g_tb_rect[i][2] = bw; g_tb_rect[i][3] = 28;
|
|||
|
|
g_tb_close_rect[i][0] = x + bw - 20; g_tb_close_rect[i][1] = tb_y + 6;
|
|||
|
|
g_tb_close_rect[i][2] = 20; g_tb_close_rect[i][3] = 28;
|
|||
|
|
x += bw + 6;
|
|||
|
|
if (x > W - 260) break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* Winux-Kate 任务栏右组(margin-left:auto):
|
|||
|
|
* [+ ADOPT 虚框] [tb-credit 署名] [EXIT 危险色] */
|
|||
|
|
const char *credit = "DEAICUP STUDIO";
|
|||
|
|
const char *quit = "EXIT";
|
|||
|
|
const char *adopt = "+ ADOPT";
|
|||
|
|
|
|||
|
|
int qw = 60;
|
|||
|
|
int qx = W - qw - 8;
|
|||
|
|
int credit_w = kstrlen(credit) * (int)DU_ASCII_STEP;
|
|||
|
|
int cx = qx - 8 - credit_w;
|
|||
|
|
int aw = kstrlen(adopt) * (int)DU_ASCII_STEP + 16;
|
|||
|
|
int ax = cx - 8 - aw;
|
|||
|
|
|
|||
|
|
/* tb-adopt:虚线 accent 边框 */
|
|||
|
|
g_tb_adopt_rect[0] = ax; g_tb_adopt_rect[1] = tb_y + 6;
|
|||
|
|
g_tb_adopt_rect[2] = aw; g_tb_adopt_rect[3] = 28;
|
|||
|
|
{
|
|||
|
|
int hover = g_mouse_x >= ax && g_mouse_x < ax + aw &&
|
|||
|
|
g_mouse_y >= tb_y + 6 && g_mouse_y < tb_y + 34;
|
|||
|
|
if (hover) du_fill_rect(&g_fb, ax, tb_y + 6, aw, 28, KS_ACCENT_DIM);
|
|||
|
|
draw_dashed_rect(ax, tb_y + 6, aw, 28, KS_ACCENT);
|
|||
|
|
du_draw_string(&g_fb, adopt, ax + 8, ty, KS_ACCENT, 0, DU_ASCII_STEP);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* tb-credit */
|
|||
|
|
du_draw_string(&g_fb, credit, cx, ty, KS_TEXT_DIM, 0, DU_ASCII_STEP);
|
|||
|
|
|
|||
|
|
/* tb-quit */
|
|||
|
|
g_tb_quit_rect[0] = qx; g_tb_quit_rect[1] = tb_y + 6;
|
|||
|
|
g_tb_quit_rect[2] = qw; g_tb_quit_rect[3] = 28;
|
|||
|
|
{
|
|||
|
|
int hover = g_mouse_x >= qx && g_mouse_x < qx + qw &&
|
|||
|
|
g_mouse_y >= tb_y + 6 && g_mouse_y < tb_y + 34;
|
|||
|
|
if (hover) du_fill_rect(&g_fb, qx, tb_y + 6, qw, 28, 0x30FF4D6Du);
|
|||
|
|
du_rect_outline(&g_fb, qx, tb_y + 6, qw, 28, KS_DANGER, 1);
|
|||
|
|
du_draw_string(&g_fb, quit, qx + (qw - 4 * (int)DU_ASCII_STEP) / 2, ty,
|
|||
|
|
KS_DANGER, 0, DU_ASCII_STEP);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* ---- 5+/CUSTOM ---- */
|
|||
|
|
void draw_custom_page(int cp_idx) {
|
|||
|
|
int W = (int)g_fb_w;
|
|||
|
|
int top = KATE_TOPBAR_H;
|
|||
|
|
cpage *cp = &g_cpages[cp_idx];
|
|||
|
|
|
|||
|
|
/* ide-tabs 栏(36px):dot + 页名 + "+ NEW INSTANCE" + ide-hint(Kate 结构) */
|
|||
|
|
du_fill_rect(&g_fb, 0, top, W, 36, 0xFF051828u);
|
|||
|
|
du_divider_h(&g_fb, 0, top + 36, W, KS_BORDER);
|
|||
|
|
int ty = top + (36 - (int)DU_ASCII_LINE_H) / 2 + 1;
|
|||
|
|
|
|||
|
|
/* .dot + 页名 */
|
|||
|
|
du_fill_rect(&g_fb, 12, top + 14, 8, 8, KS_ACCENT2);
|
|||
|
|
du_draw_string(&g_fb, cp->name, 28, ty, KS_ACCENT, 0, DU_ASCII_STEP);
|
|||
|
|
int x = 28 + kstrlen(cp->name) * (int)DU_ASCII_STEP + 12;
|
|||
|
|
|
|||
|
|
/* "+ NEW INSTANCE" 按钮(对应 Kate custom launch_custom_new) */
|
|||
|
|
{
|
|||
|
|
const char *nb = "+ NEW INSTANCE";
|
|||
|
|
int bw = kstrlen(nb) * (int)DU_ASCII_STEP + 20;
|
|||
|
|
g_cp_new_rect[0] = x; g_cp_new_rect[1] = top + 7;
|
|||
|
|
g_cp_new_rect[2] = bw; g_cp_new_rect[3] = 22;
|
|||
|
|
int hover = g_mouse_x >= x && g_mouse_x < x + bw &&
|
|||
|
|
g_mouse_y >= top + 7 && g_mouse_y < top + 29;
|
|||
|
|
if (hover) du_fill_rect(&g_fb, x, top + 7, bw, 22, KS_ACCENT_DIM);
|
|||
|
|
du_rect_outline(&g_fb, x, top + 7, bw, 22, KS_BORDER, 1);
|
|||
|
|
du_draw_string(&g_fb, nb, x + 10, ty, KS_ACCENT, 0, DU_ASCII_STEP);
|
|||
|
|
x += bw + 8;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* ide-hint */
|
|||
|
|
du_draw_string(&g_fb, "DBL-CLICK HOST LAUNCH . EXTERNAL ELF FULLSCREEN",
|
|||
|
|
x + 8, ty + 1, KS_TEXT_DIM, 0, DU_ASCII_STEP);
|
|||
|
|
|
|||
|
|
/* page-credit */
|
|||
|
|
du_draw_string(&g_fb, "DEAICUP STUDIO",
|
|||
|
|
W - 12 - 14 * (int)DU_ASCII_STEP, ty + 1,
|
|||
|
|
KS_TEXT_DIM, 0, DU_ASCII_STEP);
|
|||
|
|
|
|||
|
|
/* ide-host(虚线,margin 8px) */
|
|||
|
|
int hx = 8, hy = top + 36 + 8;
|
|||
|
|
int hw = W - 16, hh = (int)g_fb_h - hy - 8;
|
|||
|
|
g_cp_host[0] = hx; g_cp_host[1] = hy;
|
|||
|
|
g_cp_host[2] = hw; g_cp_host[3] = hh;
|
|||
|
|
draw_dashed_rect(hx, hy, hw, hh, KS_BORDER);
|
|||
|
|
|
|||
|
|
/* embed-empty(Kate:正在启动提示) */
|
|||
|
|
char msg[40];
|
|||
|
|
kstrcpy(msg, "DOUBLE-CLICK TO LAUNCH ", 40);
|
|||
|
|
kstrcat(msg, cp->name, 40);
|
|||
|
|
draw_centered(msg, hx + hw / 2, hy + hh / 2 - 12, KS_TEXT_DIM, 0);
|
|||
|
|
|
|||
|
|
char sub[40];
|
|||
|
|
kstrcpy(sub, "ELF: ", 40);
|
|||
|
|
{
|
|||
|
|
char disp[13];
|
|||
|
|
f32_name_from_83_w(cp->elf11, disp);
|
|||
|
|
kstrcat(sub, disp, 40);
|
|||
|
|
}
|
|||
|
|
draw_centered(sub, hx + hw / 2, hy + hh / 2 + 12, KS_ACCENT, 0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* ============================================================
|
|||
|
|
* 任务视图 overlay
|
|||
|
|
* ============================================================ */
|
|||
|
|
|
|||
|
|
void draw_taskview(void) {
|
|||
|
|
int W = (int)g_fb_w;
|
|||
|
|
|
|||
|
|
/* 背景暗化(全屏 blend,模态 overlay 下文字可读性优先) */
|
|||
|
|
for (u64 ry = 0; ry < g_fb_h; ry++) {
|
|||
|
|
u32 *line = (u32 *)((u8 *)g_fb.fb + ry * g_fb_pitch);
|
|||
|
|
for (u64 rx = 0; rx < g_fb_w; rx++) {
|
|||
|
|
line[rx] = du_blend(line[rx], KS_BG_PRIMARY, 220);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* tv-header */
|
|||
|
|
du_draw_string(&g_fb, "TASK VIEW", 60, 44, KS_ACCENT, 0, DU_ASCII_STEP + 4);
|
|||
|
|
du_draw_string(&g_fb, "CLICK TO SWITCH . ESC CLOSE . x CLOSE WS",
|
|||
|
|
60 + 9 * ((int)DU_ASCII_STEP + 4) + 20, 48,
|
|||
|
|
KS_TEXT_DIM, 0, DU_ASCII_STEP);
|
|||
|
|
du_divider_h(&g_fb, 60, 76, W - 120, KS_BORDER);
|
|||
|
|
|
|||
|
|
/* tv-grid 卡片 */
|
|||
|
|
int cw = 260, ch = 170, gap = 20;
|
|||
|
|
int cols = (W - 120 + gap) / (cw + gap);
|
|||
|
|
if (cols < 1) cols = 1;
|
|||
|
|
for (int i = 0; i <= g_ws_count; i++) {
|
|||
|
|
int row = i / cols, col = i % cols;
|
|||
|
|
int x = 60 + col * (cw + gap);
|
|||
|
|
int y = 96 + row * (ch + gap);
|
|||
|
|
g_tv_card[i][0] = x; g_tv_card[i][1] = y;
|
|||
|
|
g_tv_card[i][2] = cw; g_tv_card[i][3] = ch;
|
|||
|
|
|
|||
|
|
if (i == g_ws_count) {
|
|||
|
|
/* 新建工作区卡片(虚线 +) */
|
|||
|
|
draw_dashed_rect(x, y, cw, ch, KS_ACCENT2);
|
|||
|
|
du_draw_string(&g_fb, "+", x + cw / 2 - 6, y + ch / 2 - 24,
|
|||
|
|
KS_ACCENT2, 0, DU_ASCII_STEP);
|
|||
|
|
draw_centered("NEW WORKSPACE", x + cw / 2, y + ch / 2 + 8,
|
|||
|
|
KS_ACCENT2, 0);
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int active = (i == g_ws_cur);
|
|||
|
|
int hover = g_mouse_x >= x && g_mouse_x < x + cw &&
|
|||
|
|
g_mouse_y >= y && g_mouse_y < y + ch;
|
|||
|
|
du_fill_rect(&g_fb, x, y, cw, ch, KS_BG_SECONDARY);
|
|||
|
|
du_rect_outline(&g_fb, x, y, cw, ch,
|
|||
|
|
active ? KS_ACCENT2 : (hover ? KS_ACCENT : KS_BORDER), 1);
|
|||
|
|
if (active) du_kate_glow_border(&g_fb, x, y, cw, ch, KS_ACCENT2);
|
|||
|
|
|
|||
|
|
/* tv-card-top */
|
|||
|
|
du_draw_string(&g_fb, g_ws[i].name, x + 12, y + 10, KS_ACCENT, 0, DU_ASCII_STEP);
|
|||
|
|
du_divider_h(&g_fb, x, y + 34, cw, KS_BORDER);
|
|||
|
|
/* × close */
|
|||
|
|
g_tv_close[i][0] = x + cw - 26; g_tv_close[i][1] = y + 4;
|
|||
|
|
g_tv_close[i][2] = 22; g_tv_close[i][3] = 26;
|
|||
|
|
du_draw_string(&g_fb, "x", x + cw - 20, y + 8, KS_TEXT_DIM, 0, DU_ASCII_STEP);
|
|||
|
|
|
|||
|
|
/* tv-stat */
|
|||
|
|
char nbuf[4];
|
|||
|
|
int wc = ws_win_count(i);
|
|||
|
|
nbuf[0] = '0' + (char)(wc % 10); nbuf[1] = 0;
|
|||
|
|
draw_centered(nbuf, x + cw / 4, y + 70, KS_ACCENT2, 0);
|
|||
|
|
draw_centered("WINS", x + cw / 4, y + 96, KS_TEXT_DIM, 0);
|
|||
|
|
char pbuf[6];
|
|||
|
|
kstrcpy(pbuf, "PG", 6);
|
|||
|
|
pbuf[2] = '0' + (char)(g_ws[i].page % 10); pbuf[3] = 0;
|
|||
|
|
draw_centered(pbuf, x + cw * 3 / 4, y + 70, KS_ACCENT2, 0);
|
|||
|
|
draw_centered("PAGE", x + cw * 3 / 4, y + 96, KS_TEXT_DIM, 0);
|
|||
|
|
|
|||
|
|
/* badge CURRENT */
|
|||
|
|
if (active) {
|
|||
|
|
int bx = x + cw - 84, by = y + 6;
|
|||
|
|
du_fill_rect(&g_fb, bx, by, 56, 14, KS_ACCENT2);
|
|||
|
|
du_draw_string(&g_fb, "CURRENT", bx + 2, by - 1,
|
|||
|
|
KS_TEXT_INVERT, 0, DU_ASCII_STEP);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* ============================================================
|
|||
|
|
* 右键菜单(移到工作区)
|
|||
|
|
* ============================================================ */
|
|||
|
|
|
|||
|
|
void draw_ctx_menu(void) {
|
|||
|
|
if (!g_ctx_open) return;
|
|||
|
|
int lmap[MAX_WS];
|
|||
|
|
int ln = ctx_list_build(lmap);
|
|||
|
|
int rows = (ln ? ln : 1) + 1; /* 列表行(或空态行) + 新建行 */
|
|||
|
|
int mw = 200;
|
|||
|
|
int mh = 24 + rows * 22 + 8;
|
|||
|
|
int x = g_ctx_x, y = g_ctx_y;
|
|||
|
|
if (x + mw > (int)g_fb_w) x = (int)g_fb_w - mw - 4;
|
|||
|
|
if (y + mh > (int)g_fb_h) y = (int)g_fb_h - mh - 4;
|
|||
|
|
g_ctx_rect[0] = x; g_ctx_rect[1] = y;
|
|||
|
|
g_ctx_rect[2] = mw; g_ctx_rect[3] = mh;
|
|||
|
|
|
|||
|
|
du_fill_rect(&g_fb, x, y, mw, mh, 0xFF050A18u);
|
|||
|
|
du_rect_outline(&g_fb, x, y, mw, mh, KS_ACCENT, 1);
|
|||
|
|
du_kate_glow_border(&g_fb, x, y, mw, mh, KS_ACCENT);
|
|||
|
|
|
|||
|
|
du_draw_string(&g_fb, "MOVE TO WORKSPACE", x + 12, y + 5,
|
|||
|
|
KS_ACCENT, 0, DU_ASCII_STEP);
|
|||
|
|
du_divider_h(&g_fb, x, y + 22, mw, KS_BORDER);
|
|||
|
|
|
|||
|
|
int iy = y + 26;
|
|||
|
|
int row = 0;
|
|||
|
|
if (ln == 0) {
|
|||
|
|
/* 空态(不可点击) */
|
|||
|
|
du_draw_string(&g_fb, "NO OTHER WORKSPACE", x + 12, iy + 2,
|
|||
|
|
KS_TEXT_DIM, 0, DU_ASCII_STEP);
|
|||
|
|
g_ctx_item[0][2] = 0; /* 禁用命中 */
|
|||
|
|
g_ctx_item_ws[0] = -2;
|
|||
|
|
iy += 22;
|
|||
|
|
row = 1;
|
|||
|
|
}
|
|||
|
|
for (int r = 0; r < ln; r++) {
|
|||
|
|
int wi = lmap[r];
|
|||
|
|
int hover = g_mouse_x >= x && g_mouse_x < x + mw &&
|
|||
|
|
g_mouse_y >= iy && g_mouse_y < iy + 22;
|
|||
|
|
if (hover) du_fill_rect(&g_fb, x + 1, iy, mw - 2, 22, KS_ACCENT_DIM);
|
|||
|
|
du_draw_string(&g_fb, g_ws[wi].name, x + 12, iy + 2,
|
|||
|
|
hover ? KS_ACCENT : KS_TEXT_PRIMARY, 0, DU_ASCII_STEP);
|
|||
|
|
char cn[4];
|
|||
|
|
cn[0] = '0' + (char)(ws_win_count(wi) % 10); cn[1] = 0;
|
|||
|
|
du_draw_string(&g_fb, cn, x + mw - 24, iy + 2, KS_TEXT_DIM, 0, DU_ASCII_STEP);
|
|||
|
|
g_ctx_item[row][0] = x; g_ctx_item[row][1] = iy;
|
|||
|
|
g_ctx_item[row][2] = mw; g_ctx_item[row][3] = 22;
|
|||
|
|
g_ctx_item_ws[row] = wi;
|
|||
|
|
iy += 22;
|
|||
|
|
row++;
|
|||
|
|
}
|
|||
|
|
/* + NEW WORKSPACE */
|
|||
|
|
du_divider_h(&g_fb, x, iy, mw, KS_BORDER);
|
|||
|
|
int hover = g_mouse_x >= x && g_mouse_x < x + mw &&
|
|||
|
|
g_mouse_y >= iy && g_mouse_y < iy + 22;
|
|||
|
|
if (hover) du_fill_rect(&g_fb, x + 1, iy, mw - 2, 22, KS_ACCENT_DIM);
|
|||
|
|
du_draw_string(&g_fb, "+ NEW WORKSPACE", x + 12, iy + 2,
|
|||
|
|
KS_ACCENT2, 0, DU_ASCII_STEP);
|
|||
|
|
g_ctx_item[row][0] = x; g_ctx_item[row][1] = iy;
|
|||
|
|
g_ctx_item[row][2] = mw; g_ctx_item[row][3] = 22;
|
|||
|
|
g_ctx_item_ws[row] = -1;
|
|||
|
|
/* 清除残余行命中 */
|
|||
|
|
for (int r = row + 1; r <= MAX_WS; r++) g_ctx_item[r][2] = 0;
|
|||
|
|
}
|