Initial checkin of Pika from heckimp

This commit is contained in:
2023-09-25 15:35:21 -07:00
commit 891e999216
6761 changed files with 5240685 additions and 0 deletions

313
plug-ins/gfig/README Normal file
View File

@ -0,0 +1,313 @@
Objects
+++++++
The plug-in allows you to draw the following shapes:-
Lines
Circles
Ellipses
n sided regular polygons (n >=3)
Curves (arcs)
Spirals
N pointed stars
Simple Beizer curves
An object is constructed as a number of control points and these are used
to select the object on the drawing area once it has been created.
The drawing area preview is currently set to
MIN(650 x 650,img_width x img_height).
You can change this altering the PREVIEW_SIZE item in the source code.
Operations
++++++++++
The following operations can be performed on objects:-
The objects can either be moved independently around the drawing area or
all together.
Each control point can be moved.
Objects can be copied.
Objects can be deleted.
N sided Polygons can be split into N line segments. This also works for N
pointed stars.
The drawing area can be scaled.
Control points can be hidden.
To aid alignment of objects a "grid" can be placed on the drawing area.
This can be either a normal rectangular grid or a polar type grid centered
in the drawing area.
The spacings of the grid can be changed as well as the colors used to draw the
grid lines. When "Snap to grid" is checked then all operations will be
constrained to fall on a grid intersection. (Fun when using the polar grid).
Additionally the third mouse button will constrain the point movement to be
on a horiz/vert (for rect grid) or radial/radius (for polar) only when
"Snap to grid" is set.
The image that was selected when Gfig was started can also be shown (scaled) in
the drawing area. (Options tag).
Painting tab
++++++++++++
There are three possible mode when painting.
1) Brush
2) Selection
3) Selection+fill
Brush
~~~~~
When the paint button is pressed each object will be rendered/drawn onto
the image using the currently selected ink color. The objects can be drawn
onto the original layer or onto a new layer (either a single layer or
multiple layers - latter is good for animations). When new layers are
created the background can either be:-
Transparent.
Background (the current BG color).
White.
Copy.
The last option means that the layer is duplicated from the previous layer
before the draw operation is performed (re good for animations).
Lines can be drawn in reverse order. This means that reg polygons/curves/lines
that are normally constructed of lines can be drawn starting at either "end".
This is only noticeable when the current brush has fading turned on.
The "Approx Circles/Ellipses" toggle allows the same effects when drawing these
types of objects.
Note that in the current version any selections present in the image are first
de-selected when Gfig starts up. This is because selections are used to
draw circles and ellipses (unless the Approx. Circles & Ellipses toggle is set).
Selection
~~~~~~~~~
With this method closed selections are made of the objects. See selection
tab for more details.
Selections can only be made on the current layer.
Selection+Fill
~~~~~~~~~~~~~~
This method first selects the objects and then fills the selection area. The
selection tab gives more details on how the selections are filled.
Brush Tab
+++++++++
This tab now contains a preview of the selected brush in black ink. If the
brush is too large to fit in the preview use the mouse button to "move" it
around (as with the brush dialog in the main PIKA - until that brush
patch went in!).
Four types of brush can be used:-
Normal brush
~~~~~~~~~~~~
Simply paints with the current brush - honors fading if any
The Fade option allows the "brush fading" to be selected. I am sure that some
nifty anims can be created with this option.
Pencil brush
~~~~~~~~~~~~
Same as the PIKAS pencil.
Airbrush
~~~~~~~~
As PIKAS airbrush. The "pressure" can be specified and this is reflected in the
preview window.
Pattern
~~~~~~~
The lines are drawn with the currently selected pattern. The preview will
show this pattern.
Note a patch to enable a couple of "hidden" paintbrush features was recently
posted to the PIKA developers list. The patch only allowed these features
to be called via the UI and not the PDB so they cannot be used by Gfig. If they were exported via the PDB then they would have probably broken a number of
scripts and Gfig itself (number of args changes on the PDB call).
Select tab
++++++++++
This is enabled when using either Selection or Selection+fill types when
painting objects.
The anti aliasing and feather toggles apply to the selection made when
"painting" the objects. The feather radius can be changed.
The default selection mode is to add to the current selection so each object
add to the overall selection. The other selection modes are also possible
but you must bear in mind the following:-
Subtraction/Intersection will not produce any selection if no selection is
elect the area in the target window (AFTER starting Gfig up) and then paint
using this method.
Replace will leave only the last object selection.
When the paint type is selection+fill then the objects will be selected
and then filled. The opacity of the fill can be chosen. By default a fill
is performed after each section. If filling onto a single layer
then the fill will accumulate on the first objects painted. This will be
noticeable when opacity != 100. To get around this then use replace mode
OR use a new layer for each selection/fill. (Paint tab). Additionally you can
set the fill to be performed after ALL objects have been selected (useful
for intersection type selections).
Selection of non-closed objects
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For objects that are not closed the first & last points will be joined
together to form the closed selection. For arcs you can either fill
as segments or sectors. Note straight lines will not cause any selection to be
made. This can be a little confusing when filling since the whole canvas will
be filled if any straight lines are present on it.
Scaling
+++++++
When Gfig first comes up the selected group of objects are automatically scaled
upwards to the image size. (If the source image is < 256*256 then no automatic
scaling is performed - change PREVIEW_SIZE in source to alter this values).
By toggling the scale button the objects can then be scaled in the drawing
area. This scaling will be reflected when the objects are drawn.
To reposition the objects on the drawing area use SHIFT + MOVE_OBJ operation.
Other ops
+++++++++
Double click on reg polygon object selection to get dialog with slider to
selected the number of sides to draw.
Double click on star object selection to get dialog with slider to
selected the number of points the star will have.
Double click on spiral object selection to get dialog with slider to
selected the number of turns the spiral will have and it direction.
Double click on bezier object selection to get dialog which allows you to
control how the curve is displayed and if it is closed.
SHIFT + MOVE_PNT will break a reg polygon or star into a number of
connected lines.
When drawing lines if the SHIFT modifier is used then connected lines
can be drawn.
SHIFT + MOVE_OBJ will move all objects. Note if "snap to grid" is selected then
the new point will be constrained to fall on a grid intersection.
Mouse button 3 + "snap to grid" will constrain the point to fall on one of the
two gridlines it was originally on.
The ">" and "<" buttons allow you to selective move through each of the
objects in the collection. The "==" returns the display to normal. If the
"paint" button is pressed then only the single object displayed will be
drawn into the target window. Also when in this mode pressing the shift button
will temporarily show all the objects in the collection.
The the options tab there is now a toggle that allows you to turn the
position display on and off.
Gfig objects
++++++++++++
The upper right part of gfig contains a scroll region when different
collection of objects can be found. When button 1 is pressed on an entry
the small preview window will be updated with the objects contained in
the selected figure. These objects can then be loaded into the main window
by using the "Edit" button or the "Merge" button. In the former case
the objects area will first be cleared before the new objects
are added. In the latter case the objects will be merged into the drawing area.
When a collection of objects is altered to small image of a floppy disc
will be placed next to the entry signifying that this collection needs to be
saved. If a red cross appears here then the file associated with the
entry is read only and cannot be saved to (it can be copied however).
Button 3 brings up a popup menu that allows collections to be saved away to
different files. (Accel. keys also exist for some functions).
The buttons on the right of the list area allow the following operations:-
Rescan:-
This popus up a window which allows you to add directories to the internal
gfig-path. A (re)scan of these directories can the performed. Note any
modification to the gfig-path will NOT be mirrored in your ~/.pika/pikarc file.
Load:-
Allows you to load a single collection of objects.
New:-
Create a new collection. Note that until this is saved away to a file then no
filename will be associated with it. (See status area).
Delete:-
Popups a dialog asking if you wish to delete the entry selected in the list
box as well as on disc.
Additionally button 3 over the list area allows the following:-
Save as...:-
Save collection to new filename. The collections filename is also
changed to this new name. The original name is NOT deleted from the disc
but it is effectively removed from the list selection area (actually it
is overwritten internally).
Save:-
Save the currently selected entry to disc.
Copy:-
Make a copy of the collection.
Edit:-
Same as the "Edit button".
Double click on entry with Button 1 popups up a dialog that allows you to
modify the nme of an entry (similar to other list areas in PIKA).
Bezier
~~~~~~
OK my maths is a little rusty. The bezier stuff is only very simple. However...
I have tried to abstract as much as possible the bezier calculations from
the drawing of the control points / painting on the screen and in the target
window.
The bezier function is defined as:-
void
DrawBezier (gdouble (*points)[2], gint np, gdouble mid, gint depth)
{
...
}
Points an array of pairs of doubles that define the control points
np is the number of points. Mid is always starts as 0.5 - and depth
defines how deep the recursion should go when calculating the line points.
The function should call fp_pnt_add() when a point on the curve has been
calculated.
If anyone would like to produce a better/faster function then you
should be able to replace the DrawBezier function. (Only the first two args
are really needed).
The algorithm the current code is based on was obtained by looking
at the many many examples out on the web.
(Bezier drawing seems to be topic of the year for computer degrees
and people learning java!!!)

738
plug-ins/gfig/gfig-arc.c Normal file
View File

@ -0,0 +1,738 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <math.h>
#include <stdlib.h>
#include <gtk/gtk.h>
#include <libpika/pika.h>
#include "gfig.h"
#include "gfig-dobject.h"
#include "gfig-arc.h"
#include "libpika/stdplugins-intl.h"
static gdouble dist (gdouble x1,
gdouble y1,
gdouble x2,
gdouble y2);
static void mid_point (gdouble x1,
gdouble y1,
gdouble x2,
gdouble y2,
gdouble *mx,
gdouble *my);
static gdouble line_grad (gdouble x1,
gdouble y1,
gdouble x2,
gdouble y2);
static gdouble line_cons (gdouble x,
gdouble y,
gdouble lgrad);
static void line_definition (gdouble x1,
gdouble y1,
gdouble x2,
gdouble y2,
gdouble *lgrad,
gdouble *lconst);
static void arc_details (GdkPoint *vert_a,
GdkPoint *vert_b,
GdkPoint *vert_c,
GdkPoint *center_pnt,
gdouble *radius);
static gdouble arc_angle (GdkPoint *pnt,
GdkPoint *center);
static void arc_drawing_details (GfigObject *obj,
gdouble *minang,
GdkPoint *center_pnt,
gdouble *arcang,
gdouble *radius,
gboolean draw_cnts,
gboolean do_scale);
static void d_draw_arc (GfigObject *obj,
cairo_t *cr);
static void d_paint_arc (GfigObject *obj);
static GfigObject *d_copy_arc (GfigObject *obj);
static void d_update_arc_line (GdkPoint *pnt);
static void d_update_arc (GdkPoint *pnt);
static void d_arc_line_start (GdkPoint *pnt,
gboolean shift_down);
static void d_arc_line_end (PikaGfig *gfig,
GdkPoint *pnt,
gboolean shift_down);
/* Distance between two points. */
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 = (x1 + x2) / 2.0;
*my = (y1 + y2) / 2.0;
}
/* 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;
return (dx == 0.0) ? 0.0 : 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 = 0, line1_const = 0;
double line2_grad = 0, line2_const = 0;
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);
len_a = dist (ax, ay, bx, by);
len_b = dist (bx, by, cx, cy);
len_c = dist (cx, cy, ax, ay);
sum_sides2 = (fabs (len_a) + fabs (len_b) + fabs (len_c))/2;
/* Area */
area = sqrt (sum_sides2 * (sum_sides2 - len_a) *
(sum_sides2 - len_b) *
(sum_sides2 - len_c));
/* Circumcircle */
circumcircle_R = len_a * len_b * len_c / (4 * area);
*radius = circumcircle_R;
/* 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 (ay == by && by == cy)
{
/* 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 = (line2_const - line1_const) / (line1_grad - line2_grad);
if (!got_y)
inter_y = line1_grad * inter_x + line1_const;
center_pnt->x = (gint) inter_x;
center_pnt->y = (gint) inter_y;
}
static gdouble
arc_angle (GdkPoint *pnt,
GdkPoint *center)
{
/* Get angle (in degrees) 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);
if (offset_angle < 0)
offset_angle += 2.0 * G_PI;
return offset_angle * 360 / (2.0 * G_PI);
}
static void
arc_drawing_details (GfigObject *obj,
gdouble *minang,
GdkPoint *center_pnt,
gdouble *arcang,
gdouble *radius,
gboolean draw_cnts,
gboolean 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 (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 (GfigObject *obj,
cairo_t *cr)
{
DobjPoints *pnt1, *pnt2, *pnt3;
GdkPoint center_pnt;
gdouble radius, minang, arcang;
g_assert (obj != NULL);
if (!obj)
return;
pnt1 = obj->points;
pnt2 = pnt1 ? pnt1->next : NULL;
pnt3 = pnt2 ? pnt2->next : NULL;
if (! pnt3)
return;
draw_sqr (&pnt1->pnt, obj == gfig_context->selected_obj, cr);
draw_sqr (&pnt2->pnt, obj == gfig_context->selected_obj, cr);
draw_sqr (&pnt3->pnt, obj == gfig_context->selected_obj, cr);
arc_drawing_details (obj, &minang, &center_pnt, &arcang, &radius,
TRUE, FALSE);
gfig_draw_arc (center_pnt.x, center_pnt.y, radius, radius, -minang, -(minang + arcang), cr);
}
static void
d_paint_arc (GfigObject *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 last_pnt = { 0, 0 };
gboolean first = TRUE;
GdkPoint center_pnt;
gdouble minang, arcang;
g_assert (obj != NULL);
if (!obj)
return;
/* No cnt pnts & must scale */
arc_drawing_details (obj, &minang, &center_pnt, &arcang, &radius,
FALSE, TRUE);
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.0 * G_PI / 360.0;
if (arcang < 0.0)
{
/* Swap - since we always draw anti-clock wise */
minang += arcang;
arcang = -arcang;
}
minang = minang * (2.0 * G_PI / 360.0); /* 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 = RINT (lx + center_pnt.x);
calc_pnt.y = 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;
}
}
line_pnts[i++] = calc_pnt.x;
line_pnts[i++] = calc_pnt.y;
last_pnt = calc_pnt;
if (first)
{
first = FALSE;
}
}
/* One go */
if (obj->style.paint_type == PAINT_BRUSH_TYPE)
{
gfig_paint (selvals.brshtype,
gfig_context->drawable,
i, line_pnts);
}
g_free (line_pnts);
}
static GfigObject *
d_copy_arc (GfigObject *obj)
{
GfigObject *nc;
g_assert (obj->type == ARC);
nc = d_new_object (ARC, obj->points->pnt.x, obj->points->pnt.y);
nc->points->next = d_copy_dobjpoints (obj->points->next);
return nc;
}
void
d_arc_object_class_init (void)
{
GfigObjectClass *class = &dobj_class[ARC];
class->type = ARC;
class->name = "ARC";
class->drawfunc = d_draw_arc;
class->paintfunc = d_paint_arc;
class->copyfunc = d_copy_arc;
class->update = d_update_arc;
}
/* Update end point of line */
static void
d_update_arc_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))
{
g_free (epnt);
}
epnt = new_dobjpoint (pnt->x, pnt->y);
spnt->next = epnt;
}
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_arc_line (pnt);
return; /* Not fully drawn */
}
/* Update a real curve */
/* Nothing to be done ... */
}
static void
d_arc_line_start (GdkPoint *pnt,
gboolean shift_down)
{
if (!obj_creating || !shift_down)
{
/* Must delete obj_creating if we have one */
obj_creating = d_new_object (LINE, pnt->x, pnt->y);
}
else
{
/* Contniuation */
d_update_arc_line (pnt);
}
}
void
d_arc_start (GdkPoint *pnt,
gboolean shift_down)
{
/* Draw lines to start with -- then convert to an arc */
d_arc_line_start (pnt, TRUE); /* TRUE means multiple pointed line */
}
static void
d_arc_line_end (PikaGfig *gfig,
GdkPoint *pnt,
gboolean shift_down)
{
if (shift_down)
{
if (tmp_line)
{
GdkPoint tmp_pnt = *pnt;
if (need_to_scale)
{
tmp_pnt.x = pnt->x * scale_x_factor;
tmp_pnt.y = 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 (gfig, gfig_context->current_obj, obj_creating);
}
obj_creating = d_new_object (LINE, pnt->x, pnt->y);
}
else
{
if (tmp_line)
{
GdkPoint tmp_pnt = *pnt;
if (need_to_scale)
{
tmp_pnt.x = pnt->x * scale_x_factor;
tmp_pnt.y = 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 (gfig, gfig_context->current_obj, obj_creating);
}
obj_creating = NULL;
tmp_line = NULL;
}
/*gtk_widget_queue_draw (gfig_context->preview);*/
}
void
d_arc_end (PikaGfig *gfig,
GdkPoint *pnt,
gboolean shift_down)
{
/* Under control point */
if (!tmp_line ||
!tmp_line->points ||
!tmp_line->points->next)
{
/* No arc created - yet. Must have three points */
d_arc_line_end (gfig, pnt, TRUE);
}
else
{
/* Complete arc */
/* Convert to an arc ... */
tmp_line->type = ARC;
tmp_line->class = &dobj_class[ARC];
d_arc_line_end (gfig, pnt, FALSE);
if (need_to_scale)
{
selvals.scaletoimage = 0;
}
gtk_widget_queue_draw (gfig_context->preview);
if (need_to_scale)
{
selvals.scaletoimage = 1;
}
}
}

37
plug-ins/gfig/gfig-arc.h Normal file
View File

@ -0,0 +1,37 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef __GFIG_ARC_H__
#define __GFIG_ARC_H__
void d_arc_object_class_init (void);
void d_arc_start (GdkPoint *pnt,
gboolean shift_down);
void d_arc_end (PikaGfig *gfig,
GdkPoint *pnt,
gboolean shift_down);
#endif /* __GFIG_ARC_H__ */

423
plug-ins/gfig/gfig-bezier.c Normal file
View File

@ -0,0 +1,423 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <libpika/pika.h>
#include <libpika/pikaui.h>
#include "gfig.h"
#include "gfig-line.h"
#include "gfig-dobject.h"
#include "gfig-dialog.h"
#include "gfig-bezier.h"
#include "libpika/stdplugins-intl.h"
#define FP_PNT_MAX 10
typedef gdouble (*fp_pnt)[2];
static gboolean bezier_closed = FALSE;
static gboolean bezier_line_frame = FALSE;
static int fp_pnt_cnt = 0;
static int fp_pnt_chunk = 0;
static gdouble *fp_pnt_pnts = NULL;
GfigObject *tmp_bezier; /* Needed when drawing bezier curves */
static void fp_pnt_start (void);
static void fp_pnt_add (gdouble p1,
gdouble p2,
gdouble p3,
gdouble p4);
static gdouble *d_bz_get_array (gint *sz);
static void d_bz_line (cairo_t *cr);
static void DrawBezier (fp_pnt points,
gint np,
gdouble mid,
gint depth);
static void d_paint_bezier (GfigObject *obj);
static GfigObject *d_copy_bezier (GfigObject *obj);
static void d_update_bezier (GdkPoint *pnt);
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 = g_renew (gdouble, fp_pnt_pnts, 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 (cairo_t *cr)
{
gint i, x0, y0, x1, y1;
g_assert ((fp_pnt_cnt % 4) == 0);
for (i = 0 ; i < fp_pnt_cnt; i += 4)
{
x0 = fp_pnt_pnts[i];
y0 = fp_pnt_pnts[i + 1];
x1 = fp_pnt_pnts[i + 2];
y1 = fp_pnt_pnts[i + 3];
gfig_draw_line (x0, y0, x1, y1, cr);
}
}
/* Return points to plot */
/* Terminate by point with DBL_MAX, DBL_MAX */
static void
DrawBezier (fp_pnt points,
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);
}
}
}
void
d_draw_bezier (GfigObject *obj,
cairo_t *cr)
{
DobjPoints *spnt;
gint seg_count = 0;
gint i = 0;
gdouble (*line_pnts)[2];
spnt = obj->points;
/* First count the number of points */
for (spnt = obj->points; spnt; spnt = spnt->next)
seg_count++;
if (!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 */
for (spnt = obj->points; spnt; spnt = spnt->next)
{
if (! spnt->next && obj == obj_creating)
draw_circle (&spnt->pnt, TRUE, cr);
else
draw_sqr (&spnt->pnt, obj == gfig_context->selected_obj, cr);
line_pnts[i][0] = spnt->pnt.x;
line_pnts[i][1] = spnt->pnt.y;
i++;
}
/* Generate an array of doubles which are the control points */
if (bezier_line_frame && tmp_bezier)
{
fp_pnt_start ();
DrawBezier (line_pnts, seg_count, 0.5, 0);
d_bz_line (cr);
}
fp_pnt_start ();
DrawBezier (line_pnts, seg_count, 0.5, 3);
d_bz_line (cr);
g_free (line_pnts);
}
static void
d_paint_bezier (GfigObject *obj)
{
gdouble *line_pnts;
gdouble (*bz_line_pnts)[2];
DobjPoints *spnt;
gint seg_count = 0;
gint i = 0;
/* First count the number of points */
for (spnt = obj->points; spnt; spnt = spnt->next)
seg_count++;
if (!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 */
for (spnt = obj->points; spnt; spnt = spnt->next)
{
bz_line_pnts[i][0] = spnt->pnt.x;
bz_line_pnts[i][1] = spnt->pnt.y;
i++;
}
fp_pnt_start ();
DrawBezier (bz_line_pnts, seg_count, 0.5, 5);
line_pnts = d_bz_get_array (&i);
/* 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 (obj->style.paint_type == PAINT_BRUSH_TYPE)
{
gfig_paint (selvals.brshtype,
gfig_context->drawable,
i, line_pnts);
}
g_free (bz_line_pnts);
/* Don't free line_pnts - may need again */
}
static GfigObject *
d_copy_bezier (GfigObject *obj)
{
GfigObject *np;
g_assert (obj->type == BEZIER);
np = d_new_object (BEZIER, obj->points->pnt.x, obj->points->pnt.y);
np->points->next = d_copy_dobjpoints (obj->points->next);
np->type_data = obj->type_data;
return np;
}
void
d_bezier_object_class_init (void)
{
GfigObjectClass *class = &dobj_class[BEZIER];
class->type = BEZIER;
class->name = "BEZIER";
class->drawfunc = d_draw_bezier;
class->paintfunc = d_paint_bezier;
class->copyfunc = d_copy_bezier;
class->update = d_update_bezier;
}
static void
d_update_bezier (GdkPoint *pnt)
{
DobjPoints *s_pnt, *l_pnt;
g_assert (tmp_bezier != NULL);
s_pnt = tmp_bezier->points;
if (!s_pnt)
return; /* No points */
if ((l_pnt = s_pnt->next))
{
while (l_pnt->next)
{
l_pnt = l_pnt->next;
}
l_pnt->pnt = *pnt;
}
else
{
/* Radius is a few pixels away */
/* First edge point */
d_pnt_add_line (tmp_bezier, pnt->x, pnt->y,-1);
}
}
void
d_bezier_start (GdkPoint *pnt,
gboolean shift_down)
{
if (!tmp_bezier)
{
/* New curve */
tmp_bezier = obj_creating = d_new_object (BEZIER, pnt->x, pnt->y);
}
}
void
d_bezier_end (PikaGfig *gfig,
GdkPoint *pnt,
gboolean 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)
{
while (l_pnt->next)
{
l_pnt = l_pnt->next;
}
if (l_pnt)
{
if (bezier_closed)
{
/* if closed then add first point */
d_pnt_add_line (tmp_bezier,
tmp_bezier->points->pnt.x,
tmp_bezier->points->pnt.y, -1);
}
add_to_all_obj (gfig, gfig_context->current_obj, obj_creating);
}
/* small mem leak if !l_pnt ? */
tmp_bezier = NULL;
obj_creating = NULL;
}
else
{
d_pnt_add_line (tmp_bezier, pnt->x, pnt->y,-1);
}
}
void
tool_options_bezier (GtkWidget *notebook)
{
GtkWidget *vbox;
GtkWidget *toggle;
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, NULL);
gtk_widget_show (vbox);
toggle = gtk_check_button_new_with_label (_("Closed"));
g_signal_connect (toggle, "toggled",
G_CALLBACK (pika_toggle_button_update),
&bezier_closed);
pika_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"));
g_signal_connect (toggle, "toggled",
G_CALLBACK (pika_toggle_button_update),
&bezier_line_frame);
pika_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);
}

