Skip to content

Commit

Permalink
Make window icons follow title alignment
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
orestisfl committed Sep 8, 2021
1 parent 3bdea50 commit 581c06b
Showing 1 changed file with 44 additions and 37 deletions.
81 changes: 44 additions & 37 deletions src/x.c
Expand Up @@ -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))) {
Expand Down Expand Up @@ -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(min(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);
Expand Down

0 comments on commit 581c06b

Please sign in to comment.