1 /* hf_wrapper.c - functions for managing the height field creation and display
2  *
3  * Copyright (C) 2001, 2005 Patrice St-Gelais
4  *         patrstg@users.sourceforge.net
5  *         http://geomorph.sourceforge.net
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21 
22  // Modified 2005-01-09 for removing double buffering, not required with GTK2
23  // Modified 2006-01-01 for cleaning the file / code structure
24 
25 #include "globals.h"
26 #include "hf_wrapper.h"
27 #include "hf_dialog_options.h"
28 #include "hf_creation_dialog.h"
29 #include "hf_filters.h"
30 #include "hf_filters_dialog.h"
31 #include "render.h"
32 #include "gl_preview.h"
33 #include "dialog_utilities.h"
34 #include "../utils/scale_buttons.h"
35 
36 pix8_rgb rgb_mask = { 0x10, 0x0F, 0x00};
37 
38 extern gboolean INTEGRATED_INTERFACE;
39 
gl_no_refresh_callb(GtkWidget * wdg,GdkEventButton * event,gpointer data)40 gint gl_no_refresh_callb (GtkWidget *wdg, GdkEventButton *event, gpointer data) {
41 	hf_wrapper_struct *hfw;
42 	if (!data)
43 		return TRUE;
44 	hfw = (hf_wrapper_struct *) * (hf_wrapper_struct **) data;
45 	if (!hfw)
46 		return TRUE;
47 	if (!hfw->gl_preview)
48 		return TRUE;
49 	hfw->gl_preview->refresh_on_mouse_down = FALSE;
50 	return FALSE;
51 }
52 
gl_restore_refresh_callb(GtkWidget * wdg,GdkEventButton * event,gpointer data)53 gint gl_restore_refresh_callb (GtkWidget *wdg, GdkEventButton *event, gpointer data) {
54 	hf_wrapper_struct *hfw;
55 	if (!data)
56 		return TRUE;
57 	hfw = (hf_wrapper_struct *) * (hf_wrapper_struct **) data;
58 	if (!hfw)
59 		return TRUE;
60 	if (!hfw->gl_preview)
61 		return TRUE;
62 	hfw->gl_preview->refresh_on_mouse_down = TRUE;
63 	gl_area_update(hfw->gl_preview);
64 	return FALSE;
65 }
66 
gl_preview_optimize(GtkWidget * scale,gpointer data)67 void gl_preview_optimize (GtkWidget *scale, gpointer data) {
68 	// Connects a widget (typically a scale) to callbacks for decreasing
69 	// the density of texels when dragging the mouse
70 	hf_wrapper_struct *hfw;
71 	if (!data) return;
72 	hfw = (hf_wrapper_struct *) * (hf_wrapper_struct **) data;
73 	// Don't apply for a pen or a similar HF
74 	// If hfw is null, we assume we are initializing a dialog, and it's a HFMAIN
75 	if (hfw && (hfw->type != HFMAIN))
76 		return;
77 	gtk_signal_connect (GTK_OBJECT (scale), "button_press_event",
78 			(GtkSignalFunc) gl_no_refresh_callb, data);
79 	gtk_signal_connect (GTK_OBJECT (scale), "button_release_event",
80 			(GtkSignalFunc) gl_restore_refresh_callb, data);
81 }
82 
hf_default_size()83 gint hf_default_size () {
84 	gint s;
85 	if (HF_SIZE_IN_PIXELS)
86 //	"Floor" the given HF_SIZE to the nearest power of 2
87 		return pow(2,log2i(HF_SIZE_IN_PIXELS));
88 	s = log2i(HF_SIZE_IN_SCREEN_PERCENT*gdk_screen_width()/100);
89 	s = pow(2,s);
90 	return s;
91 }
92 
get_display_scale(gint hf_size)93 gint get_display_scale (gint hf_size) {
94 //	Guess display scale from HF size and current display size...
95 //	or take the value given in the RC file
96 	static gint def_size = 0;
97 	if (DOC_DISPLAY_SIZE) {
98 		if (hf_size>DOC_DISPLAY_SIZE)
99 			return log2i(hf_size / DOC_DISPLAY_SIZE);
100 		else
101 			return 0;
102 	}
103 	else {
104 		if (!def_size)
105 			def_size =  hf_default_size();
106 		if (hf_size > def_size)
107 			return log2i(hf_size / def_size);
108 		else
109 			return 0;
110 	}
111 }
display_16_to_8(hf_wrapper_struct * hfw)112 void display_16_to_8 (hf_wrapper_struct *hfw)
113 {
114 	// Transforms 16 bits HF to 8 bits hf, for displaying
115 	// or saving in 8 bits formats
116 	gint i, j, max_x, max_y, factor, index, scaled_index;
117 	hf_struct_type *hf = (hf_struct_type *) hfw->hf_struct;
118 	max_x = RIGHT_SHIFT(hf->max_x,hfw->display_scale);
119 	max_y = RIGHT_SHIFT(hf->max_y,hfw->display_scale);
120 	if (hfw->if_rgb && hf->select_buf)
121 		factor = 3;
122 	else {
123 		factor = 1;
124 		hfw->if_rgb = FALSE;
125 	}
126 //	We reallocate the memory in case of a size change
127 	// 2008-08: why is it not scaled? something to check here!
128 	realloc_buf8(hfw);
129 
130 	if (hfw->display_scale)
131 		for (i = 0; i < max_x; i++)
132 			for (j = 0; j < max_y; j++) {
133 				index = j*max_y + i;
134 				scaled_index = (LEFT_SHIFT(i,hfw->display_scale)) + (LEFT_SHIFT(j,hfw->display_scale))*hf->max_x;
135 				if (factor==1)
136 					*(hfw->hf_buf8 + index) = *(hf->hf_buf + scaled_index) >> 8;
137 				else {
138 					*(hfw->hf_buf8 + 3*index) = *(hfw->hf_buf8 + 3*index + 1) = *(hfw->hf_buf8 + 3*index + 2) = *(hf->hf_buf + scaled_index) >> 8;
139 
140 					if (*(hf->select_buf + scaled_index) > MIN_FILLING_VALUE) {
141 
142 						*(hfw->hf_buf8 + index*3)  = rgb_mask.r + *(hfw->hf_buf8 + index*3);
143 						*(hfw->hf_buf8 + index*3+1) = rgb_mask.g + *(hfw->hf_buf8 + index*3+1);
144 						*(hfw->hf_buf8 + index*3+2) = rgb_mask.b + *(hfw->hf_buf8 + index*3+2);
145 					}
146 				}
147 			}
148 	else
149 		for (i = 0; i<hf->max_x*hf->max_y; i++) {
150 			if (factor==1)
151 				*(hfw->hf_buf8 + i) = *(hf->hf_buf + i) >> 8;
152 			else { // R-G-B
153 				*(hfw->hf_buf8 + 3*i) = *(hfw->hf_buf8 + 3*i + 1) = *(hfw->hf_buf8 + 3*i + 2) = *(hf->hf_buf + i) >> 8;
154 				if (*(hf->select_buf + i) > MIN_FILLING_VALUE) {
155 					*(hfw->hf_buf8 + i*3)  = rgb_mask.r + *(hfw->hf_buf8 + i*3);
156 					*(hfw->hf_buf8 + i*3+1) = rgb_mask.g + *(hfw->hf_buf8 + i*3+1);
157 					*(hfw->hf_buf8 + i*3+2) = rgb_mask.b + *(hfw->hf_buf8 + i*3+2);
158 				}
159 			}
160 		}
161 }
162 
display_16_to_8_partial(hf_wrapper_struct * hfw,gint from_x,gint to_x,gint from_y,gint to_y)163 void display_16_to_8_partial (hf_wrapper_struct *hfw, gint from_x, gint to_x, gint from_y, gint to_y) {
164 	// Same as display_16_to_8, but only for a subwindow
165 	// We don't reallocate the buffer, but allocate it if NULL
166 	// Only the beginning of the buffer is used
167 	// Suitable for drawing only (more efficient)
168 	// from_x, from_y, to_x, to_y are in display world, not in hf world
169 	gint i, j, delta_x, delta_y, max_x, max_y, factor, index, scaled_index;
170 	hf_struct_type * hf = (hf_struct_type *) hfw->hf_struct;
171 	max_x = RIGHT_SHIFT(hf->max_x,hfw->display_scale);
172 	max_y = RIGHT_SHIFT(hf->max_y,hfw->display_scale);
173 
174 	if (hfw->if_rgb && hf->select_buf)
175 		factor = 3;
176 	else {
177 		factor = 1;
178 		hfw->if_rgb = FALSE;
179 	}
180 	if (!hfw->hf_buf8) {
181 		alloc_buf8(hfw);
182 	}
183 	if ( (!(to_x-from_x)) || (!(to_y-from_y)))
184 		return;
185 	// Be sure that from_x <= to_x, and from_y <= to_y
186 	if (from_x > to_x) {
187 		i = from_x;
188 		from_x = to_x;
189 		to_x = i;
190 	}
191 	if (from_y > to_y) {
192 		i = from_y;
193 		from_y = to_y;
194 		to_y = i;
195 	}
196 	to_x = MIN(to_x,max_x);
197 	to_y = MIN(to_y,max_y);
198 	delta_x = to_x - from_x;
199 	delta_y = to_y - from_y;
200 //	printf("DELTA_X: %d; DELTA_Y: %d\n",delta_x, delta_y);
201 	for (i = 0 ; i < delta_x; i++)
202 		for (j = 0; j < delta_y; j++) {
203 			index = j*delta_x + i;
204 			if (hfw->display_scale)
205 				scaled_index = (LEFT_SHIFT(i+from_x,hfw->display_scale)) + (LEFT_SHIFT(j+from_y,hfw->display_scale))*hf->max_x;
206 			else
207 				scaled_index = (j+from_y)*hf->max_x + i + from_x;
208 			if (factor==1)
209 				*(hfw->hf_buf8 + index) = *(hf->hf_buf + scaled_index) >> 8;
210 			else {
211 				*(hfw->hf_buf8 + 3*index) = *(hf->hf_buf + scaled_index) >> 8;
212 				*(hfw->hf_buf8 + 3*index + 1) = *(hf->hf_buf + scaled_index) >> 8;
213 				if (*(hf->select_buf + scaled_index)> MIN_FILLING_VALUE)
214 				// We keep 75% of the Blue channel
215 				// This gives a light yellow
216 					*(hfw->hf_buf8 + index*3 + 2) = (*(hf->hf_buf + scaled_index) >> 9) + (*(hf->hf_buf + scaled_index) >> 10);
217 				else
218 					*(hfw->hf_buf8 + index*3 + 2) = *(hf->hf_buf + scaled_index) >> 8;
219 			}
220 		}
221 
222 }
223 /*
224 //	TEST:  trying to boost higher frequencies (1, 2, 4 and 8 pixels period)
225 //	UPDATE 2003-03:  should try equalization (kind of)
226 void display_16_to_8(hf_struct_type *hf)
227 {
228 	// Transforms 16 bits HF to 8 bits hf, for displaying
229 	// or saving in 8 bits formats
230 	gint i, j,max_x, max_y;
231 	gfloat val,minval,divider;
232 	minval = 256.0*BLACK_THRESHOLD;
233 	divider = 256.0+BLACK_THRESHOLD;
234 	max_x = RIGHT_SHIFT(hf->max_x,hf->display_scale);
235 	max_y = RIGHT_SHIFT(hf->max_y,hf->display_scale);
236 //	We reallocate the memory in case of a size change
237 	hf->hf_buf8 = (unsigned char *)  x_realloc (hf->hf_buf8, max_x * max_y * sizeof(unsigned char), "unsigned char (hf_buf8 in display_16_to_8)");
238 
239 // printf("HF->DISPLAY_SCALE in HF_16_TO_8: %d; max_x: %d; max_y: %d \n",hf->display_scale, max_x, max_y);
240 	if (hf->display_scale)
241 		for (i = 0; i < max_x; i++)
242 			for (j = 0; j < max_y; j++) {
243 				val = 	((gfloat)*(hf->hf_buf + (LEFT_SHIFT(i,hf->display_scale)) +
244 					(LEFT_SHIFT(j,hf->display_scale))*hf->max_x) + minval )/divider;
245 				*(hf->hf_buf8 + j*max_y + i) = (unsigned char) val;
246 // printf("j*max_y+i:  %d = %d\n", j*max_y+i, RIGHT_SHIFT(i,hf->display_scale) + RIGHT_SHIFT(j,hf->display_scale)*hf->max_x);
247 			}
248 	else
249 		for (i = 0; i<hf->max_x*hf->max_y; i++) {
250 			val = (((gfloat) *(hf->hf_buf + i)) + minval )/ divider;
251 			*(hf->hf_buf8 + i) = (unsigned char) val;
252 		}
253 }
254 */
draw_hf(hf_wrapper_struct * hfw)255 void draw_hf (hf_wrapper_struct *hfw) {
256 	hf_struct_type *hf;
257 	hf = hfw->hf_struct;
258 //	if (hfw->type==HFMAIN)
259 //		printf("DRAW_HF: hfw: %p -> hf: %p -> hf_buf: %p; creation_mode: %d; if_modified: %d\n",hfw,hf, hf->hf_buf, hfw->creation_mode, *hfw->if_modified);
260 	if (hfw->apply_filter)
261 	    if (hfw->hf_options->fd_struct) {
262 		if (hfw->hf_options->fd_struct->current_filter) {
263 			if (hfw->hf_struct->max_x > hfw->hf_options->dist_matrix->hf_size)
264 				dist_matrix_init(hfw->hf_options->dist_matrix, hfw->hf_struct->max_x);
265 
266 			filter_apply(hfw->hf_struct,
267 				hfw->hf_options->fd_struct->current_filter,
268 				hfw->hf_options->dist_matrix,
269 				hfw->hf_options->fd_struct->revert_filter,
270 				hfw->hf_options->fd_struct->filter_level,
271 				hfw->hf_options->fd_struct->merge_oper);
272 	    	}
273 	}
274 // 	printf ("hf->max_x: %d; hf->display_scale: %d; SHIFT: %d\n",hf->max_x,hf->display_scale, RIGHT_SHIFT(hf->max_x,hf->display_scale));
275 	// "gtk_widget_queue_draw_area" triggers an expose_event for hf_wrapper->area:
276 	gtk_widget_queue_draw_area(hfw->area, 0, 0, RIGHT_SHIFT(hf->max_x,hfw->display_scale), RIGHT_SHIFT(hf->max_y,hfw->display_scale) );
277 
278 	// Redraw immediately, otherwise using the pen is too annoying (irregular)
279 	if (hfw->area->window)
280 		gdk_window_process_updates(hfw->area->window, FALSE);
281 	if (hfw->gl_preview) {
282 		gl_set_input_grid (hfw->gl_preview, hfw->hf_struct->hf_buf, hfw->hf_struct->max_x, hfw->hf_struct->max_y, HF_TYPE_ID);
283 // 	printf("GL_AREA_UPDATE de %d:  %s\n", hfw, *hfw->filename);
284 		gl_area_update(hfw->gl_preview);
285 	}
286 
287 	// Emit expose event required for size change during creation
288 	if (hfw->creation_mode) {
289 		emit_expose_event(hfw->area);
290 	}
291 }
292 
draw_hf_ptr(gpointer hfw_ptr_ptr)293 void draw_hf_ptr (gpointer hfw_ptr_ptr) {
294 	hf_wrapper_struct *hfw;
295 //	printf("Draw_hf_ptr 1\n");
296 	if (hfw_ptr_ptr) {
297 		hfw = (hf_wrapper_struct *) * (hf_wrapper_struct **) hfw_ptr_ptr;
298 		if (hfw) {
299 
300 			draw_hf (hfw);
301 //			printf("Draw_hf_ptr 2; hf->tmp_buf: %p; hf->result_buf: %p, hf->hf_buf: %p\n", hfw->hf_struct->tmp_buf, hfw->hf_struct->result_buf,hfw->hf_struct->hf_buf);
302 		}
303 	}
304 }
305 
draw_hf_partial(hf_wrapper_struct * hfw,gint fromx,gint tox,gint fromy,gint toy,gboolean update_gl_area)306 void draw_hf_partial (hf_wrapper_struct *hfw, gint fromx, gint tox, gint fromy, gint toy,
307 		gboolean update_gl_area) {
308 	//	Version of draw_hf drawing in a subset of the area
309 	//	from_x, to_x, from_y, to_y defined in the display world, not in the hf world
310 	hf_struct_type *hf;
311 	hf = hfw->hf_struct;
312 
313 //	printf("DRAW_HF partial: (%d, %d) - (%d, %d) \n", fromx, fromy, tox, toy);
314 
315 	gtk_widget_queue_draw_area(hfw->area, fromx, fromy, tox - fromx, toy - fromy);
316 	// Redraw immediately, otherwise using the pen is too annoying (irregular)
317 	if (hfw->area->window)
318 		gdk_window_process_updates(hfw->area->window, FALSE);
319 	if (update_gl_area && hfw->gl_preview) {
320 		gl_set_input_grid (hfw->gl_preview, hfw->hf_struct->hf_buf, hfw->hf_struct->max_x, hfw->hf_struct->max_y, HF_TYPE_ID);
321 // 	printf("GL_AREA_UPDATE de %d:  %s\n", hfw, *hfw->filename);
322 		gl_area_update(hfw->gl_preview);
323 	}
324 }
325 
gener_hf_from_ptr_ptr(gpointer hfw_ptr_ptr)326 void gener_hf_from_ptr_ptr (gpointer hfw_ptr_ptr) {
327 	if (hfw_ptr_ptr)
328 		if (* (hf_wrapper_struct **) hfw_ptr_ptr)
329 			gener_hf(* (hf_wrapper_struct **)hfw_ptr_ptr);
330 }
331 
gener_hf(hf_wrapper_struct * hfw)332 void gener_hf (hf_wrapper_struct *hfw) {
333 
334 	if (!hfw)
335 		return;
336 	if (hfw->creation_mode)
337 		if (hfw->hf_options->current_calculation) {
338 			(*hfw->hf_options->current_calculation) (hfw->hf_struct, hfw->hf_options->current_options);
339 //	if (hfw->type==HFMAIN)
340 //		printf("Calculation on %d == %x in GENER_HF\n",hfw, hfw);
341 		}
342 	if (hfw->dependent_process)
343 		if (hfw->dependent_process_data)
344 			(*hfw->dependent_process) (hfw->dependent_process_data);
345 	draw_hf(hfw);
346 }
347 
configure_event(GtkWidget * widget,GdkEventConfigure * event,gpointer data)348 static gint configure_event (GtkWidget *widget, GdkEventConfigure *event, gpointer data)
349 {
350 	hf_wrapper_struct *hf_wrapper;
351 	hf_wrapper = (hf_wrapper_struct *) data;
352 
353 //	if (hf_wrapper->type==HFMAIN)
354 //		printf("CONFIGURE_EVENT for HFW == %d; Creation mode: %d\n", hf_wrapper, hf_wrapper->creation_mode);
355 
356 //	We initialize the drawable:
357 
358 	if (GTK_IS_DRAWING_AREA(hf_wrapper->area))
359 		gdk_draw_rectangle(hf_wrapper->area->window,
360 			hf_wrapper->area->style->black_gc,TRUE, 0, 0,
361 			hf_wrapper->area->allocation.width,
362 			hf_wrapper->area->allocation.height);
363 	else
364 		return TRUE;
365 
366 
367 	if (hf_wrapper->creation_mode) {
368 		gener_hf(hf_wrapper);
369 	}
370 	/*
371 	else  {		// Probably an area size change - removed 2005-11-09
372 		draw_hf(hf_wrapper);
373 	}
374 	*/
375 	hf_wrapper->size_change_request = FALSE;
376 
377     return TRUE;
378 }
379 
expose_event(GtkWidget * widget,GdkEventExpose * event,gpointer data)380 gint expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer data)
381 {
382 
383 	gint w,h;
384 	hf_wrapper_struct *hfw;
385 
386 	hfw = (hf_wrapper_struct *) data;
387 
388   	if (event->count > 0) {
389     		return TRUE;
390   	}
391 
392 	if (hfw->size_change_request)
393 		return TRUE;		// A configure event must be done before
394 
395 //	printf("EXPOSE_EVENT: X: %d; Y: %d; W: %d;  H: %d;  hfw: %d; area size: %d\n ",event->area.x, event->area.y, event->area.width, event->area.height, hfw, hfw->area_size);
396 // 	printf("FILE: %s; AREA SIZE: %d\n",*hfw->filename,hfw->area_size);
397 
398 	if ((!event->area.width) && (!event->area.height))
399 		return TRUE;
400 	if (GTK_IS_DRAWING_AREA(hfw->area)) {
401 
402 //	We decide here what part of the HF we refresh, before drawing
403 
404 		if ( (!event->area.width) || (!event->area.height))
405 			return TRUE;
406 		if ( ((event->area.width>=hfw->area_size) &&
407 			(event->area.height>=hfw->area_size) &&
408 			(event->area.x==0) && (event->area.y==0) ) ) {
409 //			(event->area.x==0) && (event->area.y==0) ) || (hfw->hf_struct->if_rgb) ) {
410 			// Full refresh
411 			// Patched 2005-10-28 - partial refresh not working with rgb images
412 			// We fallback to full redraw
413 			// Unpatched 2005-10-29
414 //			printf("FULL REFRESH\n");
415 			display_16_to_8(hfw);
416 			if (hfw->if_rgb)
417 				gdk_draw_rgb_image(hfw->area->window,
418 					hfw->area->style->fg_gc[GTK_WIDGET_STATE (hfw->area)],
419 					0,0,hfw->area_size, hfw->area_size,
420 					GDK_RGB_DITHER_NONE,
421 					hfw->hf_buf8,
422 					3*hfw->area_size);
423 			else
424 				gdk_draw_gray_image(hfw->area->window,
425 					hfw->area->style->fg_gc[GTK_WIDGET_STATE (hfw->area)],
426 					0,0,hfw->area_size, hfw->area_size,
427 					GDK_RGB_DITHER_NONE,
428 					hfw->hf_buf8,
429 					hfw->area_size);
430 		}
431 		else {
432 			w = MIN(event->area.x+event->area.width,hfw->area_size) - event->area.x;
433 			h = MIN(event->area.y+event->area.height,hfw->area_size) - event->area.y ;
434 			display_16_to_8_partial (hfw,
435 				event->area.x, event->area.x+w,
436 				event->area.y,event->area.y + h);
437 
438 //			printf("PARTIAL REFRESH from (%d,%d) to (%d,%d)\n",event->area.x, event->area.y,event->area.x+w,event->area.y + h);
439 
440 			if (hfw->if_rgb)
441 				gdk_draw_rgb_image(hfw->area->window,
442 					hfw->area->style->fg_gc[GTK_WIDGET_STATE (hfw->area)],
443 					event->area.x,
444 					event->area.y,
445 					w,
446 					h,
447 					GDK_RGB_DITHER_NONE,
448 					hfw->hf_buf8,
449 					3*w );
450 			else
451 				gdk_draw_gray_image(hfw->area->window,
452 					hfw->area->style->fg_gc[GTK_WIDGET_STATE (hfw->area)],
453 					event->area.x,
454 					event->area.y,
455 					w,
456 					h,
457 					GDK_RGB_DITHER_NONE,
458 					hfw->hf_buf8,
459 					w );
460 
461 		}
462 
463 		control_line_draw (hfw->control_line, hfw->area->window,
464 			hfw->area_size, hfw->area_size);
465 
466 		gdk_window_set_cursor(widget->window, hfw->hf_options->current_cursor);
467 	}
468 	// GL refresh doesn't seem to be required here (?)
469 	// if (hfw->gl_preview)
470 	//	gtk_widget_queue_draw(GTK_WIDGET(hfw->gl_preview->gl_area));
471 	//    return FALSE;
472     return TRUE;
473 }
474 
hf_wrapper_display(gpointer data)475 void hf_wrapper_display(gpointer data) {
476 //	Redraws the HF after resizing the drawing area (typically:  for undo / redo)
477 	hf_wrapper_struct *hfw;
478 	hfw = (hf_wrapper_struct *) data;
479 //	This does not always automatically redraw the HF at the desired scale?
480 //	toggle_scale_button(hfw->sbs);
481 //	Accepting transformations like brightness / contrast - avoiding unseen inconsistencies!
482 //	printf("HF_WRAPPER_DISPLAY: %s .. %p;\n", *hfw->filename, hfw);
483 	if (hfw->hf_options->need_tmp_buf) {
484 		accept_callb(NULL,&data);
485 	}
486 //	Be sure that we put the HF in a state allowing a new drawing
487 	hfw->hf_options->flag_uniform_done = FALSE;
488 	if (hfw->tiling_ptr)
489 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(hfw->tiling_wdg), *hfw->tiling_ptr);
490 
491 	init_render_struct(hfw->hf_options->render_str,
492 		hfw->dirname,
493 		hfw->filename,
494 		&hfw->creation_mode,
495 		hfw->if_modified,
496 		hfw->gl_preview,
497 		hfw->hf_struct->hf_buf,
498 		hfw->hf_struct->max_x,
499 		hfw->hf_struct->max_y);
500 
501 //	The HF could be displayed 2 times ?
502 	draw_hf(hfw);
503 	// GTK 2.x: we must repeat this to display the preview when activating a new doc window
504 	if (hfw->gl_preview) {
505  //	printf("GL_AREA_UPDATE de %d:  %s\n", hfw, *hfw->filename);
506 		gl_area_update(hfw->gl_preview);
507 	}
508 }
509 
510 
hf_wrapper_copy(gpointer data_from,gpointer data_to,gint operation)511 gpointer hf_wrapper_copy(gpointer data_from, gpointer data_to, gint operation) {
512 //	Copy of a hf_wrapper, including the embedded hf_struct,
513 //	for stacking in the history (undo / redo stack) or replacing a structure with another
514 //	If data_to is null, we allocate it and return the newly allocated pointer
515 	hf_wrapper_struct *hfw, *hfwcopy;
516 	gint old_scale;
517 	gboolean flag_swap;
518 	hfw = (hf_wrapper_struct *)data_from;
519 	if ((operation==NONE) || (operation==UNDO))
520 		flag_swap = TRUE;
521 	else // operation==REDO
522 		flag_swap = FALSE;
523 	if (!data_to) {
524 		hfwcopy = (hf_wrapper_struct *) x_malloc(sizeof(hf_wrapper_struct), "hf_wrapper_struct (hfwcopy)");
525 //		printf("data_to==NULL; HF_WRAPPER_COPY, de %p sur MALLOC: %p\n",hfw, hfwcopy);
526 	}
527 	else {
528 		hfwcopy = data_to;
529 		hf_free(hfwcopy->hf_struct);
530 		old_scale = hfwcopy->display_scale;
531 //		printf("data_to!=NULL; HF_WRAPPER_COPY, de %p sur %p\n",hfw, hfwcopy);
532 	}
533 	memcpy(hfwcopy, hfw, sizeof(hf_wrapper_struct));
534 	hfwcopy->hf_struct = hf_copy_new(hfw->hf_struct,flag_swap);
535 //	The copy would certainly be reused in edit mode, not creation mode
536 	hfwcopy->creation_mode = FALSE;
537 //	hfwcopy->hf_buf8 = NULL;
538 	if (data_to) { // We are probably restoring (undoing)
539 		hfwcopy->display_scale = old_scale;
540 		alloc_buf8(hfwcopy);
541 		hfwcopy->area_size = RIGHT_SHIFT(hfwcopy->hf_options->hf_size,hfwcopy->display_scale) ;
542 	}
543 	return (gpointer) hfwcopy;
544 }
545 
hf_set_display_scale(GtkWidget * wdg,gpointer data)546 gint hf_set_display_scale(GtkWidget *wdg, gpointer data) {
547 //	Applied after getting the scale setting from the clicked button
548 //	(non generic part of the process)
549 	gchar *txt;
550 	GtkAdjustment *vadj,*hadj;
551 	GtkRequisition rq;
552 	hf_wrapper_struct *hfw;
553 	hfw = (hf_wrapper_struct *) data;
554 	if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wdg)))
555 		return TRUE;
556 
557 	if (!GTK_IS_WIDGET(hfw->draw_area_frame))
558 		return TRUE;
559 //	printf("HF_SET_DISPLAY_SCALE\n");
560 	hfw->display_scale = get_scale(hfw->sbs);
561 	hfw->area_size = RIGHT_SHIFT(hfw->hf_struct->max_x, hfw->display_scale);
562 //	Area size changes trigger a callback which reallocates and computes the buffers
563 //	2005-03: now that the draw area is in a scrolled window, we must reallocate
564 //	hf_buf8, because it could be only partially exposed, and the function
565 //	which writes into hf_buf8 doesn't reallocate it, for performance considerations
566 //	(this function was designed for use when drawing with a pen).
567 
568 	realloc_buf8(hfw);
569 
570 	gtk_widget_set_size_request (hfw->area, hfw->area_size, hfw->area_size);
571 	gtk_widget_set_size_request (hfw->draw_area_viewport, hfw->area_size, hfw->area_size);
572 
573 	if (hfw->area_size<=hfw->hf_struct->max_x)
574 		return TRUE;
575 
576 	// The image is centered in the scrolled window
577 	gtk_widget_size_request(GTK_WIDGET(hfw->draw_area_frame),&rq);
578 //	printf("WIDTH: %d; HEIGHT: %d\n",rq.width, rq.height);
579 	vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW(hfw->scrolled_window));
580 	hadj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW(hfw->scrolled_window));
581 	gtk_adjustment_set_value (vadj, (gdouble) ((hfw->area_size>>1) - (rq.height>>1)));
582 	gtk_adjustment_set_value (hadj, (gdouble) ((hfw->area_size>>1) - (rq.width>>1)));
583 
584 	return TRUE;
585 }
586 
create_standard_hf_display(hf_wrapper_struct * hf_wrapper)587 void create_standard_hf_display (hf_wrapper_struct *hf_wrapper) {
588 
589 	GtkWidget *vbox, *hbox, *frame, *label, *scrolled_window;
590 	GSList *group = NULL;
591 	GtkAdjustment *vadj,*hadj;
592 	gchar *txt;
593 
594 //	printf("CREATE_STANDARD_HF_DISPLAY\n");
595 //	Standard HF
596 
597 	vbox = gtk_vbox_new(FALSE,0);
598 	gtk_widget_show(GTK_WIDGET(vbox));
599 	gtk_container_add (GTK_CONTAINER(hf_wrapper->window), vbox);
600 
601 //	hbox for scale buttons and mouse position
602 
603 	hbox = gtk_hbox_new(FALSE,0);
604 	gtk_widget_show(GTK_WIDGET(hbox));
605 	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, DEF_PAD*0.5);
606 
607 //	frame for mouse position
608 	frame = gtk_frame_new(NULL);
609 	gtk_widget_show(frame);
610 	gtk_box_pack_start(GTK_BOX(hbox),frame,FALSE, FALSE, DEF_PAD*0.5);
611 	hf_wrapper->mouse_position = gtk_label_new("   0,0   ");
612 	gtk_widget_show(hf_wrapper->mouse_position);
613 	gtk_widget_set_size_request (hf_wrapper->mouse_position, 120, 0);
614 	gtk_container_add(GTK_CONTAINER(frame),hf_wrapper->mouse_position);
615 
616 	if (hf_wrapper->tiling_ptr) {
617 		hf_wrapper->tiling_wdg = define_check_button_in_box ("Tiling", hbox, FALSE, FALSE, DEF_PAD);
618 		gtk_toggle_button_set_active
619 			(GTK_TOGGLE_BUTTON ( hf_wrapper->tiling_wdg ),
620 			*hf_wrapper->tiling_ptr);
621 		gtk_signal_connect (GTK_OBJECT(hf_wrapper->tiling_wdg), "toggled",
622 			GTK_SIGNAL_FUNC(toggle_check_button_callb), hf_wrapper->tiling_ptr);
623 	}
624 
625 	hf_wrapper->sbs = scale_buttons_new_with_callback (GTK_ORIENTATION_HORIZONTAL, SCALE_ID_12_5, SCALE_ID_400, hf_set_display_scale, (gpointer) hf_wrapper);
626 	hf_wrapper->sbs->current = hf_wrapper->display_scale;
627 
628 	gtk_box_pack_start(GTK_BOX(hbox), hf_wrapper->sbs->box, FALSE, FALSE, DEF_PAD*0.5);
629 
630 	txt = (gchar *) x_malloc(12, "const gchar (txt in create_standard_hf_display)");
631 	sprintf(txt,"%d x %d",hf_wrapper->hf_options->hf_size, hf_wrapper->hf_options->hf_size);
632 	hf_wrapper->draw_area_frame = gtk_frame_new(txt);
633 	gtk_widget_show(hf_wrapper->draw_area_frame);
634 	gtk_widget_set_size_request (hf_wrapper->draw_area_frame, hf_wrapper->area_size+SCALE_PAD, hf_wrapper->area_size+SCALE_PAD);
635 
636 	scrolled_window = gtk_scrolled_window_new (NULL, NULL);
637         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
638 	gtk_widget_show (scrolled_window);
639 
640 	vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW(scrolled_window));
641 	hadj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW(scrolled_window));
642 
643 	// We process the viewport separately, instead of using
644 	// gtk_scrolled_window_add_with_viewport
645 	// to be able to rescale the area when its size changes
646 	hf_wrapper->draw_area_viewport = gtk_viewport_new (hadj, vadj);
647 	gtk_widget_show(hf_wrapper->draw_area_viewport);
648 	gtk_widget_set_size_request (hf_wrapper->draw_area_viewport, hf_wrapper->area_size, hf_wrapper->area_size);
649 
650 	gtk_container_add (GTK_CONTAINER(hf_wrapper->draw_area_viewport), hf_wrapper->area);
651 	gtk_container_add (GTK_CONTAINER(scrolled_window), hf_wrapper->draw_area_viewport);
652 
653 	hf_wrapper->scrolled_window = scrolled_window;
654 
655 	gtk_container_add (GTK_CONTAINER(hf_wrapper->draw_area_frame), scrolled_window);
656 
657 //	hbox for main view and GL preview
658 	hbox = gtk_hbox_new(FALSE,0);
659 	gtk_widget_show(GTK_WIDGET(hbox));
660 	gtk_box_pack_start(GTK_BOX(hbox),  hf_wrapper->draw_area_frame, TRUE, TRUE,0);
661 
662 	hf_wrapper->gl_preview =
663 		create_gl_preview_dialog(
664 			hf_wrapper->hf_options->gl_defaults,
665 			hf_wrapper->window,
666 			hf_wrapper->hf_struct->hf_buf,
667 			hf_wrapper->hf_struct->max_x,
668 			hf_wrapper->hf_struct->max_y,
669 			HF_TYPE_ID,
670 			&hf_wrapper->hf_struct->use_water,
671 			&hf_wrapper->hf_struct->water_level);
672 	if (hf_wrapper->gl_preview && hf_wrapper->gl_preview->gl_dialog) {
673 		gl_set_water_level (hf_wrapper->gl_preview);
674 		gtk_box_pack_start(GTK_BOX(hbox),
675 			align_widget(hf_wrapper->gl_preview->gl_dialog,0.5,0.5),
676 			FALSE, FALSE, DEF_PAD*0.5);
677 	}
678 	gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, DEF_PAD*0.5);
679 
680 	gtk_signal_connect (GTK_OBJECT (hf_wrapper->area), "motion_notify_event",
681 		(GtkSignalFunc) motion_notify, hf_wrapper);
682 // printf("CONNECT hfw->area in HF_WRAPPER_NEW\n");
683 	gtk_signal_connect (GTK_OBJECT (hf_wrapper->area), "button_press_event",
684 		(GtkSignalFunc) button_press, hf_wrapper);
685 	gtk_signal_connect (GTK_OBJECT (hf_wrapper->area), "button_release_event",
686 		(GtkSignalFunc) button_release, hf_wrapper);
687 
688 	toggle_scale_button(hf_wrapper->sbs);
689 
690 	init_render_struct(hf_wrapper->hf_options->render_str,
691 		hf_wrapper->dirname,
692 		hf_wrapper->filename,
693 		&hf_wrapper->creation_mode,
694 		hf_wrapper->if_modified,
695 		hf_wrapper->gl_preview,
696 		hf_wrapper->hf_struct->hf_buf,
697 		hf_wrapper->hf_struct->max_x,
698 		hf_wrapper->hf_struct->max_y);
699 
700 	if (hf_wrapper->gl_preview && hf_wrapper->gl_preview->gl_area)
701 		gtk_widget_realize(hf_wrapper->gl_preview->gl_area);
702 
703 	return;
704 
705 }
706 
set_dependent_process(hf_wrapper_struct * hfw,void (* dependent_process)(gpointer),gpointer dependent_process_data)707 void set_dependent_process (hf_wrapper_struct *hfw, void (*dependent_process) (gpointer), gpointer dependent_process_data) {
708 	hfw->dependent_process = dependent_process;
709 	hfw->dependent_process_data = dependent_process_data;
710 }
711 
hf_wrapper_new(gchar ** dirname,gchar ** filename,GtkWidget * window,GtkWidget * creation_container,gpointer hf_options,gboolean * if_modified,gboolean * flag_history,gboolean (* registering_fn)(gpointer),gpointer registering_data,gchar * path_n_file,gboolean * fname_tochoose,gint hf_category)712 gpointer hf_wrapper_new (
713 		gchar **dirname,
714 		gchar **filename,
715 		GtkWidget *window,
716 		GtkWidget *creation_container,
717 		gpointer hf_options,
718 		gboolean *if_modified,
719 		gboolean*flag_history,
720 		gboolean (*registering_fn) (gpointer),
721 		gpointer registering_data,
722 		gchar *path_n_file,
723 		gboolean *fname_tochoose,
724 		gint hf_category) {
725 	// Builds the main HF window and the HF struct
726 	// "window" is the document window
727 	//	NOTE:  for a HFW which is a pen, "window" is a box where to put the preview pixmap
728 	// "creation_container" is the creation dialog - allows adding some options
729 	//	For a HF pen, it is the HF draw dialog
730 	// hf_options is inherited from doc_type_struct
731 	// path_n_file, if not NULL, is the file name from which we try to read the file
732 	// fname_tochoose:  set to TRUE if we have to do a conversion when reading the file,
733 	//	because the file would be opened under a generic name (DOCUMENTn)
734 
735 	gint hf_size;
736 	gchar *msg=NULL;
737 	hf_wrapper_struct *hf_wrapper;
738 
739 	hf_wrapper = (hf_wrapper_struct *) x_malloc(sizeof(hf_wrapper_struct), "hf_wrapper_struct");
740 // printf("hf_wrapper in hf_wrapper_new: %p\n",hf_wrapper);
741 	hf_wrapper->filename = filename;
742 	hf_wrapper->dirname = dirname;
743 	hf_wrapper->window = window;
744 	hf_wrapper->to_register_in_history = flag_history;  // For undo / redo stack
745 	hf_wrapper->registering_fn = registering_fn;
746 	hf_wrapper->registering_data = registering_data;
747 	hf_wrapper->if_calculated = FALSE;
748 	hf_wrapper->creation_container = creation_container;
749 	hf_wrapper->hf_options = (hf_options_struct *)hf_options;
750 	hf_wrapper->tiling_wdg = NULL;
751 	hf_wrapper->tiling_ptr = (gboolean *) x_malloc(sizeof(gboolean), "hf_wrapper->tiling_ptr");
752 	*hf_wrapper->tiling_ptr = TRUE;
753 	hf_wrapper->mouse_position = NULL;
754 	hf_wrapper->size_change_request = TRUE;
755 	hf_wrapper->control_line = NULL;
756 	hf_wrapper->sbs = NULL;
757 	hf_wrapper->draw_area_frame = NULL;
758 	hf_wrapper->draw_area_viewport = NULL;
759 	hf_wrapper->dependent_process = NULL;
760 	hf_wrapper->dependent_process_data = NULL;
761 	if (hf_category)
762 		hf_wrapper->type = hf_category; // HFMAIN, HFPEN, HFPRIMITIVE, HFNOISE
763 	else
764 		hf_wrapper->type = HFMAIN;
765 	//	Initialize the current filter dialog struct to the creation filter struct
766 	hf_wrapper->hf_options->fd_struct =
767 		hf_wrapper->hf_options->creation_fd_struct;
768 	hf_wrapper->apply_filter = FALSE;
769 
770 	if (!hf_wrapper->hf_options->hf_size) {
771 		switch (hf_wrapper->type) {
772 		case HFMAIN:
773 		//	The pixmap area is best-guessed from the X screen size
774 			hf_size = hf_default_size();
775 			break;
776 		case HFPEN:
777 			hf_size = MAX_PEN_PREVIEW;
778 			break;
779 		default:
780 			//	It's any other preview
781 			hf_size = MAX_FILTER_PREVIEW;
782 		}
783 		hf_wrapper->hf_options->hf_size = hf_size;
784 	}
785 	else
786 		hf_size = hf_wrapper->hf_options->hf_size;
787 
788 	if (!path_n_file) {
789 	//	We are creating a new document from scratch
790 		// We reset the size menu for consistency (only required with
791 		// non integrated interface)
792 		if (!INTEGRATED_INTERFACE)
793 			set_size_menu_from_size ((gpointer) hf_wrapper->hf_options, hf_size);
794 		hf_wrapper->hf_struct = hf_new(hf_size);
795 		hf_set_tiling_ptr (hf_wrapper->hf_struct, hf_wrapper->tiling_ptr);
796 	//	hf_wrapper->last_creation_action initialized in hf_dialog_defaults
797 	//	(when toggling the default button)
798 
799 		hf_wrapper->last_action = _("New document");
800 		hf_wrapper->creation_mode = TRUE;
801 	}
802 	else {
803 	//	We are reading an existing document
804 		hf_wrapper->hf_struct = hf_read(path_n_file, fname_tochoose, &msg, hf_wrapper->tiling_ptr);
805 
806 		if (*fname_tochoose)
807 			(*if_modified) = TRUE;
808 
809 		if (msg)
810 			my_msg(msg, WARNING);
811 		if (!hf_wrapper->hf_struct) {	// Something had gone bad! (file unreadable?)
812 			x_free(hf_wrapper);
813 			return NULL;
814 		}
815 		else {
816 			hf_wrapper->hf_options->hf_size = hf_wrapper->hf_struct->max_x;
817 			hf_size = hf_wrapper->hf_options->hf_size ;
818 		}
819 		hf_backup(hf_wrapper->hf_struct);
820 		hf_wrapper->hf_options->last_creation_action = _("Reading");
821 		hf_wrapper->last_action = _("Reading");
822 		hf_wrapper->creation_mode = FALSE;
823 		if (hf_wrapper->hf_options->img)
824 			hf_wrapper->hf_options->fd_struct = hf_wrapper->hf_options->img->fd_struct;
825 		else
826 			hf_wrapper->hf_options->fd_struct = NULL;
827 	}
828 
829 	hf_wrapper->display_scale = get_display_scale(hf_size);
830 	hf_wrapper->if_rgb = FALSE;
831 	alloc_buf8(hf_wrapper);
832 	hf_wrapper->area = gtk_drawing_area_new();
833 	//	For mouse movements
834 	gtk_widget_set_events (hf_wrapper->area, GDK_EXPOSURE_MASK
835 				| GDK_LEAVE_NOTIFY_MASK
836 				| GDK_BUTTON_PRESS_MASK
837 				| GDK_POINTER_MOTION_MASK
838 				| GDK_POINTER_MOTION_HINT_MASK
839 				| GDK_BUTTON_RELEASE_MASK);
840 
841 	hf_wrapper->area_size = RIGHT_SHIFT(hf_size,hf_wrapper->display_scale) ;
842 	hf_wrapper->gl_preview = NULL;
843 
844 	hf_wrapper->mouse_dragging = FALSE;
845 
846 	//	The next &flag is inherited from the document wrapper in the calling app
847 	hf_wrapper->if_modified = if_modified;
848 
849 	if (hf_wrapper->type==HFMAIN) {
850  //		printf("%d == HF_MAIN\n",hf_wrapper);
851 		create_standard_hf_display (hf_wrapper);
852 	}
853 	else {
854 	//	This HF is a pen or another preview
855 	//	"window" is a box or frame where to put the preview pixmap
856 	//	We don't track the mouse movements
857 
858 		gtk_container_add(GTK_CONTAINER(window),
859 			align_widget(hf_wrapper->area,0.5,0.5));
860  //		printf("%d == HF_PEN or HF_PRIMITIVE\n",hf_wrapper);
861 	}
862 
863 	// 2006-09-27 gtk_drawing_area_size is supposed to be deprecated
864 	// Unfortunately, gtk_widget_set_size_request make the H and V scales
865 	// disappear, when the area size is larger than the window (??)
866 	gtk_drawing_area_size( GTK_DRAWING_AREA(hf_wrapper->area),
867 		hf_wrapper->area_size ,hf_wrapper->area_size );
868 //	gtk_widget_set_size_request( GTK_WIDGET(hf_wrapper->area),
869 //		hf_wrapper->area_size ,hf_wrapper->area_size );
870 	gtk_widget_show(hf_wrapper->area);
871 
872 	hf_wrapper->exp_handler =
873 		gtk_signal_connect(GTK_OBJECT(hf_wrapper->area), "expose_event", (GtkSignalFunc) expose_event, (gpointer) hf_wrapper);
874 // printf("**** HANDLER de %d: %d\n",hf_wrapper,hf_wrapper->exp_handler);
875 	gtk_signal_connect(GTK_OBJECT(hf_wrapper->area), "configure_event",
876 		(GtkSignalFunc) configure_event, (gpointer) hf_wrapper);
877 
878 	return (gpointer) hf_wrapper;
879 }
880 
hf_wrapper_free(gpointer data,gboolean free_interface)881 void hf_wrapper_free (gpointer data, gboolean free_interface) {
882 
883 	hf_wrapper_struct *hfw;
884 	if (!data) return;
885 	hfw = (hf_wrapper_struct *) data;
886 //	printf("HF_WRAPPER_FREE: %p -- H: %d; size: %d; tiling_ptr: %p\n", hfw, hfw->exp_handler, hfw->hf_struct->max_x, hfw->tiling_ptr);
887 	if (free_interface) { // FALSE if we are freeing an instance in the undo stack
888 //		printf("Disconnect exposure signal\n");
889 		gtk_signal_disconnect(GTK_OBJECT(hfw->area), hfw->exp_handler);
890 		if (hfw->sbs)
891 			scale_buttons_free(hfw->sbs);
892 		if (hfw->tiling_ptr)
893 			x_free (hfw->tiling_ptr);
894 	}
895 
896 	if (hfw->hf_struct)
897 		hf_free(hfw->hf_struct);
898 
899 	x_free(hfw);
900 }
901 
hf_get_last_action(gpointer data)902 gchar *hf_get_last_action (gpointer data) {
903 
904 	return ((hf_wrapper_struct *)data)->last_action;
905 }
906 
free_buf(guchar * pixels,gpointer data)907 static void free_buf (guchar *pixels, gpointer data) {
908 	// **buf == *pixels
909 	guchar **buf;
910 	buf = (guchar **) data;
911 	if (*buf) {
912 		x_free(*buf);
913 		*buf = NULL;
914 	}
915 }
916 
hf_get_icon(gpointer hf_wrapper,gint size_x,gint size_y)917 GtkWidget *hf_get_icon (gpointer hf_wrapper, gint size_x, gint size_y) {
918 	// Returns a small icon, representing the document
919 	hf_wrapper_struct *hfw;
920 	GtkWidget *area;
921 	GdkPixbuf *pixbuf;
922 	guchar *buf;
923 	gint i,j, len_x;
924 	gfloat ratio_x, ratio_y;
925 
926 	hfw = (hf_wrapper_struct * ) hf_wrapper;
927 	size_x =  MIN(size_x,128);
928 	size_y =  MIN(size_y,128);
929 	buf = (guchar *) x_malloc(3*size_x*size_y*sizeof(guchar), "const guchar (buf in hf_get_icon)");
930 
931 	ratio_x = ((gfloat) hfw->hf_struct->max_x) / (gfloat) size_x;
932 	ratio_y = ((gfloat) hfw->hf_struct->max_y) / (gfloat) size_y;
933 
934 	len_x = (gint) (hfw->hf_struct->max_x*ratio_y);
935 
936 	for (i=0; i<size_x; i++)
937 		for (j=0; j<size_y; j++) {
938 			*(buf + j*size_x*3 + i*3) = (*(hfw->hf_struct->hf_buf + (j*len_x) + (gint) (i*ratio_x))) >>8;
939 			*(buf + j*size_x*3 + i*3 + 1) = *(buf + j*size_x*3 + i*3);
940 			*(buf + j*size_x*3 + i*3 + 2) = *(buf + j*size_x*3 + i*3);
941 	}
942 	pixbuf = gdk_pixbuf_new_from_data (buf, GDK_COLORSPACE_RGB, FALSE, 8, size_x, size_y, 3*size_x, free_buf, (gpointer) &buf);
943 	area = gtk_image_new_from_pixbuf( pixbuf );
944 
945 	gtk_widget_show(area);
946 
947 	return area;
948 }
949 
hf_wrapper_save(gpointer data,gchar * path_n_file)950 void hf_wrapper_save (gpointer data, gchar *path_n_file) {
951 
952 	hf_wrapper_struct *hfw;
953 	if (!data) {
954 		my_msg(_("There is nothing to save!"),WARNING);
955 		return;
956 	}
957 	hfw = (hf_wrapper_struct *) data;
958 	if (hfw->hf_struct) {
959 		hf_write(hfw->hf_struct, path_n_file, hfw->gl_preview->cameras);
960 	}
961 	else
962 		my_msg(_("There is nothing to save!"),WARNING);
963 }
964 
hf_stats(gpointer data)965 void hf_stats(gpointer data) {
966 	hf_wrapper_struct *hfw;
967 	view_struct *vs=NULL;
968 	guint HISTOGRAM_WIDTH = 384;
969 	guint HISTOGRAM_HEIGHT = 256;
970 	static gchar buf[200];
971 	hfw = (hf_wrapper_struct *) data;
972 	if (!hfw)
973 		return;
974 	hf_min_max (hfw->hf_struct);
975 	sprintf(buf,"%s ... MIN: %d;  MAX: %d;  %s: %d.",
976 		*hfw->filename,hfw->hf_struct->min, hfw->hf_struct->max,
977 		_("Average"), hfw->hf_struct->avrg);
978 
979 	vs = view_struct_new (HISTOGRAM_WIDTH, HISTOGRAM_HEIGHT, NULL, NULL);
980 	histogram(hfw->hf_struct, HISTOGRAM_WIDTH, HISTOGRAM_HEIGHT, vs->buf8);
981 
982 	my_msg_with_image("HISTOGRAM",buf,vs->area);
983 	view_struct_free(vs);
984 }
985 
986 /**********************************************************************************/
987 
988 // Undo / Redo stack management - think about a separated class in the future
989 
accept_fn(hf_wrapper_struct * hfw)990 void accept_fn (hf_wrapper_struct *hfw) {
991 	if (!hfw)
992 		return;
993 //	printf("********** ACCEPT_FN\n");
994 	hf_backup(hfw->hf_struct);
995 	commit_pending_record(hfw);
996 	// Resetting the parameter values (set_fn) could trigger a recalculation
997 	// This is not what we want
998 	hfw->if_calculated = TRUE;
999 	if (hfw->hf_options->img->set_fn)
1000 		(*hfw->hf_options->img->set_fn) ((gpointer)hfw->hf_options->img);
1001 //	Check if recomputing min-max is necessary or can be done on demand
1002 //	hf_min_max(hfw->hf_struct);
1003 	gtk_widget_set_sensitive(GTK_WIDGET(hfw->hf_options->img->accept_wdg),FALSE);
1004 	hfw->if_calculated = FALSE;
1005 }
1006 
reset_fn(hf_wrapper_struct * hfw)1007 void reset_fn (hf_wrapper_struct *hfw) {
1008 //	Cancels the current operation by copying the temp buffer (backuped)
1009 // 	into the current (modified) one
1010 //	printf("********** RESET_FN\n");
1011 	if (!hfw)
1012 		return;
1013 	if (hfw->hf_options->img->set_fn)
1014 		(*hfw->hf_options->img->set_fn) ((gpointer)hfw->hf_options->img);
1015 	hf_restore (hfw->hf_struct);
1016 	gtk_widget_set_sensitive(GTK_WIDGET(hfw->hf_options->img->accept_wdg),FALSE);
1017 	// Added 2007-01-02
1018 	hfw->if_calculated = FALSE;
1019 	draw_hf(hfw);
1020 }
1021 
1022 // Standard accept / refresh functions for drawing
1023 
accept_draw_fn(hf_wrapper_struct * hfw)1024 void accept_draw_fn (hf_wrapper_struct *hfw) {
1025 	if (!hfw)
1026 		return;
1027 //	printf("********** ACCEPT_DRAW_FN\n");
1028 	hf_backup(hfw->hf_struct);
1029 	commit_pending_record(hfw);
1030 	hfw->if_calculated = FALSE;
1031 }
1032 
reset_draw_fn(hf_wrapper_struct * hfw)1033 void reset_draw_fn (hf_wrapper_struct *hfw) {
1034 //	Cancels the current operation by copying the temp buffer (backuped)
1035 // 	into the current (modified) one
1036 //	printf("********** RESET_DRAW_CALLB\n");
1037 	if (!hfw)
1038 		return;
1039 	hf_restore (hfw->hf_struct);
1040 	hfw->if_calculated = FALSE;
1041 	draw_hf(hfw);
1042 }
1043 
record_action(hf_wrapper_struct * data,gchar * action_lbl)1044 void record_action (hf_wrapper_struct *data, gchar *action_lbl) {
1045 //	Record action in the standard undo / redo stack
1046 	hf_wrapper_struct *hfw;
1047 	hfw = (hf_wrapper_struct *) data;
1048 // printf("RECORD ACTION: %s\n", _(action_lbl));
1049 	if (hfw->type != HFMAIN)	// Don't record an HFPEN, for instance
1050 		return;
1051 	commit_pending_record (data);
1052 //	if (hfw->init_history_flag)
1053 //		(*hfw->init_history_flag) (hfw->window, hfw->to_register_in_history);
1054 	hfw->last_action = _(action_lbl);
1055 }
1056 
begin_pending_record(hf_wrapper_struct * hfw,gchar * action_lbl,gpointer commit_fn,gpointer reset_fn)1057 void begin_pending_record (hf_wrapper_struct *hfw, gchar *action_lbl,
1058 	gpointer commit_fn,
1059 	gpointer reset_fn) {
1060 
1061 //	Anticipation of an action recording in the standard undo / redo stack
1062 //	The signal for actually recording the action in the stack would be
1063 //	emitted by commit_pending_record, after, for instance, a context change
1064 //	Added 2004-03: initializes the functions required to commit / reset
1065 //				the changes when we change context
1066 
1067 //	printf("BEGIN_PENDING_RECORD: %s\n",action_lbl);
1068 	if (hfw->to_register_in_history)
1069 		(*hfw->to_register_in_history) = TRUE;
1070 	hfw->last_action = _(action_lbl);
1071 	set_commit_reset_fns (hfw->hf_options->stack, commit_fn, reset_fn, (gpointer) hfw);
1072 }
1073 
commit_pending_record(hf_wrapper_struct * hfw)1074 void commit_pending_record (hf_wrapper_struct *hfw) {
1075 
1076 //	Commits an anticipated action record, in the undo / redo stack
1077 	if (*hfw->to_register_in_history)
1078 		if (hfw->registering_fn && hfw->registering_data) {
1079 //			printf("Executing registering_fn\n");
1080 			(*hfw->registering_fn) (hfw->registering_data);
1081 		}
1082 }
1083 
1084 /**********************************************************************************/
1085 
1086 // Utilities requiring hf_wrapper_struct *
1087 
set_watch_cursor(hf_wrapper_struct * hfw)1088 void set_watch_cursor (hf_wrapper_struct *hfw) {
1089 	// For long processes...
1090 	// We set it on all widgets / windows
1091 	// The HF area has its own cursor (current->cursor)
1092 	gdk_window_set_cursor(hfw->area->window, hfw->hf_options->watch_cursor);
1093 	gdk_window_set_cursor(hfw->window->window, hfw->hf_options->watch_cursor);
1094 	gdk_window_set_cursor(hfw->hf_options->tools_dialog->window, hfw->hf_options->watch_cursor);
1095 	hfw->hf_options->current_cursor = hfw->hf_options->watch_cursor;
1096 	gdk_flush();
1097 }
1098 
unset_watch_cursor(hf_wrapper_struct * hfw)1099 void unset_watch_cursor (hf_wrapper_struct *hfw) {
1100 	gdk_window_set_cursor(hfw->area->window, hfw->hf_options->default_cursor);
1101 	gdk_window_set_cursor(hfw->window->window, hfw->hf_options->default_cursor);
1102 	gdk_window_set_cursor(hfw->hf_options->tools_dialog->window, hfw->hf_options->default_cursor);
1103 	hfw->hf_options->current_cursor = hfw->hf_options->default_cursor;
1104 }
1105