diff --git a/client/common/common.c b/client/common/common.c index bed6d63..fad37d4 100644 --- a/client/common/common.c +++ b/client/common/common.c @@ -212,6 +212,8 @@ usage(FILE *out, const char *name) " --nf defines the normal foreground color. (wx)\n" " --hb defines the highlighted background color. (wx)\n" " --hf defines the highlighted foreground color. (wx)\n" + " --fbb defines the feedback background color. (wx)\n" + " --fbf defines the feedback foreground color. (wx)\n" " --sb defines the selected background color. (wx)\n" " --sf defines the selected foreground color. (wx)\n" " --scb defines the scrollbar background color. (wx)\n" @@ -257,10 +259,9 @@ do_getopt(struct client *client, int *argc, char **argv[]) { "prefix", required_argument, 0, 'P' }, { "password", no_argument, 0, 'x' }, { "scrollbar", required_argument, 0, 0x100 }, - { "ifne", no_argument, 0, 0x115 }, - { "fork", no_argument, 0, 0x116 }, - { "no-exec", no_argument, 0, 0x117 }, - + { "ifne", no_argument, 0, 0x117 }, + { "fork", no_argument, 0, 0x118 }, + { "no-exec", no_argument, 0, 0x119 }, { "bottom", no_argument, 0, 'b' }, { "grab", no_argument, 0, 'f' }, { "no-overlap", no_argument, 0, 'n' }, @@ -279,12 +280,14 @@ do_getopt(struct client *client, int *argc, char **argv[]) { "nf", required_argument, 0, 0x107 }, { "hb", required_argument, 0, 0x108 }, { "hf", required_argument, 0, 0x109 }, - { "sb", required_argument, 0, 0x110 }, - { "sf", required_argument, 0, 0x111 }, - { "scb", required_argument, 0, 0x112 }, - { "scf", required_argument, 0, 0x113 }, + { "fbb", required_argument, 0, 0x110 }, + { "fbf", required_argument, 0, 0x111 }, + { "sb", required_argument, 0, 0x112 }, + { "sf", required_argument, 0, 0x113 }, + { "scb", required_argument, 0, 0x114 }, + { "scf", required_argument, 0, 0x115 }, - { "disco", no_argument, 0, 0x114 }, + { "disco", no_argument, 0, 0x116 }, { 0, 0, 0, 0 } }; @@ -336,13 +339,13 @@ do_getopt(struct client *client, int *argc, char **argv[]) case 0x100: client->scrollbar = (!strcmp(optarg, "none") ? BM_SCROLLBAR_NONE : (!strcmp(optarg, "always") ? BM_SCROLLBAR_ALWAYS : (!strcmp(optarg, "autohide") ? BM_SCROLLBAR_AUTOHIDE : BM_SCROLLBAR_NONE))); break; - case 0x115: + case 0x117: client->ifne = true; break; - case 0x116: + case 0x118: client->force_fork = true; break; - case 0x117: + case 0x119: client->no_exec = true; break; case 'x': @@ -374,7 +377,7 @@ do_getopt(struct client *client, int *argc, char **argv[]) case 'W': client->width_factor = strtof(optarg, NULL); break; - case 0x118: + case 0x120: client->cursor_height = strtol(optarg, NULL, 10); break; case 0x101: @@ -405,19 +408,25 @@ do_getopt(struct client *client, int *argc, char **argv[]) client->colors[BM_COLOR_HIGHLIGHTED_FG] = optarg; break; case 0x110: - client->colors[BM_COLOR_SELECTED_BG] = optarg; + client->colors[BM_COLOR_FEEDBACK_BG] = optarg; break; case 0x111: - client->colors[BM_COLOR_SELECTED_FG] = optarg; + client->colors[BM_COLOR_FEEDBACK_FG] = optarg; break; case 0x112: - client->colors[BM_COLOR_SCROLLBAR_BG] = optarg; + client->colors[BM_COLOR_SELECTED_BG] = optarg; break; case 0x113: + client->colors[BM_COLOR_SELECTED_FG] = optarg; + break; + case 0x114: + client->colors[BM_COLOR_SCROLLBAR_BG] = optarg; + break; + case 0x115: client->colors[BM_COLOR_SCROLLBAR_FG] = optarg; break; - case 0x114: + case 0x116: disco(); break; diff --git a/lib/bemenu.h b/lib/bemenu.h index f5fcede..8443431 100644 --- a/lib/bemenu.h +++ b/lib/bemenu.h @@ -317,6 +317,14 @@ struct bm_touch { struct bm_touch_point points[2]; }; +enum bm_event_feedback_mask { + TOUCH_WILL_SCROLL_UP = 1 << 1, + TOUCH_WILL_SCROLL_DOWN = 1 << 2, + TOUCH_WILL_SCROLL_FIRST = 1 << 3, + TOUCH_WILL_SCROLL_LAST = 1 << 4, + TOUCH_WILL_CANCEL = 1 << 5, +}; + /** * Colorable element constants. * @@ -331,6 +339,8 @@ enum bm_color { BM_COLOR_ITEM_FG, BM_COLOR_HIGHLIGHTED_BG, BM_COLOR_HIGHLIGHTED_FG, + BM_COLOR_FEEDBACK_BG, + BM_COLOR_FEEDBACK_FG, BM_COLOR_SELECTED_BG, BM_COLOR_SELECTED_FG, BM_COLOR_SCROLLBAR_BG, diff --git a/lib/internal.h b/lib/internal.h index d82704e..6052e38 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -386,6 +386,11 @@ struct bm_menu { * Should the entry should follow the title spacing */ bool spacing; + + /** + * Mask representing a feedback to bring to user + */ + uint32_t event_feedback; }; /* library.c */ diff --git a/lib/menu.c b/lib/menu.c index 1b4603e..b1967f8 100644 --- a/lib/menu.c +++ b/lib/menu.c @@ -23,6 +23,8 @@ static const char *default_colors[BM_COLOR_LAST] = { "#CACACAFF", // BM_COLOR_ITEM_FG "#121212FF", // BM_COLOR_HIGHLIGHTED_BG "#D81860FF", // BM_COLOR_HIGHLIGHTED_FG + "#D81860FF", // BM_COLOR_FEEDBACK_BG + "#121212FF", // BM_COLOR_FEEDBACK_FG "#121212FF", // BM_COLOR_SELECTED_BG "#D81860FF", // BM_COLOR_SELECTED_FG "#121212FF", // BM_COLOR_SCROLLBAR_BG @@ -826,6 +828,31 @@ menu_scroll_up(struct bm_menu *menu, uint16_t count) } } +static void +menu_scroll_first(struct bm_menu *menu, uint16_t count) +{ + (void) count; + menu->index = 0; +} + +static void +menu_scroll_last(struct bm_menu *menu, uint16_t count) +{ + menu->index = count - 1; +} + +void +bm_menu_add_event_feedback(struct bm_menu *menu, uint32_t event_feedback) +{ + menu->event_feedback |= event_feedback; +} + +void +bm_menu_remove_event_feedback(struct bm_menu *menu, uint32_t event_feedback) +{ + menu->event_feedback &= ~event_feedback; +} + enum bm_run_result bm_menu_run_with_key(struct bm_menu *menu, enum bm_key key, uint32_t unicode) { @@ -1181,20 +1208,56 @@ bm_menu_run_with_touch(struct bm_menu *menu, struct bm_touch touch, uint32_t uni continue; menu_point_select(menu, point.pos_x, point.pos_y, displayed); + bm_menu_remove_event_feedback(menu, + TOUCH_WILL_CANCEL + | TOUCH_WILL_SCROLL_FIRST + | TOUCH_WILL_SCROLL_LAST + | TOUCH_WILL_SCROLL_UP + | TOUCH_WILL_SCROLL_DOWN + ); - if (point.event_mask & TOUCH_EVENT_UP) { - if (point.pos_y < (int32_t) (bm_menu_get_height(menu) / displayed)) { - menu_scroll_up(menu, count); - } else if ((uint32_t) point.pos_y > bm_menu_get_height(menu)) { - menu_scroll_down(menu, count); - } else if (point.pos_x > 0 - && (uint32_t) point.pos_x < bm_menu_get_width(menu)) { - { - struct bm_item *highlighted = bm_menu_get_highlighted_item(menu); - if (highlighted && !bm_menu_item_is_selected(menu, highlighted)) - list_add_item(&menu->selection, highlighted); + if (point.pos_y < (int32_t) (bm_menu_get_height(menu) / displayed)) { + if (point.pos_y < ((int32_t) (bm_menu_get_height(menu) / displayed)) - 50) { + if (point.event_mask & TOUCH_EVENT_UP) { + menu_scroll_first(menu, count); + } else if (point.event_mask & TOUCH_EVENT_MOTION) { + bm_menu_add_event_feedback(menu, TOUCH_WILL_SCROLL_FIRST); + } + } else { + if (point.event_mask & TOUCH_EVENT_UP) { + menu_scroll_up(menu, count); + } else if (point.event_mask & TOUCH_EVENT_MOTION) { + bm_menu_add_event_feedback(menu, TOUCH_WILL_SCROLL_UP); + } + } + } else if ((uint32_t) point.pos_y > bm_menu_get_height(menu)) { + if ((uint32_t) point.pos_y > bm_menu_get_height(menu) + 50) { + if (point.event_mask & TOUCH_EVENT_UP) { + menu_scroll_last(menu, count); + } else if (point.event_mask & TOUCH_EVENT_MOTION) { + bm_menu_add_event_feedback(menu, TOUCH_WILL_SCROLL_LAST); + } + } else { + if (point.event_mask & TOUCH_EVENT_UP) { + menu_scroll_down(menu, count); + } else if (point.event_mask & TOUCH_EVENT_MOTION) { + bm_menu_add_event_feedback(menu, TOUCH_WILL_SCROLL_DOWN); + } + } + } else { + if (point.pos_x > 0 && (uint32_t) point.pos_x < bm_menu_get_width(menu)) { + if (point.event_mask & TOUCH_EVENT_UP) { + { + struct bm_item *highlighted = bm_menu_get_highlighted_item(menu); + if (highlighted && !bm_menu_item_is_selected(menu, highlighted)) + list_add_item(&menu->selection, highlighted); + } + return BM_RUN_RESULT_SELECTED; + } + } else { + if (!(point.event_mask & TOUCH_EVENT_UP)) { + bm_menu_add_event_feedback(menu, TOUCH_WILL_CANCEL); } - return BM_RUN_RESULT_SELECTED; } } } diff --git a/lib/renderers/cairo_renderer.h b/lib/renderers/cairo_renderer.h index a4fd9fc..020a8fd 100644 --- a/lib/renderers/cairo_renderer.h +++ b/lib/renderers/cairo_renderer.h @@ -208,6 +208,47 @@ bm_cairo_color_from_menu_color(const struct bm_menu *menu, enum bm_color color, c->a = (float)menu->colors[color].a / 255.0f; } +static char * +bm_cairo_entry_message(char *entry_text, bool highlighted, uint32_t event_feedback, uint32_t index, uint32_t count) +{ + if (!highlighted || !event_feedback) { + return entry_text ? entry_text : ""; + } else { + if (event_feedback & TOUCH_WILL_CANCEL) { + return "Cancel…"; + } + if (event_feedback & TOUCH_WILL_SCROLL_FIRST) { + if (index == 0) { + return "Already on the first page…"; + } else { + return "First page…"; + } + } + if (event_feedback & TOUCH_WILL_SCROLL_UP) { + if (index == 0) { + return "Already on the first page…"; + } else { + return "Previous page…"; + } + } + if (event_feedback & TOUCH_WILL_SCROLL_DOWN) { + if (index == count - 1) { + return "Already on the last page…"; + } else { + return "Next page…"; + } + } + if (event_feedback & TOUCH_WILL_SCROLL_LAST) { + if (index == count - 1) { + return "Already on the last page…"; + } else { + return "Last page…"; + } + } + return "Not handled feedback…"; + } +} + static inline void bm_cairo_paint(struct cairo *cairo, uint32_t width, uint32_t max_height, const struct bm_menu *menu, struct cairo_paint_result *out_result) { @@ -303,8 +344,13 @@ bm_cairo_paint(struct cairo *cairo, uint32_t width, uint32_t max_height, const s bool highlighted = (items[i] == bm_menu_get_highlighted_item(menu)); if (highlighted) { - bm_cairo_color_from_menu_color(menu, BM_COLOR_HIGHLIGHTED_FG, &paint.fg); - bm_cairo_color_from_menu_color(menu, BM_COLOR_HIGHLIGHTED_BG, &paint.bg); + if (menu->event_feedback) { + bm_cairo_color_from_menu_color(menu, BM_COLOR_FEEDBACK_FG, &paint.fg); + bm_cairo_color_from_menu_color(menu, BM_COLOR_FEEDBACK_BG, &paint.bg); + } else { + bm_cairo_color_from_menu_color(menu, BM_COLOR_HIGHLIGHTED_FG, &paint.fg); + bm_cairo_color_from_menu_color(menu, BM_COLOR_HIGHLIGHTED_BG, &paint.bg); + } } else if (bm_menu_item_is_selected(menu, items[i])) { bm_cairo_color_from_menu_color(menu, BM_COLOR_SELECTED_FG, &paint.fg); bm_cairo_color_from_menu_color(menu, BM_COLOR_SELECTED_BG, &paint.bg); @@ -313,14 +359,15 @@ bm_cairo_paint(struct cairo *cairo, uint32_t width, uint32_t max_height, const s bm_cairo_color_from_menu_color(menu, BM_COLOR_ITEM_BG, &paint.bg); } + char *line_str = bm_cairo_entry_message(items[i]->text, highlighted, menu->event_feedback, i, count); if (menu->prefix && highlighted) { paint.pos = (struct pos){ spacing_x, posy+vpadding }; paint.box = (struct box){ 4, 0, vpadding, -vpadding, width - paint.pos.x, height }; - bm_cairo_draw_line(cairo, &paint, &result, "%s %s", menu->prefix, (items[i]->text ? items[i]->text : "")); + bm_cairo_draw_line(cairo, &paint, &result, "%s %s", menu->prefix, line_str); } else { paint.pos = (struct pos){ spacing_x, posy+vpadding }; paint.box = (struct box){ 4 + prefix_x, 0, vpadding, -vpadding, width - paint.pos.x, height }; - bm_cairo_draw_line(cairo, &paint, &result, "%s", (items[i]->text ? items[i]->text : "")); + bm_cairo_draw_line(cairo, &paint, &result, "%s", line_str); } posy += (spacing_y ? spacing_y : result.height);