diff --git a/README.md b/README.md index 31ade7e..dac530e 100644 --- a/README.md +++ b/README.md @@ -253,6 +253,8 @@ colors # size=1.0 (logo scale, e.g. 2.0 for double size) # depth=1.0 (3D extrusion depth, e.g. 3.0 for chunkier look) # height=36 (override render height in rows) +# v_alignment=top (top, center, bottom) +# h_alignment=left (left, center, right) ``` ## Options diff --git a/fetch.c b/fetch.c index c3a1052..a4e01b1 100644 --- a/fetch.c +++ b/fetch.c @@ -33,6 +33,17 @@ static struct termios orig_termios; static int termios_saved = 0; +enum v_alignment { + V_ALIGN_TOP, + V_ALIGN_CENTER, + V_ALIGN_BOTTOM +}; +enum h_alignment { + H_ALIGN_LEFT, + H_ALIGN_CENTER, + H_ALIGN_RIGHT +}; + static void cleanup(void) { if (termios_saved) tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios); @@ -75,6 +86,8 @@ static int anim_width = ANIM_WIDTH; // canvas columns, shrinks on narrow termina static int layout_stacked = 0; // info below the logo instead of beside it static int info_clip_cols = -1; // clip info lines to this many visible columns static int stacked_info_rows = 0; // info lines shown in stacked layout +static int term_cols = 0; +static int term_rows = 0; #define PI 3.14159265f #ifndef FETCH_VERSION #define FETCH_VERSION "dev" @@ -898,6 +911,8 @@ static char config_logo_inner[32] = ""; #define MAX_EXTRA_DISKS 8 static char extra_disks[MAX_EXTRA_DISKS][128]; static int extra_disk_count = 0; +static enum v_alignment config_v_alignment = V_ALIGN_TOP; +static enum h_alignment config_h_alignment = H_ALIGN_LEFT; // Light direction presets static float light_x = 0.4082f, light_y = 0.8165f, light_z = -0.4082f; @@ -1142,6 +1157,32 @@ static void load_config(void) { continue; } + if (strncmp(line, "v_alignment=", 12) == 0) { + char *val = line + 12; + strip_inline_hint(val); + if (strcmp(val, "top") == 0) { + config_v_alignment = V_ALIGN_TOP; + } else if (strcmp(val, "center") == 0) { + config_v_alignment = V_ALIGN_CENTER; + } else if (strcmp(val, "bottom") == 0) { + config_v_alignment = V_ALIGN_BOTTOM; + } + continue; + } + + if (strncmp(line, "h_alignment=", 12) == 0) { + char *val = line + 12; + strip_inline_hint(val); + if (strcmp(val, "left") == 0) { + config_h_alignment = H_ALIGN_LEFT; + } else if (strcmp(val, "center") == 0) { + config_h_alignment = H_ALIGN_CENTER; + } else if (strcmp(val, "right") == 0) { + config_h_alignment = H_ALIGN_RIGHT; + } + continue; + } + // Match field name for (int i = 0; field_map[i].name; i++) { if (strcasecmp(line, field_map[i].name) == 0) { @@ -3554,8 +3595,8 @@ static const char *cell_glyph(int row, int col, int smax, int *color_out) { // shrink the canvas to keep the info intact; phone-width ones stack the // info below the logo. Info lines clip instead of wrapping. static void apply_layout(int show_info) { - int rows = 0, cols = 0; - get_term_size(&rows, &cols); + int rows = term_rows; + int cols = term_cols; if (rows > 1) rows--; // leave 1 row margin to prevent scroll-jitter @@ -3899,6 +3940,42 @@ static void set_distro_colors(const char *distro) { } } +static void get_alignment_padding(int* vertical, int* horizontal) { + size_t max = 0; + for (int i = 0; i < fetch_line_count; i++) { + size_t len = visible_width(fetch_lines[i]); + if (len > max) { + max = len; + } + } + + switch (config_v_alignment) { + default: + case V_ALIGN_TOP: + *vertical = 0; + break; + case V_ALIGN_CENTER: + *vertical = term_rows / 2 - render_height / 2; + break; + case V_ALIGN_BOTTOM: + *vertical = term_rows - (render_height); + break; + } + + switch (config_h_alignment) { + default: + case H_ALIGN_LEFT: + *horizontal = 0; + break; + case H_ALIGN_CENTER: + *horizontal = term_cols / 2 - (anim_width + GAP + max) / 2; + break; + case H_ALIGN_RIGHT: + *horizontal= term_cols - (anim_width + GAP + max); + break; + } +} + int main(int argc, char **argv) { char distro[64] = ""; const char *logo_name = NULL; @@ -4061,6 +4138,7 @@ int main(int argc, char **argv) { config_defaults(); load_config(); + get_term_size(&term_rows, &term_cols); // Shading: CLI flags, then config, then the ascii default if (!shading && config_shading[0]) @@ -4292,6 +4370,7 @@ int main(int argc, char **argv) { // Handle terminal resize: recompute the same layout as startup if (term_resized) { term_resized = 0; + get_term_size(&term_rows, &term_cols); int old_h = render_height, old_w = anim_width; int old_stacked = layout_stacked, old_clip = info_clip_cols; apply_layout(show_info); @@ -4395,10 +4474,14 @@ int main(int argc, char **argv) { } } + int top_padding; + int left_padding; + get_alignment_padding(&top_padding, &left_padding); + // Batch entire frame into a single write (reuse buffer across frames) static char *out_buf = NULL; static size_t out_cap = 0; - size_t need = (render_height + stacked_info_rows + 2) * 2048u + 64; + size_t need = (render_height + stacked_info_rows + 2) * (2048u + left_padding) + 64 + top_padding; if (need > out_cap) { free(out_buf); out_buf = malloc(need); @@ -4424,7 +4507,17 @@ int main(int argc, char **argv) { int inner_len = strlen(color_inner); int outer_len = strlen(color_outer); + if (top_padding > 0) { + memset(p, '\n', top_padding); + p += top_padding; + } + for (int i = 0; i < render_height && p + 8 < end; i++) { + if (left_padding > 0) { + memset(p, ' ', left_padding); + p += left_padding; + } + if (!use_color) { for (int j = 0; j < aw && p + 8 < end; j++) { int c = 0;