mirror of https://github.com/GNOME/gimp.git
11282 lines
260 KiB
C
11282 lines
260 KiB
C
/*
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
*
|
|
* This is a plug-in for the 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 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.
|
|
*
|
|
* Some of this code was taken from the Whirl plug-in
|
|
* which was copyrighted by Federico Mena Quintero (as below).
|
|
*
|
|
* Whirl plug-in --- distort an image into a whirlpool
|
|
* Copyright (C) 1997 Federico Mena Quintero
|
|
*
|
|
*/
|
|
|
|
/* Change log:
|
|
* 0.9 First public release.
|
|
* 0.95 Second release.
|
|
*
|
|
* 0.96 Added patch from Rob Saunders that introduces a isometric type grid
|
|
* Removed use of gtk_idle* stuff on position update. Not required.
|
|
*
|
|
* 1.0 Fixed to work with the new gtk+-0.99.4 (tooltips stuff has changed).
|
|
*
|
|
* 1.1 Fixed crashes when objects not fully defined
|
|
*
|
|
* 1.2 More bug fixes and prevent gtk warning when creating new figs
|
|
*
|
|
* 1.3 Portability fixes and fixed bug reports 257 and 258 from and 81 & 101 & 133
|
|
* http://www.wilberworks.com/bugs.cgi
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <glib.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
#include <string.h>
|
|
#ifdef HAVE_DIRENT_H
|
|
#include <dirent.h>
|
|
#endif
|
|
#include <ctype.h>
|
|
#include <gtk/gtk.h>
|
|
|
|
#ifdef G_OS_WIN32
|
|
# include <io.h>
|
|
# ifndef W_OK
|
|
# define W_OK 2
|
|
# endif
|
|
# ifndef S_ISDIR
|
|
# define S_ISDIR(m) ((m) & _S_IFDIR)
|
|
# endif
|
|
# ifndef S_ISREG
|
|
# define S_ISREG(m) ((m) & _S_IFREG)
|
|
# endif
|
|
#endif
|
|
|
|
#if defined (GTK_CHECK_VERSION) && GTK_CHECK_VERSION (1,3,0)
|
|
#define gdk_root_parent (*gdk_parent_root)
|
|
#endif
|
|
|
|
#ifdef G_OS_WIN32
|
|
extern __declspec(dllimport) void *gdk_root_parent;
|
|
#else
|
|
extern void * gdk_root_parent;
|
|
#endif
|
|
|
|
#include <libgimp/gimp.h>
|
|
#include <libgimp/gimpui.h>
|
|
|
|
#include "libgimp/stdplugins-intl.h"
|
|
|
|
#include "pix_data.h"
|
|
|
|
/***** Magic numbers *****/
|
|
|
|
#define PREVIEW_SIZE 400
|
|
#define SCALE_WIDTH 120
|
|
|
|
#define MIN_GRID 10
|
|
#define MAX_GRID 50
|
|
#define MAX_UNDO 10
|
|
#define MIN_UNDO 1
|
|
#define MAX_LOAD_LINE 256
|
|
#define SMALL_PREVIEW_SZ 48
|
|
#define BRUSH_PREVIEW_SZ 32
|
|
#define GFIG_HEADER "GFIG Version 0.1\n"
|
|
|
|
#define PREVIEW_MASK GDK_EXPOSURE_MASK | \
|
|
GDK_MOTION_NOTIFY | \
|
|
GDK_POINTER_MOTION_MASK | \
|
|
GDK_BUTTON_PRESS_MASK | \
|
|
GDK_BUTTON_RELEASE_MASK | \
|
|
GDK_BUTTON_MOTION_MASK | \
|
|
GDK_KEY_PRESS_MASK | \
|
|
GDK_KEY_RELEASE_MASK
|
|
|
|
static GimpDrawable *gfig_select_drawable;
|
|
static GtkWidget *gfig_preview;
|
|
static GtkWidget *pic_preview;
|
|
static GtkWidget *gfig_gtk_list;
|
|
static gint gfig_preview_exp_id;
|
|
static gint32 gfig_image;
|
|
static gint32 gfig_drawable;
|
|
static GtkWidget *brush_page_pw;
|
|
static GtkWidget *brush_sel_button;
|
|
|
|
static gint tile_width, tile_height;
|
|
static gint img_width, img_height, img_bpp, real_img_bpp;
|
|
|
|
static void query (void);
|
|
static void run (gchar *name,
|
|
gint nparams,
|
|
GimpParam *param,
|
|
gint *nreturn_vals,
|
|
GimpParam **return_vals);
|
|
|
|
static gint gfig_dialog (void);
|
|
static void gfig_ok_callback (GtkWidget *widget,
|
|
gpointer data);
|
|
static void gfig_paint_callback (GtkWidget *widget,
|
|
gpointer data);
|
|
static void gfig_clear_callback (GtkWidget *widget,
|
|
gpointer data);
|
|
static void gfig_undo_callback (GtkWidget *widget,
|
|
gpointer data);
|
|
static gint gfig_preview_expose (GtkWidget *widget,
|
|
GdkEvent *event);
|
|
static gint pic_preview_expose (GtkWidget *widget,
|
|
GdkEvent *event);
|
|
static gint gfig_preview_events (GtkWidget *widget,
|
|
GdkEvent *event);
|
|
static gint gfig_brush_preview_events (GtkWidget *widget,
|
|
GdkEvent *event);
|
|
|
|
static void gfig_scale_update_scale (GtkAdjustment *adjustment,
|
|
gdouble *value);
|
|
|
|
static void gfig_scale2img_update (GtkWidget *widget,
|
|
gpointer data);
|
|
|
|
static gint gfig_scale_x (gint x);
|
|
static gint gfig_scale_y (gint y);
|
|
static gint gfig_invscale_x (gint x);
|
|
static gint gfig_invscale_y (gint y);
|
|
static GdkGC * gfig_get_grid_gc (GtkWidget *widget,
|
|
gint gctype);
|
|
static void gfig_pos_enable (GtkWidget *widget,
|
|
gpointer data);
|
|
|
|
static gint list_button_press (GtkWidget *widget,
|
|
GdkEventButton *event,
|
|
gpointer data);
|
|
|
|
static void rescan_button_callback (GtkWidget *widget,
|
|
gpointer data);
|
|
static void load_button_callback (GtkWidget *widget,
|
|
gpointer data);
|
|
static void save_button_callback (GtkWidget *widget,
|
|
gpointer data);
|
|
static void new_button_callback (GtkWidget *widget,
|
|
gpointer data);
|
|
static void gfig_do_delete_gfig_callback (GtkWidget *widget,
|
|
gboolean delete,
|
|
gpointer data);
|
|
static void gfig_delete_gfig_callback (GtkWidget *widget,
|
|
gpointer data);
|
|
static void edit_button_callback (GtkWidget *widget,
|
|
gpointer data);
|
|
static void merge_button_callback (GtkWidget *widget,
|
|
gpointer data);
|
|
static void about_button_callback (GtkWidget *widget,
|
|
gpointer data);
|
|
static void reload_button_callback (GtkWidget *widget,
|
|
gpointer data);
|
|
|
|
static void do_gfig (void);
|
|
static void dialog_update_preview (void);
|
|
|
|
static void draw_grid_clear (GtkWidget *widget,
|
|
gpointer data);
|
|
static void toggle_show_image (GtkWidget *widget,
|
|
gpointer data);
|
|
static void toggle_tooltips (GtkWidget *widget,
|
|
gpointer data);
|
|
static void toggle_obj_type (GtkWidget *widget,
|
|
gpointer data);
|
|
static void draw_grid (GtkWidget *widget,
|
|
gpointer data);
|
|
|
|
static void gfig_new_gc (void);
|
|
static void find_grid_pos (GdkPoint *p,
|
|
GdkPoint *gp,
|
|
guint state);
|
|
|
|
static void brush_list_button_callback (GtkWidget *widget,
|
|
gpointer data);
|
|
static gint calculate_point_to_line_distance (GdkPoint *p,
|
|
GdkPoint *A,
|
|
GdkPoint *B,
|
|
GdkPoint *I);
|
|
|
|
GimpPlugInInfo PLUG_IN_INFO =
|
|
{
|
|
NULL, /* init_proc */
|
|
NULL, /* quit_proc */
|
|
query, /* query_proc */
|
|
run, /* run_proc */
|
|
};
|
|
|
|
/* The types of an object */
|
|
/* Also includes actions that can be performed on objects */
|
|
|
|
typedef enum
|
|
{
|
|
LINE,
|
|
CIRCLE,
|
|
ELLIPSE,
|
|
ARC,
|
|
POLY,
|
|
STAR,
|
|
SPIRAL,
|
|
BEZIER,
|
|
MOVE_OBJ,
|
|
MOVE_POINT,
|
|
COPY_OBJ,
|
|
MOVE_COPY_OBJ,
|
|
DEL_OBJ,
|
|
NULL_OPER
|
|
} DobjType;
|
|
|
|
typedef enum
|
|
{
|
|
RECT_GRID = 0,
|
|
POLAR_GRID,
|
|
ISO_GRID
|
|
} GridType;
|
|
|
|
typedef enum
|
|
{
|
|
ORIGINAL_LAYER = 0,
|
|
SINGLE_LAYER,
|
|
MULTI_LAYER
|
|
} DrawonLayers;
|
|
|
|
typedef enum
|
|
{
|
|
LAYER_TRANS_BG = 0,
|
|
LAYER_BG_BG,
|
|
LAYER_FG_BG,
|
|
LAYER_WHITE_BG,
|
|
LAYER_COPY_BG
|
|
} LayersBGType;
|
|
|
|
typedef enum
|
|
{
|
|
PAINT_BRUSH_TYPE = 0,
|
|
PAINT_SELECTION_TYPE,
|
|
PAINT_SELECTION_FILL_TYPE
|
|
} PaintType;
|
|
|
|
typedef enum
|
|
{
|
|
BRUSH_BRUSH_TYPE = 0,
|
|
BRUSH_PENCIL_TYPE,
|
|
BRUSH_AIRBRUSH_TYPE,
|
|
BRUSH_PATTERN_TYPE
|
|
} BrushType;
|
|
|
|
|
|
#define GRID_TYPE_MENU 1
|
|
#define GRID_RENDER_MENU 2
|
|
#define GRID_IGNORE 0
|
|
#define GRID_HIGHTLIGHT 1
|
|
#define GRID_RESTORE 2
|
|
|
|
#define GFIG_BLACK_GC -2
|
|
#define GFIG_WHITE_GC -3
|
|
#define GFIG_GREY_GC -4
|
|
|
|
#define PAINT_LAYERS_MENU 1
|
|
#define PAINT_BGS_MENU 2
|
|
#define PAINT_TYPE_MENU 3
|
|
|
|
#define SELECT_TYPE_MENU 1
|
|
#define SELECT_ARCTYPE_MENU 2
|
|
#define SELECT_TYPE_MENU_FILL 3
|
|
#define SELECT_TYPE_MENU_WHEN 4
|
|
|
|
#define OBJ_SELECT_GT 1
|
|
#define OBJ_SELECT_LT 2
|
|
#define OBJ_SELECT_EQ 4
|
|
|
|
|
|
typedef struct
|
|
{
|
|
gint gridspacing;
|
|
GridType gridtype;
|
|
gint drawgrid;
|
|
gint snap2grid;
|
|
gint lockongrid;
|
|
gint showcontrol;
|
|
} GfigOpts;
|
|
|
|
/* Must keep in step with the above */
|
|
typedef struct
|
|
{
|
|
void *gridspacing;
|
|
GtkWidget *gridtypemenu;
|
|
GtkWidget *drawgrid;
|
|
GtkWidget *snap2grid;
|
|
GtkWidget *lockongrid;
|
|
GtkWidget *showcontrol;
|
|
} GfigOptWidgets;
|
|
|
|
static GfigOptWidgets gfig_opt_widget;
|
|
|
|
typedef struct
|
|
{
|
|
GfigOpts opts;
|
|
gint showimage;
|
|
gint maxundo;
|
|
gint showpos;
|
|
gdouble brushfade;
|
|
gdouble brushgradient;
|
|
gdouble airbrushpressure;
|
|
gint showtooltips;
|
|
DrawonLayers onlayers;
|
|
LayersBGType onlayerbg;
|
|
PaintType painttype;
|
|
gint reverselines;
|
|
gint scaletoimage;
|
|
gdouble scaletoimagefp;
|
|
gint approxcircles;
|
|
BrushType brshtype;
|
|
DobjType otype;
|
|
} SelectItVals;
|
|
|
|
/* Values when first invoked */
|
|
static SelectItVals selvals =
|
|
{
|
|
{
|
|
MIN_GRID + (MAX_GRID - MIN_GRID)/2, /* Gridspacing */
|
|
RECT_GRID, /* Default to rectangle type */
|
|
0, /* drawgrid */
|
|
0, /* snap2grid */
|
|
0, /* lockongrid */
|
|
1, /* show control points */
|
|
},
|
|
0, /* show image */
|
|
MIN_UNDO + (MAX_UNDO - MIN_UNDO)/2, /* Max level of undos */
|
|
FALSE, /* Show pos updates */
|
|
0.0, /* Brush fade */
|
|
0.0, /* Brush gradient */
|
|
20.0, /* Air bursh pressure */
|
|
TRUE, /* show Tool tips */
|
|
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 */
|
|
FALSE, /* Approx circles by drawing lines */
|
|
BRUSH_BRUSH_TYPE, /* Default to use a brush */
|
|
LINE /* Initial object type */
|
|
};
|
|
|
|
typedef enum
|
|
{
|
|
ADD=0,
|
|
SUBTRACT=1,
|
|
REPLACE=2,
|
|
INTERSECT=3
|
|
} SelectionType;
|
|
|
|
|
|
typedef enum
|
|
{
|
|
ARC_SEGMENT,
|
|
ARC_SECTOR
|
|
} ArcType;
|
|
|
|
typedef enum
|
|
{
|
|
FILL_FOREGROUND = 0,
|
|
FILL_BACKGROUND = 1,
|
|
FILL_PATTERN = 2
|
|
} FillType;
|
|
|
|
typedef enum
|
|
{
|
|
FILL_EACH = 0,
|
|
FILL_AFTER
|
|
} FillWhen;
|
|
|
|
struct selection_option
|
|
{
|
|
SelectionType type; /* ADD etc .. */
|
|
gint antia; /* Boolean for Antia */
|
|
gint feather; /* Feather it ? */
|
|
gdouble feather_radius; /* Radius to feather */
|
|
ArcType as_pie; /* Arc type selection segment/sector */
|
|
FillType fill_type; /* Fill type for selection */
|
|
FillWhen fill_when; /* Fill on each selection or after all? */
|
|
gdouble fill_opacity; /* You can guess this one */
|
|
} selopt =
|
|
{
|
|
ADD, /* type */
|
|
FALSE, /* Antia */
|
|
FALSE, /* Feather */
|
|
10.0, /* feather radius */
|
|
ARC_SEGMENT, /* Arc as a segment */
|
|
FILL_PATTERN, /* Fill as pattern */
|
|
FILL_EACH, /* Fill after each selection */
|
|
100.0, /* Max opacity */
|
|
};
|
|
|
|
|
|
static GList *gfig_path_list = NULL;
|
|
static GList *gfig_list = NULL;
|
|
static gint line_no;
|
|
|
|
static gint poly_num_sides = 3; /* Default to three sided object */
|
|
static gint star_num_sides = 3; /* Default to three sided object */
|
|
static gint spiral_num_turns = 4; /* Default to 4 turns */
|
|
static gint spiral_toggle = 0; /* 0 = clockwise -1 = anti-clockwise */
|
|
static gint bezier_closed = 0; /* Closed curve 0 = false 1 = true */
|
|
static gint bezier_line_frame = 0; /* Show frame = false 1 = true */
|
|
|
|
static gint obj_show_single = -1; /* -1 all >= 0 object number */
|
|
|
|
/* Structures etc for the objects */
|
|
/* Points used to draw the object */
|
|
|
|
typedef struct DobjPoints
|
|
{
|
|
struct DobjPoints * next;
|
|
GdkPoint pnt;
|
|
gint found_me;
|
|
} DobjPoints;
|
|
|
|
|
|
struct Dobject; /* fwd declaration for DobjFunc */
|
|
|
|
typedef void (*DobjFunc) (struct Dobject *);
|
|
typedef struct Dobject *(*DobjGenFunc) (struct Dobject *);
|
|
typedef struct Dobject *(*DobjLoadFunc) (FILE *);
|
|
typedef void (*DobjSaveFunc) (struct Dobject *, FILE *);
|
|
|
|
/* The object itself */
|
|
typedef struct Dobject
|
|
{
|
|
DobjType type; /* What is the type? */
|
|
gpointer type_data; /* Extra data needed by the object */
|
|
DobjPoints *points; /* List of points */
|
|
DobjFunc drawfunc; /* How do I draw myself */
|
|
DobjFunc paintfunc; /* Draw me on canvas */
|
|
DobjGenFunc copyfunc; /* copy */
|
|
DobjLoadFunc loadfunc; /* Load this type of object */
|
|
DobjSaveFunc savefunc; /* Save me out */
|
|
} Dobject;
|
|
|
|
|
|
static Dobject *obj_creating; /* Object we are creating */
|
|
static Dobject *tmp_line; /* Needed when drawing lines */
|
|
static Dobject *tmp_bezier; /* Neeed when drawing bezier curves */
|
|
|
|
typedef struct DAllObjs
|
|
{
|
|
struct DAllObjs *next;
|
|
Dobject *obj; /* Object on list */
|
|
} DAllObjs;
|
|
|
|
/* States of the object */
|
|
#define GFIG_OK 0x0
|
|
#define GFIG_MODIFIED 0x1
|
|
#define GFIG_READONLY 0x2
|
|
|
|
typedef struct DFigObj
|
|
{
|
|
gchar *name; /* Trailing name of file */
|
|
gchar *filename; /* Filename itself */
|
|
gchar *draw_name;/* Name of the drawing */
|
|
gfloat version; /* Version number of data file */
|
|
GfigOpts opts; /* Options enforced when fig saved */
|
|
DAllObjs *obj_list; /* Objects that make up this list */
|
|
gint obj_status; /* See above for possible values */
|
|
GtkWidget *list_item;
|
|
GtkWidget *label_widget;
|
|
GtkWidget *pixmap_widget;
|
|
} GFigObj;
|
|
|
|
|
|
typedef struct BrushDesc
|
|
{
|
|
gchar *bname; /* name of the brush */
|
|
gint32 width; /* Width of brush */
|
|
gint32 height; /* Height of brush */
|
|
guchar *pv_buf; /* Buffer where brush placed */
|
|
gint16 x_off;
|
|
gint16 y_off;
|
|
gint bpp; /* Depth - should ALWAYS be the same for all BrushDesc */
|
|
} BrushDesc;
|
|
|
|
static GFigObj *current_obj;
|
|
static Dobject *operation_obj;
|
|
static GdkPoint *move_all_pnt; /* Point moving all from */
|
|
static GFigObj *pic_obj;
|
|
static DAllObjs *undo_table[MAX_UNDO];
|
|
static gint need_to_scale;
|
|
static gint32 brush_image_ID = -1;
|
|
|
|
static GtkWidget *undo_widget;
|
|
static GtkWidget *gfig_op_menu; /* Popup menu in the list box */
|
|
static GtkWidget *delete_frame_to_freeze; /* Top preview frame window */
|
|
static GtkWidget *fade_out_hbox; /* Fade out widget in brush page */
|
|
static GtkWidget *gradient_hbox; /* Gradient widget in brush page */
|
|
static GtkWidget *pressure_hbox; /* Pressure widget in brush page */
|
|
static GtkWidget *pencil_hbox; /* Dummy widget in brush page */
|
|
static GtkWidget *pos_label; /* XY pos marker */
|
|
static GtkWidget *brush_page_widget; /* Widget for the brush part of notebook */
|
|
static GtkWidget *select_page_widget; /* Widget for the selection part
|
|
* of notebook */
|
|
|
|
static gint undo_water_mark = -1; /* Last slot filled in -1 = no undo */
|
|
static gint drawing_pic = FALSE; /* If true drawing to the small preview */
|
|
static GtkWidget *status_label_dname;
|
|
static GtkWidget *status_label_fname;
|
|
static GFigObj *gfig_obj_for_menu; /* More static data -
|
|
* need to know which object was selected*/
|
|
static GtkWidget *save_menu_item;
|
|
static GtkWidget *save_button;
|
|
|
|
|
|
/* Don't up just like BIGGG source files? */
|
|
|
|
static void object_start (GdkPoint *pnt, gint);
|
|
static void object_operation (GdkPoint *pnt, gint);
|
|
static void object_operation_start (GdkPoint *pnt, gint shift_down);
|
|
static void object_operation_end (GdkPoint *pnt, gint);
|
|
static void object_end (GdkPoint *pnt, gint shift_down);
|
|
static void object_update (GdkPoint * pnt);
|
|
static void add_to_all_obj (GFigObj * fobj, Dobject *obj);
|
|
static void d_delete_dobjpoints (DobjPoints *);
|
|
static Dobject * d_new_line (gint x, gint y);
|
|
static Dobject * d_new_circle (gint x, gint y);
|
|
static DAllObjs * copy_all_objs (DAllObjs *objs);
|
|
static void setup_undo (void);
|
|
static void d_pnt_add_line (Dobject *obj,
|
|
gint x, gint y, gint pos);
|
|
static GFigObj * gfig_load (gchar *filename, gchar *name);
|
|
static void free_all_objs (DAllObjs * objs);
|
|
static void draw_objects (DAllObjs *objs, gint show_single);
|
|
static Dobject * d_load_line (FILE *from);
|
|
static Dobject * d_load_circle (FILE *from);
|
|
static gchar * get_line (gchar *buf, gint s,
|
|
FILE * from, gint init);
|
|
static GFigObj * gfig_new (void);
|
|
static void clear_undo (void);
|
|
static void list_button_update (GFigObj *obj);
|
|
static void prepend_to_all_obj (GFigObj *fobj, DAllObjs *nobj);
|
|
static void gfig_update_stat_labels (void);
|
|
static void gfig_obj_modified (GFigObj *obj, gint stat_type);
|
|
static void gfig_op_menu_create (GtkWidget *window);
|
|
static void gridtype_menu_callback (GtkWidget *widget, gpointer data);
|
|
static void draw_one_obj (Dobject * obj);
|
|
static void d_save_poly (Dobject * obj, FILE *to);
|
|
static Dobject * d_load_poly (FILE *from);
|
|
static void d_draw_poly (Dobject *obj);
|
|
static void d_paint_poly (Dobject *obj);
|
|
static Dobject * d_copy_poly (Dobject * obj);
|
|
static Dobject * d_new_poly (gint x, gint y);
|
|
static void d_update_poly (GdkPoint *pnt);
|
|
static void d_poly_start (GdkPoint *pnt, gint shift_down);
|
|
static void d_poly_end (GdkPoint *pnt, gint shift_down);
|
|
static void d_save_star (Dobject * obj, FILE *to);
|
|
static Dobject * d_load_star (FILE *from);
|
|
static void d_draw_star (Dobject *obj);
|
|
static void d_paint_star (Dobject *obj);
|
|
static Dobject * d_copy_star (Dobject * obj);
|
|
static Dobject * d_new_star (gint x, gint y);
|
|
static void d_update_star (GdkPoint *pnt);
|
|
static void d_star_start (GdkPoint *pnt, gint shift_down);
|
|
static void d_star_end (GdkPoint *pnt, gint shift_down);
|
|
static Dobject * d_load_spiral (FILE *from);
|
|
static void d_draw_spiral (Dobject *obj);
|
|
static void d_paint_spiral (Dobject *obj);
|
|
static Dobject * d_copy_spiral (Dobject * obj);
|
|
static Dobject * d_new_spiral (gint x, gint y);
|
|
static void d_update_spiral (GdkPoint *pnt);
|
|
static void d_spiral_start (GdkPoint *pnt, gint shift_down);
|
|
static void d_spiral_end (GdkPoint *pnt, gint shift_down);
|
|
|
|
static Dobject * d_load_bezier (FILE *from);
|
|
static void d_draw_bezier (Dobject *obj);
|
|
static void d_paint_bezier (Dobject *obj);
|
|
static Dobject * d_copy_bezier (Dobject * obj);
|
|
static Dobject * d_new_bezier (gint x, gint y);
|
|
static void d_update_bezier (GdkPoint *pnt);
|
|
static void d_bezier_start (GdkPoint *pnt, gint shift_down);
|
|
static void d_bezier_end (GdkPoint *pnt, gint shift_down);
|
|
|
|
static void new_obj_2edit (GFigObj *obj);
|
|
static Dobject * d_new_ellipse (gint x, gint y);
|
|
static Dobject * d_load_ellipse (FILE *from);
|
|
static Dobject * d_new_arc (gint x, gint y);
|
|
static Dobject * d_load_arc (FILE *from);
|
|
static gint load_options (GFigObj *gfig, FILE *fp);
|
|
static gint gfig_obj_counts (DAllObjs * objs);
|
|
|
|
static void gfig_brush_fill_preview_xy (GtkWidget *pw, gint x , gint y);
|
|
|
|
|
|
/* globals */
|
|
|
|
static gint gfig_run;
|
|
static GdkGC *gfig_gc;
|
|
static GdkGC *grid_hightlight_drawgc;
|
|
static gint grid_gc_type = GTK_STATE_NORMAL;
|
|
static guchar *pv_cache = NULL;
|
|
static guchar preview_row[PREVIEW_SIZE*4];
|
|
|
|
/* Stuff for the preview bit */
|
|
static gint sel_x1, sel_y1, sel_x2, sel_y2;
|
|
static gint sel_width, sel_height;
|
|
static gint preview_width, preview_height;
|
|
static gint has_alpha;
|
|
static gdouble scale_x_factor, scale_y_factor;
|
|
static gdouble org_scale_x_factor, org_scale_y_factor;
|
|
|
|
MAIN ()
|
|
|
|
static void
|
|
query (void)
|
|
{
|
|
static GimpParamDef args[] =
|
|
{
|
|
{ GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
|
|
{ GIMP_PDB_IMAGE, "image", "Input image (unused)" },
|
|
{ GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
|
|
{ GIMP_PDB_INT32, "dummy", "dummy" }
|
|
};
|
|
static gint nargs = sizeof (args) / sizeof (args[0]);
|
|
|
|
gimp_install_procedure ("plug_in_gfig",
|
|
"Create Geometrical shapes with the Gimp",
|
|
"More here later",
|
|
"Andy Thomas",
|
|
"Andy Thomas",
|
|
"1997",
|
|
N_("<Image>/Filters/Render/Gfig..."),
|
|
"RGB*, GRAY*",
|
|
GIMP_PLUGIN,
|
|
nargs, 0,
|
|
args, NULL);
|
|
}
|
|
|
|
static void
|
|
run (gchar *name,
|
|
gint nparams,
|
|
GimpParam *param,
|
|
gint *nreturn_vals,
|
|
GimpParam **return_vals)
|
|
{
|
|
GimpParam * values = g_new (GimpParam, 1);
|
|
GimpDrawable *drawable;
|
|
GimpRunModeType run_mode;
|
|
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
|
|
|
|
gint pwidth, pheight;
|
|
|
|
/*kill (getpid (), 19);*/
|
|
|
|
run_mode = param[0].data.d_int32;
|
|
gfig_image = param[1].data.d_image;
|
|
gfig_drawable = param[2].data.d_drawable;
|
|
|
|
*nreturn_vals = 1;
|
|
*return_vals = values;
|
|
|
|
values[0].type = GIMP_PDB_STATUS;
|
|
values[0].data.d_status = status;
|
|
|
|
gfig_select_drawable = drawable =
|
|
gimp_drawable_get (param[2].data.d_drawable);
|
|
|
|
tile_width = gimp_tile_width ();
|
|
tile_height = gimp_tile_height ();
|
|
|
|
/* TMP Hack - clear any selections */
|
|
gimp_selection_clear (gfig_image);
|
|
|
|
gimp_drawable_mask_bounds (drawable->id, &sel_x1, &sel_y1, &sel_x2, &sel_y2);
|
|
|
|
sel_width = sel_x2 - sel_x1;
|
|
sel_height = sel_y2 - sel_y1;
|
|
|
|
/* Calculate preview size */
|
|
|
|
if (sel_width > sel_height)
|
|
{
|
|
pwidth = MIN (sel_width, PREVIEW_SIZE);
|
|
pheight = sel_height * pwidth / sel_width;
|
|
}
|
|
else
|
|
{
|
|
pheight = MIN (sel_height, PREVIEW_SIZE);
|
|
pwidth = sel_width * pheight / sel_height;
|
|
}
|
|
|
|
preview_width = MAX (pwidth, 2); /* Min size is 2 */
|
|
preview_height = MAX (pheight, 2);
|
|
|
|
org_scale_x_factor = scale_x_factor =
|
|
(gdouble) sel_width / (gdouble) preview_width;
|
|
org_scale_y_factor = scale_y_factor =
|
|
(gdouble) sel_height / (gdouble) preview_height;
|
|
|
|
switch (run_mode)
|
|
{
|
|
case GIMP_RUN_INTERACTIVE:
|
|
/*gimp_get_data ("plug_in_gfig", &selvals);*/
|
|
INIT_I18N_UI ();
|
|
if (!gfig_dialog ())
|
|
{
|
|
gimp_drawable_detach (drawable);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case GIMP_RUN_NONINTERACTIVE:
|
|
status = GIMP_PDB_CALLING_ERROR;
|
|
break;
|
|
|
|
case GIMP_RUN_WITH_LAST_VALS:
|
|
/*gimp_get_data ("plug_in_gfig", &selvals);*/
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (gimp_drawable_is_rgb (drawable->id) ||
|
|
gimp_drawable_is_gray (drawable->id))
|
|
{
|
|
/* Set the tile cache size */
|
|
gimp_tile_cache_ntiles ((drawable->width + gimp_tile_width () - 1) /
|
|
gimp_tile_width ());
|
|
|
|
do_gfig ();
|
|
|
|
if (run_mode != GIMP_RUN_NONINTERACTIVE)
|
|
gimp_displays_flush ();
|
|
|
|
#if 0
|
|
if (run_mode == GIMP_RUN_INTERACTIVE)
|
|
gimp_set_data ("plug_in_gfig", &selvals, sizeof (SelectItVals));
|
|
#endif /* 0 */
|
|
}
|
|
else
|
|
{
|
|
status = GIMP_PDB_EXECUTION_ERROR;
|
|
}
|
|
|
|
values[0].data.d_status = status;
|
|
|
|
gimp_drawable_detach (drawable);
|
|
}
|
|
|
|
/*
|
|
* Query gimprc for gfig-path, and parse it.
|
|
*/
|
|
|
|
static void
|
|
plug_in_parse_gfig_path (void)
|
|
{
|
|
GList *fail_list = NULL;
|
|
GList *list;
|
|
gchar *gfig_path;
|
|
|
|
if (gfig_path_list)
|
|
gimp_path_free (gfig_path_list);
|
|
|
|
gfig_path_list = NULL;
|
|
|
|
gfig_path = gimp_gimprc_query ("gfig-path");
|
|
|
|
if (!gfig_path)
|
|
{
|
|
gchar *gimprc = gimp_personal_rc_file ("gimprc");
|
|
gchar *path = gimp_strescape
|
|
("${gimp_dir}" G_DIR_SEPARATOR_S "gfig"
|
|
G_SEARCHPATH_SEPARATOR_S
|
|
"${gimp_data_dir}" G_DIR_SEPARATOR_S "gfig",
|
|
NULL);
|
|
g_message (_("No gfig-path in gimprc:\n"
|
|
"You need to add an entry like\n"
|
|
"(gfig-path \"%s\")\n"
|
|
"to your %s file."),
|
|
path, gimprc);
|
|
g_free (gimprc);
|
|
g_free (path);
|
|
return;
|
|
}
|
|
|
|
gfig_path_list = gimp_path_parse (gfig_path, 16, TRUE, &fail_list);
|
|
|
|
g_free (gfig_path);
|
|
|
|
if (fail_list)
|
|
{
|
|
GString *err =
|
|
g_string_new (_("gfig-path misconfigured - "
|
|
"the following directories were not found"));
|
|
|
|
for (list = fail_list; list; list = g_list_next (list))
|
|
{
|
|
g_string_append_c (err, '\n');
|
|
g_string_append (err, (gchar *) list->data);
|
|
}
|
|
|
|
g_message (err->str);
|
|
|
|
g_string_free (err, TRUE);
|
|
gimp_path_free (fail_list);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
Translate SPACE to "\\040", etc.
|
|
Taken from gflare plugin
|
|
*/
|
|
static void
|
|
gfig_name_encode (gchar *dest,
|
|
gchar *src)
|
|
{
|
|
gint cnt = MAX_LOAD_LINE - 1;
|
|
|
|
while (*src && cnt--)
|
|
{
|
|
if (iscntrl (*src) || isspace (*src) || *src == '\\')
|
|
{
|
|
sprintf (dest, "\\%03o", *src++);
|
|
dest += 4;
|
|
}
|
|
else
|
|
*dest++ = *src++;
|
|
}
|
|
*dest = '\0';
|
|
}
|
|
|
|
/*
|
|
Translate "\\040" to SPACE, etc.
|
|
*/
|
|
static void
|
|
gfig_name_decode (gchar *dest,
|
|
gchar *src)
|
|
{
|
|
gint cnt = MAX_LOAD_LINE - 1;
|
|
gint tmp;
|
|
|
|
while (*src && cnt--)
|
|
{
|
|
if (*src == '\\' && *(src+1) && *(src+2) && *(src+3))
|
|
{
|
|
sscanf (src+1, "%3o", &tmp);
|
|
*dest++ = tmp;
|
|
src += 4;
|
|
}
|
|
else
|
|
*dest++ = *src++;
|
|
}
|
|
*dest = '\0';
|
|
}
|
|
|
|
|
|
/*
|
|
* Load all gfig, which are founded in gfig-path-list, into gfig_list.
|
|
* gfig-path-list must be initialized first. (plug_in_parse_gfig_path ())
|
|
* based on code from Gflare.
|
|
*/
|
|
|
|
static gint
|
|
gfig_list_pos (GFigObj *gfig)
|
|
{
|
|
GFigObj *g;
|
|
gint n;
|
|
GList *tmp;
|
|
|
|
n = 0;
|
|
|
|
for (tmp = gfig_list; tmp; tmp = g_list_next (tmp))
|
|
{
|
|
g = tmp->data;
|
|
|
|
if (strcmp (gfig->draw_name, g->draw_name) <= 0)
|
|
break;
|
|
|
|
n++;
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
static gint
|
|
gfig_list_insert (GFigObj *gfig)
|
|
{
|
|
gint n;
|
|
|
|
/*
|
|
* Insert gfigs in alphabetical order
|
|
*/
|
|
|
|
n = gfig_list_pos (gfig);
|
|
|
|
gfig_list = g_list_insert (gfig_list, gfig, n);
|
|
|
|
#ifdef DEBUG
|
|
printf ("gfig_list_insert %s => %d\n", gfig->draw_name, n);
|
|
#endif /* DEBUG */
|
|
|
|
return n;
|
|
}
|
|
|
|
static void
|
|
gfig_free (GFigObj *gfig)
|
|
{
|
|
g_assert (gfig != NULL);
|
|
|
|
if (gfig->obj_list)
|
|
free_all_objs (gfig->obj_list);
|
|
|
|
g_free (gfig->name);
|
|
g_free (gfig->filename);
|
|
g_free (gfig->draw_name);
|
|
|
|
g_free (gfig);
|
|
}
|
|
|
|
static void
|
|
gfig_free_everything (GFigObj *gfig)
|
|
{
|
|
g_assert (gfig != NULL);
|
|
|
|
if (gfig->filename)
|
|
{
|
|
#ifdef DEBUG
|
|
printf ("Removing filename '%s'\n", gfig->filename);
|
|
#endif /* DEBUG */
|
|
remove (gfig->filename);
|
|
}
|
|
|
|
gfig_free (gfig);
|
|
}
|
|
|
|
static void
|
|
gfig_list_free_all (void)
|
|
{
|
|
GList *list;
|
|
GFigObj *gfig;
|
|
|
|
for (list = gfig_list; list; list = g_list_next (list))
|
|
{
|
|
gfig = (GFigObj *) list->data;
|
|
gfig_free (gfig);
|
|
}
|
|
|
|
g_list_free (gfig_list);
|
|
gfig_list = NULL;
|
|
}
|
|
|
|
|
|
static void
|
|
gfig_list_load_all (GList *plist)
|
|
{
|
|
GFigObj *gfig;
|
|
GList *list;
|
|
gchar *path;
|
|
gchar *filename;
|
|
DIR *dir;
|
|
struct dirent *dir_ent;
|
|
struct stat filestat;
|
|
gint err;
|
|
|
|
/* Make sure to clear any existing gfigs */
|
|
current_obj = pic_obj = NULL;
|
|
gfig_list_free_all ();
|
|
|
|
list = plist;
|
|
while (list)
|
|
{
|
|
path = list->data;
|
|
list = list->next;
|
|
|
|
/* Open directory */
|
|
dir = opendir (path);
|
|
|
|
if (!dir)
|
|
g_warning ("Error reading GFig directory \"%s\"", path);
|
|
else
|
|
{
|
|
while ((dir_ent = readdir (dir)))
|
|
{
|
|
filename = g_malloc (strlen (path) + strlen (dir_ent->d_name) + 1);
|
|
|
|
sprintf (filename, "%s%s", path, dir_ent->d_name);
|
|
|
|
/* Check the file and see that it is not a sub-directory */
|
|
err = stat (filename, &filestat);
|
|
|
|
if (!err && S_ISREG (filestat.st_mode))
|
|
{
|
|
gfig = gfig_load (filename, dir_ent->d_name);
|
|
|
|
if (gfig)
|
|
{
|
|
/* Read only ?*/
|
|
if (access (filename, W_OK))
|
|
gfig->obj_status |= GFIG_READONLY;
|
|
|
|
gfig_list_insert (gfig);
|
|
}
|
|
}
|
|
|
|
g_free (filename);
|
|
} /* while */
|
|
closedir (dir);
|
|
} /* else */
|
|
}
|
|
|
|
if (!gfig_list)
|
|
{
|
|
/* lets have at least one! */
|
|
gfig = gfig_new ();
|
|
gfig->draw_name = g_strdup (_("First Gfig"));
|
|
gfig_list_insert (gfig);
|
|
}
|
|
pic_obj = current_obj = gfig_list->data; /* set to first entry */
|
|
|
|
}
|
|
|
|
static GFigObj *
|
|
gfig_new (void)
|
|
{
|
|
GFigObj * new;
|
|
|
|
new = g_new0 (GFigObj, 1);
|
|
|
|
return new;
|
|
}
|
|
|
|
static void
|
|
gfig_load_objs (GFigObj *gfig,
|
|
gint load_count,
|
|
FILE *fp)
|
|
{
|
|
Dobject *obj;
|
|
gchar load_buf[MAX_LOAD_LINE];
|
|
|
|
/* Loading object */
|
|
/*kill (getpid (), 19);*/
|
|
/* Read first line */
|
|
while (load_count-- > 0)
|
|
{
|
|
obj = NULL;
|
|
get_line (load_buf, MAX_LOAD_LINE, fp, 0);
|
|
|
|
if (!strcmp (load_buf, "<LINE>"))
|
|
{
|
|
obj = d_load_line (fp);
|
|
}
|
|
else if (!strcmp (load_buf, "<CIRCLE>"))
|
|
{
|
|
obj = d_load_circle (fp);
|
|
}
|
|
else if (!strcmp (load_buf, "<ELLIPSE>"))
|
|
{
|
|
obj = d_load_ellipse (fp);
|
|
}
|
|
else if (!strcmp (load_buf, "<POLY>"))
|
|
{
|
|
obj = d_load_poly (fp);
|
|
}
|
|
else if (!strcmp (load_buf, "<STAR>"))
|
|
{
|
|
obj = d_load_star (fp);
|
|
}
|
|
else if (!strcmp (load_buf, "<SPIRAL>"))
|
|
{
|
|
obj = d_load_spiral (fp);
|
|
}
|
|
else if (!strcmp (load_buf, "<BEZIER>"))
|
|
{
|
|
obj = d_load_bezier (fp);
|
|
}
|
|
else if (!strcmp (load_buf, "<ARC>"))
|
|
{
|
|
obj = d_load_arc (fp);
|
|
}
|
|
else
|
|
{
|
|
g_warning ("Unknown obj type file %s line %d\n", gfig->filename, line_no);
|
|
}
|
|
|
|
if (obj)
|
|
{
|
|
add_to_all_obj (gfig, obj);
|
|
}
|
|
}
|
|
}
|
|
|
|
static GFigObj *
|
|
gfig_load (gchar *filename, gchar *name)
|
|
{
|
|
GFigObj * gfig;
|
|
FILE * fp;
|
|
gchar load_buf[MAX_LOAD_LINE];
|
|
gchar str_buf[MAX_LOAD_LINE];
|
|
gint chk_count;
|
|
gint load_count = 0;
|
|
|
|
g_assert (filename != NULL);
|
|
|
|
#ifdef DEBUG
|
|
printf ("Loading %s (%s)\n", filename, name);
|
|
#endif /* DEBUG */
|
|
|
|
fp = fopen (filename, "r");
|
|
if (!fp)
|
|
{
|
|
g_warning ("Error opening: %s", filename);
|
|
return NULL;
|
|
}
|
|
|
|
gfig = gfig_new ();
|
|
|
|
gfig->name = g_strdup (name);
|
|
gfig->filename = g_strdup (filename);
|
|
|
|
|
|
/* HEADER
|
|
* draw_name
|
|
* version
|
|
* obj_list
|
|
*/
|
|
|
|
get_line (load_buf, MAX_LOAD_LINE, fp, 1);
|
|
|
|
if (strncmp (GFIG_HEADER, load_buf, strlen (load_buf)))
|
|
{
|
|
g_message ("File '%s' is not a gfig file", gfig->filename);
|
|
return NULL;
|
|
}
|
|
|
|
get_line (load_buf, MAX_LOAD_LINE, fp, 0);
|
|
sscanf (load_buf, "Name: %100s", str_buf);
|
|
gfig_name_decode (load_buf, str_buf);
|
|
gfig->draw_name = g_strdup (load_buf);
|
|
|
|
get_line (load_buf, MAX_LOAD_LINE, fp, 0);
|
|
sscanf (load_buf, "Version: %f", &gfig->version);
|
|
|
|
get_line (load_buf, MAX_LOAD_LINE, fp, 0);
|
|
sscanf (load_buf, "ObjCount: %d", &load_count);
|
|
|
|
if (load_options (gfig, fp))
|
|
{
|
|
g_message ("File '%s' corrupt file - Line %d Option section incorrect",
|
|
filename, line_no);
|
|
return NULL;
|
|
}
|
|
|
|
/*return (NULL);*/
|
|
|
|
gfig_load_objs (gfig, load_count, fp);
|
|
|
|
/* Check count ? */
|
|
|
|
chk_count = gfig_obj_counts (gfig->obj_list);
|
|
|
|
if (chk_count != load_count)
|
|
{
|
|
g_message ("File '%s' corrupt file - Line %d Object count to small",
|
|
filename, line_no);
|
|
return NULL;
|
|
}
|
|
|
|
fclose (fp);
|
|
|
|
if (!pic_obj)
|
|
pic_obj = gfig;
|
|
|
|
gfig->obj_status = GFIG_OK;
|
|
|
|
return gfig;
|
|
}
|
|
|
|
static void
|
|
save_options (FILE *fp)
|
|
{
|
|
/* Save options */
|
|
fprintf (fp, "<OPTIONS>\n");
|
|
fprintf (fp, "GridSpacing: %d\n", selvals.opts.gridspacing);
|
|
if (selvals.opts.gridtype == RECT_GRID)
|
|
fprintf (fp, "GridType: RECT_GRID\n");
|
|
else if (selvals.opts.gridtype == POLAR_GRID)
|
|
fprintf (fp, "GridType: POLAR_GRID\n");
|
|
else if (selvals.opts.gridtype == ISO_GRID)
|
|
fprintf (fp, "GridType: ISO_GRID\n");
|
|
else fprintf (fp, "GridType: RECT_GRID\n"); /* If in doubt, default to RECT_GRID */
|
|
fprintf (fp, "DrawGrid: %s\n", (selvals.opts.drawgrid)?"TRUE":"FALSE");
|
|
fprintf (fp, "Snap2Grid: %s\n", (selvals.opts.snap2grid)?"TRUE":"FALSE");
|
|
fprintf (fp, "LockOnGrid: %s\n", (selvals.opts.lockongrid)?"TRUE":"FALSE");
|
|
/* fprintf (fp, "ShowImage: %s\n", (selvals.opts.showimage)?"TRUE":"FALSE");*/
|
|
fprintf (fp, "ShowControl: %s\n", (selvals.opts.showcontrol)?"TRUE":"FALSE");
|
|
fprintf (fp, "</OPTIONS>\n");
|
|
}
|
|
|
|
static gint
|
|
load_bool (gchar *opt_buf,
|
|
gint *toset)
|
|
{
|
|
if (!strcmp (opt_buf, "TRUE"))
|
|
*toset = 1;
|
|
else if (!strcmp (opt_buf, "FALSE"))
|
|
*toset = 0;
|
|
else
|
|
return (-1);
|
|
|
|
return (0);
|
|
}
|
|
|
|
static void
|
|
update_options (GFigObj *old_obj)
|
|
{
|
|
/* Save old vals */
|
|
if (selvals.opts.gridspacing != old_obj->opts.gridspacing)
|
|
{
|
|
old_obj->opts.gridspacing = selvals.opts.gridspacing;
|
|
}
|
|
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 != current_obj->opts.gridspacing)
|
|
{
|
|
gtk_adjustment_set_value
|
|
(GTK_ADJUSTMENT (gfig_opt_widget.gridspacing),
|
|
current_obj->opts.gridspacing);
|
|
}
|
|
if (selvals.opts.drawgrid != current_obj->opts.drawgrid)
|
|
{
|
|
gtk_toggle_button_set_active
|
|
(GTK_TOGGLE_BUTTON (gfig_opt_widget.drawgrid),
|
|
current_obj->opts.drawgrid);
|
|
}
|
|
if (selvals.opts.snap2grid != current_obj->opts.snap2grid)
|
|
{
|
|
gtk_toggle_button_set_active
|
|
(GTK_TOGGLE_BUTTON (gfig_opt_widget.snap2grid),
|
|
current_obj->opts.snap2grid);
|
|
}
|
|
if (selvals.opts.lockongrid != current_obj->opts.lockongrid)
|
|
{
|
|
gtk_toggle_button_set_active
|
|
(GTK_TOGGLE_BUTTON (gfig_opt_widget.lockongrid),
|
|
current_obj->opts.lockongrid);
|
|
}
|
|
if (selvals.opts.showcontrol != current_obj->opts.showcontrol)
|
|
{
|
|
gtk_toggle_button_set_active
|
|
(GTK_TOGGLE_BUTTON (gfig_opt_widget.showcontrol),
|
|
current_obj->opts.showcontrol);
|
|
}
|
|
if (selvals.opts.gridtype != current_obj->opts.gridtype)
|
|
{
|
|
gtk_option_menu_set_history
|
|
(GTK_OPTION_MENU (gfig_opt_widget.gridtypemenu),
|
|
current_obj->opts.gridtype);
|
|
|
|
gridtype_menu_callback
|
|
(gtk_menu_get_active
|
|
(GTK_MENU (gtk_option_menu_get_menu
|
|
(GTK_OPTION_MENU (gfig_opt_widget.gridtypemenu)))),
|
|
(gpointer) GRID_TYPE_MENU);
|
|
#ifdef DEBUG
|
|
printf ("Gridtype set in options to ");
|
|
if (current_obj->opts.gridtype == RECT_GRID)
|
|
printf ("RECT_GRID\n");
|
|
else if (current_obj->opts.gridtype == POLAR_GRID)
|
|
printf ("POLAR_GRID\n");
|
|
else if (current_obj->opts.gridtype == ISO_GRID)
|
|
printf ("ISO_GRID\n");
|
|
else printf ("NONE\n");
|
|
#endif /* DEBUG */
|
|
}
|
|
}
|
|
|
|
static gint
|
|
load_options (GFigObj *gfig,
|
|
FILE *fp)
|
|
{
|
|
gchar load_buf[MAX_LOAD_LINE];
|
|
gchar str_buf[MAX_LOAD_LINE];
|
|
gchar opt_buf[MAX_LOAD_LINE];
|
|
|
|
get_line (load_buf, MAX_LOAD_LINE, fp, 0);
|
|
|
|
#ifdef DEBUG
|
|
printf ("load '%s'\n", load_buf);
|
|
#endif /* DEBUG */
|
|
|
|
if (strcmp (load_buf, "<OPTIONS>"))
|
|
return (-1);
|
|
|
|
get_line (load_buf, MAX_LOAD_LINE, fp, 0);
|
|
|
|
#ifdef DEBUG
|
|
printf ("opt line '%s'\n", load_buf);
|
|
#endif /* DEBUG */
|
|
|
|
while (strcmp (load_buf, "</OPTIONS>"))
|
|
{
|
|
/* Get option name */
|
|
#ifdef DEBUG
|
|
printf ("num = %d\n", sscanf (load_buf, "%s %s", str_buf, opt_buf));
|
|
|
|
printf ("option %s val %s\n", str_buf, opt_buf);
|
|
#else
|
|
sscanf (load_buf, "%s %s", str_buf, opt_buf);
|
|
#endif /* DEBUG */
|
|
|
|
if (!strcmp (str_buf, "GridSpacing:"))
|
|
{
|
|
/* Value is decimal */
|
|
int sp = 0;
|
|
sp = atoi (opt_buf);
|
|
if (sp <= 0)
|
|
return (-1);
|
|
gfig->opts.gridspacing = sp;
|
|
}
|
|
else if (!strcmp (str_buf, "DrawGrid:"))
|
|
{
|
|
/* Value is bool */
|
|
if (load_bool (opt_buf, &gfig->opts.drawgrid))
|
|
return (-1);
|
|
}
|
|
else if (!strcmp (str_buf, "Snap2Grid:"))
|
|
{
|
|
/* Value is bool */
|
|
if (load_bool (opt_buf, &gfig->opts.snap2grid))
|
|
return (-1);
|
|
}
|
|
else if (!strcmp (str_buf, "LockOnGrid:"))
|
|
{
|
|
/* Value is bool */
|
|
if (load_bool (opt_buf, &gfig->opts.lockongrid))
|
|
return (-1);
|
|
}
|
|
else if (!strcmp (str_buf, "ShowControl:"))
|
|
{
|
|
/* Value is bool */
|
|
if (load_bool (opt_buf, &gfig->opts.showcontrol))
|
|
return (-1);
|
|
}
|
|
else if (!strcmp (str_buf, "GridType:"))
|
|
{
|
|
/* Value is string */
|
|
if (!strcmp (opt_buf, "RECT_GRID"))
|
|
gfig->opts.gridtype = RECT_GRID;
|
|
else if (!strcmp (opt_buf, "POLAR_GRID"))
|
|
gfig->opts.gridtype = POLAR_GRID;
|
|
else if (!strcmp (opt_buf, "ISO_GRID"))
|
|
gfig->opts.gridtype = ISO_GRID;
|
|
else
|
|
return (-1);
|
|
}
|
|
|
|
get_line (load_buf, MAX_LOAD_LINE, fp, 0);
|
|
#ifdef DEBUG
|
|
printf ("opt line '%s'\n", load_buf);
|
|
#endif /* DEBUG */
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
static gint
|
|
gfig_obj_counts (DAllObjs *objs)
|
|
{
|
|
gint count = 0;
|
|
|
|
while (objs)
|
|
{
|
|
count++;
|
|
objs = objs->next;
|
|
}
|
|
|
|
return (count);
|
|
}
|
|
|
|
static void
|
|
gfig_save_callbk (void)
|
|
{
|
|
FILE *fp;
|
|
DAllObjs * objs;
|
|
gint count = 0;
|
|
gchar *savename;
|
|
gchar *message;
|
|
gchar conv_buf[MAX_LOAD_LINE*3 +1];
|
|
|
|
savename = current_obj->filename;
|
|
|
|
fp = fopen (savename, "w+");
|
|
|
|
if (!fp)
|
|
{
|
|
message = g_strconcat (_("Error opening: %s"),
|
|
"\n",
|
|
_("Could not save."),
|
|
savename);
|
|
g_message (message);
|
|
g_free (message);
|
|
return;
|
|
}
|
|
|
|
/* Write header out */
|
|
fputs (GFIG_HEADER, fp);
|
|
|
|
/*
|
|
* draw_name
|
|
* version
|
|
* obj_list
|
|
*
|
|
*/
|
|
|
|
gfig_name_encode (conv_buf, current_obj->draw_name);
|
|
fprintf (fp, "Name: %s\n", conv_buf);
|
|
fprintf (fp, "Version: %f\n", current_obj->version);
|
|
objs = current_obj->obj_list;
|
|
|
|
count = gfig_obj_counts (objs);
|
|
|
|
fprintf (fp, "ObjCount: %d\n", count);
|
|
|
|
save_options (fp);
|
|
|
|
objs = current_obj->obj_list;
|
|
while (objs)
|
|
{
|
|
objs->obj->savefunc (objs->obj, fp);
|
|
objs = objs->next;
|
|
}
|
|
|
|
if (ferror (fp))
|
|
g_message ("Failed to write file\n");
|
|
else
|
|
{
|
|
gfig_obj_modified (current_obj, GFIG_OK);
|
|
current_obj->obj_status &= ~(GFIG_MODIFIED | GFIG_READONLY);
|
|
}
|
|
|
|
fclose (fp);
|
|
|
|
gfig_update_stat_labels ();
|
|
}
|
|
|
|
static void
|
|
file_selection_ok (GtkWidget *w,
|
|
GtkFileSelection *fs,
|
|
gpointer data)
|
|
{
|
|
gchar *filenamebuf;
|
|
struct stat filestat;
|
|
gint err;
|
|
GFigObj *obj = (GFigObj *)gtk_object_get_user_data (GTK_OBJECT (fs));
|
|
GFigObj *real_current;
|
|
|
|
filenamebuf = gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs));
|
|
#ifdef DEBUG
|
|
g_print ("name selected '%s'\n", filenamebuf);
|
|
#endif /* DEBUG */
|
|
|
|
/* Get the name */
|
|
if (strlen (filenamebuf) == 0)
|
|
{
|
|
g_message ("Save: No filename given");
|
|
return;
|
|
}
|
|
|
|
/* Check if directory exists */
|
|
err = stat (filenamebuf, &filestat);
|
|
|
|
if (!err && S_ISDIR (filestat.st_mode))
|
|
{
|
|
g_message ("Save: Can't save to a directory");
|
|
return;
|
|
}
|
|
|
|
obj->filename = g_strdup (filenamebuf);
|
|
|
|
real_current = current_obj;
|
|
current_obj = obj;
|
|
gfig_save_callbk ();
|
|
current_obj = current_obj;
|
|
|
|
gtk_widget_destroy (GTK_WIDGET (fs));
|
|
|
|
}
|
|
|
|
static void
|
|
create_file_selection (GFigObj *obj,
|
|
gchar *tpath)
|
|
{
|
|
static GtkWidget *window = NULL;
|
|
|
|
if (!window)
|
|
{
|
|
window = gtk_file_selection_new ("Save gfig drawing");
|
|
gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (window), "destroy",
|
|
GTK_SIGNAL_FUNC (gtk_widget_destroyed),
|
|
&window);
|
|
|
|
gtk_object_set_user_data (GTK_OBJECT (window), obj);
|
|
gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (window)->ok_button),
|
|
"clicked",
|
|
GTK_SIGNAL_FUNC (file_selection_ok),
|
|
(gpointer) window);
|
|
gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (window)->cancel_button),
|
|
"clicked",
|
|
GTK_SIGNAL_FUNC (gtk_widget_destroy),
|
|
GTK_OBJECT (window));
|
|
}
|
|
|
|
if (tpath)
|
|
{
|
|
gtk_file_selection_set_filename (GTK_FILE_SELECTION (window), tpath);
|
|
}
|
|
else if (gfig_path_list)
|
|
{
|
|
gchar *dir;
|
|
|
|
dir = gimp_path_get_user_writable_dir (gfig_path_list);
|
|
|
|
if (!dir)
|
|
dir = g_strdup (gimp_directory ());
|
|
|
|
gtk_file_selection_set_filename (GTK_FILE_SELECTION (window), dir);
|
|
|
|
g_free (dir);
|
|
}
|
|
else
|
|
{
|
|
gchar *tmp = g_get_tmp_dir ();
|
|
|
|
gtk_file_selection_set_filename (GTK_FILE_SELECTION (window), tmp);
|
|
g_free (tmp);
|
|
}
|
|
|
|
if (!GTK_WIDGET_VISIBLE (window))
|
|
gtk_widget_show (window);
|
|
}
|
|
|
|
static void
|
|
gfig_save (void)
|
|
{
|
|
/* Save the current object */
|
|
if (!current_obj->filename)
|
|
{
|
|
create_file_selection (current_obj, NULL);
|
|
return;
|
|
}
|
|
gfig_save_callbk ();
|
|
}
|
|
|
|
/* HACK WARNING */
|
|
void * xxx;
|
|
void * yyy;
|
|
|
|
/* Cache the preview image - updates are a lot faster. */
|
|
/* The preview_cache will contain the small image */
|
|
|
|
static void
|
|
cache_preview (void)
|
|
{
|
|
GimpPixelRgn src_rgn;
|
|
int y, x;
|
|
guchar *src_rows;
|
|
guchar *p;
|
|
int isgrey = 0;
|
|
|
|
gimp_pixel_rgn_init (&src_rgn, gfig_select_drawable,
|
|
sel_x1, sel_y1, sel_width, sel_height, FALSE, FALSE);
|
|
|
|
src_rows = g_new (guchar , sel_width * 4);
|
|
p = pv_cache = g_new (guchar , preview_width * preview_height * 4);
|
|
|
|
real_img_bpp = gimp_drawable_bpp (gfig_select_drawable->id);
|
|
|
|
has_alpha = gimp_drawable_has_alpha (gfig_select_drawable->id);
|
|
|
|
if (real_img_bpp < 3)
|
|
{
|
|
img_bpp = 3 + has_alpha;
|
|
}
|
|
else
|
|
{
|
|
img_bpp = real_img_bpp;
|
|
}
|
|
|
|
switch (gimp_drawable_type (gfig_select_drawable->id))
|
|
{
|
|
case GIMP_GRAYA_IMAGE:
|
|
case GIMP_GRAY_IMAGE:
|
|
isgrey = 1;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/*memset (p,-1, preview_width*preview_height*4); return;*/
|
|
|
|
for (y = 0; y < preview_height; y++)
|
|
{
|
|
gimp_pixel_rgn_get_row (&src_rgn,
|
|
src_rows,
|
|
sel_x1,
|
|
sel_y1 + (y*sel_height)/preview_height,
|
|
sel_width);
|
|
|
|
for (x = 0; x < (preview_width); x ++)
|
|
{
|
|
/* Get the pixels of each col */
|
|
int i;
|
|
for (i = 0 ; i < 3; i++)
|
|
p[x*img_bpp+i] =
|
|
src_rows[((x*sel_width)/preview_width)*src_rgn.bpp +((isgrey)?0:i)];
|
|
if (has_alpha)
|
|
p[x*img_bpp+3] =
|
|
src_rows[((x*sel_width)/preview_width)*src_rgn.bpp + ((isgrey)?1:3)];
|
|
}
|
|
p += (preview_width*img_bpp);
|
|
}
|
|
g_free (src_rows);
|
|
}
|
|
|
|
static void
|
|
refill_cache (void)
|
|
{
|
|
GdkCursorType ctype1 = GDK_WATCH;
|
|
GdkCursorType ctype2 = GDK_TOP_LEFT_ARROW;
|
|
static GdkCursor *preview_cursor1;
|
|
static GdkCursor *preview_cursor2;
|
|
|
|
if (!preview_cursor1)
|
|
preview_cursor1 = gdk_cursor_new (ctype1);
|
|
|
|
if (!preview_cursor2)
|
|
preview_cursor2 = gdk_cursor_new (ctype2);
|
|
|
|
gdk_window_set_cursor
|
|
(gtk_widget_get_toplevel (GTK_WIDGET (gfig_preview))->window,
|
|
preview_cursor1);
|
|
|
|
gdk_window_set_cursor (gfig_preview->window, preview_cursor1);
|
|
|
|
gdk_flush ();
|
|
|
|
cache_preview ();
|
|
|
|
gdk_window_set_cursor
|
|
(gtk_widget_get_toplevel (GTK_WIDGET (gfig_preview))->window,
|
|
preview_cursor2);
|
|
|
|
toggle_obj_type (NULL, (gpointer) selvals.otype);
|
|
}
|
|
|
|
static GtkWidget *
|
|
gfig_list_item_new_with_label_and_pixmap (GFigObj *obj,
|
|
gchar *label,
|
|
GtkWidget *pix_widget)
|
|
{
|
|
GtkWidget *list_item;
|
|
GtkWidget *label_widget;
|
|
GtkWidget *hbox;
|
|
|
|
list_item = gtk_list_item_new ();
|
|
|
|
hbox = gtk_hbox_new (FALSE, 1);
|
|
gtk_container_add (GTK_CONTAINER (list_item), hbox);
|
|
gtk_widget_show (hbox);
|
|
|
|
gtk_box_pack_start (GTK_BOX (hbox), pix_widget, FALSE, FALSE, 0);
|
|
|
|
label_widget = gtk_label_new (label);
|
|
gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
|
|
gtk_container_add (GTK_CONTAINER (hbox), label_widget);
|
|
|
|
gtk_widget_show (obj->label_widget = label_widget);
|
|
gtk_widget_show (obj->pixmap_widget = pix_widget);
|
|
gtk_widget_show (obj->list_item = list_item);
|
|
|
|
return list_item;
|
|
}
|
|
|
|
static void
|
|
gfig_obj_modified (GFigObj *obj,
|
|
gint stat_type)
|
|
{
|
|
g_assert (obj != NULL);
|
|
|
|
if (obj->obj_status == stat_type)
|
|
return;
|
|
|
|
/* Set the new one up */
|
|
if (stat_type == GFIG_MODIFIED)
|
|
gimp_pixmap_set (GIMP_PIXMAP (obj->pixmap_widget), Floppy6_xpm);
|
|
else
|
|
gimp_pixmap_set (GIMP_PIXMAP (obj->pixmap_widget), blank_xpm);
|
|
}
|
|
|
|
static gint
|
|
select_button_press (GtkWidget *widget,
|
|
GdkEventButton *event,
|
|
gpointer data)
|
|
{
|
|
gint type = (gint) data;
|
|
gint count = 0;
|
|
DAllObjs * objs;
|
|
|
|
if (current_obj)
|
|
{
|
|
objs = current_obj->obj_list;
|
|
|
|
while (objs)
|
|
{
|
|
objs = objs->next;
|
|
count++;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
draw_grid_clear (widget, data);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static GtkWidget *
|
|
obj_select_buttons (void)
|
|
{
|
|
GtkWidget *button;
|
|
GtkWidget *hbox, *vbox;
|
|
|
|
vbox = gtk_vbox_new (FALSE, 0);
|
|
gtk_widget_show (vbox);
|
|
|
|
hbox = gtk_hbox_new (FALSE, 0);
|
|
gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
|
|
gtk_widget_show (hbox);
|
|
|
|
button = gtk_button_new_with_label ("<");
|
|
gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
|
|
gtk_signal_connect (GTK_OBJECT (button), "button_press_event",
|
|
GTK_SIGNAL_FUNC (select_button_press),
|
|
(gpointer) OBJ_SELECT_LT);
|
|
gtk_widget_show (button);
|
|
|
|
button = gtk_button_new_with_label (">");
|
|
gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
|
|
gtk_signal_connect (GTK_OBJECT (button), "button_press_event",
|
|
GTK_SIGNAL_FUNC (select_button_press),
|
|
(gpointer) OBJ_SELECT_GT);
|
|
gtk_widget_show (button);
|
|
|
|
button = gtk_button_new_with_label ("==");
|
|
gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
|
|
gtk_signal_connect (GTK_OBJECT (button), "button_press_event",
|
|
GTK_SIGNAL_FUNC (select_button_press),
|
|
(gpointer) OBJ_SELECT_EQ);
|
|
gtk_widget_show (button);
|
|
|
|
return vbox;
|
|
}
|
|
|
|
static GtkWidget *
|
|
but_with_pix (gchar **pixdata,
|
|
GSList **group,
|
|
gint baction)
|
|
{
|
|
GtkWidget *button;
|
|
GtkWidget *alignment;
|
|
GtkWidget *pixmap_widget;
|
|
|
|
button = gtk_radio_button_new (*group);
|
|
gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (button), FALSE);
|
|
gtk_signal_connect (GTK_OBJECT (button), "toggled",
|
|
GTK_SIGNAL_FUNC (toggle_obj_type),
|
|
(gpointer) baction);
|
|
gtk_widget_show (button);
|
|
|
|
*group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
|
|
|
|
alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
|
|
gtk_container_add (GTK_CONTAINER (button), alignment);
|
|
gtk_widget_show (alignment);
|
|
|
|
pixmap_widget = gimp_pixmap_new (pixdata);
|
|
gtk_container_add (GTK_CONTAINER (alignment), pixmap_widget);
|
|
gtk_widget_show (pixmap_widget);
|
|
|
|
return button;
|
|
}
|
|
|
|
static GtkWidget *
|
|
small_preview (GtkWidget *list)
|
|
{
|
|
GtkWidget *label;
|
|
GtkWidget *frame;
|
|
GtkWidget *button;
|
|
GtkWidget *vbox;
|
|
gint y;
|
|
|
|
vbox = gtk_vbox_new (FALSE, 0);
|
|
gtk_widget_show (vbox);
|
|
|
|
label = gtk_label_new (_("Prev"));
|
|
gtk_container_add (GTK_CONTAINER (vbox), label);
|
|
gtk_widget_show (label);
|
|
|
|
frame = gtk_frame_new (NULL);
|
|
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
|
|
gtk_container_add (GTK_CONTAINER (vbox), frame);
|
|
gtk_widget_show (frame);
|
|
|
|
pic_preview = gtk_preview_new (GTK_PREVIEW_COLOR);
|
|
gtk_preview_size (GTK_PREVIEW (pic_preview),
|
|
SMALL_PREVIEW_SZ, SMALL_PREVIEW_SZ);
|
|
gtk_container_add (GTK_CONTAINER (frame), pic_preview);
|
|
gtk_widget_show (pic_preview);
|
|
|
|
/* Fill with white */
|
|
for (y = 0; y < SMALL_PREVIEW_SZ; y++)
|
|
{
|
|
guchar prow[SMALL_PREVIEW_SZ*3];
|
|
memset (prow, -1, SMALL_PREVIEW_SZ * 3);
|
|
gtk_preview_draw_row (GTK_PREVIEW (pic_preview), prow,
|
|
0, y, SMALL_PREVIEW_SZ);
|
|
}
|
|
|
|
gtk_signal_connect_after (GTK_OBJECT (pic_preview), "expose_event",
|
|
GTK_SIGNAL_FUNC (pic_preview_expose),
|
|
NULL);
|
|
|
|
/* More Buttons */
|
|
button = gtk_button_new_with_label (_("Edit"));
|
|
gtk_container_add (GTK_CONTAINER (vbox), button);
|
|
gtk_signal_connect (GTK_OBJECT (button), "clicked",
|
|
GTK_SIGNAL_FUNC (edit_button_callback),
|
|
(gpointer) list);
|
|
gimp_help_set_help_data (button, _("Edit Gfig object collection"), NULL);
|
|
gtk_widget_show (button);
|
|
|
|
button = gtk_button_new_with_label (_("Merge"));
|
|
gtk_container_add (GTK_CONTAINER (vbox), button);
|
|
gtk_signal_connect (GTK_OBJECT (button), "clicked",
|
|
GTK_SIGNAL_FUNC (merge_button_callback),
|
|
(gpointer) list);
|
|
gimp_help_set_help_data (button, _("Merge Gfig Object collection into the "
|
|
"current edit session"), NULL);
|
|
gtk_widget_show (button);
|
|
|
|
return vbox;
|
|
}
|
|
|
|
/* Special case for now - options on poly/star/spiral button */
|
|
|
|
static void
|
|
num_sides_dialog (gchar *d_title,
|
|
gint *num_sides,
|
|
gint *which_way,
|
|
gint adj_min,
|
|
gint adj_max)
|
|
{
|
|
GtkWidget *window;
|
|
GtkWidget *table;
|
|
GtkObject *size_data;
|
|
|
|
window = gimp_dialog_new (d_title, "gfig",
|
|
gimp_standard_help_func, "filters/gfig.html",
|
|
GTK_WIN_POS_MOUSE,
|
|
FALSE, TRUE, FALSE,
|
|
|
|
_("Close"), gtk_widget_destroy,
|
|
NULL, 1, NULL, TRUE, TRUE,
|
|
|
|
NULL);
|
|
|
|
table = gtk_table_new (which_way ? 2 : 1, 3, FALSE);
|
|
gtk_table_set_col_spacings (GTK_TABLE (table), 4);
|
|
gtk_table_set_row_spacings (GTK_TABLE (table), 2);
|
|
gtk_container_set_border_width (GTK_CONTAINER (table), 6);
|
|
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), table,
|
|
FALSE, FALSE, 0);
|
|
gtk_widget_show (table);
|
|
|
|
size_data = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
|
|
_("Number of Sides/Points/Turns:"), 0, 0,
|
|
*num_sides, adj_min, adj_max, 1, 10, 0,
|
|
TRUE, 0, 0,
|
|
NULL, NULL);
|
|
gtk_signal_connect (GTK_OBJECT (size_data), "value_changed",
|
|
GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
|
|
num_sides);
|
|
|
|
if (which_way)
|
|
{
|
|
GtkWidget *option_menu;
|
|
|
|
option_menu =
|
|
gimp_option_menu_new2 (FALSE, gimp_menu_item_update,
|
|
which_way, (gpointer) *which_way,
|
|
|
|
_("Clockwise"), (gpointer) 0, NULL,
|
|
_("Anti-Clockwise"), (gpointer) 1, NULL,
|
|
|
|
NULL);
|
|
gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
|
|
_("Orientation:"), 1.0, 0.5,
|
|
option_menu, 1, TRUE);
|
|
}
|
|
|
|
gtk_widget_show (window);
|
|
}
|
|
|
|
static void
|
|
bezier_dialog (void)
|
|
{
|
|
static GtkWidget *window = NULL;
|
|
GtkWidget *vbox;
|
|
GtkWidget *toggle;
|
|
|
|
if (window)
|
|
{
|
|
gdk_window_raise (window->window);
|
|
return;
|
|
}
|
|
|
|
window = gimp_dialog_new (_("Bezier Settings"), "gfig",
|
|
gimp_standard_help_func, "filters/gfig.html",
|
|
GTK_WIN_POS_MOUSE,
|
|
FALSE, FALSE, FALSE,
|
|
|
|
_("Close"), gtk_widget_destroy,
|
|
NULL, 1, NULL, TRUE, TRUE,
|
|
|
|
NULL);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (window), "destroy",
|
|
GTK_SIGNAL_FUNC (gtk_widget_destroyed),
|
|
&window);
|
|
|
|
vbox = gtk_vbox_new (FALSE, 2);
|
|
gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
|
|
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), vbox,
|
|
FALSE, FALSE, 0);
|
|
gtk_widget_show (vbox);
|
|
|
|
toggle = gtk_check_button_new_with_label (_("Closed"));
|
|
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
|
|
GTK_SIGNAL_FUNC (gimp_toggle_button_update),
|
|
&bezier_closed);
|
|
gimp_help_set_help_data (toggle,
|
|
_("Close curve on completion"), NULL);
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), bezier_closed);
|
|
gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
|
|
gtk_widget_show (toggle);
|
|
|
|
toggle = gtk_check_button_new_with_label (_("Show Line Frame"));
|
|
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
|
|
GTK_SIGNAL_FUNC (gimp_toggle_button_update),
|
|
&bezier_line_frame);
|
|
gimp_help_set_help_data (toggle,
|
|
_("Draws lines between the control points. "
|
|
"Only during curve creation"), NULL);
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), bezier_line_frame);
|
|
gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
|
|
gtk_widget_show (toggle);
|
|
|
|
gtk_widget_show (window);
|
|
}
|
|
|
|
static gint
|
|
poly_button_press (GtkWidget *widget,
|
|
GdkEventButton *event,
|
|
gpointer data)
|
|
{
|
|
if ((event->type == GDK_2BUTTON_PRESS) &&
|
|
(event->button == 1))
|
|
num_sides_dialog (_("Regular Polygon Number of Sides"),
|
|
&poly_num_sides, NULL, 3, 200);
|
|
return FALSE;
|
|
}
|
|
|
|
static gint
|
|
star_button_press (GtkWidget *widget,
|
|
GdkEventButton *event,
|
|
gpointer data)
|
|
{
|
|
if ((event->type == GDK_2BUTTON_PRESS) &&
|
|
(event->button == 1))
|
|
num_sides_dialog (_("Star Number of Points"),
|
|
&star_num_sides, NULL, 3, 200);
|
|
return FALSE;
|
|
}
|
|
|
|
static gint
|
|
spiral_button_press (GtkWidget *widget,
|
|
GdkEventButton *event,
|
|
gpointer data)
|
|
{
|
|
if ((event->type == GDK_2BUTTON_PRESS) &&
|
|
(event->button == 1))
|
|
num_sides_dialog (_("Spiral Number of Points"),
|
|
&spiral_num_turns, &spiral_toggle, 1, 20);
|
|
return FALSE;
|
|
}
|
|
|
|
static gint
|
|
bezier_button_press (GtkWidget *widget,
|
|
GdkEventButton *event,
|
|
gpointer data)
|
|
{
|
|
if ((event->type == GDK_2BUTTON_PRESS) &&
|
|
(event->button == 1))
|
|
bezier_dialog ();
|
|
return FALSE;
|
|
}
|
|
|
|
static GtkWidget *
|
|
draw_buttons (GtkWidget *ww)
|
|
{
|
|
GtkWidget *frame;
|
|
GtkWidget *button;
|
|
GtkWidget *vbox;
|
|
GSList *group;
|
|
|
|
frame = gtk_frame_new (_("Ops"));
|
|
gtk_container_set_border_width (GTK_CONTAINER (frame), 1);
|
|
|
|
/* Create group */
|
|
group = NULL;
|
|
vbox = gtk_vbox_new (FALSE, 0);
|
|
gtk_container_add (GTK_CONTAINER (frame), vbox);
|
|
gtk_container_set_border_width (GTK_CONTAINER (vbox), 2);
|
|
|
|
/* Put buttons in */
|
|
button = but_with_pix (line_xpm, &group, LINE);
|
|
gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
|
|
gtk_widget_show (button);
|
|
gimp_help_set_help_data (button, _("Create line"), NULL);
|
|
|
|
button = but_with_pix (circle_xpm, &group, CIRCLE);
|
|
gtk_container_add (GTK_CONTAINER (vbox), button);
|
|
gtk_widget_show (button);
|
|
gimp_help_set_help_data (button, _("Create circle"), NULL);
|
|
|
|
button = but_with_pix (ellipse_xpm, &group, ELLIPSE);
|
|
gtk_container_add (GTK_CONTAINER (vbox), button);
|
|
gtk_widget_show (button);
|
|
gimp_help_set_help_data (button, _("Create ellipse"), NULL);
|
|
|
|
button = but_with_pix (curve_xpm, &group, ARC);
|
|
gtk_container_add (GTK_CONTAINER (vbox), button);
|
|
gtk_widget_show (button);
|
|
gimp_help_set_help_data (button, _("Create arch"), NULL);
|
|
|
|
button = but_with_pix (poly_xpm, &group, POLY);
|
|
gtk_container_add (GTK_CONTAINER (vbox), button);
|
|
gtk_widget_show (button);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (button), "button_press_event",
|
|
GTK_SIGNAL_FUNC (poly_button_press),
|
|
NULL);
|
|
gimp_help_set_help_data (button, _("Create reg polygon"), NULL);
|
|
|
|
button = but_with_pix (star_xpm, &group, STAR);
|
|
gtk_container_add (GTK_CONTAINER (vbox), button);
|
|
gtk_widget_show (button);
|
|
gtk_signal_connect (GTK_OBJECT (button), "button_press_event",
|
|
GTK_SIGNAL_FUNC (star_button_press),
|
|
NULL);
|
|
gimp_help_set_help_data (button, "Create star", NULL);
|
|
|
|
button = but_with_pix (spiral_xpm, &group, SPIRAL);
|
|
gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
|
|
gtk_widget_show (button);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (button), "button_press_event",
|
|
GTK_SIGNAL_FUNC (spiral_button_press),
|
|
NULL);
|
|
gimp_help_set_help_data (button, _("Create spiral"), NULL);
|
|
|
|
button = but_with_pix (bezier_xpm, &group, BEZIER);
|
|
gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
|
|
gtk_widget_show (button);
|
|
gtk_signal_connect (GTK_OBJECT (button), "button_press_event",
|
|
GTK_SIGNAL_FUNC (bezier_button_press),
|
|
NULL);
|
|
|
|
gimp_help_set_help_data (button,
|
|
_("Create bezier curve. "
|
|
"Shift + Button ends object creation."), NULL);
|
|
|
|
button = but_with_pix (move_obj_xpm, &group, MOVE_OBJ);
|
|
gtk_container_add (GTK_CONTAINER (vbox), button);
|
|
gtk_widget_show (button);
|
|
gimp_help_set_help_data (button, _("Move an object"), NULL);
|
|
|
|
button = but_with_pix (move_point_xpm, &group, MOVE_POINT);
|
|
gtk_container_add (GTK_CONTAINER (vbox), button);
|
|
gtk_widget_show (button);
|
|
gimp_help_set_help_data (button, _("Move a single point"), NULL);
|
|
|
|
button = but_with_pix (copy_obj_xpm, &group, COPY_OBJ);
|
|
gtk_container_add (GTK_CONTAINER (vbox), button);
|
|
gtk_widget_show (button);
|
|
gimp_help_set_help_data (button, _("Copy an object"), NULL);
|
|
|
|
button = but_with_pix (delete_xpm, &group, DEL_OBJ);
|
|
gtk_container_add (GTK_CONTAINER (vbox), button);
|
|
gtk_widget_show (button);
|
|
gimp_help_set_help_data (button, _("Delete an object"), NULL);
|
|
|
|
button = obj_select_buttons ();
|
|
gtk_container_add (GTK_CONTAINER (vbox), button);
|
|
gtk_widget_show (button);
|
|
|
|
#if 0
|
|
button = but_with_pix (blank_xpm, &group, NULL_OPER);
|
|
gtk_container_add (GTK_CONTAINER (vbox), button);
|
|
gtk_widget_set_sensitive (button, FALSE);
|
|
gtk_widget_show (button);
|
|
#endif /* 0 */
|
|
|
|
gtk_widget_show (vbox);
|
|
gtk_widget_show (frame);
|
|
|
|
return frame;
|
|
}
|
|
|
|
/* Brush preview stuff */
|
|
static gint
|
|
gfig_brush_preview_events (GtkWidget *widget,
|
|
GdkEvent *event)
|
|
{
|
|
GdkEventButton *bevent;
|
|
GdkEventMotion *mevent;
|
|
static GdkPoint point;
|
|
static int have_start = 0;
|
|
|
|
switch (event->type)
|
|
{
|
|
case GDK_EXPOSE:
|
|
break;
|
|
|
|
case GDK_BUTTON_PRESS:
|
|
bevent = (GdkEventButton *) event;
|
|
point.x = bevent->x;
|
|
point.y = bevent->y;
|
|
have_start = 1;
|
|
|
|
break;
|
|
case GDK_BUTTON_RELEASE:
|
|
bevent = (GdkEventButton *) event;
|
|
have_start = 0;
|
|
|
|
break;
|
|
case GDK_MOTION_NOTIFY:
|
|
mevent = (GdkEventMotion *) event;
|
|
|
|
if (!have_start || !(mevent->state & GDK_BUTTON1_MASK))
|
|
break;
|
|
|
|
gfig_brush_fill_preview_xy (widget,
|
|
point.x - mevent->x,
|
|
point.y - mevent->y);
|
|
gtk_widget_draw (widget, NULL);
|
|
point.x = mevent->x;
|
|
point.y = mevent->y;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
gfig_brush_update_preview (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
GtkWidget *pw = (GtkWidget *) data;
|
|
BrushDesc *bdesc;
|
|
|
|
/* Must update the dialog area */
|
|
/* Use the same brush as already set in the dialog */
|
|
bdesc = gtk_object_get_user_data (GTK_OBJECT (pw));
|
|
brush_list_button_callback (NULL, bdesc);
|
|
}
|
|
|
|
static void
|
|
gfig_brush_menu_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
gimp_menu_item_update (widget, &selvals.brshtype);
|
|
|
|
switch (selvals.brshtype)
|
|
{
|
|
case BRUSH_BRUSH_TYPE:
|
|
gtk_widget_hide (pressure_hbox);
|
|
gtk_widget_hide (pencil_hbox);
|
|
gtk_widget_show (fade_out_hbox);
|
|
gtk_widget_show (gradient_hbox);
|
|
break;
|
|
case BRUSH_PENCIL_TYPE:
|
|
gtk_widget_hide (fade_out_hbox);
|
|
gtk_widget_hide (gradient_hbox);
|
|
gtk_widget_hide (pressure_hbox);
|
|
gtk_widget_show (pencil_hbox);
|
|
break;
|
|
case BRUSH_AIRBRUSH_TYPE:
|
|
gtk_widget_hide (fade_out_hbox);
|
|
gtk_widget_hide (gradient_hbox);
|
|
gtk_widget_hide (pencil_hbox);
|
|
gtk_widget_show (pressure_hbox);
|
|
break;
|
|
case BRUSH_PATTERN_TYPE:
|
|
gtk_widget_hide (fade_out_hbox);
|
|
gtk_widget_hide (gradient_hbox);
|
|
gtk_widget_hide (pressure_hbox);
|
|
gtk_widget_show (pencil_hbox);
|
|
break;
|
|
default:
|
|
g_warning ("Internal error - invalid brush type");
|
|
break;
|
|
}
|
|
|
|
gfig_brush_update_preview (widget, data);
|
|
}
|
|
|
|
|
|
static GtkWidget *
|
|
gfig_brush_preview (GtkWidget **pv)
|
|
{
|
|
GtkWidget *option_menu;
|
|
GtkWidget *frame;
|
|
GtkWidget *hbox;
|
|
GtkWidget *vbox;
|
|
gint y;
|
|
|
|
hbox = gtk_hbox_new (FALSE, 0);
|
|
gtk_container_set_border_width (GTK_CONTAINER (hbox), 4);
|
|
gtk_widget_show (hbox);
|
|
|
|
frame = gtk_frame_new (NULL);
|
|
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
|
|
gtk_container_set_border_width (GTK_CONTAINER (frame), 0);
|
|
gtk_widget_show (frame);
|
|
|
|
*pv = gtk_preview_new (GTK_PREVIEW_COLOR);
|
|
gtk_widget_show (*pv);
|
|
gtk_widget_set_events (GTK_WIDGET (*pv), PREVIEW_MASK);
|
|
gtk_signal_connect (GTK_OBJECT (*pv), "event",
|
|
GTK_SIGNAL_FUNC (gfig_brush_preview_events),
|
|
NULL);
|
|
gtk_preview_size (GTK_PREVIEW (*pv), BRUSH_PREVIEW_SZ, BRUSH_PREVIEW_SZ);
|
|
gtk_container_add (GTK_CONTAINER (frame), *pv);
|
|
|
|
/* Fill with white */
|
|
for (y = 0; y < BRUSH_PREVIEW_SZ; y++)
|
|
{
|
|
guchar prow[BRUSH_PREVIEW_SZ*3];
|
|
memset (prow, -1, BRUSH_PREVIEW_SZ * 3);
|
|
gtk_preview_draw_row (GTK_PREVIEW (*pv), prow, 0, y, BRUSH_PREVIEW_SZ);
|
|
}
|
|
|
|
/* Now the buttons */
|
|
vbox = gtk_vbox_new (FALSE, 0);
|
|
gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
|
|
gtk_widget_show (vbox);
|
|
|
|
option_menu =
|
|
gimp_option_menu_new2 (FALSE, gfig_brush_menu_callback,
|
|
*pv, (gpointer) selvals.brshtype,
|
|
|
|
_("Brush"), (gpointer) BRUSH_BRUSH_TYPE, NULL,
|
|
_("Airbrush"), (gpointer) BRUSH_AIRBRUSH_TYPE, NULL,
|
|
_("Pencil"), (gpointer) BRUSH_PENCIL_TYPE, NULL,
|
|
_("Pattern"), (gpointer) BRUSH_PATTERN_TYPE, NULL,
|
|
|
|
NULL);
|
|
gtk_widget_show (option_menu);
|
|
|
|
gtk_container_add (GTK_CONTAINER (vbox), option_menu);
|
|
gimp_help_set_help_data (option_menu,
|
|
_("Use the brush/pencil or the airbrush when drawing "
|
|
"on the image. Pattern paints with currently "
|
|
"selected brush with a pattern. Only applies to "
|
|
"circles/ellipses if Approx. Circles/Ellipses "
|
|
"toggle is set."), NULL);
|
|
|
|
gtk_container_add (GTK_CONTAINER (hbox), vbox);
|
|
gtk_container_add (GTK_CONTAINER (hbox), frame);
|
|
|
|
return hbox;
|
|
}
|
|
|
|
static void
|
|
gfig_brush_fill_preview_xy (GtkWidget *pw,
|
|
gint x1,
|
|
gint y1)
|
|
{
|
|
gint row_count;
|
|
BrushDesc *bdesc = (BrushDesc*) gtk_object_get_user_data (GTK_OBJECT (pw));
|
|
|
|
/* Adjust start position */
|
|
bdesc->x_off += x1;
|
|
bdesc->y_off += y1;
|
|
|
|
if (bdesc->y_off < 0)
|
|
bdesc->y_off = 0;
|
|
if (bdesc->y_off > (bdesc->height - BRUSH_PREVIEW_SZ))
|
|
bdesc->y_off = bdesc->height - BRUSH_PREVIEW_SZ;
|
|
|
|
if (bdesc->x_off < 0)
|
|
bdesc->x_off = 0;
|
|
if (bdesc->x_off > (bdesc->width - BRUSH_PREVIEW_SZ))
|
|
bdesc->x_off = bdesc->width - BRUSH_PREVIEW_SZ;
|
|
|
|
/* Given an x and y fill preview in correctly offsetted */
|
|
for (row_count = 0; row_count < BRUSH_PREVIEW_SZ; row_count++)
|
|
gtk_preview_draw_row (GTK_PREVIEW (pw),
|
|
&bdesc->pv_buf[bdesc->x_off*bdesc->bpp
|
|
+ (bdesc->width
|
|
*bdesc->bpp
|
|
*(row_count + bdesc->y_off))],
|
|
0,
|
|
row_count,
|
|
BRUSH_PREVIEW_SZ);
|
|
}
|
|
|
|
static void
|
|
gfig_brush_fill_preview (GtkWidget *pw,
|
|
gint32 layer_ID,
|
|
BrushDesc *bdesc)
|
|
{
|
|
GimpPixelRgn src_rgn;
|
|
GimpDrawable *brushdrawable;
|
|
gint bcount = 3;
|
|
|
|
if (bdesc->pv_buf)
|
|
{
|
|
g_free (bdesc->pv_buf); /* Free old area */
|
|
}
|
|
|
|
brushdrawable = gimp_drawable_get (layer_ID);
|
|
|
|
bdesc->bpp = bcount;
|
|
|
|
/* Fill the preview with the current brush name */
|
|
gimp_pixel_rgn_init (&src_rgn, brushdrawable,
|
|
0, 0, bdesc->width, bdesc->height, FALSE, FALSE);
|
|
|
|
bdesc->pv_buf = g_new (guchar, bdesc->width * bdesc->height * bcount);
|
|
bdesc->x_off = bdesc->y_off = 0; /* Start from top left */
|
|
|
|
gimp_pixel_rgn_get_rect (&src_rgn, bdesc->pv_buf,
|
|
0, 0, bdesc->width, bdesc->height);
|
|
|
|
/* Dump the pv_buf into the preview area */
|
|
gfig_brush_fill_preview_xy (pw, 0, 0);
|
|
}
|
|
|
|
static void
|
|
mygimp_brush_set (gchar *bname)
|
|
{
|
|
GimpParam *return_vals;
|
|
int nreturn_vals;
|
|
|
|
return_vals = gimp_run_procedure ("gimp_brushes_set_brush",
|
|
&nreturn_vals,
|
|
GIMP_PDB_STRING, bname,
|
|
GIMP_PDB_END);
|
|
|
|
if (return_vals[0].data.d_status != GIMP_PDB_SUCCESS)
|
|
{
|
|
g_message ("Can't set brush...(1)");
|
|
}
|
|
|
|
gimp_destroy_params (return_vals, nreturn_vals);
|
|
}
|
|
|
|
static gchar *
|
|
mygimp_brush_get (void)
|
|
{
|
|
GimpParam *return_vals;
|
|
int nreturn_vals;
|
|
static gchar saved_bname[1024]; /* required to be static - returned from proc */
|
|
|
|
return_vals = gimp_run_procedure ("gimp_brushes_get_brush",
|
|
&nreturn_vals,
|
|
GIMP_PDB_END);
|
|
|
|
if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS)
|
|
{
|
|
strncpy (saved_bname, return_vals[1].data.d_string, sizeof (saved_bname));
|
|
}
|
|
else
|
|
{
|
|
saved_bname[0] = '\0';
|
|
}
|
|
|
|
gimp_destroy_params (return_vals, nreturn_vals);
|
|
|
|
return (saved_bname);
|
|
}
|
|
|
|
static void
|
|
mygimp_brush_info (gint32 *width,
|
|
gint32 *height)
|
|
{
|
|
GimpParam *return_vals;
|
|
int nreturn_vals;
|
|
|
|
return_vals = gimp_run_procedure ("gimp_brushes_get_brush",
|
|
&nreturn_vals,
|
|
GIMP_PDB_END);
|
|
|
|
if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS)
|
|
{
|
|
*width = MAX (return_vals[2].data.d_int32, 32);
|
|
*height = MAX (return_vals[3].data.d_int32, 32);
|
|
}
|
|
else
|
|
{
|
|
g_message ("Failed to get brush info");
|
|
*width = *height = 48;
|
|
}
|
|
|
|
gimp_destroy_params (return_vals, nreturn_vals);
|
|
}
|
|
|
|
static 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_HARD,
|
|
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_PATTERN_CLONE,
|
|
0.0, 0.0,
|
|
seg_count, line_pnts);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static gint32
|
|
gfig_gen_brush_preview (BrushDesc *bdesc)
|
|
{
|
|
/* Given the name of a brush then paint it and return the ID of the image
|
|
* the preview can be got from
|
|
*/
|
|
static gint32 layer_ID = -1;
|
|
gchar *saved_bname;
|
|
gint32 width, height;
|
|
gdouble line_pnts[2];
|
|
GimpRGB foreground;
|
|
GimpRGB background;
|
|
GimpRGB color;
|
|
|
|
if (brush_image_ID == -1)
|
|
{
|
|
/* Create a new image */
|
|
brush_image_ID = gimp_image_new (48, 48, 0);
|
|
if (brush_image_ID < 0)
|
|
{
|
|
g_message ("Failed to generate brush preview");
|
|
return -1;
|
|
}
|
|
if ((layer_ID = gimp_layer_new (brush_image_ID,
|
|
"Brush preview",
|
|
48,
|
|
48,
|
|
0, /* RGB type */
|
|
100.0, /* opacity */
|
|
0 /* mode */)) < 0)
|
|
{
|
|
g_message ("Error in creating layer for brush preview");
|
|
return -1;
|
|
}
|
|
gimp_image_add_layer (brush_image_ID, layer_ID, -1);
|
|
}
|
|
|
|
/* Need this later to delete it */
|
|
|
|
/* Store foreground & backgroud colours set to black/white
|
|
* paint with brush
|
|
* restore colours
|
|
*/
|
|
|
|
gimp_palette_get_foreground_rgb (&foreground);
|
|
gimp_palette_get_background_rgb (&background);
|
|
|
|
saved_bname = mygimp_brush_get ();
|
|
|
|
gimp_rgba_set (&color, 1.0, 1.0, 1.0, 1.0);
|
|
gimp_palette_set_background_rgb (&color);
|
|
gimp_rgba_set (&color, 0.0, 0.0, 0.0, 1.0);
|
|
gimp_palette_set_foreground_rgb (&color);
|
|
|
|
mygimp_brush_set (bdesc->bname);
|
|
|
|
mygimp_brush_info (&width, &height);
|
|
bdesc->width = width;
|
|
bdesc->height = height;
|
|
line_pnts[0] = (gdouble) width / 2;
|
|
line_pnts[1] = (gdouble) height / 2;
|
|
|
|
gimp_layer_resize (layer_ID, width, height, 0, 0);
|
|
gimp_image_resize (brush_image_ID, width, height, 0, 0);
|
|
|
|
gimp_drawable_fill (layer_ID, 1); /* Clear... Fill with white ... */
|
|
|
|
/* Blob of paint */
|
|
gfig_paint (selvals.brshtype,
|
|
layer_ID,
|
|
2, line_pnts);
|
|
|
|
gimp_palette_set_background_rgb (&background);
|
|
gimp_palette_set_foreground_rgb (&foreground);
|
|
|
|
mygimp_brush_set (saved_bname);
|
|
|
|
return layer_ID;
|
|
}
|
|
|
|
static void
|
|
brush_list_button_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
gint32 layer_ID;
|
|
|
|
BrushDesc *bdesc = (BrushDesc *) data;
|
|
if ((layer_ID = gfig_gen_brush_preview (bdesc)) != -1)
|
|
{
|
|
gtk_object_set_user_data (GTK_OBJECT (brush_page_pw), (gpointer) bdesc);
|
|
gfig_brush_fill_preview (brush_page_pw, layer_ID, bdesc);
|
|
gtk_widget_draw (brush_page_pw, NULL);
|
|
}
|
|
}
|
|
|
|
/* Build the dialog up. This was the hard part! */
|
|
|
|
static GtkWidget *page_menu_bg;
|
|
static GtkWidget *page_menu_layers;
|
|
|
|
static void
|
|
gfig_brush_pane_activate (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
gint flag = (gint) data;
|
|
|
|
if (flag)
|
|
{
|
|
gtk_widget_show (brush_page_widget);
|
|
}
|
|
else
|
|
{
|
|
gtk_widget_hide (brush_page_widget);
|
|
}
|
|
|
|
gtk_widget_set_sensitive (brush_page_widget, flag);
|
|
}
|
|
|
|
static void
|
|
gfig_select_pane_activate (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
gint flag = (gint) data;
|
|
|
|
if (flag)
|
|
{
|
|
gtk_widget_show (select_page_widget);
|
|
}
|
|
else
|
|
{
|
|
gtk_widget_hide (select_page_widget);
|
|
}
|
|
|
|
gtk_widget_set_sensitive (select_page_widget, flag);
|
|
}
|
|
|
|
|
|
static void
|
|
paint_menu_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
gint mtype = (gint)data;
|
|
|
|
if (mtype == PAINT_LAYERS_MENU)
|
|
{
|
|
#ifdef DEBUG
|
|
printf ("layer type set to %s\n",
|
|
((DrawonLayers)gtk_object_get_user_data (GTK_OBJECT (widget)) == SINGLE_LAYER)?"SINGLE_LAYER":"MULTI_LAYER");
|
|
#endif /* DEBUG */
|
|
selvals.onlayers = (DrawonLayers)gtk_object_get_user_data (GTK_OBJECT (widget));
|
|
/* Type only meaningful if creating new layers */
|
|
if (selvals.onlayers == ORIGINAL_LAYER)
|
|
gtk_widget_set_sensitive (page_menu_bg, FALSE);
|
|
else
|
|
gtk_widget_set_sensitive (page_menu_bg, TRUE);
|
|
}
|
|
else if (mtype == PAINT_BGS_MENU)
|
|
{
|
|
#ifdef DEBUG
|
|
printf ("BG type = %d\n",
|
|
((LayersBGType)gtk_object_get_user_data (GTK_OBJECT (widget))));
|
|
#endif /* DEBUG */
|
|
selvals.onlayerbg = (LayersBGType)gtk_object_get_user_data (GTK_OBJECT (widget));
|
|
}
|
|
else if (mtype == PAINT_TYPE_MENU)
|
|
{
|
|
#ifdef DEBUG
|
|
printf ("Got type menu = %d\n", (PaintType)gtk_object_get_user_data (GTK_OBJECT (widget)));
|
|
#endif /* DEBUG */
|
|
selvals.painttype = (PaintType)gtk_object_get_user_data (GTK_OBJECT (widget));
|
|
switch (selvals.painttype)
|
|
{
|
|
case PAINT_BRUSH_TYPE:
|
|
gtk_widget_set_sensitive (select_page_widget, FALSE);
|
|
gtk_widget_set_sensitive (brush_page_widget, TRUE);
|
|
gtk_widget_set_sensitive (page_menu_layers, TRUE);
|
|
if (selvals.onlayers == ORIGINAL_LAYER)
|
|
gtk_widget_set_sensitive (page_menu_bg, FALSE);
|
|
else
|
|
gtk_widget_set_sensitive (page_menu_bg, TRUE);
|
|
break;
|
|
case PAINT_SELECTION_TYPE:
|
|
gtk_widget_set_sensitive (select_page_widget, TRUE);
|
|
gtk_widget_set_sensitive (brush_page_widget, FALSE);
|
|
gtk_widget_set_sensitive (page_menu_layers, FALSE);
|
|
gtk_widget_set_sensitive (page_menu_bg, FALSE);
|
|
break;
|
|
case PAINT_SELECTION_FILL_TYPE:
|
|
gtk_widget_set_sensitive (select_page_widget, TRUE);
|
|
gtk_widget_set_sensitive (brush_page_widget, FALSE);
|
|
gtk_widget_set_sensitive (page_menu_layers, TRUE);
|
|
if (selvals.onlayers == ORIGINAL_LAYER)
|
|
gtk_widget_set_sensitive (page_menu_bg, FALSE);
|
|
else
|
|
gtk_widget_set_sensitive (page_menu_bg, TRUE);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static GtkWidget *
|
|
paint_page (void)
|
|
{
|
|
GtkWidget *table;
|
|
GtkWidget *vbox;
|
|
GtkWidget *vbox2;
|
|
GtkWidget *hbox;
|
|
GtkWidget *toggle;
|
|
GtkWidget *page_menu_type;
|
|
GtkWidget *scale_scale;
|
|
GtkObject *scale_scale_data;
|
|
GtkWidget *item1, *item2, *item3;
|
|
|
|
vbox = gtk_vbox_new (FALSE, 0);
|
|
gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
|
|
|
|
table = gtk_table_new (5, 2, FALSE);
|
|
gtk_table_set_col_spacings (GTK_TABLE (table), 4);
|
|
gtk_table_set_row_spacings (GTK_TABLE (table), 2);
|
|
gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
|
|
gtk_widget_show (table);
|
|
|
|
page_menu_layers =
|
|
gimp_option_menu_new2 (FALSE, paint_menu_callback,
|
|
(gpointer) PAINT_LAYERS_MENU, 0,
|
|
|
|
_("Original"), (gpointer) ORIGINAL_LAYER, NULL,
|
|
_("New"), (gpointer) SINGLE_LAYER, NULL,
|
|
_("Multiple"), (gpointer) MULTI_LAYER, NULL,
|
|
|
|
NULL);
|
|
|
|
gimp_help_set_help_data (page_menu_layers,
|
|
_("Draw all objects on one layer (original or new) "
|
|
"or one object per layer"), NULL);
|
|
if (gimp_drawable_is_channel (gfig_drawable))
|
|
gtk_widget_set_sensitive (page_menu_layers, FALSE);
|
|
gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
|
|
_("Draw on:"), 1.0, 0.5,
|
|
page_menu_layers, 1, TRUE);
|
|
|
|
page_menu_type =
|
|
gimp_option_menu_new2 (FALSE, paint_menu_callback,
|
|
(gpointer) PAINT_TYPE_MENU, 0,
|
|
|
|
_("Brush"),
|
|
(gpointer) PAINT_BRUSH_TYPE, &item1,
|
|
_("Selection"),
|
|
(gpointer) PAINT_SELECTION_TYPE, &item2,
|
|
_("Selection+Fill"),
|
|
(gpointer) PAINT_SELECTION_FILL_TYPE, &item3,
|
|
|
|
NULL);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (item1), "activate",
|
|
GTK_SIGNAL_FUNC (gfig_brush_pane_activate),
|
|
(gpointer) 1);
|
|
gtk_signal_connect (GTK_OBJECT (item1), "activate",
|
|
GTK_SIGNAL_FUNC (gfig_select_pane_activate),
|
|
(gpointer) 0);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (item2), "activate",
|
|
GTK_SIGNAL_FUNC (gfig_brush_pane_activate),
|
|
(gpointer) 0);
|
|
gtk_signal_connect (GTK_OBJECT (item2), "activate",
|
|
GTK_SIGNAL_FUNC (gfig_select_pane_activate),
|
|
(gpointer) 1);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (item3), "activate",
|
|
GTK_SIGNAL_FUNC (gfig_brush_pane_activate),
|
|
(gpointer) 0);
|
|
gtk_signal_connect (GTK_OBJECT (item3), "activate",
|
|
GTK_SIGNAL_FUNC (gfig_select_pane_activate),
|
|
(gpointer) 1);
|
|
|
|
gimp_help_set_help_data (page_menu_type,
|
|
_("Draw type. Either a brush or a selection. "
|
|
"See brush page or selection page for more options"),
|
|
NULL);
|
|
gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
|
|
_("Using:"), 1.0, 0.5,
|
|
page_menu_type, 1, TRUE);
|
|
|
|
page_menu_bg =
|
|
gimp_option_menu_new2 (FALSE, paint_menu_callback,
|
|
(gpointer) PAINT_BGS_MENU, 0,
|
|
|
|
_("Transparent"), (gpointer) LAYER_TRANS_BG, NULL,
|
|
_("Background"), (gpointer) LAYER_BG_BG, NULL,
|
|
_("Foreground"), (gpointer) LAYER_FG_BG, NULL,
|
|
_("White"), (gpointer) LAYER_WHITE_BG, NULL,
|
|
_("Copy"), (gpointer) LAYER_COPY_BG, NULL,
|
|
|
|
NULL);
|
|
gimp_help_set_help_data (page_menu_bg,
|
|
_("Layer background type. Copy causes previous "
|
|
"layer to be copied before the draw is performed"),
|
|
NULL);
|
|
gtk_widget_set_sensitive (page_menu_bg, FALSE);
|
|
gimp_table_attach_aligned (GTK_TABLE (table), 0, 2,
|
|
_("With BG of:"), 1.0, 0.5,
|
|
page_menu_bg, 1, TRUE);
|
|
|
|
toggle = gtk_check_button_new_with_label (_("Reverse Line"));
|
|
gtk_table_attach (GTK_TABLE (table), toggle, 0, 1, 4, 5,
|
|
GTK_FILL, GTK_FILL, 0, 0);
|
|
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
|
|
GTK_SIGNAL_FUNC (gimp_toggle_button_update),
|
|
(gpointer)&selvals.reverselines);
|
|
gimp_help_set_help_data (toggle,
|
|
_("Draw lines in reverse order"), NULL);
|
|
gtk_widget_show (toggle);
|
|
|
|
vbox2 = gtk_vbox_new (FALSE, 0);
|
|
gtk_table_attach (GTK_TABLE (table), vbox2, 0, 1, 3, 4,
|
|
GTK_FILL, GTK_FILL, 0, 0);
|
|
gtk_widget_show (vbox2);
|
|
|
|
toggle = gtk_check_button_new_with_label (_("Scale to Image"));
|
|
gtk_box_pack_end (GTK_BOX (vbox2), toggle, FALSE, FALSE, 0);
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
|
|
selvals.scaletoimage);
|
|
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
|
|
GTK_SIGNAL_FUNC (gfig_scale2img_update),
|
|
&selvals.scaletoimage);
|
|
gimp_help_set_help_data (toggle,
|
|
_("Scale drawings to images size"), NULL);
|
|
gtk_widget_show (toggle);
|
|
|
|
hbox = gtk_hbox_new (FALSE, 1);
|
|
scale_scale_data = gtk_adjustment_new (1.0, 0.1, 5.0, 0.01, 0.01, 0.0);
|
|
scale_scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_scale_data));
|
|
gtk_box_pack_start (GTK_BOX (hbox), scale_scale, TRUE, TRUE, 0);
|
|
gtk_scale_set_value_pos (GTK_SCALE (scale_scale), GTK_POS_TOP);
|
|
gtk_scale_set_digits (GTK_SCALE (scale_scale), 2);
|
|
gtk_range_set_update_policy (GTK_RANGE (scale_scale), GTK_UPDATE_CONTINUOUS);
|
|
gtk_signal_connect (GTK_OBJECT (scale_scale_data), "value_changed",
|
|
GTK_SIGNAL_FUNC (gfig_scale_update_scale),
|
|
&selvals.scaletoimagefp);
|
|
gtk_widget_show (scale_scale);
|
|
gtk_widget_show (hbox);
|
|
gtk_table_attach (GTK_TABLE (table), hbox, 1, 2, 3, 4,
|
|
GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
|
|
|
|
gtk_widget_set_sensitive (GTK_WIDGET (scale_scale), FALSE);
|
|
gtk_object_set_data (GTK_OBJECT (toggle), "inverse_sensitive", scale_scale);
|
|
gtk_object_set_user_data (GTK_OBJECT (toggle), scale_scale_data);
|
|
|
|
toggle = gtk_check_button_new_with_label (_("Approx. Circles/Ellipses"));
|
|
gtk_table_attach (GTK_TABLE (table), toggle, 1, 2, 4, 5,
|
|
GTK_FILL, GTK_FILL, 0, 0);
|
|
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
|
|
GTK_SIGNAL_FUNC (gimp_toggle_button_update),
|
|
&selvals.approxcircles);
|
|
gimp_help_set_help_data (toggle,
|
|
_("Approx. circles & ellipses using lines. Allows "
|
|
"the use of brush fading with these types of "
|
|
"objects."), NULL);
|
|
gtk_widget_show (toggle);
|
|
|
|
return vbox;
|
|
}
|
|
|
|
static void
|
|
gfig_brush_invoker (gchar *name,
|
|
gdouble opacity,
|
|
gint spacing,
|
|
gint paint_mode,
|
|
gint width,
|
|
gint height,
|
|
gchar *mask_data,
|
|
gint closing,
|
|
gpointer udata)
|
|
{
|
|
BrushDesc *bdesc = g_new0 (BrushDesc, 1); /* Mem leak */
|
|
|
|
bdesc->bpp = 3;
|
|
bdesc->width = width;
|
|
bdesc->height = height;
|
|
bdesc->bname = g_strdup (name);
|
|
|
|
brush_list_button_callback (NULL, bdesc);
|
|
}
|
|
|
|
static void
|
|
select_brush_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
BrushDesc *bdesc = g_new0 (BrushDesc, 1);
|
|
|
|
gimp_interactive_selection_brush ("Gfig brush selection",
|
|
mygimp_brush_get (),
|
|
1.0, /* Opacity */
|
|
-1, /* spacing (default)*/
|
|
1, /* Paint mode */
|
|
gfig_brush_invoker,
|
|
NULL);
|
|
|
|
bdesc->bpp = 3;
|
|
bdesc->bname = mygimp_brush_get ();
|
|
|
|
brush_list_button_callback (NULL, bdesc);
|
|
}
|
|
|
|
static GtkWidget *
|
|
brush_page (void)
|
|
{
|
|
GtkWidget *table;
|
|
GtkWidget *label;
|
|
GtkWidget *pw;
|
|
GtkWidget *scale;
|
|
GtkObject *fade_out_scale_data;
|
|
GtkObject *gradient_scale_data;
|
|
GtkObject *pressure_scale_data;
|
|
GtkWidget *vbox;
|
|
GtkWidget *button;
|
|
BrushDesc *bdesc = g_new0 (BrushDesc, 1); /* Initial brush settings */
|
|
|
|
vbox = gtk_vbox_new (FALSE, 0);
|
|
gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
|
|
|
|
table = gtk_table_new (2, 3, FALSE);
|
|
gtk_table_set_col_spacings (GTK_TABLE (table), 4);
|
|
gtk_table_set_row_spacings (GTK_TABLE (table), 2);
|
|
gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
|
|
gtk_widget_show (table);
|
|
|
|
/* Fade option */
|
|
/* the fade-out scale From GIMP itself*/
|
|
fade_out_hbox = gtk_hbox_new (FALSE, 4);
|
|
|
|
label = gtk_label_new (_("Fade out:"));
|
|
gtk_misc_set_alignment (GTK_MISC (label), 1.0, 1.0);
|
|
gtk_box_pack_start (GTK_BOX (fade_out_hbox), label, FALSE, FALSE, 0);
|
|
gtk_widget_show (label);
|
|
|
|
fade_out_scale_data = gtk_adjustment_new (0.0, 0.0, 3000.0, 1.0, 1.0, 0.0);
|
|
scale = gtk_hscale_new (GTK_ADJUSTMENT (fade_out_scale_data));
|
|
gtk_box_pack_start (GTK_BOX (fade_out_hbox), scale, TRUE, TRUE, 0);
|
|
gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
|
|
gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED);
|
|
gtk_signal_connect (GTK_OBJECT (fade_out_scale_data), "value_changed",
|
|
GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
|
|
&selvals.brushfade);
|
|
gtk_widget_show (scale);
|
|
|
|
gtk_table_attach (GTK_TABLE (table), fade_out_hbox, 0, 2, 1, 2,
|
|
GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
|
|
gtk_widget_show (fade_out_hbox);
|
|
|
|
|
|
/* Gradient drawing */
|
|
gradient_hbox = gtk_hbox_new (FALSE, 4);
|
|
|
|
label = gtk_label_new (_("Gradient:"));
|
|
gtk_misc_set_alignment (GTK_MISC (label), 1.0, 1.0);
|
|
gtk_box_pack_start (GTK_BOX (gradient_hbox), label, FALSE, FALSE, 0);
|
|
gtk_widget_show (label);
|
|
|
|
gradient_scale_data = gtk_adjustment_new (0.0, 0.0, 3000.0, 1.0, 1.0, 0.0);
|
|
scale = gtk_hscale_new (GTK_ADJUSTMENT (gradient_scale_data));
|
|
gtk_box_pack_start (GTK_BOX (gradient_hbox), scale, TRUE, TRUE, 0);
|
|
gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
|
|
gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED);
|
|
gtk_signal_connect (GTK_OBJECT (gradient_scale_data), "value_changed",
|
|
GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
|
|
&selvals.brushgradient);
|
|
gtk_widget_show (scale);
|
|
gtk_table_attach (GTK_TABLE (table), gradient_hbox, 0, 2, 2, 3,
|
|
GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
|
|
gtk_widget_show (gradient_hbox);
|
|
|
|
|
|
pressure_hbox = gtk_hbox_new (FALSE, 4);
|
|
label = gtk_label_new (_("Pressure:"));
|
|
gtk_misc_set_alignment (GTK_MISC (label), 1.0, 1.0);
|
|
gtk_box_pack_start (GTK_BOX (pressure_hbox), label, FALSE, FALSE, 0);
|
|
gtk_widget_show (label);
|
|
|
|
pressure_scale_data = gtk_adjustment_new (20.0, 0.0, 100.0, 1.0, 1.0, 0.0);
|
|
scale = gtk_hscale_new (GTK_ADJUSTMENT (pressure_scale_data));
|
|
gtk_box_pack_start (GTK_BOX (pressure_hbox), scale, TRUE, TRUE, 0);
|
|
gtk_widget_show (scale);
|
|
gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
|
|
gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED);
|
|
gtk_signal_connect (GTK_OBJECT (pressure_scale_data), "value_changed",
|
|
GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
|
|
&selvals.airbrushpressure);
|
|
gtk_table_attach (GTK_TABLE (table), pressure_hbox, 0, 2, 1, 2,
|
|
GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
|
|
|
|
pencil_hbox = gtk_hbox_new (FALSE, 4);
|
|
label = gtk_label_new (_("No Options..."));
|
|
gtk_box_pack_start (GTK_BOX (pencil_hbox), label, FALSE, FALSE, 0);
|
|
gtk_widget_show (label);
|
|
gtk_table_attach (GTK_TABLE (table), pencil_hbox, 0, 2, 1, 2,
|
|
GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
|
|
|
|
/* Preview widget */
|
|
pw = gfig_brush_preview (&brush_page_pw);
|
|
gtk_table_attach (GTK_TABLE (table), pw, 0, 1, 0, 1, 0, 0, 0, 0);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (pressure_scale_data), "value_changed",
|
|
GTK_SIGNAL_FUNC (gfig_brush_update_preview),
|
|
(gpointer)brush_page_pw);
|
|
|
|
/* Start of new brush selection code */
|
|
brush_sel_button = button = gtk_button_new_with_label ("Set Brush...");
|
|
gtk_misc_set_padding (GTK_MISC (GTK_BIN (brush_sel_button)->child), 2, 0);
|
|
gtk_signal_connect (GTK_OBJECT (button), "clicked",
|
|
GTK_SIGNAL_FUNC (select_brush_callback),
|
|
NULL);
|
|
gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
|
|
NULL, 0, 0,
|
|
button, 1, TRUE);
|
|
|
|
/* Setup initial brush settings */
|
|
bdesc->bpp = 3;
|
|
bdesc->bname = mygimp_brush_get ();
|
|
brush_list_button_callback (NULL, bdesc);
|
|
|
|
return vbox;
|
|
}
|
|
|
|
static void
|
|
select_menu_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
gint mtype = (gint) data;
|
|
|
|
if (mtype == SELECT_TYPE_MENU)
|
|
{
|
|
SelectionType type =
|
|
(SelectionType) gtk_object_get_user_data (GTK_OBJECT (widget));
|
|
|
|
selopt.type = type;
|
|
}
|
|
else if (mtype == SELECT_ARCTYPE_MENU)
|
|
{
|
|
ArcType type =
|
|
(ArcType) gtk_object_get_user_data (GTK_OBJECT (widget));
|
|
|
|
selopt.as_pie = type;
|
|
}
|
|
else if (mtype == SELECT_TYPE_MENU_FILL)
|
|
{
|
|
FillType type =
|
|
(FillType) gtk_object_get_user_data (GTK_OBJECT (widget));
|
|
|
|
selopt.fill_type = type;
|
|
}
|
|
else if (mtype == SELECT_TYPE_MENU_WHEN)
|
|
{
|
|
FillWhen type =
|
|
(FillWhen) gtk_object_get_user_data (GTK_OBJECT (widget));
|
|
selopt.fill_when = type;
|
|
}
|
|
}
|
|
|
|
static GtkWidget *
|
|
select_page (void)
|
|
{
|
|
GtkWidget *menu;
|
|
GtkWidget *toggle;
|
|
GtkWidget *scale;
|
|
GtkObject *scale_data;
|
|
GtkWidget *table;
|
|
GtkWidget *vbox;
|
|
|
|
vbox = gtk_vbox_new (FALSE, 0);
|
|
gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
|
|
|
|
table = gtk_table_new (4, 4, FALSE);
|
|
gtk_table_set_row_spacings (GTK_TABLE (table), 4);
|
|
gtk_table_set_col_spacings (GTK_TABLE (table), 2);
|
|
gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
|
|
gtk_widget_show (table);
|
|
|
|
/* The secltion settings -
|
|
* 1) Type (option menu)
|
|
* 2) Anti A (toggle)
|
|
* 3) Feather (toggle)
|
|
* 4) F radius (slider)
|
|
* 5) Fill type (option menu)
|
|
* 6) Opacity (slider)
|
|
* 7) When to fill (toggle)
|
|
* 8) Arc as segment/sector
|
|
*/
|
|
|
|
/* 1 */
|
|
menu = gimp_option_menu_new2 (FALSE, select_menu_callback,
|
|
(gpointer) SELECT_TYPE_MENU, 0,
|
|
|
|
_("Add"), (gpointer) ADD, NULL,
|
|
_("Subtract"), (gpointer) SUBTRACT, NULL,
|
|
_("Replace"), (gpointer) REPLACE, NULL,
|
|
_("Intersect"), (gpointer) INTERSECT, NULL,
|
|
|
|
NULL);
|
|
gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
|
|
_("Selection Type:"), 1.0, 0.5,
|
|
menu, 1, FALSE);
|
|
|
|
/* 2 */
|
|
toggle = gtk_check_button_new_with_label (_("Antialiasing"));
|
|
gtk_table_attach (GTK_TABLE (table), toggle, 2, 4, 0, 1,
|
|
GTK_FILL, GTK_FILL, 0, 0);
|
|
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
|
|
GTK_SIGNAL_FUNC (gimp_toggle_button_update),
|
|
&selopt.antia);
|
|
gtk_widget_show (toggle);
|
|
|
|
/* 3 */
|
|
toggle = gtk_check_button_new_with_label (_("Feather"));
|
|
gtk_table_attach (GTK_TABLE (table), toggle, 2, 4, 2, 3,
|
|
GTK_FILL, GTK_FILL, 0, 0);
|
|
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
|
|
GTK_SIGNAL_FUNC (gimp_toggle_button_update),
|
|
&selopt.feather);
|
|
gtk_widget_show (toggle);
|
|
|
|
/* 4 */
|
|
scale_data =
|
|
gtk_adjustment_new (selopt.feather_radius, 0.0, 100.0, 1.0, 1.0, 0.0);
|
|
scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_data));
|
|
gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
|
|
gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED);
|
|
gtk_signal_connect (GTK_OBJECT (scale_data), "value_changed",
|
|
GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
|
|
&selopt.feather_radius);
|
|
gimp_table_attach_aligned (GTK_TABLE (table), 2, 3,
|
|
_("Radius:"), 1.0, 1.0,
|
|
scale, 1, FALSE);
|
|
|
|
/* 5 */
|
|
menu =
|
|
gimp_option_menu_new2 (FALSE, select_menu_callback,
|
|
(gpointer) SELECT_TYPE_MENU_FILL, 0,
|
|
|
|
_("Pattern"), (gpointer) FILL_PATTERN, NULL,
|
|
_("Foreground"), (gpointer) FILL_FOREGROUND, NULL,
|
|
_("Background"), (gpointer) FILL_BACKGROUND, NULL,
|
|
|
|
NULL);
|
|
gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
|
|
_("Fill Type:"), 1.0, 0.5,
|
|
menu, 1, FALSE);
|
|
|
|
/* 6 */
|
|
scale_data =
|
|
gtk_adjustment_new (selopt.fill_opacity, 0.0, 100.0, 1.0, 1.0, 0.0);
|
|
scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_data));
|
|
gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
|
|
gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED);
|
|
gtk_signal_connect (GTK_OBJECT (scale_data), "value_changed",
|
|
GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
|
|
&selopt.fill_opacity);
|
|
gimp_table_attach_aligned (GTK_TABLE (table), 2, 1,
|
|
_("Fill Opacity:"), 1.0, 1.0,
|
|
scale, 1, FALSE);
|
|
|
|
/* 7 */
|
|
menu =
|
|
gimp_option_menu_new2 (FALSE, select_menu_callback,
|
|
(gpointer) SELECT_TYPE_MENU_WHEN, 0,
|
|
|
|
_("Each Selection"), (gpointer) FILL_EACH, NULL,
|
|
_("All Selections"), (gpointer) FILL_AFTER, NULL,
|
|
|
|
NULL);
|
|
gimp_table_attach_aligned (GTK_TABLE (table), 0, 2,
|
|
_("Fill after:"), 1.0, 0.5,
|
|
menu, 1, FALSE);
|
|
|
|
/* 8 */
|
|
menu = gimp_option_menu_new2 (FALSE, select_menu_callback,
|
|
(gpointer) SELECT_ARCTYPE_MENU, 0,
|
|
|
|
_("Segment"), (gpointer) ARC_SEGMENT, NULL,
|
|
_("Sector"), (gpointer) ARC_SECTOR, NULL,
|
|
|
|
NULL);
|
|
gimp_table_attach_aligned (GTK_TABLE (table), 0, 3,
|
|
_("Arc as:"), 1.0, 0.5,
|
|
menu, 1, FALSE);
|
|
|
|
return vbox;
|
|
}
|
|
|
|
static void
|
|
gridtype_menu_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
gint mtype = (gint)data;
|
|
|
|
if (mtype == GRID_TYPE_MENU)
|
|
{
|
|
#ifdef DEBUG
|
|
printf ("Gridtype set to ");
|
|
if (current_obj->opts.gridtype == RECT_GRID)
|
|
printf ("RECT_GRID\n");
|
|
else if (current_obj->opts.gridtype == POLAR_GRID)
|
|
printf ("POLAR_GRID\n");
|
|
else if (current_obj->opts.gridtype == ISO_GRID)
|
|
printf ("ISO_GRID\n");
|
|
else printf ("NONE\n");
|
|
#endif /* DEBUG */
|
|
selvals.opts.gridtype = (GridType)gtk_object_get_user_data (GTK_OBJECT (widget));
|
|
}
|
|
else
|
|
{
|
|
grid_gc_type = (gint) gtk_object_get_user_data (GTK_OBJECT (widget));
|
|
}
|
|
|
|
draw_grid_clear (widget, 0);
|
|
}
|
|
|
|
static GtkWidget *
|
|
options_page (void)
|
|
{
|
|
GtkWidget *table;
|
|
GtkWidget *menu;
|
|
GtkWidget *toggle;
|
|
GtkWidget *button;
|
|
GtkWidget *vbox;
|
|
GtkObject *size_data;
|
|
|
|
vbox = gtk_vbox_new (FALSE, 0);
|
|
gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
|
|
|
|
table = gtk_table_new (6, 3, FALSE);
|
|
gtk_table_set_col_spacings (GTK_TABLE (table), 4);
|
|
gtk_table_set_row_spacings (GTK_TABLE (table), 2);
|
|
gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
|
|
gtk_widget_show (table);
|
|
|
|
/* Put buttons in */
|
|
toggle = gtk_check_button_new_with_label (_("Show Image"));
|
|
gtk_table_attach (GTK_TABLE (table), toggle, 0, 1, 0, 1,
|
|
GTK_FILL, GTK_FILL, 0, 0);
|
|
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
|
|
GTK_SIGNAL_FUNC (gimp_toggle_button_update),
|
|
&selvals.showimage);
|
|
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
|
|
(GtkSignalFunc) toggle_show_image,
|
|
(gpointer) 1);
|
|
gtk_widget_show (toggle);
|
|
|
|
button = gtk_button_new_with_label (_("Reload Image"));
|
|
gtk_misc_set_padding (GTK_MISC (GTK_BIN (button)->child), 2, 0);
|
|
gtk_signal_connect (GTK_OBJECT (button), "clicked",
|
|
GTK_SIGNAL_FUNC (reload_button_callback),
|
|
NULL);
|
|
gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
|
|
NULL, 0, 0,
|
|
button, 1, TRUE);
|
|
|
|
menu = gimp_option_menu_new2 (FALSE, gridtype_menu_callback,
|
|
(gpointer) GRID_TYPE_MENU, 0,
|
|
|
|
_("Rectangle"), (gpointer) RECT_GRID, NULL,
|
|
_("Polar"), (gpointer) POLAR_GRID, NULL,
|
|
_("Isometric"), (gpointer) ISO_GRID, NULL,
|
|
|
|
NULL);
|
|
gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
|
|
_("Grid Type:"), 1.0, 0.5,
|
|
menu, 1, TRUE);
|
|
|
|
gfig_opt_widget.gridtypemenu = menu;
|
|
|
|
menu =
|
|
gimp_option_menu_new2 (FALSE, gridtype_menu_callback,
|
|
(gpointer) GRID_RENDER_MENU, 0,
|
|
|
|
_("Normal"), (gpointer) GTK_STATE_NORMAL, NULL,
|
|
_("Black"), (gpointer) GFIG_BLACK_GC, NULL,
|
|
_("White"), (gpointer) GFIG_WHITE_GC, NULL,
|
|
_("Grey"), (gpointer) GFIG_GREY_GC, NULL,
|
|
_("Darker"), (gpointer) GTK_STATE_ACTIVE, NULL,
|
|
_("Lighter"), (gpointer) GTK_STATE_PRELIGHT, NULL,
|
|
_("Very Dark"), (gpointer) GTK_STATE_SELECTED, NULL,
|
|
|
|
NULL);
|
|
gimp_table_attach_aligned (GTK_TABLE (table), 0, 2,
|
|
_("Grid Color:"), 1.0, 0.5,
|
|
menu, 1, TRUE);
|
|
|
|
size_data = gimp_scale_entry_new (GTK_TABLE (table), 0, 3,
|
|
_("Max Undo:"), 0, 50,
|
|
selvals.maxundo, MIN_UNDO, MAX_UNDO, 1, 2, 0,
|
|
TRUE, 0, 0,
|
|
NULL, NULL);
|
|
gtk_signal_connect (GTK_OBJECT (size_data), "value_changed",
|
|
GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
|
|
&selvals.maxundo);
|
|
|
|
toggle = gtk_check_button_new_with_label (_("Show Position"));
|
|
gtk_table_attach (GTK_TABLE (table), toggle, 0, 1, 4, 5,
|
|
GTK_FILL, GTK_FILL, 0, 0);
|
|
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
|
|
GTK_SIGNAL_FUNC (gimp_toggle_button_update),
|
|
&selvals.showpos);
|
|
gtk_signal_connect_after (GTK_OBJECT (toggle), "toggled",
|
|
(GtkSignalFunc) gfig_pos_enable,
|
|
(gpointer) 1);
|
|
gtk_widget_show (toggle);
|
|
|
|
toggle = gtk_check_button_new_with_label (_("Hide Control Points"));
|
|
gtk_table_attach (GTK_TABLE (table), toggle, 1, 3, 4, 5,
|
|
GTK_FILL, GTK_FILL, 0, 0);
|
|
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
|
|
GTK_SIGNAL_FUNC (gimp_toggle_button_update),
|
|
&selvals.opts.showcontrol);
|
|
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
|
|
GTK_SIGNAL_FUNC (toggle_show_image),
|
|
(gpointer) 1);
|
|
gtk_widget_show (toggle);
|
|
gfig_opt_widget.showcontrol = toggle;
|
|
|
|
toggle = gtk_check_button_new_with_label (_("Show Tooltips"));
|
|
gtk_table_attach (GTK_TABLE (table), toggle, 0, 1, 5, 6,
|
|
GTK_FILL, GTK_FILL, 0, 0);
|
|
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
|
|
GTK_SIGNAL_FUNC (toggle_tooltips),
|
|
&selvals.showtooltips);
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
|
|
selvals.showtooltips);
|
|
gtk_widget_show (toggle);
|
|
|
|
button = gtk_button_new_with_label (_("About"));
|
|
gtk_misc_set_padding (GTK_MISC (GTK_BIN (button)->child), 8, 0);
|
|
gtk_table_attach (GTK_TABLE (table), button, 1, 3, 5, 6,
|
|
0, 0, 0, 0);
|
|
gtk_signal_connect (GTK_OBJECT (button), "clicked",
|
|
GTK_SIGNAL_FUNC (about_button_callback),
|
|
NULL);
|
|
gtk_widget_show (button);
|
|
|
|
return vbox;
|
|
}
|
|
|
|
static GtkWidget *
|
|
grid_frame (void)
|
|
{
|
|
GtkWidget *frame;
|
|
GtkWidget *vbox;
|
|
GtkWidget *hbox;
|
|
GtkWidget *table;
|
|
GtkWidget *toggle;
|
|
GtkObject *size_data;
|
|
|
|
frame = gtk_frame_new (_("Grid"));
|
|
|
|
vbox = gtk_vbox_new (FALSE, 2);
|
|
gtk_container_set_border_width (GTK_CONTAINER (vbox), 2);
|
|
gtk_container_add (GTK_CONTAINER (frame), vbox);
|
|
gtk_widget_show (vbox);
|
|
|
|
hbox = gtk_hbox_new (FALSE, 4);
|
|
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
|
|
gtk_widget_show (hbox);
|
|
|
|
toggle = gtk_check_button_new_with_label (_("Snap to Grid"));
|
|
gtk_box_pack_start (GTK_BOX (hbox), toggle, FALSE, FALSE, 0);
|
|
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
|
|
GTK_SIGNAL_FUNC (gimp_toggle_button_update),
|
|
&selvals.opts.snap2grid);
|
|
gtk_widget_show (toggle);
|
|
gfig_opt_widget.snap2grid = toggle;
|
|
|
|
toggle = gtk_check_button_new_with_label (_("Display Grid"));
|
|
gtk_box_pack_start (GTK_BOX (hbox), toggle, FALSE, FALSE, 0);
|
|
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
|
|
GTK_SIGNAL_FUNC (gimp_toggle_button_update),
|
|
&selvals.opts.drawgrid);
|
|
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
|
|
GTK_SIGNAL_FUNC (draw_grid_clear),
|
|
(gpointer) 1);
|
|
gtk_widget_show (toggle);
|
|
gfig_opt_widget.drawgrid = toggle;
|
|
|
|
toggle = gtk_check_button_new_with_label (_("Lock on Grid"));
|
|
gtk_box_pack_start (GTK_BOX (hbox), toggle, FALSE, FALSE, 0);
|
|
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
|
|
GTK_SIGNAL_FUNC (gimp_toggle_button_update),
|
|
&selvals.opts.lockongrid);
|
|
gtk_widget_show (toggle);
|
|
gfig_opt_widget.lockongrid = toggle;
|
|
|
|
table = gtk_table_new (1, 3, FALSE);
|
|
gtk_table_set_col_spacings (GTK_TABLE (table), 4);
|
|
gtk_table_set_row_spacings (GTK_TABLE (table), 2);
|
|
gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
|
|
gtk_widget_show (table);
|
|
|
|
size_data = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
|
|
_("Grid Spacing:"), 0, 50,
|
|
selvals.opts.gridspacing,
|
|
MIN_GRID, MAX_GRID, 1, 10, 0,
|
|
TRUE, 0, 0,
|
|
NULL, NULL);
|
|
gtk_signal_connect (GTK_OBJECT (size_data), "value_changed",
|
|
GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
|
|
&selvals.opts.gridspacing);
|
|
gtk_signal_connect (GTK_OBJECT (size_data), "value_changed",
|
|
GTK_SIGNAL_FUNC (draw_grid_clear),
|
|
(gpointer) 0);
|
|
gfig_opt_widget.gridspacing = size_data;
|
|
|
|
gtk_widget_show (frame);
|
|
|
|
return frame;
|
|
}
|
|
|
|
static void
|
|
clear_list_items (GtkList *list)
|
|
{
|
|
gtk_list_clear_items (list, 0, -1);
|
|
}
|
|
|
|
static void
|
|
build_list_items (GtkWidget *list)
|
|
{
|
|
GList *tmp;
|
|
GtkWidget *list_item;
|
|
GtkWidget *list_pix;
|
|
GFigObj *g;
|
|
|
|
for (tmp = gfig_list; tmp; tmp = g_list_next (tmp))
|
|
{
|
|
g = tmp->data;
|
|
|
|
if (g->obj_status & GFIG_READONLY)
|
|
list_pix = gimp_pixmap_new (mini_cross_xpm);
|
|
else
|
|
list_pix = gimp_pixmap_new (blank_xpm);
|
|
|
|
list_item =
|
|
gfig_list_item_new_with_label_and_pixmap (g, g->draw_name, list_pix);
|
|
|
|
gtk_object_set_user_data (GTK_OBJECT (list_item), (gpointer) g);
|
|
gtk_list_append_items (GTK_LIST (list), g_list_append (NULL, list_item));
|
|
|
|
gtk_signal_connect (GTK_OBJECT (list_item), "button_press_event",
|
|
GTK_SIGNAL_FUNC (list_button_press),
|
|
(gpointer) g);
|
|
gtk_widget_show (list_item);
|
|
}
|
|
}
|
|
|
|
static GtkWidget *
|
|
add_objects_list (void)
|
|
{
|
|
GtkWidget *vbox;
|
|
GtkWidget *table;
|
|
GtkWidget *frame;
|
|
GtkWidget *list_frame;
|
|
GtkWidget *scrolled_win;
|
|
GtkWidget *list;
|
|
GtkWidget *button;
|
|
|
|
frame = gtk_frame_new (_("Object"));
|
|
gtk_widget_show (frame);
|
|
|
|
table = gtk_table_new (4, 3, FALSE);
|
|
gtk_table_set_col_spacings (GTK_TABLE (table), 2);
|
|
gtk_container_set_border_width (GTK_CONTAINER (table), 2);
|
|
gtk_widget_show (table);
|
|
|
|
delete_frame_to_freeze = list_frame = gtk_frame_new (NULL);
|
|
gtk_widget_show (list_frame);
|
|
|
|
scrolled_win = gtk_scrolled_window_new (NULL, NULL);
|
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
|
|
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
|
gtk_container_add (GTK_CONTAINER (list_frame), scrolled_win);
|
|
gtk_widget_show (scrolled_win);
|
|
|
|
gfig_gtk_list = list = gtk_list_new ();
|
|
/* gtk_list_set_selection_mode (GTK_LIST (list), GTK_SELECTION_MULTIPLE); */
|
|
gtk_list_set_selection_mode (GTK_LIST (list), GTK_SELECTION_BROWSE);
|
|
gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_win),
|
|
list);
|
|
gtk_widget_show (list);
|
|
|
|
/* Load saved objects */
|
|
gfig_list_load_all (gfig_path_list);
|
|
|
|
/* Put list in */
|
|
build_list_items (list);
|
|
|
|
/* Put buttons in */
|
|
button = gtk_button_new_with_label (_("Rescan"));
|
|
gtk_signal_connect (GTK_OBJECT (button), "clicked",
|
|
GTK_SIGNAL_FUNC (rescan_button_callback),
|
|
NULL);
|
|
gimp_help_set_help_data (button,
|
|
_("Select directory and rescan Gfig object "
|
|
"collection"), NULL);
|
|
gtk_table_attach (GTK_TABLE (table), button, 2, 3, 0, 1,
|
|
GTK_FILL, GTK_FILL, 0, 0);
|
|
gtk_widget_show (button);
|
|
|
|
button = gtk_button_new_with_label (_("Load"));
|
|
gtk_signal_connect (GTK_OBJECT (button), "clicked",
|
|
GTK_SIGNAL_FUNC (load_button_callback),
|
|
list);
|
|
gimp_help_set_help_data (button,
|
|
_("Load a single Gfig object collection"), NULL);
|
|
gtk_table_attach (GTK_TABLE (table), button, 2, 3, 1, 2,
|
|
GTK_FILL, GTK_FILL, 0, 0);
|
|
gtk_widget_show (button);
|
|
|
|
button = gtk_button_new_with_label (_("New"));
|
|
gtk_signal_connect (GTK_OBJECT (button), "clicked",
|
|
GTK_SIGNAL_FUNC (new_button_callback),
|
|
"New gfig obj");
|
|
gimp_help_set_help_data (button, _("Create a new Gfig object collection "
|
|
"for editing"), NULL);
|
|
gtk_table_attach (GTK_TABLE (table), button, 2, 3, 2, 3,
|
|
GTK_FILL, GTK_FILL, 0, 0);
|
|
gtk_widget_show (button);
|
|
|
|
button = gtk_button_new_with_label (_("Delete"));
|
|
gtk_signal_connect (GTK_OBJECT (button), "clicked",
|
|
GTK_SIGNAL_FUNC (gfig_delete_gfig_callback),
|
|
(gpointer) list);
|
|
gimp_help_set_help_data (button, _("Delete currently selected Gfig Object "
|
|
"collection"), NULL);
|
|
gtk_table_attach (GTK_TABLE (table), button, 2, 3, 3, 4,
|
|
GTK_FILL, GTK_FILL, 0, 0);
|
|
gtk_widget_show (button);
|
|
|
|
/* Attach the frame for the list Show the widgets */
|
|
|
|
gtk_table_attach (GTK_TABLE (table), list_frame, 1, 2, 0, 4,
|
|
GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0);
|
|
|
|
vbox = small_preview (list);
|
|
gtk_table_attach (GTK_TABLE (table), vbox, 0, 1, 0, 4, 0, 0, 0, 0);
|
|
|
|
gtk_container_add (GTK_CONTAINER (frame), table);
|
|
|
|
return frame;
|
|
}
|
|
|
|
static gint x_pos_val;
|
|
static gint y_pos_val;
|
|
static gint pos_tag = -1;
|
|
|
|
static void
|
|
gfig_pos_enable (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
gint enable = selvals.showpos;
|
|
gtk_widget_set_sensitive (GTK_WIDGET (pos_label), enable);
|
|
}
|
|
|
|
static void
|
|
gfig_pos_update_labels (gpointer data)
|
|
{
|
|
static gchar buf[256];
|
|
|
|
/*gtk_idle_remove (pos_tag);*/
|
|
pos_tag = -1;
|
|
|
|
g_snprintf (buf, sizeof (buf), "%d, %d", x_pos_val, y_pos_val);
|
|
gtk_label_set_text (GTK_LABEL (pos_label), buf);
|
|
}
|
|
|
|
static void
|
|
gfig_pos_update (gint x,
|
|
gint y)
|
|
{
|
|
gint update;
|
|
|
|
if (x_pos_val != x || y_pos_val != y)
|
|
update = 1;
|
|
else
|
|
update = 0;
|
|
|
|
x_pos_val = x;
|
|
y_pos_val = y;
|
|
|
|
if (update && pos_tag == -1 && selvals.showpos)
|
|
{
|
|
/*pos_tag = gtk_idle_add ((GtkFunction)gfig_pos_update_labels, NULL);*/
|
|
gfig_pos_update_labels (NULL);
|
|
}
|
|
}
|
|
|
|
#if 0 /* NOT USED */
|
|
static void
|
|
gfig_obj_size_update (gint sz)
|
|
{
|
|
static gchar buf[256];
|
|
|
|
sprintf (buf, "%6d", sz);
|
|
gtk_label_set_text (GTK_LABEL (obj_size_label), buf);
|
|
}
|
|
|
|
static GtkWidget *
|
|
gfig_obj_size_label (void)
|
|
{
|
|
GtkWidget *label;
|
|
GtkWidget *hbox;
|
|
gchar buf[256];
|
|
|
|
hbox = gtk_hbox_new (TRUE, 6);
|
|
|
|
/* Position labels */
|
|
label = gtk_label_new ("Size: ");
|
|
gtk_widget_show (label);
|
|
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
|
|
|
|
obj_size_label = gtk_label_new ("");
|
|
gtk_misc_set_alignment (GTK_MISC (obj_size_label), 0.5, 0.5);
|
|
gtk_widget_show (obj_size_label);
|
|
gtk_box_pack_start (GTK_BOX (hbox), obj_size_label, FALSE, FALSE, 0);
|
|
|
|
gtk_widget_show (hbox);
|
|
|
|
sprintf (buf, "%6d", 0);
|
|
gtk_label_set_text (GTK_LABEL (obj_size_label), buf);
|
|
|
|
return (hbox);
|
|
}
|
|
|
|
#endif /* NOT USED */
|
|
|
|
static GtkWidget *
|
|
gfig_pos_labels (void)
|
|
{
|
|
GtkWidget *label;
|
|
GtkWidget *hbox;
|
|
gchar buf[256];
|
|
|
|
hbox = gtk_hbox_new (FALSE, 6);
|
|
gtk_widget_show (hbox);
|
|
|
|
/* Position labels */
|
|
label = gtk_label_new (_("XY Position:"));
|
|
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
|
|
gtk_widget_show (label);
|
|
|
|
pos_label = gtk_label_new ("");
|
|
gtk_box_pack_start (GTK_BOX (hbox), pos_label, FALSE, FALSE, 0);
|
|
gtk_widget_show (pos_label);
|
|
|
|
g_snprintf (buf, sizeof (buf), "%d, %d", 0, 0);
|
|
gtk_label_set_text (GTK_LABEL (pos_label), buf);
|
|
|
|
return hbox;
|
|
}
|
|
|
|
static GtkWidget *
|
|
make_pos_info (void)
|
|
{
|
|
GtkWidget *xframe;
|
|
GtkWidget *hbox;
|
|
GtkWidget *label;
|
|
|
|
xframe = gtk_frame_new (_("Object Details"));
|
|
|
|
hbox = gtk_hbox_new (TRUE, 6);
|
|
gtk_container_set_border_width (GTK_CONTAINER (hbox), 2);
|
|
gtk_container_add (GTK_CONTAINER (xframe), hbox);
|
|
|
|
/* Add labels */
|
|
label = gfig_pos_labels ();
|
|
gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
|
|
gfig_pos_enable (NULL, NULL);
|
|
|
|
#if 0
|
|
label = gfig_obj_size_label ();
|
|
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
|
|
#endif /* 0 */
|
|
|
|
gtk_widget_show (hbox);
|
|
gtk_widget_show (xframe);
|
|
|
|
return xframe;
|
|
}
|
|
|
|
static GtkWidget *
|
|
make_status (void)
|
|
{
|
|
GtkWidget *xframe;
|
|
GtkWidget *table;
|
|
GtkWidget *label;
|
|
|
|
xframe = gtk_frame_new (_("Collection Details"));
|
|
|
|
gtk_frame_set_shadow_type (GTK_FRAME (xframe), GTK_SHADOW_ETCHED_IN);
|
|
table = gtk_table_new (6, 6, FALSE);
|
|
gtk_table_set_col_spacing (GTK_TABLE (table), 1, 6);
|
|
gtk_container_set_border_width (GTK_CONTAINER (table), 2);
|
|
|
|
label = gtk_label_new (_("Draw Name:"));
|
|
gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
|
|
gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1,
|
|
GTK_FILL, GTK_FILL, 0, 0);
|
|
gtk_widget_show (label);
|
|
|
|
label = gtk_label_new (_("Filename:"));
|
|
gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
|
|
gtk_table_attach (GTK_TABLE (table), label, 1, 2, 1, 2,
|
|
GTK_FILL, GTK_FILL, 0, 0);
|
|
gtk_widget_show (label);
|
|
|
|
status_label_dname = gtk_label_new (_("(none)"));
|
|
gtk_misc_set_alignment (GTK_MISC (status_label_dname), 0.0, 0.5);
|
|
gtk_table_attach (GTK_TABLE (table), status_label_dname, 2, 4, 0, 1,
|
|
GTK_FILL | GTK_EXPAND, 0, 0, 0);
|
|
gtk_widget_show (status_label_dname);
|
|
|
|
status_label_fname = gtk_label_new (_("(none)"));
|
|
gtk_misc_set_alignment (GTK_MISC (status_label_fname), 0.0, 0.5);
|
|
gtk_table_attach (GTK_TABLE (table), status_label_fname, 2, 4, 1, 2,
|
|
GTK_FILL | GTK_EXPAND, 0, 0, 0);
|
|
gtk_widget_show (status_label_fname);
|
|
|
|
gtk_container_add (GTK_CONTAINER (xframe), table);
|
|
|
|
gtk_widget_show (table);
|
|
gtk_widget_show (xframe);
|
|
|
|
return xframe;
|
|
}
|
|
|
|
static GtkWidget *
|
|
make_preview (void)
|
|
{
|
|
GtkWidget *xframe;
|
|
GtkWidget *vbox;
|
|
GtkWidget *hbox;
|
|
GtkWidget *table;
|
|
GtkWidget *ruler;
|
|
|
|
gfig_preview = gtk_preview_new (GTK_PREVIEW_COLOR);
|
|
gtk_widget_set_events (GTK_WIDGET (gfig_preview), PREVIEW_MASK);
|
|
gfig_preview_exp_id =
|
|
gtk_signal_connect_after (GTK_OBJECT (gfig_preview), "expose_event",
|
|
GTK_SIGNAL_FUNC (gfig_preview_expose),
|
|
NULL);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (gfig_preview), "event",
|
|
GTK_SIGNAL_FUNC (gfig_preview_events),
|
|
NULL);
|
|
|
|
gtk_preview_size (GTK_PREVIEW (gfig_preview), preview_width, preview_height);
|
|
|
|
xframe = gtk_frame_new (NULL);
|
|
|
|
gtk_frame_set_shadow_type (GTK_FRAME (xframe), GTK_SHADOW_IN);
|
|
|
|
table = gtk_table_new (3, 3, FALSE);
|
|
gtk_table_attach (GTK_TABLE (table), gfig_preview, 1, 2, 1, 2,
|
|
GTK_FILL , GTK_FILL , 0, 0);
|
|
gtk_container_add (GTK_CONTAINER (xframe), table);
|
|
|
|
ruler = gtk_hruler_new ();
|
|
gtk_ruler_set_range (GTK_RULER (ruler), 0, preview_width, 0, PREVIEW_SIZE);
|
|
gtk_signal_connect_object (GTK_OBJECT (gfig_preview), "motion_notify_event",
|
|
(GtkSignalFunc) GTK_WIDGET_CLASS (GTK_OBJECT (ruler)->klass)->motion_notify_event,
|
|
GTK_OBJECT (ruler));
|
|
gtk_table_attach (GTK_TABLE (table), ruler, 1, 2, 0, 1,
|
|
GTK_FILL, GTK_FILL, 0, 0);
|
|
gtk_widget_show (ruler);
|
|
|
|
ruler = gtk_vruler_new ();
|
|
gtk_ruler_set_range (GTK_RULER (ruler), 0, preview_height, 0, PREVIEW_SIZE);
|
|
gtk_signal_connect_object (GTK_OBJECT (gfig_preview), "motion_notify_event",
|
|
(GtkSignalFunc) GTK_WIDGET_CLASS (GTK_OBJECT (ruler)->klass)->motion_notify_event,
|
|
GTK_OBJECT (ruler));
|
|
gtk_table_attach (GTK_TABLE (table), ruler, 0, 1, 1, 2,
|
|
GTK_FILL, GTK_FILL, 0, 0);
|
|
gtk_widget_show (ruler);
|
|
|
|
gtk_widget_show (xframe);
|
|
gtk_widget_show (table);
|
|
|
|
vbox = gtk_vbox_new (FALSE, 0);
|
|
hbox = gtk_hbox_new (FALSE, 0);
|
|
gtk_box_pack_start (GTK_BOX (hbox), xframe, FALSE, FALSE, 0);
|
|
|
|
gtk_container_set_border_width (GTK_CONTAINER (vbox), 2);
|
|
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
|
|
|
|
xframe = make_pos_info ();
|
|
gtk_box_pack_start (GTK_BOX (vbox), xframe, TRUE, TRUE, 0);
|
|
|
|
xframe = make_status ();
|
|
gtk_box_pack_start (GTK_BOX (vbox), xframe, TRUE, TRUE, 0);
|
|
|
|
gtk_widget_show (vbox);
|
|
gtk_widget_show (hbox);
|
|
|
|
return vbox;
|
|
}
|
|
|
|
#if 0
|
|
scatch ()
|
|
{
|
|
|
|
pause ();
|
|
|
|
}
|
|
#endif /* 0 */
|
|
|
|
static void
|
|
gfig_grid_colours (GtkWidget *widget,
|
|
GdkColormap *cmap)
|
|
{
|
|
GdkGCValues values;
|
|
GdkColor new_col1;
|
|
GdkColor new_col2;
|
|
guchar stipple[8] =
|
|
{
|
|
0xAA, /* ####---- */
|
|
0x55, /* ###----# */
|
|
0xAA, /* ##----## */
|
|
0x55, /* #----### */
|
|
0xAA, /* ----#### */
|
|
0x55, /* ---####- */
|
|
0xAA, /* --####-- */
|
|
0x55, /* -####--- */
|
|
};
|
|
|
|
gdk_color_parse ("gray50", &new_col1);
|
|
gdk_color_alloc (xxx, &new_col1);
|
|
gdk_color_parse ("gray80", &new_col2);
|
|
gdk_color_alloc (xxx, &new_col2);
|
|
values.background.pixel = new_col1.pixel;
|
|
values.foreground.pixel = new_col2.pixel;
|
|
values.fill = GDK_OPAQUE_STIPPLED;
|
|
values.stipple = gdk_bitmap_create_from_data (widget->window,
|
|
(gchar *) stipple,
|
|
4, 4);
|
|
grid_hightlight_drawgc = gdk_gc_new_with_values (widget->window,
|
|
&values,
|
|
GDK_GC_FOREGROUND |
|
|
GDK_GC_BACKGROUND |
|
|
GDK_GC_FILL |
|
|
GDK_GC_STIPPLE);
|
|
}
|
|
|
|
|
|
static gint
|
|
gfig_dialog (void)
|
|
{
|
|
GtkWidget *main_hbox;
|
|
GtkWidget *frame;
|
|
GtkWidget *vbox;
|
|
GtkWidget *xframe;
|
|
GtkWidget *oframe;
|
|
GtkWidget *notebook;
|
|
GtkWidget *page;
|
|
GtkWidget *top_level_dlg;
|
|
|
|
gimp_ui_init ("gfig", TRUE);
|
|
|
|
yyy = gdk_rgb_get_visual ();
|
|
xxx = gdk_rgb_get_cmap ();
|
|
|
|
plug_in_parse_gfig_path ();
|
|
|
|
/*cache_preview (); Get the preview image and store it also set has_alpha */
|
|
|
|
img_width = gimp_drawable_width (gfig_select_drawable->id);
|
|
img_height = gimp_drawable_height (gfig_select_drawable->id);
|
|
|
|
/* Start buildng the dialog up */
|
|
top_level_dlg = gimp_dialog_new (_("GFig"), "gfig",
|
|
gimp_standard_help_func, "filters/gfig.html",
|
|
GTK_WIN_POS_MOUSE,
|
|
FALSE, FALSE, FALSE,
|
|
|
|
_("Done"), gfig_ok_callback,
|
|
NULL, NULL, NULL, TRUE, FALSE,
|
|
_("Paint"), gfig_paint_callback,
|
|
NULL, NULL, NULL, FALSE, FALSE,
|
|
_("Save"), save_button_callback,
|
|
NULL, NULL, &save_button, FALSE, FALSE,
|
|
_("Clear"), gfig_clear_callback,
|
|
NULL, NULL, NULL, FALSE, FALSE,
|
|
_("Undo"), gfig_undo_callback,
|
|
NULL, NULL, &undo_widget, FALSE, FALSE,
|
|
_("Cancel"), gtk_widget_destroy,
|
|
NULL, 1, NULL, FALSE, TRUE,
|
|
|
|
NULL);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (top_level_dlg), "destroy",
|
|
GTK_SIGNAL_FUNC (gtk_main_quit),
|
|
NULL);
|
|
|
|
/* Tooltips bis */
|
|
gimp_help_init ();
|
|
|
|
main_hbox = gtk_hbox_new (FALSE, 4);
|
|
gtk_container_set_border_width (GTK_CONTAINER (main_hbox), 4);
|
|
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (top_level_dlg)->vbox), main_hbox,
|
|
TRUE, TRUE, 0);
|
|
|
|
/* Add buttons beside the preview frame */
|
|
xframe = draw_buttons (top_level_dlg);
|
|
gtk_box_pack_start (GTK_BOX (main_hbox), xframe, FALSE, FALSE, 0);
|
|
/*gtk_widget_show (xframe);*/
|
|
|
|
/* Start building the frame for the preview area */
|
|
frame = gtk_frame_new (_("Preview"));
|
|
gtk_box_pack_start (GTK_BOX (main_hbox), frame, FALSE, FALSE, 0);
|
|
gtk_widget_show (frame);
|
|
|
|
/* Preview itself */
|
|
xframe = make_preview ();
|
|
gtk_container_add (GTK_CONTAINER (frame), xframe);
|
|
/* gtk_widget_show (xframe); */
|
|
|
|
gtk_widget_show (gfig_preview);
|
|
|
|
frame = gtk_frame_new (_("Settings"));
|
|
gtk_box_pack_start (GTK_BOX (main_hbox), frame, FALSE, FALSE, 0);
|
|
gtk_widget_show (frame);
|
|
|
|
vbox = gtk_vbox_new (FALSE, 2);
|
|
gtk_container_set_border_width (GTK_CONTAINER (vbox), 2);
|
|
gtk_container_add (GTK_CONTAINER (frame), vbox);
|
|
gtk_widget_show (vbox);
|
|
|
|
/* listbox + entry */
|
|
oframe = add_objects_list ();
|
|
gtk_box_pack_start (GTK_BOX (vbox), oframe, FALSE, FALSE, 0);
|
|
|
|
/* Grid entry */
|
|
xframe = grid_frame ();
|
|
gtk_box_pack_start (GTK_BOX (vbox), xframe, FALSE, FALSE, 0);
|
|
|
|
/* The notebook */
|
|
notebook = gtk_notebook_new ();
|
|
gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
|
|
gtk_box_pack_start (GTK_BOX (vbox), notebook, FALSE, FALSE, 0);
|
|
gtk_widget_show (notebook);
|
|
|
|
page = paint_page ();
|
|
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page,
|
|
gtk_label_new (_("Paint")));
|
|
gtk_widget_show (page);
|
|
|
|
brush_page_widget = brush_page ();
|
|
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), brush_page_widget,
|
|
gtk_label_new (_("Brush")));
|
|
gtk_widget_show (brush_page_widget);
|
|
|
|
/* Sometime maybe allow all objects to be done by selections - this
|
|
* would adjust the selection options.
|
|
*/
|
|
select_page_widget = select_page ();
|
|
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), select_page_widget,
|
|
gtk_label_new (_("Select")));
|
|
gtk_widget_set_sensitive (select_page_widget, FALSE);
|
|
|
|
page = options_page ();
|
|
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page,
|
|
gtk_label_new (_("Options")));
|
|
gtk_widget_show (page);
|
|
|
|
gtk_widget_show (main_hbox);
|
|
|
|
gtk_widget_show (top_level_dlg);
|
|
|
|
dialog_update_preview ();
|
|
gfig_new_gc (); /* Need this for drawing */
|
|
gfig_update_stat_labels ();
|
|
|
|
gfig_grid_colours (gfig_preview, xxx);
|
|
/* Popup for list area */
|
|
gfig_op_menu_create (top_level_dlg);
|
|
|
|
/* signal (11, scatch); For debugging */
|
|
|
|
gtk_main ();
|
|
|
|
gimp_image_delete (brush_image_ID);
|
|
brush_image_ID = -1;
|
|
|
|
gimp_help_free ();
|
|
|
|
gdk_flush ();
|
|
|
|
return gfig_run;
|
|
}
|
|
|
|
static void
|
|
gfig_really_ok_callback (GtkWidget *widget,
|
|
gboolean doit,
|
|
gpointer data)
|
|
{
|
|
if (doit)
|
|
{
|
|
gfig_run = TRUE;
|
|
gtk_widget_destroy (GTK_WIDGET (data));
|
|
}
|
|
}
|
|
|
|
static void
|
|
gfig_ok_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
/* Check if outstanding saves */
|
|
GList *list;
|
|
GFigObj *gfig;
|
|
gint count = 0;
|
|
|
|
for (list = gfig_list; list; list = g_list_next (list))
|
|
{
|
|
gfig = (GFigObj *) list->data;
|
|
if (gfig->obj_status & GFIG_MODIFIED)
|
|
count++;
|
|
}
|
|
|
|
if (count)
|
|
{
|
|
GtkWidget *dialog;
|
|
gchar *message;
|
|
|
|
message =
|
|
g_strdup_printf (_("%d unsaved Gfig objects.\nContinue with exiting?"), count);
|
|
|
|
dialog = gimp_query_boolean_box (_("Warning"),
|
|
gimp_standard_help_func,
|
|
"filters/gfig.html",
|
|
FALSE,
|
|
message,
|
|
_("OK"), _("Cancel"),
|
|
NULL, NULL,
|
|
gfig_really_ok_callback,
|
|
data);
|
|
g_free (message);
|
|
|
|
gtk_widget_show (dialog);
|
|
}
|
|
else
|
|
{
|
|
gfig_run = TRUE;
|
|
gtk_widget_destroy (GTK_WIDGET (data));
|
|
}
|
|
}
|
|
|
|
/* Update the bits we put on the screen */
|
|
static void
|
|
update_draw_area (GtkWidget *widget,
|
|
GdkEvent *event)
|
|
{
|
|
if (!GTK_WIDGET_DRAWABLE (widget))
|
|
return;
|
|
|
|
gtk_signal_handler_block (GTK_OBJECT (widget), gfig_preview_exp_id);
|
|
gtk_widget_draw (widget, NULL);
|
|
gtk_signal_handler_unblock (GTK_OBJECT (widget), gfig_preview_exp_id);
|
|
|
|
draw_grid (widget, 0);
|
|
draw_objects (current_obj->obj_list, TRUE);
|
|
}
|
|
|
|
static gint
|
|
gfig_preview_expose (GtkWidget *widget,
|
|
GdkEvent *event)
|
|
{
|
|
GdkCursor *preview_cursor;
|
|
static gint changed_cursor = 0;
|
|
|
|
if (!changed_cursor && gfig_preview->window)
|
|
{
|
|
changed_cursor = 1;
|
|
preview_cursor = gdk_cursor_new (GDK_CROSSHAIR);
|
|
gdk_window_set_cursor (gfig_preview->window, preview_cursor);
|
|
}
|
|
update_draw_area (widget, event);
|
|
return FALSE;
|
|
}
|
|
|
|
static gint
|
|
pic_preview_expose (GtkWidget *widget,
|
|
GdkEvent *event)
|
|
{
|
|
if (pic_obj)
|
|
{
|
|
drawing_pic = TRUE;
|
|
draw_objects (pic_obj->obj_list, FALSE);
|
|
drawing_pic = FALSE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static gint
|
|
adjust_pic_coords (gint coord,
|
|
gint ratio)
|
|
{
|
|
/*return ((SMALL_PREVIEW_SZ * coord)/PREVIEW_SIZE);*/
|
|
static gint pratio = -1;
|
|
|
|
if (pratio == -1)
|
|
{
|
|
pratio = MAX (preview_width, preview_height);
|
|
}
|
|
|
|
return (SMALL_PREVIEW_SZ * coord) / pratio;
|
|
}
|
|
|
|
static gint
|
|
gfig_preview_events (GtkWidget *widget,
|
|
GdkEvent *event)
|
|
{
|
|
GdkEventButton *bevent;
|
|
GdkEventMotion *mevent;
|
|
GdkPoint point;
|
|
static gint tmp_show_single = 0;
|
|
|
|
switch (event->type)
|
|
{
|
|
case GDK_EXPOSE:
|
|
break;
|
|
|
|
case GDK_BUTTON_PRESS:
|
|
bevent = (GdkEventButton *) event;
|
|
point.x = bevent->x;
|
|
point.y = bevent->y;
|
|
|
|
g_assert (need_to_scale == 0); /* If not out of step some how */
|
|
|
|
/* Start drawing of object */
|
|
if (selvals.otype >= MOVE_OBJ)
|
|
{
|
|
if (!selvals.scaletoimage)
|
|
{
|
|
point.x = gfig_invscale_x (point.x);
|
|
point.y = gfig_invscale_y (point.y);
|
|
}
|
|
object_operation_start (&point, bevent->state & GDK_SHIFT_MASK);
|
|
|
|
/* If constraining save start pnt */
|
|
if (selvals.opts.snap2grid)
|
|
{
|
|
/* Save point to constained point ... if button 3 down */
|
|
if (bevent->button == 3)
|
|
{
|
|
find_grid_pos (&point, &point, FALSE);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (selvals.opts.snap2grid)
|
|
{
|
|
if (bevent->button == 3)
|
|
{
|
|
find_grid_pos (&point, &point, FALSE);
|
|
}
|
|
else
|
|
{
|
|
find_grid_pos (&point, &point, FALSE);
|
|
}
|
|
}
|
|
object_start (&point, bevent->state & GDK_SHIFT_MASK);
|
|
}
|
|
|
|
break;
|
|
case GDK_BUTTON_RELEASE:
|
|
bevent = (GdkEventButton *) event;
|
|
point.x = bevent->x;
|
|
point.y = bevent->y;
|
|
|
|
if (selvals.opts.snap2grid)
|
|
find_grid_pos (&point, &point, bevent->button == 3);
|
|
|
|
/* Still got shift down ?*/
|
|
if (selvals.otype >= MOVE_OBJ)
|
|
{
|
|
if (!selvals.scaletoimage)
|
|
{
|
|
point.x = gfig_invscale_x (point.x);
|
|
point.y = gfig_invscale_y (point.y);
|
|
}
|
|
object_operation_end (&point, bevent->state & GDK_SHIFT_MASK);
|
|
}
|
|
else
|
|
{
|
|
if (obj_creating)
|
|
{
|
|
object_end (&point, bevent->state & GDK_SHIFT_MASK);
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
/* make small preview reflect changes ?*/
|
|
list_button_update (current_obj);
|
|
break;
|
|
case GDK_MOTION_NOTIFY:
|
|
|
|
mevent = (GdkEventMotion *) event;
|
|
point.x = mevent->x;
|
|
point.y = mevent->y;
|
|
|
|
if (selvals.opts.snap2grid)
|
|
find_grid_pos (&point, &point, mevent->state & GDK_BUTTON3_MASK);
|
|
|
|
if (selvals.otype >= MOVE_OBJ)
|
|
{
|
|
/* Moving objects around */
|
|
if (!selvals.scaletoimage)
|
|
{
|
|
point.x = gfig_invscale_x (point.x);
|
|
point.y = gfig_invscale_y (point.y);
|
|
}
|
|
object_operation (&point, mevent->state & GDK_SHIFT_MASK);
|
|
gfig_pos_update (point.x, point.y);
|
|
return FALSE;
|
|
}
|
|
|
|
if (obj_creating)
|
|
{
|
|
object_update (&point);
|
|
}
|
|
gfig_pos_update (point.x, point.y);
|
|
break;
|
|
case GDK_KEY_PRESS:
|
|
if ((tmp_show_single = obj_show_single) != -1)
|
|
{
|
|
obj_show_single = -1;
|
|
draw_grid_clear (NULL, NULL); /*Args not used */
|
|
}
|
|
break;
|
|
case GDK_KEY_RELEASE:
|
|
if (tmp_show_single != -1)
|
|
{
|
|
obj_show_single = tmp_show_single;
|
|
draw_grid_clear (NULL, NULL); /*Args not used */
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
* 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;
|
|
gint created;
|
|
} GfigListOptions;
|
|
|
|
static GtkWidget *
|
|
gfig_list_add (GFigObj *obj)
|
|
{
|
|
GList *list;
|
|
gint pos;
|
|
GtkWidget *list_item;
|
|
GtkWidget *list_pix;
|
|
|
|
list_pix = gimp_pixmap_new (Floppy6_xpm);
|
|
list_item =
|
|
gfig_list_item_new_with_label_and_pixmap (obj, obj->draw_name, list_pix);
|
|
|
|
gtk_object_set_user_data (GTK_OBJECT (list_item), (gpointer) obj);
|
|
|
|
pos = gfig_list_insert (obj);
|
|
|
|
list = g_list_append (NULL, list_item);
|
|
gtk_list_insert_items (GTK_LIST (gfig_gtk_list), list, pos);
|
|
gtk_widget_show (list_item);
|
|
gtk_list_select_item (GTK_LIST (gfig_gtk_list), pos);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (list_item), "button_press_event",
|
|
GTK_SIGNAL_FUNC (list_button_press),
|
|
(gpointer) obj);
|
|
|
|
return list_item;
|
|
}
|
|
|
|
static void
|
|
gfig_list_ok_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
GfigListOptions *options;
|
|
GtkWidget *list;
|
|
gint pos;
|
|
|
|
options = (GfigListOptions *) data;
|
|
list = options->list_entry;
|
|
|
|
/* Set the new layer name */
|
|
#ifdef DEBUG
|
|
printf ("Found obj %s\n", options->obj->draw_name);
|
|
#endif /* DEBUG */
|
|
if (options->obj->draw_name)
|
|
{
|
|
g_free (options->obj->draw_name);
|
|
}
|
|
options->obj->draw_name =
|
|
g_strdup (gtk_entry_get_text (GTK_ENTRY (options->name_entry)));
|
|
#ifdef DEBUG
|
|
printf ("NEW name %s\n", options->obj->draw_name);
|
|
#endif /* DEBUG */
|
|
|
|
/* Need to reorder the list */
|
|
/* gtk_label_set_text (GTK_LABEL (options->layer_widget->label), layer->name);*/
|
|
|
|
pos = gtk_list_child_position (GTK_LIST (gfig_gtk_list), list);
|
|
#ifdef DEBUG
|
|
printf ("pos = %d\n", pos);
|
|
#endif /* DEBUG */
|
|
|
|
gtk_list_clear_items (GTK_LIST (gfig_gtk_list), pos, pos + 1);
|
|
|
|
/* remove/Add again */
|
|
gfig_list = g_list_remove (gfig_list, options->obj);
|
|
gfig_list_add (options->obj);
|
|
|
|
options->obj->obj_status |= GFIG_MODIFIED;
|
|
|
|
gtk_widget_destroy (options->query_box);
|
|
g_free (options);
|
|
|
|
gfig_update_stat_labels ();
|
|
}
|
|
|
|
static void
|
|
gfig_list_cancel_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
GfigListOptions *options;
|
|
|
|
options = (GfigListOptions *) data;
|
|
if (options->created)
|
|
{
|
|
/* We are creating an entry so if cancelled
|
|
* must del the list item as well
|
|
*/
|
|
gfig_do_delete_gfig_callback (widget, TRUE, gfig_gtk_list);
|
|
}
|
|
|
|
gtk_widget_destroy (options->query_box);
|
|
g_free (options);
|
|
}
|
|
|
|
static void
|
|
gfig_dialog_edit_list (GtkWidget *lwidget,
|
|
GFigObj *obj,
|
|
gint created)
|
|
{
|
|
GfigListOptions *options;
|
|
GtkWidget *vbox;
|
|
GtkWidget *hbox;
|
|
GtkWidget *label;
|
|
|
|
/* the new options structure */
|
|
options = g_new (GfigListOptions, 1);
|
|
options->list_entry = lwidget;
|
|
options->obj = obj;
|
|
options->created = created;
|
|
|
|
/* the dialog */
|
|
options->query_box =
|
|
gimp_dialog_new (_("Enter Gfig Entry Name"), "gfig",
|
|
gimp_standard_help_func, "filters/gfig.html",
|
|
GTK_WIN_POS_MOUSE,
|
|
FALSE, TRUE, FALSE,
|
|
|
|
_("OK"), gfig_list_ok_callback,
|
|
options, NULL, NULL, TRUE, FALSE,
|
|
_("Cancel"), gfig_list_cancel_callback,
|
|
options, NULL, NULL, FALSE, TRUE,
|
|
|
|
NULL);
|
|
|
|
/* the main vbox */
|
|
vbox = gtk_vbox_new (FALSE, 2);
|
|
gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
|
|
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (options->query_box)->vbox), vbox,
|
|
FALSE, FALSE, 0);
|
|
gtk_widget_show (vbox);
|
|
|
|
/* the name entry hbox, label and entry */
|
|
hbox = gtk_hbox_new (FALSE, 4);
|
|
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
|
|
gtk_widget_show (hbox);
|
|
|
|
label = gtk_label_new (_("Gfig Object Name:"));
|
|
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
|
|
gtk_widget_show (label);
|
|
|
|
options->name_entry = gtk_entry_new ();
|
|
gtk_box_pack_start (GTK_BOX (hbox), options->name_entry, TRUE, TRUE, 0);
|
|
gtk_entry_set_text (GTK_ENTRY (options->name_entry), obj->draw_name);
|
|
gtk_widget_show (options->name_entry);
|
|
|
|
gtk_widget_show (options->query_box);
|
|
}
|
|
|
|
static void
|
|
gfig_rescan_ok_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
GtkWidget *patheditor;
|
|
gchar *raw_path;
|
|
|
|
gtk_widget_set_sensitive (GTK_WIDGET (data), FALSE);
|
|
|
|
gimp_path_free (gfig_path_list);
|
|
gfig_path_list = NULL;
|
|
|
|
patheditor = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (data),
|
|
"patheditor"));
|
|
|
|
raw_path = gimp_path_editor_get_path (GIMP_PATH_EDITOR (patheditor));
|
|
|
|
gfig_path_list = gimp_path_parse (raw_path, 16, FALSE, NULL);
|
|
|
|
g_free (raw_path);
|
|
|
|
if (gfig_path_list)
|
|
{
|
|
clear_list_items (GTK_LIST (gfig_gtk_list));
|
|
gfig_list_load_all (gfig_path_list);
|
|
build_list_items (gfig_gtk_list);
|
|
list_button_update (current_obj);
|
|
}
|
|
|
|
gtk_widget_destroy (GTK_WIDGET (data));
|
|
}
|
|
|
|
static void
|
|
gfig_rescan_list (void)
|
|
{
|
|
static GtkWidget *dlg = NULL;
|
|
|
|
GtkWidget *patheditor;
|
|
gchar *path;
|
|
|
|
if (dlg)
|
|
{
|
|
gdk_window_raise (dlg->window);
|
|
return;
|
|
}
|
|
|
|
/* the dialog */
|
|
dlg = gimp_dialog_new (_("Rescan for Gfig Objects"), "gfig",
|
|
gimp_standard_help_func, "filters/gfig.html",
|
|
GTK_WIN_POS_MOUSE,
|
|
FALSE, TRUE, FALSE,
|
|
|
|
_("OK"), gfig_rescan_ok_callback,
|
|
NULL, NULL, NULL, TRUE, FALSE,
|
|
_("Cancel"), gtk_widget_destroy,
|
|
NULL, 1, NULL, FALSE, TRUE,
|
|
|
|
NULL);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
|
|
GTK_SIGNAL_FUNC (gtk_widget_destroyed),
|
|
&dlg);
|
|
|
|
path = gimp_path_to_str (gfig_path_list);
|
|
|
|
patheditor = gimp_path_editor_new (_("Add Gfig Path"), path);
|
|
gtk_container_set_border_width (GTK_CONTAINER (patheditor), 6);
|
|
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), patheditor,
|
|
TRUE, TRUE, 0);
|
|
gtk_widget_show (patheditor);
|
|
|
|
g_free (path);
|
|
|
|
gtk_object_set_data (GTK_OBJECT (dlg), "patheditor", patheditor);
|
|
|
|
gtk_widget_show (dlg);
|
|
}
|
|
|
|
static void
|
|
list_button_update (GFigObj *obj)
|
|
{
|
|
g_return_if_fail (obj != NULL);
|
|
|
|
pic_obj = (GFigObj *) obj;
|
|
|
|
gtk_widget_draw (pic_preview, NULL);
|
|
|
|
drawing_pic = TRUE;
|
|
draw_objects (pic_obj->obj_list, FALSE);
|
|
drawing_pic = FALSE;
|
|
}
|
|
|
|
|
|
static void
|
|
gfig_load_file_selection_ok (GtkWidget *widget,
|
|
GtkFileSelection *fs,
|
|
gpointer data)
|
|
{
|
|
gchar *filename;
|
|
struct stat filestat;
|
|
gint err;
|
|
GFigObj *gfig;
|
|
GFigObj *current_saved;
|
|
|
|
filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs));
|
|
|
|
#ifdef DEBUG
|
|
printf ("Loading file '%s'\n", filename);
|
|
#endif /* DEBUG */
|
|
|
|
err = stat (filename, &filestat);
|
|
|
|
if (!err && S_ISREG (filestat.st_mode))
|
|
{
|
|
/* Hack - current object MUST be NULL to prevent setup_undo ()
|
|
* from kicking in.
|
|
*/
|
|
current_saved = current_obj;
|
|
current_obj = NULL;
|
|
gfig = gfig_load (filename, filename);
|
|
current_obj = current_saved;
|
|
|
|
if (gfig)
|
|
{
|
|
/* Read only ?*/
|
|
if (access (filename, W_OK))
|
|
gfig->obj_status |= GFIG_READONLY;
|
|
|
|
gfig_list_add (gfig);
|
|
new_obj_2edit (gfig);
|
|
}
|
|
}
|
|
|
|
gtk_widget_destroy (GTK_WIDGET (fs));
|
|
}
|
|
|
|
static void
|
|
load_button_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
static GtkWidget *window = NULL;
|
|
|
|
/* Load a single object */
|
|
window = gtk_file_selection_new (_("Load Gfig obj"));
|
|
gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (window), "destroy",
|
|
GTK_SIGNAL_FUNC (gtk_widget_destroyed),
|
|
&window);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (window)->ok_button),
|
|
"clicked",
|
|
GTK_SIGNAL_FUNC (gfig_load_file_selection_ok),
|
|
(gpointer) window);
|
|
|
|
gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (window)->cancel_button),
|
|
"clicked",
|
|
GTK_SIGNAL_FUNC (gtk_widget_destroy),
|
|
GTK_OBJECT (window));
|
|
gtk_widget_show (window);
|
|
}
|
|
|
|
static void
|
|
paint_layer_copy (gchar *new_name)
|
|
{
|
|
gint32 old_drawable = gfig_drawable;
|
|
if ((gfig_drawable = gimp_layer_copy (gfig_drawable)) < 0)
|
|
{
|
|
g_warning (_("Error in copy layer for onlayers"));
|
|
gfig_drawable = old_drawable;
|
|
return;
|
|
}
|
|
|
|
gimp_layer_set_name (gfig_drawable, new_name);
|
|
gimp_image_add_layer (gfig_image, gfig_drawable, -1);
|
|
}
|
|
|
|
static void
|
|
paint_layer_new (gchar *new_name)
|
|
{
|
|
gint32 layer_id;
|
|
gint32 fill_type;
|
|
int isgrey = 0;
|
|
|
|
switch (gimp_drawable_type (gfig_select_drawable->id))
|
|
{
|
|
case GIMP_GRAYA_IMAGE:
|
|
case GIMP_GRAY_IMAGE:
|
|
isgrey = 2;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if ((layer_id = gimp_layer_new (gfig_image,
|
|
new_name,
|
|
img_width,
|
|
img_height,
|
|
1 + isgrey, /* RGBA or GRAYA type */
|
|
100.0, /* opacity */
|
|
0 /* mode */)) < 0)
|
|
g_warning (_("Error in creating layer"));
|
|
else
|
|
{
|
|
gimp_image_add_layer (gfig_image, layer_id, -1);
|
|
gimp_drawable_fill (layer_id, 1);
|
|
}
|
|
|
|
gfig_drawable = layer_id;
|
|
|
|
switch (selvals.onlayerbg)
|
|
{
|
|
case LAYER_TRANS_BG:
|
|
fill_type = 3;
|
|
break;
|
|
case LAYER_BG_BG:
|
|
fill_type = 1;
|
|
break;
|
|
case LAYER_FG_BG:
|
|
fill_type = 0;
|
|
break;
|
|
case LAYER_WHITE_BG:
|
|
fill_type = 2;
|
|
break;
|
|
case LAYER_COPY_BG:
|
|
default:
|
|
fill_type = 1;
|
|
g_warning ("Paint layer new internal error %d\n", selvals.onlayerbg);
|
|
break;
|
|
}
|
|
/* Have to clear layer out since creating transparent layer
|
|
* seems to leave rubbish in it.
|
|
*/
|
|
|
|
gimp_drawable_fill (layer_id, fill_type);
|
|
|
|
}
|
|
|
|
static void
|
|
paint_layer_fill ()
|
|
{
|
|
gimp_bucket_fill (gfig_drawable,
|
|
selopt.fill_type, /* Fill mode */
|
|
GIMP_NORMAL_MODE,
|
|
selopt.fill_opacity, /* Fill opacity */
|
|
0.0, /* threshold - ignored */
|
|
FALSE, /* Sample merged - ignored */
|
|
0.0, /* x - ignored */
|
|
0.0); /* y - ignored */
|
|
}
|
|
|
|
static void
|
|
gfig_paint_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
DAllObjs * objs;
|
|
gint layer_count = 0;
|
|
gchar buf[128];
|
|
gint count;
|
|
gint ccount = 0;
|
|
BrushDesc *bdesc;
|
|
|
|
objs = current_obj->obj_list;
|
|
|
|
count = gfig_obj_counts (objs);
|
|
#if 0
|
|
gtk_progress_bar_update (GTK_PROGRESS_BAR (progress_widget), (gfloat) 0.0);
|
|
#endif /* 0 */
|
|
|
|
/* Set the brush up */
|
|
bdesc = gtk_object_get_user_data (GTK_OBJECT (brush_page_pw));
|
|
|
|
if (bdesc)
|
|
mygimp_brush_set (bdesc->bname);
|
|
|
|
while (objs)
|
|
{
|
|
|
|
if (ccount == obj_show_single || obj_show_single == -1)
|
|
{
|
|
sprintf (buf, _("Gfig Layer %d"), layer_count++);
|
|
|
|
if (selvals.painttype != PAINT_SELECTION_TYPE)
|
|
{
|
|
switch (selvals.onlayers)
|
|
{
|
|
case SINGLE_LAYER:
|
|
if (layer_count == 1)
|
|
{
|
|
if (selvals.onlayerbg == LAYER_COPY_BG)
|
|
paint_layer_copy (buf);
|
|
else
|
|
paint_layer_new (buf);
|
|
}
|
|
break;
|
|
case MULTI_LAYER:
|
|
if (selvals.onlayerbg == LAYER_COPY_BG)
|
|
paint_layer_copy (buf);
|
|
else
|
|
paint_layer_new (buf);
|
|
break;
|
|
case ORIGINAL_LAYER:
|
|
/* Just use the given layer */
|
|
break;
|
|
default:
|
|
g_warning ("Error in onlayers val %d", selvals.onlayers);
|
|
break;
|
|
}
|
|
}
|
|
|
|
objs->obj->paintfunc (objs->obj);
|
|
|
|
/* Fill layer if required */
|
|
if (selvals.painttype == PAINT_SELECTION_FILL_TYPE
|
|
&& selopt.fill_when == FILL_EACH)
|
|
paint_layer_fill ();
|
|
}
|
|
|
|
objs = objs->next;
|
|
|
|
ccount++;
|
|
#if 0
|
|
gtk_progress_bar_update (GTK_PROGRESS_BAR (progress_widget), (gfloat)ccount/(gfloat)count);
|
|
gtk_widget_draw (GTK_WIDGET (progress_widget), NULL);
|
|
#endif /* 0 */
|
|
}
|
|
|
|
/* Fill layer if required */
|
|
if (selvals.painttype == PAINT_SELECTION_FILL_TYPE
|
|
&& selopt.fill_when == FILL_AFTER)
|
|
paint_layer_fill ();
|
|
|
|
gimp_displays_flush ();
|
|
}
|
|
|
|
static void
|
|
reload_button_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
refill_cache ();
|
|
draw_grid_clear (widget, data);
|
|
}
|
|
|
|
static void
|
|
about_button_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
GtkWidget *window;
|
|
GtkWidget *label;
|
|
GtkWidget *hbox;
|
|
GtkWidget *vbox;
|
|
GtkWidget *pm;
|
|
|
|
window = gimp_dialog_new (_("About GFig"), "gfig",
|
|
gimp_standard_help_func, "filters/gfig.html",
|
|
GTK_WIN_POS_MOUSE,
|
|
FALSE, FALSE, FALSE,
|
|
|
|
_("OK"), gtk_widget_destroy,
|
|
NULL, 1, NULL, TRUE, TRUE,
|
|
|
|
NULL);
|
|
|
|
/* Bits and bobs */
|
|
pm = gimp_pixmap_new (rulers_comp_xpm);
|
|
gtk_widget_show (pm);
|
|
|
|
hbox = gtk_hbox_new (FALSE, 1);
|
|
gtk_widget_show (hbox);
|
|
|
|
vbox = gtk_vbox_new (FALSE, 1);
|
|
gtk_widget_show (vbox);
|
|
|
|
gtk_box_pack_start (GTK_BOX (hbox), pm, TRUE, TRUE, 0);
|
|
gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
|
|
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), hbox, TRUE, TRUE, 0);
|
|
|
|
label = gtk_label_new (_("Gfig - GIMP plug-in"));
|
|
gtk_misc_set_padding (GTK_MISC (label), 2, 2);
|
|
gtk_widget_show (label);
|
|
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
|
|
|
|
label = gtk_label_new (_("Release 1.3"));
|
|
gtk_misc_set_padding (GTK_MISC (label), 2, 2);
|
|
gtk_widget_show (label);
|
|
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
|
|
|
|
label = gtk_label_new ("Andy Thomas");
|
|
gtk_misc_set_padding (GTK_MISC (label), 2, 2);
|
|
gtk_widget_show (label);
|
|
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
|
|
|
|
label = gtk_label_new (_("Email alt@picnic.demon.co.uk"));
|
|
gtk_misc_set_padding (GTK_MISC (label), 2, 2);
|
|
gtk_widget_show (label);
|
|
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
|
|
|
|
label = gtk_label_new ("http://www.picnic.demon.co.uk/");
|
|
gtk_misc_set_padding (GTK_MISC (label), 2, 2);
|
|
gtk_widget_show (label);
|
|
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
|
|
|
|
label = gtk_label_new (_("Isometric grid By Rob Saunders"));
|
|
gtk_misc_set_padding (GTK_MISC (label), 2, 2);
|
|
gtk_widget_show (label);
|
|
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
|
|
|
|
gtk_widget_show (window);
|
|
}
|
|
|
|
|
|
static void
|
|
save_button_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
gfig_save (); /* Save current object */
|
|
}
|
|
|
|
static void
|
|
rescan_button_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
gfig_rescan_list ();
|
|
}
|
|
|
|
static GtkWidget *
|
|
new_gfig_obj (gchar *name)
|
|
{
|
|
GFigObj *gfig;
|
|
GtkWidget *new_list_item;
|
|
/* Create a new entry */
|
|
|
|
gfig = gfig_new ();
|
|
|
|
if (!name)
|
|
name = _("New gfig obj");
|
|
|
|
gfig->draw_name = g_strdup (name);
|
|
|
|
/* Leave options as before */
|
|
pic_obj = current_obj = gfig;
|
|
|
|
new_list_item = gfig_list_add (gfig);
|
|
|
|
tmp_bezier = obj_creating = tmp_line = NULL;
|
|
|
|
/* Redraw areas */
|
|
update_draw_area (gfig_preview, NULL);
|
|
list_button_update (gfig);
|
|
|
|
return new_list_item;
|
|
}
|
|
|
|
static void
|
|
new_button_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
GtkWidget *new_list_item;
|
|
|
|
new_list_item = new_gfig_obj ((gchar*) data);
|
|
gfig_dialog_edit_list (new_list_item, current_obj, TRUE);
|
|
}
|
|
|
|
static GtkWidget *delete_dialog = NULL;
|
|
|
|
static void
|
|
gfig_do_delete_gfig_callback (GtkWidget *widget,
|
|
gboolean delete,
|
|
gpointer data)
|
|
{
|
|
gint pos;
|
|
GList *sellist;
|
|
GFigObj *sel_obj;
|
|
GtkWidget *list = (GtkWidget *) data;
|
|
|
|
if (!delete)
|
|
{
|
|
gtk_widget_set_sensitive (delete_frame_to_freeze, TRUE);
|
|
return;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
printf ("Delete button pressed\n");
|
|
#endif /* DEBUG */
|
|
/* Must update which object we are editing */
|
|
/* Get the list and which item is selected */
|
|
/* Only allow single selections */
|
|
|
|
sellist = GTK_LIST (list)->selection;
|
|
|
|
sel_obj = (GFigObj *) gtk_object_get_user_data (GTK_OBJECT (sellist->data));
|
|
|
|
pos = gtk_list_child_position (GTK_LIST (gfig_gtk_list), sellist->data);
|
|
#ifdef DEBUG
|
|
printf ("delete pos = %d\n", pos);
|
|
#endif /* DEBUG */
|
|
|
|
/* Delete the current item + asssociated file */
|
|
gtk_list_clear_items (GTK_LIST (gfig_gtk_list), pos, pos + 1);
|
|
/* Shadow copy for ordering info */
|
|
gfig_list = g_list_remove (gfig_list, sel_obj);
|
|
|
|
if (sel_obj == current_obj)
|
|
{
|
|
clear_undo ();
|
|
}
|
|
|
|
/* Free current obj */
|
|
gfig_free_everything (sel_obj);
|
|
|
|
/* Select previous one */
|
|
pos--;
|
|
|
|
if (pos < 0)
|
|
{
|
|
if (g_list_length (gfig_list) == 0)
|
|
{
|
|
/* Warning - we have a problem here
|
|
* since we are not really "creating an entry"
|
|
* why call gfig_new?
|
|
*/
|
|
new_button_callback (NULL, NULL);
|
|
}
|
|
|
|
pos = 0;
|
|
}
|
|
|
|
gtk_widget_set_sensitive (delete_frame_to_freeze, TRUE);
|
|
|
|
gtk_list_select_item (GTK_LIST (gfig_gtk_list), pos);
|
|
|
|
current_obj = g_list_nth (gfig_list, pos)->data;
|
|
|
|
update_draw_area (gfig_preview, NULL);
|
|
|
|
list_button_update (current_obj);
|
|
|
|
gfig_update_stat_labels ();
|
|
}
|
|
|
|
static void
|
|
gfig_delete_gfig_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
gchar *str;
|
|
|
|
GtkWidget *list = (GtkWidget *) data;
|
|
GList * sellist;
|
|
GFigObj * sel_obj;
|
|
|
|
sellist = GTK_LIST (list)->selection;
|
|
|
|
sel_obj = (GFigObj *) gtk_object_get_user_data (GTK_OBJECT (sellist->data));
|
|
|
|
if (delete_dialog)
|
|
return;
|
|
|
|
str = g_strdup_printf (_("Are you sure you want to delete\n"
|
|
"\"%s\" from the list and from disk?"),
|
|
sel_obj->draw_name);
|
|
|
|
delete_dialog = gimp_query_boolean_box (_("Delete Gfig Drawing"),
|
|
gimp_standard_help_func,
|
|
"filters/gfig.html",
|
|
FALSE,
|
|
str,
|
|
_("Delete"), _("Cancel"),
|
|
NULL, NULL,
|
|
gfig_do_delete_gfig_callback,
|
|
data);
|
|
|
|
g_free (str);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (delete_dialog), "destroy",
|
|
GTK_SIGNAL_FUNC (gtk_widget_destroyed),
|
|
&delete_dialog);
|
|
|
|
gtk_widget_set_sensitive (GTK_WIDGET (delete_frame_to_freeze), FALSE);
|
|
gtk_widget_show (delete_dialog);
|
|
}
|
|
|
|
static void
|
|
gfig_update_stat_labels (void)
|
|
{
|
|
gchar str[45];
|
|
|
|
if (current_obj->draw_name)
|
|
sprintf (str, "%.34s", current_obj->draw_name);
|
|
else
|
|
sprintf (str,_("<NONE>"));
|
|
|
|
gtk_label_set_text (GTK_LABEL (status_label_dname), str);
|
|
|
|
if (current_obj->filename)
|
|
{
|
|
gint slen;
|
|
gchar *hm = g_get_home_dir ();
|
|
gchar *dfn = g_strdup (current_obj->filename);
|
|
#ifdef __EMX__
|
|
if (hm)
|
|
hm = _fnslashify (hm);
|
|
#endif
|
|
|
|
|
|
#ifndef __EMX__
|
|
if (hm != NULL && !strncmp (dfn, hm, strlen (hm)-1))
|
|
#else
|
|
if (hm != NULL && !strnicmp (dfn, hm, strlen (hm)-1))
|
|
#endif
|
|
{
|
|
strcpy (dfn, "~");
|
|
strcat (dfn, &dfn[strlen (hm)]);
|
|
}
|
|
if ((slen = strlen (dfn)) > 40)
|
|
{
|
|
strncpy (str, dfn, 19);
|
|
str[19] = '\0';
|
|
strcat (str, "...");
|
|
strncat (str, &dfn[slen - 21], 19);
|
|
str[40] ='\0';
|
|
}
|
|
else
|
|
sprintf (str, "%.40s", dfn);
|
|
g_free (dfn);
|
|
#ifdef __EMX__
|
|
g_free (hm);
|
|
#endif
|
|
}
|
|
else
|
|
sprintf (str,_("<NONE>"));
|
|
|
|
gtk_label_set_text (GTK_LABEL (status_label_fname), str);
|
|
|
|
}
|
|
|
|
static void
|
|
new_obj_2edit (GFigObj *obj)
|
|
{
|
|
GFigObj *old_current = current_obj;
|
|
|
|
/* Clear undo levels */
|
|
/* redraw the preview */
|
|
/* Set up options as define in the selected object */
|
|
|
|
clear_undo ();
|
|
|
|
/* Point at this one */
|
|
current_obj = obj;
|
|
|
|
/* Show all objects to start with */
|
|
obj_show_single = -1;
|
|
|
|
/* Change options */
|
|
update_options (old_current);
|
|
|
|
/* If have old object and NOT scaleing currently then force
|
|
* back to saved coord type.
|
|
*/
|
|
gfig_update_stat_labels ();
|
|
|
|
/* redraw with new */
|
|
update_draw_area (gfig_preview, NULL);
|
|
/* And preview */
|
|
list_button_update (current_obj);
|
|
|
|
if (obj->obj_status & GFIG_READONLY)
|
|
{
|
|
g_message (_("Editing read-only object - "
|
|
"you will not be able to save it"));
|
|
gtk_widget_set_sensitive (save_button, FALSE);
|
|
}
|
|
else
|
|
{
|
|
gtk_widget_set_sensitive (save_button, TRUE);
|
|
}
|
|
}
|
|
|
|
static void
|
|
edit_button_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
GList *sellist;
|
|
GFigObj *sel_obj;
|
|
GtkWidget *list = (GtkWidget *) data;
|
|
|
|
#ifdef DEBUG
|
|
printf ("Edit button pressed\n");
|
|
#endif /* DEBUG */
|
|
/* Must update which object we are editing */
|
|
/* Get the list and which item is selected */
|
|
/* Only allow single selections */
|
|
|
|
sellist = GTK_LIST (list)->selection;
|
|
|
|
sel_obj = (GFigObj *) gtk_object_get_user_data (GTK_OBJECT (sellist->data));
|
|
|
|
if (sel_obj)
|
|
new_obj_2edit (sel_obj);
|
|
else
|
|
g_warning ("Internal error - list item has null object!");
|
|
}
|
|
|
|
static void
|
|
merge_button_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
GList *sellist;
|
|
GFigObj *sel_obj;
|
|
DAllObjs *obj_copies;
|
|
GtkWidget *list = (GtkWidget *) data;
|
|
|
|
#ifdef DEBUG
|
|
printf ("Merge button pressed\n");
|
|
#endif /* DEBUG */
|
|
/* Must update which object we are editing */
|
|
/* Get the list and which item is selected */
|
|
/* Only allow single selections */
|
|
|
|
sellist = GTK_LIST (list)->selection;
|
|
|
|
sel_obj = (GFigObj *) gtk_object_get_user_data (GTK_OBJECT (sellist->data));
|
|
|
|
if (sel_obj && sel_obj->obj_list && sel_obj != current_obj)
|
|
{
|
|
/* Copy list tag onto current & redraw */
|
|
obj_copies = copy_all_objs (sel_obj->obj_list);
|
|
prepend_to_all_obj (current_obj, obj_copies);
|
|
|
|
/* redraw all */
|
|
update_draw_area (gfig_preview, NULL);
|
|
/* And preview */
|
|
list_button_update (current_obj);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
gfig_save_menu_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
GFigObj * real_current = current_obj;
|
|
/* Fiddle the current object and save it */
|
|
/* What happens if we get a redraw here ? */
|
|
|
|
current_obj = gfig_obj_for_menu;
|
|
|
|
gfig_save (); /* Save current object */
|
|
|
|
current_obj = real_current;
|
|
}
|
|
|
|
static void
|
|
gfig_edit_menu_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
new_obj_2edit (gfig_obj_for_menu);
|
|
}
|
|
|
|
static void
|
|
gfig_rename_menu_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
create_file_selection (gfig_obj_for_menu, gfig_obj_for_menu->filename);
|
|
}
|
|
|
|
static void
|
|
gfig_copy_menu_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
/* Create new entry with name + copy at end & copy object into it */
|
|
gchar *new_name = g_strdup_printf (_("%s copy"), gfig_obj_for_menu->draw_name);
|
|
new_gfig_obj (new_name);
|
|
g_free (new_name);
|
|
|
|
/* Copy objs across */
|
|
current_obj->obj_list = copy_all_objs (gfig_obj_for_menu->obj_list);
|
|
current_obj->opts = gfig_obj_for_menu->opts; /* Structure copy */
|
|
|
|
/* redraw all */
|
|
update_draw_area (gfig_preview, NULL);
|
|
/* And preview */
|
|
list_button_update (current_obj);
|
|
}
|
|
|
|
static void
|
|
gfig_op_menu_create (GtkWidget *window)
|
|
{
|
|
GtkWidget *menu_item;
|
|
#if 0
|
|
GtkAcceleratorTable *accelerator_table;
|
|
#endif /* 0 */
|
|
|
|
gfig_op_menu = gtk_menu_new ();
|
|
|
|
#if 0
|
|
accelerator_table = gtk_accelerator_table_new ();
|
|
gtk_menu_set_accelerator_table (GTK_MENU (gfig_op_menu),
|
|
accelerator_table);
|
|
gtk_window_add_accelerator_table (GTK_WINDOW (window), accelerator_table);
|
|
#endif /* 0 */
|
|
|
|
save_menu_item = menu_item = gtk_menu_item_new_with_label (_("Save"));
|
|
gtk_menu_append (GTK_MENU (gfig_op_menu), menu_item);
|
|
gtk_widget_show (menu_item);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
|
|
(GtkSignalFunc)gfig_save_menu_callback,
|
|
NULL);
|
|
|
|
#if 0
|
|
gtk_widget_install_accelerator (menu_item,
|
|
accelerator_table,
|
|
"activate", 'S', 0);
|
|
#endif /* 0 */
|
|
|
|
menu_item = gtk_menu_item_new_with_label (_("Save as..."));
|
|
gtk_menu_append (GTK_MENU (gfig_op_menu), menu_item);
|
|
gtk_widget_show (menu_item);
|
|
gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
|
|
(GtkSignalFunc)gfig_rename_menu_callback,
|
|
NULL);
|
|
|
|
#if 0
|
|
gtk_widget_install_accelerator (menu_item,
|
|
accelerator_table,
|
|
"activate", 'A', 0);
|
|
#endif /* 0 */
|
|
|
|
menu_item = gtk_menu_item_new_with_label (_("Copy"));
|
|
gtk_menu_append (GTK_MENU (gfig_op_menu), menu_item);
|
|
gtk_widget_show (menu_item);
|
|
gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
|
|
(GtkSignalFunc)gfig_copy_menu_callback,
|
|
NULL);
|
|
|
|
#if 0
|
|
gtk_widget_install_accelerator (menu_item,
|
|
accelerator_table,
|
|
"activate", 'C', 0);
|
|
#endif /* 0 */
|
|
|
|
menu_item = gtk_menu_item_new_with_label (_("Edit"));
|
|
gtk_menu_append (GTK_MENU (gfig_op_menu), menu_item);
|
|
gtk_widget_show (menu_item);
|
|
gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
|
|
(GtkSignalFunc)gfig_edit_menu_callback,
|
|
NULL);
|
|
|
|
#if 0
|
|
gtk_widget_install_accelerator (menu_item,
|
|
accelerator_table,
|
|
"activate", 'E', 0);
|
|
#endif /* 0 */
|
|
|
|
}
|
|
|
|
static void
|
|
gfig_op_menu_popup (gint button,
|
|
guint32 activate_time,
|
|
GFigObj *obj)
|
|
{
|
|
gfig_obj_for_menu = obj; /* Static data again!*/
|
|
|
|
if (obj->obj_status & GFIG_READONLY)
|
|
{
|
|
gtk_widget_set_sensitive (save_menu_item, FALSE);
|
|
}
|
|
else
|
|
{
|
|
gtk_widget_set_sensitive (save_menu_item, TRUE);
|
|
}
|
|
|
|
gtk_menu_popup (GTK_MENU (gfig_op_menu),
|
|
NULL, NULL, NULL, NULL,
|
|
button, activate_time);
|
|
}
|
|
|
|
|
|
static gint
|
|
list_button_press (GtkWidget *widget,
|
|
GdkEventButton *event,
|
|
gpointer data)
|
|
{
|
|
switch (event->type)
|
|
{
|
|
case GDK_BUTTON_PRESS:
|
|
#ifdef DEBUG
|
|
printf ("Single button press\n");
|
|
#endif /* DEBUG */
|
|
if (event->button == 3)
|
|
{
|
|
#ifdef DEBUG
|
|
printf ("Popup on '%s'\n", ((GFigObj *)data)->draw_name);
|
|
#endif /* DEBUG */
|
|
gfig_op_menu_popup (event->button, event->time, (GFigObj *) data);
|
|
return FALSE;
|
|
}
|
|
list_button_update ((GFigObj *) data);
|
|
break;
|
|
case GDK_2BUTTON_PRESS:
|
|
#ifdef DEBUG
|
|
printf ("Two button press\n");
|
|
#endif /* DEBUG */
|
|
gfig_dialog_edit_list (widget, data, FALSE);
|
|
break;
|
|
default:
|
|
g_warning ("gfig: unknown event.\n");
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
gfig_scale_update_scale (GtkAdjustment *adjustment,
|
|
gdouble *value)
|
|
{
|
|
gimp_double_adjustment_update (adjustment, value);
|
|
|
|
if (!selvals.scaletoimage)
|
|
{
|
|
scale_x_factor = (1 / (*value)) * org_scale_x_factor;
|
|
scale_y_factor = (1 / (*value)) * org_scale_y_factor;
|
|
update_draw_area (gfig_preview, NULL);
|
|
}
|
|
}
|
|
|
|
/* Use to toggle the toggles */
|
|
static void
|
|
gfig_scale2img_update (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
gimp_toggle_button_update (widget, data);
|
|
|
|
if (*((gint *) data))
|
|
{
|
|
GtkObject *adj;
|
|
|
|
adj = gtk_object_get_user_data (GTK_OBJECT (widget));
|
|
|
|
scale_x_factor = org_scale_x_factor;
|
|
scale_y_factor = org_scale_y_factor;
|
|
gtk_adjustment_set_value (GTK_ADJUSTMENT (adj), 1.0);
|
|
|
|
update_draw_area (gfig_preview, NULL);
|
|
}
|
|
}
|
|
|
|
/* Given a row then srink it down a bit */
|
|
static void
|
|
do_gfig_preview (guchar *dest_row,
|
|
guchar *src_row,
|
|
gint width,
|
|
gint dh,
|
|
gint height,
|
|
gint bpp)
|
|
{
|
|
memcpy (dest_row, src_row, width*bpp);
|
|
}
|
|
|
|
static void
|
|
dialog_update_preview (void)
|
|
{
|
|
gint y;
|
|
gint check, check_0, check_1;
|
|
|
|
if (!selvals.showimage)
|
|
{
|
|
memset (preview_row, -1, preview_width*4);
|
|
for (y = 0; y < preview_height; y++)
|
|
{
|
|
gtk_preview_draw_row (GTK_PREVIEW (gfig_preview), preview_row,
|
|
0, y, preview_width);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (!pv_cache)
|
|
{
|
|
refill_cache ();
|
|
}
|
|
|
|
for (y = 0; y < preview_height; y++)
|
|
{
|
|
if ((y / GIMP_CHECK_SIZE) & 1)
|
|
{
|
|
check_0 = GIMP_CHECK_DARK * 255;
|
|
check_1 = GIMP_CHECK_LIGHT * 255;
|
|
}
|
|
else
|
|
{
|
|
check_0 = GIMP_CHECK_LIGHT * 255;
|
|
check_1 = GIMP_CHECK_DARK * 255;
|
|
}
|
|
|
|
do_gfig_preview (preview_row,
|
|
pv_cache+y*preview_width*img_bpp,
|
|
preview_width,
|
|
y,
|
|
preview_height,
|
|
img_bpp);
|
|
|
|
if (img_bpp > 3)
|
|
{
|
|
int i, j;
|
|
for (i = 0, j = 0 ; i < sizeof (preview_row); i += 4, j += 3)
|
|
{
|
|
gint alphaval;
|
|
if (((i/4) / GIMP_CHECK_SIZE) & 1)
|
|
check = check_0;
|
|
else
|
|
check = check_1;
|
|
|
|
alphaval = preview_row[i + 3];
|
|
|
|
preview_row[j] =
|
|
check + (((preview_row[i] - check)*alphaval)/255);
|
|
preview_row[j + 1] =
|
|
check + (((preview_row[i + 1] - check)*alphaval)/255);
|
|
preview_row[j + 2] =
|
|
check + (((preview_row[i + 2] - check)*alphaval)/255);
|
|
}
|
|
}
|
|
|
|
gtk_preview_draw_row (GTK_PREVIEW (gfig_preview), preview_row,
|
|
0, y, preview_width);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gfig_new_gc (void)
|
|
{
|
|
GdkColor fg, bg;
|
|
|
|
/* create a new graphics context */
|
|
gfig_gc = gdk_gc_new (gfig_preview->window);
|
|
gdk_gc_set_function (gfig_gc, GDK_INVERT);
|
|
fg.pixel = 0xFFFFFFFF;
|
|
bg.pixel = 0x00000000;
|
|
gdk_gc_set_foreground (gfig_gc, &fg);
|
|
gdk_gc_set_background (gfig_gc, &bg);
|
|
gdk_gc_set_line_attributes (gfig_gc, 1, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
|
|
}
|
|
|
|
static gint
|
|
get_num_radials (void)
|
|
{
|
|
gint gridsp = MAX_GRID + MIN_GRID;
|
|
/* select number of radials to draw */
|
|
/* Either have 16 32 or 48 */
|
|
/* correspond to GRID_MAX, midway and GRID_MIN */
|
|
|
|
return (gridsp - selvals.opts.gridspacing);
|
|
}
|
|
|
|
#define SQ_SIZE 8
|
|
|
|
static gint
|
|
inside_sqr (GdkPoint *cpnt,
|
|
GdkPoint *testpnt)
|
|
{
|
|
/* Return TRUE if testpnt is near cpnt */
|
|
gint16 x = cpnt->x;
|
|
gint16 y = cpnt->y;
|
|
gint16 tx = testpnt->x;
|
|
gint16 ty = testpnt->y;
|
|
|
|
#ifdef DEBUG
|
|
printf ("Testing if (%x,%x) is near (%x,%x)\n", tx, ty, x, y);
|
|
#endif /* DEBUG */
|
|
return (abs (x - tx) <= SQ_SIZE && abs (y - ty) < SQ_SIZE);
|
|
}
|
|
|
|
/* find_grid_pos - Given an x, y point return the grid position of it */
|
|
/* return the new position in the passed point */
|
|
|
|
static void
|
|
find_grid_pos (GdkPoint *p,
|
|
GdkPoint *gp,
|
|
guint is_butt3)
|
|
{
|
|
gint16 x = p->x;
|
|
gint16 y = p->y;
|
|
static GdkPoint cons_pnt;
|
|
static gdouble cons_radius;
|
|
static gdouble cons_ang;
|
|
static gboolean cons_center;
|
|
|
|
if (selvals.opts.gridtype == RECT_GRID)
|
|
{
|
|
if (p->x % selvals.opts.gridspacing > selvals.opts.gridspacing/2)
|
|
x += selvals.opts.gridspacing;
|
|
|
|
if (p->y % selvals.opts.gridspacing > selvals.opts.gridspacing/2)
|
|
y += selvals.opts.gridspacing;
|
|
|
|
gp->x = (x/selvals.opts.gridspacing)*selvals.opts.gridspacing;
|
|
gp->y = (y/selvals.opts.gridspacing)*selvals.opts.gridspacing;
|
|
|
|
if (is_butt3)
|
|
{
|
|
if (abs (gp->x - cons_pnt.x) < abs (gp->y - cons_pnt.y))
|
|
gp->x = cons_pnt.x;
|
|
else
|
|
gp->y = cons_pnt.y;
|
|
}
|
|
else
|
|
{
|
|
/* Store the point since might be used later */
|
|
cons_pnt = *gp; /* Structure copy */
|
|
}
|
|
}
|
|
else if (selvals.opts.gridtype == POLAR_GRID)
|
|
{
|
|
gdouble ang_grid;
|
|
gdouble ang_radius;
|
|
gdouble real_radius;
|
|
gdouble real_angle;
|
|
gdouble rounded_angle;
|
|
gint rounded_radius;
|
|
gint16 shift_x = x - preview_width/2;
|
|
gint16 shift_y = -y + preview_height/2;
|
|
|
|
real_radius = ang_radius = sqrt ((shift_y*shift_y) + (shift_x*shift_x));
|
|
|
|
/* round radius */
|
|
rounded_radius = (gint) (RINT (ang_radius/selvals.opts.gridspacing))*selvals.opts.gridspacing;
|
|
if (rounded_radius <= 0 || real_radius <=0)
|
|
{
|
|
/* DEAD CENTER */
|
|
gp->x = preview_width/2;
|
|
gp->y = preview_height/2;
|
|
if (!is_butt3) cons_center = TRUE;
|
|
#ifdef DEBUG
|
|
printf ("Dead center\n");
|
|
#endif /* DEBUG */
|
|
return;
|
|
}
|
|
|
|
ang_grid = 2*G_PI/get_num_radials ();
|
|
|
|
real_angle = atan2 (shift_y, shift_x);
|
|
if (real_angle < 0)
|
|
real_angle += 2*G_PI;
|
|
|
|
rounded_angle = (RINT ((real_angle/ang_grid)))*ang_grid;
|
|
#ifdef DEBUG
|
|
printf ("real_ang = %f ang_gid = %f rounded_angle = %f rounded radius = %d\n",
|
|
real_angle, ang_grid, rounded_angle, rounded_radius);
|
|
|
|
printf ("preview_width = %d preview_height = %d\n", preview_width, preview_height);
|
|
#endif /* DEBUG */
|
|
gp->x = (gint)RINT ((rounded_radius*cos (rounded_angle))) + preview_width/2;
|
|
gp->y = -(gint)RINT ((rounded_radius*sin (rounded_angle))) + preview_height/2;
|
|
|
|
if (is_butt3)
|
|
{
|
|
if (!cons_center)
|
|
{
|
|
if (fabs (rounded_angle - cons_ang) > ang_grid/2)
|
|
{
|
|
gp->x = (gint)RINT ((cons_radius*cos (rounded_angle))) + preview_width/2;
|
|
gp->y = -(gint)RINT ((cons_radius*sin (rounded_angle))) + preview_height/2;
|
|
}
|
|
else
|
|
{
|
|
gp->x = (gint)RINT ((rounded_radius*cos (cons_ang))) + preview_width/2;
|
|
gp->y = -(gint)RINT ((rounded_radius*sin (cons_ang))) + preview_height/2;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cons_radius = rounded_radius;
|
|
cons_ang = rounded_angle;
|
|
cons_center = FALSE;
|
|
}
|
|
}
|
|
else if (selvals.opts.gridtype == ISO_GRID)
|
|
{
|
|
if (is_butt3)
|
|
{
|
|
static GdkPoint b_pnt;
|
|
static GdkPoint i_pnt;
|
|
static GdkPoint ii_pnt;
|
|
gint d;
|
|
gint dd;
|
|
|
|
b_pnt.x = cons_pnt.x;
|
|
b_pnt.y = cons_pnt.y + preview_width;
|
|
d = calculate_point_to_line_distance (p, &cons_pnt, &b_pnt, &i_pnt);
|
|
|
|
b_pnt.x = cons_pnt.x;
|
|
b_pnt.y = cons_pnt.y - preview_width;
|
|
dd = calculate_point_to_line_distance (p, &cons_pnt, &b_pnt, &ii_pnt);
|
|
if (dd < d)
|
|
{
|
|
i_pnt.x = ii_pnt.x;
|
|
i_pnt.y = ii_pnt.y;
|
|
d = dd;
|
|
}
|
|
|
|
b_pnt.x = cons_pnt.x + preview_width;
|
|
b_pnt.y = cons_pnt.y + preview_width/2;
|
|
dd = calculate_point_to_line_distance (p, &cons_pnt, &b_pnt, &ii_pnt);
|
|
if (dd < d)
|
|
{
|
|
i_pnt.x = ii_pnt.x;
|
|
i_pnt.y = ii_pnt.y;
|
|
d = dd;
|
|
}
|
|
|
|
b_pnt.x = cons_pnt.x + preview_width;
|
|
b_pnt.y = cons_pnt.y - preview_width/2;
|
|
dd = calculate_point_to_line_distance (p, &cons_pnt, &b_pnt, &ii_pnt);
|
|
if (dd < d)
|
|
{
|
|
i_pnt.x = ii_pnt.x;
|
|
i_pnt.y = ii_pnt.y;
|
|
d = dd;
|
|
}
|
|
|
|
b_pnt.x = cons_pnt.x - preview_width;
|
|
b_pnt.y = cons_pnt.y + preview_width/2;
|
|
dd = calculate_point_to_line_distance (p, &cons_pnt, &b_pnt, &ii_pnt);
|
|
if (dd < d)
|
|
{
|
|
i_pnt.x = ii_pnt.x;
|
|
i_pnt.y = ii_pnt.y;
|
|
d = dd;
|
|
}
|
|
|
|
b_pnt.x = cons_pnt.x - preview_width;
|
|
b_pnt.y = cons_pnt.y - preview_width/2;
|
|
dd = calculate_point_to_line_distance (p, &cons_pnt, &b_pnt, &ii_pnt);
|
|
if (dd < d)
|
|
{
|
|
i_pnt.x = ii_pnt.x;
|
|
i_pnt.y = ii_pnt.y;
|
|
d = dd;
|
|
}
|
|
|
|
x = i_pnt.x;
|
|
y = i_pnt.y;
|
|
}
|
|
|
|
if (x % selvals.opts.gridspacing > selvals.opts.gridspacing/2)
|
|
x += selvals.opts.gridspacing;
|
|
|
|
gp->x = (x/selvals.opts.gridspacing)*selvals.opts.gridspacing;
|
|
|
|
if (((gp->x/selvals.opts.gridspacing) % 2) != 0)
|
|
{
|
|
y -= selvals.opts.gridspacing/2;
|
|
|
|
if (y % selvals.opts.gridspacing > selvals.opts.gridspacing/2)
|
|
y += selvals.opts.gridspacing;
|
|
|
|
gp->y = (selvals.opts.gridspacing/2) + ((y/selvals.opts.gridspacing)*selvals.opts.gridspacing);
|
|
}
|
|
else
|
|
{
|
|
if (y % selvals.opts.gridspacing > selvals.opts.gridspacing/2)
|
|
y += selvals.opts.gridspacing;
|
|
|
|
gp->y = (y/selvals.opts.gridspacing)*selvals.opts.gridspacing;
|
|
}
|
|
|
|
if (!is_butt3)
|
|
{
|
|
/* Store the point since it might be used later */
|
|
cons_pnt = *gp; /* Structure copy */
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Calculate distance from a point to a line
|
|
* Taken from the newsgroup comp.graphics.algorithms FAQ. */
|
|
static gint
|
|
calculate_point_to_line_distance (GdkPoint *p,
|
|
GdkPoint *A,
|
|
GdkPoint *B,
|
|
GdkPoint *I)
|
|
{
|
|
gint L2;
|
|
gint L;
|
|
|
|
L2 = ((B->x - A->x)*(B->x - A->x)) + ((B->y - A->y)*(B->y - A->y));
|
|
L = (gint) sqrt (L2);
|
|
|
|
/* gint r; */
|
|
/* gint s; */
|
|
/* r = ((A->y - p->y)*(A->y - B->y) - (A->x - p->x)*(B->x - A->x))/L2; */
|
|
/* s = ((A->y - p->y)*(B->x - A->x) - (A->x - p->x)*(B->y - A->y))/L2; */
|
|
|
|
/* Let I be the point of perpendicular projection of C onto AB. */
|
|
|
|
I->x = A->x + (((A->y - p->y)*(A->y - B->y) - (A->x - p->x)*(B->x - A->x))*(B->x - A->x))/L2;
|
|
I->y = A->y + (((A->y - p->y)*(A->y - B->y) - (A->x - p->x)*(B->x - A->x))*(B->y - A->y))/L2;
|
|
|
|
return abs ((((A->y - p->y)*(B->x - A->x)) - ((A->x - p->x)*(B->y - A->y)))*L);
|
|
}
|
|
|
|
/* Given a point x, y draw a circle */
|
|
static void
|
|
draw_circle (GdkPoint *p)
|
|
{
|
|
if (!selvals.opts.showcontrol || drawing_pic)
|
|
return;
|
|
|
|
gdk_draw_arc (gfig_preview->window,
|
|
gfig_gc,
|
|
0,
|
|
p->x - SQ_SIZE/2,
|
|
p->y - SQ_SIZE/2,
|
|
SQ_SIZE,
|
|
SQ_SIZE,
|
|
0,
|
|
360*64);
|
|
}
|
|
|
|
|
|
/* Given a point x, y draw a square around it */
|
|
static void
|
|
draw_sqr (GdkPoint *p)
|
|
{
|
|
if (!selvals.opts.showcontrol || drawing_pic)
|
|
return;
|
|
|
|
gdk_draw_rectangle (gfig_preview->window,
|
|
gfig_gc,
|
|
0,
|
|
gfig_scale_x ((gint)p->x) - SQ_SIZE/2,
|
|
gfig_scale_y ((gint)p->y) - SQ_SIZE/2,
|
|
(gint)SQ_SIZE,
|
|
(gint)SQ_SIZE);
|
|
}
|
|
|
|
/* Draw the grid on the screen
|
|
*/
|
|
|
|
static void
|
|
draw_grid_clear (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
/* wipe slate and start again */
|
|
dialog_update_preview ();
|
|
draw_grid (widget, data);
|
|
draw_objects (current_obj->obj_list, TRUE);
|
|
gtk_widget_draw (gfig_preview, NULL);
|
|
gdk_flush ();
|
|
}
|
|
|
|
static void
|
|
toggle_tooltips (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
gimp_toggle_button_update (widget, data);
|
|
|
|
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
|
|
gimp_help_enable_tooltips ();
|
|
else
|
|
gimp_help_disable_tooltips ();
|
|
}
|
|
|
|
static void
|
|
toggle_show_image (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
/* wipe slate and start again */
|
|
draw_grid_clear (widget, data);
|
|
}
|
|
|
|
static void
|
|
toggle_obj_type (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
GdkCursorType ctype = GDK_LAST_CURSOR;
|
|
static GdkCursor* p_cursors[DEL_OBJ + 1];
|
|
|
|
if (selvals.otype != (DobjType) data)
|
|
{
|
|
/* Mem leak */
|
|
obj_creating = NULL;
|
|
tmp_line = NULL;
|
|
tmp_bezier = NULL;
|
|
|
|
if ((DobjType)data < MOVE_OBJ)
|
|
{
|
|
obj_show_single = -1; /* Cancel select preview */
|
|
}
|
|
/* Update draw areas */
|
|
update_draw_area (gfig_preview, NULL);
|
|
/* And preview */
|
|
list_button_update (current_obj);
|
|
}
|
|
|
|
selvals.otype = (DobjType) data;
|
|
|
|
switch (selvals.otype)
|
|
{
|
|
case LINE:
|
|
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])
|
|
p_cursors[selvals.otype] = gdk_cursor_new (ctype);
|
|
|
|
gdk_window_set_cursor (gfig_preview->window, p_cursors[selvals.otype]);
|
|
}
|
|
|
|
static void
|
|
draw_grid_polar (GdkGC *drawgc)
|
|
{
|
|
gint step;
|
|
gint loop;
|
|
gint radius;
|
|
gint max_rad;
|
|
gdouble ang_grid;
|
|
gdouble ang_loop;
|
|
gdouble ang_radius;
|
|
/* Pick center and draw concentric circles */
|
|
|
|
gint grid_x_center = preview_width/2;
|
|
gint grid_y_center = preview_height/2;
|
|
|
|
step = selvals.opts.gridspacing;
|
|
max_rad = sqrt (preview_width * preview_width +
|
|
preview_height * preview_height) / 2;
|
|
|
|
for (loop = 0; loop < max_rad; loop += step)
|
|
{
|
|
radius = loop;
|
|
|
|
gdk_draw_arc (gfig_preview->window,
|
|
drawgc,
|
|
0,
|
|
grid_x_center - radius,
|
|
grid_y_center - radius,
|
|
radius*2,
|
|
radius*2,
|
|
0,
|
|
360 * 64);
|
|
}
|
|
|
|
/* Lines */
|
|
ang_grid = 2 * G_PI / get_num_radials ();
|
|
ang_radius = sqrt ((preview_width * preview_width) +
|
|
(preview_height * preview_height)) / 2;
|
|
|
|
for (loop = 0; loop <= get_num_radials (); loop++)
|
|
{
|
|
gint lx, ly;
|
|
|
|
ang_loop = loop * ang_grid;
|
|
|
|
lx = (gint) RINT (ang_radius * cos (ang_loop));
|
|
ly = (gint) RINT (ang_radius * sin (ang_loop));
|
|
|
|
gdk_draw_line (gfig_preview->window,
|
|
drawgc,
|
|
(gint) lx + (preview_width) / 2,
|
|
-(gint) ly + (preview_height) / 2,
|
|
(gint) (preview_width) / 2,
|
|
(gint) (preview_height) / 2);
|
|
}
|
|
}
|
|
|
|
static void
|
|
draw_grid_sq (GdkGC *drawgc)
|
|
{
|
|
gint step;
|
|
gint loop;
|
|
|
|
/* Draw the horizontal lines */
|
|
step = selvals.opts.gridspacing;
|
|
|
|
for (loop = 0 ; loop < preview_height ; loop += step)
|
|
{
|
|
gdk_draw_line (gfig_preview->window,
|
|
drawgc,
|
|
(gint)0,
|
|
(gint)loop,
|
|
(gint)preview_width,
|
|
(gint)loop);
|
|
}
|
|
|
|
/* Draw the vertical lines */
|
|
|
|
for (loop = 0 ; loop < preview_width ; loop += step)
|
|
{
|
|
gdk_draw_line (gfig_preview->window,
|
|
drawgc,
|
|
(gint)loop,
|
|
(gint)0,
|
|
(gint)loop,
|
|
(gint)preview_height);
|
|
}
|
|
}
|
|
|
|
static void
|
|
draw_grid_iso (GdkGC *drawgc)
|
|
{
|
|
gint step;
|
|
gint loop;
|
|
|
|
gint diagonal_start;
|
|
gint diagonal_end;
|
|
gint diagonal_width;
|
|
gint diagonal_height;
|
|
|
|
step = selvals.opts.gridspacing;
|
|
|
|
/* Draw the vertical lines */
|
|
for (loop = 0 ; loop < preview_width ; loop += step)
|
|
{
|
|
gdk_draw_line (gfig_preview->window,
|
|
drawgc,
|
|
(gint)loop,
|
|
(gint)0,
|
|
(gint)loop,
|
|
(gint)preview_height);
|
|
}
|
|
|
|
diagonal_start = preview_width/2;
|
|
diagonal_start = diagonal_start - (diagonal_start % step);
|
|
diagonal_start = -diagonal_start;
|
|
|
|
diagonal_end = preview_height + (preview_width/2);
|
|
diagonal_end = diagonal_end - (diagonal_end % step);
|
|
|
|
diagonal_width = preview_width;
|
|
diagonal_height = diagonal_width/2;
|
|
|
|
/* Draw diagonal lines */
|
|
for (loop = diagonal_start ; loop < diagonal_end ; loop += step)
|
|
{
|
|
gdk_draw_line (gfig_preview->window,
|
|
drawgc,
|
|
(gint)0,
|
|
(gint)loop,
|
|
(gint)diagonal_width,
|
|
(gint)loop + diagonal_height);
|
|
|
|
gdk_draw_line (gfig_preview->window,
|
|
drawgc,
|
|
(gint)0,
|
|
(gint)loop,
|
|
(gint)diagonal_width,
|
|
(gint)loop - diagonal_height);
|
|
}
|
|
}
|
|
|
|
static GdkGC *
|
|
gfig_get_grid_gc (GtkWidget *w, gint gctype)
|
|
{
|
|
switch (gctype)
|
|
{
|
|
case GFIG_BLACK_GC:
|
|
return (w->style->black_gc);
|
|
case GFIG_WHITE_GC:
|
|
return (w->style->white_gc);
|
|
case GFIG_GREY_GC:
|
|
return (grid_hightlight_drawgc);
|
|
case GTK_STATE_NORMAL:
|
|
return (w->style->bg_gc[GTK_STATE_NORMAL]);
|
|
case GTK_STATE_ACTIVE:
|
|
return (w->style->bg_gc[GTK_STATE_ACTIVE]);
|
|
case GTK_STATE_PRELIGHT:
|
|
return (w->style->bg_gc[GTK_STATE_PRELIGHT]);
|
|
case GTK_STATE_SELECTED:
|
|
return (w->style->bg_gc[GTK_STATE_SELECTED]);
|
|
case GTK_STATE_INSENSITIVE:
|
|
return (w->style->bg_gc[GTK_STATE_INSENSITIVE]);
|
|
default:
|
|
g_warning ("Unknown type for grid colouring\n");
|
|
return (w->style->bg_gc[GTK_STATE_PRELIGHT]);
|
|
}
|
|
}
|
|
|
|
static void
|
|
draw_grid (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
GdkGC *drawgc;
|
|
/* Get the size of the preview and calc where the lines go */
|
|
/* Draw in prelight to start with... */
|
|
/* Always start in the upper left corner for rect.
|
|
*/
|
|
|
|
if ((preview_width < selvals.opts.gridspacing &&
|
|
preview_height < selvals.opts.gridspacing) ||
|
|
drawing_pic)
|
|
{
|
|
/* Don't draw if they don't fit */
|
|
return;
|
|
}
|
|
|
|
if (selvals.opts.drawgrid)
|
|
drawgc = gfig_get_grid_gc (gfig_preview, grid_gc_type);
|
|
else
|
|
return;
|
|
|
|
if (selvals.opts.gridtype == RECT_GRID)
|
|
draw_grid_sq (drawgc);
|
|
else if (selvals.opts.gridtype == POLAR_GRID)
|
|
draw_grid_polar (drawgc);
|
|
else if (selvals.opts.gridtype == ISO_GRID)
|
|
draw_grid_iso (drawgc);
|
|
}
|
|
|
|
static void
|
|
do_gfig (void)
|
|
{
|
|
/* Not sure if requre post proc - leave stub in */
|
|
}
|
|
|
|
/* This could belong in a separate file ... but makes it easier to lump into
|
|
* one when compiling the plugin.
|
|
*/
|
|
|
|
/* Stuff for the generation/deletion of objects. */
|
|
|
|
/* Objects are easy one they are created - you just go down the object
|
|
* list calling the draw function for each object but... when they
|
|
* are been created we have to be a little more careful. When
|
|
* the first point is placed on the canvas we create the object,
|
|
* the mouse position then defines the next point that can move around.
|
|
* careful how we draw this position.
|
|
*/
|
|
|
|
static void
|
|
free_one_obj (Dobject *obj)
|
|
{
|
|
d_delete_dobjpoints (obj->points);
|
|
g_free (obj);
|
|
}
|
|
|
|
static void
|
|
free_all_objs (DAllObjs * objs)
|
|
{
|
|
/* Free all objects */
|
|
DAllObjs * next;
|
|
|
|
while (objs)
|
|
{
|
|
free_one_obj (objs->obj);
|
|
next = objs->next;
|
|
g_free (objs);
|
|
objs = next;
|
|
}
|
|
}
|
|
|
|
static gchar *
|
|
get_line (gchar *buf,
|
|
gint s,
|
|
FILE *from,
|
|
gint init)
|
|
{
|
|
gint slen;
|
|
char * ret;
|
|
|
|
if (init)
|
|
line_no = 1;
|
|
else
|
|
line_no++;
|
|
|
|
do
|
|
{
|
|
ret = fgets (buf, s, from);
|
|
} while (!ferror (from) && buf[0] == '#');
|
|
|
|
slen = strlen (buf);
|
|
|
|
/* The last newline is a pain */
|
|
if (slen > 0)
|
|
buf[slen - 1] = '\0';
|
|
|
|
if (ferror (from))
|
|
{
|
|
g_warning (_("Error reading file"));
|
|
return (0);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
printf ("Processing line '%s'\n", buf);
|
|
#endif /* DEBUG */
|
|
|
|
return (ret);
|
|
}
|
|
|
|
static void
|
|
gfig_clear_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
/* Make sure we can get back - if we have some objects to get back to */
|
|
if (!current_obj->obj_list)
|
|
return;
|
|
|
|
setup_undo ();
|
|
/* Free all objects */
|
|
free_all_objs (current_obj->obj_list);
|
|
current_obj->obj_list = NULL;
|
|
obj_creating = NULL;
|
|
tmp_line = NULL;
|
|
tmp_bezier = NULL;
|
|
update_draw_area (gfig_preview, NULL);
|
|
/* And preview */
|
|
list_button_update (current_obj);
|
|
}
|
|
|
|
|
|
static void
|
|
gfig_undo_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
if (undo_water_mark >= 0)
|
|
{
|
|
/* Free current objects an reinstate previous */
|
|
free_all_objs (current_obj->obj_list);
|
|
current_obj->obj_list = NULL;
|
|
tmp_bezier = tmp_line = obj_creating = NULL;
|
|
current_obj->obj_list = undo_table[undo_water_mark];
|
|
undo_water_mark--;
|
|
/* Update the screen */
|
|
update_draw_area (gfig_preview, NULL);
|
|
/* And preview */
|
|
list_button_update (current_obj);
|
|
gfig_obj_modified (current_obj, GFIG_MODIFIED);
|
|
current_obj->obj_status |= GFIG_MODIFIED;
|
|
}
|
|
|
|
if (undo_water_mark < 0)
|
|
gtk_widget_set_sensitive (widget, FALSE);
|
|
}
|
|
|
|
static void
|
|
clear_undo (void)
|
|
{
|
|
int lv;
|
|
|
|
for (lv = undo_water_mark; lv >= 0; lv--)
|
|
{
|
|
if (undo_table[lv])
|
|
free_all_objs (undo_table[lv]);
|
|
undo_table[lv] = NULL;
|
|
}
|
|
|
|
undo_water_mark = -1;
|
|
gtk_widget_set_sensitive (undo_widget, FALSE);
|
|
}
|
|
|
|
static void
|
|
setup_undo (void)
|
|
{
|
|
/* Copy object list to undo buffer */
|
|
#if DEBUG
|
|
printf ("setup undo level [%d]\n", undo_water_mark);
|
|
#endif /*DEBUG*/
|
|
|
|
if (!current_obj)
|
|
{
|
|
/* If no current_obj must be loading -> no undo */
|
|
return;
|
|
}
|
|
|
|
if (undo_water_mark >= selvals.maxundo - 1)
|
|
{
|
|
int loop;
|
|
/* the little one in the bed said "roll over".. */
|
|
if (undo_table[0])
|
|
free_one_obj (undo_table[0]->obj);
|
|
for (loop = 0; loop < undo_water_mark; loop++)
|
|
{
|
|
undo_table[loop] = undo_table[loop + 1];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
undo_water_mark++;
|
|
}
|
|
undo_table[undo_water_mark] = copy_all_objs (current_obj->obj_list);
|
|
gtk_widget_set_sensitive (undo_widget, TRUE);
|
|
|
|
gfig_obj_modified (current_obj, GFIG_MODIFIED);
|
|
current_obj->obj_status |= GFIG_MODIFIED;
|
|
}
|
|
|
|
/* Given a number of float co-ords adjust for scaling back to org size */
|
|
/* Size is number of PAIRS of points */
|
|
/* FP + int varients */
|
|
|
|
static void
|
|
scale_to_orginal_x (gdouble *list)
|
|
{
|
|
*list *= scale_x_factor;
|
|
}
|
|
|
|
static gint
|
|
gfig_scale_x (gint x)
|
|
{
|
|
if (!selvals.scaletoimage)
|
|
return (gint) (x * (1 / scale_x_factor));
|
|
else
|
|
return x;
|
|
}
|
|
|
|
static gint
|
|
gfig_invscale_x (gint x)
|
|
{
|
|
if (!selvals.scaletoimage)
|
|
return (gint) (x * (scale_x_factor));
|
|
else
|
|
return x;
|
|
}
|
|
|
|
static void
|
|
scale_to_orginal_y (gdouble *list)
|
|
{
|
|
*list *= scale_y_factor;
|
|
}
|
|
|
|
static gint
|
|
gfig_scale_y (gint y)
|
|
{
|
|
if (!selvals.scaletoimage)
|
|
return (gint) (y * (1 / scale_y_factor));
|
|
else
|
|
return y;
|
|
}
|
|
|
|
static gint
|
|
gfig_invscale_y (gint y)
|
|
{
|
|
if (!selvals.scaletoimage)
|
|
return (gint) (y*(scale_y_factor));
|
|
else
|
|
return y;
|
|
}
|
|
|
|
/* Pairs x followed by y */
|
|
static 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 */
|
|
static 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);
|
|
}
|
|
}
|
|
|
|
/* Given an list of PAIRS of doubles reverse the list */
|
|
/* Size is number of pairs to swap */
|
|
static void
|
|
reverse_pairs_list (gdouble *list,
|
|
gint size)
|
|
{
|
|
gint i;
|
|
|
|
struct cs
|
|
{
|
|
gdouble i1;
|
|
gdouble i2;
|
|
} copyit, *orglist;
|
|
|
|
orglist = (struct cs *) list;
|
|
|
|
/* Uses struct copies */
|
|
for (i = 0; i < size / 2; i++)
|
|
{
|
|
copyit = orglist[i];
|
|
orglist[i] = orglist[size - 1 - i];
|
|
orglist[size - 1 - i] = copyit;
|
|
}
|
|
}
|
|
|
|
/* Delete a list of points */
|
|
static void
|
|
d_delete_dobjpoints (DobjPoints * pnts)
|
|
{
|
|
DobjPoints * next;
|
|
DobjPoints * pnt2del = pnts;
|
|
|
|
while (pnt2del)
|
|
{
|
|
next = pnt2del->next;
|
|
g_free (pnt2del);
|
|
pnt2del = next;
|
|
}
|
|
}
|
|
|
|
static DobjPoints *
|
|
d_copy_dobjpoints (DobjPoints * pnts)
|
|
{
|
|
DobjPoints *ret = NULL;
|
|
DobjPoints *head = NULL;
|
|
DobjPoints *newpnt;
|
|
DobjPoints *pnt2copy = pnts;
|
|
|
|
while (pnt2copy)
|
|
{
|
|
newpnt = g_new0 (DobjPoints, 1);
|
|
newpnt->pnt.x = pnt2copy->pnt.x;
|
|
newpnt->pnt.y = pnt2copy->pnt.y;
|
|
|
|
if (!ret)
|
|
head = ret = newpnt;
|
|
else
|
|
{
|
|
head->next = newpnt;
|
|
head = newpnt;
|
|
}
|
|
pnt2copy = pnt2copy->next;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static gint
|
|
scan_obj_points (DobjPoints *opnt,
|
|
GdkPoint *pnt)
|
|
{
|
|
while (opnt)
|
|
{
|
|
if (inside_sqr (&opnt->pnt, pnt))
|
|
{
|
|
opnt->found_me = TRUE;
|
|
return TRUE;
|
|
}
|
|
opnt->found_me = FALSE;
|
|
opnt = opnt->next;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static Dobject *
|
|
get_nearest_objs (GFigObj *obj,
|
|
GdkPoint *pnt)
|
|
{
|
|
/* Nearest object to given point or NULL */
|
|
DAllObjs *all;
|
|
Dobject *test_obj;
|
|
gint count = 0;
|
|
|
|
if (!obj)
|
|
return NULL;
|
|
|
|
all = obj->obj_list;
|
|
|
|
while (all)
|
|
{
|
|
test_obj = all->obj;
|
|
|
|
if (count == obj_show_single || obj_show_single == -1)
|
|
if (scan_obj_points (test_obj->points, pnt))
|
|
{
|
|
return test_obj;
|
|
}
|
|
all = all->next;
|
|
count++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
scale_obj_points (DobjPoints *opnt,
|
|
gdouble scale_x,
|
|
gdouble scale_y)
|
|
{
|
|
while (opnt)
|
|
{
|
|
opnt->pnt.x = (gint) (opnt->pnt.x * scale_x);
|
|
opnt->pnt.y = (gint) (opnt->pnt.y * scale_y);
|
|
opnt = opnt->next;
|
|
}
|
|
}
|
|
|
|
static void
|
|
remove_obj_from_list (GFigObj *obj,
|
|
Dobject *del_obj)
|
|
{
|
|
/* Nearest object to given point or NULL */
|
|
DAllObjs *all;
|
|
DAllObjs *prev_all = NULL;
|
|
|
|
g_assert (del_obj != NULL);
|
|
|
|
all = obj->obj_list;
|
|
|
|
while (all)
|
|
{
|
|
if (all->obj == del_obj)
|
|
{
|
|
/* Found the one to delete */
|
|
#ifdef DEBUG
|
|
printf ("Found the one to delete\n");
|
|
#endif /* DEBUG */
|
|
|
|
if (prev_all)
|
|
prev_all->next = all->next;
|
|
else
|
|
obj->obj_list = all->next;
|
|
|
|
/* Draw obj (which will actually undraw it! */
|
|
del_obj->drawfunc (del_obj);
|
|
|
|
free_one_obj (del_obj);
|
|
g_free (all);
|
|
|
|
if (obj_show_single != -1)
|
|
{
|
|
/* We've just deleted the only visible one */
|
|
draw_grid_clear (NULL, NULL); /*Args not used */
|
|
obj_show_single = -1; /* Show all again */
|
|
}
|
|
return;
|
|
}
|
|
prev_all = all;
|
|
all = all->next;
|
|
}
|
|
g_warning (_("Hey where has the object gone ?"));
|
|
}
|
|
|
|
static DobjPoints *
|
|
get_diffs (Dobject *obj,
|
|
gint16 *xdiff,
|
|
gint16 *ydiff,
|
|
GdkPoint *to_pnt)
|
|
{
|
|
DobjPoints *spnt;
|
|
|
|
g_assert (obj != NULL);
|
|
|
|
spnt = obj->points;
|
|
|
|
if (!spnt)
|
|
return (NULL); /* no-line */
|
|
|
|
/* Slow slow slowwwwww....*/
|
|
while (spnt)
|
|
{
|
|
if (spnt->found_me)
|
|
{
|
|
*xdiff = spnt->pnt.x - to_pnt->x;
|
|
*ydiff = spnt->pnt.y - to_pnt->y;
|
|
return (spnt);
|
|
}
|
|
spnt = spnt->next;
|
|
}
|
|
return (NULL);
|
|
}
|
|
|
|
static void
|
|
update_pnts (Dobject *obj,
|
|
gint16 xdiff,
|
|
gint16 ydiff)
|
|
{
|
|
DobjPoints *spnt;
|
|
|
|
g_assert (obj != NULL);
|
|
|
|
/* Update all pnts */
|
|
spnt = obj->points;
|
|
|
|
if (!spnt)
|
|
return; /* no-line */
|
|
|
|
/* Go around all the points drawing a line from one to the next */
|
|
while (spnt)
|
|
{
|
|
spnt->pnt.x = spnt->pnt.x - xdiff;
|
|
spnt->pnt.y = spnt->pnt.y - ydiff;
|
|
spnt = spnt->next;
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
do_move_all_obj (GdkPoint *to_pnt)
|
|
{
|
|
/* Move all objects in one go */
|
|
/* Undraw/then draw in new pos */
|
|
DAllObjs *all;
|
|
Dobject *obj;
|
|
gint16 xdiff = 0;
|
|
gint16 ydiff = 0;
|
|
|
|
xdiff = move_all_pnt->x - to_pnt->x;
|
|
ydiff = move_all_pnt->y - to_pnt->y;
|
|
|
|
if (!xdiff && !ydiff)
|
|
return;
|
|
|
|
all = current_obj->obj_list;
|
|
|
|
while (all)
|
|
{
|
|
obj = all->obj;
|
|
|
|
/* undraw ! */
|
|
draw_one_obj (obj);
|
|
|
|
update_pnts (obj, xdiff, ydiff);
|
|
|
|
/* Draw in new pos */
|
|
draw_one_obj (obj);
|
|
|
|
all = all->next;
|
|
}
|
|
|
|
*move_all_pnt = *to_pnt; /* Structure copy */
|
|
}
|
|
|
|
|
|
static void
|
|
do_move_obj (Dobject *obj,
|
|
GdkPoint *to_pnt)
|
|
{
|
|
/* Move the whole line - undraw the line to start with */
|
|
/* Then draw in new pos */
|
|
gint16 xdiff = 0;
|
|
gint16 ydiff = 0;
|
|
|
|
get_diffs (obj, &xdiff, &ydiff, to_pnt);
|
|
|
|
if (!xdiff && !ydiff)
|
|
return;
|
|
|
|
/* undraw ! */
|
|
draw_one_obj (obj);
|
|
|
|
update_pnts (obj, xdiff, ydiff);
|
|
|
|
/* Draw in new pos */
|
|
draw_one_obj (obj);
|
|
|
|
}
|
|
|
|
static void
|
|
do_move_obj_pnt (Dobject *obj,
|
|
GdkPoint *to_pnt)
|
|
{
|
|
/* Move the whole line - undraw the line to start with */
|
|
/* Then draw in new pos */
|
|
DobjPoints *spnt;
|
|
gint16 xdiff = 0;
|
|
gint16 ydiff = 0;
|
|
|
|
spnt = get_diffs (obj, &xdiff, &ydiff, to_pnt);
|
|
|
|
if ((!xdiff && !ydiff) || !spnt)
|
|
return;
|
|
|
|
/* undraw ! */
|
|
draw_one_obj (obj);
|
|
|
|
spnt->pnt.x = spnt->pnt.x - xdiff;
|
|
spnt->pnt.y = spnt->pnt.y - ydiff;
|
|
|
|
/* Draw in new pos */
|
|
draw_one_obj (obj);
|
|
}
|
|
|
|
/* Save a line away to the specified stream */
|
|
|
|
static void
|
|
d_save_line (Dobject *obj,
|
|
FILE *to)
|
|
{
|
|
DobjPoints * spnt;
|
|
|
|
spnt = obj->points;
|
|
|
|
if (!spnt)
|
|
return; /* End-of-line */
|
|
|
|
fprintf (to, "<LINE>\n");
|
|
|
|
while (spnt)
|
|
{
|
|
fprintf (to, "%d %d\n",
|
|
(gint)spnt->pnt.x,
|
|
(gint)spnt->pnt.y);
|
|
spnt = spnt->next;
|
|
}
|
|
|
|
fprintf (to, "</LINE>\n");
|
|
}
|
|
|
|
/* Load a line from the specified stream */
|
|
|
|
static Dobject *
|
|
d_load_line (FILE *from)
|
|
{
|
|
Dobject *new_obj = NULL;
|
|
gint xpnt;
|
|
gint ypnt;
|
|
gchar buf[MAX_LOAD_LINE];
|
|
|
|
#ifdef DEBUG
|
|
printf ("Load line called\n");
|
|
#endif /* DEBUG */
|
|
|
|
while (get_line (buf, MAX_LOAD_LINE, from, 0))
|
|
{
|
|
if (sscanf (buf, "%d %d", &xpnt, &ypnt) != 2)
|
|
{
|
|
/* Must be the end */
|
|
if (strcmp ("</LINE>", buf))
|
|
{
|
|
g_warning ("[%d] Internal load error while loading line",
|
|
line_no);
|
|
return (NULL);
|
|
}
|
|
return (new_obj);
|
|
}
|
|
|
|
if (!new_obj)
|
|
new_obj = d_new_line (xpnt, ypnt);
|
|
else
|
|
d_pnt_add_line (new_obj, xpnt, ypnt, -1);
|
|
}
|
|
|
|
return (new_obj);
|
|
}
|
|
|
|
static Dobject *
|
|
d_copy_line (Dobject *obj)
|
|
{
|
|
Dobject *nl;
|
|
|
|
if (!obj)
|
|
return (NULL);
|
|
|
|
g_assert (obj->type == LINE);
|
|
|
|
nl = d_new_line (obj->points->pnt.x, obj->points->pnt.y);
|
|
|
|
nl->points->next = d_copy_dobjpoints (obj->points->next);
|
|
|
|
return (nl);
|
|
}
|
|
|
|
/* Draw the given line -- */
|
|
static void
|
|
d_draw_line (Dobject *obj)
|
|
{
|
|
DobjPoints *spnt;
|
|
DobjPoints *epnt;
|
|
|
|
spnt = obj->points;
|
|
|
|
if (!spnt)
|
|
return; /* End-of-line */
|
|
|
|
epnt = spnt->next;
|
|
|
|
while (spnt && epnt)
|
|
{
|
|
#if DEBUG
|
|
printf ("Drawing line 0x%x (%x,%x) -> (%x,%x)\n", spnt,
|
|
(gint)spnt->pnt.x,
|
|
(gint)spnt->pnt.y,
|
|
(gint)epnt->pnt.x,
|
|
(gint)epnt->pnt.y);
|
|
#endif /* DEBUG */
|
|
|
|
draw_sqr (&spnt->pnt);
|
|
/* Go around all the points drawing a line from one to the next */
|
|
if (drawing_pic)
|
|
{
|
|
gdk_draw_line (pic_preview->window,
|
|
pic_preview->style->black_gc,
|
|
adjust_pic_coords ((gint)spnt->pnt.x, preview_width),
|
|
adjust_pic_coords ((gint)spnt->pnt.y, preview_height),
|
|
adjust_pic_coords ((gint)epnt->pnt.x, preview_width),
|
|
adjust_pic_coords ((gint)epnt->pnt.y, preview_height));
|
|
}
|
|
else
|
|
{
|
|
gdk_draw_line (gfig_preview->window,
|
|
gfig_gc,
|
|
gfig_scale_x ((gint)spnt->pnt.x),
|
|
gfig_scale_y ((gint)spnt->pnt.y),
|
|
gfig_scale_x ((gint)epnt->pnt.x),
|
|
gfig_scale_y ((gint)epnt->pnt.y));
|
|
}
|
|
spnt = epnt;
|
|
epnt = epnt->next;
|
|
}
|
|
draw_sqr (&spnt->pnt);
|
|
}
|
|
|
|
static void
|
|
d_paint_line (Dobject *obj)
|
|
{
|
|
DobjPoints * spnt;
|
|
gdouble *line_pnts;
|
|
gint seg_count = 0;
|
|
gint i = 0;
|
|
|
|
spnt = obj->points;
|
|
|
|
/* count */
|
|
|
|
while (spnt)
|
|
{
|
|
seg_count++;
|
|
spnt = spnt->next;
|
|
}
|
|
|
|
spnt = obj->points;
|
|
|
|
if (!spnt || !seg_count)
|
|
return; /* no-line */
|
|
|
|
line_pnts = g_new0 (gdouble, 2 * seg_count + 1);
|
|
|
|
/* Go around all the points drawing a line from one to the next */
|
|
while (spnt)
|
|
{
|
|
line_pnts[i++] = spnt->pnt.x;
|
|
line_pnts[i++] = spnt->pnt.y;
|
|
spnt = spnt->next;
|
|
}
|
|
|
|
/* Reverse line if approp */
|
|
if (selvals.reverselines)
|
|
reverse_pairs_list (&line_pnts[0], i/2);
|
|
|
|
/* Scale before drawing */
|
|
if (selvals.scaletoimage)
|
|
scale_to_original_xy (&line_pnts[0], i/2);
|
|
else
|
|
scale_to_xy (&line_pnts[0], i/2);
|
|
|
|
/* One go */
|
|
if (selvals.painttype == PAINT_BRUSH_TYPE)
|
|
{
|
|
gfig_paint (selvals.brshtype,
|
|
gfig_drawable,
|
|
seg_count * 2, line_pnts);
|
|
}
|
|
else
|
|
{
|
|
gimp_free_select (gfig_image,
|
|
seg_count * 2, line_pnts,
|
|
selopt.type,
|
|
selopt.antia,
|
|
selopt.feather,
|
|
selopt.feather_radius);
|
|
}
|
|
|
|
g_free (line_pnts);
|
|
}
|
|
|
|
|
|
/* Create a new line object. starting at the x, y point might add styles
|
|
* later.
|
|
*/
|
|
|
|
static Dobject *
|
|
d_new_line (gint x,
|
|
gint y)
|
|
{
|
|
Dobject *nobj;
|
|
DobjPoints *npnt;
|
|
|
|
/* Get new object and starting point */
|
|
|
|
/* Start point */
|
|
npnt = g_new0 (DobjPoints, 1);
|
|
|
|
#if DEBUG
|
|
printf ("New line start at (%x,%x)\n", x, y);
|
|
#endif /* DEBUG */
|
|
npnt->pnt.x = x;
|
|
npnt->pnt.y = y;
|
|
|
|
nobj = g_new0 (Dobject, 1);
|
|
|
|
nobj->type = LINE;
|
|
nobj->points = npnt;
|
|
nobj->drawfunc = d_draw_line;
|
|
nobj->loadfunc = d_load_line;
|
|
nobj->savefunc = d_save_line;
|
|
nobj->paintfunc = d_paint_line;
|
|
nobj->copyfunc = d_copy_line;
|
|
|
|
return (nobj);
|
|
}
|
|
|
|
/* You guessed it delete the object !*/
|
|
/*
|
|
static void
|
|
d_delete_line (Dobject *obj)
|
|
{
|
|
g_assert (obj != NULL);
|
|
* First free the list of points - then the object itself *
|
|
d_delete_dobjpoints (obj->points);
|
|
g_free (obj);
|
|
}
|
|
*/
|
|
|
|
/* Add a point to a line (given x, y)
|
|
* pos = 0 = head
|
|
* pos = -1 = tail
|
|
* 0 < pos = nth position
|
|
*/
|
|
|
|
static void
|
|
d_pnt_add_line (Dobject *obj,
|
|
gint x,
|
|
gint y,
|
|
gint pos)
|
|
{
|
|
DobjPoints *npnts = g_new0 (DobjPoints, 1);
|
|
|
|
g_assert (obj != NULL);
|
|
|
|
npnts->pnt.x = x;
|
|
npnts->pnt.y = y;
|
|
|
|
if (!pos)
|
|
{
|
|
/* Add to head */
|
|
npnts->next = obj->points;
|
|
obj->points = npnts;
|
|
}
|
|
else
|
|
{
|
|
DobjPoints *pnt = obj->points;
|
|
|
|
/* Go down chain until the end if pos */
|
|
while (pos < 0 || pos-- > 0)
|
|
{
|
|
if (!(pnt->next) || !pos)
|
|
{
|
|
npnts->next = pnt->next;
|
|
pnt->next = npnts;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
pnt = pnt->next;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Update end point of line */
|
|
static void
|
|
d_update_line (GdkPoint *pnt)
|
|
{
|
|
DobjPoints *spnt, *epnt;
|
|
/* Get last but one segment and undraw it -
|
|
* Then draw new segment in.
|
|
* always dealing with the static object.
|
|
*/
|
|
|
|
/* Get start of segments */
|
|
spnt = obj_creating->points;
|
|
|
|
if (!spnt)
|
|
return; /* No points */
|
|
|
|
if ((epnt = spnt->next))
|
|
{
|
|
/* undraw current */
|
|
/* Draw square on point */
|
|
draw_circle (&epnt->pnt);
|
|
|
|
gdk_draw_line (gfig_preview->window,
|
|
/*gfig_preview->style->bg_gc[GTK_STATE_NORMAL],*/
|
|
gfig_gc,
|
|
(gint) spnt->pnt.x,
|
|
(gint) spnt->pnt.y,
|
|
(gint) epnt->pnt.x,
|
|
(gint) epnt->pnt.y);
|
|
g_free (epnt);
|
|
}
|
|
|
|
/* draw new */
|
|
/* Draw circle on point */
|
|
draw_circle (pnt);
|
|
|
|
epnt = g_new0 (DobjPoints, 1);
|
|
|
|
epnt->pnt.x = pnt->x;
|
|
epnt->pnt.y = pnt->y;
|
|
|
|
gdk_draw_line (gfig_preview->window,
|
|
/*gfig_preview->style->bg_gc[GTK_STATE_NORMAL],*/
|
|
gfig_gc,
|
|
(gint) spnt->pnt.x,
|
|
(gint) spnt->pnt.y,
|
|
(gint) epnt->pnt.x,
|
|
(gint) epnt->pnt.y);
|
|
spnt->next = epnt;
|
|
}
|
|
|
|
static void
|
|
d_line_start (GdkPoint *pnt,
|
|
gint shift_down)
|
|
{
|
|
if (!obj_creating || !shift_down)
|
|
{
|
|
/* Draw square on point */
|
|
/* Must delete obj_creating if we have one */
|
|
obj_creating = d_new_line (pnt->x, pnt->y);
|
|
}
|
|
else
|
|
{
|
|
/* Contniuation */
|
|
d_update_line (pnt);
|
|
}
|
|
}
|
|
|
|
static void
|
|
d_line_end (GdkPoint *pnt,
|
|
gint shift_down)
|
|
{
|
|
/* Undraw the last circle */
|
|
draw_circle (pnt);
|
|
|
|
if (shift_down)
|
|
{
|
|
if (tmp_line)
|
|
{
|
|
GdkPoint tmp_pnt = *pnt;
|
|
|
|
if (need_to_scale)
|
|
{
|
|
tmp_pnt.x = (gint) (pnt->x * scale_x_factor);
|
|
tmp_pnt.y = (gint) (pnt->y * scale_y_factor);
|
|
}
|
|
|
|
d_pnt_add_line (tmp_line, tmp_pnt.x, tmp_pnt.y, -1);
|
|
free_one_obj (obj_creating);
|
|
/* Must free obj_creating */
|
|
}
|
|
else
|
|
{
|
|
tmp_line = obj_creating;
|
|
add_to_all_obj (current_obj, obj_creating);
|
|
}
|
|
|
|
obj_creating = d_new_line (pnt->x, pnt->y);
|
|
}
|
|
else
|
|
{
|
|
if (tmp_line)
|
|
{
|
|
GdkPoint tmp_pnt = *pnt;
|
|
|
|
if (need_to_scale)
|
|
{
|
|
tmp_pnt.x = (gint) (pnt->x * scale_x_factor);
|
|
tmp_pnt.y = (gint) (pnt->y * scale_y_factor);
|
|
}
|
|
|
|
d_pnt_add_line (tmp_line, tmp_pnt.x, tmp_pnt.y, -1);
|
|
free_one_obj (obj_creating);
|
|
/* Must free obj_creating */
|
|
}
|
|
else
|
|
{
|
|
add_to_all_obj (current_obj, obj_creating);
|
|
}
|
|
obj_creating = NULL;
|
|
tmp_line = NULL;
|
|
}
|
|
/*update_draw_area (gfig_preview, NULL);*/
|
|
}
|
|
|
|
/* Save a circle away to the specified stream */
|
|
|
|
static void
|
|
d_save_circle (Dobject *obj,
|
|
FILE *to)
|
|
{
|
|
DobjPoints *spnt;
|
|
|
|
spnt = obj->points;
|
|
|
|
if (!spnt)
|
|
return;
|
|
|
|
fprintf (to, "<CIRCLE>\n");
|
|
|
|
while (spnt)
|
|
{
|
|
fprintf (to, "%d %d\n",
|
|
(gint) spnt->pnt.x,
|
|
(gint) spnt->pnt.y);
|
|
spnt = spnt->next;
|
|
}
|
|
|
|
fprintf (to, "</CIRCLE>\n");
|
|
}
|
|
|
|
/* Load a circle from the specified stream */
|
|
|
|
static Dobject *
|
|
d_load_circle (FILE *from)
|
|
{
|
|
Dobject *new_obj = NULL;
|
|
gint xpnt;
|
|
gint ypnt;
|
|
gchar buf[MAX_LOAD_LINE];
|
|
|
|
#ifdef DEBUG
|
|
printf ("Load circle called\n");
|
|
#endif /* DEBUG */
|
|
|
|
while (get_line (buf, MAX_LOAD_LINE, from, 0))
|
|
{
|
|
if (sscanf (buf, "%d %d", &xpnt, &ypnt) != 2)
|
|
{
|
|
/* Must be the end */
|
|
if (strcmp ("</CIRCLE>", buf))
|
|
{
|
|
g_warning ("[%d] Internal load error while loading circle",
|
|
line_no);
|
|
return NULL;
|
|
}
|
|
return new_obj;
|
|
}
|
|
|
|
if (!new_obj)
|
|
new_obj = d_new_circle (xpnt, ypnt);
|
|
else
|
|
{
|
|
DobjPoints *edge_pnt;
|
|
/* Circles only have two points */
|
|
edge_pnt = g_new0 (DobjPoints, 1);
|
|
|
|
edge_pnt->pnt.x = xpnt;
|
|
edge_pnt->pnt.y = ypnt;
|
|
|
|
new_obj->points->next = edge_pnt;
|
|
}
|
|
}
|
|
|
|
g_warning ("[%d] Not enough points for circle", line_no);
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
d_draw_circle (Dobject * obj)
|
|
{
|
|
DobjPoints *center_pnt;
|
|
DobjPoints *edge_pnt;
|
|
gdouble radius;
|
|
|
|
center_pnt = obj->points;
|
|
|
|
if (!center_pnt)
|
|
return; /* End-of-line */
|
|
|
|
edge_pnt = center_pnt->next;
|
|
|
|
if (!edge_pnt)
|
|
{
|
|
g_warning ("Internal error - circle no edge pnt");
|
|
}
|
|
|
|
radius = sqrt (((center_pnt->pnt.x - edge_pnt->pnt.x) *
|
|
(center_pnt->pnt.x - edge_pnt->pnt.x)) +
|
|
((center_pnt->pnt.y - edge_pnt->pnt.y) *
|
|
(center_pnt->pnt.y - edge_pnt->pnt.y)));
|
|
|
|
draw_sqr (¢er_pnt->pnt);
|
|
draw_sqr (&edge_pnt->pnt);
|
|
|
|
if (drawing_pic)
|
|
{
|
|
gdk_draw_arc (pic_preview->window,
|
|
pic_preview->style->black_gc,
|
|
0,
|
|
adjust_pic_coords (center_pnt->pnt.x - radius,
|
|
preview_width),
|
|
adjust_pic_coords (center_pnt->pnt.y - radius,
|
|
preview_height),
|
|
adjust_pic_coords (radius * 2,
|
|
preview_width),
|
|
adjust_pic_coords (radius * 2,
|
|
preview_height),
|
|
0,
|
|
360 * 64);
|
|
}
|
|
else
|
|
{
|
|
gdk_draw_arc (gfig_preview->window,
|
|
gfig_gc,
|
|
0,
|
|
gfig_scale_x (center_pnt->pnt.x - (gint) RINT (radius)),
|
|
gfig_scale_y (center_pnt->pnt.y - (gint) RINT (radius)),
|
|
gfig_scale_x ((gint) RINT (radius) * 2),
|
|
gfig_scale_y ((gint) RINT (radius) * 2),
|
|
0,
|
|
360 * 64);
|
|
}
|
|
}
|
|
|
|
static void
|
|
d_paint_circle (Dobject *obj)
|
|
{
|
|
DobjPoints * center_pnt;
|
|
DobjPoints * edge_pnt;
|
|
gint radius;
|
|
gdouble dpnts[4];
|
|
|
|
g_assert (obj != NULL);
|
|
|
|
if (selvals.approxcircles)
|
|
{
|
|
obj->type_data = (gpointer) 600;
|
|
#ifdef DEBUG
|
|
printf ("Painting circle as polygon\n");
|
|
#endif /* DEBUG */
|
|
d_paint_poly (obj);
|
|
return;
|
|
}
|
|
|
|
/* Drawing circles is hard .
|
|
* 1) select circle
|
|
* 2) stroke it
|
|
*/
|
|
center_pnt = obj->points;
|
|
|
|
if (!center_pnt)
|
|
return; /* End-of-line */
|
|
|
|
edge_pnt = center_pnt->next;
|
|
|
|
if (!edge_pnt)
|
|
{
|
|
g_error ("Internal error - circle no edge pnt");
|
|
}
|
|
|
|
radius = (gint) sqrt (((center_pnt->pnt.x - edge_pnt->pnt.x) *
|
|
(center_pnt->pnt.x - edge_pnt->pnt.x)) +
|
|
((center_pnt->pnt.y - edge_pnt->pnt.y) *
|
|
(center_pnt->pnt.y - edge_pnt->pnt.y)));
|
|
|
|
dpnts[0] = (gdouble) center_pnt->pnt.x - radius;
|
|
dpnts[1] = (gdouble) center_pnt->pnt.y - radius;
|
|
dpnts[3] = dpnts[2] = (gdouble) radius * 2;
|
|
|
|
/* Scale before drawing */
|
|
if (selvals.scaletoimage)
|
|
scale_to_original_xy (&dpnts[0], 2);
|
|
else
|
|
scale_to_xy (&dpnts[0], 2);
|
|
|
|
gimp_ellipse_select (gfig_image,
|
|
dpnts[0], dpnts[1],
|
|
dpnts[2], dpnts[3],
|
|
selopt.type,
|
|
selopt.antia,
|
|
selopt.feather,
|
|
selopt.feather_radius);
|
|
|
|
/* Is selection all we need ? */
|
|
if (selvals.painttype == PAINT_SELECTION_TYPE)
|
|
return;
|
|
|
|
gimp_edit_stroke (gfig_drawable);
|
|
|
|
gimp_selection_clear (gfig_image);
|
|
}
|
|
|
|
static Dobject *
|
|
d_copy_circle (Dobject * obj)
|
|
{
|
|
Dobject *nc;
|
|
|
|
#if DEBUG
|
|
printf ("Copy circle\n");
|
|
#endif /*DEBUG*/
|
|
if (!obj)
|
|
return NULL;
|
|
|
|
g_assert (obj->type == CIRCLE);
|
|
|
|
nc = d_new_circle (obj->points->pnt.x, obj->points->pnt.y);
|
|
|
|
nc->points->next = d_copy_dobjpoints (obj->points->next);
|
|
|
|
#if DEBUG
|
|
printf ("Circle (%x,%x) to (%x,%x)\n",
|
|
nc->points->pnt.x, obj->points->pnt.y,
|
|
nc->points->next->pnt.x, obj->points->next->pnt.y);
|
|
printf ("Done copy\n");
|
|
#endif /*DEBUG*/
|
|
return nc;
|
|
}
|
|
|
|
static Dobject *
|
|
d_new_circle (gint x,
|
|
gint y)
|
|
{
|
|
Dobject *nobj;
|
|
DobjPoints *npnt;
|
|
|
|
/* Get new object and starting point */
|
|
|
|
/* Start point */
|
|
npnt = g_new0 (DobjPoints, 1);
|
|
|
|
#if DEBUG
|
|
printf ("New circle start at (%x,%x)\n", x, y);
|
|
#endif /* DEBUG */
|
|
npnt->pnt.x = x;
|
|
npnt->pnt.y = y;
|
|
|
|
nobj = g_new0 (Dobject, 1);
|
|
|
|
nobj->type = CIRCLE;
|
|
nobj->points = npnt;
|
|
nobj->drawfunc = d_draw_circle;
|
|
nobj->loadfunc = d_load_circle;
|
|
nobj->savefunc = d_save_circle;
|
|
nobj->paintfunc = d_paint_circle;
|
|
nobj->copyfunc = d_copy_circle;
|
|
|
|
return nobj;
|
|
}
|
|
|
|
static void
|
|
d_update_circle (GdkPoint *pnt)
|
|
{
|
|
DobjPoints *center_pnt, *edge_pnt;
|
|
gdouble radius;
|
|
|
|
/* Undraw last one then draw new one */
|
|
center_pnt = obj_creating->points;
|
|
|
|
if (!center_pnt)
|
|
return; /* No points */
|
|
|
|
if ((edge_pnt = center_pnt->next))
|
|
{
|
|
/* Undraw current */
|
|
draw_circle (&edge_pnt->pnt);
|
|
radius = sqrt (((center_pnt->pnt.x - edge_pnt->pnt.x) *
|
|
(center_pnt->pnt.x - edge_pnt->pnt.x)) +
|
|
((center_pnt->pnt.y - edge_pnt->pnt.y) *
|
|
(center_pnt->pnt.y - edge_pnt->pnt.y)));
|
|
|
|
gdk_draw_arc (gfig_preview->window,
|
|
gfig_gc,
|
|
0,
|
|
center_pnt->pnt.x - (gint) RINT (radius),
|
|
center_pnt->pnt.y - (gint) RINT (radius),
|
|
(gint) RINT (radius) * 2,
|
|
(gint) RINT (radius) * 2,
|
|
0,
|
|
360 * 64);
|
|
}
|
|
|
|
draw_circle (pnt);
|
|
|
|
edge_pnt = g_new0 (DobjPoints, 1);
|
|
|
|
edge_pnt->pnt.x = pnt->x;
|
|
edge_pnt->pnt.y = pnt->y;
|
|
|
|
radius = sqrt (((center_pnt->pnt.x - edge_pnt->pnt.x) *
|
|
(center_pnt->pnt.x - edge_pnt->pnt.x)) +
|
|
((center_pnt->pnt.y - edge_pnt->pnt.y) *
|
|
(center_pnt->pnt.y - edge_pnt->pnt.y)));
|
|
|
|
gdk_draw_arc (gfig_preview->window,
|
|
gfig_gc,
|
|
0,
|
|
center_pnt->pnt.x - (gint) RINT (radius),
|
|
center_pnt->pnt.y - (gint) RINT (radius),
|
|
(gint) RINT (radius) * 2,
|
|
(gint) RINT (radius) * 2,
|
|
0,
|
|
360 * 64);
|
|
|
|
center_pnt->next = edge_pnt;
|
|
}
|
|
|
|
static void
|
|
d_circle_start (GdkPoint *pnt,
|
|
gint shift_down)
|
|
{
|
|
obj_creating = d_new_circle (pnt->x, pnt->y);
|
|
}
|
|
|
|
static void
|
|
d_circle_end (GdkPoint *pnt,
|
|
gint shift_down)
|
|
{
|
|
/* Under contrl point */
|
|
if (!obj_creating->points->next)
|
|
{
|
|
/* No circle created */
|
|
free_one_obj (obj_creating);
|
|
}
|
|
else
|
|
{
|
|
draw_circle (pnt);
|
|
add_to_all_obj (current_obj, obj_creating);
|
|
}
|
|
|
|
obj_creating = NULL;
|
|
}
|
|
|
|
/* Save an ellipse away to the specified stream */
|
|
|
|
static void
|
|
d_save_ellipse (Dobject *obj,
|
|
FILE *to)
|
|
{
|
|
DobjPoints *spnt;
|
|
|
|
spnt = obj->points;
|
|
|
|
if (!spnt)
|
|
return;
|
|
|
|
fprintf (to, "<ELLIPSE>\n");
|
|
|
|
while (spnt)
|
|
{
|
|
fprintf (to, "%d %d\n",
|
|
(gint) spnt->pnt.x,
|
|
(gint) spnt->pnt.y);
|
|
spnt = spnt->next;
|
|
}
|
|
|
|
fprintf (to, "</ELLIPSE>\n");
|
|
}
|
|
|
|
/* Load a circle from the specified stream */
|
|
|
|
static Dobject *
|
|
d_load_ellipse (FILE *from)
|
|
{
|
|
Dobject *new_obj = NULL;
|
|
gint xpnt;
|
|
gint ypnt;
|
|
gchar buf[MAX_LOAD_LINE];
|
|
|
|
#ifdef DEBUG
|
|
printf ("Load ellipse called\n");
|
|
#endif /* DEBUG */
|
|
|
|
while (get_line (buf, MAX_LOAD_LINE, from, 0))
|
|
{
|
|
if (sscanf (buf, "%d %d", &xpnt, &ypnt) != 2)
|
|
{
|
|
/* Must be the end */
|
|
if (strcmp ("</ELLIPSE>", buf))
|
|
{
|
|
g_message ("[%d] Internal load error while loading ellipse",
|
|
line_no);
|
|
return NULL;
|
|
}
|
|
return new_obj;
|
|
}
|
|
|
|
if (!new_obj)
|
|
new_obj = d_new_ellipse (xpnt, ypnt);
|
|
else
|
|
{
|
|
DobjPoints *edge_pnt;
|
|
/* Circles only have two points */
|
|
edge_pnt = g_new0 (DobjPoints, 1);
|
|
|
|
edge_pnt->pnt.x = xpnt;
|
|
edge_pnt->pnt.y = ypnt;
|
|
|
|
new_obj->points->next = edge_pnt;
|
|
}
|
|
}
|
|
|
|
g_message ("[%d] Not enough points for ellipse", line_no);
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
d_draw_ellipse (Dobject * obj)
|
|
{
|
|
DobjPoints *center_pnt;
|
|
DobjPoints *edge_pnt;
|
|
gint bound_wx;
|
|
gint bound_wy;
|
|
gint top_x;
|
|
gint top_y;
|
|
|
|
center_pnt = obj->points;
|
|
|
|
if (!center_pnt)
|
|
return; /* End-of-line */
|
|
|
|
edge_pnt = center_pnt->next;
|
|
|
|
if (!edge_pnt)
|
|
{
|
|
g_warning ("Internal error - ellipse no edge pnt");
|
|
}
|
|
|
|
draw_sqr (¢er_pnt->pnt);
|
|
draw_sqr (&edge_pnt->pnt);
|
|
|
|
bound_wx = abs (center_pnt->pnt.x - edge_pnt->pnt.x) * 2;
|
|
bound_wy = abs (center_pnt->pnt.y - edge_pnt->pnt.y) * 2;
|
|
|
|
if (edge_pnt->pnt.x > center_pnt->pnt.x)
|
|
top_x = 2 * center_pnt->pnt.x - edge_pnt->pnt.x;
|
|
else
|
|
top_x = edge_pnt->pnt.x;
|
|
|
|
if (edge_pnt->pnt.y > center_pnt->pnt.y)
|
|
top_y = 2 * center_pnt->pnt.y - edge_pnt->pnt.y;
|
|
else
|
|
top_y = edge_pnt->pnt.y;
|
|
|
|
if (drawing_pic)
|
|
{
|
|
gdk_draw_arc (pic_preview->window,
|
|
pic_preview->style->black_gc,
|
|
0,
|
|
adjust_pic_coords (top_x,
|
|
preview_width),
|
|
adjust_pic_coords (top_y,
|
|
preview_height),
|
|
adjust_pic_coords (bound_wx,
|
|
preview_width),
|
|
adjust_pic_coords (bound_wy,
|
|
preview_height),
|
|
0,
|
|
360 * 64);
|
|
}
|
|
else
|
|
{
|
|
gdk_draw_arc (gfig_preview->window,
|
|
gfig_gc,
|
|
0,
|
|
gfig_scale_x (top_x),
|
|
gfig_scale_y (top_y),
|
|
gfig_scale_x (bound_wx),
|
|
gfig_scale_y (bound_wy),
|
|
0,
|
|
360 * 64);
|
|
}
|
|
}
|
|
|
|
static void
|
|
d_paint_approx_ellipse (Dobject *obj)
|
|
{
|
|
/* first point center */
|
|
/* Next point is radius */
|
|
gdouble *line_pnts;
|
|
gint seg_count = 0;
|
|
gint i = 0;
|
|
DobjPoints * center_pnt;
|
|
DobjPoints * radius_pnt;
|
|
gdouble a_axis;
|
|
gdouble b_axis;
|
|
gdouble ang_grid;
|
|
gdouble ang_loop;
|
|
gdouble radius;
|
|
gint loop;
|
|
GdkPoint first_pnt, last_pnt;
|
|
gint first = 1;
|
|
|
|
g_assert (obj != NULL);
|
|
|
|
/* count - add one to close polygon */
|
|
seg_count = 600;
|
|
|
|
center_pnt = obj->points;
|
|
|
|
if (!center_pnt || !seg_count)
|
|
return; /* no-line */
|
|
|
|
line_pnts = g_new0 (gdouble, 2 * seg_count + 1);
|
|
|
|
/* Go around all the points drawing a line from one to the next */
|
|
|
|
radius_pnt = center_pnt->next; /* this defines the vetices */
|
|
|
|
/* Have center and radius - get lines */
|
|
a_axis = ((gdouble) (radius_pnt->pnt.x - center_pnt->pnt.x));
|
|
b_axis = ((gdouble) (radius_pnt->pnt.y - center_pnt->pnt.y));
|
|
|
|
/* Lines */
|
|
ang_grid = 2 * G_PI / (gdouble) (gint) 600;
|
|
|
|
for (loop = 0; loop < (gint) 600; loop++)
|
|
{
|
|
gdouble lx, ly;
|
|
GdkPoint calc_pnt;
|
|
|
|
ang_loop = (gdouble)loop * ang_grid;
|
|
|
|
radius = (a_axis * b_axis /
|
|
(sqrt (cos (ang_loop) * cos (ang_loop) *
|
|
(b_axis * b_axis - a_axis * a_axis) + a_axis * a_axis)));
|
|
|
|
lx = radius * cos (ang_loop);
|
|
ly = radius * sin (ang_loop);
|
|
|
|
calc_pnt.x = (gint) RINT (lx + center_pnt->pnt.x);
|
|
calc_pnt.y = (gint) RINT (ly + center_pnt->pnt.y);
|
|
|
|
/* Miss out duped pnts */
|
|
if (!first)
|
|
{
|
|
if (calc_pnt.x == last_pnt.x && calc_pnt.y == last_pnt.y)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
last_pnt.x = line_pnts[i++] = calc_pnt.x;
|
|
last_pnt.y = line_pnts[i++] = calc_pnt.y;
|
|
|
|
if (first)
|
|
{
|
|
first_pnt.x = calc_pnt.x;
|
|
first_pnt.y = calc_pnt.y;
|
|
first = 0;
|
|
}
|
|
}
|
|
|
|
line_pnts[i++] = first_pnt.x;
|
|
line_pnts[i++] = first_pnt.y;
|
|
|
|
/* Reverse line if approp */
|
|
if (selvals.reverselines)
|
|
reverse_pairs_list (&line_pnts[0], i / 2);
|
|
|
|
/* Scale before drawing */
|
|
if (selvals.scaletoimage)
|
|
scale_to_original_xy (&line_pnts[0], i / 2);
|
|
else
|
|
scale_to_xy (&line_pnts[0], i / 2);
|
|
|
|
/* One go */
|
|
if (selvals.painttype == PAINT_BRUSH_TYPE)
|
|
{
|
|
gfig_paint (selvals.brshtype,
|
|
gfig_drawable,
|
|
i, line_pnts);
|
|
}
|
|
else
|
|
{
|
|
gimp_free_select (gfig_image,
|
|
i, line_pnts,
|
|
selopt.type,
|
|
selopt.antia,
|
|
selopt.feather,
|
|
selopt.feather_radius);
|
|
}
|
|
|
|
g_free (line_pnts);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
d_paint_ellipse (Dobject *obj)
|
|
{
|
|
DobjPoints * center_pnt;
|
|
DobjPoints * edge_pnt;
|
|
gint bound_wx;
|
|
gint bound_wy;
|
|
gint top_x;
|
|
gint top_y;
|
|
gdouble dpnts[4];
|
|
|
|
/* Drawing ellipse is hard .
|
|
* 1) select circle
|
|
* 2) stroke it
|
|
*/
|
|
|
|
g_assert (obj != NULL);
|
|
|
|
if (selvals.approxcircles)
|
|
{
|
|
#ifdef DEBUG
|
|
printf ("Painting ellipse as polygon\n");
|
|
#endif /* DEBUG */
|
|
d_paint_approx_ellipse (obj);
|
|
return;
|
|
}
|
|
|
|
center_pnt = obj->points;
|
|
|
|
if (!center_pnt)
|
|
return; /* End-of-line */
|
|
|
|
edge_pnt = center_pnt->next;
|
|
|
|
if (!edge_pnt)
|
|
{
|
|
g_error ("Internal error - ellipse no edge pnt");
|
|
}
|
|
|
|
bound_wx = abs (center_pnt->pnt.x - edge_pnt->pnt.x)*2;
|
|
bound_wy = abs (center_pnt->pnt.y - edge_pnt->pnt.y)*2;
|
|
|
|
if (edge_pnt->pnt.x > center_pnt->pnt.x)
|
|
top_x = 2*center_pnt->pnt.x - edge_pnt->pnt.x;
|
|
else
|
|
top_x = edge_pnt->pnt.x;
|
|
|
|
if (edge_pnt->pnt.y > center_pnt->pnt.y)
|
|
top_y = 2*center_pnt->pnt.y - edge_pnt->pnt.y;
|
|
else
|
|
top_y = edge_pnt->pnt.y;
|
|
|
|
dpnts[0] = (gdouble)top_x;
|
|
dpnts[1] = (gdouble)top_y;
|
|
dpnts[2] = (gdouble)bound_wx;
|
|
dpnts[3] = (gdouble)bound_wy;
|
|
|
|
/* Scale before drawing */
|
|
if (selvals.scaletoimage)
|
|
scale_to_original_xy (&dpnts[0], 2);
|
|
else
|
|
scale_to_xy (&dpnts[0], 2);
|
|
|
|
|
|
gimp_ellipse_select (gfig_image,
|
|
dpnts[0], dpnts[1],
|
|
dpnts[2], dpnts[3],
|
|
selopt.type,
|
|
selopt.antia,
|
|
selopt.feather,
|
|
selopt.feather_radius);
|
|
|
|
/* Is selection all we need ? */
|
|
if (selvals.painttype == PAINT_SELECTION_TYPE)
|
|
return;
|
|
|
|
gimp_edit_stroke (gfig_drawable);
|
|
|
|
gimp_selection_clear (gfig_image);
|
|
}
|
|
|
|
static Dobject *
|
|
d_copy_ellipse (Dobject * obj)
|
|
{
|
|
Dobject *nc;
|
|
|
|
#if DEBUG
|
|
printf ("Copy ellipse\n");
|
|
#endif /*DEBUG*/
|
|
if (!obj)
|
|
return (NULL);
|
|
|
|
g_assert (obj->type == ELLIPSE);
|
|
|
|
nc = d_new_ellipse (obj->points->pnt.x, obj->points->pnt.y);
|
|
|
|
nc->points->next = d_copy_dobjpoints (obj->points->next);
|
|
|
|
#if DEBUG
|
|
printf ("Ellipse (%x,%x) to (%x,%x)\n",
|
|
nc->points->pnt.x, obj->points->pnt.y,
|
|
nc->points->next->pnt.x, obj->points->next->pnt.y);
|
|
printf ("Done copy\n");
|
|
#endif /*DEBUG*/
|
|
return (nc);
|
|
}
|
|
|
|
static Dobject *
|
|
d_new_ellipse (gint x, gint y)
|
|
{
|
|
Dobject *nobj;
|
|
DobjPoints *npnt;
|
|
|
|
/* Get new object and starting point */
|
|
|
|
/* Start point */
|
|
npnt = g_new0 (DobjPoints, 1);
|
|
|
|
#if DEBUG
|
|
printf ("New ellipse start at (%x,%x)\n", x, y);
|
|
#endif /* DEBUG */
|
|
npnt->pnt.x = x;
|
|
npnt->pnt.y = y;
|
|
|
|
nobj = g_new0 (Dobject, 1);
|
|
|
|
nobj->type = ELLIPSE;
|
|
nobj->points = npnt;
|
|
nobj->drawfunc = d_draw_ellipse;
|
|
nobj->loadfunc = d_load_ellipse;
|
|
nobj->savefunc = d_save_ellipse;
|
|
nobj->paintfunc = d_paint_ellipse;
|
|
nobj->copyfunc = d_copy_ellipse;
|
|
|
|
return (nobj);
|
|
}
|
|
|
|
static void
|
|
d_update_ellipse (GdkPoint *pnt)
|
|
{
|
|
DobjPoints *center_pnt, *edge_pnt;
|
|
gint bound_wx;
|
|
gint bound_wy;
|
|
gint top_x;
|
|
gint top_y;
|
|
|
|
/* Undraw last one then draw new one */
|
|
center_pnt = obj_creating->points;
|
|
|
|
if (!center_pnt)
|
|
return; /* No points */
|
|
|
|
|
|
if ((edge_pnt = center_pnt->next))
|
|
{
|
|
/* Undraw current */
|
|
bound_wx = abs (center_pnt->pnt.x - edge_pnt->pnt.x)*2;
|
|
bound_wy = abs (center_pnt->pnt.y - edge_pnt->pnt.y)*2;
|
|
|
|
if (edge_pnt->pnt.x > center_pnt->pnt.x)
|
|
top_x = 2*center_pnt->pnt.x - edge_pnt->pnt.x;
|
|
else
|
|
top_x = edge_pnt->pnt.x;
|
|
|
|
if (edge_pnt->pnt.y > center_pnt->pnt.y)
|
|
top_y = 2*center_pnt->pnt.y - edge_pnt->pnt.y;
|
|
else
|
|
top_y = edge_pnt->pnt.y;
|
|
|
|
draw_circle (&edge_pnt->pnt);
|
|
|
|
gdk_draw_arc (gfig_preview->window,
|
|
gfig_gc,
|
|
0,
|
|
top_x,
|
|
top_y,
|
|
bound_wx,
|
|
bound_wy,
|
|
0,
|
|
360*64);
|
|
}
|
|
|
|
draw_circle (pnt);
|
|
|
|
edge_pnt = g_new0 (DobjPoints, 1);
|
|
|
|
edge_pnt->pnt.x = pnt->x;
|
|
edge_pnt->pnt.y = pnt->y;
|
|
|
|
bound_wx = abs (center_pnt->pnt.x - edge_pnt->pnt.x)*2;
|
|
bound_wy = abs (center_pnt->pnt.y - edge_pnt->pnt.y)*2;
|
|
|
|
if (edge_pnt->pnt.x > center_pnt->pnt.x)
|
|
top_x = 2*center_pnt->pnt.x - edge_pnt->pnt.x;
|
|
else
|
|
top_x = edge_pnt->pnt.x;
|
|
|
|
if (edge_pnt->pnt.y > center_pnt->pnt.y)
|
|
top_y = 2* center_pnt->pnt.y - edge_pnt->pnt.y;
|
|
else
|
|
top_y = edge_pnt->pnt.y;
|
|
|
|
gdk_draw_arc (gfig_preview->window,
|
|
gfig_gc,
|
|
0,
|
|
top_x,
|
|
top_y,
|
|
bound_wx,
|
|
bound_wy,
|
|
0,
|
|
360*64);
|
|
|
|
center_pnt->next = edge_pnt;
|
|
}
|
|
|
|
static void
|
|
d_ellipse_start (GdkPoint *pnt, gint shift_down)
|
|
{
|
|
obj_creating = d_new_ellipse (pnt->x, pnt->y);
|
|
}
|
|
|
|
static void
|
|
d_ellipse_end (GdkPoint *pnt, gint shift_down)
|
|
{
|
|
/* Under contrl point */
|
|
if (!obj_creating->points->next)
|
|
{
|
|
/* No circle created */
|
|
free_one_obj (obj_creating);
|
|
}
|
|
else
|
|
{
|
|
draw_circle (pnt);
|
|
add_to_all_obj (current_obj, obj_creating);
|
|
}
|
|
|
|
obj_creating = NULL;
|
|
}
|
|
|
|
/* Normal polygon */
|
|
|
|
static void
|
|
d_save_poly (Dobject * obj, FILE *to)
|
|
{
|
|
DobjPoints * spnt;
|
|
|
|
spnt = obj->points;
|
|
|
|
if (!spnt)
|
|
return; /* End-of-line */
|
|
|
|
fprintf (to, "<POLY>\n");
|
|
|
|
while (spnt)
|
|
{
|
|
fprintf (to, "%d %d\n",
|
|
(gint)spnt->pnt.x,
|
|
(gint)spnt->pnt.y);
|
|
spnt = spnt->next;
|
|
}
|
|
|
|
fprintf (to, "<EXTRA>\n");
|
|
fprintf (to, "%d\n</EXTRA>\n", (gint)obj->type_data);
|
|
fprintf (to, "</POLY>\n");
|
|
|
|
}
|
|
|
|
/* Load a circle from the specified stream */
|
|
|
|
static Dobject *
|
|
d_load_poly (FILE *from)
|
|
{
|
|
Dobject *new_obj = NULL;
|
|
gint xpnt;
|
|
gint ypnt;
|
|
gchar buf[MAX_LOAD_LINE];
|
|
|
|
#ifdef DEBUG
|
|
printf ("Load poly called\n");
|
|
#endif /* DEBUG */
|
|
|
|
while (get_line (buf, MAX_LOAD_LINE, from, 0))
|
|
{
|
|
if (sscanf (buf, "%d %d", &xpnt, &ypnt) != 2)
|
|
{
|
|
/* Must be the end */
|
|
if (!strcmp ("<EXTRA>", buf))
|
|
{
|
|
gint nsides = 3;
|
|
/* Number of sides - data item */
|
|
if (!new_obj)
|
|
{
|
|
g_warning ("[%d] Internal load error while loading poly (extra area)",
|
|
line_no);
|
|
return (NULL);
|
|
}
|
|
get_line (buf, MAX_LOAD_LINE, from, 0);
|
|
if (sscanf (buf, "%d", &nsides) != 1)
|
|
{
|
|
g_warning ("[%d] Internal load error while loading poly (extra area scanf)",
|
|
line_no);
|
|
return (NULL);
|
|
}
|
|
new_obj->type_data = (gpointer)nsides;
|
|
get_line (buf, MAX_LOAD_LINE, from, 0);
|
|
if (strcmp ("</EXTRA>", buf))
|
|
{
|
|
g_warning ("[%d] Internal load error while loading poly",
|
|
line_no);
|
|
return (NULL);
|
|
}
|
|
/* Go around and read the last line */
|
|
continue;
|
|
}
|
|
else if (strcmp ("</POLY>", buf))
|
|
{
|
|
g_warning ("[%d] Internal load error while loading poly",
|
|
line_no);
|
|
return (NULL);
|
|
}
|
|
return (new_obj);
|
|
}
|
|
|
|
if (!new_obj)
|
|
new_obj = d_new_poly (xpnt, ypnt);
|
|
else
|
|
d_pnt_add_line (new_obj, xpnt, ypnt, -1);
|
|
}
|
|
return (new_obj);
|
|
}
|
|
|
|
static void
|
|
d_draw_poly (Dobject *obj)
|
|
{
|
|
DobjPoints * center_pnt;
|
|
DobjPoints * radius_pnt;
|
|
gint16 shift_x;
|
|
gint16 shift_y;
|
|
gdouble ang_grid;
|
|
gdouble ang_loop;
|
|
gdouble radius;
|
|
gdouble offset_angle;
|
|
gint loop;
|
|
GdkPoint start_pnt;
|
|
GdkPoint first_pnt;
|
|
gint do_line = 0;
|
|
|
|
center_pnt = obj->points;
|
|
|
|
if (!center_pnt)
|
|
return; /* End-of-line */
|
|
|
|
/* First point is the center */
|
|
/* Just draw a control point around it */
|
|
|
|
draw_sqr (¢er_pnt->pnt);
|
|
|
|
/* Next point defines the radius */
|
|
radius_pnt = center_pnt->next; /* this defines the vertices */
|
|
|
|
if (!radius_pnt)
|
|
{
|
|
#ifdef DEBUG
|
|
g_warning ("Internal error in polygon - no vertice point \n");
|
|
#endif /* DEBUG */
|
|
return;
|
|
}
|
|
|
|
/* Other control point */
|
|
draw_sqr (&radius_pnt->pnt);
|
|
|
|
/* Have center and radius - draw polygon */
|
|
|
|
shift_x = radius_pnt->pnt.x - center_pnt->pnt.x;
|
|
shift_y = radius_pnt->pnt.y - center_pnt->pnt.y;
|
|
|
|
radius = sqrt ((shift_x*shift_x) + (shift_y*shift_y));
|
|
|
|
/* Lines */
|
|
ang_grid = 2*G_PI/(gdouble) (gint)obj->type_data;
|
|
offset_angle = atan2 (shift_y, shift_x);
|
|
|
|
for (loop = 0 ; loop < (gint)obj->type_data ; loop++)
|
|
{
|
|
gdouble lx, ly;
|
|
GdkPoint calc_pnt;
|
|
|
|
ang_loop = (gdouble)loop * ang_grid + offset_angle;
|
|
|
|
lx = radius * cos (ang_loop);
|
|
ly = radius * sin (ang_loop);
|
|
|
|
calc_pnt.x = (gint)RINT (lx + center_pnt->pnt.x);
|
|
calc_pnt.y = (gint)RINT (ly + center_pnt->pnt.y);
|
|
|
|
if (do_line)
|
|
{
|
|
|
|
/* Miss out points that come to the same location */
|
|
if (calc_pnt.x == start_pnt.x && calc_pnt.y == start_pnt.y)
|
|
continue;
|
|
|
|
if (drawing_pic)
|
|
{
|
|
gdk_draw_line (pic_preview->window,
|
|
pic_preview->style->black_gc,
|
|
adjust_pic_coords (calc_pnt.x,
|
|
preview_width),
|
|
adjust_pic_coords (calc_pnt.y,
|
|
preview_height),
|
|
adjust_pic_coords (start_pnt.x,
|
|
preview_width),
|
|
adjust_pic_coords (start_pnt.y,
|
|
preview_height));
|
|
}
|
|
else
|
|
{
|
|
gdk_draw_line (gfig_preview->window,
|
|
gfig_gc,
|
|
gfig_scale_x (calc_pnt.x),
|
|
gfig_scale_y (calc_pnt.y),
|
|
gfig_scale_x (start_pnt.x),
|
|
gfig_scale_y (start_pnt.y));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
do_line = 1;
|
|
first_pnt.x = calc_pnt.x;
|
|
first_pnt.y = calc_pnt.y;
|
|
}
|
|
start_pnt.x = calc_pnt.x;
|
|
start_pnt.y = calc_pnt.y;
|
|
}
|
|
|
|
/* Join up */
|
|
if (drawing_pic)
|
|
{
|
|
gdk_draw_line (pic_preview->window,
|
|
pic_preview->style->black_gc,
|
|
adjust_pic_coords (first_pnt.x, preview_width),
|
|
adjust_pic_coords (first_pnt.y, preview_width),
|
|
adjust_pic_coords (start_pnt.x, preview_width),
|
|
adjust_pic_coords (start_pnt.y, preview_width));
|
|
}
|
|
else
|
|
{
|
|
gdk_draw_line (gfig_preview->window,
|
|
gfig_gc,
|
|
gfig_scale_x (first_pnt.x),
|
|
gfig_scale_y (first_pnt.y),
|
|
gfig_scale_x (start_pnt.x),
|
|
gfig_scale_y (start_pnt.y));
|
|
}
|
|
}
|
|
|
|
static void
|
|
d_paint_poly (Dobject *obj)
|
|
{
|
|
/* first point center */
|
|
/* Next point is radius */
|
|
gdouble *line_pnts;
|
|
gint seg_count = 0;
|
|
gint i = 0;
|
|
DobjPoints * center_pnt;
|
|
DobjPoints * radius_pnt;
|
|
gint16 shift_x;
|
|
gint16 shift_y;
|
|
gdouble ang_grid;
|
|
gdouble ang_loop;
|
|
gdouble radius;
|
|
gdouble offset_angle;
|
|
gint loop;
|
|
GdkPoint first_pnt, last_pnt;
|
|
gint first = 1;
|
|
|
|
g_assert (obj != NULL);
|
|
|
|
/* count - add one to close polygon */
|
|
seg_count = (gint)obj->type_data + 1;
|
|
|
|
center_pnt = obj->points;
|
|
|
|
if (!center_pnt || !seg_count || !center_pnt->next)
|
|
return; /* no-line */
|
|
|
|
line_pnts = g_new0 (gdouble, 2 * seg_count + 1);
|
|
|
|
/* Go around all the points drawing a line from one to the next */
|
|
|
|
radius_pnt = center_pnt->next; /* this defines the vetices */
|
|
|
|
/* Have center and radius - get lines */
|
|
shift_x = radius_pnt->pnt.x - center_pnt->pnt.x;
|
|
shift_y = radius_pnt->pnt.y - center_pnt->pnt.y;
|
|
|
|
radius = sqrt ((shift_x*shift_x) + (shift_y*shift_y));
|
|
|
|
/* Lines */
|
|
ang_grid = 2*G_PI/(gdouble) (gint)obj->type_data;
|
|
offset_angle = atan2 (shift_y, shift_x);
|
|
|
|
for (loop = 0 ; loop < (gint)obj->type_data ; loop++)
|
|
{
|
|
gdouble lx, ly;
|
|
GdkPoint calc_pnt;
|
|
|
|
ang_loop = (gdouble)loop * ang_grid + offset_angle;
|
|
|
|
lx = radius * cos (ang_loop);
|
|
ly = radius * sin (ang_loop);
|
|
|
|
calc_pnt.x = (gint)RINT (lx + center_pnt->pnt.x);
|
|
calc_pnt.y = (gint)RINT (ly + center_pnt->pnt.y);
|
|
|
|
/* Miss out duped pnts */
|
|
if (!first)
|
|
{
|
|
if (calc_pnt.x == last_pnt.x && calc_pnt.y == last_pnt.y)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
last_pnt.x = line_pnts[i++] = calc_pnt.x;
|
|
last_pnt.y = line_pnts[i++] = calc_pnt.y;
|
|
|
|
if (first)
|
|
{
|
|
first_pnt.x = calc_pnt.x;
|
|
first_pnt.y = calc_pnt.y;
|
|
first = 0;
|
|
}
|
|
}
|
|
|
|
line_pnts[i++] = first_pnt.x;
|
|
line_pnts[i++] = first_pnt.y;
|
|
|
|
/* Reverse line if approp */
|
|
if (selvals.reverselines)
|
|
reverse_pairs_list (&line_pnts[0], i/2);
|
|
|
|
/* Scale before drawing */
|
|
if (selvals.scaletoimage)
|
|
scale_to_original_xy (&line_pnts[0], i/2);
|
|
else
|
|
scale_to_xy (&line_pnts[0], i/2);
|
|
|
|
/* One go */
|
|
if (selvals.painttype == PAINT_BRUSH_TYPE)
|
|
{
|
|
gfig_paint (selvals.brshtype,
|
|
gfig_drawable,
|
|
i, line_pnts);
|
|
}
|
|
else
|
|
{
|
|
gimp_free_select (gfig_image,
|
|
i, line_pnts,
|
|
selopt.type,
|
|
selopt.antia,
|
|
selopt.feather,
|
|
selopt.feather_radius);
|
|
}
|
|
|
|
g_free (line_pnts);
|
|
}
|
|
|
|
static void
|
|
d_poly2lines (Dobject *obj)
|
|
{
|
|
/* first point center */
|
|
/* Next point is radius */
|
|
gint seg_count = 0;
|
|
DobjPoints * center_pnt;
|
|
DobjPoints * radius_pnt;
|
|
gint16 shift_x;
|
|
gint16 shift_y;
|
|
gdouble ang_grid;
|
|
gdouble ang_loop;
|
|
gdouble radius;
|
|
gdouble offset_angle;
|
|
gint loop;
|
|
GdkPoint first_pnt, last_pnt;
|
|
gint first = 1;
|
|
|
|
g_assert (obj != NULL);
|
|
|
|
#ifdef DEBUG
|
|
printf ("d_poly2lines --- \n");
|
|
#endif /* DEBUG */
|
|
|
|
/* count - add one to close polygon */
|
|
seg_count = (gint)obj->type_data + 1;
|
|
|
|
center_pnt = obj->points;
|
|
|
|
if (!center_pnt)
|
|
return; /* no-line */
|
|
|
|
/* Undraw it to start with - removes control points */
|
|
obj->drawfunc (obj);
|
|
|
|
/* NULL out these points free later */
|
|
obj->points = NULL;
|
|
|
|
/* Go around all the points creating line points */
|
|
|
|
radius_pnt = center_pnt->next; /* this defines the vertices */
|
|
|
|
/* Have center and radius - get lines */
|
|
shift_x = radius_pnt->pnt.x - center_pnt->pnt.x;
|
|
shift_y = radius_pnt->pnt.y - center_pnt->pnt.y;
|
|
|
|
radius = sqrt ((shift_x*shift_x) + (shift_y*shift_y));
|
|
|
|
/* Lines */
|
|
ang_grid = 2*G_PI/(gdouble) (gint)obj->type_data;
|
|
offset_angle = atan2 (shift_y, shift_x);
|
|
|
|
for (loop = 0 ; loop < (gint)obj->type_data ; loop++)
|
|
{
|
|
gdouble lx, ly;
|
|
GdkPoint calc_pnt;
|
|
|
|
ang_loop = (gdouble)loop * ang_grid + offset_angle;
|
|
|
|
lx = radius * cos (ang_loop);
|
|
ly = radius * sin (ang_loop);
|
|
|
|
calc_pnt.x = (gint)RINT (lx + center_pnt->pnt.x);
|
|
calc_pnt.y = (gint)RINT (ly + center_pnt->pnt.y);
|
|
|
|
if (!first)
|
|
{
|
|
if (calc_pnt.x == last_pnt.x && calc_pnt.y == last_pnt.y)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
d_pnt_add_line (obj, calc_pnt.x, calc_pnt.y, 0);
|
|
|
|
last_pnt.x = calc_pnt.x;
|
|
last_pnt.y = calc_pnt.y;
|
|
|
|
if (first)
|
|
{
|
|
first_pnt.x = calc_pnt.x;
|
|
first_pnt.y = calc_pnt.y;
|
|
first = 0;
|
|
}
|
|
}
|
|
|
|
d_pnt_add_line (obj, first_pnt.x, first_pnt.y, 0);
|
|
/* Free old pnts */
|
|
d_delete_dobjpoints (center_pnt);
|
|
|
|
/* hey we're a line now */
|
|
obj->type = LINE;
|
|
obj->drawfunc = d_draw_line;
|
|
obj->loadfunc = d_load_line;
|
|
obj->savefunc = d_save_line;
|
|
obj->paintfunc = d_paint_line;
|
|
obj->copyfunc = d_copy_line;
|
|
|
|
/* draw it + control pnts */
|
|
obj->drawfunc (obj);
|
|
}
|
|
|
|
static void
|
|
d_star2lines (Dobject *obj)
|
|
{
|
|
/* first point center */
|
|
/* Next point is radius */
|
|
gint seg_count = 0;
|
|
DobjPoints * center_pnt;
|
|
DobjPoints * outer_radius_pnt;
|
|
DobjPoints * inner_radius_pnt;
|
|
gint16 shift_x;
|
|
gint16 shift_y;
|
|
gdouble ang_grid;
|
|
gdouble ang_loop;
|
|
gdouble outer_radius;
|
|
gdouble inner_radius;
|
|
gdouble offset_angle;
|
|
gint loop;
|
|
GdkPoint first_pnt, last_pnt;
|
|
gint first = 1;
|
|
|
|
g_assert (obj != NULL);
|
|
|
|
#ifdef DEBUG
|
|
printf ("d_star2lines --- \n");
|
|
#endif /* DEBUG */
|
|
|
|
/* count - add one to close polygon */
|
|
seg_count = 2*(gint)obj->type_data + 1;
|
|
|
|
center_pnt = obj->points;
|
|
|
|
if (!center_pnt)
|
|
return; /* no-line */
|
|
|
|
/* Undraw it to start with - removes control points */
|
|
obj->drawfunc (obj);
|
|
|
|
/* NULL out these points free later */
|
|
obj->points = NULL;
|
|
|
|
/* Go around all the points creating line points */
|
|
/* Next point defines the radius */
|
|
outer_radius_pnt = center_pnt->next; /* this defines the vetices */
|
|
|
|
if (!outer_radius_pnt)
|
|
{
|
|
#ifdef DEBUG
|
|
g_warning ("Internal error in star - no outer vertice point \n");
|
|
#endif /* DEBUG */
|
|
return;
|
|
}
|
|
|
|
inner_radius_pnt = outer_radius_pnt->next; /* this defines the vetices */
|
|
|
|
if (!inner_radius_pnt)
|
|
{
|
|
#ifdef DEBUG
|
|
g_warning ("Internal error in star - no inner vertice point \n");
|
|
#endif /* DEBUG */
|
|
return;
|
|
}
|
|
|
|
shift_x = outer_radius_pnt->pnt.x - center_pnt->pnt.x;
|
|
shift_y = outer_radius_pnt->pnt.y - center_pnt->pnt.y;
|
|
|
|
outer_radius = sqrt ((shift_x*shift_x) + (shift_y*shift_y));
|
|
|
|
/* Lines */
|
|
ang_grid = 2*G_PI/(2.0*(gdouble) (gint)obj->type_data);
|
|
offset_angle = atan2 (shift_y, shift_x);
|
|
|
|
shift_x = inner_radius_pnt->pnt.x - center_pnt->pnt.x;
|
|
shift_y = inner_radius_pnt->pnt.y - center_pnt->pnt.y;
|
|
|
|
inner_radius = sqrt ((shift_x*shift_x) + (shift_y*shift_y));
|
|
|
|
for (loop = 0 ; loop < 2*(gint)obj->type_data ; loop++)
|
|
{
|
|
gdouble lx, ly;
|
|
GdkPoint calc_pnt;
|
|
|
|
ang_loop = (gdouble)loop * ang_grid + offset_angle;
|
|
|
|
if (loop%2)
|
|
{
|
|
lx = inner_radius * cos (ang_loop);
|
|
ly = inner_radius * sin (ang_loop);
|
|
}
|
|
else
|
|
{
|
|
lx = outer_radius * cos (ang_loop);
|
|
ly = outer_radius * sin (ang_loop);
|
|
}
|
|
|
|
calc_pnt.x = (gint)RINT (lx + center_pnt->pnt.x);
|
|
calc_pnt.y = (gint)RINT (ly + center_pnt->pnt.y);
|
|
|
|
if (!first)
|
|
{
|
|
if (calc_pnt.x == last_pnt.x && calc_pnt.y == last_pnt.y)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
d_pnt_add_line (obj, calc_pnt.x, calc_pnt.y, 0);
|
|
|
|
last_pnt.x = calc_pnt.x;
|
|
last_pnt.y = calc_pnt.y;
|
|
|
|
if (first)
|
|
{
|
|
first_pnt.x = calc_pnt.x;
|
|
first_pnt.y = calc_pnt.y;
|
|
first = 0;
|
|
}
|
|
}
|
|
|
|
d_pnt_add_line (obj, first_pnt.x, first_pnt.y, 0);
|
|
/* Free old pnts */
|
|
d_delete_dobjpoints (center_pnt);
|
|
|
|
/* hey we're a line now */
|
|
obj->type = LINE;
|
|
obj->drawfunc = d_draw_line;
|
|
obj->loadfunc = d_load_line;
|
|
obj->savefunc = d_save_line;
|
|
obj->paintfunc = d_paint_line;
|
|
obj->copyfunc = d_copy_line;
|
|
|
|
/* draw it + control pnts */
|
|
obj->drawfunc (obj);
|
|
}
|
|
|
|
static Dobject *
|
|
d_copy_poly (Dobject * obj)
|
|
{
|
|
Dobject *np;
|
|
|
|
#if DEBUG
|
|
printf ("Copy poly\n");
|
|
#endif /*DEBUG*/
|
|
if (!obj)
|
|
return (NULL);
|
|
|
|
g_assert (obj->type == POLY);
|
|
|
|
np = d_new_poly (obj->points->pnt.x, obj->points->pnt.y);
|
|
|
|
np->points->next = d_copy_dobjpoints (obj->points->next);
|
|
|
|
np->type_data = obj->type_data;
|
|
|
|
#if DEBUG
|
|
printf ("Done poly copy\n");
|
|
#endif /*DEBUG*/
|
|
return (np);
|
|
}
|
|
|
|
static Dobject *
|
|
d_new_poly (gint x, gint y)
|
|
{
|
|
Dobject *nobj;
|
|
DobjPoints *npnt;
|
|
|
|
/* Get new object and starting point */
|
|
|
|
/* Start point */
|
|
npnt = g_new0 (DobjPoints, 1);
|
|
|
|
#if DEBUG
|
|
printf ("New POLY start at (%x,%x)\n", x, y);
|
|
#endif /* DEBUG */
|
|
npnt->pnt.x = x;
|
|
npnt->pnt.y = y;
|
|
|
|
nobj = g_new0 (Dobject, 1);
|
|
|
|
nobj->type = POLY;
|
|
nobj->type_data = (gpointer)3; /* Default to three sides */
|
|
nobj->points = npnt;
|
|
nobj->drawfunc = d_draw_poly;
|
|
nobj->loadfunc = d_load_poly;
|
|
nobj->savefunc = d_save_poly;
|
|
nobj->paintfunc = d_paint_poly;
|
|
nobj->copyfunc = d_copy_poly;
|
|
|
|
return (nobj);
|
|
}
|
|
|
|
static void
|
|
d_update_poly (GdkPoint *pnt)
|
|
{
|
|
DobjPoints *center_pnt, *edge_pnt;
|
|
gint saved_cnt_pnt = selvals.opts.showcontrol;
|
|
|
|
/* Undraw last one then draw new one */
|
|
center_pnt = obj_creating->points;
|
|
|
|
if (!center_pnt)
|
|
return; /* No points */
|
|
|
|
/* Leave the first pnt alone -
|
|
* Edge point defines "radius"
|
|
* Only undraw if already have edge point.
|
|
*/
|
|
|
|
/* Hack - turn off cnt points in draw routine
|
|
* Looking back over the other update routines I could
|
|
* use this trick again and cut down on code size!
|
|
*/
|
|
|
|
|
|
if ((edge_pnt = center_pnt->next))
|
|
{
|
|
/* Undraw */
|
|
draw_circle (&edge_pnt->pnt);
|
|
selvals.opts.showcontrol = 0;
|
|
d_draw_poly (obj_creating);
|
|
|
|
edge_pnt->pnt.x = pnt->x;
|
|
edge_pnt->pnt.y = pnt->y;
|
|
}
|
|
else
|
|
{
|
|
/* Radius is a few pixels away */
|
|
/* First edge point */
|
|
d_pnt_add_line (obj_creating, pnt->x, pnt->y, -1);
|
|
edge_pnt = center_pnt->next;
|
|
}
|
|
|
|
/* draw it */
|
|
selvals.opts.showcontrol = 0;
|
|
d_draw_poly (obj_creating);
|
|
selvals.opts.showcontrol = saved_cnt_pnt;
|
|
|
|
/* Realy draw the control points */
|
|
draw_circle (&edge_pnt->pnt);
|
|
}
|
|
|
|
/* first point is center
|
|
* next defines the radius
|
|
*/
|
|
|
|
static void
|
|
d_poly_start (GdkPoint *pnt,
|
|
gint shift_down)
|
|
{
|
|
gint16 x, y;
|
|
/* First is center point */
|
|
obj_creating = d_new_poly (x = pnt->x, y = pnt->y);
|
|
obj_creating->type_data = (gpointer)poly_num_sides;
|
|
}
|
|
|
|
static void
|
|
d_poly_end (GdkPoint *pnt,
|
|
gint shift_down)
|
|
{
|
|
draw_circle (pnt);
|
|
add_to_all_obj (current_obj, obj_creating);
|
|
obj_creating = NULL;
|
|
}
|
|
|
|
/* ARC stuff */
|
|
/* Distance between two lines */
|
|
static gdouble
|
|
dist (gdouble x1,
|
|
gdouble y1,
|
|
gdouble x2,
|
|
gdouble y2)
|
|
{
|
|
|
|
double s1 = x1 - x2;
|
|
double s2 = y1 - y2;
|
|
|
|
return (sqrt ((s1*s1) + (s2*s2)));
|
|
}
|
|
|
|
/* Mid point of line returned */
|
|
static void
|
|
mid_point (gdouble x1,
|
|
gdouble y1,
|
|
gdouble x2,
|
|
gdouble y2,
|
|
gdouble *mx,
|
|
gdouble *my)
|
|
{
|
|
*mx = ((double) (x1 - x2))/2.0 + (double)x2;
|
|
*my = ((double) (y1 - y2))/2.0 + (double)y2;
|
|
}
|
|
|
|
/* Careful about infinite grads */
|
|
static gdouble
|
|
line_grad (gdouble x1,
|
|
gdouble y1,
|
|
gdouble x2,
|
|
gdouble y2)
|
|
{
|
|
double dx, dy;
|
|
|
|
dx = x1 - x2;
|
|
dy = y1 - y2;
|
|
|
|
if (dx == 0.0)
|
|
return (0.0); /* Infinite ! */
|
|
|
|
return (dy/dx);
|
|
}
|
|
|
|
/* Constant of line that goes through x, y with grad lgrad */
|
|
static gdouble
|
|
line_cons (gdouble x,
|
|
gdouble y,
|
|
gdouble lgrad)
|
|
{
|
|
return (y - lgrad*x);
|
|
}
|
|
|
|
/*Get grad & const for perpend. line to given points */
|
|
static void
|
|
line_definition (gdouble x1,
|
|
gdouble y1,
|
|
gdouble x2,
|
|
gdouble y2,
|
|
gdouble *lgrad,
|
|
gdouble *lconst)
|
|
{
|
|
double grad1;
|
|
double midx, midy;
|
|
|
|
grad1 = line_grad (x1, y1, x2, y2);
|
|
|
|
if (grad1 == 0.0)
|
|
{
|
|
#ifdef DEBUG
|
|
printf ("Infinite grad....\n");
|
|
#endif /* DEBUG */
|
|
return;
|
|
}
|
|
|
|
mid_point (x1, y1, x2, y2, &midx, &midy);
|
|
|
|
/* Invert grad for perpen gradient */
|
|
|
|
*lgrad = -1.0/grad1;
|
|
|
|
*lconst = line_cons (midx, midy,*lgrad);
|
|
}
|
|
|
|
/* Arch details
|
|
* Given three points get arc radius and the co-ords
|
|
* of center point.
|
|
*/
|
|
|
|
static void
|
|
arc_details (GdkPoint *vert_a,
|
|
GdkPoint *vert_b,
|
|
GdkPoint *vert_c,
|
|
GdkPoint *center_pnt,
|
|
gdouble *radius)
|
|
{
|
|
/* Only vertices are in whole numbers - everything else is in doubles */
|
|
double ax, ay;
|
|
double bx, by;
|
|
double cx, cy;
|
|
|
|
double len_a, len_b, len_c;
|
|
double sum_sides2;
|
|
double area;
|
|
double circumcircle_R;
|
|
double line1_grad, line1_const;
|
|
double line2_grad, line2_const;
|
|
double inter_x=0.0, inter_y=0.0;
|
|
int got_x=0, got_y=0;
|
|
|
|
ax = (double) (vert_a->x);
|
|
ay = (double) (vert_a->y);
|
|
bx = (double) (vert_b->x);
|
|
by = (double) (vert_b->y);
|
|
cx = (double) (vert_c->x);
|
|
cy = (double) (vert_c->y);
|
|
|
|
#ifdef DEBUG
|
|
printf ("Vertices (%f,%f), (%f,%f), (%f,%f)\n", ax, ay, bx, by, cx, cy);
|
|
#endif /* DEBUG */
|
|
|
|
len_a = dist (ax, ay, bx, by);
|
|
len_b = dist (bx, by, cx, cy);
|
|
len_c = dist (cx, cy, ax, ay);
|
|
#ifdef DEBUG
|
|
printf ("len_a = %f, len_b = %f, len_c = %f\n", len_a, len_b, len_c);
|
|
#endif /* DEBUG */
|
|
|
|
|
|
sum_sides2 = (fabs (len_a) + fabs (len_b) + fabs (len_c))/2;
|
|
#ifdef DEBUG
|
|
printf ("Sum sides / 2 = %f\n", sum_sides2);
|
|
#endif /* DEBUG */
|
|
|
|
/* Area */
|
|
area = sqrt (sum_sides2*(sum_sides2 - len_a)*(sum_sides2 - len_b)*(sum_sides2 - len_c));
|
|
#ifdef DEBUG
|
|
printf ("Area of triangle = %f\n", area);
|
|
#endif /* DEBUG */
|
|
|
|
/* Circumcircle */
|
|
circumcircle_R = len_a*len_b*len_c/(4*area);
|
|
*radius = circumcircle_R;
|
|
#ifdef DEBUG
|
|
printf ("Circumcircle radius = %f\n", circumcircle_R);
|
|
#endif /* DEBUG */
|
|
|
|
/* Deal with exceptions - I hate exceptions */
|
|
|
|
if (ax == bx || ax == cx || cx == bx)
|
|
{
|
|
/* vert line -> mid point gives inter_x */
|
|
if (ax == bx && bx == cx)
|
|
{
|
|
/* Straight line */
|
|
double miny = ay;
|
|
double maxy = ay;
|
|
|
|
if (by > maxy)
|
|
maxy = by;
|
|
|
|
if (by < miny)
|
|
miny = by;
|
|
|
|
if (cy > maxy)
|
|
maxy = cy;
|
|
|
|
if (cy < miny)
|
|
miny = cy;
|
|
|
|
inter_y = (maxy - miny)/2 + miny;
|
|
}
|
|
else if (ax == bx)
|
|
{
|
|
inter_y = (ay - by)/2 + by;
|
|
}
|
|
else if (bx == cx)
|
|
{
|
|
inter_y = (by - cy)/2 + cy;
|
|
}
|
|
else
|
|
{
|
|
inter_y = (cy - ay)/2 + ay;
|
|
}
|
|
got_y = 1;
|
|
}
|
|
|
|
if (ay == by || by == cy || ay == cy)
|
|
{
|
|
/* Horz line -> midpoint gives inter_y */
|
|
if (ax == bx && bx == cx)
|
|
{
|
|
/* Straight line */
|
|
double minx = ax;
|
|
double maxx = ax;
|
|
|
|
if (bx > maxx)
|
|
maxx = bx;
|
|
|
|
if (bx < minx)
|
|
minx = bx;
|
|
|
|
if (cx > maxx)
|
|
maxx = cx;
|
|
|
|
if (cx < minx)
|
|
minx = cx;
|
|
|
|
inter_x = (maxx - minx)/2 + minx;
|
|
}
|
|
else if (ay == by)
|
|
{
|
|
inter_x = (ax - bx)/2 + bx;
|
|
}
|
|
else if (by == cy)
|
|
{
|
|
inter_x = (bx - cx)/2 + cx;
|
|
}
|
|
else
|
|
{
|
|
inter_x = (cx - ax)/2 + ax;
|
|
}
|
|
got_x = 1;
|
|
}
|
|
|
|
if (!got_x || !got_y)
|
|
{
|
|
/* At least two of the lines are not parallel to the axis */
|
|
/*first line */
|
|
if (ax != bx && ay != by)
|
|
line_definition (ax, ay, bx, by, &line1_grad, &line1_const);
|
|
else
|
|
line_definition (ax, ay, cx, cy, &line1_grad, &line1_const);
|
|
/* second line */
|
|
if (bx != cx && by != cy)
|
|
line_definition (bx, by, cx, cy, &line2_grad, &line2_const);
|
|
else
|
|
line_definition (ax, ay, cx, cy, &line2_grad, &line2_const);
|
|
}
|
|
|
|
/* Intersection point */
|
|
|
|
if (!got_x)
|
|
inter_x = /*rint*/((line2_const - line1_const)/(line1_grad - line2_grad));
|
|
if (!got_y)
|
|
inter_y = /*rint*/((line1_grad * inter_x + line1_const));
|
|
|
|
#ifdef DEBUG
|
|
printf ("Intersection point is (%f,%f)\n", inter_x, inter_y);
|
|
#endif /* DEBUG */
|
|
|
|
center_pnt->x = (gint16)inter_x;
|
|
center_pnt->y = (gint16)inter_y;
|
|
}
|
|
|
|
static gdouble
|
|
arc_angle (GdkPoint *pnt,
|
|
GdkPoint *center)
|
|
{
|
|
/* Get angle (in degress) of point given origin of center */
|
|
gint16 shift_x;
|
|
gint16 shift_y;
|
|
gdouble offset_angle;
|
|
|
|
shift_x = pnt->x - center->x;
|
|
shift_y = -pnt->y + center->y;
|
|
offset_angle = atan2 (shift_y, shift_x);
|
|
#ifdef DEBUG
|
|
printf ("offset_ang = %f\n", offset_angle);
|
|
#endif /* DEBUG */
|
|
if (offset_angle < 0)
|
|
offset_angle += 2*G_PI;
|
|
|
|
return (offset_angle*360/(2*G_PI));
|
|
}
|
|
|
|
static void
|
|
d_save_arc (Dobject *obj,
|
|
FILE *to)
|
|
{
|
|
DobjPoints * spnt;
|
|
|
|
spnt = obj->points;
|
|
|
|
if (!spnt)
|
|
return;
|
|
|
|
fprintf (to, "<ARC>\n");
|
|
|
|
while (spnt)
|
|
{
|
|
fprintf (to, "%d %d\n",
|
|
(gint)spnt->pnt.x,
|
|
(gint)spnt->pnt.y);
|
|
spnt = spnt->next;
|
|
}
|
|
|
|
fprintf (to, "</ARC>\n");
|
|
}
|
|
|
|
/* Load a circle from the specified stream */
|
|
|
|
static Dobject *
|
|
d_load_arc (FILE *from)
|
|
{
|
|
Dobject *new_obj = NULL;
|
|
gint xpnt;
|
|
gint ypnt;
|
|
gchar buf[MAX_LOAD_LINE];
|
|
gint num_pnts = 0;
|
|
|
|
#ifdef DEBUG
|
|
printf ("Load arc called\n");
|
|
#endif /* DEBUG */
|
|
|
|
while (get_line (buf, MAX_LOAD_LINE, from, 0))
|
|
{
|
|
if (sscanf (buf, "%d %d", &xpnt, &ypnt) != 2)
|
|
{
|
|
/* Must be the end */
|
|
if (strcmp ("</ARC>", buf) || num_pnts != 3)
|
|
{
|
|
g_warning ("[%d] Internal load error while loading arc",
|
|
line_no);
|
|
return (NULL);
|
|
}
|
|
return (new_obj);
|
|
}
|
|
|
|
num_pnts++;
|
|
|
|
if (!new_obj)
|
|
new_obj = d_new_arc (xpnt, ypnt);
|
|
else
|
|
{
|
|
d_pnt_add_line (new_obj, xpnt, ypnt,-1);
|
|
}
|
|
}
|
|
g_warning ("[%d] Not enough points for arc", line_no);
|
|
return (NULL);
|
|
}
|
|
|
|
static void
|
|
arc_drawing_details (Dobject *obj,
|
|
gdouble *minang,
|
|
GdkPoint *center_pnt,
|
|
gdouble *arcang,
|
|
gdouble *radius,
|
|
gint draw_cnts,
|
|
gint do_scale)
|
|
{
|
|
DobjPoints * pnt1 = NULL;
|
|
DobjPoints * pnt2 = NULL;
|
|
DobjPoints * pnt3 = NULL;
|
|
DobjPoints dpnts[3];
|
|
gdouble ang1, ang2, ang3;
|
|
gdouble maxang;
|
|
|
|
pnt1 = obj->points;
|
|
|
|
if (!pnt1)
|
|
return; /* Not fully drawn */
|
|
|
|
pnt2 = pnt1->next;
|
|
|
|
if (!pnt2)
|
|
return; /* Not fully drawn */
|
|
|
|
pnt3 = pnt2->next;
|
|
|
|
if (!pnt3)
|
|
return; /* Still not fully drawn */
|
|
|
|
if (draw_cnts)
|
|
{
|
|
draw_sqr (&pnt1->pnt);
|
|
draw_sqr (&pnt2->pnt);
|
|
draw_sqr (&pnt3->pnt);
|
|
}
|
|
|
|
if (do_scale)
|
|
{
|
|
/* Adjust pnts for scaling */
|
|
/* Warning struct copies here! and casting to double <-> int */
|
|
/* Too complex fix me - to much hacking */
|
|
gdouble xy[2];
|
|
int j;
|
|
|
|
dpnts[0] = *pnt1;
|
|
dpnts[1] = *pnt2;
|
|
dpnts[2] = *pnt3;
|
|
|
|
pnt1 = &dpnts[0];
|
|
pnt2 = &dpnts[1];
|
|
pnt3 = &dpnts[2];
|
|
|
|
for (j = 0 ; j < 3; j++)
|
|
{
|
|
xy[0] = dpnts[j].pnt.x;
|
|
xy[1] = dpnts[j].pnt.y;
|
|
if (selvals.scaletoimage)
|
|
scale_to_original_xy (&xy[0], 1);
|
|
else
|
|
scale_to_xy (&xy[0], 1);
|
|
dpnts[j].pnt.x = xy[0];
|
|
dpnts[j].pnt.y = xy[1];
|
|
}
|
|
}
|
|
|
|
arc_details (&pnt1->pnt, &pnt2->pnt, &pnt3->pnt, center_pnt, radius);
|
|
|
|
ang1 = arc_angle (&pnt1->pnt, center_pnt);
|
|
ang2 = arc_angle (&pnt2->pnt, center_pnt);
|
|
ang3 = arc_angle (&pnt3->pnt, center_pnt);
|
|
|
|
/* Find min/max angle */
|
|
|
|
maxang = ang1;
|
|
|
|
if (ang3 > maxang)
|
|
maxang = ang3;
|
|
|
|
*minang = ang1;
|
|
|
|
if (ang3 < *minang)
|
|
*minang = ang3;
|
|
|
|
if (ang2 > *minang && ang2 < maxang)
|
|
*arcang = maxang - *minang;
|
|
else
|
|
*arcang = maxang - *minang - 360;
|
|
}
|
|
|
|
static void
|
|
d_draw_arc (Dobject * obj)
|
|
{
|
|
GdkPoint center_pnt;
|
|
gdouble radius, minang, arcang;
|
|
|
|
g_assert (obj != NULL);
|
|
|
|
if (!obj)
|
|
return;
|
|
|
|
arc_drawing_details (obj, &minang, ¢er_pnt, &arcang, &radius, TRUE, FALSE);
|
|
|
|
#ifdef DEBUG
|
|
printf ("Min ang = %f Arc ang = %f\n", minang, arcang);
|
|
#endif /* DEBUG */
|
|
|
|
if (drawing_pic)
|
|
{
|
|
gdk_draw_arc (pic_preview->window,
|
|
pic_preview->style->black_gc,
|
|
0,
|
|
adjust_pic_coords (center_pnt.x - (gint)radius,
|
|
preview_width),
|
|
adjust_pic_coords (center_pnt.y - (gint)radius,
|
|
preview_height),
|
|
adjust_pic_coords ((gint) (radius * 2),
|
|
preview_width),
|
|
adjust_pic_coords ((gint) (radius * 2),
|
|
preview_height),
|
|
(gint) (minang*64),
|
|
(gint) (arcang*64));
|
|
}
|
|
else
|
|
{
|
|
gdk_draw_arc (gfig_preview->window,
|
|
gfig_gc,
|
|
0,
|
|
gfig_scale_x (center_pnt.x - (gint)radius),
|
|
gfig_scale_y (center_pnt.y - (gint)radius),
|
|
gfig_scale_x ((gint) (radius * 2)),
|
|
gfig_scale_y ((gint) (radius * 2)),
|
|
(gint) (minang*64),
|
|
(gint) (arcang*64));
|
|
}
|
|
}
|
|
|
|
static void
|
|
d_paint_arc (Dobject *obj)
|
|
{
|
|
/* first point center */
|
|
/* Next point is radius */
|
|
gdouble *line_pnts;
|
|
gint seg_count = 0;
|
|
gint i = 0;
|
|
gdouble ang_grid;
|
|
gdouble ang_loop;
|
|
gdouble radius;
|
|
gint loop;
|
|
GdkPoint first_pnt, last_pnt;
|
|
gint first = 1;
|
|
GdkPoint center_pnt;
|
|
gdouble minang, arcang;
|
|
|
|
g_assert (obj != NULL);
|
|
|
|
if (!obj)
|
|
return;
|
|
|
|
/* No cnt pnts & must scale */
|
|
arc_drawing_details (obj, &minang, ¢er_pnt, &arcang, &radius, FALSE, TRUE);
|
|
|
|
#ifdef DEBUG
|
|
printf ("Paint Min ang = %f Arc ang = %f\n", minang, arcang);
|
|
#endif /* DEBUG */
|
|
|
|
seg_count = 360; /* Should make a smoth-ish curve */
|
|
|
|
/* +3 because we MIGHT do pie selection */
|
|
line_pnts = g_new0 (gdouble, 2 * seg_count + 3);
|
|
|
|
/* Lines */
|
|
ang_grid = 2*G_PI/(gdouble)360;
|
|
|
|
if (arcang < 0.0)
|
|
{
|
|
/* Swap - since we always draw anti-clock wise */
|
|
minang += arcang;
|
|
arcang = -arcang;
|
|
}
|
|
|
|
minang = minang * (2*G_PI/360); /* min ang is in degrees - need in rads*/
|
|
|
|
for (loop = 0 ; loop < abs ((gint)arcang) ; loop++)
|
|
{
|
|
gdouble lx, ly;
|
|
GdkPoint calc_pnt;
|
|
|
|
ang_loop = (gdouble)loop * ang_grid + minang;
|
|
|
|
lx = radius * cos (ang_loop);
|
|
ly = -radius * sin (ang_loop); /* y grows down screen and angs measured from x clockwise */
|
|
|
|
calc_pnt.x = (gint)RINT (lx + center_pnt.x);
|
|
calc_pnt.y = (gint)RINT (ly + center_pnt.y);
|
|
|
|
/* Miss out duped pnts */
|
|
if (!first)
|
|
{
|
|
if (calc_pnt.x == last_pnt.x && calc_pnt.y == last_pnt.y)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
last_pnt.x = line_pnts[i++] = calc_pnt.x;
|
|
last_pnt.y = line_pnts[i++] = calc_pnt.y;
|
|
|
|
if (first)
|
|
{
|
|
first_pnt.x = calc_pnt.x;
|
|
first_pnt.y = calc_pnt.y;
|
|
first = 0;
|
|
}
|
|
}
|
|
|
|
/* Reverse line if approp */
|
|
if (selvals.reverselines)
|
|
reverse_pairs_list (&line_pnts[0], i/2);
|
|
|
|
/* One go */
|
|
if (selvals.painttype == PAINT_BRUSH_TYPE)
|
|
{
|
|
gfig_paint (selvals.brshtype,
|
|
gfig_drawable,
|
|
i, line_pnts);
|
|
}
|
|
else
|
|
{
|
|
if (selopt.as_pie)
|
|
{
|
|
/* Add center point - cause a pie like selection... */
|
|
line_pnts[i++] = center_pnt.x;
|
|
line_pnts[i++] = center_pnt.y;
|
|
}
|
|
|
|
gimp_free_select (gfig_image,
|
|
i, line_pnts,
|
|
selopt.type,
|
|
selopt.antia,
|
|
selopt.feather,
|
|
selopt.feather_radius);
|
|
}
|
|
|
|
g_free (line_pnts);
|
|
}
|
|
|
|
static Dobject *
|
|
d_copy_arc (Dobject * obj)
|
|
{
|
|
Dobject *nc;
|
|
|
|
#if DEBUG
|
|
printf ("Copy ellipse\n");
|
|
#endif /*DEBUG*/
|
|
if (!obj)
|
|
return (NULL);
|
|
|
|
g_assert (obj->type == ARC);
|
|
|
|
nc = d_new_arc (obj->points->pnt.x, obj->points->pnt.y);
|
|
|
|
nc->points->next = d_copy_dobjpoints (obj->points->next);
|
|
|
|
#if DEBUG
|
|
printf ("Arc (%x,%x), (%x,%x), (%x,%x)\n",
|
|
nc->points->pnt.x, obj->points->pnt.y,
|
|
nc->points->next->pnt.x, obj->points->next->pnt.y,
|
|
nc->points->next->next->pnt.x, obj->points->next->next->pnt.y);
|
|
printf ("Done copy\n");
|
|
#endif /*DEBUG*/
|
|
return (nc);
|
|
}
|
|
|
|
static Dobject *
|
|
d_new_arc (gint x,
|
|
gint y)
|
|
{
|
|
Dobject *nobj;
|
|
DobjPoints *npnt;
|
|
|
|
/* Get new object and starting point */
|
|
|
|
/* Start point */
|
|
npnt = g_new0 (DobjPoints, 1);
|
|
|
|
#if DEBUG
|
|
printf ("New arc start at (%x,%x)\n", x, y);
|
|
#endif /* DEBUG */
|
|
npnt->pnt.x = x;
|
|
npnt->pnt.y = y;
|
|
|
|
nobj = g_new0 (Dobject, 1);
|
|
|
|
nobj->type = ARC;
|
|
nobj->points = npnt;
|
|
nobj->drawfunc = d_draw_arc;
|
|
nobj->loadfunc = d_load_arc;
|
|
nobj->savefunc = d_save_arc;
|
|
nobj->paintfunc = d_paint_arc;
|
|
nobj->copyfunc = d_copy_arc;
|
|
|
|
return (nobj);
|
|
}
|
|
|
|
static void
|
|
d_update_arc (GdkPoint *pnt)
|
|
{
|
|
DobjPoints * pnt1 = NULL;
|
|
DobjPoints * pnt2 = NULL;
|
|
DobjPoints * pnt3 = NULL;
|
|
|
|
/* First two points as line only become arch when third
|
|
* point is placed on canvas.
|
|
*/
|
|
|
|
pnt1 = obj_creating->points;
|
|
|
|
if (!pnt1 ||
|
|
!(pnt2 = pnt1->next) ||
|
|
!(pnt3 = pnt2->next))
|
|
{
|
|
d_update_line (pnt);
|
|
return; /* Not fully drawn */
|
|
}
|
|
|
|
/* Update a real curve */
|
|
/* Nothing to be done ... */
|
|
}
|
|
|
|
static void
|
|
d_arc_start (GdkPoint *pnt,
|
|
gint shift_down)
|
|
{
|
|
/* Draw lines to start with -- then convert to an arc */
|
|
if (!tmp_line)
|
|
draw_sqr (pnt);
|
|
d_line_start (pnt, TRUE); /* TRUE means multiple pointed line */
|
|
}
|
|
|
|
static void
|
|
d_arc_end (GdkPoint *pnt,
|
|
gint shift_down)
|
|
{
|
|
/* Under contrl point */
|
|
if (!tmp_line ||
|
|
!tmp_line->points ||
|
|
!tmp_line->points->next)
|
|
{
|
|
/* No arc created - yet */
|
|
/* Must have three points */
|
|
#ifdef DEBUG
|
|
printf ("No arc created yet\n");
|
|
#endif /* DEBUG */
|
|
d_line_end (pnt, TRUE);
|
|
}
|
|
else
|
|
{
|
|
/* Complete arc */
|
|
/* Convert to an arc ... */
|
|
tmp_line->type = ARC;
|
|
tmp_line->drawfunc = d_draw_arc;
|
|
tmp_line->loadfunc = d_load_arc;
|
|
tmp_line->savefunc = d_save_arc;
|
|
tmp_line->paintfunc = d_paint_arc;
|
|
tmp_line->copyfunc = d_copy_arc;
|
|
d_line_end (pnt, FALSE);
|
|
/*d_draw_line (newarc); Should undraw line */
|
|
if (need_to_scale)
|
|
{
|
|
selvals.scaletoimage = 0;
|
|
}
|
|
/*d_draw_arc (newarc);*/
|
|
update_draw_area (gfig_preview, NULL);
|
|
if (need_to_scale)
|
|
{
|
|
selvals.scaletoimage = 1;
|
|
}
|
|
|
|
}
|
|
}
|
|
/*XXXXXXXXXXXXXXXXXXXXXXX*/
|
|
/* Star shape */
|
|
|
|
static void
|
|
d_save_star (Dobject *obj,
|
|
FILE *to)
|
|
{
|
|
DobjPoints * spnt;
|
|
|
|
spnt = obj->points;
|
|
|
|
if (!spnt)
|
|
return; /* End-of-line */
|
|
|
|
fprintf (to, "<STAR>\n");
|
|
|
|
while (spnt)
|
|
{
|
|
fprintf (to, "%d %d\n",
|
|
(gint)spnt->pnt.x,
|
|
(gint)spnt->pnt.y);
|
|
spnt = spnt->next;
|
|
}
|
|
|
|
fprintf (to, "<EXTRA>\n");
|
|
fprintf (to, "%d\n</EXTRA>\n", (gint)obj->type_data);
|
|
fprintf (to, "</STAR>\n");
|
|
}
|
|
|
|
/* Load a circle from the specified stream */
|
|
|
|
static Dobject *
|
|
d_load_star (FILE *from)
|
|
{
|
|
Dobject *new_obj = NULL;
|
|
gint xpnt;
|
|
gint ypnt;
|
|
gchar buf[MAX_LOAD_LINE];
|
|
|
|
#ifdef DEBUG
|
|
printf ("Load star called\n");
|
|
#endif /* DEBUG */
|
|
|
|
while (get_line (buf, MAX_LOAD_LINE, from, 0))
|
|
{
|
|
if (sscanf (buf, "%d %d", &xpnt, &ypnt) != 2)
|
|
{
|
|
/* Must be the end */
|
|
if (!strcmp ("<EXTRA>", buf))
|
|
{
|
|
gint nsides = 3;
|
|
/* Number of sides - data item */
|
|
if (!new_obj)
|
|
{
|
|
g_warning ("[%d] Internal load error while loading star (extra area)",
|
|
line_no);
|
|
return (NULL);
|
|
}
|
|
get_line (buf, MAX_LOAD_LINE, from, 0);
|
|
if (sscanf (buf, "%d", &nsides) != 1)
|
|
{
|
|
g_warning ("[%d] Internal load error while loading star (extra area scanf)",
|
|
line_no);
|
|
return (NULL);
|
|
}
|
|
new_obj->type_data = (gpointer)nsides;
|
|
get_line (buf, MAX_LOAD_LINE, from, 0);
|
|
if (strcmp ("</EXTRA>", buf))
|
|
{
|
|
g_warning ("[%d] Internal load error while loading star",
|
|
line_no);
|
|
return (NULL);
|
|
}
|
|
/* Go around and read the last line */
|
|
continue;
|
|
}
|
|
else if (strcmp ("</STAR>", buf))
|
|
{
|
|
g_warning ("[%d] Internal load error while loading star",
|
|
line_no);
|
|
return (NULL);
|
|
}
|
|
return (new_obj);
|
|
}
|
|
|
|
if (!new_obj)
|
|
new_obj = d_new_star (xpnt, ypnt);
|
|
else
|
|
d_pnt_add_line (new_obj, xpnt, ypnt,-1);
|
|
}
|
|
return (new_obj);
|
|
}
|
|
|
|
static void
|
|
d_draw_star (Dobject *obj)
|
|
{
|
|
DobjPoints * center_pnt;
|
|
DobjPoints * outer_radius_pnt;
|
|
DobjPoints * inner_radius_pnt;
|
|
gint16 shift_x;
|
|
gint16 shift_y;
|
|
gdouble ang_grid;
|
|
gdouble ang_loop;
|
|
gdouble outer_radius;
|
|
gdouble inner_radius;
|
|
gdouble offset_angle;
|
|
gint loop;
|
|
GdkPoint start_pnt;
|
|
GdkPoint first_pnt;
|
|
gint do_line = 0;
|
|
|
|
center_pnt = obj->points;
|
|
|
|
if (!center_pnt)
|
|
return; /* End-of-line */
|
|
|
|
/* First point is the center */
|
|
/* Just draw a control point around it */
|
|
|
|
draw_sqr (¢er_pnt->pnt);
|
|
|
|
/* Next point defines the radius */
|
|
outer_radius_pnt = center_pnt->next; /* this defines the vetices */
|
|
|
|
if (!outer_radius_pnt)
|
|
{
|
|
#ifdef DEBUG
|
|
g_warning ("Internal error in star - no outer vertice point \n");
|
|
#endif /* DEBUG */
|
|
return;
|
|
}
|
|
|
|
inner_radius_pnt = outer_radius_pnt->next; /* this defines the vetices */
|
|
|
|
if (!inner_radius_pnt)
|
|
{
|
|
#ifdef DEBUG
|
|
g_warning ("Internal error in star - no inner vertice point \n");
|
|
#endif /* DEBUG */
|
|
return;
|
|
}
|
|
|
|
/* Other control points */
|
|
draw_sqr (&outer_radius_pnt->pnt);
|
|
draw_sqr (&inner_radius_pnt->pnt);
|
|
|
|
/* Have center and radius - draw star */
|
|
|
|
shift_x = outer_radius_pnt->pnt.x - center_pnt->pnt.x;
|
|
shift_y = outer_radius_pnt->pnt.y - center_pnt->pnt.y;
|
|
|
|
outer_radius = sqrt ((shift_x*shift_x) + (shift_y*shift_y));
|
|
|
|
/* Lines */
|
|
ang_grid = 2*G_PI/(2.0*(gdouble) (gint)obj->type_data);
|
|
offset_angle = atan2 (shift_y, shift_x);
|
|
|
|
shift_x = inner_radius_pnt->pnt.x - center_pnt->pnt.x;
|
|
shift_y = inner_radius_pnt->pnt.y - center_pnt->pnt.y;
|
|
|
|
inner_radius = sqrt ((shift_x*shift_x) + (shift_y*shift_y));
|
|
|
|
for (loop = 0 ; loop < 2*(gint)obj->type_data ; loop++)
|
|
{
|
|
gdouble lx, ly;
|
|
GdkPoint calc_pnt;
|
|
|
|
ang_loop = (gdouble)loop * ang_grid + offset_angle;
|
|
|
|
if (loop%2)
|
|
{
|
|
lx = inner_radius * cos (ang_loop);
|
|
ly = inner_radius * sin (ang_loop);
|
|
}
|
|
else
|
|
{
|
|
lx = outer_radius * cos (ang_loop);
|
|
ly = outer_radius * sin (ang_loop);
|
|
}
|
|
|
|
calc_pnt.x = (gint)RINT (lx + center_pnt->pnt.x);
|
|
calc_pnt.y = (gint)RINT (ly + center_pnt->pnt.y);
|
|
|
|
if (do_line)
|
|
{
|
|
|
|
/* Miss out points that come to the same location */
|
|
if (calc_pnt.x == start_pnt.x && calc_pnt.y == start_pnt.y)
|
|
continue;
|
|
|
|
if (drawing_pic)
|
|
{
|
|
gdk_draw_line (pic_preview->window,
|
|
pic_preview->style->black_gc,
|
|
adjust_pic_coords (calc_pnt.x,
|
|
preview_width),
|
|
adjust_pic_coords (calc_pnt.y,
|
|
preview_height),
|
|
adjust_pic_coords (start_pnt.x,
|
|
preview_width),
|
|
adjust_pic_coords (start_pnt.y,
|
|
preview_height));
|
|
}
|
|
else
|
|
{
|
|
gdk_draw_line (gfig_preview->window,
|
|
gfig_gc,
|
|
gfig_scale_x (calc_pnt.x),
|
|
gfig_scale_y (calc_pnt.y),
|
|
gfig_scale_x (start_pnt.x),
|
|
gfig_scale_y (start_pnt.y));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
do_line = 1;
|
|
first_pnt.x = calc_pnt.x;
|
|
first_pnt.y = calc_pnt.y;
|
|
}
|
|
start_pnt.x = calc_pnt.x;
|
|
start_pnt.y = calc_pnt.y;
|
|
}
|
|
|
|
/* Join up */
|
|
if (drawing_pic)
|
|
{
|
|
gdk_draw_line (pic_preview->window,
|
|
pic_preview->style->black_gc,
|
|
adjust_pic_coords (first_pnt.x, preview_width),
|
|
adjust_pic_coords (first_pnt.y, preview_width),
|
|
adjust_pic_coords (start_pnt.x, preview_width),
|
|
adjust_pic_coords (start_pnt.y, preview_width));
|
|
}
|
|
else
|
|
{
|
|
gdk_draw_line (gfig_preview->window,
|
|
gfig_gc,
|
|
gfig_scale_x (first_pnt.x),
|
|
gfig_scale_y (first_pnt.y),
|
|
gfig_scale_x (start_pnt.x),
|
|
gfig_scale_y (start_pnt.y));
|
|
}
|
|
}
|
|
|
|
static void
|
|
d_paint_star (Dobject *obj)
|
|
{
|
|
/* first point center */
|
|
/* Next point is radius */
|
|
gdouble *line_pnts;
|
|
gint seg_count = 0;
|
|
gint i = 0;
|
|
DobjPoints * center_pnt;
|
|
DobjPoints * outer_radius_pnt;
|
|
DobjPoints * inner_radius_pnt;
|
|
gint16 shift_x;
|
|
gint16 shift_y;
|
|
gdouble ang_grid;
|
|
gdouble ang_loop;
|
|
gdouble outer_radius;
|
|
gdouble inner_radius;
|
|
|
|
gdouble offset_angle;
|
|
gint loop;
|
|
GdkPoint first_pnt, last_pnt;
|
|
gint first = 1;
|
|
|
|
g_assert (obj != NULL);
|
|
|
|
/* count - add one to close polygon */
|
|
seg_count = 2*(gint)obj->type_data + 1;
|
|
|
|
center_pnt = obj->points;
|
|
|
|
if (!center_pnt || !seg_count)
|
|
return; /* no-line */
|
|
|
|
line_pnts = g_new0 (gdouble, 2 * seg_count + 1);
|
|
|
|
/* Go around all the points drawing a line from one to the next */
|
|
/* Next point defines the radius */
|
|
outer_radius_pnt = center_pnt->next; /* this defines the vetices */
|
|
|
|
if (!outer_radius_pnt)
|
|
{
|
|
#ifdef DEBUG
|
|
g_warning ("Internal error in star - no outer vertice point \n");
|
|
#endif /* DEBUG */
|
|
return;
|
|
}
|
|
|
|
inner_radius_pnt = outer_radius_pnt->next; /* this defines the vetices */
|
|
|
|
if (!inner_radius_pnt)
|
|
{
|
|
#ifdef DEBUG
|
|
g_warning ("Internal error in star - no inner vertice point \n");
|
|
#endif /* DEBUG */
|
|
return;
|
|
}
|
|
|
|
shift_x = outer_radius_pnt->pnt.x - center_pnt->pnt.x;
|
|
shift_y = outer_radius_pnt->pnt.y - center_pnt->pnt.y;
|
|
|
|
outer_radius = sqrt ((shift_x*shift_x) + (shift_y*shift_y));
|
|
|
|
/* Lines */
|
|
ang_grid = 2*G_PI/(2.0*(gdouble) (gint)obj->type_data);
|
|
offset_angle = atan2 (shift_y, shift_x);
|
|
|
|
shift_x = inner_radius_pnt->pnt.x - center_pnt->pnt.x;
|
|
shift_y = inner_radius_pnt->pnt.y - center_pnt->pnt.y;
|
|
|
|
inner_radius = sqrt ((shift_x*shift_x) + (shift_y*shift_y));
|
|
|
|
for (loop = 0 ; loop < 2*(gint)obj->type_data ; loop++)
|
|
{
|
|
gdouble lx, ly;
|
|
GdkPoint calc_pnt;
|
|
|
|
ang_loop = (gdouble)loop * ang_grid + offset_angle;
|
|
|
|
if (loop%2)
|
|
{
|
|
lx = inner_radius * cos (ang_loop);
|
|
ly = inner_radius * sin (ang_loop);
|
|
}
|
|
else
|
|
{
|
|
lx = outer_radius * cos (ang_loop);
|
|
ly = outer_radius * sin (ang_loop);
|
|
}
|
|
|
|
calc_pnt.x = (gint)RINT (lx + center_pnt->pnt.x);
|
|
calc_pnt.y = (gint)RINT (ly + center_pnt->pnt.y);
|
|
|
|
/* Miss out duped pnts */
|
|
if (!first)
|
|
{
|
|
if (calc_pnt.x == last_pnt.x && calc_pnt.y == last_pnt.y)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
last_pnt.x = line_pnts[i++] = calc_pnt.x;
|
|
last_pnt.y = line_pnts[i++] = calc_pnt.y;
|
|
|
|
if (first)
|
|
{
|
|
first_pnt.x = calc_pnt.x;
|
|
first_pnt.y = calc_pnt.y;
|
|
first = 0;
|
|
}
|
|
}
|
|
|
|
line_pnts[i++] = first_pnt.x;
|
|
line_pnts[i++] = first_pnt.y;
|
|
|
|
/* Reverse line if approp */
|
|
if (selvals.reverselines)
|
|
reverse_pairs_list (&line_pnts[0], i/2);
|
|
|
|
/* Scale before drawing */
|
|
if (selvals.scaletoimage)
|
|
scale_to_original_xy (&line_pnts[0], i/2);
|
|
else
|
|
scale_to_xy (&line_pnts[0], i/2);
|
|
|
|
/* One go */
|
|
if (selvals.painttype == PAINT_BRUSH_TYPE)
|
|
{
|
|
gfig_paint (selvals.brshtype,
|
|
gfig_drawable,
|
|
i, line_pnts);
|
|
}
|
|
else
|
|
{
|
|
gimp_free_select (gfig_image,
|
|
i, line_pnts,
|
|
selopt.type,
|
|
selopt.antia,
|
|
selopt.feather,
|
|
selopt.feather_radius);
|
|
}
|
|
|
|
g_free (line_pnts);
|
|
}
|
|
|
|
static Dobject *
|
|
d_copy_star (Dobject * obj)
|
|
{
|
|
Dobject *np;
|
|
|
|
#if DEBUG
|
|
printf ("Copy star\n");
|
|
#endif /*DEBUG*/
|
|
if (!obj)
|
|
return (NULL);
|
|
|
|
g_assert (obj->type == STAR);
|
|
|
|
np = d_new_star (obj->points->pnt.x, obj->points->pnt.y);
|
|
|
|
np->points->next = d_copy_dobjpoints (obj->points->next);
|
|
|
|
np->type_data = obj->type_data;
|
|
|
|
#if DEBUG
|
|
printf ("Done star copy\n");
|
|
#endif /*DEBUG*/
|
|
return (np);
|
|
}
|
|
|
|
static Dobject *
|
|
d_new_star (gint x,
|
|
gint y)
|
|
{
|
|
Dobject *nobj;
|
|
DobjPoints *npnt;
|
|
|
|
/* Get new object and starting point */
|
|
|
|
/* Start point */
|
|
npnt = g_new0 (DobjPoints, 1);
|
|
|
|
#if DEBUG
|
|
printf ("New STAR start at (%x,%x)\n", x, y);
|
|
#endif /* DEBUG */
|
|
npnt->pnt.x = x;
|
|
npnt->pnt.y = y;
|
|
|
|
nobj = g_new0 (Dobject, 1);
|
|
|
|
nobj->type = STAR;
|
|
nobj->type_data = (gpointer)3; /* Default to three sides 6 points*/
|
|
nobj->points = npnt;
|
|
nobj->drawfunc = d_draw_star;
|
|
nobj->loadfunc = d_load_star;
|
|
nobj->savefunc = d_save_star;
|
|
nobj->paintfunc = d_paint_star;
|
|
nobj->copyfunc = d_copy_star;
|
|
|
|
return (nobj);
|
|
}
|
|
|
|
static void
|
|
d_update_star (GdkPoint *pnt)
|
|
{
|
|
DobjPoints *center_pnt, *inner_pnt, *outer_pnt;
|
|
gint saved_cnt_pnt = selvals.opts.showcontrol;
|
|
|
|
/* Undraw last one then draw new one */
|
|
center_pnt = obj_creating->points;
|
|
|
|
if (!center_pnt)
|
|
return; /* No points */
|
|
|
|
/* Leave the first pnt alone -
|
|
* Edge point defines "radius"
|
|
* Only undraw if already have edge point.
|
|
*/
|
|
|
|
/* Hack - turn off cnt points in draw routine
|
|
* Looking back over the other update routines I could
|
|
* use this trick again and cut down on code size!
|
|
*/
|
|
|
|
|
|
if ((outer_pnt = center_pnt->next))
|
|
{
|
|
/* Undraw */
|
|
inner_pnt = outer_pnt->next;
|
|
draw_circle (&inner_pnt->pnt);
|
|
draw_circle (&outer_pnt->pnt);
|
|
selvals.opts.showcontrol = 0;
|
|
d_draw_star (obj_creating);
|
|
outer_pnt->pnt.x = pnt->x;
|
|
outer_pnt->pnt.y = pnt->y;
|
|
inner_pnt->pnt.x = pnt->x + (2*(center_pnt->pnt.x - pnt->x))/3;
|
|
inner_pnt->pnt.y = pnt->y + (2*(center_pnt->pnt.y - pnt->y))/3;
|
|
}
|
|
else
|
|
{
|
|
/* Radius is a few pixels away */
|
|
/* First edge point */
|
|
d_pnt_add_line (obj_creating, pnt->x, pnt->y,-1);
|
|
outer_pnt = center_pnt->next;
|
|
/* Inner radius */
|
|
d_pnt_add_line (obj_creating,
|
|
pnt->x + (2*(center_pnt->pnt.x - pnt->x))/3,
|
|
pnt->y + (2*(center_pnt->pnt.y - pnt->y))/3,
|
|
-1);
|
|
inner_pnt = outer_pnt->next;
|
|
}
|
|
|
|
/* draw it */
|
|
selvals.opts.showcontrol = 0;
|
|
d_draw_star (obj_creating);
|
|
selvals.opts.showcontrol = saved_cnt_pnt;
|
|
|
|
/* Realy draw the control points */
|
|
draw_circle (&outer_pnt->pnt);
|
|
draw_circle (&inner_pnt->pnt);
|
|
}
|
|
|
|
/* first point is center
|
|
* next defines the radius
|
|
*/
|
|
|
|
static void
|
|
d_star_start (GdkPoint *pnt,
|
|
gint shift_down)
|
|
{
|
|
gint16 x, y;
|
|
/* First is center point */
|
|
obj_creating = d_new_star (x = pnt->x, y = pnt->y);
|
|
obj_creating->type_data = (gpointer)star_num_sides;
|
|
}
|
|
|
|
static void
|
|
d_star_end (GdkPoint *pnt,
|
|
gint shift_down)
|
|
{
|
|
draw_circle (pnt);
|
|
add_to_all_obj (current_obj, obj_creating);
|
|
obj_creating = NULL;
|
|
}
|
|
|
|
|
|
/* Spiral */
|
|
|
|
static void
|
|
d_save_spiral (Dobject *obj,
|
|
FILE *to)
|
|
{
|
|
DobjPoints * spnt;
|
|
|
|
spnt = obj->points;
|
|
|
|
if (!spnt)
|
|
return; /* End-of-line */
|
|
|
|
fprintf (to, "<SPIRAL>\n");
|
|
|
|
while (spnt)
|
|
{
|
|
fprintf (to, "%d %d\n",
|
|
(gint)spnt->pnt.x,
|
|
(gint)spnt->pnt.y);
|
|
spnt = spnt->next;
|
|
}
|
|
|
|
fprintf (to, "<EXTRA>\n");
|
|
fprintf (to, "%d\n</EXTRA>\n", (gint)obj->type_data);
|
|
fprintf (to, "</SPIRAL>\n");
|
|
|
|
}
|
|
|
|
/* Load a spiral from the specified stream */
|
|
|
|
static Dobject *
|
|
d_load_spiral (FILE *from)
|
|
{
|
|
Dobject *new_obj = NULL;
|
|
gint xpnt;
|
|
gint ypnt;
|
|
gchar buf[MAX_LOAD_LINE];
|
|
|
|
#ifdef DEBUG
|
|
printf ("Load spiral called\n");
|
|
#endif /* DEBUG */
|
|
|
|
while (get_line (buf, MAX_LOAD_LINE, from, 0))
|
|
{
|
|
if (sscanf (buf, "%d %d", &xpnt, &ypnt) != 2)
|
|
{
|
|
/* Must be the end */
|
|
if (!strcmp ("<EXTRA>", buf))
|
|
{
|
|
gint nsides = 3;
|
|
/* Number of sides - data item */
|
|
if (!new_obj)
|
|
{
|
|
g_warning ("[%d] Internal load error while loading spiral (extra area)",
|
|
line_no);
|
|
return (NULL);
|
|
}
|
|
get_line (buf, MAX_LOAD_LINE, from, 0);
|
|
if (sscanf (buf, "%d", &nsides) != 1)
|
|
{
|
|
g_warning ("[%d] Internal load error while loading spiral (extra area scanf)",
|
|
line_no);
|
|
return (NULL);
|
|
}
|
|
new_obj->type_data = (gpointer)nsides;
|
|
get_line (buf, MAX_LOAD_LINE, from, 0);
|
|
if (strcmp ("</EXTRA>", buf))
|
|
{
|
|
g_warning ("[%d] Internal load error while loading spiral",
|
|
line_no);
|
|
return (NULL);
|
|
}
|
|
/* Go around and read the last line */
|
|
continue;
|
|
}
|
|
else if (strcmp ("</SPIRAL>", buf))
|
|
{
|
|
g_warning ("[%d] Internal load error while loading spiral",
|
|
line_no);
|
|
return (NULL);
|
|
}
|
|
return (new_obj);
|
|
}
|
|
|
|
if (!new_obj)
|
|
new_obj = d_new_spiral (xpnt, ypnt);
|
|
else
|
|
d_pnt_add_line (new_obj, xpnt, ypnt,-1);
|
|
}
|
|
return (new_obj);
|
|
}
|
|
|
|
static void
|
|
d_draw_spiral (Dobject *obj)
|
|
{
|
|
DobjPoints * center_pnt;
|
|
DobjPoints * radius_pnt;
|
|
gint16 shift_x;
|
|
gint16 shift_y;
|
|
gdouble ang_grid;
|
|
gdouble ang_loop;
|
|
gdouble radius;
|
|
gdouble offset_angle;
|
|
gdouble sp_cons;
|
|
gint loop;
|
|
GdkPoint start_pnt;
|
|
GdkPoint first_pnt;
|
|
gint do_line = 0;
|
|
gint clock_wise = 1;
|
|
|
|
center_pnt = obj->points;
|
|
|
|
if (!center_pnt)
|
|
return; /* End-of-line */
|
|
|
|
/* First point is the center */
|
|
/* Just draw a control point around it */
|
|
|
|
draw_sqr (¢er_pnt->pnt);
|
|
|
|
/* Next point defines the radius */
|
|
radius_pnt = center_pnt->next; /* this defines the vetices */
|
|
|
|
if (!radius_pnt)
|
|
{
|
|
#ifdef DEBUG
|
|
g_warning ("Internal error in spiral - no vertice point \n");
|
|
#endif /* DEBUG */
|
|
return;
|
|
}
|
|
|
|
/* Other control point */
|
|
draw_sqr (&radius_pnt->pnt);
|
|
|
|
/* Have center and radius - draw spiral */
|
|
|
|
shift_x = radius_pnt->pnt.x - center_pnt->pnt.x;
|
|
shift_y = radius_pnt->pnt.y - center_pnt->pnt.y;
|
|
|
|
radius = sqrt ((shift_x*shift_x) + (shift_y*shift_y));
|
|
|
|
offset_angle = atan2 (shift_y, shift_x);
|
|
|
|
clock_wise = ((gint)obj->type_data)/(abs ((gint) (obj->type_data)));
|
|
|
|
if (offset_angle < 0)
|
|
offset_angle += 2*G_PI;
|
|
|
|
sp_cons = radius/((gint)obj->type_data * 2 * G_PI + offset_angle);
|
|
/* Lines */
|
|
ang_grid = 2.0*G_PI/(gdouble)180;
|
|
|
|
|
|
for (loop = 0 ; loop <= abs ((gint) (obj->type_data)*180) + clock_wise*(gint)RINT (offset_angle/ang_grid) ; loop++)
|
|
{
|
|
gdouble lx, ly;
|
|
GdkPoint calc_pnt;
|
|
|
|
ang_loop = (gdouble)loop * ang_grid;
|
|
|
|
lx = sp_cons * ang_loop * cos (ang_loop)*clock_wise;
|
|
ly = sp_cons * ang_loop * sin (ang_loop);
|
|
|
|
calc_pnt.x = (gint)RINT (lx + center_pnt->pnt.x);
|
|
calc_pnt.y = (gint)RINT (ly + center_pnt->pnt.y);
|
|
|
|
if (do_line)
|
|
{
|
|
|
|
/* Miss out points that come to the same location */
|
|
if (calc_pnt.x == start_pnt.x && calc_pnt.y == start_pnt.y)
|
|
continue;
|
|
|
|
if (drawing_pic)
|
|
{
|
|
gdk_draw_line (pic_preview->window,
|
|
pic_preview->style->black_gc,
|
|
adjust_pic_coords (calc_pnt.x,
|
|
preview_width),
|
|
adjust_pic_coords (calc_pnt.y,
|
|
preview_height),
|
|
adjust_pic_coords (start_pnt.x,
|
|
preview_width),
|
|
adjust_pic_coords (start_pnt.y,
|
|
preview_height));
|
|
}
|
|
else
|
|
{
|
|
gdk_draw_line (gfig_preview->window,
|
|
gfig_gc,
|
|
gfig_scale_x (calc_pnt.x),
|
|
gfig_scale_y (calc_pnt.y),
|
|
gfig_scale_x (start_pnt.x),
|
|
gfig_scale_y (start_pnt.y));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
do_line = 1;
|
|
first_pnt.x = calc_pnt.x;
|
|
first_pnt.y = calc_pnt.y;
|
|
}
|
|
start_pnt.x = calc_pnt.x;
|
|
start_pnt.y = calc_pnt.y;
|
|
}
|
|
}
|
|
|
|
static void
|
|
d_paint_spiral (Dobject *obj)
|
|
{
|
|
/* first point center */
|
|
/* Next point is radius */
|
|
gdouble *line_pnts;
|
|
gint seg_count = 0;
|
|
gint i = 0;
|
|
DobjPoints * center_pnt;
|
|
DobjPoints * radius_pnt;
|
|
gint16 shift_x;
|
|
gint16 shift_y;
|
|
gdouble ang_grid;
|
|
gdouble ang_loop;
|
|
gdouble radius;
|
|
gdouble offset_angle;
|
|
gdouble sp_cons;
|
|
gint loop;
|
|
GdkPoint last_pnt;
|
|
gint clock_wise = 1;
|
|
|
|
g_assert (obj != NULL);
|
|
|
|
center_pnt = obj->points;
|
|
|
|
if (!center_pnt || !center_pnt->next)
|
|
return; /* no-line */
|
|
|
|
/* Go around all the points drawing a line from one to the next */
|
|
|
|
radius_pnt = center_pnt->next; /* this defines the vetices */
|
|
|
|
/* Have center and radius - get lines */
|
|
shift_x = radius_pnt->pnt.x - center_pnt->pnt.x;
|
|
shift_y = radius_pnt->pnt.y - center_pnt->pnt.y;
|
|
|
|
radius = sqrt ((shift_x*shift_x) + (shift_y*shift_y));
|
|
|
|
clock_wise = ((gint)obj->type_data)/(abs ((gint) (obj->type_data)));
|
|
|
|
offset_angle = atan2 (shift_y, shift_x);
|
|
|
|
if (offset_angle < 0)
|
|
offset_angle += 2*G_PI;
|
|
|
|
sp_cons = radius/((gint)obj->type_data * 2 * G_PI + offset_angle);
|
|
/* Lines */
|
|
ang_grid = 2.0*G_PI/(gdouble)180;
|
|
|
|
|
|
/* count - */
|
|
seg_count = abs ((gint) (obj->type_data)*180) + clock_wise*(gint)RINT (offset_angle/ang_grid);
|
|
|
|
line_pnts = g_new0 (gdouble, 2 * seg_count + 3);
|
|
|
|
for (loop = 0 ; loop <= seg_count; loop++)
|
|
{
|
|
gdouble lx, ly;
|
|
GdkPoint calc_pnt;
|
|
|
|
ang_loop = (gdouble)loop * ang_grid;
|
|
|
|
lx = sp_cons * ang_loop * cos (ang_loop)*clock_wise;
|
|
ly = sp_cons * ang_loop * sin (ang_loop);
|
|
|
|
calc_pnt.x = (gint)RINT (lx + center_pnt->pnt.x);
|
|
calc_pnt.y = (gint)RINT (ly + center_pnt->pnt.y);
|
|
|
|
/* Miss out duped pnts */
|
|
if (!loop)
|
|
{
|
|
if (calc_pnt.x == last_pnt.x && calc_pnt.y == last_pnt.y)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
last_pnt.x = line_pnts[i++] = calc_pnt.x;
|
|
last_pnt.y = line_pnts[i++] = calc_pnt.y;
|
|
}
|
|
|
|
/* Reverse line if approp */
|
|
if (selvals.reverselines)
|
|
reverse_pairs_list (&line_pnts[0], i/2);
|
|
|
|
/* Scale before drawing */
|
|
if (selvals.scaletoimage)
|
|
scale_to_original_xy (&line_pnts[0], i/2);
|
|
else
|
|
scale_to_xy (&line_pnts[0], i/2);
|
|
|
|
/* One go */
|
|
if (selvals.painttype == PAINT_BRUSH_TYPE)
|
|
{
|
|
gfig_paint (selvals.brshtype,
|
|
gfig_drawable,
|
|
i, line_pnts);
|
|
}
|
|
else
|
|
{
|
|
gimp_free_select (gfig_image,
|
|
i, line_pnts,
|
|
selopt.type,
|
|
selopt.antia,
|
|
selopt.feather,
|
|
selopt.feather_radius);
|
|
}
|
|
|
|
g_free (line_pnts);
|
|
}
|
|
|
|
static Dobject *
|
|
d_copy_spiral (Dobject * obj)
|
|
{
|
|
Dobject *np;
|
|
|
|
#if DEBUG
|
|
printf ("Copy spiral\n");
|
|
#endif /*DEBUG*/
|
|
if (!obj)
|
|
return (NULL);
|
|
|
|
g_assert (obj->type == SPIRAL);
|
|
|
|
np = d_new_spiral (obj->points->pnt.x, obj->points->pnt.y);
|
|
|
|
np->points->next = d_copy_dobjpoints (obj->points->next);
|
|
|
|
np->type_data = obj->type_data;
|
|
|
|
#if DEBUG
|
|
printf ("Done spiral copy\n");
|
|
#endif /*DEBUG*/
|
|
return (np);
|
|
}
|
|
|
|
static Dobject *
|
|
d_new_spiral (gint x,
|
|
gint y)
|
|
{
|
|
Dobject *nobj;
|
|
DobjPoints *npnt;
|
|
|
|
/* Get new object and starting point */
|
|
|
|
/* Start point */
|
|
npnt = g_new0 (DobjPoints, 1);
|
|
|
|
#if DEBUG
|
|
printf ("New SPIRAL start at (%x,%x)\n", x, y);
|
|
#endif /* DEBUG */
|
|
npnt->pnt.x = x;
|
|
npnt->pnt.y = y;
|
|
|
|
nobj = g_new0 (Dobject, 1);
|
|
|
|
nobj->type = SPIRAL;
|
|
nobj->type_data = (gpointer)4; /* Default to four turns */
|
|
nobj->points = npnt;
|
|
nobj->drawfunc = d_draw_spiral;
|
|
nobj->loadfunc = d_load_spiral;
|
|
nobj->savefunc = d_save_spiral;
|
|
nobj->paintfunc = d_paint_spiral;
|
|
nobj->copyfunc = d_copy_spiral;
|
|
|
|
return (nobj);
|
|
}
|
|
|
|
static void
|
|
d_update_spiral (GdkPoint *pnt)
|
|
{
|
|
DobjPoints *center_pnt, *edge_pnt;
|
|
gint saved_cnt_pnt = selvals.opts.showcontrol;
|
|
|
|
/* Undraw last one then draw new one */
|
|
center_pnt = obj_creating->points;
|
|
|
|
if (!center_pnt)
|
|
return; /* No points */
|
|
|
|
/* Leave the first pnt alone -
|
|
* Edge point defines "radius"
|
|
* Only undraw if already have edge point.
|
|
*/
|
|
|
|
/* Hack - turn off cnt points in draw routine
|
|
* Looking back over the other update routines I could
|
|
* use this trick again and cut down on code size!
|
|
*/
|
|
|
|
if ((edge_pnt = center_pnt->next))
|
|
{
|
|
/* Undraw */
|
|
draw_circle (&edge_pnt->pnt);
|
|
selvals.opts.showcontrol = 0;
|
|
d_draw_spiral (obj_creating);
|
|
|
|
edge_pnt->pnt.x = pnt->x;
|
|
edge_pnt->pnt.y = pnt->y;
|
|
}
|
|
else
|
|
{
|
|
/* Radius is a few pixels away */
|
|
/* First edge point */
|
|
d_pnt_add_line (obj_creating, pnt->x, pnt->y, -1);
|
|
edge_pnt = center_pnt->next;
|
|
}
|
|
|
|
/* draw it */
|
|
selvals.opts.showcontrol = 0;
|
|
d_draw_spiral (obj_creating);
|
|
selvals.opts.showcontrol = saved_cnt_pnt;
|
|
|
|
/* Realy draw the control points */
|
|
draw_circle (&edge_pnt->pnt);
|
|
}
|
|
|
|
/* first point is center
|
|
* next defines the radius
|
|
*/
|
|
|
|
static void
|
|
d_spiral_start (GdkPoint *pnt,
|
|
gint shift_down)
|
|
{
|
|
gint16 x, y;
|
|
/* First is center point */
|
|
obj_creating = d_new_spiral (x = pnt->x, y = pnt->y);
|
|
obj_creating->type_data =
|
|
(gpointer) (spiral_num_turns * ((spiral_toggle == 0) ? 1 : -1));
|
|
}
|
|
|
|
static void
|
|
d_spiral_end (GdkPoint *pnt,
|
|
gint shift_down)
|
|
{
|
|
draw_circle (pnt);
|
|
add_to_all_obj (current_obj, obj_creating);
|
|
obj_creating = NULL;
|
|
}
|
|
|
|
/* Stuff for bezier curves... */
|
|
|
|
static void
|
|
d_save_bezier (Dobject *obj,
|
|
FILE *to)
|
|
{
|
|
DobjPoints *spnt;
|
|
|
|
spnt = obj->points;
|
|
|
|
if (!spnt)
|
|
return; /* End-of-line */
|
|
|
|
fprintf (to, "<BEZIER>\n");
|
|
|
|
while (spnt)
|
|
{
|
|
fprintf (to, "%d %d\n",
|
|
(gint)spnt->pnt.x,
|
|
(gint)spnt->pnt.y);
|
|
spnt = spnt->next;
|
|
}
|
|
|
|
fprintf (to, "<EXTRA>\n");
|
|
fprintf (to, "%d\n</EXTRA>\n", (gint) obj->type_data);
|
|
fprintf (to, "</BEZIER>\n");
|
|
}
|
|
|
|
/* Load a bezier from the specified stream */
|
|
|
|
static Dobject *
|
|
d_load_bezier (FILE *from)
|
|
{
|
|
Dobject *new_obj = NULL;
|
|
gint xpnt;
|
|
gint ypnt;
|
|
gchar buf[MAX_LOAD_LINE];
|
|
|
|
#ifdef DEBUG
|
|
printf ("Load bezier called\n");
|
|
#endif /* DEBUG */
|
|
|
|
while (get_line (buf, MAX_LOAD_LINE, from, 0))
|
|
{
|
|
if (sscanf (buf, "%d %d", &xpnt, &ypnt) != 2)
|
|
{
|
|
/* Must be the end */
|
|
if (!strcmp ("<EXTRA>", buf))
|
|
{
|
|
gint nsides = 3;
|
|
/* Number of sides - data item */
|
|
if ( !new_obj)
|
|
{
|
|
g_message ("[%d] Internal load error while loading bezier "
|
|
"(extra area)", line_no);
|
|
return NULL;
|
|
}
|
|
get_line (buf, MAX_LOAD_LINE, from, 0);
|
|
if (sscanf (buf, "%d", &nsides) != 1)
|
|
{
|
|
g_message ("[%d] Internal load error while loading bezier "
|
|
"(extra area scanf)", line_no);
|
|
return NULL;
|
|
}
|
|
new_obj->type_data = (gpointer) nsides;
|
|
get_line (buf, MAX_LOAD_LINE, from, 0);
|
|
if (strcmp ("</EXTRA>", buf))
|
|
{
|
|
g_message ("[%d] Internal load error while loading bezier",
|
|
line_no);
|
|
return NULL;
|
|
}
|
|
/* Go around and read the last line */
|
|
continue;
|
|
}
|
|
else if (strcmp ("</BEZIER>", buf))
|
|
{
|
|
g_message ("[%d] Internal load error while loading bezier",
|
|
line_no);
|
|
return NULL;
|
|
}
|
|
return new_obj;
|
|
}
|
|
|
|
if (!new_obj)
|
|
new_obj = d_new_bezier (xpnt, ypnt);
|
|
else
|
|
d_pnt_add_line (new_obj, xpnt, ypnt, -1);
|
|
}
|
|
|
|
return new_obj;
|
|
}
|
|
|
|
|
|
#define FP_PNT_MAX 10
|
|
|
|
static int fp_pnt_cnt = 0;
|
|
static int fp_pnt_chunk = 0;
|
|
static gdouble *fp_pnt_pnts = NULL;
|
|
|
|
static void
|
|
fp_pnt_start (void)
|
|
{
|
|
fp_pnt_cnt = 0;
|
|
}
|
|
|
|
/* Add a line segment to collection array */
|
|
static void
|
|
fp_pnt_add (gdouble p1,
|
|
gdouble p2,
|
|
gdouble p3,
|
|
gdouble p4)
|
|
{
|
|
if (!fp_pnt_pnts)
|
|
{
|
|
fp_pnt_pnts = g_new0 (gdouble, FP_PNT_MAX);
|
|
fp_pnt_chunk = 1;
|
|
}
|
|
|
|
if (((fp_pnt_cnt + 4) / FP_PNT_MAX) >= fp_pnt_chunk)
|
|
{
|
|
/* more space pls */
|
|
fp_pnt_chunk++;
|
|
fp_pnt_pnts =
|
|
(gdouble *) g_realloc (fp_pnt_pnts,
|
|
sizeof (gdouble) * fp_pnt_chunk * FP_PNT_MAX);
|
|
}
|
|
|
|
fp_pnt_pnts[fp_pnt_cnt++] = p1;
|
|
fp_pnt_pnts[fp_pnt_cnt++] = p2;
|
|
fp_pnt_pnts[fp_pnt_cnt++] = p3;
|
|
fp_pnt_pnts[fp_pnt_cnt++] = p4;
|
|
}
|
|
|
|
static gdouble *
|
|
d_bz_get_array (gint *sz)
|
|
{
|
|
*sz = fp_pnt_cnt;
|
|
return fp_pnt_pnts;
|
|
}
|
|
|
|
|
|
static void
|
|
d_bz_line (void)
|
|
{
|
|
gint i, x0, y0, x1, y1;
|
|
|
|
g_assert ((fp_pnt_cnt % 4) == 0);
|
|
|
|
for (i = 0 ; i < fp_pnt_cnt; i += 4)
|
|
{
|
|
x0 = (gint) fp_pnt_pnts[i];
|
|
y0 = (gint) fp_pnt_pnts[i + 1];
|
|
x1 = (gint) fp_pnt_pnts[i + 2];
|
|
y1 = (gint) fp_pnt_pnts[i + 3];
|
|
|
|
if (drawing_pic)
|
|
{
|
|
gdk_draw_line (pic_preview->window,
|
|
pic_preview->style->black_gc,
|
|
adjust_pic_coords ((gint) x0,
|
|
preview_width),
|
|
adjust_pic_coords ((gint) y0,
|
|
preview_height),
|
|
adjust_pic_coords ((gint) x1,
|
|
preview_width),
|
|
adjust_pic_coords ((gint) y1,
|
|
preview_height));
|
|
}
|
|
else
|
|
{
|
|
gdk_draw_line (gfig_preview->window,
|
|
gfig_gc,
|
|
gfig_scale_x ((gint) x0),
|
|
gfig_scale_y ((gint) y0),
|
|
gfig_scale_x ((gint) x1),
|
|
gfig_scale_y ((gint) y1));
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Return points to plot */
|
|
/* Terminate by point with DBL_MAX, DBL_MAX */
|
|
typedef gdouble (*fp_pnt)[2];
|
|
|
|
static void
|
|
DrawBezier (gdouble (*points)[2],
|
|
gint np,
|
|
gdouble mid,
|
|
gint depth)
|
|
{
|
|
gint i, j, x0 = 0, y0 = 0, x1, y1;
|
|
fp_pnt left;
|
|
fp_pnt right;
|
|
|
|
if (depth == 0) /* draw polyline */
|
|
{
|
|
for (i = 0; i < np; i++)
|
|
{
|
|
x1 = (int) points[i][0];
|
|
y1 = (int) points[i][1];
|
|
if (i > 0 && (x1 != x0 || y1 != y0))
|
|
{
|
|
/* Add pnts up */
|
|
fp_pnt_add ((gdouble) x0, (gdouble) y0,
|
|
(gdouble) x1, (gdouble) y1);
|
|
}
|
|
x0 = x1;
|
|
y0 = y1;
|
|
}
|
|
}
|
|
else /* subdivide control points at mid */
|
|
{
|
|
left = (fp_pnt) g_new (gdouble, np * 2);
|
|
right = (fp_pnt) g_new (gdouble, np * 2);
|
|
for (i = 0; i < np; i++)
|
|
{
|
|
right[i][0] = points[i][0];
|
|
right[i][1] = points[i][1];
|
|
}
|
|
left[0][0] = right[0][0];
|
|
left[0][1] = right[0][1];
|
|
for (j = np - 1; j >= 1; j--)
|
|
{
|
|
for (i = 0; i < j; i++)
|
|
{
|
|
right[i][0] = (1 - mid) * right[i][0] + mid * right[i + 1][0];
|
|
right[i][1] = (1 - mid) * right[i][1] + mid * right[i + 1][1];
|
|
}
|
|
left[np - j][0] = right[0][0];
|
|
left[np - j][1] = right[0][1];
|
|
}
|
|
if (depth > 0)
|
|
{
|
|
DrawBezier (left, np, mid, depth - 1);
|
|
DrawBezier (right, np, mid, depth - 1);
|
|
g_free (left);
|
|
g_free (right);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
d_draw_bezier (Dobject *obj)
|
|
{
|
|
DobjPoints * spnt;
|
|
gint seg_count = 0;
|
|
gint i = 0;
|
|
gdouble (*line_pnts)[2];
|
|
|
|
spnt = obj->points;
|
|
|
|
/* First count the number of points */
|
|
|
|
/* count */
|
|
while (spnt)
|
|
{
|
|
seg_count++;
|
|
spnt = spnt->next;
|
|
}
|
|
|
|
spnt = obj->points;
|
|
|
|
if (!spnt || !seg_count)
|
|
return; /* no-line */
|
|
|
|
line_pnts = (fp_pnt) g_new0 (gdouble, 2 * seg_count + 1);
|
|
|
|
/* Go around all the points drawing a line from one to the next */
|
|
while (spnt)
|
|
{
|
|
draw_sqr (&spnt->pnt);
|
|
line_pnts[i][0] = spnt->pnt.x;
|
|
line_pnts[i++][1] = spnt->pnt.y;
|
|
spnt = spnt->next;
|
|
}
|
|
|
|
/* Generate an array of doubles which are the control points */
|
|
|
|
if (!drawing_pic && bezier_line_frame && tmp_bezier)
|
|
{
|
|
fp_pnt_start ();
|
|
DrawBezier (line_pnts, seg_count, 0.5, 0);
|
|
d_bz_line ();
|
|
}
|
|
|
|
fp_pnt_start ();
|
|
DrawBezier (line_pnts, seg_count, 0.5, 3);
|
|
d_bz_line ();
|
|
/*bezier4 (line_pnts, seg_count, 20);*/
|
|
|
|
g_free (line_pnts);
|
|
}
|
|
|
|
static void
|
|
d_paint_bezier (Dobject *obj)
|
|
{
|
|
gdouble *line_pnts;
|
|
gdouble (*bz_line_pnts)[2];
|
|
DobjPoints *spnt;
|
|
gint seg_count = 0;
|
|
|
|
gint i = 0;
|
|
|
|
spnt = obj->points;
|
|
|
|
/* First count the number of points */
|
|
|
|
/* count */
|
|
while (spnt)
|
|
{
|
|
seg_count++;
|
|
spnt = spnt->next;
|
|
}
|
|
|
|
spnt = obj->points;
|
|
|
|
if (!spnt || !seg_count)
|
|
return; /* no-line */
|
|
|
|
bz_line_pnts = (fp_pnt) g_new0 (gdouble, 2 * seg_count + 1);
|
|
|
|
/* Go around all the points drawing a line from one to the next */
|
|
while (spnt)
|
|
{
|
|
bz_line_pnts[i][0] = spnt->pnt.x;
|
|
bz_line_pnts[i++][1] = spnt->pnt.y;
|
|
spnt = spnt->next;
|
|
}
|
|
|
|
fp_pnt_start ();
|
|
DrawBezier (bz_line_pnts, seg_count, 0.5, 5);
|
|
line_pnts = d_bz_get_array (&i);
|
|
|
|
/* Reverse line if approp */
|
|
if (selvals.reverselines)
|
|
reverse_pairs_list (&line_pnts[0], i / 2);
|
|
|
|
/* Scale before drawing */
|
|
if (selvals.scaletoimage)
|
|
scale_to_original_xy (&line_pnts[0], i / 2);
|
|
else
|
|
scale_to_xy (&line_pnts[0], i / 2);
|
|
|
|
/* One go */
|
|
if (selvals.painttype == PAINT_BRUSH_TYPE)
|
|
{
|
|
gfig_paint (selvals.brshtype,
|
|
gfig_drawable,
|
|
i, line_pnts);
|
|
}
|
|
else
|
|
{
|
|
gimp_free_select (gfig_image,
|
|
i, line_pnts,
|
|
selopt.type,
|
|
selopt.antia,
|
|
selopt.feather,
|
|
selopt.feather_radius);
|
|
}
|
|
|
|
g_free (bz_line_pnts);
|
|
/* Don't free line_pnts - may need again */
|
|
}
|
|
|
|
static Dobject *
|
|
d_copy_bezier (Dobject * obj)
|
|
{
|
|
Dobject *np;
|
|
|
|
#if DEBUG
|
|
printf ("Copy bezier\n");
|
|
#endif /*DEBUG*/
|
|
if (!obj)
|
|
return (NULL);
|
|
|
|
g_assert (obj->type == BEZIER);
|
|
|
|
np = d_new_bezier (obj->points->pnt.x, obj->points->pnt.y);
|
|
|
|
np->points->next = d_copy_dobjpoints (obj->points->next);
|
|
|
|
np->type_data = obj->type_data;
|
|
|
|
#if DEBUG
|
|
printf ("Done bezier copy\n");
|
|
#endif /*DEBUG*/
|
|
return np;
|
|
}
|
|
|
|
static Dobject *
|
|
d_new_bezier (gint x, gint y)
|
|
{
|
|
Dobject *nobj;
|
|
DobjPoints *npnt;
|
|
|
|
/* Get new object and starting point */
|
|
|
|
/* Start point */
|
|
npnt = g_new0 (DobjPoints, 1);
|
|
|
|
#if DEBUG
|
|
printf ("New BEZIER start at (%x,%x)\n", x, y);
|
|
#endif /* DEBUG */
|
|
npnt->pnt.x = x;
|
|
npnt->pnt.y = y;
|
|
|
|
nobj = g_new0 (Dobject, 1);
|
|
|
|
nobj->type = BEZIER;
|
|
nobj->type_data = (gpointer)4; /* Default to four turns */
|
|
nobj->points = npnt;
|
|
nobj->drawfunc = d_draw_bezier;
|
|
nobj->loadfunc = d_load_bezier;
|
|
nobj->savefunc = d_save_bezier;
|
|
nobj->paintfunc = d_paint_bezier;
|
|
nobj->copyfunc = d_copy_bezier;
|
|
|
|
return (nobj);
|
|
}
|
|
|
|
static void
|
|
d_update_bezier (GdkPoint *pnt)
|
|
{
|
|
DobjPoints *s_pnt, *l_pnt;
|
|
gint saved_cnt_pnt = selvals.opts.showcontrol;
|
|
|
|
g_assert (tmp_bezier != NULL);
|
|
|
|
/* Undraw last one then draw new one */
|
|
s_pnt = tmp_bezier->points;
|
|
|
|
if (!s_pnt)
|
|
return; /* No points */
|
|
|
|
/* Hack - turn off cnt points in draw routine
|
|
*/
|
|
|
|
if ((l_pnt = s_pnt->next))
|
|
{
|
|
/* Undraw */
|
|
while (l_pnt->next)
|
|
{
|
|
l_pnt = l_pnt->next;
|
|
}
|
|
|
|
draw_circle (&l_pnt->pnt);
|
|
selvals.opts.showcontrol = 0;
|
|
d_draw_bezier (tmp_bezier);
|
|
l_pnt->pnt.x = pnt->x;
|
|
l_pnt->pnt.y = pnt->y;
|
|
}
|
|
else
|
|
{
|
|
/* Radius is a few pixels away */
|
|
/* First edge point */
|
|
d_pnt_add_line (tmp_bezier, pnt->x, pnt->y,-1);
|
|
l_pnt = s_pnt->next;
|
|
}
|
|
|
|
/* draw it */
|
|
selvals.opts.showcontrol = 0;
|
|
d_draw_bezier (tmp_bezier);
|
|
selvals.opts.showcontrol = saved_cnt_pnt;
|
|
|
|
/* Realy draw the control points */
|
|
draw_circle (&l_pnt->pnt);
|
|
}
|
|
|
|
/* first point is center
|
|
* next defines the radius
|
|
*/
|
|
|
|
static void
|
|
d_bezier_start (GdkPoint *pnt, gint shift_down)
|
|
{
|
|
gint16 x, y;
|
|
/* First is center point */
|
|
if (!tmp_bezier)
|
|
{
|
|
/* New curve */
|
|
tmp_bezier = obj_creating = d_new_bezier (x = pnt->x, y = pnt->y);
|
|
}
|
|
}
|
|
|
|
static void
|
|
d_bezier_end (GdkPoint *pnt, gint shift_down)
|
|
{
|
|
DobjPoints *l_pnt;
|
|
|
|
if (!tmp_bezier)
|
|
{
|
|
tmp_bezier = obj_creating;
|
|
}
|
|
|
|
l_pnt = tmp_bezier->points->next;
|
|
|
|
if (!l_pnt)
|
|
return;
|
|
|
|
if (shift_down)
|
|
{
|
|
/* Undraw circle on last pnt */
|
|
while (l_pnt->next)
|
|
{
|
|
l_pnt = l_pnt->next;
|
|
}
|
|
|
|
if (l_pnt)
|
|
{
|
|
draw_circle (&l_pnt->pnt);
|
|
draw_sqr (&l_pnt->pnt);
|
|
|
|
if (bezier_closed)
|
|
{
|
|
gint tmp_frame = bezier_line_frame;
|
|
/* if closed then add first point */
|
|
d_draw_bezier (tmp_bezier);
|
|
d_pnt_add_line (tmp_bezier,
|
|
tmp_bezier->points->pnt.x,
|
|
tmp_bezier->points->pnt.y,-1);
|
|
/* Final has no frame */
|
|
bezier_line_frame = 0; /* False */
|
|
d_draw_bezier (tmp_bezier);
|
|
bezier_line_frame = tmp_frame; /* What is was */
|
|
}
|
|
else if (bezier_line_frame)
|
|
{
|
|
d_draw_bezier (tmp_bezier);
|
|
bezier_line_frame = 0; /* False */
|
|
d_draw_bezier (tmp_bezier);
|
|
bezier_line_frame = 1; /* What is was */
|
|
}
|
|
|
|
add_to_all_obj (current_obj, obj_creating);
|
|
}
|
|
|
|
/* small mem leak if !l_pnt ? */
|
|
tmp_bezier = NULL;
|
|
obj_creating = NULL;
|
|
}
|
|
else
|
|
{
|
|
if (!tmp_bezier->points->next)
|
|
{
|
|
draw_circle (&tmp_bezier->points->pnt);
|
|
draw_sqr (&tmp_bezier->points->pnt);
|
|
}
|
|
|
|
d_draw_bezier (tmp_bezier);
|
|
d_pnt_add_line (tmp_bezier, pnt->x, pnt->y,-1);
|
|
d_draw_bezier (tmp_bezier);
|
|
}
|
|
}
|
|
|
|
|
|
/* copy objs */
|
|
static DAllObjs *
|
|
copy_all_objs (DAllObjs *objs)
|
|
{
|
|
DAllObjs *nobj;
|
|
DAllObjs *new_all_objs = NULL;
|
|
DAllObjs *ret = NULL;
|
|
|
|
while (objs)
|
|
{
|
|
nobj = g_new0 (DAllObjs, 1);
|
|
|
|
if (!ret)
|
|
{
|
|
ret = new_all_objs = nobj;
|
|
}
|
|
else
|
|
{
|
|
new_all_objs->next = nobj;
|
|
new_all_objs = nobj;
|
|
}
|
|
|
|
nobj->obj = (Dobject *) objs->obj->copyfunc (objs->obj);
|
|
|
|
objs = objs->next;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Screen refresh */
|
|
static void
|
|
draw_one_obj (Dobject * obj)
|
|
{
|
|
obj->drawfunc (obj);
|
|
}
|
|
|
|
static void
|
|
draw_objects (DAllObjs *objs,
|
|
gint show_single)
|
|
{
|
|
/* Show_single - only one object to draw Unless shift
|
|
* is down in whcih case show all.
|
|
*/
|
|
|
|
gint count = 0;
|
|
|
|
while (objs)
|
|
{
|
|
if (!show_single || count == obj_show_single || obj_show_single == -1)
|
|
draw_one_obj (objs->obj);
|
|
objs = objs->next;
|
|
count++;
|
|
}
|
|
}
|
|
|
|
static void
|
|
prepend_to_all_obj (GFigObj *fobj,
|
|
DAllObjs *nobj)
|
|
{
|
|
DAllObjs *cobj;
|
|
|
|
setup_undo (); /* Remember ME */
|
|
|
|
if (!fobj->obj_list)
|
|
{
|
|
fobj->obj_list = nobj;
|
|
return;
|
|
}
|
|
|
|
cobj = fobj->obj_list;
|
|
|
|
while (cobj->next)
|
|
{
|
|
cobj = cobj->next;
|
|
}
|
|
|
|
cobj->next = nobj;
|
|
}
|
|
|
|
static void
|
|
add_to_all_obj (GFigObj *fobj,
|
|
Dobject *obj)
|
|
{
|
|
DAllObjs *nobj;
|
|
|
|
nobj = g_new0 (DAllObjs, 1);
|
|
|
|
nobj->obj = obj;
|
|
|
|
if (need_to_scale)
|
|
scale_obj_points (obj->points, scale_x_factor, scale_y_factor);
|
|
|
|
prepend_to_all_obj (fobj, nobj);
|
|
}
|
|
|
|
static void
|
|
object_operation_start (GdkPoint *pnt,
|
|
gint shift_down)
|
|
{
|
|
Dobject *new_obj;
|
|
|
|
/* Find point in given object list */
|
|
operation_obj = get_nearest_objs (current_obj, pnt);
|
|
|
|
/* Special case if shift down && move obj then moving all objs */
|
|
|
|
if (shift_down && selvals.otype == MOVE_OBJ)
|
|
{
|
|
move_all_pnt = g_malloc0 (sizeof (*move_all_pnt));
|
|
*move_all_pnt = *pnt; /* Structure copy */
|
|
setup_undo ();
|
|
return;
|
|
}
|
|
|
|
if (!operation_obj)
|
|
return;/* None to work on */
|
|
|
|
setup_undo ();
|
|
|
|
switch (selvals.otype)
|
|
{
|
|
case MOVE_OBJ:
|
|
if (operation_obj->type == BEZIER)
|
|
{
|
|
d_draw_bezier (operation_obj);
|
|
tmp_bezier = operation_obj;
|
|
d_draw_bezier (operation_obj);
|
|
}
|
|
break;
|
|
case MOVE_POINT:
|
|
if (operation_obj->type == BEZIER)
|
|
{
|
|
d_draw_bezier (operation_obj);
|
|
tmp_bezier = operation_obj;
|
|
d_draw_bezier (operation_obj);
|
|
}
|
|
/* If shift is down the break into sep lines */
|
|
if ((operation_obj->type == POLY
|
|
|| operation_obj->type == STAR)
|
|
&& shift_down)
|
|
{
|
|
switch (operation_obj->type)
|
|
{
|
|
case POLY:
|
|
d_poly2lines (operation_obj);
|
|
break;
|
|
case STAR:
|
|
d_star2lines (operation_obj);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
/* Re calc which object point we are lookin at */
|
|
scan_obj_points (operation_obj->points, pnt);
|
|
}
|
|
break;
|
|
case COPY_OBJ:
|
|
/* Copy the "operation object" */
|
|
/* Then bung us into "copy/move" mode */
|
|
#ifdef DEBUG
|
|
printf ("In copy obj\n");
|
|
#endif /* DEBUG */
|
|
new_obj = (Dobject *) operation_obj->copyfunc (operation_obj);
|
|
if (new_obj)
|
|
{
|
|
scan_obj_points (new_obj->points, pnt);
|
|
add_to_all_obj (current_obj, new_obj);
|
|
operation_obj = new_obj;
|
|
selvals.otype = MOVE_COPY_OBJ;
|
|
new_obj->drawfunc (new_obj);
|
|
}
|
|
break;
|
|
case DEL_OBJ:
|
|
remove_obj_from_list (current_obj, operation_obj);
|
|
break;
|
|
case MOVE_COPY_OBJ: /* Never when button down */
|
|
default:
|
|
g_warning ("Internal error selvals.otype object operation start");
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
object_operation_end (GdkPoint *pnt,
|
|
gint shift_down)
|
|
{
|
|
if (selvals.otype != DEL_OBJ && operation_obj && operation_obj->type == BEZIER)
|
|
{
|
|
d_draw_bezier (operation_obj);
|
|
tmp_bezier = NULL; /* use as switch */
|
|
d_draw_bezier (operation_obj);
|
|
}
|
|
|
|
operation_obj = NULL;
|
|
|
|
if (move_all_pnt)
|
|
{
|
|
g_free (move_all_pnt);
|
|
move_all_pnt = 0;
|
|
}
|
|
|
|
/* Special case - if copying mode MUST be copy when button up received */
|
|
if (selvals.otype == MOVE_COPY_OBJ)
|
|
selvals.otype = COPY_OBJ;
|
|
}
|
|
|
|
/* Move object around */
|
|
static void
|
|
object_operation (GdkPoint *to_pnt,
|
|
gint shift_down)
|
|
{
|
|
/* Must do diffent things depending on object type */
|
|
/* but must have object to operate on! */
|
|
|
|
/* Special case - if shift own and move_obj then move ALL objects */
|
|
if (move_all_pnt && shift_down && selvals.otype == MOVE_OBJ)
|
|
{
|
|
do_move_all_obj (to_pnt);
|
|
return;
|
|
}
|
|
|
|
if (!operation_obj)
|
|
return;
|
|
|
|
switch (selvals.otype)
|
|
{
|
|
case MOVE_OBJ:
|
|
case MOVE_COPY_OBJ:
|
|
switch (operation_obj->type)
|
|
{
|
|
case LINE:
|
|
case CIRCLE:
|
|
case ELLIPSE:
|
|
case POLY:
|
|
case ARC:
|
|
case STAR:
|
|
case SPIRAL:
|
|
case BEZIER:
|
|
do_move_obj (operation_obj, to_pnt);
|
|
break;
|
|
default:
|
|
/* Internal error */
|
|
g_warning ("Internal error in operation_obj->type");
|
|
break;
|
|
}
|
|
break;
|
|
case MOVE_POINT:
|
|
switch (operation_obj->type)
|
|
{
|
|
case LINE:
|
|
case CIRCLE:
|
|
case ELLIPSE:
|
|
case POLY:
|
|
case ARC:
|
|
case STAR:
|
|
case SPIRAL:
|
|
case BEZIER:
|
|
do_move_obj_pnt (operation_obj, to_pnt);
|
|
break;
|
|
default:
|
|
/* Internal error */
|
|
g_warning ("Internal error in operation_obj->type");
|
|
break;
|
|
}
|
|
break;
|
|
case DEL_OBJ:
|
|
break;
|
|
case COPY_OBJ: /* Should have been changed to MOVE_COPY_OBJ */
|
|
default:
|
|
g_warning ("Internal error selvals.otype");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* First button press -- start drawing object */
|
|
static void
|
|
object_start (GdkPoint *pnt,
|
|
gint shift_down)
|
|
{
|
|
/* start for the current object */
|
|
if (!selvals.scaletoimage)
|
|
{
|
|
need_to_scale = 1;
|
|
selvals.scaletoimage = 1;
|
|
}
|
|
else
|
|
{
|
|
need_to_scale = 0;
|
|
}
|
|
|
|
switch (selvals.otype)
|
|
{
|
|
case LINE:
|
|
/* Shift means we are still drawing */
|
|
if (!shift_down || !obj_creating)
|
|
draw_sqr (pnt);
|
|
d_line_start (pnt, shift_down);
|
|
break;
|
|
case CIRCLE:
|
|
draw_sqr (pnt);
|
|
d_circle_start (pnt, shift_down);
|
|
break;
|
|
case ELLIPSE:
|
|
draw_sqr (pnt);
|
|
d_ellipse_start (pnt, shift_down);
|
|
break;
|
|
case POLY:
|
|
draw_sqr (pnt);
|
|
d_poly_start (pnt, shift_down);
|
|
break;
|
|
case ARC:
|
|
d_arc_start (pnt, shift_down);
|
|
break;
|
|
case STAR:
|
|
draw_sqr (pnt);
|
|
d_star_start (pnt, shift_down);
|
|
break;
|
|
case SPIRAL:
|
|
draw_sqr (pnt);
|
|
d_spiral_start (pnt, shift_down);
|
|
break;
|
|
case BEZIER:
|
|
if (!tmp_bezier)
|
|
draw_sqr (pnt);
|
|
d_bezier_start (pnt, shift_down);
|
|
break;
|
|
default:
|
|
/* Internal error */
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Real object now !*/
|
|
static void
|
|
object_end (GdkPoint *pnt,
|
|
gint shift_down)
|
|
{
|
|
/* end for the current object */
|
|
/* Add onto global object list */
|
|
|
|
/* If shift is down may carry on drawing */
|
|
switch (selvals.otype)
|
|
{
|
|
case LINE:
|
|
d_line_end (pnt, shift_down);
|
|
draw_sqr (pnt);
|
|
break;
|
|
case CIRCLE:
|
|
draw_sqr (pnt);
|
|
d_circle_end (pnt, shift_down);
|
|
break;
|
|
case ELLIPSE:
|
|
draw_sqr (pnt);
|
|
d_ellipse_end (pnt, shift_down);
|
|
break;
|
|
case POLY:
|
|
draw_sqr (pnt);
|
|
d_poly_end (pnt, shift_down);
|
|
break;
|
|
case STAR:
|
|
draw_sqr (pnt);
|
|
d_star_end (pnt, shift_down);
|
|
break;
|
|
case ARC:
|
|
draw_sqr (pnt);
|
|
d_arc_end (pnt, shift_down);
|
|
break;
|
|
case SPIRAL:
|
|
draw_sqr (pnt);
|
|
d_spiral_end (pnt, shift_down);
|
|
break;
|
|
case BEZIER:
|
|
d_bezier_end (pnt, shift_down);
|
|
break;
|
|
default:
|
|
/* Internal error */
|
|
break;
|
|
}
|
|
|
|
if (need_to_scale)
|
|
{
|
|
need_to_scale = 0;
|
|
selvals.scaletoimage = 0;
|
|
}
|
|
}
|
|
|
|
static void
|
|
object_update (GdkPoint *pnt)
|
|
{
|
|
/* update for the current object */
|
|
/* New position xy */
|
|
switch (selvals.otype)
|
|
{
|
|
case LINE:
|
|
d_update_line (pnt);
|
|
break;
|
|
case CIRCLE:
|
|
d_update_circle (pnt);
|
|
break;
|
|
case ELLIPSE:
|
|
d_update_ellipse (pnt);
|
|
break;
|
|
case POLY:
|
|
d_update_poly (pnt);
|
|
break;
|
|
case STAR:
|
|
d_update_star (pnt);
|
|
break;
|
|
case ARC:
|
|
d_update_arc (pnt);
|
|
break;
|
|
case SPIRAL:
|
|
d_update_spiral (pnt);
|
|
break;
|
|
case BEZIER:
|
|
d_update_bezier (pnt);
|
|
break;
|
|
default:
|
|
/* Internal error */
|
|
break;
|
|
}
|
|
}
|