diff --git a/README.md b/README.md index d3c77bb..078078e 100644 --- a/README.md +++ b/README.md @@ -454,6 +454,29 @@ All further Items can be found via the command: ```bash sketchybar -m query default_menu_items ``` +### Group Items in a Bracket for e.g. colored sections +This feature is only on HEAD currently. + +It is possible to bracket together items via the command: +```bash +sketchybar -m add component bracket ... +``` +or with batching +```bash +sketchybar -m batch --add component bracket ... +``` +The first item must always be the one listed earliest in the config. It is now possible to +set properties for the bracket, just as for any item or component. Brackets currently only support all background features. +E.g., if I wanted a colored background around *all* my space components (which are named *code*, *writing*, *reading* and *entertainment*) I would set it up like this: +```bash +sketchybar -m batch --add component bracket primary_spaces code writing reading entertainment \ + \ + --set primary_spaces background_color=0xffffffff \ + background_corner_radius=4 \ + background_height=20 +``` +this draws a white background below all my space components. I plan to expand the capability of item brackets significantly in the future. + ## Credits yabai, spacebar, diff --git a/src/bar.c b/src/bar.c index 2e0b33c..47e2d25 100644 --- a/src/bar.c +++ b/src/bar.c @@ -95,6 +95,20 @@ void bar_draw_item_background(struct bar* bar, struct bar_item* bar_item, uint32 draw_rect(bar->context, draw_region, &bar_item->background.color, bar_item->background.corner_radius, bar_item->background.border_width, &bar_item->background.border_color, false); } +void bar_draw_group(struct bar* bar, struct bar_item* item, uint32_t adid) { + if (item->group && group_is_first_member(item->group, item)) { + struct bar_item* bar_item = item->group->members[0]; + + if (!bar_item->background.enabled) return; + bool custom_height = bar_item->background.height != 0; + uint32_t group_length = group_get_length(bar_item->group); + CGRect draw_region = {{item->bounding_rects[adid - 1]->origin.x - bar->origin.x - (item->position == BAR_POSITION_RIGHT ? group_length - bar_item_get_length(item) : 0), custom_height ? ((bar->frame.size.height - bar_item->background.height)) / 2 : (g_bar_manager.background.border_width + 1)}, + {group_length, custom_height ? bar_item->background.height : (bar->frame.size.height - 2*(g_bar_manager.background.border_width + 1))}}; + draw_region = CGRectInset(draw_region, bar_item->background.border_width / 2, bar_item->background.border_width / 2); + draw_rect(bar->context, draw_region, &bar_item->background.color, bar_item->background.corner_radius, bar_item->background.border_width, &bar_item->background.border_color, false); + } +} + void bar_draw_alias(struct bar* bar, struct bar_item* bar_item, uint32_t x) { if (!bar_item->has_alias || !bar_item->alias.image_ref) return; CGRect bounds = {{x, (bar->frame.size.height - bar_item->alias.bounds.size.height) / 2 + bar_item->y_offset},{bar_item->alias.bounds.size.width, bar_item->alias.bounds.size.height}}; @@ -187,6 +201,7 @@ void bar_redraw(struct bar* bar) { bar_item_append_associated_bar(bar_item, (1 << (adid - 1))); bar_item_set_bounding_rect_for_display(bar_item, adid, bar->origin); + bar_draw_group(bar, bar_item, adid); bar_draw_item_background(bar, bar_item, adid); bar_draw_line(bar, icon, icon_position.x, icon_position.y + bar_item->y_offset); bar_draw_line(bar, label, label_position.x, label_position.y + bar_item->y_offset); diff --git a/src/bar_item.c b/src/bar_item.c index ba7580a..163d63f 100644 --- a/src/bar_item.c +++ b/src/bar_item.c @@ -179,8 +179,10 @@ void bar_item_set_type(struct bar_item* bar_item, char type) { bar_item->has_graph = true; } else if (type == BAR_COMPONENT_GROUP) { + bar_item->drawing = false; bar_item->group = group_create(); group_init(bar_item->group); + group_add_member(bar_item->group, bar_item); } } @@ -274,7 +276,7 @@ void bar_item_destroy(struct bar_item* bar_item) { if (bar_item->has_graph) { graph_destroy(&bar_item->graph); } - if (bar_item->group) group_destroy(bar_item->group); + if (bar_item->group && bar_item->type == BAR_COMPONENT_GROUP) group_destroy(bar_item->group); free(bar_item); } diff --git a/src/group.c b/src/group.c index 935616a..b61340b 100644 --- a/src/group.c +++ b/src/group.c @@ -1,6 +1,8 @@ #include "group.h" #include "background.h" +#include "bar_item.h" #include +#include #include struct group* group_create() { @@ -10,6 +12,7 @@ struct group* group_create() { } void group_init(struct group* group) { + group->num_members = 0; group->members = NULL; } @@ -20,14 +23,33 @@ bool group_is_item_member(struct group* group, struct bar_item* item) { return false; } -void group_add_item(struct group* group, struct bar_item* item) { +void group_add_member(struct group* group, struct bar_item* item) { if (group_is_item_member(group, item)) return; group->num_members++; group->members = realloc(group->members, sizeof(struct bar_item*)*group->num_members); group->members[group->num_members - 1] = item; + item->group = group; +} + +bool group_is_first_member(struct group* group, struct bar_item* item) { + if (!group_is_item_member(group, item)) return false; + if (group->num_members > 1) {return group->members[1] == item; } + return false; +} + +uint32_t group_get_length(struct group* group) { + uint32_t length = 0; + for (int i = 1; i < group->num_members; i++) { + if (!group->members[i]->nospace || (group->members[i]->nospace && i == group->num_members - 1)) + length += bar_item_get_length(group->members[i]); + } + return length; } void group_destroy(struct group* group) { + for (int i = 0; i < group->num_members; i++) { + group->members[i]->group = NULL; + } if (group->members) free(group->members); free(group); } diff --git a/src/group.h b/src/group.h index a473d70..0f0dc85 100644 --- a/src/group.h +++ b/src/group.h @@ -11,7 +11,9 @@ struct group { struct group* group_create(); void group_init(struct group* group); void group_set_name(struct group* group, char* _name); -void group_add_item(struct group* group, struct bar_item* item); +void group_add_member(struct group* group, struct bar_item* item); +uint32_t group_get_length(struct group* group); +bool group_is_first_member(struct group* group, struct bar_item* item); void group_destroy(struct group* group); #endif diff --git a/src/message.c b/src/message.c index e6c158d..2b19167 100644 --- a/src/message.c +++ b/src/message.c @@ -4,6 +4,7 @@ #include "bar_item.h" #include "bar_manager.h" #include "display.h" +#include "group.h" #include "misc/helpers.h" #include <_types/_uint32_t.h> #include @@ -28,8 +29,6 @@ extern bool g_verbose; #define COMMAND_ADD_PLUGIN "plugin" #define COMMAND_ADD_EVENT "event" -#define DOMAIN_GROUP "bracket" - #define DOMAIN_REMOVE "remove" #define DOMAIN_UPDATE "update" @@ -348,6 +347,19 @@ static void handle_domain_add(FILE* rsp, struct token domain, char* message) { alias_init(&bar_item->alias, string_copy(owner), string_copy(nme)); free(tmp_name); } + else if (bar_item->type == BAR_COMPONENT_GROUP) { + struct token member = get_token(&message); + while (member.text && member.length > 0) { + int index = bar_manager_get_item_index_for_name(&g_bar_manager, member.text); + if (index >= 0) + group_add_member(bar_item->group, g_bar_manager.bar_items[index]); + else { + printf("Item %s not found! \n", member.text); + fprintf(rsp, "Item %s not found! \n", member.text); + } + member = get_token(&message); + } + } } else { printf("Command: %s not found \n", command.text); fprintf(rsp, "Command: %s not found \n", command.text); @@ -676,10 +688,6 @@ static void handle_domain_batch(FILE* rsp, struct token domain, char* message) { bar_manager_refresh(&g_bar_manager, true); } -static void handle_domain_group(FILE* rsp, struct token domain, char* message) { - -} - static void handle_domain_query(FILE* rsp, struct token domain, char* message) { struct token token = get_token(&message); @@ -717,8 +725,6 @@ void handle_message(int sockfd, char* message) { handle_domain_bar(rsp, domain, message); } else if (token_equals(domain, DOMAIN_ADD)){ handle_domain_add(rsp, domain, message); - } else if (token_equals(domain, DOMAIN_GROUP)){ - handle_domain_group(rsp, domain, message); } else if (token_equals(domain, DOMAIN_REMOVE)){ handle_domain_remove(rsp, domain, message); } else if (token_equals(domain, DOMAIN_UPDATE)) {