]> git.mdlowis.com Git - proto/labwc.git/commitdiff
menu: render submenu arrows
authorJohan Malm <jgm323@gmail.com>
Tue, 2 Aug 2022 21:00:24 +0000 (22:00 +0100)
committerConsolatis <35009135+Consolatis@users.noreply.github.com>
Fri, 12 Aug 2022 09:16:17 +0000 (11:16 +0200)
include/common/font.h
include/common/scaled_font_buffer.h
src/common/font.c
src/common/scaled_font_buffer.c
src/menu/menu.c
src/ssd/ssd_titlebar.c

index e64dbbac585781ca72ff9c8126d489f333370878..afb78cf9fb88bbf11427e97162e84eca0aa6d3b3 100644 (file)
@@ -28,9 +28,11 @@ int font_width(struct font *font, const char *string);
  * @text: text to be generated as texture
  * @font: font description
  * @color: foreground color in rgba format
+ * @arrow: arrow (utf8) character to show or NULL for none
  */
 void font_buffer_create(struct lab_data_buffer **buffer, int max_width,
-       const char *text, struct font *font, float *color, double scale);
+       const char *text, struct font *font, float *color, const char *arrow,
+       double scale);
 
 /**
  * font_finish - free some font related resources
index 94debeaad574bca98ff131b6b45799ba60b0c3f9..dbce8fff64b92e9b89a523425d6cd8139e9f6384 100644 (file)
@@ -16,6 +16,7 @@ struct scaled_font_buffer {
        char *text;
        int max_width;
        float color[4];
+       char *arrow;
        struct font font;
        struct scaled_scene_buffer *scaled_buffer;
 };
@@ -44,6 +45,6 @@ struct scaled_font_buffer *scaled_font_buffer_create(struct wlr_scene_tree *pare
  * - font and color the same
  */
 void scaled_font_buffer_update(struct scaled_font_buffer *self, const char *text,
-       int max_width, struct font *font, float *color);
+       int max_width, struct font *font, float *color, const char *arrow);
 
 #endif /* __LAB_COMMON_SCALED_FONT_BUFFER_H */
