1 /* view_gr.c
2  * (c) 2002 Mikulas Patocka
3  * This file is a part of the Links program, released under GPL.
4  */
5 
6 #include "cfg.h"
7 
8 #ifdef G
9 
10 #include "links.h"
11 
12 static int *highlight_positions = NULL;
13 static int *highlight_lengths = NULL;
14 static int n_highlight_positions = 0;
15 
16 static int root_x = 0;
17 static int root_y = 0;
18 
19 static void get_object_pos(struct g_object *o, int *x, int *y);
20 static void g_get_search_data(struct f_data *f);
21 static struct g_object_text * g_find_nearest_object(struct f_data *f, int x, int y);
22 
23 static int previous_link=-1;	/* for mouse event handlers */
24 
g_dummy_draw(struct f_data_c * fd,struct g_object * t,int x,int y)25 void g_dummy_draw(struct f_data_c *fd, struct g_object *t, int x, int y)
26 {
27 }
28 
g_tag_destruct(struct g_object * t_)29 void g_tag_destruct(struct g_object *t_)
30 {
31 	struct g_object_tag *t = get_struct(t_, struct g_object_tag,  go);
32 	mem_free(t);
33 }
34 
g_dummy_mouse(struct f_data_c * fd,struct g_object * a,int x,int y,int b)35 void g_dummy_mouse(struct f_data_c *fd, struct g_object *a, int x, int y, int b)
36 {
37 }
38 
39 static unsigned char print_all_textarea = 0;
40 
41 
42 /* returns byte index of x in t->text */
43 /* x is relative coordinate within the text (can be out of bounds) */
g_find_text_pos(struct g_object_text * t,int x)44 static int g_find_text_pos(struct g_object_text *t, int x)
45 {
46 	int i=0, p=0;
47 	unsigned char *text=t->text;
48 	int ox, oy;
49 
50 	get_object_pos(&t->goti.go, &ox, &oy);
51 	x -= ox;
52 
53 	if (x < 0) x = 0;
54 	if (x > t->goti.go.xw) x = t->goti.go.xw;
55 
56 	while (1) {
57 		unsigned c;
58 		unsigned char *old_text;
59 		int w;
60 
61 		old_text = text;
62 		if (!*text) break;
63 		GET_UTF_8(text, c);
64 		w = g_char_width(t->style, c);
65 		if (x < (p + (w >> 1))) break;
66 		p += w;
67 		i += (int)(text - old_text);
68 		if (p >= x) break;
69 	}
70 	return i;
71 }
72 
g_text_no_search(struct f_data * f,struct g_object_text * t)73 static int g_text_no_search(struct f_data *f, struct g_object_text *t)
74 {
75 	struct link *l;
76 	if (t->goti.link_num < 0) return 0;
77 	l = f->links + t->goti.link_num;
78 	if (l->type == L_SELECT || l->type == L_FIELD || l->type == L_AREA) return 1;
79 	return 0;
80 }
81 
prepare_input_field_char(unsigned char * p,unsigned char tx[7])82 static int prepare_input_field_char(unsigned char *p, unsigned char tx[7])
83 {
84 	unsigned char *pp = p;
85 	unsigned un;
86 	unsigned char *en;
87 	GET_UTF_8(p, un);
88 	if (!un) un = '*';
89 	if (un == 0xad) un = '-';
90 	en = encode_utf_8(un);
91 	strcpy(cast_char tx, cast_const_char en);
92 	return (int)(p - pp);
93 }
94 
g_text_draw(struct f_data_c * fd,struct g_object * t_,int x,int y)95 void g_text_draw(struct f_data_c *fd, struct g_object *t_, int x, int y)
96 {
97 	struct g_object_text *t = get_struct(t_, struct g_object_text, goti.go);
98 	struct form_control *form;
99 	struct form_state *fs;
100 	struct link *link;
101 	int l;
102 	int ll;
103 	int i, j;
104 	int yy;
105 	int cur;
106 	struct format_text_cache_entry *ftce;
107 	struct graphics_device *dev = fd->ses->term->dev;
108 
109 	if (x + t->goti.go.xw <= fd->ses->term->dev->clip.x1)
110 		return;
111 	if (x >= fd->ses->term->dev->clip.x2)
112 		return;
113 	if (!print_all_textarea) {
114 		if (y + t->goti.go.yw <= fd->ses->term->dev->clip.y1)
115 			return;
116 		if (y >= fd->ses->term->dev->clip.y2)
117 			return;
118 	}
119 
120 	link = t->goti.link_num >= 0 ? fd->f_data->links + t->goti.link_num : NULL;
121 	if (link && ((form = link->form))) {
122 		fs = find_form_state(fd, form);
123 		switch (form->type) {
124 			struct style *inv;
125 			int in, lid;
126 			int sl, td;
127 			case FC_RADIO:
128 				if (link && fd->active && fd->vs->g_display_link && fd->vs->current_link == link - fd->f_data->links) inv = g_invert_style(t->style), in = 1;
129 				else inv = t->style, in = 0;
130 				g_print_text(dev, x, y, inv, fs->state ? cast_uchar "[X]" : cast_uchar "[ ]", NULL);
131 				if (in) g_free_style(inv);
132 				return;
133 			case FC_CHECKBOX:
134 				if (link && fd->active && fd->vs->g_display_link && fd->vs->current_link == link - fd->f_data->links) inv = g_invert_style(t->style), in = 1;
135 				else inv = t->style, in = 0;
136 				g_print_text(dev, x, y, inv, fs->state ? cast_uchar "[X]" : cast_uchar "[ ]", NULL);
137 				if (in) g_free_style(inv);
138 				return;
139 			case FC_SELECT:
140 				if (link && fd->active && fd->vs->g_display_link && fd->vs->current_link == link - fd->f_data->links) inv = g_invert_style(t->style), in = 1;
141 				else inv = t->style, in = 0;
142 				fixup_select_state(form, fs);
143 				l = 0;
144 				if (fs->state < form->nvalues) g_print_text(dev, x, y, inv, form->labels[fs->state], &l);
145 				while (l < t->goti.go.xw) g_print_text(dev, x + l, y, inv, cast_uchar "_", &l);
146 				if (in) g_free_style(inv);
147 				return;
148 			case FC_TEXT:
149 			case FC_PASSWORD:
150 			case FC_FILE_UPLOAD:
151 				if ((size_t)fs->vpos > strlen(cast_const_char fs->string)) fs->vpos = (int)strlen(cast_const_char fs->string);
152 				sl = (int)strlen(cast_const_char fs->string);
153 				td = textptr_diff(fs->string + fs->state, fs->string + fs->vpos, fd->f_data->opt.cp);
154 				while (fs->vpos < sl && td >= form->size) {
155 					unsigned char *p = fs->string + fs->vpos;
156 					FWD_UTF_8(p);
157 					fs->vpos = (int)(p - fs->string);
158 					td--;
159 				}
160 				while (fs->vpos > fs->state) {
161 					unsigned char *p = fs->string + fs->vpos;
162 					BACK_UTF_8(p, fs->string);
163 					fs->vpos = (int)(p - fs->string);
164 				}
165 				l = 0;
166 				i = 0;
167 				ll = (int)strlen(cast_const_char fs->string);
168 				while (l < t->goti.go.xw) {
169 					struct style *st = t->style;
170 					int sm = 0;
171 					unsigned char tx[7];
172 					if (fs->state == fs->vpos + i && t->goti.link_num == fd->vs->current_link && fd->ses->locked_link) {
173 						st = g_invert_style(t->style);
174 						sm = 1;
175 					}
176 					if (fs->vpos + i >= ll) {
177 						tx[0] = '_', tx[1] = 0, i++;
178 					} else {
179 						i += prepare_input_field_char(fs->string + fs->vpos + i, tx);
180 						if (form->type == FC_PASSWORD) tx[0] = '*', tx[1] = 0;
181 					}
182 					g_print_text(dev, x + l, y, st, tx, &l);
183 					if (sm) g_free_style(st);
184 				}
185 				return;
186 			case FC_TEXTAREA:
187 				cur = area_cursor(fd, form, fs);
188 				ftce = format_text(fd, form, fs);
189 
190 				yy = y - t->goti.link_order * t->style->height;
191 				lid = fs->vypos;
192 				for (j = 0; j < form->rows; j++) {
193 					unsigned char *pp, *en;
194 					int remaining_chars;
195 					int xx = fs->vpos;
196 					if (lid < ftce->n_lines) {
197 						pp = fs->string + ftce->ln[lid].st_offs;
198 						en = fs->string + ftce->ln[lid].en_offs;
199 						remaining_chars = ftce->ln[lid].chars;
200 					} else {
201 						pp = en = NULL;
202 						remaining_chars = 0;
203 					}
204 					while (pp && pp < en && xx > 0) {
205 						FWD_UTF_8(pp);
206 						xx--;
207 						remaining_chars--;
208 					}
209 					if (cur >= 0 && cur < form->cols && t->goti.link_num == fd->vs->current_link && fd->ses->locked_link && fd->active) {
210 						unsigned char tx[7];
211 						int xx = x;
212 
213 						if (print_all_textarea || j == t->goti.link_order) while (xx < x + t->goti.go.xw) {
214 							struct style *st = t->style;
215 							if (pp && pp < en) {
216 								pp += prepare_input_field_char(pp, tx);
217 							} else {
218 								tx[0] = '_';
219 								tx[1] = 0;
220 							}
221 							if (!cur) {
222 								st = g_invert_style(t->style);
223 							}
224 							g_print_text(dev, xx, yy + j * t->style->height, st, tx, &xx);
225 							if (!cur) {
226 								g_free_style(st);
227 							}
228 							cur--;
229 						} else cur -= form->cols;
230 					} else {
231 						if (print_all_textarea || j == t->goti.link_order) {
232 							unsigned char *a;
233 							struct rect old;
234 							size_t text_size;
235 							if (remaining_chars <= form->cols)
236 								remaining_chars = form->cols - remaining_chars;
237 							else
238 								remaining_chars = 0;
239 							text_size = pp ? en - pp : 0;
240 							a = mem_alloc(text_size + remaining_chars + 1);
241 							if (text_size) memcpy(a, pp, text_size);
242 							memset(a + text_size, '_', remaining_chars);
243 							a[text_size + remaining_chars] = 0;
244 							restrict_clip_area(dev, &old, x, 0, x + t->goti.go.xw, dev->size.y2);
245 							g_print_text(dev, x, yy + j * t->style->height, t->style, a, NULL);
246 							set_clip_area(dev, &old);
247 							mem_free(a);
248 						}
249 						cur -= form->cols;
250 					}
251 					if (lid < ftce->n_lines) lid++;
252 				}
253 				return;
254 		}
255 	}
256 	if (link && fd->active && fd->vs->g_display_link && fd->vs->current_link == link - fd->f_data->links) {
257 		struct style *inv;
258 		inv = g_invert_style(t->style);
259 		g_print_text(dev, x, y, inv, t->text, NULL);
260 		g_free_style(inv);
261 	} else if ((!fd->f_data->hlt_len && (!highlight_positions || !n_highlight_positions)) || g_text_no_search(fd->f_data, t)) {
262 		prn:
263 		g_print_text(dev, x, y, t->style, t->text, NULL);
264 	} else {
265 		int tlen = (int)strlen(cast_const_char t->text);
266 		int found;
267 		int start = t->srch_pos;
268 		int end = t->srch_pos + tlen;
269 		int hl_start, hl_len;
270 		unsigned char *mask;
271 		unsigned char *tx;
272 		int txl;
273 		int pmask;
274 		int ii;
275 		struct style *inv;
276 
277 		intersect(fd->f_data->hlt_pos, fd->f_data->hlt_len, start, tlen, &hl_start, &hl_len);
278 
279 #define B_EQUAL(t, m) (highlight_positions[t] + highlight_lengths[t] > start && highlight_positions[t] < end)
280 #define B_ABOVE(t, m) (highlight_positions[t] >= end)
281 		BIN_SEARCH(n_highlight_positions, B_EQUAL, B_ABOVE, *, found);
282 		mask = mem_calloc(tlen);
283 		if (found != -1) {
284 			while (found > 0 && B_EQUAL(found - 1, *)) found--;
285 			while (found < n_highlight_positions && !B_ABOVE(found, *)) {
286 				int pos = highlight_positions[found] - t->srch_pos;
287 				for (ii = 0; ii < highlight_lengths[found]; ii++) {
288 					if (pos >= 0 && pos < tlen) mask[pos] = 1;
289 					pos++;
290 				}
291 				found++;
292 			}
293 			if (hl_len) goto hl;
294 		}
295 		else if (hl_len)
296 		{
297 			int x;
298 			hl:
299 			for (x = 0; x < hl_len; x++) mask[hl_start - t->srch_pos + x] ^= 1;
300 			/*memset(mask+hl_start-t->srch_pos, 1, hl_len);*/
301 		}
302 		else
303 		{
304 			mem_free(mask);
305 			goto prn;
306 		}
307 
308 		inv = g_invert_style(t->style);
309 		tx = init_str();;
310 		txl = 0;
311 		pmask = -1;
312 		for (ii = 0; ii < tlen; ii++) {
313 			if (mask[ii] != pmask) {
314 				g_print_text(dev, x, y, pmask ? inv : t->style, tx, &x);
315 				mem_free(tx);
316 				tx = init_str();
317 				txl = 0;
318 			}
319 			add_chr_to_str(&tx, &txl, t->text[ii]);
320 			pmask = mask[ii];
321 		}
322 		g_print_text(dev, x, y, pmask ? inv : t->style, tx, &x);
323 		mem_free(tx);
324 		g_free_style(inv);
325 		mem_free(mask);
326 	}
327 }
328 
g_text_destruct(struct g_object * t_)329 void g_text_destruct(struct g_object *t_)
330 {
331 	struct g_object_text *t = get_struct(t_, struct g_object_text, goti.go);
332 	release_image_map(t->goti.map);
333 	g_free_style(t->style);
334 	mem_free(t);
335 }
336 
g_line_draw(struct f_data_c * fd,struct g_object * l_,int xx,int yy)337 void g_line_draw(struct f_data_c *fd, struct g_object *l_, int xx, int yy)
338 {
339 	struct g_object_line *l = get_struct(l_, struct g_object_line, go);
340 	struct graphics_device *dev = fd->ses->term->dev;
341 	int i;
342 	int x = 0;
343 	for (i = 0; i < l->n_entries; i++) {
344 		struct g_object *o = l->entries[i];
345 		if (o->x > x) g_draw_background(dev, l->bg, xx + x, yy, o->x - x, l->go.yw);
346 		if (o->y > 0) g_draw_background(dev, l->bg, xx + o->x, yy, o->xw, o->y);
347 		if (o->y + o->yw < l->go.yw) g_draw_background(dev, l->bg, xx + o->x, yy + o->y + o->yw, o->xw, l->go.yw - o->y - o->yw);
348 		o->draw(fd, o, xx + o->x, yy + o->y);
349 		x = o->x + o->xw;
350 	}
351 	if (x < l->go.xw) g_draw_background(dev, l->bg, xx + x, yy, l->go.xw - x, l->go.yw);
352 }
353 
g_line_destruct(struct g_object * l_)354 void g_line_destruct(struct g_object *l_)
355 {
356 	struct g_object_line *l = get_struct(l_, struct g_object_line, go);
357 	int i;
358 	for (i = 0; i < l->n_entries; i++) l->entries[i]->destruct(l->entries[i]);
359 	mem_free(l);
360 }
361 
g_line_bg_destruct(struct g_object * l_)362 void g_line_bg_destruct(struct g_object *l_)
363 {
364 	struct g_object_line *l = get_struct(l_, struct g_object_line, go);
365 	g_release_background(l->bg);
366 	g_line_destruct(&l->go);
367 }
368 
g_line_get_list(struct g_object * l_,void (* f)(struct g_object * parent,struct g_object * child))369 void g_line_get_list(struct g_object *l_, void (*f)(struct g_object *parent, struct g_object *child))
370 {
371 	struct g_object_line *l = get_struct(l_, struct g_object_line, go);
372 	int i;
373 	for (i = 0; i < l->n_entries; i++) f(&l->go, l->entries[i]);
374 }
375 
376 #define OBJ_EQ(n, b)	(*a[n]).go.y <= (b) && (*a[n]).go.y + (*a[n]).go.yw > (b)
377 #define OBJ_ABOVE(n, b)	(*a[n]).go.y > (b)
378 
g_find_line(struct g_object_line ** a,int n,int p)379 static inline struct g_object_line **g_find_line(struct g_object_line **a, int n, int p)
380 {
381 	int res = -1;
382 	BIN_SEARCH(n, OBJ_EQ, OBJ_ABOVE, p, res);
383 	if (res == -1) return NULL;
384 	return &a[res];
385 }
386 
387 #undef OBJ_EQ
388 #undef OBJ_ABOVE
389 
g_area_draw(struct f_data_c * fd,struct g_object * a_,int xx,int yy)390 void g_area_draw(struct f_data_c *fd, struct g_object *a_, int xx, int yy)
391 {
392 	struct g_object_area *a = get_struct(a_, struct g_object_area, go);
393 	struct g_object_line **i;
394 	int rx = root_x, ry = root_y;
395 	int y1 = fd->ses->term->dev->clip.y1 - yy;
396 	int y2 = fd->ses->term->dev->clip.y2 - yy - 1;
397 	struct g_object_line **l1;
398 	struct g_object_line **l2;
399 	if (fd->ses->term->dev->clip.y1 == fd->ses->term->dev->clip.y2 || fd->ses->term->dev->clip.x1 == fd->ses->term->dev->clip.x2) return;
400 	l1 = g_find_line(a->lines, a->n_lines, y1);
401 	l2 = g_find_line(a->lines, a->n_lines, y2);
402 	root_x = xx, root_y = yy;
403 	if (!l1) {
404 		if (y1 > a->go.yw) return;
405 		else l1 = &a->lines[0];
406 	}
407 	if (!l2) {
408 		if (y2 < 0) return;
409 		else l2 = &a->lines[a->n_lines - 1];
410 	}
411 	for (i = l1; i <= l2; i++) {
412 		struct g_object *o = &(*i)->go;
413 		o->draw(fd, o, xx + o->x, yy + o->y);
414 	}
415 	root_x = rx, root_y = ry;
416 }
417 
g_area_destruct(struct g_object * a_)418 void g_area_destruct(struct g_object *a_)
419 {
420 	struct g_object_area *a = get_struct(a_, struct g_object_area, go);
421 	int i;
422 	g_release_background(a->bg);
423 	for (i = 0; i < a->n_lines; i++) {
424 		struct g_object *o = &a->lines[i]->go;
425 		o->destruct(o);
426 	}
427 	mem_free(a);
428 }
429 
g_area_get_list(struct g_object * a_,void (* f)(struct g_object * parent,struct g_object * child))430 void g_area_get_list(struct g_object *a_, void (*f)(struct g_object *parent, struct g_object *child))
431 {
432 	struct g_object_area *a = get_struct(a_, struct g_object_area, go);
433 	int i;
434 	for (i = 0; i < a->n_lines; i++) f(&a->go, &a->lines[i]->go);
435 }
436 
437 /*
438  * dsize - size of scrollbar
439  * total - total data
440  * vsize - visible data
441  * vpos - position of visible data
442  */
443 
get_scrollbar_pos(int dsize,int total,int vsize,int vpos,int * start,int * end)444 void get_scrollbar_pos(int dsize, int total, int vsize, int vpos, int *start, int *end)
445 {
446 	int ssize;
447 	if (!total) {
448 		*start = *end = 0;
449 		return;
450 	}
451 	ssize = (int)((double)dsize * vsize / total);
452 	if (ssize < G_SCROLL_BAR_MIN_SIZE) ssize = G_SCROLL_BAR_MIN_SIZE;
453 	if (total == vsize) {
454 		*start = 0; *end = dsize;
455 		return;
456 	}
457 	*start = (int)((double)(dsize - ssize) * vpos / (total - vsize) + 0.5);
458 	*end = *start + ssize;
459 	if (*start > dsize) *start = dsize;
460 	if (*start < 0) *start = 0;
461 	if (*end > dsize) *end = dsize;
462 	if (*end < 0) *end = 0;
463 	/*
464 	else {
465 		*start = (double)vpos * dsize / total;
466 		*end = (double)(vpos + vsize) * dsize / total;
467 	}
468 	if (*end > dsize) *end = dsize;
469 	*/
470 }
471 
472 static long scroll_bar_frame_color;
473 static long scroll_bar_area_color;
474 static long scroll_bar_bar_color;
475 
draw_vscroll_bar(struct graphics_device * dev,int x,int y,int yw,int total,int view,int pos)476 void draw_vscroll_bar(struct graphics_device *dev, int x, int y, int yw, int total, int view, int pos)
477 {
478 	int spos, epos;
479 	drv->draw_hline(dev, x, y, x + G_SCROLL_BAR_WIDTH, scroll_bar_frame_color);
480 	drv->draw_vline(dev, x, y, y + yw, scroll_bar_frame_color);
481 	drv->draw_vline(dev, x + G_SCROLL_BAR_WIDTH - 1, y, y + yw, scroll_bar_frame_color);
482 	drv->draw_hline(dev, x, y + yw - 1, x + G_SCROLL_BAR_WIDTH, scroll_bar_frame_color);
483 	drv->draw_vline(dev, x + 1, y + 1, y + yw - 1, scroll_bar_area_color);
484 	drv->draw_vline(dev, x + G_SCROLL_BAR_WIDTH - 2, y + 1, y + yw - 1, scroll_bar_area_color);
485 	get_scrollbar_pos(yw - 4, total, view, pos, &spos, &epos);
486 	drv->fill_area(dev, x + 2, y + 1, x + G_SCROLL_BAR_WIDTH - 2, y + 2 + spos, scroll_bar_area_color);
487 	drv->fill_area(dev, x + 2, y + 2 + spos, x + G_SCROLL_BAR_WIDTH - 2, y + 2 + epos, scroll_bar_bar_color);
488 	drv->fill_area(dev, x + 2, y + 2 + epos, x + G_SCROLL_BAR_WIDTH - 2, y + yw - 1, scroll_bar_area_color);
489 }
490 
draw_hscroll_bar(struct graphics_device * dev,int x,int y,int xw,int total,int view,int pos)491 void draw_hscroll_bar(struct graphics_device *dev, int x, int y, int xw, int total, int view, int pos)
492 {
493 	int spos, epos;
494 	drv->draw_vline(dev, x, y, y + G_SCROLL_BAR_WIDTH, scroll_bar_frame_color);
495 	drv->draw_hline(dev, x, y, x + xw, scroll_bar_frame_color);
496 	drv->draw_hline(dev, x, y + G_SCROLL_BAR_WIDTH - 1, x + xw, scroll_bar_frame_color);
497 	drv->draw_vline(dev, x + xw - 1, y, y + G_SCROLL_BAR_WIDTH, scroll_bar_frame_color);
498 	drv->draw_hline(dev, x + 1, y + 1, x + xw - 1, scroll_bar_area_color);
499 	drv->draw_hline(dev, x + 1, y + G_SCROLL_BAR_WIDTH - 2, x + xw - 1, scroll_bar_area_color);
500 	get_scrollbar_pos(xw - 4, total, view, pos, &spos, &epos);
501 	drv->fill_area(dev, x + 1, y + 2, x + 2 + spos, y + G_SCROLL_BAR_WIDTH - 2, scroll_bar_area_color);
502 	drv->fill_area(dev, x + 2 + spos, y + 2, x + 2 + epos, y + G_SCROLL_BAR_WIDTH - 2, scroll_bar_bar_color);
503 	drv->fill_area(dev, x + 2 + epos, y + 2, x + xw - 1, y + G_SCROLL_BAR_WIDTH - 2, scroll_bar_area_color);
504 }
505 
g_get_search(struct f_data * f,unsigned char * s)506 static void g_get_search(struct f_data *f, unsigned char *s)
507 {
508 	int i;
509 	if (!s || !*s) return;
510 	if (f->last_search && !strcmp(cast_const_char f->last_search, cast_const_char s)) return;
511 	mem_free(f->search_positions);
512 	mem_free(f->search_lengths);
513 	f->search_positions = DUMMY, f->search_lengths = DUMMY, f->n_search_positions = 0;
514 	if (f->last_search) mem_free(f->last_search);
515 	if (!(f->last_search = stracpy(s))) return;
516 	for (i = 0; i < f->srch_string_size; i++) {
517 		int len;
518 		/*debug("%d: %d", i, f->srch_string[i]);*/
519 		if ((s[0] | f->srch_string[i]) < 0x80) {
520 			if ((f->srch_string[i] ^ s[0]) & 0xdf) continue;
521 			if (s[1] != 0 && (s[1] ^ f->srch_string[i + 1]) < 0x80) {
522 				if ((f->srch_string[i + 1] ^ s[1]) & 0xdf) continue;
523 			}
524 		}
525 		len = compare_case_utf8(f->srch_string + i, s);
526 		if (!len) continue;
527 		if (!(f->n_search_positions & (ALLOC_GR - 1))) {
528 			if ((unsigned)f->n_search_positions > MAXINT / sizeof(int) - ALLOC_GR) overalloc();
529 			f->search_positions = mem_realloc(f->search_positions, (f->n_search_positions + ALLOC_GR) * sizeof(int));
530 			f->search_lengths = mem_realloc(f->search_lengths, (f->n_search_positions + ALLOC_GR) * sizeof(int));
531 		}
532 		f->search_positions[f->n_search_positions] = i;
533 		f->search_lengths[f->n_search_positions] = len;
534 		f->n_search_positions++;
535 	}
536 }
537 
draw_root(struct f_data_c * scr,int x,int y)538 static void draw_root(struct f_data_c *scr, int x, int y)
539 {
540 	scr->f_data->root->draw(scr, scr->f_data->root, x, y);
541 }
542 
draw_graphical_doc(struct terminal * t,struct f_data_c * scr,int active)543 void draw_graphical_doc(struct terminal *t, struct f_data_c *scr, int active)
544 {
545 	struct rect old;
546 	struct view_state *vs = scr->vs;
547 	struct rect_set *rs;
548 	int xw = scr->xw;
549 	int yw = scr->yw;
550 	int vx, vy;
551 	int j;
552 
553 	if (active) {
554 		if (scr->ses->search_word && scr->ses->search_word[0]) {
555 			g_get_search_data(scr->f_data);
556 			g_get_search(scr->f_data, scr->ses->search_word);
557 			highlight_positions = scr->f_data->search_positions;
558 			highlight_lengths = scr->f_data->search_lengths;
559 			n_highlight_positions = scr->f_data->n_search_positions;
560 		}
561 	}
562 
563 	if (vs->view_pos > scr->f_data->y - scr->yw + scr->hsb * G_SCROLL_BAR_WIDTH) vs->view_pos = scr->f_data->y - scr->yw + scr->hsb * G_SCROLL_BAR_WIDTH;
564 	if (vs->view_pos < 0) vs->view_pos = 0;
565 	if (vs->view_posx > scr->f_data->x - scr->xw + scr->vsb * G_SCROLL_BAR_WIDTH) vs->view_posx = scr->f_data->x - scr->xw + scr->vsb * G_SCROLL_BAR_WIDTH;
566 	if (vs->view_posx < 0) vs->view_posx = 0;
567 	vx = vs->view_posx;
568 	vy = vs->view_pos;
569 	restrict_clip_area(t->dev, &old, scr->xp, scr->yp, scr->xp + xw, scr->yp + yw);
570 	if (scr->vsb) draw_vscroll_bar(t->dev, scr->xp + xw - G_SCROLL_BAR_WIDTH, scr->yp, yw - scr->hsb * G_SCROLL_BAR_WIDTH, scr->f_data->y, yw - scr->hsb * G_SCROLL_BAR_WIDTH, vs->view_pos);
571 	if (scr->hsb) draw_hscroll_bar(t->dev, scr->xp, scr->yp + yw - G_SCROLL_BAR_WIDTH, xw - scr->vsb * G_SCROLL_BAR_WIDTH, scr->f_data->x, xw - scr->vsb * G_SCROLL_BAR_WIDTH, vs->view_posx);
572 	if (scr->vsb && scr->hsb) drv->fill_area(t->dev, scr->xp + xw - G_SCROLL_BAR_WIDTH, scr->yp + yw - G_SCROLL_BAR_WIDTH, scr->xp + xw, scr->yp + yw, scroll_bar_frame_color);
573 	restrict_clip_area(t->dev, NULL, scr->xp, scr->yp, scr->xp + xw - scr->vsb * G_SCROLL_BAR_WIDTH, scr->yp + yw - scr->hsb * G_SCROLL_BAR_WIDTH);
574 	/*debug("buu: %d %d %d, %d %d %d", scr->xl, vx, xw, scr->yl, vy, yw);*/
575 	if (drv->flags & GD_DONT_USE_SCROLL && overwrite_instead_of_scroll) goto rrr;
576 	if (scr->xl == -1 || scr->yl == -1) goto rrr;
577 	if (is_rect_valid(&scr->ses->win->redr)) goto rrr;
578 	if (scr->xl - vx > xw || vx - scr->xl > xw ||
579 	    scr->yl - vy > yw || vy - scr->yl > yw) {
580 		goto rrr;
581 	}
582 
583 	rs = g_scroll(t->dev, scr->xl - vx, scr->yl - vy);
584 	for (j = 0; j < rs->m; j++) {
585 		struct rect *r = &rs->r[j];
586 		struct rect clip1;
587 		restrict_clip_area(t->dev, &clip1, r->x1, r->y1, r->x2, r->y2);
588 		draw_root(scr, scr->xp - vs->view_posx, scr->yp - vs->view_pos);
589 		set_clip_area(t->dev, &clip1);
590 	}
591 	mem_free(rs);
592 
593 	if (0) {
594 		rrr:
595 		draw_root(scr, scr->xp - vs->view_posx, scr->yp - vs->view_pos);
596 	}
597 	scr->xl = vx;
598 	scr->yl = vy;
599 	set_clip_area(t->dev, &old);
600 
601 	highlight_positions = NULL;
602 	highlight_lengths = NULL;
603 	n_highlight_positions = 0;
604 }
605 
606 struct draw_data {
607 	struct f_data_c *fd;
608 	struct g_object *o;
609 };
610 
draw_one_object_fn(struct terminal * t,void * d_)611 static void draw_one_object_fn(struct terminal *t, void *d_)
612 {
613 	struct draw_data *d = (struct draw_data *)d_;
614 	struct rect clip;
615 	struct f_data_c *scr = d->fd;
616 	struct g_object *o = d->o;
617 	int x, y;
618 	restrict_clip_area(t->dev, &clip, scr->xp, scr->yp, scr->xp + scr->xw - scr->vsb * G_SCROLL_BAR_WIDTH, scr->yp + scr->yw - scr->hsb * G_SCROLL_BAR_WIDTH);
619 	get_object_pos(o, &x, &y);
620 	o->draw(scr, o, scr->xp - scr->vs->view_posx + x, scr->yp - scr->vs->view_pos + y);
621 	set_clip_area(t->dev, &clip);
622 }
623 
draw_one_object(struct f_data_c * scr,struct g_object * o)624 void draw_one_object(struct f_data_c *scr, struct g_object *o)
625 {
626 	struct draw_data d;
627 	int *h1, *h2, h3;
628 	d.fd = scr;
629 	d.o = o;
630 	h1 = highlight_positions;
631 	h2 = highlight_lengths;
632 	h3 = n_highlight_positions;
633 	if (scr->ses->search_word && scr->ses->search_word[0]) {
634 		g_get_search_data(scr->f_data);
635 		g_get_search(scr->f_data, scr->ses->search_word);
636 		highlight_positions = scr->f_data->search_positions;
637 		highlight_lengths = scr->f_data->search_lengths;
638 		n_highlight_positions = scr->f_data->n_search_positions;
639 	}
640 	draw_to_window(scr->ses->win, draw_one_object_fn, &d);
641 	highlight_positions = h1;
642 	highlight_lengths = h2;
643 	n_highlight_positions = h3;
644 }
645 
g_forward_mouse(struct f_data_c * fd,struct g_object * a,int x,int y,int b)646 int g_forward_mouse(struct f_data_c *fd, struct g_object *a, int x, int y, int b)
647 {
648 	int r = 0;
649 	if (x < a->x) r |= 1;
650 	if (x >= a->x + a->xw) r |= 2;
651 	if (y < a->y) r |= 4;
652 	if (y >= a->y + a->yw) r |= 8;
653 	if (!r) {
654 		a->mouse_event(fd, a, x - a->x, y - a->y, b);
655 		return 0;
656 	}
657 	return r;
658 }
659 
g_area_mouse(struct f_data_c * fd,struct g_object * a_,int x,int y,int b)660 void g_area_mouse(struct f_data_c *fd, struct g_object *a_, int x, int y, int b)
661 {
662 	struct g_object_area *a = get_struct(a_, struct g_object_area, go);
663 	int found, g;
664 #define A_EQ(m, n)	((g = g_forward_mouse(fd, &a->lines[m]->go, x, y, b)), !g)
665 #define A_AB(m, n)	(g & 4)
666 	BIN_SEARCH(a->n_lines, A_EQ, A_AB, *, found);
667 	found = found + 1;	/* against warning */
668 #undef A_EQ
669 #undef A_AB
670 	/*int i;
671 	for (i = 0; i < a->n_lines; i++) if (!g_forward_mouse(fd, &a->lines[i]->go, x, y, b)) return;*/
672 }
673 
g_line_mouse(struct f_data_c * fd,struct g_object * a_,int x,int y,int b)674 void g_line_mouse(struct f_data_c *fd, struct g_object *a_, int x, int y, int b)
675 {
676 	struct g_object_line *a = get_struct(a_, struct g_object_line, go);
677 	int found, g;
678 #define A_EQ(m, n)	((g = g_forward_mouse(fd, a->entries[m], x, y, b)), !g)
679 #define A_AB(m, n)	(g & 1)
680 	BIN_SEARCH(a->n_entries, A_EQ, A_AB, *, found);
681 	found = found + 1;	/* against warning */
682 #undef A_EQ
683 #undef A_AB
684 	/*int i;
685 	for (i = 0; i < a->n_entries; i++) if (!g_forward_mouse(fd, a->entries[i], x, y, b)) return;*/
686 }
687 
688 static struct f_data *ffff;
689 
get_parents_sub(struct g_object * p,struct g_object * c)690 static void get_parents_sub(struct g_object *p, struct g_object *c)
691 {
692 	c->parent = p;
693 	if (c->get_list) c->get_list(c, get_parents_sub);
694 	if (c->destruct == g_tag_destruct) {
695 		struct g_object_tag *tg = get_struct(c, struct g_object_tag, go);
696 		int x = 0, y = 0;
697 		struct g_object *o;
698 		c->y -= c->parent->yw;
699 		for (o = c; o; o = o->parent) x += o->x, y += o->y;
700 		html_tag(ffff, tg->name, x, y);
701 	}
702 	if (c->mouse_event == g_text_mouse) {
703 		struct g_object_text_image *tc = get_struct(c, struct g_object_text_image, go);
704 		int l = tc->link_num;
705 		if (l >= 0) {
706 			struct link *link = &ffff->links[l];
707 			int x = 0, y = 0;
708 			struct g_object *o;
709 			for (o = c; o; o = o->parent) x += o->x, y += o->y;
710 			if (x < link->r.x1) link->r.x1 = x;
711 			if (y < link->r.y1) link->r.y1 = y;
712 			if (x + c->xw > link->r.x2) link->r.x2 = x + c->xw;
713 			if (y + c->yw > link->r.y2) link->r.y2 = y + c->yw;
714 			link->obj = c;
715 		}
716 	}
717 }
718 
get_parents(struct f_data * f,struct g_object * a)719 void get_parents(struct f_data *f, struct g_object *a)
720 {
721 	ffff = f;
722 	a->parent = NULL;
723 	if (a->get_list) a->get_list(a, get_parents_sub);
724 }
725 
get_object_pos(struct g_object * o,int * x,int * y)726 static void get_object_pos(struct g_object *o, int *x, int *y)
727 {
728 	*x = *y = 0;
729 	while (o) {
730 		*x += o->x;
731 		*y += o->y;
732 		o = o->parent;
733 	}
734 }
735 
736 /* if set_position is 1 sets cursor position in FIELD/AREA elements */
g_set_current_link(struct f_data_c * fd,struct g_object_text_image * a,int x,int y,int set_position)737 static void g_set_current_link(struct f_data_c *fd, struct g_object_text_image *a, int x, int y, int set_position)
738 {
739 	if (a->map) {
740 		int i;
741 		for (i = 0; i < a->map->n_areas; i++) {
742 			if (is_in_area(&a->map->area[i], x, y) && a->map->area[i].link_num >= 0) {
743 				fd->vs->current_link = a->map->area[i].link_num;
744 				fd->vs->orig_link = fd->vs->current_link;
745 				return;
746 			}
747 		}
748 	}
749 	fd->vs->current_link = -1;
750 	fd->vs->orig_link = fd->vs->current_link;
751 	if (a->link_num >= 0) {
752 		fd->vs->current_link = a->link_num;
753 		fd->vs->orig_link = fd->vs->current_link;
754 		/* if link is a field, set cursor position */
755 		if (set_position && a->link_num >= 0 && a->link_num < fd->f_data->nlinks) { /* valid link */
756 			struct link *l = &fd->f_data->links[a->link_num];
757 			struct form_state *fs;
758 			int xx, yy;
759 
760 			if (!l->form) return;
761 			if (l->type == L_AREA) {
762 				struct g_object_text *at = get_struct(a, struct g_object_text, goti);
763 				struct format_text_cache_entry *ftce;
764 				fs = find_form_state(fd,l->form);
765 
766 				if (g_char_width(at->style, ' '))
767 					xx = x / g_char_width(at->style, ' ');
768 				else
769 					xx = x;
770 				xx += fs->vpos;
771 				xx = xx < 0 ? 0 : xx;
772 				yy = a->link_order;
773 				yy += fs->vypos;
774 				ftce = format_text(fd, l->form, fs);
775 				if (yy >= ftce->n_lines)
776 					yy = ftce->n_lines - 1;
777 				if (yy >= 0) {
778 					int bla = textptr_diff(fs->string + ftce->ln[yy].en_offs, fs->string + ftce->ln[yy].st_offs, fd->f_data->opt.cp);
779 
780 					fs->state = ftce->ln[yy].st_offs;
781 					fs->state = (int)(textptr_add(fs->string + fs->state, xx < bla ? xx : bla, fd->f_data->opt.cp) - fs->string);
782 				}
783 				return;
784 			}
785 			if (l->type == L_FIELD) {
786 				struct g_object_text *at = get_struct(a, struct g_object_text, goti);
787 				fs = find_form_state(fd, l->form);
788 				if (g_char_width(at->style, ' '))
789 					xx = x / g_char_width(at->style, ' ');
790 				else
791 					xx = x;
792 				fs->state = (int)(textptr_add(fs->string + ((size_t)fs->vpos > strlen(cast_const_char fs->string) ? strlen(cast_const_char fs->string) : (size_t)fs->vpos), (xx < 0 ? 0 : xx), fd->f_data->opt.cp) - fs->string);
793 			}
794 		}
795 	}
796 }
797 
g_text_mouse(struct f_data_c * fd,struct g_object * a_,int x,int y,int b)798 void g_text_mouse(struct f_data_c *fd, struct g_object *a_, int x, int y, int b)
799 {
800 	struct g_object_text_image *a = get_struct(a_, struct g_object_text_image, go);
801 	int e;
802 	g_set_current_link(fd, a, x, y, (b == (B_UP | B_LEFT)));
803 
804 #ifdef JS
805 	if (fd->vs && fd->f_data && fd->vs->current_link >= 0 && fd->vs->current_link < fd->f_data->nlinks) {
806 		/* fd->vs->current links is a valid link */
807 
808 		struct link *l = &fd->f_data->links[fd->vs->current_link];
809 
810 		if (l->js_event && l->js_event->up_code && (b & BM_ACT) == B_UP)
811 			jsint_execute_code(fd, l->js_event->up_code, strlen(cast_const_char l->js_event->up_code), -1, -1, -1, NULL);
812 
813 		if (l->js_event && l->js_event->down_code && (b & BM_ACT) == B_DOWN)
814 			jsint_execute_code(fd, l->js_event->down_code, strlen(cast_const_char l->js_event->down_code), -1, -1, -1, NULL);
815 	}
816 #endif
817 
818 	if (b == (B_UP | B_LEFT)) {
819 		int ix = ismap_x, iy = ismap_y, il = ismap_link;
820 		ismap_x = x;
821 		ismap_y = y;
822 		ismap_link = a->ismap;
823 		e = enter(fd->ses, fd, 1);
824 		ismap_x = ix;
825 		ismap_y = iy;
826 		ismap_link = il;
827 		if (e) {
828 			print_all_textarea = 1;
829 			draw_one_object(fd, &a->go);
830 			print_all_textarea = 0;
831 		}
832 		if (e == 2) fd->f_data->locked_on = &a->go;
833 		return;
834 	}
835 	if (b == (B_UP | B_RIGHT)) {
836 		if (fd->vs->current_link != -1) link_menu(fd->ses->term, NULL, fd->ses);
837 	}
838 }
839 
horizontal_page_jump(struct f_data_c * fd)840 static int horizontal_page_jump(struct f_data_c *fd)
841 {
842 	int j = fd->xw - fd->vsb * G_SCROLL_BAR_WIDTH;
843 	if (j <= 0) j = 1;
844 	return j;
845 }
846 
vertical_page_jump(struct f_data_c * fd)847 static int vertical_page_jump(struct f_data_c *fd)
848 {
849 	int j = fd->yw - fd->hsb * G_SCROLL_BAR_WIDTH;
850 	if (j >= fd->ses->ds.font_size * 2) j -= fd->ses->ds.font_size;
851 	if (j <= 0) j = 1;
852 	return j;
853 }
854 
process_sb_event(struct f_data_c * fd,int off,int h)855 static void process_sb_event(struct f_data_c *fd, int off, int h)
856 {
857 	int spos, epos;
858 	int w = h ? fd->hsbsize : fd->vsbsize;
859 	get_scrollbar_pos(w - 4, h ? fd->f_data->x : fd->f_data->y, w, h ? fd->vs->view_posx : fd->vs->view_pos, &spos, &epos);
860 	spos += 2;
861 	epos += 2;
862 	/*debug("%d %d %d", spos, epos, off);*/
863 	if (off >= spos && off < epos) {
864 		fd->ses->scrolling = 1;
865 		fd->ses->scrolltype = h;
866 		fd->ses->scrolloff = off - spos;
867 		return;
868 	}
869 	if (off < spos) {
870 		if (h) fd->vs->view_posx -= horizontal_page_jump(fd);
871 		else fd->vs->view_pos -= vertical_page_jump(fd);
872 	} else {
873 		if (h) fd->vs->view_posx += horizontal_page_jump(fd);
874 		else fd->vs->view_pos += vertical_page_jump(fd);
875 	}
876 	fd->vs->orig_view_pos = fd->vs->view_pos;
877 	fd->vs->orig_view_posx = fd->vs->view_posx;
878 	draw_graphical_doc(fd->ses->term, fd, 1);
879 }
880 
process_sb_move(struct f_data_c * fd,int off)881 static void process_sb_move(struct f_data_c *fd, int off)
882 {
883 	int h = fd->ses->scrolltype;
884 	int w = h ? fd->hsbsize : fd->vsbsize;
885 	int rpos = off - 2 - fd->ses->scrolloff;
886 	int st, en;
887 	int new_val;
888 	get_scrollbar_pos(w - 4, h ? fd->f_data->x : fd->f_data->y, w, h ? fd->vs->view_posx : fd->vs->view_pos, &st, &en);
889 	if (en - st >= w - 4) return;
890 	/*
891 	*(h ? &fd->vs->view_posx : &fd->vs->view_pos) = rpos * (h ? fd->f_data->x : fd->f_data->y) / (w - 4);
892 	*/
893 	if (w - 4 - (en - st) <= 0) return;
894 	new_val = (int)(rpos * (double)(h ? fd->f_data->x - w : fd->f_data->y - w) / (w - 4 - (en - st)) + 0.5);
895 	*(h ? &fd->vs->view_posx : &fd->vs->view_pos) = new_val;
896 	fd->vs->orig_view_pos = fd->vs->view_pos;
897 	fd->vs->orig_view_posx = fd->vs->view_posx;
898 	draw_graphical_doc(fd->ses->term, fd, 1);
899 }
900 
ev_in_rect(struct links_event * ev,int x1,int y1,int x2,int y2)901 static inline int ev_in_rect(struct links_event *ev, int x1, int y1, int x2, int y2)
902 {
903 	return ev->x >= x1 && ev->y >= y1 && ev->x < x2 && ev->y < y2;
904 }
905 
is_link_in_view(struct f_data_c * fd,int nl)906 int is_link_in_view(struct f_data_c *fd, int nl)
907 {
908 	struct link *l = &fd->f_data->links[nl];
909 	return fd->vs->view_pos < l->r.y2 && fd->vs->view_pos + fd->yw - fd->hsb * G_SCROLL_BAR_WIDTH > l->r.y1;
910 }
911 
skip_link(struct f_data_c * fd,int nl)912 static int skip_link(struct f_data_c *fd, int nl)
913 {
914 	struct link *l = &fd->f_data->links[nl];
915 	return !l->where && !l->form;
916 }
917 
redraw_link(struct f_data_c * fd,int nl)918 static void redraw_link(struct f_data_c *fd, int nl)
919 {
920 	struct link *l = &fd->f_data->links[nl];
921 	struct rect r;
922 	memcpy(&r, &l->r, sizeof(struct rect));
923 	r.x1 += fd->xp - fd->vs->view_posx;
924 	r.x2 += fd->xp - fd->vs->view_posx;
925 	r.y1 += fd->yp - fd->vs->view_pos;
926 	r.y2 += fd->yp - fd->vs->view_pos;
927 	t_redraw(fd->ses->term->dev, &r);
928 }
929 
lr_link(struct f_data_c * fd,int nl)930 static int lr_link(struct f_data_c *fd, int nl)
931 {
932 	struct link *l = &fd->f_data->links[nl];
933 	int xx = fd->vs->view_posx;
934 	if (l->r.x2 > fd->vs->view_posx + fd->xw - fd->vsb * G_SCROLL_BAR_WIDTH) fd->vs->view_posx = l->r.x2 - (fd->xw - fd->vsb * G_SCROLL_BAR_WIDTH);
935 	if (l->r.x1 < fd->vs->view_posx) fd->vs->view_posx = l->r.x1;
936 	fd->vs->orig_view_posx = fd->vs->view_posx;
937 	return xx != fd->vs->view_posx;
938 }
939 
g_next_link(struct f_data_c * fd,int dir,int do_scroll)940 int g_next_link(struct f_data_c *fd, int dir, int do_scroll)
941 {
942 	int orig_link = -1;
943 	int r = 2;
944 	int n, pn;
945 	if (fd->vs->current_link >= 0 && fd->vs->current_link < fd->f_data->nlinks) {
946 		orig_link = fd->vs->current_link;
947 		n = (pn = fd->vs->current_link) + dir;
948 	} else retry: n = dir > 0 ? 0 : fd->f_data->nlinks - 1, pn = -1;
949 	again:
950 	if (n < 0 || n >= fd->f_data->nlinks) {
951 		if (!do_scroll)
952 			return 0;
953 		if (r == 1) {
954 			fd->vs->current_link = -1;
955 			if (fd->vs->view_pos > fd->f_data->y - fd->yw + fd->hsb * G_SCROLL_BAR_WIDTH) fd->vs->view_pos = fd->f_data->y - fd->yw + fd->hsb * G_SCROLL_BAR_WIDTH;
956 			if (fd->vs->view_pos < 0) fd->vs->view_pos = 0;
957 			if (orig_link != -1 && is_link_in_view(fd, orig_link)) fd->vs->current_link = orig_link;
958 			fd->vs->orig_link = fd->vs->current_link;
959 			if (fd->vs->current_link == -1) fd->ses->locked_link = 0;
960 			return 1;
961 		}
962 		if (dir < 0) {
963 			if (!fd->vs->view_pos) {
964 				fd->vs->orig_view_pos = fd->vs->view_pos;
965 				return 0;
966 			}
967 			fd->vs->view_pos -= vertical_page_jump(fd);
968 			fd->vs->orig_view_pos = fd->vs->view_pos;
969 		} else {
970 			if (fd->vs->view_pos >= fd->f_data->y - fd->yw + fd->hsb * G_SCROLL_BAR_WIDTH) return 0;
971 			fd->vs->view_pos += vertical_page_jump(fd);
972 			fd->vs->orig_view_pos = fd->vs->view_pos;
973 		}
974 		r = 1;
975 		goto retry;
976 	}
977 	if (!is_link_in_view(fd, n) || skip_link(fd, n)) {
978 		n += dir;
979 		goto again;
980 	}
981 	if (fd->vs->current_link >= 0 && fd->vs->current_link < fd->f_data->nlinks) {
982 		redraw_link(fd, fd->vs->current_link);
983 	}
984 	fd->vs->current_link = n;
985 	fd->vs->orig_link = fd->vs->current_link;
986 	fd->vs->g_display_link = 1;
987 	redraw_link(fd, n);
988 	fd->ses->locked_link = 0;
989 	if (fd->f_data->links[fd->vs->current_link].type == L_FIELD || fd->f_data->links[fd->vs->current_link].type == L_AREA) {
990 		if ((fd->f_data->locked_on = fd->f_data->links[fd->vs->current_link].obj)) fd->ses->locked_link = 1;
991 	}
992 	set_textarea(fd->ses, fd, -dir);
993 	change_screen_status(fd->ses);
994 	print_screen_status(fd->ses);
995 	if (lr_link(fd, fd->vs->current_link)) r = 1;
996 	return r;
997 }
998 
unset_link(struct f_data_c * fd)999 static void unset_link(struct f_data_c *fd)
1000 {
1001 	int n = fd->vs->current_link;
1002 	fd->vs->current_link = -1;
1003 	fd->vs->orig_link = fd->vs->current_link;
1004 	fd->vs->g_display_link = 0;
1005 	fd->ses->locked_link = 0;
1006 	if (n >= 0 && n < fd->f_data->nlinks) {
1007 		redraw_link(fd, n);
1008 	}
1009 }
1010 
scroll_vh(int * vp,int * ovp,int * sc,int d,int limit)1011 static int scroll_vh(int *vp, int *ovp, int *sc, int d, int limit)
1012 {
1013 	int o = *vp;
1014 	*vp += d;
1015 	if (*vp > limit)
1016 		*vp = limit;
1017 	if (*vp < 0)
1018 		*vp = 0;
1019 	*ovp = *vp;
1020 	o -= *vp;
1021 	if (sc) *sc -= o;
1022 	return o ? 3 : 0;
1023 }
1024 
scroll_v(struct f_data_c * fd,int y)1025 static int scroll_v(struct f_data_c *fd, int y)
1026 {
1027 	return scroll_vh(&fd->vs->view_pos, &fd->vs->orig_view_pos, fd->ses->scrolling == 2 ? &fd->ses->scrolloff : NULL, y, fd->f_data->y - fd->yw + fd->hsb * G_SCROLL_BAR_WIDTH);
1028 }
1029 
scroll_h(struct f_data_c * fd,int x)1030 static int scroll_h(struct f_data_c *fd, int x)
1031 {
1032 	return scroll_vh(&fd->vs->view_posx, &fd->vs->orig_view_posx, fd->ses->scrolling == 2 ? &fd->ses->scrolltype : NULL, x, fd->f_data->x - fd->xw + fd->vsb * G_SCROLL_BAR_WIDTH);
1033 }
1034 
g_frame_ev(struct session * ses,struct f_data_c * fd,struct links_event * ev)1035 int g_frame_ev(struct session *ses, struct f_data_c *fd, struct links_event *ev)
1036 {
1037 	if (!fd->f_data) return 0;
1038 	switch ((int)ev->ev) {
1039 		case EV_MOUSE:
1040 			if (BM_IS_WHEEL(ev->b) && ses->locked_link) {
1041 				if (fd->vs->current_link >= 0 && fd->vs->current_link < fd->f_data->nlinks && fd->f_data->links[fd->vs->current_link].type == L_AREA) {
1042 					if (field_op(ses, fd, &fd->f_data->links[fd->vs->current_link], ev)) {
1043 						if (fd->f_data->locked_on) {
1044 							print_all_textarea = 1;
1045 							draw_one_object(fd, fd->f_data->locked_on);
1046 							print_all_textarea = 0;
1047 							return 2;
1048 						}
1049 					}
1050 				}
1051 				return 1;
1052 			}
1053 			if ((ev->b & BM_BUTT) == B_WHEELUP)
1054 				return scroll_v(fd, -64);
1055 			if ((ev->b & BM_BUTT) == B_WHEELDOWN)
1056 				return scroll_v(fd, 64);
1057 			if ((ev->b & BM_BUTT) == B_WHEELUP1)
1058 				return scroll_v(fd, -16);
1059 			if ((ev->b & BM_BUTT) == B_WHEELDOWN1)
1060 				return scroll_v(fd, 16);
1061 			if ((ev->b & BM_BUTT) == B_WHEELLEFT)
1062 				return scroll_h(fd, -64);
1063 			if ((ev->b & BM_BUTT) == B_WHEELRIGHT)
1064 				return scroll_h(fd, 64);
1065 			if ((ev->b & BM_BUTT) == B_WHEELLEFT1)
1066 				return scroll_h(fd, -16);
1067 			if ((ev->b & BM_BUTT) == B_WHEELRIGHT1)
1068 				return scroll_h(fd, 16);
1069 			if ((ev->b & BM_ACT) == B_MOVE) ses->scrolling = 0;
1070 			if (ses->scrolling == 1) process_sb_move(fd, ses->scrolltype ? ev->x : ev->y);
1071 			if (ses->scrolling == 2) {
1072 				fd->vs->view_pos = -ev->y + ses->scrolloff;
1073 				fd->vs->view_posx = -ev->x + ses->scrolltype;
1074 				fd->vs->orig_view_pos = fd->vs->view_pos;
1075 				fd->vs->orig_view_posx = fd->vs->view_posx;
1076 				draw_graphical_doc(ses->term, fd, 1);
1077 				if ((ev->b & BM_ACT) == B_UP) {
1078 					ses->scrolling = 0;
1079 				}
1080 				break;
1081 			}
1082 			if (ses->scrolling) {
1083 				if ((ev->b & BM_ACT) == B_UP) {
1084 					ses->scrolling = 0;
1085 				}
1086 				break;
1087 			}
1088 
1089 			if ((ev->b & BM_ACT) == B_DOWN && fd->vsb && ev_in_rect(ev, fd->xw - G_SCROLL_BAR_WIDTH, 0, fd->xw, fd->yw - fd->hsb * G_SCROLL_BAR_WIDTH)) {
1090 				process_sb_event(fd, ev->y, 0);
1091 				break;
1092 			}
1093 			if ((ev->b & BM_ACT) == B_DOWN && fd->hsb && ev_in_rect(ev, 0, fd->yw - G_SCROLL_BAR_WIDTH, fd->xw - fd->vsb * G_SCROLL_BAR_WIDTH, fd->yw)) {
1094 				process_sb_event(fd, ev->x, 1);
1095 				break;
1096 			}
1097 			if (fd->vsb && ev_in_rect(ev, fd->xw - G_SCROLL_BAR_WIDTH, 0, fd->xw, fd->yw)) return 0;
1098 			if (fd->hsb && ev_in_rect(ev, 0, fd->yw - G_SCROLL_BAR_WIDTH, fd->xw, fd->yw)) return 0;
1099 
1100 			if ((ev->b & BM_ACT) == B_DOWN && (ev->b & BM_BUTT) == B_MIDDLE) {
1101 				scrll:
1102 				ses->scrolltype = ev->x + fd->vs->view_posx;
1103 				ses->scrolloff = ev->y + fd->vs->view_pos;
1104 				ses->scrolling = 2;
1105 				break;
1106 			}
1107 
1108 			previous_link=fd->vs->current_link;
1109 			if (fd->vs->g_display_link) {
1110 				fd->vs->g_display_link = 0;
1111 				if (fd->vs->current_link >= 0 && fd->vs->current_link < fd->f_data->nlinks) redraw_link(fd, fd->vs->current_link);
1112 			}
1113 			if (!(ev->b == (B_LEFT | B_UP) && fd->f_data->hlt_len && fd->f_data->start_highlight_x == -1)) {
1114 				fd->vs->current_link = -1;
1115 				fd->vs->orig_link = fd->vs->current_link;
1116 				fd->f_data->root->mouse_event(fd, fd->f_data->root, ev->x + fd->vs->view_posx, ev->y + fd->vs->view_pos, (int)ev->b);
1117 				if (previous_link!=fd->vs->current_link)
1118 					change_screen_status(ses);
1119 				print_screen_status(ses);
1120 			}
1121 
1122 			/* highlight text */
1123 			if ((ev->b & BM_ACT) == B_DOWN && (ev->b & BM_BUTT) == B_LEFT) {   /* start highlighting */
1124 				int need_redraw = !!fd->f_data->hlt_len;
1125 				fd->f_data->start_highlight_x = ev->x;
1126 				fd->f_data->start_highlight_y = ev->y;
1127 				fd->f_data->hlt_len = 0;
1128 				fd->f_data->hlt_pos = -1;
1129 				return need_redraw;
1130 			}
1131 			if (((ev->b & BM_ACT) == B_DRAG || (ev->b & BM_ACT) == B_UP) && (ev->b & BM_BUTT) == B_LEFT) {	/* stop highlighting */
1132 				struct g_object_text *t;
1133 				if (fd->f_data->start_highlight_x != -1) {
1134 					if (abs(ev->x - fd->f_data->start_highlight_x) < 8 && abs(ev->y - fd->f_data->start_highlight_y) < 8) goto skip_hl;
1135 					t = g_find_nearest_object(fd->f_data, fd->f_data->start_highlight_x + fd->vs->view_posx, fd->f_data->start_highlight_y + fd->vs->view_pos);
1136 
1137 					if (t) {
1138 						g_get_search_data(fd->f_data);
1139 						fd->f_data->hlt_pos = t->srch_pos+g_find_text_pos(t, fd->f_data->start_highlight_x+fd->vs->view_posx);
1140 						fd->f_data->hlt_len=0;
1141 					}
1142 					fd->f_data->start_highlight_x = -1;
1143 					fd->f_data->start_highlight_y = -1;
1144 				}
1145 				if (fd->f_data->hlt_pos == -1) goto skip_hl;
1146 				t = g_find_nearest_object(fd->f_data, ev->x + fd->vs->view_posx, ev->y + fd->vs->view_pos);
1147 
1148 				if (t) {
1149 					int end;
1150 					g_get_search_data(fd->f_data);
1151 					end = t->srch_pos + g_find_text_pos(t, ev->x+fd->vs->view_posx);
1152 					fd->f_data->hlt_len = end-fd->f_data->hlt_pos;
1153 					if ((ev->b & BM_ACT) == B_UP || (ev->b & BM_ACT) == B_DRAG) {
1154 						unsigned char *m = memacpy(fd->f_data->srch_string + fd->f_data->hlt_pos + (fd->f_data->hlt_len > 0 ? 0 : fd->f_data->hlt_len), fd->f_data->hlt_len > 0 ? fd->f_data->hlt_len : -fd->f_data->hlt_len);
1155 						if (m) {
1156 							unsigned char *p = m;
1157 							while ((p = cast_uchar strchr(cast_const_char p, 1))) *p++ = ' ';
1158 							p = m;
1159 							while ((p = cast_uchar strstr(cast_const_char p, "\302\255"))) memmove(p, p + 2, strlen(cast_const_char(p + 2)) + 1);
1160 							if (*m) set_clipboard_text(ses->term, m);
1161 							mem_free(m);
1162 						}
1163 					}
1164 					return 1;
1165 				}
1166 			}
1167 			skip_hl:
1168 			if (((ev->b & BM_ACT) == B_MOVE || (ev->b & BM_ACT) == B_UP) && (ev->b & BM_BUTT) == B_LEFT) {	/* stop highlighting */
1169 				fd->f_data->start_highlight_x = -1;
1170 				fd->f_data->start_highlight_y = -1;
1171 			}
1172 
1173 #ifdef JS
1174 			/* process onmouseover/onmouseout handlers */
1175 			if (previous_link!=fd->vs->current_link)
1176 			{
1177 				struct link* lnk=NULL;
1178 
1179 			if (previous_link>=0&&previous_link<fd->f_data->nlinks)lnk=&(fd->f_data->links[previous_link]);
1180 				if (lnk&&lnk->js_event&&lnk->js_event->out_code)
1181 					jsint_execute_code(fd,lnk->js_event->out_code,strlen(cast_const_char lnk->js_event->out_code),-1,-1,-1, NULL);
1182 				lnk=NULL;
1183 				if (fd->vs->current_link>=0&&fd->vs->current_link<fd->f_data->nlinks)lnk=&(fd->f_data->links[fd->vs->current_link]);
1184 				if (lnk&&lnk->js_event&&lnk->js_event->over_code)
1185 					jsint_execute_code(fd,lnk->js_event->over_code,strlen(cast_const_char lnk->js_event->over_code),-1,-1,-1, NULL);
1186 			}
1187 #endif
1188 
1189 			if ((ev->b & BM_ACT) == B_DOWN && (ev->b & BM_BUTT) == B_RIGHT && fd->vs->current_link == -1) goto scrll;
1190 			break;
1191 		case EV_KBD:
1192 			if (ses->locked_link && fd->vs->current_link >= 0 && fd->vs->current_link < fd->f_data->nlinks && (fd->f_data->links[fd->vs->current_link].type == L_FIELD || fd->f_data->links[fd->vs->current_link].type == L_AREA)) {
1193 				if (field_op(ses, fd, &fd->f_data->links[fd->vs->current_link], ev)) {
1194 					if (fd->f_data->locked_on) {
1195 						print_all_textarea = 1;
1196 						draw_one_object(fd, fd->f_data->locked_on);
1197 						print_all_textarea = 0;
1198 						return 2;
1199 					}
1200 					return 1;
1201 				}
1202 				if (ev->x == KBD_ENTER && !(ev->y & KBD_PASTING)) {
1203 					return enter(ses, fd, 0);
1204 				}
1205 			}
1206 			if (ev->y & KBD_PASTING)
1207 				return 0;
1208 			if (ev->x == KBD_ENTER && fd->f_data->opt.plain == 2) {
1209 				ses->ds.porn_enable ^= 1;
1210 				html_interpret_recursive(ses->screen);
1211 				return 1;
1212 			}
1213 			if (ev->x == KBD_RIGHT || ev->x == KBD_ENTER) {
1214 				struct link *l;
1215 				if (fd->vs->current_link >= 0 && fd->vs->current_link < fd->f_data->nlinks) {
1216 					l = &fd->f_data->links[fd->vs->current_link];
1217 					set_window_ptr(ses->win, fd->xp + l->r.x1 - fd->vs->view_posx, fd->yp + l->r.y1 - fd->vs->view_pos);
1218 				} else {
1219 					set_window_ptr(ses->win, fd->xp, fd->yp);
1220 				}
1221 				return enter(ses, fd, 0);
1222 			}
1223 			if (ev->x == '*') {
1224 				ses->ds.display_images ^= 1;
1225 				html_interpret_recursive(ses->screen);
1226 				return 1;
1227 			}
1228 			if (ev->x == KBD_PAGE_DOWN || (ev->x == ' ' && !(ev->y & KBD_ALT)) || (upcase(ev->x) == 'F' && ev->y & KBD_CTRL)) {
1229 				unset_link(fd);
1230 				return scroll_v(fd, vertical_page_jump(fd));
1231 			}
1232 			if (ev->x == KBD_PAGE_UP || (upcase(ev->x) == 'B' && !(ev->y & KBD_ALT))) {
1233 				unset_link(fd);
1234 				return scroll_v(fd, -vertical_page_jump(fd));
1235 			}
1236 			if (ev->x == KBD_DEL || (upcase(ev->x) == 'N' && ev->y & KBD_CTRL) || (ev->x == 'l' && !(ev->y & (KBD_CTRL | KBD_ALT)))) {
1237 				return scroll_v(fd, 32);
1238 			}
1239 			if (ev->x == KBD_INS || (upcase(ev->x) == 'P' && ev->y & KBD_CTRL) || (ev->x == 'p' && !(ev->y & (KBD_CTRL | KBD_ALT)))) {
1240 				return scroll_v(fd, -32);
1241 			}
1242 			if (ev->x == KBD_DOWN) {
1243 				return g_next_link(fd, 1, 1);
1244 			}
1245 			if (ev->x == KBD_UP) {
1246 				return g_next_link(fd, -1, 1);
1247 			}
1248 			if (ev->x == 'H' && !(ev->y & (KBD_CTRL | KBD_ALT))) {
1249 				unset_link(fd);
1250 				return g_next_link(fd, 1, 0);
1251 			}
1252 			if (ev->x == 'L' && !(ev->y & (KBD_CTRL | KBD_ALT))) {
1253 				unset_link(fd);
1254 				return g_next_link(fd, -1, 0);
1255 			}
1256 			if (ev->x == '[') {
1257 				return scroll_h(fd, -64);
1258 			}
1259 			if (ev->x == ']') {
1260 				return scroll_h(fd, 64);
1261 			}
1262 			if (ev->x == KBD_HOME || (upcase(ev->x) == 'A' && ev->y & KBD_CTRL)) {
1263 				fd->vs->view_pos = 0;
1264 				fd->vs->orig_view_pos = fd->vs->view_pos;
1265 				unset_link(fd);
1266 				return 3;
1267 			}
1268 			if (ev->x == KBD_END || (upcase(ev->x) == 'E' && ev->y & KBD_CTRL)) {
1269 				fd->vs->view_pos = fd->f_data->y;
1270 				fd->vs->orig_view_pos = fd->vs->view_pos;
1271 				unset_link(fd);
1272 				return 3;
1273 			}
1274 			if ((upcase(ev->x) == 'F' && !(ev->y & (KBD_ALT | KBD_CTRL))) || ev->x == KBD_FRONT) {
1275 				set_frame(ses, fd, 0);
1276 				return 2;
1277 			}
1278 			if (ev->x == '#') {
1279 				ses->ds.images ^= 1;
1280 				html_interpret_recursive(fd);
1281 				ses->ds.images ^= 1;
1282 				return 1;
1283 			}
1284 			if (ev->x == 'i' && !(ev->y & KBD_ALT)) {
1285 				if (!F || fd->f_data->opt.plain != 2) frm_view_image(ses, fd);
1286 				return 2;
1287 			}
1288 			if (ev->x == 'I' && !(ev->y & KBD_ALT)) {
1289 				if (!anonymous) frm_download_image(ses, fd);
1290 				return 2;
1291 			}
1292 			if (upcase(ev->x) == 'D' && !(ev->y & KBD_ALT)) {
1293 				if (!anonymous) frm_download(ses, fd);
1294 				return 2;
1295 			}
1296 			if (ev->x == '/' || (ev->x == KBD_FIND && !(ev->y & (KBD_SHIFT | KBD_CTRL | KBD_ALT)))) {
1297 				search_dlg(ses, fd, 0);
1298 				return 2;
1299 			}
1300 			if (ev->x == '?' || (ev->x == KBD_FIND && ev->y & (KBD_SHIFT | KBD_CTRL | KBD_ALT))) {
1301 				search_back_dlg(ses, fd, 0);
1302 				return 2;
1303 			}
1304 			if ((ev->x == 'n' && !(ev->y & KBD_ALT)) || ev->x == KBD_REDO) {
1305 				find_next(ses, fd, 0);
1306 				return 2;
1307 			}
1308 			if ((ev->x == 'N' && !(ev->y & KBD_ALT)) || ev->x == KBD_UNDO) {
1309 				find_next_back(ses, fd, 0);
1310 				return 2;
1311 			}
1312 			if (ev->x == KBD_MENU) {
1313 				if (fd->vs->current_link >= 0 && fd->vs->current_link < fd->f_data->nlinks) {
1314 					ses->win->xp = fd->f_data->links[fd->vs->current_link].r.x1 + fd->xp - fd->vs->view_posx;
1315 					ses->win->yp = fd->f_data->links[fd->vs->current_link].r.y2 + fd->yp - fd->vs->view_pos;
1316 					link_menu(ses->term, NULL, ses);
1317 				}
1318 			}
1319 			break;
1320 	}
1321 	return 0;
1322 }
1323 
draw_title(struct f_data_c * f)1324 void draw_title(struct f_data_c *f)
1325 {
1326 	int b, z, w;
1327 	struct graphics_device *dev = f->ses->term->dev;
1328 	unsigned char *title = stracpy(!drv->set_title && f->f_data && f->f_data->title && f->f_data->title[0] ? f->f_data->title : NULL);
1329 	if (!title) {
1330 		if (f->rq && f->rq->url)
1331 			title = display_url(f->ses->term, f->rq->url, 1);
1332 		else
1333 			title = stracpy((unsigned char *)"");
1334 	}
1335 	w = g_text_width(bfu_style_bw, title);
1336 	z = 0;
1337 	g_print_text(dev, 0, 0, !proxies.only_proxies ? bfu_style_bw : bfu_style_wb, cast_uchar " " G_LEFT_ARROW " ", &z);
1338 	f->ses->back_size = z;
1339 	b = (dev->size.x2 - w) - 16;
1340 	if (b < z) b = z;
1341 	drv->fill_area(dev, z, 0, b, G_BFU_FONT_SIZE, !proxies.only_proxies ? bfu_bg_color : bfu_fg_color);
1342 	g_print_text(dev, b, 0, !proxies.only_proxies ? bfu_style_bw : bfu_style_wb, title, &b);
1343 	drv->fill_area(dev, b, 0, dev->size.x2, G_BFU_FONT_SIZE, !proxies.only_proxies ? bfu_bg_color : bfu_fg_color);
1344 	mem_free(title);
1345 }
1346 
1347 static struct f_data *srch_f_data;
1348 
get_searched_sub(struct g_object * p,struct g_object * c)1349 static void get_searched_sub(struct g_object *p, struct g_object *c)
1350 {
1351 	if (c->draw == g_text_draw && !g_text_no_search(srch_f_data, get_struct(c, struct g_object_text, goti.go))) {
1352 		struct g_object_text *t = get_struct(c, struct g_object_text, goti.go);
1353 		int pos = srch_f_data->srch_string_size;
1354 		t->srch_pos = pos;
1355 		add_to_str(&srch_f_data->srch_string, &srch_f_data->srch_string_size, t->text);
1356 	}
1357 	if (c->get_list) c->get_list(c, get_searched_sub);
1358 	if (c->draw == g_line_draw) {
1359 		if (srch_f_data->srch_string_size && srch_f_data->srch_string[srch_f_data->srch_string_size - 1] != ' ')
1360 			add_chr_to_str(&srch_f_data->srch_string, &srch_f_data->srch_string_size, ' ');
1361 	}
1362 }
1363 
g_get_search_data(struct f_data * f)1364 static void g_get_search_data(struct f_data *f)
1365 {
1366 	int i;
1367 	srch_f_data = f;
1368 	if (f->srch_string) return;
1369 	f->srch_string = init_str();
1370 	f->srch_string_size = 0;
1371 	if (f->root && f->root->get_list) f->root->get_list(f->root, get_searched_sub);
1372 	while (f->srch_string_size && f->srch_string[f->srch_string_size - 1] == ' ') {
1373 		f->srch_string[--f->srch_string_size] = 0;
1374 	}
1375 	for (i = 0; i < f->srch_string_size; i++) if (f->srch_string[i] == 1) f->srch_string[i] = ' ';
1376 }
1377 
1378 struct f_data *fnd_f;
1379 static struct g_object_text *fnd_obj;
1380 static int fnd_x, fnd_y;
1381 static int fnd_obj_dist;
1382 
1383 /*
1384 #define dist(a,b) (a<b?b-a:a-b)
1385 */
1386 
dist_to_rect(int x,int y,int x1,int y1,int x2,int y2)1387 static inline int dist_to_rect(int x, int y, int x1, int y1, int x2, int y2)
1388 {
1389 	int w;
1390 	if (x < x1) w = x1 - x;
1391 	else if (x > x2) w = x - x2;
1392 	else w = 0;
1393 	if (y < y1) w += y1 - y;
1394 	else if (y > y2) w += y - y2;
1395 	return w;
1396 }
1397 
find_nearest_sub(struct g_object * p,struct g_object * c)1398 static void find_nearest_sub(struct g_object *p, struct g_object *c)
1399 {
1400 	int tx, ty, a;
1401 
1402 	if (!fnd_obj_dist) return;
1403 
1404 	get_object_pos(c, &tx, &ty);
1405 
1406 	a = dist_to_rect(fnd_x, fnd_y, tx, ty, tx+c->xw, ty+c->yw);
1407 
1408 	if (a >= fnd_obj_dist) return;
1409 
1410 	if (c->draw == g_text_draw && !g_text_no_search(fnd_f, get_struct(c, struct g_object_text, goti.go))) {
1411 
1412 		fnd_obj = get_struct(c, struct g_object_text, goti.go);
1413 		fnd_obj_dist = a;
1414 	}
1415 	if (c->get_list == g_area_get_list) {
1416 		struct g_object_area *ar = get_struct(c, struct g_object_area, go);
1417 		struct g_object_line **ln;
1418 		int idx, i, dist;
1419 		if (!ar->n_lines) return;
1420 		ln = g_find_line(ar->lines, ar->n_lines, fnd_y - ty);
1421 		if (!ln) {
1422 			if (fnd_y < ty) ln = &ar->lines[0];
1423 			else ln = &ar->lines[ar->n_lines - 1];
1424 		}
1425 		idx = (int)(ln - &ar->lines[0]);
1426 		for (i = idx; i < ar->n_lines; i++) {
1427 			dist = dist_to_rect(0, fnd_y, 0, ty + ar->lines[i]->go.y, 0, ty + ar->lines[i]->go.y + ar->lines[i]->go.yw);
1428 			if (dist >= fnd_obj_dist) break;
1429 			find_nearest_sub(NULL, &ar->lines[i]->go);
1430 		}
1431 		for (i = idx - 1; i >= 0; i--) {
1432 			dist = dist_to_rect(0, fnd_y, 0, ty + ar->lines[i]->go.y, 0, ty + ar->lines[i]->go.y + ar->lines[i]->go.yw);
1433 			if (dist >= fnd_obj_dist) break;
1434 			find_nearest_sub(NULL, &ar->lines[i]->go);
1435 		}
1436 		return;
1437 	}
1438 	if (c->get_list) {
1439 		c->get_list(c, find_nearest_sub);
1440 	}
1441 }
1442 
g_find_nearest_object(struct f_data * f,int x,int y)1443 static struct g_object_text * g_find_nearest_object(struct f_data *f, int x, int y)
1444 {
1445 	fnd_f = f;
1446 	fnd_obj = NULL;
1447 	fnd_x = x;
1448 	fnd_y = y;
1449 	fnd_obj_dist = MAXINT;
1450 
1451 	if (f->root) find_nearest_sub(NULL, f->root);
1452 	return fnd_obj;
1453 }
1454 
1455 static unsigned char *search_word;
1456 
1457 static int find_refline;
1458 static int find_direction;
1459 
1460 static int find_opt_yy;
1461 static int find_opt_y;
1462 static int find_opt_yw;
1463 static int find_opt_x;
1464 static int find_opt_xw;
1465 static struct f_data *find_opt_f_data;
1466 
find_next_sub(struct g_object * p,struct g_object * c)1467 static void find_next_sub(struct g_object *p, struct g_object *c)
1468 {
1469 	if (c->draw == g_text_draw && !g_text_no_search(find_opt_f_data, get_struct(c, struct g_object_text, goti.go))) {
1470 		struct g_object_text *t = get_struct(c, struct g_object_text, goti.go);
1471 		int start = t->srch_pos;
1472 		int end = t->srch_pos + (int)strlen(cast_const_char t->text);
1473 		int found;
1474 		BIN_SEARCH(n_highlight_positions, B_EQUAL, B_ABOVE, *, found);
1475 		if (found != -1) {
1476 			int x, y, yy;
1477 			get_object_pos(c, &x, &y);
1478 			y += t->goti.go.yw / 2;
1479 			yy = y;
1480 			if (yy < find_refline) yy += MAXINT / 2;
1481 			if (find_direction < 0) yy = MAXINT - yy;
1482 			if (find_opt_yy == -1 || yy > find_opt_yy) {
1483 				int sx, ex;
1484 				unsigned char *tt;
1485 				while (found > 0) {
1486 					found--;
1487 					if (B_EQUAL(found, *)) continue;
1488 					found++;
1489 					break;
1490 				}
1491 				find_opt_yy = yy;
1492 				find_opt_y = y;
1493 				find_opt_yw = t->style->height;
1494 				find_opt_x = x;
1495 				find_opt_xw = t->goti.go.xw;
1496 				if (highlight_positions[found] < start) sx = 0;
1497 				else sx = highlight_positions[found] - start;
1498 				if (highlight_positions[found] + highlight_lengths[found] > end) ex = end - start;
1499 				else ex = highlight_positions[found] + highlight_lengths[found] - start;
1500 
1501 				tt = memacpy(t->text, sx);
1502 				find_opt_x += g_text_width(t->style, tt);
1503 				mem_free(tt);
1504 				tt = memacpy(t->text + sx, ex - sx);
1505 				find_opt_xw = g_text_width(t->style, tt);
1506 				mem_free(tt);
1507 			}
1508 		}
1509 	}
1510 	if (c->get_list) c->get_list(c, find_next_sub);
1511 }
1512 
g_find_next_str(struct f_data * f)1513 static void g_find_next_str(struct f_data *f)
1514 {
1515 	find_opt_yy = -1;
1516 	find_opt_f_data = f;
1517 	if (f->root && f->root->get_list) f->root->get_list(f->root, find_next_sub);
1518 }
1519 
g_find_next(struct f_data_c * f,int a)1520 void g_find_next(struct f_data_c *f, int a)
1521 {
1522 	g_get_search_data(f->f_data);
1523 	g_get_search(f->f_data, f->ses->search_word);
1524 	search_word = f->ses->search_word;
1525 	if (!f->f_data->n_search_positions) msg_box(f->ses->term, NULL, TEXT_(T_SEARCH), AL_CENTER, TEXT_(T_SEARCH_STRING_NOT_FOUND), MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
1526 
1527 	highlight_positions = f->f_data->search_positions;
1528 	highlight_lengths = f->f_data->search_lengths;
1529 	n_highlight_positions = f->f_data->n_search_positions;
1530 
1531 	if ((!a && f->ses->search_direction == -1) ||
1532 	     (a && f->ses->search_direction == 1)) find_refline = f->vs->view_pos;
1533 	else find_refline = f->vs->view_pos + f->yw - f->hsb * G_SCROLL_BAR_WIDTH;
1534 	find_direction = -f->ses->search_direction;
1535 
1536 	g_find_next_str(f->f_data);
1537 
1538 	highlight_positions = NULL;
1539 	highlight_lengths = NULL;
1540 	n_highlight_positions = 0;
1541 
1542 	if (find_opt_yy == -1) goto d;
1543 	if (!a || find_opt_y < f->vs->view_pos || find_opt_y + find_opt_yw >= f->vs->view_pos + f->yw - f->hsb * G_SCROLL_BAR_WIDTH) {
1544 		f->vs->view_pos = find_opt_y - (f->yw - f->hsb * G_SCROLL_BAR_WIDTH) / 2;
1545 		f->vs->orig_view_pos = f->vs->view_pos;
1546 	}
1547 	if (find_opt_x < f->vs->view_posx || find_opt_x + find_opt_xw >= f->vs->view_posx + f->xw - f->vsb * G_SCROLL_BAR_WIDTH) {
1548 		f->vs->view_posx = find_opt_x + find_opt_xw / 2 - (f->xw - f->vsb * G_SCROLL_BAR_WIDTH) / 2;
1549 		f->vs->orig_view_posx = f->vs->view_posx;
1550 	}
1551 
1552 	d:draw_fd(f);
1553 }
1554 
init_grview(void)1555 void init_grview(void)
1556 {
1557 #ifdef DEBUG
1558 	int i, w = g_text_width(bfu_style_wb_mono, cast_uchar " ");
1559 	for (i = 32; i < 128; i++) {
1560 		unsigned char a[2];
1561 		a[0] = (unsigned char)i, a[1] = 0;
1562 		if (g_text_width(bfu_style_wb_mono, a) != w) internal_error("Monospaced font is not monospaced (error at char %d, width %d, wanted width %d)", i, (int)g_text_width(bfu_style_wb_mono, a), w);
1563 	}
1564 #endif
1565 	scroll_bar_frame_color = dip_get_color_sRGB(G_SCROLL_BAR_FRAME_COLOR);
1566 	scroll_bar_area_color = dip_get_color_sRGB(G_SCROLL_BAR_AREA_COLOR);
1567 	scroll_bar_bar_color = dip_get_color_sRGB(G_SCROLL_BAR_BAR_COLOR);
1568 }
1569 
1570 #endif
1571