~ubuntu-branches/ubuntu/utopic/inkscape/utopic-proposed

« back to all changes in this revision

Viewing changes to .pc/0004-Fix_FTBFS_on_gcc-4.8.patch/src/widgets/toolbox.cpp

  • Committer: Package Import Robot
  • Author(s): Mattia Rizzolo
  • Date: 2014-01-14 15:44:58 UTC
  • mfrom: (2.5.10 sid)
  • Revision ID: package-import@ubuntu.com-20140114154458-3283675h9vtv5ccc
Tags: 0.48.4-3ubuntu1
* Merge from Debian unstable (LP: #1225013).  Remaining changes:
  - debian/control:
    + Set Ubuntu Developer as maintainer,
    + build-depend on dh-translation to handle Ubuntu translation,
    + build against liblcsm2 instead of liblcsm1,
    + demote pstoedit from Recommends to Suggests (because it's on universe),
    + add a ${python:Depends}.
  - debian/patches/0006_add_unity_quicklist_support.patch: add.
  - debian/patches/series: update.
  - debian/rules:
    + add dh_translation to handle Ubuntu translation,
    + add python2 to dh addon.
* Debian changes:
  - debian/control: make description more user-friendly (LP: #811634)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/** @file
 
2
 * @brief Controls bars for some of Inkscape's tools (for some tools,
 
3
 * they are in their own files)
 
4
 */
 
5
/* Authors:
 
6
 *   MenTaLguY <mental@rydia.net>
 
7
 *   Lauris Kaplinski <lauris@kaplinski.com>
 
8
 *   bulia byak <buliabyak@users.sf.net>
 
9
 *   Frank Felfe <innerspace@iname.com>
 
10
 *   John Cliff <simarilius@yahoo.com>
 
11
 *   David Turner <novalis@gnu.org>
 
12
 *   Josh Andler <scislac@scislac.com>
 
13
 *   Jon A. Cruz <jon@joncruz.org>
 
14
 *   Maximilian Albert <maximilian.albert@gmail.com>
 
15
 *   Tavmjong Bah <tavmjong@free.fr>
 
16
 *
 
17
 * Copyright (C) 2004 David Turner
 
18
 * Copyright (C) 2003 MenTaLguY
 
19
 * Copyright (C) 1999-2010 authors
 
20
 * Copyright (C) 2001-2002 Ximian, Inc.
 
21
 *
 
22
 * Released under GNU GPL, read the file 'COPYING' for more information
 
23
 */
 
24
 
 
25
#ifdef HAVE_CONFIG_H
 
26
# include "config.h"
 
27
#endif
 
28
 
 
29
#include <cstring>
 
30
#include <string>
 
31
 
 
32
#include <gtkmm.h>
 
33
#include <gtk/gtk.h>
 
34
#include <iostream>
 
35
#include <sstream>
 
36
#include <glibmm/i18n.h>
 
37
 
 
38
#include "../box3d-context.h"
 
39
#include "../box3d.h"
 
40
#include "../conn-avoid-ref.h"
 
41
#include "../connection-pool.h"
 
42
#include "../connector-context.h"
 
43
#include "../desktop.h"
 
44
#include "../desktop-handles.h"
 
45
#include "../desktop-style.h"
 
46
#include "../dialogs/dialog-events.h"
 
47
#include "../dialogs/text-edit.h"
 
48
#include "../document-private.h"
 
49
#include "../ege-adjustment-action.h"
 
50
#include "../ege-output-action.h"
 
51
#include "../ege-select-one-action.h"
 
52
#include "../flood-context.h"
 
53
#include "gradient-toolbar.h"
 
54
#include "../graphlayout.h"
 
55
#include "../helper/unit-menu.h"
 
56
#include "../helper/units.h"
 
57
#include "../helper/unit-tracker.h"
 
58
#include "icon.h"
 
59
#include "../ink-action.h"
 
60
#include "../ink-comboboxentry-action.h"
 
61
#include "../inkscape.h"
 
62
#include "../interface.h"
 
63
#include "../libnrtype/font-instance.h"
 
64
#include "../libnrtype/font-lister.h"
 
65
#include "../live_effects/effect.h"
 
66
#include "../live_effects/lpe-angle_bisector.h"
 
67
#include "../live_effects/lpe-line_segment.h"
 
68
#include "../lpe-tool-context.h"
 
69
#include "../mod360.h"
 
70
#include "../pen-context.h"
 
71
#include "../preferences.h"
 
72
#include "../selection-chemistry.h"
 
73
#include "../selection.h"
 
74
#include "select-toolbar.h"
 
75
#include "../shape-editor.h"
 
76
#include "../shortcuts.h"
 
77
#include "../sp-clippath.h"
 
78
#include "../sp-ellipse.h"
 
79
#include "../sp-flowtext.h"
 
80
#include "../sp-mask.h"
 
81
#include "../sp-namedview.h"
 
82
#include "../sp-rect.h"
 
83
#include "../sp-spiral.h"
 
84
#include "../sp-star.h"
 
85
#include "../sp-text.h"
 
86
#include "../style.h"
 
87
#include "../svg/css-ostringstream.h"
 
88
#include "../text-context.h"
 
89
#include "../text-editing.h"
 
90
#include "../tools-switch.h"
 
91
#include "../tweak-context.h"
 
92
#include "../spray-context.h"
 
93
#include "../ui/dialog/calligraphic-profile-rename.h"
 
94
#include "../ui/icon-names.h"
 
95
#include "../ui/tool/control-point-selection.h"
 
96
#include "../ui/tool/node-tool.h"
 
97
#include "../ui/tool/multi-path-manipulator.h"
 
98
#include "../ui/widget/style-swatch.h"
 
99
#include "../verbs.h"
 
100
#include "../widgets/button.h"
 
101
#include "../widgets/spinbutton-events.h"
 
102
#include "../widgets/spw-utilities.h"
 
103
#include "../widgets/widget-sizes.h"
 
104
#include "../xml/attribute-record.h"
 
105
#include "../xml/node-event-vector.h"
 
106
#include "../xml/repr.h"
 
107
#include "ui/uxmanager.h"
 
108
 
 
109
#include "toolbox.h"
 
110
 
 
111
//#define DEBUG_TEXT
 
112
 
 
113
using Inkscape::UnitTracker;
 
114
using Inkscape::UI::UXManager;
 
115
 
 
116
typedef void (*SetupFunction)(GtkWidget *toolbox, SPDesktop *desktop);
 
117
typedef void (*UpdateFunction)(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
 
118
 
 
119
enum BarId {
 
120
    BAR_TOOL = 0,
 
121
    BAR_AUX,
 
122
    BAR_COMMANDS,
 
123
    BAR_SNAP,
 
124
};
 
125
 
 
126
#define BAR_ID_KEY "BarIdValue"
 
127
#define HANDLE_POS_MARK "x-inkscape-pos"
 
128
 
 
129
static void       sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
 
130
static void       sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
 
131
static void       sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
 
132
static void       sp_zoom_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
 
133
static void       sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
 
134
static void       sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
 
135
static void       sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
 
136
static void       box3d_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
 
137
static void       sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
 
138
static void       sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
 
139
static void       sp_pen_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
 
140
static void       sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
 
141
static void       sp_dropper_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
 
142
static GtkWidget *sp_empty_toolbox_new(SPDesktop *desktop);
 
143
static void       sp_connector_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
 
144
static void       sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
 
145
static void       sp_eraser_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
 
146
static void       sp_text_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
 
147
static void       sp_lpetool_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
 
148
 
 
149
using Inkscape::UI::ToolboxFactory;
 
150
 
 
151
 
 
152
Inkscape::IconSize ToolboxFactory::prefToSize( Glib::ustring const &path, int base ) {
 
153
    static Inkscape::IconSize sizeChoices[] = {
 
154
        Inkscape::ICON_SIZE_LARGE_TOOLBAR,
 
155
        Inkscape::ICON_SIZE_SMALL_TOOLBAR,
 
156
        Inkscape::ICON_SIZE_MENU
 
157
    };
 
158
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
159
    int index = prefs->getIntLimited( path, base, 0, G_N_ELEMENTS(sizeChoices) );
 
160
    return sizeChoices[index];
 
161
}
 
162
 
 
163
static struct {
 
164
    gchar const *type_name;
 
165
    gchar const *data_name;
 
166
    sp_verb_t verb;
 
167
    sp_verb_t doubleclick_verb;
 
168
} const tools[] = {
 
169
    { "SPSelectContext",   "select_tool",    SP_VERB_CONTEXT_SELECT,  SP_VERB_CONTEXT_SELECT_PREFS},
 
170
    { "InkNodeTool",     "node_tool",      SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS },
 
171
    { "SPTweakContext",    "tweak_tool",     SP_VERB_CONTEXT_TWEAK, SP_VERB_CONTEXT_TWEAK_PREFS },
 
172
    { "SPSprayContext",    "spray_tool",     SP_VERB_CONTEXT_SPRAY, SP_VERB_CONTEXT_SPRAY_PREFS },
 
173
    { "SPZoomContext",     "zoom_tool",      SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS },
 
174
    { "SPRectContext",     "rect_tool",      SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS },
 
175
    { "Box3DContext",      "3dbox_tool",     SP_VERB_CONTEXT_3DBOX, SP_VERB_CONTEXT_3DBOX_PREFS },
 
176
    { "SPArcContext",      "arc_tool",       SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS },
 
177
    { "SPStarContext",     "star_tool",      SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS },
 
178
    { "SPSpiralContext",   "spiral_tool",    SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS },
 
179
    { "SPPencilContext",   "pencil_tool",    SP_VERB_CONTEXT_PENCIL, SP_VERB_CONTEXT_PENCIL_PREFS },
 
180
    { "SPPenContext",      "pen_tool",       SP_VERB_CONTEXT_PEN, SP_VERB_CONTEXT_PEN_PREFS },
 
181
    { "SPDynaDrawContext", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS },
 
182
    { "SPLPEToolContext",  "lpetool_tool",   SP_VERB_CONTEXT_LPETOOL, SP_VERB_CONTEXT_LPETOOL_PREFS },
 
183
    { "SPEraserContext",   "eraser_tool",    SP_VERB_CONTEXT_ERASER, SP_VERB_CONTEXT_ERASER_PREFS },
 
184
    { "SPFloodContext",    "paintbucket_tool",     SP_VERB_CONTEXT_PAINTBUCKET, SP_VERB_CONTEXT_PAINTBUCKET_PREFS },
 
185
    { "SPTextContext",     "text_tool",      SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS },
 
186
    { "SPConnectorContext","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS },
 
187
    { "SPGradientContext", "gradient_tool",  SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS },
 
188
    { "SPDropperContext",  "dropper_tool",   SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_DROPPER_PREFS },
 
189
    { NULL, NULL, 0, 0 }
 
190
};
 
191
 
 
192
static struct {
 
193
    gchar const *type_name;
 
194
    gchar const *data_name;
 
195
    GtkWidget *(*create_func)(SPDesktop *desktop);
 
196
    void (*prep_func)(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
 
197
    gchar const *ui_name;
 
198
    gint swatch_verb_id;
 
199
    gchar const *swatch_tool;
 
200
    gchar const *swatch_tip;
 
201
} const aux_toolboxes[] = {
 
202
    { "SPSelectContext", "select_toolbox", 0, sp_select_toolbox_prep,            "SelectToolbar",
 
203
      SP_VERB_INVALID, 0, 0},
 
204
    { "InkNodeTool",   "node_toolbox",   0, sp_node_toolbox_prep,              "NodeToolbar",
 
205
      SP_VERB_INVALID, 0, 0},
 
206
    { "SPTweakContext",   "tweak_toolbox",   0, sp_tweak_toolbox_prep,              "TweakToolbar",
 
207
      SP_VERB_CONTEXT_TWEAK_PREFS, "/tools/tweak", N_("Color/opacity used for color tweaking")},
 
208
    { "SPSprayContext",   "spray_toolbox",   0, sp_spray_toolbox_prep,              "SprayToolbar",
 
209
      SP_VERB_INVALID, 0, 0},
 
210
    { "SPZoomContext",   "zoom_toolbox",   0, sp_zoom_toolbox_prep,              "ZoomToolbar",
 
211
      SP_VERB_INVALID, 0, 0},
 
212
    { "SPStarContext",   "star_toolbox",   0, sp_star_toolbox_prep,              "StarToolbar",
 
213
      SP_VERB_CONTEXT_STAR_PREFS,   "/tools/shapes/star",     N_("Style of new stars")},
 
214
    { "SPRectContext",   "rect_toolbox",   0, sp_rect_toolbox_prep,              "RectToolbar",
 
215
      SP_VERB_CONTEXT_RECT_PREFS,   "/tools/shapes/rect",     N_("Style of new rectangles")},
 
216
    { "Box3DContext",  "3dbox_toolbox",  0, box3d_toolbox_prep,             "3DBoxToolbar",
 
217
      SP_VERB_CONTEXT_3DBOX_PREFS,  "/tools/shapes/3dbox",    N_("Style of new 3D boxes")},
 
218
    { "SPArcContext",    "arc_toolbox",    0, sp_arc_toolbox_prep,               "ArcToolbar",
 
219
      SP_VERB_CONTEXT_ARC_PREFS,    "/tools/shapes/arc",      N_("Style of new ellipses")},
 
220
    { "SPSpiralContext", "spiral_toolbox", 0, sp_spiral_toolbox_prep,            "SpiralToolbar",
 
221
      SP_VERB_CONTEXT_SPIRAL_PREFS, "/tools/shapes/spiral",   N_("Style of new spirals")},
 
222
    { "SPPencilContext", "pencil_toolbox", 0, sp_pencil_toolbox_prep,            "PencilToolbar",
 
223
      SP_VERB_CONTEXT_PENCIL_PREFS, "/tools/freehand/pencil", N_("Style of new paths created by Pencil")},
 
224
    { "SPPenContext", "pen_toolbox", 0, sp_pen_toolbox_prep,                     "PenToolbar",
 
225
      SP_VERB_CONTEXT_PEN_PREFS,    "/tools/freehand/pen",    N_("Style of new paths created by Pen")},
 
226
    { "SPDynaDrawContext", "calligraphy_toolbox", 0, sp_calligraphy_toolbox_prep,"CalligraphyToolbar",
 
227
      SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS, "/tools/calligraphic", N_("Style of new calligraphic strokes")},
 
228
    { "SPEraserContext", "eraser_toolbox", 0, sp_eraser_toolbox_prep,"EraserToolbar",
 
229
      SP_VERB_CONTEXT_ERASER_PREFS, "/tools/eraser", _("TBD")},
 
230
    { "SPLPEToolContext", "lpetool_toolbox", 0, sp_lpetool_toolbox_prep, "LPEToolToolbar",
 
231
      SP_VERB_CONTEXT_LPETOOL_PREFS, "/tools/lpetool", _("TBD")},
 
232
    { "SPTextContext",   "text_toolbox",   0, sp_text_toolbox_prep, "TextToolbar",
 
233
      SP_VERB_INVALID, 0, 0},
 
234
    { "SPDropperContext", "dropper_toolbox", 0, sp_dropper_toolbox_prep,         "DropperToolbar",
 
235
      SP_VERB_INVALID, 0, 0},
 
236
    { "SPGradientContext", "gradient_toolbox", sp_gradient_toolbox_new, 0,       0,
 
237
      SP_VERB_INVALID, 0, 0},
 
238
    { "SPConnectorContext", "connector_toolbox", 0, sp_connector_toolbox_prep,   "ConnectorToolbar",
 
239
      SP_VERB_INVALID, 0, 0},
 
240
    { "SPFloodContext",  "paintbucket_toolbox",  0, sp_paintbucket_toolbox_prep, "PaintbucketToolbar",
 
241
      SP_VERB_CONTEXT_PAINTBUCKET_PREFS, "/tools/paintbucket", N_("Style of Paint Bucket fill objects")},
 
242
    { NULL, NULL, NULL, NULL, NULL, SP_VERB_INVALID, NULL, NULL }
 
243
};
 
244
 
 
245
#define TOOLBAR_SLIDER_HINT "full"
 
246
 
 
247
static gchar const * ui_descr =
 
248
        "<ui>"
 
249
        "  <toolbar name='SelectToolbar'>"
 
250
        "    <toolitem action='EditSelectAll' />"
 
251
        "    <toolitem action='EditSelectAllInAllLayers' />"
 
252
        "    <toolitem action='EditDeselect' />"
 
253
        "    <separator />"
 
254
        "    <toolitem action='ObjectRotate90CCW' />"
 
255
        "    <toolitem action='ObjectRotate90' />"
 
256
        "    <toolitem action='ObjectFlipHorizontally' />"
 
257
        "    <toolitem action='ObjectFlipVertically' />"
 
258
        "    <separator />"
 
259
        "    <toolitem action='SelectionToBack' />"
 
260
        "    <toolitem action='SelectionLower' />"
 
261
        "    <toolitem action='SelectionRaise' />"
 
262
        "    <toolitem action='SelectionToFront' />"
 
263
        "    <separator />"
 
264
        "    <toolitem action='XAction' />"
 
265
        "    <toolitem action='YAction' />"
 
266
        "    <toolitem action='WidthAction' />"
 
267
        "    <toolitem action='LockAction' />"
 
268
        "    <toolitem action='HeightAction' />"
 
269
        "    <toolitem action='UnitsAction' />"
 
270
        "    <separator />"
 
271
        "    <toolitem action='transform_affect_label' />"
 
272
        "    <toolitem action='transform_stroke' />"
 
273
        "    <toolitem action='transform_corners' />"
 
274
        "    <toolitem action='transform_gradient' />"
 
275
        "    <toolitem action='transform_pattern' />"
 
276
        "  </toolbar>"
 
277
 
 
278
        "  <toolbar name='NodeToolbar'>"
 
279
        "    <separator />"
 
280
        "    <toolitem action='NodeInsertAction' />"
 
281
        "    <toolitem action='NodeDeleteAction' />"
 
282
        "    <separator />"
 
283
        "    <toolitem action='NodeJoinAction' />"
 
284
        "    <toolitem action='NodeBreakAction' />"
 
285
        "    <separator />"
 
286
        "    <toolitem action='NodeJoinSegmentAction' />"
 
287
        "    <toolitem action='NodeDeleteSegmentAction' />"
 
288
        "    <separator />"
 
289
        "    <toolitem action='NodeCuspAction' />"
 
290
        "    <toolitem action='NodeSmoothAction' />"
 
291
        "    <toolitem action='NodeSymmetricAction' />"
 
292
        "    <toolitem action='NodeAutoAction' />"
 
293
        "    <separator />"
 
294
        "    <toolitem action='NodeLineAction' />"
 
295
        "    <toolitem action='NodeCurveAction' />"
 
296
        "    <separator />"
 
297
        "    <toolitem action='ObjectToPath' />"
 
298
        "    <toolitem action='StrokeToPath' />"
 
299
        "    <separator />"
 
300
        "    <toolitem action='NodeXAction' />"
 
301
        "    <toolitem action='NodeYAction' />"
 
302
        "    <toolitem action='NodeUnitsAction' />"
 
303
        "    <separator />"
 
304
        "    <toolitem action='ObjectEditClipPathAction' />"
 
305
        "    <toolitem action='ObjectEditMaskPathAction' />"
 
306
        "    <toolitem action='EditNextPathEffectParameter' />"
 
307
        "    <separator />"
 
308
        "    <toolitem action='NodesShowTransformHandlesAction' />"
 
309
        "    <toolitem action='NodesShowHandlesAction' />"
 
310
        "    <toolitem action='NodesShowHelperpath' />"
 
311
        "  </toolbar>"
 
312
 
 
313
        "  <toolbar name='TweakToolbar'>"
 
314
        "    <toolitem action='TweakWidthAction' />"
 
315
        "    <separator />"
 
316
        "    <toolitem action='TweakForceAction' />"
 
317
        "    <toolitem action='TweakPressureAction' />"
 
318
        "    <separator />"
 
319
        "    <toolitem action='TweakModeAction' />"
 
320
        "    <separator />"
 
321
        "    <toolitem action='TweakFidelityAction' />"
 
322
        "    <separator />"
 
323
        "    <toolitem action='TweakChannelsLabel' />"
 
324
        "    <toolitem action='TweakDoH' />"
 
325
        "    <toolitem action='TweakDoS' />"
 
326
        "    <toolitem action='TweakDoL' />"
 
327
        "    <toolitem action='TweakDoO' />"
 
328
        "  </toolbar>"
 
329
 
 
330
        "  <toolbar name='SprayToolbar'>"
 
331
        "    <toolitem action='SprayModeAction' />"
 
332
        "    <separator />"
 
333
        "    <separator />"
 
334
        "    <toolitem action='SprayWidthAction' />"
 
335
        "    <toolitem action='SprayPressureAction' />"
 
336
        "    <toolitem action='SprayPopulationAction' />"
 
337
        "    <separator />"
 
338
        "    <toolitem action='SprayRotationAction' />"
 
339
        "    <toolitem action='SprayScaleAction' />"
 
340
        "    <separator />"
 
341
        "    <toolitem action='SprayStandard_deviationAction' />"
 
342
        "    <toolitem action='SprayMeanAction' />"
 
343
        "  </toolbar>"
 
344
 
 
345
        "  <toolbar name='ZoomToolbar'>"
 
346
        "    <toolitem action='ZoomIn' />"
 
347
        "    <toolitem action='ZoomOut' />"
 
348
        "    <separator />"
 
349
        "    <toolitem action='Zoom1:0' />"
 
350
        "    <toolitem action='Zoom1:2' />"
 
351
        "    <toolitem action='Zoom2:1' />"
 
352
        "    <separator />"
 
353
        "    <toolitem action='ZoomSelection' />"
 
354
        "    <toolitem action='ZoomDrawing' />"
 
355
        "    <toolitem action='ZoomPage' />"
 
356
        "    <toolitem action='ZoomPageWidth' />"
 
357
        "    <separator />"
 
358
        "    <toolitem action='ZoomPrev' />"
 
359
        "    <toolitem action='ZoomNext' />"
 
360
        "  </toolbar>"
 
361
 
 
362
        "  <toolbar name='StarToolbar'>"
 
363
        "    <separator />"
 
364
        "    <toolitem action='StarStateAction' />"
 
365
        "    <separator />"
 
366
        "    <toolitem action='FlatAction' />"
 
367
        "    <separator />"
 
368
        "    <toolitem action='MagnitudeAction' />"
 
369
        "    <toolitem action='SpokeAction' />"
 
370
        "    <toolitem action='RoundednessAction' />"
 
371
        "    <toolitem action='RandomizationAction' />"
 
372
        "    <separator />"
 
373
        "    <toolitem action='StarResetAction' />"
 
374
        "  </toolbar>"
 
375
 
 
376
        "  <toolbar name='RectToolbar'>"
 
377
        "    <toolitem action='RectStateAction' />"
 
378
        "    <toolitem action='RectWidthAction' />"
 
379
        "    <toolitem action='RectHeightAction' />"
 
380
        "    <toolitem action='RadiusXAction' />"
 
381
        "    <toolitem action='RadiusYAction' />"
 
382
        "    <toolitem action='RectUnitsAction' />"
 
383
        "    <separator />"
 
384
        "    <toolitem action='RectResetAction' />"
 
385
        "  </toolbar>"
 
386
 
 
387
        "  <toolbar name='3DBoxToolbar'>"
 
388
        "    <toolitem action='3DBoxAngleXAction' />"
 
389
        "    <toolitem action='3DBoxVPXStateAction' />"
 
390
        "    <separator />"
 
391
        "    <toolitem action='3DBoxAngleYAction' />"
 
392
        "    <toolitem action='3DBoxVPYStateAction' />"
 
393
        "    <separator />"
 
394
        "    <toolitem action='3DBoxAngleZAction' />"
 
395
        "    <toolitem action='3DBoxVPZStateAction' />"
 
396
        "  </toolbar>"
 
397
 
 
398
        "  <toolbar name='SpiralToolbar'>"
 
399
        "    <toolitem action='SpiralStateAction' />"
 
400
        "    <toolitem action='SpiralRevolutionAction' />"
 
401
        "    <toolitem action='SpiralExpansionAction' />"
 
402
        "    <toolitem action='SpiralT0Action' />"
 
403
        "    <separator />"
 
404
        "    <toolitem action='SpiralResetAction' />"
 
405
        "  </toolbar>"
 
406
 
 
407
        "  <toolbar name='PenToolbar'>"
 
408
        "    <toolitem action='FreehandModeActionPen' />"
 
409
        "    <separator />"
 
410
        "    <toolitem action='SetPenShapeAction'/>"
 
411
        "  </toolbar>"
 
412
 
 
413
        "  <toolbar name='PencilToolbar'>"
 
414
        "    <toolitem action='FreehandModeActionPencil' />"
 
415
        "    <separator />"
 
416
        "    <toolitem action='PencilToleranceAction' />"
 
417
        "    <separator />"
 
418
        "    <toolitem action='PencilResetAction' />"
 
419
        "    <separator />"
 
420
        "    <toolitem action='SetPencilShapeAction'/>"
 
421
        "  </toolbar>"
 
422
 
 
423
        "  <toolbar name='CalligraphyToolbar'>"
 
424
        "    <separator />"
 
425
        "    <toolitem action='SetProfileAction'/>"
 
426
        "    <separator />"
 
427
        "    <toolitem action='CalligraphyWidthAction' />"
 
428
        "    <toolitem action='PressureAction' />"
 
429
        "    <toolitem action='TraceAction' />"
 
430
        "    <toolitem action='ThinningAction' />"
 
431
        "    <separator />"
 
432
        "    <toolitem action='AngleAction' />"
 
433
        "    <toolitem action='TiltAction' />"
 
434
        "    <toolitem action='FixationAction' />"
 
435
        "    <separator />"
 
436
        "    <toolitem action='CapRoundingAction' />"
 
437
        "    <separator />"
 
438
        "    <toolitem action='TremorAction' />"
 
439
        "    <toolitem action='WiggleAction' />"
 
440
        "    <toolitem action='MassAction' />"
 
441
        "    <separator />"
 
442
        "  </toolbar>"
 
443
 
 
444
        "  <toolbar name='ArcToolbar'>"
 
445
        "    <toolitem action='ArcStateAction' />"
 
446
        "    <separator />"
 
447
        "    <toolitem action='ArcStartAction' />"
 
448
        "    <toolitem action='ArcEndAction' />"
 
449
        "    <separator />"
 
450
        "    <toolitem action='ArcOpenAction' />"
 
451
        "    <separator />"
 
452
        "    <toolitem action='ArcResetAction' />"
 
453
        "    <separator />"
 
454
        "  </toolbar>"
 
455
 
 
456
        "  <toolbar name='PaintbucketToolbar'>"
 
457
        "    <toolitem action='ChannelsAction' />"
 
458
        "    <separator />"
 
459
        "    <toolitem action='ThresholdAction' />"
 
460
        "    <separator />"
 
461
        "    <toolitem action='OffsetAction' />"
 
462
        "    <toolitem action='PaintbucketUnitsAction' />"
 
463
        "    <separator />"
 
464
        "    <toolitem action='AutoGapAction' />"
 
465
        "    <separator />"
 
466
        "    <toolitem action='PaintbucketResetAction' />"
 
467
        "  </toolbar>"
 
468
 
 
469
        "  <toolbar name='EraserToolbar'>"
 
470
        "    <toolitem action='EraserWidthAction' />"
 
471
        "    <separator />"
 
472
        "    <toolitem action='EraserModeAction' />"
 
473
        "  </toolbar>"
 
474
 
 
475
        "  <toolbar name='TextToolbar'>"
 
476
        "    <toolitem action='TextFontFamilyAction' />"
 
477
        "    <toolitem action='TextFontSizeAction' />"
 
478
        "    <toolitem action='TextBoldAction' />"
 
479
        "    <toolitem action='TextItalicAction' />"
 
480
        "    <separator />"
 
481
        "    <toolitem action='TextAlignAction' />"
 
482
        "    <separator />"
 
483
        "    <toolitem action='TextSuperscriptAction' />"
 
484
        "    <toolitem action='TextSubscriptAction' />"
 
485
        "    <separator />"
 
486
        "    <toolitem action='TextLineHeightAction' />"
 
487
        "    <toolitem action='TextLetterSpacingAction' />"
 
488
        "    <toolitem action='TextWordSpacingAction' />"
 
489
        "    <toolitem action='TextDxAction' />"
 
490
        "    <toolitem action='TextDyAction' />"
 
491
        "    <toolitem action='TextRotationAction' />"
 
492
        "    <separator />"
 
493
        "    <toolitem action='TextOrientationAction' />"
 
494
        "  </toolbar>"
 
495
 
 
496
        "  <toolbar name='LPEToolToolbar'>"
 
497
        "    <toolitem action='LPEToolModeAction' />"
 
498
        "    <separator />"
 
499
        "    <toolitem action='LPEShowBBoxAction' />"
 
500
        "    <toolitem action='LPEBBoxFromSelectionAction' />"
 
501
        "    <separator />"
 
502
        "    <toolitem action='LPELineSegmentAction' />"
 
503
        "    <separator />"
 
504
        "    <toolitem action='LPEMeasuringAction' />"
 
505
        "    <toolitem action='LPEToolUnitsAction' />"
 
506
        "    <separator />"
 
507
        "    <toolitem action='LPEOpenLPEDialogAction' />"
 
508
        "  </toolbar>"
 
509
 
 
510
        "  <toolbar name='DropperToolbar'>"
 
511
        "    <toolitem action='DropperOpacityAction' />"
 
512
        "    <toolitem action='DropperPickAlphaAction' />"
 
513
        "    <toolitem action='DropperSetAlphaAction' />"
 
514
        "  </toolbar>"
 
515
 
 
516
        "  <toolbar name='ConnectorToolbar'>"
 
517
//        "    <toolitem action='ConnectorEditModeAction' />"
 
518
        "    <toolitem action='ConnectorAvoidAction' />"
 
519
        "    <toolitem action='ConnectorIgnoreAction' />"
 
520
        "    <toolitem action='ConnectorOrthogonalAction' />"
 
521
        "    <toolitem action='ConnectorCurvatureAction' />"
 
522
        "    <toolitem action='ConnectorSpacingAction' />"
 
523
        "    <toolitem action='ConnectorGraphAction' />"
 
524
        "    <toolitem action='ConnectorLengthAction' />"
 
525
        "    <toolitem action='ConnectorDirectedAction' />"
 
526
        "    <toolitem action='ConnectorOverlapAction' />"
 
527
//        "    <toolitem action='ConnectorNewConnPointAction' />"
 
528
//        "    <toolitem action='ConnectorRemoveConnPointAction' />"
 
529
        "  </toolbar>"
 
530
 
 
531
        "</ui>"
 
532
;
 
533
 
 
534
static Glib::RefPtr<Gtk::ActionGroup> create_or_fetch_actions( SPDesktop* desktop );
 
535
 
 
536
static void setup_snap_toolbox(GtkWidget *toolbox, SPDesktop *desktop);
 
537
 
 
538
static void setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop);
 
539
static void update_tool_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
 
540
 
 
541
static void setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop);
 
542
static void update_aux_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
 
543
 
 
544
static void setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop);
 
545
static void update_commands_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
 
546
 
 
547
static GtkWidget * sp_toolbox_button_new_from_verb_with_doubleclick( GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
 
548
                                                                     Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
 
549
                                                                     Inkscape::UI::View::View *view, GtkTooltips *tt);
 
550
 
 
551
class VerbAction : public Gtk::Action {
 
552
public:
 
553
    static Glib::RefPtr<VerbAction> create(Inkscape::Verb* verb, Inkscape::Verb* verb2, Inkscape::UI::View::View *view, GtkTooltips *tooltips);
 
554
 
 
555
    virtual ~VerbAction();
 
556
    virtual void set_active(bool active = true);
 
557
 
 
558
protected:
 
559
    virtual Gtk::Widget* create_menu_item_vfunc();
 
560
    virtual Gtk::Widget* create_tool_item_vfunc();
 
561
 
 
562
    virtual void connect_proxy_vfunc(Gtk::Widget* proxy);
 
563
    virtual void disconnect_proxy_vfunc(Gtk::Widget* proxy);
 
564
 
 
565
    virtual void on_activate();
 
566
 
 
567
private:
 
568
    Inkscape::Verb* verb;
 
569
    Inkscape::Verb* verb2;
 
570
    Inkscape::UI::View::View *view;
 
571
    GtkTooltips *tooltips;
 
572
    bool active;
 
573
 
 
574
    VerbAction(Inkscape::Verb* verb, Inkscape::Verb* verb2, Inkscape::UI::View::View *view, GtkTooltips *tooltips);
 
575
};
 
576
 
 
577
 
 
578
Glib::RefPtr<VerbAction> VerbAction::create(Inkscape::Verb* verb, Inkscape::Verb* verb2, Inkscape::UI::View::View *view, GtkTooltips *tooltips)
 
579
{
 
580
    Glib::RefPtr<VerbAction> result;
 
581
    SPAction *action = verb->get_action(view);
 
582
    if ( action ) {
 
583
        //SPAction* action2 = verb2 ? verb2->get_action(view) : 0;
 
584
        result = Glib::RefPtr<VerbAction>(new VerbAction(verb, verb2, view, tooltips));
 
585
    }
 
586
 
 
587
    return result;
 
588
}
 
589
 
 
590
VerbAction::VerbAction(Inkscape::Verb* verb, Inkscape::Verb* verb2, Inkscape::UI::View::View *view, GtkTooltips *tooltips) :
 
591
    Gtk::Action(Glib::ustring(verb->get_id()), Gtk::StockID(verb->get_image()), Glib::ustring(_(verb->get_name())), Glib::ustring(_(verb->get_tip()))),
 
592
    verb(verb),
 
593
    verb2(verb2),
 
594
    view(view),
 
595
    tooltips(tooltips),
 
596
    active(false)
 
597
{
 
598
}
 
599
 
 
600
VerbAction::~VerbAction()
 
601
{
 
602
}
 
603
 
 
604
Gtk::Widget* VerbAction::create_menu_item_vfunc()
 
605
{
 
606
// First call in to get the icon rendered if present in SVG
 
607
    Gtk::Widget *widget = sp_icon_get_icon( property_stock_id().get_value().get_string(), Inkscape::ICON_SIZE_MENU );
 
608
    delete widget;
 
609
    widget = 0;
 
610
 
 
611
    Gtk::Widget* widg = Gtk::Action::create_menu_item_vfunc();
 
612
//     g_message("create_menu_item_vfunc() = %p  for '%s'", widg, verb->get_id());
 
613
    return widg;
 
614
}
 
615
 
 
616
Gtk::Widget* VerbAction::create_tool_item_vfunc()
 
617
{
 
618
//     Gtk::Widget* widg = Gtk::Action::create_tool_item_vfunc();
 
619
    Inkscape::IconSize toolboxSize = ToolboxFactory::prefToSize("/toolbox/tools/small");
 
620
    GtkWidget* toolbox = 0;
 
621
    GtkWidget *button = sp_toolbox_button_new_from_verb_with_doubleclick( toolbox, toolboxSize,
 
622
                                                                          SP_BUTTON_TYPE_TOGGLE,
 
623
                                                                          verb,
 
624
                                                                          verb2,
 
625
                                                                          view,
 
626
                                                                          tooltips );
 
627
    if ( active ) {
 
628
        sp_button_toggle_set_down( SP_BUTTON(button), active);
 
629
    }
 
630
    gtk_widget_show_all( button );
 
631
    Gtk::Widget* wrapped = Glib::wrap(button);
 
632
    Gtk::ToolItem* holder = Gtk::manage(new Gtk::ToolItem());
 
633
    holder->add(*wrapped);
 
634
 
 
635
//     g_message("create_tool_item_vfunc() = %p  for '%s'", holder, verb->get_id());
 
636
    return holder;
 
637
}
 
638
 
 
639
void VerbAction::connect_proxy_vfunc(Gtk::Widget* proxy)
 
640
{
 
641
//     g_message("connect_proxy_vfunc(%p)  for '%s'", proxy, verb->get_id());
 
642
    Gtk::Action::connect_proxy_vfunc(proxy);
 
643
}
 
644
 
 
645
void VerbAction::disconnect_proxy_vfunc(Gtk::Widget* proxy)
 
646
{
 
647
//     g_message("disconnect_proxy_vfunc(%p)  for '%s'", proxy, verb->get_id());
 
648
    Gtk::Action::disconnect_proxy_vfunc(proxy);
 
649
}
 
650
 
 
651
void VerbAction::set_active(bool active)
 
652
{
 
653
    this->active = active;
 
654
    Glib::SListHandle<Gtk::Widget*> proxies = get_proxies();
 
655
    for ( Glib::SListHandle<Gtk::Widget*>::iterator it = proxies.begin(); it != proxies.end(); ++it ) {
 
656
        Gtk::ToolItem* ti = dynamic_cast<Gtk::ToolItem*>(*it);
 
657
        if (ti) {
 
658
            // *should* have one child that is the SPButton
 
659
            Gtk::Widget* child = ti->get_child();
 
660
            if ( child && SP_IS_BUTTON(child->gobj()) ) {
 
661
                SPButton* button = SP_BUTTON(child->gobj());
 
662
                sp_button_toggle_set_down( button, active );
 
663
            }
 
664
        }
 
665
    }
 
666
}
 
667
 
 
668
void VerbAction::on_activate()
 
669
{
 
670
    if ( verb ) {
 
671
        SPAction *action = verb->get_action(view);
 
672
        if ( action ) {
 
673
            sp_action_perform(action, 0);
 
674
        }
 
675
    }
 
676
}
 
677
 
 
678
/* Global text entry widgets necessary for update */
 
679
/* GtkWidget *dropper_rgb_entry,
 
680
          *dropper_opacity_entry ; */
 
681
// should be made a private member once this is converted to class
 
682
 
 
683
static void delete_connection(GObject * /*obj*/, sigc::connection *connection)
 
684
{
 
685
    connection->disconnect();
 
686
    delete connection;
 
687
}
 
688
 
 
689
static void purge_repr_listener( GObject* /*obj*/, GObject* tbl )
 
690
{
 
691
    Inkscape::XML::Node* oldrepr = reinterpret_cast<Inkscape::XML::Node *>( g_object_get_data( tbl, "repr" ) );
 
692
    if (oldrepr) { // remove old listener
 
693
        sp_repr_remove_listener_by_data(oldrepr, tbl);
 
694
        Inkscape::GC::release(oldrepr);
 
695
        oldrepr = 0;
 
696
        g_object_set_data( tbl, "repr", NULL );
 
697
    }
 
698
}
 
699
 
 
700
// ------------------------------------------------------
 
701
 
 
702
/**
 
703
 * A simple mediator class that keeps UI controls matched to the preference values they set.
 
704
 */
 
705
class PrefPusher : public Inkscape::Preferences::Observer
 
706
{
 
707
public:
 
708
    /**
 
709
     * Constructor for a boolean value that syncs to the supplied path.
 
710
     * Initializes the widget to the current preference stored state and registers callbacks
 
711
     * for widget changes and preference changes.
 
712
     *
 
713
     * @param act the widget to synchronize preference with.
 
714
     * @param path the path to the preference the widget is synchronized with.
 
715
     * @param callback function to invoke when changes are pushed.
 
716
     * @param cbData data to be passed on to the callback function.
 
717
     */
 
718
    PrefPusher( GtkToggleAction *act, Glib::ustring const &path, void (*callback)(GObject*) = 0, GObject *cbData = 0 );
 
719
 
 
720
    /**
 
721
     * Destructor that unregisters the preference callback.
 
722
     */
 
723
    virtual ~PrefPusher();
 
724
 
 
725
    /**
 
726
     * Callback method invoked when the preference setting changes.
 
727
     */
 
728
    virtual void notify(Inkscape::Preferences::Entry const &new_val);
 
729
 
 
730
private:
 
731
    /**
 
732
     * Callback hook invoked when the widget changes.
 
733
     *
 
734
     * @param act the toggle action widget that was changed.
 
735
     * @param self the PrefPusher instance the callback was registered to.
 
736
     */
 
737
    static void toggleCB( GtkToggleAction *act, PrefPusher *self );
 
738
 
 
739
    /**
 
740
     * Method to handle the widget change.
 
741
     */
 
742
    void handleToggled();
 
743
 
 
744
    GtkToggleAction *act;
 
745
    void (*callback)(GObject*);
 
746
    GObject *cbData;
 
747
    bool freeze;
 
748
};
 
749
 
 
750
PrefPusher::PrefPusher( GtkToggleAction *act, Glib::ustring const &path, void (*callback)(GObject*), GObject *cbData ) :
 
751
    Observer(path),
 
752
    act(act),
 
753
    callback(callback),
 
754
    cbData(cbData),
 
755
    freeze(false)
 
756
{
 
757
    g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggleCB), this);
 
758
    freeze = true;
 
759
    gtk_toggle_action_set_active( act, Inkscape::Preferences::get()->getBool(observed_path) );
 
760
    freeze = false;
 
761
 
 
762
    Inkscape::Preferences::get()->addObserver(*this);
 
763
}
 
764
 
 
765
PrefPusher::~PrefPusher()
 
766
{
 
767
    Inkscape::Preferences::get()->removeObserver(*this);
 
768
}
 
769
 
 
770
void PrefPusher::toggleCB( GtkToggleAction * /*act*/, PrefPusher *self )
 
771
{
 
772
    if (self) {
 
773
        self->handleToggled();
 
774
    }
 
775
}
 
776
 
 
777
void PrefPusher::handleToggled()
 
778
{
 
779
    if (!freeze) {
 
780
        freeze = true;
 
781
        Inkscape::Preferences::get()->setBool(observed_path, gtk_toggle_action_get_active( act ));
 
782
        if (callback) {
 
783
            (*callback)(cbData);
 
784
        }
 
785
        freeze = false;
 
786
    }
 
787
}
 
788
 
 
789
void PrefPusher::notify(Inkscape::Preferences::Entry const &newVal)
 
790
{
 
791
    bool newBool = newVal.getBool();
 
792
    bool oldBool = gtk_toggle_action_get_active(act);
 
793
 
 
794
    if (!freeze && (newBool != oldBool)) {
 
795
        gtk_toggle_action_set_active( act, newBool );
 
796
    }
 
797
}
 
798
 
 
799
static void delete_prefspusher(GtkObject * /*obj*/, PrefPusher *watcher )
 
800
{
 
801
    delete watcher;
 
802
}
 
803
 
 
804
// ------------------------------------------------------
 
805
 
 
806
 
 
807
GtkWidget * sp_toolbox_button_new_from_verb_with_doubleclick(GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
 
808
                                                             Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
 
809
                                                             Inkscape::UI::View::View *view, GtkTooltips *tt)
 
810
{
 
811
    SPAction *action = verb->get_action(view);
 
812
    if (!action) {
 
813
        return NULL;
 
814
    }
 
815
 
 
816
    SPAction *doubleclick_action;
 
817
    if (doubleclick_verb) {
 
818
        doubleclick_action = doubleclick_verb->get_action(view);
 
819
    } else {
 
820
        doubleclick_action = NULL;
 
821
    }
 
822
 
 
823
    /* fixme: Handle sensitive/unsensitive */
 
824
    /* fixme: Implement sp_button_new_from_action */
 
825
    GtkWidget *b = sp_button_new(size, type, action, doubleclick_action, tt);
 
826
    gtk_widget_show(b);
 
827
 
 
828
 
 
829
    unsigned int shortcut = sp_shortcut_get_primary(verb);
 
830
    if (shortcut != GDK_VoidSymbol) {
 
831
        gchar *key = sp_shortcut_get_label(shortcut);
 
832
        gchar *tip = g_strdup_printf ("%s (%s)", action->tip, key);
 
833
        if ( t ) {
 
834
            gtk_toolbar_append_widget( GTK_TOOLBAR(t), b, tip, 0 );
 
835
        }
 
836
        g_free(tip);
 
837
        g_free(key);
 
838
    } else {
 
839
        if ( t ) {
 
840
            gtk_toolbar_append_widget( GTK_TOOLBAR(t), b, action->tip, 0 );
 
841
        }
 
842
    }
 
843
 
 
844
    return b;
 
845
}
 
846
 
 
847
 
 
848
static void trigger_sp_action( GtkAction* /*act*/, gpointer user_data )
 
849
{
 
850
    SPAction* targetAction = SP_ACTION(user_data);
 
851
    if ( targetAction ) {
 
852
        sp_action_perform( targetAction, NULL );
 
853
    }
 
854
}
 
855
 
 
856
static void sp_action_action_set_sensitive(SPAction * /*action*/, unsigned int sensitive, void *data)
 
857
{
 
858
    if ( data ) {
 
859
        GtkAction* act = GTK_ACTION(data);
 
860
        gtk_action_set_sensitive( act, sensitive );
 
861
    }
 
862
}
 
863
 
 
864
static SPActionEventVector action_event_vector = {
 
865
    {NULL},
 
866
    NULL,
 
867
    NULL,
 
868
    sp_action_action_set_sensitive,
 
869
    NULL,
 
870
    NULL
 
871
};
 
872
 
 
873
static GtkAction* create_action_for_verb( Inkscape::Verb* verb, Inkscape::UI::View::View* view, Inkscape::IconSize size )
 
874
{
 
875
    GtkAction* act = 0;
 
876
 
 
877
    SPAction* targetAction = verb->get_action(view);
 
878
    InkAction* inky = ink_action_new( verb->get_id(), _(verb->get_name()), verb->get_tip(), verb->get_image(), size  );
 
879
    act = GTK_ACTION(inky);
 
880
    gtk_action_set_sensitive( act, targetAction->sensitive );
 
881
 
 
882
    g_signal_connect( G_OBJECT(inky), "activate", GTK_SIGNAL_FUNC(trigger_sp_action), targetAction );
 
883
 
 
884
    SPAction*rebound = dynamic_cast<SPAction *>( nr_object_ref( dynamic_cast<NRObject *>(targetAction) ) );
 
885
    nr_active_object_add_listener( (NRActiveObject *)rebound, (NRObjectEventVector *)&action_event_vector, sizeof(SPActionEventVector), inky );
 
886
 
 
887
    return act;
 
888
}
 
889
 
 
890
static Glib::RefPtr<Gtk::ActionGroup> create_or_fetch_actions( SPDesktop* desktop )
 
891
{
 
892
    Inkscape::UI::View::View *view = desktop;
 
893
    gint verbsToUse[] = {
 
894
        // disabled until we have icons for them:
 
895
        //find
 
896
        //SP_VERB_EDIT_TILE,
 
897
        //SP_VERB_EDIT_UNTILE,
 
898
        SP_VERB_DIALOG_ALIGN_DISTRIBUTE,
 
899
        SP_VERB_DIALOG_DISPLAY,
 
900
        SP_VERB_DIALOG_FILL_STROKE,
 
901
        SP_VERB_DIALOG_NAMEDVIEW,
 
902
        SP_VERB_DIALOG_TEXT,
 
903
        SP_VERB_DIALOG_XML_EDITOR,
 
904
        SP_VERB_DIALOG_LAYERS,
 
905
        SP_VERB_EDIT_CLONE,
 
906
        SP_VERB_EDIT_COPY,
 
907
        SP_VERB_EDIT_CUT,
 
908
        SP_VERB_EDIT_DUPLICATE,
 
909
        SP_VERB_EDIT_PASTE,
 
910
        SP_VERB_EDIT_REDO,
 
911
        SP_VERB_EDIT_UNDO,
 
912
        SP_VERB_EDIT_UNLINK_CLONE,
 
913
        SP_VERB_FILE_EXPORT,
 
914
        SP_VERB_FILE_IMPORT,
 
915
        SP_VERB_FILE_NEW,
 
916
        SP_VERB_FILE_OPEN,
 
917
        SP_VERB_FILE_PRINT,
 
918
        SP_VERB_FILE_SAVE,
 
919
        SP_VERB_OBJECT_TO_CURVE,
 
920
        SP_VERB_SELECTION_GROUP,
 
921
        SP_VERB_SELECTION_OUTLINE,
 
922
        SP_VERB_SELECTION_UNGROUP,
 
923
        SP_VERB_ZOOM_1_1,
 
924
        SP_VERB_ZOOM_1_2,
 
925
        SP_VERB_ZOOM_2_1,
 
926
        SP_VERB_ZOOM_DRAWING,
 
927
        SP_VERB_ZOOM_IN,
 
928
        SP_VERB_ZOOM_NEXT,
 
929
        SP_VERB_ZOOM_OUT,
 
930
        SP_VERB_ZOOM_PAGE,
 
931
        SP_VERB_ZOOM_PAGE_WIDTH,
 
932
        SP_VERB_ZOOM_PREV,
 
933
        SP_VERB_ZOOM_SELECTION,
 
934
    };
 
935
 
 
936
    Inkscape::IconSize toolboxSize = ToolboxFactory::prefToSize("/toolbox/small");
 
937
 
 
938
    static std::map<SPDesktop*, Glib::RefPtr<Gtk::ActionGroup> > groups;
 
939
    Glib::RefPtr<Gtk::ActionGroup> mainActions;
 
940
    if ( groups.find(desktop) != groups.end() ) {
 
941
        mainActions = groups[desktop];
 
942
    }
 
943
 
 
944
    if ( !mainActions ) {
 
945
        mainActions = Gtk::ActionGroup::create("main");
 
946
        groups[desktop] = mainActions;
 
947
    }
 
948
 
 
949
    for ( guint i = 0; i < G_N_ELEMENTS(verbsToUse); i++ ) {
 
950
        Inkscape::Verb* verb = Inkscape::Verb::get(verbsToUse[i]);
 
951
        if ( verb ) {
 
952
            if (!mainActions->get_action(verb->get_id())) {
 
953
                GtkAction* act = create_action_for_verb( verb, view, toolboxSize );
 
954
                mainActions->add(Glib::wrap(act));
 
955
            }
 
956
        }
 
957
    }
 
958
 
 
959
    if ( !mainActions->get_action("ToolZoom") ) {
 
960
        GtkTooltips *tt = gtk_tooltips_new();
 
961
        for ( guint i = 0; i < G_N_ELEMENTS(tools) && tools[i].type_name; i++ ) {
 
962
            Glib::RefPtr<VerbAction> va = VerbAction::create(Inkscape::Verb::get(tools[i].verb), Inkscape::Verb::get(tools[i].doubleclick_verb), view, tt);
 
963
            if ( va ) {
 
964
                mainActions->add(va);
 
965
                if ( i == 0 ) {
 
966
                    va->set_active(true);
 
967
                }
 
968
            }
 
969
        }
 
970
    }
 
971
 
 
972
    return mainActions;
 
973
}
 
974
 
 
975
 
 
976
static void handlebox_detached(GtkHandleBox* /*handlebox*/, GtkWidget* widget, gpointer /*userData*/)
 
977
{
 
978
    gtk_widget_set_size_request( widget,
 
979
                                 widget->allocation.width,
 
980
                                 widget->allocation.height );
 
981
}
 
982
 
 
983
static void handlebox_attached(GtkHandleBox* /*handlebox*/, GtkWidget* widget, gpointer /*userData*/)
 
984
{
 
985
    gtk_widget_set_size_request( widget, -1, -1 );
 
986
}
 
987
 
 
988
static GtkWidget* toolboxNewCommon( GtkWidget* tb, BarId id, GtkPositionType handlePos )
 
989
{
 
990
    g_object_set_data(G_OBJECT(tb), "desktop", NULL);
 
991
 
 
992
    gtk_widget_set_sensitive(tb, FALSE);
 
993
 
 
994
    GtkWidget *hb = 0;
 
995
    gboolean forceFloatAllowed = Inkscape::Preferences::get()->getBool("/options/workarounds/floatallowed", false);
 
996
    if ( UXManager::getInstance()->isFloatWindowProblem() && !forceFloatAllowed ) {
 
997
        hb = gtk_event_box_new(); // A simple, neutral container.
 
998
    } else {
 
999
        hb = gtk_handle_box_new();
 
1000
        gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), handlePos);
 
1001
        gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
 
1002
        gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
 
1003
    }
 
1004
 
 
1005
    gtk_container_add(GTK_CONTAINER(hb), tb);
 
1006
    gtk_widget_show(GTK_WIDGET(tb));
 
1007
 
 
1008
    sigc::connection* conn = new sigc::connection;
 
1009
    g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
 
1010
 
 
1011
    if ( GTK_IS_HANDLE_BOX(hb) ) {
 
1012
        g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(handlebox_detached), static_cast<gpointer>(0));
 
1013
        g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(handlebox_attached), static_cast<gpointer>(0));
 
1014
    }
 
1015
 
 
1016
    gpointer val = GINT_TO_POINTER(id);
 
1017
    g_object_set_data(G_OBJECT(hb), BAR_ID_KEY, val);
 
1018
 
 
1019
    return hb;
 
1020
}
 
1021
 
 
1022
GtkWidget *ToolboxFactory::createToolToolbox()
 
1023
{
 
1024
    GtkWidget *tb = gtk_vbox_new(FALSE, 0);
 
1025
 
 
1026
    return toolboxNewCommon( tb, BAR_TOOL, GTK_POS_TOP );
 
1027
}
 
1028
 
 
1029
GtkWidget *ToolboxFactory::createAuxToolbox()
 
1030
{
 
1031
    GtkWidget *tb = gtk_vbox_new(FALSE, 0);
 
1032
 
 
1033
    return toolboxNewCommon( tb, BAR_AUX, GTK_POS_LEFT );
 
1034
}
 
1035
 
 
1036
//####################################
 
1037
//# Commands Bar
 
1038
//####################################
 
1039
 
 
1040
GtkWidget *ToolboxFactory::createCommandsToolbox()
 
1041
{
 
1042
    GtkWidget *tb = gtk_vbox_new(FALSE, 0);
 
1043
 
 
1044
    return toolboxNewCommon( tb, BAR_COMMANDS, GTK_POS_LEFT );
 
1045
}
 
1046
 
 
1047
GtkWidget *ToolboxFactory::createSnapToolbox()
 
1048
{
 
1049
    GtkWidget *tb = gtk_vbox_new(FALSE, 0);
 
1050
 
 
1051
    return toolboxNewCommon( tb, BAR_SNAP, GTK_POS_LEFT );
 
1052
}
 
1053
 
 
1054
static EgeAdjustmentAction * create_adjustment_action( gchar const *name,
 
1055
                                                       gchar const *label, gchar const *shortLabel, gchar const *tooltip,
 
1056
                                                       Glib::ustring const &path, gdouble def,
 
1057
                                                       GtkWidget *focusTarget,
 
1058
                                                       GtkWidget *us,
 
1059
                                                       GObject *dataKludge,
 
1060
                                                       gboolean altx, gchar const *altx_mark,
 
1061
                                                       gdouble lower, gdouble upper, gdouble step, gdouble page,
 
1062
                                                       gchar const** descrLabels, gdouble const* descrValues, guint descrCount,
 
1063
                                                       void (*callback)(GtkAdjustment *, GObject *),
 
1064
                                                       gdouble climb = 0.1, guint digits = 3, double factor = 1.0 )
 
1065
{
 
1066
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
1067
    GtkAdjustment* adj = GTK_ADJUSTMENT( gtk_adjustment_new( prefs->getDouble(path, def) * factor,
 
1068
                                                             lower, upper, step, page, 0 ) );
 
1069
    if (us) {
 
1070
        sp_unit_selector_add_adjustment( SP_UNIT_SELECTOR(us), adj );
 
1071
    }
 
1072
 
 
1073
    gtk_signal_connect( GTK_OBJECT(adj), "value-changed", GTK_SIGNAL_FUNC(callback), dataKludge );
 
1074
 
 
1075
    EgeAdjustmentAction* act = ege_adjustment_action_new( adj, name, label, tooltip, 0, climb, digits );
 
1076
    if ( shortLabel ) {
 
1077
        g_object_set( act, "short_label", shortLabel, NULL );
 
1078
    }
 
1079
 
 
1080
    if ( (descrCount > 0) && descrLabels && descrValues ) {
 
1081
        ege_adjustment_action_set_descriptions( act, descrLabels, descrValues, descrCount );
 
1082
    }
 
1083
 
 
1084
    if ( focusTarget ) {
 
1085
        ege_adjustment_action_set_focuswidget( act, focusTarget );
 
1086
    }
 
1087
 
 
1088
    if ( altx && altx_mark ) {
 
1089
        g_object_set( G_OBJECT(act), "self-id", altx_mark, NULL );
 
1090
    }
 
1091
 
 
1092
    if ( dataKludge ) {
 
1093
        // Rather lame, but it's the only place where we need to get the entry name
 
1094
        // but we don't have an Entry
 
1095
        g_object_set_data( dataKludge, prefs->getEntry(path).getEntryName().data(), adj );
 
1096
    }
 
1097
 
 
1098
    // Using a cast just to make sure we pass in the right kind of function pointer
 
1099
    g_object_set( G_OBJECT(act), "tool-post", static_cast<EgeWidgetFixup>(sp_set_font_size_smaller), NULL );
 
1100
 
 
1101
    return act;
 
1102
}
 
1103
 
 
1104
 
 
1105
//####################################
 
1106
//# node editing callbacks
 
1107
//####################################
 
1108
 
 
1109
/** Temporary hack: Returns the node tool in the active desktop.
 
1110
 * Will go away during tool refactoring. */
 
1111
static InkNodeTool *get_node_tool()
 
1112
{
 
1113
    InkNodeTool *tool = 0;
 
1114
    if (SP_ACTIVE_DESKTOP ) {
 
1115
        SPEventContext *ec = SP_ACTIVE_DESKTOP->event_context;
 
1116
        if (INK_IS_NODE_TOOL(ec)) {
 
1117
            tool = static_cast<InkNodeTool*>(ec);
 
1118
        }
 
1119
    }
 
1120
    return tool;
 
1121
}
 
1122
 
 
1123
static void sp_node_path_edit_add(void)
 
1124
{
 
1125
    InkNodeTool *nt = get_node_tool();
 
1126
    if (nt) {
 
1127
        nt->_multipath->insertNodes();
 
1128
    }
 
1129
}
 
1130
 
 
1131
static void sp_node_path_edit_delete(void)
 
1132
{
 
1133
    InkNodeTool *nt = get_node_tool();
 
1134
    if (nt) {
 
1135
        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
1136
        nt->_multipath->deleteNodes(prefs->getBool("/tools/nodes/delete_preserves_shape", true));
 
1137
    }
 
1138
}
 
1139
 
 
1140
static void sp_node_path_edit_delete_segment(void)
 
1141
{
 
1142
    InkNodeTool *nt = get_node_tool();
 
1143
    if (nt) {
 
1144
        nt->_multipath->deleteSegments();
 
1145
    }
 
1146
}
 
1147
 
 
1148
static void sp_node_path_edit_break(void)
 
1149
{
 
1150
    InkNodeTool *nt = get_node_tool();
 
1151
    if (nt) {
 
1152
        nt->_multipath->breakNodes();
 
1153
    }
 
1154
}
 
1155
 
 
1156
static void sp_node_path_edit_join(void)
 
1157
{
 
1158
    InkNodeTool *nt = get_node_tool();
 
1159
    if (nt) {
 
1160
        nt->_multipath->joinNodes();
 
1161
    }
 
1162
}
 
1163
 
 
1164
static void sp_node_path_edit_join_segment(void)
 
1165
{
 
1166
    InkNodeTool *nt = get_node_tool();
 
1167
    if (nt) {
 
1168
        nt->_multipath->joinSegments();
 
1169
    }
 
1170
}
 
1171
 
 
1172
static void sp_node_path_edit_toline(void)
 
1173
{
 
1174
    InkNodeTool *nt = get_node_tool();
 
1175
    if (nt) {
 
1176
        nt->_multipath->setSegmentType(Inkscape::UI::SEGMENT_STRAIGHT);
 
1177
    }
 
1178
}
 
1179
 
 
1180
static void sp_node_path_edit_tocurve(void)
 
1181
{
 
1182
    InkNodeTool *nt = get_node_tool();
 
1183
    if (nt) {
 
1184
        nt->_multipath->setSegmentType(Inkscape::UI::SEGMENT_CUBIC_BEZIER);
 
1185
    }
 
1186
}
 
1187
 
 
1188
static void sp_node_path_edit_cusp(void)
 
1189
{
 
1190
    InkNodeTool *nt = get_node_tool();
 
1191
    if (nt) {
 
1192
        nt->_multipath->setNodeType(Inkscape::UI::NODE_CUSP);
 
1193
    }
 
1194
}
 
1195
 
 
1196
static void sp_node_path_edit_smooth(void)
 
1197
{
 
1198
    InkNodeTool *nt = get_node_tool();
 
1199
    if (nt) {
 
1200
        nt->_multipath->setNodeType(Inkscape::UI::NODE_SMOOTH);
 
1201
    }
 
1202
}
 
1203
 
 
1204
static void sp_node_path_edit_symmetrical(void)
 
1205
{
 
1206
    InkNodeTool *nt = get_node_tool();
 
1207
    if (nt) {
 
1208
        nt->_multipath->setNodeType(Inkscape::UI::NODE_SYMMETRIC);
 
1209
    }
 
1210
}
 
1211
 
 
1212
static void sp_node_path_edit_auto(void)
 
1213
{
 
1214
    InkNodeTool *nt = get_node_tool();
 
1215
    if (nt) {
 
1216
        nt->_multipath->setNodeType(Inkscape::UI::NODE_AUTO);
 
1217
    }
 
1218
}
 
1219
 
 
1220
static void sp_node_path_edit_nextLPEparam(GtkAction * /*act*/, gpointer data) {
 
1221
    sp_selection_next_patheffect_param( reinterpret_cast<SPDesktop*>(data) );
 
1222
}
 
1223
 
 
1224
/* is called when the node selection is modified */
 
1225
static void sp_node_toolbox_coord_changed(gpointer /*shape_editor*/, GObject *tbl)
 
1226
{
 
1227
    GtkAction* xact = GTK_ACTION( g_object_get_data( tbl, "nodes_x_action" ) );
 
1228
    GtkAction* yact = GTK_ACTION( g_object_get_data( tbl, "nodes_y_action" ) );
 
1229
    GtkAdjustment *xadj = ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION(xact));
 
1230
    GtkAdjustment *yadj = ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION(yact));
 
1231
 
 
1232
    // quit if run by the attr_changed listener
 
1233
    if (g_object_get_data( tbl, "freeze" )) {
 
1234
        return;
 
1235
    }
 
1236
 
 
1237
    // in turn, prevent listener from responding
 
1238
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
 
1239
 
 
1240
    UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) );
 
1241
    SPUnit const *unit = tracker->getActiveUnit();
 
1242
 
 
1243
    InkNodeTool *nt = get_node_tool();
 
1244
    if (!nt || nt->_selected_nodes->empty()) {
 
1245
        // no path selected
 
1246
        gtk_action_set_sensitive(xact, FALSE);
 
1247
        gtk_action_set_sensitive(yact, FALSE);
 
1248
    } else {
 
1249
        gtk_action_set_sensitive(xact, TRUE);
 
1250
        gtk_action_set_sensitive(yact, TRUE);
 
1251
        Geom::Coord oldx = sp_units_get_pixels(gtk_adjustment_get_value(xadj), *unit);
 
1252
        Geom::Coord oldy = sp_units_get_pixels(gtk_adjustment_get_value(xadj), *unit);
 
1253
        Geom::Point mid = nt->_selected_nodes->pointwiseBounds()->midpoint();
 
1254
 
 
1255
        if (oldx != mid[Geom::X]) {
 
1256
            gtk_adjustment_set_value(xadj, sp_pixels_get_units(mid[Geom::X], *unit));
 
1257
        }
 
1258
        if (oldy != mid[Geom::Y]) {
 
1259
            gtk_adjustment_set_value(yadj, sp_pixels_get_units(mid[Geom::Y], *unit));
 
1260
        }
 
1261
    }
 
1262
 
 
1263
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 
1264
}
 
1265
 
 
1266
static void sp_node_path_value_changed(GtkAdjustment *adj, GObject *tbl, Geom::Dim2 d)
 
1267
{
 
1268
    SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
 
1269
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
1270
 
 
1271
    UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
 
1272
    SPUnit const *unit = tracker->getActiveUnit();
 
1273
 
 
1274
    if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
 
1275
        prefs->setDouble(Glib::ustring("/tools/nodes/") + (d == Geom::X ? "x" : "y"),
 
1276
            sp_units_get_pixels(adj->value, *unit));
 
1277
    }
 
1278
 
 
1279
    // quit if run by the attr_changed listener
 
1280
    if (g_object_get_data( tbl, "freeze" )) {
 
1281
        return;
 
1282
    }
 
1283
 
 
1284
    // in turn, prevent listener from responding
 
1285
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
 
1286
 
 
1287
    InkNodeTool *nt = get_node_tool();
 
1288
    if (nt && !nt->_selected_nodes->empty()) {
 
1289
        double val = sp_units_get_pixels(gtk_adjustment_get_value(adj), *unit);
 
1290
        double oldval = nt->_selected_nodes->pointwiseBounds()->midpoint()[d];
 
1291
        Geom::Point delta(0,0);
 
1292
        delta[d] = val - oldval;
 
1293
        nt->_multipath->move(delta);
 
1294
    }
 
1295
 
 
1296
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 
1297
}
 
1298
 
 
1299
static void sp_node_path_x_value_changed(GtkAdjustment *adj, GObject *tbl)
 
1300
{
 
1301
    sp_node_path_value_changed(adj, tbl, Geom::X);
 
1302
}
 
1303
 
 
1304
static void sp_node_path_y_value_changed(GtkAdjustment *adj, GObject *tbl)
 
1305
{
 
1306
    sp_node_path_value_changed(adj, tbl, Geom::Y);
 
1307
}
 
1308
 
 
1309
static void sp_node_toolbox_sel_changed(Inkscape::Selection *selection, GObject *tbl)
 
1310
{
 
1311
    {
 
1312
    GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "nodes_lpeedit" ) );
 
1313
    SPItem *item = selection->singleItem();
 
1314
    if (item && SP_IS_LPE_ITEM(item)) {
 
1315
       if (sp_lpe_item_has_path_effect(SP_LPE_ITEM(item))) {
 
1316
           gtk_action_set_sensitive(w, TRUE);
 
1317
       } else {
 
1318
           gtk_action_set_sensitive(w, FALSE);
 
1319
       }
 
1320
    } else {
 
1321
       gtk_action_set_sensitive(w, FALSE);
 
1322
    }
 
1323
    }
 
1324
}
 
1325
 
 
1326
static void sp_node_toolbox_sel_modified(Inkscape::Selection *selection, guint /*flags*/, GObject *tbl)
 
1327
{
 
1328
    sp_node_toolbox_sel_changed (selection, tbl);
 
1329
}
 
1330
 
 
1331
 
 
1332
 
 
1333
//################################
 
1334
//##    Node Editing Toolbox    ##
 
1335
//################################
 
1336
 
 
1337
static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
 
1338
{
 
1339
    UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
 
1340
    tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
 
1341
    g_object_set_data( holder, "tracker", tracker );
 
1342
 
 
1343
    Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1);
 
1344
 
 
1345
    {
 
1346
        InkAction* inky = ink_action_new( "NodeInsertAction",
 
1347
                                          _("Insert node"),
 
1348
                                          _("Insert new nodes into selected segments"),
 
1349
                                          INKSCAPE_ICON_NODE_ADD,
 
1350
                                          secondarySize );
 
1351
        g_object_set( inky, "short_label", _("Insert"), NULL );
 
1352
        g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_add), 0 );
 
1353
        gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
 
1354
    }
 
1355
 
 
1356
    {
 
1357
        InkAction* inky = ink_action_new( "NodeDeleteAction",
 
1358
                                          _("Delete node"),
 
1359
                                          _("Delete selected nodes"),
 
1360
                                          INKSCAPE_ICON_NODE_DELETE,
 
1361
                                          secondarySize );
 
1362
        g_object_set( inky, "short_label", _("Delete"), NULL );
 
1363
        g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete), 0 );
 
1364
        gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
 
1365
    }
 
1366
 
 
1367
    {
 
1368
        InkAction* inky = ink_action_new( "NodeJoinAction",
 
1369
                                          _("Join nodes"),
 
1370
                                          _("Join selected nodes"),
 
1371
                                          INKSCAPE_ICON_NODE_JOIN,
 
1372
                                          secondarySize );
 
1373
        g_object_set( inky, "short_label", _("Join"), NULL );
 
1374
        g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join), 0 );
 
1375
        gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
 
1376
    }
 
1377
 
 
1378
    {
 
1379
        InkAction* inky = ink_action_new( "NodeBreakAction",
 
1380
                                          _("Break nodes"),
 
1381
                                          _("Break path at selected nodes"),
 
1382
                                          INKSCAPE_ICON_NODE_BREAK,
 
1383
                                          secondarySize );
 
1384
        g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_break), 0 );
 
1385
        gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
 
1386
    }
 
1387
 
 
1388
 
 
1389
    {
 
1390
        InkAction* inky = ink_action_new( "NodeJoinSegmentAction",
 
1391
                                          _("Join with segment"),
 
1392
                                          _("Join selected endnodes with a new segment"),
 
1393
                                          INKSCAPE_ICON_NODE_JOIN_SEGMENT,
 
1394
                                          secondarySize );
 
1395
        g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join_segment), 0 );
 
1396
        gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
 
1397
    }
 
1398
 
 
1399
    {
 
1400
        InkAction* inky = ink_action_new( "NodeDeleteSegmentAction",
 
1401
                                          _("Delete segment"),
 
1402
                                          _("Delete segment between two non-endpoint nodes"),
 
1403
                                          INKSCAPE_ICON_NODE_DELETE_SEGMENT,
 
1404
                                          secondarySize );
 
1405
        g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete_segment), 0 );
 
1406
        gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
 
1407
    }
 
1408
 
 
1409
    {
 
1410
        InkAction* inky = ink_action_new( "NodeCuspAction",
 
1411
                                          _("Node Cusp"),
 
1412
                                          _("Make selected nodes corner"),
 
1413
                                          INKSCAPE_ICON_NODE_TYPE_CUSP,
 
1414
                                          secondarySize );
 
1415
        g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_cusp), 0 );
 
1416
        gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
 
1417
    }
 
1418
 
 
1419
    {
 
1420
        InkAction* inky = ink_action_new( "NodeSmoothAction",
 
1421
                                          _("Node Smooth"),
 
1422
                                          _("Make selected nodes smooth"),
 
1423
                                          INKSCAPE_ICON_NODE_TYPE_SMOOTH,
 
1424
                                          secondarySize );
 
1425
        g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_smooth), 0 );
 
1426
        gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
 
1427
    }
 
1428
 
 
1429
    {
 
1430
        InkAction* inky = ink_action_new( "NodeSymmetricAction",
 
1431
                                          _("Node Symmetric"),
 
1432
                                          _("Make selected nodes symmetric"),
 
1433
                                          INKSCAPE_ICON_NODE_TYPE_SYMMETRIC,
 
1434
                                          secondarySize );
 
1435
        g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_symmetrical), 0 );
 
1436
        gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
 
1437
    }
 
1438
 
 
1439
    {
 
1440
        InkAction* inky = ink_action_new( "NodeAutoAction",
 
1441
                                          _("Node Auto"),
 
1442
                                          _("Make selected nodes auto-smooth"),
 
1443
                                          INKSCAPE_ICON_NODE_TYPE_AUTO_SMOOTH,
 
1444
                                          secondarySize );
 
1445
        g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_auto), 0 );
 
1446
        gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
 
1447
    }
 
1448
 
 
1449
    {
 
1450
        InkAction* inky = ink_action_new( "NodeLineAction",
 
1451
                                          _("Node Line"),
 
1452
                                          _("Make selected segments lines"),
 
1453
                                          INKSCAPE_ICON_NODE_SEGMENT_LINE,
 
1454
                                          secondarySize );
 
1455
        g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_toline), 0 );
 
1456
        gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
 
1457
    }
 
1458
 
 
1459
    {
 
1460
        InkAction* inky = ink_action_new( "NodeCurveAction",
 
1461
                                          _("Node Curve"),
 
1462
                                          _("Make selected segments curves"),
 
1463
                                          INKSCAPE_ICON_NODE_SEGMENT_CURVE,
 
1464
                                          secondarySize );
 
1465
        g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_tocurve), 0 );
 
1466
        gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
 
1467
    }
 
1468
 
 
1469
    {
 
1470
        InkToggleAction* act = ink_toggle_action_new( "NodesShowTransformHandlesAction",
 
1471
                                                      _("Show Transform Handles"),
 
1472
                                                      _("Show transformation handles for selected nodes"),
 
1473
                                                      "node-transform",
 
1474
                                                      secondarySize );
 
1475
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
1476
        PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/nodes/show_transform_handles");
 
1477
        g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher);
 
1478
    }
 
1479
 
 
1480
    {
 
1481
        InkToggleAction* act = ink_toggle_action_new( "NodesShowHandlesAction",
 
1482
                                                      _("Show Handles"),
 
1483
                                                      _("Show Bezier handles of selected nodes"),
 
1484
                                                      INKSCAPE_ICON_SHOW_NODE_HANDLES,
 
1485
                                                      secondarySize );
 
1486
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
1487
        PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/nodes/show_handles");
 
1488
        g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher);
 
1489
    }
 
1490
 
 
1491
    {
 
1492
        InkToggleAction* act = ink_toggle_action_new( "NodesShowHelperpath",
 
1493
                                                      _("Show Outline"),
 
1494
                                                      _("Show path outline (without path effects)"),
 
1495
                                                      INKSCAPE_ICON_SHOW_PATH_OUTLINE,
 
1496
                                                      secondarySize );
 
1497
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
1498
        PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/nodes/show_outline");
 
1499
        g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher);
 
1500
    }
 
1501
 
 
1502
    {
 
1503
        Inkscape::Verb* verb = Inkscape::Verb::get(SP_VERB_EDIT_NEXT_PATHEFFECT_PARAMETER);
 
1504
        InkAction* inky = ink_action_new( verb->get_id(),
 
1505
                                          verb->get_name(),
 
1506
                                          verb->get_tip(),
 
1507
                                          INKSCAPE_ICON_PATH_EFFECT_PARAMETER_NEXT,
 
1508
                                          secondarySize );
 
1509
        g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_nextLPEparam), desktop );
 
1510
        gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
 
1511
        g_object_set_data( holder, "nodes_lpeedit", inky);
 
1512
    }
 
1513
 
 
1514
    {
 
1515
        InkToggleAction* inky = ink_toggle_action_new( "ObjectEditClipPathAction",
 
1516
                                          _("Edit clipping paths"),
 
1517
                                          _("Show clipping path(s) of selected object(s)"),
 
1518
                                          INKSCAPE_ICON_PATH_CLIP_EDIT,
 
1519
                                          secondarySize );
 
1520
        gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
 
1521
        PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(inky), "/tools/nodes/edit_clipping_paths");
 
1522
        g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher);
 
1523
    }
 
1524
 
 
1525
    {
 
1526
        InkToggleAction* inky = ink_toggle_action_new( "ObjectEditMaskPathAction",
 
1527
                                          _("Edit masks"),
 
1528
                                          _("Show mask(s) of selected object(s)"),
 
1529
                                          INKSCAPE_ICON_PATH_MASK_EDIT,
 
1530
                                          secondarySize );
 
1531
        gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
 
1532
        PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(inky), "/tools/nodes/edit_masks");
 
1533
        g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher);
 
1534
    }
 
1535
 
 
1536
    /* X coord of selected node(s) */
 
1537
    {
 
1538
        EgeAdjustmentAction* eact = 0;
 
1539
        gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 
1540
        gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
 
1541
        eact = create_adjustment_action( "NodeXAction",
 
1542
                                         _("X coordinate:"), _("X:"), _("X coordinate of selected node(s)"),
 
1543
                                         "/tools/nodes/Xcoord", 0,
 
1544
                                         GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-nodes",
 
1545
                                         -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
 
1546
                                         labels, values, G_N_ELEMENTS(labels),
 
1547
                                         sp_node_path_x_value_changed );
 
1548
        tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
 
1549
        g_object_set_data( holder, "nodes_x_action", eact );
 
1550
        gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
 
1551
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
1552
    }
 
1553
 
 
1554
    /* Y coord of selected node(s) */
 
1555
    {
 
1556
        EgeAdjustmentAction* eact = 0;
 
1557
        gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 
1558
        gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
 
1559
        eact = create_adjustment_action( "NodeYAction",
 
1560
                                         _("Y coordinate:"), _("Y:"), _("Y coordinate of selected node(s)"),
 
1561
                                         "/tools/nodes/Ycoord", 0,
 
1562
                                         GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
 
1563
                                         -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
 
1564
                                         labels, values, G_N_ELEMENTS(labels),
 
1565
                                         sp_node_path_y_value_changed );
 
1566
        tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
 
1567
        g_object_set_data( holder, "nodes_y_action", eact );
 
1568
        gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
 
1569
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
1570
    }
 
1571
 
 
1572
    // add the units menu
 
1573
    {
 
1574
        GtkAction* act = tracker->createAction( "NodeUnitsAction", _("Units"), ("") );
 
1575
        gtk_action_group_add_action( mainActions, act );
 
1576
    }
 
1577
 
 
1578
 
 
1579
    sp_node_toolbox_sel_changed(sp_desktop_selection(desktop), holder);
 
1580
 
 
1581
    //watch selection
 
1582
    Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISNodeToolbox");
 
1583
 
 
1584
    sigc::connection *c_selection_changed =
 
1585
        new sigc::connection (sp_desktop_selection (desktop)->connectChanged
 
1586
                              (sigc::bind (sigc::ptr_fun (sp_node_toolbox_sel_changed), (GObject*)holder)));
 
1587
    pool->add_connection ("selection-changed", c_selection_changed);
 
1588
 
 
1589
    sigc::connection *c_selection_modified =
 
1590
        new sigc::connection (sp_desktop_selection (desktop)->connectModified
 
1591
                              (sigc::bind (sigc::ptr_fun (sp_node_toolbox_sel_modified), (GObject*)holder)));
 
1592
    pool->add_connection ("selection-modified", c_selection_modified);
 
1593
 
 
1594
    sigc::connection *c_subselection_changed =
 
1595
        new sigc::connection (desktop->connectToolSubselectionChanged
 
1596
                              (sigc::bind (sigc::ptr_fun (sp_node_toolbox_coord_changed), (GObject*)holder)));
 
1597
    pool->add_connection ("tool-subselection-changed", c_subselection_changed);
 
1598
 
 
1599
    Inkscape::ConnectionPool::connect_destroy (G_OBJECT (holder), pool);
 
1600
 
 
1601
    g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
 
1602
} // end of sp_node_toolbox_prep()
 
1603
 
 
1604
 
 
1605
//########################
 
1606
//##    Zoom Toolbox    ##
 
1607
//########################
 
1608
 
 
1609
static void sp_zoom_toolbox_prep(SPDesktop * /*desktop*/, GtkActionGroup* /*mainActions*/, GObject* /*holder*/)
 
1610
{
 
1611
    // no custom GtkAction setup needed
 
1612
} // end of sp_zoom_toolbox_prep()
 
1613
 
 
1614
void ToolboxFactory::setToolboxDesktop(GtkWidget *toolbox, SPDesktop *desktop)
 
1615
{
 
1616
    sigc::connection *conn = static_cast<sigc::connection*>(g_object_get_data(G_OBJECT(toolbox),
 
1617
                                                                              "event_context_connection"));
 
1618
 
 
1619
    BarId id = static_cast<BarId>( GPOINTER_TO_INT(g_object_get_data(G_OBJECT(toolbox), BAR_ID_KEY)) );
 
1620
 
 
1621
    SetupFunction setup_func = 0;
 
1622
    UpdateFunction update_func = 0;
 
1623
 
 
1624
    switch (id) {
 
1625
        case BAR_TOOL:
 
1626
            setup_func = setup_tool_toolbox;
 
1627
            update_func = update_tool_toolbox;
 
1628
            break;
 
1629
 
 
1630
        case BAR_AUX:
 
1631
            toolbox = gtk_bin_get_child(GTK_BIN(toolbox));
 
1632
            setup_func = setup_aux_toolbox;
 
1633
            update_func = update_aux_toolbox;
 
1634
            break;
 
1635
 
 
1636
        case BAR_COMMANDS:
 
1637
            setup_func = setup_commands_toolbox;
 
1638
            update_func = update_commands_toolbox;
 
1639
            break;
 
1640
 
 
1641
        case BAR_SNAP:
 
1642
            setup_func = setup_snap_toolbox;
 
1643
            update_func = updateSnapToolbox;
 
1644
            break;
 
1645
        default:
 
1646
            g_warning("Unexpected toolbox id encountered.");
 
1647
    }
 
1648
 
 
1649
    gpointer ptr = g_object_get_data(G_OBJECT(toolbox), "desktop");
 
1650
    SPDesktop *old_desktop = static_cast<SPDesktop*>(ptr);
 
1651
 
 
1652
    if (old_desktop) {
 
1653
        GList *children, *iter;
 
1654
 
 
1655
        children = gtk_container_get_children(GTK_CONTAINER(toolbox));
 
1656
        for ( iter = children ; iter ; iter = iter->next ) {
 
1657
            gtk_container_remove( GTK_CONTAINER(toolbox), GTK_WIDGET(iter->data) );
 
1658
        }
 
1659
        g_list_free(children);
 
1660
    }
 
1661
 
 
1662
    g_object_set_data(G_OBJECT(toolbox), "desktop", (gpointer)desktop);
 
1663
 
 
1664
    if (desktop && setup_func && update_func) {
 
1665
        gtk_widget_set_sensitive(toolbox, TRUE);
 
1666
        setup_func(toolbox, desktop);
 
1667
        update_func(desktop, desktop->event_context, toolbox);
 
1668
        *conn = desktop->connectEventContextChanged(sigc::bind (sigc::ptr_fun(update_func), toolbox));
 
1669
    } else {
 
1670
        gtk_widget_set_sensitive(toolbox, FALSE);
 
1671
    }
 
1672
 
 
1673
} // end of sp_toolbox_set_desktop()
 
1674
 
 
1675
 
 
1676
static void setupToolboxCommon( GtkWidget *toolbox,
 
1677
                                SPDesktop *desktop,
 
1678
                                gchar const *descr,
 
1679
                                gchar const* toolbarName,
 
1680
                                gchar const* sizePref )
 
1681
{
 
1682
    Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions( desktop );
 
1683
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
1684
 
 
1685
    GtkUIManager* mgr = gtk_ui_manager_new();
 
1686
    GError* errVal = 0;
 
1687
 
 
1688
    GtkOrientation orientation = GTK_ORIENTATION_HORIZONTAL;
 
1689
 
 
1690
    gtk_ui_manager_insert_action_group( mgr, mainActions->gobj(), 0 );
 
1691
    gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
 
1692
 
 
1693
    GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, toolbarName );
 
1694
    if ( prefs->getBool("/toolbox/icononly", true) ) {
 
1695
        gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
 
1696
    }
 
1697
 
 
1698
    Inkscape::IconSize toolboxSize = ToolboxFactory::prefToSize(sizePref);
 
1699
    gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), static_cast<GtkIconSize>(toolboxSize) );
 
1700
 
 
1701
    if (GTK_IS_HANDLE_BOX(toolbox)) {
 
1702
        // g_message("GRABBING ORIENTATION   [%s]", toolbarName);
 
1703
        GtkPositionType pos = gtk_handle_box_get_handle_position(GTK_HANDLE_BOX(toolbox));
 
1704
        orientation = ((pos == GTK_POS_LEFT) || (pos == GTK_POS_RIGHT)) ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
 
1705
    } else {
 
1706
        GtkPositionType pos = static_cast<GtkPositionType>(GPOINTER_TO_INT(g_object_get_data( G_OBJECT(toolbox), HANDLE_POS_MARK )));
 
1707
        orientation = ((pos == GTK_POS_LEFT) || (pos == GTK_POS_RIGHT)) ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
 
1708
    }
 
1709
    gtk_toolbar_set_orientation(GTK_TOOLBAR(toolBar), orientation);
 
1710
    gtk_toolbar_set_show_arrow(GTK_TOOLBAR(toolBar), TRUE);
 
1711
 
 
1712
    g_object_set_data(G_OBJECT(toolBar), "desktop", NULL);
 
1713
 
 
1714
    GtkWidget* child = gtk_bin_get_child(GTK_BIN(toolbox));
 
1715
    if ( child ) {
 
1716
        gtk_container_remove( GTK_CONTAINER(toolbox), child );
 
1717
    }
 
1718
 
 
1719
    gtk_container_add( GTK_CONTAINER(toolbox), toolBar );
 
1720
}
 
1721
 
 
1722
#define noDUMP_DETAILS 1
 
1723
 
 
1724
void ToolboxFactory::setOrientation(GtkWidget* toolbox, GtkOrientation orientation)
 
1725
{
 
1726
#if DUMP_DETAILS
 
1727
    g_message("Set orientation for %p to be %d", toolbox, orientation);
 
1728
    GType type = GTK_WIDGET_TYPE(toolbox);
 
1729
    g_message("        [%s]", g_type_name(type));
 
1730
    g_message("             %p", g_object_get_data(G_OBJECT(toolbox), BAR_ID_KEY));
 
1731
#endif
 
1732
 
 
1733
    GtkPositionType pos = (orientation == GTK_ORIENTATION_HORIZONTAL) ? GTK_POS_LEFT : GTK_POS_TOP;
 
1734
    GtkHandleBox* handleBox = 0;
 
1735
 
 
1736
    if (GTK_IS_BIN(toolbox)) {
 
1737
#if DUMP_DETAILS
 
1738
        g_message("            is a BIN");
 
1739
#endif // DUMP_DETAILS
 
1740
        GtkWidget* child = gtk_bin_get_child(GTK_BIN(toolbox));
 
1741
        if (child) {
 
1742
#if DUMP_DETAILS
 
1743
            GType type2 = GTK_WIDGET_TYPE(child);
 
1744
            g_message("            child    [%s]", g_type_name(type2));
 
1745
#endif // DUMP_DETAILS
 
1746
 
 
1747
            if (GTK_IS_BOX(child)) {
 
1748
#if DUMP_DETAILS
 
1749
                g_message("                is a BOX");
 
1750
#endif // DUMP_DETAILS
 
1751
 
 
1752
                GList* children = gtk_container_get_children(GTK_CONTAINER(child));
 
1753
                if (children) {
 
1754
                    for (GList* curr = children; curr; curr = g_list_next(curr)) {
 
1755
                        GtkWidget* child2 = GTK_WIDGET(curr->data);
 
1756
#if DUMP_DETAILS
 
1757
                        GType type3 = GTK_WIDGET_TYPE(child2);
 
1758
                        g_message("                child2   [%s]", g_type_name(type3));
 
1759
#endif // DUMP_DETAILS
 
1760
 
 
1761
                        if (GTK_IS_CONTAINER(child2)) {
 
1762
                            GList* children2 = gtk_container_get_children(GTK_CONTAINER(child2));
 
1763
                            if (children2) {
 
1764
                                for (GList* curr2 = children2; curr2; curr2 = g_list_next(curr2)) {
 
1765
                                    GtkWidget* child3 = GTK_WIDGET(curr2->data);
 
1766
#if DUMP_DETAILS
 
1767
                                    GType type4 = GTK_WIDGET_TYPE(child3);
 
1768
                                    g_message("                    child3   [%s]", g_type_name(type4));
 
1769
#endif // DUMP_DETAILS
 
1770
                                    if (GTK_IS_TOOLBAR(child3)) {
 
1771
                                        GtkToolbar* childBar = GTK_TOOLBAR(child3);
 
1772
                                        gtk_toolbar_set_orientation(childBar, orientation);
 
1773
                                    }
 
1774
                                }
 
1775
                                g_list_free(children2);
 
1776
                            }
 
1777
                        }
 
1778
 
 
1779
 
 
1780
                        if (GTK_IS_TOOLBAR(child2)) {
 
1781
                            GtkToolbar* childBar = GTK_TOOLBAR(child2);
 
1782
                            gtk_toolbar_set_orientation(childBar, orientation);
 
1783
                            if (GTK_IS_HANDLE_BOX(toolbox)) {
 
1784
                                handleBox = GTK_HANDLE_BOX(toolbox);
 
1785
                            }
 
1786
                        } else {
 
1787
                            g_message("need to add dynamic switch");
 
1788
                        }
 
1789
                    }
 
1790
                    g_list_free(children);
 
1791
                } else {
 
1792
                    // The call is being made before the toolbox proper has been setup.
 
1793
                    if (GTK_IS_HANDLE_BOX(toolbox)) {
 
1794
                        handleBox = GTK_HANDLE_BOX(toolbox);
 
1795
                    } else {
 
1796
                        g_object_set_data(G_OBJECT(toolbox), HANDLE_POS_MARK, GINT_TO_POINTER(pos));
 
1797
                    }
 
1798
                }
 
1799
            } else if (GTK_IS_TOOLBAR(child)) {
 
1800
                GtkToolbar* toolbar = GTK_TOOLBAR(child);
 
1801
                gtk_toolbar_set_orientation( toolbar, orientation );
 
1802
                if (GTK_IS_HANDLE_BOX(toolbox)) {
 
1803
                    handleBox = GTK_HANDLE_BOX(toolbox);
 
1804
                }
 
1805
            }
 
1806
        }
 
1807
    }
 
1808
 
 
1809
    if (handleBox) {
 
1810
        gtk_handle_box_set_handle_position(handleBox, pos);
 
1811
    }
 
1812
}
 
1813
 
 
1814
void setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
 
1815
{
 
1816
    gchar const * descr =
 
1817
        "<ui>"
 
1818
        "  <toolbar name='ToolToolbar'>"
 
1819
 
 
1820
        "   <!-- Basics -->"
 
1821
        "    <toolitem action='ToolSelector' />"
 
1822
        "    <toolitem action='ToolNode' />"
 
1823
        "    <toolitem action='ToolTweak' />"
 
1824
        "    <toolitem action='ToolZoom' />"
 
1825
 
 
1826
        "   <!-- Shapes -->"
 
1827
        "    <toolitem action='ToolRect' />"
 
1828
        "    <toolitem action='Tool3DBox' />"
 
1829
        "    <toolitem action='ToolArc' />"
 
1830
        "    <toolitem action='ToolStar' />"
 
1831
        "    <toolitem action='ToolSpiral' />"
 
1832
 
 
1833
        "   <!-- Paths -->"
 
1834
        "    <toolitem action='ToolPencil' />"
 
1835
        "    <toolitem action='ToolPen' />"
 
1836
        "    <toolitem action='ToolCalligraphic' />"
 
1837
 
 
1838
        "   <!-- Text -->"
 
1839
        "    <toolitem action='ToolText' />"
 
1840
 
 
1841
        "   <!-- Paint large areas -->"
 
1842
        "    <toolitem action='ToolSpray' />"
 
1843
        "    <toolitem action='ToolEraser' />"
 
1844
 
 
1845
        "   <!-- Fill -->"
 
1846
        "    <toolitem action='ToolPaintBucket' />"
 
1847
        "    <toolitem action='ToolGradient' />"
 
1848
        "    <toolitem action='ToolDropper' />"
 
1849
 
 
1850
        "    <toolitem action='ToolConnector' />"
 
1851
 
 
1852
//        "    <toolitem action='ToolLPETool' />"
 
1853
        "  </toolbar>"
 
1854
        "</ui>";
 
1855
 
 
1856
    setupToolboxCommon( toolbox, desktop, descr,
 
1857
                        "/ui/ToolToolbar",
 
1858
                        "/toolbox/tools/small");
 
1859
}
 
1860
 
 
1861
void update_tool_toolbox( SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget * /*toolbox*/ )
 
1862
{
 
1863
    gchar const *const tname = ( eventcontext
 
1864
                                 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
 
1865
                                 : NULL );
 
1866
    Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions( desktop );
 
1867
 
 
1868
    for (int i = 0 ; tools[i].type_name ; i++ ) {
 
1869
        Glib::RefPtr<Gtk::Action> act = mainActions->get_action( Inkscape::Verb::get(tools[i].verb)->get_id() );
 
1870
        if ( act ) {
 
1871
            bool setActive = tname && !strcmp(tname, tools[i].type_name);
 
1872
            Glib::RefPtr<VerbAction> verbAct = Glib::RefPtr<VerbAction>::cast_dynamic(act);
 
1873
            if ( verbAct ) {
 
1874
                verbAct->set_active(setActive);
 
1875
            }
 
1876
        }
 
1877
    }
 
1878
}
 
1879
 
 
1880
void setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
 
1881
{
 
1882
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
1883
    GtkSizeGroup* grouper = gtk_size_group_new( GTK_SIZE_GROUP_BOTH );
 
1884
    Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions( desktop );
 
1885
    GtkUIManager* mgr = gtk_ui_manager_new();
 
1886
    GError* errVal = 0;
 
1887
    gtk_ui_manager_insert_action_group( mgr, mainActions->gobj(), 0 );
 
1888
    gtk_ui_manager_add_ui_from_string( mgr, ui_descr, -1, &errVal );
 
1889
 
 
1890
    std::map<std::string, GtkWidget*> dataHolders;
 
1891
 
 
1892
    for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
 
1893
        if ( aux_toolboxes[i].prep_func ) {
 
1894
            // converted to GtkActions and UIManager
 
1895
 
 
1896
            GtkWidget* kludge = gtk_toolbar_new();
 
1897
            g_object_set_data( G_OBJECT(kludge), "dtw", desktop->canvas);
 
1898
            g_object_set_data( G_OBJECT(kludge), "desktop", desktop);
 
1899
            dataHolders[aux_toolboxes[i].type_name] = kludge;
 
1900
            aux_toolboxes[i].prep_func( desktop, mainActions->gobj(), G_OBJECT(kludge) );
 
1901
        } else {
 
1902
 
 
1903
            GtkWidget *sub_toolbox = 0;
 
1904
            if (aux_toolboxes[i].create_func == NULL) {
 
1905
                sub_toolbox = sp_empty_toolbox_new(desktop);
 
1906
            } else {
 
1907
                sub_toolbox = aux_toolboxes[i].create_func(desktop);
 
1908
            }
 
1909
 
 
1910
            gtk_size_group_add_widget( grouper, sub_toolbox );
 
1911
 
 
1912
            gtk_container_add(GTK_CONTAINER(toolbox), sub_toolbox);
 
1913
            g_object_set_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name, sub_toolbox);
 
1914
 
 
1915
        }
 
1916
    }
 
1917
 
 
1918
    // Second pass to create toolbars *after* all GtkActions are created
 
1919
    for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
 
1920
        if ( aux_toolboxes[i].prep_func ) {
 
1921
            // converted to GtkActions and UIManager
 
1922
 
 
1923
            GtkWidget* kludge = dataHolders[aux_toolboxes[i].type_name];
 
1924
 
 
1925
            GtkWidget* holder = gtk_table_new( 1, 3, FALSE );
 
1926
            gtk_table_attach( GTK_TABLE(holder), kludge, 2, 3, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0 );
 
1927
 
 
1928
            gchar* tmp = g_strdup_printf( "/ui/%s", aux_toolboxes[i].ui_name );
 
1929
            GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, tmp );
 
1930
            g_free( tmp );
 
1931
            tmp = 0;
 
1932
 
 
1933
            if ( prefs->getBool( "/toolbox/icononly", true) ) {
 
1934
                gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
 
1935
            }
 
1936
 
 
1937
            Inkscape::IconSize toolboxSize = ToolboxFactory::prefToSize("/toolbox/small");
 
1938
            gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), static_cast<GtkIconSize>(toolboxSize) );
 
1939
 
 
1940
            gtk_table_attach( GTK_TABLE(holder), toolBar, 0, 1, 0, 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0 );
 
1941
 
 
1942
            if ( aux_toolboxes[i].swatch_verb_id != SP_VERB_INVALID ) {
 
1943
                Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch( NULL, _(aux_toolboxes[i].swatch_tip) );
 
1944
                swatch->setDesktop( desktop );
 
1945
                swatch->setClickVerb( aux_toolboxes[i].swatch_verb_id );
 
1946
                swatch->setWatchedTool( aux_toolboxes[i].swatch_tool, true );
 
1947
                GtkWidget *swatch_ = GTK_WIDGET( swatch->gobj() );
 
1948
                gtk_table_attach( GTK_TABLE(holder), swatch_, 1, 2, 0, 1, (GtkAttachOptions)(GTK_SHRINK | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), AUX_BETWEEN_BUTTON_GROUPS, 0 );
 
1949
            }
 
1950
 
 
1951
            gtk_widget_show_all( holder );
 
1952
            sp_set_font_size_smaller( holder );
 
1953
 
 
1954
            gtk_size_group_add_widget( grouper, holder );
 
1955
 
 
1956
            gtk_container_add( GTK_CONTAINER(toolbox), holder );
 
1957
            g_object_set_data( G_OBJECT(toolbox), aux_toolboxes[i].data_name, holder );
 
1958
        }
 
1959
    }
 
1960
 
 
1961
    g_object_unref( G_OBJECT(grouper) );
 
1962
}
 
1963
 
 
1964
void update_aux_toolbox(SPDesktop * /*desktop*/, SPEventContext *eventcontext, GtkWidget *toolbox)
 
1965
{
 
1966
    gchar const *tname = ( eventcontext
 
1967
                           ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
 
1968
                           : NULL );
 
1969
    for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
 
1970
        GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name));
 
1971
        if (tname && !strcmp(tname, aux_toolboxes[i].type_name)) {
 
1972
            gtk_widget_show_all(sub_toolbox);
 
1973
            g_object_set_data(G_OBJECT(toolbox), "shows", sub_toolbox);
 
1974
        } else {
 
1975
            gtk_widget_hide(sub_toolbox);
 
1976
        }
 
1977
    }
 
1978
}
 
1979
 
 
1980
void setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
 
1981
{
 
1982
    gchar const * descr =
 
1983
        "<ui>"
 
1984
        "  <toolbar name='CommandsToolbar'>"
 
1985
        "    <toolitem action='FileNew' />"
 
1986
        "    <toolitem action='FileOpen' />"
 
1987
        "    <toolitem action='FileSave' />"
 
1988
        "    <toolitem action='FilePrint' />"
 
1989
        "    <separator />"
 
1990
        "    <toolitem action='FileImport' />"
 
1991
        "    <toolitem action='FileExport' />"
 
1992
        "    <separator />"
 
1993
        "    <toolitem action='EditUndo' />"
 
1994
        "    <toolitem action='EditRedo' />"
 
1995
        "    <separator />"
 
1996
        "    <toolitem action='EditCopy' />"
 
1997
        "    <toolitem action='EditCut' />"
 
1998
        "    <toolitem action='EditPaste' />"
 
1999
        "    <separator />"
 
2000
        "    <toolitem action='ZoomSelection' />"
 
2001
        "    <toolitem action='ZoomDrawing' />"
 
2002
        "    <toolitem action='ZoomPage' />"
 
2003
        "    <separator />"
 
2004
        "    <toolitem action='EditDuplicate' />"
 
2005
        "    <toolitem action='EditClone' />"
 
2006
        "    <toolitem action='EditUnlinkClone' />"
 
2007
        "    <separator />"
 
2008
        "    <toolitem action='SelectionGroup' />"
 
2009
        "    <toolitem action='SelectionUnGroup' />"
 
2010
        "    <separator />"
 
2011
        "    <toolitem action='DialogFillStroke' />"
 
2012
        "    <toolitem action='DialogText' />"
 
2013
        "    <toolitem action='DialogLayers' />"
 
2014
        "    <toolitem action='DialogXMLEditor' />"
 
2015
        "    <toolitem action='DialogAlignDistribute' />"
 
2016
        "    <separator />"
 
2017
        "    <toolitem action='DialogPreferences' />"
 
2018
        "    <toolitem action='DialogDocumentProperties' />"
 
2019
        "  </toolbar>"
 
2020
        "</ui>";
 
2021
 
 
2022
    setupToolboxCommon( toolbox, desktop, descr,
 
2023
                        "/ui/CommandsToolbar",
 
2024
                        "/toolbox/small" );
 
2025
}
 
2026
 
 
2027
void update_commands_toolbox(SPDesktop * /*desktop*/, SPEventContext * /*eventcontext*/, GtkWidget * /*toolbox*/)
 
2028
{
 
2029
}
 
2030
 
 
2031
static void toggle_snap_callback(GtkToggleAction *act, gpointer data) //data points to the toolbox
 
2032
{
 
2033
    if (g_object_get_data(G_OBJECT(data), "freeze" )) {
 
2034
        return;
 
2035
    }
 
2036
 
 
2037
    gpointer ptr = g_object_get_data(G_OBJECT(data), "desktop");
 
2038
    g_assert(ptr != NULL);
 
2039
 
 
2040
    SPDesktop *dt = reinterpret_cast<SPDesktop*>(ptr);
 
2041
    SPNamedView *nv = sp_desktop_namedview(dt);
 
2042
    SPDocument *doc = SP_OBJECT_DOCUMENT(nv);
 
2043
 
 
2044
    if (dt == NULL || nv == NULL) {
 
2045
        g_warning("No desktop or namedview specified (in toggle_snap_callback)!");
 
2046
        return;
 
2047
    }
 
2048
 
 
2049
    Inkscape::XML::Node *repr = SP_OBJECT_REPR(nv);
 
2050
 
 
2051
    if (repr == NULL) {
 
2052
        g_warning("This namedview doesn't have a xml representation attached!");
 
2053
        return;
 
2054
    }
 
2055
 
 
2056
    bool saved = sp_document_get_undo_sensitive(doc);
 
2057
    sp_document_set_undo_sensitive(doc, false);
 
2058
 
 
2059
    bool v = false;
 
2060
    SPAttributeEnum attr = (SPAttributeEnum) GPOINTER_TO_INT(g_object_get_data(G_OBJECT(act), "SP_ATTR_INKSCAPE"));
 
2061
 
 
2062
    switch (attr) {
 
2063
        case SP_ATTR_INKSCAPE_SNAP_GLOBAL:
 
2064
            dt->toggleSnapGlobal();
 
2065
            break;
 
2066
        case SP_ATTR_INKSCAPE_SNAP_BBOX:
 
2067
            v = nv->snap_manager.snapprefs.getSnapModeBBox();
 
2068
            sp_repr_set_boolean(repr, "inkscape:snap-bbox", !v);
 
2069
            break;
 
2070
        case SP_ATTR_INKSCAPE_BBOX_PATHS:
 
2071
            v = nv->snap_manager.snapprefs.getSnapToBBoxPath();
 
2072
            sp_repr_set_boolean(repr, "inkscape:bbox-paths", !v);
 
2073
            break;
 
2074
        case SP_ATTR_INKSCAPE_BBOX_NODES:
 
2075
            v = nv->snap_manager.snapprefs.getSnapToBBoxNode();
 
2076
            sp_repr_set_boolean(repr, "inkscape:bbox-nodes", !v);
 
2077
            break;
 
2078
        case SP_ATTR_INKSCAPE_SNAP_NODES:
 
2079
            v = nv->snap_manager.snapprefs.getSnapModeNode();
 
2080
            sp_repr_set_boolean(repr, "inkscape:snap-nodes", !v);
 
2081
            break;
 
2082
        case SP_ATTR_INKSCAPE_OBJECT_PATHS:
 
2083
            v = nv->snap_manager.snapprefs.getSnapToItemPath();
 
2084
            sp_repr_set_boolean(repr, "inkscape:object-paths", !v);
 
2085
            break;
 
2086
        case SP_ATTR_INKSCAPE_OBJECT_NODES:
 
2087
            v = nv->snap_manager.snapprefs.getSnapToItemNode();
 
2088
            sp_repr_set_boolean(repr, "inkscape:object-nodes", !v);
 
2089
            break;
 
2090
        case SP_ATTR_INKSCAPE_SNAP_SMOOTH_NODES:
 
2091
            v = nv->snap_manager.snapprefs.getSnapSmoothNodes();
 
2092
            sp_repr_set_boolean(repr, "inkscape:snap-smooth-nodes", !v);
 
2093
            break;
 
2094
        case SP_ATTR_INKSCAPE_SNAP_INTERS_PATHS:
 
2095
            v = nv->snap_manager.snapprefs.getSnapIntersectionCS();
 
2096
            sp_repr_set_boolean(repr, "inkscape:snap-intersection-paths", !v);
 
2097
            break;
 
2098
        case SP_ATTR_INKSCAPE_SNAP_CENTER:
 
2099
            v = nv->snap_manager.snapprefs.getIncludeItemCenter();
 
2100
            sp_repr_set_boolean(repr, "inkscape:snap-center", !v);
 
2101
            break;
 
2102
        case SP_ATTR_INKSCAPE_SNAP_GRIDS:
 
2103
            v = nv->snap_manager.snapprefs.getSnapToGrids();
 
2104
            sp_repr_set_boolean(repr, "inkscape:snap-grids", !v);
 
2105
            break;
 
2106
        case SP_ATTR_INKSCAPE_SNAP_TO_GUIDES:
 
2107
            v = nv->snap_manager.snapprefs.getSnapToGuides();
 
2108
            sp_repr_set_boolean(repr, "inkscape:snap-to-guides", !v);
 
2109
            break;
 
2110
        case SP_ATTR_INKSCAPE_SNAP_PAGE:
 
2111
            v = nv->snap_manager.snapprefs.getSnapToPageBorder();
 
2112
            sp_repr_set_boolean(repr, "inkscape:snap-page", !v);
 
2113
            break;
 
2114
            /*case SP_ATTR_INKSCAPE_SNAP_INTERS_GRIDGUIDE:
 
2115
              v = nv->snap_manager.snapprefs.getSnapIntersectionGG();
 
2116
              sp_repr_set_boolean(repr, "inkscape:snap-intersection-grid-guide", !v);
 
2117
              break;*/
 
2118
        case SP_ATTR_INKSCAPE_SNAP_LINE_MIDPOINTS:
 
2119
            v = nv->snap_manager.snapprefs.getSnapLineMidpoints();
 
2120
            sp_repr_set_boolean(repr, "inkscape:snap-midpoints", !v);
 
2121
            break;
 
2122
        case SP_ATTR_INKSCAPE_SNAP_OBJECT_MIDPOINTS:
 
2123
            v = nv->snap_manager.snapprefs.getSnapObjectMidpoints();
 
2124
            sp_repr_set_boolean(repr, "inkscape:snap-object-midpoints", !v);
 
2125
            break;
 
2126
        case SP_ATTR_INKSCAPE_SNAP_BBOX_EDGE_MIDPOINTS:
 
2127
            v = nv->snap_manager.snapprefs.getSnapBBoxEdgeMidpoints();
 
2128
            sp_repr_set_boolean(repr, "inkscape:snap-bbox-edge-midpoints", !v);
 
2129
            break;
 
2130
        case SP_ATTR_INKSCAPE_SNAP_BBOX_MIDPOINTS:
 
2131
            v = nv->snap_manager.snapprefs.getSnapBBoxMidpoints();
 
2132
            sp_repr_set_boolean(repr, "inkscape:snap-bbox-midpoints", !v);
 
2133
            break;
 
2134
        default:
 
2135
            g_warning("toggle_snap_callback has been called with an ID for which no action has been defined");
 
2136
            break;
 
2137
    }
 
2138
 
 
2139
    // The snapping preferences are stored in the document, and therefore toggling makes the document dirty
 
2140
    doc->setModifiedSinceSave();
 
2141
 
 
2142
    sp_document_set_undo_sensitive(doc, saved);
 
2143
}
 
2144
 
 
2145
void setup_snap_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
 
2146
{
 
2147
    Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions(desktop);
 
2148
 
 
2149
    gchar const * descr =
 
2150
        "<ui>"
 
2151
        "  <toolbar name='SnapToolbar'>"
 
2152
        "    <toolitem action='ToggleSnapGlobal' />"
 
2153
        "    <separator />"
 
2154
        "    <toolitem action='ToggleSnapFromBBoxCorner' />"
 
2155
        "    <toolitem action='ToggleSnapToBBoxPath' />"
 
2156
        "    <toolitem action='ToggleSnapToBBoxNode' />"
 
2157
        "    <toolitem action='ToggleSnapToFromBBoxEdgeMidpoints' />"
 
2158
        "    <toolitem action='ToggleSnapToFromBBoxCenters' />"
 
2159
        "    <separator />"
 
2160
        "    <toolitem action='ToggleSnapFromNode' />"
 
2161
        "    <toolitem action='ToggleSnapToItemPath' />"
 
2162
        "    <toolitem action='ToggleSnapToPathIntersections' />"
 
2163
        "    <toolitem action='ToggleSnapToItemNode' />"
 
2164
        "    <toolitem action='ToggleSnapToSmoothNodes' />"
 
2165
        "    <toolitem action='ToggleSnapToFromLineMidpoints' />"
 
2166
        "    <toolitem action='ToggleSnapToFromObjectCenters' />"
 
2167
        "    <toolitem action='ToggleSnapToFromRotationCenter' />"
 
2168
        "    <separator />"
 
2169
        "    <toolitem action='ToggleSnapToPageBorder' />"
 
2170
        "    <toolitem action='ToggleSnapToGrids' />"
 
2171
        "    <toolitem action='ToggleSnapToGuides' />"
 
2172
        //"    <toolitem action='ToggleSnapToGridGuideIntersections' />"
 
2173
        "  </toolbar>"
 
2174
        "</ui>";
 
2175
 
 
2176
    Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1);
 
2177
 
 
2178
    {
 
2179
        // TODO: This is a cludge. On the one hand we have verbs+actions,
 
2180
        //       on the other we have all these explicit callbacks specified here.
 
2181
        //       We should really unify these (should save some lines of code as well).
 
2182
        //       For example, this action could be based on the verb(+action) + PrefsPusher.
 
2183
        Inkscape::Verb* verb = Inkscape::Verb::get(SP_VERB_TOGGLE_SNAPPING);
 
2184
        InkToggleAction* act = ink_toggle_action_new(verb->get_id(),
 
2185
                                                     verb->get_name(), verb->get_tip(), INKSCAPE_ICON_SNAP, secondarySize,
 
2186
                                                     SP_ATTR_INKSCAPE_SNAP_GLOBAL);
 
2187
 
 
2188
        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
 
2189
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
 
2190
    }
 
2191
 
 
2192
    {
 
2193
        InkToggleAction* act = ink_toggle_action_new("ToggleSnapFromBBoxCorner",
 
2194
                                                     _("Bounding box"), _("Snap bounding box corners"), INKSCAPE_ICON_SNAP_BOUNDING_BOX,
 
2195
                                                     secondarySize, SP_ATTR_INKSCAPE_SNAP_BBOX);
 
2196
 
 
2197
        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
 
2198
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
 
2199
    }
 
2200
 
 
2201
    {
 
2202
        InkToggleAction* act = ink_toggle_action_new("ToggleSnapToBBoxPath",
 
2203
                                                     _("Bounding box edges"), _("Snap to edges of a bounding box"),
 
2204
                                                     INKSCAPE_ICON_SNAP_BOUNDING_BOX_EDGES, secondarySize, SP_ATTR_INKSCAPE_BBOX_PATHS);
 
2205
 
 
2206
        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
 
2207
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
 
2208
    }
 
2209
 
 
2210
    {
 
2211
        InkToggleAction* act = ink_toggle_action_new("ToggleSnapToBBoxNode",
 
2212
                                                     _("Bounding box corners"), _("Snap to bounding box corners"),
 
2213
                                                     INKSCAPE_ICON_SNAP_BOUNDING_BOX_CORNERS, secondarySize, SP_ATTR_INKSCAPE_BBOX_NODES);
 
2214
 
 
2215
        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
 
2216
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
 
2217
    }
 
2218
 
 
2219
    {
 
2220
        InkToggleAction* act = ink_toggle_action_new("ToggleSnapToFromBBoxEdgeMidpoints",
 
2221
                                                     _("BBox Edge Midpoints"), _("Snap from and to midpoints of bounding box edges"),
 
2222
                                                     INKSCAPE_ICON_SNAP_BOUNDING_BOX_MIDPOINTS, secondarySize,
 
2223
                                                     SP_ATTR_INKSCAPE_SNAP_BBOX_EDGE_MIDPOINTS);
 
2224
 
 
2225
        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
 
2226
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
 
2227
    }
 
2228
 
 
2229
    {
 
2230
        InkToggleAction* act = ink_toggle_action_new("ToggleSnapToFromBBoxCenters",
 
2231
                                                     _("BBox Centers"), _("Snapping from and to centers of bounding boxes"),
 
2232
                                                     INKSCAPE_ICON_SNAP_BOUNDING_BOX_CENTER, secondarySize, SP_ATTR_INKSCAPE_SNAP_BBOX_MIDPOINTS);
 
2233
 
 
2234
        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
 
2235
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
 
2236
    }
 
2237
 
 
2238
    {
 
2239
        InkToggleAction* act = ink_toggle_action_new("ToggleSnapFromNode",
 
2240
                                                     _("Nodes"), _("Snap nodes or handles"), INKSCAPE_ICON_SNAP_NODES, secondarySize, SP_ATTR_INKSCAPE_SNAP_NODES);
 
2241
 
 
2242
        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
 
2243
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
 
2244
    }
 
2245
 
 
2246
    {
 
2247
        InkToggleAction* act = ink_toggle_action_new("ToggleSnapToItemPath",
 
2248
                                                     _("Paths"), _("Snap to paths"), INKSCAPE_ICON_SNAP_NODES_PATH, secondarySize,
 
2249
                                                     SP_ATTR_INKSCAPE_OBJECT_PATHS);
 
2250
 
 
2251
        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
 
2252
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
 
2253
    }
 
2254
 
 
2255
    {
 
2256
        InkToggleAction* act = ink_toggle_action_new("ToggleSnapToPathIntersections",
 
2257
                                                     _("Path intersections"), _("Snap to path intersections"),
 
2258
                                                     INKSCAPE_ICON_SNAP_NODES_INTERSECTION, secondarySize, SP_ATTR_INKSCAPE_SNAP_INTERS_PATHS);
 
2259
 
 
2260
        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
 
2261
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
 
2262
    }
 
2263
 
 
2264
    {
 
2265
        InkToggleAction* act = ink_toggle_action_new("ToggleSnapToItemNode",
 
2266
                                                     _("To nodes"), _("Snap to cusp nodes"), INKSCAPE_ICON_SNAP_NODES_CUSP, secondarySize,
 
2267
                                                     SP_ATTR_INKSCAPE_OBJECT_NODES);
 
2268
 
 
2269
        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
 
2270
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
 
2271
    }
 
2272
 
 
2273
    {
 
2274
        InkToggleAction* act = ink_toggle_action_new("ToggleSnapToSmoothNodes",
 
2275
                                                     _("Smooth nodes"), _("Snap to smooth nodes"), INKSCAPE_ICON_SNAP_NODES_SMOOTH,
 
2276
                                                     secondarySize, SP_ATTR_INKSCAPE_SNAP_SMOOTH_NODES);
 
2277
 
 
2278
        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
 
2279
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
 
2280
    }
 
2281
 
 
2282
    {
 
2283
        InkToggleAction* act = ink_toggle_action_new("ToggleSnapToFromLineMidpoints",
 
2284
                                                     _("Line Midpoints"), _("Snap from and to midpoints of line segments"),
 
2285
                                                     INKSCAPE_ICON_SNAP_NODES_MIDPOINT, secondarySize, SP_ATTR_INKSCAPE_SNAP_LINE_MIDPOINTS);
 
2286
 
 
2287
        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
 
2288
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
 
2289
    }
 
2290
 
 
2291
    {
 
2292
        InkToggleAction* act = ink_toggle_action_new("ToggleSnapToFromObjectCenters",
 
2293
                                                     _("Object Centers"), _("Snap from and to centers of objects"),
 
2294
                                                     INKSCAPE_ICON_SNAP_NODES_CENTER, secondarySize, SP_ATTR_INKSCAPE_SNAP_OBJECT_MIDPOINTS);
 
2295
 
 
2296
        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
 
2297
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
 
2298
    }
 
2299
 
 
2300
    {
 
2301
        InkToggleAction* act = ink_toggle_action_new("ToggleSnapToFromRotationCenter",
 
2302
                                                     _("Rotation Centers"), _("Snap from and to an item's rotation center"),
 
2303
                                                     INKSCAPE_ICON_SNAP_NODES_ROTATION_CENTER, secondarySize, SP_ATTR_INKSCAPE_SNAP_CENTER);
 
2304
 
 
2305
        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
 
2306
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
 
2307
    }
 
2308
 
 
2309
    {
 
2310
        InkToggleAction* act = ink_toggle_action_new("ToggleSnapToPageBorder",
 
2311
                                                     _("Page border"), _("Snap to the page border"), INKSCAPE_ICON_SNAP_PAGE,
 
2312
                                                     secondarySize, SP_ATTR_INKSCAPE_SNAP_PAGE);
 
2313
 
 
2314
        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
 
2315
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
 
2316
    }
 
2317
 
 
2318
    {
 
2319
        InkToggleAction* act = ink_toggle_action_new("ToggleSnapToGrids",
 
2320
                                                     _("Grids"), _("Snap to grids"), INKSCAPE_ICON_GRID_RECTANGULAR, secondarySize,
 
2321
                                                     SP_ATTR_INKSCAPE_SNAP_GRIDS);
 
2322
 
 
2323
        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
 
2324
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
 
2325
    }
 
2326
 
 
2327
    {
 
2328
        InkToggleAction* act = ink_toggle_action_new("ToggleSnapToGuides",
 
2329
                                                     _("Guides"), _("Snap to guides"), INKSCAPE_ICON_GUIDES, secondarySize,
 
2330
                                                     SP_ATTR_INKSCAPE_SNAP_TO_GUIDES);
 
2331
 
 
2332
        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
 
2333
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
 
2334
    }
 
2335
 
 
2336
    /*{
 
2337
      InkToggleAction* act = ink_toggle_action_new("ToggleSnapToGridGuideIntersections",
 
2338
      _("Grid/guide intersections"), _("Snap to intersections of a grid with a guide"),
 
2339
      INKSCAPE_ICON_SNAP_GRID_GUIDE_INTERSECTIONS, secondarySize,
 
2340
      SP_ATTR_INKSCAPE_SNAP_INTERS_GRIDGUIDE);
 
2341
 
 
2342
      gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
 
2343
      g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
 
2344
      }*/
 
2345
 
 
2346
    setupToolboxCommon( toolbox, desktop, descr,
 
2347
                        "/ui/SnapToolbar",
 
2348
                        "/toolbox/secondary" );
 
2349
}
 
2350
 
 
2351
Glib::ustring ToolboxFactory::getToolboxName(GtkWidget* toolbox)
 
2352
{
 
2353
    Glib::ustring name;
 
2354
    BarId id = static_cast<BarId>( GPOINTER_TO_INT(g_object_get_data(G_OBJECT(toolbox), BAR_ID_KEY)) );
 
2355
    switch(id) {
 
2356
        case BAR_TOOL:
 
2357
            name = "ToolToolbar";
 
2358
            break;
 
2359
        case BAR_AUX:
 
2360
            name = "AuxToolbar";
 
2361
            break;
 
2362
        case BAR_COMMANDS:
 
2363
            name = "CommandsToolbar";
 
2364
            break;
 
2365
        case BAR_SNAP:
 
2366
            name = "SnapToolbar";
 
2367
            break;
 
2368
    }
 
2369
 
 
2370
    return name;
 
2371
}
 
2372
 
 
2373
void ToolboxFactory::updateSnapToolbox(SPDesktop *desktop, SPEventContext * /*eventcontext*/, GtkWidget *toolbox)
 
2374
{
 
2375
    g_assert(desktop != NULL);
 
2376
    g_assert(toolbox != NULL);
 
2377
 
 
2378
    SPNamedView *nv = sp_desktop_namedview(desktop);
 
2379
    if (nv == NULL) {
 
2380
        g_warning("Namedview cannot be retrieved (in updateSnapToolbox)!");
 
2381
        return;
 
2382
    }
 
2383
 
 
2384
    Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions(desktop);
 
2385
 
 
2386
    Glib::RefPtr<Gtk::Action> act1 = mainActions->get_action("ToggleSnapGlobal");
 
2387
    Glib::RefPtr<Gtk::Action> act2 = mainActions->get_action("ToggleSnapFromBBoxCorner");
 
2388
    Glib::RefPtr<Gtk::Action> act3 = mainActions->get_action("ToggleSnapToBBoxPath");
 
2389
    Glib::RefPtr<Gtk::Action> act4 = mainActions->get_action("ToggleSnapToBBoxNode");
 
2390
    Glib::RefPtr<Gtk::Action> act4b = mainActions->get_action("ToggleSnapToFromBBoxEdgeMidpoints");
 
2391
    Glib::RefPtr<Gtk::Action> act4c = mainActions->get_action("ToggleSnapToFromBBoxCenters");
 
2392
    Glib::RefPtr<Gtk::Action> act5 = mainActions->get_action("ToggleSnapFromNode");
 
2393
    Glib::RefPtr<Gtk::Action> act6 = mainActions->get_action("ToggleSnapToItemPath");
 
2394
    Glib::RefPtr<Gtk::Action> act6b = mainActions->get_action("ToggleSnapToPathIntersections");
 
2395
    Glib::RefPtr<Gtk::Action> act7 = mainActions->get_action("ToggleSnapToItemNode");
 
2396
    Glib::RefPtr<Gtk::Action> act8 = mainActions->get_action("ToggleSnapToSmoothNodes");
 
2397
    Glib::RefPtr<Gtk::Action> act9 = mainActions->get_action("ToggleSnapToFromLineMidpoints");
 
2398
    Glib::RefPtr<Gtk::Action> act10 = mainActions->get_action("ToggleSnapToFromObjectCenters");
 
2399
    Glib::RefPtr<Gtk::Action> act11 = mainActions->get_action("ToggleSnapToFromRotationCenter");
 
2400
    Glib::RefPtr<Gtk::Action> act12 = mainActions->get_action("ToggleSnapToPageBorder");
 
2401
    //Glib::RefPtr<Gtk::Action> act13 = mainActions->get_action("ToggleSnapToGridGuideIntersections");
 
2402
    Glib::RefPtr<Gtk::Action> act14 = mainActions->get_action("ToggleSnapToGrids");
 
2403
    Glib::RefPtr<Gtk::Action> act15 = mainActions->get_action("ToggleSnapToGuides");
 
2404
 
 
2405
 
 
2406
    if (!act1) {
 
2407
        return; // The snap actions haven't been defined yet (might be the case during startup)
 
2408
    }
 
2409
 
 
2410
    // The ..._set_active calls below will toggle the buttons, but this shouldn't lead to
 
2411
    // changes in our document because we're only updating the UI;
 
2412
    // Setting the "freeze" parameter to true will block the code in toggle_snap_callback()
 
2413
    g_object_set_data(G_OBJECT(toolbox), "freeze", GINT_TO_POINTER(TRUE));
 
2414
 
 
2415
    bool const c1 = nv->snap_manager.snapprefs.getSnapEnabledGlobally();
 
2416
    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act1->gobj()), c1);
 
2417
 
 
2418
    bool const c2 = nv->snap_manager.snapprefs.getSnapModeBBox();
 
2419
    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act2->gobj()), c2);
 
2420
    gtk_action_set_sensitive(GTK_ACTION(act2->gobj()), c1);
 
2421
 
 
2422
    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act3->gobj()), nv->snap_manager.snapprefs.getSnapToBBoxPath());
 
2423
    gtk_action_set_sensitive(GTK_ACTION(act3->gobj()), c1 && c2);
 
2424
    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act4->gobj()), nv->snap_manager.snapprefs.getSnapToBBoxNode());
 
2425
    gtk_action_set_sensitive(GTK_ACTION(act4->gobj()), c1 && c2);
 
2426
    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act4b->gobj()), nv->snap_manager.snapprefs.getSnapBBoxEdgeMidpoints());
 
2427
    gtk_action_set_sensitive(GTK_ACTION(act4b->gobj()), c1 && c2);
 
2428
    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act4c->gobj()), nv->snap_manager.snapprefs.getSnapBBoxMidpoints());
 
2429
    gtk_action_set_sensitive(GTK_ACTION(act4c->gobj()), c1 && c2);
 
2430
 
 
2431
    bool const c3 = nv->snap_manager.snapprefs.getSnapModeNode();
 
2432
    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act5->gobj()), c3);
 
2433
    gtk_action_set_sensitive(GTK_ACTION(act5->gobj()), c1);
 
2434
 
 
2435
    bool const c4 = nv->snap_manager.snapprefs.getSnapToItemPath();
 
2436
    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act6->gobj()), c4);
 
2437
    gtk_action_set_sensitive(GTK_ACTION(act6->gobj()), c1 && c3);
 
2438
    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act6b->gobj()), nv->snap_manager.snapprefs.getSnapIntersectionCS());
 
2439
    gtk_action_set_sensitive(GTK_ACTION(act6b->gobj()), c1 && c3 && c4);
 
2440
    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act7->gobj()), nv->snap_manager.snapprefs.getSnapToItemNode());
 
2441
    gtk_action_set_sensitive(GTK_ACTION(act7->gobj()), c1 && c3);
 
2442
    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act8->gobj()), nv->snap_manager.snapprefs.getSnapSmoothNodes());
 
2443
    gtk_action_set_sensitive(GTK_ACTION(act8->gobj()), c1 && c3);
 
2444
    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act9->gobj()), nv->snap_manager.snapprefs.getSnapLineMidpoints());
 
2445
    gtk_action_set_sensitive(GTK_ACTION(act9->gobj()), c1 && c3);
 
2446
    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act10->gobj()), nv->snap_manager.snapprefs.getSnapObjectMidpoints());
 
2447
    gtk_action_set_sensitive(GTK_ACTION(act10->gobj()), c1 && c3);
 
2448
    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act11->gobj()), nv->snap_manager.snapprefs.getIncludeItemCenter());
 
2449
    gtk_action_set_sensitive(GTK_ACTION(act11->gobj()), c1 && c3);
 
2450
 
 
2451
    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act12->gobj()), nv->snap_manager.snapprefs.getSnapToPageBorder());
 
2452
    gtk_action_set_sensitive(GTK_ACTION(act12->gobj()), c1);
 
2453
    //gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act13->gobj()), nv->snap_manager.snapprefs.getSnapIntersectionGG());
 
2454
    //gtk_action_set_sensitive(GTK_ACTION(act13->gobj()), c1);
 
2455
 
 
2456
    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act14->gobj()), nv->snap_manager.snapprefs.getSnapToGrids());
 
2457
    gtk_action_set_sensitive(GTK_ACTION(act14->gobj()), c1);
 
2458
    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act15->gobj()), nv->snap_manager.snapprefs.getSnapToGuides());
 
2459
    gtk_action_set_sensitive(GTK_ACTION(act15->gobj()), c1);
 
2460
 
 
2461
 
 
2462
    g_object_set_data(G_OBJECT(toolbox), "freeze", GINT_TO_POINTER(FALSE)); // unfreeze (see above)
 
2463
}
 
2464
 
 
2465
void ToolboxFactory::showAuxToolbox(GtkWidget *toolbox_toplevel)
 
2466
{
 
2467
    gtk_widget_show(toolbox_toplevel);
 
2468
    GtkWidget *toolbox = gtk_bin_get_child(GTK_BIN(toolbox_toplevel));
 
2469
 
 
2470
    GtkWidget *shown_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "shows"));
 
2471
    if (!shown_toolbox) {
 
2472
        return;
 
2473
    }
 
2474
    gtk_widget_show(toolbox);
 
2475
 
 
2476
    gtk_widget_show_all(shown_toolbox);
 
2477
}
 
2478
 
 
2479
static GtkWidget *sp_empty_toolbox_new(SPDesktop *desktop)
 
2480
{
 
2481
    GtkWidget *tbl = gtk_toolbar_new();
 
2482
    gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
 
2483
    gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
 
2484
 
 
2485
    gtk_widget_show_all(tbl);
 
2486
    sp_set_font_size_smaller (tbl);
 
2487
 
 
2488
    return tbl;
 
2489
}
 
2490
 
 
2491
#define MODE_LABEL_WIDTH 70
 
2492
 
 
2493
//########################
 
2494
//##       Star         ##
 
2495
//########################
 
2496
 
 
2497
static void sp_stb_magnitude_value_changed( GtkAdjustment *adj, GObject *dataKludge )
 
2498
{
 
2499
    SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
 
2500
 
 
2501
    if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
 
2502
        // do not remember prefs if this call is initiated by an undo change, because undoing object
 
2503
        // creation sets bogus values to its attributes before it is deleted
 
2504
        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
2505
        prefs->setInt("/tools/shapes/star/magnitude", (gint)adj->value);
 
2506
    }
 
2507
 
 
2508
    // quit if run by the attr_changed listener
 
2509
    if (g_object_get_data( dataKludge, "freeze" )) {
 
2510
        return;
 
2511
    }
 
2512
 
 
2513
    // in turn, prevent listener from responding
 
2514
    g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
 
2515
 
 
2516
    bool modmade = false;
 
2517
 
 
2518
    Inkscape::Selection *selection = sp_desktop_selection(desktop);
 
2519
    GSList const *items = selection->itemList();
 
2520
    for (; items != NULL; items = items->next) {
 
2521
        if (SP_IS_STAR((SPItem *) items->data)) {
 
2522
            Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
 
2523
            sp_repr_set_int(repr,"sodipodi:sides",(gint)adj->value);
 
2524
            sp_repr_set_svg_double(repr, "sodipodi:arg2",
 
2525
                                   (sp_repr_get_double_attribute(repr, "sodipodi:arg1", 0.5)
 
2526
                                    + M_PI / (gint)adj->value));
 
2527
            SP_OBJECT((SPItem *) items->data)->updateRepr();
 
2528
            modmade = true;
 
2529
        }
 
2530
    }
 
2531
    if (modmade) {
 
2532
        sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
 
2533
                         _("Star: Change number of corners"));
 
2534
    }
 
2535
 
 
2536
    g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
 
2537
}
 
2538
 
 
2539
static void sp_stb_proportion_value_changed( GtkAdjustment *adj, GObject *dataKludge )
 
2540
{
 
2541
    SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
 
2542
 
 
2543
    if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
 
2544
        if (!IS_NAN(adj->value)) {
 
2545
            Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
2546
            prefs->setDouble("/tools/shapes/star/proportion", adj->value);
 
2547
        }
 
2548
    }
 
2549
 
 
2550
    // quit if run by the attr_changed listener
 
2551
    if (g_object_get_data( dataKludge, "freeze" )) {
 
2552
        return;
 
2553
    }
 
2554
 
 
2555
    // in turn, prevent listener from responding
 
2556
    g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
 
2557
 
 
2558
    bool modmade = false;
 
2559
    Inkscape::Selection *selection = sp_desktop_selection(desktop);
 
2560
    GSList const *items = selection->itemList();
 
2561
    for (; items != NULL; items = items->next) {
 
2562
        if (SP_IS_STAR((SPItem *) items->data)) {
 
2563
            Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
 
2564
 
 
2565
            gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
 
2566
            gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
 
2567
            if (r2 < r1) {
 
2568
                sp_repr_set_svg_double(repr, "sodipodi:r2", r1*adj->value);
 
2569
            } else {
 
2570
                sp_repr_set_svg_double(repr, "sodipodi:r1", r2*adj->value);
 
2571
            }
 
2572
 
 
2573
            SP_OBJECT((SPItem *) items->data)->updateRepr();
 
2574
            modmade = true;
 
2575
        }
 
2576
    }
 
2577
 
 
2578
    if (modmade) {
 
2579
        sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
 
2580
                         _("Star: Change spoke ratio"));
 
2581
    }
 
2582
 
 
2583
    g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
 
2584
}
 
2585
 
 
2586
static void sp_stb_sides_flat_state_changed( EgeSelectOneAction *act, GObject *dataKludge )
 
2587
{
 
2588
    SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
 
2589
    bool flat = ege_select_one_action_get_active( act ) == 0;
 
2590
 
 
2591
    if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
 
2592
        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
2593
        prefs->setBool( "/tools/shapes/star/isflatsided", flat);
 
2594
    }
 
2595
 
 
2596
    // quit if run by the attr_changed listener
 
2597
    if (g_object_get_data( dataKludge, "freeze" )) {
 
2598
        return;
 
2599
    }
 
2600
 
 
2601
    // in turn, prevent listener from responding
 
2602
    g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
 
2603
 
 
2604
    Inkscape::Selection *selection = sp_desktop_selection(desktop);
 
2605
    GSList const *items = selection->itemList();
 
2606
    GtkAction* prop_action = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
 
2607
    bool modmade = false;
 
2608
 
 
2609
    if ( prop_action ) {
 
2610
        gtk_action_set_sensitive( prop_action, !flat );
 
2611
    }
 
2612
 
 
2613
    for (; items != NULL; items = items->next) {
 
2614
        if (SP_IS_STAR((SPItem *) items->data)) {
 
2615
            Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
 
2616
            repr->setAttribute("inkscape:flatsided", flat ? "true" : "false" );
 
2617
            SP_OBJECT((SPItem *) items->data)->updateRepr();
 
2618
            modmade = true;
 
2619
        }
 
2620
    }
 
2621
 
 
2622
    if (modmade) {
 
2623
        sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
 
2624
                         flat ? _("Make polygon") : _("Make star"));
 
2625
    }
 
2626
 
 
2627
    g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
 
2628
}
 
2629
 
 
2630
static void sp_stb_rounded_value_changed( GtkAdjustment *adj, GObject *dataKludge )
 
2631
{
 
2632
    SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
 
2633
 
 
2634
    if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
 
2635
        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
2636
        prefs->setDouble("/tools/shapes/star/rounded", (gdouble) adj->value);
 
2637
    }
 
2638
 
 
2639
    // quit if run by the attr_changed listener
 
2640
    if (g_object_get_data( dataKludge, "freeze" )) {
 
2641
        return;
 
2642
    }
 
2643
 
 
2644
    // in turn, prevent listener from responding
 
2645
    g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
 
2646
 
 
2647
    bool modmade = false;
 
2648
 
 
2649
    Inkscape::Selection *selection = sp_desktop_selection(desktop);
 
2650
    GSList const *items = selection->itemList();
 
2651
    for (; items != NULL; items = items->next) {
 
2652
        if (SP_IS_STAR((SPItem *) items->data)) {
 
2653
            Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
 
2654
            sp_repr_set_svg_double(repr, "inkscape:rounded", (gdouble) adj->value);
 
2655
            SP_OBJECT(items->data)->updateRepr();
 
2656
            modmade = true;
 
2657
        }
 
2658
    }
 
2659
    if (modmade) {
 
2660
        sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
 
2661
                         _("Star: Change rounding"));
 
2662
    }
 
2663
 
 
2664
    g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
 
2665
}
 
2666
 
 
2667
static void sp_stb_randomized_value_changed( GtkAdjustment *adj, GObject *dataKludge )
 
2668
{
 
2669
    SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
 
2670
 
 
2671
    if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
 
2672
        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
2673
        prefs->setDouble("/tools/shapes/star/randomized", (gdouble) adj->value);
 
2674
    }
 
2675
 
 
2676
    // quit if run by the attr_changed listener
 
2677
    if (g_object_get_data( dataKludge, "freeze" )) {
 
2678
        return;
 
2679
    }
 
2680
 
 
2681
    // in turn, prevent listener from responding
 
2682
    g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
 
2683
 
 
2684
    bool modmade = false;
 
2685
 
 
2686
    Inkscape::Selection *selection = sp_desktop_selection(desktop);
 
2687
    GSList const *items = selection->itemList();
 
2688
    for (; items != NULL; items = items->next) {
 
2689
        if (SP_IS_STAR((SPItem *) items->data)) {
 
2690
            Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
 
2691
            sp_repr_set_svg_double(repr, "inkscape:randomized", (gdouble) adj->value);
 
2692
            SP_OBJECT(items->data)->updateRepr();
 
2693
            modmade = true;
 
2694
        }
 
2695
    }
 
2696
    if (modmade) {
 
2697
        sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
 
2698
                         _("Star: Change randomization"));
 
2699
    }
 
2700
 
 
2701
    g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
 
2702
}
 
2703
 
 
2704
 
 
2705
static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
 
2706
                                       gchar const * /*old_value*/, gchar const * /*new_value*/,
 
2707
                                       bool /*is_interactive*/, gpointer data)
 
2708
{
 
2709
    GtkWidget *tbl = GTK_WIDGET(data);
 
2710
 
 
2711
    // quit if run by the _changed callbacks
 
2712
    if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
 
2713
        return;
 
2714
    }
 
2715
 
 
2716
    // in turn, prevent callbacks from responding
 
2717
    g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
 
2718
 
 
2719
    GtkAdjustment *adj = 0;
 
2720
 
 
2721
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
2722
    bool isFlatSided = prefs->getBool("/tools/shapes/star/isflatsided", true);
 
2723
 
 
2724
    if (!strcmp(name, "inkscape:randomized")) {
 
2725
        adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "randomized") );
 
2726
        gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:randomized", 0.0));
 
2727
    } else if (!strcmp(name, "inkscape:rounded")) {
 
2728
        adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "rounded") );
 
2729
        gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:rounded", 0.0));
 
2730
    } else if (!strcmp(name, "inkscape:flatsided")) {
 
2731
        GtkAction* prop_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "prop_action") );
 
2732
        char const *flatsides = repr->attribute("inkscape:flatsided");
 
2733
        EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( G_OBJECT(tbl), "flat_action" ) );
 
2734
        if ( flatsides && !strcmp(flatsides,"false") ) {
 
2735
            ege_select_one_action_set_active( flat_action, 1 );
 
2736
            gtk_action_set_sensitive( prop_action, TRUE );
 
2737
        } else {
 
2738
            ege_select_one_action_set_active( flat_action, 0 );
 
2739
            gtk_action_set_sensitive( prop_action, FALSE );
 
2740
        }
 
2741
    } else if ((!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) && (!isFlatSided) ) {
 
2742
        adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
 
2743
        gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
 
2744
        gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
 
2745
        if (r2 < r1) {
 
2746
            gtk_adjustment_set_value(adj, r2/r1);
 
2747
        } else {
 
2748
            gtk_adjustment_set_value(adj, r1/r2);
 
2749
        }
 
2750
    } else if (!strcmp(name, "sodipodi:sides")) {
 
2751
        adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
 
2752
        gtk_adjustment_set_value(adj, sp_repr_get_int_attribute(repr, "sodipodi:sides", 0));
 
2753
    }
 
2754
 
 
2755
    g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
 
2756
}
 
2757
 
 
2758
 
 
2759
static Inkscape::XML::NodeEventVector star_tb_repr_events =
 
2760
{
 
2761
    NULL, /* child_added */
 
2762
    NULL, /* child_removed */
 
2763
    star_tb_event_attr_changed,
 
2764
    NULL, /* content_changed */
 
2765
    NULL  /* order_changed */
 
2766
};
 
2767
 
 
2768
 
 
2769
/**
 
2770
 *  \param selection Should not be NULL.
 
2771
 */
 
2772
static void
 
2773
sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
 
2774
{
 
2775
    int n_selected = 0;
 
2776
    Inkscape::XML::Node *repr = NULL;
 
2777
 
 
2778
    purge_repr_listener( tbl, tbl );
 
2779
 
 
2780
    for (GSList const *items = selection->itemList();
 
2781
         items != NULL;
 
2782
         items = items->next)
 
2783
    {
 
2784
        if (SP_IS_STAR((SPItem *) items->data)) {
 
2785
            n_selected++;
 
2786
            repr = SP_OBJECT_REPR((SPItem *) items->data);
 
2787
        }
 
2788
    }
 
2789
 
 
2790
    EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
 
2791
 
 
2792
    if (n_selected == 0) {
 
2793
        g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
 
2794
    } else if (n_selected == 1) {
 
2795
        g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
 
2796
 
 
2797
        if (repr) {
 
2798
            g_object_set_data( tbl, "repr", repr );
 
2799
            Inkscape::GC::anchor(repr);
 
2800
            sp_repr_add_listener(repr, &star_tb_repr_events, tbl);
 
2801
            sp_repr_synthesize_events(repr, &star_tb_repr_events, tbl);
 
2802
        }
 
2803
    } else {
 
2804
        // FIXME: implement averaging of all parameters for multiple selected stars
 
2805
        //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
 
2806
        //gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
 
2807
    }
 
2808
}
 
2809
 
 
2810
 
 
2811
static void sp_stb_defaults( GtkWidget * /*widget*/, GObject *dataKludge )
 
2812
{
 
2813
    // FIXME: in this and all other _default functions, set some flag telling the value_changed
 
2814
    // callbacks to lump all the changes for all selected objects in one undo step
 
2815
 
 
2816
    GtkAdjustment *adj = 0;
 
2817
 
 
2818
    // fixme: make settable in prefs!
 
2819
    gint mag = 5;
 
2820
    gdouble prop = 0.5;
 
2821
    gboolean flat = FALSE;
 
2822
    gdouble randomized = 0;
 
2823
    gdouble rounded = 0;
 
2824
 
 
2825
    EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "flat_action" ) );
 
2826
    ege_select_one_action_set_active( flat_action, flat ? 0 : 1 );
 
2827
 
 
2828
    GtkAction* sb2 = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
 
2829
    gtk_action_set_sensitive( sb2, !flat );
 
2830
 
 
2831
    adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "magnitude" ) );
 
2832
    gtk_adjustment_set_value(adj, mag);
 
2833
    gtk_adjustment_value_changed(adj);
 
2834
 
 
2835
    adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "proportion" ) );
 
2836
    gtk_adjustment_set_value(adj, prop);
 
2837
    gtk_adjustment_value_changed(adj);
 
2838
 
 
2839
    adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "rounded" ) );
 
2840
    gtk_adjustment_set_value(adj, rounded);
 
2841
    gtk_adjustment_value_changed(adj);
 
2842
 
 
2843
    adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "randomized" ) );
 
2844
    gtk_adjustment_set_value(adj, randomized);
 
2845
    gtk_adjustment_value_changed(adj);
 
2846
}
 
2847
 
 
2848
 
 
2849
// public:
 
2850
void sp_toolbox_add_label(GtkWidget *tbl, gchar const *title, bool wide)
 
2851
{
 
2852
    GtkWidget *boxl = gtk_hbox_new(FALSE, 0);
 
2853
    if (wide) {
 
2854
        gtk_widget_set_size_request(boxl, MODE_LABEL_WIDTH, -1);
 
2855
    }
 
2856
    GtkWidget *l = gtk_label_new(NULL);
 
2857
    gtk_label_set_markup(GTK_LABEL(l), title);
 
2858
    gtk_box_pack_end(GTK_BOX(boxl), l, FALSE, FALSE, 0);
 
2859
    if ( GTK_IS_TOOLBAR(tbl) ) {
 
2860
        gtk_toolbar_append_widget( GTK_TOOLBAR(tbl), boxl, "", "" );
 
2861
    } else {
 
2862
        gtk_box_pack_start(GTK_BOX(tbl), boxl, FALSE, FALSE, 0);
 
2863
    }
 
2864
    gtk_object_set_data(GTK_OBJECT(tbl), "mode_label", l);
 
2865
}
 
2866
 
 
2867
 
 
2868
static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
 
2869
{
 
2870
    Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1);
 
2871
 
 
2872
    {
 
2873
        EgeOutputAction* act = ege_output_action_new( "StarStateAction", _("<b>New:</b>"), "", 0 );
 
2874
        ege_output_action_set_use_markup( act, TRUE );
 
2875
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
2876
        g_object_set_data( holder, "mode_action", act );
 
2877
    }
 
2878
 
 
2879
    {
 
2880
        EgeAdjustmentAction* eact = 0;
 
2881
        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
2882
        bool isFlatSided = prefs->getBool("/tools/shapes/star/isflatsided", true);
 
2883
 
 
2884
        /* Flatsided checkbox */
 
2885
        {
 
2886
            GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
 
2887
 
 
2888
            GtkTreeIter iter;
 
2889
            gtk_list_store_append( model, &iter );
 
2890
            gtk_list_store_set( model, &iter,
 
2891
                                0, _("Polygon"),
 
2892
                                1, _("Regular polygon (with one handle) instead of a star"),
 
2893
                                2, INKSCAPE_ICON_DRAW_POLYGON,
 
2894
                                -1 );
 
2895
 
 
2896
            gtk_list_store_append( model, &iter );
 
2897
            gtk_list_store_set( model, &iter,
 
2898
                                0, _("Star"),
 
2899
                                1, _("Star instead of a regular polygon (with one handle)"),
 
2900
                                2, INKSCAPE_ICON_DRAW_STAR,
 
2901
                                -1 );
 
2902
 
 
2903
            EgeSelectOneAction* act = ege_select_one_action_new( "FlatAction", (""), (""), NULL, GTK_TREE_MODEL(model) );
 
2904
            gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
 
2905
            g_object_set_data( holder, "flat_action", act );
 
2906
 
 
2907
            ege_select_one_action_set_appearance( act, "full" );
 
2908
            ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
 
2909
            g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
 
2910
            ege_select_one_action_set_icon_column( act, 2 );
 
2911
            ege_select_one_action_set_icon_size( act, secondarySize );
 
2912
            ege_select_one_action_set_tooltip_column( act, 1  );
 
2913
 
 
2914
            ege_select_one_action_set_active( act, isFlatSided ? 0 : 1 );
 
2915
            g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_stb_sides_flat_state_changed), holder);
 
2916
        }
 
2917
 
 
2918
        /* Magnitude */
 
2919
        {
 
2920
        gchar const* labels[] = {_("triangle/tri-star"), _("square/quad-star"), _("pentagon/five-pointed star"), _("hexagon/six-pointed star"), 0, 0, 0, 0, 0};
 
2921
        gdouble values[] = {3, 4, 5, 6, 7, 8, 10, 12, 20};
 
2922
        eact = create_adjustment_action( "MagnitudeAction",
 
2923
                                         _("Corners"), _("Corners:"), _("Number of corners of a polygon or star"),
 
2924
                                         "/tools/shapes/star/magnitude", 3,
 
2925
                                         GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
 
2926
                                         3, 1024, 1, 5,
 
2927
                                         labels, values, G_N_ELEMENTS(labels),
 
2928
                                         sp_stb_magnitude_value_changed,
 
2929
                                         1.0, 0 );
 
2930
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
2931
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
2932
        }
 
2933
 
 
2934
        /* Spoke ratio */
 
2935
        {
 
2936
        gchar const* labels[] = {_("thin-ray star"), 0, _("pentagram"), _("hexagram"), _("heptagram"), _("octagram"), _("regular polygon")};
 
2937
        gdouble values[] = {0.01, 0.2, 0.382, 0.577, 0.692, 0.765, 1};
 
2938
        eact = create_adjustment_action( "SpokeAction",
 
2939
                                         _("Spoke ratio"), _("Spoke ratio:"),
 
2940
                                         // TRANSLATORS: Tip radius of a star is the distance from the center to the farthest handle.
 
2941
                                         // Base radius is the same for the closest handle.
 
2942
                                         _("Base radius to tip radius ratio"),
 
2943
                                         "/tools/shapes/star/proportion", 0.5,
 
2944
                                         GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
 
2945
                                         0.01, 1.0, 0.01, 0.1,
 
2946
                                         labels, values, G_N_ELEMENTS(labels),
 
2947
                                         sp_stb_proportion_value_changed );
 
2948
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
2949
        g_object_set_data( holder, "prop_action", eact );
 
2950
        }
 
2951
 
 
2952
        if ( !isFlatSided ) {
 
2953
            gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
2954
        } else {
 
2955
            gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
 
2956
        }
 
2957
 
 
2958
        /* Roundedness */
 
2959
        {
 
2960
        gchar const* labels[] = {_("stretched"), _("twisted"), _("slightly pinched"), _("NOT rounded"), _("slightly rounded"), _("visibly rounded"), _("well rounded"), _("amply rounded"), 0, _("stretched"), _("blown up")};
 
2961
        gdouble values[] = {-1, -0.2, -0.03, 0, 0.05, 0.1, 0.2, 0.3, 0.5, 1, 10};
 
2962
        eact = create_adjustment_action( "RoundednessAction",
 
2963
                                         _("Rounded"), _("Rounded:"), _("How much rounded are the corners (0 for sharp)"),
 
2964
                                         "/tools/shapes/star/rounded", 0.0,
 
2965
                                         GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
 
2966
                                         -10.0, 10.0, 0.01, 0.1,
 
2967
                                         labels, values, G_N_ELEMENTS(labels),
 
2968
                                         sp_stb_rounded_value_changed );
 
2969
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
2970
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
2971
        }
 
2972
 
 
2973
        /* Randomization */
 
2974
        {
 
2975
        gchar const* labels[] = {_("NOT randomized"), _("slightly irregular"), _("visibly randomized"), _("strongly randomized"), _("blown up")};
 
2976
        gdouble values[] = {0, 0.01, 0.1, 0.5, 10};
 
2977
        eact = create_adjustment_action( "RandomizationAction",
 
2978
                                         _("Randomized"), _("Randomized:"), _("Scatter randomly the corners and angles"),
 
2979
                                         "/tools/shapes/star/randomized", 0.0,
 
2980
                                         GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
 
2981
                                         -10.0, 10.0, 0.001, 0.01,
 
2982
                                         labels, values, G_N_ELEMENTS(labels),
 
2983
                                         sp_stb_randomized_value_changed, 0.1, 3 );
 
2984
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
2985
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
2986
        }
 
2987
    }
 
2988
 
 
2989
    {
 
2990
        /* Reset */
 
2991
        {
 
2992
            GtkAction* act = gtk_action_new( "StarResetAction",
 
2993
                                             _("Defaults"),
 
2994
                                             _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
 
2995
                                             GTK_STOCK_CLEAR );
 
2996
            g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_stb_defaults), holder );
 
2997
            gtk_action_group_add_action( mainActions, act );
 
2998
            gtk_action_set_sensitive( act, TRUE );
 
2999
        }
 
3000
    }
 
3001
 
 
3002
    sigc::connection *connection = new sigc::connection(
 
3003
        sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_star_toolbox_selection_changed), (GObject *)holder))
 
3004
        );
 
3005
    g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
 
3006
    g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
 
3007
}
 
3008
 
 
3009
 
 
3010
//########################
 
3011
//##       Rect         ##
 
3012
//########################
 
3013
 
 
3014
static void sp_rtb_sensitivize( GObject *tbl )
 
3015
{
 
3016
    GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data(tbl, "rx") );
 
3017
    GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data(tbl, "ry") );
 
3018
    GtkAction* not_rounded = GTK_ACTION( g_object_get_data(tbl, "not_rounded") );
 
3019
 
 
3020
    if (adj1->value == 0 && adj2->value == 0 && g_object_get_data(tbl, "single")) { // only for a single selected rect (for now)
 
3021
        gtk_action_set_sensitive( not_rounded, FALSE );
 
3022
    } else {
 
3023
        gtk_action_set_sensitive( not_rounded, TRUE );
 
3024
    }
 
3025
}
 
3026
 
 
3027
 
 
3028
static void sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name,
 
3029
                                 void (*setter)(SPRect *, gdouble))
 
3030
{
 
3031
    SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
 
3032
 
 
3033
    UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
 
3034
    SPUnit const *unit = tracker->getActiveUnit();
 
3035
 
 
3036
    if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
 
3037
        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
3038
        prefs->setDouble(Glib::ustring("/tools/shapes/rect/") + value_name, sp_units_get_pixels(adj->value, *unit));
 
3039
    }
 
3040
 
 
3041
    // quit if run by the attr_changed listener
 
3042
    if (g_object_get_data( tbl, "freeze" )) {
 
3043
        return;
 
3044
    }
 
3045
 
 
3046
    // in turn, prevent listener from responding
 
3047
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
 
3048
 
 
3049
    bool modmade = false;
 
3050
    Inkscape::Selection *selection = sp_desktop_selection(desktop);
 
3051
    for (GSList const *items = selection->itemList(); items != NULL; items = items->next) {
 
3052
        if (SP_IS_RECT(items->data)) {
 
3053
            if (adj->value != 0) {
 
3054
                setter(SP_RECT(items->data), sp_units_get_pixels(adj->value, *unit));
 
3055
            } else {
 
3056
                SP_OBJECT_REPR(items->data)->setAttribute(value_name, NULL);
 
3057
            }
 
3058
            modmade = true;
 
3059
        }
 
3060
    }
 
3061
 
 
3062
    sp_rtb_sensitivize( tbl );
 
3063
 
 
3064
    if (modmade) {
 
3065
        sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_RECT,
 
3066
                                   _("Change rectangle"));
 
3067
    }
 
3068
 
 
3069
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 
3070
}
 
3071
 
 
3072
static void sp_rtb_rx_value_changed(GtkAdjustment *adj, GObject *tbl)
 
3073
{
 
3074
    sp_rtb_value_changed(adj, tbl, "rx", sp_rect_set_visible_rx);
 
3075
}
 
3076
 
 
3077
static void sp_rtb_ry_value_changed(GtkAdjustment *adj, GObject *tbl)
 
3078
{
 
3079
    sp_rtb_value_changed(adj, tbl, "ry", sp_rect_set_visible_ry);
 
3080
}
 
3081
 
 
3082
static void sp_rtb_width_value_changed(GtkAdjustment *adj, GObject *tbl)
 
3083
{
 
3084
    sp_rtb_value_changed(adj, tbl, "width", sp_rect_set_visible_width);
 
3085
}
 
3086
 
 
3087
static void sp_rtb_height_value_changed(GtkAdjustment *adj, GObject *tbl)
 
3088
{
 
3089
    sp_rtb_value_changed(adj, tbl, "height", sp_rect_set_visible_height);
 
3090
}
 
3091
 
 
3092
 
 
3093
 
 
3094
static void sp_rtb_defaults( GtkWidget * /*widget*/, GObject *obj)
 
3095
{
 
3096
    GtkAdjustment *adj = 0;
 
3097
 
 
3098
    adj = GTK_ADJUSTMENT( g_object_get_data(obj, "rx") );
 
3099
    gtk_adjustment_set_value(adj, 0.0);
 
3100
    // this is necessary if the previous value was 0, but we still need to run the callback to change all selected objects
 
3101
    gtk_adjustment_value_changed(adj);
 
3102
 
 
3103
    adj = GTK_ADJUSTMENT( g_object_get_data(obj, "ry") );
 
3104
    gtk_adjustment_set_value(adj, 0.0);
 
3105
    gtk_adjustment_value_changed(adj);
 
3106
 
 
3107
    sp_rtb_sensitivize( obj );
 
3108
}
 
3109
 
 
3110
static void rect_tb_event_attr_changed(Inkscape::XML::Node * /*repr*/, gchar const * /*name*/,
 
3111
                                       gchar const * /*old_value*/, gchar const * /*new_value*/,
 
3112
                                       bool /*is_interactive*/, gpointer data)
 
3113
{
 
3114
    GObject *tbl = G_OBJECT(data);
 
3115
 
 
3116
    // quit if run by the _changed callbacks
 
3117
    if (g_object_get_data( tbl, "freeze" )) {
 
3118
        return;
 
3119
    }
 
3120
 
 
3121
    // in turn, prevent callbacks from responding
 
3122
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
 
3123
 
 
3124
    UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) );
 
3125
    SPUnit const *unit = tracker->getActiveUnit();
 
3126
 
 
3127
    gpointer item = g_object_get_data( tbl, "item" );
 
3128
    if (item && SP_IS_RECT(item)) {
 
3129
        {
 
3130
            GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "rx" ) );
 
3131
            gdouble rx = sp_rect_get_visible_rx(SP_RECT(item));
 
3132
            gtk_adjustment_set_value(adj, sp_pixels_get_units(rx, *unit));
 
3133
        }
 
3134
 
 
3135
        {
 
3136
            GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "ry" ) );
 
3137
            gdouble ry = sp_rect_get_visible_ry(SP_RECT(item));
 
3138
            gtk_adjustment_set_value(adj, sp_pixels_get_units(ry, *unit));
 
3139
        }
 
3140
 
 
3141
        {
 
3142
            GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "width" ) );
 
3143
            gdouble width = sp_rect_get_visible_width (SP_RECT(item));
 
3144
            gtk_adjustment_set_value(adj, sp_pixels_get_units(width, *unit));
 
3145
        }
 
3146
 
 
3147
        {
 
3148
            GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "height" ) );
 
3149
            gdouble height = sp_rect_get_visible_height (SP_RECT(item));
 
3150
            gtk_adjustment_set_value(adj, sp_pixels_get_units(height, *unit));
 
3151
        }
 
3152
    }
 
3153
 
 
3154
    sp_rtb_sensitivize( tbl );
 
3155
 
 
3156
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 
3157
}
 
3158
 
 
3159
 
 
3160
static Inkscape::XML::NodeEventVector rect_tb_repr_events = {
 
3161
    NULL, /* child_added */
 
3162
    NULL, /* child_removed */
 
3163
    rect_tb_event_attr_changed,
 
3164
    NULL, /* content_changed */
 
3165
    NULL  /* order_changed */
 
3166
};
 
3167
 
 
3168
/**
 
3169
 *  \param selection should not be NULL.
 
3170
 */
 
3171
static void sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
 
3172
{
 
3173
    int n_selected = 0;
 
3174
    Inkscape::XML::Node *repr = NULL;
 
3175
    SPItem *item = NULL;
 
3176
 
 
3177
    if ( g_object_get_data( tbl, "repr" ) ) {
 
3178
        g_object_set_data( tbl, "item", NULL );
 
3179
    }
 
3180
    purge_repr_listener( tbl, tbl );
 
3181
 
 
3182
    for (GSList const *items = selection->itemList();
 
3183
         items != NULL;
 
3184
         items = items->next) {
 
3185
        if (SP_IS_RECT((SPItem *) items->data)) {
 
3186
            n_selected++;
 
3187
            item = (SPItem *) items->data;
 
3188
            repr = SP_OBJECT_REPR(item);
 
3189
        }
 
3190
    }
 
3191
 
 
3192
    EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
 
3193
 
 
3194
    g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
 
3195
 
 
3196
    if (n_selected == 0) {
 
3197
        g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
 
3198
 
 
3199
        GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
 
3200
        gtk_action_set_sensitive(w, FALSE);
 
3201
        GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
 
3202
        gtk_action_set_sensitive(h, FALSE);
 
3203
 
 
3204
    } else if (n_selected == 1) {
 
3205
        g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
 
3206
        g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
 
3207
 
 
3208
        GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
 
3209
        gtk_action_set_sensitive(w, TRUE);
 
3210
        GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
 
3211
        gtk_action_set_sensitive(h, TRUE);
 
3212
 
 
3213
        if (repr) {
 
3214
            g_object_set_data( tbl, "repr", repr );
 
3215
            g_object_set_data( tbl, "item", item );
 
3216
            Inkscape::GC::anchor(repr);
 
3217
            sp_repr_add_listener(repr, &rect_tb_repr_events, tbl);
 
3218
            sp_repr_synthesize_events(repr, &rect_tb_repr_events, tbl);
 
3219
        }
 
3220
    } else {
 
3221
        // FIXME: implement averaging of all parameters for multiple selected
 
3222
        //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
 
3223
        g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
 
3224
        sp_rtb_sensitivize( tbl );
 
3225
    }
 
3226
}
 
3227
 
 
3228
 
 
3229
static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
 
3230
{
 
3231
    EgeAdjustmentAction* eact = 0;
 
3232
    Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1);
 
3233
 
 
3234
    {
 
3235
        EgeOutputAction* act = ege_output_action_new( "RectStateAction", _("<b>New:</b>"), "", 0 );
 
3236
        ege_output_action_set_use_markup( act, TRUE );
 
3237
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
3238
        g_object_set_data( holder, "mode_action", act );
 
3239
    }
 
3240
 
 
3241
    // rx/ry units menu: create
 
3242
    UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
 
3243
    //tracker->addUnit( SP_UNIT_PERCENT, 0 );
 
3244
    // fixme: add % meaning per cent of the width/height
 
3245
    tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
 
3246
    g_object_set_data( holder, "tracker", tracker );
 
3247
 
 
3248
    /* W */
 
3249
    {
 
3250
        gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 
3251
        gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
 
3252
        eact = create_adjustment_action( "RectWidthAction",
 
3253
                                         _("Width"), _("W:"), _("Width of rectangle"),
 
3254
                                         "/tools/shapes/rect/width", 0,
 
3255
                                         GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-rect",
 
3256
                                         0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
 
3257
                                         labels, values, G_N_ELEMENTS(labels),
 
3258
                                         sp_rtb_width_value_changed );
 
3259
        tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
 
3260
        g_object_set_data( holder, "width_action", eact );
 
3261
        gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
 
3262
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
3263
    }
 
3264
 
 
3265
    /* H */
 
3266
    {
 
3267
        gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 
3268
        gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
 
3269
        eact = create_adjustment_action( "RectHeightAction",
 
3270
                                         _("Height"), _("H:"), _("Height of rectangle"),
 
3271
                                         "/tools/shapes/rect/height", 0,
 
3272
                                         GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
 
3273
                                         0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
 
3274
                                         labels, values, G_N_ELEMENTS(labels),
 
3275
                                         sp_rtb_height_value_changed );
 
3276
        tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
 
3277
        g_object_set_data( holder, "height_action", eact );
 
3278
        gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
 
3279
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
3280
    }
 
3281
 
 
3282
    /* rx */
 
3283
    {
 
3284
        gchar const* labels[] = {_("not rounded"), 0, 0, 0, 0, 0, 0, 0, 0};
 
3285
        gdouble values[] = {0.5, 1, 2, 3, 5, 10, 20, 50, 100};
 
3286
        eact = create_adjustment_action( "RadiusXAction",
 
3287
                                         _("Horizontal radius"), _("Rx:"), _("Horizontal radius of rounded corners"),
 
3288
                                         "/tools/shapes/rect/rx", 0,
 
3289
                                         GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
 
3290
                                         0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
 
3291
                                         labels, values, G_N_ELEMENTS(labels),
 
3292
                                         sp_rtb_rx_value_changed);
 
3293
        tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
 
3294
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
3295
    }
 
3296
 
 
3297
    /* ry */
 
3298
    {
 
3299
        gchar const* labels[] = {_("not rounded"), 0, 0, 0, 0, 0, 0, 0, 0};
 
3300
        gdouble values[] = {0.5, 1, 2, 3, 5, 10, 20, 50, 100};
 
3301
        eact = create_adjustment_action( "RadiusYAction",
 
3302
                                         _("Vertical radius"), _("Ry:"), _("Vertical radius of rounded corners"),
 
3303
                                         "/tools/shapes/rect/ry", 0,
 
3304
                                         GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
 
3305
                                         0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
 
3306
                                         labels, values, G_N_ELEMENTS(labels),
 
3307
                                         sp_rtb_ry_value_changed);
 
3308
        tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
 
3309
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
3310
    }
 
3311
 
 
3312
    // add the units menu
 
3313
    {
 
3314
        GtkAction* act = tracker->createAction( "RectUnitsAction", _("Units"), ("") );
 
3315
        gtk_action_group_add_action( mainActions, act );
 
3316
    }
 
3317
 
 
3318
    /* Reset */
 
3319
    {
 
3320
        InkAction* inky = ink_action_new( "RectResetAction",
 
3321
                                          _("Not rounded"),
 
3322
                                          _("Make corners sharp"),
 
3323
                                          INKSCAPE_ICON_RECTANGLE_MAKE_CORNERS_SHARP,
 
3324
                                          secondarySize );
 
3325
        g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_rtb_defaults), holder );
 
3326
        gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
 
3327
        gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
 
3328
        g_object_set_data( holder, "not_rounded", inky );
 
3329
    }
 
3330
 
 
3331
    g_object_set_data( holder, "single", GINT_TO_POINTER(TRUE) );
 
3332
    sp_rtb_sensitivize( holder );
 
3333
 
 
3334
    sigc::connection *connection = new sigc::connection(
 
3335
        sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_rect_toolbox_selection_changed), (GObject *)holder))
 
3336
        );
 
3337
    g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
 
3338
    g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
 
3339
}
 
3340
 
 
3341
//########################
 
3342
//##       3D Box       ##
 
3343
//########################
 
3344
 
 
3345
// normalize angle so that it lies in the interval [0,360]
 
3346
static double box3d_normalize_angle (double a) {
 
3347
    double angle = a + ((int) (a/360.0))*360;
 
3348
    if (angle < 0) {
 
3349
        angle += 360.0;
 
3350
    }
 
3351
    return angle;
 
3352
}
 
3353
 
 
3354
static void box3d_set_button_and_adjustment(Persp3D *persp,
 
3355
                                            Proj::Axis axis,
 
3356
                                            GtkAdjustment *adj,
 
3357
                                            GtkAction *act,
 
3358
                                            GtkToggleAction *tact)
 
3359
{
 
3360
    // TODO: Take all selected perspectives into account but don't touch the state button if not all of them
 
3361
    //       have the same state (otherwise a call to box3d_vp_z_state_changed() is triggered and the states
 
3362
    //       are reset).
 
3363
    bool is_infinite = !persp3d_VP_is_finite(persp->perspective_impl, axis);
 
3364
 
 
3365
    if (is_infinite) {
 
3366
        gtk_toggle_action_set_active(tact, TRUE);
 
3367
        gtk_action_set_sensitive(act, TRUE);
 
3368
 
 
3369
        double angle = persp3d_get_infinite_angle(persp, axis);
 
3370
        if (angle != NR_HUGE) { // FIXME: We should catch this error earlier (don't show the spinbutton at all)
 
3371
            gtk_adjustment_set_value(adj, box3d_normalize_angle(angle));
 
3372
        }
 
3373
    } else {
 
3374
        gtk_toggle_action_set_active(tact, FALSE);
 
3375
        gtk_action_set_sensitive(act, FALSE);
 
3376
    }
 
3377
}
 
3378
 
 
3379
static void box3d_resync_toolbar(Inkscape::XML::Node *persp_repr, GObject *data)
 
3380
{
 
3381
    if (!persp_repr) {
 
3382
        g_print ("No perspective given to box3d_resync_toolbar().\n");
 
3383
        return;
 
3384
    }
 
3385
 
 
3386
    GtkWidget *tbl = GTK_WIDGET(data);
 
3387
    GtkAdjustment *adj = 0;
 
3388
    GtkAction *act = 0;
 
3389
    GtkToggleAction *tact = 0;
 
3390
    Persp3D *persp = persp3d_get_from_repr(persp_repr);
 
3391
    if (!persp) {
 
3392
        // Hmm, is it an error if this happens?
 
3393
        return;
 
3394
    }
 
3395
    {
 
3396
        adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "box3d_angle_x"));
 
3397
        act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_x_action"));
 
3398
        tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_x_state_action"))->action;
 
3399
 
 
3400
        box3d_set_button_and_adjustment(persp, Proj::X, adj, act, tact);
 
3401
    }
 
3402
    {
 
3403
        adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "box3d_angle_y"));
 
3404
        act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_y_action"));
 
3405
        tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_y_state_action"))->action;
 
3406
 
 
3407
        box3d_set_button_and_adjustment(persp, Proj::Y, adj, act, tact);
 
3408
    }
 
3409
    {
 
3410
        adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "box3d_angle_z"));
 
3411
        act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_z_action"));
 
3412
        tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_z_state_action"))->action;
 
3413
 
 
3414
        box3d_set_button_and_adjustment(persp, Proj::Z, adj, act, tact);
 
3415
    }
 
3416
}
 
3417
 
 
3418
static void box3d_persp_tb_event_attr_changed(Inkscape::XML::Node *repr,
 
3419
                                              gchar const * /*name*/,
 
3420
                                              gchar const * /*old_value*/,
 
3421
                                              gchar const * /*new_value*/,
 
3422
                                              bool /*is_interactive*/,
 
3423
                                              gpointer data)
 
3424
{
 
3425
    GtkWidget *tbl = GTK_WIDGET(data);
 
3426
 
 
3427
    // quit if run by the attr_changed or selection changed listener
 
3428
    if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
 
3429
        return;
 
3430
    }
 
3431
 
 
3432
    // set freeze so that it can be caught in box3d_angle_z_value_changed() (to avoid calling
 
3433
    // sp_document_maybe_done() when the document is undo insensitive)
 
3434
    g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
 
3435
 
 
3436
    // TODO: Only update the appropriate part of the toolbar
 
3437
//    if (!strcmp(name, "inkscape:vp_z")) {
 
3438
        box3d_resync_toolbar(repr, G_OBJECT(tbl));
 
3439
//    }
 
3440
 
 
3441
    Persp3D *persp = persp3d_get_from_repr(repr);
 
3442
    persp3d_update_box_reprs(persp);
 
3443
 
 
3444
    g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
 
3445
}
 
3446
 
 
3447
static Inkscape::XML::NodeEventVector box3d_persp_tb_repr_events =
 
3448
{
 
3449
    NULL, /* child_added */
 
3450
    NULL, /* child_removed */
 
3451
    box3d_persp_tb_event_attr_changed,
 
3452
    NULL, /* content_changed */
 
3453
    NULL  /* order_changed */
 
3454
};
 
3455
 
 
3456
/**
 
3457
 *  \param selection Should not be NULL.
 
3458
 */
 
3459
// FIXME: This should rather be put into persp3d-reference.cpp or something similar so that it reacts upon each
 
3460
//        Change of the perspective, and not of the current selection (but how to refer to the toolbar then?)
 
3461
static void box3d_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
 
3462
{
 
3463
    // Here the following should be done: If all selected boxes have finite VPs in a certain direction,
 
3464
    // disable the angle entry fields for this direction (otherwise entering a value in them should only
 
3465
    // update the perspectives with infinite VPs and leave the other ones untouched).
 
3466
 
 
3467
    Inkscape::XML::Node *persp_repr = NULL;
 
3468
    purge_repr_listener(tbl, tbl);
 
3469
 
 
3470
    SPItem *item = selection->singleItem();
 
3471
    if (item && SP_IS_BOX3D(item)) {
 
3472
        // FIXME: Also deal with multiple selected boxes
 
3473
        SPBox3D *box = SP_BOX3D(item);
 
3474
        Persp3D *persp = box3d_get_perspective(box);
 
3475
        persp_repr = SP_OBJECT_REPR(persp);
 
3476
        if (persp_repr) {
 
3477
            g_object_set_data(tbl, "repr", persp_repr);
 
3478
            Inkscape::GC::anchor(persp_repr);
 
3479
            sp_repr_add_listener(persp_repr, &box3d_persp_tb_repr_events, tbl);
 
3480
            sp_repr_synthesize_events(persp_repr, &box3d_persp_tb_repr_events, tbl);
 
3481
        }
 
3482
 
 
3483
        inkscape_active_document()->setCurrentPersp3D(persp3d_get_from_repr(persp_repr));
 
3484
        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
3485
        prefs->setString("/tools/shapes/3dbox/persp", persp_repr->attribute("id"));
 
3486
 
 
3487
        g_object_set_data(tbl, "freeze", GINT_TO_POINTER(TRUE));
 
3488
        box3d_resync_toolbar(persp_repr, tbl);
 
3489
        g_object_set_data(tbl, "freeze", GINT_TO_POINTER(FALSE));
 
3490
    }
 
3491
}
 
3492
 
 
3493
static void box3d_angle_value_changed(GtkAdjustment *adj, GObject *dataKludge, Proj::Axis axis)
 
3494
{
 
3495
    SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
 
3496
    SPDocument *document = sp_desktop_document(desktop);
 
3497
 
 
3498
    // quit if run by the attr_changed or selection changed listener
 
3499
    if (g_object_get_data( dataKludge, "freeze" )) {
 
3500
        return;
 
3501
    }
 
3502
 
 
3503
    // in turn, prevent listener from responding
 
3504
    g_object_set_data(dataKludge, "freeze", GINT_TO_POINTER(TRUE));
 
3505
 
 
3506
    std::list<Persp3D *> sel_persps = sp_desktop_selection(desktop)->perspList();
 
3507
    if (sel_persps.empty()) {
 
3508
        // this can happen when the document is created; we silently ignore it
 
3509
        return;
 
3510
    }
 
3511
    Persp3D *persp = sel_persps.front();
 
3512
 
 
3513
    persp->perspective_impl->tmat.set_infinite_direction (axis, adj->value);
 
3514
    SP_OBJECT(persp)->updateRepr();
 
3515
 
 
3516
    // TODO: use the correct axis here, too
 
3517
    sp_document_maybe_done(document, "perspangle", SP_VERB_CONTEXT_3DBOX, _("3D Box: Change perspective (angle of infinite axis)"));
 
3518
 
 
3519
    g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
 
3520
}
 
3521
 
 
3522
 
 
3523
static void box3d_angle_x_value_changed(GtkAdjustment *adj, GObject *dataKludge)
 
3524
{
 
3525
    box3d_angle_value_changed(adj, dataKludge, Proj::X);
 
3526
}
 
3527
 
 
3528
static void box3d_angle_y_value_changed(GtkAdjustment *adj, GObject *dataKludge)
 
3529
{
 
3530
    box3d_angle_value_changed(adj, dataKludge, Proj::Y);
 
3531
}
 
3532
 
 
3533
static void box3d_angle_z_value_changed(GtkAdjustment *adj, GObject *dataKludge)
 
3534
{
 
3535
    box3d_angle_value_changed(adj, dataKludge, Proj::Z);
 
3536
}
 
3537
 
 
3538
 
 
3539
static void box3d_vp_state_changed( GtkToggleAction *act, GtkAction * /*box3d_angle*/, Proj::Axis axis )
 
3540
{
 
3541
    // TODO: Take all selected perspectives into account
 
3542
    std::list<Persp3D *> sel_persps = sp_desktop_selection(inkscape_active_desktop())->perspList();
 
3543
    if (sel_persps.empty()) {
 
3544
        // this can happen when the document is created; we silently ignore it
 
3545
        return;
 
3546
    }
 
3547
    Persp3D *persp = sel_persps.front();
 
3548
 
 
3549
    bool set_infinite = gtk_toggle_action_get_active(act);
 
3550
    persp3d_set_VP_state (persp, axis, set_infinite ? Proj::VP_INFINITE : Proj::VP_FINITE);
 
3551
}
 
3552
 
 
3553
static void box3d_vp_x_state_changed( GtkToggleAction *act, GtkAction *box3d_angle )
 
3554
{
 
3555
    box3d_vp_state_changed(act, box3d_angle, Proj::X);
 
3556
}
 
3557
 
 
3558
static void box3d_vp_y_state_changed( GtkToggleAction *act, GtkAction *box3d_angle )
 
3559
{
 
3560
    box3d_vp_state_changed(act, box3d_angle, Proj::Y);
 
3561
}
 
3562
 
 
3563
static void box3d_vp_z_state_changed( GtkToggleAction *act, GtkAction *box3d_angle )
 
3564
{
 
3565
    box3d_vp_state_changed(act, box3d_angle, Proj::Z);
 
3566
}
 
3567
 
 
3568
static void box3d_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
 
3569
{
 
3570
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
3571
    EgeAdjustmentAction* eact = 0;
 
3572
    SPDocument *document = sp_desktop_document (desktop);
 
3573
    Persp3DImpl *persp_impl = document->getCurrentPersp3DImpl();
 
3574
 
 
3575
    EgeAdjustmentAction* box3d_angle_x = 0;
 
3576
    EgeAdjustmentAction* box3d_angle_y = 0;
 
3577
    EgeAdjustmentAction* box3d_angle_z = 0;
 
3578
 
 
3579
    /* Angle X */
 
3580
    {
 
3581
        gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0 };
 
3582
        gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
 
3583
        eact = create_adjustment_action( "3DBoxAngleXAction",
 
3584
                                         _("Angle in X direction"), _("Angle X:"),
 
3585
                                         // Translators: PL is short for 'perspective line'
 
3586
                                         _("Angle of PLs in X direction"),
 
3587
                                         "/tools/shapes/3dbox/box3d_angle_x", 30,
 
3588
                                         GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-box3d",
 
3589
                                         -360.0, 360.0, 1.0, 10.0,
 
3590
                                         labels, values, G_N_ELEMENTS(labels),
 
3591
                                         box3d_angle_x_value_changed );
 
3592
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
3593
        g_object_set_data( holder, "box3d_angle_x_action", eact );
 
3594
        box3d_angle_x = eact;
 
3595
    }
 
3596
 
 
3597
    if (!persp_impl || !persp3d_VP_is_finite(persp_impl, Proj::X)) {
 
3598
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
3599
    } else {
 
3600
        gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
 
3601
    }
 
3602
 
 
3603
 
 
3604
    /* VP X state */
 
3605
    {
 
3606
        InkToggleAction* act = ink_toggle_action_new( "3DBoxVPXStateAction",
 
3607
                                                      // Translators: VP is short for 'vanishing point'
 
3608
                                                      _("State of VP in X direction"),
 
3609
                                                      _("Toggle VP in X direction between 'finite' and 'infinite' (=parallel)"),
 
3610
                                                      INKSCAPE_ICON_PERSPECTIVE_PARALLEL,
 
3611
                                                      Inkscape::ICON_SIZE_DECORATION );
 
3612
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
3613
        g_object_set_data( holder, "box3d_vp_x_state_action", act );
 
3614
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_x_state_changed), box3d_angle_x );
 
3615
        gtk_action_set_sensitive( GTK_ACTION(box3d_angle_x), !prefs->getBool("/tools/shapes/3dbox/vp_x_state", true) );
 
3616
        gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/shapes/3dbox/vp_x_state", true) );
 
3617
    }
 
3618
 
 
3619
    /* Angle Y */
 
3620
    {
 
3621
        gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0 };
 
3622
        gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
 
3623
        eact = create_adjustment_action( "3DBoxAngleYAction",
 
3624
                                         _("Angle in Y direction"), _("Angle Y:"),
 
3625
                                         // Translators: PL is short for 'perspective line'
 
3626
                                         _("Angle of PLs in Y direction"),
 
3627
                                         "/tools/shapes/3dbox/box3d_angle_y", 30,
 
3628
                                         GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
 
3629
                                         -360.0, 360.0, 1.0, 10.0,
 
3630
                                         labels, values, G_N_ELEMENTS(labels),
 
3631
                                         box3d_angle_y_value_changed );
 
3632
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
3633
        g_object_set_data( holder, "box3d_angle_y_action", eact );
 
3634
        box3d_angle_y = eact;
 
3635
    }
 
3636
 
 
3637
    if (!persp_impl || !persp3d_VP_is_finite(persp_impl, Proj::Y)) {
 
3638
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
3639
    } else {
 
3640
        gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
 
3641
    }
 
3642
 
 
3643
    /* VP Y state */
 
3644
    {
 
3645
        InkToggleAction* act = ink_toggle_action_new( "3DBoxVPYStateAction",
 
3646
                                                      // Translators: VP is short for 'vanishing point'
 
3647
                                                      _("State of VP in Y direction"),
 
3648
                                                      _("Toggle VP in Y direction between 'finite' and 'infinite' (=parallel)"),
 
3649
                                                      INKSCAPE_ICON_PERSPECTIVE_PARALLEL,
 
3650
                                                      Inkscape::ICON_SIZE_DECORATION );
 
3651
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
3652
        g_object_set_data( holder, "box3d_vp_y_state_action", act );
 
3653
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_y_state_changed), box3d_angle_y );
 
3654
        gtk_action_set_sensitive( GTK_ACTION(box3d_angle_y), !prefs->getBool("/tools/shapes/3dbox/vp_y_state", true) );
 
3655
        gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/shapes/3dbox/vp_y_state", true) );
 
3656
    }
 
3657
 
 
3658
    /* Angle Z */
 
3659
    {
 
3660
        gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0 };
 
3661
        gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
 
3662
        eact = create_adjustment_action( "3DBoxAngleZAction",
 
3663
                                         _("Angle in Z direction"), _("Angle Z:"),
 
3664
                                         // Translators: PL is short for 'perspective line'
 
3665
                                         _("Angle of PLs in Z direction"),
 
3666
                                         "/tools/shapes/3dbox/box3d_angle_z", 30,
 
3667
                                         GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
 
3668
                                         -360.0, 360.0, 1.0, 10.0,
 
3669
                                         labels, values, G_N_ELEMENTS(labels),
 
3670
                                         box3d_angle_z_value_changed );
 
3671
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
3672
        g_object_set_data( holder, "box3d_angle_z_action", eact );
 
3673
        box3d_angle_z = eact;
 
3674
    }
 
3675
 
 
3676
    if (!persp_impl || !persp3d_VP_is_finite(persp_impl, Proj::Z)) {
 
3677
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
3678
    } else {
 
3679
        gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
 
3680
    }
 
3681
 
 
3682
    /* VP Z state */
 
3683
    {
 
3684
        InkToggleAction* act = ink_toggle_action_new( "3DBoxVPZStateAction",
 
3685
                                                      // Translators: VP is short for 'vanishing point'
 
3686
                                                      _("State of VP in Z direction"),
 
3687
                                                      _("Toggle VP in Z direction between 'finite' and 'infinite' (=parallel)"),
 
3688
                                                      INKSCAPE_ICON_PERSPECTIVE_PARALLEL,
 
3689
                                                      Inkscape::ICON_SIZE_DECORATION );
 
3690
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
3691
        g_object_set_data( holder, "box3d_vp_z_state_action", act );
 
3692
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_z_state_changed), box3d_angle_z );
 
3693
        gtk_action_set_sensitive( GTK_ACTION(box3d_angle_z), !prefs->getBool("/tools/shapes/3dbox/vp_z_state", true) );
 
3694
        gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/shapes/3dbox/vp_z_state", true) );
 
3695
    }
 
3696
 
 
3697
    sigc::connection *connection = new sigc::connection(
 
3698
        sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(box3d_toolbox_selection_changed), (GObject *)holder))
 
3699
       );
 
3700
    g_signal_connect(holder, "destroy", G_CALLBACK(delete_connection), connection);
 
3701
    g_signal_connect(holder, "destroy", G_CALLBACK(purge_repr_listener), holder);
 
3702
}
 
3703
 
 
3704
//########################
 
3705
//##       Spiral       ##
 
3706
//########################
 
3707
 
 
3708
static void sp_spl_tb_value_changed(GtkAdjustment *adj, GObject *tbl, Glib::ustring const &value_name)
 
3709
{
 
3710
    SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
 
3711
 
 
3712
    if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
 
3713
        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
3714
        prefs->setDouble("/tools/shapes/spiral/" + value_name, adj->value);
 
3715
    }
 
3716
 
 
3717
    // quit if run by the attr_changed listener
 
3718
    if (g_object_get_data( tbl, "freeze" )) {
 
3719
        return;
 
3720
    }
 
3721
 
 
3722
    // in turn, prevent listener from responding
 
3723
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
 
3724
 
 
3725
    gchar* namespaced_name = g_strconcat("sodipodi:", value_name.data(), NULL);
 
3726
 
 
3727
    bool modmade = false;
 
3728
    for (GSList const *items = sp_desktop_selection(desktop)->itemList();
 
3729
         items != NULL;
 
3730
         items = items->next)
 
3731
    {
 
3732
        if (SP_IS_SPIRAL((SPItem *) items->data)) {
 
3733
            Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
 
3734
            sp_repr_set_svg_double( repr, namespaced_name, adj->value );
 
3735
            SP_OBJECT((SPItem *) items->data)->updateRepr();
 
3736
            modmade = true;
 
3737
        }
 
3738
    }
 
3739
 
 
3740
    g_free(namespaced_name);
 
3741
 
 
3742
    if (modmade) {
 
3743
        sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_SPIRAL,
 
3744
                                   _("Change spiral"));
 
3745
    }
 
3746
 
 
3747
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 
3748
}
 
3749
 
 
3750
static void sp_spl_tb_revolution_value_changed(GtkAdjustment *adj, GObject *tbl)
 
3751
{
 
3752
    sp_spl_tb_value_changed(adj, tbl, "revolution");
 
3753
}
 
3754
 
 
3755
static void sp_spl_tb_expansion_value_changed(GtkAdjustment *adj, GObject *tbl)
 
3756
{
 
3757
    sp_spl_tb_value_changed(adj, tbl, "expansion");
 
3758
}
 
3759
 
 
3760
static void sp_spl_tb_t0_value_changed(GtkAdjustment *adj, GObject *tbl)
 
3761
{
 
3762
    sp_spl_tb_value_changed(adj, tbl, "t0");
 
3763
}
 
3764
 
 
3765
static void sp_spl_tb_defaults(GtkWidget * /*widget*/, GtkObject *obj)
 
3766
{
 
3767
    GtkWidget *tbl = GTK_WIDGET(obj);
 
3768
 
 
3769
    GtkAdjustment *adj;
 
3770
 
 
3771
    // fixme: make settable
 
3772
    gdouble rev = 5;
 
3773
    gdouble exp = 1.0;
 
3774
    gdouble t0 = 0.0;
 
3775
 
 
3776
    adj = (GtkAdjustment*)gtk_object_get_data(obj, "revolution");
 
3777
    gtk_adjustment_set_value(adj, rev);
 
3778
    gtk_adjustment_value_changed(adj);
 
3779
 
 
3780
    adj = (GtkAdjustment*)gtk_object_get_data(obj, "expansion");
 
3781
    gtk_adjustment_set_value(adj, exp);
 
3782
    gtk_adjustment_value_changed(adj);
 
3783
 
 
3784
    adj = (GtkAdjustment*)gtk_object_get_data(obj, "t0");
 
3785
    gtk_adjustment_set_value(adj, t0);
 
3786
    gtk_adjustment_value_changed(adj);
 
3787
 
 
3788
    spinbutton_defocus(GTK_OBJECT(tbl));
 
3789
}
 
3790
 
 
3791
 
 
3792
static void spiral_tb_event_attr_changed(Inkscape::XML::Node *repr,
 
3793
                                         gchar const * /*name*/,
 
3794
                                         gchar const * /*old_value*/,
 
3795
                                         gchar const * /*new_value*/,
 
3796
                                         bool /*is_interactive*/,
 
3797
                                         gpointer data)
 
3798
{
 
3799
    GtkWidget *tbl = GTK_WIDGET(data);
 
3800
 
 
3801
    // quit if run by the _changed callbacks
 
3802
    if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
 
3803
        return;
 
3804
    }
 
3805
 
 
3806
    // in turn, prevent callbacks from responding
 
3807
    g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
 
3808
 
 
3809
    GtkAdjustment *adj;
 
3810
    adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "revolution");
 
3811
    gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:revolution", 3.0)));
 
3812
 
 
3813
    adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "expansion");
 
3814
    gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:expansion", 1.0)));
 
3815
 
 
3816
    adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "t0");
 
3817
    gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:t0", 0.0)));
 
3818
 
 
3819
    g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
 
3820
}
 
3821
 
 
3822
 
 
3823
static Inkscape::XML::NodeEventVector spiral_tb_repr_events = {
 
3824
    NULL, /* child_added */
 
3825
    NULL, /* child_removed */
 
3826
    spiral_tb_event_attr_changed,
 
3827
    NULL, /* content_changed */
 
3828
    NULL  /* order_changed */
 
3829
};
 
3830
 
 
3831
static void sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
 
3832
{
 
3833
    int n_selected = 0;
 
3834
    Inkscape::XML::Node *repr = NULL;
 
3835
 
 
3836
    purge_repr_listener( tbl, tbl );
 
3837
 
 
3838
    for (GSList const *items = selection->itemList();
 
3839
         items != NULL;
 
3840
         items = items->next)
 
3841
    {
 
3842
        if (SP_IS_SPIRAL((SPItem *) items->data)) {
 
3843
            n_selected++;
 
3844
            repr = SP_OBJECT_REPR((SPItem *) items->data);
 
3845
        }
 
3846
    }
 
3847
 
 
3848
    EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
 
3849
 
 
3850
    if (n_selected == 0) {
 
3851
        g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
 
3852
    } else if (n_selected == 1) {
 
3853
        g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
 
3854
 
 
3855
        if (repr) {
 
3856
            g_object_set_data( tbl, "repr", repr );
 
3857
            Inkscape::GC::anchor(repr);
 
3858
            sp_repr_add_listener(repr, &spiral_tb_repr_events, tbl);
 
3859
            sp_repr_synthesize_events(repr, &spiral_tb_repr_events, tbl);
 
3860
        }
 
3861
    } else {
 
3862
        // FIXME: implement averaging of all parameters for multiple selected
 
3863
        //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
 
3864
        g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
 
3865
    }
 
3866
}
 
3867
 
 
3868
 
 
3869
static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
 
3870
{
 
3871
    EgeAdjustmentAction* eact = 0;
 
3872
    Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1);
 
3873
 
 
3874
    {
 
3875
        EgeOutputAction* act = ege_output_action_new( "SpiralStateAction", _("<b>New:</b>"), "", 0 );
 
3876
        ege_output_action_set_use_markup( act, TRUE );
 
3877
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
3878
        g_object_set_data( holder, "mode_action", act );
 
3879
    }
 
3880
 
 
3881
    /* Revolution */
 
3882
    {
 
3883
        gchar const* labels[] = {_("just a curve"), 0, _("one full revolution"), 0, 0, 0, 0, 0, 0};
 
3884
        gdouble values[] = {0.01, 0.5, 1, 2, 3, 5, 10, 20, 50, 100};
 
3885
        eact = create_adjustment_action( "SpiralRevolutionAction",
 
3886
                                         _("Number of turns"), _("Turns:"), _("Number of revolutions"),
 
3887
                                         "/tools/shapes/spiral/revolution", 3.0,
 
3888
                                         GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-spiral",
 
3889
                                         0.01, 1024.0, 0.1, 1.0,
 
3890
                                         labels, values, G_N_ELEMENTS(labels),
 
3891
                                         sp_spl_tb_revolution_value_changed, 1, 2);
 
3892
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
3893
    }
 
3894
 
 
3895
    /* Expansion */
 
3896
    {
 
3897
        gchar const* labels[] = {_("circle"), _("edge is much denser"), _("edge is denser"), _("even"), _("center is denser"), _("center is much denser"), 0};
 
3898
        gdouble values[] = {0, 0.1, 0.5, 1, 1.5, 5, 20};
 
3899
        eact = create_adjustment_action( "SpiralExpansionAction",
 
3900
                                         _("Divergence"), _("Divergence:"), _("How much denser/sparser are outer revolutions; 1 = uniform"),
 
3901
                                         "/tools/shapes/spiral/expansion", 1.0,
 
3902
                                         GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
 
3903
                                         0.0, 1000.0, 0.01, 1.0,
 
3904
                                         labels, values, G_N_ELEMENTS(labels),
 
3905
                                         sp_spl_tb_expansion_value_changed);
 
3906
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
3907
    }
 
3908
 
 
3909
    /* T0 */
 
3910
    {
 
3911
        gchar const* labels[] = {_("starts from center"), _("starts mid-way"), _("starts near edge")};
 
3912
        gdouble values[] = {0, 0.5, 0.9};
 
3913
        eact = create_adjustment_action( "SpiralT0Action",
 
3914
                                         _("Inner radius"), _("Inner radius:"), _("Radius of the innermost revolution (relative to the spiral size)"),
 
3915
                                         "/tools/shapes/spiral/t0", 0.0,
 
3916
                                         GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
 
3917
                                         0.0, 0.999, 0.01, 1.0,
 
3918
                                         labels, values, G_N_ELEMENTS(labels),
 
3919
                                         sp_spl_tb_t0_value_changed);
 
3920
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
3921
    }
 
3922
 
 
3923
    /* Reset */
 
3924
    {
 
3925
        InkAction* inky = ink_action_new( "SpiralResetAction",
 
3926
                                          _("Defaults"),
 
3927
                                          _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
 
3928
                                          GTK_STOCK_CLEAR,
 
3929
                                          secondarySize );
 
3930
        g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_spl_tb_defaults), holder );
 
3931
        gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
 
3932
    }
 
3933
 
 
3934
 
 
3935
    sigc::connection *connection = new sigc::connection(
 
3936
        sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_spiral_toolbox_selection_changed), (GObject *)holder))
 
3937
        );
 
3938
    g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
 
3939
    g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
 
3940
}
 
3941
 
 
3942
//########################
 
3943
//##     Pen/Pencil     ##
 
3944
//########################
 
3945
 
 
3946
/* This is used in generic functions below to share large portions of code between pen and pencil tool */
 
3947
static Glib::ustring const freehand_tool_name(GObject *dataKludge)
 
3948
{
 
3949
    SPDesktop *desktop = (SPDesktop *) g_object_get_data(dataKludge, "desktop");
 
3950
    return ( tools_isactive(desktop, TOOLS_FREEHAND_PEN)
 
3951
             ? "/tools/freehand/pen"
 
3952
             : "/tools/freehand/pencil" );
 
3953
}
 
3954
 
 
3955
static void freehand_mode_changed(EgeSelectOneAction* act, GObject* tbl)
 
3956
{
 
3957
    gint mode = ege_select_one_action_get_active(act);
 
3958
 
 
3959
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
3960
    prefs->setInt(freehand_tool_name(tbl) + "/freehand-mode", mode);
 
3961
 
 
3962
    SPDesktop *desktop = (SPDesktop *) g_object_get_data(tbl, "desktop");
 
3963
 
 
3964
    // in pen tool we have more options than in pencil tool; if one of them was chosen, we do any
 
3965
    // preparatory work here
 
3966
    if (SP_IS_PEN_CONTEXT(desktop->event_context)) {
 
3967
        SPPenContext *pc = SP_PEN_CONTEXT(desktop->event_context);
 
3968
        sp_pen_context_set_polyline_mode(pc);
 
3969
    }
 
3970
}
 
3971
 
 
3972
static void sp_add_freehand_mode_toggle(GtkActionGroup* mainActions, GObject* holder, bool tool_is_pencil)
 
3973
{
 
3974
    /* Freehand mode toggle buttons */
 
3975
    {
 
3976
        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
3977
        guint freehandMode = prefs->getInt(( tool_is_pencil ? "/tools/freehand/pencil/freehand-mode" : "/tools/freehand/pen/freehand-mode" ), 0);
 
3978
        Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1);
 
3979
 
 
3980
        {
 
3981
            GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
 
3982
 
 
3983
            GtkTreeIter iter;
 
3984
            gtk_list_store_append( model, &iter );
 
3985
            gtk_list_store_set( model, &iter,
 
3986
                                0, _("Bezier"),
 
3987
                                1, _("Create regular Bezier path"),
 
3988
                                2, INKSCAPE_ICON_PATH_MODE_BEZIER,
 
3989
                                -1 );
 
3990
 
 
3991
            gtk_list_store_append( model, &iter );
 
3992
            gtk_list_store_set( model, &iter,
 
3993
                                0, _("Spiro"),
 
3994
                                1, _("Create Spiro path"),
 
3995
                                2, INKSCAPE_ICON_PATH_MODE_SPIRO,
 
3996
                                -1 );
 
3997
 
 
3998
            if (!tool_is_pencil) {
 
3999
                gtk_list_store_append( model, &iter );
 
4000
                gtk_list_store_set( model, &iter,
 
4001
                                    0, _("Zigzag"),
 
4002
                                    1, _("Create a sequence of straight line segments"),
 
4003
                                    2, INKSCAPE_ICON_PATH_MODE_POLYLINE,
 
4004
                                    -1 );
 
4005
 
 
4006
                gtk_list_store_append( model, &iter );
 
4007
                gtk_list_store_set( model, &iter,
 
4008
                                    0, _("Paraxial"),
 
4009
                                    1, _("Create a sequence of paraxial line segments"),
 
4010
                                    2, INKSCAPE_ICON_PATH_MODE_POLYLINE_PARAXIAL,
 
4011
                                    -1 );
 
4012
            }
 
4013
 
 
4014
            EgeSelectOneAction* act = ege_select_one_action_new(tool_is_pencil ?
 
4015
                                                                "FreehandModeActionPencil" :
 
4016
                                                                "FreehandModeActionPen",
 
4017
                                                                (_("Mode:")), (_("Mode of new lines drawn by this tool")), NULL, GTK_TREE_MODEL(model) );
 
4018
            gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
 
4019
 
 
4020
            ege_select_one_action_set_appearance( act, "full" );
 
4021
            ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
 
4022
            g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
 
4023
            ege_select_one_action_set_icon_column( act, 2 );
 
4024
            ege_select_one_action_set_icon_size( act, secondarySize );
 
4025
            ege_select_one_action_set_tooltip_column( act, 1  );
 
4026
 
 
4027
            ege_select_one_action_set_active( act, freehandMode);
 
4028
            g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(freehand_mode_changed), holder);
 
4029
        }
 
4030
    }
 
4031
}
 
4032
 
 
4033
static void freehand_change_shape(EgeSelectOneAction* act, GObject *dataKludge) {
 
4034
    gint shape = ege_select_one_action_get_active( act );
 
4035
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4036
    prefs->setInt(freehand_tool_name(dataKludge) + "/shape", shape);
 
4037
}
 
4038
 
 
4039
/**
 
4040
 * \brief Generate the list of freehand advanced shape option entries.
 
4041
 */
 
4042
static GList * freehand_shape_dropdown_items_list() {
 
4043
    GList *glist = NULL;
 
4044
 
 
4045
    glist = g_list_append (glist, _("None"));
 
4046
    glist = g_list_append (glist, _("Triangle in"));
 
4047
    glist = g_list_append (glist, _("Triangle out"));
 
4048
    glist = g_list_append (glist, _("Ellipse"));
 
4049
    glist = g_list_append (glist, _("From clipboard"));
 
4050
 
 
4051
    return glist;
 
4052
}
 
4053
 
 
4054
static void freehand_add_advanced_shape_options(GtkActionGroup* mainActions, GObject* holder, bool tool_is_pencil)
 
4055
{
 
4056
    /*advanced shape options */
 
4057
    {
 
4058
        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4059
        GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
 
4060
 
 
4061
        GList* items = 0;
 
4062
        gint count = 0;
 
4063
        for ( items = freehand_shape_dropdown_items_list(); items ; items = g_list_next(items) )
 
4064
        {
 
4065
            GtkTreeIter iter;
 
4066
            gtk_list_store_append( model, &iter );
 
4067
            gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
 
4068
            count++;
 
4069
        }
 
4070
        g_list_free( items );
 
4071
        items = 0;
 
4072
        EgeSelectOneAction* act1 = ege_select_one_action_new(
 
4073
            tool_is_pencil ? "SetPencilShapeAction" : "SetPenShapeAction",
 
4074
            _("Shape:"), (_("Shape of new paths drawn by this tool")), NULL, GTK_TREE_MODEL(model));
 
4075
        g_object_set( act1, "short_label", _("Shape:"), NULL );
 
4076
        ege_select_one_action_set_appearance( act1, "compact" );
 
4077
        ege_select_one_action_set_active( act1, prefs->getInt(( tool_is_pencil ? "/tools/freehand/pencil/shape" : "/tools/freehand/pen/shape" ), 0) );
 
4078
        g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(freehand_change_shape), holder );
 
4079
        gtk_action_group_add_action( mainActions, GTK_ACTION(act1) );
 
4080
        g_object_set_data( holder, "shape_action", act1 );
 
4081
    }
 
4082
}
 
4083
 
 
4084
static void sp_pen_toolbox_prep(SPDesktop * /*desktop*/, GtkActionGroup* mainActions, GObject* holder)
 
4085
{
 
4086
    sp_add_freehand_mode_toggle(mainActions, holder, false);
 
4087
    freehand_add_advanced_shape_options(mainActions, holder, false);
 
4088
}
 
4089
 
 
4090
 
 
4091
static void sp_pencil_tb_defaults(GtkWidget * /*widget*/, GtkObject *obj)
 
4092
{
 
4093
    GtkWidget *tbl = GTK_WIDGET(obj);
 
4094
 
 
4095
    GtkAdjustment *adj;
 
4096
 
 
4097
    // fixme: make settable
 
4098
    gdouble tolerance = 4;
 
4099
 
 
4100
    adj = (GtkAdjustment*)gtk_object_get_data(obj, "tolerance");
 
4101
    gtk_adjustment_set_value(adj, tolerance);
 
4102
    gtk_adjustment_value_changed(adj);
 
4103
 
 
4104
    spinbutton_defocus(GTK_OBJECT(tbl));
 
4105
}
 
4106
 
 
4107
static void sp_pencil_tb_tolerance_value_changed(GtkAdjustment *adj, GObject *tbl)
 
4108
{
 
4109
    // quit if run by the attr_changed listener
 
4110
    if (g_object_get_data( tbl, "freeze" )) {
 
4111
        return;
 
4112
    }
 
4113
    // in turn, prevent listener from responding
 
4114
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4115
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
 
4116
    prefs->setDouble("/tools/freehand/pencil/tolerance", adj->value);
 
4117
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 
4118
}
 
4119
 
 
4120
/*
 
4121
class PencilToleranceObserver : public Inkscape::Preferences::Observer {
 
4122
public:
 
4123
    PencilToleranceObserver(Glib::ustring const &path, GObject *x) : Observer(path), _obj(x)
 
4124
    {
 
4125
        g_object_set_data(_obj, "prefobserver", this);
 
4126
    }
 
4127
    virtual ~PencilToleranceObserver() {
 
4128
        if (g_object_get_data(_obj, "prefobserver") == this) {
 
4129
            g_object_set_data(_obj, "prefobserver", NULL);
 
4130
        }
 
4131
    }
 
4132
    virtual void notify(Inkscape::Preferences::Entry const &val) {
 
4133
        GObject* tbl = _obj;
 
4134
        if (g_object_get_data( tbl, "freeze" )) {
 
4135
            return;
 
4136
        }
 
4137
        g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
 
4138
 
 
4139
        GtkAdjustment * adj = (GtkAdjustment*)g_object_get_data(tbl, "tolerance");
 
4140
 
 
4141
        double v = val.getDouble(adj->value);
 
4142
        gtk_adjustment_set_value(adj, v);
 
4143
        g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 
4144
    }
 
4145
private:
 
4146
    GObject *_obj;
 
4147
};
 
4148
*/
 
4149
 
 
4150
static void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
 
4151
{
 
4152
    sp_add_freehand_mode_toggle(mainActions, holder, true);
 
4153
 
 
4154
    EgeAdjustmentAction* eact = 0;
 
4155
 
 
4156
    /* Tolerance */
 
4157
    {
 
4158
        gchar const* labels[] = {_("(many nodes, rough)"), _("(default)"), 0, 0, 0, 0, _("(few nodes, smooth)")};
 
4159
        gdouble values[] = {1, 10, 20, 30, 50, 75, 100};
 
4160
        eact = create_adjustment_action( "PencilToleranceAction",
 
4161
                                         _("Smoothing:"), _("Smoothing: "),
 
4162
                 _("How much smoothing (simplifying) is applied to the line"),
 
4163
                                         "/tools/freehand/pencil/tolerance",
 
4164
                                         3.0,
 
4165
                                         GTK_WIDGET(desktop->canvas), NULL,
 
4166
                                         holder, TRUE, "altx-pencil",
 
4167
                                         1, 100.0, 0.5, 1.0,
 
4168
                                         labels, values, G_N_ELEMENTS(labels),
 
4169
                                         sp_pencil_tb_tolerance_value_changed,
 
4170
                                         1, 2);
 
4171
        ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
 
4172
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
4173
    }
 
4174
 
 
4175
    /* advanced shape options */
 
4176
    freehand_add_advanced_shape_options(mainActions, holder, true);
 
4177
 
 
4178
    /* Reset */
 
4179
    {
 
4180
        InkAction* inky = ink_action_new( "PencilResetAction",
 
4181
                                          _("Defaults"),
 
4182
                                          _("Reset pencil parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
 
4183
                                          GTK_STOCK_CLEAR,
 
4184
                                          Inkscape::ICON_SIZE_SMALL_TOOLBAR );
 
4185
        g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_pencil_tb_defaults), holder );
 
4186
        gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
 
4187
    }
 
4188
 
 
4189
    g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
 
4190
 
 
4191
}
 
4192
 
 
4193
 
 
4194
//########################
 
4195
//##       Tweak        ##
 
4196
//########################
 
4197
 
 
4198
static void sp_tweak_width_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ )
 
4199
{
 
4200
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4201
    prefs->setDouble( "/tools/tweak/width", adj->value * 0.01 );
 
4202
}
 
4203
 
 
4204
static void sp_tweak_force_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ )
 
4205
{
 
4206
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4207
    prefs->setDouble( "/tools/tweak/force", adj->value * 0.01 );
 
4208
}
 
4209
 
 
4210
static void sp_tweak_pressure_state_changed( GtkToggleAction *act, gpointer /*data*/ )
 
4211
{
 
4212
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4213
    prefs->setBool("/tools/tweak/usepressure", gtk_toggle_action_get_active(act));
 
4214
}
 
4215
 
 
4216
static void sp_tweak_mode_changed( EgeSelectOneAction *act, GObject *tbl )
 
4217
{
 
4218
    int mode = ege_select_one_action_get_active( act );
 
4219
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4220
    prefs->setInt("/tools/tweak/mode", mode);
 
4221
 
 
4222
    static gchar const* names[] = {"tweak_doh", "tweak_dos", "tweak_dol", "tweak_doo", "tweak_channels_label"};
 
4223
    bool flag = ((mode == TWEAK_MODE_COLORPAINT) || (mode == TWEAK_MODE_COLORJITTER));
 
4224
    for (size_t i = 0; i < G_N_ELEMENTS(names); ++i) {
 
4225
        GtkAction *act = GTK_ACTION(g_object_get_data( tbl, names[i] ));
 
4226
        if (act) {
 
4227
            gtk_action_set_sensitive(act, flag);
 
4228
        }
 
4229
    }
 
4230
    GtkAction *fid = GTK_ACTION(g_object_get_data( tbl, "tweak_fidelity"));
 
4231
    if (fid) {
 
4232
        gtk_action_set_sensitive(fid, !flag);
 
4233
    }
 
4234
}
 
4235
 
 
4236
static void sp_tweak_fidelity_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ )
 
4237
{
 
4238
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4239
    prefs->setDouble( "/tools/tweak/fidelity", adj->value * 0.01 );
 
4240
}
 
4241
 
 
4242
static void tweak_toggle_doh(GtkToggleAction *act, gpointer /*data*/) {
 
4243
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4244
    prefs->setBool("/tools/tweak/doh", gtk_toggle_action_get_active(act));
 
4245
}
 
4246
static void tweak_toggle_dos(GtkToggleAction *act, gpointer /*data*/) {
 
4247
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4248
    prefs->setBool("/tools/tweak/dos", gtk_toggle_action_get_active(act));
 
4249
}
 
4250
static void tweak_toggle_dol(GtkToggleAction *act, gpointer /*data*/) {
 
4251
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4252
    prefs->setBool("/tools/tweak/dol", gtk_toggle_action_get_active(act));
 
4253
}
 
4254
static void tweak_toggle_doo(GtkToggleAction *act, gpointer /*data*/) {
 
4255
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4256
    prefs->setBool("/tools/tweak/doo", gtk_toggle_action_get_active(act));
 
4257
}
 
4258
 
 
4259
static void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
 
4260
{
 
4261
    Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1);
 
4262
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4263
 
 
4264
    {
 
4265
        /* Width */
 
4266
        gchar const* labels[] = {_("(pinch tweak)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad tweak)")};
 
4267
        gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
 
4268
        EgeAdjustmentAction *eact = create_adjustment_action( "TweakWidthAction",
 
4269
                                                              _("Width"), _("Width:"), _("The width of the tweak area (relative to the visible canvas area)"),
 
4270
                                                              "/tools/tweak/width", 15,
 
4271
                                                              GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-tweak",
 
4272
                                                              1, 100, 1.0, 10.0,
 
4273
                                                              labels, values, G_N_ELEMENTS(labels),
 
4274
                                                              sp_tweak_width_value_changed,  0.01, 0, 100 );
 
4275
        ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
 
4276
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
4277
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
4278
    }
 
4279
 
 
4280
 
 
4281
    {
 
4282
        /* Force */
 
4283
        gchar const* labels[] = {_("(minimum force)"), 0, 0, _("(default)"), 0, 0, 0, _("(maximum force)")};
 
4284
        gdouble values[] = {1, 5, 10, 20, 30, 50, 70, 100};
 
4285
        EgeAdjustmentAction *eact = create_adjustment_action( "TweakForceAction",
 
4286
                                                              _("Force"), _("Force:"), _("The force of the tweak action"),
 
4287
                                                              "/tools/tweak/force", 20,
 
4288
                                                              GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "tweak-force",
 
4289
                                                              1, 100, 1.0, 10.0,
 
4290
                                                              labels, values, G_N_ELEMENTS(labels),
 
4291
                                                              sp_tweak_force_value_changed,  0.01, 0, 100 );
 
4292
        ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
 
4293
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
4294
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
4295
    }
 
4296
 
 
4297
    /* Mode */
 
4298
    {
 
4299
        GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
 
4300
 
 
4301
        GtkTreeIter iter;
 
4302
        gtk_list_store_append( model, &iter );
 
4303
        gtk_list_store_set( model, &iter,
 
4304
                            0, _("Move mode"),
 
4305
                            1, _("Move objects in any direction"),
 
4306
                            2, INKSCAPE_ICON_OBJECT_TWEAK_PUSH,
 
4307
                            -1 );
 
4308
 
 
4309
        gtk_list_store_append( model, &iter );
 
4310
        gtk_list_store_set( model, &iter,
 
4311
                            0, _("Move in/out mode"),
 
4312
                            1, _("Move objects towards cursor; with Shift from cursor"),
 
4313
                            2, INKSCAPE_ICON_OBJECT_TWEAK_ATTRACT,
 
4314
                            -1 );
 
4315
 
 
4316
        gtk_list_store_append( model, &iter );
 
4317
        gtk_list_store_set( model, &iter,
 
4318
                            0, _("Move jitter mode"),
 
4319
                            1, _("Move objects in random directions"),
 
4320
                            2, INKSCAPE_ICON_OBJECT_TWEAK_RANDOMIZE,
 
4321
                            -1 );
 
4322
 
 
4323
        gtk_list_store_append( model, &iter );
 
4324
        gtk_list_store_set( model, &iter,
 
4325
                            0, _("Scale mode"),
 
4326
                            1, _("Shrink objects, with Shift enlarge"),
 
4327
                            2, INKSCAPE_ICON_OBJECT_TWEAK_SHRINK,
 
4328
                            -1 );
 
4329
 
 
4330
        gtk_list_store_append( model, &iter );
 
4331
        gtk_list_store_set( model, &iter,
 
4332
                            0, _("Rotate mode"),
 
4333
                            1, _("Rotate objects, with Shift counterclockwise"),
 
4334
                            2, INKSCAPE_ICON_OBJECT_TWEAK_ROTATE,
 
4335
                            -1 );
 
4336
 
 
4337
        gtk_list_store_append( model, &iter );
 
4338
        gtk_list_store_set( model, &iter,
 
4339
                            0, _("Duplicate/delete mode"),
 
4340
                            1, _("Duplicate objects, with Shift delete"),
 
4341
                            2, INKSCAPE_ICON_OBJECT_TWEAK_DUPLICATE,
 
4342
                            -1 );
 
4343
 
 
4344
        gtk_list_store_append( model, &iter );
 
4345
        gtk_list_store_set( model, &iter,
 
4346
                            0, _("Push mode"),
 
4347
                            1, _("Push parts of paths in any direction"),
 
4348
                            2, INKSCAPE_ICON_PATH_TWEAK_PUSH,
 
4349
                            -1 );
 
4350
 
 
4351
        gtk_list_store_append( model, &iter );
 
4352
        gtk_list_store_set( model, &iter,
 
4353
                            0, _("Shrink/grow mode"),
 
4354
                            1, _("Shrink (inset) parts of paths; with Shift grow (outset)"),
 
4355
                            2, INKSCAPE_ICON_PATH_TWEAK_SHRINK,
 
4356
                            -1 );
 
4357
 
 
4358
        gtk_list_store_append( model, &iter );
 
4359
        gtk_list_store_set( model, &iter,
 
4360
                            0, _("Attract/repel mode"),
 
4361
                            1, _("Attract parts of paths towards cursor; with Shift from cursor"),
 
4362
                            2, INKSCAPE_ICON_PATH_TWEAK_ATTRACT,
 
4363
                            -1 );
 
4364
 
 
4365
        gtk_list_store_append( model, &iter );
 
4366
        gtk_list_store_set( model, &iter,
 
4367
                            0, _("Roughen mode"),
 
4368
                            1, _("Roughen parts of paths"),
 
4369
                            2, INKSCAPE_ICON_PATH_TWEAK_ROUGHEN,
 
4370
                            -1 );
 
4371
 
 
4372
        gtk_list_store_append( model, &iter );
 
4373
        gtk_list_store_set( model, &iter,
 
4374
                            0, _("Color paint mode"),
 
4375
                            1, _("Paint the tool's color upon selected objects"),
 
4376
                            2, INKSCAPE_ICON_OBJECT_TWEAK_PAINT,
 
4377
                            -1 );
 
4378
 
 
4379
        gtk_list_store_append( model, &iter );
 
4380
        gtk_list_store_set( model, &iter,
 
4381
                            0, _("Color jitter mode"),
 
4382
                            1, _("Jitter the colors of selected objects"),
 
4383
                            2, INKSCAPE_ICON_OBJECT_TWEAK_JITTER_COLOR,
 
4384
                            -1 );
 
4385
 
 
4386
        gtk_list_store_append( model, &iter );
 
4387
        gtk_list_store_set( model, &iter,
 
4388
                            0, _("Blur mode"),
 
4389
                            1, _("Blur selected objects more; with Shift, blur less"),
 
4390
                            2, INKSCAPE_ICON_OBJECT_TWEAK_BLUR,
 
4391
                            -1 );
 
4392
 
 
4393
 
 
4394
        EgeSelectOneAction* act = ege_select_one_action_new( "TweakModeAction", _("Mode"), (""), NULL, GTK_TREE_MODEL(model) );
 
4395
        g_object_set( act, "short_label", _("Mode:"), NULL );
 
4396
        gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
 
4397
        g_object_set_data( holder, "mode_action", act );
 
4398
 
 
4399
        ege_select_one_action_set_appearance( act, "full" );
 
4400
        ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
 
4401
        g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
 
4402
        ege_select_one_action_set_icon_column( act, 2 );
 
4403
        ege_select_one_action_set_icon_size( act, secondarySize );
 
4404
        ege_select_one_action_set_tooltip_column( act, 1  );
 
4405
 
 
4406
        gint mode = prefs->getInt("/tools/tweak/mode", 0);
 
4407
        ege_select_one_action_set_active( act, mode );
 
4408
        g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_tweak_mode_changed), holder );
 
4409
 
 
4410
        g_object_set_data( G_OBJECT(holder), "tweak_tool_mode", act);
 
4411
    }
 
4412
 
 
4413
    guint mode = prefs->getInt("/tools/tweak/mode", 0);
 
4414
 
 
4415
    {
 
4416
        EgeOutputAction* act = ege_output_action_new( "TweakChannelsLabel", _("Channels:"), "", 0 );
 
4417
        ege_output_action_set_use_markup( act, TRUE );
 
4418
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
4419
        if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER) {
 
4420
            gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
 
4421
        }
 
4422
        g_object_set_data( holder, "tweak_channels_label", act);
 
4423
    }
 
4424
 
 
4425
    {
 
4426
        InkToggleAction* act = ink_toggle_action_new( "TweakDoH",
 
4427
                                                      _("Hue"),
 
4428
                                                      _("In color mode, act on objects' hue"),
 
4429
                                                      NULL,
 
4430
                                                      Inkscape::ICON_SIZE_DECORATION );
 
4431
        //TRANSLATORS:  "H" here stands for hue
 
4432
        g_object_set( act, "short_label", _("H"), NULL );
 
4433
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
4434
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_doh), desktop );
 
4435
        gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/doh", true) );
 
4436
        if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER) {
 
4437
            gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
 
4438
        }
 
4439
        g_object_set_data( holder, "tweak_doh", act);
 
4440
    }
 
4441
    {
 
4442
        InkToggleAction* act = ink_toggle_action_new( "TweakDoS",
 
4443
                                                      _("Saturation"),
 
4444
                                                      _("In color mode, act on objects' saturation"),
 
4445
                                                      NULL,
 
4446
                                                      Inkscape::ICON_SIZE_DECORATION );
 
4447
        //TRANSLATORS: "S" here stands for Saturation
 
4448
        g_object_set( act, "short_label", _("S"), NULL );
 
4449
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
4450
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_dos), desktop );
 
4451
        gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/dos", true) );
 
4452
        if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER) {
 
4453
            gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
 
4454
        }
 
4455
        g_object_set_data( holder, "tweak_dos", act );
 
4456
    }
 
4457
    {
 
4458
        InkToggleAction* act = ink_toggle_action_new( "TweakDoL",
 
4459
                                                      _("Lightness"),
 
4460
                                                      _("In color mode, act on objects' lightness"),
 
4461
                                                      NULL,
 
4462
                                                      Inkscape::ICON_SIZE_DECORATION );
 
4463
        //TRANSLATORS: "L" here stands for Lightness
 
4464
        g_object_set( act, "short_label", _("L"), NULL );
 
4465
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
4466
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_dol), desktop );
 
4467
        gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/dol", true) );
 
4468
        if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER) {
 
4469
            gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
 
4470
        }
 
4471
        g_object_set_data( holder, "tweak_dol", act );
 
4472
    }
 
4473
    {
 
4474
        InkToggleAction* act = ink_toggle_action_new( "TweakDoO",
 
4475
                                                      _("Opacity"),
 
4476
                                                      _("In color mode, act on objects' opacity"),
 
4477
                                                      NULL,
 
4478
                                                      Inkscape::ICON_SIZE_DECORATION );
 
4479
        //TRANSLATORS: "O" here stands for Opacity
 
4480
        g_object_set( act, "short_label", _("O"), NULL );
 
4481
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
4482
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_doo), desktop );
 
4483
        gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/doo", true) );
 
4484
        if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER) {
 
4485
            gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
 
4486
        }
 
4487
        g_object_set_data( holder, "tweak_doo", act );
 
4488
    }
 
4489
 
 
4490
    {   /* Fidelity */
 
4491
        gchar const* labels[] = {_("(rough, simplified)"), 0, 0, _("(default)"), 0, 0, _("(fine, but many nodes)")};
 
4492
        gdouble values[] = {10, 25, 35, 50, 60, 80, 100};
 
4493
        EgeAdjustmentAction *eact = create_adjustment_action( "TweakFidelityAction",
 
4494
                                                              _("Fidelity"), _("Fidelity:"),
 
4495
                                                              _("Low fidelity simplifies paths; high fidelity preserves path features but may generate a lot of new nodes"),
 
4496
                                                              "/tools/tweak/fidelity", 50,
 
4497
                                                              GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "tweak-fidelity",
 
4498
                                                              1, 100, 1.0, 10.0,
 
4499
                                                              labels, values, G_N_ELEMENTS(labels),
 
4500
                                                              sp_tweak_fidelity_value_changed,  0.01, 0, 100 );
 
4501
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
4502
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
4503
        if (mode == TWEAK_MODE_COLORPAINT || mode == TWEAK_MODE_COLORJITTER) {
 
4504
            gtk_action_set_sensitive (GTK_ACTION(eact), FALSE);
 
4505
        }
 
4506
        g_object_set_data( holder, "tweak_fidelity", eact );
 
4507
    }
 
4508
 
 
4509
 
 
4510
    /* Use Pressure button */
 
4511
    {
 
4512
        InkToggleAction* act = ink_toggle_action_new( "TweakPressureAction",
 
4513
                                                      _("Pressure"),
 
4514
                                                      _("Use the pressure of the input device to alter the force of tweak action"),
 
4515
                                                      INKSCAPE_ICON_DRAW_USE_PRESSURE,
 
4516
                                                      Inkscape::ICON_SIZE_DECORATION );
 
4517
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
4518
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_tweak_pressure_state_changed), NULL);
 
4519
        gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/usepressure", true) );
 
4520
    }
 
4521
 
 
4522
}
 
4523
 
 
4524
 
 
4525
//########################
 
4526
//##       Spray        ##
 
4527
//########################
 
4528
 
 
4529
static void sp_spray_width_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ )
 
4530
{
 
4531
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4532
    prefs->setDouble( "/tools/spray/width", adj->value );
 
4533
}
 
4534
 
 
4535
static void sp_spray_mean_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ )
 
4536
{
 
4537
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4538
    prefs->setDouble( "/tools/spray/mean", adj->value );
 
4539
}
 
4540
 
 
4541
static void sp_spray_standard_deviation_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ )
 
4542
{
 
4543
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4544
    prefs->setDouble( "/tools/spray/standard_deviation", adj->value );
 
4545
}
 
4546
 
 
4547
static void sp_spray_pressure_state_changed( GtkToggleAction *act, gpointer /*data*/ )
 
4548
{
 
4549
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4550
    prefs->setBool("/tools/spray/usepressure", gtk_toggle_action_get_active(act));
 
4551
}
 
4552
 
 
4553
static void sp_spray_mode_changed( EgeSelectOneAction *act, GObject * /*tbl*/ )
 
4554
{
 
4555
    int mode = ege_select_one_action_get_active( act );
 
4556
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4557
    prefs->setInt("/tools/spray/mode", mode);
 
4558
}
 
4559
 
 
4560
static void sp_spray_population_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ )
 
4561
{
 
4562
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4563
    prefs->setDouble( "/tools/spray/population", adj->value );
 
4564
}
 
4565
 
 
4566
static void sp_spray_rotation_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ )
 
4567
{
 
4568
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4569
    prefs->setDouble( "/tools/spray/rotation_variation", adj->value );
 
4570
}
 
4571
 
 
4572
static void sp_spray_scale_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ )
 
4573
{
 
4574
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4575
    prefs->setDouble( "/tools/spray/scale_variation", adj->value );
 
4576
}
 
4577
 
 
4578
 
 
4579
static void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
 
4580
{
 
4581
    Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1);
 
4582
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4583
 
 
4584
    {
 
4585
        /* Width */
 
4586
        gchar const* labels[] = {_("(narrow spray)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad spray)")};
 
4587
        gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
 
4588
        EgeAdjustmentAction *eact = create_adjustment_action( "SprayWidthAction",
 
4589
                                                              _("Width"), _("Width:"), _("The width of the spray area (relative to the visible canvas area)"),
 
4590
                                                              "/tools/spray/width", 15,
 
4591
                                                              GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-spray",
 
4592
                                                              1, 100, 1.0, 10.0,
 
4593
                                                              labels, values, G_N_ELEMENTS(labels),
 
4594
                                                              sp_spray_width_value_changed,  1, 0 );
 
4595
        ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
 
4596
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
4597
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
4598
    }
 
4599
 
 
4600
    {
 
4601
        /* Mean */
 
4602
        gchar const* labels[] = {_("(minimum mean)"), 0, 0, _("(default)"), 0, 0, 0, _("(maximum mean)")};
 
4603
        gdouble values[] = {1, 5, 10, 20, 30, 50, 70, 100};
 
4604
        EgeAdjustmentAction *eact = create_adjustment_action( "SprayMeanAction",
 
4605
                                                              _("Focus"), _("Focus:"), _("0 to spray a spot. Increase to enlarge the ring radius."),
 
4606
                                                              "/tools/spray/mean", 0,
 
4607
                                                              GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "spray-mean",
 
4608
                                                              0, 100, 1.0, 10.0,
 
4609
                                                              labels, values, G_N_ELEMENTS(labels),
 
4610
                                                              sp_spray_mean_value_changed,  1, 0 );
 
4611
        ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
 
4612
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
4613
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
4614
    }
 
4615
 
 
4616
    {
 
4617
        /* Standard_deviation */
 
4618
        gchar const* labels[] = {_("(minimum scatter)"), 0, 0, _("(default)"), 0, 0, 0, _("(maximum scatter)")};
 
4619
        gdouble values[] = {1, 5, 10, 20, 30, 50, 70, 100};
 
4620
 
 
4621
        //TRANSLATORS: only translate "string" in "context|string".
 
4622
        // For more details, see http://developer.gnome.org/doc/API/2.0/glib/glib-I18N.html#Q-:CAPS
 
4623
        EgeAdjustmentAction *eact = create_adjustment_action( "SprayStandard_deviationAction",
 
4624
                                                              Q_("Toolbox|Scatter"), Q_("Toolbox|Scatter:"), _("Increase to scatter sprayed objects."),
 
4625
                                                              "/tools/spray/standard_deviation", 70,
 
4626
                                                              GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "spray-standard_deviation",
 
4627
                                                              1, 100, 1.0, 10.0,
 
4628
                                                              labels, values, G_N_ELEMENTS(labels),
 
4629
                                                              sp_spray_standard_deviation_value_changed,  1, 0 );
 
4630
        ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
 
4631
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
4632
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
4633
    }
 
4634
 
 
4635
    /* Mode */
 
4636
    {
 
4637
        GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
 
4638
 
 
4639
        GtkTreeIter iter;
 
4640
        gtk_list_store_append( model, &iter );
 
4641
        gtk_list_store_set( model, &iter,
 
4642
                            0, _("Spray with copies"),
 
4643
                            1, _("Spray copies of the initial selection"),
 
4644
                            2, INKSCAPE_ICON_SPRAY_COPY_MODE,
 
4645
                            -1 );
 
4646
 
 
4647
        gtk_list_store_append( model, &iter );
 
4648
        gtk_list_store_set( model, &iter,
 
4649
                            0, _("Spray with clones"),
 
4650
                            1, _("Spray clones of the initial selection"),
 
4651
                            2, INKSCAPE_ICON_SPRAY_CLONE_MODE,
 
4652
                            -1 );
 
4653
 
 
4654
        gtk_list_store_append( model, &iter );
 
4655
        gtk_list_store_set( model, &iter,
 
4656
                            0, _("Spray single path"),
 
4657
                            1, _("Spray objects in a single path"),
 
4658
                            2, INKSCAPE_ICON_SPRAY_UNION_MODE,
 
4659
                            -1 );
 
4660
 
 
4661
        EgeSelectOneAction* act = ege_select_one_action_new( "SprayModeAction", _("Mode"), (""), NULL, GTK_TREE_MODEL(model) );
 
4662
        g_object_set( act, "short_label", _("Mode:"), NULL );
 
4663
        gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
 
4664
        g_object_set_data( holder, "mode_action", act );
 
4665
 
 
4666
        ege_select_one_action_set_appearance( act, "full" );
 
4667
        ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
 
4668
        g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
 
4669
        ege_select_one_action_set_icon_column( act, 2 );
 
4670
        ege_select_one_action_set_icon_size( act, secondarySize );
 
4671
        ege_select_one_action_set_tooltip_column( act, 1  );
 
4672
 
 
4673
        gint mode = prefs->getInt("/tools/spray/mode", 1);
 
4674
        ege_select_one_action_set_active( act, mode );
 
4675
        g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_spray_mode_changed), holder );
 
4676
 
 
4677
        g_object_set_data( G_OBJECT(holder), "spray_tool_mode", act);
 
4678
    }
 
4679
 
 
4680
    {   /* Population */
 
4681
        gchar const* labels[] = {_("(low population)"), 0, 0, _("(default)"), 0, 0, _("(high population)")};
 
4682
        gdouble values[] = {10, 25, 35, 50, 60, 80, 100};
 
4683
        EgeAdjustmentAction *eact = create_adjustment_action( "SprayPopulationAction",
 
4684
                                                              _("Amount"), _("Amount:"),
 
4685
                                                              _("Adjusts the number of items sprayed per clic."),
 
4686
                                                              "/tools/spray/population", 70,
 
4687
                                                              GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "spray-population",
 
4688
                                                              1, 100, 1.0, 10.0,
 
4689
                                                              labels, values, G_N_ELEMENTS(labels),
 
4690
                                                              sp_spray_population_value_changed,  1, 0 );
 
4691
        ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
 
4692
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
4693
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
4694
        g_object_set_data( holder, "spray_population", eact );
 
4695
    }
 
4696
 
 
4697
    /* Use Pressure button */
 
4698
    {
 
4699
        InkToggleAction* act = ink_toggle_action_new( "SprayPressureAction",
 
4700
                                                      _("Pressure"),
 
4701
                                                      _("Use the pressure of the input device to alter the amount of sprayed objects."),
 
4702
                                                      "use_pressure",
 
4703
                                                      Inkscape::ICON_SIZE_DECORATION );
 
4704
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
4705
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_spray_pressure_state_changed), NULL);
 
4706
        gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/spray/usepressure", true) );
 
4707
    }
 
4708
 
 
4709
    {   /* Rotation */
 
4710
        gchar const* labels[] = {_("(low rotation variation)"), 0, 0, _("(default)"), 0, 0, _("(high rotation variation)")};
 
4711
        gdouble values[] = {10, 25, 35, 50, 60, 80, 100};
 
4712
        EgeAdjustmentAction *eact = create_adjustment_action( "SprayRotationAction",
 
4713
                                                              _("Rotation"), _("Rotation:"),
 
4714
                                                              // xgettext:no-c-format
 
4715
                                                              _("Variation of the rotation of the sprayed objects. 0% for the same rotation than the original object."),
 
4716
                                                              "/tools/spray/rotation_variation", 0,
 
4717
                                                              GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "spray-rotation",
 
4718
                                                              0, 100, 1.0, 10.0,
 
4719
                                                              labels, values, G_N_ELEMENTS(labels),
 
4720
                                                              sp_spray_rotation_value_changed,  1, 0 );
 
4721
        ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
 
4722
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
4723
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
4724
        g_object_set_data( holder, "spray_rotation", eact );
 
4725
    }
 
4726
 
 
4727
    {   /* Scale */
 
4728
        gchar const* labels[] = {_("(low scale variation)"), 0, 0, _("(default)"), 0, 0, _("(high scale variation)")};
 
4729
        gdouble values[] = {10, 25, 35, 50, 60, 80, 100};
 
4730
 
 
4731
        //TRANSLATORS: only translate "string" in "context|string".
 
4732
        // For more details, see http://developer.gnome.org/doc/API/2.0/glib/glib-I18N.html#Q-:CAPS
 
4733
        EgeAdjustmentAction *eact = create_adjustment_action( "SprayScaleAction",
 
4734
                                                              Q_("Toolbox|Scale"), Q_("Toolbox|Scale:"),
 
4735
                                                              // xgettext:no-c-format
 
4736
                                                              _("Variation in the scale of the sprayed objects. 0% for the same scale than the original object."),
 
4737
                                                              "/tools/spray/scale_variation", 0,
 
4738
                                                              GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "spray-scale",
 
4739
                                                              0, 100, 1.0, 10.0,
 
4740
                                                              labels, values, G_N_ELEMENTS(labels),
 
4741
                                                              sp_spray_scale_value_changed,  1, 0 );
 
4742
        ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
 
4743
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
4744
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
4745
        g_object_set_data( holder, "spray_scale", eact );
 
4746
    }
 
4747
 
 
4748
 
 
4749
 
 
4750
}
 
4751
 
 
4752
 
 
4753
//########################
 
4754
//##     Calligraphy    ##
 
4755
//########################
 
4756
static void update_presets_list(GObject *tbl)
 
4757
{
 
4758
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4759
    if (g_object_get_data(tbl, "presets_blocked")) {
 
4760
        return;
 
4761
    }
 
4762
 
 
4763
    EgeSelectOneAction *sel = static_cast<EgeSelectOneAction *>(g_object_get_data(tbl, "profile_selector"));
 
4764
    if (!sel) {
 
4765
        // WTF!? This will cause a segfault if ever reached
 
4766
        //ege_select_one_action_set_active(sel, 0);
 
4767
        return;
 
4768
    }
 
4769
 
 
4770
    std::vector<Glib::ustring> presets = prefs->getAllDirs("/tools/calligraphic/preset");
 
4771
 
 
4772
    int ege_index = 1;
 
4773
    for (std::vector<Glib::ustring>::iterator i = presets.begin(); i != presets.end(); ++i, ++ege_index) {
 
4774
        bool match = true;
 
4775
 
 
4776
        std::vector<Inkscape::Preferences::Entry> preset = prefs->getAllEntries(*i);
 
4777
        for (std::vector<Inkscape::Preferences::Entry>::iterator j = preset.begin(); j != preset.end(); ++j) {
 
4778
            Glib::ustring entry_name = j->getEntryName();
 
4779
            if (entry_name == "id" || entry_name == "name") {
 
4780
                continue;
 
4781
            }
 
4782
 
 
4783
            void *widget = g_object_get_data(tbl, entry_name.data());
 
4784
            if (widget) {
 
4785
                if (GTK_IS_ADJUSTMENT(widget)) {
 
4786
                    double v = j->getDouble();
 
4787
                    GtkAdjustment* adj = static_cast<GtkAdjustment *>(widget);
 
4788
                    //std::cout << "compared adj " << attr_name << gtk_adjustment_get_value(adj) << " to " << v << "\n";
 
4789
                    if (fabs(gtk_adjustment_get_value(adj) - v) > 1e-6) {
 
4790
                        match = false;
 
4791
                        break;
 
4792
                    }
 
4793
                } else if (GTK_IS_TOGGLE_ACTION(widget)) {
 
4794
                    bool v = j->getBool();
 
4795
                    GtkToggleAction* toggle = static_cast<GtkToggleAction *>(widget);
 
4796
                    //std::cout << "compared toggle " << attr_name << gtk_toggle_action_get_active(toggle) << " to " << v << "\n";
 
4797
                    if ( static_cast<bool>(gtk_toggle_action_get_active(toggle)) != v ) {
 
4798
                        match = false;
 
4799
                        break;
 
4800
                    }
 
4801
                }
 
4802
            }
 
4803
        }
 
4804
 
 
4805
        if (match) {
 
4806
            // newly added item is at the same index as the
 
4807
            // save command, so we need to change twice for it to take effect
 
4808
            ege_select_one_action_set_active(sel, 0);
 
4809
            ege_select_one_action_set_active(sel, ege_index); // one-based index
 
4810
            return;
 
4811
        }
 
4812
    }
 
4813
 
 
4814
    // no match found
 
4815
    ege_select_one_action_set_active(sel, 0);
 
4816
}
 
4817
 
 
4818
static void sp_ddc_mass_value_changed( GtkAdjustment *adj, GObject* tbl )
 
4819
{
 
4820
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4821
    prefs->setDouble( "/tools/calligraphic/mass", adj->value );
 
4822
    update_presets_list(tbl);
 
4823
}
 
4824
 
 
4825
static void sp_ddc_wiggle_value_changed( GtkAdjustment *adj, GObject* tbl )
 
4826
{
 
4827
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4828
    prefs->setDouble( "/tools/calligraphic/wiggle", adj->value );
 
4829
    update_presets_list(tbl);
 
4830
}
 
4831
 
 
4832
static void sp_ddc_angle_value_changed( GtkAdjustment *adj, GObject* tbl )
 
4833
{
 
4834
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4835
    prefs->setDouble( "/tools/calligraphic/angle", adj->value );
 
4836
    update_presets_list(tbl);
 
4837
}
 
4838
 
 
4839
static void sp_ddc_width_value_changed( GtkAdjustment *adj, GObject *tbl )
 
4840
{
 
4841
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4842
    prefs->setDouble( "/tools/calligraphic/width", adj->value );
 
4843
    update_presets_list(tbl);
 
4844
}
 
4845
 
 
4846
static void sp_ddc_velthin_value_changed( GtkAdjustment *adj, GObject* tbl )
 
4847
{
 
4848
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4849
    prefs->setDouble("/tools/calligraphic/thinning", adj->value );
 
4850
    update_presets_list(tbl);
 
4851
}
 
4852
 
 
4853
static void sp_ddc_flatness_value_changed( GtkAdjustment *adj, GObject* tbl )
 
4854
{
 
4855
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4856
    prefs->setDouble( "/tools/calligraphic/flatness", adj->value );
 
4857
    update_presets_list(tbl);
 
4858
}
 
4859
 
 
4860
static void sp_ddc_tremor_value_changed( GtkAdjustment *adj, GObject* tbl )
 
4861
{
 
4862
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4863
    prefs->setDouble( "/tools/calligraphic/tremor", adj->value );
 
4864
    update_presets_list(tbl);
 
4865
}
 
4866
 
 
4867
static void sp_ddc_cap_rounding_value_changed( GtkAdjustment *adj, GObject* tbl )
 
4868
{
 
4869
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4870
    prefs->setDouble( "/tools/calligraphic/cap_rounding", adj->value );
 
4871
    update_presets_list(tbl);
 
4872
}
 
4873
 
 
4874
static void sp_ddc_tilt_state_changed( GtkToggleAction *act, GObject*  tbl )
 
4875
{
 
4876
    // TODO merge into PrefPusher
 
4877
    GtkAction * calligraphy_angle = static_cast<GtkAction *> (g_object_get_data(tbl,"angle_action"));
 
4878
    if (calligraphy_angle ) {
 
4879
        gtk_action_set_sensitive( calligraphy_angle, !gtk_toggle_action_get_active( act ) );
 
4880
    }
 
4881
}
 
4882
 
 
4883
 
 
4884
static gchar const *const widget_names[] = {
 
4885
    "width",
 
4886
    "mass",
 
4887
    "wiggle",
 
4888
    "angle",
 
4889
    "thinning",
 
4890
    "tremor",
 
4891
    "flatness",
 
4892
    "cap_rounding",
 
4893
    "usepressure",
 
4894
    "tracebackground",
 
4895
    "usetilt"
 
4896
};
 
4897
 
 
4898
 
 
4899
static void sp_dcc_build_presets_list(GObject *tbl)
 
4900
{
 
4901
    g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(TRUE));
 
4902
 
 
4903
    EgeSelectOneAction* selector = static_cast<EgeSelectOneAction *>(g_object_get_data(tbl, "profile_selector"));
 
4904
    GtkListStore* model = GTK_LIST_STORE(ege_select_one_action_get_model(selector));
 
4905
    gtk_list_store_clear (model);
 
4906
 
 
4907
    {
 
4908
        GtkTreeIter iter;
 
4909
        gtk_list_store_append( model, &iter );
 
4910
        gtk_list_store_set( model, &iter, 0, _("No preset"), 1, 0, -1 );
 
4911
    }
 
4912
 
 
4913
    // iterate over all presets to populate the list
 
4914
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4915
    std::vector<Glib::ustring> presets = prefs->getAllDirs("/tools/calligraphic/preset");
 
4916
    int ii=1;
 
4917
 
 
4918
    for (std::vector<Glib::ustring>::iterator i = presets.begin(); i != presets.end(); ++i) {
 
4919
        GtkTreeIter iter;
 
4920
        Glib::ustring preset_name = prefs->getString(*i + "/name");
 
4921
        gtk_list_store_append( model, &iter );
 
4922
        gtk_list_store_set( model, &iter, 0, _(preset_name.data()), 1, ii++, -1 );
 
4923
    }
 
4924
 
 
4925
    {
 
4926
        GtkTreeIter iter;
 
4927
        gtk_list_store_append( model, &iter );
 
4928
        gtk_list_store_set( model, &iter, 0, _("Save..."), 1, ii, -1 );
 
4929
        g_object_set_data(tbl, "save_presets_index", GINT_TO_POINTER(ii));
 
4930
    }
 
4931
 
 
4932
    g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(FALSE));
 
4933
 
 
4934
    update_presets_list (tbl);
 
4935
}
 
4936
 
 
4937
static void sp_dcc_save_profile(GtkWidget * /*widget*/, GObject *tbl)
 
4938
{
 
4939
    using Inkscape::UI::Dialog::CalligraphicProfileRename;
 
4940
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
4941
    SPDesktop *desktop = (SPDesktop *) g_object_get_data(tbl, "desktop" );
 
4942
    if (! desktop) {
 
4943
        return;
 
4944
    }
 
4945
 
 
4946
    if (g_object_get_data(tbl, "presets_blocked")) {
 
4947
        return;
 
4948
    }
 
4949
 
 
4950
    CalligraphicProfileRename::show(desktop);
 
4951
    if ( !CalligraphicProfileRename::applied()) {
 
4952
        // dialog cancelled
 
4953
        update_presets_list (tbl);
 
4954
        return;
 
4955
    }
 
4956
    Glib::ustring profile_name = CalligraphicProfileRename::getProfileName();
 
4957
 
 
4958
    if (profile_name.empty()) {
 
4959
        // empty name entered
 
4960
        update_presets_list (tbl);
 
4961
        return;
 
4962
    }
 
4963
 
 
4964
    g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(TRUE));
 
4965
 
 
4966
    // If there's a preset with the given name, find it and set save_path appropriately
 
4967
    std::vector<Glib::ustring> presets = prefs->getAllDirs("/tools/calligraphic/preset");
 
4968
    int total_presets = presets.size();
 
4969
    int new_index = -1;
 
4970
    Glib::ustring save_path; // profile pref path without a trailing slash
 
4971
 
 
4972
    int temp_index = 0;
 
4973
    for (std::vector<Glib::ustring>::iterator i = presets.begin(); i != presets.end(); ++i, ++temp_index) {
 
4974
        Glib::ustring name = prefs->getString(*i + "/name");
 
4975
        if (!name.empty() && profile_name == name) {
 
4976
            new_index = temp_index;
 
4977
            save_path = *i;
 
4978
            break;
 
4979
        }
 
4980
    }
 
4981
 
 
4982
    if (new_index == -1) {
 
4983
        // no preset with this name, create
 
4984
        new_index = total_presets + 1;
 
4985
        gchar *profile_id = g_strdup_printf("/dcc%d", new_index);
 
4986
        save_path = Glib::ustring("/tools/calligraphic/preset") + profile_id;
 
4987
        g_free(profile_id);
 
4988
    }
 
4989
 
 
4990
    for (unsigned i = 0; i < G_N_ELEMENTS(widget_names); ++i) {
 
4991
        gchar const *const widget_name = widget_names[i];
 
4992
        void *widget = g_object_get_data(tbl, widget_name);
 
4993
        if (widget) {
 
4994
            if (GTK_IS_ADJUSTMENT(widget)) {
 
4995
                GtkAdjustment* adj = static_cast<GtkAdjustment *>(widget);
 
4996
                prefs->setDouble(save_path + "/" + widget_name, gtk_adjustment_get_value(adj));
 
4997
                //std::cout << "wrote adj " << widget_name << ": " << v << "\n";
 
4998
            } else if (GTK_IS_TOGGLE_ACTION(widget)) {
 
4999
                GtkToggleAction* toggle = static_cast<GtkToggleAction *>(widget);
 
5000
                prefs->setBool(save_path + "/" + widget_name, gtk_toggle_action_get_active(toggle));
 
5001
                //std::cout << "wrote tog " << widget_name << ": " << v << "\n";
 
5002
            } else {
 
5003
                g_warning("Unknown widget type for preset: %s\n", widget_name);
 
5004
            }
 
5005
        } else {
 
5006
            g_warning("Bad key when writing preset: %s\n", widget_name);
 
5007
        }
 
5008
    }
 
5009
    prefs->setString(save_path + "/name", profile_name);
 
5010
 
 
5011
    g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(FALSE));
 
5012
    sp_dcc_build_presets_list (tbl);
 
5013
}
 
5014
 
 
5015
 
 
5016
static void sp_ddc_change_profile(EgeSelectOneAction* act, GObject* tbl)
 
5017
{
 
5018
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
5019
 
 
5020
    gint preset_index = ege_select_one_action_get_active( act );
 
5021
    // This is necessary because EgeSelectOneAction spams us with GObject "changed" signal calls
 
5022
    // even when the preset is not changed. It would be good to replace it with something more
 
5023
    // modern. Index 0 means "No preset", so we don't do anything.
 
5024
    if (preset_index == 0) {
 
5025
        return;
 
5026
    }
 
5027
 
 
5028
    gint save_presets_index = GPOINTER_TO_INT(g_object_get_data(tbl, "save_presets_index"));
 
5029
 
 
5030
    if (preset_index == save_presets_index) {
 
5031
        // this is the Save command
 
5032
        sp_dcc_save_profile(NULL, tbl);
 
5033
        return;
 
5034
    }
 
5035
 
 
5036
    if (g_object_get_data(tbl, "presets_blocked")) {
 
5037
        return;
 
5038
    }
 
5039
 
 
5040
    // preset_index is one-based so we subtract 1
 
5041
    std::vector<Glib::ustring> presets = prefs->getAllDirs("/tools/calligraphic/preset");
 
5042
    Glib::ustring preset_path = presets.at(preset_index - 1);
 
5043
 
 
5044
    if (!preset_path.empty()) {
 
5045
        g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(TRUE)); //temporarily block the selector so no one will updadte it while we're reading it
 
5046
 
 
5047
        std::vector<Inkscape::Preferences::Entry> preset = prefs->getAllEntries(preset_path);
 
5048
 
 
5049
        // Shouldn't this be std::map?
 
5050
        for (std::vector<Inkscape::Preferences::Entry>::iterator i = preset.begin(); i != preset.end(); ++i) {
 
5051
            Glib::ustring entry_name = i->getEntryName();
 
5052
            if (entry_name == "id" || entry_name == "name") {
 
5053
                continue;
 
5054
            }
 
5055
            void *widget = g_object_get_data(tbl, entry_name.data());
 
5056
            if (widget) {
 
5057
                if (GTK_IS_ADJUSTMENT(widget)) {
 
5058
                    GtkAdjustment* adj = static_cast<GtkAdjustment *>(widget);
 
5059
                    gtk_adjustment_set_value(adj, i->getDouble());
 
5060
                    //std::cout << "set adj " << attr_name << " to " << v << "\n";
 
5061
                } else if (GTK_IS_TOGGLE_ACTION(widget)) {
 
5062
                    GtkToggleAction* toggle = static_cast<GtkToggleAction *>(widget);
 
5063
                    gtk_toggle_action_set_active(toggle, i->getBool());
 
5064
                    //std::cout << "set toggle " << attr_name << " to " << v << "\n";
 
5065
                } else {
 
5066
                    g_warning("Unknown widget type for preset: %s\n", entry_name.data());
 
5067
                }
 
5068
            } else {
 
5069
                g_warning("Bad key found in a preset record: %s\n", entry_name.data());
 
5070
            }
 
5071
        }
 
5072
        g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(FALSE));
 
5073
    }
 
5074
}
 
5075
 
 
5076
static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
 
5077
{
 
5078
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
5079
    {
 
5080
        g_object_set_data(holder, "presets_blocked", GINT_TO_POINTER(TRUE));
 
5081
 
 
5082
        EgeAdjustmentAction* calligraphy_angle = 0;
 
5083
 
 
5084
        {
 
5085
        /* Width */
 
5086
        gchar const* labels[] = {_("(hairline)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad stroke)")};
 
5087
        gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
 
5088
        EgeAdjustmentAction *eact = create_adjustment_action( "CalligraphyWidthAction",
 
5089
                                                              _("Pen Width"), _("Width:"),
 
5090
                                                              _("The width of the calligraphic pen (relative to the visible canvas area)"),
 
5091
                                                              "/tools/calligraphic/width", 15,
 
5092
                                                              GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-calligraphy",
 
5093
                                                              1, 100, 1.0, 10.0,
 
5094
                                                              labels, values, G_N_ELEMENTS(labels),
 
5095
                                                              sp_ddc_width_value_changed,  1, 0 );
 
5096
        ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
 
5097
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
5098
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
5099
        }
 
5100
 
 
5101
        {
 
5102
        /* Thinning */
 
5103
            gchar const* labels[] = {_("(speed blows up stroke)"), 0, 0, _("(slight widening)"), _("(constant width)"), _("(slight thinning, default)"), 0, 0, _("(speed deflates stroke)")};
 
5104
            gdouble values[] = {-100, -40, -20, -10, 0, 10, 20, 40, 100};
 
5105
        EgeAdjustmentAction* eact = create_adjustment_action( "ThinningAction",
 
5106
                                                              _("Stroke Thinning"), _("Thinning:"),
 
5107
                                                              _("How much velocity thins the stroke (> 0 makes fast strokes thinner, < 0 makes them broader, 0 makes width independent of velocity)"),
 
5108
                                                              "/tools/calligraphic/thinning", 10,
 
5109
                                                              GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
 
5110
                                                              -100, 100, 1, 10.0,
 
5111
                                                              labels, values, G_N_ELEMENTS(labels),
 
5112
                                                              sp_ddc_velthin_value_changed, 1, 0);
 
5113
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
5114
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
5115
        }
 
5116
 
 
5117
        {
 
5118
        /* Angle */
 
5119
        gchar const* labels[] = {_("(left edge up)"), 0, 0, _("(horizontal)"), _("(default)"), 0, _("(right edge up)")};
 
5120
        gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
 
5121
        EgeAdjustmentAction* eact = create_adjustment_action( "AngleAction",
 
5122
                                                              _("Pen Angle"), _("Angle:"),
 
5123
                                                              _("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"),
 
5124
                                                              "/tools/calligraphic/angle", 30,
 
5125
                                                              GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "calligraphy-angle",
 
5126
                                                              -90.0, 90.0, 1.0, 10.0,
 
5127
                                                              labels, values, G_N_ELEMENTS(labels),
 
5128
                                                              sp_ddc_angle_value_changed, 1, 0 );
 
5129
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
5130
        g_object_set_data( holder, "angle_action", eact );
 
5131
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
5132
        calligraphy_angle = eact;
 
5133
        }
 
5134
 
 
5135
        {
 
5136
        /* Fixation */
 
5137
            gchar const* labels[] = {_("(perpendicular to stroke, \"brush\")"), 0, 0, 0, _("(almost fixed, default)"), _("(fixed by Angle, \"pen\")")};
 
5138
        gdouble values[] = {0, 20, 40, 60, 90, 100};
 
5139
        EgeAdjustmentAction* eact = create_adjustment_action( "FixationAction",
 
5140
                                                              _("Fixation"), _("Fixation:"),
 
5141
                                                              _("Angle behavior (0 = nib always perpendicular to stroke direction, 100 = fixed angle)"),
 
5142
                                                              "/tools/calligraphic/flatness", 90,
 
5143
                                                              GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
 
5144
                                                              0.0, 100, 1.0, 10.0,
 
5145
                                                              labels, values, G_N_ELEMENTS(labels),
 
5146
                                                              sp_ddc_flatness_value_changed, 1, 0);
 
5147
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
5148
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
5149
        }
 
5150
 
 
5151
        {
 
5152
        /* Cap Rounding */
 
5153
            gchar const* labels[] = {_("(blunt caps, default)"), _("(slightly bulging)"), 0, 0, _("(approximately round)"), _("(long protruding caps)")};
 
5154
        gdouble values[] = {0, 0.3, 0.5, 1.0, 1.4, 5.0};
 
5155
        // TRANSLATORS: "cap" means "end" (both start and finish) here
 
5156
        EgeAdjustmentAction* eact = create_adjustment_action( "CapRoundingAction",
 
5157
                                                              _("Cap rounding"), _("Caps:"),
 
5158
                                                              _("Increase to make caps at the ends of strokes protrude more (0 = no caps, 1 = round caps)"),
 
5159
                                                              "/tools/calligraphic/cap_rounding", 0.0,
 
5160
                                                              GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
 
5161
                                                              0.0, 5.0, 0.01, 0.1,
 
5162
                                                              labels, values, G_N_ELEMENTS(labels),
 
5163
                                                              sp_ddc_cap_rounding_value_changed, 0.01, 2 );
 
5164
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
5165
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
5166
        }
 
5167
 
 
5168
        {
 
5169
        /* Tremor */
 
5170
            gchar const* labels[] = {_("(smooth line)"), _("(slight tremor)"), _("(noticeable tremor)"), 0, 0, _("(maximum tremor)")};
 
5171
        gdouble values[] = {0, 10, 20, 40, 60, 100};
 
5172
        EgeAdjustmentAction* eact = create_adjustment_action( "TremorAction",
 
5173
                                                              _("Stroke Tremor"), _("Tremor:"),
 
5174
                                                              _("Increase to make strokes rugged and trembling"),
 
5175
                                                              "/tools/calligraphic/tremor", 0.0,
 
5176
                                                              GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
 
5177
                                                              0.0, 100, 1, 10.0,
 
5178
                                                              labels, values, G_N_ELEMENTS(labels),
 
5179
                                                              sp_ddc_tremor_value_changed, 1, 0);
 
5180
 
 
5181
        ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
 
5182
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
5183
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
5184
        }
 
5185
 
 
5186
        {
 
5187
        /* Wiggle */
 
5188
        gchar const* labels[] = {_("(no wiggle)"), _("(slight deviation)"), 0, 0, _("(wild waves and curls)")};
 
5189
        gdouble values[] = {0, 20, 40, 60, 100};
 
5190
        EgeAdjustmentAction* eact = create_adjustment_action( "WiggleAction",
 
5191
                                                              _("Pen Wiggle"), _("Wiggle:"),
 
5192
                                                              _("Increase to make the pen waver and wiggle"),
 
5193
                                                              "/tools/calligraphic/wiggle", 0.0,
 
5194
                                                              GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
 
5195
                                                              0.0, 100, 1, 10.0,
 
5196
                                                              labels, values, G_N_ELEMENTS(labels),
 
5197
                                                              sp_ddc_wiggle_value_changed, 1, 0);
 
5198
        ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
 
5199
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
5200
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
5201
        }
 
5202
 
 
5203
        {
 
5204
        /* Mass */
 
5205
            gchar const* labels[] = {_("(no inertia)"), _("(slight smoothing, default)"), _("(noticeable lagging)"), 0, 0, _("(maximum inertia)")};
 
5206
        gdouble values[] = {0.0, 2, 10, 20, 50, 100};
 
5207
        EgeAdjustmentAction* eact = create_adjustment_action( "MassAction",
 
5208
                                                              _("Pen Mass"), _("Mass:"),
 
5209
                                                              _("Increase to make the pen drag behind, as if slowed by inertia"),
 
5210
                                                              "/tools/calligraphic/mass", 2.0,
 
5211
                                                              GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
 
5212
                                                              0.0, 100, 1, 10.0,
 
5213
                                                              labels, values, G_N_ELEMENTS(labels),
 
5214
                                                              sp_ddc_mass_value_changed, 1, 0);
 
5215
        ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
 
5216
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
5217
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
5218
        }
 
5219
 
 
5220
 
 
5221
        /* Trace Background button */
 
5222
        {
 
5223
            InkToggleAction* act = ink_toggle_action_new( "TraceAction",
 
5224
                                                          _("Trace Background"),
 
5225
                                                          _("Trace the lightness of the background by the width of the pen (white - minimum width, black - maximum width)"),
 
5226
                                                          INKSCAPE_ICON_DRAW_TRACE_BACKGROUND,
 
5227
                                                          Inkscape::ICON_SIZE_DECORATION );
 
5228
            gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
5229
            PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/calligraphic/tracebackground", update_presets_list, holder);
 
5230
            g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher);
 
5231
            g_object_set_data( holder, "tracebackground", act );
 
5232
        }
 
5233
 
 
5234
        /* Use Pressure button */
 
5235
        {
 
5236
            InkToggleAction* act = ink_toggle_action_new( "PressureAction",
 
5237
                                                          _("Pressure"),
 
5238
                                                          _("Use the pressure of the input device to alter the width of the pen"),
 
5239
                                                          INKSCAPE_ICON_DRAW_USE_PRESSURE,
 
5240
                                                          Inkscape::ICON_SIZE_DECORATION );
 
5241
            gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
5242
            PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/calligraphic/usepressure", update_presets_list, holder);
 
5243
            g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher);
 
5244
            g_object_set_data( holder, "usepressure", act );
 
5245
        }
 
5246
 
 
5247
        /* Use Tilt button */
 
5248
        {
 
5249
            InkToggleAction* act = ink_toggle_action_new( "TiltAction",
 
5250
                                                          _("Tilt"),
 
5251
                                                          _("Use the tilt of the input device to alter the angle of the pen's nib"),
 
5252
                                                          INKSCAPE_ICON_DRAW_USE_TILT,
 
5253
                                                          Inkscape::ICON_SIZE_DECORATION );
 
5254
            gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
5255
            PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/calligraphic/usetilt", update_presets_list, holder);
 
5256
            g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher);
 
5257
            g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_tilt_state_changed), holder );
 
5258
            gtk_action_set_sensitive( GTK_ACTION(calligraphy_angle), !prefs->getBool("/tools/calligraphic/usetilt", true) );
 
5259
            gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/calligraphic/usetilt", true) );
 
5260
            g_object_set_data( holder, "usetilt", act );
 
5261
        }
 
5262
 
 
5263
        /*calligraphic profile */
 
5264
        {
 
5265
            GtkListStore* model = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
 
5266
            EgeSelectOneAction* act1 = ege_select_one_action_new ("SetProfileAction", "" , (_("Choose a preset")), NULL, GTK_TREE_MODEL(model));
 
5267
            ege_select_one_action_set_appearance (act1, "compact");
 
5268
            g_object_set_data (holder, "profile_selector", act1 );
 
5269
 
 
5270
            g_object_set_data(holder, "presets_blocked", GINT_TO_POINTER(FALSE));
 
5271
 
 
5272
            sp_dcc_build_presets_list (holder);
 
5273
 
 
5274
            g_signal_connect(G_OBJECT(act1), "changed", G_CALLBACK(sp_ddc_change_profile), holder);
 
5275
            gtk_action_group_add_action(mainActions, GTK_ACTION(act1));
 
5276
        }
 
5277
    }
 
5278
}
 
5279
 
 
5280
 
 
5281
//########################
 
5282
//##    Circle / Arc    ##
 
5283
//########################
 
5284
 
 
5285
static void sp_arctb_sensitivize( GObject *tbl, double v1, double v2 )
 
5286
{
 
5287
    GtkAction *ocb = GTK_ACTION( g_object_get_data( tbl, "open_action" ) );
 
5288
    GtkAction *make_whole = GTK_ACTION( g_object_get_data( tbl, "make_whole" ) );
 
5289
 
 
5290
    if (v1 == 0 && v2 == 0) {
 
5291
        if (g_object_get_data( tbl, "single" )) { // only for a single selected ellipse (for now)
 
5292
            gtk_action_set_sensitive( ocb, FALSE );
 
5293
            gtk_action_set_sensitive( make_whole, FALSE );
 
5294
        }
 
5295
    } else {
 
5296
        gtk_action_set_sensitive( ocb, TRUE );
 
5297
        gtk_action_set_sensitive( make_whole, TRUE );
 
5298
    }
 
5299
}
 
5300
 
 
5301
static void
 
5302
sp_arctb_startend_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name, gchar const *other_name)
 
5303
{
 
5304
    SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
 
5305
 
 
5306
    if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
 
5307
        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
5308
        prefs->setDouble(Glib::ustring("/tools/shapes/arc/") + value_name, adj->value);
 
5309
    }
 
5310
 
 
5311
    // quit if run by the attr_changed listener
 
5312
    if (g_object_get_data( tbl, "freeze" )) {
 
5313
        return;
 
5314
    }
 
5315
 
 
5316
    // in turn, prevent listener from responding
 
5317
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
 
5318
 
 
5319
    gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
 
5320
 
 
5321
    bool modmade = false;
 
5322
    for (GSList const *items = sp_desktop_selection(desktop)->itemList();
 
5323
         items != NULL;
 
5324
         items = items->next)
 
5325
    {
 
5326
        SPItem *item = SP_ITEM(items->data);
 
5327
 
 
5328
        if (SP_IS_ARC(item) && SP_IS_GENERICELLIPSE(item)) {
 
5329
 
 
5330
            SPGenericEllipse *ge = SP_GENERICELLIPSE(item);
 
5331
            SPArc *arc = SP_ARC(item);
 
5332
 
 
5333
            if (!strcmp(value_name, "start")) {
 
5334
                ge->start = (adj->value * M_PI)/ 180;
 
5335
            } else {
 
5336
                ge->end = (adj->value * M_PI)/ 180;
 
5337
            }
 
5338
 
 
5339
            sp_genericellipse_normalize(ge);
 
5340
            ((SPObject *)arc)->updateRepr();
 
5341
            ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
 
5342
 
 
5343
            modmade = true;
 
5344
        }
 
5345
    }
 
5346
 
 
5347
    g_free(namespaced_name);
 
5348
 
 
5349
    GtkAdjustment *other = GTK_ADJUSTMENT( g_object_get_data( tbl, other_name ) );
 
5350
 
 
5351
    sp_arctb_sensitivize( tbl, adj->value, other->value );
 
5352
 
 
5353
    if (modmade) {
 
5354
        sp_document_maybe_done(sp_desktop_document(desktop), value_name, SP_VERB_CONTEXT_ARC,
 
5355
                                   _("Arc: Change start/end"));
 
5356
    }
 
5357
 
 
5358
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 
5359
}
 
5360
 
 
5361
 
 
5362
static void sp_arctb_start_value_changed(GtkAdjustment *adj,  GObject *tbl)
 
5363
{
 
5364
    sp_arctb_startend_value_changed(adj,  tbl, "start", "end");
 
5365
}
 
5366
 
 
5367
static void sp_arctb_end_value_changed(GtkAdjustment *adj, GObject *tbl)
 
5368
{
 
5369
    sp_arctb_startend_value_changed(adj,  tbl, "end", "start");
 
5370
}
 
5371
 
 
5372
 
 
5373
static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl )
 
5374
{
 
5375
    SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
 
5376
    if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
 
5377
        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
5378
        prefs->setBool("/tools/shapes/arc/open", ege_select_one_action_get_active(act) != 0);
 
5379
    }
 
5380
 
 
5381
    // quit if run by the attr_changed listener
 
5382
    if (g_object_get_data( tbl, "freeze" )) {
 
5383
        return;
 
5384
    }
 
5385
 
 
5386
    // in turn, prevent listener from responding
 
5387
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
 
5388
 
 
5389
    bool modmade = false;
 
5390
 
 
5391
    if ( ege_select_one_action_get_active(act) != 0 ) {
 
5392
        for (GSList const *items = sp_desktop_selection(desktop)->itemList();
 
5393
             items != NULL;
 
5394
             items = items->next)
 
5395
        {
 
5396
            if (SP_IS_ARC((SPItem *) items->data)) {
 
5397
                Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
 
5398
                repr->setAttribute("sodipodi:open", "true");
 
5399
                SP_OBJECT((SPItem *) items->data)->updateRepr();
 
5400
                modmade = true;
 
5401
            }
 
5402
        }
 
5403
    } else {
 
5404
        for (GSList const *items = sp_desktop_selection(desktop)->itemList();
 
5405
             items != NULL;
 
5406
             items = items->next)
 
5407
        {
 
5408
            if (SP_IS_ARC((SPItem *) items->data)) {
 
5409
                Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
 
5410
                repr->setAttribute("sodipodi:open", NULL);
 
5411
                SP_OBJECT((SPItem *) items->data)->updateRepr();
 
5412
                modmade = true;
 
5413
            }
 
5414
        }
 
5415
    }
 
5416
 
 
5417
    if (modmade) {
 
5418
        sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ARC,
 
5419
                                   _("Arc: Change open/closed"));
 
5420
    }
 
5421
 
 
5422
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 
5423
}
 
5424
 
 
5425
static void sp_arctb_defaults(GtkWidget *, GObject *obj)
 
5426
{
 
5427
    GtkAdjustment *adj;
 
5428
    adj = GTK_ADJUSTMENT( g_object_get_data(obj, "start") );
 
5429
    gtk_adjustment_set_value(adj, 0.0);
 
5430
    gtk_adjustment_value_changed(adj);
 
5431
 
 
5432
    adj = GTK_ADJUSTMENT( g_object_get_data(obj, "end") );
 
5433
    gtk_adjustment_set_value(adj, 0.0);
 
5434
    gtk_adjustment_value_changed(adj);
 
5435
 
 
5436
    spinbutton_defocus( GTK_OBJECT(obj) );
 
5437
}
 
5438
 
 
5439
static void arc_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const * /*name*/,
 
5440
                                      gchar const * /*old_value*/, gchar const * /*new_value*/,
 
5441
                                      bool /*is_interactive*/, gpointer data)
 
5442
{
 
5443
    GObject *tbl = G_OBJECT(data);
 
5444
 
 
5445
    // quit if run by the _changed callbacks
 
5446
    if (g_object_get_data( tbl, "freeze" )) {
 
5447
        return;
 
5448
    }
 
5449
 
 
5450
    // in turn, prevent callbacks from responding
 
5451
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
 
5452
 
 
5453
    gdouble start = sp_repr_get_double_attribute(repr, "sodipodi:start", 0.0);
 
5454
    gdouble end = sp_repr_get_double_attribute(repr, "sodipodi:end", 0.0);
 
5455
 
 
5456
    GtkAdjustment *adj1,*adj2;
 
5457
    adj1 = GTK_ADJUSTMENT( g_object_get_data( tbl, "start" ) );
 
5458
    gtk_adjustment_set_value(adj1, mod360((start * 180)/M_PI));
 
5459
    adj2 = GTK_ADJUSTMENT( g_object_get_data( tbl, "end" ) );
 
5460
    gtk_adjustment_set_value(adj2, mod360((end * 180)/M_PI));
 
5461
 
 
5462
    sp_arctb_sensitivize( tbl, adj1->value, adj2->value );
 
5463
 
 
5464
    char const *openstr = NULL;
 
5465
    openstr = repr->attribute("sodipodi:open");
 
5466
    EgeSelectOneAction *ocb = EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "open_action" ) );
 
5467
 
 
5468
    if (openstr) {
 
5469
        ege_select_one_action_set_active( ocb, 1 );
 
5470
    } else {
 
5471
        ege_select_one_action_set_active( ocb, 0 );
 
5472
    }
 
5473
 
 
5474
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 
5475
}
 
5476
 
 
5477
static Inkscape::XML::NodeEventVector arc_tb_repr_events = {
 
5478
    NULL, /* child_added */
 
5479
    NULL, /* child_removed */
 
5480
    arc_tb_event_attr_changed,
 
5481
    NULL, /* content_changed */
 
5482
    NULL  /* order_changed */
 
5483
};
 
5484
 
 
5485
 
 
5486
static void sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
 
5487
{
 
5488
    int n_selected = 0;
 
5489
    Inkscape::XML::Node *repr = NULL;
 
5490
 
 
5491
    purge_repr_listener( tbl, tbl );
 
5492
 
 
5493
    for (GSList const *items = selection->itemList();
 
5494
         items != NULL;
 
5495
         items = items->next)
 
5496
    {
 
5497
        if (SP_IS_ARC((SPItem *) items->data)) {
 
5498
            n_selected++;
 
5499
            repr = SP_OBJECT_REPR((SPItem *) items->data);
 
5500
        }
 
5501
    }
 
5502
 
 
5503
    EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
 
5504
 
 
5505
    g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
 
5506
    if (n_selected == 0) {
 
5507
        g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
 
5508
    } else if (n_selected == 1) {
 
5509
        g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
 
5510
        g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
 
5511
 
 
5512
        if (repr) {
 
5513
            g_object_set_data( tbl, "repr", repr );
 
5514
            Inkscape::GC::anchor(repr);
 
5515
            sp_repr_add_listener(repr, &arc_tb_repr_events, tbl);
 
5516
            sp_repr_synthesize_events(repr, &arc_tb_repr_events, tbl);
 
5517
        }
 
5518
    } else {
 
5519
        // FIXME: implement averaging of all parameters for multiple selected
 
5520
        //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
 
5521
        g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
 
5522
        sp_arctb_sensitivize( tbl, 1, 0 );
 
5523
    }
 
5524
}
 
5525
 
 
5526
 
 
5527
static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
 
5528
{
 
5529
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
5530
 
 
5531
    EgeAdjustmentAction* eact = 0;
 
5532
    Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1);
 
5533
 
 
5534
 
 
5535
    {
 
5536
        EgeOutputAction* act = ege_output_action_new( "ArcStateAction", _("<b>New:</b>"), "", 0 );
 
5537
        ege_output_action_set_use_markup( act, TRUE );
 
5538
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
5539
        g_object_set_data( holder, "mode_action", act );
 
5540
    }
 
5541
 
 
5542
    /* Start */
 
5543
    {
 
5544
        eact = create_adjustment_action( "ArcStartAction",
 
5545
                                         _("Start"), _("Start:"),
 
5546
                                         _("The angle (in degrees) from the horizontal to the arc's start point"),
 
5547
                                         "/tools/shapes/arc/start", 0.0,
 
5548
                                         GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-arc",
 
5549
                                         -360.0, 360.0, 1.0, 10.0,
 
5550
                                         0, 0, 0,
 
5551
                                         sp_arctb_start_value_changed);
 
5552
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
5553
    }
 
5554
 
 
5555
    /* End */
 
5556
    {
 
5557
        eact = create_adjustment_action( "ArcEndAction",
 
5558
                                         _("End"), _("End:"),
 
5559
                                         _("The angle (in degrees) from the horizontal to the arc's end point"),
 
5560
                                         "/tools/shapes/arc/end", 0.0,
 
5561
                                         GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
 
5562
                                         -360.0, 360.0, 1.0, 10.0,
 
5563
                                         0, 0, 0,
 
5564
                                         sp_arctb_end_value_changed);
 
5565
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
5566
    }
 
5567
 
 
5568
    /* Segments / Pie checkbox */
 
5569
    {
 
5570
        GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
 
5571
 
 
5572
        GtkTreeIter iter;
 
5573
        gtk_list_store_append( model, &iter );
 
5574
        gtk_list_store_set( model, &iter,
 
5575
                            0, _("Closed arc"),
 
5576
                            1, _("Switch to segment (closed shape with two radii)"),
 
5577
                            2, INKSCAPE_ICON_DRAW_ELLIPSE_SEGMENT,
 
5578
                            -1 );
 
5579
 
 
5580
        gtk_list_store_append( model, &iter );
 
5581
        gtk_list_store_set( model, &iter,
 
5582
                            0, _("Open Arc"),
 
5583
                            1, _("Switch to arc (unclosed shape)"),
 
5584
                            2, INKSCAPE_ICON_DRAW_ELLIPSE_ARC,
 
5585
                            -1 );
 
5586
 
 
5587
        EgeSelectOneAction* act = ege_select_one_action_new( "ArcOpenAction", (""), (""), NULL, GTK_TREE_MODEL(model) );
 
5588
        gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
 
5589
        g_object_set_data( holder, "open_action", act );
 
5590
 
 
5591
        ege_select_one_action_set_appearance( act, "full" );
 
5592
        ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
 
5593
        g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
 
5594
        ege_select_one_action_set_icon_column( act, 2 );
 
5595
        ege_select_one_action_set_icon_size( act, secondarySize );
 
5596
        ege_select_one_action_set_tooltip_column( act, 1  );
 
5597
 
 
5598
        bool isClosed = !prefs->getBool("/tools/shapes/arc/open", false);
 
5599
        ege_select_one_action_set_active( act, isClosed ? 0 : 1 );
 
5600
        g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_arctb_open_state_changed), holder );
 
5601
    }
 
5602
 
 
5603
    /* Make Whole */
 
5604
    {
 
5605
        InkAction* inky = ink_action_new( "ArcResetAction",
 
5606
                                          _("Make whole"),
 
5607
                                          _("Make the shape a whole ellipse, not arc or segment"),
 
5608
                                          INKSCAPE_ICON_DRAW_ELLIPSE_WHOLE,
 
5609
                                          secondarySize );
 
5610
        g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_arctb_defaults), holder );
 
5611
        gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
 
5612
        gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
 
5613
        g_object_set_data( holder, "make_whole", inky );
 
5614
    }
 
5615
 
 
5616
    g_object_set_data( G_OBJECT(holder), "single", GINT_TO_POINTER(TRUE) );
 
5617
    // sensitivize make whole and open checkbox
 
5618
    {
 
5619
        GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data( holder, "start" ) );
 
5620
        GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data( holder, "end" ) );
 
5621
        sp_arctb_sensitivize( holder, adj1->value, adj2->value );
 
5622
    }
 
5623
 
 
5624
 
 
5625
    sigc::connection *connection = new sigc::connection(
 
5626
        sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_arc_toolbox_selection_changed), (GObject *)holder))
 
5627
        );
 
5628
    g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
 
5629
    g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
 
5630
}
 
5631
 
 
5632
 
 
5633
 
 
5634
 
 
5635
// toggle button callbacks and updaters
 
5636
 
 
5637
//########################
 
5638
//##      Dropper       ##
 
5639
//########################
 
5640
 
 
5641
static void toggle_dropper_pick_alpha( GtkToggleAction* act, gpointer tbl )
 
5642
{
 
5643
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
5644
    prefs->setInt( "/tools/dropper/pick", gtk_toggle_action_get_active( act ) );
 
5645
    GtkAction* set_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "set_action") );
 
5646
    if ( set_action ) {
 
5647
        if ( gtk_toggle_action_get_active( act ) ) {
 
5648
            gtk_action_set_sensitive( set_action, TRUE );
 
5649
        } else {
 
5650
            gtk_action_set_sensitive( set_action, FALSE );
 
5651
        }
 
5652
    }
 
5653
 
 
5654
    spinbutton_defocus(GTK_OBJECT(tbl));
 
5655
}
 
5656
 
 
5657
static void toggle_dropper_set_alpha( GtkToggleAction* act, gpointer tbl )
 
5658
{
 
5659
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
5660
    prefs->setBool( "/tools/dropper/setalpha", gtk_toggle_action_get_active( act ) );
 
5661
    spinbutton_defocus(GTK_OBJECT(tbl));
 
5662
}
 
5663
 
 
5664
 
 
5665
/**
 
5666
 * Dropper auxiliary toolbar construction and setup.
 
5667
 *
 
5668
 * TODO: Would like to add swatch of current color.
 
5669
 * TODO: Add queue of last 5 or so colors selected with new swatches so that
 
5670
 *       can drag and drop places. Will provide a nice mixing palette.
 
5671
 */
 
5672
static void sp_dropper_toolbox_prep(SPDesktop * /*desktop*/, GtkActionGroup* mainActions, GObject* holder)
 
5673
{
 
5674
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
5675
    gint pickAlpha = prefs->getInt( "/tools/dropper/pick", 1 );
 
5676
 
 
5677
    {
 
5678
        EgeOutputAction* act = ege_output_action_new( "DropperOpacityAction", _("Opacity:"), "", 0 );
 
5679
        ege_output_action_set_use_markup( act, TRUE );
 
5680
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
5681
    }
 
5682
 
 
5683
    {
 
5684
        InkToggleAction* act = ink_toggle_action_new( "DropperPickAlphaAction",
 
5685
                                                      _("Pick opacity"),
 
5686
                                                      _("Pick both the color and the alpha (transparency) under cursor; otherwise, pick only the visible color premultiplied by alpha"),
 
5687
                                                      NULL,
 
5688
                                                      Inkscape::ICON_SIZE_DECORATION );
 
5689
        g_object_set( act, "short_label", _("Pick"), NULL );
 
5690
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
5691
        g_object_set_data( holder, "pick_action", act );
 
5692
        gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), pickAlpha );
 
5693
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_pick_alpha), holder );
 
5694
    }
 
5695
 
 
5696
    {
 
5697
        InkToggleAction* act = ink_toggle_action_new( "DropperSetAlphaAction",
 
5698
                                                      _("Assign opacity"),
 
5699
                                                      _("If alpha was picked, assign it to selection as fill or stroke transparency"),
 
5700
                                                      NULL,
 
5701
                                                      Inkscape::ICON_SIZE_DECORATION );
 
5702
        g_object_set( act, "short_label", _("Assign"), NULL );
 
5703
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
5704
        g_object_set_data( holder, "set_action", act );
 
5705
        gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool( "/tools/dropper/setalpha", true) );
 
5706
        // make sure it's disabled if we're not picking alpha
 
5707
        gtk_action_set_sensitive( GTK_ACTION(act), pickAlpha );
 
5708
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_set_alpha), holder );
 
5709
    }
 
5710
}
 
5711
 
 
5712
 
 
5713
//########################
 
5714
//##      LPETool       ##
 
5715
//########################
 
5716
 
 
5717
// the subtools from which the toolbar is built automatically are listed in lpe-tool-context.h
 
5718
 
 
5719
// this is called when the mode is changed via the toolbar (i.e., one of the subtool buttons is pressed)
 
5720
static void sp_lpetool_mode_changed(EgeSelectOneAction *act, GObject *tbl)
 
5721
{
 
5722
    using namespace Inkscape::LivePathEffect;
 
5723
 
 
5724
    SPDesktop *desktop = (SPDesktop *) g_object_get_data(tbl, "desktop");
 
5725
    SPEventContext *ec = desktop->event_context;
 
5726
    if (!SP_IS_LPETOOL_CONTEXT(ec)) {
 
5727
        return;
 
5728
    }
 
5729
 
 
5730
    // only take action if run by the attr_changed listener
 
5731
    if (!g_object_get_data(tbl, "freeze")) {
 
5732
        // in turn, prevent listener from responding
 
5733
        g_object_set_data(tbl, "freeze", GINT_TO_POINTER(TRUE));
 
5734
 
 
5735
        gint mode = ege_select_one_action_get_active(act);
 
5736
        EffectType type = lpesubtools[mode].type;
 
5737
 
 
5738
        SPLPEToolContext *lc = SP_LPETOOL_CONTEXT(desktop->event_context);
 
5739
        bool success = lpetool_try_construction(lc, type);
 
5740
        if (success) {
 
5741
            // since the construction was already performed, we set the state back to inactive
 
5742
            ege_select_one_action_set_active(act, 0);
 
5743
            mode = 0;
 
5744
        } else {
 
5745
            // switch to the chosen subtool
 
5746
            SP_LPETOOL_CONTEXT(desktop->event_context)->mode = type;
 
5747
        }
 
5748
 
 
5749
        if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
 
5750
            Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
5751
            prefs->setInt( "/tools/lpetool/mode", mode );
 
5752
        }
 
5753
 
 
5754
        g_object_set_data(tbl, "freeze", GINT_TO_POINTER(FALSE));
 
5755
    }
 
5756
}
 
5757
 
 
5758
static void sp_lpetool_toolbox_sel_modified(Inkscape::Selection *selection, guint /*flags*/, GObject * /*tbl*/)
 
5759
{
 
5760
    SPEventContext *ec = selection->desktop()->event_context;
 
5761
    if (SP_IS_LPETOOL_CONTEXT(ec)) {
 
5762
        lpetool_update_measuring_items(SP_LPETOOL_CONTEXT(ec));
 
5763
    }
 
5764
}
 
5765
 
 
5766
static void sp_lpetool_toolbox_sel_changed(Inkscape::Selection *selection, GObject *tbl)
 
5767
{
 
5768
    using namespace Inkscape::LivePathEffect;
 
5769
    SPEventContext *ec = selection->desktop()->event_context;
 
5770
    if (!SP_IS_LPETOOL_CONTEXT(ec)) {
 
5771
        return;
 
5772
    }
 
5773
    SPLPEToolContext *lc = SP_LPETOOL_CONTEXT(ec);
 
5774
 
 
5775
    lpetool_delete_measuring_items(lc);
 
5776
    lpetool_create_measuring_items(lc, selection);
 
5777
 
 
5778
    // activate line segment combo box if a single item with LPELineSegment is selected
 
5779
    GtkAction* w = GTK_ACTION(g_object_get_data(tbl, "lpetool_line_segment_action"));
 
5780
    SPItem *item = selection->singleItem();
 
5781
    if (item && SP_IS_LPE_ITEM(item) && lpetool_item_has_construction(lc, item)) {
 
5782
        SPLPEItem *lpeitem = SP_LPE_ITEM(item);
 
5783
        Effect* lpe = sp_lpe_item_get_current_lpe(lpeitem);
 
5784
        if (lpe && lpe->effectType() == LINE_SEGMENT) {
 
5785
            LPELineSegment *lpels = static_cast<LPELineSegment*>(lpe);
 
5786
            g_object_set_data(tbl, "currentlpe", lpe);
 
5787
            g_object_set_data(tbl, "currentlpeitem", lpeitem);
 
5788
            gtk_action_set_sensitive(w, TRUE);
 
5789
            ege_select_one_action_set_active(EGE_SELECT_ONE_ACTION(w), lpels->end_type.get_value());
 
5790
        } else {
 
5791
            g_object_set_data(tbl, "currentlpe", NULL);
 
5792
            g_object_set_data(tbl, "currentlpeitem", NULL);
 
5793
            gtk_action_set_sensitive(w, FALSE);
 
5794
        }
 
5795
    } else {
 
5796
        g_object_set_data(tbl, "currentlpe", NULL);
 
5797
        g_object_set_data(tbl, "currentlpeitem", NULL);
 
5798
        gtk_action_set_sensitive(w, FALSE);
 
5799
    }
 
5800
}
 
5801
 
 
5802
static void lpetool_toggle_show_bbox(GtkToggleAction *act, gpointer data) {
 
5803
    SPDesktop *desktop = static_cast<SPDesktop *>(data);
 
5804
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
5805
 
 
5806
    bool show = gtk_toggle_action_get_active( act );
 
5807
    prefs->setBool("/tools/lpetool/show_bbox",  show);
 
5808
 
 
5809
    if (tools_isactive(desktop, TOOLS_LPETOOL)) {
 
5810
        SPLPEToolContext *lc = SP_LPETOOL_CONTEXT(desktop->event_context);
 
5811
        lpetool_context_reset_limiting_bbox(lc);
 
5812
    }
 
5813
}
 
5814
 
 
5815
static void lpetool_toggle_show_measuring_info(GtkToggleAction *act, GObject *tbl)
 
5816
{
 
5817
    SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data(tbl, "desktop"));
 
5818
    if (!tools_isactive(desktop, TOOLS_LPETOOL)) {
 
5819
        return;
 
5820
    }
 
5821
 
 
5822
    GtkAction *unitact = static_cast<GtkAction*>(g_object_get_data(tbl, "lpetool_units_action"));
 
5823
    SPLPEToolContext *lc = SP_LPETOOL_CONTEXT(desktop->event_context);
 
5824
    if (tools_isactive(desktop, TOOLS_LPETOOL)) {
 
5825
        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
5826
        bool show = gtk_toggle_action_get_active( act );
 
5827
        prefs->setBool("/tools/lpetool/show_measuring_info",  show);
 
5828
        lpetool_show_measuring_info(lc, show);
 
5829
        gtk_action_set_sensitive(GTK_ACTION(unitact), show);
 
5830
    }
 
5831
}
 
5832
 
 
5833
static void lpetool_unit_changed(GtkAction* /*act*/, GObject* tbl)
 
5834
{
 
5835
    UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data(tbl, "tracker"));
 
5836
    SPUnit const *unit = tracker->getActiveUnit();
 
5837
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
5838
    prefs->setInt("/tools/lpetool/unitid", unit->unit_id);
 
5839
 
 
5840
    SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
 
5841
    if (SP_IS_LPETOOL_CONTEXT(desktop->event_context)) {
 
5842
        SPLPEToolContext *lc = SP_LPETOOL_CONTEXT(desktop->event_context);
 
5843
        lpetool_delete_measuring_items(lc);
 
5844
        lpetool_create_measuring_items(lc);
 
5845
    }
 
5846
}
 
5847
 
 
5848
static void lpetool_toggle_set_bbox(GtkToggleAction *act, gpointer data)
 
5849
{
 
5850
    SPDesktop *desktop = static_cast<SPDesktop *>(data);
 
5851
    Inkscape::Selection *selection = desktop->selection;
 
5852
 
 
5853
    Geom::OptRect bbox = selection->bounds();
 
5854
 
 
5855
    if (bbox) {
 
5856
        Geom::Point A(bbox->min());
 
5857
        Geom::Point B(bbox->max());
 
5858
 
 
5859
        A *= desktop->doc2dt();
 
5860
        B *= desktop->doc2dt();
 
5861
 
 
5862
        // TODO: should we provide a way to store points in prefs?
 
5863
        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
5864
        prefs->setDouble("/tools/lpetool/bbox_upperleftx", A[Geom::X]);
 
5865
        prefs->setDouble("/tools/lpetool/bbox_upperlefty", A[Geom::Y]);
 
5866
        prefs->setDouble("/tools/lpetool/bbox_lowerrightx", B[Geom::X]);
 
5867
        prefs->setDouble("/tools/lpetool/bbox_lowerrighty", B[Geom::Y]);
 
5868
 
 
5869
        lpetool_context_reset_limiting_bbox(SP_LPETOOL_CONTEXT(desktop->event_context));
 
5870
    }
 
5871
 
 
5872
    gtk_toggle_action_set_active(act, false);
 
5873
}
 
5874
 
 
5875
static void sp_line_segment_build_list(GObject *tbl)
 
5876
{
 
5877
    g_object_set_data(tbl, "line_segment_list_blocked", GINT_TO_POINTER(TRUE));
 
5878
 
 
5879
    EgeSelectOneAction* selector = static_cast<EgeSelectOneAction *>(g_object_get_data(tbl, "lpetool_line_segment_action"));
 
5880
    GtkListStore* model = GTK_LIST_STORE(ege_select_one_action_get_model(selector));
 
5881
    gtk_list_store_clear (model);
 
5882
 
 
5883
    // TODO: we add the entries of rht combo box manually; later this should be done automatically
 
5884
    {
 
5885
        GtkTreeIter iter;
 
5886
        gtk_list_store_append( model, &iter );
 
5887
        gtk_list_store_set( model, &iter, 0, _("Closed"), 1, 0, -1 );
 
5888
        gtk_list_store_append( model, &iter );
 
5889
        gtk_list_store_set( model, &iter, 0, _("Open start"), 1, 1, -1 );
 
5890
        gtk_list_store_append( model, &iter );
 
5891
        gtk_list_store_set( model, &iter, 0, _("Open end"), 1, 2, -1 );
 
5892
        gtk_list_store_append( model, &iter );
 
5893
        gtk_list_store_set( model, &iter, 0, _("Open both"), 1, 3, -1 );
 
5894
    }
 
5895
 
 
5896
    g_object_set_data(tbl, "line_segment_list_blocked", GINT_TO_POINTER(FALSE));
 
5897
}
 
5898
 
 
5899
static void sp_lpetool_change_line_segment_type(EgeSelectOneAction* act, GObject* tbl)
 
5900
{
 
5901
    using namespace Inkscape::LivePathEffect;
 
5902
 
 
5903
    // quit if run by the attr_changed listener
 
5904
    if (g_object_get_data(tbl, "freeze")) {
 
5905
        return;
 
5906
    }
 
5907
 
 
5908
    // in turn, prevent listener from responding
 
5909
    g_object_set_data(tbl, "freeze", GINT_TO_POINTER(TRUE));
 
5910
 
 
5911
    LPELineSegment *lpe = static_cast<LPELineSegment *>(g_object_get_data(tbl, "currentlpe"));
 
5912
    SPLPEItem *lpeitem = static_cast<SPLPEItem *>(g_object_get_data(tbl, "currentlpeitem"));
 
5913
    if (lpeitem) {
 
5914
        SPLPEItem *lpeitem = static_cast<SPLPEItem *>(g_object_get_data(tbl, "currentlpeitem"));
 
5915
        lpe->end_type.param_set_value(static_cast<Inkscape::LivePathEffect::EndType>(ege_select_one_action_get_active(act)));
 
5916
        sp_lpe_item_update_patheffect(lpeitem, true, true);
 
5917
    }
 
5918
 
 
5919
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 
5920
}
 
5921
 
 
5922
static void lpetool_open_lpe_dialog(GtkToggleAction *act, gpointer data)
 
5923
{
 
5924
    SPDesktop *desktop = static_cast<SPDesktop *>(data);
 
5925
 
 
5926
    if (tools_isactive(desktop, TOOLS_LPETOOL)) {
 
5927
        sp_action_perform(Inkscape::Verb::get(SP_VERB_DIALOG_LIVE_PATH_EFFECT)->get_action(desktop), NULL);
 
5928
    }
 
5929
    gtk_toggle_action_set_active(act, false);
 
5930
}
 
5931
 
 
5932
static void sp_lpetool_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
 
5933
{
 
5934
    UnitTracker* tracker = new UnitTracker(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
 
5935
    tracker->setActiveUnit(sp_desktop_namedview(desktop)->doc_units);
 
5936
    g_object_set_data(holder, "tracker", tracker);
 
5937
    SPUnit const *unit = tracker->getActiveUnit();
 
5938
 
 
5939
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
5940
    prefs->setInt("/tools/lpetool/unitid", unit->unit_id);
 
5941
 
 
5942
    /** Automatically create a list of LPEs that get added to the toolbar **/
 
5943
    {
 
5944
        GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
 
5945
 
 
5946
        GtkTreeIter iter;
 
5947
 
 
5948
        // the first toggle button represents the state that no subtool is active (remove this when
 
5949
        // this can be modeled by EgeSelectOneAction or some other action)
 
5950
        gtk_list_store_append( model, &iter );
 
5951
        gtk_list_store_set( model, &iter,
 
5952
                            0, _("All inactive"),
 
5953
                            1, _("No geometric tool is active"),
 
5954
                            2, "draw-geometry-inactive",
 
5955
                            -1 );
 
5956
 
 
5957
        Inkscape::LivePathEffect::EffectType type;
 
5958
        for (int i = 1; i < num_subtools; ++i) { // we start with i = 1 because INVALID_LPE was already added
 
5959
            type =  lpesubtools[i].type;
 
5960
            gtk_list_store_append( model, &iter );
 
5961
            gtk_list_store_set( model, &iter,
 
5962
                                0, Inkscape::LivePathEffect::LPETypeConverter.get_label(type).c_str(),
 
5963
                                1, Inkscape::LivePathEffect::LPETypeConverter.get_label(type).c_str(),
 
5964
                                2, lpesubtools[i].icon_name,
 
5965
                                -1 );
 
5966
        }
 
5967
 
 
5968
        EgeSelectOneAction* act = ege_select_one_action_new( "LPEToolModeAction", (""), (""), NULL, GTK_TREE_MODEL(model) );
 
5969
        gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
 
5970
        g_object_set_data( holder, "lpetool_mode_action", act );
 
5971
 
 
5972
        ege_select_one_action_set_appearance( act, "full" );
 
5973
        ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
 
5974
        g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
 
5975
        ege_select_one_action_set_icon_column( act, 2 );
 
5976
        ege_select_one_action_set_tooltip_column( act, 1  );
 
5977
 
 
5978
        gint lpeToolMode = prefs->getInt("/tools/lpetool/mode", 0);
 
5979
        ege_select_one_action_set_active( act, lpeToolMode );
 
5980
        g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_lpetool_mode_changed), holder );
 
5981
    }
 
5982
 
 
5983
    /* Show limiting bounding box */
 
5984
    {
 
5985
        InkToggleAction* act = ink_toggle_action_new( "LPEShowBBoxAction",
 
5986
                                                      _("Show limiting bounding box"),
 
5987
                                                      _("Show bounding box (used to cut infinite lines)"),
 
5988
                                                      "show-bounding-box",
 
5989
                                                      Inkscape::ICON_SIZE_DECORATION );
 
5990
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
5991
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(lpetool_toggle_show_bbox), desktop );
 
5992
        gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool( "/tools/lpetool/show_bbox", true ) );
 
5993
    }
 
5994
 
 
5995
    /* Set limiting bounding box to bbox of current selection */
 
5996
    {
 
5997
        InkToggleAction* act = ink_toggle_action_new( "LPEBBoxFromSelectionAction",
 
5998
                                                      _("Get limiting bounding box from selection"),
 
5999
                                                      _("Set limiting bounding box (used to cut infinite lines) to the bounding box of current selection"),
 
6000
                                                      "draw-geometry-set-bounding-box",
 
6001
                                                      Inkscape::ICON_SIZE_DECORATION );
 
6002
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
6003
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(lpetool_toggle_set_bbox), desktop );
 
6004
        gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), FALSE );
 
6005
    }
 
6006
 
 
6007
 
 
6008
    /* Combo box to choose line segment type */
 
6009
    {
 
6010
        GtkListStore* model = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
 
6011
        EgeSelectOneAction* act = ege_select_one_action_new ("LPELineSegmentAction", "" , (_("Choose a line segment type")), NULL, GTK_TREE_MODEL(model));
 
6012
        ege_select_one_action_set_appearance (act, "compact");
 
6013
        g_object_set_data (holder, "lpetool_line_segment_action", act );
 
6014
 
 
6015
        g_object_set_data(holder, "line_segment_list_blocked", GINT_TO_POINTER(FALSE));
 
6016
 
 
6017
        sp_line_segment_build_list (holder);
 
6018
 
 
6019
        g_signal_connect(G_OBJECT(act), "changed", G_CALLBACK(sp_lpetool_change_line_segment_type), holder);
 
6020
        gtk_action_set_sensitive( GTK_ACTION(act), FALSE );
 
6021
        gtk_action_group_add_action(mainActions, GTK_ACTION(act));
 
6022
    }
 
6023
 
 
6024
    /* Display measuring info for selected items */
 
6025
    {
 
6026
        InkToggleAction* act = ink_toggle_action_new( "LPEMeasuringAction",
 
6027
                                                      _("Display measuring info"),
 
6028
                                                      _("Display measuring info for selected items"),
 
6029
                                                      "draw-geometry-show-measuring-info",
 
6030
                                                      Inkscape::ICON_SIZE_DECORATION );
 
6031
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
6032
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(lpetool_toggle_show_measuring_info), holder );
 
6033
        gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool( "/tools/lpetool/show_measuring_info", true ) );
 
6034
    }
 
6035
 
 
6036
    // add the units menu
 
6037
    {
 
6038
        GtkAction* act = tracker->createAction( "LPEToolUnitsAction", _("Units"), ("") );
 
6039
        gtk_action_group_add_action( mainActions, act );
 
6040
        g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(lpetool_unit_changed), (GObject*)holder );
 
6041
        g_object_set_data(holder, "lpetool_units_action", act);
 
6042
        gtk_action_set_sensitive(act, prefs->getBool("/tools/lpetool/show_measuring_info", true));
 
6043
    }
 
6044
 
 
6045
    /* Open LPE dialog (to adapt parameters numerically) */
 
6046
    {
 
6047
        InkToggleAction* act = ink_toggle_action_new( "LPEOpenLPEDialogAction",
 
6048
                                                      _("Open LPE dialog"),
 
6049
                                                      _("Open LPE dialog (to adapt parameters numerically)"),
 
6050
                                                      "dialog-geometry",
 
6051
                                                      Inkscape::ICON_SIZE_DECORATION );
 
6052
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
6053
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(lpetool_open_lpe_dialog), desktop );
 
6054
        gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), FALSE );
 
6055
    }
 
6056
 
 
6057
    //watch selection
 
6058
    Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISNodeToolbox");
 
6059
 
 
6060
    sigc::connection *c_selection_modified =
 
6061
        new sigc::connection (sp_desktop_selection (desktop)->connectModified
 
6062
                              (sigc::bind (sigc::ptr_fun (sp_lpetool_toolbox_sel_modified), (GObject*)holder)));
 
6063
    pool->add_connection ("selection-modified", c_selection_modified);
 
6064
 
 
6065
    sigc::connection *c_selection_changed =
 
6066
        new sigc::connection (sp_desktop_selection (desktop)->connectChanged
 
6067
                              (sigc::bind (sigc::ptr_fun(sp_lpetool_toolbox_sel_changed), (GObject*)holder)));
 
6068
    pool->add_connection ("selection-changed", c_selection_changed);
 
6069
}
 
6070
 
 
6071
//########################
 
6072
//##       Eraser       ##
 
6073
//########################
 
6074
 
 
6075
static void sp_erc_width_value_changed( GtkAdjustment *adj, GObject *tbl )
 
6076
{
 
6077
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
6078
    prefs->setDouble( "/tools/eraser/width", adj->value );
 
6079
    update_presets_list(tbl);
 
6080
}
 
6081
 
 
6082
static void sp_erasertb_mode_changed( EgeSelectOneAction *act, GObject *tbl )
 
6083
{
 
6084
    SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
 
6085
    bool eraserMode = ege_select_one_action_get_active( act ) != 0;
 
6086
    if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
 
6087
        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
6088
        prefs->setBool( "/tools/eraser/mode", eraserMode );
 
6089
    }
 
6090
 
 
6091
    // only take action if run by the attr_changed listener
 
6092
    if (!g_object_get_data( tbl, "freeze" )) {
 
6093
        // in turn, prevent listener from responding
 
6094
        g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
 
6095
 
 
6096
        if ( eraserMode != 0 ) {
 
6097
        } else {
 
6098
        }
 
6099
        // TODO finish implementation
 
6100
 
 
6101
        g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 
6102
    }
 
6103
}
 
6104
 
 
6105
static void sp_eraser_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
 
6106
{
 
6107
    {
 
6108
        /* Width */
 
6109
        gchar const* labels[] = {_("(hairline)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad stroke)")};
 
6110
        gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
 
6111
        EgeAdjustmentAction *eact = create_adjustment_action( "EraserWidthAction",
 
6112
                                                              _("Pen Width"), _("Width:"),
 
6113
                                                              _("The width of the eraser pen (relative to the visible canvas area)"),
 
6114
                                                              "/tools/eraser/width", 15,
 
6115
                                                              GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-eraser",
 
6116
                                                              1, 100, 1.0, 10.0,
 
6117
                                                              labels, values, G_N_ELEMENTS(labels),
 
6118
                                                              sp_erc_width_value_changed, 1, 0);
 
6119
        ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
 
6120
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
6121
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
6122
    }
 
6123
 
 
6124
    {
 
6125
        GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
 
6126
 
 
6127
        GtkTreeIter iter;
 
6128
        gtk_list_store_append( model, &iter );
 
6129
        gtk_list_store_set( model, &iter,
 
6130
                            0, _("Delete"),
 
6131
                            1, _("Delete objects touched by the eraser"),
 
6132
                            2, INKSCAPE_ICON_DRAW_ERASER_DELETE_OBJECTS,
 
6133
                            -1 );
 
6134
 
 
6135
        gtk_list_store_append( model, &iter );
 
6136
        gtk_list_store_set( model, &iter,
 
6137
                            0, _("Cut"),
 
6138
                            1, _("Cut out from objects"),
 
6139
                            2, INKSCAPE_ICON_PATH_DIFFERENCE,
 
6140
                            -1 );
 
6141
 
 
6142
        EgeSelectOneAction* act = ege_select_one_action_new( "EraserModeAction", (""), (""), NULL, GTK_TREE_MODEL(model) );
 
6143
        gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
 
6144
        g_object_set_data( holder, "eraser_mode_action", act );
 
6145
 
 
6146
        ege_select_one_action_set_appearance( act, "full" );
 
6147
        ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
 
6148
        g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
 
6149
        ege_select_one_action_set_icon_column( act, 2 );
 
6150
        ege_select_one_action_set_tooltip_column( act, 1  );
 
6151
 
 
6152
        /// @todo Convert to boolean?
 
6153
        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
6154
        gint eraserMode = prefs->getBool("/tools/eraser/mode") ? 1 : 0;
 
6155
        ege_select_one_action_set_active( act, eraserMode );
 
6156
        g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_erasertb_mode_changed), holder );
 
6157
    }
 
6158
 
 
6159
}
 
6160
 
 
6161
//########################
 
6162
//##    Text Toolbox    ##
 
6163
//########################
 
6164
 
 
6165
// Functions for debugging:
 
6166
#ifdef DEBUG_TEXT
 
6167
 
 
6168
static void       sp_print_font( SPStyle *query ) {
 
6169
 
 
6170
    bool family_set   = query->text->font_family.set;
 
6171
    bool style_set    = query->font_style.set;
 
6172
    bool fontspec_set = query->text->font_specification.set;
 
6173
 
 
6174
    std::cout << "    Family set? " << family_set
 
6175
              << "    Style set? "  << style_set
 
6176
              << "    FontSpec set? " << fontspec_set
 
6177
              << std::endl;
 
6178
    std::cout << "    Family: "
 
6179
              << (query->text->font_family.value ? query->text->font_family.value : "No value")
 
6180
              << "    Style: "    <<  query->font_style.computed
 
6181
              << "    Weight: "   <<  query->font_weight.computed
 
6182
              << "    FontSpec: "
 
6183
              << (query->text->font_specification.value ? query->text->font_specification.value : "No value")
 
6184
              << std::endl;
 
6185
}
 
6186
        
 
6187
static void       sp_print_fontweight( SPStyle *query ) {
 
6188
    const gchar* names[] = {"100", "200", "300", "400", "500", "600", "700", "800", "900",
 
6189
                            "NORMAL", "BOLD", "LIGHTER", "BOLDER", "Out of range"};
 
6190
    // Missing book = 380
 
6191
    int index = query->font_weight.computed;
 
6192
    if( index < 0 || index > 13 ) index = 13;
 
6193
    std::cout << "    Weight: " << names[ index ]
 
6194
              << " (" << query->font_weight.computed << ")" << std::endl;
 
6195
 
 
6196
}
 
6197
 
 
6198
static void       sp_print_fontstyle( SPStyle *query ) {
 
6199
 
 
6200
    const gchar* names[] = {"NORMAL", "ITALIC", "OBLIQUE", "Out of range"};
 
6201
    int index = query->font_style.computed;
 
6202
    if( index < 0 || index > 3 ) index = 3;
 
6203
    std::cout << "    Style:  " << names[ index ] << std::endl;
 
6204
 
 
6205
}
 
6206
#endif
 
6207
 
 
6208
// Format family drop-down menu.
 
6209
static void cell_data_func(GtkCellLayout * /*cell_layout*/,
 
6210
                           GtkCellRenderer   *cell,
 
6211
                           GtkTreeModel      *tree_model,
 
6212
                           GtkTreeIter       *iter,
 
6213
                           gpointer           /*data*/)
 
6214
{
 
6215
    gchar *family;
 
6216
    gtk_tree_model_get(tree_model, iter, 0, &family, -1);
 
6217
    gchar *const family_escaped = g_markup_escape_text(family, -1);
 
6218
 
 
6219
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
6220
    int show_sample = prefs->getInt("/tools/text/show_sample_in_list", 1);
 
6221
    if (show_sample) {
 
6222
 
 
6223
        Glib::ustring sample = prefs->getString("/tools/text/font_sample");
 
6224
        gchar *const sample_escaped = g_markup_escape_text(sample.data(), -1);
 
6225
 
 
6226
        std::stringstream markup;
 
6227
        markup << family_escaped << "  <span foreground='gray' font_family='"
 
6228
               << family_escaped << "'>" << sample_escaped << "</span>";
 
6229
        g_object_set (G_OBJECT (cell), "markup", markup.str().c_str(), NULL);
 
6230
 
 
6231
        g_free(sample_escaped);
 
6232
    } else {
 
6233
        g_object_set (G_OBJECT (cell), "markup", family_escaped, NULL);
 
6234
    }
 
6235
    // This doesn't work for two reasons... it set both selected and not selected backgrounds
 
6236
    // to white.. which means that white foreground text is invisible. It also only effects
 
6237
    // the text region, leaving the padding untouched.
 
6238
    // g_object_set (G_OBJECT (cell), "cell-background", "white", "cell-background-set", true, NULL);
 
6239
 
 
6240
    g_free(family);
 
6241
    g_free(family_escaped);
 
6242
}
 
6243
 
 
6244
// Font family
 
6245
static void sp_text_fontfamily_value_changed( Ink_ComboBoxEntry_Action *act, GObject *tbl )
 
6246
{
 
6247
#ifdef DEBUG_TEXT
 
6248
    std::cout << std::endl;
 
6249
    std::cout << "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" << std::endl;
 
6250
    std::cout << "sp_text_fontfamily_value_changed: " << std::endl;
 
6251
#endif
 
6252
 
 
6253
     // quit if run by the _changed callbacks
 
6254
    if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
 
6255
        return;
 
6256
    }
 
6257
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
 
6258
 
 
6259
    gchar *family = ink_comboboxentry_action_get_active_text( act );
 
6260
#ifdef DEBUG_TEXT
 
6261
    std::cout << "  New family: " << family << std::endl;
 
6262
#endif
 
6263
 
 
6264
    // First try to get the old font spec from the stored value
 
6265
    SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT);
 
6266
    int result_fontspec = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
 
6267
 
 
6268
    Glib::ustring fontSpec = query->text->font_specification.set ?  query->text->font_specification.value : "";
 
6269
 
 
6270
    // If that didn't work, try to get font spec from style
 
6271
    if (fontSpec.empty()) {
 
6272
 
 
6273
        // Must query all to fill font-family, font-style, font-weight, font-specification
 
6274
        sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
 
6275
        sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
 
6276
        sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
 
6277
 
 
6278
        // Construct a new font specification if it does not yet exist
 
6279
        font_instance * fontFromStyle = font_factory::Default()->FaceFromStyle(query);
 
6280
        if( fontFromStyle ) {
 
6281
            fontSpec = font_factory::Default()->ConstructFontSpecification(fontFromStyle);
 
6282
            fontFromStyle->Unref();
 
6283
        }
 
6284
#ifdef DEBUG_TEXT
 
6285
        std::cout << "  Fontspec not defined, reconstructed from style :" << fontSpec << ":" << std::endl;
 
6286
        sp_print_font( query );
 
6287
#endif
 
6288
    }
 
6289
 
 
6290
    // And if that didn't work use default
 
6291
    if( fontSpec.empty() ) {
 
6292
        sp_style_read_from_prefs(query, "/tools/text");
 
6293
#ifdef DEBUG_TEXT
 
6294
        std::cout << "    read style from prefs:" << std::endl;
 
6295
        sp_print_font( query );
 
6296
#endif
 
6297
        // Construct a new font specification if it does not yet exist
 
6298
        font_instance * fontFromStyle = font_factory::Default()->FaceFromStyle(query);
 
6299
        if( fontFromStyle ) {
 
6300
            fontSpec = font_factory::Default()->ConstructFontSpecification(fontFromStyle);
 
6301
            fontFromStyle->Unref();
 
6302
        }
 
6303
#ifdef DEBUG_TEXT
 
6304
        std::cout << "  Fontspec not defined, reconstructed from style :" << fontSpec << ":" << std::endl;
 
6305
        sp_print_font( query );
 
6306
#endif
 
6307
    }
 
6308
 
 
6309
    SPCSSAttr *css = sp_repr_css_attr_new ();
 
6310
    if (!fontSpec.empty()) {
 
6311
 
 
6312
        // Now we have a font specification, replace family.
 
6313
        Glib::ustring  newFontSpec = font_factory::Default()->ReplaceFontSpecificationFamily(fontSpec, family);
 
6314
 
 
6315
#ifdef DEBUG_TEXT
 
6316
        std::cout << "  New FontSpec from ReplaceFontSpecificationFamily :" << newFontSpec << ":" << std::endl;
 
6317
#endif
 
6318
 
 
6319
        if (!newFontSpec.empty()) {
 
6320
 
 
6321
            if (fontSpec != newFontSpec) {
 
6322
 
 
6323
                font_instance *font = font_factory::Default()->FaceFromFontSpecification(newFontSpec.c_str());
 
6324
 
 
6325
                if (font) {
 
6326
                    sp_repr_css_set_property (css, "-inkscape-font-specification", newFontSpec.c_str());
 
6327
 
 
6328
                    // Set all the these just in case they were altered when finding the best
 
6329
                    // match for the new family and old style...
 
6330
 
 
6331
                    gchar c[256];
 
6332
 
 
6333
                    font->Family(c, 256);
 
6334
 
 
6335
                    sp_repr_css_set_property (css, "font-family", c);
 
6336
 
 
6337
                    font->Attribute( "weight", c, 256);
 
6338
                    sp_repr_css_set_property (css, "font-weight", c);
 
6339
 
 
6340
                    font->Attribute("style", c, 256);
 
6341
                    sp_repr_css_set_property (css, "font-style", c);
 
6342
 
 
6343
                    font->Attribute("stretch", c, 256);
 
6344
                    sp_repr_css_set_property (css, "font-stretch", c);
 
6345
 
 
6346
                    font->Attribute("variant", c, 256);
 
6347
                    sp_repr_css_set_property (css, "font-variant", c);
 
6348
 
 
6349
                    font->Unref();
 
6350
                }
 
6351
            }
 
6352
 
 
6353
        } else {
 
6354
 
 
6355
            // newFontSpec empty
 
6356
            // If the old font on selection (or default) does not exist on the system,
 
6357
            // or the new font family does not exist,
 
6358
            // ReplaceFontSpecificationFamily does not work. In that case we fall back to blindly
 
6359
            // setting the family reported by the family chooser.
 
6360
 
 
6361
            // g_print ("fallback setting family: %s\n", family);
 
6362
            sp_repr_css_set_property (css, "-inkscape-font-specification", family);
 
6363
            sp_repr_css_set_property (css, "font-family", family);
 
6364
            // Shoud we set other css font attributes?
 
6365
        }
 
6366
 
 
6367
    }  // fontSpec not empty or not
 
6368
 
 
6369
    // If querying returned nothing, update default style.
 
6370
    if (result_fontspec == QUERY_STYLE_NOTHING)
 
6371
    {
 
6372
        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
6373
        prefs->mergeStyle("/tools/text/style", css);
 
6374
        sp_text_edit_dialog_default_set_insensitive (); //FIXME: Replace through a verb
 
6375
    }
 
6376
    else
 
6377
    {
 
6378
        sp_desktop_set_style (SP_ACTIVE_DESKTOP, css, true, true);
 
6379
    }
 
6380
 
 
6381
    sp_style_unref(query);
 
6382
 
 
6383
    g_free (family);
 
6384
 
 
6385
    // Save for undo
 
6386
    if (result_fontspec != QUERY_STYLE_NOTHING) {
 
6387
        sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
 
6388
                       _("Text: Change font family"));
 
6389
    }
 
6390
    sp_repr_css_attr_unref (css);
 
6391
 
 
6392
    // unfreeze
 
6393
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 
6394
 
 
6395
    // focus to canvas
 
6396
    gtk_widget_grab_focus (GTK_WIDGET((SP_ACTIVE_DESKTOP)->canvas));
 
6397
 
 
6398
#ifdef DEBUG_TEXT
 
6399
    std::cout << "sp_text_toolbox_fontfamily_changes: exit"  << std::endl;
 
6400
    std::cout << "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" << std::endl;
 
6401
    std::cout << std::endl;
 
6402
#endif
 
6403
}
 
6404
 
 
6405
// Font size
 
6406
static void sp_text_fontsize_value_changed( Ink_ComboBoxEntry_Action *act, GObject *tbl )
 
6407
{
 
6408
     // quit if run by the _changed callbacks
 
6409
    if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
 
6410
        return;
 
6411
    }
 
6412
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
 
6413
 
 
6414
    gchar *text = ink_comboboxentry_action_get_active_text( act );
 
6415
    gchar *endptr;
 
6416
    gdouble size = g_strtod( text, &endptr );
 
6417
    if (endptr == text) {  // Conversion failed, non-numeric input.
 
6418
        g_warning( "Conversion of size text to double failed, input: %s\n", text );
 
6419
        g_free( text );
 
6420
        return;
 
6421
    }
 
6422
    g_free( text );
 
6423
 
 
6424
    // Set css font size.
 
6425
    SPCSSAttr *css = sp_repr_css_attr_new ();
 
6426
    Inkscape::CSSOStringStream osfs;
 
6427
    osfs << size << "px"; // For now always use px
 
6428
    sp_repr_css_set_property (css, "font-size", osfs.str().c_str());
 
6429
 
 
6430
    // Apply font size to selected objects.
 
6431
    SPDesktop *desktop = SP_ACTIVE_DESKTOP;
 
6432
    sp_desktop_set_style (desktop, css, true, true);
 
6433
 
 
6434
    // If no selected objects, set default.
 
6435
    SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT);
 
6436
    int result_numbers =
 
6437
        sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
 
6438
    if (result_numbers == QUERY_STYLE_NOTHING)
 
6439
    {
 
6440
        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
6441
        prefs->mergeStyle("/tools/text/style", css);
 
6442
    } else {
 
6443
        // Save for undo
 
6444
        sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "ttb:size", SP_VERB_NONE,
 
6445
                             _("Text: Change font size"));
 
6446
    }
 
6447
 
 
6448
    sp_style_unref(query);
 
6449
 
 
6450
    sp_repr_css_attr_unref (css);
 
6451
 
 
6452
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 
6453
}
 
6454
 
 
6455
// Handles both Bold and Italic/Oblique
 
6456
static void sp_text_style_changed( InkToggleAction* act, GObject *tbl )
 
6457
{
 
6458
    // quit if run by the _changed callbacks
 
6459
    if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
 
6460
        return;
 
6461
    }
 
6462
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
 
6463
 
 
6464
    // Called by Bold or Italics button?
 
6465
    const gchar* name = gtk_action_get_name( GTK_ACTION( act ) );
 
6466
    gint prop = (strcmp(name, "TextBoldAction") == 0) ? 0 : 1;
 
6467
 
 
6468
    // First query font-specification, this is the most complete font face description.
 
6469
    SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT);
 
6470
    int result_fontspec = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
 
6471
 
 
6472
    // font_specification will not be set unless defined explicitely on a tspan.
 
6473
    // This should be fixed!
 
6474
    Glib::ustring fontSpec = query->text->font_specification.set ?  query->text->font_specification.value : "";
 
6475
 
 
6476
    if (fontSpec.empty()) {
 
6477
        // Construct a new font specification if it does not yet exist
 
6478
        // Must query font-family, font-style, font-weight, to find correct font face.
 
6479
        sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
 
6480
        sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
 
6481
        sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
 
6482
 
 
6483
        font_instance * fontFromStyle = font_factory::Default()->FaceFromStyle(query);
 
6484
        if( fontFromStyle ) {
 
6485
            fontSpec = font_factory::Default()->ConstructFontSpecification(fontFromStyle);
 
6486
            fontFromStyle->Unref();
 
6487
        }
 
6488
    }
 
6489
 
 
6490
    // Now that we have the old face, find the new face.
 
6491
    Glib::ustring newFontSpec = "";
 
6492
    SPCSSAttr   *css        = sp_repr_css_attr_new ();
 
6493
    gboolean nochange = true;
 
6494
    gboolean active = gtk_toggle_action_get_active( GTK_TOGGLE_ACTION(act) );
 
6495
 
 
6496
    switch (prop)
 
6497
    {
 
6498
        case 0:
 
6499
        {
 
6500
            // Bold
 
6501
            if (!fontSpec.empty()) {
 
6502
 
 
6503
                newFontSpec = font_factory::Default()->FontSpecificationSetBold(fontSpec, active);
 
6504
 
 
6505
                if (!newFontSpec.empty()) {
 
6506
 
 
6507
                    // Set weight if we found font.
 
6508
                    font_instance * font = font_factory::Default()->FaceFromFontSpecification(newFontSpec.c_str());
 
6509
                    if (font) {
 
6510
                        gchar c[256];
 
6511
                        font->Attribute( "weight", c, 256);
 
6512
                        sp_repr_css_set_property (css, "font-weight", c);
 
6513
                        font->Unref();
 
6514
                        font = NULL;
 
6515
                    }
 
6516
                    nochange = false;
 
6517
                }
 
6518
            }
 
6519
            // Reset button if no change.
 
6520
            // The reset code didn't work in 0.47 and doesn't here... one must prevent an infinite loop
 
6521
            /*
 
6522
            if(nochange) {
 
6523
                gtk_action_block_activate( GTK_ACTION(act) );
 
6524
                gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), !active );
 
6525
                gtk_action_unblock_activate( GTK_ACTION(act) );
 
6526
            }
 
6527
            */
 
6528
            break;
 
6529
        }
 
6530
 
 
6531
        case 1:
 
6532
        {
 
6533
            // Italic/Oblique
 
6534
            if (!fontSpec.empty()) {
 
6535
 
 
6536
                newFontSpec = font_factory::Default()->FontSpecificationSetItalic(fontSpec, active);
 
6537
 
 
6538
                if (!newFontSpec.empty()) {
 
6539
 
 
6540
                    // Don't even set the italic/oblique if the font didn't exist on the system
 
6541
                    if( active ) {
 
6542
                        if( newFontSpec.find( "Italic" ) != Glib::ustring::npos ) {
 
6543
                            sp_repr_css_set_property (css, "font-style", "italic");
 
6544
                        } else {
 
6545
                            sp_repr_css_set_property (css, "font-style", "oblique");
 
6546
                        }
 
6547
                    } else {
 
6548
                        sp_repr_css_set_property (css, "font-style", "normal");
 
6549
                    }
 
6550
                    nochange = false;
 
6551
                }
 
6552
            }
 
6553
            // Reset button if no change.
 
6554
            // The reset code didn't work in 0.47... one must prevent an infinite loop
 
6555
            /*
 
6556
            if(nochange) {
 
6557
                gtk_action_block_activate( GTK_ACTION(act) );
 
6558
                gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), !active );
 
6559
                gtk_action_unblock_activate( GTK_ACTION(act) );
 
6560
            }
 
6561
            */
 
6562
            break;
 
6563
        }
 
6564
    }
 
6565
 
 
6566
    if (!newFontSpec.empty()) {
 
6567
        sp_repr_css_set_property (css, "-inkscape-font-specification", newFontSpec.c_str());
 
6568
    }
 
6569
 
 
6570
    // If querying returned nothing, update default style.
 
6571
    if (result_fontspec == QUERY_STYLE_NOTHING)
 
6572
    {
 
6573
        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
6574
        prefs->mergeStyle("/tools/text/style", css);
 
6575
    }
 
6576
 
 
6577
    sp_style_unref(query);
 
6578
 
 
6579
    // Do we need to update other CSS values?
 
6580
    SPDesktop   *desktop    = SP_ACTIVE_DESKTOP;
 
6581
    sp_desktop_set_style (desktop, css, true, true);
 
6582
    if (result_fontspec != QUERY_STYLE_NOTHING) {
 
6583
        sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
 
6584
                       _("Text: Change font style"));
 
6585
    }
 
6586
    sp_repr_css_attr_unref (css);
 
6587
 
 
6588
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 
6589
}
 
6590
 
 
6591
// Handles both Superscripts and Subscripts
 
6592
static void sp_text_script_changed( InkToggleAction* act, GObject *tbl )
 
6593
{
 
6594
    // quit if run by the _changed callbacks
 
6595
    if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
 
6596
        return;
 
6597
    }
 
6598
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
 
6599
 
 
6600
    // Called by Superscript or Subscript button?
 
6601
    const gchar* name = gtk_action_get_name( GTK_ACTION( act ) );
 
6602
    gint prop = (strcmp(name, "TextSuperscriptAction") == 0) ? 0 : 1;
 
6603
 
 
6604
#ifdef DEBUG_TEXT
 
6605
    std::cout << "sp_text_script_changed: " << prop << std::endl;
 
6606
#endif
 
6607
 
 
6608
    // Query baseline
 
6609
    SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT);
 
6610
    int result_baseline = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_BASELINES);
 
6611
 
 
6612
    bool setSuper = false;
 
6613
    bool setSub   = false;
 
6614
 
 
6615
    if(result_baseline == QUERY_STYLE_NOTHING || result_baseline == QUERY_STYLE_MULTIPLE_DIFFERENT ) {
 
6616
        // If not set or mixed, turn on superscript or subscript
 
6617
        if( prop == 0 ) {
 
6618
            setSuper = true;
 
6619
        } else {
 
6620
            setSub = true;
 
6621
        }
 
6622
    } else {
 
6623
        // Superscript
 
6624
        gboolean superscriptSet = (query->baseline_shift.set &&
 
6625
                                   query->baseline_shift.type == SP_BASELINE_SHIFT_LITERAL &&
 
6626
                                   query->baseline_shift.literal == SP_CSS_BASELINE_SHIFT_SUPER );
 
6627
 
 
6628
        // Subscript
 
6629
        gboolean subscriptSet = (query->baseline_shift.set &&
 
6630
                                 query->baseline_shift.type == SP_BASELINE_SHIFT_LITERAL &&
 
6631
                                 query->baseline_shift.literal == SP_CSS_BASELINE_SHIFT_SUB );
 
6632
 
 
6633
        setSuper = !superscriptSet && prop == 0;
 
6634
        setSub   = !subscriptSet   && prop == 1;
 
6635
    }
 
6636
 
 
6637
    // Set css properties
 
6638
    SPCSSAttr *css = sp_repr_css_attr_new ();
 
6639
    if( setSuper || setSub ) {
 
6640
        // Openoffice 2.3 and Adobe use 58%, Microsoft Word 2002 uses 65%, LaTex about 70%.
 
6641
        // 58% looks too small to me, especially if a superscript is placed on a superscript.
 
6642
        // If you make a change here, consider making a change to baseline-shift amount
 
6643
        // in style.cpp.
 
6644
        sp_repr_css_set_property (css, "font-size", "65%");
 
6645
    } else {
 
6646
        sp_repr_css_set_property (css, "font-size", "");
 
6647
    }
 
6648
    if( setSuper ) {
 
6649
        sp_repr_css_set_property (css, "baseline-shift", "super");
 
6650
    } else if( setSub ) {
 
6651
        sp_repr_css_set_property (css, "baseline-shift", "sub");
 
6652
    } else {
 
6653
        sp_repr_css_set_property (css, "baseline-shift", "baseline");
 
6654
    }
 
6655
 
 
6656
    // Apply css to selected objects.
 
6657
    SPDesktop *desktop = SP_ACTIVE_DESKTOP;
 
6658
    sp_desktop_set_style (desktop, css, true, false);
 
6659
 
 
6660
    // Save for undo
 
6661
    if(result_baseline != QUERY_STYLE_NOTHING) {
 
6662
        sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "ttb:script", SP_VERB_NONE,
 
6663
                             _("Text: Change superscript or subscript"));
 
6664
    }
 
6665
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 
6666
}
 
6667
 
 
6668
static void sp_text_align_mode_changed( EgeSelectOneAction *act, GObject *tbl )
 
6669
{
 
6670
    // quit if run by the _changed callbacks
 
6671
    if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
 
6672
        return;
 
6673
    }
 
6674
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
 
6675
 
 
6676
    int mode = ege_select_one_action_get_active( act );
 
6677
 
 
6678
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
6679
    prefs->setInt("/tools/text/align_mode", mode);
 
6680
 
 
6681
    SPDesktop *desktop = SP_ACTIVE_DESKTOP;
 
6682
 
 
6683
    // move the x of all texts to preserve the same bbox
 
6684
    Inkscape::Selection *selection = sp_desktop_selection(desktop);
 
6685
    for (GSList const *items = selection->itemList(); items != NULL; items = items->next) {
 
6686
        if (SP_IS_TEXT((SPItem *) items->data)) {
 
6687
            SPItem *item = SP_ITEM(items->data);
 
6688
 
 
6689
            unsigned writing_mode = SP_OBJECT_STYLE(item)->writing_mode.value;
 
6690
            // below, variable names suggest horizontal move, but we check the writing direction
 
6691
            // and move in the corresponding axis
 
6692
            int axis;
 
6693
            if (writing_mode == SP_CSS_WRITING_MODE_LR_TB || writing_mode == SP_CSS_WRITING_MODE_RL_TB) {
 
6694
                axis = NR::X;
 
6695
            } else {
 
6696
                axis = NR::Y;
 
6697
            }
 
6698
 
 
6699
            Geom::OptRect bbox
 
6700
                  = item->getBounds(Geom::identity(), SPItem::GEOMETRIC_BBOX);
 
6701
            if (!bbox)
 
6702
                continue;
 
6703
            double width = bbox->dimensions()[axis];
 
6704
            // If you want to align within some frame, other than the text's own bbox, calculate
 
6705
            // the left and right (or top and bottom for tb text) slacks of the text inside that
 
6706
            // frame (currently unused)
 
6707
            double left_slack = 0;
 
6708
            double right_slack = 0;
 
6709
            unsigned old_align = SP_OBJECT_STYLE(item)->text_align.value;
 
6710
            double move = 0;
 
6711
            if (old_align == SP_CSS_TEXT_ALIGN_START || old_align == SP_CSS_TEXT_ALIGN_LEFT) {
 
6712
                switch (mode) {
 
6713
                    case 0:
 
6714
                        move = -left_slack;
 
6715
                        break;
 
6716
                    case 1:
 
6717
                        move = width/2 + (right_slack - left_slack)/2;
 
6718
                        break;
 
6719
                    case 2:
 
6720
                        move = width + right_slack;
 
6721
                        break;
 
6722
                }
 
6723
            } else if (old_align == SP_CSS_TEXT_ALIGN_CENTER) {
 
6724
                switch (mode) {
 
6725
                    case 0:
 
6726
                        move = -width/2 - left_slack;
 
6727
                        break;
 
6728
                    case 1:
 
6729
                        move = (right_slack - left_slack)/2;
 
6730
                        break;
 
6731
                    case 2:
 
6732
                        move = width/2 + right_slack;
 
6733
                        break;
 
6734
                }
 
6735
            } else if (old_align == SP_CSS_TEXT_ALIGN_END || old_align == SP_CSS_TEXT_ALIGN_RIGHT) {
 
6736
                switch (mode) {
 
6737
                    case 0:
 
6738
                        move = -width - left_slack;
 
6739
                        break;
 
6740
                    case 1:
 
6741
                        move = -width/2 + (right_slack - left_slack)/2;
 
6742
                        break;
 
6743
                    case 2:
 
6744
                        move = right_slack;
 
6745
                        break;
 
6746
                }
 
6747
            }
 
6748
            Geom::Point XY = SP_TEXT(item)->attributes.firstXY();
 
6749
            if (axis == NR::X) {
 
6750
                XY = XY + Geom::Point (move, 0);
 
6751
            } else {
 
6752
                XY = XY + Geom::Point (0, move);
 
6753
            }
 
6754
            SP_TEXT(item)->attributes.setFirstXY(XY);
 
6755
            SP_OBJECT(item)->updateRepr();
 
6756
            SP_OBJECT(item)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
 
6757
        }
 
6758
    }
 
6759
 
 
6760
    SPCSSAttr *css = sp_repr_css_attr_new ();
 
6761
    switch (mode)
 
6762
    {
 
6763
        case 0:
 
6764
        {
 
6765
            sp_repr_css_set_property (css, "text-anchor", "start");
 
6766
            sp_repr_css_set_property (css, "text-align", "start");
 
6767
            break;
 
6768
        }
 
6769
        case 1:
 
6770
        {
 
6771
            sp_repr_css_set_property (css, "text-anchor", "middle");
 
6772
            sp_repr_css_set_property (css, "text-align", "center");
 
6773
            break;
 
6774
        }
 
6775
 
 
6776
        case 2:
 
6777
        {
 
6778
            sp_repr_css_set_property (css, "text-anchor", "end");
 
6779
            sp_repr_css_set_property (css, "text-align", "end");
 
6780
            break;
 
6781
        }
 
6782
 
 
6783
        case 3:
 
6784
        {
 
6785
            sp_repr_css_set_property (css, "text-anchor", "start");
 
6786
            sp_repr_css_set_property (css, "text-align", "justify");
 
6787
            break;
 
6788
        }
 
6789
    }
 
6790
 
 
6791
    SPStyle *query =
 
6792
        sp_style_new (SP_ACTIVE_DOCUMENT);
 
6793
    int result_numbers =
 
6794
        sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
 
6795
 
 
6796
    // If querying returned nothing, update default style.
 
6797
    if (result_numbers == QUERY_STYLE_NOTHING)
 
6798
    {
 
6799
        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
6800
        prefs->mergeStyle("/tools/text/style", css);
 
6801
    }
 
6802
 
 
6803
    sp_style_unref(query);
 
6804
 
 
6805
    sp_desktop_set_style (desktop, css, true, true);
 
6806
    if (result_numbers != QUERY_STYLE_NOTHING)
 
6807
    {
 
6808
        sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
 
6809
                                   _("Text: Change alignment"));
 
6810
    }
 
6811
    sp_repr_css_attr_unref (css);
 
6812
 
 
6813
    gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
 
6814
 
 
6815
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 
6816
}
 
6817
 
 
6818
static void sp_text_lineheight_value_changed( GtkAdjustment *adj, GObject *tbl )
 
6819
{
 
6820
    // quit if run by the _changed callbacks
 
6821
    if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
 
6822
        return;
 
6823
    }
 
6824
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
 
6825
 
 
6826
    // At the moment this handles only numerical values (i.e. no percent).
 
6827
    // Set css line height.
 
6828
    SPCSSAttr *css = sp_repr_css_attr_new ();
 
6829
    Inkscape::CSSOStringStream osfs;
 
6830
    osfs << adj->value*100 << "%";
 
6831
    sp_repr_css_set_property (css, "line-height", osfs.str().c_str());
 
6832
 
 
6833
    // Apply line-height to selected objects.
 
6834
    SPDesktop *desktop = SP_ACTIVE_DESKTOP;
 
6835
    sp_desktop_set_style (desktop, css, true, false);
 
6836
 
 
6837
 
 
6838
    // Until deprecated sodipodi:linespacing purged:
 
6839
    Inkscape::Selection *selection = sp_desktop_selection(desktop);
 
6840
    GSList const *items = selection->itemList();
 
6841
    bool modmade = false;
 
6842
    for (; items != NULL; items = items->next) {
 
6843
        if (SP_IS_TEXT (items->data)) {
 
6844
            SP_OBJECT_REPR(items->data)->setAttribute("sodipodi:linespacing", sp_repr_css_property (css, "line-height", NULL));
 
6845
            modmade = true;
 
6846
        }
 
6847
    }
 
6848
 
 
6849
    // Save for undo
 
6850
    if(modmade) {
 
6851
        sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "ttb:line-height", SP_VERB_NONE,
 
6852
                                   _("Text: Change line-height"));
 
6853
    }
 
6854
 
 
6855
    // If no selected objects, set default.
 
6856
    SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT);
 
6857
    int result_numbers =
 
6858
        sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
 
6859
    if (result_numbers == QUERY_STYLE_NOTHING)
 
6860
    {
 
6861
        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
6862
        prefs->mergeStyle("/tools/text/style", css);
 
6863
    }
 
6864
    sp_style_unref(query);
 
6865
 
 
6866
    sp_repr_css_attr_unref (css);
 
6867
 
 
6868
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 
6869
}
 
6870
 
 
6871
static void sp_text_wordspacing_value_changed( GtkAdjustment *adj, GObject *tbl )
 
6872
{
 
6873
    // quit if run by the _changed callbacks
 
6874
    if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
 
6875
        return;
 
6876
    }
 
6877
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
 
6878
 
 
6879
    // At the moment this handles only numerical values (i.e. no em unit).
 
6880
    // Set css word-spacing
 
6881
    SPCSSAttr *css = sp_repr_css_attr_new ();
 
6882
    Inkscape::CSSOStringStream osfs;
 
6883
    osfs << adj->value << "px"; // For now always use px
 
6884
    sp_repr_css_set_property (css, "word-spacing", osfs.str().c_str());
 
6885
 
 
6886
    // Apply word-spacing to selected objects.
 
6887
    SPDesktop *desktop = SP_ACTIVE_DESKTOP;
 
6888
    sp_desktop_set_style (desktop, css, true, false);
 
6889
 
 
6890
    // If no selected objects, set default.
 
6891
    SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT);
 
6892
    int result_numbers =
 
6893
        sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
 
6894
    if (result_numbers == QUERY_STYLE_NOTHING)
 
6895
    {
 
6896
        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
6897
        prefs->mergeStyle("/tools/text/style", css);
 
6898
    } else {
 
6899
        // Save for undo
 
6900
        sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "ttb:word-spacing", SP_VERB_NONE,
 
6901
                             _("Text: Change word-spacing"));
 
6902
    }
 
6903
    sp_style_unref(query);
 
6904
 
 
6905
    sp_repr_css_attr_unref (css);
 
6906
 
 
6907
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 
6908
}
 
6909
 
 
6910
static void sp_text_letterspacing_value_changed( GtkAdjustment *adj, GObject *tbl )
 
6911
{
 
6912
    // quit if run by the _changed callbacks
 
6913
    if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
 
6914
        return;
 
6915
    }
 
6916
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
 
6917
 
 
6918
    // At the moment this handles only numerical values (i.e. no em unit).
 
6919
    // Set css letter-spacing
 
6920
    SPCSSAttr *css = sp_repr_css_attr_new ();
 
6921
    Inkscape::CSSOStringStream osfs;
 
6922
    osfs << adj->value << "px";  // For now always use px
 
6923
    sp_repr_css_set_property (css, "letter-spacing", osfs.str().c_str());
 
6924
 
 
6925
    // Apply letter-spacing to selected objects.
 
6926
    SPDesktop *desktop = SP_ACTIVE_DESKTOP;
 
6927
    sp_desktop_set_style (desktop, css, true, false);
 
6928
 
 
6929
 
 
6930
    // If no selected objects, set default.
 
6931
    SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT);
 
6932
    int result_numbers =
 
6933
        sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
 
6934
    if (result_numbers == QUERY_STYLE_NOTHING)
 
6935
    {
 
6936
        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
6937
        prefs->mergeStyle("/tools/text/style", css);
 
6938
    }
 
6939
    else
 
6940
    {
 
6941
        // Save for undo
 
6942
        sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "ttb:letter-spacing", SP_VERB_NONE,
 
6943
                             _("Text: Change letter-spacing"));
 
6944
    }
 
6945
 
 
6946
    sp_style_unref(query);
 
6947
 
 
6948
    sp_repr_css_attr_unref (css);
 
6949
 
 
6950
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 
6951
}
 
6952
 
 
6953
 
 
6954
static void sp_text_dx_value_changed( GtkAdjustment *adj, GObject *tbl )
 
6955
{
 
6956
    // quit if run by the _changed callbacks
 
6957
    if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
 
6958
        return;
 
6959
    }
 
6960
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
 
6961
 
 
6962
    gdouble new_dx = adj->value;
 
6963
    bool modmade = false;
 
6964
 
 
6965
    if( SP_IS_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context) ) {
 
6966
        SPTextContext *const tc = SP_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context);
 
6967
        if( tc ) {
 
6968
            unsigned char_index = -1;
 
6969
            TextTagAttributes *attributes =
 
6970
                text_tag_attributes_at_position( tc->text, std::min(tc->text_sel_start, tc->text_sel_end), &char_index );
 
6971
            if( attributes ) {
 
6972
                double old_dx = attributes->getDx( char_index );
 
6973
                double delta_dx = new_dx - old_dx;
 
6974
                sp_te_adjust_dx( tc->text, tc->text_sel_start, tc->text_sel_end, SP_ACTIVE_DESKTOP, delta_dx );
 
6975
                modmade = true;
 
6976
            }
 
6977
        }
 
6978
    }
 
6979
 
 
6980
    if(modmade) {
 
6981
        // Save for undo
 
6982
        sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "ttb:dx", SP_VERB_NONE,
 
6983
                                   _("Text: Change dx (kern)"));
 
6984
    }
 
6985
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 
6986
}
 
6987
 
 
6988
static void sp_text_dy_value_changed( GtkAdjustment *adj, GObject *tbl )
 
6989
{
 
6990
    // quit if run by the _changed callbacks
 
6991
    if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
 
6992
        return;
 
6993
    }
 
6994
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
 
6995
 
 
6996
    gdouble new_dy = adj->value;
 
6997
    bool modmade = false;
 
6998
 
 
6999
    if( SP_IS_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context) ) {
 
7000
        SPTextContext *const tc = SP_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context);
 
7001
        if( tc ) {
 
7002
            unsigned char_index = -1;
 
7003
            TextTagAttributes *attributes =
 
7004
                text_tag_attributes_at_position( tc->text, std::min(tc->text_sel_start, tc->text_sel_end), &char_index );
 
7005
            if( attributes ) {
 
7006
                double old_dy = attributes->getDy( char_index );
 
7007
                double delta_dy = new_dy - old_dy;
 
7008
                sp_te_adjust_dy( tc->text, tc->text_sel_start, tc->text_sel_end, SP_ACTIVE_DESKTOP, delta_dy );
 
7009
                modmade = true;
 
7010
            }
 
7011
        }
 
7012
    }
 
7013
 
 
7014
    if(modmade) {
 
7015
        // Save for undo
 
7016
        sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "ttb:dy", SP_VERB_NONE,
 
7017
                            _("Text: Change dy"));
 
7018
    }
 
7019
 
 
7020
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 
7021
}
 
7022
 
 
7023
static void sp_text_rotation_value_changed( GtkAdjustment *adj, GObject *tbl )
 
7024
{
 
7025
    // quit if run by the _changed callbacks
 
7026
    if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
 
7027
        return;
 
7028
    }
 
7029
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
 
7030
 
 
7031
    gdouble new_degrees = adj->value;
 
7032
 
 
7033
    bool modmade = false;
 
7034
    if( SP_IS_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context) ) {
 
7035
        SPTextContext *const tc = SP_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context);
 
7036
        if( tc ) {
 
7037
            unsigned char_index = -1;
 
7038
            TextTagAttributes *attributes =
 
7039
                text_tag_attributes_at_position( tc->text, std::min(tc->text_sel_start, tc->text_sel_end), &char_index );
 
7040
            if( attributes ) {
 
7041
                double old_degrees = attributes->getRotate( char_index );
 
7042
                double delta_deg = new_degrees - old_degrees;
 
7043
                sp_te_adjust_rotation( tc->text, tc->text_sel_start, tc->text_sel_end, SP_ACTIVE_DESKTOP, delta_deg );
 
7044
                modmade = true;
 
7045
            }
 
7046
        }
 
7047
    }
 
7048
 
 
7049
    // Save for undo
 
7050
    if(modmade) {
 
7051
        sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "ttb:rotate", SP_VERB_NONE,
 
7052
                            _("Text: Change rotate"));
 
7053
    }
 
7054
 
 
7055
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 
7056
}
 
7057
 
 
7058
static void sp_text_orientation_mode_changed( EgeSelectOneAction *act, GObject *tbl )
 
7059
{
 
7060
    // quit if run by the _changed callbacks
 
7061
    if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
 
7062
        return;
 
7063
    }
 
7064
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
 
7065
 
 
7066
    int mode = ege_select_one_action_get_active( act );
 
7067
 
 
7068
    SPCSSAttr   *css        = sp_repr_css_attr_new ();
 
7069
    switch (mode)
 
7070
    {
 
7071
        case 0:
 
7072
        {
 
7073
            sp_repr_css_set_property (css, "writing-mode", "lr");
 
7074
            break;
 
7075
        }
 
7076
 
 
7077
        case 1:
 
7078
        {
 
7079
            sp_repr_css_set_property (css, "writing-mode", "tb");
 
7080
            break;
 
7081
        }
 
7082
    }
 
7083
 
 
7084
    SPStyle *query =
 
7085
        sp_style_new (SP_ACTIVE_DOCUMENT);
 
7086
    int result_numbers =
 
7087
        sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
 
7088
 
 
7089
    // If querying returned nothing, update default style.
 
7090
    if (result_numbers == QUERY_STYLE_NOTHING)
 
7091
    {
 
7092
        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
7093
        prefs->mergeStyle("/tools/text/style", css);
 
7094
    }
 
7095
 
 
7096
    sp_desktop_set_style (SP_ACTIVE_DESKTOP, css, true, true);
 
7097
    if(result_numbers != QUERY_STYLE_NOTHING)
 
7098
    {
 
7099
        sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
 
7100
                                   _("Text: Change orientation"));
 
7101
    }
 
7102
    sp_repr_css_attr_unref (css);
 
7103
 
 
7104
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 
7105
}
 
7106
 
 
7107
/*
 
7108
 * This function sets up the text-tool tool-controls, setting the entry boxes
 
7109
 * etc. to the values from the current selection or the default if no selection.
 
7110
 * It is called whenever a text selection is changed, including stepping cursor
 
7111
 * through text.
 
7112
 */
 
7113
static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/, GObject *tbl)
 
7114
{
 
7115
#ifdef DEBUG_TEXT
 
7116
    static int count = 0;
 
7117
    ++count;
 
7118
    std::cout << std::endl;
 
7119
    std::cout << "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&" << std::endl;
 
7120
    std::cout << "sp_text_toolbox_selection_changed: start " << count << std::endl;
 
7121
 
 
7122
    std::cout << "  Selected items:" << std::endl;
 
7123
    for (GSList const *items = sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList();
 
7124
         items != NULL;
 
7125
         items = items->next)
 
7126
    {
 
7127
        const gchar* id = SP_OBJECT_ID((SPItem *) items->data);
 
7128
        std::cout << "    " << id << std::endl;
 
7129
    }
 
7130
    Glib::ustring selected_text = sp_text_get_selected_text((SP_ACTIVE_DESKTOP)->event_context);
 
7131
    std::cout << "  Selected text:" << std::endl;
 
7132
    std::cout << selected_text << std::endl;
 
7133
#endif
 
7134
 
 
7135
    // quit if run by the _changed callbacks
 
7136
    if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
 
7137
#ifdef DEBUG_TEXT
 
7138
        std::cout << "    Frozen, returning" << std::endl;
 
7139
        std::cout << "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&" << std::endl;
 
7140
        std::cout << std::endl;
 
7141
#endif
 
7142
        return;
 
7143
    }
 
7144
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
 
7145
 
 
7146
    // Only flowed text can be justified, only normal text can be kerned...
 
7147
    // Find out if we have flowed text now so we can use it several places
 
7148
    gboolean isFlow = false;
 
7149
    for (GSList const *items = sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList();
 
7150
         items != NULL;
 
7151
         items = items->next) {
 
7152
        // const gchar* id = SP_OBJECT_ID((SPItem *) items->data);
 
7153
        // std::cout << "    " << id << std::endl;
 
7154
        if( SP_IS_FLOWTEXT(( SPItem *) items->data )) {
 
7155
            isFlow = true;
 
7156
            // std::cout << "   Found flowed text" << std::endl;
 
7157
            break;
 
7158
        }
 
7159
    }
 
7160
 
 
7161
    /*
 
7162
     * Query from current selection:
 
7163
     *   Font family (font-family)
 
7164
     *   Style (font-weight, font-style, font-stretch, font-variant, font-align)
 
7165
     *   Numbers (font-size, letter-spacing, word-spacing, line-height, text-anchor, writing-mode)
 
7166
     *   Font specification (Inkscape private attribute)
 
7167
     */
 
7168
    SPStyle *query =
 
7169
        sp_style_new (SP_ACTIVE_DOCUMENT);
 
7170
    int result_family   = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
 
7171
    int result_style    = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
 
7172
    int result_numbers  = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
 
7173
    int result_baseline = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_BASELINES);
 
7174
 
 
7175
    // Used later:
 
7176
    sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
 
7177
 
 
7178
    /*
 
7179
     * If no text in selection (querying returned nothing), read the style from
 
7180
     * the /tools/text preferencess (default style for new texts). Return if
 
7181
     * tool bar already set to these preferences.
 
7182
     */
 
7183
    if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING) {
 
7184
        // There are no texts in selection, read from preferences.
 
7185
        sp_style_read_from_prefs(query, "/tools/text");
 
7186
#ifdef DEBUG_TEXT
 
7187
        std::cout << "    read style from prefs:" << std::endl;
 
7188
        sp_print_font( query );
 
7189
#endif
 
7190
        if (g_object_get_data(tbl, "text_style_from_prefs")) {
 
7191
            // Do not reset the toolbar style from prefs if we already did it last time
 
7192
            sp_style_unref(query);
 
7193
            g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 
7194
#ifdef DEBUG_TEXT
 
7195
            std::cout << "    text_style_from_prefs: toolbar already set" << std:: endl;
 
7196
            std::cout << "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&" << std::endl;
 
7197
            std::cout << std::endl;
 
7198
#endif
 
7199
            return;
 
7200
        }
 
7201
 
 
7202
        g_object_set_data(tbl, "text_style_from_prefs", GINT_TO_POINTER(TRUE));
 
7203
    } else {
 
7204
        g_object_set_data(tbl, "text_style_from_prefs", GINT_TO_POINTER(FALSE));
 
7205
    }
 
7206
 
 
7207
    // If we have valid query data for text (font-family, font-specification) set toolbar accordingly.
 
7208
    if (query->text)
 
7209
    {
 
7210
        // Font family
 
7211
        if( query->text->font_family.value ) {
 
7212
            gchar *fontFamily = query->text->font_family.value;
 
7213
 
 
7214
            Ink_ComboBoxEntry_Action* fontFamilyAction =
 
7215
                INK_COMBOBOXENTRY_ACTION( g_object_get_data( tbl, "TextFontFamilyAction" ) );
 
7216
            ink_comboboxentry_action_set_active_text( fontFamilyAction, fontFamily );
 
7217
        }
 
7218
 
 
7219
 
 
7220
        // Size (average of text selected)
 
7221
        double size = query->font_size.computed;
 
7222
        gchar size_text[G_ASCII_DTOSTR_BUF_SIZE];
 
7223
        g_ascii_dtostr (size_text, sizeof (size_text), size);
 
7224
 
 
7225
        Ink_ComboBoxEntry_Action* fontSizeAction =
 
7226
            INK_COMBOBOXENTRY_ACTION( g_object_get_data( tbl, "TextFontSizeAction" ) );
 
7227
        ink_comboboxentry_action_set_active_text( fontSizeAction, size_text );
 
7228
 
 
7229
 
 
7230
        // Weight (Bold)
 
7231
        // Note: in the enumeration, normal and lighter come at the end so we must explicitly test for them.
 
7232
        gboolean boldSet = ((query->font_weight.computed >= SP_CSS_FONT_WEIGHT_700) &&
 
7233
                            (query->font_weight.computed != SP_CSS_FONT_WEIGHT_NORMAL) &&
 
7234
                            (query->font_weight.computed != SP_CSS_FONT_WEIGHT_LIGHTER));
 
7235
 
 
7236
        InkToggleAction* textBoldAction = INK_TOGGLE_ACTION( g_object_get_data( tbl, "TextBoldAction" ) );
 
7237
        gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(textBoldAction), boldSet );
 
7238
 
 
7239
 
 
7240
        // Style (Italic/Oblique)
 
7241
        gboolean italicSet = (query->font_style.computed != SP_CSS_FONT_STYLE_NORMAL);
 
7242
 
 
7243
        InkToggleAction* textItalicAction = INK_TOGGLE_ACTION( g_object_get_data( tbl, "TextItalicAction" ) );
 
7244
        gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(textItalicAction), italicSet );
 
7245
 
 
7246
 
 
7247
        // Superscript
 
7248
        gboolean superscriptSet =
 
7249
            ((result_baseline == QUERY_STYLE_SINGLE || result_baseline == QUERY_STYLE_MULTIPLE_SAME ) && 
 
7250
             query->baseline_shift.set &&
 
7251
             query->baseline_shift.type == SP_BASELINE_SHIFT_LITERAL &&
 
7252
             query->baseline_shift.literal == SP_CSS_BASELINE_SHIFT_SUPER );
 
7253
 
 
7254
        InkToggleAction* textSuperscriptAction = INK_TOGGLE_ACTION( g_object_get_data( tbl, "TextSuperscriptAction" ) );
 
7255
        gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(textSuperscriptAction), superscriptSet );
 
7256
 
 
7257
 
 
7258
        // Subscript
 
7259
        gboolean subscriptSet =
 
7260
            ((result_baseline == QUERY_STYLE_SINGLE || result_baseline == QUERY_STYLE_MULTIPLE_SAME ) && 
 
7261
             query->baseline_shift.set &&
 
7262
             query->baseline_shift.type == SP_BASELINE_SHIFT_LITERAL &&
 
7263
             query->baseline_shift.literal == SP_CSS_BASELINE_SHIFT_SUB );
 
7264
 
 
7265
        InkToggleAction* textSubscriptAction = INK_TOGGLE_ACTION( g_object_get_data( tbl, "TextSubscriptAction" ) );
 
7266
        gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(textSubscriptAction), subscriptSet );
 
7267
 
 
7268
 
 
7269
        // Alignment
 
7270
        EgeSelectOneAction* textAlignAction = EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "TextAlignAction" ) );
 
7271
 
 
7272
        // Note: SVG 1.1 doesn't include text-align, SVG 1.2 Tiny doesn't include text-align="justify"
 
7273
        // text-align="justify" was a draft SVG 1.2 item (along with flowed text).
 
7274
        // Only flowed text can be left and right justified at the same time.
 
7275
        // Disable button if we don't have flowed text.
 
7276
 
 
7277
        // The GtkTreeModel class doesn't have a set function so we can't
 
7278
        // simply add an ege_select_one_action_set_sensitive method!
 
7279
        // We must set values directly with the GtkListStore and then
 
7280
        // ask that the GtkAction update the sensitive parameters.
 
7281
        GtkListStore * model = GTK_LIST_STORE( ege_select_one_action_get_model( textAlignAction ) );
 
7282
        GtkTreePath * path = gtk_tree_path_new_from_string("3"); // Justify entry
 
7283
        GtkTreeIter iter;
 
7284
        gtk_tree_model_get_iter( GTK_TREE_MODEL (model), &iter, path );
 
7285
        gtk_list_store_set( model, &iter, /* column */ 3, isFlow, -1 );
 
7286
        ege_select_one_action_update_sensitive( textAlignAction );
 
7287
        // ege_select_one_action_set_sensitive( textAlignAction, 3, isFlow );
 
7288
 
 
7289
        int activeButton = 0;
 
7290
        if (query->text_align.computed  == SP_CSS_TEXT_ALIGN_JUSTIFY)
 
7291
        {
 
7292
            activeButton = 3;
 
7293
        } else {
 
7294
            if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_START)  activeButton = 0;
 
7295
            if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_MIDDLE) activeButton = 1;
 
7296
            if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_END)    activeButton = 2;
 
7297
        }
 
7298
        ege_select_one_action_set_active( textAlignAction, activeButton );
 
7299
 
 
7300
 
 
7301
        // Line height (spacing)
 
7302
        double height;
 
7303
        if (query->line_height.normal) {
 
7304
            height = Inkscape::Text::Layout::LINE_HEIGHT_NORMAL;
 
7305
        } else {
 
7306
            if (query->line_height.unit == SP_CSS_UNIT_PERCENT) {
 
7307
                height = query->line_height.value;
 
7308
            } else {
 
7309
                height = query->line_height.computed;
 
7310
            }
 
7311
        }
 
7312
 
 
7313
        GtkAction* lineHeightAction = GTK_ACTION( g_object_get_data( tbl, "TextLineHeightAction" ) );
 
7314
        GtkAdjustment *lineHeightAdjustment =
 
7315
            ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION( lineHeightAction ));
 
7316
        gtk_adjustment_set_value( lineHeightAdjustment, height );
 
7317
 
 
7318
 
 
7319
        // Word spacing
 
7320
        double wordSpacing;
 
7321
        if (query->word_spacing.normal) wordSpacing = 0.0;
 
7322
        else wordSpacing = query->word_spacing.computed; // Assume no units (change in desktop-style.cpp)
 
7323
 
 
7324
        GtkAction* wordSpacingAction = GTK_ACTION( g_object_get_data( tbl, "TextWordSpacingAction" ) );
 
7325
        GtkAdjustment *wordSpacingAdjustment =
 
7326
            ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION( wordSpacingAction ));
 
7327
        gtk_adjustment_set_value( wordSpacingAdjustment, wordSpacing );
 
7328
 
 
7329
 
 
7330
        // Letter spacing
 
7331
        double letterSpacing;
 
7332
        if (query->letter_spacing.normal) letterSpacing = 0.0;
 
7333
        else letterSpacing = query->letter_spacing.computed; // Assume no units (change in desktop-style.cpp)
 
7334
 
 
7335
        GtkAction* letterSpacingAction = GTK_ACTION( g_object_get_data( tbl, "TextLetterSpacingAction" ) );
 
7336
        GtkAdjustment *letterSpacingAdjustment =
 
7337
            ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION( letterSpacingAction ));
 
7338
        gtk_adjustment_set_value( letterSpacingAdjustment, letterSpacing );
 
7339
 
 
7340
 
 
7341
        // Orientation
 
7342
        int activeButton2 = (query->writing_mode.computed == SP_CSS_WRITING_MODE_LR_TB ? 0 : 1);
 
7343
 
 
7344
        EgeSelectOneAction* textOrientationAction =
 
7345
            EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "TextOrientationAction" ) );
 
7346
        ege_select_one_action_set_active( textOrientationAction, activeButton2 );
 
7347
 
 
7348
 
 
7349
    } // if( query->text )
 
7350
 
 
7351
#ifdef DEBUG_TEXT
 
7352
    std::cout << "    GUI: fontfamily.value: "
 
7353
              << (query->text->font_family.value ? query->text->font_family.value : "No value")
 
7354
              << std::endl;
 
7355
    std::cout << "    GUI: font_size.computed: "   << query->font_size.computed   << std::endl;
 
7356
    std::cout << "    GUI: font_weight.computed: " << query->font_weight.computed << std::endl;
 
7357
    std::cout << "    GUI: font_style.computed: "  << query->font_style.computed  << std::endl;
 
7358
    std::cout << "    GUI: text_anchor.computed: " << query->text_anchor.computed << std::endl;
 
7359
    std::cout << "    GUI: text_align.computed:  " << query->text_align.computed  << std::endl;
 
7360
    std::cout << "    GUI: line_height.computed: " << query->line_height.computed
 
7361
              << "  line_height.value: "    << query->line_height.value
 
7362
              << "  line_height.unit: "     << query->line_height.unit  << std::endl;
 
7363
    std::cout << "    GUI: word_spacing.computed: " << query->word_spacing.computed
 
7364
              << "  word_spacing.value: "    << query->word_spacing.value
 
7365
              << "  word_spacing.unit: "     << query->word_spacing.unit  << std::endl;
 
7366
    std::cout << "    GUI: letter_spacing.computed: " << query->letter_spacing.computed
 
7367
              << "  letter_spacing.value: "    << query->letter_spacing.value
 
7368
              << "  letter_spacing.unit: "     << query->letter_spacing.unit  << std::endl;
 
7369
    std::cout << "    GUI: writing_mode.computed: " << query->writing_mode.computed << std::endl;
 
7370
#endif
 
7371
 
 
7372
    sp_style_unref(query);
 
7373
 
 
7374
    // Kerning (xshift), yshift, rotation.  NB: These are not CSS attributes.
 
7375
    if( SP_IS_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context) ) {
 
7376
        SPTextContext *const tc = SP_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context);
 
7377
        if( tc ) {
 
7378
            unsigned char_index = -1;
 
7379
            TextTagAttributes *attributes =
 
7380
                text_tag_attributes_at_position( tc->text, std::min(tc->text_sel_start, tc->text_sel_end), &char_index );
 
7381
            if( attributes ) {
 
7382
 
 
7383
                // Dx
 
7384
                double dx = attributes->getDx( char_index );
 
7385
                GtkAction* dxAction = GTK_ACTION( g_object_get_data( tbl, "TextDxAction" ));
 
7386
                GtkAdjustment *dxAdjustment =
 
7387
                    ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION( dxAction ));
 
7388
                gtk_adjustment_set_value( dxAdjustment, dx );
 
7389
 
 
7390
                // Dy
 
7391
                double dy = attributes->getDy( char_index );
 
7392
                GtkAction* dyAction = GTK_ACTION( g_object_get_data( tbl, "TextDyAction" ));
 
7393
                GtkAdjustment *dyAdjustment =
 
7394
                    ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION( dyAction ));
 
7395
                gtk_adjustment_set_value( dyAdjustment, dy );
 
7396
 
 
7397
                // Rotation
 
7398
                double rotation = attributes->getRotate( char_index );
 
7399
                /* SVG value is between 0 and 360 but we're using -180 to 180 in widget */
 
7400
                if( rotation > 180.0 ) rotation -= 360.0;
 
7401
                GtkAction* rotationAction = GTK_ACTION( g_object_get_data( tbl, "TextRotationAction" ));
 
7402
                GtkAdjustment *rotationAdjustment =
 
7403
                    ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION( rotationAction ));
 
7404
                gtk_adjustment_set_value( rotationAdjustment, rotation );
 
7405
 
 
7406
#ifdef DEBUG_TEXT
 
7407
                std::cout << "    GUI: Dx: " << dx << std::endl;
 
7408
                std::cout << "    GUI: Dy: " << dy << std::endl;
 
7409
                std::cout << "    GUI: Rotation: " << rotation << std::endl;
 
7410
#endif
 
7411
            }
 
7412
        }
 
7413
    }
 
7414
 
 
7415
    {
 
7416
        // Set these here as we don't always have kerning/rotating attributes
 
7417
        GtkAction* dxAction = GTK_ACTION( g_object_get_data( tbl, "TextDxAction" ));
 
7418
        gtk_action_set_sensitive( GTK_ACTION(dxAction), !isFlow );
 
7419
 
 
7420
        GtkAction* dyAction = GTK_ACTION( g_object_get_data( tbl, "TextDyAction" ));
 
7421
        gtk_action_set_sensitive( GTK_ACTION(dyAction), !isFlow );
 
7422
 
 
7423
        GtkAction* rotationAction = GTK_ACTION( g_object_get_data( tbl, "TextRotationAction" ));
 
7424
        gtk_action_set_sensitive( GTK_ACTION(rotationAction), !isFlow );
 
7425
    }
 
7426
 
 
7427
#ifdef DEBUG_TEXT
 
7428
    std::cout << "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&" << std::endl;
 
7429
    std::cout << std::endl;
 
7430
#endif
 
7431
 
 
7432
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 
7433
 
 
7434
}
 
7435
 
 
7436
static void sp_text_toolbox_selection_modified(Inkscape::Selection *selection, guint /*flags*/, GObject *tbl)
 
7437
{
 
7438
    sp_text_toolbox_selection_changed (selection, tbl);
 
7439
}
 
7440
 
 
7441
void
 
7442
sp_text_toolbox_subselection_changed (gpointer /*tc*/, GObject *tbl)
 
7443
{
 
7444
    sp_text_toolbox_selection_changed (NULL, tbl);
 
7445
}
 
7446
 
 
7447
// Define all the "widgets" in the toolbar.
 
7448
static void sp_text_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
 
7449
{
 
7450
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
7451
    Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1);
 
7452
 
 
7453
    // Is this used?
 
7454
    UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
 
7455
    tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
 
7456
    g_object_set_data( holder, "tracker", tracker );
 
7457
 
 
7458
    /* Font family */
 
7459
    {
 
7460
        // Font list
 
7461
        Glib::RefPtr<Gtk::ListStore> store = Inkscape::FontLister::get_instance()->get_font_list();
 
7462
        GtkListStore* model = store->gobj();
 
7463
 
 
7464
        Ink_ComboBoxEntry_Action* act = ink_comboboxentry_action_new( "TextFontFamilyAction",
 
7465
                                                                      _("Font Family"),
 
7466
                                                                      _("Select Font Family (Alt-X to access)"),
 
7467
                                                                      NULL,
 
7468
                                                                      GTK_TREE_MODEL(model),
 
7469
                                                                      -1,                // Entry width
 
7470
                                                                      50,                // Extra list width
 
7471
                                                                      (gpointer)cell_data_func ); // Cell layout
 
7472
        ink_comboboxentry_action_popup_enable( act ); // Enable entry completion
 
7473
        gchar *const warning = _("Font not found on system");
 
7474
        ink_comboboxentry_action_set_warning( act, warning ); // Show icon with tooltip if missing font
 
7475
        ink_comboboxentry_action_set_altx_name( act, "altx-text" ); // Set Alt-X keyboard shortcut
 
7476
        g_signal_connect( G_OBJECT(act), "changed", G_CALLBACK(sp_text_fontfamily_value_changed), holder );
 
7477
        gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
 
7478
        g_object_set_data( holder, "TextFontFamilyAction", act );
 
7479
 
 
7480
        // Change style of drop-down from menu to list
 
7481
        gtk_rc_parse_string (
 
7482
            "style \"dropdown-as-list-style\"\n"
 
7483
            "{\n"
 
7484
            "    GtkComboBox::appears-as-list = 1\n"
 
7485
            "}\n"
 
7486
            "widget \"*.TextFontFamilyAction_combobox\" style \"dropdown-as-list-style\"");
 
7487
    }
 
7488
 
 
7489
    /* Font size */
 
7490
    {
 
7491
        // List of font sizes for drop-down menu
 
7492
        GtkListStore* model_size = gtk_list_store_new( 1, G_TYPE_STRING );
 
7493
        gchar const *const sizes[] = {
 
7494
            "4",  "6",  "8",  "9", "10", "11", "12", "13", "14", "16",
 
7495
            "18", "20", "22", "24", "28", "32", "36", "40", "48", "56",
 
7496
            "64", "72", "144"
 
7497
        };
 
7498
        for( unsigned int i = 0; i < G_N_ELEMENTS(sizes); ++i ) {
 
7499
            GtkTreeIter iter;
 
7500
            gtk_list_store_append( model_size, &iter );
 
7501
            gtk_list_store_set( model_size, &iter, 0, sizes[i], -1 );
 
7502
        }
 
7503
 
 
7504
        Ink_ComboBoxEntry_Action* act = ink_comboboxentry_action_new( "TextFontSizeAction",
 
7505
                                                                      _("Font Size"),
 
7506
                                                                      _("Font size (px)"),
 
7507
                                                                      NULL,
 
7508
                                                                      GTK_TREE_MODEL(model_size),
 
7509
                                                                      4 ); // Width in characters
 
7510
        g_signal_connect( G_OBJECT(act), "changed", G_CALLBACK(sp_text_fontsize_value_changed), holder );
 
7511
        gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
 
7512
        g_object_set_data( holder, "TextFontSizeAction", act );
 
7513
    }
 
7514
 
 
7515
    /* Style - Bold */
 
7516
    {
 
7517
        InkToggleAction* act = ink_toggle_action_new( "TextBoldAction",               // Name
 
7518
                                                      _("Toggle Bold"),               // Label
 
7519
                                                      _("Toggle bold or normal weight"),  // Tooltip
 
7520
                                                      GTK_STOCK_BOLD,                 // Icon (inkId)
 
7521
                                                      secondarySize );                // Icon size
 
7522
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
7523
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_text_style_changed), holder );
 
7524
        gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/text/bold", false) );
 
7525
        g_object_set_data( holder, "TextBoldAction", act );
 
7526
    }
 
7527
 
 
7528
    /* Style - Italic/Oblique */
 
7529
    {
 
7530
        InkToggleAction* act = ink_toggle_action_new( "TextItalicAction",                     // Name
 
7531
                                                      _("Toggle Italic/Oblique"),             // Label
 
7532
                                                      _("Toggle italic/oblique style"),// Tooltip
 
7533
                                                      GTK_STOCK_ITALIC,                       // Icon (inkId)
 
7534
                                                      secondarySize );                        // Icon size
 
7535
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
7536
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_text_style_changed), holder );
 
7537
        gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/text/italic", false) );
 
7538
        g_object_set_data( holder, "TextItalicAction", act );
 
7539
    }
 
7540
 
 
7541
    /* Style - Superscript */
 
7542
    {
 
7543
        InkToggleAction* act = ink_toggle_action_new( "TextSuperscriptAction",             // Name
 
7544
                                                      _("Toggle Superscript"),             // Label
 
7545
                                                      _("Toggle superscript"),             // Tooltip
 
7546
                                                      "text_superscript",                  // Icon (inkId)
 
7547
                                                      secondarySize );                     // Icon size
 
7548
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
7549
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_text_script_changed), holder );
 
7550
        gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/text/super", false) );
 
7551
        g_object_set_data( holder, "TextSuperscriptAction", act );
 
7552
    }
 
7553
 
 
7554
    /* Style - Subscript */
 
7555
    {
 
7556
        InkToggleAction* act = ink_toggle_action_new( "TextSubscriptAction",             // Name
 
7557
                                                      _("Toggle Subscript"),             // Label
 
7558
                                                      _("Toggle subscript"),             // Tooltip
 
7559
                                                      "text_subscript",                  // Icon (inkId)
 
7560
                                                      secondarySize );                     // Icon size
 
7561
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
7562
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_text_script_changed), holder );
 
7563
        gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/text/sub", false) );
 
7564
        g_object_set_data( holder, "TextSubscriptAction", act );
 
7565
    }
 
7566
 
 
7567
    /* Alignment */
 
7568
    {
 
7569
        GtkListStore* model = gtk_list_store_new( 4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN );
 
7570
 
 
7571
        GtkTreeIter iter;
 
7572
 
 
7573
        gtk_list_store_append( model, &iter );
 
7574
        gtk_list_store_set( model, &iter,
 
7575
                            0, _("Align left"),
 
7576
                            1, _("Align left"),
 
7577
                            2, GTK_STOCK_JUSTIFY_LEFT,
 
7578
                            3, true,
 
7579
                            -1 );
 
7580
 
 
7581
        gtk_list_store_append( model, &iter );
 
7582
        gtk_list_store_set( model, &iter,
 
7583
                            0, _("Align center"),
 
7584
                            1, _("Align center"),
 
7585
                            2, GTK_STOCK_JUSTIFY_CENTER,
 
7586
                            3, true,
 
7587
                            -1 );
 
7588
 
 
7589
        gtk_list_store_append( model, &iter );
 
7590
        gtk_list_store_set( model, &iter,
 
7591
                            0, _("Align right"),
 
7592
                            1, _("Align right"),
 
7593
                            2, GTK_STOCK_JUSTIFY_RIGHT,
 
7594
                            3, true,
 
7595
                            -1 );
 
7596
 
 
7597
        gtk_list_store_append( model, &iter );
 
7598
        gtk_list_store_set( model, &iter,
 
7599
                            0, _("Justify"),
 
7600
                            1, _("Justify (only flowed text)"),
 
7601
                            2, GTK_STOCK_JUSTIFY_FILL,
 
7602
                            3, false,
 
7603
                            -1 );
 
7604
 
 
7605
        EgeSelectOneAction* act = ege_select_one_action_new( "TextAlignAction",       // Name
 
7606
                                                             _("Alignment"),          // Label
 
7607
                                                             _("Text alignment"),     // Tooltip
 
7608
                                                             NULL,                    // StockID
 
7609
                                                             GTK_TREE_MODEL(model) ); // Model
 
7610
        g_object_set( act, "short_label", "NotUsed", NULL );
 
7611
        gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
 
7612
        g_object_set_data( holder, "TextAlignAction", act );
 
7613
 
 
7614
        ege_select_one_action_set_appearance( act, "full" );
 
7615
        ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
 
7616
        g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
 
7617
        ege_select_one_action_set_icon_column( act, 2 );
 
7618
        ege_select_one_action_set_icon_size( act, secondarySize );
 
7619
        ege_select_one_action_set_tooltip_column( act, 1  );
 
7620
        ege_select_one_action_set_sensitive_column( act, 3 );
 
7621
        gint mode = prefs->getInt("/tools/text/align_mode", 0);
 
7622
        ege_select_one_action_set_active( act, mode );
 
7623
        g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_text_align_mode_changed), holder );
 
7624
    }
 
7625
 
 
7626
    /* Orientation (Left to Right, Top to Bottom */
 
7627
    {
 
7628
        GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
 
7629
 
 
7630
        GtkTreeIter iter;
 
7631
 
 
7632
        gtk_list_store_append( model, &iter );
 
7633
        gtk_list_store_set( model, &iter,
 
7634
                            0, _("Horizontal"),
 
7635
                            1, _("Horizontal text"),
 
7636
                            2, INKSCAPE_ICON_FORMAT_TEXT_DIRECTION_HORIZONTAL,
 
7637
                            -1 );
 
7638
 
 
7639
        gtk_list_store_append( model, &iter );
 
7640
        gtk_list_store_set( model, &iter,
 
7641
                            0, _("Vertical"),
 
7642
                            1, _("Vertical text"),
 
7643
                            2, INKSCAPE_ICON_FORMAT_TEXT_DIRECTION_VERTICAL,
 
7644
                            -1 );
 
7645
 
 
7646
        EgeSelectOneAction* act = ege_select_one_action_new( "TextOrientationAction", // Name
 
7647
                                                             _("Orientation"),        // Label
 
7648
                                                             _("Text orientation"),   // Tooltip
 
7649
                                                             NULL,                    // StockID
 
7650
                                                             GTK_TREE_MODEL(model) ); // Model
 
7651
 
 
7652
        g_object_set( act, "short_label", "NotUsed", NULL );
 
7653
        gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
 
7654
        g_object_set_data( holder, "TextOrientationAction", act );
 
7655
 
 
7656
        ege_select_one_action_set_appearance( act, "full" );
 
7657
        ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
 
7658
        g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
 
7659
        ege_select_one_action_set_icon_column( act, 2 );
 
7660
        ege_select_one_action_set_icon_size( act, secondarySize );
 
7661
        ege_select_one_action_set_tooltip_column( act, 1  );
 
7662
 
 
7663
        gint mode = prefs->getInt("/tools/text/orientation", 0);
 
7664
        ege_select_one_action_set_active( act, mode );
 
7665
        g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_text_orientation_mode_changed), holder );
 
7666
    }
 
7667
 
 
7668
    /* Line height */
 
7669
    {
 
7670
        // Drop down menu
 
7671
        gchar const* labels[] = {_("Smaller spacing"), 0, 0, 0, 0, _("Normal"), 0, 0, 0, 0, 0, _("Larger spacing")};
 
7672
        gdouble values[] = { 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1,2, 1.3, 1.4, 1.5, 2.0};
 
7673
 
 
7674
        EgeAdjustmentAction *eact = create_adjustment_action(
 
7675
            "TextLineHeightAction",               /* name */
 
7676
            _("Line Height"),                     /* label */
 
7677
            _("Line:"),                           /* short label */
 
7678
            _("Spacing between lines (times font size)"),      /* tooltip */
 
7679
            "/tools/text/lineheight",             /* preferences path */
 
7680
            0.0,                                  /* default */
 
7681
            GTK_WIDGET(desktop->canvas),          /* focusTarget */
 
7682
            NULL,                                 /* unit selector */
 
7683
            holder,                               /* dataKludge */
 
7684
            FALSE,                                /* set alt-x keyboard shortcut? */
 
7685
            NULL,                                 /* altx_mark */
 
7686
            0.0, 10.0, 0.01, 0.10,                /* lower, upper, step (arrow up/down), page up/down */
 
7687
            labels, values, G_N_ELEMENTS(labels), /* drop down menu */
 
7688
            sp_text_lineheight_value_changed,     /* callback */
 
7689
            0.1,                                  /* step (used?) */
 
7690
            2,                                    /* digits to show */
 
7691
            1.0                                   /* factor (multiplies default) */
 
7692
            );
 
7693
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
7694
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
7695
        g_object_set_data( holder, "TextLineHeightAction", eact );
 
7696
        g_object_set( G_OBJECT(eact), "iconId", "text_line_spacing", NULL );
 
7697
    }
 
7698
 
 
7699
    /* Word spacing */
 
7700
    {
 
7701
        // Drop down menu
 
7702
        gchar const* labels[] = {_("Negative spacing"), 0, 0, 0, _("Normal"), 0, 0, 0, 0, 0, 0, 0, _("Positive spacing")};
 
7703
        gdouble values[] = {-2.0, -1.5, -1.0, -0.5, 0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0};
 
7704
 
 
7705
        EgeAdjustmentAction *eact = create_adjustment_action(
 
7706
            "TextWordSpacingAction",              /* name */
 
7707
            _("Word spacing"),                    /* label */
 
7708
            _("Word:"),                           /* short label */
 
7709
            _("Spacing between words (px)"),     /* tooltip */
 
7710
            "/tools/text/wordspacing",            /* preferences path */
 
7711
            0.0,                                  /* default */
 
7712
            GTK_WIDGET(desktop->canvas),          /* focusTarget */
 
7713
            NULL,                                 /* unit selector */
 
7714
            holder,                               /* dataKludge */
 
7715
            FALSE,                                /* set alt-x keyboard shortcut? */
 
7716
            NULL,                                 /* altx_mark */
 
7717
            -100.0, 100.0, 0.01, 0.10,            /* lower, upper, step (arrow up/down), page up/down */
 
7718
            labels, values, G_N_ELEMENTS(labels), /* drop down menu */
 
7719
            sp_text_wordspacing_value_changed,    /* callback */
 
7720
            0.1,                                  /* step (used?) */
 
7721
            2,                                    /* digits to show */
 
7722
            1.0                                   /* factor (multiplies default) */
 
7723
            );
 
7724
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
7725
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
7726
        g_object_set_data( holder, "TextWordSpacingAction", eact );
 
7727
        g_object_set( G_OBJECT(eact), "iconId", "text_word_spacing", NULL );
 
7728
    }
 
7729
 
 
7730
    /* Letter spacing */
 
7731
    {
 
7732
        // Drop down menu
 
7733
        gchar const* labels[] = {_("Negative spacing"), 0, 0, 0, _("Normal"), 0, 0, 0, 0, 0, 0, 0, _("Positive spacing")};
 
7734
        gdouble values[] = {-2.0, -1.5, -1.0, -0.5, 0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0};
 
7735
 
 
7736
        EgeAdjustmentAction *eact = create_adjustment_action(
 
7737
            "TextLetterSpacingAction",            /* name */
 
7738
            _("Letter spacing"),                  /* label */
 
7739
            _("Letter:"),                         /* short label */
 
7740
            _("Spacing between letters (px)"),   /* tooltip */
 
7741
            "/tools/text/letterspacing",          /* preferences path */
 
7742
            0.0,                                  /* default */
 
7743
            GTK_WIDGET(desktop->canvas),          /* focusTarget */
 
7744
            NULL,                                 /* unit selector */
 
7745
            holder,                               /* dataKludge */
 
7746
            FALSE,                                /* set alt-x keyboard shortcut? */
 
7747
            NULL,                                 /* altx_mark */
 
7748
            -100.0, 100.0, 0.01, 0.10,            /* lower, upper, step (arrow up/down), page up/down */
 
7749
            labels, values, G_N_ELEMENTS(labels), /* drop down menu */
 
7750
            sp_text_letterspacing_value_changed,  /* callback */
 
7751
            0.1,                                  /* step (used?) */
 
7752
            2,                                    /* digits to show */
 
7753
            1.0                                   /* factor (multiplies default) */
 
7754
            );
 
7755
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
7756
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
7757
        g_object_set_data( holder, "TextLetterSpacingAction", eact );
 
7758
        g_object_set( G_OBJECT(eact), "iconId", "text_letter_spacing", NULL );
 
7759
    }
 
7760
 
 
7761
    /* Character kerning (horizontal shift) */
 
7762
    {
 
7763
        // Drop down menu
 
7764
        gchar const* labels[] = {   0,   0,   0,   0,   0,   0,   0,   0,   0,   0 };
 
7765
        gdouble values[]      = { -2.0, -1.5, -1.0, -0.5,   0,  0.5,  1.0,  1.5,  2.0, 2.5 };
 
7766
 
 
7767
        EgeAdjustmentAction *eact = create_adjustment_action(
 
7768
            "TextDxAction",                       /* name */
 
7769
            _("Kerning"),                         /* label */
 
7770
            _("Kern:"),                           /* short label */
 
7771
            _("Horizontal kerning (px)"), /* tooltip */
 
7772
            "/tools/text/dx",                     /* preferences path */
 
7773
            0.0,                                  /* default */
 
7774
            GTK_WIDGET(desktop->canvas),          /* focusTarget */
 
7775
            NULL,                                 /* unit selector */
 
7776
            holder,                               /* dataKludge */
 
7777
            FALSE,                                /* set alt-x keyboard shortcut? */
 
7778
            NULL,                                 /* altx_mark */
 
7779
            -100.0, 100.0, 0.01, 0.1,             /* lower, upper, step (arrow up/down), page up/down */
 
7780
            labels, values, G_N_ELEMENTS(labels), /* drop down menu */
 
7781
            sp_text_dx_value_changed,             /* callback */
 
7782
            0.1,                                  /* step (used?) */
 
7783
            2,                                    /* digits to show */
 
7784
            1.0                                   /* factor (multiplies default) */
 
7785
            );
 
7786
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
7787
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
7788
        g_object_set_data( holder, "TextDxAction", eact );
 
7789
        g_object_set( G_OBJECT(eact), "iconId", "text_horz_kern", NULL );
 
7790
    }
 
7791
 
 
7792
    /* Character vertical shift */
 
7793
    {
 
7794
        // Drop down menu
 
7795
        gchar const* labels[] = {   0,   0,   0,   0,   0,   0,   0,   0,   0,   0 };
 
7796
        gdouble values[]      = { -2.0, -1.5, -1.0, -0.5,   0,  0.5,  1.0,  1.5,  2.0, 2.5 };
 
7797
 
 
7798
        EgeAdjustmentAction *eact = create_adjustment_action(
 
7799
            "TextDyAction",                       /* name */
 
7800
            _("Vertical Shift"),                  /* label */
 
7801
            _("Vert:"),                           /* short label */
 
7802
            _("Vertical shift (px)"),   /* tooltip */
 
7803
            "/tools/text/dy",                     /* preferences path */
 
7804
            0.0,                                  /* default */
 
7805
            GTK_WIDGET(desktop->canvas),          /* focusTarget */
 
7806
            NULL,                                 /* unit selector */
 
7807
            holder,                               /* dataKludge */
 
7808
            FALSE,                                /* set alt-x keyboard shortcut? */
 
7809
            NULL,                                 /* altx_mark */
 
7810
            -100.0, 100.0, 0.01, 0.1,             /* lower, upper, step (arrow up/down), page up/down */
 
7811
            labels, values, G_N_ELEMENTS(labels), /* drop down menu */
 
7812
            sp_text_dy_value_changed,             /* callback */
 
7813
            0.1,                                  /* step (used?) */
 
7814
            2,                                    /* digits to show */
 
7815
            1.0                                   /* factor (multiplies default) */
 
7816
            );
 
7817
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
7818
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
7819
        g_object_set_data( holder, "TextDyAction", eact );
 
7820
        g_object_set( G_OBJECT(eact), "iconId", "text_vert_kern", NULL );
 
7821
    }
 
7822
 
 
7823
    /* Character rotation */
 
7824
    {
 
7825
        // Drop down menu
 
7826
        gchar const* labels[] = {   0,   0,   0,   0,   0,   0,   0,   0,   0,   0 };
 
7827
        gdouble values[]      = { -90, -45, -30, -15,   0,  15,  30,  45,  90, 180 };
 
7828
 
 
7829
        EgeAdjustmentAction *eact = create_adjustment_action(
 
7830
            "TextRotationAction",                 /* name */
 
7831
            _("Letter rotation"),                 /* label */
 
7832
            _("Rot:"),                            /* short label */
 
7833
            _("Character rotation (degrees)"),/* tooltip */
 
7834
            "/tools/text/rotation",               /* preferences path */
 
7835
            0.0,                                  /* default */
 
7836
            GTK_WIDGET(desktop->canvas),          /* focusTarget */
 
7837
            NULL,                                 /* unit selector */
 
7838
            holder,                               /* dataKludge */
 
7839
            FALSE,                                /* set alt-x keyboard shortcut? */
 
7840
            NULL,                                 /* altx_mark */
 
7841
            -180.0, 180.0, 0.1, 1.0,              /* lower, upper, step (arrow up/down), page up/down */
 
7842
            labels, values, G_N_ELEMENTS(labels), /* drop down menu */
 
7843
            sp_text_rotation_value_changed,       /* callback */
 
7844
            0.1,                                  /* step (used?) */
 
7845
            2,                                    /* digits to show */
 
7846
            1.0                                   /* factor (multiplies default) */
 
7847
            );
 
7848
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
7849
        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
 
7850
        g_object_set_data( holder, "TextRotationAction", eact );
 
7851
        g_object_set( G_OBJECT(eact), "iconId", "text_rotation", NULL );
 
7852
    }
 
7853
 
 
7854
    // Is this necessary to call? Shouldn't hurt.
 
7855
    sp_text_toolbox_selection_changed(sp_desktop_selection(desktop), holder);
 
7856
 
 
7857
    // Watch selection
 
7858
    Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISTextToolboxGTK");
 
7859
 
 
7860
    sigc::connection *c_selection_changed =
 
7861
        new sigc::connection (sp_desktop_selection (desktop)->connectChanged
 
7862
                              (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), (GObject*)holder)));
 
7863
    pool->add_connection ("selection-changed", c_selection_changed);
 
7864
 
 
7865
    sigc::connection *c_selection_modified =
 
7866
        new sigc::connection (sp_desktop_selection (desktop)->connectModified
 
7867
                              (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_modified), (GObject*)holder)));
 
7868
    pool->add_connection ("selection-modified", c_selection_modified);
 
7869
 
 
7870
    sigc::connection *c_subselection_changed =
 
7871
        new sigc::connection (desktop->connectToolSubselectionChanged
 
7872
                              (sigc::bind (sigc::ptr_fun (sp_text_toolbox_subselection_changed), (GObject*)holder)));
 
7873
    pool->add_connection ("tool-subselection-changed", c_subselection_changed);
 
7874
 
 
7875
    Inkscape::ConnectionPool::connect_destroy (G_OBJECT (holder), pool);
 
7876
 
 
7877
    g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
 
7878
 
 
7879
}
 
7880
 
 
7881
 
 
7882
//#########################
 
7883
//##      Connector      ##
 
7884
//#########################
 
7885
 
 
7886
static void sp_connector_mode_toggled( GtkToggleAction* act, GtkObject * /*tbl*/ )
 
7887
{
 
7888
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
7889
    prefs->setBool("/tools/connector/mode",
 
7890
                gtk_toggle_action_get_active( act ));
 
7891
}
 
7892
 
 
7893
static void sp_connector_path_set_avoid(void)
 
7894
{
 
7895
    cc_selection_set_avoid(true);
 
7896
}
 
7897
 
 
7898
 
 
7899
static void sp_connector_path_set_ignore(void)
 
7900
{
 
7901
    cc_selection_set_avoid(false);
 
7902
}
 
7903
 
 
7904
static void sp_connector_orthogonal_toggled( GtkToggleAction* act, GObject *tbl )
 
7905
{
 
7906
    SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
 
7907
    Inkscape::Selection * selection = sp_desktop_selection(desktop);
 
7908
    SPDocument *doc = sp_desktop_document(desktop);
 
7909
 
 
7910
    if (!sp_document_get_undo_sensitive(doc)) {
 
7911
        return;
 
7912
    }
 
7913
 
 
7914
 
 
7915
    // quit if run by the _changed callbacks
 
7916
    if (g_object_get_data( tbl, "freeze" )) {
 
7917
        return;
 
7918
    }
 
7919
 
 
7920
    // in turn, prevent callbacks from responding
 
7921
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
 
7922
 
 
7923
    bool is_orthog = gtk_toggle_action_get_active( act );
 
7924
    gchar orthog_str[] = "orthogonal";
 
7925
    gchar polyline_str[] = "polyline";
 
7926
    gchar *value = is_orthog ? orthog_str : polyline_str ;
 
7927
 
 
7928
    bool modmade = false;
 
7929
    GSList *l = (GSList *) selection->itemList();
 
7930
    while (l) {
 
7931
        SPItem *item = (SPItem *) l->data;
 
7932
 
 
7933
        if (cc_item_is_connector(item)) {
 
7934
            sp_object_setAttribute(item, "inkscape:connector-type",
 
7935
                    value, false);
 
7936
            item->avoidRef->handleSettingChange();
 
7937
            modmade = true;
 
7938
        }
 
7939
        l = l->next;
 
7940
    }
 
7941
 
 
7942
    if (!modmade) {
 
7943
        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
7944
        prefs->setBool("/tools/connector/orthogonal", is_orthog);
 
7945
    } else {
 
7946
 
 
7947
        sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR,
 
7948
            is_orthog ? _("Set connector type: orthogonal"): _("Set connector type: polyline"));
 
7949
    }
 
7950
 
 
7951
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 
7952
}
 
7953
 
 
7954
static void connector_curvature_changed(GtkAdjustment *adj, GObject* tbl)
 
7955
{
 
7956
    SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
 
7957
    Inkscape::Selection * selection = sp_desktop_selection(desktop);
 
7958
    SPDocument *doc = sp_desktop_document(desktop);
 
7959
 
 
7960
    if (!sp_document_get_undo_sensitive(doc)) {
 
7961
        return;
 
7962
    }
 
7963
 
 
7964
 
 
7965
    // quit if run by the _changed callbacks
 
7966
    if (g_object_get_data( tbl, "freeze" )) {
 
7967
        return;
 
7968
    }
 
7969
 
 
7970
    // in turn, prevent callbacks from responding
 
7971
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
 
7972
 
 
7973
    gdouble newValue = gtk_adjustment_get_value(adj);
 
7974
    gchar value[G_ASCII_DTOSTR_BUF_SIZE];
 
7975
    g_ascii_dtostr(value, G_ASCII_DTOSTR_BUF_SIZE, newValue);
 
7976
 
 
7977
    bool modmade = false;
 
7978
    GSList *l = (GSList *) selection->itemList();
 
7979
    while (l) {
 
7980
        SPItem *item = (SPItem *) l->data;
 
7981
 
 
7982
        if (cc_item_is_connector(item)) {
 
7983
            sp_object_setAttribute(item, "inkscape:connector-curvature",
 
7984
                    value, false);
 
7985
            item->avoidRef->handleSettingChange();
 
7986
            modmade = true;
 
7987
        }
 
7988
        l = l->next;
 
7989
    }
 
7990
 
 
7991
    if (!modmade) {
 
7992
        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
7993
        prefs->setDouble(Glib::ustring("/tools/connector/curvature"), newValue);
 
7994
    }
 
7995
    else {
 
7996
        sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR,
 
7997
            _("Change connector curvature"));
 
7998
    }
 
7999
 
 
8000
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 
8001
}
 
8002
 
 
8003
 
 
8004
static void connector_spacing_changed(GtkAdjustment *adj, GObject* tbl)
 
8005
{
 
8006
    SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
 
8007
    SPDocument *doc = sp_desktop_document(desktop);
 
8008
 
 
8009
    if (!sp_document_get_undo_sensitive(doc)) {
 
8010
        return;
 
8011
    }
 
8012
 
 
8013
    Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
 
8014
 
 
8015
    if ( !repr->attribute("inkscape:connector-spacing") &&
 
8016
            ( adj->value == defaultConnSpacing )) {
 
8017
        // Don't need to update the repr if the attribute doesn't
 
8018
        // exist and it is being set to the default value -- as will
 
8019
        // happen at startup.
 
8020
        return;
 
8021
    }
 
8022
 
 
8023
    // quit if run by the attr_changed listener
 
8024
    if (g_object_get_data( tbl, "freeze" )) {
 
8025
        return;
 
8026
    }
 
8027
 
 
8028
    // in turn, prevent listener from responding
 
8029
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
 
8030
 
 
8031
    sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
 
8032
    SP_OBJECT(desktop->namedview)->updateRepr();
 
8033
    bool modmade = false;
 
8034
 
 
8035
    GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
 
8036
    for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
 
8037
        SPItem *item = reinterpret_cast<SPItem *>(iter->data);
 
8038
        Geom::Matrix m = Geom::identity();
 
8039
        avoid_item_move(&m, item);
 
8040
        modmade = true;
 
8041
    }
 
8042
 
 
8043
    if (items) {
 
8044
        g_slist_free(items);
 
8045
    }
 
8046
    if(modmade) {
 
8047
        sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR,
 
8048
            _("Change connector spacing"));
 
8049
    }
 
8050
    g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 
8051
}
 
8052
 
 
8053
static void sp_connector_graph_layout(void)
 
8054
{
 
8055
    if (!SP_ACTIVE_DESKTOP) {
 
8056
        return;
 
8057
    }
 
8058
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
8059
 
 
8060
    // hack for clones, see comment in align-and-distribute.cpp
 
8061
    int saved_compensation = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED);
 
8062
    prefs->setInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED);
 
8063
 
 
8064
    graphlayout(sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList());
 
8065
 
 
8066
    prefs->setInt("/options/clonecompensation/value", saved_compensation);
 
8067
 
 
8068
    sp_document_done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, _("Arrange connector network"));
 
8069
}
 
8070
 
 
8071
static void sp_directed_graph_layout_toggled( GtkToggleAction* act, GtkObject * /*tbl*/ )
 
8072
{
 
8073
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
8074
    prefs->setBool("/tools/connector/directedlayout",
 
8075
                gtk_toggle_action_get_active( act ));
 
8076
}
 
8077
 
 
8078
static void sp_nooverlaps_graph_layout_toggled( GtkToggleAction* act, GtkObject * /*tbl*/ )
 
8079
{
 
8080
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
8081
    prefs->setBool("/tools/connector/avoidoverlaplayout",
 
8082
                gtk_toggle_action_get_active( act ));
 
8083
}
 
8084
 
 
8085
 
 
8086
static void connector_length_changed(GtkAdjustment *adj, GObject* /*tbl*/)
 
8087
{
 
8088
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
8089
    prefs->setDouble("/tools/connector/length", adj->value);
 
8090
}
 
8091
 
 
8092
static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
 
8093
                                            gchar const *name, gchar const * /*old_value*/, gchar const * /*new_value*/,
 
8094
                                            bool /*is_interactive*/, gpointer data)
 
8095
{
 
8096
    GtkWidget *tbl = GTK_WIDGET(data);
 
8097
 
 
8098
    if ( !g_object_get_data(G_OBJECT(tbl), "freeze")
 
8099
         && (strcmp(name, "inkscape:connector-spacing") == 0) ) {
 
8100
        GtkAdjustment *adj = static_cast<GtkAdjustment*>(gtk_object_get_data(GTK_OBJECT(tbl), "spacing"));
 
8101
        gdouble spacing = defaultConnSpacing;
 
8102
        sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
 
8103
 
 
8104
        gtk_adjustment_set_value(adj, spacing);
 
8105
        gtk_adjustment_value_changed(adj);
 
8106
 
 
8107
        spinbutton_defocus(GTK_OBJECT(tbl));
 
8108
    }
 
8109
}
 
8110
 
 
8111
static void sp_connector_new_connection_point(GtkWidget *, GObject *tbl)
 
8112
{
 
8113
    SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
 
8114
    SPConnectorContext* cc = SP_CONNECTOR_CONTEXT(desktop->event_context);
 
8115
 
 
8116
    if (cc->mode == SP_CONNECTOR_CONTEXT_EDITING_MODE) {
 
8117
        cc_create_connection_point(cc);
 
8118
    }
 
8119
}
 
8120
 
 
8121
static void sp_connector_remove_connection_point(GtkWidget *, GObject *tbl)
 
8122
{
 
8123
    SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
 
8124
    SPConnectorContext* cc = SP_CONNECTOR_CONTEXT(desktop->event_context);
 
8125
 
 
8126
    if (cc->mode == SP_CONNECTOR_CONTEXT_EDITING_MODE) {
 
8127
        cc_remove_connection_point(cc);
 
8128
    }
 
8129
}
 
8130
 
 
8131
static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
 
8132
    NULL, /* child_added */
 
8133
    NULL, /* child_removed */
 
8134
    connector_tb_event_attr_changed,
 
8135
    NULL, /* content_changed */
 
8136
    NULL  /* order_changed */
 
8137
};
 
8138
 
 
8139
static void sp_connector_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
 
8140
{
 
8141
    GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "curvature" ) );
 
8142
    GtkToggleAction *act = GTK_TOGGLE_ACTION( g_object_get_data( tbl, "orthogonal" ) );
 
8143
    SPItem *item = selection->singleItem();
 
8144
    if (SP_IS_PATH(item))
 
8145
    {
 
8146
        gdouble curvature = SP_PATH(item)->connEndPair.getCurvature();
 
8147
        bool is_orthog = SP_PATH(item)->connEndPair.isOrthogonal();
 
8148
        gtk_toggle_action_set_active(act, is_orthog);
 
8149
        gtk_adjustment_set_value(adj, curvature);
 
8150
    }
 
8151
 
 
8152
}
 
8153
 
 
8154
static void sp_connector_toolbox_prep( SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder )
 
8155
{
 
8156
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
8157
    Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1);
 
8158
 
 
8159
    // Editing mode toggle button
 
8160
    {
 
8161
        InkToggleAction* act = ink_toggle_action_new( "ConnectorEditModeAction",
 
8162
                                                      _("EditMode"),
 
8163
                                                      _("Switch between connection point editing and connector drawing mode"),
 
8164
                                                      INKSCAPE_ICON_CONNECTOR_EDIT,
 
8165
                                                      Inkscape::ICON_SIZE_DECORATION );
 
8166
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
8167
 
 
8168
        bool tbuttonstate = prefs->getBool("/tools/connector/mode");
 
8169
        gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), ( tbuttonstate ? TRUE : FALSE ));
 
8170
        g_object_set_data( holder, "mode", act );
 
8171
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_connector_mode_toggled), holder );
 
8172
    }
 
8173
 
 
8174
 
 
8175
    {
 
8176
        InkAction* inky = ink_action_new( "ConnectorAvoidAction",
 
8177
                                          _("Avoid"),
 
8178
                                          _("Make connectors avoid selected objects"),
 
8179
                                          INKSCAPE_ICON_CONNECTOR_AVOID,
 
8180
                                          secondarySize );
 
8181
        g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_avoid), holder );
 
8182
        gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
 
8183
    }
 
8184
 
 
8185
    {
 
8186
        InkAction* inky = ink_action_new( "ConnectorIgnoreAction",
 
8187
                                          _("Ignore"),
 
8188
                                          _("Make connectors ignore selected objects"),
 
8189
                                          INKSCAPE_ICON_CONNECTOR_IGNORE,
 
8190
                                          secondarySize );
 
8191
        g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_ignore), holder );
 
8192
        gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
 
8193
    }
 
8194
 
 
8195
    // Orthogonal connectors toggle button
 
8196
    {
 
8197
        InkToggleAction* act = ink_toggle_action_new( "ConnectorOrthogonalAction",
 
8198
                                                      _("Orthogonal"),
 
8199
                                                      _("Make connector orthogonal or polyline"),
 
8200
                                                      INKSCAPE_ICON_CONNECTOR_ORTHOGONAL,
 
8201
                                                      Inkscape::ICON_SIZE_DECORATION );
 
8202
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
8203
 
 
8204
        bool tbuttonstate = prefs->getBool("/tools/connector/orthogonal");
 
8205
        gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), ( tbuttonstate ? TRUE : FALSE ));
 
8206
        g_object_set_data( holder, "orthogonal", act );
 
8207
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_connector_orthogonal_toggled), holder );
 
8208
    }
 
8209
 
 
8210
    EgeAdjustmentAction* eact = 0;
 
8211
    // Curvature spinbox
 
8212
    eact = create_adjustment_action( "ConnectorCurvatureAction",
 
8213
                                    _("Connector Curvature"), _("Curvature:"),
 
8214
                                    _("The amount of connectors curvature"),
 
8215
                                    "/tools/connector/curvature", defaultConnCurvature,
 
8216
                                    GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-curvature",
 
8217
                                    0, 100, 1.0, 10.0,
 
8218
                                    0, 0, 0,
 
8219
                                    connector_curvature_changed, 1, 0 );
 
8220
    gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
8221
 
 
8222
    // Spacing spinbox
 
8223
    eact = create_adjustment_action( "ConnectorSpacingAction",
 
8224
                                    _("Connector Spacing"), _("Spacing:"),
 
8225
                                    _("The amount of space left around objects by auto-routing connectors"),
 
8226
                                    "/tools/connector/spacing", defaultConnSpacing,
 
8227
                                    GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-spacing",
 
8228
                                    0, 100, 1.0, 10.0,
 
8229
                                    0, 0, 0,
 
8230
                                    connector_spacing_changed, 1, 0 );
 
8231
    gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
8232
 
 
8233
    // Graph (connector network) layout
 
8234
    {
 
8235
        InkAction* inky = ink_action_new( "ConnectorGraphAction",
 
8236
                                          _("Graph"),
 
8237
                                          _("Nicely arrange selected connector network"),
 
8238
                                          INKSCAPE_ICON_DISTRIBUTE_GRAPH,
 
8239
                                          secondarySize );
 
8240
        g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_graph_layout), holder );
 
8241
        gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
 
8242
    }
 
8243
 
 
8244
    // Default connector length spinbox
 
8245
    eact = create_adjustment_action( "ConnectorLengthAction",
 
8246
                                     _("Connector Length"), _("Length:"),
 
8247
                                     _("Ideal length for connectors when layout is applied"),
 
8248
                                     "/tools/connector/length", 100,
 
8249
                                     GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-length",
 
8250
                                     10, 1000, 10.0, 100.0,
 
8251
                                     0, 0, 0,
 
8252
                                     connector_length_changed, 1, 0 );
 
8253
    gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
8254
 
 
8255
 
 
8256
    // Directed edges toggle button
 
8257
    {
 
8258
        InkToggleAction* act = ink_toggle_action_new( "ConnectorDirectedAction",
 
8259
                                                      _("Downwards"),
 
8260
                                                      _("Make connectors with end-markers (arrows) point downwards"),
 
8261
                                                      INKSCAPE_ICON_DISTRIBUTE_GRAPH_DIRECTED,
 
8262
                                                      Inkscape::ICON_SIZE_DECORATION );
 
8263
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
8264
 
 
8265
        bool tbuttonstate = prefs->getBool("/tools/connector/directedlayout");
 
8266
        gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), ( tbuttonstate ? TRUE : FALSE ));
 
8267
 
 
8268
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_directed_graph_layout_toggled), holder );
 
8269
        sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_connector_toolbox_selection_changed), (GObject *)holder));
 
8270
    }
 
8271
 
 
8272
    // Avoid overlaps toggle button
 
8273
    {
 
8274
        InkToggleAction* act = ink_toggle_action_new( "ConnectorOverlapAction",
 
8275
                                                      _("Remove overlaps"),
 
8276
                                                      _("Do not allow overlapping shapes"),
 
8277
                                                      INKSCAPE_ICON_DISTRIBUTE_REMOVE_OVERLAPS,
 
8278
                                                      Inkscape::ICON_SIZE_DECORATION );
 
8279
        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
 
8280
 
 
8281
        bool tbuttonstate = prefs->getBool("/tools/connector/avoidoverlaplayout");
 
8282
        gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), (tbuttonstate ? TRUE : FALSE ));
 
8283
 
 
8284
        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_nooverlaps_graph_layout_toggled), holder );
 
8285
    }
 
8286
 
 
8287
 
 
8288
    // New connection point button
 
8289
    {
 
8290
        InkAction* inky = ink_action_new( "ConnectorNewConnPointAction",
 
8291
                                          _("New connection point"),
 
8292
                                          _("Add a new connection point to the currently selected item"),
 
8293
                                          INKSCAPE_ICON_CONNECTOR_NEW_CONNPOINT,
 
8294
                                          secondarySize );
 
8295
        g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_new_connection_point), holder );
 
8296
        gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
 
8297
    }
 
8298
 
 
8299
    // Remove selected connection point button
 
8300
 
 
8301
    {
 
8302
        InkAction* inky = ink_action_new( "ConnectorRemoveConnPointAction",
 
8303
                                          _("Remove connection point"),
 
8304
                                          _("Remove the currently selected connection point"),
 
8305
                                          INKSCAPE_ICON_CONNECTOR_REMOVE_CONNPOINT,
 
8306
                                          secondarySize );
 
8307
        g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_remove_connection_point), holder );
 
8308
        gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
 
8309
    }
 
8310
 
 
8311
 
 
8312
    // Code to watch for changes to the connector-spacing attribute in
 
8313
    // the XML.
 
8314
    Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
 
8315
    g_assert(repr != NULL);
 
8316
 
 
8317
    purge_repr_listener( holder, holder );
 
8318
 
 
8319
    if (repr) {
 
8320
        g_object_set_data( holder, "repr", repr );
 
8321
        Inkscape::GC::anchor(repr);
 
8322
        sp_repr_add_listener( repr, &connector_tb_repr_events, holder );
 
8323
        sp_repr_synthesize_events( repr, &connector_tb_repr_events, holder );
 
8324
    }
 
8325
} // end of sp_connector_toolbox_prep()
 
8326
 
 
8327
 
 
8328
//#########################
 
8329
//##     Paintbucket     ##
 
8330
//#########################
 
8331
 
 
8332
static void paintbucket_channels_changed(EgeSelectOneAction* act, GObject* /*tbl*/)
 
8333
{
 
8334
    gint channels = ege_select_one_action_get_active( act );
 
8335
    flood_channels_set_channels( channels );
 
8336
}
 
8337
 
 
8338
static void paintbucket_threshold_changed(GtkAdjustment *adj, GObject * /*tbl*/)
 
8339
{
 
8340
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
8341
    prefs->setInt("/tools/paintbucket/threshold", (gint)adj->value);
 
8342
}
 
8343
 
 
8344
static void paintbucket_autogap_changed(EgeSelectOneAction* act, GObject * /*tbl*/)
 
8345
{
 
8346
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
8347
    prefs->setBool("/tools/paintbucket/autogap", ege_select_one_action_get_active( act ));
 
8348
}
 
8349
 
 
8350
static void paintbucket_offset_changed(GtkAdjustment *adj, GObject *tbl)
 
8351
{
 
8352
    UnitTracker* tracker = static_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
 
8353
    SPUnit const *unit = tracker->getActiveUnit();
 
8354
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
8355
 
 
8356
    // Don't adjust the offset value because we're saving the
 
8357
    // unit and it'll be correctly handled on load.
 
8358
    prefs->setDouble("/tools/paintbucket/offset", (gdouble)adj->value);
 
8359
    prefs->setString("/tools/paintbucket/offsetunits", sp_unit_get_abbreviation(unit));
 
8360
}
 
8361
 
 
8362
static void paintbucket_defaults(GtkWidget *, GObject *tbl)
 
8363
{
 
8364
    // FIXME: make defaults settable via Inkscape Options
 
8365
    struct KeyValue {
 
8366
        char const *key;
 
8367
        double value;
 
8368
    } const key_values[] = {
 
8369
        {"threshold", 15},
 
8370
        {"offset", 0.0}
 
8371
    };
 
8372
 
 
8373
    for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
 
8374
        KeyValue const &kv = key_values[i];
 
8375
        GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(tbl, kv.key));
 
8376
        if ( adj ) {
 
8377
            gtk_adjustment_set_value(adj, kv.value);
 
8378
        }
 
8379
    }
 
8380
 
 
8381
    EgeSelectOneAction* channels_action = EGE_SELECT_ONE_ACTION( g_object_get_data (tbl, "channels_action" ) );
 
8382
    ege_select_one_action_set_active( channels_action, FLOOD_CHANNELS_RGB );
 
8383
    EgeSelectOneAction* autogap_action = EGE_SELECT_ONE_ACTION( g_object_get_data (tbl, "autogap_action" ) );
 
8384
    ege_select_one_action_set_active( autogap_action, 0 );
 
8385
}
 
8386
 
 
8387
static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
 
8388
{
 
8389
    EgeAdjustmentAction* eact = 0;
 
8390
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
8391
 
 
8392
    {
 
8393
        GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
 
8394
 
 
8395
        GList* items = 0;
 
8396
        gint count = 0;
 
8397
        for ( items = flood_channels_dropdown_items_list(); items ; items = g_list_next(items) )
 
8398
        {
 
8399
            GtkTreeIter iter;
 
8400
            gtk_list_store_append( model, &iter );
 
8401
            gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
 
8402
            count++;
 
8403
        }
 
8404
        g_list_free( items );
 
8405
        items = 0;
 
8406
        EgeSelectOneAction* act1 = ege_select_one_action_new( "ChannelsAction", _("Fill by"), (""), NULL, GTK_TREE_MODEL(model) );
 
8407
        g_object_set( act1, "short_label", _("Fill by:"), NULL );
 
8408
        ege_select_one_action_set_appearance( act1, "compact" );
 
8409
        ege_select_one_action_set_active( act1, prefs->getInt("/tools/paintbucket/channels", 0) );
 
8410
        g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(paintbucket_channels_changed), holder );
 
8411
        gtk_action_group_add_action( mainActions, GTK_ACTION(act1) );
 
8412
        g_object_set_data( holder, "channels_action", act1 );
 
8413
    }
 
8414
 
 
8415
    // Spacing spinbox
 
8416
    {
 
8417
        eact = create_adjustment_action(
 
8418
            "ThresholdAction",
 
8419
            _("Fill Threshold"), _("Threshold:"),
 
8420
            _("The maximum allowed difference between the clicked pixel and the neighboring pixels to be counted in the fill"),
 
8421
            "/tools/paintbucket/threshold", 5, GTK_WIDGET(desktop->canvas), NULL, holder, TRUE,
 
8422
            "inkscape:paintbucket-threshold", 0, 100.0, 1.0, 10.0,
 
8423
            0, 0, 0,
 
8424
            paintbucket_threshold_changed, 1, 0 );
 
8425
 
 
8426
        ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
 
8427
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
8428
    }
 
8429
 
 
8430
    // Create the units menu.
 
8431
    UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
 
8432
    Glib::ustring stored_unit = prefs->getString("/tools/paintbucket/offsetunits");
 
8433
    if (!stored_unit.empty()) {
 
8434
        tracker->setActiveUnit(sp_unit_get_by_abbreviation(stored_unit.data()));
 
8435
    }
 
8436
    g_object_set_data( holder, "tracker", tracker );
 
8437
    {
 
8438
        GtkAction* act = tracker->createAction( "PaintbucketUnitsAction", _("Units"), ("") );
 
8439
        gtk_action_group_add_action( mainActions, act );
 
8440
    }
 
8441
 
 
8442
    // Offset spinbox
 
8443
    {
 
8444
        eact = create_adjustment_action(
 
8445
            "OffsetAction",
 
8446
            _("Grow/shrink by"), _("Grow/shrink by:"),
 
8447
            _("The amount to grow (positive) or shrink (negative) the created fill path"),
 
8448
            "/tools/paintbucket/offset", 0, GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE,
 
8449
            "inkscape:paintbucket-offset", -1e4, 1e4, 0.1, 0.5,
 
8450
            0, 0, 0,
 
8451
            paintbucket_offset_changed, 1, 2);
 
8452
        tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
 
8453
 
 
8454
        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
8455
    }
 
8456
 
 
8457
    /* Auto Gap */
 
8458
    {
 
8459
        GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
 
8460
 
 
8461
        GList* items = 0;
 
8462
        gint count = 0;
 
8463
        for ( items = flood_autogap_dropdown_items_list(); items ; items = g_list_next(items) )
 
8464
        {
 
8465
            GtkTreeIter iter;
 
8466
            gtk_list_store_append( model, &iter );
 
8467
            gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
 
8468
            count++;
 
8469
        }
 
8470
        g_list_free( items );
 
8471
        items = 0;
 
8472
        EgeSelectOneAction* act2 = ege_select_one_action_new( "AutoGapAction", _("Close gaps"), (""), NULL, GTK_TREE_MODEL(model) );
 
8473
        g_object_set( act2, "short_label", _("Close gaps:"), NULL );
 
8474
        ege_select_one_action_set_appearance( act2, "compact" );
 
8475
        ege_select_one_action_set_active( act2, prefs->getBool("/tools/paintbucket/autogap") );
 
8476
        g_signal_connect( G_OBJECT(act2), "changed", G_CALLBACK(paintbucket_autogap_changed), holder );
 
8477
        gtk_action_group_add_action( mainActions, GTK_ACTION(act2) );
 
8478
        g_object_set_data( holder, "autogap_action", act2 );
 
8479
    }
 
8480
 
 
8481
    /* Reset */
 
8482
    {
 
8483
        GtkAction* act = gtk_action_new( "PaintbucketResetAction",
 
8484
                                          _("Defaults"),
 
8485
                                          _("Reset paint bucket parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
 
8486
                                          GTK_STOCK_CLEAR );
 
8487
        g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(paintbucket_defaults), holder );
 
8488
        gtk_action_group_add_action( mainActions, act );
 
8489
        gtk_action_set_sensitive( act, TRUE );
 
8490
    }
 
8491
 
 
8492
}
 
8493
 
 
8494
/*
 
8495
  Local Variables:
 
8496
  mode:c++
 
8497
  c-file-style:"stroustrup"
 
8498
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
 
8499
  indent-tabs-mode:nil
 
8500
  fill-column:99
 
8501
  End:
 
8502
*/
 
8503
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :