c306d16902805dd47cece36c066dc01bfd5a9b5d
1 #define __SP_MAINTOOLBOX_C__
3 /** \file
4 * Controls bars for some of Inkscape's tools
5 * (for some tools, they are in their own files)
6 */
8 /*
9 *
10 * Authors:
11 * MenTaLguY <mental@rydia.net>
12 * Lauris Kaplinski <lauris@kaplinski.com>
13 * bulia byak <buliabyak@users.sf.net>
14 * Frank Felfe <innerspace@iname.com>
15 * John Cliff <simarilius@yahoo.com>
16 * David Turner <novalis@gnu.org>
17 * Josh Andler <scislac@scislac.com>
18 *
19 * Copyright (C) 2004 David Turner
20 * Copyright (C) 2003 MenTaLguY
21 * Copyright (C) 1999-2005 authors
22 * Copyright (C) 2001-2002 Ximian, Inc.
23 *
24 * Released under GNU GPL, read the file 'COPYING' for more information
25 */
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
31 #include <gtkmm.h>
32 #include <gtk/gtk.h>
34 #include "widgets/button.h"
35 #include "widgets/widget-sizes.h"
36 #include "widgets/spw-utilities.h"
37 #include "widgets/spinbutton-events.h"
39 #include "ui/widget/style-swatch.h"
41 #include "prefs-utils.h"
42 #include "verbs.h"
43 #include "sp-namedview.h"
44 #include "desktop.h"
45 #include "desktop-handles.h"
46 #include "nodepath.h"
47 #include "xml/repr.h"
48 #include "xml/node-event-vector.h"
49 #include <glibmm/i18n.h>
50 #include "helper/unit-menu.h"
51 #include "helper/units.h"
53 #include "inkscape.h"
54 #include "conn-avoid-ref.h"
57 #include "select-toolbar.h"
58 #include "gradient-toolbar.h"
60 #include "connector-context.h"
61 #include "sp-rect.h"
62 #include "sp-star.h"
63 #include "sp-spiral.h"
64 #include "sp-ellipse.h"
65 #include "sp-text.h"
66 #include "sp-flowtext.h"
67 #include "style.h"
68 #include "selection.h"
69 #include "document-private.h"
70 #include "desktop-style.h"
71 #include "../libnrtype/font-lister.h"
73 #include "mod360.h"
75 #include "toolbox.h"
77 typedef void (*SetupFunction)(GtkWidget *toolbox, SPDesktop *desktop);
78 typedef void (*UpdateFunction)(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
80 static GtkWidget *sp_node_toolbox_new(SPDesktop *desktop);
81 static GtkWidget *sp_zoom_toolbox_new(SPDesktop *desktop);
82 static GtkWidget *sp_star_toolbox_new(SPDesktop *desktop);
83 static GtkWidget *sp_arc_toolbox_new(SPDesktop *desktop);
84 static GtkWidget *sp_rect_toolbox_new(SPDesktop *desktop);
85 static GtkWidget *sp_spiral_toolbox_new(SPDesktop *desktop);
86 static GtkWidget *sp_pencil_toolbox_new(SPDesktop *desktop);
87 static GtkWidget *sp_pen_toolbox_new(SPDesktop *desktop);
88 static GtkWidget *sp_calligraphy_toolbox_new(SPDesktop *desktop);
89 static GtkWidget *sp_dropper_toolbox_new(SPDesktop *desktop);
90 static GtkWidget *sp_empty_toolbox_new(SPDesktop *desktop);
91 static GtkWidget *sp_connector_toolbox_new(SPDesktop *desktop);
92 static GtkWidget *sp_text_toolbox_new (SPDesktop *desktop);
95 static struct {
96 gchar const *type_name;
97 gchar const *data_name;
98 sp_verb_t verb;
99 sp_verb_t doubleclick_verb;
100 } const tools[] = {
101 { "SPSelectContext", "select_tool", SP_VERB_CONTEXT_SELECT, SP_VERB_CONTEXT_SELECT_PREFS},
102 { "SPNodeContext", "node_tool", SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS },
103 { "SPZoomContext", "zoom_tool", SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS },
104 { "SPRectContext", "rect_tool", SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS },
105 { "SPArcContext", "arc_tool", SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS },
106 { "SPStarContext", "star_tool", SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS },
107 { "SPSpiralContext", "spiral_tool", SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS },
108 { "SPPencilContext", "pencil_tool", SP_VERB_CONTEXT_PENCIL, SP_VERB_CONTEXT_PENCIL_PREFS },
109 { "SPPenContext", "pen_tool", SP_VERB_CONTEXT_PEN, SP_VERB_CONTEXT_PEN_PREFS },
110 { "SPDynaDrawContext", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS },
111 { "SPTextContext", "text_tool", SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS },
112 { "SPConnectorContext","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS },
113 { "SPGradientContext", "gradient_tool", SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS },
114 { "SPDropperContext", "dropper_tool", SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_DROPPER_PREFS },
115 { NULL, NULL, 0, 0 }
116 };
118 static struct {
119 gchar const *type_name;
120 gchar const *data_name;
121 GtkWidget *(*create_func)(SPDesktop *desktop);
122 } const aux_toolboxes[] = {
123 { "SPSelectContext", "select_toolbox", sp_select_toolbox_new },
124 { "SPNodeContext", "node_toolbox", sp_node_toolbox_new },
125 { "SPZoomContext", "zoom_toolbox", sp_zoom_toolbox_new },
126 { "SPStarContext", "star_toolbox", sp_star_toolbox_new },
127 { "SPRectContext", "rect_toolbox", sp_rect_toolbox_new },
128 { "SPArcContext", "arc_toolbox", sp_arc_toolbox_new },
129 { "SPSpiralContext", "spiral_toolbox", sp_spiral_toolbox_new },
130 { "SPPencilContext", "pencil_toolbox", sp_pencil_toolbox_new },
131 { "SPPenContext", "pen_toolbox", sp_pen_toolbox_new },
132 { "SPDynaDrawContext", "calligraphy_toolbox", sp_calligraphy_toolbox_new },
133 { "SPTextContext", "text_toolbox", sp_text_toolbox_new },
134 { "SPDropperContext", "dropper_toolbox", sp_dropper_toolbox_new },
135 { "SPGradientContext", "gradient_toolbox", sp_gradient_toolbox_new },
136 { "SPConnectorContext", "connector_toolbox", sp_connector_toolbox_new },
137 { NULL, NULL, NULL }
138 };
140 static void toolbox_set_desktop (GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection*);
142 static void setup_tool_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
143 static void update_tool_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
145 static void setup_aux_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
146 static void update_aux_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
148 static void setup_commands_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
149 static void update_commands_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
151 /* Global text entry widgets necessary for update */
152 /* GtkWidget *dropper_rgb_entry,
153 *dropper_opacity_entry ; */
154 // should be made a private member once this is converted to class
156 static void delete_connection(GObject *obj, sigc::connection *connection) {
157 connection->disconnect();
158 delete connection;
159 }
161 static GtkWidget *
162 sp_toolbox_button_new(GtkWidget *t, Inkscape::IconSize size, gchar const *pxname, GtkSignalFunc handler,
163 GtkTooltips *tt, gchar const *tip)
164 {
165 GtkWidget *b = sp_button_new_from_data(size, SP_BUTTON_TYPE_NORMAL, NULL, pxname, tip, tt);
166 gtk_widget_show(b);
167 if (handler) gtk_signal_connect(GTK_OBJECT(b), "clicked", handler, NULL);
168 gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
170 return b;
171 }
173 GtkWidget *
174 sp_toolbox_button_new_from_verb_with_doubleclick(GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
175 Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
176 Inkscape::UI::View::View *view, GtkTooltips *tt)
177 {
178 SPAction *action = verb->get_action(view);
179 if (!action) return NULL;
181 SPAction *doubleclick_action;
182 if (doubleclick_verb)
183 doubleclick_action = doubleclick_verb->get_action(view);
184 else
185 doubleclick_action = NULL;
187 /* fixme: Handle sensitive/unsensitive */
188 /* fixme: Implement sp_button_new_from_action */
189 GtkWidget *b = sp_button_new(size, type, action, doubleclick_action, tt);
190 gtk_widget_show(b);
191 gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
193 return b;
194 }
196 GtkWidget *sp_toolbox_button_new_from_verb(GtkWidget *t, Inkscape::IconSize size, SPButtonType type, Inkscape::Verb *verb,
197 Inkscape::UI::View::View *view, GtkTooltips *tt)
198 {
199 return sp_toolbox_button_new_from_verb_with_doubleclick(t, size, type, verb, NULL, view, tt);
200 }
202 GtkWidget * sp_toolbox_button_normal_new_from_verb(GtkWidget *t, Inkscape::IconSize size, Inkscape::Verb *verb,
203 Inkscape::UI::View::View *view, GtkTooltips *tt)
204 {
205 return sp_toolbox_button_new_from_verb(t, size, SP_BUTTON_TYPE_NORMAL, verb, view, tt);
206 }
208 GtkWidget *
209 sp_tool_toolbox_new()
210 {
211 GtkTooltips *tt = gtk_tooltips_new();
212 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
214 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
215 g_object_set_data(G_OBJECT(tb), "tooltips", tt);
217 gtk_widget_set_sensitive(tb, FALSE);
219 GtkWidget *hb = gtk_handle_box_new();
220 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_TOP);
221 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
222 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
224 gtk_container_add(GTK_CONTAINER(hb), tb);
225 gtk_widget_show(GTK_WIDGET(tb));
227 sigc::connection* conn = new sigc::connection;
228 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
230 return hb;
231 }
233 static void
234 aux_toolbox_attached(GtkHandleBox *toolbox, GtkWidget *child)
235 {
236 g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(FALSE));
237 gtk_widget_queue_resize(child);
238 }
240 static void
241 aux_toolbox_detached(GtkHandleBox *toolbox, GtkWidget *child)
242 {
243 g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(TRUE));
244 gtk_widget_queue_resize(child);
245 }
247 GtkWidget *
248 sp_aux_toolbox_new()
249 {
250 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
252 GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
253 GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
254 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
255 gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
256 gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
258 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
259 g_object_set_data(G_OBJECT(tb), "top_spacer", tb_s);
261 gtk_widget_set_sensitive(tb, FALSE);
263 GtkWidget *hb = gtk_handle_box_new();
264 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
265 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
266 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
268 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
269 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
271 gtk_container_add(GTK_CONTAINER(hb), tb);
272 gtk_widget_show(GTK_WIDGET(tb));
274 sigc::connection* conn = new sigc::connection;
275 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
277 return hb;
278 }
280 //####################################
281 //# Commands Bar
282 //####################################
284 GtkWidget *
285 sp_commands_toolbox_new()
286 {
287 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
289 GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
290 GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
291 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
292 gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
293 gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
295 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
296 gtk_widget_set_sensitive(tb, FALSE);
298 GtkWidget *hb = gtk_handle_box_new();
299 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
300 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
301 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
303 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
304 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
306 gtk_container_add(GTK_CONTAINER(hb), tb);
307 gtk_widget_show(GTK_WIDGET(tb));
309 sigc::connection* conn = new sigc::connection;
310 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
312 return hb;
313 }
316 //####################################
317 //# node editing callbacks
318 //####################################
320 void
321 sp_node_path_edit_add(void)
322 {
323 sp_node_selected_add_node();
324 }
326 void
327 sp_node_path_edit_delete(void)
328 {
329 sp_node_selected_delete();
330 }
332 void
333 sp_node_path_edit_delete_segment(void)
334 {
335 sp_node_selected_delete_segment();
336 }
338 void
339 sp_node_path_edit_break(void)
340 {
341 sp_node_selected_break();
342 }
344 void
345 sp_node_path_edit_join(void)
346 {
347 sp_node_selected_join();
348 }
350 void
351 sp_node_path_edit_join_segment(void)
352 {
353 sp_node_selected_join_segment();
354 }
356 void
357 sp_node_path_edit_toline(void)
358 {
359 sp_node_selected_set_line_type(NR_LINETO);
360 }
362 void
363 sp_node_path_edit_tocurve(void)
364 {
365 sp_node_selected_set_line_type(NR_CURVETO);
366 }
368 void
369 sp_node_path_edit_cusp(void)
370 {
371 sp_node_selected_set_type(Inkscape::NodePath::NODE_CUSP);
372 }
374 void
375 sp_node_path_edit_smooth(void)
376 {
377 sp_node_selected_set_type(Inkscape::NodePath::NODE_SMOOTH);
378 }
380 void
381 sp_node_path_edit_symmetrical(void)
382 {
383 sp_node_selected_set_type(Inkscape::NodePath::NODE_SYMM);
384 }
386 static void toggle_show_handles (GtkWidget *button, gpointer data) {
387 bool show = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
388 prefs_set_int_attribute ("tools.nodes", "show_handles", show ? 1 : 0);
389 sp_nodepath_show_handles(show);
390 }
392 //################################
393 //## Node Editing Toolbox ##
394 //################################
396 static GtkWidget *
397 sp_node_toolbox_new(SPDesktop *desktop)
398 {
399 Inkscape::UI::View::View *view = desktop;
401 GtkTooltips *tt = gtk_tooltips_new();
402 GtkWidget *tb = gtk_hbox_new(FALSE, 0);
404 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
406 sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_insert",
407 GTK_SIGNAL_FUNC(sp_node_path_edit_add), tt, _("Insert new nodes into selected segments"));
408 sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_delete",
409 GTK_SIGNAL_FUNC(sp_node_path_edit_delete), tt, _("Delete selected nodes"));
411 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
413 sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_join",
414 GTK_SIGNAL_FUNC(sp_node_path_edit_join), tt, _("Join selected endnodes"));
415 sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_join_segment",
416 GTK_SIGNAL_FUNC(sp_node_path_edit_join_segment), tt, _("Join selected endnodes with a new segment"));
418 sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_delete_segment",
419 GTK_SIGNAL_FUNC(sp_node_path_edit_delete_segment), tt, _("Split path between two non-endpoint nodes"));
421 sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_break",
422 GTK_SIGNAL_FUNC(sp_node_path_edit_break), tt, _("Break path at selected nodes"));
424 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
426 sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_cusp",
427 GTK_SIGNAL_FUNC(sp_node_path_edit_cusp), tt, _("Make selected nodes corner"));
429 sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_smooth",
430 GTK_SIGNAL_FUNC(sp_node_path_edit_smooth), tt, _("Make selected nodes smooth"));
432 sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_symmetric",
433 GTK_SIGNAL_FUNC(sp_node_path_edit_symmetrical), tt, _("Make selected nodes symmetric"));
435 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
437 sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_line",
438 GTK_SIGNAL_FUNC(sp_node_path_edit_toline), tt, _("Make selected segments lines"));
440 sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_curve",
441 GTK_SIGNAL_FUNC(sp_node_path_edit_tocurve), tt, _("Make selected segments curves"));
443 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
445 sp_toolbox_button_normal_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, Inkscape::Verb::get(SP_VERB_OBJECT_TO_CURVE), view, tt);
447 sp_toolbox_button_normal_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, Inkscape::Verb::get(SP_VERB_SELECTION_OUTLINE), view, tt);
449 aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
451 GtkWidget *cvbox = gtk_vbox_new (FALSE, 0);
452 GtkWidget *cbox = gtk_hbox_new (FALSE, 0);
454 {
455 GtkWidget *button = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
456 SP_BUTTON_TYPE_TOGGLE,
457 NULL,
458 "nodes_show_handles",
459 _("Show the Bezier handles of selected nodes"),
460 tt);
461 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), prefs_get_int_attribute ("tools.nodes", "show_handles", 1));
462 g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (toggle_show_handles), desktop);
463 gtk_box_pack_start(GTK_BOX(cbox), button, FALSE, FALSE, 0);
464 }
466 gtk_box_pack_start(GTK_BOX(cvbox), cbox, TRUE, FALSE, 0);
467 gtk_box_pack_start(GTK_BOX(tb), cvbox, FALSE, FALSE, 0);
469 gtk_widget_show_all(tb);
471 return tb;
473 } // end of sp_node_toolbox_new()
476 //########################
477 //## Zoom Toolbox ##
478 //########################
480 static GtkWidget *
481 sp_zoom_toolbox_new(SPDesktop *desktop)
482 {
483 Inkscape::UI::View::View *view=desktop;
485 GtkTooltips *tt = gtk_tooltips_new();
486 GtkWidget *tb = gtk_hbox_new(FALSE, 0);
488 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0),
489 FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
491 sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_IN), view, tt);
493 sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_OUT), view, tt);
495 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
497 sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_SELECTION), view, tt);
499 sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_DRAWING), view, tt);
501 sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_PAGE), view, tt);
503 sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_PAGE_WIDTH), view, tt);
505 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
507 sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_PREV), view, tt);
509 sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_NEXT), view, tt);
511 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
513 sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_1_1), view, tt);
515 sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_1_2), view, tt);
517 sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_2_1), view, tt);
519 gtk_widget_show_all(tb);
521 return tb;
523 } // end of sp_zoom_toolbox_new()
525 void
526 sp_tool_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
527 {
528 toolbox_set_desktop(gtk_bin_get_child(GTK_BIN(toolbox)), desktop, setup_tool_toolbox, update_tool_toolbox, static_cast<sigc::connection*>(g_object_get_data(G_OBJECT(toolbox), "event_context_connection")));
529 }
532 void
533 sp_aux_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
534 {
535 toolbox_set_desktop(gtk_bin_get_child(GTK_BIN(toolbox)), desktop, setup_aux_toolbox, update_aux_toolbox, static_cast<sigc::connection*>(g_object_get_data(G_OBJECT(toolbox), "event_context_connection")));
536 }
538 void
539 sp_commands_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
540 {
541 toolbox_set_desktop(gtk_bin_get_child(GTK_BIN(toolbox)), desktop, setup_commands_toolbox, update_commands_toolbox, static_cast<sigc::connection*>(g_object_get_data(G_OBJECT(toolbox), "event_context_connection")));
542 }
544 static void
545 toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection *conn)
546 {
547 gpointer ptr = g_object_get_data(G_OBJECT(toolbox), "desktop");
548 SPDesktop *old_desktop = static_cast<SPDesktop*>(ptr);
550 if (old_desktop) {
551 GList *children, *iter;
553 children = gtk_container_get_children(GTK_CONTAINER(toolbox));
554 for ( iter = children ; iter ; iter = iter->next ) {
555 gtk_container_remove( GTK_CONTAINER(toolbox), GTK_WIDGET(iter->data) );
556 }
557 g_list_free(children);
558 }
560 g_object_set_data(G_OBJECT(toolbox), "desktop", (gpointer)desktop);
562 if (desktop) {
563 gtk_widget_set_sensitive(toolbox, TRUE);
564 setup_func(toolbox, desktop);
565 update_func(desktop, desktop->event_context, toolbox);
566 *conn = desktop->connectEventContextChanged
567 (sigc::bind (sigc::ptr_fun(update_func), toolbox));
568 } else {
569 gtk_widget_set_sensitive(toolbox, FALSE);
570 }
572 } // end of toolbox_set_desktop()
575 static void
576 setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
577 {
578 GtkTooltips *tooltips=GTK_TOOLTIPS(g_object_get_data(G_OBJECT(toolbox), "tooltips"));
579 gint shrinkLeft = prefs_get_int_attribute_limited( "toolbox.left", "small", 0, 0, 1 );
580 Inkscape::IconSize toolboxSize = shrinkLeft ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
582 for (int i = 0 ; tools[i].type_name ; i++ ) {
583 GtkWidget *button =
584 sp_toolbox_button_new_from_verb_with_doubleclick( toolbox, toolboxSize,
585 SP_BUTTON_TYPE_TOGGLE,
586 Inkscape::Verb::get(tools[i].verb),
587 Inkscape::Verb::get(tools[i].doubleclick_verb),
588 desktop,
589 tooltips );
591 g_object_set_data( G_OBJECT(toolbox), tools[i].data_name,
592 (gpointer)button );
593 }
594 }
597 static void
598 update_tool_toolbox( SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox )
599 {
600 gchar const *const tname = ( eventcontext
601 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
602 : NULL );
603 for (int i = 0 ; tools[i].type_name ; i++ ) {
604 SPButton *button = SP_BUTTON(g_object_get_data(G_OBJECT(toolbox), tools[i].data_name));
605 sp_button_toggle_set_down(button, tname && !strcmp(tname, tools[i].type_name));
606 }
607 }
609 static void
610 setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
611 {
612 GtkSizeGroup* grouper = gtk_size_group_new( GTK_SIZE_GROUP_BOTH );
614 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
615 GtkWidget *sub_toolbox;
616 if (aux_toolboxes[i].create_func == NULL)
617 sub_toolbox = sp_empty_toolbox_new(desktop);
618 else
619 sub_toolbox = aux_toolboxes[i].create_func(desktop);
621 gtk_size_group_add_widget( grouper, sub_toolbox );
623 gtk_container_add(GTK_CONTAINER(toolbox), sub_toolbox);
624 g_object_set_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name, sub_toolbox);
625 }
626 g_object_unref( G_OBJECT(grouper) );
627 }
629 static void
630 update_aux_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
631 {
632 gchar const *tname = ( eventcontext
633 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
634 : NULL );
635 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
636 GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name));
637 if (tname && !strcmp(tname, aux_toolboxes[i].type_name)) {
638 gtk_widget_show_all(sub_toolbox);
639 g_object_set_data(G_OBJECT(toolbox), "shows", sub_toolbox);
640 } else {
641 gtk_widget_hide(sub_toolbox);
642 }
643 }
644 }
646 static void
647 setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
648 {
649 Inkscape::UI::View::View *view = desktop;
651 GtkTooltips *tt = gtk_tooltips_new();
652 GtkWidget *tb = gtk_hbox_new(FALSE, 0);
654 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
655 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
657 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_NEW), view, tt);
658 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_OPEN), view, tt);
659 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_SAVE), view, tt);
660 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_PRINT), view, tt);
662 aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
664 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_IMPORT), view, tt);
665 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_EXPORT), view, tt);
667 aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
669 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_UNDO), view, tt);
670 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_REDO), view, tt);
672 aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
674 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_COPY), view, tt);
675 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_CUT), view, tt);
676 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_PASTE), view, tt);
678 aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
680 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_SELECTION), view, tt);
681 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_DRAWING), view, tt);
682 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_PAGE), view, tt);
684 aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
686 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_DUPLICATE), view, tt);
687 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_CLONE), view, tt);
688 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_UNLINK_CLONE), view, tt);
690 aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
692 sp_toolbox_button_normal_new_from_verb(tb, toolboxSize, Inkscape::Verb::get(SP_VERB_SELECTION_GROUP), view, tt);
693 sp_toolbox_button_normal_new_from_verb(tb, toolboxSize, Inkscape::Verb::get(SP_VERB_SELECTION_UNGROUP), view, tt);
695 // disabled until we have icons for them:
697 //find
699 //sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_TILE), view, tt);
700 //sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_UNTILE), view, tt);
702 aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
704 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_FILL_STROKE), view, tt);
705 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_TEXT), view, tt);
706 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_XML_EDITOR), view, tt);
707 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_ALIGN_DISTRIBUTE), view, tt);
709 aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
711 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_DISPLAY), view, tt);
712 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_NAMEDVIEW), view, tt);
714 gtk_widget_show_all(tb);
716 gtk_container_add(GTK_CONTAINER(toolbox), tb);
717 }
719 static void
720 update_commands_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
721 {
722 }
724 void show_aux_toolbox(GtkWidget *toolbox_toplevel)
725 {
726 gtk_widget_show(toolbox_toplevel);
727 GtkWidget *toolbox = gtk_bin_get_child(GTK_BIN(toolbox_toplevel));
729 GtkWidget *shown_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "shows"));
730 if (!shown_toolbox) {
731 return;
732 }
733 gtk_widget_show(toolbox);
735 // need to show the spacer, or the padding will be off
736 GtkWidget *spacer = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "top_spacer"));
737 gtk_widget_show(spacer);
739 gtk_widget_show_all(shown_toolbox);
740 }
742 void
743 aux_toolbox_space(GtkWidget *tb, gint space)
744 {
745 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, space);
746 }
748 static GtkWidget *
749 sp_empty_toolbox_new(SPDesktop *desktop)
750 {
751 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
752 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
753 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
755 gtk_widget_show_all(tbl);
756 sp_set_font_size_smaller (tbl);
758 return tbl;
759 }
761 // helper UI functions
763 GtkWidget *
764 sp_tb_spinbutton(
765 gchar *label, gchar const *tooltip,
766 gchar const *path, gchar const *data, gdouble def,
767 GtkWidget *us,
768 GtkWidget *tbl,
769 gboolean altx, gchar const *altx_mark,
770 gdouble lower, gdouble upper, gdouble step, gdouble page,
771 void (*callback)(GtkAdjustment *, GtkWidget *),
772 gdouble climb = 0.1, guint digits = 3, double factor = 1.0)
773 {
774 GtkTooltips *tt = gtk_tooltips_new();
776 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
778 GtkWidget *l = gtk_label_new(label);
779 gtk_widget_show(l);
780 gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
781 gtk_container_add(GTK_CONTAINER(hb), l);
783 GtkObject *a = gtk_adjustment_new(prefs_get_double_attribute(path, data, def) * factor,
784 lower, upper, step, page, page);
785 gtk_object_set_data(GTK_OBJECT(tbl), data, a);
786 if (us)
787 sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(us), GTK_ADJUSTMENT(a));
789 GtkWidget *sb = gtk_spin_button_new(GTK_ADJUSTMENT(a), climb, digits);
790 gtk_tooltips_set_tip(tt, sb, tooltip, NULL);
791 if (altx)
792 gtk_object_set_data(GTK_OBJECT(sb), altx_mark, sb);
793 gtk_widget_set_size_request(sb,
794 (upper <= 1.0 || digits == 0)? AUX_SPINBUTTON_WIDTH_SMALL - 10: AUX_SPINBUTTON_WIDTH_SMALL,
795 AUX_SPINBUTTON_HEIGHT);
796 gtk_widget_show(sb);
797 gtk_signal_connect(GTK_OBJECT(sb), "focus-in-event", GTK_SIGNAL_FUNC(spinbutton_focus_in), tbl);
798 gtk_signal_connect(GTK_OBJECT(sb), "key-press-event", GTK_SIGNAL_FUNC(spinbutton_keypress), tbl);
799 gtk_container_add(GTK_CONTAINER(hb), sb);
800 gtk_signal_connect(GTK_OBJECT(a), "value_changed", GTK_SIGNAL_FUNC(callback), tbl);
802 return hb;
803 }
805 #define MODE_LABEL_WIDTH 70
807 //########################
808 //## Star ##
809 //########################
811 static void
812 sp_stb_magnitude_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
813 {
814 SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
816 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
817 // do not remember prefs if this call is initiated by an undo change, because undoing object
818 // creation sets bogus values to its attributes before it is deleted
819 prefs_set_int_attribute("tools.shapes.star", "magnitude", (gint)adj->value);
820 }
822 // quit if run by the attr_changed listener
823 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
824 return;
825 }
827 // in turn, prevent listener from responding
828 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
830 bool modmade = false;
832 Inkscape::Selection *selection = sp_desktop_selection(desktop);
833 GSList const *items = selection->itemList();
834 for (; items != NULL; items = items->next) {
835 if (SP_IS_STAR((SPItem *) items->data)) {
836 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
837 sp_repr_set_int(repr,"sodipodi:sides",(gint)adj->value);
838 sp_repr_set_svg_double(repr, "sodipodi:arg2",
839 (sp_repr_get_double_attribute(repr, "sodipodi:arg1", 0.5)
840 + M_PI / (gint)adj->value));
841 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
842 modmade = true;
843 }
844 }
845 if (modmade) sp_document_done(sp_desktop_document(desktop));
847 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
849 spinbutton_defocus(GTK_OBJECT(tbl));
850 }
852 static void
853 sp_stb_proportion_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
854 {
855 SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
857 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
858 prefs_set_double_attribute("tools.shapes.star", "proportion", adj->value);
859 }
861 // quit if run by the attr_changed listener
862 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
863 return;
864 }
866 // in turn, prevent listener from responding
867 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
869 bool modmade = false;
870 Inkscape::Selection *selection = sp_desktop_selection(desktop);
871 GSList const *items = selection->itemList();
872 for (; items != NULL; items = items->next) {
873 if (SP_IS_STAR((SPItem *) items->data)) {
874 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
876 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
877 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
878 if (r2 < r1) {
879 sp_repr_set_svg_double(repr, "sodipodi:r2", r1*adj->value);
880 } else {
881 sp_repr_set_svg_double(repr, "sodipodi:r1", r2*adj->value);
882 }
884 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
885 modmade = true;
886 }
887 }
889 if (modmade) sp_document_done(sp_desktop_document(desktop));
891 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
893 spinbutton_defocus(GTK_OBJECT(tbl));
894 }
896 static void
897 sp_stb_sides_flat_state_changed(GtkWidget *widget, GtkObject *tbl)
898 {
899 SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
901 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
902 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
903 prefs_set_string_attribute("tools.shapes.star", "isflatsided", "true");
904 } else {
905 prefs_set_string_attribute("tools.shapes.star", "isflatsided", "false");
906 }
907 }
909 // quit if run by the attr_changed listener
910 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
911 return;
912 }
914 // in turn, prevent listener from responding
915 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
917 Inkscape::Selection *selection = sp_desktop_selection(desktop);
918 GSList const *items = selection->itemList();
919 GtkWidget *prop_widget = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "prop_widget");
920 bool modmade = false;
921 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
922 gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), FALSE);
923 for (; items != NULL; items = items->next) {
924 if (SP_IS_STAR((SPItem *) items->data)) {
925 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
926 repr->setAttribute("inkscape:flatsided", "true");
927 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
928 modmade = true;
929 }
930 }
931 } else {
932 gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), TRUE);
933 for (; items != NULL; items = items->next) {
934 if (SP_IS_STAR((SPItem *) items->data)) {
935 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
936 repr->setAttribute("inkscape:flatsided", "false");
937 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
938 modmade = true;
939 }
940 }
941 }
942 if (modmade) sp_document_done(sp_desktop_document(desktop));
944 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
946 spinbutton_defocus(GTK_OBJECT(tbl));
947 }
949 static void
950 sp_stb_rounded_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
951 {
952 SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
954 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
955 prefs_set_double_attribute("tools.shapes.star", "rounded", (gdouble) adj->value);
956 }
958 // quit if run by the attr_changed listener
959 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
960 return;
961 }
963 // in turn, prevent listener from responding
964 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
966 bool modmade = false;
968 Inkscape::Selection *selection = sp_desktop_selection(desktop);
969 GSList const *items = selection->itemList();
970 for (; items != NULL; items = items->next) {
971 if (SP_IS_STAR((SPItem *) items->data)) {
972 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
973 sp_repr_set_svg_double(repr, "inkscape:rounded", (gdouble) adj->value);
974 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
975 modmade = true;
976 }
977 }
978 if (modmade) sp_document_done(sp_desktop_document(desktop));
980 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
982 spinbutton_defocus(GTK_OBJECT(tbl));
983 }
986 static void
987 sp_stb_randomized_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
988 {
989 SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
991 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
992 prefs_set_double_attribute("tools.shapes.star", "randomized", (gdouble) adj->value);
993 }
995 // quit if run by the attr_changed listener
996 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
997 return;
998 }
1000 // in turn, prevent listener from responding
1001 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1003 bool modmade = false;
1005 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1006 GSList const *items = selection->itemList();
1007 for (; items != NULL; items = items->next) {
1008 if (SP_IS_STAR((SPItem *) items->data)) {
1009 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1010 sp_repr_set_svg_double(repr, "inkscape:randomized", (gdouble) adj->value);
1011 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1012 modmade = true;
1013 }
1014 }
1015 if (modmade) sp_document_done(sp_desktop_document(desktop));
1017 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1019 spinbutton_defocus(GTK_OBJECT(tbl));
1020 }
1023 static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1024 gchar const *old_value, gchar const *new_value,
1025 bool is_interactive, gpointer data)
1026 {
1027 GtkWidget *tbl = GTK_WIDGET(data);
1029 // quit if run by the _changed callbacks
1030 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1031 return;
1032 }
1034 // in turn, prevent callbacks from responding
1035 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1037 GtkAdjustment *adj;
1039 if (!strcmp(name, "inkscape:randomized")) {
1040 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "randomized");
1041 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:randomized", 0.0));
1042 } else if (!strcmp(name, "inkscape:rounded")) {
1043 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "rounded");
1044 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:rounded", 0.0));
1045 } else if (!strcmp(name, "inkscape:flatsided")) {
1046 GtkWidget *fscb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "flat_checkbox");
1047 GtkWidget *prop_widget = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "prop_widget");
1048 char const *flatsides = repr->attribute("inkscape:flatsided");
1049 if (flatsides && !strcmp(flatsides,"false" )) {
1050 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb), FALSE);
1051 gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), TRUE);
1052 } else {
1053 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb), TRUE);
1054 gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), FALSE);
1055 }
1056 } else if (!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) {
1057 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1058 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1059 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1060 if (r2 < r1) {
1061 gtk_adjustment_set_value(adj, r2/r1);
1062 } else {
1063 gtk_adjustment_set_value(adj, r1/r2);
1064 }
1065 } else if (!strcmp(name, "sodipodi:sides")) {
1066 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1067 gtk_adjustment_set_value(adj, sp_repr_get_int_attribute(repr, "sodipodi:sides", 0));
1068 }
1070 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1071 }
1074 static Inkscape::XML::NodeEventVector star_tb_repr_events =
1075 {
1076 NULL, /* child_added */
1077 NULL, /* child_removed */
1078 star_tb_event_attr_changed,
1079 NULL, /* content_changed */
1080 NULL /* order_changed */
1081 };
1084 /**
1085 * \param selection Should not be NULL.
1086 */
1087 static void
1088 sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1089 {
1090 int n_selected = 0;
1091 Inkscape::XML::Node *repr = NULL;
1092 Inkscape::XML::Node *oldrepr = NULL;
1094 for (GSList const *items = selection->itemList();
1095 items != NULL;
1096 items = items->next)
1097 {
1098 if (SP_IS_STAR((SPItem *) items->data)) {
1099 n_selected++;
1100 repr = SP_OBJECT_REPR((SPItem *) items->data);
1101 }
1102 }
1104 GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
1106 if (n_selected == 0) {
1107 gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
1108 } else if (n_selected == 1) {
1109 gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1111 oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1112 if (oldrepr) { // remove old listener
1113 sp_repr_remove_listener_by_data(oldrepr, tbl);
1114 Inkscape::GC::release(oldrepr);
1115 oldrepr = 0;
1116 g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1117 }
1119 if (repr) {
1120 g_object_set_data(G_OBJECT(tbl), "repr", repr);
1121 Inkscape::GC::anchor(repr);
1122 sp_repr_add_listener(repr, &star_tb_repr_events, tbl);
1123 sp_repr_synthesize_events(repr, &star_tb_repr_events, tbl);
1124 }
1125 } else {
1126 // FIXME: implement averaging of all parameters for multiple selected stars
1127 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1128 gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1129 }
1130 }
1133 static void
1134 sp_stb_defaults(GtkWidget *widget, GtkWidget *tbl)
1135 {
1136 // FIXME: in this and all other _default functions, set some flag telling the value_changed
1137 // callbacks to lump all the changes for all selected objects in one undo step
1139 GtkAdjustment *adj;
1141 // fixme: make settable in prefs!
1142 gint mag = 5;
1143 gdouble prop = 0.5;
1144 gboolean flat = FALSE;
1145 gdouble randomized = 0;
1146 gdouble rounded = 0;
1148 GtkWidget *fscb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "flat_checkbox");
1149 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb), flat);
1150 GtkWidget *sb2 = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "prop_widget");
1151 gtk_widget_set_sensitive(GTK_WIDGET(sb2), !flat);
1153 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1154 gtk_adjustment_set_value(adj, mag);
1155 gtk_adjustment_value_changed(adj);
1157 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1158 gtk_adjustment_set_value(adj, prop);
1159 gtk_adjustment_value_changed(adj);
1161 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "rounded");
1162 gtk_adjustment_set_value(adj, rounded);
1163 gtk_adjustment_value_changed(adj);
1165 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "randomized");
1166 gtk_adjustment_set_value(adj, randomized);
1167 gtk_adjustment_value_changed(adj);
1169 spinbutton_defocus(GTK_OBJECT(tbl));
1170 }
1173 void
1174 sp_toolbox_add_label(GtkWidget *tbl, gchar const *title, bool wide)
1175 {
1176 GtkWidget *boxl = gtk_hbox_new(FALSE, 0);
1177 if (wide) gtk_widget_set_size_request(boxl, MODE_LABEL_WIDTH, -1);
1178 GtkWidget *l = gtk_label_new(NULL);
1179 gtk_label_set_markup(GTK_LABEL(l), title);
1180 gtk_box_pack_end(GTK_BOX(boxl), l, FALSE, FALSE, 0);
1181 gtk_box_pack_start(GTK_BOX(tbl), boxl, FALSE, FALSE, 0);
1182 gtk_object_set_data(GTK_OBJECT(tbl), "mode_label", l);
1183 }
1186 static GtkWidget *
1187 sp_star_toolbox_new(SPDesktop *desktop)
1188 {
1189 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1191 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1192 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1194 GtkTooltips *tt = gtk_tooltips_new();
1196 sp_toolbox_add_label(tbl, _("<b>New:</b>"));
1198 gchar const *flatsidedstr = NULL;
1200 /* Flatsided checkbox */
1201 {
1202 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1203 GtkWidget *fscb = gtk_check_button_new_with_label(_("Polygon"));
1204 gtk_widget_set_sensitive(GTK_WIDGET(fscb), TRUE);
1205 flatsidedstr = prefs_get_string_attribute("tools.shapes.star", "isflatsided");
1206 if (!flatsidedstr || (flatsidedstr && !strcmp(flatsidedstr, "false")))
1207 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb), FALSE);
1208 else
1209 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb), TRUE);
1210 gtk_tooltips_set_tip(tt, fscb, _("Regular polygon (with one handle) instead of a star"), NULL);
1211 gtk_widget_show(fscb);
1212 gtk_object_set_data(GTK_OBJECT(tbl), "flat_checkbox", fscb);
1213 gtk_container_add(GTK_CONTAINER(hb), fscb);
1214 g_signal_connect(G_OBJECT(fscb), "toggled", GTK_SIGNAL_FUNC(sp_stb_sides_flat_state_changed ), tbl);
1215 gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_SPACING);
1216 }
1218 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
1220 /* Magnitude */
1221 {
1222 GtkWidget *hb = sp_tb_spinbutton(_("Corners:"), _("Number of corners of a polygon or star"),
1223 "tools.shapes.star", "magnitude", 3,
1224 NULL, tbl, TRUE, "altx-star",
1225 3, 1024, 1, 1,
1226 sp_stb_magnitude_value_changed, 1, 0);
1227 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1228 }
1230 /* Spoke ratio */
1231 {
1232 GtkWidget *hb = sp_tb_spinbutton(_("Spoke ratio:"),
1233 // TRANSLATORS: Tip radius of a star is the distance from the center to the farthest handle.
1234 // Base radius is the same for the closest handle.
1235 _("Base radius to tip radius ratio"),
1236 "tools.shapes.star", "proportion", 0.5,
1237 NULL, tbl, FALSE, NULL,
1238 0.01, 1.0, 0.01, 0.1,
1239 sp_stb_proportion_value_changed);
1240 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1241 g_object_set_data(G_OBJECT(tbl), "prop_widget", hb);
1242 if (!flatsidedstr || (flatsidedstr && !strcmp(flatsidedstr, "false")))
1243 gtk_widget_set_sensitive(GTK_WIDGET(hb), TRUE);
1244 else
1245 gtk_widget_set_sensitive(GTK_WIDGET(hb), FALSE);
1246 }
1248 /* Roundedness */
1249 {
1250 GtkWidget *hb = sp_tb_spinbutton(_("Rounded:"), _("How much rounded are the corners (0 for sharp)"),
1251 "tools.shapes.star", "rounded", 0.0,
1252 NULL, tbl, FALSE, NULL,
1253 -100.0, 100.0, 0.01, 0.1,
1254 sp_stb_rounded_value_changed);
1255 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1256 }
1258 /* Randomization */
1259 {
1260 GtkWidget *hb = sp_tb_spinbutton(_("Randomized:"), _("Scatter randomly the corners and angles"),
1261 "tools.shapes.star", "randomized", 0.0,
1262 NULL, tbl, FALSE, NULL,
1263 -10.0, 10.0, 0.001, 0.01,
1264 sp_stb_randomized_value_changed, 0.1, 3);
1265 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1266 }
1268 aux_toolbox_space(tbl, AUX_SPACING);
1270 /* Reset */
1271 {
1272 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1273 GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
1274 gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
1275 gtk_widget_show(b);
1276 gtk_container_add(GTK_CONTAINER(hb), b);
1277 gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_stb_defaults), tbl);
1278 gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_SPACING);
1279 }
1281 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1282 swatch->setWatchedTool ("tools.shapes.star", true);
1283 GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1284 gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1286 gtk_widget_show_all(tbl);
1287 sp_set_font_size_smaller (tbl);
1289 sigc::connection *connection = new sigc::connection(
1290 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_star_toolbox_selection_changed), (GtkObject *)tbl))
1291 );
1292 g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
1294 return tbl;
1295 }
1298 //########################
1299 //## Rect ##
1300 //########################
1302 static void
1303 sp_rtb_sensitivize (GtkWidget *tbl)
1304 {
1305 GtkAdjustment *adj1 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "rx"));
1306 GtkAdjustment *adj2 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "ry"));
1307 GtkWidget *not_rounded = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "not_rounded");
1309 if (adj1->value == 0 && adj2->value == 0 && gtk_object_get_data(GTK_OBJECT(tbl), "single")) { // only for a single selected rect (for now)
1310 gtk_widget_set_sensitive(GTK_WIDGET(not_rounded), FALSE);
1311 } else {
1312 gtk_widget_set_sensitive(GTK_WIDGET(not_rounded), TRUE);
1313 }
1314 }
1317 static void
1318 sp_rtb_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name,
1319 void (*setter)(SPRect *, gdouble))
1320 {
1321 SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
1323 GtkWidget *us = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(tbl), "units");
1324 SPUnit const *unit = sp_unit_selector_get_unit(SP_UNIT_SELECTOR(us));
1326 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1327 prefs_set_double_attribute("tools.shapes.rect", value_name, sp_units_get_pixels(adj->value, *unit));
1328 }
1330 // quit if run by the attr_changed listener
1331 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1332 return;
1333 }
1335 // in turn, prevent listener from responding
1336 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1338 bool modmade = false;
1339 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1340 for (GSList const *items = selection->itemList(); items != NULL; items = items->next) {
1341 if (SP_IS_RECT(items->data)) {
1342 if (adj->value != 0) {
1343 setter(SP_RECT(items->data), sp_units_get_pixels(adj->value, *unit));
1344 } else {
1345 SP_OBJECT_REPR(items->data)->setAttribute(value_name, NULL);
1346 }
1347 modmade = true;
1348 }
1349 }
1351 sp_rtb_sensitivize (tbl);
1353 if (modmade) {
1354 sp_document_done(sp_desktop_document(desktop));
1355 }
1357 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1359 // defocus spinbuttons by moving focus to the canvas, unless "stay" is on
1360 spinbutton_defocus(GTK_OBJECT(tbl));
1361 }
1363 static void
1364 sp_rtb_rx_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1365 {
1366 sp_rtb_value_changed(adj, tbl, "rx", sp_rect_set_visible_rx);
1367 }
1369 static void
1370 sp_rtb_ry_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1371 {
1372 sp_rtb_value_changed(adj, tbl, "ry", sp_rect_set_visible_ry);
1373 }
1375 static void
1376 sp_rtb_width_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1377 {
1378 sp_rtb_value_changed(adj, tbl, "width", sp_rect_set_visible_width);
1379 }
1381 static void
1382 sp_rtb_height_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1383 {
1384 sp_rtb_value_changed(adj, tbl, "height", sp_rect_set_visible_height);
1385 }
1389 static void
1390 sp_rtb_defaults( GtkWidget *widget, GtkObject *obj)
1391 {
1392 GtkWidget *tbl = GTK_WIDGET(obj);
1394 GtkAdjustment *adj;
1396 adj = (GtkAdjustment*)gtk_object_get_data(obj, "rx");
1397 gtk_adjustment_set_value(adj, 0.0);
1398 // this is necessary if the previous value was 0, but we still need to run the callback to change all selected objects
1399 gtk_adjustment_value_changed(adj);
1401 adj = (GtkAdjustment*)gtk_object_get_data(obj, "ry");
1402 gtk_adjustment_set_value(adj, 0.0);
1403 gtk_adjustment_value_changed(adj);
1405 sp_rtb_sensitivize (tbl);
1407 spinbutton_defocus(GTK_OBJECT(tbl));
1408 }
1410 static void rect_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1411 gchar const *old_value, gchar const *new_value,
1412 bool is_interactive, gpointer data)
1413 {
1414 GtkWidget *tbl = GTK_WIDGET(data);
1416 // quit if run by the _changed callbacks
1417 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1418 return;
1419 }
1421 // in turn, prevent callbacks from responding
1422 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1424 GtkWidget *us = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(tbl), "units");
1425 SPUnit const *unit = sp_unit_selector_get_unit(SP_UNIT_SELECTOR(us));
1427 SPItem *item = SP_ITEM(g_object_get_data(G_OBJECT(tbl), "item"));
1428 if (SP_IS_RECT(item)) {
1429 {
1430 GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "rx");
1431 gdouble rx = sp_rect_get_visible_rx(SP_RECT(item));
1432 gtk_adjustment_set_value(adj, sp_pixels_get_units(rx, *unit));
1433 }
1435 {
1436 GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "ry");
1437 gdouble ry = sp_rect_get_visible_ry(SP_RECT(item));
1438 gtk_adjustment_set_value(adj, sp_pixels_get_units(ry, *unit));
1439 }
1441 {
1442 GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "width");
1443 gdouble width = sp_rect_get_visible_width (SP_RECT(item));
1444 gtk_adjustment_set_value(adj, sp_pixels_get_units(width, *unit));
1445 }
1447 {
1448 GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "height");
1449 gdouble height = sp_rect_get_visible_height (SP_RECT(item));
1450 gtk_adjustment_set_value(adj, sp_pixels_get_units(height, *unit));
1451 }
1452 }
1454 sp_rtb_sensitivize (tbl);
1456 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1457 }
1460 static Inkscape::XML::NodeEventVector rect_tb_repr_events = {
1461 NULL, /* child_added */
1462 NULL, /* child_removed */
1463 rect_tb_event_attr_changed,
1464 NULL, /* content_changed */
1465 NULL /* order_changed */
1466 };
1468 /**
1469 * \param selection should not be NULL.
1470 */
1471 static void
1472 sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1473 {
1474 int n_selected = 0;
1475 Inkscape::XML::Node *repr = NULL;
1476 SPItem *item = NULL;
1477 Inkscape::XML::Node *oldrepr = NULL;
1479 for (GSList const *items = selection->itemList();
1480 items != NULL;
1481 items = items->next) {
1482 if (SP_IS_RECT((SPItem *) items->data)) {
1483 n_selected++;
1484 item = (SPItem *) items->data;
1485 repr = SP_OBJECT_REPR(item);
1486 }
1487 }
1489 GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
1491 g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(FALSE));
1493 if (n_selected == 0) {
1494 gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
1496 GtkWidget *w = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "width_sb");
1497 gtk_widget_set_sensitive(w, FALSE);
1498 GtkWidget *h = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "height_sb");
1499 gtk_widget_set_sensitive(h, FALSE);
1501 } else if (n_selected == 1) {
1502 gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1503 g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
1505 GtkWidget *w = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "width_sb");
1506 gtk_widget_set_sensitive(w, TRUE);
1507 GtkWidget *h = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "height_sb");
1508 gtk_widget_set_sensitive(h, TRUE);
1510 oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1511 if (oldrepr) { // remove old listener
1512 sp_repr_remove_listener_by_data(oldrepr, tbl);
1513 Inkscape::GC::release(oldrepr);
1514 oldrepr = 0;
1515 g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1516 }
1517 if (repr) {
1518 g_object_set_data(G_OBJECT(tbl), "repr", repr);
1519 g_object_set_data(G_OBJECT(tbl), "item", item);
1520 Inkscape::GC::anchor(repr);
1521 sp_repr_add_listener(repr, &rect_tb_repr_events, tbl);
1522 sp_repr_synthesize_events(repr, &rect_tb_repr_events, tbl);
1523 }
1524 } else {
1525 // FIXME: implement averaging of all parameters for multiple selected
1526 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1527 gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1528 sp_rtb_sensitivize (GTK_WIDGET(tbl));
1529 }
1530 }
1533 static GtkWidget *
1534 sp_rect_toolbox_new(SPDesktop *desktop)
1535 {
1536 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1538 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1539 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1541 GtkTooltips *tt = gtk_tooltips_new();
1543 sp_toolbox_add_label(tbl, _("<b>New:</b>"));
1545 // rx/ry units menu: create
1546 GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
1547 sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
1548 sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
1549 // fixme: add % meaning per cent of the width/height
1551 /* W */
1552 {
1553 GtkWidget *hb = sp_tb_spinbutton(_("W:"), _("Width of rectangle"),
1554 "tools.shapes.rect", "width", 0,
1555 us, tbl, TRUE, "altx-rect",
1556 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1557 sp_rtb_width_value_changed);
1558 gtk_object_set_data(GTK_OBJECT(tbl), "width_sb", hb);
1559 gtk_widget_set_sensitive(hb, FALSE);
1560 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1561 }
1563 /* H */
1564 {
1565 GtkWidget *hb = sp_tb_spinbutton(_("H:"), _("Height of rectangle"),
1566 "tools.shapes.rect", "height", 0,
1567 us, tbl, FALSE, NULL,
1568 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1569 sp_rtb_height_value_changed);
1570 gtk_object_set_data(GTK_OBJECT(tbl), "height_sb", hb);
1571 gtk_widget_set_sensitive(hb, FALSE);
1572 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1573 }
1575 /* rx */
1576 {
1577 GtkWidget *hb = sp_tb_spinbutton(_("Rx:"), _("Horizontal radius of rounded corners"),
1578 "tools.shapes.rect", "rx", 0,
1579 us, tbl, FALSE, NULL,
1580 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1581 sp_rtb_rx_value_changed);
1582 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1583 }
1585 /* ry */
1586 {
1587 GtkWidget *hb = sp_tb_spinbutton(_("Ry:"), _("Vertical radius of rounded corners"),
1588 "tools.shapes.rect", "ry", 0,
1589 us, tbl, FALSE, NULL,
1590 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1591 sp_rtb_ry_value_changed);
1592 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1593 }
1595 // add the units menu
1596 gtk_widget_show(us);
1597 gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1598 gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
1600 /* Reset */
1601 {
1602 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1603 GtkWidget *b = gtk_button_new_with_label(_("Not rounded"));
1604 gtk_object_set_data(GTK_OBJECT(tbl), "not_rounded", b);
1605 gtk_tooltips_set_tip(tt, b, _("Make corners sharp"), NULL);
1606 gtk_widget_show(b);
1607 gtk_container_add(GTK_CONTAINER(hb), b);
1608 gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_rtb_defaults), tbl);
1609 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1610 }
1612 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1613 swatch->setWatchedTool ("tools.shapes.rect", true);
1614 GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1615 gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1617 g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
1618 sp_rtb_sensitivize (tbl);
1620 gtk_widget_show_all(tbl);
1621 sp_set_font_size_smaller (tbl);
1623 sigc::connection *connection = new sigc::connection(
1624 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_rect_toolbox_selection_changed), (GtkObject *)tbl))
1625 );
1626 g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
1628 return tbl;
1629 }
1631 //########################
1632 //## Spiral ##
1633 //########################
1635 static void
1636 sp_spl_tb_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name)
1637 {
1638 SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
1640 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1641 prefs_set_double_attribute("tools.shapes.spiral", value_name, adj->value);
1642 }
1644 // quit if run by the attr_changed listener
1645 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1646 return;
1647 }
1649 // in turn, prevent listener from responding
1650 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1652 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
1654 bool modmade = false;
1655 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
1656 items != NULL;
1657 items = items->next)
1658 {
1659 if (SP_IS_SPIRAL((SPItem *) items->data)) {
1660 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1661 sp_repr_set_svg_double( repr, namespaced_name, adj->value );
1662 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1663 modmade = true;
1664 }
1665 }
1667 g_free(namespaced_name);
1669 if (modmade) {
1670 sp_document_done(sp_desktop_document(desktop));
1671 }
1673 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1675 spinbutton_defocus(GTK_OBJECT(tbl));
1676 }
1678 static void
1679 sp_spl_tb_revolution_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1680 {
1681 sp_spl_tb_value_changed(adj, tbl, "revolution");
1682 }
1684 static void
1685 sp_spl_tb_expansion_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1686 {
1687 sp_spl_tb_value_changed(adj, tbl, "expansion");
1688 }
1690 static void
1691 sp_spl_tb_t0_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1692 {
1693 sp_spl_tb_value_changed(adj, tbl, "t0");
1694 }
1696 static void
1697 sp_spl_tb_defaults(GtkWidget *widget, GtkObject *obj)
1698 {
1699 GtkWidget *tbl = GTK_WIDGET(obj);
1701 GtkAdjustment *adj;
1703 // fixme: make settable
1704 gdouble rev = 5;
1705 gdouble exp = 1.0;
1706 gdouble t0 = 0.0;
1708 adj = (GtkAdjustment*)gtk_object_get_data(obj, "revolution");
1709 gtk_adjustment_set_value(adj, rev);
1710 gtk_adjustment_value_changed(adj);
1712 adj = (GtkAdjustment*)gtk_object_get_data(obj, "expansion");
1713 gtk_adjustment_set_value(adj, exp);
1714 gtk_adjustment_value_changed(adj);
1716 adj = (GtkAdjustment*)gtk_object_get_data(obj, "t0");
1717 gtk_adjustment_set_value(adj, t0);
1718 gtk_adjustment_value_changed(adj);
1720 spinbutton_defocus(GTK_OBJECT(tbl));
1721 }
1724 static void spiral_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1725 gchar const *old_value, gchar const *new_value,
1726 bool is_interactive, gpointer data)
1727 {
1728 GtkWidget *tbl = GTK_WIDGET(data);
1730 // quit if run by the _changed callbacks
1731 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1732 return;
1733 }
1735 // in turn, prevent callbacks from responding
1736 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1738 GtkAdjustment *adj;
1739 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "revolution");
1740 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:revolution", 3.0)));
1742 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "expansion");
1743 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:expansion", 1.0)));
1745 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "t0");
1746 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:t0", 0.0)));
1748 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1749 }
1752 static Inkscape::XML::NodeEventVector spiral_tb_repr_events = {
1753 NULL, /* child_added */
1754 NULL, /* child_removed */
1755 spiral_tb_event_attr_changed,
1756 NULL, /* content_changed */
1757 NULL /* order_changed */
1758 };
1760 static void
1761 sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1762 {
1763 int n_selected = 0;
1764 Inkscape::XML::Node *repr = NULL;
1765 Inkscape::XML::Node *oldrepr = NULL;
1767 for (GSList const *items = selection->itemList();
1768 items != NULL;
1769 items = items->next)
1770 {
1771 if (SP_IS_SPIRAL((SPItem *) items->data)) {
1772 n_selected++;
1773 repr = SP_OBJECT_REPR((SPItem *) items->data);
1774 }
1775 }
1777 GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
1779 if (n_selected == 0) {
1780 gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
1781 } else if (n_selected == 1) {
1782 gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1784 oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1785 if (oldrepr) { // remove old listener
1786 sp_repr_remove_listener_by_data(oldrepr, tbl);
1787 Inkscape::GC::release(oldrepr);
1788 oldrepr = 0;
1789 g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1790 }
1792 if (repr) {
1793 g_object_set_data(G_OBJECT(tbl), "repr", repr);
1794 Inkscape::GC::anchor(repr);
1795 sp_repr_add_listener(repr, &spiral_tb_repr_events, tbl);
1796 sp_repr_synthesize_events(repr, &spiral_tb_repr_events, tbl);
1797 }
1798 } else {
1799 // FIXME: implement averaging of all parameters for multiple selected
1800 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1801 gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1802 }
1803 }
1806 static GtkWidget *
1807 sp_spiral_toolbox_new(SPDesktop *desktop)
1808 {
1809 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1810 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1811 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1813 GtkTooltips *tt = gtk_tooltips_new();
1815 sp_toolbox_add_label(tbl, _("<b>New:</b>"));
1817 /* Revolution */
1818 {
1819 GtkWidget *hb = sp_tb_spinbutton(_("Turns:"), _("Number of revolutions"),
1820 "tools.shapes.spiral", "revolution", 3.0,
1821 NULL, tbl, TRUE, "altx-spiral",
1822 0.01, 1024.0, 0.1, 1.0,
1823 sp_spl_tb_revolution_value_changed, 1, 2);
1824 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1825 }
1827 /* Expansion */
1828 {
1829 GtkWidget *hb = sp_tb_spinbutton(_("Divergence:"), _("How much denser/sparser are outer revolutions; 1 = uniform"),
1830 "tools.shapes.spiral", "expansion", 1.0,
1831 NULL, tbl, FALSE, NULL,
1832 0.0, 1000.0, 0.01, 1.0,
1833 sp_spl_tb_expansion_value_changed);
1834 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1835 }
1837 /* T0 */
1838 {
1839 GtkWidget *hb = sp_tb_spinbutton(_("Inner radius:"), _("Radius of the innermost revolution (relative to the spiral size)"),
1840 "tools.shapes.spiral", "t0", 0.0,
1841 NULL, tbl, FALSE, NULL,
1842 0.0, 0.999, 0.01, 1.0,
1843 sp_spl_tb_t0_value_changed);
1844 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1845 }
1847 aux_toolbox_space(tbl, AUX_SPACING);
1849 /* Reset */
1850 {
1851 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1852 GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
1853 gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
1854 gtk_widget_show(b);
1855 gtk_container_add(GTK_CONTAINER(hb), b);
1856 gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_spl_tb_defaults), tbl);
1857 gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1858 }
1860 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1861 swatch->setWatchedTool ("tools.shapes.spiral", true);
1862 GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1863 gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1865 gtk_widget_show_all(tbl);
1866 sp_set_font_size_smaller (tbl);
1868 sigc::connection *connection = new sigc::connection(
1869 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_spiral_toolbox_selection_changed), (GtkObject *)tbl))
1870 );
1871 g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
1873 return tbl;
1874 }
1876 //########################
1877 //## Pen/Pencil ##
1878 //########################
1881 static GtkWidget *
1882 sp_pen_toolbox_new(SPDesktop *desktop)
1883 {
1884 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1885 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1886 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1888 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1889 swatch->setWatchedTool ("tools.freehand.pen", true);
1890 GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1891 gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1893 gtk_widget_show_all(tbl);
1894 sp_set_font_size_smaller (tbl);
1896 return tbl;
1897 }
1899 static GtkWidget *
1900 sp_pencil_toolbox_new(SPDesktop *desktop)
1901 {
1902 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1903 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1904 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1906 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1907 swatch->setWatchedTool ("tools.freehand.pencil", true);
1908 GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1909 gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1911 gtk_widget_show_all(tbl);
1912 sp_set_font_size_smaller (tbl);
1914 return tbl;
1915 }
1918 //########################
1919 //## Calligraphy ##
1920 //########################
1922 static void
1923 sp_ddc_mass_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1924 {
1925 prefs_set_double_attribute("tools.calligraphic", "mass", adj->value);
1926 spinbutton_defocus(GTK_OBJECT(tbl));
1927 }
1929 static void
1930 sp_ddc_drag_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1931 {
1932 prefs_set_double_attribute("tools.calligraphic", "drag", adj->value);
1933 spinbutton_defocus(GTK_OBJECT(tbl));
1934 }
1936 static void
1937 sp_ddc_angle_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1938 {
1939 prefs_set_double_attribute("tools.calligraphic", "angle", adj->value);
1940 spinbutton_defocus(GTK_OBJECT(tbl));
1941 }
1943 static void
1944 sp_ddc_width_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1945 {
1946 prefs_set_double_attribute("tools.calligraphic", "width", adj->value * 0.01);
1947 spinbutton_defocus(GTK_OBJECT(tbl));
1948 }
1950 static void
1951 sp_ddc_velthin_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1952 {
1953 prefs_set_double_attribute("tools.calligraphic", "thinning", adj->value);
1954 spinbutton_defocus(GTK_OBJECT(tbl));
1955 }
1957 static void
1958 sp_ddc_flatness_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1959 {
1960 prefs_set_double_attribute("tools.calligraphic", "flatness", adj->value);
1961 spinbutton_defocus(GTK_OBJECT(tbl));
1962 }
1964 static void
1965 sp_ddc_tremor_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1966 {
1967 prefs_set_double_attribute("tools.calligraphic", "tremor", adj->value);
1968 spinbutton_defocus(GTK_OBJECT(tbl));
1969 }
1971 static void
1972 sp_ddc_pressure_state_changed(GtkWidget *button, gpointer data)
1973 {
1974 prefs_set_int_attribute ("tools.calligraphic", "usepressure", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 1 : 0);
1975 }
1977 static void
1978 sp_ddc_tilt_state_changed(GtkWidget *button, GtkWidget *calligraphy_angle)
1979 {
1980 prefs_set_int_attribute ("tools.calligraphic", "usetilt", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 1 : 0);
1982 gtk_widget_set_sensitive(GTK_WIDGET(calligraphy_angle), !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)));
1983 }
1985 static void sp_ddc_defaults(GtkWidget *, GtkWidget *tbl)
1986 {
1987 // FIXME: make defaults settable via Inkscape Options
1988 struct KeyValue {
1989 char const *key;
1990 double value;
1991 } const key_values[] = {
1992 {"mass", 0.02},
1993 {"drag", 1.0},
1994 {"angle", 30.0},
1995 {"width", 15},
1996 {"thinning", 0.1},
1997 {"tremor", 0.0},
1998 {"flatness", 0.9}
1999 };
2001 for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
2002 KeyValue const &kv = key_values[i];
2003 GtkAdjustment &adj = *static_cast<GtkAdjustment *>(gtk_object_get_data(GTK_OBJECT(tbl), kv.key));
2004 gtk_adjustment_set_value(&adj, kv.value);
2005 }
2007 spinbutton_defocus(GTK_OBJECT(tbl));
2008 }
2010 static GtkWidget *
2011 sp_calligraphy_toolbox_new(SPDesktop *desktop)
2012 {
2013 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2014 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2015 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2017 GtkTooltips *tt = gtk_tooltips_new();
2018 GtkWidget *calligraphy_angle;
2020 // interval
2021 gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2023 /* Width */
2024 {
2025 GtkWidget *hb = sp_tb_spinbutton(_("Width:"), _("The width of the calligraphic pen (relative to the visible canvas area)"),
2026 "tools.calligraphic", "width", 15,
2027 NULL, tbl, TRUE, "altx-calligraphy",
2028 1, 100, 1.0, 10.0,
2029 sp_ddc_width_value_changed, 0.01, 0, 100);
2030 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2031 }
2033 /* Thinning */
2034 {
2035 GtkWidget *hb = sp_tb_spinbutton(_("Thinning:"), _("How much velocity thins the stroke (> 0 makes fast strokes thinner, < 0 makes them broader, 0 makes width independent of velocity)"),
2036 "tools.calligraphic", "thinning", 0.1,
2037 NULL, tbl, FALSE, NULL,
2038 -1.0, 1.0, 0.01, 0.1,
2039 sp_ddc_velthin_value_changed, 0.01, 2);
2040 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2041 }
2043 // interval
2044 gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2046 /* Angle */
2047 {
2048 calligraphy_angle = sp_tb_spinbutton(_("Angle:"), _("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"),
2049 "tools.calligraphic", "angle", 30,
2050 NULL, tbl, TRUE, "calligraphy-angle",
2051 -90.0, 90.0, 1.0, 10.0,
2052 sp_ddc_angle_value_changed, 1, 0);
2053 gtk_box_pack_start(GTK_BOX(tbl), calligraphy_angle, FALSE, FALSE, AUX_SPACING);
2054 }
2056 /* Fixation */
2057 {
2058 GtkWidget *hb = sp_tb_spinbutton(_("Fixation:"), _("How fixed is the pen angle (0 = always perpendicular to stroke direction, 1 = fixed)"),
2059 "tools.calligraphic", "flatness", 0.9,
2060 NULL, tbl, FALSE, NULL,
2061 0.0, 1.0, 0.01, 0.1,
2062 sp_ddc_flatness_value_changed, 0.01, 2);
2063 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2064 }
2066 // interval
2067 gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2069 /* Tremor */
2070 {
2071 GtkWidget *hb = sp_tb_spinbutton(_("Tremor:"), _("How uneven or trembling is the pen stroke"),
2072 "tools.calligraphic", "tremor", 0.0,
2073 NULL, tbl, FALSE, NULL,
2074 0.0, 1.0, 0.01, 0.1,
2075 sp_ddc_tremor_value_changed, 0.01, 2);
2076 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2077 }
2078 /* Mass */
2079 {
2080 GtkWidget *hb = sp_tb_spinbutton(_("Mass:"), _("How much inertia affects the movement of the pen"),
2081 "tools.calligraphic", "mass", 0.02,
2082 NULL, tbl, FALSE, NULL,
2083 0.0, 1.0, 0.01, 0.1,
2084 sp_ddc_mass_value_changed, 0.01, 2);
2085 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2086 }
2088 /* Drag */
2089 {
2090 // TRANSLATORS: "drag" means "resistance" here
2091 GtkWidget *hb = sp_tb_spinbutton(_("Drag:"), _("How much resistance affects the movement of the pen"),
2092 "tools.calligraphic", "drag", 1,
2093 NULL, tbl, FALSE, NULL,
2094 0.0, 1.0, 0.01, 0.1,
2095 sp_ddc_drag_value_changed, 0.01, 2);
2096 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2097 }
2099 // interval
2100 gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2102 GtkWidget *cvbox = gtk_vbox_new (FALSE, 0);
2103 GtkWidget *cbox = gtk_hbox_new (FALSE, 0);
2105 /* Use Pressure button */
2106 {
2107 GtkWidget *button = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
2108 SP_BUTTON_TYPE_TOGGLE,
2109 NULL,
2110 "use_pressure",
2111 _("Use the pressure of the input device to alter the width of the pen"),
2112 tt);
2113 g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (sp_ddc_pressure_state_changed), NULL);
2114 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), prefs_get_int_attribute ("tools.calligraphic", "usepressure", 1));
2115 gtk_box_pack_start(GTK_BOX(cbox), button, FALSE, FALSE, 0);
2116 }
2118 /* Use Tilt button */
2119 {
2120 GtkWidget *button = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
2121 SP_BUTTON_TYPE_TOGGLE,
2122 NULL,
2123 "use_tilt",
2124 _("Use the tilt of the input device to alter the angle of the pen's nib"),
2125 tt);
2126 g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (sp_ddc_tilt_state_changed), calligraphy_angle);
2127 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), prefs_get_int_attribute ("tools.calligraphic", "usetilt", 1));
2128 gtk_widget_set_sensitive(GTK_WIDGET(calligraphy_angle), !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)));
2129 gtk_box_pack_start(GTK_BOX(cbox), button, FALSE, FALSE, 0);
2130 }
2132 gtk_box_pack_start(GTK_BOX(cvbox), cbox, TRUE, FALSE, 0);
2133 gtk_box_pack_start(GTK_BOX(tbl), cvbox, FALSE, FALSE, 0);
2135 /* Reset */
2136 {
2137 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2138 GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
2139 gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
2140 gtk_widget_show(b);
2141 gtk_container_add(GTK_CONTAINER(hb), b);
2142 gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_ddc_defaults), tbl);
2143 gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2144 }
2147 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
2148 swatch->setWatchedTool ("tools.calligraphic", true);
2149 GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
2150 gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
2152 gtk_widget_show_all(tbl);
2153 sp_set_font_size_smaller (tbl);
2155 return tbl;
2156 }
2159 //########################
2160 //## Circle / Arc ##
2161 //########################
2163 static void
2164 sp_arctb_sensitivize (GtkWidget *tbl, double v1, double v2)
2165 {
2166 GtkWidget *ocb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "open_checkbox");
2167 GtkWidget *make_whole = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "make_whole");
2169 if (v1 == 0 && v2 == 0) {
2170 if (gtk_object_get_data(GTK_OBJECT(tbl), "single")) { // only for a single selected ellipse (for now)
2171 gtk_widget_set_sensitive(GTK_WIDGET(ocb), FALSE);
2172 gtk_widget_set_sensitive(GTK_WIDGET(make_whole), FALSE);
2173 }
2174 } else {
2175 gtk_widget_set_sensitive(GTK_WIDGET(ocb), TRUE);
2176 gtk_widget_set_sensitive(GTK_WIDGET(make_whole), TRUE);
2177 }
2178 }
2180 static void
2181 sp_arctb_startend_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name, gchar const *other_name)
2182 {
2183 SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2185 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2186 prefs_set_double_attribute("tools.shapes.arc", value_name, (adj->value * M_PI)/ 180);
2187 }
2189 // quit if run by the attr_changed listener
2190 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2191 return;
2192 }
2194 // in turn, prevent listener from responding
2195 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2197 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
2199 bool modmade = false;
2200 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2201 items != NULL;
2202 items = items->next)
2203 {
2204 SPItem *item = SP_ITEM(items->data);
2206 if (SP_IS_ARC(item) && SP_IS_GENERICELLIPSE(item)) {
2208 SPGenericEllipse *ge = SP_GENERICELLIPSE(item);
2209 SPArc *arc = SP_ARC(item);
2211 if (!strcmp(value_name, "start"))
2212 ge->start = (adj->value * M_PI)/ 180;
2213 else
2214 ge->end = (adj->value * M_PI)/ 180;
2216 sp_genericellipse_normalize(ge);
2217 ((SPObject *)arc)->updateRepr();
2218 ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
2220 modmade = true;
2221 }
2222 }
2224 g_free(namespaced_name);
2226 GtkAdjustment *other = (GtkAdjustment *)gtk_object_get_data(GTK_OBJECT(tbl), other_name);
2228 sp_arctb_sensitivize (tbl, adj->value, other->value);
2230 if (modmade) {
2231 sp_document_maybe_done(sp_desktop_document(desktop), value_name);
2232 }
2234 // defocus spinbuttons by moving focus to the canvas, unless "stay" is on
2235 spinbutton_defocus(GTK_OBJECT(tbl));
2237 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2238 }
2241 static void
2242 sp_arctb_start_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
2243 {
2244 sp_arctb_startend_value_changed(adj, tbl, "start", "end");
2245 }
2247 static void
2248 sp_arctb_end_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
2249 {
2250 sp_arctb_startend_value_changed(adj, tbl, "end", "start");
2251 }
2253 static void
2254 sp_arctb_open_state_changed(GtkWidget *widget, GtkObject *tbl)
2255 {
2256 SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2258 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2259 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
2260 prefs_set_string_attribute("tools.shapes.arc", "open", "true");
2261 } else {
2262 prefs_set_string_attribute("tools.shapes.arc", "open", NULL);
2263 }
2264 }
2266 // quit if run by the attr_changed listener
2267 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2268 return;
2269 }
2271 // in turn, prevent listener from responding
2272 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2274 bool modmade = false;
2276 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
2277 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2278 items != NULL;
2279 items = items->next)
2280 {
2281 if (SP_IS_ARC((SPItem *) items->data)) {
2282 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2283 repr->setAttribute("sodipodi:open", "true");
2284 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2285 modmade = true;
2286 }
2287 }
2288 } else {
2289 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2290 items != NULL;
2291 items = items->next)
2292 {
2293 if (SP_IS_ARC((SPItem *) items->data)) {
2294 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2295 repr->setAttribute("sodipodi:open", NULL);
2296 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2297 modmade = true;
2298 }
2299 }
2300 }
2302 if (modmade) {
2303 sp_document_done(sp_desktop_document(desktop));
2304 }
2306 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2308 spinbutton_defocus(GTK_OBJECT(tbl));
2309 }
2311 static void sp_arctb_defaults(GtkWidget *, GtkObject *obj)
2312 {
2313 GtkWidget *tbl = GTK_WIDGET(obj);
2315 GtkAdjustment *adj;
2316 adj = (GtkAdjustment*)gtk_object_get_data(obj, "start");
2317 gtk_adjustment_set_value(adj, 0.0);
2318 gtk_adjustment_value_changed(adj);
2320 adj = (GtkAdjustment*)gtk_object_get_data(obj, "end");
2321 gtk_adjustment_set_value(adj, 0.0);
2322 gtk_adjustment_value_changed(adj);
2324 spinbutton_defocus(GTK_OBJECT(tbl));
2325 }
2327 static void arc_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
2328 gchar const *old_value, gchar const *new_value,
2329 bool is_interactive, gpointer data)
2330 {
2331 GtkWidget *tbl = GTK_WIDGET(data);
2333 // quit if run by the _changed callbacks
2334 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2335 return;
2336 }
2338 // in turn, prevent callbacks from responding
2339 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2341 gdouble start = sp_repr_get_double_attribute(repr, "sodipodi:start", 0.0);
2342 gdouble end = sp_repr_get_double_attribute(repr, "sodipodi:end", 0.0);
2344 GtkAdjustment *adj1,*adj2;
2345 adj1 = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "start");
2346 gtk_adjustment_set_value(adj1, mod360((start * 180)/M_PI));
2347 adj2 = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "end");
2348 gtk_adjustment_set_value(adj2, mod360((end * 180)/M_PI));
2350 sp_arctb_sensitivize (tbl, adj1->value, adj2->value);
2352 char const *openstr = NULL;
2353 openstr = repr->attribute("sodipodi:open");
2354 GtkWidget *ocb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "open_checkbox");
2356 if (openstr) {
2357 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ocb), TRUE);
2358 } else {
2359 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ocb), FALSE);
2360 }
2362 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2363 }
2365 static Inkscape::XML::NodeEventVector arc_tb_repr_events = {
2366 NULL, /* child_added */
2367 NULL, /* child_removed */
2368 arc_tb_event_attr_changed,
2369 NULL, /* content_changed */
2370 NULL /* order_changed */
2371 };
2374 static void
2375 sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
2376 {
2377 int n_selected = 0;
2378 Inkscape::XML::Node *repr = NULL;
2379 Inkscape::XML::Node *oldrepr = NULL;
2381 for (GSList const *items = selection->itemList();
2382 items != NULL;
2383 items = items->next)
2384 {
2385 if (SP_IS_ARC((SPItem *) items->data)) {
2386 n_selected++;
2387 repr = SP_OBJECT_REPR((SPItem *) items->data);
2388 }
2389 }
2391 GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
2393 g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(FALSE));
2394 if (n_selected == 0) {
2395 gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
2396 } else if (n_selected == 1) {
2397 g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
2398 gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2400 oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
2402 if (oldrepr) { // remove old listener
2403 sp_repr_remove_listener_by_data(oldrepr, tbl);
2404 Inkscape::GC::release(oldrepr);
2405 oldrepr = 0;
2406 g_object_set_data(G_OBJECT(tbl), "repr", NULL);
2407 }
2409 if (repr) {
2410 g_object_set_data(G_OBJECT(tbl), "repr", repr);
2411 Inkscape::GC::anchor(repr);
2412 sp_repr_add_listener(repr, &arc_tb_repr_events, tbl);
2413 sp_repr_synthesize_events(repr, &arc_tb_repr_events, tbl);
2414 }
2415 } else {
2416 // FIXME: implement averaging of all parameters for multiple selected
2417 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2418 gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2419 sp_arctb_sensitivize (GTK_WIDGET(tbl), 1, 0);
2420 }
2421 }
2424 static GtkWidget *
2425 sp_arc_toolbox_new(SPDesktop *desktop)
2426 {
2427 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2429 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2430 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2432 GtkTooltips *tt = gtk_tooltips_new();
2434 sp_toolbox_add_label(tbl, _("<b>New:</b>"));
2436 /* Start */
2437 {
2438 GtkWidget *hb = sp_tb_spinbutton(_("Start:"), _("The angle (in degrees) from the horizontal to the arc's start point"),
2439 "tools.shapes.arc", "start", 0.0,
2440 NULL, tbl, TRUE, "altx-arc",
2441 -360.0, 360.0, 1.0, 10.0,
2442 sp_arctb_start_value_changed);
2443 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2444 }
2446 /* End */
2447 {
2448 GtkWidget *hb = sp_tb_spinbutton(_("End:"), _("The angle (in degrees) from the horizontal to the arc's end point"),
2449 "tools.shapes.arc", "end", 0.0,
2450 NULL, tbl, FALSE, NULL,
2451 -360.0, 360.0, 1.0, 10.0,
2452 sp_arctb_end_value_changed);
2453 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2454 }
2456 /* Segments / Pie checkbox */
2457 {
2458 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2459 GtkWidget *fscb = gtk_check_button_new_with_label(_("Open arc"));
2460 gtk_tooltips_set_tip(tt, fscb, _("Switch between arc (unclosed shape) and segment (closed shape with two radii)"), NULL);
2462 gchar const *openstr = NULL;
2463 openstr = prefs_get_string_attribute("tools.shapes.arc", "open");
2464 if (!openstr || (openstr && !strcmp(openstr, "false")))
2465 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb), FALSE);
2466 else
2467 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb), TRUE);
2469 gtk_widget_show(fscb);
2470 gtk_object_set_data(GTK_OBJECT(tbl), "open_checkbox", fscb);
2471 gtk_container_add(GTK_CONTAINER(hb), fscb);
2472 g_signal_connect(G_OBJECT(fscb), "toggled", GTK_SIGNAL_FUNC(sp_arctb_open_state_changed ), tbl);
2473 gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2474 }
2476 /* Make Whole */
2477 {
2478 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2479 GtkWidget *b = gtk_button_new_with_label(_("Make whole"));
2480 gtk_object_set_data(GTK_OBJECT(tbl), "make_whole", b);
2481 gtk_tooltips_set_tip(tt, b, _("Make the shape a whole ellipse, not arc or segment"), NULL);
2482 gtk_widget_show(b);
2483 gtk_container_add(GTK_CONTAINER(hb), b);
2484 gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_arctb_defaults), tbl);
2485 gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2486 }
2488 g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
2489 // sensitivize make whole and open checkbox
2490 {
2491 GtkAdjustment *adj1 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "start"));
2492 GtkAdjustment *adj2 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "end"));
2493 sp_arctb_sensitivize (tbl, adj1->value, adj2->value);
2494 }
2496 sigc::connection *connection = new sigc::connection(
2497 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_arc_toolbox_selection_changed), (GtkObject *)tbl))
2498 );
2499 g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
2501 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
2502 swatch->setWatchedTool ("tools.shapes.arc", true);
2503 GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
2504 gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
2506 gtk_widget_show_all(tbl);
2507 sp_set_font_size_smaller (tbl);
2509 return tbl;
2510 }
2515 // toggle button callbacks and updaters
2517 //########################
2518 //## Dropper ##
2519 //########################
2521 static void toggle_dropper_color_pick (GtkWidget *button, gpointer data) {
2522 prefs_set_int_attribute ("tools.dropper", "pick",
2523 // 0 and 1 are backwards here because of pref
2524 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 0 : 1);
2525 }
2528 /**
2529 * Copy the current saved desktop color to the clipboard as full hex + alpha
2530 * color representation. This is useful for passing values between various
2531 * input boxes, or directly to xml.
2532 */
2533 /* static void
2534 sp_dropper_copy( GtkWidget *widget, GtkObject *obj)
2535 {
2536 GtkWidget *tbl = GTK_WIDGET(obj);
2538 SPDesktop *desktop =
2539 (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2542 sp_dropper_c32_color_copy( sp_desktop_get_color(desktop, true) );
2543 }*/
2546 /**
2547 * Copies currently saved desktop color to the clipboard as a hex value. This
2548 * is useful for editing webpages and needing a value quickly for web
2549 * colors.
2550 *
2551 * TODO: When the toggle of the dropper is set to not mix color against
2552 * page background, this still just gets the color of the page and
2553 * doesn't get the actual mixed against background which is needed
2554 * for the hex value ppl. want for web pages, etc.
2555 */
2557 /* static void
2558 sp_dropper_copy_as_hex ( GtkWidget *widget, GtkObject *obj)
2559 {
2560 GtkWidget *tbl = GTK_WIDGET(obj);
2562 SPDesktop *desktop =
2563 (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2565 sp_dropper_c32_color_copy_hex( sp_desktop_get_color(desktop, true) );
2566 }*/
2569 /**
2570 * Sets the input boxes with the changed color and opacity. This is used as a
2571 * callback for style changing.
2572 */
2573 /* static bool
2574 sp_style_changed (const SPCSSAttr *css, gpointer data)
2575 {
2576 // GrDrag *drag = (GrDrag *) data;
2578 // set fill of text entry box
2579 if (css->attribute("fill"))
2580 gtk_entry_set_text((GtkEntry *)dropper_rgb_entry,
2581 css->attribute("fill"));
2583 // set opacity of text entry box
2584 if (css->attribute("fill-opacity"))
2585 gtk_entry_set_text((GtkEntry *)dropper_opacity_entry,
2586 css->attribute("fill-opacity"));
2588 // set fill of text entry box
2589 if (css->attribute("stroke"))
2590 gtk_entry_set_text((GtkEntry *)dropper_rgb_entry,
2591 css->attribute("stroke"));
2593 // set opacity of text entry box
2594 if (css->attribute("stroke-opacity"))
2595 gtk_entry_set_text((GtkEntry *)dropper_opacity_entry,
2596 css->attribute("stroke-opacity"));
2597 return false;
2599 }
2600 */
2603 /**
2604 * Dropper auxiliary toolbar construction and setup.
2605 *
2606 * TODO: Would like to add swatch of current color.
2607 * TODO: Add queue of last 5 or so colors selected with new swatches so that
2608 * can drag and drop places. Will provide a nice mixing palette.
2609 */
2610 static GtkWidget *
2611 sp_dropper_toolbox_new(SPDesktop *desktop)
2612 {
2613 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2615 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2616 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2618 GtkTooltips *tt = gtk_tooltips_new();
2621 gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
2622 AUX_BETWEEN_BUTTON_GROUPS);
2623 // sp_toolbox_add_label(tbl, _("<b>New:</b>"));
2627 /* RGB Input Field */
2628 /* {
2629 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2630 GtkWidget *dropper_rgba_label = gtk_label_new ("Color:");
2631 gtk_widget_show (dropper_rgba_label);
2632 gtk_container_add(GTK_CONTAINER(hb), dropper_rgba_label);
2634 dropper_rgb_entry = gtk_entry_new ();
2635 sp_dialog_defocus_on_enter (dropper_rgb_entry);
2636 gtk_entry_set_max_length (GTK_ENTRY (dropper_rgb_entry), 7);
2637 gtk_entry_set_width_chars (GTK_ENTRY (dropper_rgb_entry), 7);
2638 gtk_tooltips_set_tip(tt, dropper_rgb_entry,
2639 _("Hexidecimal representation of last selected "
2640 "color"),
2641 NULL);
2642 gtk_widget_show (dropper_rgb_entry);
2643 gtk_container_add(GTK_CONTAINER(hb), dropper_rgb_entry);
2645 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE,
2646 AUX_BETWEEN_BUTTON_GROUPS);
2647 } */
2649 /* Opacity Input Field */
2650 /* {
2651 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2652 GtkWidget *dropper_opacity_label = gtk_label_new ( _("Opacity:") );
2653 gtk_widget_show (dropper_opacity_label);
2654 gtk_container_add(GTK_CONTAINER(hb), dropper_opacity_label);
2656 dropper_opacity_entry = gtk_entry_new ();
2657 sp_dialog_defocus_on_enter (dropper_opacity_entry);
2658 gtk_entry_set_max_length (GTK_ENTRY (dropper_opacity_entry), 11);
2659 gtk_entry_set_width_chars (GTK_ENTRY (dropper_opacity_entry), 11);
2660 gtk_tooltips_set_tip(tt, dropper_opacity_entry,
2661 _("Opacity of last selected color"),
2662 NULL);
2663 gtk_widget_show (dropper_opacity_entry);
2664 gtk_container_add(GTK_CONTAINER(hb), dropper_opacity_entry);
2666 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE,
2667 AUX_BETWEEN_BUTTON_GROUPS);
2668 } */
2671 /* Copy to Clipboard */
2672 /* {
2673 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2674 GtkWidget *b = gtk_button_new_with_label(_("Copy as RGBA"));
2675 gtk_tooltips_set_tip(tt, b, _("Copy last saved color as hexidecimal "
2676 "RGB + Alpha (RGBA) to "
2677 "clipboard"),
2678 NULL);
2679 gtk_widget_show(b);
2680 gtk_container_add(GTK_CONTAINER(hb), b);
2681 gtk_signal_connect(GTK_OBJECT(b), "clicked",
2682 GTK_SIGNAL_FUNC(sp_dropper_copy), tbl);
2683 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE,
2684 AUX_BETWEEN_BUTTON_GROUPS);
2685 } */
2688 /* Copy to Clipboard as HEX */
2689 /* {
2690 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2691 GtkWidget *b = gtk_button_new_with_label(_("Copy as HEX"));
2692 gtk_tooltips_set_tip(tt, b, _("Copy last saved color as "
2693 "hexidecimal RGB without alpha "
2694 "to clipboard"), NULL);
2695 gtk_widget_show(b);
2696 gtk_container_add(GTK_CONTAINER(hb), b);
2697 gtk_signal_connect(GTK_OBJECT(b), "clicked",
2698 GTK_SIGNAL_FUNC(sp_dropper_copy_as_hex), tbl);
2699 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE,
2700 AUX_BETWEEN_BUTTON_GROUPS);
2701 } */
2703 // aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2705 {
2706 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2708 GtkWidget *button =
2709 sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
2710 SP_BUTTON_TYPE_TOGGLE,
2711 NULL,
2712 "pick_color",
2713 _("When pressed, picks visible color "
2714 "without alpha and when not pressed, "
2715 "picks color including its "
2716 "alpha"),
2717 tt);
2719 gtk_widget_show(button);
2720 gtk_container_add (GTK_CONTAINER (hb), button);
2722 g_signal_connect_after (G_OBJECT (button), "clicked",
2723 G_CALLBACK (toggle_dropper_color_pick), NULL);
2724 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
2725 !prefs_get_int_attribute ("tools.dropper",
2726 "pick", 0));
2727 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE,
2728 AUX_BETWEEN_BUTTON_GROUPS);
2729 }
2731 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2734 // where new gtkmm stuff should go
2736 gtk_widget_show_all(tbl);
2737 sp_set_font_size_smaller (tbl);
2739 /*
2740 sigc::connection *connection = new sigc::connection(
2741 desktop->connectSetStyle(
2742 sigc::bind(sigc::ptr_fun(sp_style_changed),
2743 desktop)) );
2745 g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection),
2746 connection); */
2748 return tbl;
2749 }
2752 //########################
2753 //## Text Toolbox ##
2754 //########################
2755 /*
2756 static void
2757 sp_text_letter_changed(GtkAdjustment *adj, GtkWidget *tbl)
2758 {
2759 //Call back for letter sizing spinbutton
2760 }
2762 static void
2763 sp_text_line_changed(GtkAdjustment *adj, GtkWidget *tbl)
2764 {
2765 //Call back for line height spinbutton
2766 }
2768 static void
2769 sp_text_horiz_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
2770 {
2771 //Call back for horizontal kerning spinbutton
2772 }
2774 static void
2775 sp_text_vert_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
2776 {
2777 //Call back for vertical kerning spinbutton
2778 }
2780 static void
2781 sp_text_letter_rotation_changed(GtkAdjustment *adj, GtkWidget *tbl)
2782 {
2783 //Call back for letter rotation spinbutton
2784 }*/
2786 static void
2787 sp_text_toolbox_selection_changed (Inkscape::Selection *selection, GObject *tbl)
2788 {
2789 GtkWidget *cbox = GTK_WIDGET(g_object_get_data (G_OBJECT(tbl), "combo-box-family"));
2790 Inkscape::XML::Node *repr = 0;
2791 SPStyle *style = 0;
2792 bool multiple = false;
2794 // create temporary style
2795 SPStyle *query = sp_style_new ();
2796 // query style from desktop into it. This returns a result flag and fills query with the style of subselection, if any, or selection
2797 int result_family = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
2798 int result_style = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
2799 int result_numbers = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
2801 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
2802 if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING)
2803 {
2804 return;
2805 }
2807 if (result_numbers == QUERY_STYLE_MULTIPLE_DIFFERENT)
2808 {
2809 g_object_set_data (G_OBJECT (cbox), "block", GINT_TO_POINTER(1));
2810 gtk_combo_box_set_active (GTK_COMBO_BOX (cbox), -1);
2811 g_object_set_data (G_OBJECT (cbox), "block", GINT_TO_POINTER(0));
2812 return;
2813 }
2815 if (query->text && query->text->font_family.value)
2816 {
2817 Gtk::TreePath path;
2818 try {
2819 path = Inkscape::FontLister::get_instance()->get_row_for_font (query->text->font_family.value);
2820 } catch (...) {
2821 return;
2822 }
2823 g_object_set_data (G_OBJECT (cbox), "block", GINT_TO_POINTER(1));
2824 gtk_combo_box_set_active (GTK_COMBO_BOX (cbox), gtk_tree_path_get_indices (path.gobj())[0]);
2825 g_object_set_data (G_OBJECT (cbox), "block", GINT_TO_POINTER(0));
2826 }
2827 }
2829 static void
2830 sp_text_toolbox_family_changed (GtkComboBox *cbox,
2831 GtkWidget *tbl)
2832 {
2833 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
2835 if (GPOINTER_TO_INT(g_object_get_data (G_OBJECT (cbox), "block")) != 0) return;
2837 SPCSSAttr *css = sp_repr_css_attr_new ();
2838 sp_repr_css_set_property (css, "font-family", gtk_combo_box_get_active_text (cbox));
2839 sp_desktop_set_style (desktop, css, true, true);
2840 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP));
2841 sp_repr_css_attr_unref (css);
2842 }
2844 #if 0
2845 static void cell_data_func (GtkCellLayout *cell_layout,
2846 GtkCellRenderer *cell,
2847 GtkTreeModel *tree_model,
2848 GtkTreeIter *iter,
2849 gpointer data)
2850 {
2851 char *text;
2852 gtk_tree_model_get (tree_model, iter, 0, &text, -1);
2853 g_object_set (G_OBJECT (cell), "family", text, NULL);
2854 }
2855 #endif
2857 static GtkWidget*
2858 sp_text_toolbox_new (SPDesktop *desktop)
2859 {
2860 GtkWidget *tbl = gtk_hbox_new (FALSE, 0);
2862 #if 0
2863 GtkWidget *us = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "units"));
2864 GtkTooltips *tt = gtk_tooltips_new();
2865 GtkWidget *group;
2866 #endif
2868 //Font Family
2869 GtkWidget *cbox = gtk_combo_box_entry_new_text ();
2870 Glib::RefPtr<Gtk::ListStore> store = Inkscape::FontLister::get_instance()->get_font_list();
2871 gtk_cell_layout_clear (GTK_CELL_LAYOUT (cbox));
2872 GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
2873 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (cbox), cell, FALSE);
2874 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (cbox), cell, "text", 0, NULL);
2876 #if 0
2877 gtk_cell_layout_set_cell_data_func
2878 (GTK_CELL_LAYOUT (cbox),
2879 cell,
2880 GtkCellLayoutDataFunc (cell_data_func),
2881 tbl,
2882 NULL);
2883 #endif
2885 gtk_combo_box_set_model (GTK_COMBO_BOX (cbox), GTK_TREE_MODEL (Glib::unwrap(store)));
2887 gtk_widget_set_size_request (cbox, 250, -1);
2888 aux_toolbox_space (tbl, 1);
2889 gtk_box_pack_start (GTK_BOX (tbl), cbox, FALSE, FALSE, 0);
2890 g_object_set_data (G_OBJECT (tbl), "combo-box-family", cbox);
2891 g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (sp_text_toolbox_family_changed), tbl);
2893 #if 0
2894 //Font Style
2895 GtkWidget *cbox = gtk_combo_box_new_text ();
2896 gtk_widget_set_size_request (cbox, 144, -1);
2897 aux_toolbox_space (tbl, 1);
2898 gtk_box_pack_start (GTK_BOX (tbl), cbox, FALSE, FALSE, 0);
2899 g_object_set_data (G_OBJECT (tbl), "combo-box-style", cbox);
2900 #endif
2902 sigc::connection *connection =
2903 new sigc::connection( sp_desktop_selection (desktop)->connectChanged (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), (GObject*)tbl)));
2904 g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
2906 #if 0
2907 //Font Size
2908 {
2909 GtkWidget *c = gtk_combo_new ();
2910 gtk_combo_set_value_in_list ((GtkCombo *) c, FALSE, FALSE);
2911 gtk_combo_set_use_arrows ((GtkCombo *) c, TRUE);
2912 gtk_combo_set_use_arrows_always ((GtkCombo *) c, TRUE);
2913 gtk_widget_set_size_request (c, 64, -1);
2914 aux_toolbox_space(tbl, 1);
2915 gtk_box_pack_start (GTK_BOX (tbl), c, FALSE, FALSE, 0);
2916 }
2918 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2919 //Bold
2920 {
2921 GtkWidget *px = gtk_image_new_from_stock(GTK_STOCK_BOLD, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
2922 GtkWidget *button = gtk_toggle_button_new ();
2923 gtk_container_add (GTK_CONTAINER (button), px);
2924 gtk_widget_show(button);
2925 gtk_tooltips_set_tip (tt, button, _("Bold"), NULL);
2926 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
2927 gtk_widget_set_sensitive(button, TRUE);
2928 gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
2929 }
2932 //Italic
2933 {
2934 GtkWidget *px = gtk_image_new_from_stock(GTK_STOCK_ITALIC, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
2935 GtkWidget *button = gtk_toggle_button_new ();
2936 gtk_container_add (GTK_CONTAINER (button), px);
2937 gtk_widget_show(button);
2938 gtk_tooltips_set_tip (tt, button, _("Italics"), NULL);
2939 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
2940 gtk_widget_set_sensitive(button, TRUE);
2941 gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
2942 }
2944 //Underline
2945 {
2946 GtkWidget *px = gtk_image_new_from_stock(GTK_STOCK_UNDERLINE, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
2947 GtkWidget *button = gtk_toggle_button_new ();
2948 gtk_container_add (GTK_CONTAINER (button), px);
2949 gtk_widget_show(button);
2950 gtk_tooltips_set_tip (tt, button, _("Underline"), NULL);
2951 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
2952 gtk_widget_set_sensitive(button, FALSE);
2953 gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
2954 }
2956 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2957 // align left
2958 {
2959 GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
2960 GtkWidget *b = group = gtk_radio_button_new (NULL);
2961 gtk_container_add (GTK_CONTAINER (b), px);
2962 gtk_tooltips_set_tip (tt, b, _("Align lines left"), NULL);
2963 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
2964 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
2965 gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
2966 }
2968 // align center
2969 {
2970 GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
2971 GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
2972 gtk_container_add (GTK_CONTAINER (b), px);
2973 // TRANSLATORS: `Center' here is a verb.
2974 gtk_tooltips_set_tip (tt, b, _("Center lines"), NULL);
2975 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
2976 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
2977 gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
2978 }
2980 // align right
2981 {
2982 GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
2983 GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
2984 gtk_container_add (GTK_CONTAINER (b), px);
2985 gtk_tooltips_set_tip (tt, b, _("Align lines right"), NULL);
2986 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
2987 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
2988 gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
2989 }
2991 // full justification
2992 {
2993 GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
2994 GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
2995 gtk_container_add (GTK_CONTAINER (b), px);
2996 gtk_tooltips_set_tip (tt, b, _("Full justification"), NULL);
2997 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
2998 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
2999 gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3000 }
3003 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3005 // horizontal
3006 {
3007 GtkWidget *px= sp_icon_new(Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR);
3008 GtkWidget *b = group = gtk_radio_button_new (NULL);
3009 gtk_container_add (GTK_CONTAINER (b), px);
3010 gtk_tooltips_set_tip (tt, b, _("Horizontal text"), NULL);
3011 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3012 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3013 gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3014 }
3016 // vertical
3017 {
3018 GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB);
3019 GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3020 gtk_container_add (GTK_CONTAINER (b), px);
3021 gtk_tooltips_set_tip (tt, b, _("Vertical text"), NULL);
3022 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3023 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3024 gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3025 }
3027 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3029 // letter spacing
3030 {
3031 {
3032 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LETTER_SPACING);
3033 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3034 gtk_container_add (GTK_CONTAINER (hb), image);
3035 gtk_widget_show(image);
3036 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3037 }
3039 {
3040 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between letters"),
3041 "tools.text", "letter_spacing", 0.0,
3042 us, tbl, FALSE, NULL,
3043 -1000.0, 1000.0, 0.1, 0.1,
3044 sp_text_letter_changed, 0.1, 1);
3045 gtk_widget_set_size_request (hb, 45, 6);
3046 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3047 }
3048 }
3050 // line spacing
3051 {
3052 {
3053 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LINE_SPACING);
3054 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3055 gtk_container_add (GTK_CONTAINER (hb), image);
3056 gtk_widget_show(image);
3057 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3058 }
3060 {
3061 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between lines"),
3062 "tools.text", "line_spacing", 0,
3063 us, tbl, FALSE, NULL,
3064 -1000.0, 1000.0, 0.1, 0.1,
3065 sp_text_line_changed, 0.1, 1);
3066 gtk_widget_set_size_request (hb, 45, 0);
3067 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 3);
3068 }
3069 }
3071 {
3072 // horizontal kerning/vertical kerning units menu: create
3073 GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
3074 sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
3075 sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
3077 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3079 // horizontal kerning
3080 {
3081 {
3082 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_HORZ_KERN);
3083 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3084 gtk_container_add (GTK_CONTAINER (hb), image);
3085 gtk_widget_show(image);
3086 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3087 }
3089 {
3090 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Horizontal kerning"),
3091 "tools.text", "horizontal_kerning", 0,
3092 us, tbl, FALSE, NULL,
3093 -100.00, 100.00, 0.01, 0.1,
3094 sp_text_horiz_kern_changed);
3095 gtk_widget_set_size_request (hb, 45, 0);
3096 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3097 }
3098 }
3100 // vertical kerning
3101 {
3102 {
3103 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_VERT_KERN);
3104 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3105 gtk_container_add (GTK_CONTAINER (hb), image);
3106 gtk_widget_show(image);
3107 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3108 }
3110 {
3111 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Vertical kerning"),
3112 "tools.text", "vertical_kerning", 0,
3113 us, tbl, FALSE, NULL,
3114 -100.00, 100.00, 0.01, 0.1,
3115 sp_text_vert_kern_changed);
3116 gtk_widget_set_size_request (hb, 45, 0);
3117 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 5);
3118 }
3119 }
3121 // add the units menu
3122 gtk_widget_show(us);
3123 gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, 1);
3124 gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
3125 }
3127 // letter rotation
3128 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3129 {
3130 {
3131 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_ROTATION);
3132 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3133 gtk_container_add (GTK_CONTAINER (hb), image);
3134 gtk_widget_show(image);
3135 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3136 }
3137 {
3138 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Letter rotation"),
3139 "tools.text", "letter_rotation", 0,
3140 us, tbl, FALSE, NULL,
3141 -180.0, 180.0, 0.1, 0.1,
3142 sp_text_letter_rotation_changed, 0.1, 1);
3143 gtk_widget_set_size_request (hb, 45, 0);
3144 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3145 }
3146 // rotation degree label
3147 {
3148 GtkWidget *label = gtk_widget_new (GTK_TYPE_LABEL, "label", "\302\260", "xalign", 0.0, NULL);
3149 gtk_box_pack_start(GTK_BOX(tbl), label, FALSE, FALSE, 0);
3150 }
3151 }
3153 // Remove Manual Kerns
3154 {
3155 GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_REMOVE_KERNS);
3156 GtkWidget *button = gtk_button_new ();
3157 gtk_container_add (GTK_CONTAINER (button), px);
3158 gtk_widget_show(button);
3159 gtk_tooltips_set_tip (tt, button, _("Remove manual kerns"), NULL);
3160 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
3161 gtk_widget_set_sensitive(button, TRUE);
3162 gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
3163 }
3164 #endif
3166 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
3167 swatch->setWatchedTool ("tools.text", true);
3168 GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
3169 gtk_box_pack_end (GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
3170 gtk_widget_show_all (tbl);
3172 return tbl;
3174 } // end of sp_text_toolbox_new()
3177 //#########################
3178 //## Connector Toolbox ##
3179 //#########################
3181 static void sp_connector_path_set_avoid(void)
3182 {
3183 cc_selection_set_avoid(true);
3184 }
3187 static void sp_connector_path_set_ignore(void)
3188 {
3189 cc_selection_set_avoid(false);
3190 }
3193 static void connector_spacing_changed(GtkAdjustment *adj, GtkWidget *tbl)
3194 {
3195 // quit if run by the _changed callbacks
3196 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
3197 return;
3198 }
3200 SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl),
3201 "desktop");
3202 SPDocument *doc = sp_desktop_document(desktop);
3204 if (!sp_document_get_undo_sensitive(doc))
3205 {
3206 return;
3207 }
3209 // in turn, prevent callbacks from responding
3210 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
3212 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
3214 sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
3215 SP_OBJECT(desktop->namedview)->updateRepr();
3217 GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
3218 for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
3219 SPItem *item = reinterpret_cast<SPItem *>(iter->data);
3220 NR::Matrix m = NR::identity();
3221 avoid_item_move(&m, item);
3222 }
3224 if (items) {
3225 g_slist_free(items);
3226 }
3228 sp_document_done(doc);
3230 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
3232 spinbutton_defocus(GTK_OBJECT(tbl));
3233 }
3236 static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
3237 gchar const *name, gchar const *old_value, gchar const *new_value,
3238 bool is_interactive, gpointer data)
3239 {
3240 GtkWidget *tbl = GTK_WIDGET(data);
3242 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
3243 return;
3244 }
3245 if (strcmp(name, "inkscape:connector-spacing") != 0) {
3246 return;
3247 }
3249 GtkAdjustment *adj = (GtkAdjustment*)
3250 gtk_object_get_data(GTK_OBJECT(tbl), "spacing");
3251 gdouble spacing = defaultConnSpacing;
3252 sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
3254 gtk_adjustment_set_value(adj, spacing);
3255 }
3258 static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
3259 NULL, /* child_added */
3260 NULL, /* child_removed */
3261 connector_tb_event_attr_changed,
3262 NULL, /* content_changed */
3263 NULL /* order_changed */
3264 };
3267 static GtkWidget *
3268 sp_connector_toolbox_new(SPDesktop *desktop)
3269 {
3270 GtkTooltips *tt = gtk_tooltips_new();
3271 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
3273 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
3274 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
3276 gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
3277 AUX_BETWEEN_BUTTON_GROUPS);
3279 sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
3280 "connector_avoid", GTK_SIGNAL_FUNC(sp_connector_path_set_avoid),
3281 tt, _("Make connectors avoid selected objects"));
3283 sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
3284 "connector_ignore", GTK_SIGNAL_FUNC(sp_connector_path_set_ignore),
3285 tt, _("Make connectors ignore selected objects"));
3287 // interval
3288 gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
3289 AUX_BETWEEN_BUTTON_GROUPS);
3291 // Spacing spinbox
3292 {
3293 GtkWidget *object_spacing = sp_tb_spinbutton(_("Spacing:"),
3294 _("The amount of space left around objects by auto-routing connectors"),
3295 "tools.connector", "spacing", 10, NULL, tbl, TRUE,
3296 "inkscape:connector-spacing", 0, 100, 1.0, 10.0,
3297 connector_spacing_changed, 1, 0);
3299 gtk_box_pack_start(GTK_BOX(tbl), object_spacing, FALSE, FALSE,
3300 AUX_SPACING);
3301 }
3303 gtk_widget_show_all(tbl);
3304 sp_set_font_size_smaller (tbl);
3306 // Code to watch for changes to the connector-spacing attribute in
3307 // the XML.
3308 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
3309 g_assert(repr != NULL);
3311 Inkscape::XML::Node *oldrepr = (Inkscape::XML::Node *)
3312 gtk_object_get_data(GTK_OBJECT(tbl), "repr");
3314 if (oldrepr) { // remove old listener
3315 sp_repr_remove_listener_by_data(oldrepr, tbl);
3316 Inkscape::GC::release(oldrepr);
3317 oldrepr = NULL;
3318 g_object_set_data(G_OBJECT(tbl), "repr", NULL);
3319 }
3321 if (repr) {
3322 g_object_set_data(G_OBJECT(tbl), "repr", repr);
3323 Inkscape::GC::anchor(repr);
3324 sp_repr_add_listener(repr, &connector_tb_repr_events, tbl);
3325 sp_repr_synthesize_events(repr, &connector_tb_repr_events, tbl);
3326 }
3328 return tbl;
3330 } // end of sp_connector_toolbox_new()
3333 /*
3334 Local Variables:
3335 mode:c++
3336 c-file-style:"stroustrup"
3337 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
3338 indent-tabs-mode:nil
3339 fill-column:99
3340 End:
3341 */
3342 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :