1 /*
2  * Copyright 2013 Ole Loots <ole@monochrom.net>
3  *
4  * This file is part of NetSurf, http://www.netsurf-browser.org/
5  *
6  * NetSurf is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * NetSurf is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "assert.h"
20 
21 #include "utils/log.h"
22 #include "utils/messages.h"
23 #include "netsurf/inttypes.h"
24 #include "netsurf/core_window.h"
25 #include "netsurf/plotters.h"
26 
27 #include "atari/gui.h"
28 #include "atari/plot/plot.h"
29 #include "atari/misc.h"
30 #include "atari/gemtk/gemtk.h"
31 #include "atari/treeview.h"
32 #include "atari/res/netsurf.rsh"
33 
34 
35 struct atari_treeview_window {
36 	struct atari_treeview_window * prev_open;
37 	struct atari_treeview_window * next_open;
38 	GUIWIN * window;
39 	bool disposing;
40 	bool redraw;
41 	bool is_open;
42 	GRECT rdw_area;
43 	POINT extent;
44 	POINT click;
45 	POINT startdrag;
46 	struct atari_treeview_callbacks *io;
47 	void * user_data;
48 };
49 
50 static struct atari_treeview_window * treeviews_open;
51 
52 /**
53  * Schedule a redraw of the treeview content
54  *
55  */
56 static void
atari_treeview_redraw_grect_request(struct core_window * cw,GRECT * area)57 atari_treeview_redraw_grect_request(struct core_window *cw, GRECT *area)
58 {
59 	struct atari_treeview_window *tv = (struct atari_treeview_window *)cw;
60 	if (cw != NULL) {
61 		if( tv->redraw == false ){
62 			tv->redraw = true;
63 			tv->rdw_area.g_x = area->g_x;
64 			tv->rdw_area.g_y = area->g_y;
65 			tv->rdw_area.g_w = area->g_w;
66 			tv->rdw_area.g_h = area->g_h;
67 		} else {
68 			/* merge the redraw area to the new area.: */
69 			int newx1 = area->g_x+area->g_w;
70 			int newy1 = area->g_y+area->g_h;
71 			int oldx1 = tv->rdw_area.g_x + tv->rdw_area.g_w;
72 			int oldy1 = tv->rdw_area.g_y + tv->rdw_area.g_h;
73 			tv->rdw_area.g_x = MIN(tv->rdw_area.g_x, area->g_x);
74 			tv->rdw_area.g_y = MIN(tv->rdw_area.g_y, area->g_y);
75 
76 			if ( oldx1 > newx1 ) {
77 				tv->rdw_area.g_w = oldx1 - tv->rdw_area.g_x;
78 			} else {
79 				tv->rdw_area.g_w = newx1 - tv->rdw_area.g_x;
80 			}
81 
82 			if ( oldy1 > newy1 ) {
83 				tv->rdw_area.g_h = oldy1 - tv->rdw_area.g_y;
84 			} else {
85 				tv->rdw_area.g_h = newy1 - tv->rdw_area.g_y;
86 			}
87 		}
88 		//dbg_grect("atari_treeview_request_redraw_grect", &tv->rdw_area);
89 	}
90 }
91 
92 
93 #ifdef ATARI_TREEVIEW_DUMP
94 static void
atari_treeview_dump_info(struct atari_treeview_window * tv,char * title)95 atari_treeview_dump_info(struct atari_treeview_window *tv, char * title)
96 {
97 	printf("Treeview Dump (%s)\n", title);
98 	printf("=================================\n");
99 	gemtk_wm_dump_window_info(atari_treeview_get_gemtk_window((struct core_window *)tv));
100 	GEMTK_DBG_GRECT("Redraw Area: \n", &tv->rdw_area)
101 		dbg_grect("Redraw Area2:      \n", &tv->rdw_area);
102 	printf("Extent: x: %d, y: %d\n", tv->extent.x, tv->extent.y);
103 }
104 #endif
105 
106 
atari_treeview_is_iconified(struct core_window * cw)107 static bool atari_treeview_is_iconified(struct core_window *cw)
108 {
109 	struct atari_treeview_window *tv = (struct atari_treeview_window *)cw;
110 
111 	return((gemtk_wm_get_state(tv->window)&GEMTK_WM_STATUS_ICONIFIED) != 0);
112 }
113 
114 
atari_treeview_redraw_icon(struct core_window * cw,GRECT * clip)115 static void atari_treeview_redraw_icon(struct core_window *cw, GRECT *clip)
116 {
117 	struct atari_treeview_window *tv = (struct atari_treeview_window *)cw;
118 	GRECT visible, work;
119 	OBJECT * tree = gemtk_obj_get_tree(ICONIFY);
120 	short aesh = gemtk_wm_get_handle(tv->window);
121 
122 	gemtk_wm_get_grect(tv->window, GEMTK_WM_AREA_WORK, &work);
123 
124 	tree->ob_x = work.g_x;
125 	tree->ob_y = work.g_y;
126 	tree->ob_width = work.g_w;
127 	tree->ob_height = work.g_h;
128 
129 	wind_get_grect(aesh, WF_FIRSTXYWH, &visible);
130 	while (visible.g_h > 0 && visible.g_w > 0) {
131 
132 		if (rc_intersect(&work, &visible)) {
133 			objc_draw(tree, 0, 8, visible.g_x, visible.g_y, visible.g_w,
134 				  visible.g_h);
135 		} else {
136 			//dbg_grect("redraw vis area outside", &visible);
137 		}
138 
139 		wind_get_grect(aesh, WF_NEXTXYWH, &visible);
140 	}
141 }
142 
143 
144 static void __CDECL
on_redraw_event(struct core_window * cw,EVMULT_OUT * ev_out,short msg[8])145 on_redraw_event(struct core_window *cw, EVMULT_OUT *ev_out, short msg[8])
146 {
147 	GRECT work, clip;
148 	struct atari_treeview_window *tv = (struct atari_treeview_window *)cw;
149 
150 	if (tv == NULL)
151 		return;
152 
153 	gemtk_wm_get_grect(tv->window, GEMTK_WM_AREA_CONTENT, &work);
154 	//dbg_grect("treeview work: ", &work);
155 
156 	atari_treeview_get_grect(cw, TREEVIEW_AREA_CONTENT, &work);
157 	//dbg_grect("treeview work: ", &work);
158 	gemtk_wm_get_scroll_info(tv->window);
159 
160 	clip = work;
161 
162 	/* check if the redraw area intersects with the content area: */
163 	if ( !rc_intersect( (GRECT*)&msg[4], &clip)) {
164 		return;
165 	}
166 
167 	if (atari_treeview_is_iconified(cw) == true) {
168 		atari_treeview_redraw_icon(cw, &clip);
169 		return;
170 	}
171 
172 	/* make redraw coords relative to content viewport */
173 	clip.g_x -= work.g_x;
174 	clip.g_y -= work.g_y;
175 
176 	/* normalize the redraw coords: */
177 	if( clip.g_x < 0 ) {
178 		clip.g_w = work.g_w + clip.g_x;
179 		clip.g_x = 0;
180 	}
181 	if( clip.g_y < 0 ) {
182 		clip.g_h = work.g_h + clip.g_y;
183 		clip.g_y = 0;
184 	}
185 
186 	/* Merge redraw coords: */
187 	if( clip.g_h > 0 && clip.g_w > 0 ) {
188 
189 		GRECT rdrw_area;
190 
191 		rdrw_area.g_x = clip.g_x;
192 		rdrw_area.g_y = clip.g_y;
193 		rdrw_area.g_w = clip.g_w;
194 		rdrw_area.g_h = clip.g_h;
195 
196 		//dbg_grect("treeview on_redraw_event ", &rdrw_area);
197 
198 		atari_treeview_redraw_grect_request(cw, &rdrw_area);
199 	}
200 }
201 
202 
203 static void __CDECL
on_mbutton_event(struct core_window * cw,EVMULT_OUT * ev_out,short msg[8])204 on_mbutton_event(struct core_window *cw, EVMULT_OUT *ev_out, short msg[8])
205 {
206 	struct atari_treeview_window *tv = (struct atari_treeview_window *)cw;
207 	struct gemtk_wm_scroll_info_s *slid;
208 	GRECT work;
209 	short mx, my;
210 	short cur_rel_x, cur_rel_y, dummy, mbut;
211 
212 	assert(tv);
213 
214 	gemtk_wm_get_grect(tv->window, GEMTK_WM_AREA_CONTENT, &work);
215 	slid = gemtk_wm_get_scroll_info(tv->window);
216 	mx = ev_out->emo_mouse.p_x;
217 	my = ev_out->emo_mouse.p_y;
218 
219 	/* mouse click relative origin: */
220 
221 	short origin_rel_x = (mx-work.g_x) + (slid->x_pos*slid->x_unit_px);
222 	short origin_rel_y = (my-work.g_y) + (slid->y_pos*slid->y_unit_px);
223 
224 	/* Only pass on events in the content area: */
225 	if ((origin_rel_x >= 0) &&
226 	    (origin_rel_y >= 0) &&
227 	    (mx < work.g_x + work.g_w) &&
228 	    (my < work.g_y + work.g_h))	{
229 		if (ev_out->emo_mclicks == 2) {
230 			tv->io->mouse_action(cw,
231 					     BROWSER_MOUSE_CLICK_1 |
232 					     BROWSER_MOUSE_DOUBLE_CLICK,
233 					     origin_rel_x,
234 					     origin_rel_y);
235 			return;
236 		}
237 
238 		graf_mkstate(&cur_rel_x, &cur_rel_y, &mbut, &dummy);
239 		/* check for click or hold: */
240 		if ((mbut & 1) == 0 ) {
241 			int bms;
242 			bms = BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_PRESS_1;
243 			if(ev_out->emo_mclicks == 2 ) {
244 				bms = BROWSER_MOUSE_DOUBLE_CLICK;
245 			}
246 			tv->io->mouse_action(cw, bms, origin_rel_x, origin_rel_y);
247 		} else {
248 			/* button still pressed */
249 			short prev_x = origin_rel_x;
250 			short prev_y = origin_rel_y;
251 
252 			cur_rel_x = origin_rel_x;
253 			cur_rel_y = origin_rel_y;
254 
255 			gem_set_cursor(&gem_cursors.hand);
256 
257 			tv->startdrag.x = origin_rel_x;
258 			tv->startdrag.y = origin_rel_y;
259 			/* First, report mouse press, to trigger entry selection */
260 			tv->io->mouse_action(cw,
261 					     BROWSER_MOUSE_CLICK_1 |
262 					     BROWSER_MOUSE_PRESS_1,
263 					     cur_rel_x,
264 					     cur_rel_y);
265 			atari_treeview_redraw(cw);
266 			tv->io->mouse_action(cw,
267 					     BROWSER_MOUSE_DRAG_1 |
268 					     BROWSER_MOUSE_DRAG_ON,
269 					     cur_rel_x,
270 					     cur_rel_y);
271 			do {
272 				if (abs(prev_x-cur_rel_x) > 5 ||
273 				    abs(prev_y-cur_rel_y) > 5) {
274 					tv->io->mouse_action(cw,
275 							     BROWSER_MOUSE_HOLDING_1 |
276 							     BROWSER_MOUSE_DRAG_ON,
277 							     cur_rel_x,
278 							     cur_rel_y);
279 					prev_x = cur_rel_x;
280 					prev_y = cur_rel_y;
281 				}
282 
283 				if (tv->redraw) {
284 					// TODO: maybe GUI poll would fit better here?
285 					//		 ... is gui_poll re-entrance save?
286 					atari_treeview_redraw(cw);
287 				}
288 
289 				/* sample mouse button state: */
290 				graf_mkstate(&cur_rel_x,
291 					     &cur_rel_y,
292 					     &mbut,
293 					     &dummy);
294 				cur_rel_x = (cur_rel_x-work.g_x) +
295 					(slid->x_pos*slid->x_unit_px);
296 				cur_rel_y = (cur_rel_y-work.g_y) +
297 					(slid->y_pos*slid->y_unit_px);
298 			} while (mbut & 1);
299 
300 			/* End drag: */
301 			tv->io->mouse_action(cw,
302 					     BROWSER_MOUSE_HOVER,
303 					     cur_rel_x,
304 					     cur_rel_y);
305 			gem_set_cursor(&gem_cursors.arrow);
306 		}
307 	}
308 }
309 
310 
311 static void __CDECL
on_keybd_event(struct core_window * cw,EVMULT_OUT * ev_out,short msg[8])312 on_keybd_event(struct core_window *cw, EVMULT_OUT *ev_out, short msg[8])
313 {
314 	long kstate = 0;
315 	long kcode = 0;
316 	long ucs4;
317 	long ik;
318 	unsigned short nkc = 0;
319 	unsigned char ascii;
320 	struct atari_treeview_window *tv = (struct atari_treeview_window *)cw;
321 
322 	kstate = ev_out->emo_kmeta;
323 	kcode = ev_out->emo_kreturn;
324 	nkc= gem_to_norm( (short)kstate, (short)kcode );
325 	ascii = (nkc & 0xFF);
326 	ik = nkc_to_input_key(nkc, &ucs4);
327 
328 	if (ik == 0) {
329 		if (ascii >= 9) {
330 			tv->io->keypress(cw, ucs4);
331 		}
332 	} else {
333 		tv->io->keypress(cw, ik);
334 	}
335 }
336 
337 
338 /**
339  * GEMTK (netsurf's GEM toolkit) event sink
340  *
341  */
handle_event(GUIWIN * win,EVMULT_OUT * ev_out,short msg[8])342 static short handle_event(GUIWIN *win, EVMULT_OUT *ev_out, short msg[8])
343 {
344 	short retval = 0;
345 	struct atari_treeview_window *tv = (struct atari_treeview_window *)
346 		gemtk_wm_get_user_data(win);
347 	struct core_window *cw = (struct core_window *)tv;
348 
349 	if( (ev_out->emo_events & MU_MESAG) != 0 ) {
350 		// handle message
351 		switch (msg[0]) {
352 
353 		case WM_REDRAW:
354 			on_redraw_event(cw, ev_out, msg);
355 			break;
356 
357 		default:
358 			break;
359 		}
360 	}
361 	if ((ev_out->emo_events & MU_KEYBD) != 0 ) {
362 		on_keybd_event(cw, ev_out, msg);
363 	}
364 	if ((ev_out->emo_events & MU_BUTTON) != 0 ) {
365 		NSLOG(netsurf, INFO, "Treeview click at: %d,%d\n",
366 		      ev_out->emo_mouse.p_x, ev_out->emo_mouse.p_y);
367 		on_mbutton_event(cw, ev_out, msg);
368 	}
369 
370 	if (tv != NULL && tv->io->gemtk_user_func != NULL){
371 		tv->io->gemtk_user_func(win, ev_out, msg);
372 	}
373 
374 	// TODO: evaluate return values of event handler functions and pass them on:
375 	return(retval);
376 }
377 
378 
379 /**
380  * callback from core to request an invalidation of a window area.
381  *
382  * The specified area of the window should now be considered
383  *  out of date. If the area is NULL the entire window must be
384  *  invalidated.
385  *
386  * \param[in] cw The core window to invalidate.
387  * \param[in] r area to redraw or NULL for the entire window area.
388  * \return NSERROR_OK on success or appropriate error code.
389  */
390 static nserror
atari_treeview_invalidate_area(struct core_window * cw,const struct rect * r)391 atari_treeview_invalidate_area(struct core_window *cw,
392 			       const struct rect *r)
393 {
394 	GRECT area;
395 	struct gemtk_wm_scroll_info_s * slid;
396 	struct atari_treeview_window * tv = (struct atari_treeview_window *)cw;
397 
398 	assert(tv);
399 
400 	if (r != NULL) {
401 		RECT_TO_GRECT(r, &area);
402 
403 		slid = gemtk_wm_get_scroll_info(tv->window);
404 
405 		//dbg_rect("redraw rect request", r);
406 
407 		// treeview redraw is always full window width:
408 		area.g_x = 0;
409 		area.g_w = 8000;
410 		// but vertical redraw region is clipped:
411 		area.g_y = r->y0 - (slid->y_pos*slid->y_unit_px);
412 		area.g_h = r->y1 - r->y0;
413 	} else {
414 		atari_treeview_get_grect(cw, TREEVIEW_AREA_CONTENT, &area);
415 	}
416 	atari_treeview_redraw_grect_request(cw, &area);
417 
418 	return NSERROR_OK;
419 }
420 
421 
422 /**
423  * Update the limits of the window
424  *
425  * \param cw		the core window object
426  * \param width		the width in px, or negative if don't care
427  * \param height	the height in px, or negative if don't care
428  */
429 static nserror
atari_treeview_update_size(struct core_window * cw,int width,int height)430 atari_treeview_update_size(struct core_window *cw, int width, int height)
431 {
432 	GRECT area;
433 	struct gemtk_wm_scroll_info_s *slid;
434 	struct atari_treeview_window *tv = (struct atari_treeview_window *)cw;
435 
436 	if (tv != NULL) {
437 
438 		if (tv->disposing)
439 			return NSERROR_INVALID;
440 
441 		/* Get acces to the gemtk window slider settings: */
442 		slid = gemtk_wm_get_scroll_info(tv->window);
443 
444 		/* recalculate and refresh sliders: */
445 		atari_treeview_get_grect(cw, TREEVIEW_AREA_CONTENT, &area);
446 		if (width > -1) {
447 			slid->x_units = (width/slid->x_unit_px);
448 		} else {
449 			slid->x_units = 1;
450 		}
451 
452 		if (height > -1) {
453 			slid->y_units = (height/slid->y_unit_px);
454 		} else {
455 			slid->y_units = 1;
456 		}
457 
458 		tv->extent.x = width;
459 		tv->extent.y = height;
460 
461 
462 		/* printf("units content: %d, units viewport: %d\n",
463 			  (height/slid->y_unit_px),
464 			  (area.g_h/slid->y_unit_px));
465 		 */
466 		gemtk_wm_update_slider(tv->window, GEMTK_WM_VH_SLIDER);
467 	}
468 
469 	return NSERROR_OK;
470 }
471 
472 
473 /**
474  * Scroll the window to make area visible
475  *
476  * \param cw		the core window object
477  * \param r		rectangle to make visible
478  */
479 static nserror
atari_treeview_set_scroll(struct core_window * cw,int x,int y)480 atari_treeview_set_scroll(struct core_window *cw, int x, int y)
481 {
482 	/* TODO */
483 	return NSERROR_OK;
484 }
485 
486 static nserror
atari_treeview_get_scroll(const struct core_window * cw,int * x,int * y)487 atari_treeview_get_scroll(const struct core_window *cw, int *x, int *y)
488 {
489 	/* TODO */
490 	return NSERROR_NOT_IMPLEMENTED;
491 }
492 
493 
494 /**
495  * Get window viewport dimensions
496  *
497  * \param cw		the core window object
498  * \param width		to be set to viewport width in px, if non NULL
499  * \param height	to be set to viewport height in px, if non NULL
500  */
501 static nserror
atari_treeview_get_window_dimensions(const struct core_window * cw,int * width,int * height)502 atari_treeview_get_window_dimensions(const struct core_window *cw,
503 				     int *width,
504 				     int *height)
505 {
506 	if ((cw != NULL) &&
507 	    (width != NULL || height != NULL)) {
508 		GRECT work;
509 		atari_treeview_get_grect(cw, TREEVIEW_AREA_CONTENT, &work);
510 		*width = work.g_w;
511 		*height = work.g_h;
512 	}
513 
514 	return NSERROR_OK;
515 }
516 
517 
518 /**
519  * Inform corewindow owner of drag status
520  *
521  * \param cw		the core window object
522  * \param ds		the current drag status
523  */
524 static nserror
atari_treeview_drag_status(struct core_window * cw,core_window_drag_status ds)525 atari_treeview_drag_status(struct core_window *cw, core_window_drag_status ds)
526 {
527 	return NSERROR_NOT_IMPLEMENTED;
528 }
529 
530 
531 /**
532  * Declare Core Window Callbacks:
533  */
534 static struct core_window_callback_table cw_t = {
535 	.invalidate = atari_treeview_invalidate_area,
536 	.update_size = atari_treeview_update_size,
537 	.set_scroll = atari_treeview_set_scroll,
538 	.get_scroll = atari_treeview_get_scroll,
539 	.get_window_dimensions = atari_treeview_get_window_dimensions,
540 	.drag_status = atari_treeview_drag_status
541 };
542 
543 
544 /* exported interface documented in atari/treeview.h */
545 struct core_window *
atari_treeview_create(GUIWIN * win,struct atari_treeview_callbacks * callbacks,void * user_data,uint32_t flags)546 atari_treeview_create(GUIWIN *win, struct atari_treeview_callbacks * callbacks,
547 		      void * user_data, uint32_t flags)
548 {
549 
550 	/* allocate the core_window struct: */
551 	struct atari_treeview_window * tv;
552 	struct gemtk_wm_scroll_info_s *slid;
553 
554 	tv = calloc(1, sizeof(struct atari_treeview_window));
555 	if (tv == NULL) {
556 		NSLOG(netsurf, INFO, "calloc failed");
557 		atari_warn_user(messages_get_errorcode(NSERROR_NOMEM), 0);
558 		return NULL;
559 	}
560 
561 	/* Store the window ref inside the new treeview: */
562 	tv->window = win;
563 	tv->io = callbacks;
564 	tv->user_data = user_data;
565 
566 	// Setup gemtk event handler function:
567 	gemtk_wm_set_event_handler(win, handle_event);
568 
569 	// bind window user data to treeview ref:
570 	gemtk_wm_set_user_data(win, (void*)tv);
571 
572 	// Get acces to the gemtk scroll info struct:
573 	slid = gemtk_wm_get_scroll_info(tv->window);
574 
575 	// Setup line and column height/width of the window,
576 	// each scroll takes the configured steps:
577 	slid->y_unit_px = 16;
578 	slid->x_unit_px = 16;
579 
580 	assert(tv->io);
581 	assert(tv->io->init_phase2);
582 
583 	/* Now that the window is configured for treeview content, */
584 	/* call init_phase2 which must create the treeview */
585 	/* descriptor, and at least setup the the default */
586 	/* event handlers of the treeview: */
587 	/* It would be more simple to not pass around the callbacks */
588 	/* but the treeview constructor requires them for initialization...  */
589 	nserror err = tv->io->init_phase2((struct core_window *)tv, &cw_t);
590 	if (err != NSERROR_OK) {
591 		free(tv);
592 		tv = NULL;
593 	}
594 
595 	return((struct core_window *)tv);
596 }
597 
598 
599 /* exported interface documented in atari/treeview.h */
600 void
atari_treeview_get_grect(struct core_window * cw,enum treeview_area_e mode,GRECT * dest)601 atari_treeview_get_grect(struct core_window *cw,
602 			 enum treeview_area_e mode,
603 			 GRECT *dest)
604 {
605 
606 	struct atari_treeview_window *tv = (struct atari_treeview_window *)cw;
607 
608 	if (mode == TREEVIEW_AREA_CONTENT) {
609 		gemtk_wm_get_grect(tv->window, GEMTK_WM_AREA_CONTENT, dest);
610 	}
611 	else if (mode == TREEVIEW_AREA_TOOLBAR) {
612 		gemtk_wm_get_grect(tv->window, GEMTK_WM_AREA_TOOLBAR, dest);
613 	}
614 }
615 
616 
617 /* exported interface documented in atari/treeview.h */
atari_treeview_get_gemtk_window(struct core_window * cw)618 GUIWIN * atari_treeview_get_gemtk_window(struct core_window *cw)
619 {
620 	struct atari_treeview_window *tv = (struct atari_treeview_window *)cw;
621 	return(tv->window);
622 }
623 
624 
625 /* exported interface documented in atari/treeview.h */
atari_treeview_redraw(struct core_window * cw)626 void atari_treeview_redraw(struct core_window *cw)
627 {
628 	struct atari_treeview_window *tv = (struct atari_treeview_window *)cw;
629 	short pxy[4];
630 
631 	if (tv != NULL && tv->is_open) {
632 		if( tv->redraw && ((plot_get_flags() & PLOT_FLAG_OFFSCREEN) == 0) ) {
633 
634 			short todo[4];
635 			GRECT work;
636 			short handle = gemtk_wm_get_handle(tv->window);
637 			struct gemtk_wm_scroll_info_s *slid;
638 
639 			gemtk_wm_get_grect(tv->window, GEMTK_WM_AREA_CONTENT, &work);
640 			slid = gemtk_wm_get_scroll_info(tv->window);
641 
642 //			// Debug code: this 3 lines help to inspect the redraw
643 //			// areas...
644 //			pxy[0] = work.g_x;
645 //			pxy[1] = work.g_y;
646 //			pxy[2] = pxy[0] + work.g_w-1;
647 //			pxy[3] = pxy[1] + work.g_h-1;
648 //
649 //			vsf_color(plot_get_vdi_handle(), 0);
650 //			v_bar(plot_get_vdi_handle(), (short*)&pxy);
651 //			evnt_timer(500);
652 
653 			struct redraw_context ctx = {
654 				.interactive = true,
655 				.background_images = true,
656 				.plot = &atari_plotters
657 			};
658 			plot_set_dimensions(&ctx,
659 					    work.g_x,
660 					    work.g_y,
661 					    work.g_w,
662 					    work.g_h);
663 			if (plot_lock() == false)
664 				return;
665 
666 			if( wind_get(handle, WF_FIRSTXYWH,
667 				     &todo[0], &todo[1], &todo[2], &todo[3] )!=0 ) {
668 				while (todo[2] && todo[3]) {
669 
670 					if(!rc_intersect(&work, (GRECT*)&todo)){
671 						if (wind_get(handle, WF_NEXTXYWH,
672 							     &todo[0], &todo[1], &todo[2], &todo[3])==0) {
673 							break;
674 						}
675 						continue;
676 					}
677 					pxy[0] = todo[0];
678 					pxy[1] = todo[1];
679 					pxy[2] = todo[0] + todo[2]-1;
680 					pxy[3] = todo[1] + todo[3]-1;
681 					vs_clip(plot_get_vdi_handle(), 1, (short*)&pxy);
682 
683 					// Debug code: this 3 lines help to inspect the redraw
684 					// areas...
685 
686 //					vsf_color(plot_get_vdi_handle(), 3);
687 //					v_bar(plot_get_vdi_handle(), (short*)&pxy);
688 //					evnt_timer(500);
689 
690 
691 					/* convert screen to treeview coords: */
692 					todo[0] = todo[0] - work.g_x ;//+ slid->x_pos*slid->x_unit_px;
693 					todo[1] = todo[1] - work.g_y ;//+ slid->y_pos*slid->y_unit_px;
694 					if( todo[0] < 0 ){
695 						todo[2] = todo[2] + todo[0];
696 						todo[0] = 0;
697 					}
698 					if( todo[1] < 0 ){
699 						todo[3] = todo[3] + todo[1];
700 						todo[1] = 0;
701 					}
702 
703 					if (rc_intersect((GRECT *)&tv->rdw_area,(GRECT *)&todo)) {
704 						struct rect clip;
705 
706 						clip.x0 = todo[0]+(slid->x_pos*slid->x_unit_px);
707 						clip.y0 = todo[1]+(slid->y_pos*slid->y_unit_px);
708 						clip.x1 = clip.x0 + todo[2]+(slid->x_pos*slid->x_unit_px);
709 						clip.y1 = clip.y0 + todo[3]+(slid->y_pos*slid->y_unit_px);
710 
711 						tv->io->draw(cw, -(slid->x_pos*slid->x_unit_px),
712 							     -(slid->y_pos*slid->y_unit_px),
713 							     &clip, &ctx);
714 					}
715 					vs_clip(plot_get_vdi_handle(), 0, (short*)&pxy);
716 					if (wind_get(handle, WF_NEXTXYWH,
717 						     &todo[0], &todo[1], &todo[2], &todo[3])==0) {
718 						break;
719 					}
720 				}
721 			} else {
722 				plot_unlock();
723 				return;
724 			}
725 			plot_unlock();
726 			tv->redraw = false;
727 			tv->rdw_area.g_x = 65000;
728 			tv->rdw_area.g_y = 65000;
729 			tv->rdw_area.g_w = -1;
730 			tv->rdw_area.g_h = -1;
731 		} else {
732 			/* just copy stuff from the offscreen buffer */
733 		}
734 	}
735 }
736 
737 
738 /* exported interface documented in atari/treeview.h */
atari_treeview_delete(struct core_window * cw)739 void atari_treeview_delete(struct core_window * cw)
740 {
741 	struct atari_treeview_window *tv = (struct atari_treeview_window*)cw;
742 
743 	assert(tv);
744 	assert(tv->io->finish);
745 
746 	tv->io->finish(cw);
747 
748 	free(tv);
749 }
750 
751 
752 /* exported interface documented in atari/treeview.h */
atari_treeview_open(struct core_window * cw,GRECT * pos)753 void atari_treeview_open(struct core_window *cw, GRECT *pos)
754 {
755 	struct atari_treeview_window *tv = (struct atari_treeview_window*)cw;
756 	if (tv->window != NULL && tv->is_open == false) {
757 		tv->is_open = true;
758 		wind_open_grect(gemtk_wm_get_handle(tv->window), pos);
759 		gemtk_wm_link(tv->window);
760 		if (treeviews_open == NULL) {
761 			treeviews_open = tv;
762 			treeviews_open->next_open = NULL;
763 			treeviews_open->prev_open = NULL;
764 		} else {
765 			struct atari_treeview_window * tmp;
766 			tmp = treeviews_open;
767 			while(tmp->next_open != NULL){
768 				tmp = tmp->next_open;
769 			}
770 			tmp->next_open = tv;
771 			tv->prev_open = tmp;
772 			tv->next_open = NULL;
773 		}
774 	}
775 }
776 
777 
778 /* exported interface documented in atari/treeview.h */
atari_treeview_is_open(struct core_window * cw)779 bool atari_treeview_is_open(struct core_window *cw)
780 {
781 	struct atari_treeview_window *tv = (struct atari_treeview_window*)cw;
782 	return(tv->is_open);
783 }
784 
785 
786 /* exported interface documented in atari/treeview.h */
atari_treeview_set_user_data(struct core_window * cw,void * user_data_ptr)787 void atari_treeview_set_user_data(struct core_window *cw, void *user_data_ptr)
788 {
789 	struct atari_treeview_window *tv = (struct atari_treeview_window*)cw;
790 	tv->user_data = user_data_ptr;
791 }
792 
793 
794 /* exported interface documented in atari/treeview.h */
atari_treeview_get_user_data(struct core_window * cw)795 void * atari_treeview_get_user_data(struct core_window * cw)
796 {
797 	struct atari_treeview_window *tv = (struct atari_treeview_window*)cw;
798 	return(tv->user_data);
799 }
800 
801 
802 /* exported interface documented in atari/treeview.h */
atari_treeview_close(struct core_window * cw)803 void atari_treeview_close(struct core_window *cw)
804 {
805 	struct atari_treeview_window *tv = (struct atari_treeview_window*)cw;
806 	if (tv->window != NULL) {
807 		tv->is_open = false;
808 		wind_close(gemtk_wm_get_handle(tv->window));
809 		gemtk_wm_unlink(tv->window);
810 		/* unlink the window: */
811 		if (tv->prev_open != NULL) {
812 			tv->prev_open->next_open = tv->next_open;
813 		} else {
814 			treeviews_open = tv->next_open;
815 		}
816 		if (tv->next_open != NULL) {
817 			tv->next_open->prev_open = tv->prev_open;
818 		}
819 	}
820 }
821 
822 
823 /* exported interface documented in atari/treeview.h */
atari_treeview_flush_redraws(void)824 void atari_treeview_flush_redraws(void)
825 {
826 	struct atari_treeview_window *tmp;
827 
828 	tmp = treeviews_open;
829 
830 	while (tmp != NULL) {
831 		assert(tmp->is_open);
832 		if (tmp->redraw &&
833 		    (!atari_treeview_is_iconified((struct core_window *)tmp))) {
834 			/* Content redraw only for iconified windows
835 			 *  because otherwise the icon draw function
836 			 *  would have to deal with plot canvas coords
837 			 */
838 			atari_treeview_redraw((struct core_window *)tmp);
839 		}
840 		tmp = tmp->next_open;
841 	}
842 
843 }
844