/* hf_wrapper.c - functions for managing the height field creation and display * * Copyright (C) 2001, 2005 Patrice St-Gelais * patrstg@users.sourceforge.net * http://geomorph.sourceforge.net * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // Modified 2005-01-09 for removing double buffering, not required with GTK2 // Modified 2006-01-01 for cleaning the file / code structure #include "globals.h" #include "hf_wrapper.h" #include "hf_dialog_options.h" #include "hf_filters.h" #include "hf_filters_dialog.h" #include "gl_preview.h" #include "dialog_utilities.h" gint hf_default_size () { gint s; if (HF_SIZE_IN_PIXELS) // "Floor" the given HF_SIZE to the nearest power of 2 return pow(2,log2i(HF_SIZE_IN_PIXELS)); s = log2i(HF_SIZE_IN_SCREEN_PERCENT*gdk_screen_width()/100); s = pow(2,s); return s; } void draw_hf (hf_wrapper_struct *hfw) { hf_struct_type *hf; hf = hfw->hf_struct; // printf("DRAW_HF\n"); if (hfw->apply_filter) if (hfw->hf_options->fd_struct) { if (hfw->hf_options->fd_struct->current_filter) { if (hfw->hf_struct->max_x > hfw->hf_options->dist_matrix->hf_size) dist_matrix_init(hfw->hf_options->dist_matrix, hfw->hf_struct->max_x); filter_apply(hfw->hf_struct, hfw->hf_options->fd_struct->current_filter, hfw->hf_options->dist_matrix, hfw->hf_options->fd_struct->revert_filter, hfw->hf_options->fd_struct->filter_level, hfw->hf_options->fd_struct->merge_oper); } } // 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)); // "gtk_widget_queue_draw_area" triggers an expose_event for hf_wrapper->area: gtk_widget_queue_draw_area(hfw->area, 0, 0, RIGHT_SHIFT(hf->max_x,hf->display_scale), RIGHT_SHIFT(hf->max_y,hf->display_scale) ); // Redraw immediately, otherwise using the pen is too annoying (irregular) if (hfw->area->window) gdk_window_process_updates(hfw->area->window, FALSE); if (hfw->gl_preview) { // printf("GL_AREA_UPDATE de %d: %s\n", hfw, *hfw->filename); gl_area_update(hfw); } // Emit expose event required for size change during creation if (hfw->creation_mode) { emit_expose_event(hfw->area); } } void draw_hf_partial (hf_wrapper_struct *hfw, gint fromx, gint tox, gint fromy, gint toy, gboolean update_gl_area) { // Version of draw_hf drawing in a subset of the area // from_x, to_x, from_y, to_y defined in the display world, not in the hf world hf_struct_type *hf; hf = hfw->hf_struct; // printf("DRAW_HF partial: (%d, %d) - (%d, %d) \n", fromx, fromy, tox, toy); gtk_widget_queue_draw_area(hfw->area, fromx, fromy, tox - fromx, toy - fromy); // Redraw immediately, otherwise using the pen is too annoying (irregular) if (hfw->area->window) gdk_window_process_updates(hfw->area->window, FALSE); if (update_gl_area && hfw->gl_preview) { // printf("GL_AREA_UPDATE de %d: %s\n", hfw, *hfw->filename); gl_area_update(hfw); } } void gener_hf (hf_wrapper_struct *hfw) { // printf("GENER_HF - current_calculation: %d\n", hfw->hf_options->current_calculation); if (hfw->creation_mode) if (hfw->hf_options->current_calculation) (*hfw->hf_options->current_calculation) (hfw->hf_struct, hfw->hf_options->current_options); draw_hf(hfw); } static gint configure_event (GtkWidget *widget, GdkEventConfigure *event, gpointer data) { hf_wrapper_struct *hf_wrapper; hf_wrapper = (hf_wrapper_struct *) data; // printf("CONFIGURE_EVENT for HFW == %d\n", hf_wrapper); // We initialize the drawable: if (GTK_IS_DRAWING_AREA(hf_wrapper->area)) gdk_draw_rectangle(hf_wrapper->area->window, hf_wrapper->area->style->black_gc,TRUE, 0, 0, hf_wrapper->area->allocation.width, hf_wrapper->area->allocation.height); else return TRUE; if (hf_wrapper->creation_mode) { gener_hf(hf_wrapper); } /* else { // Probably an area size change - removed 2005-11-09 draw_hf(hf_wrapper); } */ hf_wrapper->size_change_request = FALSE; return TRUE; } gint expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer data) { gint w,h; hf_wrapper_struct *hfw; hfw = (hf_wrapper_struct *) data; if (event->count > 0) { return TRUE; } if (hfw->size_change_request) return TRUE; // A configure event must be done before // 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); // printf("FILE: %s; AREA SIZE: %d\n",*hfw->filename,hfw->area_size); if ((!event->area.width) && (!event->area.height)) return TRUE; if (GTK_IS_DRAWING_AREA(hfw->area)) { // We decide here what part of the HF we refresh, before drawing // 2005-03-29: Partial drawing buggy // 2005-04-29: Seems to be corrected if ( (!event->area.width) || (!event->area.height)) return TRUE; if ( ((event->area.width>=hfw->area_size) && (event->area.height>=hfw->area_size) && (event->area.x==0) && (event->area.y==0) ) ) { // (event->area.x==0) && (event->area.y==0) ) || (hfw->hf_struct->if_rgb) ) { // Full refresh // Patched 2005-10-28 - partial refresh not working with rgb images // We fallback to full redraw // Unpatched 2005-10-29 // printf("FULL REFRESH\n"); hf_16_to_8(hfw->hf_struct); if (hfw->hf_struct->if_rgb) gdk_draw_rgb_image(hfw->area->window, hfw->area->style->fg_gc[GTK_WIDGET_STATE (hfw->area)], 0,0,hfw->area_size, hfw->area_size, GDK_RGB_DITHER_NONE, hfw->hf_struct->hf_buf8, 3*hfw->area_size); else gdk_draw_gray_image(hfw->area->window, hfw->area->style->fg_gc[GTK_WIDGET_STATE (hfw->area)], 0,0,hfw->area_size, hfw->area_size, GDK_RGB_DITHER_NONE, hfw->hf_struct->hf_buf8, hfw->area_size); } else { w = MIN(event->area.x+event->area.width,hfw->area_size) - event->area.x; h = MIN(event->area.y+event->area.height,hfw->area_size) - event->area.y ; hf_16_to_8_partial (hfw->hf_struct, event->area.x, event->area.x+w, event->area.y,event->area.y + h); // printf("PARTIAL REFRESH from (%d,%d) to (%d,%d)\n",event->area.x, event->area.y,event->area.x+w,event->area.y + h); if (hfw->hf_struct->if_rgb) gdk_draw_rgb_image(hfw->area->window, hfw->area->style->fg_gc[GTK_WIDGET_STATE (hfw->area)], event->area.x, event->area.y, w, h, GDK_RGB_DITHER_NONE, hfw->hf_struct->hf_buf8, 3*w ); else gdk_draw_gray_image(hfw->area->window, hfw->area->style->fg_gc[GTK_WIDGET_STATE (hfw->area)], event->area.x, event->area.y, w, h, GDK_RGB_DITHER_NONE, hfw->hf_struct->hf_buf8, w ); } control_line_draw (hfw->control_line, hfw->area->window, hfw->area_size, hfw->area_size); gdk_window_set_cursor(widget->window, hfw->hf_options->current_cursor); } // GL refresh doesn't seem to be required here (?) // if (hfw->gl_preview) // gtk_widget_queue_draw(GTK_WIDGET(hfw->gl_preview->gl_area)); // return FALSE; return TRUE; } void hf_wrapper_display(gpointer data) { // Redraws the HF after resizing the drawing area (typically: for undo / redo) hf_wrapper_struct *hfw; hfw = (hf_wrapper_struct *) data; // This does not always automatically redraw the HF at the desired scale? set_widget_display_scale(hfw); // Accepting transformations like brightness / contrast - avoiding unseen inconsistencies! // printf("HF_WRAPPER_DISPLAY: %s .. %d == %x;\n", *hfw->filename, hfw, hfw); if (hfw->hf_options->need_tmp_buf) { accept_callb(NULL,&data); } // Be sure that we put the HF in a state allowing a new drawing hfw->hf_options->flag_uniform_done = FALSE; gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(hfw->tiling_wdg), hfw->hf_struct->if_tiles); // The HF could be displayed 2 times ? draw_hf(hfw); // GTK 2.x: we must repeat this to display the preview when activating a new doc window if (hfw->gl_preview) { // printf("GL_AREA_UPDATE de %d: %s\n", hfw, *hfw->filename); gl_area_update(hfw); } } gpointer hf_wrapper_copy(gpointer data_from, gpointer data_to) { // Copy of a hf_wrapper, including the embedded hf_struct, // for stacking in the history (undo / redo stack) or replacing a structure with another // If data_to is null, we allocate it hf_wrapper_struct *hfw, *hfwcopy; hfw = (hf_wrapper_struct *)data_from; if (!data_to) { hfwcopy = (hf_wrapper_struct *) malloc(sizeof(hf_wrapper_struct)); // printf("HF_WRAPPER_COPY, de %d sur MALLOC: %d\n",hfw, hfwcopy); } else { hfwcopy = data_to; hf_free(hfwcopy->hf_struct); // printf("HF_WRAPPER_COPY, de %d sur %d\n",hfw, hfwcopy); } memcpy(hfwcopy, hfw, sizeof(hf_wrapper_struct)); hfwcopy->hf_struct = hf_copy_new(hfw->hf_struct); // The copy would certainly be reused in edit mode, not creation mode hfwcopy->creation_mode = FALSE; return (gpointer) hfwcopy; } void set_widget_display_scale(hf_wrapper_struct *hfw) { // Set the appropriate radio button from the current display scale gchar *lbl, *txt; GSList *node; // Find label from scale: switch (hfw->display_scale) { case 0: lbl = SCALE_100; break; case 1: lbl = SCALE_50; break; case 2: lbl = SCALE_25; break; case 3: lbl = SCALE_12_5; break; case -1: lbl = SCALE_200; break; case -2: lbl = SCALE_400; } for (node = hfw->scale_group; node; node = node->next) { gtk_label_get(GTK_LABEL(GTK_BIN(node->data)->child), &txt); if (!strcmp(txt,lbl)) break; } if (node) { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(node->data), TRUE); } } void hf_set_display_scale(GtkWidget *wdg, gpointer data) { // Sets the display scale from the label of a radio button // Scales on the buttons are in % // Internally, they are a binary shift (>>) gchar *txt; GtkAdjustment *vadj,*hadj; GtkRequisition rq; hf_wrapper_struct *hfw; hfw = (hf_wrapper_struct *) data; if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wdg))) return; // printf("HF_SET_DISPLAY_SCALE\n"); gtk_label_get(GTK_LABEL(GTK_BIN(wdg)->child), &txt); if (!strcmp(SCALE_100, txt)) hfw->display_scale = 0; else if (!strcmp(SCALE_50, txt)) hfw->display_scale = 1; else if (!strcmp(SCALE_25, txt)) hfw->display_scale = 2; else if (!strcmp(SCALE_12_5, txt)) hfw->display_scale = 3; else if (!strcmp(SCALE_200, txt)) hfw->display_scale = -1; else if (!strcmp(SCALE_400, txt)) hfw->display_scale = -2; hfw->hf_struct->display_scale = hfw->display_scale; hfw->area_size = RIGHT_SHIFT(hfw->hf_struct->max_x,hfw->display_scale); // Area size changes trigger a callback which reallocates and computes the buffers // 2005-03: now that the draw area is in a scrolled window, we must reallocate // hf_buf8, because it could be only partially exposed, and the function // which writes into hf_buf8 doesn't reallocate it, for performance considerations // (this function was designed for use when drawing with a pen). hfw->hf_struct->hf_buf8 = (unsigned char*) realloc (hfw->hf_struct->hf_buf8, RIGHT_SHIFT(hfw->hf_struct->max_x,hfw->display_scale)*RIGHT_SHIFT(hfw->hf_struct->max_x,hfw->display_scale) * (hfw->hf_struct->if_rgb?3:1)); gtk_drawing_area_size(GTK_DRAWING_AREA(hfw->area), hfw->area_size, hfw->area_size); if (hfw->area_size<=hfw->hf_struct->max_x) return; // The image is centered in the scrolled window gtk_widget_size_request(GTK_WIDGET(hfw->draw_area_frame),&rq); // printf("WIDTH: %d; HEIGHT: %d\n",rq.width, rq.height); vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW(hfw->scrolled_window)); hadj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW(hfw->scrolled_window)); gtk_adjustment_set_value (vadj, (gdouble) ((hfw->area_size>>1) - (rq.height>>1))); gtk_adjustment_set_value (hadj, (gdouble) ((hfw->area_size>>1) - (rq.width>>1))); } gpointer create_standard_hf_display (hf_wrapper_struct *hf_wrapper) { GtkWidget *vbox, *hbox, *frame, *label, *scrolled_window; GSList *group = NULL; gchar *txt; // Standard HF vbox = gtk_vbox_new(FALSE,0); gtk_widget_show(GTK_WIDGET(vbox)); gtk_container_add (GTK_CONTAINER(hf_wrapper->window), vbox); // hbox for scale buttons hbox = gtk_hbox_new(FALSE,0); gtk_widget_show(GTK_WIDGET(hbox)); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, DEF_PAD*0.5); // frame for mouse position frame = gtk_frame_new(NULL); gtk_widget_show(frame); gtk_box_pack_start(GTK_BOX(hbox),frame,FALSE, FALSE, DEF_PAD*0.5); hf_wrapper->mouse_position = gtk_label_new(" 0,0 "); gtk_widget_show(hf_wrapper->mouse_position); gtk_container_add(GTK_CONTAINER(frame),hf_wrapper->mouse_position); hf_wrapper->tiling_wdg = define_check_button_in_box ("Tiling", hbox, TRUE, TRUE, DEF_PAD); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON ( hf_wrapper->tiling_wdg ), hf_wrapper->hf_struct->if_tiles); gtk_signal_connect (GTK_OBJECT(hf_wrapper->tiling_wdg), "toggled", GTK_SIGNAL_FUNC(toggle_check_button_callb), &(hf_wrapper->hf_struct->if_tiles)); label = gtk_label_new(_("Scale % ")); gtk_widget_show (label); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, DEF_PAD*0.5); define_radio_button_in_box_with_data (hbox, &group, SCALE_12_5, hf_set_display_scale, hf_wrapper, FALSE); define_radio_button_in_box_with_data (hbox, &group, SCALE_25, hf_set_display_scale, hf_wrapper, FALSE) ; define_radio_button_in_box_with_data (hbox, &group, SCALE_50, hf_set_display_scale, hf_wrapper, FALSE) ; define_radio_button_in_box_with_data (hbox, &group, SCALE_100, hf_set_display_scale, hf_wrapper, TRUE) ; define_radio_button_in_box_with_data (hbox, &group, SCALE_200, hf_set_display_scale, hf_wrapper, FALSE) ; define_radio_button_in_box_with_data (hbox, &group, SCALE_400, hf_set_display_scale, hf_wrapper, FALSE) ; hf_wrapper->scale_group = group; txt = (gchar *) malloc(12); sprintf(txt,"%d x %d",hf_wrapper->hf_options->hf_size, hf_wrapper->hf_options->hf_size); hf_wrapper->draw_area_frame = gtk_frame_new(txt); gtk_widget_show(hf_wrapper->draw_area_frame); gtk_widget_set_size_request (hf_wrapper->draw_area_frame, hf_wrapper->area_size+SCALE_PAD, hf_wrapper->area_size+SCALE_PAD); scrolled_window = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_widget_show (scrolled_window); gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window), hf_wrapper->area); hf_wrapper->scrolled_window = scrolled_window; // gtk_widget_set_size_request (scrolled_window, hf_wrapper->area_size+25, hf_wrapper->area_size+25); // The only way I was able to remove the black stripe when resizing the frame... // gtk_container_add (GTK_CONTAINER(hf_wrapper->draw_area_frame), // align_widget(hf_wrapper->area,0.5,0.5)); gtk_container_add (GTK_CONTAINER(hf_wrapper->draw_area_frame), scrolled_window); // align_widget(scrolled_window,0.5,0.5)); // hbox for main view and GL preview hbox = gtk_hbox_new(FALSE,0); gtk_widget_show(GTK_WIDGET(hbox)); gtk_box_pack_start(GTK_BOX(hbox), hf_wrapper->draw_area_frame, TRUE, TRUE,0); // gtk_container_add (GTK_CONTAINER(hbox), hf_wrapper->draw_area_frame); hf_wrapper->gl_preview = create_preview_dialog( hf_wrapper->hf_options->gl_defaults,(gpointer) hf_wrapper); if (hf_wrapper->gl_preview && hf_wrapper->gl_preview->gl_dialog) { gtk_box_pack_start(GTK_BOX(hbox), align_widget(hf_wrapper->gl_preview->gl_dialog,0.5,0.5), FALSE, FALSE, DEF_PAD*0.5); } gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, DEF_PAD*0.5); gtk_signal_connect (GTK_OBJECT (hf_wrapper->area), "motion_notify_event", (GtkSignalFunc) motion_notify, hf_wrapper); // printf("CONNECT hfw->area in HF_WRAPPER_NEW\n"); gtk_signal_connect (GTK_OBJECT (hf_wrapper->area), "button_press_event", (GtkSignalFunc) button_press, hf_wrapper); gtk_signal_connect (GTK_OBJECT (hf_wrapper->area), "button_release_event", (GtkSignalFunc) button_release, hf_wrapper); set_widget_display_scale(hf_wrapper); if (hf_wrapper->gl_preview && hf_wrapper->gl_preview->gl_area) gtk_widget_realize(hf_wrapper->gl_preview->gl_area); return; } gpointer hf_wrapper_new ( gchar **dirname, gchar **filename, GtkWidget *window, GtkWidget *creation_container, gpointer hf_options, gboolean *if_modified, gboolean*flag_history, void (*init_history_flag) (GtkWidget *, gboolean*), gchar *path_n_file, gboolean *fname_tochoose, gchar *doc_type, gpointer all_docs, GList * (*get_doc_list_from_type) (gpointer, gchar *) ) { // Builds the main HF window and the HF struct // "window" is the document window // NOTE: for a HFW which is a pen, "window" is a box where to put the preview pixmap // "creation_container" is the creation dialog - allows adding some options // For a HF pen, it is the HF draw dialog // hf_options is inherited from doc_type_struct // path_n_file, if not NULL, is the file name from which we try to read the file // fname_tochoose: set to TRUE if we have to do a conversion when reading the file, // because the file would be opened under a generic name (DOCUMENTn) // doc_type, all_docs, get_doc_list_from_type: required for building a list of other available open documents gint hf_size; gchar *msg=NULL; hf_wrapper_struct *hf_wrapper; hf_wrapper = (hf_wrapper_struct *) malloc(sizeof(hf_wrapper_struct)); // printf("Création de HF_WRAPPER: %d; HF_OPTIONS: %d\n",hf_wrapper, hf_options); // ************** NE PAS OUBLIER D'ALLER CHERCHER LES VALEURS PAR DÉFAUT // DANS LES WIDGETS À CHAQUE NOUVELLE CRÉATION!! ****************** hf_wrapper->filename = filename; hf_wrapper->dirname = dirname; hf_wrapper->window = window; hf_wrapper->init_history_flag = init_history_flag; hf_wrapper->if_calculated = FALSE; hf_wrapper->creation_container = creation_container; hf_wrapper->all_docs = all_docs; hf_wrapper->doc_type = doc_type; hf_wrapper->get_doc_list_from_type = get_doc_list_from_type; hf_wrapper->hf_options = (hf_options_struct *)hf_options; hf_wrapper->tiling_wdg = NULL; hf_wrapper->mouse_position = NULL; hf_wrapper->size_change_request = TRUE; hf_wrapper->control_line = NULL; // Initialize the current filter dialog struct to the creation filter struct hf_wrapper->hf_options->fd_struct = hf_wrapper->hf_options->creation_fd_struct; hf_wrapper->apply_filter = FALSE; if (!hf_wrapper->hf_options->hf_size) { // So: if it's a box or frame, we use a 16 pixels preview. // If it's a window, the pixmap area is best-guessed from the X screen size if (GTK_IS_WINDOW(GTK_OBJECT(window))) { hf_size = hf_default_size(); } else { if (GTK_IS_FRAME(GTK_OBJECT(window))) // It's a HFPEN hf_size = MAX_PEN_PREVIEW; else // It's any other preview hf_size = MAX_FILTER_PREVIEW; // printf("GTK_IS_WINDOW is FALSE; %d\n",hf_size); } hf_wrapper->hf_options->hf_size = hf_size; } else hf_size = hf_wrapper->hf_options->hf_size; if (!path_n_file) { // We are creating a new document from scratch hf_wrapper->hf_struct = hf_new(hf_size,get_display_scale(hf_size)); hf_wrapper->last_action = _("New document"); if (!hf_wrapper->hf_options->last_creation_action) hf_wrapper->hf_options->last_creation_action = _("Uniform"); hf_wrapper->creation_mode = TRUE; } else { // We are reading an existing document hf_wrapper->hf_struct = hf_read(path_n_file, fname_tochoose, &msg); if (msg) my_msg(msg, WARNING); if (!hf_wrapper->hf_struct) { // Something had gone bad! (file unreadable?) free(hf_wrapper); return NULL; } else { hf_wrapper->hf_options->hf_size = hf_wrapper->hf_struct->max_x; hf_size = hf_wrapper->hf_options->hf_size ; } hf_backup(hf_wrapper->hf_struct); hf_wrapper->hf_options->last_creation_action = _("Reading"); hf_wrapper->last_action = _("Reading"); hf_wrapper->creation_mode = FALSE; if (hf_wrapper->hf_options->img) hf_wrapper->hf_options->fd_struct = hf_wrapper->hf_options->img->fd_struct; else hf_wrapper->hf_options->fd_struct = NULL; } hf_wrapper->display_scale = hf_wrapper->hf_struct->display_scale; hf_wrapper->area = gtk_drawing_area_new(); // For mouse movements gtk_widget_set_events (hf_wrapper->area, GDK_EXPOSURE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_RELEASE_MASK); hf_wrapper->area_size = RIGHT_SHIFT(hf_size,hf_wrapper->display_scale) ; // 2006-09-27 gtk_drawing_area_size is supposed to be deprecated // Unfortunately, gtk_widget_set_size_request make the H and V scales // disappear, when the area size is larger than the window (??) gtk_drawing_area_size( GTK_DRAWING_AREA(hf_wrapper->area), hf_wrapper->area_size ,hf_wrapper->area_size ); // gtk_widget_set_size_request( GTK_WIDGET(hf_wrapper->area), // hf_wrapper->area_size ,hf_wrapper->area_size ); hf_wrapper->gl_preview = NULL; // printf ("APRÈS L'AJOUT DU DIALOGUE DE FILTRE; area size: %d \n", RIGHT_SHIFT(hf_size,hf_wrapper->display_scale)); hf_wrapper->mouse_dragging = FALSE; hf_wrapper->type = HFMAIN; // or HFPEN, HFPRIMITIVE, HFNOISE // The next &flag is inherited from the document wrapper in the calling app hf_wrapper->if_modified = if_modified; hf_wrapper->to_register_in_history = flag_history; // For undo / redo stack hf_wrapper->exp_handler = gtk_signal_connect(GTK_OBJECT(hf_wrapper->area),"expose_event", (GtkSignalFunc) expose_event, (gpointer) hf_wrapper); // printf("**** HANDLER de %d: %d\n",hf_wrapper,hf_wrapper->exp_handler); gtk_signal_connect(GTK_OBJECT(hf_wrapper->area), "configure_event", (GtkSignalFunc) configure_event, (gpointer) hf_wrapper); if (!GTK_IS_WINDOW(GTK_OBJECT(window))) { // This HF is a pen or another preview // "window" is a box or frame where to put the preview pixmap // We don't track the mouse movements gtk_container_add(GTK_CONTAINER(window), align_widget(hf_wrapper->area,0.5,0.5)); hf_wrapper->scale_group = NULL; hf_wrapper->draw_area_frame = NULL; // printf("%d == HF_PEN or HF_PRIMITIVE\n",hf_wrapper); } else { create_standard_hf_display (hf_wrapper); if (all_docs && doc_type && get_doc_list_from_type) // Ugly patch... review in the future! 2005-04 instantiate_hf_pen (hf_wrapper, hf_wrapper->hf_options->draw->hf_pen->hf); } gtk_widget_show(hf_wrapper->area); return (gpointer) hf_wrapper; } void hf_wrapper_free (gpointer data, gboolean free_interface) { hf_wrapper_struct *hfw; guint i,j, k,l, m; if (!data) return; hfw = (hf_wrapper_struct *) data; // printf("HF_WRAPPER_FREE: %d -- H: %d; size: %d\n", hfw, hfw->exp_handler, hfw->hf_struct->max_x); if (free_interface) { // FALSE if we are freeing an instance in the undo stack // printf("Disconnect exposure signal\n"); gtk_signal_disconnect(GTK_OBJECT(hfw->area), hfw->exp_handler); } if (hfw->hf_struct) hf_free(hfw->hf_struct); free(hfw); } gchar *hf_get_last_action (gpointer data) { return ((hf_wrapper_struct *)data)->last_action; } static void free_buf (guchar *pixels, gpointer data) { // **buf == *pixels guchar **buf; buf = (guchar **) data; if (*buf) { free(*buf); *buf = NULL; } } GtkWidget *hf_get_icon (gpointer hf_wrapper, gint size_x, gint size_y) { // Returns a small icon, representing the document hf_wrapper_struct *hfw; GtkWidget *area; GdkPixbuf *pixbuf; guchar *buf; gint i,j, len_x; gfloat ratio_x, ratio_y; hfw = (hf_wrapper_struct * ) hf_wrapper; size_x = MIN(size_x,128); size_y = MIN(size_y,128); buf = (guchar *) malloc(3*size_x*size_y*sizeof(guchar)); ratio_x = ((gfloat) hfw->hf_struct->max_x) / (gfloat) size_x; ratio_y = ((gfloat) hfw->hf_struct->max_y) / (gfloat) size_y; len_x = (gint) (hfw->hf_struct->max_x*ratio_y); for (i=0; ihf_struct->hf_buf + (j*len_x) + (gint) (i*ratio_x))) >>8; *(buf + j*size_x*3 + i*3 + 1) = *(buf + j*size_x*3 + i*3); *(buf + j*size_x*3 + i*3 + 2) = *(buf + j*size_x*3 + i*3); } pixbuf = gdk_pixbuf_new_from_data (buf, GDK_COLORSPACE_RGB, FALSE, 8, size_x, size_y, 3*size_x, free_buf, (gpointer) &buf); area = gtk_image_new_from_pixbuf( pixbuf ); gtk_widget_show(area); return area; } void hf_wrapper_save (gpointer data, gchar *path_n_file) { hf_wrapper_struct *hfw; if (!data) { my_msg(_("There is nothing to save!"),WARNING); return; } hfw = (hf_wrapper_struct *) data; if (hfw->hf_struct) { hf_write(hfw->hf_struct, path_n_file, hfw->gl_preview->cameras); } else my_msg(_("There is nothing to save!"),WARNING); } void hf_stats(gpointer data) { hf_wrapper_struct *hfw; GtkWidget *area; view_struct *vs=NULL; guint HISTOGRAM_WIDTH = 384; guint HISTOGRAM_HEIGHT = 256; static gchar buf[200]; hfw = (hf_wrapper_struct *) data; if (!hfw) return; hf_min_max_avrg(hfw->hf_struct); sprintf(buf,"%s ... MIN: %d; MAX: %d; %s: %d.", *hfw->filename,hfw->hf_struct->min, hfw->hf_struct->max, _("Average"), hfw->hf_struct->avrg); vs = view_struct_new (HISTOGRAM_WIDTH, HISTOGRAM_HEIGHT, NULL, NULL); histogram(hfw->hf_struct, HISTOGRAM_WIDTH, HISTOGRAM_HEIGHT, vs->buf8); my_msg_with_image("HISTOGRAM",buf,vs->area); view_struct_free(vs); } /**********************************************************************************/ // Undo / Redo stack management - think about a separated class in the future void accept_fn (hf_wrapper_struct *hfw) { if (!hfw) return; // printf("********** ACCEPT_CALLB\n"); hf_backup(hfw->hf_struct); commit_pending_record(hfw); if (hfw->hf_options->img->set_fn) (*hfw->hf_options->img->set_fn) ((gpointer)hfw->hf_options->img); // Check if recomputing min-max is necessary or can be done on demand // hf_min_max(hfw->hf_struct); gtk_widget_set_sensitive(GTK_WIDGET(hfw->hf_options->img->accept_wdg),FALSE); hfw->if_calculated = FALSE; } void reset_fn (hf_wrapper_struct *hfw) { // Cancels the current operation by copying the temp buffer (backuped) // into the current (modified) one // printf("********** RESET_CALLB\n"); if (!hfw) return; if (hfw->hf_options->img->set_fn) (*hfw->hf_options->img->set_fn) ((gpointer)hfw->hf_options->img); hf_restore (hfw->hf_struct); gtk_widget_set_sensitive(GTK_WIDGET(hfw->hf_options->img->accept_wdg),FALSE); // Added 2007-01-02 hfw->if_calculated = FALSE; draw_hf(hfw); } void record_action (hf_wrapper_struct *data, gchar *action_lbl) { // Record action in the standard undo / redo stack hf_wrapper_struct *hfw; hfw = (hf_wrapper_struct *) data; // printf("RECORD ACTION: %s\n", _(action_lbl)); if (hfw->type != HFMAIN) // Don't record an HFPEN, for instance return; if (hfw->init_history_flag) (*hfw->init_history_flag) (hfw->window, hfw->to_register_in_history); hfw->last_action = _(action_lbl); } void begin_pending_record (hf_wrapper_struct *hfw, gchar *action_lbl, gpointer commit_fn, gpointer reset_fn) { // Anticipation of an action recording in the standard undo / redo stack // The signal for actually recording the action in the stack would be // emitted by commit_pending_record, after, for instance, a context change // Added 2004-03: initializes the functions required to commit / reset // the changes when we change context // printf("BEGIN_PENDING_RECORD: %s\n",action_lbl); if (hfw->to_register_in_history) (*hfw->to_register_in_history) = TRUE; hfw->last_action = _(action_lbl); set_commit_reset_fns (hfw->hf_options, commit_fn, reset_fn, (gpointer) hfw); } void commit_pending_record (hf_wrapper_struct *data) { // Commits an anticipated action record, in the undo / redo stack hf_wrapper_struct *hfw; hfw = (hf_wrapper_struct *) data; // printf("COMMIT_PENDING_RECORD\n"); if (hfw->to_register_in_history) // Hoping the flag address exists! { // printf("Commit_pending_record - to_register_in_history: %d\n",hfw->to_register_in_history); if (*hfw->to_register_in_history) // Flag on? { // printf("Flag_on YES\n"); if (hfw->init_history_flag) // Hoping the recording function exists! { // printf("FN: %d; window: %d\n",hfw->init_history_flag, hfw->to_register_in_history); (*hfw->init_history_flag) (hfw->window, hfw->to_register_in_history); } } } } // See also these functions in hf_dialog_options: // void hf_commit_or_reset (hf_options_struct *hfo); // void hf_options_dialog_free(hf_options_struct *); /**********************************************************************************/ // Utilities requiring hf_wrapper_struct * void set_watch_cursor (hf_wrapper_struct *hfw) { // For long processes... // We set it on all widgets / windows // The HF area has its own cursor (current->cursor) gdk_window_set_cursor(hfw->area->window, hfw->hf_options->watch_cursor); gdk_window_set_cursor(hfw->window->window, hfw->hf_options->watch_cursor); gdk_window_set_cursor(hfw->hf_options->tools_dialog->window, hfw->hf_options->watch_cursor); hfw->hf_options->current_cursor = hfw->hf_options->watch_cursor; gdk_flush(); } void unset_watch_cursor (hf_wrapper_struct *hfw) { gdk_window_set_cursor(hfw->area->window, hfw->hf_options->default_cursor); gdk_window_set_cursor(hfw->window->window, hfw->hf_options->default_cursor); gdk_window_set_cursor(hfw->hf_options->tools_dialog->window, hfw->hf_options->default_cursor); hfw->hf_options->current_cursor = hfw->hf_options->default_cursor; }