Initial checkin of Pika from heckimp
313
plug-ins/gfig/README
Normal 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
@ -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, ¢er_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, ¢er_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
@ -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
@ -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);
|
||||
}
|
||||
|
43
plug-ins/gfig/gfig-bezier.h
Normal 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
@ -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 (¢er_pnt->pnt, obj == gfig_context->selected_obj, cr);
|
||||
|
||||
edge_pnt = center_pnt->next;
|
||||
|
||||
if (!edge_pnt)
|
||||
return;
|
||||
|
||||
radius = calc_radius (¢er_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 (¢er_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;
|
||||
}
|
||||
|
36
plug-ins/gfig/gfig-circle.h
Normal 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
39
plug-ins/gfig/gfig-dialog.h
Normal 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
115
plug-ins/gfig/gfig-dobject.h
Normal 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__ */
|
||||
|
||||
|
236
plug-ins/gfig/gfig-ellipse.c
Normal 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 (¢er_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;
|
||||
}
|
||||
|
36
plug-ins/gfig/gfig-ellipse.h
Normal 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__ */
|
84
plug-ins/gfig/gfig-examples/A_star
Normal 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>
|
57
plug-ins/gfig/gfig-examples/curves
Normal 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>
|
14
plug-ins/gfig/gfig-examples/meson.build
Normal 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',
|
||||
)
|
40
plug-ins/gfig/gfig-examples/polys
Normal 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>
|
44
plug-ins/gfig/gfig-examples/ring
Normal 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>
|
123
plug-ins/gfig/gfig-examples/ring+star
Normal 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>
|
47
plug-ins/gfig/gfig-examples/smiley
Normal 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>
|
55
plug-ins/gfig/gfig-examples/spirals_and_stars
Normal 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>
|
38
plug-ins/gfig/gfig-examples/sprial
Normal 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>
|
61
plug-ins/gfig/gfig-examples/star2
Normal 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>
|
44
plug-ins/gfig/gfig-examples/stars
Normal 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
@ -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
@ -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__ */
|
49
plug-ins/gfig/gfig-icons.c
Normal 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");
|
||||
}
|
47
plug-ins/gfig/gfig-icons.h
Normal 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
@ -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
@ -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
@ -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>
|
6
plug-ins/gfig/gfig-menus.gresource.xml
Normal 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
@ -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 (¢er_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
@ -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__ */
|
417
plug-ins/gfig/gfig-preview.c
Normal 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);
|
||||
}
|
||||
}
|
35
plug-ins/gfig/gfig-preview.h
Normal 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__ */
|
219
plug-ins/gfig/gfig-rectangle.c
Normal 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;
|
||||
}
|
||||
|
36
plug-ins/gfig/gfig-rectangle.h
Normal 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
@ -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 (¢er_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;
|
||||
}
|
38
plug-ins/gfig/gfig-spiral.h
Normal 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
@ -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 (¢er_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
@ -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
@ -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 (¤t_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 (¤t_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
@ -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
@ -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
@ -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, ¶site_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
@ -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__ */
|
BIN
plug-ins/gfig/images/gfig-bezier.png
Normal file
After Width: | Height: | Size: 258 B |
BIN
plug-ins/gfig/images/gfig-circle.png
Normal file
After Width: | Height: | Size: 354 B |
BIN
plug-ins/gfig/images/gfig-copy-object.png
Normal file
After Width: | Height: | Size: 268 B |
BIN
plug-ins/gfig/images/gfig-curve.png
Normal file
After Width: | Height: | Size: 284 B |
BIN
plug-ins/gfig/images/gfig-delete-object.png
Normal file
After Width: | Height: | Size: 461 B |
BIN
plug-ins/gfig/images/gfig-ellipse.png
Normal file
After Width: | Height: | Size: 446 B |
21
plug-ins/gfig/images/gfig-icon-images.gresource.xml
Normal 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>
|
BIN
plug-ins/gfig/images/gfig-line.png
Normal file
After Width: | Height: | Size: 185 B |
BIN
plug-ins/gfig/images/gfig-logo.png
Normal file
After Width: | Height: | Size: 6.3 KiB |
BIN
plug-ins/gfig/images/gfig-move-object.png
Normal file
After Width: | Height: | Size: 500 B |
BIN
plug-ins/gfig/images/gfig-move-point.png
Normal file
After Width: | Height: | Size: 508 B |
BIN
plug-ins/gfig/images/gfig-polygon.png
Normal file
After Width: | Height: | Size: 251 B |
BIN
plug-ins/gfig/images/gfig-rectangle.png
Normal file
After Width: | Height: | Size: 230 B |
BIN
plug-ins/gfig/images/gfig-select-object.png
Normal file
After Width: | Height: | Size: 552 B |
BIN
plug-ins/gfig/images/gfig-show-all.png
Normal file
After Width: | Height: | Size: 690 B |
BIN
plug-ins/gfig/images/gfig-spiral.png
Normal file
After Width: | Height: | Size: 203 B |
BIN
plug-ins/gfig/images/gfig-star.png
Normal file
After Width: | Height: | Size: 365 B |
24
plug-ins/gfig/images/meson.build
Normal 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
@ -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
@ -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).
|
||||
|