View File

@ -0,0 +1,43 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef __GFIG_BEZIER_H__
#define __GFIG_BEZIER_H__
extern GfigObject *tmp_bezier;
void d_draw_bezier (GfigObject *obj,
cairo_t *cr);
void d_bezier_object_class_init (void);
void d_bezier_start (GdkPoint *pnt,
gboolean shift_down);
void d_bezier_end (PikaGfig *gfig,
GdkPoint *pnt,
gboolean shift_down);
void tool_options_bezier (GtkWidget *notebook);
#endif /* __GFIG_BEZIER_H__ */

235
plug-ins/gfig/gfig-circle.c Normal file
View File

@ -0,0 +1,235 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <libpika/pika.h>
#include <libpika/pikaui.h>
#include "gfig.h"
#include "gfig-dobject.h"
#include "gfig-poly.h"
#include "gfig-circle.h"
#include "libpika/stdplugins-intl.h"
static gint calc_radius (GdkPoint *center,
GdkPoint *edge);
static void d_draw_circle (GfigObject *obj,
cairo_t *cr);
static void d_paint_circle (GfigObject *obj);
static GfigObject *d_copy_circle (GfigObject *obj);
static void d_update_circle (GdkPoint *pnt);
static gint
calc_radius (GdkPoint *center, GdkPoint *edge)
{
gint dx = center->x - edge->x;
gint dy = center->y - edge->y;
return (gint) sqrt (dx * dx + dy * dy);
}
static void
d_draw_circle (GfigObject *obj,
cairo_t *cr)
{
DobjPoints *center_pnt;
DobjPoints *edge_pnt;
gint radius;
center_pnt = obj->points;
if (!center_pnt)
return; /* End-of-line */
draw_sqr (&center_pnt->pnt, obj == gfig_context->selected_obj, cr);
edge_pnt = center_pnt->next;
if (!edge_pnt)
return;
radius = calc_radius (&center_pnt->pnt, &edge_pnt->pnt);
if (obj_creating == obj)
draw_circle (&edge_pnt->pnt, TRUE, cr);
else
draw_sqr (&edge_pnt->pnt, obj == gfig_context->selected_obj, cr);
gfig_draw_arc (center_pnt->pnt.x, center_pnt->pnt.y,
radius, radius, 0, 360, cr);
}
static void
d_paint_circle (GfigObject *obj)
{
DobjPoints *center_pnt;
DobjPoints *edge_pnt;
gint radius;
gdouble dpnts[4];
g_assert (obj != NULL);
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 = calc_radius (&center_pnt->pnt, &edge_pnt->pnt);
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);
if (gfig_context_get_current_style ()->fill_type != FILL_NONE)
{
pika_context_push ();
pika_context_set_antialias (selopt.antia);
pika_context_set_feather (selopt.feather);
pika_context_set_feather_radius (selopt.feather_radius, selopt.feather_radius);
pika_image_select_ellipse (gfig_context->image,
selopt.type,
dpnts[0], dpnts[1],
dpnts[2], dpnts[3]);
pika_context_pop ();
paint_layer_fill (center_pnt->pnt.x - radius,
center_pnt->pnt.y - radius,
center_pnt->pnt.x + radius,
center_pnt->pnt.y + radius);
pika_selection_none (gfig_context->image);
}
/* Drawing a circle may be harder than stroking a circular selection,
* but we have to do it or we will not be able to draw outside of the
* layer. */
if (obj->style.paint_type == PAINT_BRUSH_TYPE)
{
const gdouble r = dpnts[2] / 2;
const gdouble cx = dpnts[0] + r, cy = dpnts[1] + r;
gdouble line_pnts[362];
gdouble angle = 0;
gint i = 0;
while (i < 361)
{
static const gdouble step = 2 * G_PI / 180;
line_pnts[i++] = cx + r * cos (angle);
line_pnts[i++] = cy + r * sin (angle);
angle += step;
}
gfig_paint (selvals.brshtype, gfig_context->drawable, i, line_pnts);
}
}
static GfigObject *
d_copy_circle (GfigObject * obj)
{
GfigObject *nc;
g_assert (obj->type == CIRCLE);
nc = d_new_object (CIRCLE, obj->points->pnt.x, obj->points->pnt.y);
nc->points->next = d_copy_dobjpoints (obj->points->next);
return nc;
}
void
d_circle_object_class_init (void)
{
GfigObjectClass *class = &dobj_class[CIRCLE];
class->type = CIRCLE;
class->name = "CIRCLE";
class->drawfunc = d_draw_circle;
class->paintfunc = d_paint_circle;
class->copyfunc = d_copy_circle;
class->update = d_update_circle;
}
static void
d_update_circle (GdkPoint *pnt)
{
DobjPoints *center_pnt, *edge_pnt;
center_pnt = obj_creating->points;
if (!center_pnt)
return; /* No points */
if ((edge_pnt = center_pnt->next))
{
edge_pnt->pnt = *pnt;
}
else
{
edge_pnt = new_dobjpoint (pnt->x, pnt->y);
center_pnt->next = edge_pnt;
}
}
void
d_circle_start (GdkPoint *pnt,
gboolean shift_down)
{
obj_creating = d_new_object (CIRCLE, pnt->x, pnt->y);
}
void
d_circle_end (PikaGfig *gfig,
GdkPoint *pnt,
gboolean shift_down)
{
/* Under control point */
if (!obj_creating->points->next)
{
/* No circle created */
free_one_obj (obj_creating);
}
else
{
add_to_all_obj (gfig, gfig_context->current_obj, obj_creating);
}
obj_creating = NULL;
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef __GFIG_CIRCLE_H__
#define __GFIG_CIRCLE_H__
void d_circle_object_class_init (void);
void d_circle_start (GdkPoint *pnt,
gboolean shift_down);
void d_circle_end (PikaGfig *gfig,
GdkPoint *pnt,
gboolean shift_down);
#endif /* __GFIG_CIRCLE_H__ */

2251
plug-ins/gfig/gfig-dialog.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,39 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef __GFIG_DIALOG_H__
#define __GFIG_DIALOG_H__
extern gint undo_level; /* Last slot filled in -1 = no undo */
extern GList *undo_table[MAX_UNDO];
gboolean gfig_dialog (PikaGfig *gfig);
void gfig_dialog_action_set_sensitive (const gchar *name,
gboolean sensitive);
void options_update (GFigObj *old_obj);
void tool_option_page_update (GtkWidget *button,
GtkWidget *notebook);
#endif /* __GFIG_DIALOG_H__ */

1078
plug-ins/gfig/gfig-dobject.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,115 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __GFIG_DOBJECT_H__
#define __GFIG_DOBJECT_H__
#include "gfig-types.h"
#include "gfig-style.h"
typedef void (*DobjDrawFunc) (GfigObject *, cairo_t *);
typedef void (*DobjFunc) (GfigObject *);
typedef GfigObject *(*DobjGenFunc) (GfigObject *);
typedef struct DobjPoints
{
struct DobjPoints *next;
GdkPoint pnt;
gboolean found_me;
} DobjPoints;
typedef struct
{
DobjType type; /* the object type for this class */
const gchar *name;
/* virtuals */
DobjDrawFunc drawfunc; /* How do I draw myself */
DobjFunc paintfunc; /* Draw me on canvas */
DobjGenFunc copyfunc; /* copy */
void (*update) (GdkPoint *pnt);
} GfigObjectClass;
extern GfigObjectClass dobj_class[10];
/* The object itself */
struct _GfigObject
{
DobjType type; /* What is the type? */
GfigObjectClass *class; /* What class does it belong to? */
gint type_data; /* Extra data needed by the object */
DobjPoints *points; /* List of points */
Style style; /* this object's individual style settings */
gint style_no; /* style index of this specific object */
};
/* States of the object */
#define GFIG_OK 0x0
#define GFIG_MODIFIED 0x1
#define GFIG_READONLY 0x2
extern GfigObject *obj_creating;
extern GfigObject *tmp_line;
DobjPoints *new_dobjpoint (gint x,
gint y);
void do_save_obj (GfigObject *obj,
GString *to);
DobjPoints *d_copy_dobjpoints (DobjPoints *pnts);
void free_one_obj (GfigObject *obj);
void d_delete_dobjpoints (DobjPoints *pnts);
void object_update (GdkPoint *pnt);
GList *copy_all_objs (GList *objs);
void draw_objects (GList *objs,
gboolean show_single,
cairo_t *cr);
GfigObject *d_load_object (gchar *desc,
FILE *fp);
GfigObject *d_new_object (DobjType type,
gint x,
gint y);
void d_save_object (GfigObject *obj,
GString *string);
void free_all_objs (GList *objs);
void clear_undo (PikaGfig *gfig);
void new_obj_2edit (PikaGfig *gfig,
GFigObj *obj);
void gfig_init_object_classes (void);
void d_pnt_add_line (GfigObject *obj,
gint x,
gint y,
gint pos);
#endif /* __GFIG_DOBJECT_H__ */

View File

@ -0,0 +1,236 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <stdlib.h>
#include <libpika/pika.h>
#include <libpika/pikaui.h>
#include "gfig.h"
#include "gfig-dobject.h"
#include "gfig-ellipse.h"
#include "libpika/stdplugins-intl.h"
static void d_draw_ellipse (GfigObject *obj,
cairo_t *cr);
static void d_paint_ellipse (GfigObject *obj);
static GfigObject *d_copy_ellipse (GfigObject *obj);
static void d_update_ellipse (GdkPoint *pnt);
static void
d_draw_ellipse (GfigObject *obj,
cairo_t *cr)
{
DobjPoints *center_pnt;
DobjPoints *edge_pnt;
gint bound_wx;
gint bound_wy;
center_pnt = obj->points;
if (!center_pnt)
return; /* End-of-line */
draw_sqr (&center_pnt->pnt, obj == gfig_context->selected_obj, cr);
edge_pnt = center_pnt->next;
if (!edge_pnt)
return;
if (obj == obj_creating)
draw_circle (&edge_pnt->pnt, TRUE, cr);
else
draw_sqr (&edge_pnt->pnt, obj == gfig_context->selected_obj, cr);
bound_wx = abs (center_pnt->pnt.x - edge_pnt->pnt.x);
bound_wy = abs (center_pnt->pnt.y - edge_pnt->pnt.y);
gfig_draw_arc (center_pnt->pnt.x, center_pnt->pnt.y, bound_wx, bound_wy, 0, 360, cr);
}
static void
d_paint_ellipse (GfigObject *obj)
{
DobjPoints *center_pnt;
DobjPoints *edge_pnt;
gint bound_wx;
gint bound_wy;
gint top_x;
gint top_y;
gdouble dpnts[4];
g_assert (obj != NULL);
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);
if (gfig_context_get_current_style ()->fill_type != FILL_NONE)
{
pika_context_push ();
pika_context_set_antialias (selopt.antia);
pika_context_set_feather (selopt.feather);
pika_context_set_feather_radius (selopt.feather_radius, selopt.feather_radius);
pika_image_select_ellipse (gfig_context->image,
selopt.type,
dpnts[0], dpnts[1],
dpnts[2], dpnts[3]);
pika_context_pop ();
paint_layer_fill (top_x, top_y, top_x + bound_wx, top_y + bound_wy);
pika_selection_none (gfig_context->image);
}
if (obj->style.paint_type == PAINT_BRUSH_TYPE)
{
const gdouble rx = dpnts[2] / 2, ry = dpnts[3] / 2;
const gdouble cx = dpnts[0] + rx, cy = dpnts[1] + ry;
gdouble line_pnts[362];
gdouble angle = 0;
gint i = 0;
while (i < 361)
{
static const gdouble step = 2 * G_PI / 180;
line_pnts[i++] = cx + rx * cos (angle);
line_pnts[i++] = cy + ry * sin (angle);
angle += step;
}
gfig_paint (selvals.brshtype, gfig_context->drawable, i, line_pnts);
}
}
static GfigObject *
d_copy_ellipse (GfigObject * obj)
{
GfigObject *nc;
g_assert (obj->type == ELLIPSE);
nc = d_new_object (ELLIPSE, obj->points->pnt.x, obj->points->pnt.y);
nc->points->next = d_copy_dobjpoints (obj->points->next);
return nc;
}
void
d_ellipse_object_class_init (void)
{
GfigObjectClass *class = &dobj_class[ELLIPSE];
class->type = ELLIPSE;
class->name = "ELLIPSE";
class->drawfunc = d_draw_ellipse;
class->paintfunc = d_paint_ellipse;
class->copyfunc = d_copy_ellipse;
class->update = d_update_ellipse;
}
static void
d_update_ellipse (GdkPoint *pnt)
{
DobjPoints *center_pnt, *edge_pnt;
center_pnt = obj_creating->points;
if (!center_pnt)
return; /* No points */
if ((edge_pnt = center_pnt->next))
{
edge_pnt->pnt = *pnt;
}
else
{
edge_pnt = new_dobjpoint (pnt->x, pnt->y);
center_pnt->next = edge_pnt;
}
}
void
d_ellipse_start (GdkPoint *pnt,
gboolean shift_down)
{
obj_creating = d_new_object (ELLIPSE, pnt->x, pnt->y);
}
void
d_ellipse_end (PikaGfig *gfig,
GdkPoint *pnt,
gboolean shift_down)
{
/* Under control point */
if (!obj_creating->points->next)
{
/* No circle created */
free_one_obj (obj_creating);
}
else
{
add_to_all_obj (gfig, gfig_context->current_obj, obj_creating);
}
obj_creating = NULL;
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef __GFIG_ELLIPSE_H__
#define __GFIG_ELLIPSE_H__
void d_ellipse_object_class_init (void);
void d_ellipse_start (GdkPoint *pnt,
gboolean shift_down);
void d_ellipse_end (PikaGfig *gfig,
GdkPoint *pnt,
gboolean shift_down);
#endif /* __GFIG_ELLIPSE_H__ */

View File

@ -0,0 +1,84 @@
GFIG Version 0.1
Name: A\040star
Version: 0.000000
ObjCount: 18
<OPTIONS>
GridSpacing: 30
GridType: POLAR_GRID
DrawGrid: TRUE
Snap2Grid: TRUE
LockOnGrid: FALSE
ShowControl: TRUE
</OPTIONS>
<LINE>
127 67
44 44
</LINE>
<LINE>
44 44
68 128
</LINE>
<LINE>
68 128
44 212
</LINE>
<LINE>
44 212
128 188
</LINE>
<LINE>
128 188
212 212
</LINE>
<LINE>
212 212
188 128
</LINE>
<LINE>
188 128
212 44
</LINE>
<LINE>
212 44
128 68
</LINE>
<CIRCLE>
128 128
139 186
</CIRCLE>
<CIRCLE>
128 128
151 245
</CIRCLE>
<LINE>
128 8
86 86
</LINE>
<LINE>
86 86
8 128
</LINE>
<LINE>
8 128
86 170
</LINE>
<LINE>
86 170
128 248
</LINE>
<LINE>
128 248
170 170
</LINE>
<LINE>
170 170
248 128
</LINE>
<LINE>
248 128
170 86
</LINE>
<LINE>
170 86
128 8
</LINE>

View File

@ -0,0 +1,57 @@
GFIG Version 0.1
Name: curves
Version: 0.000000
ObjCount: 9
<OPTIONS>
GridSpacing: 13
GridType: POLAR_GRID
DrawGrid: TRUE
Snap2Grid: TRUE
LockOnGrid: FALSE
ShowControl: TRUE
</OPTIONS>
<ARC>
53 39
109 13
170 19
</ARC>
<ARC>
177 37
217 75
231 115
</ARC>
<ARC>
219 128
199 184
160 212
</ARC>
<ARC>
146 203
105 202
71 180
</ARC>
<ARC>
75 164
64 132
70 99
</ARC>
<ARC>
95 89
128 77
158 87
</ARC>
<ARC>
158 104
166 128
155 156
</ARC>
<ARC>
143 148
121 152
105 139
</ARC>
<ARC>
116 130
125 116
139 123
</ARC>

View File

@ -0,0 +1,14 @@
install_data([
'A_star',
'curves',
'polys',
'ring',
'ring+star',
'smiley',
'spirals_and_stars',
'sprial',
'star2',
'stars',
],
install_dir: pikadatadir / 'gfig',
)

View File

@ -0,0 +1,40 @@
GFIG Version 0.1
Name: polys
Version: 0.000000
ObjCount: 4
<OPTIONS>
GridSpacing: 10
GridType: RECT_GRID
DrawGrid: TRUE
Snap2Grid: TRUE
LockOnGrid: FALSE
ShowControl: TRUE
</OPTIONS>
<POLY>
60 40
60 100
<EXTRA>
3
</EXTRA>
</POLY>
<POLY>
170 60
200 110
<EXTRA>
4
</EXTRA>
</POLY>
<POLY>
50 170
70 210
<EXTRA>
5
</EXTRA>
</POLY>
<POLY>
170 170
110 160
<EXTRA>
6
</EXTRA>
</POLY>

View File

@ -0,0 +1,44 @@
GFIG Version 0.1
Name: a\040ring
Version: 0.000000
ObjCount: 8
<OPTIONS>
GridSpacing: 50
GridType: RECT_GRID
DrawGrid: TRUE
Snap2Grid: TRUE
LockOnGrid: FALSE
ShowControl: TRUE
</OPTIONS>
<CIRCLE>
163 163
147 174
</CIRCLE>
<CIRCLE>
178 128
174 147
</CIRCLE>
<CIRCLE>
163 93
174 109
</CIRCLE>
<CIRCLE>
128 78
109 82
</CIRCLE>
<CIRCLE>
93 93
82 109
</CIRCLE>
<CIRCLE>
78 128
82 147
</CIRCLE>
<CIRCLE>
93 163
109 174
</CIRCLE>
<CIRCLE>
128 178
147 174
</CIRCLE>

View File

@ -0,0 +1,123 @@
GFIG Version 0.1
Name: a\040ring\040merged
Version: 0.000000
ObjCount: 27
<OPTIONS>
GridSpacing: 47
GridType: RECT_GRID
DrawGrid: TRUE
Snap2Grid: TRUE
LockOnGrid: FALSE
ShowControl: TRUE
</OPTIONS>
<CIRCLE>
163 163
147 174
</CIRCLE>
<CIRCLE>
178 128
174 147
</CIRCLE>
<CIRCLE>
163 93
174 109
</CIRCLE>
<CIRCLE>
128 78
109 82
</CIRCLE>
<CIRCLE>
93 93
82 109
</CIRCLE>
<CIRCLE>
78 128
82 147
</CIRCLE>
<CIRCLE>
93 163
109 174
</CIRCLE>
<CIRCLE>
128 178
147 174
</CIRCLE>
<LINE>
127 67
44 44
</LINE>
<LINE>
44 44
68 128
</LINE>
<LINE>
68 128
44 212
</LINE>
<LINE>
44 212
128 188
</LINE>
<LINE>
128 188
212 212
</LINE>
<LINE>
212 212
188 128
</LINE>
<LINE>
188 128
212 44
</LINE>
<LINE>
212 44
128 68
</LINE>
<CIRCLE>
128 128
139 186
</CIRCLE>
<CIRCLE>
128 128
151 245
</CIRCLE>
<LINE>
128 8
86 86
</LINE>
<LINE>
86 86
8 128
</LINE>
<LINE>
8 128
86 170
</LINE>
<LINE>
86 170
128 248
</LINE>
<LINE>
128 248
170 170
</LINE>
<LINE>
170 170
248 128
</LINE>
<LINE>
248 128
170 86
</LINE>
<LINE>
170 86
128 8
</LINE>
<POLY>
338 132
256 256
<EXTRA>
3
</EXTRA>
</POLY>

View File

@ -0,0 +1,47 @@
GFIG Version 0.1
Name: Smiley\040face
Version: 0.000000
ObjCount: 5
<OPTIONS>
GridSpacing: 30
GridType: RECT_GRID
DrawGrid: FALSE
Snap2Grid: FALSE
LockOnGrid: FALSE
ShowControl: TRUE
</OPTIONS>
<CIRCLE>
128 128
142 235
</CIRCLE>
<CIRCLE>
72 90
72 108
</CIRCLE>
<CIRCLE>
180 90
180 108
</CIRCLE>
<LINE>
66 163
71 171
78 178
85 185
92 190
101 194
110 197
119 199
128 200
137 199
146 197
155 194
163 190
171 185
178 178
185 171
190 164
</LINE>
<CIRCLE>
128 145
128 164
</CIRCLE>

View File

@ -0,0 +1,55 @@
GFIG Version 0.1
Name: First\040gfig
Version: 0.000000
ObjCount: 6
<OPTIONS>
GridSpacing: 30
GridType: RECT_GRID
DrawGrid: FALSE
Snap2Grid: FALSE
LockOnGrid: FALSE
ShowControl: TRUE
</OPTIONS>
<SPIRAL>
71 81
96 103
<EXTRA>
4
</EXTRA>
</SPIRAL>
<SPIRAL>
152 79
179 91
<EXTRA>
-4
</EXTRA>
</SPIRAL>
<BEZIER>
116 94
105 147
73 161
<EXTRA>
4
</EXTRA>
</BEZIER>
<STAR>
206 106
228 123
214 112
<EXTRA>
3
</EXTRA>
</STAR>
<STAR>
26 115
10 133
20 121
<EXTRA>
3
</EXTRA>
</STAR>
<ARC>
38 169
92 218
182 182
</ARC>

View File

@ -0,0 +1,38 @@
GFIG Version 0.1
Name: square\040sprial
Version: 0.000000
ObjCount: 2
<OPTIONS>
GridSpacing: 30
GridType: RECT_GRID
DrawGrid: FALSE
Snap2Grid: FALSE
LockOnGrid: FALSE
ShowControl: TRUE
</OPTIONS>
<LINE>
30 20
230 20
230 230
50 230
50 40
210 40
210 210
70 210
70 60
190 60
190 190
90 190
90 80
170 80
170 170
110 170
110 100
150 100
150 150
130 150
</LINE>
<LINE>
130 150
130 120
</LINE>

View File

@ -0,0 +1,61 @@
GFIG Version 0.1
Name: Another\040star
Version: 0.000000
ObjCount: 7
<OPTIONS>
GridSpacing: 30
GridType: RECT_GRID
DrawGrid: FALSE
Snap2Grid: FALSE
LockOnGrid: FALSE
ShowControl: TRUE
</OPTIONS>
<POLY>
128 128
164 190
<EXTRA>
6
</EXTRA>
</POLY>
<POLY>
128 43
163 63
<EXTRA>
3
</EXTRA>
</POLY>
<POLY>
203 170
238 190
<EXTRA>
3
</EXTRA>
</POLY>
<POLY>
54 170
89 190
<EXTRA>
3
</EXTRA>
</POLY>
<POLY>
202 85
237 65
<EXTRA>
3
</EXTRA>
</POLY>
<POLY>
54 85
89 65
<EXTRA>
3
</EXTRA>
</POLY>
<POLY>
128 213
163 193
<EXTRA>
3
</EXTRA>
</POLY>

View File

@ -0,0 +1,44 @@
GFIG Version 0.1
Name: First\040gfig
Version: 0.000000
ObjCount: 4
<OPTIONS>
GridSpacing: 30
GridType: RECT_GRID
DrawGrid: FALSE
Snap2Grid: FALSE
LockOnGrid: FALSE
ShowControl: TRUE
</OPTIONS>
<STAR>
80 70
80 130
80 90
<EXTRA>
6
</EXTRA>
</STAR>
<STAR>
200 70
200 130
200 90
<EXTRA>
6
</EXTRA>
</STAR>
<STAR>
200 190
200 250
200 210
<EXTRA>
6
</EXTRA>
</STAR>
<STAR>
80 190
80 250
80 210
<EXTRA>
6
</EXTRA>
</STAR>

540
plug-ins/gfig/gfig-grid.c Normal file
View File

@ -0,0 +1,540 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <math.h>
#include <stdlib.h>
#include <libpika/pika.h>
#include <libpika/pikaui.h>
#include "gfig.h"
#include "gfig-grid.h"
#include "libpika/stdplugins-intl.h"
/* For the isometric grid */
#define SQRT3 1.73205080756887729353 /* Square root of 3 */
#define SIN_1o6PI_RAD 0.5 /* Sine 1/6 Pi Radians */
#define COS_1o6PI_RAD SQRT3 / 2 /* Cosine 1/6 Pi Radians */
#define TAN_1o6PI_RAD 1 / SQRT3 /* Tangent 1/6 Pi Radians == SIN / COS */
#define RECIP_TAN_1o6PI_RAD SQRT3 /* Reciprocal of Tangent 1/6 Pi Radians */
gint grid_gc_type = GFIG_NORMAL_GC;
static void draw_grid_polar (cairo_t *drawgc);
static void draw_grid_sq (cairo_t *drawgc);
static void draw_grid_iso (cairo_t *drawgc);
static cairo_t * gfig_get_grid_gc (cairo_t *cr,
GtkWidget *widget,
gint gctype);
static void find_grid_pos_polar (GdkPoint *p,
GdkPoint *gp);
/********** PrimeFactors for Shaneyfelt-style Polar Grid **********
* Quickly factor any number up to 17160
* Correctly factors numbers up to 131 * 131 - 1
*/
typedef struct
{
gint product;
gint remaining;
gint current;
gint next;
gint index;
} PrimeFactors;
static gchar primes[] = { 2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,
59,61,67,71,73,79,83,89,97,101,103,107,109,113,127 };
#define PRIMES_MAX_INDEX 30
static gint
prime_factors_get (PrimeFactors *this)
{
this->current = this->next;
while (this->index <= PRIMES_MAX_INDEX)
{
if (this->remaining % primes[this->index] == 0) /* divisible */
{
this->remaining /= primes[this->index];
this->next = primes[this->index];
return this->current;
}
this->index++;
}
this->next = this->remaining;
this->remaining = 1;
return this->current;
}
static gint
prime_factors_lookahead (PrimeFactors *this)
{
return this->next;
}
static void
prime_factors_reset (PrimeFactors *this)
{
this->remaining = this->product;
this->index = 0;
prime_factors_get (this);
}
static PrimeFactors *
prime_factors_new (gint n)
{
PrimeFactors *this = g_new (PrimeFactors, 1);
this->product = n;
prime_factors_reset (this);
return this;
}
static void
prime_factors_delete (PrimeFactors* this)
{
g_free (this);
}
/********** ********** **********/
static gdouble
sector_size_at_radius (gdouble inner_radius)
{
PrimeFactors *factors = prime_factors_new (selvals.opts.grid_sectors_desired);
gint current_sectors = 1;
gdouble sector_size = 2 * G_PI / current_sectors;
while ((current_sectors < selvals.opts.grid_sectors_desired)
&& (inner_radius*sector_size
> (prime_factors_lookahead (factors) *
selvals.opts.grid_granularity)))
{
current_sectors *= prime_factors_get (factors);
sector_size = 2 * G_PI / current_sectors;
}
prime_factors_delete(factors);
return sector_size;
}
static void
find_grid_pos_polar (GdkPoint *p,
GdkPoint *gp)
{
gdouble cx = preview_width / 2.0;
gdouble cy = preview_height / 2.0;
gdouble px = p->x - cx;
gdouble py = p->y - cy;
gdouble x = 0;
gdouble y = 0;
gdouble r = sqrt (SQR (px) + SQR (py));
if (r >= selvals.opts.grid_radius_min * 0.5)
{
gdouble t;
gdouble sectorSize;
r = selvals.opts.grid_radius_interval
* (gint) (0.5 + ((r - selvals.opts.grid_radius_min) /
selvals.opts.grid_radius_interval))
+ selvals.opts.grid_radius_min;
t = atan2 (py, px) + 2 * G_PI;
sectorSize = sector_size_at_radius (r);
t = selvals.opts.grid_rotation
+ (gint) (0.5 + ((t - selvals.opts.grid_rotation) / sectorSize))
* sectorSize;
x = r * cos (t);
y = r * sin (t);
}
gp->x = x + cx;
gp->y = y + cy;
}
/* find_grid_pos - Given an x, y point return the grid position of it */
/* return the new position in the passed point */
void
gfig_grid_colors (GtkWidget *widget)
{
}
void
find_grid_pos (GdkPoint *p,
GdkPoint *gp,
guint is_butt3)
{
gint16 x = p->x;
gint16 y = p->y;
static GdkPoint cons_pnt;
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)
{
find_grid_pos_polar (p,gp);
}
else if (selvals.opts.gridtype == ISO_GRID)
{
/*
* This really needs a picture to show the math...
*
* Consider an isometric grid with one of the sets of lines
* parallel to the y axis (vertical alignment). Further define
* that the origin of a Cartesian grid is at a isometric vertex.
* For simplicity consider the first quadrant only.
*
* - Let one line segment between vertices be r
* - Define the value of r as the grid spacing
* - Assign an integer n identifier to each vertical grid line
* along the x axis. with n=0 being the y axis. n can be any
* integer
* - Let m to be any integer
* - Let h be the spacing between vertical grid lines measured
* along the x axis. It follows from the isometric grid that
* h has a value of r * COS(1/6 Pi Rad)
*
* Consider a Vertex V at the Cartesian location [Xv, Yv]
*
* It follows that vertices belong to the set...
* V[Xv, Yv] = [ [ n * h ] ,
* [ m * r + ( 0.5 * r (n % 2) ) ] ]
* for all integers n and m
*
* Who cares? Me. It's useful in solving this problem:
* Consider an arbitrary point P[Xp,Yp], find the closest vertex
* in the set V.
*
* Restated this problem is "find values for m and n that are
* drive V closest to P"
*
* A Solution method (there may be a better one?):
*
* Step 1) bound n to the two closest values for Xp
* n_lo = (int) (Xp / h)
* n_hi = n_lo + 1
*
* Step 2) Consider the two closes vertices for each n_lo and
* n_hi. The further of the vertices in each pair can
* readily be discarded.
*
* m_lo_n_lo = (int) ( (Yp / r) - 0.5 (n_lo % 2) )
* m_hi_n_lo = m_lo_n_lo + 1
*
* m_lo_n_hi = (int) ( (Yp / r) - 0.5 (n_hi % 2) )
* m_hi_n_hi = m_hi_n_hi
*
* Step 3) compute the distance from P to V1 and V2. Snap to the
* closer point.
*/
gint n_lo;
gint n_hi;
gint m_lo_n_lo;
gint m_hi_n_lo;
gint m_lo_n_hi;
gint m_hi_n_hi;
gint m_n_lo;
gint m_n_hi;
gdouble r;
gdouble h;
gint x1;
gint x2;
gint y1;
gint y2;
r = selvals.opts.gridspacing;
h = COS_1o6PI_RAD * r;
n_lo = (gint) x / h;
n_hi = n_lo + 1;
/* evaluate m candidates for n_lo */
m_lo_n_lo = (gint) ((y / r) - 0.5 * (n_lo % 2));
m_hi_n_lo = m_lo_n_lo + 1;
/* figure out which is the better candidate */
if (fabs ((m_lo_n_lo * r + (0.5 * r * (n_lo % 2))) - y) <
fabs ((m_hi_n_lo * r + (0.5 * r * (n_lo % 2))) - y))
{
m_n_lo = m_lo_n_lo;
}
else
{
m_n_lo = m_hi_n_lo;
}
/* evaluate m candidates for n_hi */
m_lo_n_hi = (gint) ( (y / r) - 0.5 * (n_hi % 2) );
m_hi_n_hi = m_lo_n_hi + 1;
/* figure out which is the better candidate */
if (fabs((m_lo_n_hi * r + (0.5 * r * (n_hi % 2))) - y) <
fabs((m_hi_n_hi * r + (0.5 * r * (n_hi % 2))) - y))
{
m_n_hi = m_lo_n_hi;
}
else
{
m_n_hi = m_hi_n_hi;
}
/* Now, which is closer to [x,y]? we can use a somewhat
* abbreviated form of the distance formula since we only care
* about relative values.
*/
x1 = (gint) (n_lo * h);
y1 = (gint) (m_n_lo * r + (0.5 * r * (n_lo % 2)));
x2 = (gint) (n_hi * h);
y2 = (gint) (m_n_hi * r + (0.5 * r * (n_hi % 2)));
if (((x - x1) * (x - x1) + (y - y1) * (y - y1)) <
((x - x2) * (x - x2) + (y - y2) * (y - y2)))
{
gp->x = x1;
gp->y = y1;
}
else
{
gp->x = x2;
gp->y = y2;
}
}
}
static void
draw_grid_polar (cairo_t *cr)
{
gdouble inner_radius;
gdouble outer_radius;
gdouble max_radius = sqrt (SQR (preview_width) + SQR (preview_height));
gint current_sectors = 1;
PrimeFactors *factors = prime_factors_new (selvals.opts.grid_sectors_desired);
for (inner_radius = 0, outer_radius = selvals.opts.grid_radius_min;
outer_radius <= max_radius;
inner_radius = outer_radius, outer_radius += selvals.opts.grid_radius_interval)
{
gdouble t;
gdouble sector_size = 2 * G_PI / current_sectors;
cairo_arc (cr,
0.5 + preview_width / 2.0,
0.5 + preview_height / 2.0,
outer_radius, 0, 2 * G_PI);
cairo_stroke (cr);
while ((current_sectors < selvals.opts.grid_sectors_desired)
&& (inner_radius * sector_size
> prime_factors_lookahead (factors) * selvals.opts.grid_granularity ))
{
current_sectors *= prime_factors_get (factors);
sector_size = 2 * G_PI / current_sectors;
}
for (t = 0 ; t < 2 * G_PI ; t += sector_size)
{
gdouble normal_x = cos (selvals.opts.grid_rotation+t);
gdouble normal_y = sin (selvals.opts.grid_rotation+t);
cairo_move_to (cr,
0.5 + (preview_width / 2.0 + inner_radius * normal_x),
0.5 + (preview_height / 2.0 - inner_radius * normal_y));
cairo_line_to (cr,
0.5 + (preview_width / 2.0 + outer_radius * normal_x),
0.5 + (preview_height / 2.0 - outer_radius * normal_y));
cairo_stroke (cr);
}
}
prime_factors_delete (factors);
}
static void
draw_grid_sq (cairo_t *cr)
{
gint step;
gint loop;
/* Draw the horizontal lines */
step = selvals.opts.gridspacing;
for (loop = 0 ; loop < preview_height ; loop += step)
{
cairo_move_to (cr, 0 + .5, loop + .5);
cairo_line_to (cr, preview_width + .5, loop + .5);
}
/* Draw the vertical lines */
for (loop = 0 ; loop < preview_width ; loop += step)
{
cairo_move_to (cr, loop + .5, 0 + .5);
cairo_line_to (cr, loop + .5, preview_height + .5);
}
cairo_stroke (cr);
}
static void
draw_grid_iso (cairo_t *cr)
{
/* vstep is an int since it's defined from grid size */
gint vstep;
gdouble loop;
gdouble hstep;
gdouble diagonal_start;
gdouble diagonal_end;
gdouble diagonal_width;
gdouble diagonal_height;
vstep = selvals.opts.gridspacing;
hstep = selvals.opts.gridspacing * COS_1o6PI_RAD;
/* Draw the vertical lines - These are easy */
for (loop = 0 ; loop < preview_width ; loop += hstep)
{
cairo_move_to (cr, loop, 0);
cairo_line_to (cr, loop, preview_height);
}
cairo_stroke (cr);
/* draw diag lines at a Theta of +/- 1/6 Pi Rad */
diagonal_start = -(((int)preview_width * TAN_1o6PI_RAD) - (((int)(preview_width * TAN_1o6PI_RAD)) % vstep));
diagonal_end = preview_height + (preview_width * TAN_1o6PI_RAD);
diagonal_end -= ((int)diagonal_end) % vstep;
diagonal_width = preview_width;
diagonal_height = preview_width * TAN_1o6PI_RAD;
/* Draw diag lines */
for (loop = diagonal_start ; loop < diagonal_end ; loop += vstep)
{
cairo_move_to (cr, 0, loop);
cairo_line_to (cr, diagonal_width, loop + diagonal_height);
cairo_move_to (cr, 0, loop);
cairo_line_to (cr, diagonal_width, loop - diagonal_height);
}
cairo_stroke (cr);
}
static cairo_t *
gfig_get_grid_gc (cairo_t *cr, GtkWidget *w, gint gctype)
{
switch (gctype)
{
default:
case GFIG_NORMAL_GC:
cairo_set_source_rgb (cr, .92, .92, .92);
break;
case GFIG_BLACK_GC:
cairo_set_source_rgb (cr, 0., 0., 0.);
break;
case GFIG_WHITE_GC:
cairo_set_source_rgb (cr, 1., 1., 1.);
break;
case GFIG_GREY_GC:
cairo_set_source_rgb (cr, .5, .5, .5);
break;
case GFIG_DARKER_GC:
cairo_set_source_rgb (cr, .25, .25, .25);
break;
case GFIG_LIGHTER_GC:
cairo_set_source_rgb (cr, .75, .75, .75);
break;
case GFIG_VERY_DARK_GC:
cairo_set_source_rgb (cr, .125, .125, .125);
break;
}
return cr;
}
void
draw_grid (cairo_t *cr)
{
/* 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))
{
/* Don't draw if they don't fit */
return;
}
if (selvals.opts.drawgrid)
gfig_get_grid_gc (cr, gfig_context->preview, grid_gc_type);
else
return;
cairo_set_line_width (cr, 1.);
if (selvals.opts.gridtype == RECT_GRID)
draw_grid_sq (cr);
else if (selvals.opts.gridtype == POLAR_GRID)
draw_grid_polar (cr);
else if (selvals.opts.gridtype == ISO_GRID)
draw_grid_iso (cr);
}

