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
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.
48 dia_arrow_preview_get_type(void)
50 static GType type
= 0;
53 static const GTypeInfo info
= {
54 sizeof (DiaArrowPreviewClass
),
56 (GBaseFinalizeFunc
) NULL
,
57 (GClassInitFunc
) dia_arrow_preview_class_init
,
58 (GClassFinalizeFunc
) NULL
,
60 sizeof (DiaArrowPreview
),
62 (GInstanceInitFunc
) dia_arrow_preview_init
65 type
= g_type_register_static(GTK_TYPE_MISC
, "DiaArrowPreview", &info
, 0);
71 /** Initialize class information for the arrow preview class.
72 * @param class The class object to initialize/
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.
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
;
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.
104 dia_arrow_preview_new(ArrowType atype
, gboolean left
)
106 DiaArrowPreview
*arrow
= g_object_new(DIA_TYPE_ARROW_PREVIEW
, NULL
);
108 arrow
->atype
= atype
;
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.
119 dia_arrow_preview_set(DiaArrowPreview
*arrow
, ArrowType atype
, gboolean left
)
121 if (arrow
->atype
!= atype
|| arrow
->left
!= left
) {
122 arrow
->atype
= atype
;
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.
136 dia_arrow_preview_expose(GtkWidget
*widget
, GdkEventExpose
*event
)
138 if (GTK_WIDGET_DRAWABLE(widget
)) {
140 Point move_arrow
, move_line
, arrow_head
;
141 DiaRenderer
*renderer
;
142 DiaArrowPreview
*arrow
= DIA_ARROW_PREVIEW(widget
);
144 GtkMisc
*misc
= GTK_MISC(widget
);
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;
160 from
.x
= width
-linewidth
;
164 to
.x
= width
-linewidth
;
167 /* here we must do some acrobaticts and construct Arrow type
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
,
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
,
192 linewidth
, &color_black
, &color_white
);
193 renderer_ops
->end_render(renderer
);
194 g_object_unref(renderer
);
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).
210 dia_arrow_chooser_get_type(void)
212 static GType type
= 0;
215 static const GTypeInfo info
= {
216 sizeof (DiaArrowChooserClass
),
217 (GBaseInitFunc
) NULL
,
218 (GBaseFinalizeFunc
) NULL
,
219 (GClassInitFunc
) dia_arrow_chooser_class_init
,
220 (GClassFinalizeFunc
) NULL
,
222 sizeof (DiaArrowChooser
),
224 (GInstanceInitFunc
) dia_arrow_chooser_init
227 type
= g_type_register_static(GTK_TYPE_BUTTON
, "DiaArrowChooser", &info
, 0);
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.
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
);
252 /** Initialize class information for the arrow choose.
253 * @param class Class structure to initialize private fields of.
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.
268 dia_arrow_chooser_init(DiaArrowChooser
*arrow
)
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)
291 dia_arrow_chooser_dialog_response(GtkWidget
*dialog
,
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
);
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.
317 dia_arrow_chooser_dialog_new(DiaArrowChooser
*chooser
)
321 chooser
->dialog
= gtk_dialog_new_with_buttons(_("Arrow Properties"),
323 GTK_DIALOG_NO_SEPARATOR
,
329 gtk_dialog_set_default_response(GTK_DIALOG(chooser
->dialog
),
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
,
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.
350 dia_arrow_chooser_dialog_show(GtkWidget
*widget
, DiaArrowChooser
*chooser
)
352 if (chooser
->dialog
) {
353 gtk_window_present(GTK_WINDOW(chooser
->dialog
));
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.
367 dia_arrow_chooser_change_arrow_type(GtkMenuItem
*mi
, DiaArrowChooser
*chooser
)
369 ArrowType atype
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(mi
),
372 arrow
.width
= chooser
->arrow
.width
;
373 arrow
.length
= chooser
->arrow
.length
;
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.
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
;
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
));
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
);
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
);
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
);
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?
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.
455 dia_arrow_chooser_get_arrow_type(DiaArrowChooser
*arrow
)
457 return arrow
->arrow
.type
;