feat: Word Processor discovers fonts automatically (via 0:/fonts), UI fix

This commit is contained in:
2026-06-06 10:12:11 +02:00
parent 8341082bd6
commit 0728dd58e5
7 changed files with 435 additions and 106 deletions
+56 -12
View File
@@ -128,6 +128,44 @@ static void wp_fit_ui_text(const char* src, char* out, int out_len, int max_w) {
}
}
// Truncate from the end with a trailing ".." so `src` fits in max_w pixels.
// Used for labels (e.g. font names) where the start carries the meaning.
static void wp_fit_ui_text_end(const char* src, char* out, int out_len, int max_w) {
if (out_len <= 0) return;
if (!src) { out[0] = '\0'; return; }
montauk::strncpy(out, src, out_len - 1);
out[out_len - 1] = '\0';
if (text_width(g_ui_font, out, fonts::UI_SIZE) <= max_w) return;
for (int keep = montauk::slen(src); keep > 0; keep--) {
char candidate[256];
if (keep > (int)sizeof(candidate) - 3) continue;
montauk::memcpy(candidate, src, keep);
candidate[keep] = '.';
candidate[keep + 1] = '.';
candidate[keep + 2] = '\0';
if (text_width(g_ui_font, candidate, fonts::UI_SIZE) <= max_w) {
montauk::strncpy(out, candidate, out_len - 1);
out[out_len - 1] = '\0';
return;
}
}
out[0] = '\0';
}
// Width of the font popup, sized to the longest discovered name (clamped) so
// names display in full in the list even when the toolbar button is narrow.
int wp_font_dropdown_width() {
int w = 110;
for (int i = 0; i < wp_font_count(); i++) {
int tw = text_width(g_ui_font, wp_font_name(i), fonts::UI_SIZE) + 24;
if (tw > w) w = tw;
}
if (w > 260) w = 260;
return w;
}
static ParagraphStyle* wp_current_paragraph_style(WordProcessorState* wp) {
if (wp->paragraph_count <= 0) {
static ParagraphStyle fallback = { PARA_ALIGN_LEFT, PARA_LIST_NONE, 100, PARA_DIVIDER_NONE, 0, 0, 0, 0 };
@@ -247,14 +285,18 @@ void wp_render() {
Color italic_bg = (wp->cur_flags & STYLE_ITALIC) ? btn_active : btn_bg;
c.fill_rounded_rect(WP_BTN_ITALIC_X, 6, 24, 24, 3, italic_bg);
{
TrueTypeFont* italic_font = wp_get_font(FONT_ROBOTO, STYLE_ITALIC);
TrueTypeFont* italic_font = wp_get_font(wp_default_font_id(), STYLE_ITALIC);
draw_text(c, italic_font ? italic_font : g_ui_font, WP_BTN_ITALIC_X + 9, 8, "I", colors::TEXT_COLOR, fonts::UI_SIZE);
}
c.fill_rounded_rect(WP_FONT_DD_X, 6, WP_FONT_DD_W, 24, 3, btn_bg);
wp_draw_ui_text(c, WP_FONT_DD_X + 6, (WP_TOOLBAR_H - sfh) / 2,
WP_FONT_NAMES[wp->cur_font_id < FONT_COUNT ? wp->cur_font_id : 0],
colors::TEXT_COLOR);
{
char font_fit[WP_FONT_NAME_MAX + 4];
wp_fit_ui_text_end(wp_font_name(wp->cur_font_id), font_fit, sizeof(font_fit),
WP_FONT_DD_W - 12);
wp_draw_ui_text(c, WP_FONT_DD_X + 6, (WP_TOOLBAR_H - sfh) / 2,
font_fit, colors::TEXT_COLOR);
}
c.fill_rounded_rect(WP_SIZE_DD_X, 6, WP_SIZE_DD_W, 24, 3, btn_bg);
{
@@ -305,7 +347,7 @@ void wp_render() {
c.fill_rounded_rect(WP_BTN_SECTION_X, 6, 24, 24, 3, special_bg);
{
char section[2] = { (char)0xA7, '\0' };
TrueTypeFont* font = wp_get_font(FONT_ROBOTO, 0);
TrueTypeFont* font = wp_get_font(wp_default_font_id(), 0);
draw_text(c, font ? font : g_ui_font, WP_BTN_SECTION_X + 6, 8, section, colors::TEXT_COLOR, fonts::UI_SIZE);
}
@@ -573,12 +615,12 @@ void wp_render() {
if (cur_para->divider_type != PARA_DIVIDER_NONE) {
snprintf(status_left, sizeof(status_left), " %s%s | %s %dpt | Divider: %s | %d%%",
name, wp->modified ? " *" : "",
WP_FONT_NAMES[wp->cur_font_id < FONT_COUNT ? wp->cur_font_id : 0], (int)wp->cur_size,
wp_font_name(wp->cur_font_id), (int)wp->cur_size,
wp_divider_label(cur_para->divider_type), (int)cur_para->line_spacing);
} else {
snprintf(status_left, sizeof(status_left), " %s%s | %s %dpt | %s | %s | %d%%",
name, wp->modified ? " *" : "",
WP_FONT_NAMES[wp->cur_font_id < FONT_COUNT ? wp->cur_font_id : 0], (int)wp->cur_size,
wp_font_name(wp->cur_font_id), (int)wp->cur_size,
wp_align_label(cur_para->align), wp_list_label(cur_para->list_type),
(int)cur_para->line_spacing);
}
@@ -599,15 +641,17 @@ void wp_render() {
if (wp->font_dropdown_open) {
int dx = WP_FONT_DD_X;
int dy = WP_TOOLBAR_H;
int dw = 110;
int dh = FONT_COUNT * 26 + 4;
int dw = wp_font_dropdown_width();
int dh = wp_font_count() * 26 + 4;
c.fill_rect(dx, dy, dw, dh, colors::MENU_BG);
c.rect(dx, dy, dw, dh, colors::BORDER);
for (int i = 0; i < FONT_COUNT; i++) {
for (int i = 0; i < wp_font_count(); i++) {
int iy = dy + 2 + i * 26;
if (i == wp->cur_font_id)
c.fill_rect(dx + 2, iy, dw - 4, 24, colors::MENU_HOVER);
wp_draw_ui_text(c, dx + 8, iy + (24 - sfh) / 2, WP_FONT_NAMES[i], colors::TEXT_COLOR);
char item_fit[WP_FONT_NAME_MAX + 4];
wp_fit_ui_text_end(wp_font_name(i), item_fit, sizeof(item_fit), dw - 16);
wp_draw_ui_text(c, dx + 8, iy + (24 - sfh) / 2, item_fit, colors::TEXT_COLOR);
}
}
@@ -668,7 +712,7 @@ void wp_render() {
int dy = WP_TOOLBAR_H;
int dw = WP_SPECIAL_CHAR_FLYOUT_W;
int dh = WP_SPECIAL_CHAR_OPTION_COUNT * WP_SPECIAL_CHAR_ROW_H + 4;
TrueTypeFont* glyph_font = wp_get_font(FONT_ROBOTO, 0);
TrueTypeFont* glyph_font = wp_get_font(wp_default_font_id(), 0);
c.fill_rect(dx, dy, dw, dh, colors::MENU_BG);
c.rect(dx, dy, dw, dh, colors::BORDER);
for (int i = 0; i < WP_SPECIAL_CHAR_OPTION_COUNT; i++) {