1 /* $Id$ $Revision$ */
2 /* vim:set shiftwidth=4 ts=8: */
3
4 /*************************************************************************
5 * Copyright (c) 2011 AT&T Intellectual Property
6 * All rights reserved. This program and the accompanying materials
7 * are made available under the terms of the Eclipse Public License v1.0
8 * which accompanies this distribution, and is available at
9 * http://www.eclipse.org/legal/epl-v10.html
10 *
11 * Contributors: See CVS logs. Details at http://www.graphviz.org/
12 *************************************************************************/
13
14 #include "config.h"
15
16 #include <gtk/gtk.h>
17
18 #include "gvplugin_device.h"
19
20 #include "callbacks.h"
21 #include "interface.h"
22 #include "support.h"
23
24 void
on_new1_activate(GtkMenuItem * menuitem,gpointer user_data)25 on_new1_activate (GtkMenuItem *menuitem,
26 gpointer user_data)
27 {
28 GtkWindow *window1;
29 GVJ_t *job;
30
31 window1 = GTK_WINDOW(menuitem);
32 job = g_object_get_data(G_OBJECT(window1), "job");
33
34 (job->callbacks->read)(job, NULL, "dot");
35
36 // should there be specific menus for (un)directed graphs etc?
37 // - I think the directed flag only affects layout and rendering
38 // so I plan to make it look like a graph attribute.
39 // Similarly "strict".
40 }
41
42 static void
ui_open_graph(GtkWindow * window1,gchar * filename)43 ui_open_graph(GtkWindow *window1, gchar *filename)
44 {
45 GVJ_t *job;
46 GtkWidget *dialog;
47
48 job = g_object_get_data(G_OBJECT(window1), "job");
49 dialog = gtk_file_chooser_dialog_new(
50 "Open graph", window1, GTK_FILE_CHOOSER_ACTION_OPEN,
51 "Cancel", GTK_RESPONSE_CANCEL,
52 "Open", GTK_RESPONSE_ACCEPT,
53 NULL);
54 if (filename)
55 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), filename);
56 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
57 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
58 gtk_widget_destroy(dialog);
59 if (filename) {
60 (job->callbacks->read)(job, filename, "dot");
61 // if (!file) // we'll probably want to create a error dialog function
62 // fprintf(stderr, "Could not open file: %s\n", filename);
63 // else
64 g_object_set_data_full(G_OBJECT(window1),
65 "activefilename", filename, (GDestroyNotify)g_free);
66 }
67 }
68
69 void
on_open1_activate(GtkMenuItem * menuitem,gpointer user_data)70 on_open1_activate (GtkMenuItem *menuitem,
71 gpointer user_data)
72 {
73 GtkWindow *window1;
74 gchar *filename;
75
76 window1 = GTK_WINDOW(menuitem);
77 filename = g_object_get_data(G_OBJECT(window1), "activefilename");
78 ui_open_graph(window1, filename);
79 }
80
81 static void
ui_save_graph(GtkWindow * window1,gchar * filename)82 ui_save_graph(GtkWindow *window1, gchar *filename)
83 {
84 GVJ_t *job;
85 GtkWidget *dialog;
86
87 job = (GVJ_t *)g_object_get_data(G_OBJECT(window1), "job");
88
89 dialog = gtk_file_chooser_dialog_new(
90 "Save graph as", window1, GTK_FILE_CHOOSER_ACTION_SAVE,
91 "Cancel", GTK_RESPONSE_CANCEL,
92 "Save", GTK_RESPONSE_ACCEPT,
93 NULL);
94 filename = g_object_get_data(G_OBJECT(window1), "activefilename");
95 if (filename)
96 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), filename);
97 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
98 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
99 gtk_widget_destroy(dialog);
100 if (filename) {
101 (job->callbacks->render)(job, "dot", filename);
102 g_object_set_data_full(G_OBJECT(window1),
103 "activefilename", filename, (GDestroyNotify)g_free);
104 }
105 }
106
107 void
on_save1_activate(GtkMenuItem * menuitem,gpointer user_data)108 on_save1_activate (GtkMenuItem *menuitem,
109 gpointer user_data)
110 {
111 GtkWindow *window1;
112 gchar *filename;
113
114 window1 = GTK_WINDOW(menuitem);
115 filename = (gchar *)g_object_get_data(G_OBJECT(window1), "activefilename");
116 ui_save_graph(window1, filename);
117 }
118
119
120 void
on_save_as1_activate(GtkMenuItem * menuitem,gpointer user_data)121 on_save_as1_activate (GtkMenuItem *menuitem,
122 gpointer user_data)
123 {
124 GtkWindow *window1;
125
126 window1 = GTK_WINDOW(menuitem);
127 ui_save_graph(window1, NULL);
128 }
129
130
131 void
on_quit1_activate(GtkMenuItem * menuitem,gpointer user_data)132 on_quit1_activate (GtkMenuItem *menuitem,
133 gpointer user_data)
134 {
135 gtk_widget_destroy(GTK_WIDGET(gtk_widget_get_toplevel(GTK_WIDGET(menuitem))));
136 gtk_main_quit();
137 }
138
139
140 void
on_cut1_activate(GtkMenuItem * menuitem,gpointer user_data)141 on_cut1_activate (GtkMenuItem *menuitem,
142 gpointer user_data)
143 {
144 // I am thinking that we will annotate a node as to whether it is selected,
145 // then retrieve a list of selected nodes for these operations
146 }
147
148
149 void
on_copy1_activate(GtkMenuItem * menuitem,gpointer user_data)150 on_copy1_activate (GtkMenuItem *menuitem,
151 gpointer user_data)
152 {
153
154 }
155
156
157 void
on_paste1_activate(GtkMenuItem * menuitem,gpointer user_data)158 on_paste1_activate (GtkMenuItem *menuitem,
159 gpointer user_data)
160 {
161
162 }
163
164
165 void
on_delete1_activate(GtkMenuItem * menuitem,gpointer user_data)166 on_delete1_activate (GtkMenuItem *menuitem,
167 gpointer user_data)
168 {
169
170 }
171
172
173 void
on_about1_activate(GtkMenuItem * menuitem,gpointer user_data)174 on_about1_activate (GtkMenuItem *menuitem,
175 gpointer user_data)
176 {
177 static gchar *authors[] = {
178 "John Ellson",
179 "Emden Gansner",
180 "Stephen North",
181 "special thanks to Michael Lawrence",
182 NULL };
183 GtkWindow *window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(menuitem)));
184 gtk_show_about_dialog(window,
185 "name", "DotEdit",
186 "program-name", "DotEdit",
187 "version", "0.1",
188 "copyright", "(C) 2011 AT&T Intellectual Procerty.",
189 "license", "Eclipse Public License v1.0.",
190 "website", "http://www.graphviz.org",
191 "comments", "Visualize and edit graphs of nodes and edges",
192 "authors", authors,
193 NULL);
194 }
195
196 static void
load_store_with_attrs(GtkListStore * model,GVJ_t * job)197 load_store_with_attrs(GtkListStore *model, GVJ_t *job)
198 {
199 #if 0
200 gint attrs_len = job->selected_obj_attributes.argc, i;
201 gchar **attrs = job->selected_obj_attributes.argv;
202 GtkTreeIter iter;
203 gvattr_t type;
204 #endif
205
206 gtk_list_store_clear(model);
207
208 #if 0
209 for (i = 0; i < attrs_len; i+=3) {
210 gtk_list_store_append(model, &iter);
211 gtk_list_store_set(model, &iter, 0, attrs[i], 1, g_strdup(attrs[i+1]), -1);
212 type = (gvattr_t)attrs[i+2];
213 }
214 #endif
215 }
216
217
218 gboolean
on_drawingarea1_expose_event(GtkWidget * widget,GdkEventExpose * event,gpointer user_data)219 on_drawingarea1_expose_event (GtkWidget *widget,
220 GdkEventExpose *event,
221 gpointer user_data)
222 {
223 GVJ_t *job;
224 cairo_t *cr;
225
226 job = (GVJ_t *)g_object_get_data(G_OBJECT(widget),"job");
227 cr = gdk_cairo_create(widget->window);
228
229 (job->callbacks->motion)(job, job->pointer);
230
231 job->context = (void *)cr;
232 job->external_context = TRUE;
233 job->width = widget->allocation.width;
234 job->height = widget->allocation.height;
235 if (job->has_been_rendered) {
236 (job->callbacks->refresh)(job);
237 }
238 else {
239 (job->callbacks->refresh)(job);
240
241 // FIXME - copy image to keyhole
242 // the keyhole image is a fixed size and doesn;t need to be recomputed
243 // each time. save a pixmap, then each time, show pixmap and overlay
244 // with scaled view rectangle.
245
246 }
247 cairo_destroy(cr);
248
249 load_store_with_attrs(GTK_LIST_STORE(g_object_get_data(G_OBJECT(widget), "attr_store")), job);
250
251 return FALSE;
252 }
253
254
255 gboolean
on_drawingarea1_motion_notify_event(GtkWidget * widget,GdkEventMotion * event,gpointer user_data)256 on_drawingarea1_motion_notify_event (GtkWidget *widget,
257 GdkEventMotion *event,
258 gpointer user_data)
259 {
260 GVJ_t *job;
261
262 job = (GVJ_t *)g_object_get_data(G_OBJECT(widget),"job");
263 job->pointer.x = event->x;
264 job->pointer.y = event->y;
265 gtk_widget_queue_draw(widget);
266
267 #if 0
268 if (job->active_tooltip && job->active_tooltip[0])
269 fprintf(stderr,"tooltip = \"%s\"\n", job->active_tooltip);
270 #endif
271
272 return FALSE;
273 }
274
275
276 gboolean
on_drawingarea2_motion_notify_event(GtkWidget * widget,GdkEventMotion * event,gpointer user_data)277 on_drawingarea2_motion_notify_event (GtkWidget *widget,
278 GdkEventMotion *event,
279 gpointer user_data)
280 {
281
282 return FALSE;
283 }
284
285
286
287 gboolean
on_drawingarea2_expose_event(GtkWidget * widget,GdkEventExpose * event,gpointer user_data)288 on_drawingarea2_expose_event (GtkWidget *widget,
289 GdkEventExpose *event,
290 gpointer user_data)
291 {
292 GVJ_t *job;
293 cairo_t *cr;
294 double tmp;
295
296 job = (GVJ_t *)g_object_get_data(G_OBJECT(widget),"job");
297 cr = gdk_cairo_create(widget->window);
298
299 (job->callbacks->motion)(job, job->pointer);
300
301 job->context = (void *)cr;
302 job->external_context = TRUE;
303 job->width = widget->allocation.width;
304 job->height = widget->allocation.height;
305
306 tmp = job->zoom;
307 job->zoom = MIN(job->width * POINTS_PER_INCH / (job->bb.UR.x * job->dpi.x),
308 job->height * POINTS_PER_INCH / (job->bb.UR.y * job->dpi.y));
309 (job->callbacks->refresh)(job);
310 job->zoom = tmp;
311
312 cairo_destroy(cr);
313
314 return FALSE;
315 }
316
317 gboolean
on_window1_delete_event(GtkWidget * widget,GdkEvent * event,gpointer user_data)318 on_window1_delete_event (GtkWidget *widget,
319 GdkEvent *event,
320 gpointer user_data)
321 {
322 gtk_main_quit();
323 return FALSE;
324 }
325
326
327 gboolean
on_drawingarea1_configure_event(GtkWidget * widget,GdkEventConfigure * event,gpointer user_data)328 on_drawingarea1_configure_event (GtkWidget *widget,
329 GdkEventConfigure *event,
330 gpointer user_data)
331 {
332 GVJ_t *job;
333 double zoom_to_fit;
334
335 /*FIXME - should allow for margins */
336 /* - similar zoom_to_fit code exists in: */
337 /* plugin/gtk/callbacks.c */
338 /* plugin/xlib/gvdevice_xlib.c */
339 /* lib/gvc/gvevent.c */
340
341 job = (GVJ_t *)g_object_get_data(G_OBJECT(widget),"job");
342 if (! job->has_been_rendered) {
343 zoom_to_fit = MIN((double) event->width / (double) job->width,
344 (double) event->height / (double) job->height);
345 if (zoom_to_fit < 1.0) /* don't make bigger */
346 job->zoom *= zoom_to_fit;
347 }
348 else if (job->fit_mode) {
349 zoom_to_fit = MIN((double) event->width / (double) job->width,
350 (double) event->height / (double) job->height);
351 job->zoom *= zoom_to_fit;
352 }
353 if (event->width > job->width || event->height > job->height)
354 job->has_grown = TRUE;
355 job->width = event->width;
356 job->height = event->height;
357 job->needs_refresh = TRUE;
358
359 return FALSE;
360 }
361
362
363 gboolean
on_drawingarea1_button_press_event(GtkWidget * widget,GdkEventButton * event,gpointer user_data)364 on_drawingarea1_button_press_event (GtkWidget *widget,
365 GdkEventButton *event,
366 gpointer user_data)
367 {
368 GVJ_t *job;
369 pointf pointer;
370
371 job = (GVJ_t *)g_object_get_data(G_OBJECT(widget),"job");
372 pointer.x = event->x;
373 pointer.y = event->y;
374 (job->callbacks->button_press)(job, event->button, pointer);
375
376 load_store_with_attrs(GTK_LIST_STORE(g_object_get_data(G_OBJECT(widget), "attr_store")), job);
377 return FALSE;
378 }
379
380
381 gboolean
on_drawingarea1_button_release_event(GtkWidget * widget,GdkEventButton * event,gpointer user_data)382 on_drawingarea1_button_release_event (GtkWidget *widget,
383 GdkEventButton *event,
384 gpointer user_data)
385 {
386 GVJ_t *job;
387 pointf pointer;
388
389 job = (GVJ_t *)g_object_get_data(G_OBJECT(widget),"job");
390 pointer.x = event->x;
391 pointer.y = event->y;
392 (job->callbacks->button_release)(job, event->button, pointer);
393
394 return FALSE;
395 }
396
397
398 gboolean
on_drawingarea1_scroll_event(GtkWidget * widget,GdkEvent * event,gpointer user_data)399 on_drawingarea1_scroll_event (GtkWidget *widget,
400 GdkEvent *event,
401 gpointer user_data)
402 {
403 GVJ_t *job;
404 pointf pointer;
405
406 job = (GVJ_t *)g_object_get_data(G_OBJECT(widget),"job");
407 pointer.x = ((GdkEventScroll *)event)->x;
408 pointer.y = ((GdkEventScroll *)event)->y;
409 switch (((GdkEventScroll *)event)->direction) {
410 case GDK_SCROLL_UP:
411 (job->callbacks->button_press)(job, 4, pointer);
412 break;
413 case GDK_SCROLL_DOWN:
414 (job->callbacks->button_press)(job, 5, pointer);
415 break;
416 case GDK_SCROLL_LEFT:
417 case GDK_SCROLL_RIGHT:
418 break;
419 }
420 gtk_widget_queue_draw(widget);
421
422 return FALSE;
423 }
424
425 gboolean
on_button1_button_press_event(GtkWidget * widget,GdkEventButton * event,gpointer user_data)426 on_button1_button_press_event (GtkWidget *widget,
427 GdkEventButton *event,
428 gpointer user_data)
429 {
430
431
432 fprintf(stderr, "will delete selected object\n");
433
434 return FALSE;
435 }
436
437