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 /** \file diaarrowchooser.c A widget to choose arrowhead. This only select arrowhead, not width and height.
30 #include "diaarrowchooser.h"
31 #include "render_pixmap.h"
33 static const char *button_menu_key
= "dia-button-menu";
34 static const char *menuitem_enum_key
= "dia-menuitem-value";
36 /* --------------- DiaArrowPreview -------------------------------- */
37 static void dia_arrow_preview_set(DiaArrowPreview
*arrow
,
38 ArrowType atype
, gboolean left
);
40 static void dia_arrow_preview_class_init (DiaArrowPreviewClass
*klass
);
41 static void dia_arrow_preview_init (DiaArrowPreview
*arrow
);
42 static gint
dia_arrow_preview_expose (GtkWidget
*widget
,
43 GdkEventExpose
*event
);
45 /** Get the class information for the arrow preview widget.
46 * @return A type object (statically allocated) for the arrow preview object.
49 dia_arrow_preview_get_type(void)
51 static GType type
= 0;
54 static const GTypeInfo info
= {
55 sizeof (DiaArrowPreviewClass
),
57 (GBaseFinalizeFunc
) NULL
,
58 (GClassInitFunc
) dia_arrow_preview_class_init
,
59 (GClassFinalizeFunc
) NULL
,
61 sizeof (DiaArrowPreview
),
63 (GInstanceInitFunc
) dia_arrow_preview_init
66 type
= g_type_register_static(GTK_TYPE_MISC
, "DiaArrowPreview", &info
, 0);
72 /** Initialize class information for the arrow preview class.
73 * @param class The class object to initialize/
76 dia_arrow_preview_class_init(DiaArrowPreviewClass
*class)
78 GtkWidgetClass
*widget_class
;
80 widget_class
= GTK_WIDGET_CLASS (class);
81 widget_class
->expose_event
= dia_arrow_preview_expose
;
84 /** Initialize an arrow preview widget.
85 * @param arrow The widget to initialize.
88 dia_arrow_preview_init(DiaArrowPreview
*arrow
)
90 GTK_WIDGET_SET_FLAGS (arrow
, GTK_NO_WINDOW
);
92 GTK_WIDGET (arrow
)->requisition
.width
= 40 + GTK_MISC (arrow
)->xpad
* 2;
93 GTK_WIDGET (arrow
)->requisition
.height
= 20 + GTK_MISC (arrow
)->ypad
* 2;
95 arrow
->atype
= ARROW_NONE
;
99 /** Create a new arrow preview widget.
100 * @param atype The type of arrow to start out selected with.
101 * @param left If TRUE, this preview will point to the left.
102 * @return A new widget.
105 dia_arrow_preview_new(ArrowType atype
, gboolean left
)
107 DiaArrowPreview
*arrow
= g_object_new(DIA_TYPE_ARROW_PREVIEW
, NULL
);
109 arrow
->atype
= atype
;
111 return GTK_WIDGET(arrow
);
114 /** Set the values shown by an arrow preview widget.
115 * @param arrow Preview widget to change.
116 * @param atype New arrow type to use.
117 * @param left If TRUE, the preview should point to the left.
120 dia_arrow_preview_set(DiaArrowPreview
*arrow
, ArrowType atype
, gboolean left
)
122 if (arrow
->atype
!= atype
|| arrow
->left
!= left
) {
123 arrow
->atype
= atype
;
125 if (GTK_WIDGET_DRAWABLE(arrow
))
126 gtk_widget_queue_draw(GTK_WIDGET(arrow
));
130 /** Expose handle for the arrow preview widget.
131 * @param widget The widget to display.
132 * @param event The event that caused the call.
133 * @return TRUE always.
134 * The expose handler gets called when the Arrow needs to be drawn.
137 dia_arrow_preview_expose(GtkWidget
*widget
, GdkEventExpose
*event
)
139 if (GTK_WIDGET_DRAWABLE(widget
)) {
141 Point move_arrow
, move_line
, arrow_head
;
142 DiaRenderer
*renderer
;
143 DiaArrowPreview
*arrow
= DIA_ARROW_PREVIEW(widget
);
145 GtkMisc
*misc
= GTK_MISC(widget
);
150 DiaRendererClass
*renderer_ops
;
152 width
= widget
->allocation
.width
- misc
->xpad
* 2;
153 height
= widget
->allocation
.height
- misc
->ypad
* 2;
154 x
= (widget
->allocation
.x
+ misc
->xpad
);
155 y
= (widget
->allocation
.y
+ misc
->ypad
);
157 win
= widget
->window
;
159 to
.y
= from
.y
= height
/2;
161 from
.x
= width
-linewidth
;
165 to
.x
= width
-linewidth
;
168 /* here we must do some acrobaticts and construct Arrow type
171 arrow_type
.type
= arrow
->atype
;
172 arrow_type
.length
= .75*((real
)height
-linewidth
);
173 arrow_type
.width
= .75*((real
)height
-linewidth
);
175 /* and here we calculate new arrow start and end of line points */
176 calculate_arrow_point(&arrow_type
, &from
, &to
,
177 &move_arrow
, &move_line
,
180 point_add(&arrow_head
, &move_arrow
);
181 point_add(&to
, &move_line
);
183 renderer
= new_pixmap_renderer(win
, width
, height
);
184 renderer_ops
= DIA_RENDERER_GET_CLASS (renderer
);
185 renderer_pixmap_set_pixmap(renderer
, win
, x
, y
, width
, height
);
186 renderer_ops
->begin_render(renderer
);
187 renderer_ops
->set_linewidth(renderer
, linewidth
);
188 renderer_ops
->draw_line(renderer
, &from
, &to
, &color_black
);
189 arrow_draw (renderer
, arrow_type
.type
,
193 linewidth
, &color_black
, &color_white
);
194 renderer_ops
->end_render(renderer
);
195 g_object_unref(renderer
);
202 /* ------- Code for DiaArrowChooser ----------------------- */
204 static void dia_arrow_chooser_class_init (DiaArrowChooserClass
*klass
);
205 static void dia_arrow_chooser_init (DiaArrowChooser
*arrow
);
207 /** Get the class info for the arrow chooser.
208 * @return GType structure filled in for arrow chooser (statically allocated).
211 dia_arrow_chooser_get_type(void)
213 static GType type
= 0;
216 static const GTypeInfo info
= {
217 sizeof (DiaArrowChooserClass
),
218 (GBaseInitFunc
) NULL
,
219 (GBaseFinalizeFunc
) NULL
,
220 (GClassInitFunc
) dia_arrow_chooser_class_init
,
221 (GClassFinalizeFunc
) NULL
,
223 sizeof (DiaArrowChooser
),
225 (GInstanceInitFunc
) dia_arrow_chooser_init
228 type
= g_type_register_static(GTK_TYPE_BUTTON
, "DiaArrowChooser", &info
, 0);
234 /** Generic event handle for the arrow choose.
235 * This just handles popping up the arrowhead menu when the button is clicked.
236 * @param widget The arrow chooser widget.
237 * @param event An event affecting the arrow chooser.
238 * @return TRUE if we handled the event, FALSE otherwise.
241 dia_arrow_chooser_event(GtkWidget
*widget
, GdkEvent
*event
)
243 if (event
->type
== GDK_BUTTON_PRESS
&& event
->button
.button
== 1) {
244 GtkMenu
*menu
= gtk_object_get_data(GTK_OBJECT(widget
), button_menu_key
);
245 gtk_menu_popup(menu
, NULL
, NULL
, NULL
, NULL
,
246 event
->button
.button
, event
->button
.time
);
253 /** Initialize class information for the arrow choose.
254 * @param class Class structure to initialize private fields of.
257 dia_arrow_chooser_class_init(DiaArrowChooserClass
*class)
259 GtkWidgetClass
*widget_class
;
261 widget_class
= GTK_WIDGET_CLASS(class);
262 widget_class
->event
= dia_arrow_chooser_event
;
265 /** Initialize an arrow choose object.
266 * @param arrow Newly allocated arrow choose object.
269 dia_arrow_chooser_init(DiaArrowChooser
*arrow
)
274 arrow
->arrow
.type
= ARROW_NONE
;
275 arrow
->arrow
.length
= DEFAULT_ARROW_LENGTH
;
276 arrow
->arrow
.width
= DEFAULT_ARROW_WIDTH
;
278 wid
= dia_arrow_preview_new(ARROW_NONE
, arrow
->left
);
279 gtk_container_add(GTK_CONTAINER(arrow
), wid
);
280 gtk_widget_show(wid
);
281 arrow
->preview
= DIA_ARROW_PREVIEW(wid
);
283 arrow
->dialog
= NULL
;
286 /** Handle the "ressponse" event for the arrow chooser dialog.
287 * @param dialog The dialog that got a response.
288 * @param response_id The ID of the response (e.g. GTK_RESPONSE_OK)
289 * @param chooser The arrowchooser widget (userdata)
292 dia_arrow_chooser_dialog_response(GtkWidget
*dialog
,
294 DiaArrowChooser
*chooser
)
296 if (response_id
== GTK_RESPONSE_OK
) {
297 Arrow new_arrow
= dia_arrow_selector_get_arrow(chooser
->selector
);
299 if (new_arrow
.type
!= chooser
->arrow
.type
||
300 new_arrow
.length
!= chooser
->arrow
.length
||
301 new_arrow
.width
!= chooser
->arrow
.width
) {
302 chooser
->arrow
= new_arrow
;
303 dia_arrow_preview_set(chooser
->preview
, new_arrow
.type
, chooser
->left
);
304 if (chooser
->callback
)
305 (* chooser
->callback
)(chooser
->arrow
, chooser
->user_data
);
308 dia_arrow_selector_set_arrow(chooser
->selector
, chooser
->arrow
);
310 gtk_widget_hide(chooser
->dialog
);
313 /** Create a new arrow chooser dialog.
314 * @param chooser The widget to attach a dialog to. The dialog will be placed
315 * in chooser->dialog.
318 dia_arrow_chooser_dialog_new(DiaArrowChooser
*chooser
)
322 chooser
->dialog
= gtk_dialog_new_with_buttons(_("Arrow Properties"),
324 GTK_DIALOG_NO_SEPARATOR
,
330 gtk_dialog_set_default_response(GTK_DIALOG(chooser
->dialog
),
332 g_signal_connect(G_OBJECT(chooser
->dialog
), "response",
333 G_CALLBACK(dia_arrow_chooser_dialog_response
), chooser
);
334 g_signal_connect(G_OBJECT(chooser
->dialog
), "destroy",
335 G_CALLBACK(gtk_widget_destroyed
), &chooser
->dialog
);
337 wid
= dia_arrow_selector_new();
338 gtk_container_set_border_width(GTK_CONTAINER(wid
), 5);
339 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(chooser
->dialog
)->vbox
), wid
,
341 gtk_widget_show(wid
);
342 chooser
->selector
= DIA_ARROW_SELECTOR(wid
);
345 /** Display an arrow chooser dialog, creating one if necessary.
346 * @param widget Ignored
347 * @param chooser An arrowchooser widget to display in a dialog. This may
348 * get the dialog field set as a sideeffect.
351 dia_arrow_chooser_dialog_show(GtkWidget
*widget
, DiaArrowChooser
*chooser
)
353 if (chooser
->dialog
) {
354 gtk_window_present(GTK_WINDOW(chooser
->dialog
));
358 dia_arrow_chooser_dialog_new(chooser
);
359 dia_arrow_selector_set_arrow(chooser
->selector
, chooser
->arrow
);
360 gtk_widget_show(chooser
->dialog
);
363 /** Set a new arrow type for an arrow chooser, as selected from a menu.
364 * @param mi The menu item currently selected in the arrow chooser menu.
365 * @param chooser The arrow chooser to update.
368 dia_arrow_chooser_change_arrow_type(GtkMenuItem
*mi
, DiaArrowChooser
*chooser
)
370 ArrowType atype
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(mi
),
373 arrow
.width
= chooser
->arrow
.width
;
374 arrow
.length
= chooser
->arrow
.length
;
376 dia_arrow_chooser_set_arrow(chooser
, &arrow
);
379 /** Create a new arrow chooser object.
380 * @param left If TRUE, this chooser will point its arrowheads to the left.
381 * @param callback void (*callback)(Arrow *arrow, gpointer user_data) which
382 * will be called when the arrow type or dimensions change.
383 * @param user_data Any user data. This will be stored in chooser->user_data.
384 * @param tool_tips An object to set arrow names with.
385 * @return A new DiaArrowChooser widget.
388 dia_arrow_chooser_new(gboolean left
, DiaChangeArrowCallback callback
,
389 gpointer user_data
, GtkTooltips
*tool_tips
)
391 DiaArrowChooser
*chooser
= g_object_new(DIA_TYPE_ARROW_CHOOSER
, NULL
);
392 GtkWidget
*menu
, *mi
, *ar
;
395 chooser
->left
= left
;
396 dia_arrow_preview_set(chooser
->preview
, chooser
->preview
->atype
, left
);
397 chooser
->callback
= callback
;
398 chooser
->user_data
= user_data
;
400 menu
= gtk_menu_new();
401 g_object_ref(G_OBJECT(menu
));
402 gtk_object_sink(GTK_OBJECT(menu
));
403 g_object_set_data_full(G_OBJECT(chooser
), button_menu_key
, menu
,
404 (GtkDestroyNotify
)gtk_widget_unref
);
405 for (i
= 0; arrow_types
[i
].name
!= NULL
; i
++) {
406 mi
= gtk_menu_item_new();
407 g_object_set_data(G_OBJECT(mi
), menuitem_enum_key
,
408 GINT_TO_POINTER(arrow_types
[i
].enum_value
));
410 gtk_tooltips_set_tip(tool_tips
, mi
, gettext(arrow_types
[i
].name
), NULL
);
412 ar
= dia_arrow_preview_new(arrow_types
[i
].enum_value
, left
);
414 gtk_container_add(GTK_CONTAINER(mi
), ar
);
416 g_signal_connect(G_OBJECT(mi
), "activate",
417 G_CALLBACK(dia_arrow_chooser_change_arrow_type
), chooser
);
418 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), mi
);
421 mi
= gtk_menu_item_new_with_label(_("Details..."));
422 g_signal_connect(G_OBJECT(mi
), "activate",
423 G_CALLBACK(dia_arrow_chooser_dialog_show
), chooser
);
424 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), mi
);
427 return GTK_WIDGET(chooser
);
430 /** Set the type of arrow shown by the arrow chooser. If the arrow type
431 * changes, the callback function will be called.
432 * @param chooser The chooser to update.
433 * @param arrow The arrow type and dimensions the chooser will dispaly.
434 * Should it be called as well when the dimensions change?
437 dia_arrow_chooser_set_arrow(DiaArrowChooser
*chooser
, Arrow
*arrow
)
439 if (chooser
->arrow
.type
!= arrow
->type
) {
440 dia_arrow_preview_set(chooser
->preview
, arrow
->type
, chooser
->left
);
441 chooser
->arrow
.type
= arrow
->type
;
442 if (chooser
->dialog
!= NULL
)
443 dia_arrow_selector_set_arrow(chooser
->selector
, chooser
->arrow
);
444 if (chooser
->callback
)
445 (* chooser
->callback
)(chooser
->arrow
, chooser
->user_data
);
447 chooser
->arrow
.width
= arrow
->width
;
448 chooser
->arrow
.length
= arrow
->length
;
451 /** Get the currently selected arrow type from an arrow chooser.
452 * @param arrow An arrow chooser to query.
453 * @return The arrow type that is currently selected in the chooser.
456 dia_arrow_chooser_get_arrow_type(DiaArrowChooser
*arrow
)
458 return arrow
->arrow
.type
;