1 /*
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * This is a plug-in for GIMP.
5  *
6  * Generates images containing vector type drawings.
7  *
8  * Copyright (C) 1997 Andy Thomas  alt@picnic.demon.co.uk
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
22  *
23  */
24 
25 #include "config.h"
26 
27 #include <libgimp/gimp.h>
28 #include <libgimp/gimpui.h>
29 
30 #include "gfig.h"
31 #include "gfig-dobject.h"
32 #include "gfig-rectangle.h"
33 
34 #include "libgimp/stdplugins-intl.h"
35 
36 static void        d_draw_rectangle   (GfigObject *obj,
37                                        cairo_t    *cr);
38 static void        d_paint_rectangle  (GfigObject *obj);
39 static GfigObject *d_copy_rectangle   (GfigObject *obj);
40 
41 static void        d_update_rectangle (GdkPoint   *pnt);
42 
43 static void
d_draw_rectangle(GfigObject * obj,cairo_t * cr)44 d_draw_rectangle (GfigObject *obj,
45                   cairo_t    *cr)
46 {
47   DobjPoints *first_pnt;
48   DobjPoints *second_pnt;
49   gint        xmin, ymin;
50   gint        xmax, ymax;
51 
52   first_pnt = obj->points;
53 
54   if (!first_pnt)
55     return; /* End-of-line */
56 
57   draw_sqr (&first_pnt->pnt, obj == gfig_context->selected_obj, cr);
58 
59   second_pnt = first_pnt->next;
60 
61   if (!second_pnt)
62     return;
63 
64   if (obj == obj_creating)
65     draw_circle (&second_pnt->pnt, TRUE, cr);
66   else
67     draw_sqr (&second_pnt->pnt, obj == gfig_context->selected_obj, cr);
68 
69   xmin = MIN (gfig_scale_x (first_pnt->pnt.x),
70               gfig_scale_x (second_pnt->pnt.x));
71   ymin = MIN (gfig_scale_y (first_pnt->pnt.y),
72               gfig_scale_y (second_pnt->pnt.y));
73   xmax = MAX (gfig_scale_x (first_pnt->pnt.x),
74               gfig_scale_x (second_pnt->pnt.x));
75   ymax = MAX (gfig_scale_y (first_pnt->pnt.y),
76               gfig_scale_y (second_pnt->pnt.y));
77 
78   cairo_rectangle (cr, xmin + .5, ymin + .5, xmax - xmin, ymax - ymin);
79   draw_item (cr, FALSE);
80 }
81 
82 static void
d_paint_rectangle(GfigObject * obj)83 d_paint_rectangle (GfigObject *obj)
84 {
85   DobjPoints *first_pnt;
86   DobjPoints *second_pnt;
87   gdouble     dpnts[4];
88 
89   g_assert (obj != NULL);
90 
91   /* Drawing rectangles is hard .
92    * 1) select rectangle
93    * 2) stroke it
94    */
95   first_pnt = obj->points;
96 
97   if (!first_pnt)
98     return; /* End-of-line */
99 
100   second_pnt = first_pnt->next;
101 
102   if (!second_pnt)
103     {
104       g_error ("Internal error - rectangle no second pnt");
105     }
106 
107   dpnts[0] = (gdouble) MIN (first_pnt->pnt.x, second_pnt->pnt.x);
108   dpnts[1] = (gdouble) MIN (first_pnt->pnt.y, second_pnt->pnt.y);
109   dpnts[2] = (gdouble) MAX (first_pnt->pnt.x, second_pnt->pnt.x);
110   dpnts[3] = (gdouble) MAX (first_pnt->pnt.y, second_pnt->pnt.y);
111 
112   /* Scale before drawing */
113   if (selvals.scaletoimage)
114     scale_to_original_xy (&dpnts[0], 2);
115   else
116     scale_to_xy (&dpnts[0], 2);
117 
118   if (gfig_context_get_current_style ()->fill_type != FILL_NONE)
119     {
120       gimp_context_push ();
121       gimp_context_set_feather (selopt.feather);
122       gimp_context_set_feather_radius (selopt.feather_radius, selopt.feather_radius);
123       gimp_image_select_rectangle (gfig_context->image_id,
124                                    selopt.type,
125                                    dpnts[0], dpnts[1],
126                                    dpnts[2] - dpnts[0],
127                                    dpnts[3] - dpnts[1]);
128       gimp_context_pop ();
129 
130       paint_layer_fill (dpnts[0], dpnts[1], dpnts[2], dpnts[3]);
131       gimp_selection_none (gfig_context->image_id);
132     }
133 
134   if (obj->style.paint_type == PAINT_BRUSH_TYPE)
135     {
136       gdouble line_pnts[] = { dpnts[0], dpnts[1], dpnts[2], dpnts[1],
137                               dpnts[2], dpnts[3], dpnts[0], dpnts[3],
138                               dpnts[0], dpnts[1] };
139 
140       gfig_paint (selvals.brshtype, gfig_context->drawable_id, 10, line_pnts);
141     }
142 }
143 
144 static GfigObject *
d_copy_rectangle(GfigObject * obj)145 d_copy_rectangle (GfigObject * obj)
146 {
147   GfigObject *new_rectangle;
148 
149   g_assert (obj->type == RECTANGLE);
150 
151   new_rectangle = d_new_object (RECTANGLE,
152                                 obj->points->pnt.x, obj->points->pnt.y);
153   new_rectangle->points->next = d_copy_dobjpoints (obj->points->next);
154 
155   return new_rectangle;
156 }
157 
158 void
d_rectangle_object_class_init(void)159 d_rectangle_object_class_init (void)
160 {
161   GfigObjectClass *class = &dobj_class[RECTANGLE];
162 
163   class->type      = RECTANGLE;
164   class->name      = "RECTANGLE";
165   class->drawfunc  = d_draw_rectangle;
166   class->paintfunc = d_paint_rectangle;
167   class->copyfunc  = d_copy_rectangle;
168   class->update    = d_update_rectangle;
169 }
170 
171 static void
d_update_rectangle(GdkPoint * pnt)172 d_update_rectangle (GdkPoint *pnt)
173 {
174   DobjPoints *first_pnt;
175   DobjPoints *second_pnt;
176 
177   first_pnt = obj_creating->points;
178 
179   if (!first_pnt)
180     return; /* No points */
181 
182   if ((second_pnt = first_pnt->next))
183     {
184       second_pnt->pnt.x = pnt->x;
185       second_pnt->pnt.y = pnt->y;
186     }
187   else
188     {
189       second_pnt = new_dobjpoint (pnt->x, pnt->y);
190       first_pnt->next = second_pnt;
191     }
192 }
193 
194 void
d_rectangle_start(GdkPoint * pnt,gboolean shift_down)195 d_rectangle_start (GdkPoint *pnt,
196                    gboolean  shift_down)
197 {
198   obj_creating = d_new_object (RECTANGLE, pnt->x, pnt->y);
199 }
200 
201 void
d_rectangle_end(GdkPoint * pnt,gboolean shift_down)202 d_rectangle_end (GdkPoint *pnt,
203                  gboolean  shift_down)
204 {
205   /* Under control point */
206   if (!obj_creating->points->next)
207     {
208       /* No circle created */
209       free_one_obj (obj_creating);
210     }
211   else
212     {
213       add_to_all_obj (gfig_context->current_obj, obj_creating);
214     }
215 
216   obj_creating = NULL;
217 }
218 
219