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