big dialogs: Refactoring. do not pass the term.
[elinks.git] / src / bfu / button.c
blob0f3ccdfc9fc148af3f84f1e2d05f9f7c44ca6834
1 /* Button widget handlers. */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include <string.h>
9 #include "elinks.h"
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
38 void
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)
43 #else
44 void
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)
48 #endif
50 int textlen = strlen(text);
51 struct widget *widget = &dlg->widgets[dlg->number_of_widgets++];
53 widget->type = WIDGET_BUTTON;
54 widget->handler = handler;
55 widget->text = text;
56 widget->data = data;
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;
65 if (textlen > 1) {
66 unsigned char *pos = memchr(text, '~', textlen - 1);
68 if (pos) {
69 widget->info.button.hotkey_pos = pos - text;
70 widget->info.button.textlen--;
72 #ifdef DEBUG_BUTTON_HOTKEY
73 else {
74 DBG("%s:%d missing keyboard accelerator in \"%s\".", file, line, text);
76 #endif
80 #ifdef CONFIG_UTF8
81 static void
82 buttons_width(struct widget_data *widget_data, int n,
83 int *minwidth, int *maxwidth, int utf8)
84 #else
85 static void
86 buttons_width(struct widget_data *widget_data, int n,
87 int *minwidth, int *maxwidth)
88 #endif /* CONFIG_UTF8 */
90 int maxw = -BUTTON_HSPACING;
91 #ifdef CONFIG_UTF8
92 int button_lr_len = utf8_ptr2cells(BUTTON_LEFT, NULL)
93 + utf8_ptr2cells(BUTTON_RIGHT, NULL);
94 #endif /* CONFIG_UTF8 */
96 assert(n > 0);
97 if_assert_failed return;
99 while (n--) {
100 int minw;
101 #ifdef CONFIG_UTF8
102 if (utf8)
103 minw = utf8_ptr2cells((widget_data++)->widget->text, NULL)
104 + BUTTON_HSPACING + button_lr_len;
105 else
106 #endif /* CONFIG_UTF8 */
107 minw = (widget_data++)->widget->info.button.textlen
108 + BUTTON_HSPACING + BUTTON_LR_LEN;
110 maxw += minw;
111 if (minwidth) int_lower_bound(minwidth, minw);
114 if (maxwidth) int_lower_bound(maxwidth, maxw);
117 void
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;
123 int i1 = 0;
125 while (i1 < n) {
126 struct widget_data *widget_data1 = widget_data + i1;
127 int i2 = i1 + 1;
128 int mw;
130 while (i2 < n) {
131 mw = 0;
132 #ifdef CONFIG_UTF8
133 buttons_width(widget_data1, i2 - i1 + 1, NULL, &mw,
134 term->utf8_cp);
135 #else
136 buttons_width(widget_data1, i2 - i1 + 1, NULL, &mw);
137 #endif /* CONFIG_UTF8 */
138 if (mw <= w) i2++;
139 else break;
142 mw = 0;
143 #ifdef CONFIG_UTF8
144 buttons_width(widget_data1, i2 - i1, NULL, &mw, term->utf8_cp);
145 #else
146 buttons_width(widget_data1, i2 - i1, NULL, &mw);
147 #endif /* CONFIG_UTF8 */
148 if (rw) int_bounds(rw, mw, w);
150 if (!format_only) {
151 int i;
152 int p = x + (align == ALIGN_CENTER ? (w - mw) / 2 : 0);
153 #ifdef CONFIG_UTF8
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++) {
159 #ifdef CONFIG_UTF8
160 if (term->utf8_cp)
161 set_box(&widget_data[i].box,
162 p, *y,
163 utf8_ptr2cells(widget_data[i].widget->text, NULL)
164 + button_lr_len, BUTTON_HEIGHT);
165 else
166 #endif /* CONFIG_UTF8 */
167 set_box(&widget_data[i].box,
168 p, *y,
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;
177 i1 = i2;
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;
187 int len, x;
188 int sel = is_selected_widget(dlg_data, widget_data);
190 if (sel) {
191 shortcut_color = get_bfu_color(term, "dialog.button-shortcut-selected");
192 color = get_bfu_color(term, "dialog.button-selected");
193 } else {
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;
199 #ifdef CONFIG_UTF8
200 if (term->utf8_cp) {
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);
208 } else
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);
217 if (len > 0) {
218 unsigned char *text = widget_data->widget->text;
219 int hk_pos = widget_data->widget->info.button.hotkey_pos;
220 int attr;
222 attr = get_opt_bool("ui.dialogs.underline_button_shortcuts",
223 NULL)
224 ? SCREEN_ATTR_UNDERLINE : 0;
226 #ifdef CONFIG_UTF8
227 if (term->utf8_cp) {
228 if (hk_pos >= 0) {
229 int hk_bytes = utf8charlen(&text[hk_pos+1]);
230 int cells_to_hk = utf8_ptr2cells(text,
231 &text[hk_pos]);
232 int right = widget_data->widget->info.button.truetextlen
233 - hk_pos
234 - hk_bytes;
236 int hk_cells = utf8_char2cells(&text[hk_pos
237 + 1],
238 NULL);
240 if (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);
248 if (right > 1)
249 draw_dlg_text(term, dlg_data, x+cells_to_hk+hk_cells,
250 pos->y,
251 &text[hk_pos + hk_bytes + 1],
252 right - 1, 0, color);
254 } else {
255 int hk_width = utf8_char2cells(text, NULL);
256 int hk_len = utf8charlen(text);
257 int len_to_display =
258 utf8_cells2bytes(&text[hk_len],
259 len - hk_width,
260 NULL);
262 draw_dlg_text(term, dlg_data, x, pos->y,
263 text, hk_len,
264 attr, shortcut_color);
266 draw_dlg_text(term, dlg_data, x + hk_width, pos->y,
267 &text[hk_len], len_to_display,
268 0, color);
270 } else
271 #endif /* CONFIG_UTF8 */
272 if (hk_pos >= 0) {
273 int right = widget_data->widget->info.button.truetextlen - hk_pos - 1;
275 if (hk_pos) {
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);
280 if (right > 1) {
281 draw_dlg_text(term, dlg_data, x + hk_pos + 1, pos->y,
282 &text[hk_pos + 2], right - 1, 0, color);
285 } else {
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);
290 #ifdef CONFIG_UTF8
291 if (term->utf8_cp) {
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);
297 } else
298 #endif /* CONFIG_UTF8 */
299 draw_dlg_text(term, dlg_data, x + len, pos->y, BUTTON_RIGHT,
300 BUTTON_RIGHT_LEN, 0, color);
301 if (sel) {
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 = {
337 display_button,
338 NULL,
339 mouse_button,
340 NULL,
341 select_button,
342 NULL,