index 02cfc197a5e4d92555020e51f14a9c1e4a378f65..9fd49b50113922183ab477f80648628eb1a9e97c 100644 (file)
@@ -1,4 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
+#include <assert.h>
 #include <cairo.h>
 #include <drm_fourcc.h>
 #include <pango/pangocairo.h>
 static PangoRectangle
 font_extents(struct font *font, const char *string)
 {
-       PangoRectangle rect;
+       PangoRectangle rect = { 0 };
+       if (!string) {
+               return rect;
+       }
        cairo_surface_t *surface;
        cairo_t *c;
        PangoLayout *layout;
@@ -58,20 +62,37 @@ font_width(struct font *font, const char *string)
 
 void
 font_buffer_create(struct lab_data_buffer **buffer, int max_width,
-       const char *text, struct font *font, float *color, double scale)
+       const char *text, struct font *font, float *color, const char *arrow,
+       double scale)
 {
+       /* Allow a minimum of one pixel each for text and arrow */
+       if (max_width < 2) {
+               max_width = 2;
+       }
+
        if (!text || !*text) {
                return;
        }
 
-       PangoRectangle rect = font_extents(font, text);
-       if (max_width && rect.width > max_width) {
-               rect.width = max_width;
+       PangoRectangle text_extents = font_extents(font, text);
+       PangoRectangle arrow_extents = font_extents(font, arrow);
+
+       if (arrow) {
+               if (arrow_extents.width >= max_width - 1) {
+                       /* It would be weird to get here, but just in case */
+                       arrow_extents.width = max_width - 1;
+                       text_extents.width = 1;
+               } else {
+                       text_extents.width = max_width - arrow_extents.width;
+               }
+       } else if (text_extents.width > max_width) {
+               text_extents.width = max_width;
        }
-       *buffer = buffer_create_cairo(rect.width, rect.height, scale, true);
+
+       *buffer = buffer_create_cairo(text_extents.width + arrow_extents.width,
+                       text_extents.height, scale, true);
        if (!*buffer) {
-               wlr_log(WLR_ERROR, "Failed to create font buffer of size %dx%d",
-                       rect.width, rect.height);
+               wlr_log(WLR_ERROR, "Failed to create font buffer");
                return;
        }
 
@@ -82,7 +103,7 @@ font_buffer_create(struct lab_data_buffer **buffer, int max_width,
        cairo_move_to(cairo, 0, 0);
 
        PangoLayout *layout = pango_cairo_create_layout(cairo);
-       pango_layout_set_width(layout, rect.width * PANGO_SCALE);
+       pango_layout_set_width(layout, text_extents.width * PANGO_SCALE);
        pango_layout_set_text(layout, text, -1);
        pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
 
@@ -92,8 +113,15 @@ font_buffer_create(struct lab_data_buffer **buffer, int max_width,
        pango_layout_set_font_description(layout, desc);
        pango_font_description_free(desc);
        pango_cairo_update_layout(cairo, layout);
-
        pango_cairo_show_layout(cairo, layout);
+
+       if (arrow) {
+               cairo_move_to(cairo, text_extents.width, 0);
+               pango_layout_set_width(layout, arrow_extents.width * PANGO_SCALE);
+               pango_layout_set_text(layout, arrow, -1);
+               pango_cairo_show_layout(cairo, layout);
+       }
+
        g_object_unref(layout);
 
        cairo_surface_flush(surf);
index 66375a728166428e1f4d62bd501b10be772d9e2e..ef2548dd5304c585bcfbaf5503aefd8b9c4e686f 100644 (file)
@@ -19,7 +19,7 @@ _create_buffer(struct scaled_scene_buffer *scaled_buffer, double scale)
 
        /* Buffer gets free'd automatically along the backing wlr_buffer */
        font_buffer_create(&buffer, self->max_width, self->text,
-               &self->font, self->color, scale);
+               &self->font, self->color, self->arrow, scale);
 
        self->width = buffer ? buffer->unscaled_width : 0;
        self->height = buffer ? buffer->unscaled_height : 0;
@@ -36,6 +36,7 @@ _destroy(struct scaled_scene_buffer *scaled_buffer)
        if (self->font.name) {
                zfree(self->font.name);
        }
+       zfree(self->arrow);
        zfree(scaled_buffer->data);
 }
 
@@ -68,8 +69,9 @@ scaled_font_buffer_create(struct wlr_scene_tree *parent)
 }
 
 void
-scaled_font_buffer_update(struct scaled_font_buffer *self,
-               const char *text, int max_width, struct font *font, float *color)
+scaled_font_buffer_update(struct scaled_font_buffer *self, const char *text,
+               int max_width, struct font *font, float *color,
+               const char *arrow)
 {
        assert(self);
        assert(text);
@@ -83,6 +85,7 @@ scaled_font_buffer_update(struct scaled_font_buffer *self,
        if (self->font.name) {
                zfree(self->font.name);
        }
+       zfree(self->arrow);
 
        /* Update internal state */
        self->text = strdup(text);
@@ -92,6 +95,7 @@ scaled_font_buffer_update(struct scaled_font_buffer *self,
        }
        self->font.size = font->size;
        memcpy(self->color, color, sizeof(self->color));
+       self->arrow = arrow ? strdup(arrow) : NULL;
 
        /* Invalidate cache and force a new render */
        scaled_scene_buffer_invalidate_cache(self->scaled_buffer);
index fa4d26092a6ab9c08d9930a3e6ef05ce16bc5cf4..0aeae3731daf1484110c5aa101260005e02cf6ac 100644 (file)
@@ -78,7 +78,7 @@ menu_get_by_id(const char *id)
 }
 
 static struct menuitem *
-item_create(struct menu *menu, const char *text)
+item_create(struct menu *menu, const char *text, bool show_arrow)
 {
        struct menuitem *menuitem = calloc(1, sizeof(struct menuitem));
        if (!menuitem) {
@@ -137,10 +137,11 @@ item_create(struct menu *menu, const char *text)
        menuitem->selected.text = &menuitem->selected.buffer->scene_buffer->node;
 
        /* Font buffers */
+       const char *arrow = show_arrow ? "›" : NULL;
        scaled_font_buffer_update(menuitem->normal.buffer, text, item_max_width,
-               &font, theme->menu_items_text_color);
+               &font, theme->menu_items_text_color, arrow);
        scaled_font_buffer_update(menuitem->selected.buffer, text, item_max_width,
-               &font, theme->menu_items_active_text_color);
+               &font, theme->menu_items_active_text_color, arrow);
 
        /* Center font nodes */
        x = MENU_ITEM_PADDING_X;
@@ -221,7 +222,7 @@ fill_item(char *nodename, char *content)
 
        /* <item label=""> defines the start of a new item */
        if (!strcmp(nodename, "label")) {
-               current_item = item_create(current_menu, content);
+               current_item = item_create(current_menu, content, false);
                current_item_action = NULL;
        } else if (!current_item) {
                wlr_log(WLR_ERROR, "expect <item label=\"\"> element first. "
@@ -349,7 +350,7 @@ handle_menu_element(xmlNode *n, struct server *server)
                         * In a nested (inline) menu definition we need to
                         * create an item pointing to the new submenu
                         */
-                       current_item = item_create(current_menu, label);
+                       current_item = item_create(current_menu, label, true);
                        if (current_item) {
                                submenu = &current_item->submenu;
                        } else {
@@ -371,7 +372,7 @@ handle_menu_element(xmlNode *n, struct server *server)
                 */
                struct menu *menu = menu_get_by_id(id);
                if (menu) {
-                       current_item = item_create(current_menu, menu->label);
+                       current_item = item_create(current_menu, menu->label, true);
                        if (current_item) {
                                current_item->submenu = menu;
                        }
@@ -592,9 +593,9 @@ menu_init_rootmenu(struct server *server)
                menu = menu_create(server, "root-menu", "");
        }
        if (wl_list_empty(&menu->menuitems)) {
-               current_item = item_create(menu, _("Reconfigure"));
+               current_item = item_create(menu, _("Reconfigure"), false);
                fill_item("name.action", "Reconfigure");
-               current_item = item_create(menu, _("Exit"));
+               current_item = item_create(menu, _("Exit"), false);
                fill_item("name.action", "Exit");
        }
 }
@@ -610,33 +611,33 @@ menu_init_windowmenu(struct server *server)
                menu = menu_create(server, "client-menu", "");
        }
        if (wl_list_empty(&menu->menuitems)) {
-               current_item = item_create(menu, _("Minimize"));
+               current_item = item_create(menu, _("Minimize"), false);
                fill_item("name.action", "Iconify");
-               current_item = item_create(menu, _("Maximize"));
+               current_item = item_create(menu, _("Maximize"), false);
                fill_item("name.action", "ToggleMaximize");
-               current_item = item_create(menu, _("Fullscreen"));
+               current_item = item_create(menu, _("Fullscreen"), false);
                fill_item("name.action", "ToggleFullscreen");
-               current_item = item_create(menu, _("Decorations"));
+               current_item = item_create(menu, _("Decorations"), false);
                fill_item("name.action", "ToggleDecorations");
-               current_item = item_create(menu, _("AlwaysOnTop"));
+               current_item = item_create(menu, _("AlwaysOnTop"), false);
                fill_item("name.action", "ToggleAlwaysOnTop");
 
                /* Workspace sub-menu */
                struct menu *workspace_menu = menu_create(server, "workspaces", "");
-               current_item = item_create(workspace_menu, _("Move left"));
+               current_item = item_create(workspace_menu, _("Move left"), false);
                fill_item("name.action", "SendToDesktop");
                fill_item("to.action", "left");
                fill_item("name.action", "GoToDesktop");
                fill_item("to.action", "left");
-               current_item = item_create(workspace_menu, _("Move right"));
+               current_item = item_create(workspace_menu, _("Move right"), false);
                fill_item("name.action", "SendToDesktop");
                fill_item("to.action", "right");
                fill_item("name.action", "GoToDesktop");
                fill_item("to.action", "right");
-               current_item = item_create(menu, _("Workspace"));
+               current_item = item_create(menu, _("Workspace"), true);
                current_item->submenu = workspace_menu;
 
-               current_item = item_create(menu, _("Close"));
+               current_item = item_create(menu, _("Close"), false);
                fill_item("name.action", "Close");
        }
 
index bac4c7edb387ad9242faf7c14232719545670f3c..3ae0b78bb6d043f55602e46bfb24676c163a2585 100644 (file)
@@ -254,8 +254,8 @@ ssd_update_title(struct view *view)
                }
 
                if (part->buffer) {
-                       scaled_font_buffer_update(part->buffer,
-                               title, title_bg_width, &font, text_color);
+                       scaled_font_buffer_update(part->buffer, title,
+                               title_bg_width, &font, text_color, NULL);
                }
 
                /* And finally update the cache */