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 terminal
*term
,
119 struct widget_data
*widget_data
, int n
,
120 int x
, int *y
, int w
, int *rw
, enum format_align align
, int format_only
)
125 struct widget_data
*widget_data1
= widget_data
+ i1
;
132 buttons_width(widget_data1
, i2
- i1
+ 1, NULL
, &mw
,
135 buttons_width(widget_data1
, i2
- i1
+ 1, NULL
, &mw
);
136 #endif /* CONFIG_UTF8 */
143 buttons_width(widget_data1
, i2
- i1
, NULL
, &mw
, term
->utf8_cp
);
145 buttons_width(widget_data1
, i2
- i1
, NULL
, &mw
);
146 #endif /* CONFIG_UTF8 */
147 if (rw
) int_bounds(rw
, mw
, w
);
151 int p
= x
+ (align
== ALIGN_CENTER
? (w
- mw
) / 2 : 0);
153 int button_lr_len
= utf8_ptr2cells(BUTTON_LEFT
, NULL
)
154 + utf8_ptr2cells(BUTTON_RIGHT
, NULL
);
155 #endif /* CONFIG_UTF8 */
157 for (i
= i1
; i
< i2
; i
++) {
160 set_box(&widget_data
[i
].box
,
162 utf8_ptr2cells(widget_data
[i
].widget
->text
, NULL
)
163 + button_lr_len
, BUTTON_HEIGHT
);
165 #endif /* CONFIG_UTF8 */
166 set_box(&widget_data
[i
].box
,
168 widget_data
[i
].widget
->info
.button
.textlen
169 + BUTTON_LR_LEN
, BUTTON_HEIGHT
);
171 p
+= widget_data
[i
].box
.width
+ BUTTON_HSPACING
;
175 *y
+= BUTTON_VSPACING
+ BUTTON_HEIGHT
;
180 static widget_handler_status_T
181 display_button(struct dialog_data
*dlg_data
, struct widget_data
*widget_data
)
183 struct terminal
*term
= dlg_data
->win
->term
;
184 struct color_pair
*color
, *shortcut_color
;
185 struct box
*pos
= &widget_data
->box
;
187 int sel
= is_selected_widget(dlg_data
, widget_data
);
190 shortcut_color
= get_bfu_color(term
, "dialog.button-shortcut-selected");
191 color
= get_bfu_color(term
, "dialog.button-selected");
193 shortcut_color
= get_bfu_color(term
, "dialog.button-shortcut");
194 color
= get_bfu_color(term
, "dialog.button");
196 if (!color
|| !shortcut_color
) return EVENT_PROCESSED
;
200 int button_left_len
= utf8_ptr2cells(BUTTON_LEFT
, NULL
);
201 int button_right_len
= utf8_ptr2cells(BUTTON_RIGHT
, NULL
);
203 x
= pos
->x
+ button_left_len
;
204 len
= widget_data
->box
.width
-
205 (button_left_len
+ button_right_len
);
208 #endif /* CONFIG_UTF8 */
210 x
= pos
->x
+ BUTTON_LEFT_LEN
;
211 len
= widget_data
->box
.width
- BUTTON_LR_LEN
;
215 draw_text(term
, pos
->x
, pos
->y
, BUTTON_LEFT
, BUTTON_LEFT_LEN
, 0, color
);
217 unsigned char *text
= widget_data
->widget
->text
;
218 int hk_pos
= widget_data
->widget
->info
.button
.hotkey_pos
;
221 attr
= get_opt_bool("ui.dialogs.underline_button_shortcuts",
223 ? SCREEN_ATTR_UNDERLINE
: 0;
228 int hk_bytes
= utf8charlen(&text
[hk_pos
+1]);
229 int cells_to_hk
= utf8_ptr2cells(text
,
231 int right
= widget_data
->widget
->info
.button
.truetextlen
235 int hk_cells
= utf8_char2cells(&text
[hk_pos
240 draw_text(term
, x
, pos
->y
,
241 text
, hk_pos
, 0, color
);
243 draw_text(term
, x
+ cells_to_hk
, pos
->y
,
244 &text
[hk_pos
+ 1], hk_bytes
,
245 attr
, shortcut_color
);
248 draw_text(term
, x
+cells_to_hk
+hk_cells
,
250 &text
[hk_pos
+ hk_bytes
+ 1],
251 right
- 1, 0, color
);
254 int hk_width
= utf8_char2cells(text
, NULL
);
255 int hk_len
= utf8charlen(text
);
257 utf8_cells2bytes(&text
[hk_len
],
261 draw_text(term
, x
, pos
->y
,
263 attr
, shortcut_color
);
265 draw_text(term
, x
+ hk_width
, pos
->y
,
266 &text
[hk_len
], len_to_display
,
270 #endif /* CONFIG_UTF8 */
272 int right
= widget_data
->widget
->info
.button
.truetextlen
- hk_pos
- 1;
275 draw_text(term
, x
, pos
->y
, text
, hk_pos
, 0, color
);
277 draw_text(term
, x
+ hk_pos
, pos
->y
,
278 &text
[hk_pos
+ 1], 1, attr
, shortcut_color
);
280 draw_text(term
, x
+ hk_pos
+ 1, pos
->y
,
281 &text
[hk_pos
+ 2], right
- 1, 0, color
);
285 draw_text(term
, x
, pos
->y
, text
, 1, attr
, shortcut_color
);
286 draw_text(term
, x
+ 1, pos
->y
, &text
[1], len
- 1, 0, color
);
291 int text_cells
= utf8_ptr2cells(widget_data
->widget
->text
, NULL
);
292 int hk
= (widget_data
->widget
->info
.button
.hotkey_pos
>= 0);
294 draw_text(term
, x
+ text_cells
- hk
, pos
->y
,
295 BUTTON_RIGHT
, BUTTON_RIGHT_LEN
, 0, color
);
297 #endif /* CONFIG_UTF8 */
298 draw_text(term
, x
+ len
, pos
->y
, BUTTON_RIGHT
,
299 BUTTON_RIGHT_LEN
, 0, color
);
301 set_cursor(term
, x
, pos
->y
, 1);
302 set_window_ptr(dlg_data
->win
, pos
->x
, pos
->y
);
304 return EVENT_PROCESSED
;
307 static widget_handler_status_T
308 mouse_button(struct dialog_data
*dlg_data
, struct widget_data
*widget_data
)
310 struct terminal
*term
= dlg_data
->win
->term
;
311 struct term_event
*ev
= dlg_data
->term_event
;
313 if (check_mouse_wheel(ev
))
314 return EVENT_NOT_PROCESSED
;
316 if (!check_mouse_position(ev
, &widget_data
->box
))
317 return EVENT_NOT_PROCESSED
;
319 select_widget(dlg_data
, widget_data
);
321 do_not_ignore_next_mouse_event(term
);
323 if (check_mouse_action(ev
, B_UP
) && widget_data
->widget
->ops
->select
)
324 return widget_data
->widget
->ops
->select(dlg_data
, widget_data
);
326 return EVENT_PROCESSED
;
329 static widget_handler_status_T
330 select_button(struct dialog_data
*dlg_data
, struct widget_data
*widget_data
)
332 return widget_data
->widget
->handler(dlg_data
, widget_data
);
335 const struct widget_ops button_ops
= {