decor: Improve buttons with hover states using focus hack

This commit is contained in:
K. Lange 2023-04-26 18:32:33 +09:00
parent f44b4c4519
commit d2cff8331c
5 changed files with 85 additions and 19 deletions

View File

@ -46,6 +46,8 @@ struct decor_bounds {
extern void (*decor_render_decorations)(yutani_window_t *, gfx_context_t *, char *, int); extern void (*decor_render_decorations)(yutani_window_t *, gfx_context_t *, char *, int);
extern int (*decor_check_button_press)(yutani_window_t *, int x, int y); extern int (*decor_check_button_press)(yutani_window_t *, int x, int y);
extern int (*decor_get_bounds)(yutani_window_t *, struct decor_bounds *); extern int (*decor_get_bounds)(yutani_window_t *, struct decor_bounds *);
extern int decor_hover_button;
extern yutani_window_t * decor_hover_window;
/* /*
* Run me once to set things up * Run me once to set things up
@ -67,6 +69,7 @@ extern yutani_window_t * decor_show_default_menu(yutani_window_t * window, int y
#define DECOR_MAXIMIZE 4 #define DECOR_MAXIMIZE 4
#define DECOR_RIGHT 5 #define DECOR_RIGHT 5
#define DECOR_MINIMIZE 6 #define DECOR_MINIMIZE 6
#define DECOR_REDRAW 7
#define DECOR_ACTIVE 0 #define DECOR_ACTIVE 0
#define DECOR_INACTIVE 1 #define DECOR_INACTIVE 1

View File

@ -567,6 +567,7 @@ extern gfx_context_t * init_graphics_yutani(yutani_window_t * window);
extern gfx_context_t * init_graphics_yutani_double_buffer(yutani_window_t * window); extern gfx_context_t * init_graphics_yutani_double_buffer(yutani_window_t * window);
extern void reinit_graphics_yutani(gfx_context_t * out, yutani_window_t * window); extern void reinit_graphics_yutani(gfx_context_t * out, yutani_window_t * window);
extern void release_graphics_yutani(gfx_context_t * gfx); extern void release_graphics_yutani(gfx_context_t * gfx);
extern void yutani_internal_refocus(yutani_t * yctx, yutani_window_t * window);
_End_C_Header _End_C_Header

View File

@ -139,6 +139,8 @@ static char * ellipsify(char * input, int font_size, struct TT_Font * font, int
return out; return out;
} }
#define BUTTON_PAD 5
static void render_decorations_fancy(yutani_window_t * window, gfx_context_t * ctx, char * title, int decors_active) { static void render_decorations_fancy(yutani_window_t * window, gfx_context_t * ctx, char * title, int decors_active) {
int width = window->width; int width = window->width;
int height = window->height; int height = window->height;
@ -238,21 +240,39 @@ static void render_decorations_fancy(yutani_window_t * window, gfx_context_t * c
tt_draw_string(ctx, _tt_font, title_offset, (TEXT_OFFSET + 14) * TOTAL_SCALE, title, title_color); tt_draw_string(ctx, _tt_font, title_offset, (TEXT_OFFSET + 14) * TOTAL_SCALE, title, title_color);
} }
uint32_t h_color = rgb(100,100,100);
uint32_t i_color = (decor_hover_window == window && decor_hover_button) ? ACTIVE_COLOR : title_color;
if (width + (BUTTON_OFFSET - 28) * TOTAL_SCALE > bounds.left_width) { if (width + (BUTTON_OFFSET - 28) * TOTAL_SCALE > bounds.left_width) {
if (decor_hover_window == window && decor_hover_button == DECOR_CLOSE) {
draw_rounded_rectangle(ctx,
width + (BUTTON_OFFSET - 28 - BUTTON_PAD) * TOTAL_SCALE,
(16 - BUTTON_OFFSET - BUTTON_PAD) * TOTAL_SCALE, 8 + BUTTON_PAD * 2, 8 + BUTTON_PAD * 2, 4, h_color);
}
draw_sprite_alpha_paint(ctx, sprites[BUTTON_CLOSE], draw_sprite_alpha_paint(ctx, sprites[BUTTON_CLOSE],
width + (BUTTON_OFFSET - 28) * TOTAL_SCALE, width + (BUTTON_OFFSET - 28) * TOTAL_SCALE,
(16 - BUTTON_OFFSET) * TOTAL_SCALE, 1.0, title_color); (16 - BUTTON_OFFSET) * TOTAL_SCALE, 1.0, i_color);
if (width + (BUTTON_OFFSET - 50) * TOTAL_SCALE > bounds.left_width) { if (width + (BUTTON_OFFSET - 50) * TOTAL_SCALE > bounds.left_width) {
if (!(window->decorator_flags & DECOR_FLAG_NO_MAXIMIZE)) { if (!(window->decorator_flags & DECOR_FLAG_NO_MAXIMIZE)) {
if (decor_hover_window == window && decor_hover_button == DECOR_MAXIMIZE) {
draw_rounded_rectangle(ctx,
width + (BUTTON_OFFSET - 50 - BUTTON_PAD) * TOTAL_SCALE,
(16 - BUTTON_OFFSET - BUTTON_PAD) * TOTAL_SCALE, 8 + BUTTON_PAD * 2, 8 + BUTTON_PAD * 2, 4, h_color);
}
draw_sprite_alpha_paint(ctx, sprites[BUTTON_MAXIMIZE], draw_sprite_alpha_paint(ctx, sprites[BUTTON_MAXIMIZE],
width + (BUTTON_OFFSET - 50) * TOTAL_SCALE, width + (BUTTON_OFFSET - 50) * TOTAL_SCALE,
(16 - BUTTON_OFFSET) * TOTAL_SCALE, 1.0, title_color); (16 - BUTTON_OFFSET) * TOTAL_SCALE, 1.0, i_color);
if (width + (BUTTON_OFFSET - 72) * TOTAL_SCALE > bounds.left_width) { if (width + (BUTTON_OFFSET - 72) * TOTAL_SCALE > bounds.left_width) {
if (decor_hover_window == window && decor_hover_button == DECOR_MINIMIZE) {
draw_rounded_rectangle(ctx,
width + (BUTTON_OFFSET - 72 - BUTTON_PAD) * TOTAL_SCALE,
(16 - BUTTON_OFFSET - BUTTON_PAD) * TOTAL_SCALE, 8 + BUTTON_PAD * 2, 8 + BUTTON_PAD * 2, 4, h_color);
}
draw_sprite_alpha_paint(ctx, sprites[BUTTON_MINIMIZE], draw_sprite_alpha_paint(ctx, sprites[BUTTON_MINIMIZE],
width + (BUTTON_OFFSET - 72) * TOTAL_SCALE, width + (BUTTON_OFFSET - 72) * TOTAL_SCALE,
(16 - BUTTON_OFFSET) * TOTAL_SCALE, 1.0, title_color); (16 - BUTTON_OFFSET) * TOTAL_SCALE, 1.0, i_color);
} }
} }
} }
@ -260,23 +280,27 @@ static void render_decorations_fancy(yutani_window_t * window, gfx_context_t * c
} }
static int check_button_press_fancy(yutani_window_t * window, int x, int y) { static int check_button_press_fancy(yutani_window_t * window, int x, int y) {
if (x >= (int)window->width + (BUTTON_OFFSET - 28) * TOTAL_SCALE && if (y >= (16 - BUTTON_OFFSET - BUTTON_PAD) * TOTAL_SCALE && y <= (16 - BUTTON_OFFSET + 8 + BUTTON_PAD) * TOTAL_SCALE ) {
x <= (int)window->width + (BUTTON_OFFSET - 18) * TOTAL_SCALE && if (x >= (int)window->width + (BUTTON_OFFSET - 28 - BUTTON_PAD) * TOTAL_SCALE &&
y >= 16 * TOTAL_SCALE && y <= 26 * TOTAL_SCALE ) { x <= (int)window->width + (BUTTON_OFFSET - 28 + 8 + BUTTON_PAD) * TOTAL_SCALE) {
return DECOR_CLOSE; return DECOR_CLOSE;
}
if (!(window->decorator_flags & DECOR_FLAG_NO_MAXIMIZE)) {
if (x >= (int)window->width + (BUTTON_OFFSET - 50) * TOTAL_SCALE &&
x <= (int)window->width + (BUTTON_OFFSET - 40) * TOTAL_SCALE &&
y >= 16 * TOTAL_SCALE && y <= 26 * TOTAL_SCALE) {
return DECOR_MAXIMIZE;
} }
if (x >= (int)window->width + (BUTTON_OFFSET - 72) * TOTAL_SCALE && if (!(window->decorator_flags & DECOR_FLAG_NO_MAXIMIZE)) {
x <= (int)window->width + (BUTTON_OFFSET - 62) * TOTAL_SCALE && if (x >= (int)window->width + (BUTTON_OFFSET - 50 - BUTTON_PAD) * TOTAL_SCALE &&
y >= 16 * TOTAL_SCALE && y <= 26 * TOTAL_SCALE) { x <= (int)window->width + (BUTTON_OFFSET - 50 + 8 + BUTTON_PAD) * TOTAL_SCALE) {
return DECOR_MINIMIZE; return DECOR_MAXIMIZE;
}
if (x >= (int)window->width + (BUTTON_OFFSET - 72 - BUTTON_PAD) * TOTAL_SCALE &&
x <= (int)window->width + (BUTTON_OFFSET - 72 + 8 + BUTTON_PAD) * TOTAL_SCALE) {
return DECOR_MINIMIZE;
}
}
if (x >= (int)window->width + (BUTTON_OFFSET - 72 - BUTTON_PAD) * TOTAL_SCALE &&
x <= (int)window->width + (BUTTON_OFFSET - 28 + 8 + BUTTON_PAD) * TOTAL_SCALE) {
return DECOR_OTHER;
} }
} }

View File

@ -253,6 +253,8 @@ static yutani_scale_direction_t check_resize_direction(struct yutani_msg_window_
} }
static yutani_scale_direction_t old_resize_direction = SCALE_NONE; static yutani_scale_direction_t old_resize_direction = SCALE_NONE;
int decor_hover_button = 0;
yutani_window_t * decor_hover_window = NULL;
int decor_handle_event(yutani_t * yctx, yutani_msg_t * m) { int decor_handle_event(yutani_t * yctx, yutani_msg_t * m) {
if (m) { if (m) {
@ -265,10 +267,16 @@ int decor_handle_event(yutani_t * yctx, yutani_msg_t * m) {
decor_get_bounds(window, &bounds); decor_get_bounds(window, &bounds);
if (!window) return 0; if (!window) return 0;
if (!(window->decorator_flags & DECOR_FLAG_DECORATED)) return 0; if (!(window->decorator_flags & DECOR_FLAG_DECORATED)) return 0;
if (me->command == YUTANI_MOUSE_EVENT_LEAVE && decor_hover_window == window) {
decor_hover_window = NULL;
decor_hover_button = 0;
yutani_internal_refocus(yctx, window);
return DECOR_REDRAW;
}
if (within_decors(window, me->new_x, me->new_y)) { if (within_decors(window, me->new_x, me->new_y)) {
int button = decor_check_button_press(window, me->new_x, me->new_y); int button = decor_check_button_press(window, me->new_x, me->new_y);
if (me->command == YUTANI_MOUSE_EVENT_DOWN && me->buttons & YUTANI_MOUSE_BUTTON_LEFT) { if (me->command == YUTANI_MOUSE_EVENT_DOWN && me->buttons & YUTANI_MOUSE_BUTTON_LEFT) {
if (!button) { if (!button || button == DECOR_OTHER) {
/* Resize edges */ /* Resize edges */
yutani_scale_direction_t resize_direction = check_resize_direction(me, window); yutani_scale_direction_t resize_direction = check_resize_direction(me, window);
@ -317,6 +325,9 @@ int decor_handle_event(yutani_t * yctx, yutani_msg_t * m) {
} }
old_resize_direction = resize_direction; old_resize_direction = resize_direction;
} }
} else if (old_resize_direction != SCALE_NONE) {
yutani_window_show_mouse(yctx, window, YUTANI_CURSOR_TYPE_RESET);
old_resize_direction = SCALE_NONE;
} }
} }
if (me->command == YUTANI_MOUSE_EVENT_CLICK || close_enough(me)) { if (me->command == YUTANI_MOUSE_EVENT_CLICK || close_enough(me)) {
@ -337,13 +348,28 @@ int decor_handle_event(yutani_t * yctx, yutani_msg_t * m) {
default: default:
break; break;
} }
decor_hover_window = NULL;
decor_hover_button = 0;
yutani_internal_refocus(yctx, window);
return button; return button;
} }
if (button != decor_hover_button || window != decor_hover_window) {
decor_hover_button = button;
decor_hover_window = window;
yutani_internal_refocus(yctx, window);
return DECOR_REDRAW;
}
} else { } else {
if (old_resize_direction != SCALE_NONE) { if (old_resize_direction != SCALE_NONE) {
yutani_window_show_mouse(yctx, window, YUTANI_CURSOR_TYPE_RESET); yutani_window_show_mouse(yctx, window, YUTANI_CURSOR_TYPE_RESET);
old_resize_direction = SCALE_NONE; old_resize_direction = SCALE_NONE;
} }
if (decor_hover_window == window) {
decor_hover_button = 0;
decor_hover_window = NULL;
yutani_internal_refocus(yctx, window);
return DECOR_REDRAW;
}
} }
} }
break; break;

View File

@ -1156,3 +1156,15 @@ void release_graphics_yutani(gfx_context_t * gfx) {
} }
free(gfx); free(gfx);
} }
void yutani_internal_refocus(yutani_t * yctx, yutani_window_t * window) {
/* Check if a refocus is already in our queue to be processed */
foreach(node, yctx->queued) {
yutani_msg_t * out = (yutani_msg_t *)node->value;
if (out->type == YUTANI_MSG_WINDOW_FOCUS_CHANGE) return;
}
/* Otherwise, produce an artificial one matching the reported focus state of the window */
yutani_msg_t * msg = malloc(sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_focus_change));
yutani_msg_buildx_window_focus_change(msg, window->wid, window->focused);
list_insert(yctx->queued, msg);
}