From cc44d9a99918d5a92766b5db9e0ba034935298bb Mon Sep 17 00:00:00 2001 From: Orestis Floros Date: Tue, 7 Sep 2021 19:52:38 +0200 Subject: [PATCH] Make window icons follow title alignment Fixes #4464. Inspired by changes from #4453 but I didn't end up using the original code. For ALIGN_LEFT and ALIGN_CENTER icon offset is calculated first and then title offset is based on that. For ALIGN_RIGHT title offset is calculated first but we make sure that the icon fits in the window. Additionally, icons will now hide if there is not enough space to render them + their padding. Realistically, this won't happen in normal usecases. Effectively, icons have higher precedence over text: draw_util_text will hide text when it exceeds the max width and the code takes this into consideration. Icons will only hide when they can't fit at all, not in order to assure that the text can be displayed fully. --- src/x.c | 81 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 44 insertions(+), 37 deletions(-) diff --git a/src/x.c b/src/x.c index 55dc63a0b..cdc298767 100644 --- a/src/x.c +++ b/src/x.c @@ -614,33 +614,11 @@ void x_draw_decoration(Con *con) { /* 6: draw the icon and title */ int text_offset_y = (con->deco_rect.height - config.font.height) / 2; - int text_offset_x = 0; struct Window *win = con->window; - const int title_padding = logical_px(2); const int deco_width = (int)con->deco_rect.width; - - /* Draw the icon */ - if (con->window_icon_padding > -1 && win && win->icon) { - /* icon_padding is applied horizontally only, - * the icon will always use all available vertical space. */ - const int icon_padding = logical_px(1 + con->window_icon_padding); - - const uint16_t icon_size = con->deco_rect.height - 2 * logical_px(1); - - const int icon_offset_y = logical_px(1); - - text_offset_x += icon_size + 2 * icon_padding; - - draw_util_image( - win->icon, - &(parent->frame_buffer), - con->deco_rect.x + icon_padding, - con->deco_rect.y + icon_offset_y, - icon_size, - icon_size); - } + const int title_padding = logical_px(2); int mark_width = 0; if (config.show_marks && !TAILQ_EMPTY(&(con->marks_head))) { @@ -699,33 +677,62 @@ void x_draw_decoration(Con *con) { goto copy_pixmaps; } + /* icon_padding is applied horizontally only, the icon will always use all + * available vertical space. */ + int icon_size = max(0, con->deco_rect.height - logical_px(2)); + int icon_padding = logical_px(max(1, con->window_icon_padding)); + int total_icon_space = icon_size + 2 * icon_padding; + const bool has_icon = (con->window_icon_padding > -1) && win && win->icon && (total_icon_space < deco_width); + if (!has_icon) { + icon_size = icon_padding = total_icon_space = 0; + } + /* Determine x offsets according to title alignment */ + int icon_offset_x; int title_offset_x; switch (config.title_align) { case ALIGN_LEFT: - /* (pad)[text ](pad)[mark + its pad) */ - title_offset_x = title_padding; + /* (pad)[(pad)(icon)(pad)][text ](pad)[mark + its pad) + * ^ ^--- title_offset_x + * ^--- icon_offset_x */ + icon_offset_x = icon_padding; + title_offset_x = title_padding + total_icon_space; break; case ALIGN_CENTER: - /* (pad)[ text ](pad)[mark + its pad) - * To center the text inside its allocated space, the surface - * between the brackets, we use the formula - * (surface_width - predict_text_width) / 2 - * where surface_width = deco_width - 2 * pad - mark_width - * so, offset = pad + (surface_width - predict_text_width) / 2 = - * = … = (deco_width - mark_width - predict_text_width) / 2 */ - title_offset_x = max(title_padding, (deco_width - mark_width - predict_text_width(title)) / 2); + /* (pad)[ ][(pad)(icon)(pad)][text ](pad)[mark + its pad) + * ^ ^--- title_offset_x + * ^--- icon_offset_x + * Text should come right after the icon (+padding). We calculate + * the offset for the icon (white space in the title) by dividing + * by two the total available area. That's the decoration width + * minus the elements that come after icon_offset_x (icon, its + * padding, text, marks). */ + icon_offset_x = max(icon_padding, (deco_width - icon_padding - icon_size - predict_text_width(title) - title_padding - mark_width) / 2); + title_offset_x = max(title_padding, icon_offset_x + icon_padding + icon_size); break; case ALIGN_RIGHT: - /* [mark + its pad](pad)[ text](pad) */ - title_offset_x = max(title_padding + mark_width, deco_width - title_padding - predict_text_width(title)); + /* [mark + its pad](pad)[ text][(pad)(icon)(pad)](pad) + * ^ ^--- icon_offset_x + * ^--- title_offset_x */ + title_offset_x = max(title_padding + mark_width, deco_width - title_padding - predict_text_width(title) - total_icon_space); + /* Make sure the icon does not escape title boundaries */ + icon_offset_x = min(deco_width - icon_size - icon_padding - title_padding, title_offset_x + predict_text_width(title) + icon_padding); break; } draw_util_text(title, &(parent->frame_buffer), p->color->text, p->color->background, - con->deco_rect.x + text_offset_x + title_offset_x, + con->deco_rect.x + title_offset_x, con->deco_rect.y + text_offset_y, - deco_width - text_offset_x - mark_width - 2 * title_padding); + deco_width - mark_width - 2 * title_padding - total_icon_space); + if (has_icon) { + draw_util_image( + win->icon, + &(parent->frame_buffer), + con->deco_rect.x + icon_offset_x, + con->deco_rect.y + logical_px(1), + icon_size, + icon_size); + } if (win == NULL || con->title_format != NULL) { I3STRING_FREE(title);