Add a feedback for touchscreen support

The idea is to write "Scroll up…", "Scroll down…" when the finger
touching bemenu will trigger a page scroll on release.
This commit is contained in:
Stacy Harper 2021-08-27 13:19:34 +02:00 committed by Jari Vetoniemi
parent a111aa2afa
commit 9b8da12467
5 changed files with 167 additions and 33 deletions

View File

@ -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;

View File

@ -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,

View File

@ -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 */

View File

@ -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;
}
}
}

View File

@ -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);