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