47
plug-ins/gfig/gfig-grid.h Normal file
View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef __GFIG_GRID_H__
#define __GFIG_GRID_H__
#define GFIG_NORMAL_GC -1
#define GFIG_BLACK_GC -2
#define GFIG_WHITE_GC -3
#define GFIG_GREY_GC -4
#define GFIG_DARKER_GC -5
#define GFIG_LIGHTER_GC -6
#define GFIG_VERY_DARK_GC -7
#define MIN_GRID 10
#define MAX_GRID 50
extern gint grid_gc_type;
void gfig_grid_colors (GtkWidget *widget);
void find_grid_pos (GdkPoint *p,
GdkPoint *gp,
guint state);
void draw_grid (cairo_t *cr);
#endif /* __GFIG_GRID_H__ */

View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas <alt@picnic.demon.co.uk>
* 2003 Sven Neumann <sven@gimp.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gtk/gtk.h>
#include "gfig-icons.h"
#include "images/gfig-icon-images.h"
void
gfig_icons_init (void)
{
static gboolean initialized = FALSE;
GtkIconTheme *icon_theme;
if (initialized)
return;
initialized = TRUE;
icon_theme = gtk_icon_theme_get_default ();
gtk_icon_theme_add_resource_path (icon_theme, "/technology.heckin/gfig/icons");
}

