Refactor rendering code - wmenu - 🔧 fork of wmenu
 (HTM) git clone git@git.drkhsh.at/wmenu.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 628a5d82eedb93401e71f08c8ad976294ba6453e
 (DIR) parent da25fbfb275e5f9ffa7fff3ff1cd1d6f16c652b1
 (HTM) Author: adnano <me@adnano.co>
       Date:   Mon, 26 Feb 2024 16:14:04 -0500
       
       Refactor rendering code
       
       Diffstat:
         M main.c                              |     157 ++++++++++++-------------------
       
       1 file changed, 61 insertions(+), 96 deletions(-)
       ---
 (DIR) diff --git a/main.c b/main.c
       @@ -171,7 +171,7 @@ static void page_items(struct menu *menu) {
                }
        }
        
       -static const char * fstrstr(struct menu *menu, const char *s, const char *sub) {
       +static const char *fstrstr(struct menu *menu, const char *s, const char *sub) {
                for (size_t len = strlen(sub); *s; s++) {
                        if (!menu->strncmp(s, sub, len)) {
                                return s;
       @@ -261,6 +261,30 @@ static size_t nextrune(struct menu *menu, int incr) {
                return n;
        }
        
       +// Calculate text widths.
       +static void calc_widths(struct menu *menu) {
       +        cairo_t *cairo = menu->current->cairo;
       +
       +        // Calculate prompt width
       +        if (menu->prompt) {
       +                menu->promptw = text_width(cairo, menu->font, menu->prompt);
       +        } else {
       +                menu->promptw = 0;
       +        }
       +
       +        // Calculate scroll indicator widths
       +        menu->left_arrow = text_width(cairo, menu->font, "<") + 2 * menu->padding;
       +        menu->right_arrow = text_width(cairo, menu->font, ">") + 2 * menu->padding;
       +
       +        // Calculate item widths and input area width
       +        for (struct item *item = menu->items; item; item = item->next) {
       +                item->width = text_width(cairo, menu->font, item->text);
       +                if (item->width > menu->inputw) {
       +                        menu->inputw = item->width;
       +                }
       +        }
       +}
       +
        static void cairo_set_source_u32(cairo_t *cairo, uint32_t color) {
                cairo_set_source_rgba(cairo,
                                (color >> (3*8) & 0xFF) / 255.0,
       @@ -270,76 +294,47 @@ static void cairo_set_source_u32(cairo_t *cairo, uint32_t color) {
        }
        
        static int render_text(struct menu *menu, cairo_t *cairo, const char *str,
       -                int x, int y, int width, int height,
       -                uint32_t foreground, uint32_t background,
       +                int x, int y, int width, uint32_t bg_color, uint32_t fg_color,
                        int left_padding, int right_padding) {
        
                int text_width, text_height;
                get_text_size(cairo, menu->font, &text_width, &text_height, NULL, 1, str);
                int text_y = (menu->line_height / 2.0) - (text_height / 2.0);
        
       -        if (background) {
       -                int bg_width = text_width + left_padding + right_padding;
       -                cairo_set_source_u32(cairo, background);
       -                cairo_rectangle(cairo, x, y, bg_width, height);
       -                cairo_fill(cairo);
       +        if (width == 0) {
       +                width = text_width + left_padding + right_padding;
                }
       -
       -        cairo_move_to(cairo, x + left_padding, y + text_y);
       -        cairo_set_source_u32(cairo, foreground);
       -        pango_printf(cairo, menu->font, 1, str);
       -
       -        return x + text_width + left_padding + right_padding;
       -}
       -
       -static int render_horizontal_item(struct menu *menu, cairo_t *cairo, const char *str,
       -                int x, int y, int width, int height,
       -                uint32_t foreground, uint32_t background,
       -                int left_padding, int right_padding) {
       -
       -        int text_width, text_height;
       -        get_text_size(cairo, menu->font, &text_width, &text_height, NULL, 1, str);
       -        int text_y = (menu->line_height / 2.0) - (text_height / 2.0);
       -
       -        if (background) {
       -                int bg_width = text_width + left_padding + right_padding;
       -                cairo_set_source_u32(cairo, background);
       -                cairo_rectangle(cairo, x, y, bg_width, height);
       +        if (bg_color) {
       +                cairo_set_source_u32(cairo, bg_color);
       +                cairo_rectangle(cairo, x, y, width, menu->line_height);
                        cairo_fill(cairo);
                }
       -
                cairo_move_to(cairo, x + left_padding, y + text_y);
       -        cairo_set_source_u32(cairo, foreground);
       +        cairo_set_source_u32(cairo, fg_color);
                pango_printf(cairo, menu->font, 1, str);
        
       -        return x + text_width + left_padding + right_padding;
       +        return width;
        }
        
       -static void render_vertical_item(struct menu *menu, cairo_t *cairo, const char *str,
       -                int x, int y, int width, int height,
       -                uint32_t foreground, uint32_t background,
       -                int left_padding) {
       +static int render_horizontal_item(struct menu *menu, cairo_t *cairo, struct item *item, int x) {
       +        uint32_t bg_color = menu->sel == item ? menu->selectionbg : menu->background;
       +        uint32_t fg_color = menu->sel == item ? menu->selectionfg : menu->foreground;
        
       -        int text_height;
       -        get_text_size(cairo, menu->font, NULL, &text_height, NULL, 1, str);
       -        int text_y = (menu->line_height / 2.0) - (text_height / 2.0);
       +        return render_text(menu, cairo, item->text, x, 0, 0,
       +                bg_color, fg_color, menu->padding, menu->padding);
       +}
        
       -        if (background) {
       -                int bg_width = menu->width - x;
       -                cairo_set_source_u32(cairo, background);
       -                cairo_rectangle(cairo, x, y, bg_width, height);
       -                cairo_fill(cairo);
       -        }
       +static void render_vertical_item(struct menu *menu, cairo_t *cairo, struct item *item, int x, int y) {
       +        uint32_t bg_color = menu->sel == item ? menu->selectionbg : menu->background;
       +        uint32_t fg_color = menu->sel == item ? menu->selectionfg : menu->foreground;
        
       -        cairo_move_to(cairo, x + left_padding, y + text_y);
       -        cairo_set_source_u32(cairo, foreground);
       -        pango_printf(cairo, menu->font, 1, str);
       +        render_text(menu, cairo, item->text, x, y, menu->width - x,
       +                bg_color, fg_color, menu->padding, 0);
       +        return;
        }
        
        static void render_to_cairo(struct menu *menu, cairo_t *cairo) {
       -        int width = menu->width;
       -        int padding = menu->padding;
       -
       +        // Draw background
                cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
                cairo_set_source_u32(cairo, menu->background);
                cairo_paint(cairo);
       @@ -348,28 +343,19 @@ static void render_to_cairo(struct menu *menu, cairo_t *cairo) {
        
                // Draw prompt
                if (menu->prompt) {
       -                menu->promptw = render_text(menu, cairo, menu->prompt,
       -                                0, 0, menu->width, menu->line_height,
       -                                menu->promptfg, menu->promptbg,
       -                                padding, padding/2);
       -                x += menu->promptw;
       +                x += render_text(menu, cairo, menu->prompt, 0, 0, 0,
       +                        menu->promptbg, menu->promptfg, menu->padding, menu->padding/2);
                }
        
       -        // Draw background
       -        cairo_set_source_u32(cairo, menu->background);
       -        cairo_rectangle(cairo, x, 0, 300, menu->height);
       -        cairo_fill(cairo);
       -
                // Draw input
       -        render_text(menu, cairo, menu->text,
       -                        x, 0, menu->width, menu->line_height,
       -                        menu->foreground, 0, padding, padding);
       +        render_text(menu, cairo, menu->text, x, 0, 0,
       +                0, menu->foreground, menu->padding, menu->padding);
        
                // Draw cursor
                {
       -                int cursor_width = 2;
       -                int cursor_margin = 2;
       -                int cursor_pos = x + padding
       +                const int cursor_width = 2;
       +                const int cursor_margin = 2;
       +                int cursor_pos = x + menu->padding
                                + text_width(cairo, menu->font, menu->text)
                                - text_width(cairo, menu->font, &menu->text[menu->cursor])
                                - cursor_width / 2;
       @@ -382,50 +368,34 @@ static void render_to_cairo(struct menu *menu, cairo_t *cairo) {
                        return;
                }
        
       +        // Draw matches
                if (menu->vertical) {
                        // Draw matches vertically
                        int y = menu->line_height;
                        struct item *item;
                        for (item = menu->sel->page->first; item != menu->sel->page->last->next_match; item = item->next_match) {
       -                        uint32_t bg_color = menu->sel == item ? menu->selectionbg : menu->background;
       -                        uint32_t fg_color = menu->sel == item ? menu->selectionfg : menu->foreground;
       -                        render_vertical_item(menu, cairo, item->text,
       -                                x, y, width, menu->line_height,
       -                                fg_color, bg_color, padding);
       +                        render_vertical_item(menu, cairo, item, x, y);
                                y += menu->line_height;
                        }
                } else {
       -                // Leave room for input
       -                x += menu->inputw;
       -
       -                // Calculate scroll indicator widths
       -                menu->left_arrow = text_width(cairo, menu->font, "<") + 2 * padding;
       -                menu->right_arrow = text_width(cairo, menu->font, ">") + 2 * padding;
       -
       -                // Remember scroll indicator position
       -                int left_arrow_pos = x + padding;
       -                x += menu->left_arrow;
       +                // Leave room for input and left arrow
       +                x += menu->inputw + menu->left_arrow;
        
                        // Draw matches horizontally
                        struct item *item;
                        for (item = menu->sel->page->first; item != menu->sel->page->last->next_match; item = item->next_match) {
       -                        uint32_t bg_color = menu->sel == item ? menu->selectionbg : menu->background;
       -                        uint32_t fg_color = menu->sel == item ? menu->selectionfg : menu->foreground;
       -                        x = render_horizontal_item(menu, cairo, item->text,
       -                                x, 0, width - menu->right_arrow, menu->line_height,
       -                                fg_color, bg_color, padding, padding);
       -                        // TODO: Make sure render_horizontal_item doesn't return -1
       +                        x += render_horizontal_item(menu, cairo, item, x);
                        }
        
                        // Draw left scroll indicator if necessary
                        if (menu->sel->page->prev) {
       -                        cairo_move_to(cairo, left_arrow_pos, 0);
       +                        cairo_move_to(cairo, menu->promptw + menu->inputw + menu->padding, 0);
                                pango_printf(cairo, menu->font, 1, "<");
                        }
        
                        // Draw right scroll indicator if necessary
                        if (menu->sel->page->next) {
       -                        cairo_move_to(cairo, width - menu->right_arrow + padding, 0);
       +                        cairo_move_to(cairo, menu->width - menu->right_arrow + menu->padding, 0);
                                pango_printf(cairo, menu->font, 1, ">");
                        }
                }
       @@ -949,12 +919,6 @@ static void read_stdin(struct menu *menu) {
        
                        item->text = strdup(buf);
                        item->next = item->prev_match = item->next_match = NULL;
       -
       -                cairo_t *cairo = menu->current->cairo;
       -                item->width = text_width(cairo, menu->font, item->text);
       -                if (item->width > menu->inputw) {
       -                        menu->inputw = item->width;
       -                }
                }
        }
        
       @@ -1142,6 +1106,7 @@ int main(int argc, char **argv) {
                render_frame(&menu);
        
                read_stdin(&menu);
       +        calc_widths(&menu);
                match_items(&menu);
                render_frame(&menu);