iconv: Bail out of the loop when an illegal sequence of bytes occurs.
[elinks/elinks-j605.git] / src / bfu / button.c
blobb522321b5a39380e2c40ce60db32fac6d2d23b6d
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 #ifdef CONFIG_UTF8
123 struct terminal *term = dlg_data->win->term;
124 #endif
125 int i1 = 0;
127 while (i1 < n) {
128 struct widget_data *widget_data1 = widget_data + i1;
129 int i2 = i1 + 1;
130 int mw;
132 while (i2 < n) {
133 mw = 0;
134 #ifdef CONFIG_UTF8
135 buttons_width(widget_data1, i2 - i1 + 1, NULL, &mw,
136 term->utf8_cp);
137 #else
138 buttons_width(widget_data1, i2 - i1 + 1, NULL, &mw);
139 #endif /* CONFIG_UTF8 */
140 if (mw <= w) i2++;
141 else break;
144 mw = 0;
145 #ifdef CONFIG_UTF8
146 buttons_width(widget_data1, i2 - i1, NULL, &mw, term->utf8_cp);
147 #else
148 buttons_width(widget_data1, i2 - i1, NULL, &mw);
149 #endif /* CONFIG_UTF8 */
150 if (rw) int_bounds(rw, mw, w);
152 if (!format_only) {
153 int i;
154 int p = x + (align == ALIGN_CENTER ? (w - mw) / 2 : 0);
155 #ifdef CONFIG_UTF8
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++) {
161 #ifdef CONFIG_UTF8
162 if (term->utf8_cp)
163 set_box(&widget_data[i].box,
164 p, *y,
165 utf8_ptr2cells(widget_data[i].widget->text, NULL)
166 + button_lr_len, BUTTON_HEIGHT);
167 else
168 #endif /* CONFIG_UTF8 */
169 set_box(&widget_data[i].box,
170 p, *y,
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;
179 i1 = i2;
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;
189 int len, x;
190 int sel = is_selected_widget(dlg_data, widget_data);
192 if (sel) {
193 shortcut_color = get_bfu_color(term, "dialog.button-shortcut-selected");
194 color = get_bfu_color(term, "dialog.button-selected");
195 } else {
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;
201 #ifdef CONFIG_UTF8
202 if (term->utf8_cp) {
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);
210 } else
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);
219 if (len > 0) {
220 unsigned char *text = widget_data->widget->text;
221 int hk_pos = widget_data->widget->info.button.hotkey_pos;
222 int attr;
224 attr = get_opt_bool("ui.dialogs.underline_button_shortcuts",
225 NULL)
226 ? SCREEN_ATTR_UNDERLINE : 0;
228 #ifdef CONFIG_UTF8
229 if (term->utf8_cp) {
230 if (hk_pos >= 0) {
231 int hk_bytes = utf8charlen(&text[hk_pos+1]);
232 int cells_to_hk = utf8_ptr2cells(text,
233 &text[hk_pos]);
234 int right = widget_data->widget->info.button.truetextlen
235 - hk_pos
236 - hk_bytes;
238 int hk_cells = utf8_char2cells(&text[hk_pos
239 + 1],
240 NULL);
242 if (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);
250 if (right > 1)
251 draw_dlg_text(dlg_data, x+cells_to_hk+hk_cells,
252 pos->y,
253 &text[hk_pos + hk_bytes + 1],
254 right - 1, 0, color);
256 } else {
257 int hk_width = utf8_char2cells(text, NULL);
258 int hk_len = utf8charlen(text);
259 int len_to_display =
260 utf8_cells2bytes(&text[hk_len],
261 len - hk_width,
262 NULL);
264 draw_dlg_text(dlg_data, x, pos->y,
265 text, hk_len,
266 attr, shortcut_color);
268 draw_dlg_text(dlg_data, x + hk_width, pos->y,
269 &text[hk_len], len_to_display,
270 0, color);
272 } else
273 #endif /* CONFIG_UTF8 */
274 if (hk_pos >= 0) {
275 int right = widget_data->widget->info.button.truetextlen - hk_pos - 1;
277 if (hk_pos) {
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);
282 if (right > 1) {
283 draw_dlg_text(dlg_data, x + hk_pos + 1, pos->y,
284 &text[hk_pos + 2], right - 1, 0, color);
287 } else {
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);
292 #ifdef CONFIG_UTF8
293 if (term->utf8_cp) {
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);
299 } else
300 #endif /* CONFIG_UTF8 */
301 draw_dlg_text(dlg_data, x + len, pos->y, BUTTON_RIGHT,
302 BUTTON_RIGHT_LEN, 0, color);
303 if (sel) {
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 = {
339 display_button,
340 NULL,
341 mouse_button,
342 NULL,
343 select_button,
344 NULL,