1 /* Dia -- an diagram creation/manipulation program
2  * Copyright (C) 1998 Alexander Larsson
3  *
4  * dialinechooser.c -- Copyright (C) 1999 James Henstridge.
5  *                     Copyright (C) 2004 Hubert Figuiere
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 
26 #include "intl.h"
27 #include "widgets.h"
28 #include "dialinechooser.h"
29 
30 static const char *button_menu_key = "dia-button-menu";
31 static const char *menuitem_enum_key = "dia-menuitem-value";
32 
33 
34 /* --------------- DiaLinePreview -------------------------------- */
35 
36 static void dia_line_preview_set(DiaLinePreview *line, LineStyle lstyle);
37 
38 static void dia_line_preview_class_init (DiaLinePreviewClass  *klass);
39 static void dia_line_preview_init       (DiaLinePreview       *arrow);
40 static gint dia_line_preview_expose     (GtkWidget      *widget,
41 					 GdkEventExpose *event);
42 
43 GType
dia_line_preview_get_type(void)44 dia_line_preview_get_type (void)
45 {
46   static GType type = 0;
47 
48   if (!type) {
49     static const GTypeInfo info = {
50       sizeof (DiaLinePreviewClass),
51       (GBaseInitFunc) NULL,
52       (GBaseFinalizeFunc) NULL,
53       (GClassInitFunc) dia_line_preview_class_init,
54       (GClassFinalizeFunc) NULL,
55       NULL,
56       sizeof (DiaLinePreview),
57       0,
58       (GInstanceInitFunc) dia_line_preview_init
59     };
60 
61     type = g_type_register_static (GTK_TYPE_MISC, "DiaLinePreview", &info, 0);
62   }
63 
64   return type;
65 }
66 
67 static void
dia_line_preview_class_init(DiaLinePreviewClass * class)68 dia_line_preview_class_init (DiaLinePreviewClass *class)
69 {
70   GtkWidgetClass *widget_class;
71 
72   widget_class = GTK_WIDGET_CLASS(class);
73   widget_class->expose_event = dia_line_preview_expose;
74 }
75 
76 static void
dia_line_preview_init(DiaLinePreview * line)77 dia_line_preview_init (DiaLinePreview *line)
78 {
79   GTK_WIDGET_SET_FLAGS (line, GTK_NO_WINDOW);
80 
81   GTK_WIDGET (line)->requisition.width = 30 + GTK_MISC (line)->xpad * 2;
82   GTK_WIDGET (line)->requisition.height = 15 + GTK_MISC (line)->ypad * 2;
83 
84   line->lstyle = LINESTYLE_SOLID;
85 }
86 
87 GtkWidget *
dia_line_preview_new(LineStyle lstyle)88 dia_line_preview_new (LineStyle lstyle)
89 {
90   DiaLinePreview *line = g_object_new(DIA_TYPE_LINE_PREVIEW, NULL);
91 
92   line->lstyle = lstyle;
93   return GTK_WIDGET(line);
94 }
95 
96 static void
dia_line_preview_set(DiaLinePreview * line,LineStyle lstyle)97 dia_line_preview_set(DiaLinePreview *line, LineStyle lstyle)
98 {
99   if (line->lstyle != lstyle) {
100     line->lstyle = lstyle;
101     if (GTK_WIDGET_DRAWABLE(line))
102       gtk_widget_queue_draw(GTK_WIDGET(line));
103   }
104 }
105 
106 static gint
dia_line_preview_expose(GtkWidget * widget,GdkEventExpose * event)107 dia_line_preview_expose(GtkWidget *widget, GdkEventExpose *event)
108 {
109   DiaLinePreview *line = DIA_LINE_PREVIEW(widget);
110   GtkMisc *misc = GTK_MISC(widget);
111   gint width, height;
112   gint x, y;
113   gint extent;
114   GdkWindow *win;
115   GdkGC *gc;
116   GdkGCValues gcvalues;
117   gint8 dash_list[6];
118   int line_width = 2;
119 
120   if (GTK_WIDGET_DRAWABLE(widget)) {
121     width = widget->allocation.width - misc->xpad * 2;
122     height = widget->allocation.height - misc->ypad * 2;
123     extent = MIN(width, height);
124     x = (widget->allocation.x + misc->xpad);
125     y = (widget->allocation.y + misc->ypad);
126 
127     win = widget->window;
128     gc = widget->style->fg_gc[widget->state];
129 
130     /* increase line width */
131     gdk_gc_get_values(gc, &gcvalues);
132     switch (line->lstyle) {
133     case LINESTYLE_SOLID:
134       gdk_gc_set_line_attributes(gc, line_width, GDK_LINE_SOLID,
135 				 gcvalues.cap_style, gcvalues.join_style);
136       break;
137     case LINESTYLE_DASHED:
138       gdk_gc_set_line_attributes(gc, line_width, GDK_LINE_ON_OFF_DASH,
139 				 gcvalues.cap_style, gcvalues.join_style);
140       dash_list[0] = 10;
141       dash_list[1] = 10;
142       gdk_gc_set_dashes(gc, 0, dash_list, 2);
143       break;
144     case LINESTYLE_DASH_DOT:
145       gdk_gc_set_line_attributes(gc, line_width, GDK_LINE_ON_OFF_DASH,
146 				 gcvalues.cap_style, gcvalues.join_style);
147       dash_list[0] = 10;
148       dash_list[1] = 4;
149       dash_list[2] = 2;
150       dash_list[3] = 4;
151       gdk_gc_set_dashes(gc, 0, dash_list, 4);
152       break;
153     case LINESTYLE_DASH_DOT_DOT:
154       gdk_gc_set_line_attributes(gc, line_width, GDK_LINE_ON_OFF_DASH,
155 				 gcvalues.cap_style, gcvalues.join_style);
156       dash_list[0] = 10;
157       dash_list[1] = 2;
158       dash_list[2] = 2;
159       dash_list[3] = 2;
160       dash_list[4] = 2;
161       dash_list[5] = 2;
162       gdk_gc_set_dashes(gc, 0, dash_list, 6);
163       break;
164     case LINESTYLE_DOTTED:
165       gdk_gc_set_line_attributes(gc, line_width, GDK_LINE_ON_OFF_DASH,
166 				 gcvalues.cap_style, gcvalues.join_style);
167       dash_list[0] = 2;
168       dash_list[1] = 2;
169       gdk_gc_set_dashes(gc, 0, dash_list, 2);
170       break;
171     }
172     gdk_draw_line(win, gc, x, y+height/2, x+width, y+height/2);
173     gdk_gc_set_line_attributes(gc, gcvalues.line_width, gcvalues.line_style,
174 			       gcvalues.cap_style, gcvalues.join_style);
175   }
176   return TRUE;
177 }
178 
179 
180 /* ------- Code for DiaLineChooser ---------------------- */
181 
182 static void dia_line_chooser_class_init (DiaLineChooserClass  *klass);
183 static void dia_line_chooser_init       (DiaLineChooser       *arrow);
184 
185 GType
dia_line_chooser_get_type(void)186 dia_line_chooser_get_type (void)
187 {
188   static GType type = 0;
189 
190   if (!type) {
191     static const GTypeInfo info = {
192       sizeof (DiaLineChooserClass),
193       (GBaseInitFunc) NULL,
194       (GBaseFinalizeFunc) NULL,
195       (GClassInitFunc) dia_line_chooser_class_init,
196       (GClassFinalizeFunc) NULL,
197       NULL,
198       sizeof (DiaLineChooser),
199       0,
200       (GInstanceInitFunc) dia_line_chooser_init
201     };
202 
203     type = g_type_register_static (GTK_TYPE_BUTTON, "DiaLineChooser", &info, 0);
204   }
205 
206   return type;
207 }
208 
209 static gint
dia_line_chooser_event(GtkWidget * widget,GdkEvent * event)210 dia_line_chooser_event(GtkWidget *widget, GdkEvent *event)
211 {
212   if (event->type == GDK_BUTTON_PRESS && event->button.button == 1) {
213     GtkMenu *menu = g_object_get_data(G_OBJECT(widget), button_menu_key);
214     gtk_menu_popup(menu, NULL, NULL, NULL, NULL,
215 		   event->button.button, event->button.time);
216     return TRUE;
217   }
218   return FALSE;
219 }
220 
221 static void
dia_line_chooser_class_init(DiaLineChooserClass * class)222 dia_line_chooser_class_init (DiaLineChooserClass *class)
223 {
224   GtkWidgetClass *widget_class;
225 
226   widget_class = GTK_WIDGET_CLASS(class);
227   widget_class->event = dia_line_chooser_event;
228 }
229 
230 static void
dia_line_chooser_dialog_response(GtkWidget * dialog,gint response_id,DiaLineChooser * lchooser)231 dia_line_chooser_dialog_response (GtkWidget *dialog,
232                                   gint response_id,
233                                   DiaLineChooser *lchooser)
234 {
235   LineStyle new_style;
236   real new_dash;
237 
238   if (response_id == GTK_RESPONSE_OK) {
239     dia_line_style_selector_get_linestyle(lchooser->selector,
240 					  &new_style, &new_dash);
241     if (new_style != lchooser->lstyle || new_dash != lchooser->dash_length) {
242       lchooser->lstyle = new_style;
243       lchooser->dash_length = new_dash;
244       dia_line_preview_set(lchooser->preview, new_style);
245       if (lchooser->callback)
246         (* lchooser->callback)(new_style, new_dash, lchooser->user_data);
247     }
248   } else {
249     dia_line_style_selector_set_linestyle(lchooser->selector,
250                                           lchooser->lstyle,
251                                           lchooser->dash_length);
252   }
253   gtk_widget_hide(lchooser->dialog);
254 }
255 
256 static void
dia_line_chooser_change_line_style(GtkMenuItem * mi,DiaLineChooser * lchooser)257 dia_line_chooser_change_line_style(GtkMenuItem *mi, DiaLineChooser *lchooser)
258 {
259   LineStyle lstyle = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(mi),
260 						       menuitem_enum_key));
261 
262   dia_line_chooser_set_line_style(lchooser, lstyle, lchooser->dash_length);
263 }
264 
265 void
dia_line_chooser_set_line_style(DiaLineChooser * lchooser,LineStyle lstyle,real dashlength)266 dia_line_chooser_set_line_style(DiaLineChooser *lchooser,
267 				LineStyle lstyle,
268 				real dashlength)
269 {
270   if (lstyle != lchooser->lstyle) {
271     dia_line_preview_set(lchooser->preview, lstyle);
272     lchooser->lstyle = lstyle;
273     dia_line_style_selector_set_linestyle(lchooser->selector, lchooser->lstyle,
274 					  lchooser->dash_length);
275   }
276   lchooser->dash_length = dashlength;
277   if (lchooser->callback)
278     (* lchooser->callback)(lchooser->lstyle, lchooser->dash_length,
279 			   lchooser->user_data);
280 }
281 
282 static void
dia_line_chooser_init(DiaLineChooser * lchooser)283 dia_line_chooser_init (DiaLineChooser *lchooser)
284 {
285   GtkWidget *wid;
286   GtkWidget *menu, *mi, *ln;
287   gint i;
288 
289   lchooser->lstyle = LINESTYLE_SOLID;
290   lchooser->dash_length = DEFAULT_LINESTYLE_DASHLEN;
291 
292   wid = dia_line_preview_new(LINESTYLE_SOLID);
293   gtk_container_add(GTK_CONTAINER(lchooser), wid);
294   gtk_widget_show(wid);
295   lchooser->preview = DIA_LINE_PREVIEW(wid);
296 
297   lchooser->dialog = gtk_dialog_new_with_buttons(_("Line Style Properties"),
298                                                  NULL,
299                                                  GTK_DIALOG_NO_SEPARATOR,
300                                                  GTK_STOCK_CANCEL,
301                                                  GTK_RESPONSE_CANCEL,
302                                                  GTK_STOCK_OK,
303                                                  GTK_RESPONSE_OK,
304                                                  NULL);
305   gtk_dialog_set_default_response(GTK_DIALOG(lchooser->dialog),
306                                   GTK_RESPONSE_OK);
307   g_signal_connect(G_OBJECT(lchooser->dialog), "response",
308                    G_CALLBACK(dia_line_chooser_dialog_response), lchooser);
309 
310   wid = dia_line_style_selector_new();
311   gtk_container_set_border_width(GTK_CONTAINER(wid), 5);
312   gtk_box_pack_start(GTK_BOX(GTK_DIALOG(lchooser->dialog)->vbox), wid,
313 		     TRUE, TRUE, 0);
314   gtk_widget_show(wid);
315   lchooser->selector = DIALINESTYLESELECTOR(wid);
316 
317   menu = gtk_menu_new();
318 #if GLIB_CHECK_VERSION(2,10,0)
319   g_object_ref_sink(GTK_OBJECT(menu));
320   g_object_set_data_full(G_OBJECT(lchooser), button_menu_key, menu,
321 			 (GDestroyNotify)g_object_unref);
322 #else
323   g_object_ref(G_OBJECT(menu));
324   gtk_object_sink(GTK_OBJECT(menu));
325   g_object_set_data_full(G_OBJECT(lchooser), button_menu_key, menu,
326 			 (GDestroyNotify)gtk_widget_unref);
327 #endif
328   for (i = 0; i <= LINESTYLE_DOTTED; i++) {
329     mi = gtk_menu_item_new();
330     g_object_set_data(G_OBJECT(mi), menuitem_enum_key, GINT_TO_POINTER(i));
331     ln = dia_line_preview_new(i);
332     gtk_container_add(GTK_CONTAINER(mi), ln);
333     gtk_widget_show(ln);
334     g_signal_connect(G_OBJECT(mi), "activate",
335 		     G_CALLBACK(dia_line_chooser_change_line_style), lchooser);
336     gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
337     gtk_widget_show (mi);
338   }
339   mi = gtk_menu_item_new_with_label(_("Details..."));
340   g_signal_connect_swapped(G_OBJECT(mi), "activate",
341 			   G_CALLBACK(gtk_widget_show), lchooser->dialog);
342   gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
343   gtk_widget_show (mi);
344 }
345 
346 GtkWidget *
dia_line_chooser_new(DiaChangeLineCallback callback,gpointer user_data)347 dia_line_chooser_new(DiaChangeLineCallback callback,
348 		     gpointer user_data)
349 {
350   DiaLineChooser *chooser = g_object_new(DIA_TYPE_LINE_CHOOSER, NULL);
351 
352   chooser->callback = callback;
353   chooser->user_data = user_data;
354 
355   return GTK_WIDGET(chooser);
356 }
357 
358