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
)
123 struct terminal
*term
= dlg_data
->win
->term
;
128 struct widget_data
*widget_data1
= widget_data
+ i1
;
135 buttons_width(widget_data1
, i2
- i1
+ 1, NULL
, &mw
,
138 buttons_width(widget_data1
, i2
- i1
+ 1, NULL
, &mw
);
139 #endif /* CONFIG_UTF8 */
146 buttons_width(widget_data1
, i2
- i1
, NULL
, &mw
, term
->utf8_cp
);
148 buttons_width(widget_data1
, i2
- i1
, NULL
, &mw
);
149 #endif /* CONFIG_UTF8 */
150 if (rw
) int_bounds(rw
, mw
, w
);
154 int p
= x
+ (align
== ALIGN_CENTER
? (w
- mw
) / 2 : 0);
156 int button_lr_len
= utf8_ptr2cells(BUTTON_LEFT
, NULL
)
157 + utf8_ptr2cells(BUTTON_RIGHT
, NULL
);
158 #endif /* CONFIG_UTF8 */
160 for (i
= i1
; i
< i2
; i
++) {
163 set_box(&widget_data
[i
].box
,
165 utf8_ptr2cells(widget_data
[i
].widget
->text
, NULL
)
166 + button_lr_len
, BUTTON_HEIGHT
);
168 #endif /* CONFIG_UTF8 */
169 set_box(&widget_data
[i
].box
,
171 widget_data
[i
].widget
->info
.button
.textlen
172 + BUTTON_LR_LEN
, BUTTON_HEIGHT
);
174 p
+= widget_data
[i
].box
.width
+ BUTTON_HSPACING
;
178 *y
+= BUTTON_VSPACING
+ BUTTON_HEIGHT
;
183 static widget_handler_status_T
184 display_button(struct dialog_data
*dlg_data
, struct widget_data
*widget_data
)
186 struct terminal
*term
= dlg_data
->win
->term
;
187 struct color_pair
*color
, *shortcut_color
;
188 struct box
*pos
= &widget_data
->box
;
190 int sel
= is_selected_widget(dlg_data
, widget_data
);
193 shortcut_color
= get_bfu_color(term
, "dialog.button-shortcut-selected");
194 color
= get_bfu_color(term
, "dialog.button-selected");
196 shortcut_color
= get_bfu_color(term
, "dialog.button-shortcut");
197 color
= get_bfu_color(term
, "dialog.button");
199 if (!color
|| !shortcut_color
) return EVENT_PROCESSED
;
203 int button_left_len
= utf8_ptr2cells(BUTTON_LEFT
, NULL
);
204 int button_right_len
= utf8_ptr2cells(BUTTON_RIGHT
, NULL
);
206 x
= pos
->x
+ button_left_len
;
207 len
= widget_data
->box
.width
-
208 (button_left_len
+ button_right_len
);
211 #endif /* CONFIG_UTF8 */
213 x
= pos
->x
+ BUTTON_LEFT_LEN
;
214 len
= widget_data
->box
.width
- BUTTON_LR_LEN
;
218 draw_dlg_text(dlg_data
, pos
->x
, pos
->y
, BUTTON_LEFT
, BUTTON_LEFT_LEN
, 0, color
);
220 unsigned char *text
= widget_data
->widget
->text
;
221 int hk_pos
= widget_data
->widget
->info
.button
.hotkey_pos
;
224 attr
= get_opt_bool("ui.dialogs.underline_button_shortcuts",
226 ? SCREEN_ATTR_UNDERLINE
: 0;
231 int hk_bytes
= utf8charlen(&text
[hk_pos
+1]);
232 int cells_to_hk
= utf8_ptr2cells(text
,
234 int right
= widget_data
->widget
->info
.button
.truetextlen
238 int hk_cells
= utf8_char2cells(&text
[hk_pos
243 draw_dlg_text(dlg_data
, x
, pos
->y
,
244 text
, hk_pos
, 0, color
);
246 draw_dlg_text(dlg_data
, x
+ cells_to_hk
, pos
->y
,
247 &text
[hk_pos
+ 1], hk_bytes
,
248 attr
, shortcut_color
);
251 draw_dlg_text(dlg_data
, x
+cells_to_hk
+hk_cells
,
253 &text
[hk_pos
+ hk_bytes
+ 1],
254 right
- 1, 0, color
);
257 int hk_width
= utf8_char2cells(text
, NULL
);
258 int hk_len
= utf8charlen(text
);
260 utf8_cells2bytes(&text
[hk_len
],
264 draw_dlg_text(dlg_data
, x
, pos
->y
,
266 attr
, shortcut_color
);
268 draw_dlg_text(dlg_data
, x
+ hk_width
, pos
->y
,
269 &text
[hk_len
], len_to_display
,
273 #endif /* CONFIG_UTF8 */
275 int right
= widget_data
->widget
->info
.button
.truetextlen
- hk_pos
- 1;
278 draw_dlg_text(dlg_data
, x
, pos
->y
, text
, hk_pos
, 0, color
);
280 draw_dlg_text(dlg_data
, x
+ hk_pos
, pos
->y
,
281 &text
[hk_pos
+ 1], 1, attr
, shortcut_color
);
283 draw_dlg_text(dlg_data
, x
+ hk_pos
+ 1, pos
->y
,
284 &text
[hk_pos
+ 2], right
- 1, 0, color
);
288 draw_dlg_text(dlg_data
, x
, pos
->y
, text
, 1, attr
, shortcut_color
);
289 draw_dlg_text(dlg_data
, x
+ 1, pos
->y
, &text
[1], len
- 1, 0, color
);
294 int text_cells
= utf8_ptr2cells(widget_data
->widget
->text
, NULL
);
295 int hk
= (widget_data
->widget
->info
.button
.hotkey_pos
>= 0);
297 draw_dlg_text(dlg_data
, x
+ text_cells
- hk
, pos
->y
,
298 BUTTON_RIGHT
, BUTTON_RIGHT_LEN
, 0, color
);
300 #endif /* CONFIG_UTF8 */
301 draw_dlg_text(dlg_data
, x
+ len
, pos
->y
, BUTTON_RIGHT
,
302 BUTTON_RIGHT_LEN
, 0, color
);
304 set_dlg_cursor(term
, dlg_data
, x
, pos
->y
, 1);
305 set_dlg_window_ptr(dlg_data
, dlg_data
->win
, pos
->x
, pos
->y
);
307 return EVENT_PROCESSED
;
310 static widget_handler_status_T
311 mouse_button(struct dialog_data
*dlg_data
, struct widget_data
*widget_data
)
313 struct terminal
*term
= dlg_data
->win
->term
;
314 struct term_event
*ev
= dlg_data
->term_event
;
316 if (check_mouse_wheel(ev
))
317 return EVENT_NOT_PROCESSED
;
319 if (!check_mouse_position(ev
, &widget_data
->box
))
320 return EVENT_NOT_PROCESSED
;
322 select_widget(dlg_data
, widget_data
);
324 do_not_ignore_next_mouse_event(term
);
326 if (check_mouse_action(ev
, B_UP
) && widget_data
->widget
->ops
->select
)
327 return widget_data
->widget
->ops
->select(dlg_data
, widget_data
);
329 return EVENT_PROCESSED
;
332 static widget_handler_status_T
333 select_button(struct dialog_data
*dlg_data
, struct widget_data
*widget_data
)
335 return widget_data
->widget
->handler(dlg_data
, widget_data
);
338 const struct widget_ops button_ops
= {