View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas <alt@picnic.demon.co.uk>
* 2003 Sven Neumann <sven@gimp.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __GFIG_ICONS_H__
#define __GFIG_ICONS_H__
#define GFIG_ICON_BEZIER "gfig-bezier"
#define GFIG_ICON_CIRCLE "gfig-circle"
#define GFIG_ICON_COPY_OBJECT "gfig-copy-object"
#define GFIG_ICON_CURVE "gfig-curve"
#define GFIG_ICON_DELETE_OBJECT "gfig-delete-object"
#define GFIG_ICON_ELLIPSE "gfig-ellipse"
#define GFIG_ICON_LINE "gfig-line"
#define GFIG_ICON_MOVE_OBJECT "gfig-move-object"
#define GFIG_ICON_MOVE_POINT "gfig-move-point"
#define GFIG_ICON_POLYGON "gfig-polygon"
#define GFIG_ICON_RECTANGLE "gfig-rectangle"
#define GFIG_ICON_SELECT_OBJECT "gfig-select-object"
#define GFIG_ICON_SHOW_ALL "gfig-show-all"
#define GFIG_ICON_SPIRAL "gfig-spiral"
#define GFIG_ICON_STAR "gfig-star"
#define GFIG_ICON_LOGO "gfig-logo"
void gfig_icons_init (void);
#endif /* __GFIG_ICONS_H__ */

226
plug-ins/gfig/gfig-line.c Normal file
View File

@ -0,0 +1,226 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <libpika/pika.h>
#include <libpika/pikaui.h>
#include "gfig.h"
#include "gfig-dobject.h"
#include "gfig-line.h"
#include "libpika/stdplugins-intl.h"
static GfigObject *d_copy_line (GfigObject *obj);
static void d_draw_line (GfigObject *obj,
cairo_t *cr);
static void d_paint_line (GfigObject *obj);
static void d_update_line (GdkPoint *pnt);
static GfigObject *
d_copy_line (GfigObject *obj)
{
GfigObject *nl;
g_assert (obj->type == LINE);
nl = d_new_object (LINE, obj->points->pnt.x, obj->points->pnt.y);
nl->points->next = d_copy_dobjpoints (obj->points->next);
return nl;
}
static void
d_draw_line (GfigObject *obj,
cairo_t *cr)
{
DobjPoints *spnt;
DobjPoints *epnt;
spnt = obj->points;
if (!spnt)
return; /* End-of-line */
epnt = spnt->next;
while (spnt && epnt)
{
draw_sqr (&spnt->pnt, obj == gfig_context->selected_obj, cr);
/* Go around all the points drawing a line from one to the next */
gfig_draw_line (spnt->pnt.x, spnt->pnt.y, epnt->pnt.x, epnt->pnt.y, cr);
spnt = epnt;
epnt = epnt->next;
}
if (obj_creating == obj)
draw_circle (&spnt->pnt, TRUE, cr);
else
draw_sqr (&spnt->pnt, obj == gfig_context->selected_obj, cr);
}
static void
d_paint_line (GfigObject *obj)
{
DobjPoints *spnt;
gdouble *line_pnts;
gint seg_count = 0;
gint i = 0;
for (spnt = obj->points; spnt; spnt = spnt->next)
seg_count++;
if (!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 */
for (spnt = obj->points; spnt; spnt = spnt->next)
{
line_pnts[i++] = spnt->pnt.x;
line_pnts[i++] = spnt->pnt.y;
}
/* 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 (obj->style.paint_type == PAINT_BRUSH_TYPE)
{
gfig_paint (selvals.brshtype,
gfig_context->drawable,
seg_count * 2, line_pnts);
}
g_free (line_pnts);
}
void
d_line_object_class_init (void)
{
GfigObjectClass *class = &dobj_class[LINE];
class->type = LINE;
class->name = "LINE";
class->drawfunc = d_draw_line;
class->paintfunc = d_paint_line;
class->copyfunc = d_copy_line;
class->update = d_update_line;
}
static void
d_update_line (GdkPoint *pnt)
{
DobjPoints *spnt, *epnt;
/* Get start of segments */
spnt = obj_creating->points;
if (!spnt)
return; /* No points */
if ((epnt = spnt->next))
{
g_free (epnt);
}
epnt = new_dobjpoint (pnt->x, pnt->y);
spnt->next = epnt;
}
void
d_line_start (GdkPoint *pnt,
gboolean shift_down)
{
if (!obj_creating || !shift_down)
{
/* Must delete obj_creating if we have one */
obj_creating = d_new_object (LINE, pnt->x, pnt->y);
}
else
{
/* Contniuation */
d_update_line (pnt);
}
}
void
d_line_end (PikaGfig *gfig,
GdkPoint *pnt,
gboolean shift_down)
{
if (shift_down)
{
if (tmp_line)
{
GdkPoint tmp_pnt = *pnt;
if (need_to_scale)
{
tmp_pnt.x = pnt->x * scale_x_factor;
tmp_pnt.y = 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 (gfig, gfig_context->current_obj, obj_creating);
}
obj_creating = d_new_object (LINE, pnt->x, pnt->y);
}
else
{
if (tmp_line)
{
GdkPoint tmp_pnt = *pnt;
if (need_to_scale)
{
tmp_pnt.x = pnt->x * scale_x_factor;
tmp_pnt.y = 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 (gfig, gfig_context->current_obj, obj_creating);
}
obj_creating = NULL;
tmp_line = NULL;
}
}

36
plug-ins/gfig/gfig-line.h Normal file
View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef __GFIG_LINE_H__
#define __GFIG_LINE_H__
void d_line_object_class_init (void);
void d_line_start (GdkPoint *pnt,
gboolean shift_down);
void d_line_end (PikaGfig *gfig,
GdkPoint *pnt,
gboolean shift_down);
#endif /* __GFIG_LINE_H__ */

147
plug-ins/gfig/gfig-menu.ui Normal file
View File

@ -0,0 +1,147 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<menu id="gfig-menubar">
<section>
<submenu>
<attribute name="label" translatable="yes">File</attribute>
<item>
<attribute name="label" translatable="yes">Open</attribute>
<attribute name="action">app.open</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Save</attribute>
<attribute name="action">app.save</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Close</attribute>
<attribute name="action">app.close</attribute>
</item>
</submenu>
<submenu>
<attribute name="label" translatable="yes">Edit</attribute>
<item>
<attribute name="label" translatable="yes">Undo</attribute>
<attribute name="action">app.undo</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Clear</attribute>
<attribute name="action">app.clear</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Grid</attribute>
<attribute name="action">app.grid</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Preferences</attribute>
<attribute name="action">app.preferences</attribute>
</item>
</submenu>
</section>
</menu>
<menu id="gfig-toolbar">
<section>
<item>
<attribute name="label" translatable="yes">Line</attribute>
<attribute name="action">app.shape</attribute>
<attribute name="target">line</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Rectangle</attribute>
<attribute name="action">app.shape</attribute>
<attribute name="target">rectangle</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Circle</attribute>
<attribute name="action">app.shape</attribute>
<attribute name="target">circle</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Ellipse</attribute>
<attribute name="action">app.shape</attribute>
<attribute name="target">ellipse</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Arc</attribute>
<attribute name="action">app.shape</attribute>
<attribute name="target">arc</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Polygon</attribute>
<attribute name="action">app.shape</attribute>
<attribute name="target">polygon</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Star</attribute>
<attribute name="action">app.shape</attribute>
<attribute name="target">star</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Spiral</attribute>
<attribute name="action">app.shape</attribute>
<attribute name="target">spiral</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Bezier</attribute>
<attribute name="action">app.shape</attribute>
<attribute name="target">bezier</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Move Object</attribute>
<attribute name="action">app.shape</attribute>
<attribute name="target">move-obj</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Move Point</attribute>
<attribute name="action">app.shape</attribute>
<attribute name="target">move-point</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Copy</attribute>
<attribute name="action">app.shape</attribute>
<attribute name="target">copy</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Delete</attribute>
<attribute name="action">app.shape</attribute>
<attribute name="target">delete</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Select</attribute>
<attribute name="action">app.shape</attribute>
<attribute name="target">select</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">Raise</attribute>
<attribute name="action">app.raise</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Lower</attribute>
<attribute name="action">app.lower</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Top</attribute>
<attribute name="action">app.top</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Bottom</attribute>
<attribute name="action">app.bottom</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">Show Previous</attribute>
<attribute name="action">app.show-prev</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Show Next</attribute>
<attribute name="action">app.show-next</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Show All</attribute>
<attribute name="action">app.show-all</attribute>
</item>
</section>
</menu>
</interface>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/technology.heckin/gfig/">
<file preprocess="xml-stripblanks">gfig-menu.ui</file>
</gresource>
</gresources>

534
plug-ins/gfig/gfig-poly.c Normal file
View File

@ -0,0 +1,534 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <libpika/pika.h>
#include <libpika/pikaui.h>
#include "gfig.h"
#include "gfig-dobject.h"
#include "gfig-line.h"
#include "gfig-dialog.h"
#include "gfig-poly.h"
#include "libpika/stdplugins-intl.h"
static gint poly_num_sides = 3; /* Default to three sided object */
static void d_draw_poly (GfigObject *obj,
cairo_t *cr);
static GfigObject *d_copy_poly (GfigObject *obj);
static void d_update_poly (GdkPoint *pnt);
void
tool_options_poly (GtkWidget *notebook)
{
GtkWidget *sides;
sides = num_sides_widget (_("Regular Polygon Number of Sides"),
&poly_num_sides, NULL, 3, 200);
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), sides, NULL);
}
static void
d_draw_poly (GfigObject *obj,
cairo_t *cr)
{
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 = { 0, 0 };
GdkPoint first_pnt = { 0, 0 };
gboolean do_line = FALSE;
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 (&center_pnt->pnt, obj == gfig_context->selected_obj, cr);
/* 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 */
if (obj == obj_creating)
draw_circle (&radius_pnt->pnt, TRUE, cr);
else
draw_sqr (&radius_pnt->pnt, obj == gfig_context->selected_obj, cr);
/* 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) obj->type_data;
offset_angle = atan2 (shift_y, shift_x);
for (loop = 0 ; loop < 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 = RINT (lx + center_pnt->pnt.x);
calc_pnt.y = 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;
gfig_draw_line (calc_pnt.x, calc_pnt.y, start_pnt.x, start_pnt.y, cr);
}
else
{
do_line = TRUE;
first_pnt = calc_pnt;
}
start_pnt = calc_pnt;
}
gfig_draw_line (first_pnt.x, first_pnt.y, start_pnt.x, start_pnt.y, cr);
}
void
d_paint_poly (GfigObject *obj)
{
/* first point center */
/* Next point is radius */
gdouble *line_pnts;
gint seg_count;
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 = { 0, 0 };
GdkPoint last_pnt = { 0, 0 };
gboolean first = TRUE;
gdouble *min_max;
g_assert (obj != NULL);
/* count - add one to close polygon */
seg_count = 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);
min_max = g_new (gdouble, 4);
/* 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.0 * G_PI/(gdouble) obj->type_data;
offset_angle = atan2 (shift_y, shift_x);
for (loop = 0 ; loop < 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 = RINT (lx + center_pnt->pnt.x);
calc_pnt.y = 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;
}
}
line_pnts[i++] = calc_pnt.x;
line_pnts[i++] = calc_pnt.y;
last_pnt = calc_pnt;
if (first)
{
first_pnt = calc_pnt;
first = FALSE;
min_max[0] = min_max[2] = calc_pnt.x;
min_max[1] = min_max[3] = calc_pnt.y;
}
else
{
min_max[0] = MIN (min_max[0], calc_pnt.x);
min_max[1] = MIN (min_max[1], calc_pnt.y);
min_max[2] = MAX (min_max[2], calc_pnt.x);
min_max[3] = MAX (min_max[3], calc_pnt.y);
}
}
line_pnts[i++] = first_pnt.x;
line_pnts[i++] = first_pnt.y;
/* Scale before drawing */
if (selvals.scaletoimage)
{/* FIXME scale xmax and al. */
scale_to_original_xy (&line_pnts[0], i/2);
scale_to_original_xy (min_max, 2);
}
else
{
scale_to_xy (&line_pnts[0], i/2);
scale_to_xy (min_max, 2);
}
if (gfig_context_get_current_style ()->fill_type != FILL_NONE)
{
pika_context_push ();
pika_context_set_antialias (selopt.antia);
pika_context_set_feather (selopt.feather);
pika_context_set_feather_radius (selopt.feather_radius, selopt.feather_radius);
pika_image_select_polygon (gfig_context->image,
selopt.type,
i, line_pnts);
pika_context_pop ();
paint_layer_fill (min_max[0], min_max[1], min_max[2], min_max[3]);
pika_selection_none (gfig_context->image);
}
if (obj->style.paint_type == PAINT_BRUSH_TYPE)
gfig_paint (selvals.brshtype, gfig_context->drawable, i, line_pnts);
g_free (line_pnts);
g_free (min_max);
}
void
d_poly2lines (GfigObject *obj)
{
/* first point center */
/* Next point is radius */
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 = { 0, 0 };
GdkPoint last_pnt = { 0, 0 };
gboolean first = TRUE;
g_assert (obj != NULL);
center_pnt = obj->points;
if (!center_pnt)
return; /* no-line */
/* 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.0 * G_PI / (gdouble) obj->type_data;
offset_angle = atan2 (shift_y, shift_x);
for (loop = 0 ; loop < 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 = RINT (lx + center_pnt->pnt.x);
calc_pnt.y = 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 = calc_pnt;
if (first)
{
first_pnt = calc_pnt;
first = FALSE;
}
}
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->class = &dobj_class[LINE];
}
void
d_star2lines (GfigObject *obj)
{
/* first point center */
/* Next point is radius */
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 = { 0, 0 };
GdkPoint last_pnt = { 0, 0 };
gboolean first = TRUE;
g_assert (obj != NULL);
center_pnt = obj->points;
if (!center_pnt)
return; /* no-line */
/* 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.0 * G_PI / (2.0 * (gdouble) 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 * 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 = RINT (lx + center_pnt->pnt.x);
calc_pnt.y = 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 = calc_pnt;
if (first)
{
first_pnt = calc_pnt;
first = FALSE;
}
}
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->class = &dobj_class[LINE];
}
static GfigObject *
d_copy_poly (GfigObject *obj)
{
GfigObject *np;
g_assert (obj->type == POLY);
np = d_new_object (POLY, obj->points->pnt.x, obj->points->pnt.y);
np->points->next = d_copy_dobjpoints (obj->points->next);
np->type_data = obj->type_data;
return np;
}
void
d_poly_object_class_init (void)
{
GfigObjectClass *class = &dobj_class[POLY];
class->type = POLY;
class->name = "POLY";
class->drawfunc = d_draw_poly;
class->paintfunc = d_paint_poly;
class->copyfunc = d_copy_poly;
class->update = d_update_poly;
}
static void
d_update_poly (GdkPoint *pnt)
{
DobjPoints *center_pnt;
DobjPoints *edge_pnt;
center_pnt = obj_creating->points;
if (!center_pnt)
return; /* No points */
if ((edge_pnt = center_pnt->next))
{
edge_pnt->pnt = *pnt;
}
else
{
d_pnt_add_line (obj_creating, pnt->x, pnt->y, -1);
}
}
void
d_poly_start (GdkPoint *pnt,
gboolean shift_down)
{
obj_creating = d_new_object (POLY, pnt->x, pnt->y);
obj_creating->type_data = poly_num_sides;
}
void
d_poly_end (PikaGfig *gfig,
GdkPoint *pnt,
gboolean shift_down)
{
add_to_all_obj (gfig, gfig_context->current_obj, obj_creating);
obj_creating = NULL;
}

43
plug-ins/gfig/gfig-poly.h Normal file
View File

@ -0,0 +1,43 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef __GFIG_POLY_H__
#define __GFIG_POLY_H__
void tool_options_poly (GtkWidget *notebook);
void d_paint_poly (GfigObject *obj);
void d_poly2lines (GfigObject *obj);
void d_star2lines (GfigObject *obj);
void d_poly_object_class_init (void);
void d_poly_start (GdkPoint *pnt,
gboolean shift_down);
void d_poly_end (PikaGfig *gfig,
GdkPoint *pnt,
gboolean shift_down);
#endif /* __GFIG_POLY_H__ */

View File

