/* draw_hf_dialog.c: dialogs and callbacks for drawing with a hf in a hf * * Copyright (C) 2001 Patrice St-Gelais * patrstg@users.sourceforge.net * www.oricom.ca/patrice.st-gelais * * 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. */ #include "hf_wrapper.h" #include "hf_creation_dialog.h" // For the HF algorithm toolbar #include "dialog_utilities.h" // Icons for merge mode #include "../icons/raise.xpm" #include "../icons/dig.xpm" #include "../icons/smooth.xpm" void pensize_callb (GtkWidget *, gpointer); // Menu for pen size #define NBPENSIZES 6 command_item_struct pensizes[NBPENSIZES] = { "Size", "16", "16", 0, NULL, GDK_PENCIL, pensize_callb,NULL, NULL,TRUE, "Size", "32", "32",0, NULL, GDK_PENCIL, pensize_callb, NULL, NULL,FALSE, "Size", "64", "64",0, NULL, GDK_PENCIL, pensize_callb,NULL, NULL,FALSE, "Size", "128", "128",0, NULL, GDK_PENCIL, pensize_callb,NULL, NULL,FALSE, "Size", "256", "256",0, NULL, GDK_PENCIL, pensize_callb,NULL, NULL,FALSE, "Size", "512", "512",0, NULL, GDK_PENCIL, pensize_callb,NULL, NULL,FALSE }; void pensize_callb (GtkWidget *button, gpointer data) { gchar *lbl; GList *list; hf_wrapper_struct *hfw; gint hf_size; if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) // Nothing to do if we are just unactivating the button return; hfw = (hf_wrapper_struct *) * (hf_wrapper_struct **) data; // printf("HFWrapper adr in SIZE_CALLB: %d; HFWrapper: %d; WIDGET: %d\n",data,hfw, button); // The pen size is the toolbar button label for (list = gtk_container_children(GTK_CONTAINER(GTK_BIN(button)->child)); list != NULL; list = list->next) { if (GTK_IS_LABEL(GTK_OBJECT(list->data))) { gtk_label_get(GTK_LABEL(list->data), &lbl); } } if (!lbl) // Button label not found! hf_size= 16; else hf_size = atoi((char *) lbl); if (hf_size == hfw->hf_struct->max_x) // No change! return; hf_free(hfw->hf_struct); // We adjust the scale to the MAX_PEN_PREVIEW value hfw->display_scale = log2i(MAX(hf_size,MAX_PEN_PREVIEW) / MAX_PEN_PREVIEW); hfw->hf_struct = (hf_struct_type *) hf_new( hf_size, hfw->display_scale); hfw->hf_options->flag_uniform_done = FALSE; hfw->area_size = RIGHT_SHIFT(hfw->hf_struct->max_x,hfw->display_scale); gtk_drawing_area_size(GTK_DRAWING_AREA(hfw->area), RIGHT_SHIFT(hf_size,hfw->display_scale), RIGHT_SHIFT(hf_size,hfw->display_scale)); } void stroke_dot (gpointer hfw_ptr, draw_hf_struct *pen, gint x, gint y) { // Draw one dot of a stroke // printf("STROKE_DOT\n"); // We init the history flag, even if the action is not recorded // (the action is not recorded when the user draws a single dot - // the flag allows recording it before undoing the current HF) gboolean wrap; hf_wrapper_struct *hfw; hf_options_struct *opt; hf_struct_type *phf; hfw = (hf_wrapper_struct *) hfw_ptr; phf = ((hf_wrapper_struct *) pen->hf)->hf_struct; opt = ((hf_wrapper_struct *) pen->hf)->hf_options; wrap = (pen->wrap==TILING_YES) || ((pen->wrap==TILING_AUTO) && hfw->hf_struct->if_tiles); // No need to recalculate a uniform HF after the 1st pass if ((gpointer) opt->current_calculation != (gpointer) uniform) { if ((gpointer) opt->current_calculation == (gpointer) subdiv1) if (opt->subdiv1_options) opt->subdiv1_options->seed = rand(); if ((gpointer) opt->current_calculation == (gpointer) surfadd) if (opt->surfadd_options) opt->surfadd_options->seed = rand(); if ((gpointer) opt->current_calculation == (gpointer) subdiv2) if (opt->subdiv2_options) opt->subdiv2_options->seed = rand(); (*opt->current_calculation) (phf, opt->current_options); filter_apply(phf, opt->fd_struct->current_filter, opt->dist_matrix, opt->fd_struct->revert_filter, opt->fd_struct->filter_level, opt->fd_struct->merge_oper); } else { if (!opt->flag_uniform_done) { (*opt->current_calculation) (phf, opt->current_options); filter_apply(phf, opt->fd_struct->current_filter, opt->dist_matrix, opt->fd_struct->revert_filter, opt->fd_struct->filter_level, opt->fd_struct->merge_oper); opt->flag_uniform_done = TRUE; } } if (pen->merge==SMOOTH_OP) hf_map_convolve(phf, hfw->hf_struct, x,y, wrap, pen->level, hfw->hf_options->gauss_list); else hf_merge(phf, hfw->hf_struct, x,y, pen->merge, wrap, (gfloat) pen->level * (gfloat) pen->level / 10000.0, FALSE); } gboolean draw_hf_line (gpointer hfw_ptr, draw_hf_struct *pen, gint begin_x, gint begin_y, gint *end_x_ptr, gint *end_y_ptr) { // Return TRUE if something has been drawn, FALSE otherwise gint i,end_x,end_y, steps; gdouble spacing, dist, dx, dy; hf_wrapper_struct *hfw; hfw = (hf_wrapper_struct *) hfw_ptr; end_x = *end_x_ptr; end_y = *end_y_ptr; // Draw a line built by repeating a HF if (pen->control_spacing) { // Draw each dot from the last x,y // Won't draw the last (just before the mouse release) spacing = ((gdouble) pen->spacing*((hf_wrapper_struct *) pen->hf)->hf_struct->max_x)/100.0; spacing = (spacing<1.0?1.0:spacing); // Should be more than one pixel // printf("(last_x,last_y): (%d,%d); (x,y): (%d,%d)\n",begin_x,begin_y,end_x,end_y); dist = pow(2.0,hfw->display_scale) * (gdouble) DIST2((gdouble) begin_x, (gdouble) begin_y, (gdouble) end_x, (gdouble) end_y); steps = (gint) floor(dist/spacing); if (!steps) return FALSE; // printf("SPACING: %5.2f; DIST: %5.2f; STEPS: %d; ddx: %5.2f; ddy: %5.2f; \n",spacing, dist, steps, end_x - begin_x,end_y -begin_y); dx = spacing * ((gdouble) (end_x - begin_x)) / dist; dy = spacing * ((gdouble) (end_y - begin_y)) /dist ; // printf("ddx: %5.2f; ddy: %5.2f; \n",dx,dy); for (i=1; i<=steps; i++) { end_x =begin_x + (gint) (i*dx); end_y = begin_y + (gint) (i*dy); stroke_dot (hfw, pen, LEFT_SHIFT(end_x, hfw->display_scale), LEFT_SHIFT(end_y, hfw->display_scale)); draw_hf(hfw); } } // control_spacing test else { // Behavior of Geomorph 0.11 and 0.12 stroke_dot (hfw, pen, LEFT_SHIFT(end_x, hfw->display_scale), LEFT_SHIFT(end_y,hfw->display_scale)); draw_hf(hfw); } // The last dot drawn doesn't fell on the coordinates where the motion motify event was emitted, // so we must adjust these coordinates (*end_x_ptr) = end_x; (*end_y_ptr) = end_y; return TRUE; } draw_hf_struct *hf_pen_new() { draw_hf_struct *d; d = (draw_hf_struct *) malloc(sizeof(draw_hf_struct)); d->merge = ADD; d->wrap = TILING_AUTO; d->level = 35; // equals to 12,25% of the full level // (ratio = pow(level,2)/10000) d->size_toolbar = NULL; d->hf = NULL; d->control_spacing = TRUE; d->spacing = 25; d->adj_spacing = NULL; return d; } void hf_pen_free (draw_hf_struct *pen) { if (pen) { if (pen->hf) { // printf("Freeing pen->hf\n"); hf_wrapper_free(pen->hf, TRUE); } free(pen); } } void instantiate_hf_pen (gpointer hfw, gpointer pen) { // Initializes some pen values after the creation of a HF document // The pen inherits the values from the HF document if (!hfw) return; if (!pen) return; ((hf_wrapper_struct *)pen)->doc_type = ((hf_wrapper_struct *)hfw)->doc_type; ((hf_wrapper_struct *)pen)->all_docs = ((hf_wrapper_struct *)hfw)->all_docs; ((hf_wrapper_struct *)pen)->get_doc_list_from_type = ((hf_wrapper_struct *)hfw)->get_doc_list_from_type; } GtkWidget *draw_hf_dialog_new(GtkWidget *window, GtkTooltips *tooltips, draw_hf_struct *pen, dist_matrix_struct *dist_matrix, gpointer data) { GtkWidget *dialog, *frame, *frame2, *hbox, *hbox2, *vbox, *vbox2, *button, *wdg, *types_toolbar; toolbar_struct *tb; static gboolean dummy_flag; GtkObject *adj; gchar default_pen[4]; // printf("DRAW_DIALOG_NEW\n"); dialog = gtk_vbox_new(FALSE, 0); gtk_widget_show(dialog); frame = frame_new("Pen - height field",DEF_PAD); gtk_container_add(GTK_CONTAINER(frame),dialog); vbox = gtk_vbox_new(FALSE, 0); gtk_widget_show(GTK_WIDGET(vbox)); // Pen size toolbar hbox = gtk_hbox_new(FALSE,DEF_PAD); gtk_widget_show(GTK_WIDGET(hbox)); define_label_in_box("Size", hbox, FALSE, FALSE, 0); // toolbar_struct is a bit overkill for this purpose... tb = toolbar_new(NBPENSIZES, pensizes, tooltips, window, &pen->hf, GTK_ORIENTATION_HORIZONTAL, GTK_TOOLBAR_TEXT, TRUE); gtk_box_pack_start(GTK_BOX(hbox), tb->toolbarwdg, FALSE, FALSE, 0); pen->size_toolbar = tb->toolbarwdg; free(tb); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); // Pen level // level is a number from 0 to 100 // it is supposed to translate in a ratio from 0 to 1 with this rule: // ratio = (level*level)/10 000 (quadratic variation), // so that a 50 level means a 25% ratio. hbox = gtk_hbox_new(FALSE,0); gtk_widget_show(hbox); define_label_in_box("Level",hbox,FALSE, FALSE,0); adj = gtk_adjustment_new (pen->level, 0, 100, 1, 1, 0.01); define_scale_in_box(adj,hbox,0, DEF_PAD*0.5); gtk_signal_connect (GTK_OBJECT (adj), "value_changed", GTK_SIGNAL_FUNC (gint_adj_callb), (gpointer) &pen->level); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, DEF_PAD*0.5); // HF type for pen, merge mode and preview are in the same hbox hbox = gtk_hbox_new(FALSE,DEF_PAD); gtk_widget_show(GTK_WIDGET(hbox)); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); vbox2 = gtk_vbox_new(FALSE,0); gtk_widget_show(vbox2); gtk_box_pack_start(GTK_BOX(hbox),vbox2, TRUE, TRUE, 0); // HF type for pen gtk_box_pack_start(GTK_BOX(vbox2), hf_types_toolbar_new(window, tooltips, &types_toolbar, &pen->hf), FALSE, FALSE, DEF_PAD*0.5); // Adding the effect control (RAISE / DIG / SMOOTH) gtk_box_pack_start(GTK_BOX(vbox2), effect_toolbar(window, (gpointer) &pen->merge), TRUE, TRUE, 0); // Spacing control hbox2 = gtk_hbox_new(FALSE,0); gtk_widget_show(GTK_WIDGET(hbox2)); gtk_box_pack_start(GTK_BOX(vbox2),align_widget(hbox2,0.5,0.5), TRUE, TRUE, 0); define_label_in_box("Spacing", hbox2, FALSE, TRUE, 0); define_label_in_box(" ", hbox2, FALSE, TRUE, 0); button = define_check_button_in_box (" ", hbox2, 0, 0, 0); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), pen->control_spacing); gtk_signal_connect (GTK_OBJECT(button), "toggled", GTK_SIGNAL_FUNC(toggle_check_button_callb), (gpointer) &pen->control_spacing); define_label_in_box("%", hbox2, FALSE, TRUE, 0); adj = gtk_adjustment_new (pen->spacing, 5, 100, 1, 1, 0.01); wdg = define_scale_in_box(adj,hbox2,0, 0); gtk_signal_connect (GTK_OBJECT (adj), "value_changed", GTK_SIGNAL_FUNC (gint_adj_callb), (gpointer) &pen->spacing); gtk_signal_connect (GTK_OBJECT(button), "toggled", GTK_SIGNAL_FUNC(enable_wdg), wdg); if (!pen->control_spacing) gtk_widget_set_sensitive(GTK_WIDGET(wdg),FALSE); // The preview pixmap... frame2 = frame_new("Preview (<=64)",DEF_PAD*0.5); gtk_box_pack_start(GTK_BOX(hbox), frame2, TRUE, TRUE, 0); // Tiling - wrapping control gtk_box_pack_start(GTK_BOX(vbox),tiling_control((gpointer) &pen->wrap), TRUE, TRUE, DEF_PAD); // Main HBOX gtk_box_pack_start(GTK_BOX(dialog), vbox, FALSE, FALSE, 0); // We create the pen, and the preview area at the same time pen->hf = hf_wrapper_new(NULL,NULL,frame2, dialog, hf_options_dialog_new(window, dialog, tooltips, NULL, &pen->hf, NULL,NULL,NULL), &dummy_flag, &dummy_flag, NULL, NULL, NULL, _("HeightField"), NULL, NULL); // hfw->doc_type, hfw->all_docs, hfw->get_doc_list_from_type); // Shareable data: ((hf_wrapper_struct *)pen->hf)->hf_options->dist_matrix = dist_matrix; // Initialize the HF type: ((hf_wrapper_struct *)pen->hf)->type = HFPEN; // Some defaults values for the pencil sprintf(default_pen,"%3d",MIN(512,hf_default_size()>>2)); set_toolbar_button_from_label(pen->size_toolbar,default_pen,TRUE); set_toolbar_button_from_label( ((hf_wrapper_struct *) pen->hf) ->hf_options->fd_struct->filter_toolbar->toolbarwdg, _("Wide"), TRUE); set_toolbar_button_from_label(types_toolbar, "Subdiv1", TRUE); return frame; }