/* * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * This is a plug-in for GIMP. * * Generates images containing vector type drawings. * * Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk * * 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 3 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, see <https://www.gnu.org/licenses/>. */ #include "config.h" #include <stdlib.h> #include <string.h> #include <errno.h> #ifdef HAVE_UNISTD_H #include <unistd.h> #endif #include <glib.h> #ifdef G_OS_WIN32 #include <libgimpbase/gimpwin32-io.h> #endif #include <libgimp/gimp.h> #include <libgimp/gimpui.h> #include "libgimp/stdplugins-intl.h" #include "gfig.h" #include "gfig-style.h" #include "gfig-dialog.h" #include "gfig-arc.h" #include "gfig-bezier.h" #include "gfig-circle.h" #include "gfig-dobject.h" #include "gfig-ellipse.h" #include "gfig-grid.h" #include "gfig-line.h" #include "gfig-poly.h" #include "gfig-preview.h" #include "gfig-rectangle.h" #include "gfig-spiral.h" #include "gfig-star.h" #include "gfig-stock.h" #define SEL_BUTTON_WIDTH 100 #define SEL_BUTTON_HEIGHT 20 #define GRID_TYPE_MENU 1 #define GRID_RENDER_MENU 2 #define PAINT_BGS_MENU 2 #define PAINT_TYPE_MENU 3 #define OBJ_SELECT_GT 1 #define OBJ_SELECT_LT 2 #define OBJ_SELECT_EQ 4 #define UPDATE_DELAY 300 /* From GtkRange in GTK+ 2.22 */ /* Globals */ gint undo_level; /* Last slot filled in -1 = no undo */ GList *undo_table[MAX_UNDO]; /* Values when first invoked */ SelectItVals selvals = { { MIN_GRID + (MAX_GRID - MIN_GRID)/2, /* Gridspacing */ RECT_GRID, /* Default to rectangle type */ FALSE, /* drawgrid */ FALSE, /* snap2grid */ FALSE, /* lockongrid */ TRUE, /* show control points */ 0.0, /* grid_radius_min */ 10.0, /* grid_radius_interval */ 0.0, /* grid_rotation */ 5.0, /* grid_granularity */ 120 /* grid_sectors_desired */ }, FALSE, /* show image */ MIN_UNDO + (MAX_UNDO - MIN_UNDO)/2, /* Max level of undos */ TRUE, /* Show pos updates */ 0.0, /* Brush fade */ 0.0, /* Brush gradient */ 20.0, /* Air brush pressure */ ORIGINAL_LAYER, /* Draw all objects on one layer */ LAYER_TRANS_BG, /* New layers background */ PAINT_BRUSH_TYPE, /* Default to use brushes */ FALSE, /* reverse lines */ TRUE, /* Scale to image when painting */ 1.0, /* Scale to image fp */ BRUSH_BRUSH_TYPE, /* Default to use a brush */ LINE /* Initial object type */ }; selection_option selopt = { ADD, /* type */ FALSE, /* Antia */ FALSE, /* Feather */ 10.0, /* feather radius */ ARC_SEGMENT, /* Arc as a segment */ FILL_PATTERN, /* Fill as pattern */ 100.0, /* Max opacity */ }; /* Should be kept in sync with GfigOpts */ typedef struct { GtkAdjustment *gridspacing; GtkAdjustment *grid_sectors_desired; GtkAdjustment *grid_radius_interval; GtkWidget *gridtypemenu; GtkWidget *drawgrid; GtkWidget *snap2grid; GtkWidget *lockongrid; GtkWidget *showcontrol; } GfigOptWidgets; static GfigOptWidgets gfig_opt_widget = { NULL, NULL, NULL, NULL, NULL, NULL }; static gchar *gfig_path = NULL; static GtkWidget *page_menu_bg; static GtkWidget *tool_options_notebook; static GtkWidget *fill_type_notebook; static guint paint_timeout = 0; static GtkActionGroup *gfig_actions = NULL; static void gfig_response (GtkWidget *widget, gint response_id, gpointer data); static void gfig_load_action_callback (GtkAction *action, gpointer data); static void gfig_save_action_callback (GtkAction *action, gpointer data); static void gfig_list_load_all (const gchar *path); static void gfig_list_free_all (void); static void create_notebook_pages (GtkWidget *notebook); static void select_filltype_callback (GtkWidget *widget); static void gfig_grid_action_callback (GtkAction *action, gpointer data); static void gfig_prefs_action_callback (GtkAction *action, gpointer data); static void toggle_show_image (void); static void gridtype_combo_callback (GtkWidget *widget, gpointer data); static void load_file_chooser_response (GtkFileChooser *chooser, gint response_id, gpointer data); static void save_file_chooser_response (GtkFileChooser *chooser, gint response_id, GFigObj *obj); static void paint_combo_callback (GtkWidget *widget, gpointer data); static void select_button_clicked (gint type); static void select_button_clicked_lt (void); static void select_button_clicked_gt (void); static void select_button_clicked_eq (void); static void raise_selected_obj_to_top (GtkWidget *widget, gpointer data); static void lower_selected_obj_to_bottom (GtkWidget *widget, gpointer data); static void raise_selected_obj (GtkWidget *widget, gpointer data); static void lower_selected_obj (GtkWidget *widget, gpointer data); static void toggle_obj_type (GtkRadioAction *action, GtkRadioAction *current, gpointer data); static GtkUIManager *create_ui_manager (GtkWidget *window); gboolean gfig_dialog (void) { GtkWidget *main_hbox; GtkWidget *vbox; GFigObj *gfig; GimpParasite *parasite; gint newlayer; GtkWidget *menubar; GtkWidget *toolbar; GtkWidget *combo; GtkWidget *frame; gint img_width; gint img_height; GimpImageType img_type; GtkWidget *toggle; GtkWidget *right_vbox; GtkWidget *hbox; GtkUIManager *ui_manager; GtkWidget *empty_label; gchar *path; gimp_ui_init (PLUG_IN_BINARY, TRUE); img_width = gimp_drawable_width (gfig_context->drawable_id); img_height = gimp_drawable_height (gfig_context->drawable_id); img_type = gimp_drawable_type_with_alpha (gfig_context->drawable_id); /* * See if there is a "gfig" parasite. If so, this is a gfig layer, * and we start by clearing it to transparent. * If not, we create a new transparent layer. */ gfig_list = NULL; undo_level = -1; parasite = gimp_item_get_parasite (gfig_context->drawable_id, "gfig"); gfig_context->enable_repaint = FALSE; /* debug */ gfig_context->debug_styles = FALSE; /* initial default style */ gfig_read_gimp_style (&gfig_context->default_style, "Base"); gfig_context->default_style.paint_type = selvals.painttype; if (parasite) { gimp_drawable_fill (gfig_context->drawable_id, GIMP_FILL_TRANSPARENT); gfig_context->using_new_layer = FALSE; gimp_parasite_free (parasite); } else { newlayer = gimp_layer_new (gfig_context->image_id, "GFig", img_width, img_height, img_type, 100.0, gimp_image_get_default_new_layer_mode (gfig_context->image_id)); gimp_drawable_fill (newlayer, GIMP_FILL_TRANSPARENT); gimp_image_insert_layer (gfig_context->image_id, newlayer, -1, -1); gfig_context->drawable_id = newlayer; gfig_context->using_new_layer = TRUE; } gfig_stock_init (); path = gimp_gimprc_query ("gfig-path"); if (path) { gfig_path = g_filename_from_utf8 (path, -1, NULL, NULL, NULL); g_free (path); } else { gchar *gimprc = gimp_personal_rc_file ("gimprc"); gchar *full_path = gimp_config_build_data_path ("gfig"); gchar *esc_path = g_strescape (full_path, NULL); g_free (full_path); g_message (_("No %s in gimprc:\n" "You need to add an entry like\n" "(%s \"%s\")\n" "to your %s file."), "gfig-path", "gfig-path", esc_path, gimp_filename_to_utf8 (gimprc)); g_free (gimprc); g_free (esc_path); } /* Start building the dialog up */ top_level_dlg = gimp_dialog_new (_("Gfig"), PLUG_IN_ROLE, NULL, 0, gimp_standard_help_func, PLUG_IN_PROC, _("_Cancel"), GTK_RESPONSE_CANCEL, _("_Close"), GTK_RESPONSE_OK, NULL); gtk_dialog_set_alternative_button_order (GTK_DIALOG (top_level_dlg), GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1); g_signal_connect (top_level_dlg, "response", G_CALLBACK (gfig_response), top_level_dlg); /* build the menu */ ui_manager = create_ui_manager (top_level_dlg); menubar = gtk_ui_manager_get_widget (ui_manager, "/ui/gfig-menubar"); gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (top_level_dlg))), menubar, FALSE, FALSE, 0); gtk_widget_show (menubar); toolbar = gtk_ui_manager_get_widget (ui_manager, "/ui/gfig-toolbar"); gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_ICONS); gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (top_level_dlg))), toolbar, FALSE, FALSE, 0); gtk_widget_show (toolbar); gfig_dialog_action_set_sensitive ("undo", undo_level >= 0); /* Main box */ main_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); gtk_container_set_border_width (GTK_CONTAINER (main_hbox), 12); gtk_box_pack_end (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (top_level_dlg))), main_hbox, TRUE, TRUE, 0); /* Preview itself */ gtk_box_pack_start (GTK_BOX (main_hbox), make_preview (), FALSE, FALSE, 0); gtk_widget_show (gfig_context->preview); right_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); gtk_box_pack_start (GTK_BOX (main_hbox), right_vbox, FALSE, FALSE, 0); gtk_widget_show (right_vbox); /* Tool options notebook */ frame = gimp_frame_new ( _("Tool Options")); gtk_box_pack_start (GTK_BOX (right_vbox), frame, FALSE, FALSE, 0); gtk_widget_show (frame); tool_options_notebook = gtk_notebook_new (); gtk_container_add (GTK_CONTAINER (frame), tool_options_notebook); gtk_notebook_set_show_tabs (GTK_NOTEBOOK (tool_options_notebook), FALSE); gtk_notebook_set_show_border (GTK_NOTEBOOK (tool_options_notebook), FALSE); gtk_widget_show (tool_options_notebook); create_notebook_pages (tool_options_notebook); /* Stroke frame on right side */ frame = gimp_frame_new (NULL); gtk_box_pack_start (GTK_BOX (right_vbox), frame, FALSE, FALSE, 0); gtk_widget_show (frame); gfig_context->paint_type_toggle = toggle = gtk_check_button_new_with_mnemonic (_("_Stroke")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), selvals.painttype); gtk_frame_set_label_widget (GTK_FRAME (frame), toggle); gtk_widget_show (toggle); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_container_add (GTK_CONTAINER (frame), hbox); gtk_widget_show (hbox); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); gtk_widget_show (vbox); gtk_widget_set_sensitive (vbox, selvals.painttype); g_signal_connect (toggle, "toggled", G_CALLBACK (set_paint_type_callback), vbox); /* foreground color button in Stroke frame*/ gfig_context->fg_color = g_new0 (GimpRGB, 1); gfig_context->fg_color_button = gimp_color_button_new ("Foreground", SEL_BUTTON_WIDTH, SEL_BUTTON_HEIGHT, gfig_context->fg_color, GIMP_COLOR_AREA_SMALL_CHECKS); g_signal_connect (gfig_context->fg_color_button, "color-changed", G_CALLBACK (set_foreground_callback), gfig_context->fg_color); gimp_color_button_set_color (GIMP_COLOR_BUTTON (gfig_context->fg_color_button), &gfig_context->default_style.foreground); gtk_box_pack_start (GTK_BOX (vbox), gfig_context->fg_color_button, FALSE, FALSE, 0); gtk_widget_show (gfig_context->fg_color_button); /* brush selector in Stroke frame */ gfig_context->brush_select = gimp_brush_select_button_new ("Brush", gfig_context->default_style.brush_name, -1.0, -1, -1); g_signal_connect (gfig_context->brush_select, "brush-set", G_CALLBACK (gfig_brush_changed_callback), NULL); gtk_box_pack_start (GTK_BOX (vbox), gfig_context->brush_select, FALSE, FALSE, 0); gtk_widget_show (gfig_context->brush_select); /* Fill frame on right side */ frame = gimp_frame_new (_("Fill")); gtk_box_pack_start (GTK_BOX (right_vbox), frame, FALSE, FALSE, 0); gtk_widget_show (frame); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_container_add (GTK_CONTAINER (frame), hbox); gtk_widget_show (hbox); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); gtk_widget_show (vbox); /* fill style combo box in Style frame */ gfig_context->fillstyle_combo = combo = gimp_int_combo_box_new (_("No fill"), FILL_NONE, _("Color fill"), FILL_COLOR, _("Pattern fill"), FILL_PATTERN, _("Shape gradient"), FILL_GRADIENT, _("Vertical gradient"), FILL_VERTICAL, _("Horizontal gradient"), FILL_HORIZONTAL, NULL); gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo), 0); g_signal_connect (combo, "changed", G_CALLBACK (select_filltype_callback), NULL); gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, FALSE, 0); gtk_widget_show (combo); fill_type_notebook = gtk_notebook_new (); gtk_box_pack_start (GTK_BOX (vbox), fill_type_notebook, FALSE, FALSE, 0); gtk_notebook_set_show_tabs (GTK_NOTEBOOK (fill_type_notebook), FALSE); gtk_notebook_set_show_border (GTK_NOTEBOOK (fill_type_notebook), FALSE); gtk_widget_show (fill_type_notebook); /* An empty page for "No fill" */ empty_label = gtk_label_new (""); gtk_widget_show (empty_label); gtk_notebook_append_page (GTK_NOTEBOOK (fill_type_notebook), empty_label, NULL); /* A page for the fill color button */ gfig_context->bg_color = g_new0 (GimpRGB, 1); gfig_context->bg_color_button = gimp_color_button_new ("Background", SEL_BUTTON_WIDTH, SEL_BUTTON_HEIGHT, gfig_context->bg_color, GIMP_COLOR_AREA_SMALL_CHECKS); g_signal_connect (gfig_context->bg_color_button, "color-changed", G_CALLBACK (set_background_callback), gfig_context->bg_color); gimp_color_button_set_color (GIMP_COLOR_BUTTON (gfig_context->bg_color_button), &gfig_context->default_style.background); gtk_widget_show (gfig_context->bg_color_button); gtk_notebook_append_page (GTK_NOTEBOOK (fill_type_notebook), gfig_context->bg_color_button, NULL); /* A page for the pattern selector */ gfig_context->pattern_select = gimp_pattern_select_button_new ("Pattern", gfig_context->default_style.pattern); g_signal_connect (gfig_context->pattern_select, "pattern-set", G_CALLBACK (gfig_pattern_changed_callback), NULL); gtk_widget_show (gfig_context->pattern_select); gtk_notebook_append_page (GTK_NOTEBOOK (fill_type_notebook), gfig_context->pattern_select, NULL); /* A page for the gradient selector */ gfig_context->gradient_select = gimp_gradient_select_button_new ("Gradient", gfig_context->default_style.gradient); g_signal_connect (gfig_context->gradient_select, "gradient-set", G_CALLBACK (gfig_gradient_changed_callback), NULL); gtk_widget_show (gfig_context->gradient_select); gtk_notebook_append_page (GTK_NOTEBOOK (fill_type_notebook), gfig_context->gradient_select, NULL); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); gtk_box_pack_start (GTK_BOX (right_vbox), vbox, FALSE, FALSE, 0); gtk_widget_show (vbox); /* "show image" checkbutton at bottom of style frame */ toggle = gtk_check_button_new_with_label (_("Show image")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), gfig_context->show_background); gtk_box_pack_end (GTK_BOX (vbox), toggle, FALSE, FALSE, 0); g_signal_connect (toggle, "toggled", G_CALLBACK (gimp_toggle_button_update), &gfig_context->show_background); g_signal_connect_swapped (toggle, "toggled", G_CALLBACK (gtk_widget_queue_draw), gfig_context->preview); gtk_widget_show (toggle); /* "snap to grid" checkbutton at bottom of style frame */ toggle = gtk_check_button_new_with_label (C_("checkbutton", "Snap to grid")); gtk_box_pack_end (GTK_BOX (vbox), toggle, FALSE, FALSE, 0); g_signal_connect (toggle, "toggled", G_CALLBACK (gimp_toggle_button_update), &selvals.opts.snap2grid); gtk_widget_show (toggle); gfig_opt_widget.snap2grid = toggle; /* "show grid" checkbutton at bottom of style frame */ toggle = gtk_check_button_new_with_label (_("Show grid")); gtk_box_pack_end (GTK_BOX (vbox), toggle, FALSE, FALSE, 0); g_signal_connect (toggle, "toggled", G_CALLBACK (gimp_toggle_button_update), &selvals.opts.drawgrid); g_signal_connect (toggle, "toggled", G_CALLBACK (draw_grid_clear), NULL); gtk_widget_show (toggle); gfig_opt_widget.drawgrid = toggle; /* Load saved objects */ gfig_list_load_all (gfig_path); /* Setup initial brush settings */ gfig_context->bdesc.name = gimp_context_get_brush (); mygimp_brush_info (&gfig_context->bdesc.width, &gfig_context->bdesc.height); gtk_widget_show (main_hbox); gtk_widget_show (top_level_dlg); gfig = gfig_load_from_parasite (); if (gfig) { gfig_list_insert (gfig); new_obj_2edit (gfig); gfig_style_set_context_from_style (&gfig_context->default_style); gfig_style_apply (&gfig_context->default_style); } gfig_context->enable_repaint = TRUE; gfig_paint_callback (); gtk_main (); /* FIXME */ return TRUE; } static void gfig_response (GtkWidget *widget, gint response_id, gpointer data) { GFigObj *gfig; switch (response_id) { case GTK_RESPONSE_DELETE_EVENT: case GTK_RESPONSE_CANCEL: /* if we created a new layer, delete it */ if (gfig_context->using_new_layer) { gimp_image_remove_layer (gfig_context->image_id, gfig_context->drawable_id); } else /* revert back to the original figure */ { free_all_objs (gfig_context->current_obj->obj_list); gfig_context->current_obj->obj_list = NULL; gfig = gfig_load_from_parasite (); if (gfig) { gfig_list_insert (gfig); new_obj_2edit (gfig); } gfig_context->enable_repaint = TRUE; gfig_paint_callback (); } break; case GTK_RESPONSE_OK: /* Close button */ gfig_save_as_parasite (); break; default: break; } gtk_widget_destroy (widget); gtk_main_quit (); } void gfig_dialog_action_set_sensitive (const gchar *name, gboolean sensitive) { g_return_if_fail (name != NULL); if (gfig_actions) { GtkAction *action = gtk_action_group_get_action (gfig_actions, name); if (! action) { g_warning ("%s: Unable to set sensitivity of action " "which doesn't exist: %s", G_STRFUNC, name); return; } g_object_set (action, "sensitive", sensitive ? TRUE : FALSE, NULL); } } static gchar * gfig_get_user_writable_dir (void) { if (gfig_path) { GList *list; gchar *dir; list = gimp_path_parse (gfig_path, 256, FALSE, NULL); dir = gimp_path_get_user_writable_dir (list); gimp_path_free (list); return dir; } return g_strdup (gimp_directory ()); } static void gfig_load_action_callback (GtkAction *action, gpointer data) { static GtkWidget *dialog = NULL; if (! dialog) { gchar *dir; dialog = gtk_file_chooser_dialog_new (_("Load Gfig Object Collection"), GTK_WINDOW (data), GTK_FILE_CHOOSER_ACTION_OPEN, _("_Cancel"), GTK_RESPONSE_CANCEL, _("_Open"), GTK_RESPONSE_OK, NULL); gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog), GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); g_object_add_weak_pointer (G_OBJECT (dialog), (gpointer) &dialog); g_signal_connect (dialog, "response", G_CALLBACK (load_file_chooser_response), NULL); dir = gfig_get_user_writable_dir (); if (dir) { gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), dir); g_free (dir); } gtk_widget_show (dialog); } else { gtk_window_present (GTK_WINDOW (dialog)); } } static void gfig_save_action_callback (GtkAction *action, gpointer data) { static GtkWidget *dialog = NULL; if (!dialog) { gchar *dir; dialog = gtk_file_chooser_dialog_new (_("Save Gfig Drawing"), GTK_WINDOW (data), GTK_FILE_CHOOSER_ACTION_SAVE, _("_Cancel"), GTK_RESPONSE_CANCEL, _("_Save"), GTK_RESPONSE_OK, NULL); gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog), GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE); g_object_add_weak_pointer (G_OBJECT (dialog), (gpointer) &dialog); /* FIXME: GFigObj should be a GObject and g_signal_connect_object() * should be used here. */ g_signal_connect (dialog, "response", G_CALLBACK (save_file_chooser_response), gfig_context->current_obj); dir = gfig_get_user_writable_dir (); if (dir) { gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), dir); g_free (dir); } gtk_widget_show (dialog); } else { gtk_window_present (GTK_WINDOW (dialog)); } } static void gfig_close_action_callback (GtkAction *action, gpointer data) { gtk_dialog_response (GTK_DIALOG (data), GTK_RESPONSE_OK); } static void gfig_undo_action_callback (GtkAction *action, gpointer data) { if (undo_level >= 0) { /* Free current objects an reinstate previous */ free_all_objs (gfig_context->current_obj->obj_list); gfig_context->current_obj->obj_list = NULL; tmp_bezier = tmp_line = obj_creating = NULL; gfig_context->current_obj->obj_list = undo_table[undo_level]; undo_level--; /* Update the screen */ gtk_widget_queue_draw (gfig_context->preview); /* And preview */ gfig_context->current_obj->obj_status |= GFIG_MODIFIED; if (gfig_context->current_obj->obj_list) gfig_context->selected_obj = gfig_context->current_obj->obj_list->data; else gfig_context->selected_obj = NULL; } gfig_dialog_action_set_sensitive ("undo", undo_level >= 0); gfig_paint_callback (); } static void gfig_clear_action_callback (GtkWidget *widget, gpointer data) { /* Make sure we can get back - if we have some objects to get back to */ if (!gfig_context->current_obj->obj_list) return; setup_undo (); /* Free all objects */ free_all_objs (gfig_context->current_obj->obj_list); gfig_context->current_obj->obj_list = NULL; gfig_context->selected_obj = NULL; obj_creating = NULL; tmp_line = NULL; tmp_bezier = NULL; gtk_widget_queue_draw (gfig_context->preview); gfig_paint_callback (); } void draw_item (cairo_t *cr, gboolean fill) { cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0); if (fill) { cairo_fill_preserve (cr); } else { cairo_set_line_width (cr, 3.0); cairo_stroke_preserve (cr); } cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0); cairo_set_line_width (cr, 1.0); cairo_stroke (cr); } /* Given a point x, y draw a circle */ void draw_circle (GdkPoint *p, gboolean selected, cairo_t *cr) { if (!selvals.opts.showcontrol) return; cairo_arc (cr, gfig_scale_x (p->x) + .5, gfig_scale_y (p->y) + .5, SQ_SIZE / 2, 0, 2 * G_PI); draw_item (cr, selected); } /* Given a point x, y draw a square around it */ void draw_sqr (GdkPoint *p, gboolean selected, cairo_t *cr) { if (!selvals.opts.showcontrol) return; cairo_rectangle (cr, gfig_scale_x (p->x) + .5 - SQ_SIZE / 2, gfig_scale_y (p->y) + .5 - SQ_SIZE / 2, SQ_SIZE, SQ_SIZE); draw_item (cr, selected); } static void gfig_list_load_all (const gchar *path) { /* Make sure to clear any existing gfigs */ gfig_context->current_obj = NULL; gfig_list_free_all (); if (! gfig_list) { GFigObj *gfig; /* lets have at least one! */ gfig = gfig_new (); gfig->draw_name = g_strdup (_("First Gfig")); gfig_list_insert (gfig); } gfig_context->current_obj = gfig_list->data; /* set to first entry */ } static void gfig_list_free_all (void) { g_list_free_full (gfig_list, (GDestroyNotify) gfig_free); gfig_list = NULL; } static GtkUIManager * create_ui_manager (GtkWidget *window) { static GtkActionEntry actions[] = { { "gfig-menubar", NULL, "GFig Menu" }, { "gfig-file-menu", NULL, "_File" }, { "open", GIMP_ICON_DOCUMENT_OPEN, N_("_Open..."), "<control>O", NULL, G_CALLBACK (gfig_load_action_callback) }, { "save", GIMP_ICON_DOCUMENT_SAVE, N_("_Save..."), "<control>S", NULL, G_CALLBACK (gfig_save_action_callback) }, { "close", GIMP_ICON_CLOSE, N_("_Close"), "<control>C", NULL, G_CALLBACK (gfig_close_action_callback) }, { "gfig-edit-menu", NULL, "_Edit" }, { "undo", GIMP_ICON_EDIT_UNDO, N_("_Undo"), "<control>Z", NULL, G_CALLBACK (gfig_undo_action_callback) }, { "clear", GIMP_ICON_EDIT_CLEAR, N_("_Clear"), NULL, NULL, G_CALLBACK (gfig_clear_action_callback) }, { "grid", GIMP_ICON_GRID, N_("_Grid"), "<control>G", NULL, G_CALLBACK (gfig_grid_action_callback) }, { "prefs", GIMP_ICON_PREFERENCES_SYSTEM, N_("_Preferences..."), "<control>P", NULL, G_CALLBACK (gfig_prefs_action_callback) }, { "raise", GIMP_ICON_GO_UP, N_("_Raise"), "<control>U", N_("Raise selected object"), G_CALLBACK (raise_selected_obj) }, { "lower", GIMP_ICON_GO_DOWN, N_("_Lower"), "<control>D", N_("Lower selected object"), G_CALLBACK (lower_selected_obj) }, { "top", GIMP_ICON_GO_TOP, N_("Raise to _top"), "<control>T", N_("Raise selected object to top"), G_CALLBACK (raise_selected_obj_to_top) }, { "bottom", GIMP_ICON_GO_BOTTOM, N_("Lower to _bottom"), "<control>B", N_("Lower selected object to bottom"), G_CALLBACK (lower_selected_obj_to_bottom) }, { "show_previous", GIMP_ICON_GO_PREVIOUS, N_("_Previous"), "<control>H", N_("Show previous object"), G_CALLBACK (select_button_clicked_lt) }, { "show_next", GIMP_ICON_GO_NEXT, N_("_Next"), "<control>L", N_("Show next object"), G_CALLBACK (select_button_clicked_gt) }, { "show_all", GFIG_STOCK_SHOW_ALL, N_("Show _all"), "<control>A", N_("Show all objects"), G_CALLBACK (select_button_clicked_eq) } }; static GtkRadioActionEntry radio_actions[] = { { "line", GFIG_STOCK_LINE, NULL, "L", N_("Create line"), LINE }, { "rectangle", GFIG_STOCK_RECTANGLE, NULL, "R", N_("Create rectangle"), RECTANGLE }, { "circle", GFIG_STOCK_CIRCLE, NULL, "C", N_("Create circle"), CIRCLE }, { "ellipse", GFIG_STOCK_ELLIPSE, NULL, "E", N_("Create ellipse"), ELLIPSE }, { "arc", GFIG_STOCK_CURVE, NULL, "A", N_("Create arc"), ARC }, { "polygon", GFIG_STOCK_POLYGON, NULL, "P", N_("Create reg polygon"), POLY }, { "star", GFIG_STOCK_STAR, NULL, "S", N_("Create star"), STAR }, { "spiral", GFIG_STOCK_SPIRAL, NULL, "I", N_("Create spiral"), SPIRAL }, { "bezier", GFIG_STOCK_BEZIER, NULL, "B", N_("Create bezier curve. " "Shift + Button ends object creation."), BEZIER }, { "move_obj", GFIG_STOCK_MOVE_OBJECT, NULL, "M", N_("Move an object"), MOVE_OBJ }, { "move_point", GFIG_STOCK_MOVE_POINT, NULL, "V", N_("Move a single point"), MOVE_POINT }, { "copy", GFIG_STOCK_COPY_OBJECT, NULL, "Y", N_("Copy an object"), COPY_OBJ }, { "delete", GFIG_STOCK_DELETE_OBJECT, NULL, "D", N_("Delete an object"), DEL_OBJ }, { "select", GFIG_STOCK_SELECT_OBJECT, NULL, "A", N_("Select an object"), SELECT_OBJ } }; GtkUIManager *ui_manager = gtk_ui_manager_new (); gfig_actions = gtk_action_group_new ("Actions"); gtk_action_group_set_translation_domain (gfig_actions, NULL); gtk_action_group_add_actions (gfig_actions, actions, G_N_ELEMENTS (actions), window); gtk_action_group_add_radio_actions (gfig_actions, radio_actions, G_N_ELEMENTS (radio_actions), LINE, G_CALLBACK (toggle_obj_type), window); gtk_window_add_accel_group (GTK_WINDOW (window), gtk_ui_manager_get_accel_group (ui_manager)); gtk_accel_group_lock (gtk_ui_manager_get_accel_group (ui_manager)); gtk_ui_manager_insert_action_group (ui_manager, gfig_actions, -1); g_object_unref (gfig_actions); gtk_ui_manager_add_ui_from_string (ui_manager, "<ui>" " <menubar name=\"gfig-menubar\">" " <menu name=\"File\" action=\"gfig-file-menu\">" " <menuitem action=\"open\" />" " <menuitem action=\"save\" />" " <menuitem action=\"close\" />" " </menu>" " <menu name=\"Edit\" action=\"gfig-edit-menu\">" " <menuitem action=\"undo\" />" " <menuitem action=\"clear\" />" " <menuitem action=\"grid\" />" " <menuitem action=\"prefs\" />" " </menu>" " </menubar>" "</ui>", -1, NULL); gtk_ui_manager_add_ui_from_string (ui_manager, "<ui>" " <toolbar name=\"gfig-toolbar\">" " <toolitem action=\"line\" />" " <toolitem action=\"rectangle\" />" " <toolitem action=\"circle\" />" " <toolitem action=\"ellipse\" />" " <toolitem action=\"arc\" />" " <toolitem action=\"polygon\" />" " <toolitem action=\"star\" />" " <toolitem action=\"spiral\" />" " <toolitem action=\"bezier\" />" " <toolitem action=\"move_obj\" />" " <toolitem action=\"move_point\" />" " <toolitem action=\"copy\" />" " <toolitem action=\"delete\" />" " <toolitem action=\"select\" />" " <separator />" " <toolitem action=\"raise\" />" " <toolitem action=\"lower\" />" " <toolitem action=\"top\" />" " <toolitem action=\"bottom\" />" " <separator />" " <toolitem action=\"show_previous\" />" " <toolitem action=\"show_next\" />" " <toolitem action=\"show_all\" />" " </toolbar>" "</ui>", -1, NULL); return ui_manager; } static void tool_option_no_option (GtkWidget *notebook) { GtkWidget *label; label = gtk_label_new (_("This tool has no options")); gtk_widget_show (label); gtk_notebook_append_page (GTK_NOTEBOOK (notebook), label, NULL); } static void create_notebook_pages (GtkWidget *notebook) { tool_option_no_option (notebook); /* Line */ tool_option_no_option (notebook); /* Rectangle */ tool_option_no_option (notebook); /* Circle */ tool_option_no_option (notebook); /* Ellipse */ tool_option_no_option (notebook); /* Arc */ tool_options_poly (notebook); /* Polygon */ tool_options_star (notebook); /* Star */ tool_options_spiral (notebook); /* Spiral */ tool_options_bezier (notebook); /* Bezier */ tool_option_no_option (notebook); /* Dummy */ tool_option_no_option (notebook); /* Move Object */ tool_option_no_option (notebook); /* Move Point */ tool_option_no_option (notebook); /* Copy Object */ tool_option_no_option (notebook); /* Delete Object */ } static void raise_selected_obj_to_top (GtkWidget *widget, gpointer data) { if (!gfig_context->selected_obj) return; if (g_list_find (gfig_context->current_obj->obj_list, gfig_context->selected_obj)) { gfig_context->current_obj->obj_list = g_list_remove (gfig_context->current_obj->obj_list, gfig_context->selected_obj); gfig_context->current_obj->obj_list = g_list_append (gfig_context->current_obj->obj_list, gfig_context->selected_obj); } else { g_message ("Trying to raise object that does not exist."); return; } gfig_paint_callback (); } static void lower_selected_obj_to_bottom (GtkWidget *widget, gpointer data) { if (!gfig_context->selected_obj) return; if (g_list_find (gfig_context->current_obj->obj_list, gfig_context->selected_obj)) { gfig_context->current_obj->obj_list = g_list_remove (gfig_context->current_obj->obj_list, gfig_context->selected_obj); gfig_context->current_obj->obj_list = g_list_prepend (gfig_context->current_obj->obj_list, gfig_context->selected_obj); } else { g_message ("Trying to lower object that does not exist."); return; } gfig_paint_callback (); } static void raise_selected_obj (GtkWidget *widget, gpointer data) { if (!gfig_context->selected_obj) return; if (g_list_find (gfig_context->current_obj->obj_list, gfig_context->selected_obj)) { int position; position = g_list_index (gfig_context->current_obj->obj_list, gfig_context->selected_obj); gfig_context->current_obj->obj_list = g_list_remove (gfig_context->current_obj->obj_list, gfig_context->selected_obj); gfig_context->current_obj->obj_list = g_list_insert (gfig_context->current_obj->obj_list, gfig_context->selected_obj, position + 1); } else { g_message ("Trying to raise object that does not exist."); return; } gfig_paint_callback (); } static void lower_selected_obj (GtkWidget *widget, gpointer data) { if (!gfig_context->selected_obj) return; if (g_list_find (gfig_context->current_obj->obj_list, gfig_context->selected_obj)) { int position; position = g_list_index (gfig_context->current_obj->obj_list, gfig_context->selected_obj); gfig_context->current_obj->obj_list = g_list_remove (gfig_context->current_obj->obj_list, gfig_context->selected_obj); gfig_context->current_obj->obj_list = g_list_insert (gfig_context->current_obj->obj_list, gfig_context->selected_obj, MAX (0, position - 1)); } else { g_message ("Trying to lower object that does not exist."); return; } gfig_paint_callback (); } static void select_filltype_callback (GtkWidget *widget) { gint value; gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &value); gtk_notebook_set_current_page (GTK_NOTEBOOK (fill_type_notebook), MIN (value, FILL_GRADIENT)); gfig_context_get_current_style ()->fill_type = (FillType) value; gfig_paint_callback (); } static gboolean gfig_paint_timeout (gpointer data) { gfig_paint_callback (); paint_timeout = 0; return FALSE; } static void gfig_paint_delayed (void) { if (paint_timeout) g_source_remove (paint_timeout); paint_timeout = g_timeout_add (UPDATE_DELAY, gfig_paint_timeout, NULL); } static void gfig_prefs_action_callback (GtkAction *widget, gpointer data) { static GtkWidget *dialog = NULL; if (!dialog) { GtkWidget *main_vbox; GtkWidget *table; GtkWidget *toggle; GtkObject *size_data; GtkWidget *scale; GtkAdjustment *scale_data; dialog = gimp_dialog_new (_("Options"), "gimp-gfig-options", GTK_WIDGET (data), 0, NULL, NULL, _("_Close"), GTK_RESPONSE_CLOSE, NULL); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE); g_object_add_weak_pointer (G_OBJECT (dialog), (gpointer) &dialog); g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL); main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12); gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), main_vbox, TRUE, TRUE, 0); gtk_widget_show (main_vbox); /* Put buttons in */ toggle = gtk_check_button_new_with_label (_("Show position")); gtk_box_pack_start (GTK_BOX (main_vbox), toggle, FALSE, FALSE, 6); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), selvals.showpos); g_signal_connect (toggle, "toggled", G_CALLBACK (gimp_toggle_button_update), &selvals.showpos); g_signal_connect_after (toggle, "toggled", G_CALLBACK (gfig_pos_enable), NULL); gtk_widget_show (toggle); toggle = gtk_check_button_new_with_label (_("Show control points")); gtk_box_pack_start (GTK_BOX (main_vbox), toggle, FALSE, FALSE, 6); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), selvals.opts.showcontrol); g_signal_connect (toggle, "toggled", G_CALLBACK (gimp_toggle_button_update), &selvals.opts.showcontrol); g_signal_connect (toggle, "toggled", G_CALLBACK (toggle_show_image), NULL); gtk_widget_show (toggle); gfig_opt_widget.showcontrol = toggle; g_object_add_weak_pointer (G_OBJECT (gfig_opt_widget.showcontrol), (gpointer) &gfig_opt_widget.showcontrol); toggle = gtk_check_button_new_with_label (_("Antialiasing")); gtk_box_pack_start (GTK_BOX (main_vbox), toggle, FALSE, FALSE, 6); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), selopt.antia); g_signal_connect (toggle, "toggled", G_CALLBACK (gimp_toggle_button_update), &selopt.antia); g_signal_connect (toggle, "toggled", G_CALLBACK (gfig_paint_callback), NULL); gtk_widget_show (toggle); table = gtk_table_new (4, 4, FALSE); gtk_table_set_col_spacings (GTK_TABLE (table), 6); gtk_table_set_row_spacings (GTK_TABLE (table), 6); gtk_box_pack_start (GTK_BOX (main_vbox), table, FALSE, FALSE, 6); gtk_widget_show (table); size_data = gimp_scale_entry_new (GTK_TABLE (table), 0, 0, _("Max undo:"), 100, 50, selvals.maxundo, MIN_UNDO, MAX_UNDO, 1, 2, 0, TRUE, 0, 0, NULL, NULL); g_signal_connect (size_data, "value-changed", G_CALLBACK (gimp_int_adjustment_update), &selvals.maxundo); page_menu_bg = gimp_int_combo_box_new (_("Transparent"), LAYER_TRANS_BG, _("Background"), LAYER_BG_BG, _("Foreground"), LAYER_FG_BG, _("White"), LAYER_WHITE_BG, _("Copy"), LAYER_COPY_BG, NULL); gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (page_menu_bg), selvals.onlayerbg); g_signal_connect (page_menu_bg, "changed", G_CALLBACK (paint_combo_callback), GINT_TO_POINTER (PAINT_BGS_MENU)); gimp_help_set_help_data (page_menu_bg, _("Layer background type. Copy causes the " "previous layer to be copied before the " "draw is performed."), NULL); gimp_table_attach_aligned (GTK_TABLE (table), 0, 1, _("Background:"), 0.0, 0.5, page_menu_bg, 2, FALSE); toggle = gtk_check_button_new_with_label (_("Feather")); gtk_table_attach (GTK_TABLE (table), toggle, 2, 3, 2, 3, GTK_FILL, GTK_FILL, 0, 0); g_signal_connect (toggle, "toggled", G_CALLBACK (gimp_toggle_button_update), &selopt.feather); g_signal_connect (toggle, "toggled", G_CALLBACK (gfig_paint_callback), NULL); gtk_widget_show (toggle); scale_data = (GtkAdjustment *) gtk_adjustment_new (selopt.feather_radius, 0.0, 100.0, 1.0, 1.0, 0.0); scale = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, scale_data); gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP); g_signal_connect (scale_data, "value-changed", G_CALLBACK (gimp_double_adjustment_update), &selopt.feather_radius); g_signal_connect (scale_data, "value-changed", G_CALLBACK (gfig_paint_delayed), NULL); gimp_table_attach_aligned (GTK_TABLE (table), 0, 2, _("Radius:"), 0.0, 1.0, scale, 1, FALSE); gtk_widget_show (dialog); } else { gtk_window_present (GTK_WINDOW (dialog)); } } static void gfig_grid_action_callback (GtkAction *action, gpointer data) { static GtkWidget *dialog = NULL; if (!dialog) { GtkWidget *main_vbox; GtkWidget *hbox; GtkWidget *table; GtkWidget *combo; GtkObject *size_data; GtkObject *sectors_data; GtkObject *radius_data; dialog = gimp_dialog_new (_("Grid"), "gimp-gfig-grid", GTK_WIDGET (data), 0, NULL, NULL, _("_Close"), GTK_RESPONSE_CLOSE, NULL); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE); g_object_add_weak_pointer (G_OBJECT (dialog), (gpointer) &dialog); g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL); main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12); gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), main_vbox, TRUE, TRUE, 0); gtk_widget_show (main_vbox); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0); gtk_widget_show (hbox); table = gtk_table_new (3, 3, FALSE); gtk_table_set_col_spacings (GTK_TABLE (table), 6); gtk_table_set_row_spacings (GTK_TABLE (table), 6); gtk_box_pack_start (GTK_BOX (main_vbox), table, FALSE, FALSE, 0); gtk_widget_show (table); size_data = gimp_scale_entry_new (GTK_TABLE (table), 0, 0, _("Grid spacing:"), 100, 50, selvals.opts.gridspacing, MIN_GRID, MAX_GRID, 1, 10, 0, TRUE, 0, 0, NULL, NULL); g_signal_connect (size_data, "value-changed", G_CALLBACK (gimp_int_adjustment_update), &selvals.opts.gridspacing); g_signal_connect (size_data, "value-changed", G_CALLBACK (draw_grid_clear), NULL); gfig_opt_widget.gridspacing = GTK_ADJUSTMENT (size_data); g_object_add_weak_pointer (G_OBJECT (gfig_opt_widget.gridspacing), (gpointer) &gfig_opt_widget.gridspacing); sectors_data = gimp_scale_entry_new (GTK_TABLE (table), 0, 3, _("Polar grid sectors desired:"), 1, 5, selvals.opts.grid_sectors_desired, 5, 360, 5, 1, 0, TRUE, 0, 0, NULL, NULL); g_signal_connect (sectors_data, "value-changed", G_CALLBACK (gimp_int_adjustment_update), &selvals.opts.grid_sectors_desired); g_signal_connect (sectors_data, "value-changed", G_CALLBACK (draw_grid_clear), NULL); gfig_opt_widget.grid_sectors_desired = GTK_ADJUSTMENT (sectors_data); g_object_add_weak_pointer (G_OBJECT (gfig_opt_widget.grid_sectors_desired), (gpointer) &gfig_opt_widget.grid_sectors_desired); gfig_opt_widget.gridspacing = GTK_ADJUSTMENT (size_data); g_object_add_weak_pointer (G_OBJECT (gfig_opt_widget.gridspacing), (gpointer) &gfig_opt_widget.gridspacing); radius_data = gimp_scale_entry_new (GTK_TABLE (table), 0, 4, _("Polar grid radius interval:"), 1, 5, selvals.opts.grid_radius_interval, 5, 50, 5, 1, 0, TRUE, 0, 0, NULL, NULL); g_signal_connect (radius_data, "value-changed", G_CALLBACK (gimp_double_adjustment_update), &selvals.opts.grid_radius_interval); g_signal_connect (radius_data, "value-changed", G_CALLBACK (draw_grid_clear), NULL); gfig_opt_widget.grid_radius_interval = GTK_ADJUSTMENT (radius_data); g_object_add_weak_pointer (G_OBJECT (gfig_opt_widget.grid_radius_interval), (gpointer) &gfig_opt_widget.grid_radius_interval); combo = gimp_int_combo_box_new (_("Rectangle"), RECT_GRID, _("Polar"), POLAR_GRID, _("Isometric"), ISO_GRID, NULL); gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo), selvals.opts.gridtype); g_signal_connect (combo, "changed", G_CALLBACK (gridtype_combo_callback), GINT_TO_POINTER (GRID_TYPE_MENU)); gimp_table_attach_aligned (GTK_TABLE (table), 0, 1, _("Grid type:"), 0.0, 0.5, combo, 2, FALSE); gfig_opt_widget.gridtypemenu = combo; g_object_add_weak_pointer (G_OBJECT (gfig_opt_widget.gridtypemenu), (gpointer) &gfig_opt_widget.gridtypemenu); combo = gimp_int_combo_box_new (_("Normal"), GFIG_NORMAL_GC, _("Black"), GFIG_BLACK_GC, _("White"), GFIG_WHITE_GC, _("Grey"), GFIG_GREY_GC, _("Darker"), GFIG_DARKER_GC, _("Lighter"), GFIG_LIGHTER_GC, _("Very dark"), GFIG_VERY_DARK_GC, NULL); gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo), grid_gc_type); g_signal_connect (combo, "changed", G_CALLBACK (gridtype_combo_callback), GINT_TO_POINTER (GRID_RENDER_MENU)); gimp_table_attach_aligned (GTK_TABLE (table), 0, 2, _("Grid color:"), 0.0, 0.5, combo, 2, FALSE); gtk_widget_show (dialog); } else { gtk_window_present (GTK_WINDOW (dialog)); } } void options_update (GFigObj *old_obj) { /* Save old vals */ if (selvals.opts.gridspacing != old_obj->opts.gridspacing) { old_obj->opts.gridspacing = selvals.opts.gridspacing; } if (selvals.opts.grid_sectors_desired != old_obj->opts.grid_sectors_desired) { old_obj->opts.grid_sectors_desired = selvals.opts.grid_sectors_desired; } if (selvals.opts.grid_radius_interval != old_obj->opts.grid_radius_interval) { old_obj->opts.grid_radius_interval = selvals.opts.grid_radius_interval; } if (selvals.opts.gridtype != old_obj->opts.gridtype) { old_obj->opts.gridtype = selvals.opts.gridtype; } if (selvals.opts.drawgrid != old_obj->opts.drawgrid) { old_obj->opts.drawgrid = selvals.opts.drawgrid; } if (selvals.opts.snap2grid != old_obj->opts.snap2grid) { old_obj->opts.snap2grid = selvals.opts.snap2grid; } if (selvals.opts.lockongrid != old_obj->opts.lockongrid) { old_obj->opts.lockongrid = selvals.opts.lockongrid; } if (selvals.opts.showcontrol != old_obj->opts.showcontrol) { old_obj->opts.showcontrol = selvals.opts.showcontrol; } /* New vals */ if (selvals.opts.gridspacing != gfig_context->current_obj->opts.gridspacing) { if (gfig_opt_widget.gridspacing) gtk_adjustment_set_value (gfig_opt_widget.gridspacing, gfig_context->current_obj->opts.gridspacing); } if (selvals.opts.grid_sectors_desired != gfig_context->current_obj->opts.grid_sectors_desired) { if (gfig_opt_widget.grid_sectors_desired) gtk_adjustment_set_value (gfig_opt_widget.grid_sectors_desired, gfig_context->current_obj->opts.grid_sectors_desired); } if (selvals.opts.grid_radius_interval != gfig_context->current_obj->opts.grid_radius_interval) { if (gfig_opt_widget.grid_radius_interval) gtk_adjustment_set_value (gfig_opt_widget.grid_radius_interval, gfig_context->current_obj->opts.grid_radius_interval); } if (selvals.opts.gridtype != gfig_context->current_obj->opts.gridtype) { if (gfig_opt_widget.gridtypemenu) gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (gfig_opt_widget.gridtypemenu), gfig_context->current_obj->opts.gridtype); } if (selvals.opts.drawgrid != gfig_context->current_obj->opts.drawgrid) { if (gfig_opt_widget.drawgrid) gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gfig_opt_widget.drawgrid), gfig_context->current_obj->opts.drawgrid); } if (selvals.opts.snap2grid != gfig_context->current_obj->opts.snap2grid) { if (gfig_opt_widget.snap2grid) gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gfig_opt_widget.snap2grid), gfig_context->current_obj->opts.snap2grid); } if (selvals.opts.lockongrid != gfig_context->current_obj->opts.lockongrid) { if (gfig_opt_widget.lockongrid) gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gfig_opt_widget.lockongrid), gfig_context->current_obj->opts.lockongrid); } if (selvals.opts.showcontrol != gfig_context->current_obj->opts.showcontrol) { if (gfig_opt_widget.showcontrol) gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gfig_opt_widget.showcontrol), gfig_context->current_obj->opts.showcontrol); } } static void save_file_chooser_response (GtkFileChooser *chooser, gint response_id, GFigObj *obj) { if (response_id == GTK_RESPONSE_OK) { gchar *filename; filename = gtk_file_chooser_get_filename (chooser); obj->filename = filename; gfig_context->current_obj = obj; gfig_save_callbk (); } gtk_widget_destroy (GTK_WIDGET (chooser)); } static GfigObject * gfig_select_obj_by_number (gint count) { GList *objs; GfigObject *object = NULL; gint k; gfig_context->selected_obj = NULL; for (objs = gfig_context->current_obj->obj_list, k = 0; objs; objs = g_list_next (objs), k++) { if (k == obj_show_single) { object = objs->data; gfig_context->selected_obj = object; gfig_style_set_context_from_style (&object->style); break; } } return object; } static void select_button_clicked (gint type) { gint count = 0; if (gfig_context->current_obj) { count = g_list_length (gfig_context->current_obj->obj_list); } switch (type) { case OBJ_SELECT_LT: obj_show_single--; if (obj_show_single < 0) obj_show_single = count - 1; break; case OBJ_SELECT_GT: obj_show_single++; if (obj_show_single >= count) obj_show_single = 0; break; case OBJ_SELECT_EQ: obj_show_single = -1; /* Reset to show all */ break; default: break; } if (obj_show_single >= 0) gfig_select_obj_by_number (obj_show_single); draw_grid_clear (); gfig_paint_callback (); } static void select_button_clicked_lt (void) { select_button_clicked (OBJ_SELECT_LT); } static void select_button_clicked_gt (void) { select_button_clicked (OBJ_SELECT_GT); } static void select_button_clicked_eq (void) { select_button_clicked (OBJ_SELECT_EQ); } /* Special case for now - options on poly/star/spiral button */ GtkWidget * num_sides_widget (const gchar *d_title, gint *num_sides, gint *which_way, gint adj_min, gint adj_max) { GtkWidget *table; GtkObject *size_data; table = gtk_table_new (which_way ? 2 : 1, 3, FALSE); gtk_table_set_col_spacings (GTK_TABLE (table), 6); gtk_table_set_row_spacings (GTK_TABLE (table), 6); gtk_container_set_border_width (GTK_CONTAINER (table), 12); gtk_widget_show (table); size_data = gimp_scale_entry_new (GTK_TABLE (table), 0, 0, _("Sides:"), 0, 0, *num_sides, adj_min, adj_max, 1, 10, 0, TRUE, 0, 0, NULL, NULL); g_signal_connect (size_data, "value-changed", G_CALLBACK (gimp_int_adjustment_update), num_sides); if (which_way) { GtkWidget *combo = gimp_int_combo_box_new (_("Right"), 0, _("Left"), 1, NULL); gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo), *which_way); g_signal_connect (combo, "changed", G_CALLBACK (gimp_int_combo_box_get_active), which_way); gimp_table_attach_aligned (GTK_TABLE (table), 0, 1, _("Orientation:"), 0.0, 0.5, combo, 1, FALSE); } return table; } void gfig_paint (BrushType brush_type, gint32 drawable_ID, gint seg_count, gdouble line_pnts[]) { switch (brush_type) { case BRUSH_BRUSH_TYPE: gimp_paintbrush (drawable_ID, selvals.brushfade, seg_count, line_pnts, GIMP_PAINT_CONSTANT, selvals.brushgradient); break; case BRUSH_PENCIL_TYPE: gimp_pencil (drawable_ID, seg_count, line_pnts); break; case BRUSH_AIRBRUSH_TYPE: gimp_airbrush (drawable_ID, selvals.airbrushpressure, seg_count, line_pnts); break; case BRUSH_PATTERN_TYPE: gimp_clone (drawable_ID, drawable_ID, GIMP_CLONE_PATTERN, 0.0, 0.0, seg_count, line_pnts); break; } } static void paint_combo_callback (GtkWidget *widget, gpointer data) { gint mtype = GPOINTER_TO_INT (data); gint value; gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &value); switch (mtype) { case PAINT_BGS_MENU: selvals.onlayerbg = (LayersBGType) value; break; default: g_return_if_reached (); break; } gfig_paint_callback (); } static void gridtype_combo_callback (GtkWidget *widget, gpointer data) { gint mtype = GPOINTER_TO_INT (data); gint value; gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &value); switch (mtype) { case GRID_TYPE_MENU: selvals.opts.gridtype = value; break; case GRID_RENDER_MENU: grid_gc_type = value; break; default: g_return_if_reached (); break; } draw_grid_clear (); } /* * The edit gfig name attributes dialog * Modified from Gimp source - layer edit. */ typedef struct _GfigListOptions { GtkWidget *query_box; GtkWidget *name_entry; GtkWidget *list_entry; GFigObj *obj; gboolean created; } GfigListOptions; static void load_file_chooser_response (GtkFileChooser *chooser, gint response_id, gpointer data) { if (response_id == GTK_RESPONSE_OK) { gchar *filename; GFigObj *gfig; GFigObj *current_saved; filename = gtk_file_chooser_get_filename (chooser); if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) { /* Hack - current object MUST be NULL to prevent setup_undo () * from kicking in. */ current_saved = gfig_context->current_obj; gfig_context->current_obj = NULL; gfig = gfig_load (filename, filename); gfig_context->current_obj = current_saved; if (gfig) { /* Read only ?*/ if (access (filename, W_OK)) gfig->obj_status |= GFIG_READONLY; gfig_list_insert (gfig); new_obj_2edit (gfig); } } g_free (filename); } gtk_widget_destroy (GTK_WIDGET (chooser)); gfig_paint_callback (); } void paint_layer_fill (gdouble x1, gdouble y1, gdouble x2, gdouble y2) { GimpFillType fill_type = GIMP_FILL_FOREGROUND; Style *current_style; current_style = gfig_context_get_current_style (); gimp_context_push (); gimp_context_set_paint_mode (GIMP_LAYER_MODE_NORMAL_LEGACY); gimp_context_set_opacity (100.0); gimp_context_set_gradient_repeat_mode (GIMP_REPEAT_NONE); gimp_context_set_gradient_reverse (FALSE); switch (current_style->fill_type) { case FILL_NONE: return; case FILL_COLOR: fill_type = GIMP_FILL_BACKGROUND; break; case FILL_PATTERN: fill_type = GIMP_FILL_PATTERN; break; case FILL_GRADIENT: gimp_drawable_edit_gradient_fill (gfig_context->drawable_id, GIMP_GRADIENT_SHAPEBURST_DIMPLED, 0.0, /* offset */ FALSE, /* supersampling */ 0, /* max_depth */ 0.0, /* threshold */ FALSE, /* dither */ 0.0, 0.0, /* (x1, y1) - ignored */ 0.0, 0.0); /* (x2, y2) - ignored */ return; case FILL_VERTICAL: gimp_drawable_edit_gradient_fill (gfig_context->drawable_id, GIMP_GRADIENT_LINEAR, 0.0, FALSE, 0, 0.0, FALSE, x1, y1, x1, y2); return; case FILL_HORIZONTAL: gimp_drawable_edit_gradient_fill (gfig_context->drawable_id, GIMP_GRADIENT_LINEAR, 0.0, FALSE, 0, 0.0, FALSE, x1, y1, x2, y1); return; } gimp_context_set_opacity (current_style->fill_opacity); gimp_drawable_edit_fill (gfig_context->drawable_id, fill_type); gimp_context_pop (); } void gfig_paint_callback (void) { GList *objs; gint ccount = 0; GfigObject *object; if (!gfig_context->enable_repaint || !gfig_context->current_obj) return; objs = gfig_context->current_obj->obj_list; gimp_drawable_fill (gfig_context->drawable_id, GIMP_FILL_TRANSPARENT); while (objs) { if (ccount == obj_show_single || obj_show_single == -1) { FillType saved_filltype; object = objs->data; gfig_style_apply (&object->style); saved_filltype = gfig_context_get_current_style ()->fill_type; gfig_context_get_current_style ()->fill_type = object->style.fill_type; object->class->paintfunc (object); gfig_context_get_current_style ()->fill_type = saved_filltype; } objs = g_list_next (objs); ccount++; } gimp_displays_flush (); if (back_pixbuf) { g_object_unref (back_pixbuf); back_pixbuf = NULL; } gtk_widget_queue_draw (gfig_context->preview); } /* Draw the grid on the screen */ void draw_grid_clear (void) { /* wipe slate and start again */ gtk_widget_queue_draw (gfig_context->preview); } static void toggle_show_image (void) { /* wipe slate and start again */ draw_grid_clear (); } static void toggle_obj_type (GtkRadioAction *action, GtkRadioAction *current, gpointer data) { static GdkCursor *p_cursors[DEL_OBJ + 1]; GdkCursorType ctype = GDK_LAST_CURSOR; DobjType new_type; new_type = gtk_radio_action_get_current_value (action); if (selvals.otype != new_type) { /* Mem leak */ obj_creating = NULL; tmp_line = NULL; tmp_bezier = NULL; if (new_type < MOVE_OBJ) /* Eeeeek */ { obj_show_single = -1; /* Cancel select preview */ } /* Update draw areas */ gtk_widget_queue_draw (gfig_context->preview); } selvals.otype = new_type; gtk_notebook_set_current_page (GTK_NOTEBOOK (tool_options_notebook), new_type - 1); switch (selvals.otype) { case LINE: case RECTANGLE: case CIRCLE: case ELLIPSE: case ARC: case POLY: case STAR: case SPIRAL: case BEZIER: default: ctype = GDK_CROSSHAIR; break; case MOVE_OBJ: case MOVE_POINT: case COPY_OBJ: case MOVE_COPY_OBJ: ctype = GDK_DIAMOND_CROSS; break; case DEL_OBJ: ctype = GDK_PIRATE; break; } if (!p_cursors[selvals.otype]) { GdkDisplay *display = gtk_widget_get_display (gfig_context->preview); p_cursors[selvals.otype] = gdk_cursor_new_for_display (display, ctype); } gdk_window_set_cursor (gtk_widget_get_window (gfig_context->preview), p_cursors[selvals.otype]); } /* This could belong in a separate file ... but makes it easier to lump into * one when compiling the plugin. */ /* Given a number of float co-ords adjust for scaling back to org size */ /* Size is number of PAIRS of points */ /* FP + int variants */ static void scale_to_orginal_x (gdouble *list) { *list *= scale_x_factor; } gint gfig_scale_x (gint x) { if (!selvals.scaletoimage) return (gint) (x * (1 / scale_x_factor)); else return x; } static void scale_to_orginal_y (gdouble *list) { *list *= scale_y_factor; } gint gfig_scale_y (gint y) { if (!selvals.scaletoimage) return (gint) (y * (1 / scale_y_factor)); else return y; } /* Pairs x followed by y */ void scale_to_original_xy (gdouble *list, gint size) { gint i; for (i = 0; i < size * 2; i += 2) { scale_to_orginal_x (&list[i]); scale_to_orginal_y (&list[i + 1]); } } /* Pairs x followed by y */ void scale_to_xy (gdouble *list, gint size) { gint i; for (i = 0; i < size * 2; i += 2) { list[i] *= (org_scale_x_factor / scale_x_factor); list[i + 1] *= (org_scale_y_factor / scale_y_factor); } } void gfig_draw_arc (gint x, gint y, gint width, gint height, gint angle1, gint angle2, cairo_t *cr) { cairo_save (cr); cairo_translate (cr, gfig_scale_x (x), gfig_scale_y (y)); cairo_scale (cr, gfig_scale_x (width), gfig_scale_y (height)); if (angle1 < angle2) cairo_arc (cr, 0., 0., 1., angle1 * G_PI / 180, angle2 * G_PI / 180); else cairo_arc_negative (cr, 0., 0., 1., angle1 * G_PI / 180, angle2 * G_PI / 180); cairo_restore (cr); draw_item (cr, FALSE); } void gfig_draw_line (gint x0, gint y0, gint x1, gint y1, cairo_t *cr) { cairo_move_to (cr, gfig_scale_x (x0) + .5, gfig_scale_y (y0) + .5); cairo_line_to (cr, gfig_scale_x (x1) + .5, gfig_scale_y (y1) + .5); draw_item (cr, FALSE); }