@ -0,0 +1,417 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <libpika/pika.h>
#include <libpika/pikaui.h>
#include "gfig.h"
#include "gfig-grid.h"
#include "gfig-dobject.h"
#include "gfig-preview.h"
#include "libpika/stdplugins-intl.h"
#define PREVIEW_MASK (GDK_EXPOSURE_MASK | \
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 gint x_pos_val;
static gint y_pos_val;
static gint pos_tag = -1;
GtkWidget *status_label_dname;
GtkWidget *status_label_fname;
static GtkWidget *pos_label; /* XY pos marker */
static void gfig_preview_realize (GtkWidget *widget);
static gboolean gfig_preview_events (GtkWidget *widget,
GdkEvent *event,
gpointer data);
static gboolean gfig_preview_draw (GtkWidget *widget,
cairo_t *cr);
static gint gfig_invscale_x (gint x);
static gint gfig_invscale_y (gint y);
static GtkWidget *gfig_pos_labels (void);
static GtkWidget *make_pos_info (void);
static void gfig_pos_update (gint x,
gint y);
static void gfig_pos_update_labels (gpointer data);
GtkWidget *
make_preview (PikaGfig *gfig)
{
GtkWidget *frame;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *grid;
GtkWidget *ruler;
gfig_context->preview = gtk_drawing_area_new ();
gtk_widget_set_events (GTK_WIDGET (gfig_context->preview), PREVIEW_MASK);
g_signal_connect (gfig_context->preview , "realize",
G_CALLBACK (gfig_preview_realize),
NULL);
g_signal_connect (gfig_context->preview , "event",
G_CALLBACK (gfig_preview_events),
gfig);
g_signal_connect_after (gfig_context->preview , "draw",
G_CALLBACK (gfig_preview_draw),
NULL);
gtk_widget_set_size_request (gfig_context->preview,
preview_width, preview_height);
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
grid = gtk_grid_new ();
gtk_grid_attach (GTK_GRID (grid), gfig_context->preview, 1, 1, 1, 1);
gtk_container_add (GTK_CONTAINER (frame), grid);
ruler = pika_ruler_new (GTK_ORIENTATION_HORIZONTAL);
pika_ruler_set_range (PIKA_RULER (ruler), 0, preview_width, PREVIEW_SIZE);
g_signal_connect_swapped (gfig_context->preview, "motion-notify-event",
G_CALLBACK (GTK_WIDGET_CLASS (G_OBJECT_GET_CLASS (ruler))->motion_notify_event),
ruler);
gtk_grid_attach (GTK_GRID (grid), ruler, 1, 0, 1, 1);
gtk_widget_show (ruler);
ruler = pika_ruler_new (GTK_ORIENTATION_VERTICAL);
pika_ruler_set_range (PIKA_RULER (ruler), 0, preview_height, PREVIEW_SIZE);
g_signal_connect_swapped (gfig_context->preview, "motion-notify-event",
G_CALLBACK (GTK_WIDGET_CLASS (G_OBJECT_GET_CLASS (ruler))->motion_notify_event),
ruler);
gtk_grid_attach (GTK_GRID (grid), ruler, 0, 1, 1, 1);
gtk_widget_show (ruler);
gtk_widget_show (frame);
gtk_widget_show (grid);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
frame = make_pos_info ();
gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
gtk_widget_show (vbox);
gtk_widget_show (hbox);
return vbox;
}
static void
gfig_preview_realize (GtkWidget *widget)
{
GdkDisplay *display = gtk_widget_get_display (widget);
gdk_window_set_cursor (gtk_widget_get_window (gfig_context->preview),
gdk_cursor_new_for_display (display, GDK_CROSSHAIR));
gfig_grid_colors (widget);
}
static void
draw_background (cairo_t *cr)
{
if (! back_pixbuf)
back_pixbuf = pika_image_get_thumbnail (gfig_context->image,
preview_width, preview_height,
PIKA_PIXBUF_LARGE_CHECKS);
if (back_pixbuf)
{
gdk_cairo_set_source_pixbuf (cr, back_pixbuf, 0, 0);
cairo_paint (cr);
}
}
static gboolean
gfig_preview_draw (GtkWidget *widget,
cairo_t *cr)
{
if (gfig_context->show_background)
draw_background (cr);
draw_grid (cr);
draw_objects (gfig_context->current_obj->obj_list, TRUE, cr);
if (obj_creating)
{
GList *single = g_list_prepend (NULL, obj_creating);
draw_objects (single, TRUE, cr);
g_list_free (single);
}
return FALSE;
}
static gboolean
gfig_preview_events (GtkWidget *widget,
GdkEvent *event,
gpointer data)
{
GdkEventButton *bevent;
GdkEventMotion *mevent;
GdkPoint point;
static gint tmp_show_single = 0;
switch (event->type)
{
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 (PIKA_GFIG (data), &point,
bevent->state & GDK_SHIFT_MASK);
/* If constraining save start pnt */
if (selvals.opts.snap2grid)
{
/* Save point to constrained point ... if button 3 down */
if (bevent->button == 3)
{
find_grid_pos (&point, &point, FALSE);
}
}
}
else
{
if (selvals.opts.snap2grid)
find_grid_pos (&point, &point, FALSE);
object_start (&point, bevent->state & GDK_SHIFT_MASK);
gtk_widget_queue_draw (widget);
}
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 (PIKA_GFIG (data), &point, bevent->state & GDK_SHIFT_MASK);
}
else
break;
}
gfig_paint_callback ();
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)
{
obj_creating->class->update (&point);
gtk_widget_queue_draw (widget);
}
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 ();
}
break;
case GDK_KEY_RELEASE:
if (tmp_show_single != -1)
{
obj_show_single = tmp_show_single;
draw_grid_clear ();
}
break;
default:
break;
}
return FALSE;
}
static GtkWidget *
make_pos_info (void)
{
GtkWidget *frame;
GtkWidget *hbox;
GtkWidget *label;
frame = pika_frame_new (_("Object Details"));
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_set_homogeneous (GTK_BOX (hbox), TRUE);
gtk_container_add (GTK_CONTAINER (frame), 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 (frame);
return frame;
}
static gint
gfig_invscale_x (gint x)
{
if (!selvals.scaletoimage)
return (gint) (x * scale_x_factor);
else
return x;
}
static gint
gfig_invscale_y (gint y)
{
if (!selvals.scaletoimage)
return (gint) (y * scale_y_factor);
else
return y;
}
static GtkWidget *
gfig_pos_labels (void)
{
GtkWidget *label;
GtkWidget *hbox;
gchar buf[256];
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 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;
}
void
gfig_pos_enable (GtkWidget *widget,
gpointer data)
{
gboolean enable = selvals.showpos;
gtk_widget_set_sensitive (GTK_WIDGET (pos_label), enable);
}
static void
gfig_pos_update_labels (gpointer data)
{
static gchar buf[256];
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)
{
if ((x_pos_val !=x || y_pos_val != y) && pos_tag == -1 && selvals.showpos)
{
x_pos_val = x;
y_pos_val = y;
gfig_pos_update_labels (NULL);
}
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef __GFIG_PREVIEW_H__
#define __GFIG_PREVIEW_H__
#define PREVIEW_SIZE 400
GtkWidget *make_preview (PikaGfig *gfig);
void gfig_pos_enable (GtkWidget *widget,
gpointer data);
#endif /* __GFIG_PREVIEW_H__ */

View File

@ -0,0 +1,219 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <libpika/pika.h>
#include <libpika/pikaui.h>
#include "gfig.h"
#include "gfig-dobject.h"
#include "gfig-rectangle.h"
#include "libpika/stdplugins-intl.h"
static void d_draw_rectangle (GfigObject *obj,
cairo_t *cr);
static void d_paint_rectangle (GfigObject *obj);
static GfigObject *d_copy_rectangle (GfigObject *obj);
static void d_update_rectangle (GdkPoint *pnt);
static void
d_draw_rectangle (GfigObject *obj,
cairo_t *cr)
{
DobjPoints *first_pnt;
DobjPoints *second_pnt;
gint xmin, ymin;
gint xmax, ymax;
first_pnt = obj->points;
if (!first_pnt)
return; /* End-of-line */
draw_sqr (&first_pnt->pnt, obj == gfig_context->selected_obj, cr);
second_pnt = first_pnt->next;
if (!second_pnt)
return;
if (obj == obj_creating)
draw_circle (&second_pnt->pnt, TRUE, cr);
else
draw_sqr (&second_pnt->pnt, obj == gfig_context->selected_obj, cr);
xmin = MIN (gfig_scale_x (first_pnt->pnt.x),
gfig_scale_x (second_pnt->pnt.x));
ymin = MIN (gfig_scale_y (first_pnt->pnt.y),
gfig_scale_y (second_pnt->pnt.y));
xmax = MAX (gfig_scale_x (first_pnt->pnt.x),
gfig_scale_x (second_pnt->pnt.x));
ymax = MAX (gfig_scale_y (first_pnt->pnt.y),
gfig_scale_y (second_pnt->pnt.y));
cairo_rectangle (cr, xmin + .5, ymin + .5, xmax - xmin, ymax - ymin);
draw_item (cr, FALSE);
}
static void
d_paint_rectangle (GfigObject *obj)
{
DobjPoints *first_pnt;
DobjPoints *second_pnt;
gdouble dpnts[4];
g_assert (obj != NULL);
/* Drawing rectangles is hard .
* 1) select rectangle
* 2) stroke it
*/
first_pnt = obj->points;
if (!first_pnt)
return; /* End-of-line */
second_pnt = first_pnt->next;
if (!second_pnt)
{
g_error ("Internal error - rectangle no second pnt");
}
dpnts[0] = (gdouble) MIN (first_pnt->pnt.x, second_pnt->pnt.x);
dpnts[1] = (gdouble) MIN (first_pnt->pnt.y, second_pnt->pnt.y);
dpnts[2] = (gdouble) MAX (first_pnt->pnt.x, second_pnt->pnt.x);
dpnts[3] = (gdouble) MAX (first_pnt->pnt.y, second_pnt->pnt.y);
/* Scale before drawing */
if (selvals.scaletoimage)
scale_to_original_xy (&dpnts[0], 2);
else
scale_to_xy (&dpnts[0], 2);
if (gfig_context_get_current_style ()->fill_type != FILL_NONE)
{
pika_context_push ();
pika_context_set_feather (selopt.feather);
pika_context_set_feather_radius (selopt.feather_radius, selopt.feather_radius);
pika_image_select_rectangle (gfig_context->image,
selopt.type,
dpnts[0], dpnts[1],
dpnts[2] - dpnts[0],
dpnts[3] - dpnts[1]);
pika_context_pop ();
paint_layer_fill (dpnts[0], dpnts[1], dpnts[2], dpnts[3]);
pika_selection_none (gfig_context->image);
}
if (obj->style.paint_type == PAINT_BRUSH_TYPE)
{
gdouble line_pnts[] = { dpnts[0], dpnts[1], dpnts[2], dpnts[1],
dpnts[2], dpnts[3], dpnts[0], dpnts[3],
dpnts[0], dpnts[1] };
gfig_paint (selvals.brshtype, gfig_context->drawable, 10, line_pnts);
}
}
static GfigObject *
d_copy_rectangle (GfigObject * obj)
{
GfigObject *new_rectangle;
g_assert (obj->type == RECTANGLE);
new_rectangle = d_new_object (RECTANGLE,
obj->points->pnt.x, obj->points->pnt.y);
new_rectangle->points->next = d_copy_dobjpoints (obj->points->next);
return new_rectangle;
}
void
d_rectangle_object_class_init (void)
{
GfigObjectClass *class = &dobj_class[RECTANGLE];
class->type = RECTANGLE;
class->name = "RECTANGLE";
class->drawfunc = d_draw_rectangle;
class->paintfunc = d_paint_rectangle;
class->copyfunc = d_copy_rectangle;
class->update = d_update_rectangle;
}
static void
d_update_rectangle (GdkPoint *pnt)
{
DobjPoints *first_pnt;
DobjPoints *second_pnt;
first_pnt = obj_creating->points;
if (!first_pnt)
return; /* No points */
if ((second_pnt = first_pnt->next))
{
second_pnt->pnt.x = pnt->x;
second_pnt->pnt.y = pnt->y;
}
else
{
second_pnt = new_dobjpoint (pnt->x, pnt->y);
first_pnt->next = second_pnt;
}
}
void
d_rectangle_start (GdkPoint *pnt,
gboolean shift_down)
{
obj_creating = d_new_object (RECTANGLE, pnt->x, pnt->y);
}
void
d_rectangle_end (PikaGfig *gfig,
GdkPoint *pnt,
gboolean shift_down)
{
/* Under control point */
if (!obj_creating->points->next)
{
/* No circle created */
free_one_obj (obj_creating);
}
else
{
add_to_all_obj (gfig, gfig_context->current_obj, obj_creating);
}
obj_creating = NULL;
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef __GFIG_RECTANGLE_H__
#define __GFIG_RECTANGLE_H__
void d_rectangle_object_class_init (void);
void d_rectangle_start (GdkPoint *pnt,
gboolean shift_down);
void d_rectangle_end (PikaGfig *gfig,
GdkPoint *pnt,
gboolean shift_down);
#endif /* __GFIG_RECTANGLE_H__ */

317
plug-ins/gfig/gfig-spiral.c Normal file
View File

@ -0,0 +1,317 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <stdlib.h>
#include <libpika/pika.h>
#include <libpika/pikaui.h>
#include "gfig.h"
#include "gfig-dobject.h"
#include "gfig-line.h"
#include "gfig-spiral.h"
#include "gfig-dialog.h"
#include "libpika/stdplugins-intl.h"
static void d_draw_spiral (GfigObject *obj,
cairo_t *cr);
static void d_paint_spiral (GfigObject *obj);
static GfigObject *d_copy_spiral (GfigObject *obj);
static void d_update_spiral (GdkPoint *pnt);
static gint spiral_num_turns = 4; /* Default to 4 turns */
static gint spiral_toggle = 0; /* 0 = clockwise -1 = anti-clockwise */
void
tool_options_spiral (GtkWidget *notebook)
{
GtkWidget *sides;
sides = num_sides_widget (_("Spiral Number of Turns"),
&spiral_num_turns, &spiral_toggle, 1, 20);
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), sides, NULL);
}
static void
d_draw_spiral (GfigObject *obj,
cairo_t *cr)
{
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 = { 0, 0 };
gboolean do_line = FALSE;
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 (&center_pnt->pnt, obj == gfig_context->selected_obj, cr);
/* 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 */
if (obj_creating == obj)
draw_circle (&radius_pnt->pnt, TRUE, cr);
else
draw_sqr (&radius_pnt->pnt, obj == gfig_context->selected_obj, cr);
/* 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 = obj->type_data / abs (obj->type_data);
if (offset_angle < 0)
offset_angle += 2.0 * G_PI;
sp_cons = radius/(obj->type_data * 2 * G_PI + offset_angle);
/* Lines */
ang_grid = 2.0 * G_PI / 180.0;
for (loop = 0 ; loop <= abs (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 = RINT (lx + center_pnt->pnt.x);
calc_pnt.y = 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;
gfig_draw_line (calc_pnt.x, calc_pnt.y, start_pnt.x, start_pnt.y, cr);
}
else
{
do_line = TRUE;
}
start_pnt = calc_pnt;
}
}
static void
d_paint_spiral (GfigObject *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 = { 0, 0 };
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 = obj->type_data / abs (obj->type_data);
offset_angle = atan2 (shift_y, shift_x);
if (offset_angle < 0)
offset_angle += 2.0 * G_PI;
sp_cons = radius/(obj->type_data * 2.0 * G_PI + offset_angle);
/* Lines */
ang_grid = 2.0 * G_PI / 180.0;
/* count - */
seg_count = abs (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 = RINT (lx + center_pnt->pnt.x);
calc_pnt.y = 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;
}
}
line_pnts[i++] = calc_pnt.x;
line_pnts[i++] = calc_pnt.y;
last_pnt = calc_pnt;
}
/* 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 (obj->style.paint_type == PAINT_BRUSH_TYPE)
{
gfig_paint (selvals.brshtype,
gfig_context->drawable,
i, line_pnts);
}
g_free (line_pnts);
}
static GfigObject *
d_copy_spiral (GfigObject *obj)
{
GfigObject *np;
g_assert (obj->type == SPIRAL);
np = d_new_object (SPIRAL, obj->points->pnt.x, obj->points->pnt.y);
np->points->next = d_copy_dobjpoints (obj->points->next);
np->type_data = obj->type_data;
return np;
}
void
d_spiral_object_class_init (void)
{
GfigObjectClass *class = &dobj_class[SPIRAL];
class->type = SPIRAL;
class->name = "SPIRAL";
class->drawfunc = d_draw_spiral;
class->paintfunc = d_paint_spiral;
class->copyfunc = d_copy_spiral;
class->update = d_update_spiral;
}
static void
d_update_spiral (GdkPoint *pnt)
{
DobjPoints *center_pnt;
DobjPoints *edge_pnt;
center_pnt = obj_creating->points;
if (!center_pnt)
return; /* No points */
if ((edge_pnt = center_pnt->next))
{
edge_pnt->pnt = *pnt;
}
else
{
/* Radius is a few pixels away */
/* First edge point */
d_pnt_add_line (obj_creating, pnt->x, pnt->y, -1);
}
}
void
d_spiral_start (GdkPoint *pnt,
gboolean shift_down)
{
obj_creating = d_new_object (SPIRAL, pnt->x, pnt->y);
obj_creating->type_data = spiral_num_turns * ((spiral_toggle == 0) ? 1 : -1);
}
void
d_spiral_end (PikaGfig *gfig,
GdkPoint *pnt,
gboolean shift_down)
{
add_to_all_obj (gfig, gfig_context->current_obj, obj_creating);
obj_creating = NULL;
}

View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef __GFIG_SPIRAL_H__
#define __GFIG_SPIRAL_H__
void tool_options_spiral (GtkWidget *notebook);
void d_spiral_object_class_init (void);
void d_spiral_start (GdkPoint *pnt,
gboolean shift_down);
void d_spiral_end (PikaGfig *gfig,
GdkPoint *pnt,
gboolean shift_down);
#endif /* __GFIG_SPIRAL_H__ */

407
plug-ins/gfig/gfig-star.c Normal file
View File

