1008: Moved the definition of the big_files_offset to the form.c.
[elinks.git] / src / bfu / button.c
blobb567251f8b1b1d57c3c9b16805c1f3db61d525c4
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 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)
122 int i1 = 0;
124 while (i1 < n) {
125 struct widget_data *widget_data1 = widget_data + i1;
126 int i2 = i1 + 1;
127 int mw;
129 while (i2 < n) {
130 mw = 0;
131 #ifdef CONFIG_UTF8
132 buttons_width(widget_data1, i2 - i1 + 1, NULL, &mw,
133 term->utf8_cp);
134 #else
135 buttons_width(widget_data1, i2 - i1 + 1, NULL, &mw);
136 #endif /* CONFIG_UTF8 */
137 if (mw <= w) i2++;
138 else break;
141 mw = 0;
142 #ifdef CONFIG_UTF8
143 buttons_width(widget_data1, i2 - i1, NULL, &mw, term->utf8_cp);
144 #else
145 buttons_width(widget_data1, i2 - i1, NULL, &mw);
146 #endif /* CONFIG_UTF8 */
147 if (rw) int_bounds(rw, mw, w);
149 if (!format_only) {
150 int i;
151 int p = x + (align == ALIGN_CENTER ? (w - mw) / 2 : 0);
152 #ifdef CONFIG_UTF8
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++) {
158 #ifdef CONFIG_UTF8
159 if (term->utf8_cp)
160 set_box(&widget_data[i].box,
161 p, *y,
162 utf8_ptr2cells(widget_data[i].widget->text, NULL)
163 + button_lr_len, BUTTON_HEIGHT);
164 else
165 #endif /* CONFIG_UTF8 */
166 set_box(&widget_data[i].box,
167 p, *y,
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;
176 i1 = i2;
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;
186 int len, x;
187 int sel = is_selected_widget(dlg_data, widget_data);
189 if (sel) {
190 shortcut_color = get_bfu_color(term, "dialog.button-shortcut-selected");
191 color = get_bfu_color(term, "dialog.button-selected");
192 } else {
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;
198 #ifdef CONFIG_UTF8
199 if (term->utf8_cp) {
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);
207 } else
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);
216 if (len > 0) {
217 unsigned char *text = widget_data->widget->text;
218 int hk_pos = widget_data->widget->info.button.hotkey_pos;
219 int attr;
221 attr = get_opt_bool("ui.dialogs.underline_button_shortcuts",
222 NULL)
223 ? SCREEN_ATTR_UNDERLINE : 0;
225 #ifdef CONFIG_UTF8
226 if (term->utf8_cp) {
227 if (hk_pos >= 0) {
228 int hk_bytes = utf8charlen(&text[hk_pos+1]);
229 int cells_to_hk = utf8_ptr2cells(text,
230 &text[hk_pos]);
231 int right = widget_data->widget->info.button.truetextlen
232 - hk_pos
233 - hk_bytes;
235 int hk_cells = utf8_char2cells(&text[hk_pos
236 + 1],
237 NULL);
239 if (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);
247 if (right > 1)
248 draw_text(term, x+cells_to_hk+hk_cells,
249 pos->y,
250 &text[hk_pos + hk_bytes + 1],
251 right - 1, 0, color);
253 } else {
254 int hk_width = utf8_char2cells(text, NULL);
255 int hk_len = utf8charlen(text);
256 int len_to_display =
257 utf8_cells2bytes(&text[hk_len],
258 len - hk_width,
259 NULL);
261 draw_text(term, x, pos->y,
262 text, hk_len,
263 attr, shortcut_color);
265 draw_text(term, x + hk_width, pos->y,
266 &text[hk_len], len_to_display,
267 0, color);
269 } else
270 #endif /* CONFIG_UTF8 */
271 if (hk_pos >= 0) {
272 int right = widget_data->widget->info.button.truetextlen - hk_pos - 1;
274 if (hk_pos) {
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);
279 if (right > 1) {
280 draw_text(term, x + hk_pos + 1, pos->y,
281 &text[hk_pos + 2], right - 1, 0, color);
284 } else {
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);
289 #ifdef CONFIG_UTF8
290 if (term->utf8_cp) {
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);
296 } else
297 #endif /* CONFIG_UTF8 */
298 draw_text(term, x + len, pos->y, BUTTON_RIGHT,
299 BUTTON_RIGHT_LEN, 0, color);
300 if (sel) {
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 = {
336 display_button,
337 NULL,
338 mouse_button,
339 NULL,
340 select_button,
341 NULL,