summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/bemenu-run.c1
-rw-r--r--client/bemenu.c1
-rw-r--r--client/common/common.c8
-rw-r--r--client/common/common.h1
-rw-r--r--lib/bemenu.h16
-rw-r--r--lib/internal.h5
-rw-r--r--lib/menu.c12
-rw-r--r--lib/renderers/cairo.h39
-rw-r--r--lib/renderers/curses/curses.c20
9 files changed, 86 insertions, 17 deletions
diff --git a/client/bemenu-run.c b/client/bemenu-run.c
index a1cb5ef..8f25348 100644
--- a/client/bemenu-run.c
+++ b/client/bemenu-run.c
@@ -19,6 +19,7 @@ static struct client client = {
.bottom = false,
.grab = false,
.wrap = false,
+ .scrollbar = false,
};
struct paths {
diff --git a/client/bemenu.c b/client/bemenu.c
index 6a4f95d..37dc9e2 100644
--- a/client/bemenu.c
+++ b/client/bemenu.c
@@ -16,6 +16,7 @@ static struct client client = {
.bottom = false,
.grab = false,
.wrap = false,
+ .scrollbar = false,
};
static void
diff --git a/client/common/common.c b/client/common/common.c
index e8ad262..72335e7 100644
--- a/client/common/common.c
+++ b/client/common/common.c
@@ -67,7 +67,8 @@ usage(FILE *out, const char *name)
" -l, --list list items vertically with the given number of lines.\n"
" -p, --prompt defines the prompt text to be displayed.\n"
" -P, --prefix text to shown before highlighted item.\n"
- " -I, --index select item at index automatically.\n\n"
+ " -I, --index select item at index automatically.\n"
+ " --scrollbar display scrollbar.\n\n"
"Use BEMENU_BACKEND env variable to force backend:\n"
" curses ncurses based terminal backend\n"
@@ -114,6 +115,7 @@ parse_args(struct client *client, int *argc, char **argv[])
{ "prompt", required_argument, 0, 'p' },
{ "index", required_argument, 0, 'I' },
{ "prefix", required_argument, 0, 'P' },
+ { "scrollbar", no_argument, 0, 0x113 },
{ "bottom", no_argument, 0, 'b' },
{ "grab", no_argument, 0, 'f' },
@@ -170,6 +172,9 @@ parse_args(struct client *client, int *argc, char **argv[])
case 'I':
client->selected = strtol(optarg, NULL, 10);
break;
+ case 0x113:
+ client->scrollbar = true;
+ break;
case 'b':
client->bottom = true;
@@ -249,6 +254,7 @@ menu_with_options(struct client *client)
bm_menu_set_wrap(menu, client->wrap);
bm_menu_set_bottom(menu, client->bottom);
bm_menu_set_monitor(menu, client->monitor);
+ bm_menu_set_scrollbar(menu, client->scrollbar);
for (uint32_t i = 0; i < BM_COLOR_LAST; ++i)
bm_menu_set_color(menu, i, client->colors[i]);
diff --git a/client/common/common.h b/client/common/common.h
index fab8758..914ddf0 100644
--- a/client/common/common.h
+++ b/client/common/common.h
@@ -15,6 +15,7 @@ struct client {
bool bottom;
bool grab;
bool wrap;
+ bool scrollbar;
};
void parse_args(struct client *client, int *argc, char **argv[]);
diff --git a/lib/bemenu.h b/lib/bemenu.h
index 54d82f9..490132f 100644
--- a/lib/bemenu.h
+++ b/lib/bemenu.h
@@ -387,6 +387,22 @@ bool bm_menu_set_color(struct bm_menu *menu, enum bm_color color, const char *he
const char* bm_menu_get_color(const struct bm_menu *menu, enum bm_color color);
/**
+ * Display scrollbar at left side of the menu.
+ *
+ * @param menu bm_menu instance to set scrollbar for.
+ * @param scrollbar true for scrollbar, false for no scrollbar.
+ */
+void bm_menu_set_scrollbar(struct bm_menu *menu, bool scrollbar);
+
+/**
+ * Is scrollbar being displayed on the menu?
+ *
+ * @param menu bm_menu instance where to get scrollbar display state from.
+ * @return true if scrollbar displayed, false otherwise.
+ */
+bool bm_menu_get_scrollbar(struct bm_menu *menu);
+
+/**
* Display menu at bottom of the screen.
* This may be no-op on some renderers (curses, wayland)
*
diff --git a/lib/internal.h b/lib/internal.h
index 7b71eb4..5291b56 100644
--- a/lib/internal.h
+++ b/lib/internal.h
@@ -287,6 +287,11 @@ struct bm_menu {
* Is menu grabbed?
*/
bool grabbed;
+
+ /**
+ * Scrollbar enabled?
+ */
+ bool scrollbar;
};
/* library.c */
diff --git a/lib/menu.c b/lib/menu.c
index 4fc00e7..0b39d83 100644
--- a/lib/menu.c
+++ b/lib/menu.c
@@ -296,6 +296,18 @@ char* bm_menu_get_color(const struct bm_menu *menu, enum bm_color color)
}
void
+bm_menu_set_scrollbar(struct bm_menu *menu, bool scrollbar)
+{
+ menu->scrollbar = scrollbar;
+}
+
+bool
+bm_menu_get_scrollbar(struct bm_menu *menu)
+{
+ return menu->scrollbar;
+}
+
+void
bm_menu_set_bottom(struct bm_menu *menu, bool bottom)
{
assert(menu);
diff --git a/lib/renderers/cairo.h b/lib/renderers/cairo.h
index 5eb5b68..c135a51 100644
--- a/lib/renderers/cairo.h
+++ b/lib/renderers/cairo.h
@@ -197,29 +197,31 @@ bm_cairo_paint(struct cairo *cairo, uint32_t width, uint32_t height, uint32_t ma
paint.pos = (struct pos){ (menu->title ? 2 : 0) + result.x_advance, 2 };
paint.box = (struct box){ (menu->title ? 2 : 4), 0, 2, 2, width - paint.pos.x, 0 };
bm_cairo_draw_line(cairo, &paint, &result, "%s", (menu->filter ? menu->filter : ""));
- out_result->height = result.height;
uint32_t count;
struct bm_item **items = bm_menu_get_filtered_items(menu, &count);
uint32_t lines = (menu->lines > 0 ? menu->lines : 1);
+ uint32_t titleh = result.height;
+ out_result->height = titleh;
if (lines > 1) {
/* vertical mode */
- uint32_t spacing = 0; // 0 == variable width spacing
- if (lines > max_height / result.height) {
+ uint32_t spacing_x = (menu->scrollbar ? 4 : 0);
+ uint32_t spacing_y = 0; // 0 == variable width spacing
+ if (lines > max_height / titleh) {
/* there is more lines than screen can fit, enter fixed spacing mode */
- lines = max_height / result.height - 1;
- spacing = result.height;
+ lines = max_height / titleh - 1;
+ spacing_y = titleh;
}
- uint32_t start_x = 0;
+ uint32_t prefix_x = 0;
if (menu->prefix) {
bm_pango_get_text_extents(cairo, &paint, &result, "%s ", menu->prefix);
- start_x = result.x_advance;
+ prefix_x += result.x_advance;
}
- uint32_t posy = out_result->height;
+ uint32_t posy = titleh;
for (uint32_t l = 0, i = (menu->index / lines) * lines; l < lines && i < count && posy < max_height; ++i, ++l) {
bool highlighted = (items[i] == bm_menu_get_highlighted_item(menu));
@@ -236,18 +238,33 @@ bm_cairo_paint(struct cairo *cairo, uint32_t width, uint32_t height, uint32_t ma
if (menu->prefix && highlighted) {
paint.pos = (struct pos){ 0, 2 + posy };
- paint.box = (struct box){ 4, 0, 2, 2, width - paint.pos.x, 0 };
+ paint.box = (struct box){ 4 + spacing_x, 0, 2, 2, width - paint.pos.x, 0 };
bm_cairo_draw_line(cairo, &paint, &result, "%s %s", menu->prefix, (items[i]->text ? items[i]->text : ""));
} else {
paint.pos = (struct pos){ 0, 2 + posy };
- paint.box = (struct box){ 4 + start_x, 0, 2, 2, width - paint.pos.x, 0 };
+ paint.box = (struct box){ 4 + spacing_x + prefix_x, 0, 2, 2, width - paint.pos.x, 0 };
bm_cairo_draw_line(cairo, &paint, &result, "%s", (items[i]->text ? items[i]->text : ""));
}
- posy += (spacing ? spacing : result.height);
+ posy += (spacing_y ? spacing_y : result.height);
out_result->height = posy + 2;
out_result->displayed++;
}
+
+ if (menu->scrollbar && count > 0) {
+ uint32_t sheight = out_result->height - titleh;
+ bm_cairo_color_from_menu_color(menu, BM_COLOR_TITLE_FG, &paint.bg);
+ cairo_set_source_rgba(cairo->cr, paint.bg.r, paint.bg.b, paint.bg.g, paint.bg.a);
+ cairo_rectangle(cairo->cr, 0, titleh, 2, sheight);
+ cairo_fill(cairo->cr);
+
+ uint32_t size = sheight / lines;
+ uint32_t percent = (menu->index / (float)(count - 1)) * (sheight - size);
+ bm_cairo_color_from_menu_color(menu, BM_COLOR_BG, &paint.bg);
+ cairo_set_source_rgba(cairo->cr, paint.bg.r, paint.bg.b, paint.bg.g, paint.bg.a);
+ cairo_rectangle(cairo->cr, 0, titleh + percent, 2, size);
+ cairo_fill(cairo->cr);
+ }
} else {
/* single-line mode */
bm_pango_get_text_extents(cairo, &paint, &result, "lorem ipsum lorem ipsum lorem ipsum lorem");
diff --git a/lib/renderers/curses/curses.c b/lib/renderers/curses/curses.c
index af54846..bab031b 100644
--- a/lib/renderers/curses/curses.c
+++ b/lib/renderers/curses/curses.c
@@ -186,20 +186,30 @@ render(const struct bm_menu *menu)
uint32_t count, cl = 1;
const uint32_t lines = getmaxy(curses.stdscr);
+ const int32_t prefix_x = (menu->prefix ? bm_utf8_string_screen_width(menu->prefix) : 0);
+ const int32_t offset_x = (menu->scrollbar ? 2 : 0);
if (lines > 1) {
+ uint32_t displayed = 0;
struct bm_item **items = bm_menu_get_filtered_items(menu, &count);
for (uint32_t i = (menu->index / (lines - 1)) * (lines - 1); i < count && cl < lines; ++i) {
bool highlighted = (items[i] == bm_menu_get_highlighted_item(menu));
int32_t color = (highlighted ? 2 : (bm_menu_item_is_selected(menu, items[i]) ? 1 : 0));
if (menu->prefix && highlighted) {
- draw_line(color, cl++, "%s %s", menu->prefix, (items[i]->text ? items[i]->text : ""));
- } else if (menu->prefix) {
- int32_t offset = (menu->prefix ? bm_utf8_string_screen_width(menu->prefix) : 0);
- draw_line(color, cl++, "%*s %s", offset, "", (items[i]->text ? items[i]->text : ""));
+ draw_line(color, cl++, "%*s%s %s", offset_x, "", menu->prefix, (items[i]->text ? items[i]->text : ""));
} else {
- draw_line(color, cl++, "%s", (items[i]->text ? items[i]->text : ""));
+ draw_line(color, cl++, "%*s%s%s", offset_x + prefix_x, "", (menu->prefix ? " " : ""), (items[i]->text ? items[i]->text : ""));
}
+
+ ++displayed;
+ }
+
+ if (menu->scrollbar) {
+ attron(COLOR_PAIR(1));
+ uint32_t percent = (menu->index / (float)(count - 1)) * (displayed - 1);
+ for (uint32_t i = 0; i < displayed; ++i)
+ mvprintw(1 + i, 0, (i == percent ? "█" : "▒"));
+ attroff(COLOR_PAIR(1));
}
}