@ -0,0 +1,407 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <libpika/pika.h>
#include <libpika/pikaui.h>
#include "gfig.h"
#include "gfig-line.h"
#include "gfig-dobject.h"
#include "gfig-star.h"
#include "gfig-dialog.h"
#include "libpika/stdplugins-intl.h"
static gint star_num_sides = 3; /* Default to three sided object */
static void d_draw_star (GfigObject *obj,
cairo_t *cr);
static void d_paint_star (GfigObject *obj);
static GfigObject *d_copy_star (GfigObject *obj);
static void d_update_star (GdkPoint *pnt);
void
tool_options_star (GtkWidget *notebook)
{
GtkWidget *sides;
sides = num_sides_widget (_("Star Number of Points"),
&star_num_sides, NULL, 3, 200);
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), sides, NULL);
}
static void
d_draw_star (GfigObject *obj,
cairo_t *cr)
{
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 = { 0, 0 };
GdkPoint first_pnt = { 0, 0 };
gboolean do_line = FALSE;
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 (&center_pnt->pnt, obj == gfig_context->selected_obj, cr);
/* Next point defines the radius */
outer_radius_pnt = center_pnt->next; /* this defines the vertices */
if (!outer_radius_pnt)
{
return;
}
inner_radius_pnt = outer_radius_pnt->next; /* this defines the vertices */
if (!inner_radius_pnt)
{
return;
}
/* Other control points */
if (obj == obj_creating)
{
draw_circle (&outer_radius_pnt->pnt, TRUE, cr);
draw_circle (&inner_radius_pnt->pnt, TRUE, cr);
}
else
{
draw_sqr (&outer_radius_pnt->pnt, obj == gfig_context->selected_obj, cr);
draw_sqr (&inner_radius_pnt->pnt, obj == gfig_context->selected_obj, cr);
}
/* 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.0 * G_PI / (2.0 * (gdouble) 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 * 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 = RINT (lx + center_pnt->pnt.x);
calc_pnt.y = 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;
gfig_draw_line (calc_pnt.x, calc_pnt.y, start_pnt.x, start_pnt.y, cr);
}
else
{
do_line = TRUE;
first_pnt = calc_pnt;
}
start_pnt = calc_pnt;
}
gfig_draw_line (first_pnt.x, first_pnt.y, start_pnt.x, start_pnt.y, cr);
}
static void
d_paint_star (GfigObject *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 = { 0, 0 };
GdkPoint last_pnt = { 0, 0 };
gboolean first = TRUE;
gdouble *min_max;
g_assert (obj != NULL);
/* count - add one to close polygon */
seg_count = 2 * 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);
min_max = g_new (gdouble, 4);
/* 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 */
g_free (line_pnts);
g_free (min_max);
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 */
g_free (line_pnts);
g_free (min_max);
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.0 * G_PI / (2.0 * (gdouble) 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 * 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 = RINT (lx + center_pnt->pnt.x);
calc_pnt.y = 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;
}
}
line_pnts[i++] = calc_pnt.x;
line_pnts[i++] = calc_pnt.y;
last_pnt = calc_pnt;
if (first)
{
first_pnt = calc_pnt;
first = FALSE;
min_max[0] = min_max[2] = calc_pnt.x;
min_max[1] = min_max[3] = calc_pnt.y;
}
else
{
min_max[0] = MIN (min_max[0], calc_pnt.x);
min_max[1] = MIN (min_max[1], calc_pnt.y);
min_max[2] = MAX (min_max[2], calc_pnt.x);
min_max[3] = MAX (min_max[3], calc_pnt.y);
}
}
line_pnts[i++] = first_pnt.x;
line_pnts[i++] = first_pnt.y;
/* Scale before drawing */
if (selvals.scaletoimage)
{
scale_to_original_xy (&line_pnts[0], i / 2);
scale_to_original_xy (min_max, 2);
}
else
{
scale_to_xy (&line_pnts[0], i / 2);
scale_to_xy (min_max, 2);
}
if (gfig_context_get_current_style ()->fill_type != FILL_NONE)
{
pika_context_push ();
pika_context_set_antialias (selopt.antia);
pika_context_set_feather (selopt.feather);
pika_context_set_feather_radius (selopt.feather_radius, selopt.feather_radius);
pika_image_select_polygon (gfig_context->image,
selopt.type,
i, line_pnts);
pika_context_pop ();
paint_layer_fill (min_max[0], min_max[1], min_max[2], min_max[3]);
pika_selection_none (gfig_context->image);
}
if (obj->style.paint_type == PAINT_BRUSH_TYPE)
gfig_paint (selvals.brshtype, gfig_context->drawable, i, line_pnts);
g_free (line_pnts);
g_free (min_max);
}
static GfigObject *
d_copy_star (GfigObject *obj)
{
GfigObject *np;
g_assert (obj->type == STAR);
np = d_new_object (STAR, obj->points->pnt.x, obj->points->pnt.y);
np->points->next = d_copy_dobjpoints (obj->points->next);
np->type_data = obj->type_data;
return np;
}
void
d_star_object_class_init (void)
{
GfigObjectClass *class = &dobj_class[STAR];
class->type = STAR;
class->name = "STAR";
class->drawfunc = d_draw_star;
class->paintfunc = d_paint_star;
class->copyfunc = d_copy_star;
class->update = d_update_star;
}
static void
d_update_star (GdkPoint *pnt)
{
DobjPoints *center_pnt, *inner_pnt, *outer_pnt;
center_pnt = obj_creating->points;
if (!center_pnt)
return; /* No points */
if ((outer_pnt = center_pnt->next))
{
inner_pnt = outer_pnt->next;
outer_pnt->pnt = *pnt;
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);
/* 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);
}
}
void
d_star_start (GdkPoint *pnt,
gboolean shift_down)
{
obj_creating = d_new_object (STAR, pnt->x, pnt->y);
obj_creating->type_data = star_num_sides;
}
void
d_star_end (PikaGfig *gfig,
GdkPoint *pnt,
gboolean shift_down)
{
add_to_all_obj (gfig, gfig_context->current_obj, obj_creating);
obj_creating = NULL;
}

39
plug-ins/gfig/gfig-star.h Normal file
View File

@ -0,0 +1,39 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef __GFIG_STAR_H__
#define __GFIG_STAR_H__
void tool_options_star (GtkWidget *notebook);
void d_star_object_class_init (void);
void d_star_start (GdkPoint *pnt,
gboolean shift_down);
void d_star_end (PikaGfig *gfig,
GdkPoint *pnt,
gboolean shift_down);
#endif /* __GFIG_STAR_H__ */

800
plug-ins/gfig/gfig-style.c Normal file
View File

@ -0,0 +1,800 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <libpika/pika.h>
#include <libpika/pikaui.h>
#include "libpika/stdplugins-intl.h"
#include "gfig.h"
#include "gfig-dobject.h"
#include "gfig-style.h"
static void gfig_read_resource (gchar **text,
gint nitems,
const gchar *tag,
PikaResource **style_entry,
GType resource_type);
static void gfig_read_parameter_int (gchar **text,
gint nitems,
const gchar *name,
gint *style_entry);
static void gfig_read_parameter_double (gchar **text,
gint nitems,
const gchar *name,
gdouble *style_entry);
static void gfig_read_parameter_pika_rgb (gchar **text,
gint nitems,
const gchar *name,
PikaRGB *style_entry);
/* From a style string, read a resource name,
* create a resource object, and put it in
* given entry of a style.
*/
static void
gfig_read_resource (gchar **text,
gint nitems,
const gchar *tag,
PikaResource **style_entry,
GType resource_type)
{
gint n = 0;
gchar *ptr;
gchar *tmpstr;
while (n < nitems)
{
ptr = strchr (text[n], ':');
if (ptr)
{
tmpstr = g_strndup (text[n], ptr - text[n]);
ptr++;
if (!strcmp (tmpstr, tag))
{
const gchar *resource_name = g_strchug (ptr);
*style_entry = pika_resource_get_by_name (resource_type,
resource_name);
g_free (tmpstr);
return;
}
g_free (tmpstr);
}
++n;
}
*style_entry = NULL;
g_message ("Parameter '%s' not found", tag);
}
static void
gfig_read_parameter_int (gchar **text,
gint nitems,
const gchar *name,
gint *style_entry)
{
gint n = 0;
gchar *ptr;
gchar *tmpstr;
*style_entry = 0;
while (n < nitems)
{
ptr = strchr (text[n], ':');
if (ptr)
{
tmpstr = g_strndup (text[n], ptr - text[n]);
ptr++;
if (!strcmp (tmpstr, name))
{
*style_entry = atoi (g_strchug (ptr));
g_free (tmpstr);
return;
}
g_free (tmpstr);
}
++n;
}
}
static void
gfig_read_parameter_double (gchar **text,
gint nitems,
const gchar *name,
gdouble *style_entry)
{
gint n = 0;
gchar *ptr;
gchar *endptr;
gchar *tmpstr;
*style_entry = 0.;
while (n < nitems)
{
ptr = strchr (text[n], ':');
if (ptr)
{
tmpstr = g_strndup (text[n], ptr - text[n]);
ptr++;
if (!strcmp (tmpstr, name))
{
*style_entry = g_ascii_strtod (g_strchug (ptr), &endptr);
g_free (tmpstr);
return;
}
g_free (tmpstr);
}
++n;
}
}
static void
gfig_read_parameter_pika_rgb (gchar **text,
gint nitems,
const gchar *name,
PikaRGB *style_entry)
{
gint n = 0;
gchar *ptr;
gchar *tmpstr;
gchar *endptr;
gchar fmt_str[32];
gchar colorstr_r[G_ASCII_DTOSTR_BUF_SIZE];
gchar colorstr_g[G_ASCII_DTOSTR_BUF_SIZE];
gchar colorstr_b[G_ASCII_DTOSTR_BUF_SIZE];
gchar colorstr_a[G_ASCII_DTOSTR_BUF_SIZE];
style_entry->r = style_entry->g = style_entry->b = style_entry->a = 0.;
snprintf (fmt_str, sizeof (fmt_str),
"%%%" G_GSIZE_FORMAT "s"
" %%%" G_GSIZE_FORMAT "s"
" %%%" G_GSIZE_FORMAT "s"
" %%%" G_GSIZE_FORMAT "s",
sizeof (colorstr_r) - 1, sizeof (colorstr_g) - 1,
sizeof (colorstr_b) - 1, sizeof (colorstr_a) - 1);
while (n < nitems)
{
ptr = strchr (text[n], ':');
if (ptr)
{
tmpstr = g_strndup (text[n], ptr - text[n]);
ptr++;
if (!strcmp (tmpstr, name))
{
sscanf (ptr, fmt_str,
colorstr_r, colorstr_g, colorstr_b, colorstr_a);
style_entry->r = g_ascii_strtod (colorstr_r, &endptr);
style_entry->g = g_ascii_strtod (colorstr_g, &endptr);
style_entry->b = g_ascii_strtod (colorstr_b, &endptr);
style_entry->a = g_ascii_strtod (colorstr_a, &endptr);
g_free (tmpstr);
return;
}
g_free (tmpstr);
}
++n;
}
}
#define MAX_STYLE_TEXT_ENTRIES 100
gboolean
gfig_load_style (Style *style,
FILE *fp)
{
gulong offset;
gchar load_buf2[MAX_LOAD_LINE];
gchar *style_text[MAX_STYLE_TEXT_ENTRIES];
gint nitems = 0;
gint value;
gint k;
gchar name[100];
offset = ftell (fp);
get_line (load_buf2, MAX_LOAD_LINE, fp, 0);
/* nuke final > and preserve spaces in name */
if (1 != sscanf (load_buf2, "<Style %99[^>]>", name))
{
/* no style data, copy default style and fail silently */
gfig_style_copy (style, &gfig_context->default_style, "default style");
fseek (fp, offset, SEEK_SET);
return TRUE;
}
if (gfig_context->debug_styles)
g_printerr ("Loading style '%s' -- ", name);
style->name = g_strdup (name);
while (TRUE)
{
get_line (load_buf2, MAX_LOAD_LINE, fp, 0);
if (!strcmp (load_buf2, "</Style>") || feof (fp))
break;
style_text[nitems] = g_strdup (load_buf2);
nitems++;
if (nitems >= MAX_STYLE_TEXT_ENTRIES)
break;
}
if (feof (fp) || (nitems >= MAX_STYLE_TEXT_ENTRIES))
{
g_message ("Error reading style data");
return TRUE;
}
gfig_read_resource (style_text, nitems, "BrushName",
(PikaResource**) &style->brush, PIKA_TYPE_BRUSH);
if (style->brush == NULL)
g_message ("Error loading style: missing brush.");
gfig_read_resource (style_text, nitems, "Pattern",
(PikaResource**) &style->pattern, PIKA_TYPE_PATTERN);
gfig_read_resource (style_text, nitems, "Gradient",
(PikaResource**) &style->gradient, PIKA_TYPE_GRADIENT);
gfig_read_parameter_pika_rgb (style_text, nitems, "Foreground",
&style->foreground);
gfig_read_parameter_pika_rgb (style_text, nitems, "Background",
&style->background);
gfig_read_parameter_int (style_text, nitems, "FillType", &value);
style->fill_type = value;
gfig_read_parameter_int (style_text, nitems, "PaintType", &value);
style->paint_type = value;
gfig_read_parameter_double (style_text, nitems, "FillOpacity",
&style->fill_opacity);
for (k = 0; k < nitems; k++)
{
g_free (style_text[k]);
}
if (gfig_context->debug_styles)
g_printerr ("done\n");
return FALSE;
}
gboolean
gfig_skip_style (Style *style,
FILE *fp)
{
gulong offset;
gchar load_buf2[MAX_LOAD_LINE];
offset = ftell (fp);
get_line (load_buf2, MAX_LOAD_LINE, fp, 0);
if (strncmp (load_buf2, "<Style ", 7))
{
/* no style data */
fseek (fp, offset, SEEK_SET);
return TRUE;
}
while (TRUE)
{
get_line (load_buf2, MAX_LOAD_LINE, fp, 0);
if (!strcmp (load_buf2, "</Style>") || feof (fp))
break;
}
if (feof (fp))
{
g_message ("Error trying to skip style data");
return TRUE;
}
return FALSE;
}
/*
* FIXME: need to make this load a list of styles if there are more than one.
*/
gboolean
gfig_load_styles (GFigObj *gfig,
FILE *fp)
{
if (gfig_context->debug_styles)
g_printerr ("Loading global styles -- ");
/* currently we only have the default style */
gfig_load_style (&gfig_context->default_style, fp);
if (gfig_context->debug_styles)
g_printerr ("done\n");
return FALSE;
}
void
gfig_save_style (Style *style,
GString *string)
{
gchar buffer[G_ASCII_DTOSTR_BUF_SIZE];
gchar buffer_r[G_ASCII_DTOSTR_BUF_SIZE];
gchar buffer_g[G_ASCII_DTOSTR_BUF_SIZE];
gchar buffer_b[G_ASCII_DTOSTR_BUF_SIZE];
gchar buffer_a[G_ASCII_DTOSTR_BUF_SIZE];
gint blen = G_ASCII_DTOSTR_BUF_SIZE;
if (gfig_context->debug_styles)
g_printerr ("Saving style %s, brush name '%s'\n", style->name,
pika_resource_get_name (PIKA_RESOURCE (style->brush)));
g_string_append_printf (string, "<Style %s>\n", style->name);
g_string_append_printf (string, "BrushName: %s\n",
pika_resource_get_name (PIKA_RESOURCE (style->brush)));
if (!style->brush)
g_message ("Error saving style %s: saving NULL for brush name", style->name);
g_string_append_printf (string, "PaintType: %d\n", style->paint_type);
g_string_append_printf (string, "FillType: %d\n", style->fill_type);
g_string_append_printf (string, "FillOpacity: %s\n",
g_ascii_dtostr (buffer, blen, style->fill_opacity));
g_string_append_printf (string, "Pattern: %s\n",
pika_resource_get_name (PIKA_RESOURCE (style->pattern)));
g_string_append_printf (string, "Gradient: %s\n",
pika_resource_get_name (PIKA_RESOURCE (style->gradient)));
g_string_append_printf (string, "Foreground: %s %s %s %s\n",
g_ascii_dtostr (buffer_r, blen, style->foreground.r),
g_ascii_dtostr (buffer_g, blen, style->foreground.g),
g_ascii_dtostr (buffer_b, blen, style->foreground.b),
g_ascii_dtostr (buffer_a, blen, style->foreground.a));
g_string_append_printf (string, "Background: %s %s %s %s\n",
g_ascii_dtostr (buffer_r, blen, style->background.r),
g_ascii_dtostr (buffer_g, blen, style->background.g),
g_ascii_dtostr (buffer_b, blen, style->background.b),
g_ascii_dtostr (buffer_a, blen, style->background.a));
g_string_append_printf (string, "</Style>\n");
}
void
gfig_style_save_as_attributes (Style *style,
GString *string)
{
gchar buffer[G_ASCII_DTOSTR_BUF_SIZE];
gchar buffer_r[G_ASCII_DTOSTR_BUF_SIZE];
gchar buffer_g[G_ASCII_DTOSTR_BUF_SIZE];
gchar buffer_b[G_ASCII_DTOSTR_BUF_SIZE];
gchar buffer_a[G_ASCII_DTOSTR_BUF_SIZE];
gint blen = G_ASCII_DTOSTR_BUF_SIZE;
if (gfig_context->debug_styles)
g_printerr ("Saving style %s as attributes\n", style->name);
/* Tags must match the ones written, see below in the code. */
g_string_append_printf (string, "BrushName=\"%s\" ",
pika_resource_get_name (PIKA_RESOURCE (style->brush)));
/* Why only brush and not pattern and gradient? */
g_string_append_printf (string, "Foreground=\"%s %s %s %s\" ",
g_ascii_dtostr (buffer_r, blen, style->foreground.r),
g_ascii_dtostr (buffer_g, blen, style->foreground.g),
g_ascii_dtostr (buffer_b, blen, style->foreground.b),
g_ascii_dtostr (buffer_a, blen, style->foreground.a));
g_string_append_printf (string, "Background=\"%s %s %s %s\" ",
g_ascii_dtostr (buffer_r, blen, style->background.r),
g_ascii_dtostr (buffer_g, blen, style->background.g),
g_ascii_dtostr (buffer_b, blen, style->background.b),
g_ascii_dtostr (buffer_a, blen, style->background.a));
g_string_append_printf (string, "FillType=%d ", style->fill_type);
g_string_append_printf (string, "PaintType=%d ", style->paint_type);
g_string_append_printf (string, "FillOpacity=%s ",
g_ascii_dtostr (buffer, blen, style->fill_opacity));
}
void
gfig_save_styles (GString *string)
{
if (gfig_context->debug_styles)
g_printerr ("Saving global styles.\n");
gfig_save_style (&gfig_context->default_style, string);
}
/*
* set_foreground_callback() is the callback for the Foreground color select
* widget. It reads the color from the widget, and applies this color to the
* current style. It then produces a repaint (which will be suppressed if
* gfig_context->enable_repaint is FALSE).
*/
void
set_foreground_callback (PikaColorButton *button,
gpointer data)
{
PikaRGB color2;
Style *current_style;
if (gfig_context->debug_styles)
g_printerr ("Setting foreground color from color selector\n");
current_style = gfig_context_get_current_style ();
pika_color_button_get_color (button, &color2);
pika_rgba_set (&current_style->foreground,
color2.r, color2.g, color2.b, color2.a);
gfig_paint_callback ();
}
void
set_background_callback (PikaColorButton *button,
gpointer data)
{
PikaRGB color2;
Style *current_style;
if (gfig_context->debug_styles)
g_printerr ("Setting background color from color selector\n");
current_style = gfig_context_get_current_style ();
pika_color_button_get_color (button, &color2);
pika_rgba_set (&current_style->background,
color2.r, color2.g, color2.b, color2.a);
gfig_paint_callback ();
}
void
set_paint_type_callback (GtkToggleButton *toggle,
gpointer data)
{
gboolean paint_type;
Style *current_style;
current_style = gfig_context_get_current_style ();
paint_type = gtk_toggle_button_get_active (toggle);
current_style->paint_type = paint_type;
gfig_paint_callback ();
gtk_widget_set_sensitive (GTK_WIDGET (data), paint_type);
}
/*
* gfig_brush_changed_callback() is the callback for the brush
* selector widget. It receives the brush from the widget, and
* sets the brush in the current style, as well as the gfig_context->bdesc
* values. It then produces a repaint (which will be suppressed if
* gfig_context->enable_repaint is FALSE).
*/
void
gfig_brush_changed_callback (gpointer user_data,
PikaBrush *brush,
gboolean dialog_closing)
{
Style *current_style;
current_style = gfig_context_get_current_style ();
current_style->brush = brush;
/* this will soon be unneeded. How soon? */
set_context_bdesc (brush);
pika_context_set_brush (brush);
pika_context_set_brush_default_size ();
gfig_paint_callback ();
}
void
gfig_pattern_changed_callback (gpointer user_data,
PikaPattern *pattern,
gboolean dialog_closing)
{
Style *current_style;
current_style = gfig_context_get_current_style ();
current_style->pattern = pattern;
gfig_paint_callback ();
}
void
gfig_gradient_changed_callback (gpointer user_data,
PikaGradient *gradient,
gboolean dialog_closing)
{
Style *current_style;
current_style = gfig_context_get_current_style ();
current_style->gradient = gradient;
gfig_paint_callback ();
}
void
gfig_rgba_copy (PikaRGB *color1,
PikaRGB *color2)
{
color1->r = color2->r;
color1->g = color2->g;
color1->b = color2->b;
color1->a = color2->a;
}
void
gfig_style_copy (Style *style1,
Style *style0,
const gchar *name)
{
if (name)
style1->name = g_strdup (name);
else
g_message ("Error: name is NULL in gfig_style_copy.");
if (gfig_context->debug_styles)
g_printerr ("Copying style %s as style %s\n", style0->name, name);
gfig_rgba_copy (&style1->foreground, &style0->foreground);
gfig_rgba_copy (&style1->background, &style0->background);
if (!style0->brush)
g_message ("Error copying style %s: brush name is NULL.", style0->name);
/* ownership issues ? */
style1->brush = style0->brush;
style1->gradient = style0->gradient;
style1->pattern = style0->pattern;
style1->fill_type = style0->fill_type;
style1->fill_opacity = style0->fill_opacity;
style1->paint_type = style0->paint_type;
}
/*
* gfig_style_apply() applies the settings from the specified style to
* the PIKA core. It does not change any widgets, and does not cause
* a repaint.
*/
void
gfig_style_apply (Style *style)
{
if (gfig_context->debug_styles)
g_printerr ("Applying style '%s' -- ", style->name);
pika_context_set_foreground (&style->foreground);
pika_context_set_background (&style->background);
if (! pika_context_set_brush (style->brush))
g_message ("Style apply: Failed to set brush to '%s' in style '%s'",
pika_resource_get_name (PIKA_RESOURCE (style->brush)),
style->name);
pika_context_set_brush_default_size ();
g_assert (style->pattern != NULL);
pika_context_set_pattern (style->pattern);
pika_context_set_gradient (style->gradient);
if (gfig_context->debug_styles)
g_printerr ("done.\n");
}
/*
* gfig_read_pika_style() reads the style settings from the Pika core,
* and applies them to the specified style, giving that style the
* specified name. This is mainly useful as a way of initializing
* a style. The function does not cause a repaint.
*/
void
gfig_read_pika_style (Style *style,
const gchar *name)
{
gint dummy;
if (!name)
g_message ("Error: name is NULL in gfig_read_pika_style.");
if (gfig_context->debug_styles)
g_printerr ("Reading Pika settings as style %s\n", name);
style->name = g_strdup (name);
pika_context_get_foreground (&style->foreground);
pika_context_get_background (&style->background);
style->brush = pika_context_get_brush ();
style->gradient = pika_context_get_gradient ();
style->pattern = pika_context_get_pattern ();
style->fill_opacity = 100.;
/* Cache attributes of brush. */
pika_brush_get_info (style->brush,
&style->brush_width, &style->brush_height,
&dummy, &dummy);
style->brush_spacing = pika_brush_get_spacing (style->brush);
set_context_bdesc (style->brush);
}
/*
* gfig_style_set_content_from_style() sets all of the style control widgets
* to values from the specified style. This in turn sets the Pika core's
* values to the same things. Repainting is suppressed while this happens,
* so calling this function will not produce a repaint.
*
*/
void
gfig_style_set_context_from_style (Style *style)
{
gboolean enable_repaint;
if (gfig_context->debug_styles)
g_printerr ("Setting context from style '%s' -- ", style->name);
enable_repaint = gfig_context->enable_repaint;
gfig_context->enable_repaint = FALSE;
pika_color_button_set_color (PIKA_COLOR_BUTTON (gfig_context->fg_color_button),
&style->foreground);
pika_color_button_set_color (PIKA_COLOR_BUTTON (gfig_context->bg_color_button),
&style->background);
if (! pika_context_set_brush (style->brush))
g_message ("Style from context: Failed to set brush");
pika_context_set_brush_default_size ();
pika_resource_select_button_set_resource (PIKA_RESOURCE_SELECT_BUTTON (gfig_context->brush_select),
PIKA_RESOURCE (style->brush));
pika_resource_select_button_set_resource (PIKA_RESOURCE_SELECT_BUTTON (gfig_context->pattern_select),
PIKA_RESOURCE (style->pattern));
pika_resource_select_button_set_resource (PIKA_RESOURCE_SELECT_BUTTON (gfig_context->gradient_select),
PIKA_RESOURCE (style->gradient));
set_context_bdesc (style->brush);
if (gfig_context->debug_styles)
g_printerr ("done.\n");
pika_int_combo_box_set_active (PIKA_INT_COMBO_BOX (gfig_context->fillstyle_combo),
(gint) style->fill_type);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gfig_context->paint_type_toggle),
style->paint_type);
gfig_context->enable_repaint = enable_repaint;
}
/*
* gfig_style_set_style_from_context() sets the values in the specified
* style to those that appear in the style control widgets f
*/
void
gfig_style_set_style_from_context (Style *style)
{
Style *current_style;
PikaRGB color;
gint value;
style->name = "object";
current_style = gfig_context_get_current_style ();
pika_color_button_get_color (PIKA_COLOR_BUTTON (gfig_context->fg_color_button),
&color);
if (gfig_context->debug_styles)
g_printerr ("Setting foreground color to %lg %lg %lg\n",
color.r, color.g, color.b);
gfig_rgba_copy (&style->foreground, &color);
pika_color_button_get_color (PIKA_COLOR_BUTTON (gfig_context->bg_color_button),
&color);
gfig_rgba_copy (&style->background, &color);
/* FIXME: issues of ownership.
* A resource is a pointer to an object.
* We own each resource object returned by pika_context_get_<resource> and should unref it.
* Here this is possibly overwriting a reference that should be unreffed.
* Also, this is copying a reference, so we should ref the object.
*
* For now, its just a plugin, we don't care much about leaks.
*/
style->brush = current_style->brush;
style->pattern = current_style->pattern;
style->gradient = current_style->gradient;
if (pika_int_combo_box_get_active (PIKA_INT_COMBO_BOX (gfig_context->fillstyle_combo), &value))
style->fill_type = value;
/* FIXME when there is an opacity control widget to read */
style->fill_opacity = 100.;
style->paint_type = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (gfig_context->paint_type_toggle));
}
/* Set bdesc from brush. Side effects on gfig_context->bdesc */
void
set_context_bdesc (PikaBrush *brush)
{
gint width;
gint height;
gint dummy;
g_return_if_fail (brush != NULL);
g_return_if_fail (PIKA_IS_BRUSH (brush));
if (brush && pika_brush_get_info (brush, &width, &height, &dummy, &dummy))
{
gfig_context->bdesc.brush = brush;
gfig_context->bdesc.width = MAX (width, 32);
gfig_context->bdesc.height = MAX (height, 32);
}
else
{
g_message ("Failed to get brush info");
gfig_context->bdesc.width = 48;
gfig_context->bdesc.height = 48;
}
}
Style *
gfig_context_get_current_style (void)
{
if (gfig_context->selected_obj)
return &gfig_context->selected_obj->style;
else
return &gfig_context->default_style;
}

