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"
72 #include "../connection-pool.h"
74 #include "mod360.h"
76 #include "toolbox.h"
78 typedef void (*SetupFunction)(GtkWidget *toolbox, SPDesktop *desktop);
79 typedef void (*UpdateFunction)(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
81 static GtkWidget *sp_node_toolbox_new(SPDesktop *desktop);
82 static GtkWidget *sp_zoom_toolbox_new(SPDesktop *desktop);
83 static GtkWidget *sp_star_toolbox_new(SPDesktop *desktop);
84 static GtkWidget *sp_arc_toolbox_new(SPDesktop *desktop);
85 static GtkWidget *sp_rect_toolbox_new(SPDesktop *desktop);
86 static GtkWidget *sp_spiral_toolbox_new(SPDesktop *desktop);
87 static GtkWidget *sp_pencil_toolbox_new(SPDesktop *desktop);
88 static GtkWidget *sp_pen_toolbox_new(SPDesktop *desktop);
89 static GtkWidget *sp_calligraphy_toolbox_new(SPDesktop *desktop);
90 static GtkWidget *sp_dropper_toolbox_new(SPDesktop *desktop);
91 static GtkWidget *sp_empty_toolbox_new(SPDesktop *desktop);
92 static GtkWidget *sp_connector_toolbox_new(SPDesktop *desktop);
94 namespace { GtkWidget *sp_text_toolbox_new (SPDesktop *desktop); }
97 static struct {
98 gchar const *type_name;
99 gchar const *data_name;
100 sp_verb_t verb;
101 sp_verb_t doubleclick_verb;
102 } const tools[] = {
103 { "SPSelectContext", "select_tool", SP_VERB_CONTEXT_SELECT, SP_VERB_CONTEXT_SELECT_PREFS},
104 { "SPNodeContext", "node_tool", SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS },
105 { "SPZoomContext", "zoom_tool", SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS },
106 { "SPRectContext", "rect_tool", SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS },
107 { "SPArcContext", "arc_tool", SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS },
108 { "SPStarContext", "star_tool", SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS },
109 { "SPSpiralContext", "spiral_tool", SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS },
110 { "SPPencilContext", "pencil_tool", SP_VERB_CONTEXT_PENCIL, SP_VERB_CONTEXT_PENCIL_PREFS },
111 { "SPPenContext", "pen_tool", SP_VERB_CONTEXT_PEN, SP_VERB_CONTEXT_PEN_PREFS },
112 { "SPDynaDrawContext", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS },
113 { "SPTextContext", "text_tool", SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS },
114 { "SPConnectorContext","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS },
115 { "SPGradientContext", "gradient_tool", SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS },
116 { "SPDropperContext", "dropper_tool", SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_DROPPER_PREFS },
117 { NULL, NULL, 0, 0 }
118 };
120 static struct {
121 gchar const *type_name;
122 gchar const *data_name;
123 GtkWidget *(*create_func)(SPDesktop *desktop);
124 } const aux_toolboxes[] = {
125 { "SPSelectContext", "select_toolbox", sp_select_toolbox_new },
126 { "SPNodeContext", "node_toolbox", sp_node_toolbox_new },
127 { "SPZoomContext", "zoom_toolbox", sp_zoom_toolbox_new },
128 { "SPStarContext", "star_toolbox", sp_star_toolbox_new },
129 { "SPRectContext", "rect_toolbox", sp_rect_toolbox_new },
130 { "SPArcContext", "arc_toolbox", sp_arc_toolbox_new },
131 { "SPSpiralContext", "spiral_toolbox", sp_spiral_toolbox_new },
132 { "SPPencilContext", "pencil_toolbox", sp_pencil_toolbox_new },
133 { "SPPenContext", "pen_toolbox", sp_pen_toolbox_new },
134 { "SPDynaDrawContext", "calligraphy_toolbox", sp_calligraphy_toolbox_new },
135 { "SPTextContext", "text_toolbox", sp_text_toolbox_new },
136 { "SPDropperContext", "dropper_toolbox", sp_dropper_toolbox_new },
137 { "SPGradientContext", "gradient_toolbox", sp_gradient_toolbox_new },
138 { "SPConnectorContext", "connector_toolbox", sp_connector_toolbox_new },
139 { NULL, NULL, NULL }
140 };
142 static void toolbox_set_desktop (GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection*);
144 static void setup_tool_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
145 static void update_tool_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
147 static void setup_aux_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
148 static void update_aux_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
150 static void setup_commands_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
151 static void update_commands_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
153 /* Global text entry widgets necessary for update */
154 /* GtkWidget *dropper_rgb_entry,
155 *dropper_opacity_entry ; */
156 // should be made a private member once this is converted to class
158 static void delete_connection(GObject *obj, sigc::connection *connection) {
159 connection->disconnect();
160 delete connection;
161 }
163 static GtkWidget *
164 sp_toolbox_button_new(GtkWidget *t, Inkscape::IconSize size, gchar const *pxname, GtkSignalFunc handler,
165 GtkTooltips *tt, gchar const *tip)
166 {
167 GtkWidget *b = sp_button_new_from_data(size, SP_BUTTON_TYPE_NORMAL, NULL, pxname, tip, tt);
168 gtk_widget_show(b);
169 if (handler) gtk_signal_connect(GTK_OBJECT(b), "clicked", handler, NULL);
170 gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
172 return b;
173 }
175 GtkWidget *
176 sp_toolbox_button_new_from_verb_with_doubleclick(GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
177 Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
178 Inkscape::UI::View::View *view, GtkTooltips *tt)
179 {
180 SPAction *action = verb->get_action(view);
181 if (!action) return NULL;
183 SPAction *doubleclick_action;
184 if (doubleclick_verb)
185 doubleclick_action = doubleclick_verb->get_action(view);
186 else
187 doubleclick_action = NULL;
189 /* fixme: Handle sensitive/unsensitive */
190 /* fixme: Implement sp_button_new_from_action */
191 GtkWidget *b = sp_button_new(size, type, action, doubleclick_action, tt);
192 gtk_widget_show(b);
193 gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
195 return b;
196 }
198 GtkWidget *sp_toolbox_button_new_from_verb(GtkWidget *t, Inkscape::IconSize size, SPButtonType type, Inkscape::Verb *verb,
199 Inkscape::UI::View::View *view, GtkTooltips *tt)
200 {
201 return sp_toolbox_button_new_from_verb_with_doubleclick(t, size, type, verb, NULL, view, tt);
202 }
204 GtkWidget * sp_toolbox_button_normal_new_from_verb(GtkWidget *t, Inkscape::IconSize size, Inkscape::Verb *verb,
205 Inkscape::UI::View::View *view, GtkTooltips *tt)
206 {
207 return sp_toolbox_button_new_from_verb(t, size, SP_BUTTON_TYPE_NORMAL, verb, view, tt);
208 }
210 GtkWidget *
211 sp_tool_toolbox_new()
212 {
213 GtkTooltips *tt = gtk_tooltips_new();
214 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
216 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
217 g_object_set_data(G_OBJECT(tb), "tooltips", tt);
219 gtk_widget_set_sensitive(tb, FALSE);
221 GtkWidget *hb = gtk_handle_box_new();
222 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_TOP);
223 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
224 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
226 gtk_container_add(GTK_CONTAINER(hb), tb);
227 gtk_widget_show(GTK_WIDGET(tb));
229 sigc::connection* conn = new sigc::connection;
230 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
232 return hb;
233 }
235 static void
236 aux_toolbox_attached(GtkHandleBox *toolbox, GtkWidget *child)
237 {
238 g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(FALSE));
239 gtk_widget_queue_resize(child);
240 }
242 static void
243 aux_toolbox_detached(GtkHandleBox *toolbox, GtkWidget *child)
244 {
245 g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(TRUE));
246 gtk_widget_queue_resize(child);
247 }
249 GtkWidget *
250 sp_aux_toolbox_new()
251 {
252 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
254 GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
255 GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
256 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
257 gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
258 gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
260 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
261 g_object_set_data(G_OBJECT(tb), "top_spacer", tb_s);
263 gtk_widget_set_sensitive(tb, FALSE);
265 GtkWidget *hb = gtk_handle_box_new();
266 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
267 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
268 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
270 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
271 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
273 gtk_container_add(GTK_CONTAINER(hb), tb);
274 gtk_widget_show(GTK_WIDGET(tb));
276 sigc::connection* conn = new sigc::connection;
277 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
279 return hb;
280 }
282 //####################################
283 //# Commands Bar
284 //####################################
286 GtkWidget *
287 sp_commands_toolbox_new()
288 {
289 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
291 GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
292 GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
293 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
294 gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
295 gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
297 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
298 gtk_widget_set_sensitive(tb, FALSE);
300 GtkWidget *hb = gtk_handle_box_new();
301 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
302 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
303 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
305 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
306 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
308 gtk_container_add(GTK_CONTAINER(hb), tb);
309 gtk_widget_show(GTK_WIDGET(tb));
311 sigc::connection* conn = new sigc::connection;
312 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
314 return hb;
315 }
318 //####################################
319 //# node editing callbacks
320 //####################################
322 void
323 sp_node_path_edit_add(void)
324 {
325 sp_node_selected_add_node();
326 }
328 void
329 sp_node_path_edit_delete(void)
330 {
331 sp_node_selected_delete();
332 }
334 void
335 sp_node_path_edit_delete_segment(void)
336 {
337 sp_node_selected_delete_segment();
338 }
340 void
341 sp_node_path_edit_break(void)
342 {
343 sp_node_selected_break();
344 }
346 void
347 sp_node_path_edit_join(void)
348 {
349 sp_node_selected_join();
350 }
352 void
353 sp_node_path_edit_join_segment(void)
354 {
355 sp_node_selected_join_segment();
356 }
358 void
359 sp_node_path_edit_toline(void)
360 {
361 sp_node_selected_set_line_type(NR_LINETO);
362 }
364 void
365 sp_node_path_edit_tocurve(void)
366 {
367 sp_node_selected_set_line_type(NR_CURVETO);
368 }
370 void
371 sp_node_path_edit_cusp(void)
372 {
373 sp_node_selected_set_type(Inkscape::NodePath::NODE_CUSP);
374 }
376 void
377 sp_node_path_edit_smooth(void)
378 {
379 sp_node_selected_set_type(Inkscape::NodePath::NODE_SMOOTH);
380 }
382 void
383 sp_node_path_edit_symmetrical(void)
384 {
385 sp_node_selected_set_type(Inkscape::NodePath::NODE_SYMM);
386 }
388 static void toggle_show_handles (GtkWidget *button, gpointer data) {
389 bool show = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
390 prefs_set_int_attribute ("tools.nodes", "show_handles", show ? 1 : 0);
391 sp_nodepath_show_handles(show);
392 }
394 //################################
395 //## Node Editing Toolbox ##
396 //################################
398 static GtkWidget *
399 sp_node_toolbox_new(SPDesktop *desktop)
400 {
401 Inkscape::UI::View::View *view = desktop;
403 GtkTooltips *tt = gtk_tooltips_new();
404 GtkWidget *tb = gtk_hbox_new(FALSE, 0);
406 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
408 sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_insert",
409 GTK_SIGNAL_FUNC(sp_node_path_edit_add), tt, _("Insert new nodes into selected segments"));
410 sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_delete",
411 GTK_SIGNAL_FUNC(sp_node_path_edit_delete), tt, _("Delete selected nodes"));
413 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
415 sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_join",
416 GTK_SIGNAL_FUNC(sp_node_path_edit_join), tt, _("Join selected endnodes"));
417 sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_join_segment",
418 GTK_SIGNAL_FUNC(sp_node_path_edit_join_segment), tt, _("Join selected endnodes with a new segment"));
420 sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_delete_segment",
421 GTK_SIGNAL_FUNC(sp_node_path_edit_delete_segment), tt, _("Split path between two non-endpoint nodes"));
423 sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_break",
424 GTK_SIGNAL_FUNC(sp_node_path_edit_break), tt, _("Break path at selected nodes"));
426 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
428 sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_cusp",
429 GTK_SIGNAL_FUNC(sp_node_path_edit_cusp), tt, _("Make selected nodes corner"));
431 sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_smooth",
432 GTK_SIGNAL_FUNC(sp_node_path_edit_smooth), tt, _("Make selected nodes smooth"));
434 sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_symmetric",
435 GTK_SIGNAL_FUNC(sp_node_path_edit_symmetrical), tt, _("Make selected nodes symmetric"));
437 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
439 sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_line",
440 GTK_SIGNAL_FUNC(sp_node_path_edit_toline), tt, _("Make selected segments lines"));
442 sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_curve",
443 GTK_SIGNAL_FUNC(sp_node_path_edit_tocurve), tt, _("Make selected segments curves"));
445 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
447 sp_toolbox_button_normal_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, Inkscape::Verb::get(SP_VERB_OBJECT_TO_CURVE), view, tt);
449 sp_toolbox_button_normal_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, Inkscape::Verb::get(SP_VERB_SELECTION_OUTLINE), view, tt);
451 aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
453 GtkWidget *cvbox = gtk_vbox_new (FALSE, 0);
454 GtkWidget *cbox = gtk_hbox_new (FALSE, 0);
456 {
457 GtkWidget *button = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
458 SP_BUTTON_TYPE_TOGGLE,
459 NULL,
460 "nodes_show_handles",
461 _("Show the Bezier handles of selected nodes"),
462 tt);
463 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), prefs_get_int_attribute ("tools.nodes", "show_handles", 1));
464 g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (toggle_show_handles), desktop);
465 gtk_box_pack_start(GTK_BOX(cbox), button, FALSE, FALSE, 0);
466 }
468 gtk_box_pack_start(GTK_BOX(cvbox), cbox, TRUE, FALSE, 0);
469 gtk_box_pack_start(GTK_BOX(tb), cvbox, FALSE, FALSE, 0);
471 gtk_widget_show_all(tb);
473 return tb;
475 } // end of sp_node_toolbox_new()
478 //########################
479 //## Zoom Toolbox ##
480 //########################
482 static GtkWidget *
483 sp_zoom_toolbox_new(SPDesktop *desktop)
484 {
485 Inkscape::UI::View::View *view=desktop;
487 GtkTooltips *tt = gtk_tooltips_new();
488 GtkWidget *tb = gtk_hbox_new(FALSE, 0);
490 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0),
491 FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
493 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);
495 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);
497 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
499 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);
501 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);
503 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);
505 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);
507 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
509 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);
511 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);
513 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
515 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);
517 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);
519 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);
521 gtk_widget_show_all(tb);
523 return tb;
525 } // end of sp_zoom_toolbox_new()
527 void
528 sp_tool_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
529 {
530 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")));
531 }
534 void
535 sp_aux_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
536 {
537 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")));
538 }
540 void
541 sp_commands_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
542 {
543 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")));
544 }
546 static void
547 toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection *conn)
548 {
549 gpointer ptr = g_object_get_data(G_OBJECT(toolbox), "desktop");
550 SPDesktop *old_desktop = static_cast<SPDesktop*>(ptr);
552 if (old_desktop) {
553 GList *children, *iter;
555 children = gtk_container_get_children(GTK_CONTAINER(toolbox));
556 for ( iter = children ; iter ; iter = iter->next ) {
557 gtk_container_remove( GTK_CONTAINER(toolbox), GTK_WIDGET(iter->data) );
558 }
559 g_list_free(children);
560 }
562 g_object_set_data(G_OBJECT(toolbox), "desktop", (gpointer)desktop);
564 if (desktop) {
565 gtk_widget_set_sensitive(toolbox, TRUE);
566 setup_func(toolbox, desktop);
567 update_func(desktop, desktop->event_context, toolbox);
568 *conn = desktop->connectEventContextChanged
569 (sigc::bind (sigc::ptr_fun(update_func), toolbox));
570 } else {
571 gtk_widget_set_sensitive(toolbox, FALSE);
572 }
574 } // end of toolbox_set_desktop()
577 static void
578 setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
579 {
580 GtkTooltips *tooltips=GTK_TOOLTIPS(g_object_get_data(G_OBJECT(toolbox), "tooltips"));
581 gint shrinkLeft = prefs_get_int_attribute_limited( "toolbox.left", "small", 0, 0, 1 );
582 Inkscape::IconSize toolboxSize = shrinkLeft ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
584 for (int i = 0 ; tools[i].type_name ; i++ ) {
585 GtkWidget *button =
586 sp_toolbox_button_new_from_verb_with_doubleclick( toolbox, toolboxSize,
587 SP_BUTTON_TYPE_TOGGLE,
588 Inkscape::Verb::get(tools[i].verb),
589 Inkscape::Verb::get(tools[i].doubleclick_verb),
590 desktop,
591 tooltips );
593 g_object_set_data( G_OBJECT(toolbox), tools[i].data_name,
594 (gpointer)button );
595 }
596 }
599 static void
600 update_tool_toolbox( SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox )
601 {
602 gchar const *const tname = ( eventcontext
603 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
604 : NULL );
605 for (int i = 0 ; tools[i].type_name ; i++ ) {
606 SPButton *button = SP_BUTTON(g_object_get_data(G_OBJECT(toolbox), tools[i].data_name));
607 sp_button_toggle_set_down(button, tname && !strcmp(tname, tools[i].type_name));
608 }
609 }
611 static void
612 setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
613 {
614 GtkSizeGroup* grouper = gtk_size_group_new( GTK_SIZE_GROUP_BOTH );
616 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
617 GtkWidget *sub_toolbox;
618 if (aux_toolboxes[i].create_func == NULL)
619 sub_toolbox = sp_empty_toolbox_new(desktop);
620 else
621 sub_toolbox = aux_toolboxes[i].create_func(desktop);
623 gtk_size_group_add_widget( grouper, sub_toolbox );
625 gtk_container_add(GTK_CONTAINER(toolbox), sub_toolbox);
626 g_object_set_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name, sub_toolbox);
627 }
628 g_object_unref( G_OBJECT(grouper) );
629 }
631 static void
632 update_aux_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
633 {
634 gchar const *tname = ( eventcontext
635 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
636 : NULL );
637 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
638 GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name));
639 if (tname && !strcmp(tname, aux_toolboxes[i].type_name)) {
640 gtk_widget_show_all(sub_toolbox);
641 g_object_set_data(G_OBJECT(toolbox), "shows", sub_toolbox);
642 } else {
643 gtk_widget_hide(sub_toolbox);
644 }
645 }
646 }
648 static void
649 setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
650 {
651 Inkscape::UI::View::View *view = desktop;
653 GtkTooltips *tt = gtk_tooltips_new();
654 GtkWidget *tb = gtk_hbox_new(FALSE, 0);
656 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
657 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
659 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_NEW), view, tt);
660 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_OPEN), view, tt);
661 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_SAVE), view, tt);
662 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_PRINT), view, tt);
664 aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
666 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_IMPORT), view, tt);
667 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_EXPORT), view, tt);
669 aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
671 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_UNDO), view, tt);
672 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_REDO), view, tt);
674 aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
676 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_COPY), view, tt);
677 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_CUT), view, tt);
678 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_PASTE), view, tt);
680 aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
682 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_SELECTION), view, tt);
683 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_DRAWING), view, tt);
684 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_PAGE), view, tt);
686 aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
688 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_DUPLICATE), view, tt);
689 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_CLONE), view, tt);
690 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_UNLINK_CLONE), view, tt);
692 aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
694 sp_toolbox_button_normal_new_from_verb(tb, toolboxSize, Inkscape::Verb::get(SP_VERB_SELECTION_GROUP), view, tt);
695 sp_toolbox_button_normal_new_from_verb(tb, toolboxSize, Inkscape::Verb::get(SP_VERB_SELECTION_UNGROUP), view, tt);
697 // disabled until we have icons for them:
699 //find
701 //sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_TILE), view, tt);
702 //sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_UNTILE), view, tt);
704 aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
706 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_FILL_STROKE), view, tt);
707 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_TEXT), view, tt);
708 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_XML_EDITOR), view, tt);
709 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_ALIGN_DISTRIBUTE), view, tt);
711 aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
713 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_DISPLAY), view, tt);
714 sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_NAMEDVIEW), view, tt);
716 gtk_widget_show_all(tb);
718 gtk_container_add(GTK_CONTAINER(toolbox), tb);
719 }
721 static void
722 update_commands_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
723 {
724 }
726 void show_aux_toolbox(GtkWidget *toolbox_toplevel)
727 {
728 gtk_widget_show(toolbox_toplevel);
729 GtkWidget *toolbox = gtk_bin_get_child(GTK_BIN(toolbox_toplevel));
731 GtkWidget *shown_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "shows"));
732 if (!shown_toolbox) {
733 return;
734 }
735 gtk_widget_show(toolbox);
737 // need to show the spacer, or the padding will be off
738 GtkWidget *spacer = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "top_spacer"));
739 gtk_widget_show(spacer);
741 gtk_widget_show_all(shown_toolbox);
742 }
744 void
745 aux_toolbox_space(GtkWidget *tb, gint space)
746 {
747 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, space);
748 }
750 static GtkWidget *
751 sp_empty_toolbox_new(SPDesktop *desktop)
752 {
753 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
754 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
755 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
757 gtk_widget_show_all(tbl);
758 sp_set_font_size_smaller (tbl);
760 return tbl;
761 }
763 // helper UI functions
765 GtkWidget *
766 sp_tb_spinbutton(
767 gchar *label, gchar const *tooltip,
768 gchar const *path, gchar const *data, gdouble def,
769 GtkWidget *us,
770 GtkWidget *tbl,
771 gboolean altx, gchar const *altx_mark,
772 gdouble lower, gdouble upper, gdouble step, gdouble page,
773 void (*callback)(GtkAdjustment *, GtkWidget *),
774 gdouble climb = 0.1, guint digits = 3, double factor = 1.0)
775 {
776 GtkTooltips *tt = gtk_tooltips_new();
778 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
780 GtkWidget *l = gtk_label_new(label);
781 gtk_widget_show(l);
782 gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
783 gtk_container_add(GTK_CONTAINER(hb), l);
785 GtkObject *a = gtk_adjustment_new(prefs_get_double_attribute(path, data, def) * factor,
786 lower, upper, step, page, page);
787 gtk_object_set_data(GTK_OBJECT(tbl), data, a);
788 if (us)
789 sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(us), GTK_ADJUSTMENT(a));
791 GtkWidget *sb = gtk_spin_button_new(GTK_ADJUSTMENT(a), climb, digits);
792 gtk_tooltips_set_tip(tt, sb, tooltip, NULL);
793 if (altx)
794 gtk_object_set_data(GTK_OBJECT(sb), altx_mark, sb);
795 gtk_widget_set_size_request(sb,
796 (upper <= 1.0 || digits == 0)? AUX_SPINBUTTON_WIDTH_SMALL - 10: AUX_SPINBUTTON_WIDTH_SMALL,
797 AUX_SPINBUTTON_HEIGHT);
798 gtk_widget_show(sb);
799 gtk_signal_connect(GTK_OBJECT(sb), "focus-in-event", GTK_SIGNAL_FUNC(spinbutton_focus_in), tbl);
800 gtk_signal_connect(GTK_OBJECT(sb), "key-press-event", GTK_SIGNAL_FUNC(spinbutton_keypress), tbl);
801 gtk_container_add(GTK_CONTAINER(hb), sb);
802 gtk_signal_connect(GTK_OBJECT(a), "value_changed", GTK_SIGNAL_FUNC(callback), tbl);
804 return hb;
805 }
807 #define MODE_LABEL_WIDTH 70
809 //########################
810 //## Star ##
811 //########################
813 static void
814 sp_stb_magnitude_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
815 {
816 SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
818 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
819 // do not remember prefs if this call is initiated by an undo change, because undoing object
820 // creation sets bogus values to its attributes before it is deleted
821 prefs_set_int_attribute("tools.shapes.star", "magnitude", (gint)adj->value);
822 }
824 // quit if run by the attr_changed listener
825 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
826 return;
827 }
829 // in turn, prevent listener from responding
830 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
832 bool modmade = false;
834 Inkscape::Selection *selection = sp_desktop_selection(desktop);
835 GSList const *items = selection->itemList();
836 for (; items != NULL; items = items->next) {
837 if (SP_IS_STAR((SPItem *) items->data)) {
838 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
839 sp_repr_set_int(repr,"sodipodi:sides",(gint)adj->value);
840 sp_repr_set_svg_double(repr, "sodipodi:arg2",
841 (sp_repr_get_double_attribute(repr, "sodipodi:arg1", 0.5)
842 + M_PI / (gint)adj->value));
843 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
844 modmade = true;
845 }
846 }
847 if (modmade) sp_document_done(sp_desktop_document(desktop));
849 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
851 spinbutton_defocus(GTK_OBJECT(tbl));
852 }
854 static void
855 sp_stb_proportion_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
856 {
857 SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
859 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
860 prefs_set_double_attribute("tools.shapes.star", "proportion", adj->value);
861 }
863 // quit if run by the attr_changed listener
864 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
865 return;
866 }
868 // in turn, prevent listener from responding
869 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
871 bool modmade = false;
872 Inkscape::Selection *selection = sp_desktop_selection(desktop);
873 GSList const *items = selection->itemList();
874 for (; items != NULL; items = items->next) {
875 if (SP_IS_STAR((SPItem *) items->data)) {
876 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
878 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
879 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
880 if (r2 < r1) {
881 sp_repr_set_svg_double(repr, "sodipodi:r2", r1*adj->value);
882 } else {
883 sp_repr_set_svg_double(repr, "sodipodi:r1", r2*adj->value);
884 }
886 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
887 modmade = true;
888 }
889 }
891 if (modmade) sp_document_done(sp_desktop_document(desktop));
893 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
895 spinbutton_defocus(GTK_OBJECT(tbl));
896 }
898 static void
899 sp_stb_sides_flat_state_changed(GtkWidget *widget, GtkObject *tbl)
900 {
901 SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
903 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
904 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
905 prefs_set_string_attribute("tools.shapes.star", "isflatsided", "true");
906 } else {
907 prefs_set_string_attribute("tools.shapes.star", "isflatsided", "false");
908 }
909 }
911 // quit if run by the attr_changed listener
912 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
913 return;
914 }
916 // in turn, prevent listener from responding
917 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
919 Inkscape::Selection *selection = sp_desktop_selection(desktop);
920 GSList const *items = selection->itemList();
921 GtkWidget *prop_widget = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "prop_widget");
922 bool modmade = false;
923 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
924 gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), FALSE);
925 for (; items != NULL; items = items->next) {
926 if (SP_IS_STAR((SPItem *) items->data)) {
927 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
928 repr->setAttribute("inkscape:flatsided", "true");
929 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
930 modmade = true;
931 }
932 }
933 } else {
934 gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), TRUE);
935 for (; items != NULL; items = items->next) {
936 if (SP_IS_STAR((SPItem *) items->data)) {
937 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
938 repr->setAttribute("inkscape:flatsided", "false");
939 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
940 modmade = true;
941 }
942 }
943 }
944 if (modmade) sp_document_done(sp_desktop_document(desktop));
946 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
948 spinbutton_defocus(GTK_OBJECT(tbl));
949 }
951 static void
952 sp_stb_rounded_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
953 {
954 SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
956 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
957 prefs_set_double_attribute("tools.shapes.star", "rounded", (gdouble) adj->value);
958 }
960 // quit if run by the attr_changed listener
961 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
962 return;
963 }
965 // in turn, prevent listener from responding
966 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
968 bool modmade = false;
970 Inkscape::Selection *selection = sp_desktop_selection(desktop);
971 GSList const *items = selection->itemList();
972 for (; items != NULL; items = items->next) {
973 if (SP_IS_STAR((SPItem *) items->data)) {
974 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
975 sp_repr_set_svg_double(repr, "inkscape:rounded", (gdouble) adj->value);
976 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
977 modmade = true;
978 }
979 }
980 if (modmade) sp_document_done(sp_desktop_document(desktop));
982 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
984 spinbutton_defocus(GTK_OBJECT(tbl));
985 }
988 static void
989 sp_stb_randomized_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
990 {
991 SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
993 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
994 prefs_set_double_attribute("tools.shapes.star", "randomized", (gdouble) adj->value);
995 }
997 // quit if run by the attr_changed listener
998 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
999 return;
1000 }
1002 // in turn, prevent listener from responding
1003 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1005 bool modmade = false;
1007 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1008 GSList const *items = selection->itemList();
1009 for (; items != NULL; items = items->next) {
1010 if (SP_IS_STAR((SPItem *) items->data)) {
1011 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1012 sp_repr_set_svg_double(repr, "inkscape:randomized", (gdouble) adj->value);
1013 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1014 modmade = true;
1015 }
1016 }
1017 if (modmade) sp_document_done(sp_desktop_document(desktop));
1019 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1021 spinbutton_defocus(GTK_OBJECT(tbl));
1022 }
1025 static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1026 gchar const *old_value, gchar const *new_value,
1027 bool is_interactive, gpointer data)
1028 {
1029 GtkWidget *tbl = GTK_WIDGET(data);
1031 // quit if run by the _changed callbacks
1032 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1033 return;
1034 }
1036 // in turn, prevent callbacks from responding
1037 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1039 GtkAdjustment *adj;
1041 if (!strcmp(name, "inkscape:randomized")) {
1042 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "randomized");
1043 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:randomized", 0.0));
1044 } else if (!strcmp(name, "inkscape:rounded")) {
1045 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "rounded");
1046 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:rounded", 0.0));
1047 } else if (!strcmp(name, "inkscape:flatsided")) {
1048 GtkWidget *fscb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "flat_checkbox");
1049 GtkWidget *prop_widget = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "prop_widget");
1050 char const *flatsides = repr->attribute("inkscape:flatsided");
1051 if (flatsides && !strcmp(flatsides,"false" )) {
1052 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb), FALSE);
1053 gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), TRUE);
1054 } else {
1055 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb), TRUE);
1056 gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), FALSE);
1057 }
1058 } else if (!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) {
1059 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1060 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1061 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1062 if (r2 < r1) {
1063 gtk_adjustment_set_value(adj, r2/r1);
1064 } else {
1065 gtk_adjustment_set_value(adj, r1/r2);
1066 }
1067 } else if (!strcmp(name, "sodipodi:sides")) {
1068 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1069 gtk_adjustment_set_value(adj, sp_repr_get_int_attribute(repr, "sodipodi:sides", 0));
1070 }
1072 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1073 }
1076 static Inkscape::XML::NodeEventVector star_tb_repr_events =
1077 {
1078 NULL, /* child_added */
1079 NULL, /* child_removed */
1080 star_tb_event_attr_changed,
1081 NULL, /* content_changed */
1082 NULL /* order_changed */
1083 };
1086 /**
1087 * \param selection Should not be NULL.
1088 */
1089 static void
1090 sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1091 {
1092 int n_selected = 0;
1093 Inkscape::XML::Node *repr = NULL;
1094 Inkscape::XML::Node *oldrepr = NULL;
1096 for (GSList const *items = selection->itemList();
1097 items != NULL;
1098 items = items->next)
1099 {
1100 if (SP_IS_STAR((SPItem *) items->data)) {
1101 n_selected++;
1102 repr = SP_OBJECT_REPR((SPItem *) items->data);
1103 }
1104 }
1106 GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
1108 if (n_selected == 0) {
1109 gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
1110 } else if (n_selected == 1) {
1111 gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1113 oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1114 if (oldrepr) { // remove old listener
1115 sp_repr_remove_listener_by_data(oldrepr, tbl);
1116 Inkscape::GC::release(oldrepr);
1117 oldrepr = 0;
1118 g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1119 }
1121 if (repr) {
1122 g_object_set_data(G_OBJECT(tbl), "repr", repr);
1123 Inkscape::GC::anchor(repr);
1124 sp_repr_add_listener(repr, &star_tb_repr_events, tbl);
1125 sp_repr_synthesize_events(repr, &star_tb_repr_events, tbl);
1126 }
1127 } else {
1128 // FIXME: implement averaging of all parameters for multiple selected stars
1129 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1130 gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1131 }
1132 }
1135 static void
1136 sp_stb_defaults(GtkWidget *widget, GtkWidget *tbl)
1137 {
1138 // FIXME: in this and all other _default functions, set some flag telling the value_changed
1139 // callbacks to lump all the changes for all selected objects in one undo step
1141 GtkAdjustment *adj;
1143 // fixme: make settable in prefs!
1144 gint mag = 5;
1145 gdouble prop = 0.5;
1146 gboolean flat = FALSE;
1147 gdouble randomized = 0;
1148 gdouble rounded = 0;
1150 GtkWidget *fscb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "flat_checkbox");
1151 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb), flat);
1152 GtkWidget *sb2 = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "prop_widget");
1153 gtk_widget_set_sensitive(GTK_WIDGET(sb2), !flat);
1155 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1156 gtk_adjustment_set_value(adj, mag);
1157 gtk_adjustment_value_changed(adj);
1159 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1160 gtk_adjustment_set_value(adj, prop);
1161 gtk_adjustment_value_changed(adj);
1163 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "rounded");
1164 gtk_adjustment_set_value(adj, rounded);
1165 gtk_adjustment_value_changed(adj);
1167 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "randomized");
1168 gtk_adjustment_set_value(adj, randomized);
1169 gtk_adjustment_value_changed(adj);
1171 spinbutton_defocus(GTK_OBJECT(tbl));
1172 }
1175 void
1176 sp_toolbox_add_label(GtkWidget *tbl, gchar const *title, bool wide)
1177 {
1178 GtkWidget *boxl = gtk_hbox_new(FALSE, 0);
1179 if (wide) gtk_widget_set_size_request(boxl, MODE_LABEL_WIDTH, -1);
1180 GtkWidget *l = gtk_label_new(NULL);
1181 gtk_label_set_markup(GTK_LABEL(l), title);
1182 gtk_box_pack_end(GTK_BOX(boxl), l, FALSE, FALSE, 0);
1183 gtk_box_pack_start(GTK_BOX(tbl), boxl, FALSE, FALSE, 0);
1184 gtk_object_set_data(GTK_OBJECT(tbl), "mode_label", l);
1185 }
1188 static GtkWidget *
1189 sp_star_toolbox_new(SPDesktop *desktop)
1190 {
1191 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1193 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1194 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1196 GtkTooltips *tt = gtk_tooltips_new();
1198 sp_toolbox_add_label(tbl, _("<b>New:</b>"));
1200 gchar const *flatsidedstr = NULL;
1202 /* Flatsided checkbox */
1203 {
1204 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1205 GtkWidget *fscb = gtk_check_button_new_with_label(_("Polygon"));
1206 gtk_widget_set_sensitive(GTK_WIDGET(fscb), TRUE);
1207 flatsidedstr = prefs_get_string_attribute("tools.shapes.star", "isflatsided");
1208 if (!flatsidedstr || (flatsidedstr && !strcmp(flatsidedstr, "false")))
1209 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb), FALSE);
1210 else
1211 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb), TRUE);
1212 gtk_tooltips_set_tip(tt, fscb, _("Regular polygon (with one handle) instead of a star"), NULL);
1213 gtk_widget_show(fscb);
1214 gtk_object_set_data(GTK_OBJECT(tbl), "flat_checkbox", fscb);
1215 gtk_container_add(GTK_CONTAINER(hb), fscb);
1216 g_signal_connect(G_OBJECT(fscb), "toggled", GTK_SIGNAL_FUNC(sp_stb_sides_flat_state_changed ), tbl);
1217 gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_SPACING);
1218 }
1220 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
1222 /* Magnitude */
1223 {
1224 GtkWidget *hb = sp_tb_spinbutton(_("Corners:"), _("Number of corners of a polygon or star"),
1225 "tools.shapes.star", "magnitude", 3,
1226 NULL, tbl, TRUE, "altx-star",
1227 3, 1024, 1, 1,
1228 sp_stb_magnitude_value_changed, 1, 0);
1229 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1230 }
1232 /* Spoke ratio */
1233 {
1234 GtkWidget *hb = sp_tb_spinbutton(_("Spoke ratio:"),
1235 // TRANSLATORS: Tip radius of a star is the distance from the center to the farthest handle.
1236 // Base radius is the same for the closest handle.
1237 _("Base radius to tip radius ratio"),
1238 "tools.shapes.star", "proportion", 0.5,
1239 NULL, tbl, FALSE, NULL,
1240 0.01, 1.0, 0.01, 0.1,
1241 sp_stb_proportion_value_changed);
1242 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1243 g_object_set_data(G_OBJECT(tbl), "prop_widget", hb);
1244 if (!flatsidedstr || (flatsidedstr && !strcmp(flatsidedstr, "false")))
1245 gtk_widget_set_sensitive(GTK_WIDGET(hb), TRUE);
1246 else
1247 gtk_widget_set_sensitive(GTK_WIDGET(hb), FALSE);
1248 }
1250 /* Roundedness */
1251 {
1252 GtkWidget *hb = sp_tb_spinbutton(_("Rounded:"), _("How much rounded are the corners (0 for sharp)"),
1253 "tools.shapes.star", "rounded", 0.0,
1254 NULL, tbl, FALSE, NULL,
1255 -100.0, 100.0, 0.01, 0.1,
1256 sp_stb_rounded_value_changed);
1257 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1258 }
1260 /* Randomization */
1261 {
1262 GtkWidget *hb = sp_tb_spinbutton(_("Randomized:"), _("Scatter randomly the corners and angles"),
1263 "tools.shapes.star", "randomized", 0.0,
1264 NULL, tbl, FALSE, NULL,
1265 -10.0, 10.0, 0.001, 0.01,
1266 sp_stb_randomized_value_changed, 0.1, 3);
1267 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1268 }
1270 aux_toolbox_space(tbl, AUX_SPACING);
1272 /* Reset */
1273 {
1274 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1275 GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
1276 gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
1277 gtk_widget_show(b);
1278 gtk_container_add(GTK_CONTAINER(hb), b);
1279 gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_stb_defaults), tbl);
1280 gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_SPACING);
1281 }
1283 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1284 swatch->setWatchedTool ("tools.shapes.star", true);
1285 GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1286 gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1288 gtk_widget_show_all(tbl);
1289 sp_set_font_size_smaller (tbl);
1291 sigc::connection *connection = new sigc::connection(
1292 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_star_toolbox_selection_changed), (GtkObject *)tbl))
1293 );
1294 g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
1296 return tbl;
1297 }
1300 //########################
1301 //## Rect ##
1302 //########################
1304 static void
1305 sp_rtb_sensitivize (GtkWidget *tbl)
1306 {
1307 GtkAdjustment *adj1 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "rx"));
1308 GtkAdjustment *adj2 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "ry"));
1309 GtkWidget *not_rounded = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "not_rounded");
1311 if (adj1->value == 0 && adj2->value == 0 && gtk_object_get_data(GTK_OBJECT(tbl), "single")) { // only for a single selected rect (for now)
1312 gtk_widget_set_sensitive(GTK_WIDGET(not_rounded), FALSE);
1313 } else {
1314 gtk_widget_set_sensitive(GTK_WIDGET(not_rounded), TRUE);
1315 }
1316 }
1319 static void
1320 sp_rtb_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name,
1321 void (*setter)(SPRect *, gdouble))
1322 {
1323 SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
1325 GtkWidget *us = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(tbl), "units");
1326 SPUnit const *unit = sp_unit_selector_get_unit(SP_UNIT_SELECTOR(us));
1328 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1329 prefs_set_double_attribute("tools.shapes.rect", value_name, sp_units_get_pixels(adj->value, *unit));
1330 }
1332 // quit if run by the attr_changed listener
1333 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1334 return;
1335 }
1337 // in turn, prevent listener from responding
1338 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1340 bool modmade = false;
1341 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1342 for (GSList const *items = selection->itemList(); items != NULL; items = items->next) {
1343 if (SP_IS_RECT(items->data)) {
1344 if (adj->value != 0) {
1345 setter(SP_RECT(items->data), sp_units_get_pixels(adj->value, *unit));
1346 } else {
1347 SP_OBJECT_REPR(items->data)->setAttribute(value_name, NULL);
1348 }
1349 modmade = true;
1350 }
1351 }
1353 sp_rtb_sensitivize (tbl);
1355 if (modmade) {
1356 sp_document_done(sp_desktop_document(desktop));
1357 }
1359 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1361 // defocus spinbuttons by moving focus to the canvas, unless "stay" is on
1362 spinbutton_defocus(GTK_OBJECT(tbl));
1363 }
1365 static void
1366 sp_rtb_rx_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1367 {
1368 sp_rtb_value_changed(adj, tbl, "rx", sp_rect_set_visible_rx);
1369 }
1371 static void
1372 sp_rtb_ry_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1373 {
1374 sp_rtb_value_changed(adj, tbl, "ry", sp_rect_set_visible_ry);
1375 }
1377 static void
1378 sp_rtb_width_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1379 {
1380 sp_rtb_value_changed(adj, tbl, "width", sp_rect_set_visible_width);
1381 }
1383 static void
1384 sp_rtb_height_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1385 {
1386 sp_rtb_value_changed(adj, tbl, "height", sp_rect_set_visible_height);
1387 }
1391 static void
1392 sp_rtb_defaults( GtkWidget *widget, GtkObject *obj)
1393 {
1394 GtkWidget *tbl = GTK_WIDGET(obj);
1396 GtkAdjustment *adj;
1398 adj = (GtkAdjustment*)gtk_object_get_data(obj, "rx");
1399 gtk_adjustment_set_value(adj, 0.0);
1400 // this is necessary if the previous value was 0, but we still need to run the callback to change all selected objects
1401 gtk_adjustment_value_changed(adj);
1403 adj = (GtkAdjustment*)gtk_object_get_data(obj, "ry");
1404 gtk_adjustment_set_value(adj, 0.0);
1405 gtk_adjustment_value_changed(adj);
1407 sp_rtb_sensitivize (tbl);
1409 spinbutton_defocus(GTK_OBJECT(tbl));
1410 }
1412 static void rect_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1413 gchar const *old_value, gchar const *new_value,
1414 bool is_interactive, gpointer data)
1415 {
1416 GtkWidget *tbl = GTK_WIDGET(data);
1418 // quit if run by the _changed callbacks
1419 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1420 return;
1421 }
1423 // in turn, prevent callbacks from responding
1424 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1426 GtkWidget *us = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(tbl), "units");
1427 SPUnit const *unit = sp_unit_selector_get_unit(SP_UNIT_SELECTOR(us));
1429 SPItem *item = SP_ITEM(g_object_get_data(G_OBJECT(tbl), "item"));
1430 if (SP_IS_RECT(item)) {
1431 {
1432 GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "rx");
1433 gdouble rx = sp_rect_get_visible_rx(SP_RECT(item));
1434 gtk_adjustment_set_value(adj, sp_pixels_get_units(rx, *unit));
1435 }
1437 {
1438 GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "ry");
1439 gdouble ry = sp_rect_get_visible_ry(SP_RECT(item));
1440 gtk_adjustment_set_value(adj, sp_pixels_get_units(ry, *unit));
1441 }
1443 {
1444 GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "width");
1445 gdouble width = sp_rect_get_visible_width (SP_RECT(item));
1446 gtk_adjustment_set_value(adj, sp_pixels_get_units(width, *unit));
1447 }
1449 {
1450 GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "height");
1451 gdouble height = sp_rect_get_visible_height (SP_RECT(item));
1452 gtk_adjustment_set_value(adj, sp_pixels_get_units(height, *unit));
1453 }
1454 }
1456 sp_rtb_sensitivize (tbl);
1458 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1459 }
1462 static Inkscape::XML::NodeEventVector rect_tb_repr_events = {
1463 NULL, /* child_added */
1464 NULL, /* child_removed */
1465 rect_tb_event_attr_changed,
1466 NULL, /* content_changed */
1467 NULL /* order_changed */
1468 };
1470 /**
1471 * \param selection should not be NULL.
1472 */
1473 static void
1474 sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1475 {
1476 int n_selected = 0;
1477 Inkscape::XML::Node *repr = NULL;
1478 SPItem *item = NULL;
1479 Inkscape::XML::Node *oldrepr = NULL;
1481 for (GSList const *items = selection->itemList();
1482 items != NULL;
1483 items = items->next) {
1484 if (SP_IS_RECT((SPItem *) items->data)) {
1485 n_selected++;
1486 item = (SPItem *) items->data;
1487 repr = SP_OBJECT_REPR(item);
1488 }
1489 }
1491 GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
1493 g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(FALSE));
1495 if (n_selected == 0) {
1496 gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
1498 GtkWidget *w = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "width_sb");
1499 gtk_widget_set_sensitive(w, FALSE);
1500 GtkWidget *h = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "height_sb");
1501 gtk_widget_set_sensitive(h, FALSE);
1503 } else if (n_selected == 1) {
1504 gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1505 g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
1507 GtkWidget *w = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "width_sb");
1508 gtk_widget_set_sensitive(w, TRUE);
1509 GtkWidget *h = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "height_sb");
1510 gtk_widget_set_sensitive(h, TRUE);
1512 oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1513 if (oldrepr) { // remove old listener
1514 sp_repr_remove_listener_by_data(oldrepr, tbl);
1515 Inkscape::GC::release(oldrepr);
1516 oldrepr = 0;
1517 g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1518 }
1519 if (repr) {
1520 g_object_set_data(G_OBJECT(tbl), "repr", repr);
1521 g_object_set_data(G_OBJECT(tbl), "item", item);
1522 Inkscape::GC::anchor(repr);
1523 sp_repr_add_listener(repr, &rect_tb_repr_events, tbl);
1524 sp_repr_synthesize_events(repr, &rect_tb_repr_events, tbl);
1525 }
1526 } else {
1527 // FIXME: implement averaging of all parameters for multiple selected
1528 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1529 gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1530 sp_rtb_sensitivize (GTK_WIDGET(tbl));
1531 }
1532 }
1535 static GtkWidget *
1536 sp_rect_toolbox_new(SPDesktop *desktop)
1537 {
1538 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1540 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1541 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1543 GtkTooltips *tt = gtk_tooltips_new();
1545 sp_toolbox_add_label(tbl, _("<b>New:</b>"));
1547 // rx/ry units menu: create
1548 GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
1549 sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
1550 sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
1551 // fixme: add % meaning per cent of the width/height
1553 /* W */
1554 {
1555 GtkWidget *hb = sp_tb_spinbutton(_("W:"), _("Width of rectangle"),
1556 "tools.shapes.rect", "width", 0,
1557 us, tbl, TRUE, "altx-rect",
1558 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1559 sp_rtb_width_value_changed);
1560 gtk_object_set_data(GTK_OBJECT(tbl), "width_sb", hb);
1561 gtk_widget_set_sensitive(hb, FALSE);
1562 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1563 }
1565 /* H */
1566 {
1567 GtkWidget *hb = sp_tb_spinbutton(_("H:"), _("Height of rectangle"),
1568 "tools.shapes.rect", "height", 0,
1569 us, tbl, FALSE, NULL,
1570 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1571 sp_rtb_height_value_changed);
1572 gtk_object_set_data(GTK_OBJECT(tbl), "height_sb", hb);
1573 gtk_widget_set_sensitive(hb, FALSE);
1574 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1575 }
1577 /* rx */
1578 {
1579 GtkWidget *hb = sp_tb_spinbutton(_("Rx:"), _("Horizontal radius of rounded corners"),
1580 "tools.shapes.rect", "rx", 0,
1581 us, tbl, FALSE, NULL,
1582 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1583 sp_rtb_rx_value_changed);
1584 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1585 }
1587 /* ry */
1588 {
1589 GtkWidget *hb = sp_tb_spinbutton(_("Ry:"), _("Vertical radius of rounded corners"),
1590 "tools.shapes.rect", "ry", 0,
1591 us, tbl, FALSE, NULL,
1592 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1593 sp_rtb_ry_value_changed);
1594 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1595 }
1597 // add the units menu
1598 gtk_widget_show(us);
1599 gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1600 gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
1602 /* Reset */
1603 {
1604 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1605 GtkWidget *b = gtk_button_new_with_label(_("Not rounded"));
1606 gtk_object_set_data(GTK_OBJECT(tbl), "not_rounded", b);
1607 gtk_tooltips_set_tip(tt, b, _("Make corners sharp"), NULL);
1608 gtk_widget_show(b);
1609 gtk_container_add(GTK_CONTAINER(hb), b);
1610 gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_rtb_defaults), tbl);
1611 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1612 }
1614 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1615 swatch->setWatchedTool ("tools.shapes.rect", true);
1616 GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1617 gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1619 g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
1620 sp_rtb_sensitivize (tbl);
1622 gtk_widget_show_all(tbl);
1623 sp_set_font_size_smaller (tbl);
1625 sigc::connection *connection = new sigc::connection(
1626 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_rect_toolbox_selection_changed), (GtkObject *)tbl))
1627 );
1628 g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
1630 return tbl;
1631 }
1633 //########################
1634 //## Spiral ##
1635 //########################
1637 static void
1638 sp_spl_tb_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name)
1639 {
1640 SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
1642 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1643 prefs_set_double_attribute("tools.shapes.spiral", value_name, adj->value);
1644 }
1646 // quit if run by the attr_changed listener
1647 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1648 return;
1649 }
1651 // in turn, prevent listener from responding
1652 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1654 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
1656 bool modmade = false;
1657 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
1658 items != NULL;
1659 items = items->next)
1660 {
1661 if (SP_IS_SPIRAL((SPItem *) items->data)) {
1662 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1663 sp_repr_set_svg_double( repr, namespaced_name, adj->value );
1664 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1665 modmade = true;
1666 }
1667 }
1669 g_free(namespaced_name);
1671 if (modmade) {
1672 sp_document_done(sp_desktop_document(desktop));
1673 }
1675 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1677 spinbutton_defocus(GTK_OBJECT(tbl));
1678 }
1680 static void
1681 sp_spl_tb_revolution_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1682 {
1683 sp_spl_tb_value_changed(adj, tbl, "revolution");
1684 }
1686 static void
1687 sp_spl_tb_expansion_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1688 {
1689 sp_spl_tb_value_changed(adj, tbl, "expansion");
1690 }
1692 static void
1693 sp_spl_tb_t0_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1694 {
1695 sp_spl_tb_value_changed(adj, tbl, "t0");
1696 }
1698 static void
1699 sp_spl_tb_defaults(GtkWidget *widget, GtkObject *obj)
1700 {
1701 GtkWidget *tbl = GTK_WIDGET(obj);
1703 GtkAdjustment *adj;
1705 // fixme: make settable
1706 gdouble rev = 5;
1707 gdouble exp = 1.0;
1708 gdouble t0 = 0.0;
1710 adj = (GtkAdjustment*)gtk_object_get_data(obj, "revolution");
1711 gtk_adjustment_set_value(adj, rev);
1712 gtk_adjustment_value_changed(adj);
1714 adj = (GtkAdjustment*)gtk_object_get_data(obj, "expansion");
1715 gtk_adjustment_set_value(adj, exp);
1716 gtk_adjustment_value_changed(adj);
1718 adj = (GtkAdjustment*)gtk_object_get_data(obj, "t0");
1719 gtk_adjustment_set_value(adj, t0);
1720 gtk_adjustment_value_changed(adj);
1722 spinbutton_defocus(GTK_OBJECT(tbl));
1723 }
1726 static void spiral_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1727 gchar const *old_value, gchar const *new_value,
1728 bool is_interactive, gpointer data)
1729 {
1730 GtkWidget *tbl = GTK_WIDGET(data);
1732 // quit if run by the _changed callbacks
1733 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1734 return;
1735 }
1737 // in turn, prevent callbacks from responding
1738 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1740 GtkAdjustment *adj;
1741 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "revolution");
1742 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:revolution", 3.0)));
1744 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "expansion");
1745 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:expansion", 1.0)));
1747 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "t0");
1748 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:t0", 0.0)));
1750 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1751 }
1754 static Inkscape::XML::NodeEventVector spiral_tb_repr_events = {
1755 NULL, /* child_added */
1756 NULL, /* child_removed */
1757 spiral_tb_event_attr_changed,
1758 NULL, /* content_changed */
1759 NULL /* order_changed */
1760 };
1762 static void
1763 sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1764 {
1765 int n_selected = 0;
1766 Inkscape::XML::Node *repr = NULL;
1767 Inkscape::XML::Node *oldrepr = NULL;
1769 for (GSList const *items = selection->itemList();
1770 items != NULL;
1771 items = items->next)
1772 {
1773 if (SP_IS_SPIRAL((SPItem *) items->data)) {
1774 n_selected++;
1775 repr = SP_OBJECT_REPR((SPItem *) items->data);
1776 }
1777 }
1779 GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
1781 if (n_selected == 0) {
1782 gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
1783 } else if (n_selected == 1) {
1784 gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1786 oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1787 if (oldrepr) { // remove old listener
1788 sp_repr_remove_listener_by_data(oldrepr, tbl);
1789 Inkscape::GC::release(oldrepr);
1790 oldrepr = 0;
1791 g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1792 }
1794 if (repr) {
1795 g_object_set_data(G_OBJECT(tbl), "repr", repr);
1796 Inkscape::GC::anchor(repr);
1797 sp_repr_add_listener(repr, &spiral_tb_repr_events, tbl);
1798 sp_repr_synthesize_events(repr, &spiral_tb_repr_events, tbl);
1799 }
1800 } else {
1801 // FIXME: implement averaging of all parameters for multiple selected
1802 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1803 gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1804 }
1805 }
1808 static GtkWidget *
1809 sp_spiral_toolbox_new(SPDesktop *desktop)
1810 {
1811 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1812 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1813 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1815 GtkTooltips *tt = gtk_tooltips_new();
1817 sp_toolbox_add_label(tbl, _("<b>New:</b>"));
1819 /* Revolution */
1820 {
1821 GtkWidget *hb = sp_tb_spinbutton(_("Turns:"), _("Number of revolutions"),
1822 "tools.shapes.spiral", "revolution", 3.0,
1823 NULL, tbl, TRUE, "altx-spiral",
1824 0.01, 1024.0, 0.1, 1.0,
1825 sp_spl_tb_revolution_value_changed, 1, 2);
1826 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1827 }
1829 /* Expansion */
1830 {
1831 GtkWidget *hb = sp_tb_spinbutton(_("Divergence:"), _("How much denser/sparser are outer revolutions; 1 = uniform"),
1832 "tools.shapes.spiral", "expansion", 1.0,
1833 NULL, tbl, FALSE, NULL,
1834 0.0, 1000.0, 0.01, 1.0,
1835 sp_spl_tb_expansion_value_changed);
1836 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1837 }
1839 /* T0 */
1840 {
1841 GtkWidget *hb = sp_tb_spinbutton(_("Inner radius:"), _("Radius of the innermost revolution (relative to the spiral size)"),
1842 "tools.shapes.spiral", "t0", 0.0,
1843 NULL, tbl, FALSE, NULL,
1844 0.0, 0.999, 0.01, 1.0,
1845 sp_spl_tb_t0_value_changed);
1846 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1847 }
1849 aux_toolbox_space(tbl, AUX_SPACING);
1851 /* Reset */
1852 {
1853 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1854 GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
1855 gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
1856 gtk_widget_show(b);
1857 gtk_container_add(GTK_CONTAINER(hb), b);
1858 gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_spl_tb_defaults), tbl);
1859 gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1860 }
1862 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1863 swatch->setWatchedTool ("tools.shapes.spiral", true);
1864 GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1865 gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1867 gtk_widget_show_all(tbl);
1868 sp_set_font_size_smaller (tbl);
1870 sigc::connection *connection = new sigc::connection(
1871 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_spiral_toolbox_selection_changed), (GtkObject *)tbl))
1872 );
1873 g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
1875 return tbl;
1876 }
1878 //########################
1879 //## Pen/Pencil ##
1880 //########################
1883 static GtkWidget *
1884 sp_pen_toolbox_new(SPDesktop *desktop)
1885 {
1886 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1887 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1888 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1890 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1891 swatch->setWatchedTool ("tools.freehand.pen", true);
1892 GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1893 gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1895 gtk_widget_show_all(tbl);
1896 sp_set_font_size_smaller (tbl);
1898 return tbl;
1899 }
1901 static GtkWidget *
1902 sp_pencil_toolbox_new(SPDesktop *desktop)
1903 {
1904 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1905 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1906 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1908 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1909 swatch->setWatchedTool ("tools.freehand.pencil", true);
1910 GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1911 gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1913 gtk_widget_show_all(tbl);
1914 sp_set_font_size_smaller (tbl);
1916 return tbl;
1917 }
1920 //########################
1921 //## Calligraphy ##
1922 //########################
1924 static void
1925 sp_ddc_mass_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1926 {
1927 prefs_set_double_attribute("tools.calligraphic", "mass", adj->value);
1928 spinbutton_defocus(GTK_OBJECT(tbl));
1929 }
1931 static void
1932 sp_ddc_drag_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1933 {
1934 prefs_set_double_attribute("tools.calligraphic", "drag", adj->value);
1935 spinbutton_defocus(GTK_OBJECT(tbl));
1936 }
1938 static void
1939 sp_ddc_angle_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1940 {
1941 prefs_set_double_attribute("tools.calligraphic", "angle", adj->value);
1942 spinbutton_defocus(GTK_OBJECT(tbl));
1943 }
1945 static void
1946 sp_ddc_width_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1947 {
1948 prefs_set_double_attribute("tools.calligraphic", "width", adj->value * 0.01);
1949 spinbutton_defocus(GTK_OBJECT(tbl));
1950 }
1952 static void
1953 sp_ddc_velthin_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1954 {
1955 prefs_set_double_attribute("tools.calligraphic", "thinning", adj->value);
1956 spinbutton_defocus(GTK_OBJECT(tbl));
1957 }
1959 static void
1960 sp_ddc_flatness_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1961 {
1962 prefs_set_double_attribute("tools.calligraphic", "flatness", adj->value);
1963 spinbutton_defocus(GTK_OBJECT(tbl));
1964 }
1966 static void
1967 sp_ddc_tremor_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1968 {
1969 prefs_set_double_attribute("tools.calligraphic", "tremor", adj->value);
1970 spinbutton_defocus(GTK_OBJECT(tbl));
1971 }
1973 static void
1974 sp_ddc_pressure_state_changed(GtkWidget *button, gpointer data)
1975 {
1976 prefs_set_int_attribute ("tools.calligraphic", "usepressure", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 1 : 0);
1977 }
1979 static void
1980 sp_ddc_tilt_state_changed(GtkWidget *button, GtkWidget *calligraphy_angle)
1981 {
1982 prefs_set_int_attribute ("tools.calligraphic", "usetilt", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 1 : 0);
1984 gtk_widget_set_sensitive(GTK_WIDGET(calligraphy_angle), !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)));
1985 }
1987 static void sp_ddc_defaults(GtkWidget *, GtkWidget *tbl)
1988 {
1989 // FIXME: make defaults settable via Inkscape Options
1990 struct KeyValue {
1991 char const *key;
1992 double value;
1993 } const key_values[] = {
1994 {"mass", 0.02},
1995 {"drag", 1.0},
1996 {"angle", 30.0},
1997 {"width", 15},
1998 {"thinning", 0.1},
1999 {"tremor", 0.0},
2000 {"flatness", 0.9}
2001 };
2003 for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
2004 KeyValue const &kv = key_values[i];
2005 GtkAdjustment &adj = *static_cast<GtkAdjustment *>(gtk_object_get_data(GTK_OBJECT(tbl), kv.key));
2006 gtk_adjustment_set_value(&adj, kv.value);
2007 }
2009 spinbutton_defocus(GTK_OBJECT(tbl));
2010 }
2012 static GtkWidget *
2013 sp_calligraphy_toolbox_new(SPDesktop *desktop)
2014 {
2015 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2016 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2017 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2019 GtkTooltips *tt = gtk_tooltips_new();
2020 GtkWidget *calligraphy_angle;
2022 // interval
2023 gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2025 /* Width */
2026 {
2027 GtkWidget *hb = sp_tb_spinbutton(_("Width:"), _("The width of the calligraphic pen (relative to the visible canvas area)"),
2028 "tools.calligraphic", "width", 15,
2029 NULL, tbl, TRUE, "altx-calligraphy",
2030 1, 100, 1.0, 10.0,
2031 sp_ddc_width_value_changed, 0.01, 0, 100);
2032 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2033 }
2035 /* Thinning */
2036 {
2037 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)"),
2038 "tools.calligraphic", "thinning", 0.1,
2039 NULL, tbl, FALSE, NULL,
2040 -1.0, 1.0, 0.01, 0.1,
2041 sp_ddc_velthin_value_changed, 0.01, 2);
2042 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2043 }
2045 // interval
2046 gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2048 /* Angle */
2049 {
2050 calligraphy_angle = sp_tb_spinbutton(_("Angle:"), _("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"),
2051 "tools.calligraphic", "angle", 30,
2052 NULL, tbl, TRUE, "calligraphy-angle",
2053 -90.0, 90.0, 1.0, 10.0,
2054 sp_ddc_angle_value_changed, 1, 0);
2055 gtk_box_pack_start(GTK_BOX(tbl), calligraphy_angle, FALSE, FALSE, AUX_SPACING);
2056 }
2058 /* Fixation */
2059 {
2060 GtkWidget *hb = sp_tb_spinbutton(_("Fixation:"), _("How fixed is the pen angle (0 = always perpendicular to stroke direction, 1 = fixed)"),
2061 "tools.calligraphic", "flatness", 0.9,
2062 NULL, tbl, FALSE, NULL,
2063 0.0, 1.0, 0.01, 0.1,
2064 sp_ddc_flatness_value_changed, 0.01, 2);
2065 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2066 }
2068 // interval
2069 gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2071 /* Tremor */
2072 {
2073 GtkWidget *hb = sp_tb_spinbutton(_("Tremor:"), _("How uneven or trembling is the pen stroke"),
2074 "tools.calligraphic", "tremor", 0.0,
2075 NULL, tbl, FALSE, NULL,
2076 0.0, 1.0, 0.01, 0.1,
2077 sp_ddc_tremor_value_changed, 0.01, 2);
2078 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2079 }
2080 /* Mass */
2081 {
2082 GtkWidget *hb = sp_tb_spinbutton(_("Mass:"), _("How much inertia affects the movement of the pen"),
2083 "tools.calligraphic", "mass", 0.02,
2084 NULL, tbl, FALSE, NULL,
2085 0.0, 1.0, 0.01, 0.1,
2086 sp_ddc_mass_value_changed, 0.01, 2);
2087 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2088 }
2090 /* Drag */
2091 {
2092 // TRANSLATORS: "drag" means "resistance" here
2093 GtkWidget *hb = sp_tb_spinbutton(_("Drag:"), _("How much resistance affects the movement of the pen"),
2094 "tools.calligraphic", "drag", 1,
2095 NULL, tbl, FALSE, NULL,
2096 0.0, 1.0, 0.01, 0.1,
2097 sp_ddc_drag_value_changed, 0.01, 2);
2098 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2099 }
2101 // interval
2102 gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2104 GtkWidget *cvbox = gtk_vbox_new (FALSE, 0);
2105 GtkWidget *cbox = gtk_hbox_new (FALSE, 0);
2107 /* Use Pressure button */
2108 {
2109 GtkWidget *button = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
2110 SP_BUTTON_TYPE_TOGGLE,
2111 NULL,
2112 "use_pressure",
2113 _("Use the pressure of the input device to alter the width of the pen"),
2114 tt);
2115 g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (sp_ddc_pressure_state_changed), NULL);
2116 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), prefs_get_int_attribute ("tools.calligraphic", "usepressure", 1));
2117 gtk_box_pack_start(GTK_BOX(cbox), button, FALSE, FALSE, 0);
2118 }
2120 /* Use Tilt button */
2121 {
2122 GtkWidget *button = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
2123 SP_BUTTON_TYPE_TOGGLE,
2124 NULL,
2125 "use_tilt",
2126 _("Use the tilt of the input device to alter the angle of the pen's nib"),
2127 tt);
2128 g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (sp_ddc_tilt_state_changed), calligraphy_angle);
2129 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), prefs_get_int_attribute ("tools.calligraphic", "usetilt", 1));
2130 gtk_widget_set_sensitive(GTK_WIDGET(calligraphy_angle), !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)));
2131 gtk_box_pack_start(GTK_BOX(cbox), button, FALSE, FALSE, 0);
2132 }
2134 gtk_box_pack_start(GTK_BOX(cvbox), cbox, TRUE, FALSE, 0);
2135 gtk_box_pack_start(GTK_BOX(tbl), cvbox, FALSE, FALSE, 0);
2137 /* Reset */
2138 {
2139 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2140 GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
2141 gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
2142 gtk_widget_show(b);
2143 gtk_container_add(GTK_CONTAINER(hb), b);
2144 gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_ddc_defaults), tbl);
2145 gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2146 }
2149 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
2150 swatch->setWatchedTool ("tools.calligraphic", true);
2151 GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
2152 gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
2154 gtk_widget_show_all(tbl);
2155 sp_set_font_size_smaller (tbl);
2157 return tbl;
2158 }
2161 //########################
2162 //## Circle / Arc ##
2163 //########################
2165 static void
2166 sp_arctb_sensitivize (GtkWidget *tbl, double v1, double v2)
2167 {
2168 GtkWidget *ocb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "open_checkbox");
2169 GtkWidget *make_whole = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "make_whole");
2171 if (v1 == 0 && v2 == 0) {
2172 if (gtk_object_get_data(GTK_OBJECT(tbl), "single")) { // only for a single selected ellipse (for now)
2173 gtk_widget_set_sensitive(GTK_WIDGET(ocb), FALSE);
2174 gtk_widget_set_sensitive(GTK_WIDGET(make_whole), FALSE);
2175 }
2176 } else {
2177 gtk_widget_set_sensitive(GTK_WIDGET(ocb), TRUE);
2178 gtk_widget_set_sensitive(GTK_WIDGET(make_whole), TRUE);
2179 }
2180 }
2182 static void
2183 sp_arctb_startend_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name, gchar const *other_name)
2184 {
2185 SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2187 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2188 prefs_set_double_attribute("tools.shapes.arc", value_name, (adj->value * M_PI)/ 180);
2189 }
2191 // quit if run by the attr_changed listener
2192 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2193 return;
2194 }
2196 // in turn, prevent listener from responding
2197 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2199 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
2201 bool modmade = false;
2202 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2203 items != NULL;
2204 items = items->next)
2205 {
2206 SPItem *item = SP_ITEM(items->data);
2208 if (SP_IS_ARC(item) && SP_IS_GENERICELLIPSE(item)) {
2210 SPGenericEllipse *ge = SP_GENERICELLIPSE(item);
2211 SPArc *arc = SP_ARC(item);
2213 if (!strcmp(value_name, "start"))
2214 ge->start = (adj->value * M_PI)/ 180;
2215 else
2216 ge->end = (adj->value * M_PI)/ 180;
2218 sp_genericellipse_normalize(ge);
2219 ((SPObject *)arc)->updateRepr();
2220 ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
2222 modmade = true;
2223 }
2224 }
2226 g_free(namespaced_name);
2228 GtkAdjustment *other = (GtkAdjustment *)gtk_object_get_data(GTK_OBJECT(tbl), other_name);
2230 sp_arctb_sensitivize (tbl, adj->value, other->value);
2232 if (modmade) {
2233 sp_document_maybe_done(sp_desktop_document(desktop), value_name);
2234 }
2236 // defocus spinbuttons by moving focus to the canvas, unless "stay" is on
2237 spinbutton_defocus(GTK_OBJECT(tbl));
2239 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2240 }
2243 static void
2244 sp_arctb_start_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
2245 {
2246 sp_arctb_startend_value_changed(adj, tbl, "start", "end");
2247 }
2249 static void
2250 sp_arctb_end_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
2251 {
2252 sp_arctb_startend_value_changed(adj, tbl, "end", "start");
2253 }
2255 static void
2256 sp_arctb_open_state_changed(GtkWidget *widget, GtkObject *tbl)
2257 {
2258 SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2260 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2261 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
2262 prefs_set_string_attribute("tools.shapes.arc", "open", "true");
2263 } else {
2264 prefs_set_string_attribute("tools.shapes.arc", "open", NULL);
2265 }
2266 }
2268 // quit if run by the attr_changed listener
2269 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2270 return;
2271 }
2273 // in turn, prevent listener from responding
2274 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2276 bool modmade = false;
2278 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
2279 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2280 items != NULL;
2281 items = items->next)
2282 {
2283 if (SP_IS_ARC((SPItem *) items->data)) {
2284 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2285 repr->setAttribute("sodipodi:open", "true");
2286 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2287 modmade = true;
2288 }
2289 }
2290 } else {
2291 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2292 items != NULL;
2293 items = items->next)
2294 {
2295 if (SP_IS_ARC((SPItem *) items->data)) {
2296 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2297 repr->setAttribute("sodipodi:open", NULL);
2298 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2299 modmade = true;
2300 }
2301 }
2302 }
2304 if (modmade) {
2305 sp_document_done(sp_desktop_document(desktop));
2306 }
2308 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2310 spinbutton_defocus(GTK_OBJECT(tbl));
2311 }
2313 static void sp_arctb_defaults(GtkWidget *, GtkObject *obj)
2314 {
2315 GtkWidget *tbl = GTK_WIDGET(obj);
2317 GtkAdjustment *adj;
2318 adj = (GtkAdjustment*)gtk_object_get_data(obj, "start");
2319 gtk_adjustment_set_value(adj, 0.0);
2320 gtk_adjustment_value_changed(adj);
2322 adj = (GtkAdjustment*)gtk_object_get_data(obj, "end");
2323 gtk_adjustment_set_value(adj, 0.0);
2324 gtk_adjustment_value_changed(adj);
2326 spinbutton_defocus(GTK_OBJECT(tbl));
2327 }
2329 static void arc_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
2330 gchar const *old_value, gchar const *new_value,
2331 bool is_interactive, gpointer data)
2332 {
2333 GtkWidget *tbl = GTK_WIDGET(data);
2335 // quit if run by the _changed callbacks
2336 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2337 return;
2338 }
2340 // in turn, prevent callbacks from responding
2341 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2343 gdouble start = sp_repr_get_double_attribute(repr, "sodipodi:start", 0.0);
2344 gdouble end = sp_repr_get_double_attribute(repr, "sodipodi:end", 0.0);
2346 GtkAdjustment *adj1,*adj2;
2347 adj1 = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "start");
2348 gtk_adjustment_set_value(adj1, mod360((start * 180)/M_PI));
2349 adj2 = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "end");
2350 gtk_adjustment_set_value(adj2, mod360((end * 180)/M_PI));
2352 sp_arctb_sensitivize (tbl, adj1->value, adj2->value);
2354 char const *openstr = NULL;
2355 openstr = repr->attribute("sodipodi:open");
2356 GtkWidget *ocb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "open_checkbox");
2358 if (openstr) {
2359 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ocb), TRUE);
2360 } else {
2361 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ocb), FALSE);
2362 }
2364 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2365 }
2367 static Inkscape::XML::NodeEventVector arc_tb_repr_events = {
2368 NULL, /* child_added */
2369 NULL, /* child_removed */
2370 arc_tb_event_attr_changed,
2371 NULL, /* content_changed */
2372 NULL /* order_changed */
2373 };
2376 static void
2377 sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
2378 {
2379 int n_selected = 0;
2380 Inkscape::XML::Node *repr = NULL;
2381 Inkscape::XML::Node *oldrepr = NULL;
2383 for (GSList const *items = selection->itemList();
2384 items != NULL;
2385 items = items->next)
2386 {
2387 if (SP_IS_ARC((SPItem *) items->data)) {
2388 n_selected++;
2389 repr = SP_OBJECT_REPR((SPItem *) items->data);
2390 }
2391 }
2393 GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
2395 g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(FALSE));
2396 if (n_selected == 0) {
2397 gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
2398 } else if (n_selected == 1) {
2399 g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
2400 gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2402 oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
2404 if (oldrepr) { // remove old listener
2405 sp_repr_remove_listener_by_data(oldrepr, tbl);
2406 Inkscape::GC::release(oldrepr);
2407 oldrepr = 0;
2408 g_object_set_data(G_OBJECT(tbl), "repr", NULL);
2409 }
2411 if (repr) {
2412 g_object_set_data(G_OBJECT(tbl), "repr", repr);
2413 Inkscape::GC::anchor(repr);
2414 sp_repr_add_listener(repr, &arc_tb_repr_events, tbl);
2415 sp_repr_synthesize_events(repr, &arc_tb_repr_events, tbl);
2416 }
2417 } else {
2418 // FIXME: implement averaging of all parameters for multiple selected
2419 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2420 gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2421 sp_arctb_sensitivize (GTK_WIDGET(tbl), 1, 0);
2422 }
2423 }
2426 static GtkWidget *
2427 sp_arc_toolbox_new(SPDesktop *desktop)
2428 {
2429 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2431 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2432 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2434 GtkTooltips *tt = gtk_tooltips_new();
2436 sp_toolbox_add_label(tbl, _("<b>New:</b>"));
2438 /* Start */
2439 {
2440 GtkWidget *hb = sp_tb_spinbutton(_("Start:"), _("The angle (in degrees) from the horizontal to the arc's start point"),
2441 "tools.shapes.arc", "start", 0.0,
2442 NULL, tbl, TRUE, "altx-arc",
2443 -360.0, 360.0, 1.0, 10.0,
2444 sp_arctb_start_value_changed);
2445 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2446 }
2448 /* End */
2449 {
2450 GtkWidget *hb = sp_tb_spinbutton(_("End:"), _("The angle (in degrees) from the horizontal to the arc's end point"),
2451 "tools.shapes.arc", "end", 0.0,
2452 NULL, tbl, FALSE, NULL,
2453 -360.0, 360.0, 1.0, 10.0,
2454 sp_arctb_end_value_changed);
2455 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2456 }
2458 /* Segments / Pie checkbox */
2459 {
2460 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2461 GtkWidget *fscb = gtk_check_button_new_with_label(_("Open arc"));
2462 gtk_tooltips_set_tip(tt, fscb, _("Switch between arc (unclosed shape) and segment (closed shape with two radii)"), NULL);
2464 gchar const *openstr = NULL;
2465 openstr = prefs_get_string_attribute("tools.shapes.arc", "open");
2466 if (!openstr || (openstr && !strcmp(openstr, "false")))
2467 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb), FALSE);
2468 else
2469 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb), TRUE);
2471 gtk_widget_show(fscb);
2472 gtk_object_set_data(GTK_OBJECT(tbl), "open_checkbox", fscb);
2473 gtk_container_add(GTK_CONTAINER(hb), fscb);
2474 g_signal_connect(G_OBJECT(fscb), "toggled", GTK_SIGNAL_FUNC(sp_arctb_open_state_changed ), tbl);
2475 gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2476 }
2478 /* Make Whole */
2479 {
2480 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2481 GtkWidget *b = gtk_button_new_with_label(_("Make whole"));
2482 gtk_object_set_data(GTK_OBJECT(tbl), "make_whole", b);
2483 gtk_tooltips_set_tip(tt, b, _("Make the shape a whole ellipse, not arc or segment"), NULL);
2484 gtk_widget_show(b);
2485 gtk_container_add(GTK_CONTAINER(hb), b);
2486 gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_arctb_defaults), tbl);
2487 gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2488 }
2490 g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
2491 // sensitivize make whole and open checkbox
2492 {
2493 GtkAdjustment *adj1 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "start"));
2494 GtkAdjustment *adj2 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "end"));
2495 sp_arctb_sensitivize (tbl, adj1->value, adj2->value);
2496 }
2498 sigc::connection *connection = new sigc::connection(
2499 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_arc_toolbox_selection_changed), (GtkObject *)tbl))
2500 );
2501 g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
2503 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
2504 swatch->setWatchedTool ("tools.shapes.arc", true);
2505 GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
2506 gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
2508 gtk_widget_show_all(tbl);
2509 sp_set_font_size_smaller (tbl);
2511 return tbl;
2512 }
2517 // toggle button callbacks and updaters
2519 //########################
2520 //## Dropper ##
2521 //########################
2523 static void toggle_dropper_color_pick (GtkWidget *button, gpointer data) {
2524 prefs_set_int_attribute ("tools.dropper", "pick",
2525 // 0 and 1 are backwards here because of pref
2526 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 0 : 1);
2527 }
2530 /**
2531 * Copy the current saved desktop color to the clipboard as full hex + alpha
2532 * color representation. This is useful for passing values between various
2533 * input boxes, or directly to xml.
2534 */
2535 /* static void
2536 sp_dropper_copy( GtkWidget *widget, GtkObject *obj)
2537 {
2538 GtkWidget *tbl = GTK_WIDGET(obj);
2540 SPDesktop *desktop =
2541 (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2544 sp_dropper_c32_color_copy( sp_desktop_get_color(desktop, true) );
2545 }*/
2548 /**
2549 * Copies currently saved desktop color to the clipboard as a hex value. This
2550 * is useful for editing webpages and needing a value quickly for web
2551 * colors.
2552 *
2553 * TODO: When the toggle of the dropper is set to not mix color against
2554 * page background, this still just gets the color of the page and
2555 * doesn't get the actual mixed against background which is needed
2556 * for the hex value ppl. want for web pages, etc.
2557 */
2559 /* static void
2560 sp_dropper_copy_as_hex ( GtkWidget *widget, GtkObject *obj)
2561 {
2562 GtkWidget *tbl = GTK_WIDGET(obj);
2564 SPDesktop *desktop =
2565 (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2567 sp_dropper_c32_color_copy_hex( sp_desktop_get_color(desktop, true) );
2568 }*/
2571 /**
2572 * Sets the input boxes with the changed color and opacity. This is used as a
2573 * callback for style changing.
2574 */
2575 /* static bool
2576 sp_style_changed (const SPCSSAttr *css, gpointer data)
2577 {
2578 // GrDrag *drag = (GrDrag *) data;
2580 // set fill of text entry box
2581 if (css->attribute("fill"))
2582 gtk_entry_set_text((GtkEntry *)dropper_rgb_entry,
2583 css->attribute("fill"));
2585 // set opacity of text entry box
2586 if (css->attribute("fill-opacity"))
2587 gtk_entry_set_text((GtkEntry *)dropper_opacity_entry,
2588 css->attribute("fill-opacity"));
2590 // set fill of text entry box
2591 if (css->attribute("stroke"))
2592 gtk_entry_set_text((GtkEntry *)dropper_rgb_entry,
2593 css->attribute("stroke"));
2595 // set opacity of text entry box
2596 if (css->attribute("stroke-opacity"))
2597 gtk_entry_set_text((GtkEntry *)dropper_opacity_entry,
2598 css->attribute("stroke-opacity"));
2599 return false;
2601 }
2602 */
2605 /**
2606 * Dropper auxiliary toolbar construction and setup.
2607 *
2608 * TODO: Would like to add swatch of current color.
2609 * TODO: Add queue of last 5 or so colors selected with new swatches so that
2610 * can drag and drop places. Will provide a nice mixing palette.
2611 */
2612 static GtkWidget *
2613 sp_dropper_toolbox_new(SPDesktop *desktop)
2614 {
2615 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2617 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2618 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2620 GtkTooltips *tt = gtk_tooltips_new();
2623 gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
2624 AUX_BETWEEN_BUTTON_GROUPS);
2625 // sp_toolbox_add_label(tbl, _("<b>New:</b>"));
2629 /* RGB Input Field */
2630 /* {
2631 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2632 GtkWidget *dropper_rgba_label = gtk_label_new ("Color:");
2633 gtk_widget_show (dropper_rgba_label);
2634 gtk_container_add(GTK_CONTAINER(hb), dropper_rgba_label);
2636 dropper_rgb_entry = gtk_entry_new ();
2637 sp_dialog_defocus_on_enter (dropper_rgb_entry);
2638 gtk_entry_set_max_length (GTK_ENTRY (dropper_rgb_entry), 7);
2639 gtk_entry_set_width_chars (GTK_ENTRY (dropper_rgb_entry), 7);
2640 gtk_tooltips_set_tip(tt, dropper_rgb_entry,
2641 _("Hexidecimal representation of last selected "
2642 "color"),
2643 NULL);
2644 gtk_widget_show (dropper_rgb_entry);
2645 gtk_container_add(GTK_CONTAINER(hb), dropper_rgb_entry);
2647 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE,
2648 AUX_BETWEEN_BUTTON_GROUPS);
2649 } */
2651 /* Opacity Input Field */
2652 /* {
2653 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2654 GtkWidget *dropper_opacity_label = gtk_label_new ( _("Opacity:") );
2655 gtk_widget_show (dropper_opacity_label);
2656 gtk_container_add(GTK_CONTAINER(hb), dropper_opacity_label);
2658 dropper_opacity_entry = gtk_entry_new ();
2659 sp_dialog_defocus_on_enter (dropper_opacity_entry);
2660 gtk_entry_set_max_length (GTK_ENTRY (dropper_opacity_entry), 11);
2661 gtk_entry_set_width_chars (GTK_ENTRY (dropper_opacity_entry), 11);
2662 gtk_tooltips_set_tip(tt, dropper_opacity_entry,
2663 _("Opacity of last selected color"),
2664 NULL);
2665 gtk_widget_show (dropper_opacity_entry);
2666 gtk_container_add(GTK_CONTAINER(hb), dropper_opacity_entry);
2668 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE,
2669 AUX_BETWEEN_BUTTON_GROUPS);
2670 } */
2673 /* Copy to Clipboard */
2674 /* {
2675 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2676 GtkWidget *b = gtk_button_new_with_label(_("Copy as RGBA"));
2677 gtk_tooltips_set_tip(tt, b, _("Copy last saved color as hexidecimal "
2678 "RGB + Alpha (RGBA) to "
2679 "clipboard"),
2680 NULL);
2681 gtk_widget_show(b);
2682 gtk_container_add(GTK_CONTAINER(hb), b);
2683 gtk_signal_connect(GTK_OBJECT(b), "clicked",
2684 GTK_SIGNAL_FUNC(sp_dropper_copy), tbl);
2685 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE,
2686 AUX_BETWEEN_BUTTON_GROUPS);
2687 } */
2690 /* Copy to Clipboard as HEX */
2691 /* {
2692 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2693 GtkWidget *b = gtk_button_new_with_label(_("Copy as HEX"));
2694 gtk_tooltips_set_tip(tt, b, _("Copy last saved color as "
2695 "hexidecimal RGB without alpha "
2696 "to clipboard"), NULL);
2697 gtk_widget_show(b);
2698 gtk_container_add(GTK_CONTAINER(hb), b);
2699 gtk_signal_connect(GTK_OBJECT(b), "clicked",
2700 GTK_SIGNAL_FUNC(sp_dropper_copy_as_hex), tbl);
2701 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE,
2702 AUX_BETWEEN_BUTTON_GROUPS);
2703 } */
2705 // aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2707 {
2708 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2710 GtkWidget *button =
2711 sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
2712 SP_BUTTON_TYPE_TOGGLE,
2713 NULL,
2714 "pick_color",
2715 _("When pressed, picks visible color "
2716 "without alpha and when not pressed, "
2717 "picks color including its "
2718 "alpha"),
2719 tt);
2721 gtk_widget_show(button);
2722 gtk_container_add (GTK_CONTAINER (hb), button);
2724 g_signal_connect_after (G_OBJECT (button), "clicked",
2725 G_CALLBACK (toggle_dropper_color_pick), NULL);
2726 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
2727 !prefs_get_int_attribute ("tools.dropper",
2728 "pick", 0));
2729 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE,
2730 AUX_BETWEEN_BUTTON_GROUPS);
2731 }
2733 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2736 // where new gtkmm stuff should go
2738 gtk_widget_show_all(tbl);
2739 sp_set_font_size_smaller (tbl);
2741 /*
2742 sigc::connection *connection = new sigc::connection(
2743 desktop->connectSetStyle(
2744 sigc::bind(sigc::ptr_fun(sp_style_changed),
2745 desktop)) );
2747 g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection),
2748 connection); */
2750 return tbl;
2751 }
2754 //########################
2755 //## Text Toolbox ##
2756 //########################
2757 /*
2758 static void
2759 sp_text_letter_changed(GtkAdjustment *adj, GtkWidget *tbl)
2760 {
2761 //Call back for letter sizing spinbutton
2762 }
2764 static void
2765 sp_text_line_changed(GtkAdjustment *adj, GtkWidget *tbl)
2766 {
2767 //Call back for line height spinbutton
2768 }
2770 static void
2771 sp_text_horiz_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
2772 {
2773 //Call back for horizontal kerning spinbutton
2774 }
2776 static void
2777 sp_text_vert_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
2778 {
2779 //Call back for vertical kerning spinbutton
2780 }
2782 static void
2783 sp_text_letter_rotation_changed(GtkAdjustment *adj, GtkWidget *tbl)
2784 {
2785 //Call back for letter rotation spinbutton
2786 }*/
2788 namespace {
2790 void
2791 sp_text_toolbox_selection_changed (Inkscape::Selection *selection, GObject *tbl)
2792 {
2793 GtkComboBox *cbox = 0;
2795 SPStyle *query =
2796 sp_style_new ();
2798 int result_family =
2799 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
2801 int result_style =
2802 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
2804 int result_numbers =
2805 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
2807 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
2808 if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING)
2809 {
2810 Inkscape::XML::Node *repr = inkscape_get_repr (INKSCAPE, "tools.text");
2812 if (repr)
2813 {
2814 sp_style_read_from_repr (query, repr);
2815 }
2816 else
2817 {
2818 return;
2819 }
2820 }
2822 if (result_numbers == QUERY_STYLE_MULTIPLE_DIFFERENT)
2823 {
2824 static char* cboxes[] = { "combo-box-family", "combo-box-style" };
2826 for (unsigned n = 0 ; n < G_N_ELEMENTS(cboxes); ++n)
2827 {
2828 cbox = GTK_COMBO_BOX(g_object_get_data (G_OBJECT(tbl), cboxes[n]));
2829 g_object_set_data (G_OBJECT (cbox), "block", GINT_TO_POINTER(1));
2830 gtk_combo_box_set_active (GTK_COMBO_BOX (cbox), -1);
2831 g_object_set_data (G_OBJECT (cbox), "block", GINT_TO_POINTER(0));
2832 }
2833 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
2834 return;
2835 }
2837 if (query->text)
2838 {
2839 if (query->text->font_family.value)
2840 {
2841 Gtk::TreePath path;
2842 try {
2843 path = Inkscape::FontLister::get_instance()->get_row_for_font (query->text->font_family.value);
2844 } catch (...) {
2845 return;
2846 }
2848 cbox = GTK_COMBO_BOX(g_object_get_data (G_OBJECT(tbl), "combo-box-family"));
2849 g_object_set_data (G_OBJECT (cbox), "block", GINT_TO_POINTER(1));
2850 gtk_combo_box_set_active (GTK_COMBO_BOX (cbox), gtk_tree_path_get_indices (path.gobj())[0]);
2851 g_object_set_data (G_OBJECT (cbox), "block", GINT_TO_POINTER(0));
2852 }
2854 //Style
2855 cbox = GTK_COMBO_BOX(g_object_get_data (G_OBJECT(tbl), "combo-box-style"));
2856 g_object_set_data (G_OBJECT (cbox), "block", GINT_TO_POINTER(1));
2857 gtk_combo_box_set_active (GTK_COMBO_BOX (cbox), gint(query->font_style.value));
2858 g_object_set_data (G_OBJECT (cbox), "block", GINT_TO_POINTER(0));
2860 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
2861 }
2862 }
2864 void
2865 sp_text_toolbox_selection_modified (Inkscape::Selection *selection, guint flags, GObject *tbl)
2866 {
2867 sp_text_toolbox_selection_changed (selection, tbl);
2868 }
2870 void
2871 sp_text_toolbox_subselection_changed (gpointer dragger, GObject *tbl)
2872 {
2873 sp_text_toolbox_selection_changed (NULL, tbl);
2874 }
2876 void
2877 sp_text_toolbox_family_changed (GtkComboBox *cbox,
2878 GtkWidget *tbl)
2879 {
2880 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
2882 if (GPOINTER_TO_INT(g_object_get_data (G_OBJECT (cbox), "block")) != 0) return;
2884 if (gtk_combo_box_get_active (cbox) < 0) return;
2886 SPCSSAttr *css = sp_repr_css_attr_new ();
2887 sp_repr_css_set_property (css, "font-family", gtk_combo_box_get_active_text (cbox));
2888 sp_desktop_set_style (desktop, css, true, true);
2889 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP));
2890 sp_repr_css_attr_unref (css);
2892 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
2893 }
2895 void
2896 sp_text_toolbox_family_entry_activate (GtkEntry *entry,
2897 GtkWidget *tbl)
2898 {
2899 const char* family = gtk_entry_get_text (entry);
2901 try {
2902 Gtk::TreePath path = Inkscape::FontLister::get_instance()->get_row_for_font (family);
2903 GtkComboBox *cbox = GTK_COMBO_BOX(g_object_get_data (G_OBJECT(tbl), "combo-box-family"));
2904 gtk_combo_box_set_active (cbox, gtk_tree_path_get_indices (path.gobj())[0]);
2905 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
2906 } catch (...) {
2907 //XXX: Accept it anyway and show the warning
2908 if (family && strlen (family)) gtk_widget_show_all (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
2909 }
2910 }
2912 void
2913 sp_text_toolbox_style_changed (GtkComboBox *cbox,
2914 GtkWidget *tbl)
2915 {
2916 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
2918 if (GPOINTER_TO_INT(g_object_get_data (G_OBJECT (cbox), "block")) != 0) return;
2920 static char* styles[] = { "normal", "italic" , "oblique" };
2922 SPCSSAttr *css = sp_repr_css_attr_new ();
2923 sp_repr_css_set_property (css, "font-style", styles[gtk_combo_box_get_active (cbox)]);
2924 sp_desktop_set_style (desktop, css, true, true);
2925 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP));
2926 sp_repr_css_attr_unref (css);
2927 }
2929 }//<unnamed> namespace
2931 #if 0
2932 static void cell_data_func (GtkCellLayout *cell_layout,
2933 GtkCellRenderer *cell,
2934 GtkTreeModel *tree_model,
2935 GtkTreeIter *iter,
2936 gpointer data)
2937 {
2938 char *text;
2939 gtk_tree_model_get (tree_model, iter, 0, &text, -1);
2940 g_object_set (G_OBJECT (cell), "family", text, NULL);
2941 }
2942 #endif
2944 namespace
2945 {
2946 GtkWidget*
2947 sp_text_toolbox_new (SPDesktop *desktop)
2948 {
2949 GtkWidget *tbl = gtk_hbox_new (FALSE, 0);
2951 #if 0
2952 GtkWidget *us = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "units"));
2953 GtkTooltips *tt = gtk_tooltips_new();
2954 GtkWidget *group;
2955 #endif
2957 //Font Family
2958 GtkWidget *cbox = gtk_combo_box_entry_new_text ();
2959 Glib::RefPtr<Gtk::ListStore> store = Inkscape::FontLister::get_instance()->get_font_list();
2960 gtk_cell_layout_clear (GTK_CELL_LAYOUT (cbox));
2961 GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
2962 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (cbox), cell, FALSE);
2963 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (cbox), cell, "text", 0, NULL);
2964 GtkEntryCompletion *completion = gtk_entry_completion_new ();
2965 gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (Glib::unwrap(store)));
2966 gtk_entry_completion_set_text_column (completion, 0);
2967 gtk_entry_completion_set_minimum_key_length (completion, 3); //3 characters minimum sounds reasonable
2968 g_object_set (G_OBJECT(completion), "inline-completion", TRUE, "popup-completion", TRUE, NULL);
2970 #if 0
2971 gtk_cell_layout_set_cell_data_func
2972 (GTK_CELL_LAYOUT (cbox),
2973 cell,
2974 GtkCellLayoutDataFunc (cell_data_func),
2975 tbl,
2976 NULL);
2977 #endif
2979 gtk_combo_box_set_model (GTK_COMBO_BOX (cbox), GTK_TREE_MODEL (Glib::unwrap(store)));
2980 gtk_widget_set_size_request (cbox, 250, -1);
2981 aux_toolbox_space (tbl, 1);
2982 gtk_box_pack_start (GTK_BOX (tbl), cbox, FALSE, FALSE, 0);
2983 g_object_set_data (G_OBJECT (tbl), "combo-box-family", cbox);
2984 g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (sp_text_toolbox_family_changed), tbl);
2985 g_signal_connect (G_OBJECT (GTK_BIN(cbox)->child), "activate", G_CALLBACK (sp_text_toolbox_family_entry_activate), tbl);
2986 gtk_entry_set_completion (GTK_ENTRY(GTK_BIN(cbox)->child), completion);
2988 GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
2989 aux_toolbox_space (tbl, 1);
2990 GtkWidget *box = gtk_event_box_new ();
2991 gtk_container_add (GTK_CONTAINER (box), image);
2992 gtk_box_pack_start (GTK_BOX (tbl), box, FALSE, FALSE, 4);
2993 g_object_set_data (G_OBJECT (tbl), "warning-image", box);
2994 GtkTooltips *tooltips = gtk_tooltips_new ();
2995 gtk_tooltips_set_tip (tooltips, box, _("This font is currently not installed on your system. Inkscape will use the default font instead."), "");
2996 gtk_widget_hide (GTK_WIDGET (box));
2998 //Font Style
2999 cbox = gtk_combo_box_new_text ();
3000 gtk_combo_box_append_text (GTK_COMBO_BOX (cbox), _("Normal"));
3001 gtk_combo_box_append_text (GTK_COMBO_BOX (cbox), _("Italic"));
3002 gtk_combo_box_append_text (GTK_COMBO_BOX (cbox), _("Oblique"));
3003 gtk_widget_set_size_request (cbox, 144, -1);
3004 aux_toolbox_space (tbl, 1);
3005 gtk_box_pack_start (GTK_BOX (tbl), cbox, FALSE, FALSE, 0);
3006 g_object_set_data (G_OBJECT (tbl), "combo-box-style", cbox);
3007 g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (sp_text_toolbox_style_changed), tbl);
3009 Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISTextToolbox");
3011 sigc::connection *c_selection_changed =
3012 new sigc::connection (sp_desktop_selection (desktop)->connectChanged
3013 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), (GObject*)tbl)));
3014 pool->add_connection ("selection-changed", c_selection_changed);
3016 sigc::connection *c_selection_modified =
3017 new sigc::connection (sp_desktop_selection (desktop)->connectModified
3018 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_modified), (GObject*)tbl)));
3019 pool->add_connection ("selection-modified", c_selection_modified);
3021 sigc::connection *c_subselection_changed =
3022 new sigc::connection (desktop->connectToolSubselectionChanged
3023 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_subselection_changed), (GObject*)tbl)));
3024 pool->add_connection ("tool-subselection-changed", c_subselection_changed);
3026 Inkscape::ConnectionPool::connect_destroy (G_OBJECT (tbl), pool);
3028 #if 0
3029 //Font Size
3030 {
3031 GtkWidget *c = gtk_combo_new ();
3032 gtk_combo_set_value_in_list ((GtkCombo *) c, FALSE, FALSE);
3033 gtk_combo_set_use_arrows ((GtkCombo *) c, TRUE);
3034 gtk_combo_set_use_arrows_always ((GtkCombo *) c, TRUE);
3035 gtk_widget_set_size_request (c, 64, -1);
3036 aux_toolbox_space(tbl, 1);
3037 gtk_box_pack_start (GTK_BOX (tbl), c, FALSE, FALSE, 0);
3038 }
3040 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3041 //Bold
3042 {
3043 GtkWidget *px = gtk_image_new_from_stock(GTK_STOCK_BOLD, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
3044 GtkWidget *button = gtk_toggle_button_new ();
3045 gtk_container_add (GTK_CONTAINER (button), px);
3046 gtk_widget_show(button);
3047 gtk_tooltips_set_tip (tt, button, _("Bold"), NULL);
3048 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
3049 gtk_widget_set_sensitive(button, TRUE);
3050 gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
3051 }
3054 //Italic
3055 {
3056 GtkWidget *px = gtk_image_new_from_stock(GTK_STOCK_ITALIC, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
3057 GtkWidget *button = gtk_toggle_button_new ();
3058 gtk_container_add (GTK_CONTAINER (button), px);
3059 gtk_widget_show(button);
3060 gtk_tooltips_set_tip (tt, button, _("Italics"), NULL);
3061 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
3062 gtk_widget_set_sensitive(button, TRUE);
3063 gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
3064 }
3066 //Underline
3067 {
3068 GtkWidget *px = gtk_image_new_from_stock(GTK_STOCK_UNDERLINE, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
3069 GtkWidget *button = gtk_toggle_button_new ();
3070 gtk_container_add (GTK_CONTAINER (button), px);
3071 gtk_widget_show(button);
3072 gtk_tooltips_set_tip (tt, button, _("Underline"), NULL);
3073 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
3074 gtk_widget_set_sensitive(button, FALSE);
3075 gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
3076 }
3078 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3079 // align left
3080 {
3081 GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
3082 GtkWidget *b = group = gtk_radio_button_new (NULL);
3083 gtk_container_add (GTK_CONTAINER (b), px);
3084 gtk_tooltips_set_tip (tt, b, _("Align lines left"), NULL);
3085 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3086 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3087 gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3088 }
3090 // align center
3091 {
3092 GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
3093 GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3094 gtk_container_add (GTK_CONTAINER (b), px);
3095 // TRANSLATORS: `Center' here is a verb.
3096 gtk_tooltips_set_tip (tt, b, _("Center lines"), NULL);
3097 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3098 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3099 gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3100 }
3102 // align right
3103 {
3104 GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
3105 GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3106 gtk_container_add (GTK_CONTAINER (b), px);
3107 gtk_tooltips_set_tip (tt, b, _("Align lines right"), NULL);
3108 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3109 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3110 gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3111 }
3113 // full justification
3114 {
3115 GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
3116 GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3117 gtk_container_add (GTK_CONTAINER (b), px);
3118 gtk_tooltips_set_tip (tt, b, _("Full justification"), NULL);
3119 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3120 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3121 gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3122 }
3125 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3127 // horizontal
3128 {
3129 GtkWidget *px= sp_icon_new(Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR);
3130 GtkWidget *b = group = gtk_radio_button_new (NULL);
3131 gtk_container_add (GTK_CONTAINER (b), px);
3132 gtk_tooltips_set_tip (tt, b, _("Horizontal text"), NULL);
3133 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3134 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3135 gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3136 }
3138 // vertical
3139 {
3140 GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB);
3141 GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3142 gtk_container_add (GTK_CONTAINER (b), px);
3143 gtk_tooltips_set_tip (tt, b, _("Vertical text"), NULL);
3144 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3145 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3146 gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3147 }
3149 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3151 // letter spacing
3152 {
3153 {
3154 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LETTER_SPACING);
3155 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3156 gtk_container_add (GTK_CONTAINER (hb), image);
3157 gtk_widget_show(image);
3158 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3159 }
3161 {
3162 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between letters"),
3163 "tools.text", "letter_spacing", 0.0,
3164 us, tbl, FALSE, NULL,
3165 -1000.0, 1000.0, 0.1, 0.1,
3166 sp_text_letter_changed, 0.1, 1);
3167 gtk_widget_set_size_request (hb, 45, 6);
3168 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3169 }
3170 }
3172 // line spacing
3173 {
3174 {
3175 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LINE_SPACING);
3176 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3177 gtk_container_add (GTK_CONTAINER (hb), image);
3178 gtk_widget_show(image);
3179 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3180 }
3182 {
3183 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between lines"),
3184 "tools.text", "line_spacing", 0,
3185 us, tbl, FALSE, NULL,
3186 -1000.0, 1000.0, 0.1, 0.1,
3187 sp_text_line_changed, 0.1, 1);
3188 gtk_widget_set_size_request (hb, 45, 0);
3189 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 3);
3190 }
3191 }
3193 {
3194 // horizontal kerning/vertical kerning units menu: create
3195 GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
3196 sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
3197 sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
3199 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3201 // horizontal kerning
3202 {
3203 {
3204 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_HORZ_KERN);
3205 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3206 gtk_container_add (GTK_CONTAINER (hb), image);
3207 gtk_widget_show(image);
3208 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3209 }
3211 {
3212 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Horizontal kerning"),
3213 "tools.text", "horizontal_kerning", 0,
3214 us, tbl, FALSE, NULL,
3215 -100.00, 100.00, 0.01, 0.1,
3216 sp_text_horiz_kern_changed);
3217 gtk_widget_set_size_request (hb, 45, 0);
3218 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3219 }
3220 }
3222 // vertical kerning
3223 {
3224 {
3225 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_VERT_KERN);
3226 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3227 gtk_container_add (GTK_CONTAINER (hb), image);
3228 gtk_widget_show(image);
3229 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3230 }
3232 {
3233 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Vertical kerning"),
3234 "tools.text", "vertical_kerning", 0,
3235 us, tbl, FALSE, NULL,
3236 -100.00, 100.00, 0.01, 0.1,
3237 sp_text_vert_kern_changed);
3238 gtk_widget_set_size_request (hb, 45, 0);
3239 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 5);
3240 }
3241 }
3243 // add the units menu
3244 gtk_widget_show(us);
3245 gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, 1);
3246 gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
3247 }
3249 // letter rotation
3250 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3251 {
3252 {
3253 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_ROTATION);
3254 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3255 gtk_container_add (GTK_CONTAINER (hb), image);
3256 gtk_widget_show(image);
3257 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3258 }
3259 {
3260 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Letter rotation"),
3261 "tools.text", "letter_rotation", 0,
3262 us, tbl, FALSE, NULL,
3263 -180.0, 180.0, 0.1, 0.1,
3264 sp_text_letter_rotation_changed, 0.1, 1);
3265 gtk_widget_set_size_request (hb, 45, 0);
3266 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3267 }
3268 // rotation degree label
3269 {
3270 GtkWidget *label = gtk_widget_new (GTK_TYPE_LABEL, "label", "\302\260", "xalign", 0.0, NULL);
3271 gtk_box_pack_start(GTK_BOX(tbl), label, FALSE, FALSE, 0);
3272 }
3273 }
3275 // Remove Manual Kerns
3276 {
3277 GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_REMOVE_KERNS);
3278 GtkWidget *button = gtk_button_new ();
3279 gtk_container_add (GTK_CONTAINER (button), px);
3280 gtk_widget_show(button);
3281 gtk_tooltips_set_tip (tt, button, _("Remove manual kerns"), NULL);
3282 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
3283 gtk_widget_set_sensitive(button, TRUE);
3284 gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
3285 }
3286 #endif
3288 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
3289 swatch->setWatchedTool ("tools.text", true);
3290 GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
3291 gtk_box_pack_end (GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
3292 gtk_widget_show_all (tbl);
3294 return tbl;
3296 } // end of sp_text_toolbox_new()
3298 }//<unnamed> namespace
3301 //#########################
3302 //## Connector Toolbox ##
3303 //#########################
3305 static void sp_connector_path_set_avoid(void)
3306 {
3307 cc_selection_set_avoid(true);
3308 }
3311 static void sp_connector_path_set_ignore(void)
3312 {
3313 cc_selection_set_avoid(false);
3314 }
3317 static void connector_spacing_changed(GtkAdjustment *adj, GtkWidget *tbl)
3318 {
3319 // quit if run by the _changed callbacks
3320 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
3321 return;
3322 }
3324 SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl),
3325 "desktop");
3326 SPDocument *doc = sp_desktop_document(desktop);
3328 if (!sp_document_get_undo_sensitive(doc))
3329 {
3330 return;
3331 }
3333 // in turn, prevent callbacks from responding
3334 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
3336 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
3338 sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
3339 SP_OBJECT(desktop->namedview)->updateRepr();
3341 GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
3342 for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
3343 SPItem *item = reinterpret_cast<SPItem *>(iter->data);
3344 NR::Matrix m = NR::identity();
3345 avoid_item_move(&m, item);
3346 }
3348 if (items) {
3349 g_slist_free(items);
3350 }
3352 sp_document_done(doc);
3354 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
3356 spinbutton_defocus(GTK_OBJECT(tbl));
3357 }
3360 static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
3361 gchar const *name, gchar const *old_value, gchar const *new_value,
3362 bool is_interactive, gpointer data)
3363 {
3364 GtkWidget *tbl = GTK_WIDGET(data);
3366 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
3367 return;
3368 }
3369 if (strcmp(name, "inkscape:connector-spacing") != 0) {
3370 return;
3371 }
3373 GtkAdjustment *adj = (GtkAdjustment*)
3374 gtk_object_get_data(GTK_OBJECT(tbl), "spacing");
3375 gdouble spacing = defaultConnSpacing;
3376 sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
3378 gtk_adjustment_set_value(adj, spacing);
3379 }
3382 static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
3383 NULL, /* child_added */
3384 NULL, /* child_removed */
3385 connector_tb_event_attr_changed,
3386 NULL, /* content_changed */
3387 NULL /* order_changed */
3388 };
3391 static GtkWidget *
3392 sp_connector_toolbox_new(SPDesktop *desktop)
3393 {
3394 GtkTooltips *tt = gtk_tooltips_new();
3395 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
3397 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
3398 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
3400 gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
3401 AUX_BETWEEN_BUTTON_GROUPS);
3403 sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
3404 "connector_avoid", GTK_SIGNAL_FUNC(sp_connector_path_set_avoid),
3405 tt, _("Make connectors avoid selected objects"));
3407 sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
3408 "connector_ignore", GTK_SIGNAL_FUNC(sp_connector_path_set_ignore),
3409 tt, _("Make connectors ignore selected objects"));
3411 // interval
3412 gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
3413 AUX_BETWEEN_BUTTON_GROUPS);
3415 // Spacing spinbox
3416 {
3417 GtkWidget *object_spacing = sp_tb_spinbutton(_("Spacing:"),
3418 _("The amount of space left around objects by auto-routing connectors"),
3419 "tools.connector", "spacing", 10, NULL, tbl, TRUE,
3420 "inkscape:connector-spacing", 0, 100, 1.0, 10.0,
3421 connector_spacing_changed, 1, 0);
3423 gtk_box_pack_start(GTK_BOX(tbl), object_spacing, FALSE, FALSE,
3424 AUX_SPACING);
3425 }
3427 gtk_widget_show_all(tbl);
3428 sp_set_font_size_smaller (tbl);
3430 // Code to watch for changes to the connector-spacing attribute in
3431 // the XML.
3432 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
3433 g_assert(repr != NULL);
3435 Inkscape::XML::Node *oldrepr = (Inkscape::XML::Node *)
3436 gtk_object_get_data(GTK_OBJECT(tbl), "repr");
3438 if (oldrepr) { // remove old listener
3439 sp_repr_remove_listener_by_data(oldrepr, tbl);
3440 Inkscape::GC::release(oldrepr);
3441 oldrepr = NULL;
3442 g_object_set_data(G_OBJECT(tbl), "repr", NULL);
3443 }
3445 if (repr) {
3446 g_object_set_data(G_OBJECT(tbl), "repr", repr);
3447 Inkscape::GC::anchor(repr);
3448 sp_repr_add_listener(repr, &connector_tb_repr_events, tbl);
3449 sp_repr_synthesize_events(repr, &connector_tb_repr_events, tbl);
3450 }
3452 return tbl;
3454 } // end of sp_connector_toolbox_new()
3457 /*
3458 Local Variables:
3459 mode:c++
3460 c-file-style:"stroustrup"
3461 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
3462 indent-tabs-mode:nil
3463 fill-column:99
3464 End:
3465 */
3466 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :