1 /* Button widget handlers. */
11 #include "bfu/button.h"
12 #include "bfu/dialog.h"
13 #include "intl/gettext/libintl.h"
14 #include "terminal/draw.h"
15 #include "terminal/mouse.h"
16 #include "terminal/terminal.h"
17 #include "util/align.h"
19 /* Height of a button. */
20 #define BUTTON_HEIGHT 1
22 /* Vertical spacing between buttons. */
23 #define BUTTON_VSPACING 1
25 /* Horizontal spacing between buttons. */
26 #define BUTTON_HSPACING 2
28 /* Left and right text appearing around label of button.
29 * Currently a dialog button is displayed as [ LABEL ] */
30 #define BUTTON_LEFT "[ "
31 #define BUTTON_RIGHT " ]"
32 #define BUTTON_LEFT_LEN (sizeof(BUTTON_LEFT) - 1)
33 #define BUTTON_RIGHT_LEN (sizeof(BUTTON_RIGHT) - 1)
35 #define BUTTON_LR_LEN (BUTTON_LEFT_LEN + BUTTON_RIGHT_LEN)
37 #ifdef DEBUG_BUTTON_HOTKEY
39 add_dlg_button_do(const unsigned char *file
, int line
,
40 struct dialog
*dlg
, unsigned char *text
, int flags
,
41 widget_handler_T
*handler
, void *data
,
42 done_handler_T
*done
, void *done_data
)
45 add_dlg_button_do(struct dialog
*dlg
, unsigned char *text
, int flags
,
46 widget_handler_T
*handler
, void *data
,
47 done_handler_T
*done
, void *done_data
)
50 int textlen
= strlen(text
);
51 struct widget
*widget
= &dlg
->widgets
[dlg
->number_of_widgets
++];
53 widget
->type
= WIDGET_BUTTON
;
54 widget
->handler
= handler
;
58 widget
->info
.button
.flags
= flags
;
59 widget
->info
.button
.done
= done
;
60 widget
->info
.button
.done_data
= done_data
;
61 widget
->info
.button
.hotkey_pos
= -1;
62 widget
->info
.button
.textlen
= textlen
;
63 widget
->info
.button
.truetextlen
= textlen
;
66 unsigned char *pos
= memchr(text
, '~', textlen
- 1);
69 widget
->info
.button
.hotkey_pos
= pos
- text
;
70 widget
->info
.button
.textlen
--;
72 #ifdef DEBUG_BUTTON_HOTKEY
74 DBG("%s:%d missing keyboard accelerator in \"%s\".", file
, line
, text
);
82 buttons_width(struct widget_data
*widget_data
, int n
,
83 int *minwidth
, int *maxwidth
, int utf8
)
86 buttons_width(struct widget_data
*widget_data
, int n
,
87 int *minwidth
, int *maxwidth
)
88 #endif /* CONFIG_UTF8 */
90 int maxw
= -BUTTON_HSPACING
;
92 int button_lr_len
= utf8_ptr2cells(BUTTON_LEFT
, NULL
)
93 + utf8_ptr2cells(BUTTON_RIGHT
, NULL
);
94 #endif /* CONFIG_UTF8 */
97 if_assert_failed
return;
103 minw
= utf8_ptr2cells((widget_data
++)->widget
->text
, NULL
)
104 + BUTTON_HSPACING
+ button_lr_len
;
106 #endif /* CONFIG_UTF8 */
107 minw
= (widget_data
++)->widget
->info
.button
.textlen
108 + BUTTON_HSPACING
+ BUTTON_LR_LEN
;
111 if (minwidth
) int_lower_bound(minwidth
, minw
);
114 if (maxwidth
) int_lower_bound(maxwidth
, maxw
);
118 dlg_format_buttons(struct dialog_data
*dlg_data
,
119 struct widget_data
*widget_data
, int n
,
120 int x
, int *y
, int w
, int *rw
, enum format_align align
, int format_only
)
122 struct terminal
*term
= dlg_data
->win
->term
;
126 struct widget_data
*widget_data1
= widget_data
+ i1
;
133 buttons_width(widget_data1
, i2
- i1
+ 1, NULL
, &mw
,
136 buttons_width(widget_data1
, i2
- i1
+ 1, NULL
, &mw
);
137 #endif /* CONFIG_UTF8 */
144 buttons_width(widget_data1
, i2
- i1
, NULL
, &mw
, term
->utf8_cp
);
146 buttons_width(widget_data1
, i2
- i1
, NULL
, &mw
);
147 #endif /* CONFIG_UTF8 */
148 if (rw
) int_bounds(rw
, mw
, w
);
152 int p
= x
+ (align
== ALIGN_CENTER
? (w
- mw
) / 2 : 0);
154 int button_lr_len
= utf8_ptr2cells(BUTTON_LEFT
, NULL
)
155 + utf8_ptr2cells(BUTTON_RIGHT
, NULL
);
156 #endif /* CONFIG_UTF8 */
158 for (i
= i1
; i
< i2
; i
++) {
161 set_box(&widget_data
[i
].box
,
163 utf8_ptr2cells(widget_data
[i
].widget
->text
, NULL
)
164 + button_lr_len
, BUTTON_HEIGHT
);
166 #endif /* CONFIG_UTF8 */
167 set_box(&widget_data
[i
].box
,
169 widget_data
[i
].widget
->info
.button
.textlen
170 + BUTTON_LR_LEN
, BUTTON_HEIGHT
);
172 p
+= widget_data
[i
].box
.width
+ BUTTON_HSPACING
;
176 *y
+= BUTTON_VSPACING
+ BUTTON_HEIGHT
;
181 static widget_handler_status_T
182 display_button(struct dialog_data
*dlg_data
, struct widget_data
*widget_data
)
184 struct terminal
*term
= dlg_data
->win
->term
;
185 struct color_pair
*color
, *shortcut_color
;
186 struct box
*pos
= &widget_data
->box
;
188 int sel
= is_selected_widget(dlg_data
, widget_data
);
191 shortcut_color
= get_bfu_color(term
, "dialog.button-shortcut-selected");
192 color
= get_bfu_color(term
, "dialog.button-selected");
194 shortcut_color
= get_bfu_color(term
, "dialog.button-shortcut");
195 color
= get_bfu_color(term
, "dialog.button");
197 if (!color
|| !shortcut_color
) return EVENT_PROCESSED
;
201 int button_left_len
= utf8_ptr2cells(BUTTON_LEFT
, NULL
);
202 int button_right_len
= utf8_ptr2cells(BUTTON_RIGHT
, NULL
);
204 x
= pos
->x
+ button_left_len
;
205 len
= widget_data
->box
.width
-
206 (button_left_len
+ button_right_len
);
209 #endif /* CONFIG_UTF8 */
211 x
= pos
->x
+ BUTTON_LEFT_LEN
;
212 len
= widget_data
->box
.width
- BUTTON_LR_LEN
;
216 draw_dlg_text(term
, dlg_data
, pos
->x
, pos
->y
, BUTTON_LEFT
, BUTTON_LEFT_LEN
, 0, color
);
218 unsigned char *text
= widget_data
->widget
->text
;
219 int hk_pos
= widget_data
->widget
->info
.button
.hotkey_pos
;
222 attr
= get_opt_bool("ui.dialogs.underline_button_shortcuts",
224 ? SCREEN_ATTR_UNDERLINE
: 0;
229 int hk_bytes
= utf8charlen(&text
[hk_pos
+1]);
230 int cells_to_hk
= utf8_ptr2cells(text
,
232 int right
= widget_data
->widget
->info
.button
.truetextlen
236 int hk_cells
= utf8_char2cells(&text
[hk_pos
241 draw_dlg_text(term
, dlg_data
, x
, pos
->y
,
242 text
, hk_pos
, 0, color
);
244 draw_dlg_text(term
, dlg_data
, x
+ cells_to_hk
, pos
->y
,
245 &text
[hk_pos
+ 1], hk_bytes
,
246 attr
, shortcut_color
);
249 draw_dlg_text(term
, dlg_data
, x
+cells_to_hk
+hk_cells
,
251 &text
[hk_pos
+ hk_bytes
+ 1],
252 right
- 1, 0, color
);
255 int hk_width
= utf8_char2cells(text
, NULL
);
256 int hk_len
= utf8charlen(text
);
258 utf8_cells2bytes(&text
[hk_len
],
262 draw_dlg_text(term
, dlg_data
, x
, pos
->y
,
264 attr
, shortcut_color
);
266 draw_dlg_text(term
, dlg_data
, x
+ hk_width
, pos
->y
,
267 &text
[hk_len
], len_to_display
,
271 #endif /* CONFIG_UTF8 */
273 int right
= widget_data
->widget
->info
.button
.truetextlen
- hk_pos
- 1;
276 draw_dlg_text(term
, dlg_data
, x
, pos
->y
, text
, hk_pos
, 0, color
);
278 draw_dlg_text(term
, dlg_data
, x
+ hk_pos
, pos
->y
,
279 &text
[hk_pos
+ 1], 1, attr
, shortcut_color
);
281 draw_dlg_text(term
, dlg_data
, x
+ hk_pos
+ 1, pos
->y
,
282 &text
[hk_pos
+ 2], right
- 1, 0, color
);
286 draw_dlg_text(term
, dlg_data
, x
, pos
->y
, text
, 1, attr
, shortcut_color
);
287 draw_dlg_text(term
, dlg_data
, x
+ 1, pos
->y
, &text
[1], len
- 1, 0, color
);
292 int text_cells
= utf8_ptr2cells(widget_data
->widget
->text
, NULL
);
293 int hk
= (widget_data
->widget
->info
.button
.hotkey_pos
>= 0);
295 draw_dlg_text(term
, dlg_data
, x
+ text_cells
- hk
, pos
->y
,
296 BUTTON_RIGHT
, BUTTON_RIGHT_LEN
, 0, color
);
298 #endif /* CONFIG_UTF8 */
299 draw_dlg_text(term
, dlg_data
, x
+ len
, pos
->y
, BUTTON_RIGHT
,
300 BUTTON_RIGHT_LEN
, 0, color
);
302 set_dlg_cursor(term
, dlg_data
, x
, pos
->y
, 1);
303 set_dlg_window_ptr(dlg_data
, dlg_data
->win
, pos
->x
, pos
->y
);
305 return EVENT_PROCESSED
;
308 static widget_handler_status_T
309 mouse_button(struct dialog_data
*dlg_data
, struct widget_data
*widget_data
)
311 struct terminal
*term
= dlg_data
->win
->term
;
312 struct term_event
*ev
= dlg_data
->term_event
;
314 if (check_mouse_wheel(ev
))
315 return EVENT_NOT_PROCESSED
;
317 if (!check_mouse_position(ev
, &widget_data
->box
))
318 return EVENT_NOT_PROCESSED
;
320 select_widget(dlg_data
, widget_data
);
322 do_not_ignore_next_mouse_event(term
);
324 if (check_mouse_action(ev
, B_UP
) && widget_data
->widget
->ops
->select
)
325 return widget_data
->widget
->ops
->select(dlg_data
, widget_data
);
327 return EVENT_PROCESSED
;
330 static widget_handler_status_T
331 select_button(struct dialog_data
*dlg_data
, struct widget_data
*widget_data
)
333 return widget_data
->widget
->handler(dlg_data
, widget_data
);
336 const struct widget_ops button_ops
= {