111
plug-ins/gfig/gfig-style.h Normal file
View File

@ -0,0 +1,111 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef __GFIG_STYLE_H__
#define __GFIG_STYLE_H__
#include <libpika/pikaui.h>
struct _Style
{
gchar *name;
PikaBrush *brush;
PikaPattern *pattern;
PikaGradient *gradient;
gint brush_width;
gint brush_height;
gint brush_spacing;
BrushType brush_type;
gdouble brushfade;
gdouble brushgradient;
gdouble airbrushpressure;
FillType fill_type;
gdouble fill_opacity;
PaintType paint_type;
PikaRGB foreground;
PikaRGB background;
gboolean reverselines;
gint ref_count;
};
gboolean gfig_load_style (Style *style,
FILE *fp);
gboolean gfig_skip_style (Style *style,
FILE *fp);
gboolean gfig_load_styles (GFigObj *gfig,
FILE *fp);
void gfig_save_style (Style *style,
GString *string);
void gfig_style_save_as_attributes (Style *style,
GString *string);
void gfig_save_styles (GString *string);
void set_foreground_callback (PikaColorButton *button,
gpointer data);
void set_background_callback (PikaColorButton *button,
gpointer data);
void set_paint_type_callback (GtkToggleButton *toggle,
gpointer data);
void gfig_brush_changed_callback (gpointer user_data,
PikaBrush *brush,
gboolean dialog_closing);
void gfig_pattern_changed_callback (gpointer user_data,
PikaPattern *pattern,
gboolean dialog_closing);
void gfig_gradient_changed_callback (gpointer user_data,
PikaGradient *gradient,
gboolean dialog_closing);
void gfig_rgba_copy (PikaRGB *color1,
PikaRGB *color2);
void gfig_style_copy (Style *style1,
Style *style0,
const gchar *name);
void gfig_style_apply (Style *style);
void gfig_read_pika_style (Style *style,
const gchar *name);
void gfig_style_set_context_from_style (Style *style);
void gfig_style_set_style_from_context (Style *style);
void set_context_bdesc (PikaBrush *brush);
Style *gfig_context_get_current_style (void);
#endif /* __GFIG_STYLE_H__ */

107
plug-ins/gfig/gfig-types.h Normal file
View File

@ -0,0 +1,107 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef __GFIG_TYPES_H__
#define __GFIG_TYPES_H__
typedef enum
{
RECT_GRID = 0,
POLAR_GRID,
ISO_GRID
} GridType;
typedef enum
{
ARC_SEGMENT = 0,
ARC_SECTOR
} ArcType;
typedef enum
{
FILL_NONE = 0,
FILL_COLOR,
FILL_PATTERN,
FILL_GRADIENT,
FILL_VERTICAL,
FILL_HORIZONTAL
} FillType;
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_NONE = 0,
PAINT_BRUSH_TYPE = 1
} PaintType;
typedef enum
{
BRUSH_BRUSH_TYPE = 0,
BRUSH_PENCIL_TYPE,
BRUSH_AIRBRUSH_TYPE,
BRUSH_PATTERN_TYPE
} BrushType;
typedef enum
{
OBJ_TYPE_NONE = 0,
LINE,
RECTANGLE,
CIRCLE,
ELLIPSE,
ARC,
POLY,
STAR,
SPIRAL,
BEZIER,
NUM_OBJ_TYPES,
MOVE_OBJ,
MOVE_POINT,
COPY_OBJ,
MOVE_COPY_OBJ,
DEL_OBJ,
SELECT_OBJ,
NULL_OPER
} DobjType;
typedef struct _GFigObj GFigObj;
typedef struct _GfigObject GfigObject;
typedef struct _Style Style;
#endif /* __GFIG_TYPES_H__ */

912
plug-ins/gfig/gfig.c Normal file
View File

@ -0,0 +1,912 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <glib/gstdio.h>
#include <libpika/pika.h>
#include <libpika/pikaui.h>
#include "gfig.h"
#include "gfig-style.h"
#include "gfig-dialog.h"
#include "gfig-arc.h"
#include "gfig-bezier.h"
#include "gfig-circle.h"
#include "gfig-dobject.h"
#include "gfig-ellipse.h"
#include "gfig-grid.h"
#include "gfig-icons.h"
#include "gfig-line.h"
#include "gfig-poly.h"
#include "gfig-preview.h"
#include "gfig-spiral.h"
#include "gfig-star.h"
#include "libpika/stdplugins-intl.h"
#define GFIG_HEADER "GFIG Version 0.2\n"
GType gfig_get_type (void) G_GNUC_CONST;
static void pika_gfig_finalize (GObject *object);
static GList * gfig_query_procedures (PikaPlugIn *plug_in);
static PikaProcedure * gfig_create_procedure (PikaPlugIn *plug_in,
const gchar *name);
static PikaValueArray * gfig_run (PikaProcedure *procedure,
PikaRunMode run_mode,
PikaImage *image,
gint n_drawables,
PikaDrawable **drawables,
const PikaValueArray *args,
gpointer run_data);
static void on_app_activate (GApplication *gapp,
gpointer user_data);
static gint load_options (GFigObj *gfig,
FILE *fp);
G_DEFINE_TYPE (PikaGfig, pika_gfig, PIKA_TYPE_PLUG_IN)
PIKA_MAIN (PIKA_TYPE_GFIG)
DEFINE_STD_SET_I18N
gint line_no;
gint obj_show_single = -1; /* -1 all >= 0 object number */
/* Structures etc for the objects */
/* Points used to draw the object */
GfigObject *obj_creating; /* Object we are creating */
GfigObject *tmp_line; /* Needed when drawing lines */
gboolean need_to_scale;
/* globals */
GfigObjectClass dobj_class[10];
GFigContext *gfig_context;
GtkWidget *top_level_dlg;
GList *gfig_list;
gdouble org_scale_x_factor, org_scale_y_factor;
/* Stuff for the preview bit */
static gint sel_x, sel_y;
static gint sel_width, sel_height;
gint preview_width, preview_height;
gdouble scale_x_factor, scale_y_factor;
GdkPixbuf *back_pixbuf = NULL;
static void
pika_gfig_class_init (PikaGfigClass *klass)
{
PikaPlugInClass *plug_in_class = PIKA_PLUG_IN_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = pika_gfig_finalize;
plug_in_class->query_procedures = gfig_query_procedures;
plug_in_class->create_procedure = gfig_create_procedure;
plug_in_class->set_i18n = STD_SET_I18N;
}
static void
pika_gfig_init (PikaGfig *gfig)
{
}
static void
pika_gfig_finalize (GObject *object)
{
PikaGfig *gfig = PIKA_GFIG (object);
G_OBJECT_CLASS (pika_gfig_parent_class)->finalize (object);
g_clear_object (&gfig->builder);
}
static GList *
gfig_query_procedures (PikaPlugIn *plug_in)
{
return g_list_append (NULL, g_strdup (PLUG_IN_PROC));
}
static PikaProcedure *
gfig_create_procedure (PikaPlugIn *plug_in,
const gchar *name)
{
PikaProcedure *procedure = NULL;
if (! strcmp (name, PLUG_IN_PROC))
{
procedure = pika_image_procedure_new (plug_in, name,
PIKA_PDB_PROC_TYPE_PLUGIN,
gfig_run, NULL, NULL);
pika_procedure_set_image_types (procedure, "RGB*, GRAY*");
pika_procedure_set_sensitivity_mask (procedure,
PIKA_PROCEDURE_SENSITIVE_DRAWABLE);
pika_procedure_set_menu_label (procedure, _("_Gfig..."));
pika_procedure_add_menu_path (procedure, "<Image>/Filters/Render");
pika_procedure_set_documentation (procedure,
_("Create geometric shapes"),
"Draw Vector Graphics and paint them "
"onto your images. Gfig allows you "
"to draw many types of objects "
"including Lines, Circles, Ellipses, "
"Curves, Polygons, pointed stars, "
"Bezier curves, and Spirals. "
"Objects can be painted using "
"Brushes or other tools or filled "
"using colors or patterns. "
"Gfig objects can also be used to "
"create selections.",
name);
pika_procedure_set_attribution (procedure,
"Andy Thomas",
"Andy Thomas",
"1997");
}
return procedure;
}
static PikaValueArray *
gfig_run (PikaProcedure *procedure,
PikaRunMode run_mode,
PikaImage *image,
gint n_drawables,
PikaDrawable **drawables,
const PikaValueArray *args,
gpointer run_data)
{
PikaDrawable *drawable;
PikaPDBStatusType status = PIKA_PDB_SUCCESS;
gint pwidth, pheight;
PikaGfig *gfig;
if (n_drawables != 1)
{
GError *error = NULL;
g_set_error (&error, PIKA_PLUG_IN_ERROR, 0,
_("Procedure '%s' only works with one drawable."),
pika_procedure_get_name (procedure));
return pika_procedure_new_return_values (procedure,
PIKA_PDB_CALLING_ERROR,
error);
}
else
{
drawable = drawables[0];
}
gfig = PIKA_GFIG (pika_procedure_get_plug_in (procedure));
#if GLIB_CHECK_VERSION(2,74,0)
gfig->app = gtk_application_new (NULL, G_APPLICATION_DEFAULT_FLAGS);
#else
gfig->app = gtk_application_new (NULL, G_APPLICATION_FLAGS_NONE);
#endif
gfig->success = FALSE;
gfig->builder = gtk_builder_new_from_resource ("/technology.heckin/gfig/gfig-menu.ui");
gfig_context = g_new0 (GFigContext, 1);
gfig_context->show_background = TRUE;
gfig_context->selected_obj = NULL;
gfig_context->image = image;
gfig_context->drawable = drawable;
pika_image_undo_group_start (gfig_context->image);
pika_context_push ();
/* TMP Hack - clear any selections */
if (! pika_selection_is_empty (gfig_context->image))
pika_selection_none (gfig_context->image);
if (! pika_drawable_mask_intersect (drawable, &sel_x, &sel_y,
&sel_width, &sel_height))
{
pika_context_pop ();
pika_image_undo_group_end (gfig_context->image);
return pika_procedure_new_return_values (procedure, status, NULL);
}
/* 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;
/* initialize */
gfig_init_object_classes ();
switch (run_mode)
{
case PIKA_RUN_INTERACTIVE:
case PIKA_RUN_WITH_LAST_VALS:
g_signal_connect (gfig->app, "activate", G_CALLBACK (on_app_activate), gfig);
g_application_run (G_APPLICATION (gfig->app), 0, NULL);
g_clear_object (&gfig->app);
if (! gfig->success)
{
pika_image_undo_group_end (gfig_context->image);
return pika_procedure_new_return_values (procedure, PIKA_PDB_CANCEL,
NULL);
}
break;
case PIKA_RUN_NONINTERACTIVE:
status = PIKA_PDB_CALLING_ERROR;
break;
default:
break;
}
pika_context_pop ();
pika_image_undo_group_end (gfig_context->image);
if (run_mode != PIKA_RUN_NONINTERACTIVE)
pika_displays_flush ();
return pika_procedure_new_return_values (procedure, status, NULL);
}
static void
on_app_activate (GApplication *gapp,
gpointer user_data)
{
PikaGfig *gfig = PIKA_GFIG (user_data);
gfig_dialog (gfig);
gtk_application_set_accels_for_action (gfig->app, "app.open", (const char*[]) { "<control>O", NULL });
gtk_application_set_accels_for_action (gfig->app, "app.save", (const char*[]) { "<control>S", NULL });
gtk_application_set_accels_for_action (gfig->app, "app.close", (const char*[]) { "<control>C", NULL });
gtk_application_set_accels_for_action (gfig->app, "app.undo", (const char*[]) { "<control>Z", NULL });
gtk_application_set_accels_for_action (gfig->app, "app.clear", (const char*[]) { NULL });
gtk_application_set_accels_for_action (gfig->app, "app.grid", (const char*[]) { "<control>G", NULL });
gtk_application_set_accels_for_action (gfig->app, "app.preferences", (const char*[]) { "<control>P", NULL });
gtk_application_set_accels_for_action (gfig->app, "app.shape::line", (const char*[]) { "L", NULL });
gtk_application_set_accels_for_action (gfig->app, "app.shape::rectangle", (const char*[]) { "R", NULL });
gtk_application_set_accels_for_action (gfig->app, "app.shape::circle", (const char*[]) { "C", NULL });
gtk_application_set_accels_for_action (gfig->app, "app.shape::ellipse", (const char*[]) { "E", NULL });
gtk_application_set_accels_for_action (gfig->app, "app.shape::arc", (const char*[]) { "A", NULL });
gtk_application_set_accels_for_action (gfig->app, "app.shape::polygon", (const char*[]) { "P", NULL });
gtk_application_set_accels_for_action (gfig->app, "app.shape::star", (const char*[]) { "S", NULL });
gtk_application_set_accels_for_action (gfig->app, "app.shape::spiral", (const char*[]) { "I", NULL });
gtk_application_set_accels_for_action (gfig->app, "app.shape::bezier", (const char*[]) { "B", NULL });
gtk_application_set_accels_for_action (gfig->app, "app.shape::move-obj", (const char*[]) { "M", NULL });
gtk_application_set_accels_for_action (gfig->app, "app.shape::move-point", (const char*[]) { "V", NULL });
gtk_application_set_accels_for_action (gfig->app, "app.shape::copy", (const char*[]) { "Y", NULL });
gtk_application_set_accels_for_action (gfig->app, "app.shape::delete", (const char*[]) { "D", NULL });
gtk_application_set_accels_for_action (gfig->app, "app.shape::select", (const char*[]) { "A", NULL });
}
/*
Translate SPACE to "\\040", etc.
Taken from gflare plugin
*/
void
gfig_name_encode (gchar *dest,
gchar *src)
{
gint cnt = MAX_LOAD_LINE - 1;
while (*src && cnt--)
{
if (g_ascii_iscntrl (*src) || g_ascii_isspace (*src) || *src == '\\')
{
sprintf (dest, "\\%03o", *src++);
dest += 4;
}
else
*dest++ = *src++;
}
*dest = '\0';
}
/*
Translate "\\040" to SPACE, etc.
*/
void
gfig_name_decode (gchar *dest,
const gchar *src)
{
gint cnt = MAX_LOAD_LINE - 1;
guint 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.
*/
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;
}
/*
* Insert gfigs in alphabetical order
*/
gint
gfig_list_insert (GFigObj *gfig)
{
gint n;
n = gfig_list_pos (gfig);
gfig_list = g_list_insert (gfig_list, gfig, n);
return n;
}
void
gfig_free (GFigObj *gfig)
{
g_assert (gfig != NULL);
free_all_objs (gfig->obj_list);
g_free (gfig->name);
g_free (gfig->filename);
g_free (gfig->draw_name);
g_free (gfig);
}
GFigObj *
gfig_new (void)
{
return g_new0 (GFigObj, 1);
}
static void
gfig_load_objs (PikaGfig *gfig,
GFigObj *gfig_obj,
gint load_count,
FILE *fp)
{
GfigObject *obj;
gchar load_buf[MAX_LOAD_LINE];
glong offset;
glong offset2;
Style style;
while (load_count-- > 0)
{
obj = NULL;
get_line (load_buf, MAX_LOAD_LINE, fp, 0);
/* kludge */
offset = ftell (fp);
gfig_skip_style (&style, fp);
obj = d_load_object (load_buf, fp);
if (obj)
{
add_to_all_obj (gfig, gfig_obj, obj);
offset2 = ftell (fp);
fseek (fp, offset, SEEK_SET);
gfig_load_style (&obj->style, fp);
fseek (fp, offset2, SEEK_SET);
}
else
{
g_message ("Failed to load object, load count = %d", load_count);
}
}
}
GFigObj *
gfig_load (PikaGfig *gfig,
const gchar *filename,
const gchar *name)
{
GFigObj *gfig_obj;
FILE *fp;
gchar load_buf[MAX_LOAD_LINE];
gchar str_buf[MAX_LOAD_LINE];
gint chk_count;
gint load_count = 0;
gdouble version;
gchar magic1[20];
gchar magic2[20];
g_assert (filename != NULL);
#ifdef DEBUG
printf ("Loading %s (%s)\n", filename, name);
#endif /* DEBUG */
fp = g_fopen (filename, "rb");
if (!fp)
{
g_message (_("Could not open '%s' for reading: %s"),
pika_filename_to_utf8 (filename), g_strerror (errno));
return NULL;
}
gfig_obj = gfig_new ();
gfig_obj->name = g_strdup (name);
gfig_obj->filename = g_strdup (filename);
/* HEADER
* draw_name
* version
* obj_list
*/
get_line (load_buf, MAX_LOAD_LINE, fp, 1);
sscanf (load_buf, "%10s %10s %lf", magic1, magic2, &version);
if (strcmp (magic1, "GFIG") || strcmp (magic2, "Version"))
{
g_message ("File '%s' is not a gfig file",
pika_filename_to_utf8 (gfig_obj->filename));
gfig_free (gfig_obj);
fclose (fp);
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_obj->draw_name = g_strdup (load_buf);
get_line (load_buf, MAX_LOAD_LINE, fp, 0);
if (strncmp (load_buf, "Version: ", 9) == 0)
gfig_obj->version = g_ascii_strtod (load_buf + 9, NULL);
get_line (load_buf, MAX_LOAD_LINE, fp, 0);
sscanf (load_buf, "ObjCount: %d", &load_count);
if (load_options (gfig_obj, fp))
{
g_message ("File '%s' corrupt file - Line %d Option section incorrect",
pika_filename_to_utf8 (filename), line_no);
gfig_free (gfig_obj);
fclose (fp);
return NULL;
}
if (gfig_load_styles (gfig_obj, fp))
{
g_message ("File '%s' corrupt file - Line %d Option section incorrect",
pika_filename_to_utf8 (filename), line_no);
gfig_free (gfig_obj);
fclose (fp);
return NULL;
}
gfig_load_objs (gfig, gfig_obj, load_count, fp);
/* Check count ? */
chk_count = g_list_length (gfig_obj->obj_list);
if (chk_count != load_count)
{
g_message ("File '%s' corrupt file - Line %d Object count to small",
pika_filename_to_utf8 (filename), line_no);
gfig_free (gfig_obj);
fclose (fp);
return NULL;
}
fclose (fp);
if (!gfig_context->current_obj)
gfig_context->current_obj = gfig_obj;
gfig_obj->obj_status = GFIG_OK;
return gfig_obj;
}
void
save_options (GString *string)
{
/* Save options */
g_string_append_printf (string, "<OPTIONS>\n");
g_string_append_printf (string, "GridSpacing: %d\n",
selvals.opts.gridspacing);
if (selvals.opts.gridtype == RECT_GRID)
{
g_string_append_printf (string, "GridType: RECT_GRID\n");
}
else if (selvals.opts.gridtype == POLAR_GRID)
{
g_string_append_printf (string, "GridType: POLAR_GRID\n");
}
else if (selvals.opts.gridtype == ISO_GRID)
{
g_string_append_printf (string, "GridType: ISO_GRID\n");
}
else
{
/* default to RECT_GRID */
g_string_append_printf (string, "GridType: RECT_GRID\n");
}
g_string_append_printf (string, "DrawGrid: %s\n",
(selvals.opts.drawgrid) ? "TRUE" : "FALSE");
g_string_append_printf (string, "Snap2Grid: %s\n",
(selvals.opts.snap2grid) ? "TRUE" : "FALSE");
g_string_append_printf (string, "LockOnGrid: %s\n",
(selvals.opts.lockongrid) ? "TRUE" : "FALSE");
g_string_append_printf (string, "ShowControl: %s\n",
(selvals.opts.showcontrol) ? "TRUE" : "FALSE");
g_string_append_printf (string, "</OPTIONS>\n");
}
static void
gfig_save_obj_start (GfigObject *obj,
GString *string)
{
g_string_append_printf (string, "<%s ", obj->class->name);
gfig_style_save_as_attributes (&obj->style, string);
g_string_append_printf (string, ">\n");
}
static void
gfig_save_obj_end (GfigObject *obj,
GString *string)
{
g_string_append_printf (string, "</%s>\n",obj->class->name);
}
static gboolean
load_bool (gchar *opt_buf,
gint *toset)
{
if (!strcmp (opt_buf, "TRUE"))
*toset = 1;
else if (!strcmp (opt_buf, "FALSE"))
*toset = 0;
else
return TRUE;
return FALSE;
}
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, "%255s %255s", str_buf, opt_buf));
printf ("option %s val %s\n", str_buf, opt_buf);
#else
sscanf (load_buf, "%255s %255s", 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);
}
GString *
gfig_save_as_string (void)
{
GList *objs;
gint count;
gchar buf[G_ASCII_DTOSTR_BUF_SIZE];
gchar conv_buf[MAX_LOAD_LINE * 3 + 1];
GString *string;
string = g_string_new (GFIG_HEADER);
gfig_name_encode (conv_buf, gfig_context->current_obj->draw_name);
g_string_append_printf (string, "Name: %s\n", conv_buf);
g_string_append_printf (string, "Version: %s\n",
g_ascii_formatd (buf, G_ASCII_DTOSTR_BUF_SIZE, "%f",
gfig_context->current_obj->version));
objs = gfig_context->current_obj->obj_list;
count = g_list_length (objs);
g_string_append_printf (string, "ObjCount: %d\n", count);
save_options (string);
gfig_save_styles (string);
for (objs = gfig_context->current_obj->obj_list;
objs;
objs = g_list_next (objs))
{
GfigObject *object = objs->data;
gfig_save_obj_start (object, string);
gfig_save_style (&object->style, string);
if (object->points)
d_save_object (object, string);
gfig_save_obj_end (object, string);
}
return string;
}
gboolean
gfig_save_as_parasite (void)
{
PikaParasite *parasite;
GString *string;
string = gfig_save_as_string ();
parasite = pika_parasite_new ("gfig",
PIKA_PARASITE_PERSISTENT |
PIKA_PARASITE_UNDOABLE,
string->len, string->str);
g_string_free (string, TRUE);
if (!pika_item_attach_parasite (PIKA_ITEM (gfig_context->drawable),
parasite))
{
g_message (_("Error trying to save figure as a parasite: "
"can't attach parasite to drawable."));
pika_parasite_free (parasite);
return FALSE;
}
pika_parasite_free (parasite);
return TRUE;
}
GFigObj *
gfig_load_from_parasite (PikaGfig *gfig)
{
GFile *file;
FILE *fp;
PikaParasite *parasite;
const gchar *parasite_data;
guint32 parasite_size;
GFigObj *gfig_obj;
parasite = pika_item_get_parasite (PIKA_ITEM (gfig_context->drawable),
"gfig");
if (! parasite)
return NULL;
file = pika_temp_file ("gfigtmp");
fp = g_fopen (g_file_peek_path (file), "wb");
if (! fp)
{
g_message (_("Error trying to open temporary file '%s' "
"for parasite loading: %s"),
pika_file_get_utf8_name (file), g_strerror (errno));
return NULL;
}
parasite_data = pika_parasite_get_data (parasite, &parasite_size);
fwrite (parasite_data, sizeof (guchar), parasite_size, fp);
fclose (fp);
pika_parasite_free (parasite);
gfig_obj = gfig_load (gfig, g_file_peek_path (file), "(none)");
g_file_delete (file, NULL, NULL);
g_object_unref (file);
return gfig_obj;
}
void
gfig_save_callbk (void)
{
FILE *fp;
gchar *savename;
GString *string;
savename = gfig_context->current_obj->filename;
fp = g_fopen (savename, "w+b");
if (!fp)
{
g_message (_("Could not open '%s' for writing: %s"),
pika_filename_to_utf8 (savename), g_strerror (errno));
return;
}
string = gfig_save_as_string ();
fwrite (string->str, string->len, 1, fp);
if (ferror (fp))
g_message ("Failed to write file.");
else
gfig_context->current_obj->obj_status &= ~(GFIG_MODIFIED | GFIG_READONLY);
fclose (fp);
}

