diff --git a/CHANGELOG.md b/CHANGELOG.md index ead014cf..9538ccca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,10 +52,14 @@ * String values in `foot.ini` may now be quoted. This can be used to set a value to the empty string, for example. * Environment variables can now be **unset**, by setting - `[environment].=""` (quotes are required) ([#1225][1225]) + `[environment].=""` (quotes are required) ([#1225][1225]). +* `font-size-adjustment=N[px]` option, letting you configure how much + to increment/decrement the font size when zooming in or out + ([#1188][1188]). [1136]: https://codeberg.org/dnkl/foot/issues/1136 [1225]: https://codeberg.org/dnkl/foot/issues/1225 +[1188]: https://codeberg.org/dnkl/foot/issues/1188 ### Changed diff --git a/config.c b/config.c index 68641647..b10f42b2 100644 --- a/config.c +++ b/config.c @@ -925,6 +925,31 @@ parse_section_main(struct context *ctx) return true; } + else if (strcmp(key, "font-size-adjustment") == 0) { + const size_t len = strlen(ctx->value); + if (len >= 1 && ctx->value[len - 1] == '%') { + errno = 0; + char *end = NULL; + + float percent = strtof(ctx->value, &end); + if (!(errno == 0 && end == ctx->value + len - 1)) { + LOG_CONTEXTUAL_ERR( + "invalid percent value (must be in the form 10.5%%)"); + return false; + } + + conf->font_size_adjustment.percent = percent / 100.; + conf->font_size_adjustment.pt_or_px.pt = 0; + conf->font_size_adjustment.pt_or_px.px = 0; + return true; + } else { + bool ret = value_to_pt_or_px(ctx, &conf->font_size_adjustment.pt_or_px); + if (ret) + conf->font_size_adjustment.percent = 0.; + return ret; + } + } + else if (strcmp(key, "line-height") == 0) return value_to_pt_or_px(ctx, &conf->line_height); @@ -2886,6 +2911,7 @@ config_load(struct config *conf, const char *conf_path, }, .startup_mode = STARTUP_WINDOWED, .fonts = {{0}}, + .font_size_adjustment = {.percent = 0., .pt_or_px = {.pt = 0.5, .px = 0}}, .line_height = {.pt = 0, .px = -1}, .letter_spacing = {.pt = 0, .px = 0}, .horizontal_letter_offset = {.pt = 0, .px = 0}, diff --git a/config.h b/config.h index d35abbb2..648d92e4 100644 --- a/config.h +++ b/config.h @@ -22,6 +22,11 @@ struct pt_or_px { float pt; }; +struct font_size_adjustment { + struct pt_or_px pt_or_px; + float percent; +}; + enum cursor_style { CURSOR_BLOCK, CURSOR_UNDERLINE, CURSOR_BEAM }; enum conf_size_type {CONF_SIZE_PX, CONF_SIZE_CELLS}; @@ -139,6 +144,7 @@ struct config { enum {DPI_AWARE_AUTO, DPI_AWARE_YES, DPI_AWARE_NO} dpi_aware; struct config_font_list fonts[4]; + struct font_size_adjustment font_size_adjustment; /* Custom font metrics (-1 = use real font metrics) */ struct pt_or_px line_height; diff --git a/doc/foot.ini.5.scd b/doc/foot.ini.5.scd index e18a6208..6443d2ba 100644 --- a/doc/foot.ini.5.scd +++ b/doc/foot.ini.5.scd @@ -80,6 +80,19 @@ empty string to be set, but it must be quoted: *KEY=""*) Default: _monospace:size=8_ (*font*), _not set_ (*font-bold*, *font-italic*, *font-bold-italic*). +*font-size-adjustment* + Amount, in _points_, _pixels_ or _percent_, to increment/decrement + the font size when zooming in our out. + + Examples: + ``` + font-size-adjustment=0.5 # Adjust by 0.5 points + font-size-adjustment=10xp # Adjust by 10 pixels + font-size-adjustment=7.5% # Adjust by 7.5 percent + ``` + + Default: _0.5_ + *include* Absolute path to configuration file to import. diff --git a/terminal.c b/terminal.c index 1914a229..78ce4bc3 100644 --- a/terminal.c +++ b/terminal.c @@ -2035,29 +2035,70 @@ term_reset(struct terminal *term, bool hard) } static bool -term_font_size_adjust(struct terminal *term, double amount) +term_font_size_adjust_by_points(struct terminal *term, float amount) { const struct config *conf = term->conf; - const float dpi = term->font_is_sized_by_dpi ? term->font_dpi : 96.; for (size_t i = 0; i < 4; i++) { const struct config_font_list *font_list = &conf->fonts[i]; for (size_t j = 0; j < font_list->count; j++) { - float old_pt_size = term->font_sizes[i][j].pt_size; + struct config_font *font = &term->font_sizes[i][j]; + float old_pt_size = font->pt_size; - /* - * To ensure primary and user-configured fallback fonts are - * resizes by the same amount, convert pixel sizes to point - * sizes, and to the adjustment on point sizes only. - */ + if (font->px_size > 0) + old_pt_size = font->px_size * 72. / dpi; - if (term->font_sizes[i][j].px_size > 0) - old_pt_size = term->font_sizes[i][j].px_size * 72. / dpi; + font->pt_size = fmaxf(old_pt_size + amount, 0.); + font->px_size = -1; + } + } - term->font_sizes[i][j].pt_size = fmaxf(old_pt_size + amount, 0.); - term->font_sizes[i][j].px_size = -1; + return reload_fonts(term); +} + +static bool +term_font_size_adjust_by_pixels(struct terminal *term, int amount) +{ + const struct config *conf = term->conf; + const float dpi = term->font_is_sized_by_dpi ? term->font_dpi : 96.; + + for (size_t i = 0; i < 4; i++) { + const struct config_font_list *font_list = &conf->fonts[i]; + + for (size_t j = 0; j < font_list->count; j++) { + struct config_font *font = &term->font_sizes[i][j]; + int old_px_size = font->px_size; + + if (font->px_size <= 0) + old_px_size = font->pt_size * dpi / 72.; + + font->px_size = max(old_px_size + amount, 1); + } + } + + return reload_fonts(term); +} + +static bool +term_font_size_adjust_by_percent(struct terminal *term, bool increment, float percent) +{ + const struct config *conf = term->conf; + const float multiplier = increment + ? 1. + percent + : 1. / (1. + percent); + + for (size_t i = 0; i < 4; i++) { + const struct config_font_list *font_list = &conf->fonts[i]; + + for (size_t j = 0; j < font_list->count; j++) { + struct config_font *font = &term->font_sizes[i][j]; + + if (font->px_size > 0) + font->px_size = max(font->px_size * multiplier, 1); + else + font->pt_size = fmax(font->pt_size * multiplier, 0); } } @@ -2067,19 +2108,29 @@ term_font_size_adjust(struct terminal *term, double amount) bool term_font_size_increase(struct terminal *term) { - if (!term_font_size_adjust(term, 0.5)) - return false; + const struct config *conf = term->conf; + const struct font_size_adjustment *inc_dec = &conf->font_size_adjustment; - return true; + if (inc_dec->percent > 0.) + return term_font_size_adjust_by_percent(term, true, inc_dec->percent); + else if (inc_dec->pt_or_px.px > 0) + return term_font_size_adjust_by_pixels(term, inc_dec->pt_or_px.px); + else + return term_font_size_adjust_by_points(term, inc_dec->pt_or_px.pt); } bool term_font_size_decrease(struct terminal *term) { - if (!term_font_size_adjust(term, -0.5)) - return false; + const struct config *conf = term->conf; + const struct font_size_adjustment *inc_dec = &conf->font_size_adjustment; - return true; + if (inc_dec->percent > 0.) + return term_font_size_adjust_by_percent(term, false, inc_dec->percent); + else if (inc_dec->pt_or_px.px > 0) + return term_font_size_adjust_by_pixels(term, -inc_dec->pt_or_px.px); + else + return term_font_size_adjust_by_points(term, -inc_dec->pt_or_px.pt); } bool diff --git a/tests/test-config.c b/tests/test-config.c index ae7969dc..4f8b0c3b 100644 --- a/tests/test-config.c +++ b/tests/test-config.c @@ -467,6 +467,7 @@ test_section_main(void) test_boolean(&ctx, &parse_section_main, "locked-title", &conf.locked_title); test_boolean(&ctx, &parse_section_main, "notify-focus-inhibit", &conf.notify_focus_inhibit); + test_pt_or_px(&ctx, &parse_section_main, "font-size-adjustment", &conf.font_size_adjustment.pt_or_px); /* TODO: test ‘N%’ values too */ test_pt_or_px(&ctx, &parse_section_main, "line-height", &conf.line_height); test_pt_or_px(&ctx, &parse_section_main, "letter-spacing", &conf.letter_spacing); test_pt_or_px(&ctx, &parse_section_main, "horizontal-letter-offset", &conf.horizontal_letter_offset);