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 #include "config.h"
25
26 #include <libgimp/gimp.h>
27 #include <libgimp/gimpui.h>
28
29 #include "gfig.h"
30 #include "gfig-grid.h"
31 #include "gfig-dobject.h"
32 #include "gfig-preview.h"
33
34 #include "libgimp/stdplugins-intl.h"
35
36 #define PREVIEW_MASK (GDK_EXPOSURE_MASK | \
37 GDK_POINTER_MOTION_MASK | \
38 GDK_BUTTON_PRESS_MASK | \
39 GDK_BUTTON_RELEASE_MASK | \
40 GDK_BUTTON_MOTION_MASK | \
41 GDK_KEY_PRESS_MASK | \
42 GDK_KEY_RELEASE_MASK)
43
44 static gint x_pos_val;
45 static gint y_pos_val;
46 static gint pos_tag = -1;
47 GtkWidget *status_label_dname;
48 GtkWidget *status_label_fname;
49 static GtkWidget *pos_label; /* XY pos marker */
50
51
52 static void gfig_preview_realize (GtkWidget *widget);
53 static gboolean gfig_preview_events (GtkWidget *widget,
54 GdkEvent *event);
55 static gboolean gfig_preview_expose (GtkWidget *widget,
56 GdkEvent *event);
57
58 static gint gfig_invscale_x (gint x);
59 static gint gfig_invscale_y (gint y);
60 static GtkWidget *gfig_pos_labels (void);
61 static GtkWidget *make_pos_info (void);
62
63 static void gfig_pos_update (gint x,
64 gint y);
65 static void gfig_pos_update_labels (gpointer data);
66
67 GtkWidget *
make_preview(void)68 make_preview (void)
69 {
70 GtkWidget *frame;
71 GtkWidget *vbox;
72 GtkWidget *hbox;
73 GtkWidget *table;
74 GtkWidget *ruler;
75
76 gfig_context->preview = gtk_drawing_area_new ();
77 gtk_widget_set_events (GTK_WIDGET (gfig_context->preview), PREVIEW_MASK);
78
79 g_signal_connect (gfig_context->preview , "realize",
80 G_CALLBACK (gfig_preview_realize),
81 NULL);
82
83 g_signal_connect (gfig_context->preview , "event",
84 G_CALLBACK (gfig_preview_events),
85 NULL);
86
87 g_signal_connect_after (gfig_context->preview , "expose-event",
88 G_CALLBACK (gfig_preview_expose),
89 NULL);
90
91 gtk_widget_set_size_request (gfig_context->preview,
92 preview_width, preview_height);
93
94 frame = gtk_frame_new (NULL);
95
96 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
97
98 table = gtk_table_new (3, 3, FALSE);
99 gtk_table_attach (GTK_TABLE (table), gfig_context->preview, 1, 2, 1, 2,
100 GTK_FILL , GTK_FILL , 0, 0);
101 gtk_container_add (GTK_CONTAINER (frame), table);
102
103 ruler = gimp_ruler_new (GTK_ORIENTATION_HORIZONTAL);
104 gimp_ruler_set_range (GIMP_RULER (ruler), 0, preview_width, PREVIEW_SIZE);
105 g_signal_connect_swapped (gfig_context->preview, "motion-notify-event",
106 G_CALLBACK (GTK_WIDGET_CLASS (G_OBJECT_GET_CLASS (ruler))->motion_notify_event),
107 ruler);
108 gtk_table_attach (GTK_TABLE (table), ruler, 1, 2, 0, 1,
109 GTK_FILL, GTK_FILL, 0, 0);
110 gtk_widget_show (ruler);
111
112 ruler = gimp_ruler_new (GTK_ORIENTATION_VERTICAL);
113 gimp_ruler_set_range (GIMP_RULER (ruler), 0, preview_height, PREVIEW_SIZE);
114 g_signal_connect_swapped (gfig_context->preview, "motion-notify-event",
115 G_CALLBACK (GTK_WIDGET_CLASS (G_OBJECT_GET_CLASS (ruler))->motion_notify_event),
116 ruler);
117 gtk_table_attach (GTK_TABLE (table), ruler, 0, 1, 1, 2,
118 GTK_FILL, GTK_FILL, 0, 0);
119 gtk_widget_show (ruler);
120
121 gtk_widget_show (frame);
122 gtk_widget_show (table);
123
124 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
125 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
126 gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
127 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
128
129 frame = make_pos_info ();
130 gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
131
132 gtk_widget_show (vbox);
133 gtk_widget_show (hbox);
134
135 return vbox;
136 }
137
138 static void
gfig_preview_realize(GtkWidget * widget)139 gfig_preview_realize (GtkWidget *widget)
140 {
141 GdkDisplay *display = gtk_widget_get_display (widget);
142
143 gdk_window_set_cursor (gtk_widget_get_window (gfig_context->preview),
144 gdk_cursor_new_for_display (display, GDK_CROSSHAIR));
145 gfig_grid_colors (widget);
146 }
147
148 static void
draw_background(cairo_t * cr)149 draw_background (cairo_t *cr)
150 {
151 if (! back_pixbuf)
152 back_pixbuf = gimp_image_get_thumbnail (gfig_context->image_id,
153 preview_width, preview_height,
154 GIMP_PIXBUF_LARGE_CHECKS);
155
156 if (back_pixbuf)
157 {
158 gdk_cairo_set_source_pixbuf (cr, back_pixbuf, 0, 0);
159 cairo_paint (cr);
160 }
161 }
162
163 static gboolean
gfig_preview_expose(GtkWidget * widget,GdkEvent * event)164 gfig_preview_expose (GtkWidget *widget,
165 GdkEvent *event)
166 {
167 cairo_t *cr = gdk_cairo_create (event->expose.window);
168
169 if (gfig_context->show_background)
170 draw_background (cr);
171
172 draw_grid (cr);
173 draw_objects (gfig_context->current_obj->obj_list, TRUE, cr);
174
175 if (obj_creating)
176 {
177 GList *single = g_list_prepend (NULL, obj_creating);
178 draw_objects (single, TRUE, cr);
179 g_list_free (single);
180 }
181
182 cairo_destroy (cr);
183 return FALSE;
184 }
185
186 static gboolean
gfig_preview_events(GtkWidget * widget,GdkEvent * event)187 gfig_preview_events (GtkWidget *widget,
188 GdkEvent *event)
189 {
190 GdkEventButton *bevent;
191 GdkEventMotion *mevent;
192 GdkPoint point;
193 static gint tmp_show_single = 0;
194
195 switch (event->type)
196 {
197 case GDK_EXPOSE:
198 break;
199
200 case GDK_BUTTON_PRESS:
201 bevent = (GdkEventButton *) event;
202 point.x = bevent->x;
203 point.y = bevent->y;
204
205 g_assert (need_to_scale == 0); /* If not out of step some how */
206
207 /* Start drawing of object */
208 if (selvals.otype >= MOVE_OBJ)
209 {
210 if (!selvals.scaletoimage)
211 {
212 point.x = gfig_invscale_x (point.x);
213 point.y = gfig_invscale_y (point.y);
214 }
215 object_operation_start (&point, bevent->state & GDK_SHIFT_MASK);
216
217 /* If constraining save start pnt */
218 if (selvals.opts.snap2grid)
219 {
220 /* Save point to constrained point ... if button 3 down */
221 if (bevent->button == 3)
222 {
223 find_grid_pos (&point, &point, FALSE);
224 }
225 }
226 }
227 else
228 {
229 if (selvals.opts.snap2grid)
230 find_grid_pos (&point, &point, FALSE);
231 object_start (&point, bevent->state & GDK_SHIFT_MASK);
232
233 gtk_widget_queue_draw (widget);
234 }
235
236 break;
237
238 case GDK_BUTTON_RELEASE:
239 bevent = (GdkEventButton *) event;
240 point.x = bevent->x;
241 point.y = bevent->y;
242
243 if (selvals.opts.snap2grid)
244 find_grid_pos (&point, &point, bevent->button == 3);
245
246 /* Still got shift down ?*/
247 if (selvals.otype >= MOVE_OBJ)
248 {
249 if (!selvals.scaletoimage)
250 {
251 point.x = gfig_invscale_x (point.x);
252 point.y = gfig_invscale_y (point.y);
253 }
254 object_operation_end (&point, bevent->state & GDK_SHIFT_MASK);
255 }
256 else
257 {
258 if (obj_creating)
259 {
260 object_end (&point, bevent->state & GDK_SHIFT_MASK);
261 }
262 else
263 break;
264 }
265
266 gfig_paint_callback ();
267 break;
268
269 case GDK_MOTION_NOTIFY:
270 mevent = (GdkEventMotion *) event;
271 point.x = mevent->x;
272 point.y = mevent->y;
273
274 if (selvals.opts.snap2grid)
275 find_grid_pos (&point, &point, mevent->state & GDK_BUTTON3_MASK);
276
277 if (selvals.otype >= MOVE_OBJ)
278 {
279 /* Moving objects around */
280 if (!selvals.scaletoimage)
281 {
282 point.x = gfig_invscale_x (point.x);
283 point.y = gfig_invscale_y (point.y);
284 }
285 object_operation (&point, mevent->state & GDK_SHIFT_MASK);
286 gfig_pos_update (point.x, point.y);
287 return FALSE;
288 }
289
290 if (obj_creating)
291 {
292 obj_creating->class->update (&point);
293 gtk_widget_queue_draw (widget);
294 }
295 gfig_pos_update (point.x, point.y);
296 break;
297
298 case GDK_KEY_PRESS:
299 if ((tmp_show_single = obj_show_single) != -1)
300 {
301 obj_show_single = -1;
302 draw_grid_clear ();
303 }
304 break;
305
306 case GDK_KEY_RELEASE:
307 if (tmp_show_single != -1)
308 {
309 obj_show_single = tmp_show_single;
310 draw_grid_clear ();
311 }
312 break;
313
314 default:
315 break;
316 }
317
318 return FALSE;
319 }
320
321 static GtkWidget *
make_pos_info(void)322 make_pos_info (void)
323 {
324 GtkWidget *frame;
325 GtkWidget *hbox;
326 GtkWidget *label;
327
328 frame = gimp_frame_new (_("Object Details"));
329
330 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
331 gtk_box_set_homogeneous (GTK_BOX (hbox), TRUE);
332 gtk_container_add (GTK_CONTAINER (frame), hbox);
333
334 /* Add labels */
335 label = gfig_pos_labels ();
336 gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
337 gfig_pos_enable (NULL, NULL);
338
339 #if 0
340 label = gfig_obj_size_label ();
341 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
342 #endif /* 0 */
343
344 gtk_widget_show (hbox);
345 gtk_widget_show (frame);
346
347 return frame;
348 }
349
350 static gint
gfig_invscale_x(gint x)351 gfig_invscale_x (gint x)
352 {
353 if (!selvals.scaletoimage)
354 return (gint) (x * scale_x_factor);
355 else
356 return x;
357 }
358
359 static gint
gfig_invscale_y(gint y)360 gfig_invscale_y (gint y)
361 {
362 if (!selvals.scaletoimage)
363 return (gint) (y * scale_y_factor);
364 else
365 return y;
366 }
367
368 static GtkWidget *
gfig_pos_labels(void)369 gfig_pos_labels (void)
370 {
371 GtkWidget *label;
372 GtkWidget *hbox;
373 gchar buf[256];
374
375 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
376 gtk_widget_show (hbox);
377
378 /* Position labels */
379 label = gtk_label_new (_("XY position:"));
380 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
381 gtk_widget_show (label);
382
383 pos_label = gtk_label_new ("");
384 gtk_box_pack_start (GTK_BOX (hbox), pos_label, FALSE, FALSE, 0);
385 gtk_widget_show (pos_label);
386
387 g_snprintf (buf, sizeof (buf), "%d, %d", 0, 0);
388 gtk_label_set_text (GTK_LABEL (pos_label), buf);
389
390 return hbox;
391 }
392
393 void
gfig_pos_enable(GtkWidget * widget,gpointer data)394 gfig_pos_enable (GtkWidget *widget,
395 gpointer data)
396 {
397 gboolean enable = selvals.showpos;
398
399 gtk_widget_set_sensitive (GTK_WIDGET (pos_label), enable);
400 }
401
402 static void
gfig_pos_update_labels(gpointer data)403 gfig_pos_update_labels (gpointer data)
404 {
405 static gchar buf[256];
406
407 pos_tag = -1;
408
409 g_snprintf (buf, sizeof (buf), "%d, %d", x_pos_val, y_pos_val);
410 gtk_label_set_text (GTK_LABEL (pos_label), buf);
411 }
412
413 static void
gfig_pos_update(gint x,gint y)414 gfig_pos_update (gint x,
415 gint y)
416 {
417 if ((x_pos_val !=x || y_pos_val != y) && pos_tag == -1 && selvals.showpos)
418 {
419 x_pos_val = x;
420 y_pos_val = y;
421 gfig_pos_update_labels (NULL);
422 }
423 }
424