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