Signal patch
[dia.git] / lib / diaarrowchooser.c
blobd7b21d960749ddb1d62450d1d463914a6a4cce6a
1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
4 * diarrowchooser.c -- Copyright (C) 1999 James Henstridge.
5 * Copyright (C) 2004 Hubert Figuiere
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.
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.
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.
22 /** A widget to choose arrowhead. This only select arrowhead, not width
23 * and height. */
25 #include <gtk/gtk.h>
27 #include "intl.h"
28 #include "widgets.h"
29 #include "diaarrowchooser.h"
30 #include "render_pixmap.h"
32 static const char *button_menu_key = "dia-button-menu";
33 static const char *menuitem_enum_key = "dia-menuitem-value";
35 /* --------------- DiaArrowPreview -------------------------------- */
36 static void dia_arrow_preview_set(DiaArrowPreview *arrow,
37 ArrowType atype, gboolean left);
39 static void dia_arrow_preview_class_init (DiaArrowPreviewClass *klass);
40 static void dia_arrow_preview_init (DiaArrowPreview *arrow);
41 static gint dia_arrow_preview_expose (GtkWidget *widget,
42 GdkEventExpose *event);
44 /** Get the class information for the arrow preview widget.
45 * @return A type object (statically allocated) for the arrow preview object.
47 GType
48 dia_arrow_preview_get_type(void)
50 static GType type = 0;
52 if (!type) {
53 static const GTypeInfo info = {
54 sizeof (DiaArrowPreviewClass),
55 (GBaseInitFunc) NULL,
56 (GBaseFinalizeFunc) NULL,
57 (GClassInitFunc) dia_arrow_preview_class_init,
58 (GClassFinalizeFunc) NULL,
59 NULL,
60 sizeof (DiaArrowPreview),
62 (GInstanceInitFunc) dia_arrow_preview_init
65 type = g_type_register_static(GTK_TYPE_MISC, "DiaArrowPreview", &info, 0);
68 return type;
71 /** Initialize class information for the arrow preview class.
72 * @param class The class object to initialize/
74 static void
75 dia_arrow_preview_class_init(DiaArrowPreviewClass *class)
77 GtkWidgetClass *widget_class;
79 widget_class = GTK_WIDGET_CLASS (class);
80 widget_class->expose_event = dia_arrow_preview_expose;
83 /** Initialize an arrow preview widget.
84 * @param arrow The widget to initialize.
86 static void
87 dia_arrow_preview_init(DiaArrowPreview *arrow)
89 GTK_WIDGET_SET_FLAGS (arrow, GTK_NO_WINDOW);
91 GTK_WIDGET (arrow)->requisition.width = 40 + GTK_MISC (arrow)->xpad * 2;
92 GTK_WIDGET (arrow)->requisition.height = 20 + GTK_MISC (arrow)->ypad * 2;
94 arrow->atype = ARROW_NONE;
95 arrow->left = TRUE;
98 /** Create a new arrow preview widget.
99 * @param atype The type of arrow to start out selected with.
100 * @param left If TRUE, this preview will point to the left.
101 * @return A new widget.
103 GtkWidget *
104 dia_arrow_preview_new(ArrowType atype, gboolean left)
106 DiaArrowPreview *arrow = g_object_new(DIA_TYPE_ARROW_PREVIEW, NULL);
108 arrow->atype = atype;
109 arrow->left = left;
110 return GTK_WIDGET(arrow);
113 /** Set the values shown by an arrow preview widget.
114 * @param arrow Preview widget to change.
115 * @param atype New arrow type to use.
116 * @param left If TRUE, the preview should point to the left.
118 static void
119 dia_arrow_preview_set(DiaArrowPreview *arrow, ArrowType atype, gboolean left)
121 if (arrow->atype != atype || arrow->left != left) {
122 arrow->atype = atype;
123 arrow->left = left;
124 if (GTK_WIDGET_DRAWABLE(arrow))
125 gtk_widget_queue_draw(GTK_WIDGET(arrow));
129 /** Expose handle for the arrow preview widget.
130 * @param widget The widget to display.
131 * @param event The event that caused the call.
132 * @return TRUE always.
133 * @bugs Reference the situations where this gets called.
135 static gint
136 dia_arrow_preview_expose(GtkWidget *widget, GdkEventExpose *event)
138 if (GTK_WIDGET_DRAWABLE(widget)) {
139 Point from, to;
140 Point move_arrow, move_line, arrow_head;
141 DiaRenderer *renderer;
142 DiaArrowPreview *arrow = DIA_ARROW_PREVIEW(widget);
143 Arrow arrow_type;
144 GtkMisc *misc = GTK_MISC(widget);
145 gint width, height;
146 gint x, y;
147 GdkWindow *win;
148 int linewidth = 2;
149 DiaRendererClass *renderer_ops;
151 width = widget->allocation.width - misc->xpad * 2;
152 height = widget->allocation.height - misc->ypad * 2;
153 x = (widget->allocation.x + misc->xpad);
154 y = (widget->allocation.y + misc->ypad);
156 win = widget->window;
158 to.y = from.y = height/2;
159 if (arrow->left) {
160 from.x = width-linewidth;
161 to.x = 0;
162 } else {
163 from.x = 0;
164 to.x = width-linewidth;
167 /* here we must do some acrobaticts and construct Arrow type
168 * variable
170 arrow_type.type = arrow->atype;
171 arrow_type.length = .75*((real)height-linewidth);
172 arrow_type.width = .75*((real)height-linewidth);
174 /* and here we calculate new arrow start and end of line points */
175 calculate_arrow_point(&arrow_type, &from, &to,
176 &move_arrow, &move_line,
177 linewidth);
178 arrow_head = to;
179 point_add(&arrow_head, &move_arrow);
180 point_add(&to, &move_line);
182 renderer = new_pixmap_renderer(win, width, height);
183 renderer_ops = DIA_RENDERER_GET_CLASS (renderer);
184 renderer_pixmap_set_pixmap(renderer, win, x, y, width, height);
185 renderer_ops->begin_render(renderer);
186 renderer_ops->set_linewidth(renderer, linewidth);
187 renderer_ops->draw_line(renderer, &from, &to, &color_black);
188 arrow_draw (renderer, arrow_type.type,
189 &arrow_head, &from,
190 arrow_type.length,
191 arrow_type.width,
192 linewidth, &color_black, &color_white);
193 renderer_ops->end_render(renderer);
194 g_object_unref(renderer);
197 return TRUE;
201 /* ------- Code for DiaArrowChooser ----------------------- */
203 static void dia_arrow_chooser_class_init (DiaArrowChooserClass *klass);
204 static void dia_arrow_chooser_init (DiaArrowChooser *arrow);
206 /** Get the class info for the arrow chooser.
207 * @return GType structure filled in for arrow chooser (statically allocated).
209 GType
210 dia_arrow_chooser_get_type(void)
212 static GType type = 0;
214 if (!type) {
215 static const GTypeInfo info = {
216 sizeof (DiaArrowChooserClass),
217 (GBaseInitFunc) NULL,
218 (GBaseFinalizeFunc) NULL,
219 (GClassInitFunc) dia_arrow_chooser_class_init,
220 (GClassFinalizeFunc) NULL,
221 NULL,
222 sizeof (DiaArrowChooser),
224 (GInstanceInitFunc) dia_arrow_chooser_init
227 type = g_type_register_static(GTK_TYPE_BUTTON, "DiaArrowChooser", &info, 0);
230 return type;
233 /** Generic event handle for the arrow choose.
234 * This just handles popping up the arrowhead menu when the button is clicked.
235 * @param widget The arrow chooser widget.
236 * @param event An event affecting the arrow chooser.
237 * @return TRUE if we handled the event, FALSE otherwise.
239 static gint
240 dia_arrow_chooser_event(GtkWidget *widget, GdkEvent *event)
242 if (event->type == GDK_BUTTON_PRESS && event->button.button == 1) {
243 GtkMenu *menu = gtk_object_get_data(GTK_OBJECT(widget), button_menu_key);
244 gtk_menu_popup(menu, NULL, NULL, NULL, NULL,
245 event->button.button, event->button.time);
246 return TRUE;
249 return FALSE;
252 /** Initialize class information for the arrow choose.
253 * @param class Class structure to initialize private fields of.
255 static void
256 dia_arrow_chooser_class_init(DiaArrowChooserClass *class)
258 GtkWidgetClass *widget_class;
260 widget_class = GTK_WIDGET_CLASS(class);
261 widget_class->event = dia_arrow_chooser_event;
264 /** Initialize an arrow choose object.
265 * @param arrow Newly allocated arrow choose object.
267 static void
268 dia_arrow_chooser_init(DiaArrowChooser *arrow)
270 GtkWidget *wid;
272 arrow->left = FALSE;
273 arrow->arrow.type = ARROW_NONE;
274 arrow->arrow.length = DEFAULT_ARROW_LENGTH;
275 arrow->arrow.width = DEFAULT_ARROW_WIDTH;
277 wid = dia_arrow_preview_new(ARROW_NONE, arrow->left);
278 gtk_container_add(GTK_CONTAINER(arrow), wid);
279 gtk_widget_show(wid);
280 arrow->preview = DIA_ARROW_PREVIEW(wid);
282 arrow->dialog = NULL;
285 /** Handle the "ressponse" event for the arrow chooser dialog.
286 * @param dialog The dialog that got a response.
287 * @param response_id The ID of the response (e.g. GTK_RESPONSE_OK)
288 * @param chooser The arrowchooser widget (userdata)
290 static void
291 dia_arrow_chooser_dialog_response(GtkWidget *dialog,
292 gint response_id,
293 DiaArrowChooser *chooser)
295 if (response_id == GTK_RESPONSE_OK) {
296 Arrow new_arrow = dia_arrow_selector_get_arrow(chooser->selector);
298 if (new_arrow.type != chooser->arrow.type ||
299 new_arrow.length != chooser->arrow.length ||
300 new_arrow.width != chooser->arrow.width) {
301 chooser->arrow = new_arrow;
302 dia_arrow_preview_set(chooser->preview, new_arrow.type, chooser->left);
303 if (chooser->callback)
304 (* chooser->callback)(chooser->arrow, chooser->user_data);
306 } else {
307 dia_arrow_selector_set_arrow(chooser->selector, chooser->arrow);
309 gtk_widget_hide(chooser->dialog);
312 /** Create a new arrow chooser dialog.
313 * @param chooser The widget to attach a dialog to. The dialog will be placed
314 * in chooser->dialog.
316 static void
317 dia_arrow_chooser_dialog_new(DiaArrowChooser *chooser)
319 GtkWidget *wid;
321 chooser->dialog = gtk_dialog_new_with_buttons(_("Arrow Properties"),
322 NULL,
323 GTK_DIALOG_NO_SEPARATOR,
324 GTK_STOCK_CANCEL,
325 GTK_RESPONSE_CANCEL,
326 GTK_STOCK_OK,
327 GTK_RESPONSE_OK,
328 NULL);
329 gtk_dialog_set_default_response(GTK_DIALOG(chooser->dialog),
330 GTK_RESPONSE_OK);
331 g_signal_connect(G_OBJECT(chooser->dialog), "response",
332 G_CALLBACK(dia_arrow_chooser_dialog_response), chooser);
333 g_signal_connect(G_OBJECT(chooser->dialog), "destroy",
334 G_CALLBACK(gtk_widget_destroyed), &chooser->dialog);
336 wid = dia_arrow_selector_new();
337 gtk_container_set_border_width(GTK_CONTAINER(wid), 5);
338 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(chooser->dialog)->vbox), wid,
339 TRUE, TRUE, 0);
340 gtk_widget_show(wid);
341 chooser->selector = DIA_ARROW_SELECTOR(wid);
344 /** Display an arrow chooser dialog, creating one if necessary.
345 * @param widget Ignored
346 * @param chooser An arrowchooser widget to display in a dialog. This may
347 * get the dialog field set as a sideeffect.
349 static void
350 dia_arrow_chooser_dialog_show(GtkWidget *widget, DiaArrowChooser *chooser)
352 if (chooser->dialog) {
353 gtk_window_present(GTK_WINDOW(chooser->dialog));
354 return;
357 dia_arrow_chooser_dialog_new(chooser);
358 dia_arrow_selector_set_arrow(chooser->selector, chooser->arrow);
359 gtk_widget_show(chooser->dialog);
362 /** Set a new arrow type for an arrow chooser, as selected from a menu.
363 * @param mi The menu item currently selected in the arrow chooser menu.
364 * @param chooser The arrow chooser to update.
366 static void
367 dia_arrow_chooser_change_arrow_type(GtkMenuItem *mi, DiaArrowChooser *chooser)
369 ArrowType atype = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(mi),
370 menuitem_enum_key));
371 Arrow arrow;
372 arrow.width = chooser->arrow.width;
373 arrow.length = chooser->arrow.length;
374 arrow.type = atype;
375 dia_arrow_chooser_set_arrow(chooser, &arrow);
378 /** Create a new arrow chooser object.
379 * @param left If TRUE, this chooser will point its arrowheads to the left.
380 * @param callback void (*callback)(Arrow *arrow, gpointer user_data) which
381 * will be called when the arrow type or dimensions change.
382 * @param user_data Any user data. This will be stored in chooser->user_data.
383 * @param tool_tips An object to set arrow names with.
384 * @return A new DiaArrowChooser widget.
386 GtkWidget *
387 dia_arrow_chooser_new(gboolean left, DiaChangeArrowCallback callback,
388 gpointer user_data, GtkTooltips *tool_tips)
390 DiaArrowChooser *chooser = g_object_new(DIA_TYPE_ARROW_CHOOSER, NULL);
391 GtkWidget *menu, *mi, *ar;
392 gint i;
394 chooser->left = left;
395 dia_arrow_preview_set(chooser->preview, chooser->preview->atype, left);
396 chooser->callback = callback;
397 chooser->user_data = user_data;
399 menu = gtk_menu_new();
400 g_object_ref(G_OBJECT(menu));
401 gtk_object_sink(GTK_OBJECT(menu));
402 g_object_set_data_full(G_OBJECT(chooser), button_menu_key, menu,
403 (GtkDestroyNotify)gtk_widget_unref);
404 for (i = 0; arrow_types[i].name != NULL; i++) {
405 mi = gtk_menu_item_new();
406 g_object_set_data(G_OBJECT(mi), menuitem_enum_key,
407 GINT_TO_POINTER(arrow_types[i].enum_value));
408 if (tool_tips) {
409 gtk_tooltips_set_tip(tool_tips, mi, arrow_types[i].name, NULL);
411 ar = dia_arrow_preview_new(arrow_types[i].enum_value, left);
413 gtk_container_add(GTK_CONTAINER(mi), ar);
414 gtk_widget_show(ar);
415 g_signal_connect(G_OBJECT(mi), "activate",
416 G_CALLBACK(dia_arrow_chooser_change_arrow_type), chooser);
417 gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
418 gtk_widget_show(mi);
420 mi = gtk_menu_item_new_with_label(_("Details..."));
421 g_signal_connect(G_OBJECT(mi), "activate",
422 G_CALLBACK(dia_arrow_chooser_dialog_show), chooser);
423 gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
424 gtk_widget_show(mi);
426 return GTK_WIDGET(chooser);
429 /** Set the type of arrow shown by the arrow chooser. If the arrow type
430 * changes, the callback function will be called.
431 * @param chooser The chooser to update.
432 * @param arrow The arrow type and dimensions the chooser will dispaly.
433 * @bugs Should it be called as well when the dimensions change?
435 void
436 dia_arrow_chooser_set_arrow(DiaArrowChooser *chooser, Arrow *arrow)
438 if (chooser->arrow.type != arrow->type) {
439 dia_arrow_preview_set(chooser->preview, arrow->type, chooser->left);
440 chooser->arrow.type = arrow->type;
441 if (chooser->dialog != NULL)
442 dia_arrow_selector_set_arrow(chooser->selector, chooser->arrow);
443 if (chooser->callback)
444 (* chooser->callback)(chooser->arrow, chooser->user_data);
446 chooser->arrow.width = arrow->width;
447 chooser->arrow.length = arrow->length;
450 /** Get the currently selected arrow type from an arrow chooser.
451 * @param arrow An arrow chooser to query.
452 * @return The arrow type that is currently selected in the chooser.
454 ArrowType
455 dia_arrow_chooser_get_arrow_type(DiaArrowChooser *arrow)
457 return arrow->arrow.type;