266
plug-ins/gfig/gfig.h Normal file
View File

@ -0,0 +1,266 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This is a plug-in for PIKA.
*
* Generates images containing vector type drawings.
*
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef __GFIG_H__
#define __GFIG_H__
#include "gfig-types.h"
#include "gfig-style.h"
#define MAX_UNDO 10
#define MIN_UNDO 1
struct _PikaGfig
{
PikaPlugIn parent_instance;
GtkApplication *app;
GtkWidget *top_level_dlg;
gboolean success;
GtkBuilder *builder;
};
#define PLUG_IN_PROC "plug-in-gfig"
#define PLUG_IN_BINARY "gfig"
#define PLUG_IN_ROLE "pika-gfig"
#define PIKA_TYPE_GFIG (pika_gfig_get_type ())
G_DECLARE_FINAL_TYPE (PikaGfig, pika_gfig, PIKA, GFIG, PikaPlugIn)
typedef struct
{
gint gridspacing;
GridType gridtype;
gboolean drawgrid;
gboolean snap2grid;
gboolean lockongrid;
gboolean showcontrol;
gdouble grid_radius_min;
gdouble grid_radius_interval;
gdouble grid_rotation;
gdouble grid_granularity;
gint grid_sectors_desired;
} GfigOpts;
typedef struct
{
PikaChannelOps 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 */
gdouble fill_opacity; /* You can guess this one */
} selection_option;
void object_start (GdkPoint *pnt, gint);
void object_operation (GdkPoint *pnt, gint);
void object_operation_start (PikaGfig *gfig,
GdkPoint *pnt,
gint shift_down);
void object_operation_end (GdkPoint *pnt, gint);
void object_end (PikaGfig *gfig,
GdkPoint *pnt,
gint shift_down);
#define MAX_LOAD_LINE 256
#define SQ_SIZE 8
extern gint line_no;
extern gint preview_width, preview_height;
extern gint need_to_scale;
extern gdouble scale_x_factor, scale_y_factor;
extern GdkPixbuf *back_pixbuf;
extern GtkWidget *pic_preview;
extern gint obj_show_single;
typedef struct
{
GfigOpts opts;
gboolean showimage;
gint maxundo;
gboolean showpos;
gdouble brushfade;
gdouble brushgradient;
gdouble airbrushpressure;
DrawonLayers onlayers;
LayersBGType onlayerbg;
PaintType painttype;
gboolean reverselines;
gboolean scaletoimage;
gdouble scaletoimagefp;
BrushType brshtype;
DobjType otype;
} SelectItVals;
struct _GFigObj
{
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 */
GList *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;
};
/* this is temp, should be able to get rid of */
typedef struct BrushDesc
{
PikaBrush *brush;
gdouble opacity;
gint spacing;
PikaLayerMode paint_mode;
gint width;
gint height;
guchar *pv_buf; /* Buffer where brush placed */
gint16 x_off;
gint16 y_off;
const gchar *popup;
} BrushDesc;
typedef struct
{
gboolean debug_styles;
gboolean show_background; /* show thumbnail of image behind figure */
PikaImage *image; /* Pika image */
PikaDrawable *drawable; /* Pika drawable to paint on */
GFigObj *current_obj;
GfigObject *selected_obj;
GtkWidget *preview;
Style default_style;
BrushDesc bdesc;
GtkWidget *fg_color_button;
GtkWidget *bg_color_button;
GtkWidget *brush_select;
GtkWidget *pattern_select;
GtkWidget *gradient_select;
GtkWidget *fillstyle_combo;
GtkWidget *paint_type_toggle;
PikaRGB *fg_color;
PikaRGB *bg_color;
gboolean enable_repaint;
gboolean using_new_layer;
} GFigContext;
extern GFigContext *gfig_context;
extern selection_option selopt;
extern SelectItVals selvals;
void add_to_all_obj (PikaGfig *gfig,
GFigObj *fobj,
GfigObject *obj);
gchar *get_line (gchar *buf,
gint s,
FILE *from,
gint init);
gint gfig_scale_x (gint x);
gint gfig_scale_y (gint y);
void scale_to_xy (gdouble *list,
gint size);
void scale_to_original_xy (gdouble *list,
gint size);
void gfig_paint (BrushType brush_type,
PikaDrawable *drawable,
gint seg_count,
gdouble line_pnts[]);
void draw_item (cairo_t *cr,
gboolean fill);
void draw_circle (GdkPoint *p,
gboolean selected,
cairo_t *cr);
void draw_sqr (GdkPoint *p,
gboolean selected,
cairo_t *cr);
void list_button_update (GFigObj *obj);
GtkWidget *num_sides_widget (const gchar *d_title,
gint *num_sides,
gint *which_way,
gint adj_min,
gint adj_max);
void setup_undo (PikaGfig *gfig);
void draw_grid_clear (void);
void prepend_to_all_obj (PikaGfig *gfig,
GFigObj *fobj,
GList *nobj);
void gfig_draw_arc (gint x,
gint y,
gint width,
gint height,
gint angle1,
gint angle2,
cairo_t *cr);
void gfig_draw_line (gint x0,
gint y0,
gint x1,
gint y1,
cairo_t *cr);
void gfig_paint_callback (void);
GFigObj *gfig_load (PikaGfig *gfig,
const gchar *filename,
const gchar *name);
void gfig_name_encode (gchar *dest,
gchar *src);
void gfig_name_decode (gchar *dest,
const gchar *src);
gint gfig_list_pos (GFigObj *gfig);
gint gfig_list_insert (GFigObj *gfig);
void gfig_free (GFigObj *gfig);
void save_options (GString *string);
GString *gfig_save_as_string (void);
gboolean gfig_save_as_parasite (void);
GFigObj *gfig_load_from_parasite (PikaGfig *gfig);
GFigObj *gfig_new (void);
void gfig_save_callbk (void);
void paint_layer_fill (gdouble x1,
gdouble y1,
gdouble x2,
gdouble y2);
extern GtkWidget *top_level_dlg;
extern GList *gfig_list;
extern gdouble org_scale_x_factor, org_scale_y_factor;
#endif /* __GFIG_H__ */

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 461 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 446 B

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/technology.heckin/gfig/icons">
<file preprocess="to-pixdata">gfig-bezier.png</file>
<file preprocess="to-pixdata">gfig-circle.png</file>
<file preprocess="to-pixdata">gfig-copy-object.png</file>
<file preprocess="to-pixdata">gfig-curve.png</file>
<file preprocess="to-pixdata">gfig-delete-object.png</file>
<file preprocess="to-pixdata">gfig-ellipse.png</file>
<file preprocess="to-pixdata">gfig-line.png</file>
<file preprocess="to-pixdata">gfig-move-object.png</file>
<file preprocess="to-pixdata">gfig-move-point.png</file>
<file preprocess="to-pixdata">gfig-polygon.png</file>
<file preprocess="to-pixdata">gfig-rectangle.png</file>
<file preprocess="to-pixdata">gfig-select-object.png</file>
<file preprocess="to-pixdata">gfig-show-all.png</file>
<file preprocess="to-pixdata">gfig-spiral.png</file>
<file preprocess="to-pixdata">gfig-star.png</file>
<file preprocess="to-pixdata">gfig-logo.png</file>
</gresource>
</gresources>

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 508 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 552 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 690 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 365 B

View File

@ -0,0 +1,24 @@
stock_icons = [
'gfig-bezier.png',
'gfig-circle.png',
'gfig-copy-object.png',
'gfig-curve.png',
'gfig-delete-object.png',
'gfig-ellipse.png',
'gfig-line.png',
'gfig-logo.png',
'gfig-move-object.png',
'gfig-move-point.png',
'gfig-polygon.png',
'gfig-rectangle.png',
'gfig-select-object.png',
'gfig-show-all.png',
'gfig-spiral.png',
'gfig-star.png',
]
gfig_icon_sources = gnome.compile_resources(
'gfig-icon-images',
'gfig-icon-images.gresource.xml',
# source_dir: meson.current_source_directory(),
)

53
plug-ins/gfig/meson.build Normal file
View File

@ -0,0 +1,53 @@
subdir('gfig-examples')
subdir('images')
plugin_name = 'gfig'
plugin_sources = [
'gfig-arc.c',
'gfig-bezier.c',
'gfig-circle.c',
'gfig-dialog.c',
'gfig-dobject.c',
'gfig-ellipse.c',
'gfig-grid.c',
'gfig-icons.c',
'gfig-line.c',
'gfig-poly.c',
'gfig-preview.c',
'gfig-rectangle.c',
'gfig-spiral.c',
'gfig-star.c',
'gfig-style.c',
'gfig.c',
gfig_icon_sources,
]
plugin_sources += gnome.compile_resources(
'gfig-menus',
'gfig-menus.gresource.xml',
)
if platform_windows
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
'--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
'--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
'--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
],
)
endif
executable(plugin_name,
plugin_sources,
dependencies: [
libpikaui_dep,
math,
],
install: true,
install_dir: pikaplugindir / 'plug-ins' / plugin_name,
)

61
plug-ins/gfig/notes.txt Normal file
View File

@ -0,0 +1,61 @@
Notes regarding GFig
Bill Skaggs, July 3, 2004
Most importantly: this version of Gfig has been massively revised. It
is very unstable. It is likely to crash at any moment. It is full of
bugs. Many things are incompletely implemented, and others do not
work yet. Play with it at your own risk.
(If it does crash, though, it is not likely to corrupt the image, so
in most cases you should be able to Exit the plug-in and continue
working.)
A quick summary of recent changes:
Gfig now works somewhat like the text tool. It uses special dedicated
"Gfig" layers. A Gfig layer is defined by the presence of a parasite
called "Gfig", which contains a representation of the figure. (It is
actually a Gfig file whose contents are attached to the layer as a
parasite.)
If Gfig is run when the active layer is a Gfig layer, then it loads
the figure that is stored there, so that it can be modified. If the
active layer is not a Gfig layer, then a new layer is created, and
initialized to transparent.
The figure that you create is saved to the layer when you hit the
Close button. If you hit the Cancel button, the results of your work
are not saved. The GFig data parasite is not overwritten until you
hit Close, so you can always revert to the previous version of the
figure by hitting Cancel and then re-running GFig.
Each object that you create in Gfig can have its own style. Currently
the only style attributes that work are foreground color and brush
shape; others will be added shortly.
When you start Gfig, and the dialog comes up, the background of the
preview shows a representation of the image you are working on. Each
time you do something in GFig, the result is reflected by a change in
both the Pika image and the GFig preview, so you can see in real time
the results of everything that you do. (The rendering could stand to
be speeded up, though.) You can turn the background display in the
preview on or off by toggling Edit->Options->Show image.
PLEASE NOTE: The Gfig file format has not yet stabilized. Until it
does, the parasite used to store the layer data is marked
non-persistent, meaning it will not be stored in XCF files. This will
be trivial to change when the time comes. The ordinary pixel data
*is* stored in XCF files, though. This means that if you save the
image as XCF and re-open it, the GFig layers will be there but you
will not be able to use GFig to modify them.
ALSO NOTE: When GFig loads a GFig layer, it begins by clearing the
layer to transparent and redrawing it as stored in the GFig parasite.
This means that any changes you have made in the layer in the meantime
will be lost. It would be nice if GFig could give a warning that this
is about to happen, but it is difficult to implement, because Gimp
does not yet provide an easy way to tell whether a layer has been
modified (as far as I know).