diff --git a/include/common/graphic-helpers.h b/include/common/graphic-helpers.h index 067da644..1b4bcbe2 100644 --- a/include/common/graphic-helpers.h +++ b/include/common/graphic-helpers.h @@ -9,29 +9,49 @@ struct wlr_scene_tree; struct wlr_scene_rect; struct wlr_fbox; -struct multi_rect { +struct border_rect { struct wlr_scene_tree *tree; - int line_width; /* read-only */ + int border_width; /* read-only */ /* Private */ - struct wlr_scene_rect *top[3]; - struct wlr_scene_rect *bottom[3]; - struct wlr_scene_rect *left[3]; - struct wlr_scene_rect *right[3]; + struct wlr_scene_rect *top; + struct wlr_scene_rect *bottom; + struct wlr_scene_rect *left; + struct wlr_scene_rect *right; + struct wlr_scene_rect *bg; + + struct wl_listener destroy; +}; + +struct multi_rect { + struct wlr_scene_tree *tree; + + /* Private */ + struct border_rect *border_rects[3]; struct wl_listener destroy; }; +/** + * Create a new rectangular with a single border (border_rect). + * + * bg_color can take NULL, in which case no background is rendered. + * + * A border_rect can be positioned by positioning border_rect->tree->node. + * + * It can be destroyed by destroying its tree node (or one of its parent nodes). + * Once the tree node has been destroyed the struct will be free'd automatically. + */ +struct border_rect *border_rect_create(struct wlr_scene_tree *parent, + float border_color[4], float bg_color[4], int border_width); + +void border_rect_set_size(struct border_rect *rect, int width, int height); + /** * Create a new multi_rect. - * A multi_rect consists of 3 nested rectangular outlines. - * Each of the rectangular outlines is using the same @line_width - * but its own color based on the @colors argument. * - * The multi-rect can be positioned by positioning multi_rect->tree->node. - * - * It can be destroyed by destroying its tree node (or one of its - * parent nodes). Once the tree node has been destroyed the struct - * will be free'd automatically. + * A multi_rect consists of 3 nested border_rects without a background. + * Each of the border_rect is using the same @line_width but its own color + * based on the @colors argument. */ struct multi_rect *multi_rect_create(struct wlr_scene_tree *parent, float *colors[3], int line_width); diff --git a/src/common/graphic-helpers.c b/src/common/graphic-helpers.c index 4739b899..ba1dda4a 100644 --- a/src/common/graphic-helpers.c +++ b/src/common/graphic-helpers.c @@ -11,6 +11,83 @@ #include "common/macros.h" #include "common/mem.h" +static void +border_rect_destroy_notify(struct wl_listener *listener, void *data) +{ + struct border_rect *rect = wl_container_of(listener, rect, destroy); + wl_list_remove(&rect->destroy.link); + free(rect); +} + +struct border_rect * +border_rect_create(struct wlr_scene_tree *parent, float border_color[4], + float bg_color[4], int border_width) +{ + struct border_rect *rect = znew(*rect); + rect->border_width = border_width; + rect->tree = wlr_scene_tree_create(parent); + rect->destroy.notify = border_rect_destroy_notify; + wl_signal_add(&rect->tree->node.events.destroy, &rect->destroy); + + rect->top = wlr_scene_rect_create(rect->tree, 0, 0, border_color); + rect->right = wlr_scene_rect_create(rect->tree, 0, 0, border_color); + rect->bottom = wlr_scene_rect_create(rect->tree, 0, 0, border_color); + rect->left = wlr_scene_rect_create(rect->tree, 0, 0, border_color); + if (bg_color) { + rect->bg = wlr_scene_rect_create(rect->tree, 0, 0, bg_color); + } + + return rect; +} + +void +border_rect_set_size(struct border_rect *rect, int width, int height) +{ + assert(rect); + int border_width = rect->border_width; + + /* + * The border is drawn like below: + * + * <--width--> + * +---------+ ^ + * +-+-----+-+ | + * | | | | height + * | | | | | + * +-+-----+-+ | + * +---------+ v + */ + + /* Update positions (positions of top/left rectangles are static) */ + wlr_scene_node_set_position(&rect->top->node, + 0, 0); + wlr_scene_node_set_position(&rect->bottom->node, + 0, height - border_width); + wlr_scene_node_set_position(&rect->left->node, + 0, border_width); + wlr_scene_node_set_position(&rect->right->node, + width - border_width, border_width); + if (rect->bg) { + wlr_scene_node_set_position(&rect->bg->node, + border_width, border_width); + } + + /* Update sizes */ + wlr_scene_rect_set_size(rect->top, + width, border_width); + wlr_scene_rect_set_size(rect->bottom, + width, border_width); + wlr_scene_rect_set_size(rect->left, + border_width, height - border_width * 2); + wlr_scene_rect_set_size(rect->right, + border_width, height - border_width * 2); + if (rect->bg) { + wlr_scene_rect_set_size(rect->bg, + width - border_width * 2, + height - border_width * 2); + } +} + static void multi_rect_destroy_notify(struct wl_listener *listener, void *data) { @@ -23,61 +100,26 @@ struct multi_rect * multi_rect_create(struct wlr_scene_tree *parent, float *colors[3], int line_width) { struct multi_rect *rect = znew(*rect); - rect->line_width = line_width; rect->tree = wlr_scene_tree_create(parent); rect->destroy.notify = multi_rect_destroy_notify; wl_signal_add(&rect->tree->node.events.destroy, &rect->destroy); for (size_t i = 0; i < 3; i++) { - rect->top[i] = wlr_scene_rect_create(rect->tree, 0, 0, colors[i]); - rect->right[i] = wlr_scene_rect_create(rect->tree, 0, 0, colors[i]); - rect->bottom[i] = wlr_scene_rect_create(rect->tree, 0, 0, colors[i]); - rect->left[i] = wlr_scene_rect_create(rect->tree, 0, 0, colors[i]); - wlr_scene_node_set_position(&rect->top[i]->node, + rect->border_rects[i] = border_rect_create(rect->tree, colors[i], + NULL, line_width); + wlr_scene_node_set_position(&rect->border_rects[i]->tree->node, i * line_width, i * line_width); - wlr_scene_node_set_position(&rect->left[i]->node, - i * line_width, (i + 1) * line_width); } return rect; } void -multi_rect_set_size(struct multi_rect *rect, int width, int height) +multi_rect_set_size(struct multi_rect *multi_rect, int width, int height) { - assert(rect); - int line_width = rect->line_width; - - /* - * The outmost outline is drawn like below: - * - * |--width--| - * - * +---------+ --- - * +-+-----+-+ | - * | | | | height - * | | | | | - * +-+-----+-+ | - * +---------+ --- - */ - for (int i = 0; i < 3; i++) { - /* Reposition, top and left don't ever change */ - wlr_scene_node_set_position(&rect->right[i]->node, - width - (i + 1) * line_width, (i + 1) * line_width); - wlr_scene_node_set_position(&rect->bottom[i]->node, - i * line_width, height - (i + 1) * line_width); - - /* Update sizes */ - wlr_scene_rect_set_size(rect->top[i], - MAX(width - i * line_width * 2, 0), - line_width); - wlr_scene_rect_set_size(rect->bottom[i], - MAX(width - i * line_width * 2, 0), - line_width); - wlr_scene_rect_set_size(rect->left[i], - line_width, - MAX(height - (i + 1) * line_width * 2, 0)); - wlr_scene_rect_set_size(rect->right[i], - line_width, - MAX(height - (i + 1) * line_width * 2, 0)); + assert(multi_rect); + int line_width = multi_rect->border_rects[0]->border_width; + for (size_t i = 0; i < 3; i++) { + border_rect_set_size(multi_rect->border_rects[i], + width - i * line_width * 2, height - i * line_width * 2); } }