Code

Add button whether to display limiting bounding box; add 'all inactive' toggle button...
[inkscape.git] / src / lpe-tool-context.cpp
1 /*
2  * LPEToolContext: a context for a generic tool composed of subtools that are given by LPEs
3  *
4  * Authors:
5  *   Maximilian Albert <maximilian.albert@gmail.com>
6  *   Lauris Kaplinski <lauris@kaplinski.com>
7  *
8  * Copyright (C) 1998 The Free Software Foundation
9  * Copyright (C) 1999-2005 authors
10  * Copyright (C) 2001-2002 Ximian, Inc.
11  * Copyright (C) 2008 Maximilian Albert
12  *
13  * Released under GNU GPL, read the file 'COPYING' for more information
14  */
16 #ifdef HAVE_CONFIG_H
17 #include "config.h"
18 #endif
20 #include "forward.h"
21 #include "pixmaps/cursor-node.xpm"
22 #include "pixmaps/cursor-crosshairs.xpm"
23 #include <gtk/gtk.h>
24 #include "desktop.h"
25 #include "message-context.h"
26 #include "prefs-utils.h"
27 #include "shape-editor.h"
28 #include "selection.h"
29 #include "desktop-handles.h"
30 #include "document.h"
31 #include "display/curve.h"
32 #include "display/canvas-bpath.h"
34 #include "lpe-tool-context.h"
36 static void sp_lpetool_context_class_init(SPLPEToolContextClass *klass);
37 static void sp_lpetool_context_init(SPLPEToolContext *erc);
38 static void sp_lpetool_context_dispose(GObject *object);
40 static void sp_lpetool_context_setup(SPEventContext *ec);
41 static void sp_lpetool_context_set(SPEventContext *ec, gchar const *key, gchar const *val);
42 static gint sp_lpetool_context_root_handler(SPEventContext *ec, GdkEvent *event);
44 void sp_lpetool_context_selection_changed(Inkscape::Selection *selection, gpointer data);
46 const int num_subtools = 7;
48 Inkscape::LivePathEffect::EffectType lpesubtools[] = {
49     Inkscape::LivePathEffect::INVALID_LPE, // this must be here to account for the "all inactive" action
50     Inkscape::LivePathEffect::LINE_SEGMENT,
51     Inkscape::LivePathEffect::CIRCLE_3PTS,
52     Inkscape::LivePathEffect::CIRCLE_WITH_RADIUS,
53     Inkscape::LivePathEffect::PARALLEL,
54     Inkscape::LivePathEffect::PERP_BISECTOR,
55     Inkscape::LivePathEffect::ANGLE_BISECTOR,
56 };
58 static SPPenContextClass *lpetool_parent_class = 0;
60 GType sp_lpetool_context_get_type(void)
61 {
62     static GType type = 0;
63     if (!type) {
64         GTypeInfo info = {
65             sizeof(SPLPEToolContextClass),
66             0, // base_init
67             0, // base_finalize
68             (GClassInitFunc)sp_lpetool_context_class_init,
69             0, // class_finalize
70             0, // class_data
71             sizeof(SPLPEToolContext),
72             0, // n_preallocs
73             (GInstanceInitFunc)sp_lpetool_context_init,
74             0 // value_table
75         };
76         type = g_type_register_static(SP_TYPE_PEN_CONTEXT, "SPLPEToolContext", &info, static_cast<GTypeFlags>(0));
77     }
78     return type;
79 }
81 static void
82 sp_lpetool_context_class_init(SPLPEToolContextClass *klass)
83 {
84     GObjectClass *object_class = (GObjectClass *) klass;
85     SPEventContextClass *event_context_class = (SPEventContextClass *) klass;
87     lpetool_parent_class = (SPPenContextClass*)g_type_class_peek_parent(klass);
89     object_class->dispose = sp_lpetool_context_dispose;
91     event_context_class->setup = sp_lpetool_context_setup;
92     event_context_class->set = sp_lpetool_context_set;
93     event_context_class->root_handler = sp_lpetool_context_root_handler;
94 }
96 static void
97 sp_lpetool_context_init(SPLPEToolContext *lc)
98 {
99     lc->cursor_shape = cursor_crosshairs_xpm;
100     lc->hot_x = 7;
101     lc->hot_y = 7;
103     lc->canvas_bbox = NULL;
105     new (&lc->sel_changed_connection) sigc::connection();
108 static void
109 sp_lpetool_context_dispose(GObject *object)
111     SPLPEToolContext *lc = SP_LPETOOL_CONTEXT(object);
112     delete lc->shape_editor;
114     if (lc->canvas_bbox) {
115         gtk_object_destroy(GTK_OBJECT(lc->canvas_bbox));
116         lc->canvas_bbox = NULL;
117     }
119     lc->sel_changed_connection.disconnect();
120     lc->sel_changed_connection.~connection();
122     G_OBJECT_CLASS(lpetool_parent_class)->dispose(object);
125 static void
126 sp_lpetool_context_setup(SPEventContext *ec)
128     SPLPEToolContext *lc = SP_LPETOOL_CONTEXT(ec);
130     if (((SPEventContextClass *) lpetool_parent_class)->setup)
131         ((SPEventContextClass *) lpetool_parent_class)->setup(ec);
133     Inkscape::Selection *selection = sp_desktop_selection (ec->desktop);
134     SPItem *item = selection->singleItem();
136     lc->sel_changed_connection.disconnect();
137     lc->sel_changed_connection =
138         selection->connectChanged(sigc::bind(sigc::ptr_fun(&sp_lpetool_context_selection_changed), (gpointer)lc));
140     //lc->my_nc = new NodeContextCpp(lc->desktop, lc->prefs_repr, lc->key);
141     lc->shape_editor = new ShapeEditor(ec->desktop);
143     lpetool_context_reset_limiting_bbox(lc);
145 // TODO temp force:
146     ec->enableSelectionCue();
148     if (item) {
149         lc->shape_editor->set_item(item, SH_NODEPATH);
150         lc->shape_editor->set_item(item, SH_KNOTHOLDER);
151     }
153     if (prefs_get_int_attribute("tools.lpetool", "selcue", 0) != 0) {
154         ec->enableSelectionCue();
155     }
157     lc->_message_context = new Inkscape::MessageContext((ec->desktop)->messageStack());
159     lc->shape_editor->update_statusbar();
162 /**
163 \brief  Callback that processes the "changed" signal on the selection;
164 destroys old and creates new nodepath and reassigns listeners to the new selected item's repr
165 */
166 void
167 sp_lpetool_context_selection_changed(Inkscape::Selection *selection, gpointer data)
169     SPLPEToolContext *lc = SP_LPETOOL_CONTEXT(data);
171     // TODO: update ShapeEditorsCollective instead
172     lc->shape_editor->unset_item(SH_NODEPATH);
173     lc->shape_editor->unset_item(SH_KNOTHOLDER);
174     SPItem *item = selection->singleItem();
175     lc->shape_editor->set_item(item, SH_NODEPATH);
176     lc->shape_editor->set_item(item, SH_KNOTHOLDER);
177     lc->shape_editor->update_statusbar();
180 static void
181 sp_lpetool_context_set(SPEventContext *ec, gchar const *key, gchar const *val)
183     // FIXME: how to set this correcly? the value from preferences-skeleton.h doesn't seem to get
184     // read (it wants to set drag = 1)
185     lpetool_parent_class->set(ec, key, "drag");
187     /**
188     //pass on up to parent class to handle common attributes.
189     if ( lpetool_parent_class->set ) {
190         lpetool_parent_class->set(ec, key, val);
191     }
192     **/
195 gint
196 sp_lpetool_context_root_handler(SPEventContext *event_context, GdkEvent *event)
198     //g_print ("sp_lpetool_context_root_handler()\n");
199     SPLPEToolContext *lc = SP_LPETOOL_CONTEXT(event_context);
200     SPDesktop *desktop = event_context->desktop;
201     Inkscape::Selection *selection = sp_desktop_selection (desktop);
203     bool ret = false;
205     if (sp_pen_context_has_waiting_LPE(lc)) {
206         // quit when we are waiting for a LPE to be applied
207         g_print ("LPETool has waiting LPE. We call the pen tool parent context and return\n");
208         ret = ((SPEventContextClass *) lpetool_parent_class)->root_handler(event_context, event);
209         return ret;
210     }
212     switch (event->type) {
213         case GDK_BUTTON_PRESS:
214             g_print ("GDK_BUTTON_PRESS\n");
215             if (event->button.button == 1 && !event_context->space_panning) {
216                 g_print ("   ... (passed if construct)\n");
217                 // save drag origin
218                 event_context->xp = (gint) event->button.x;
219                 event_context->yp = (gint) event->button.y;
220                 event_context->within_tolerance = true;
221                 lc->shape_editor->cancel_hit();
223                 using namespace Inkscape::LivePathEffect;
225                 int mode = prefs_get_int_attribute("tools.lpetool", "mode", 0);
226                 EffectType type = lpesubtools[mode];
227                 g_print ("Activating mode %d\n", mode);
229                 // save drag origin
230                 bool over_stroke = lc->shape_editor->is_over_stroke(NR::Point(event->button.x, event->button.y), true);
231                 g_print ("over_stroke: %s\n", over_stroke ? "true" : "false");
233                 sp_pen_context_wait_for_LPE_mouse_clicks(lc, type, Effect::acceptsNumClicks(type));
235                 // we pass the mouse click on to pen tool as the first click which it should collect
236                 ret = ((SPEventContextClass *) lpetool_parent_class)->root_handler(event_context, event);
237             }
238             break;
239         case GDK_MOTION_NOTIFY:
240         {
241             if (!lc->shape_editor->has_nodepath() || selection->singleItem() == NULL) {
242                 break;
243             }
245             bool over_stroke = false;
246             over_stroke = lc->shape_editor->is_over_stroke(NR::Point(event->motion.x, event->motion.y), false);
248             if (over_stroke) {
249                 event_context->cursor_shape = cursor_node_xpm;
250                 event_context->hot_x = 1;
251                 event_context->hot_y = 1;
252                 sp_event_context_update_cursor(event_context);
253             } else {
254                 lc->cursor_shape = cursor_crosshairs_xpm;
255                 lc->hot_x = 7;
256                 lc->hot_y = 7;
257                 sp_event_context_update_cursor(event_context);
258             }
259         }
260         break;
263     case GDK_BUTTON_RELEASE:
264     {
265         /**
266         break;
267         **/
268     }
270     case GDK_KEY_PRESS:
271         /**
272         switch (get_group0_keyval (&event->key)) {
273         }
274         break;
275         **/
277     case GDK_KEY_RELEASE:
278         /**
279         switch (get_group0_keyval(&event->key)) {
280             case GDK_Control_L:
281             case GDK_Control_R:
282                 dc->_message_context->clear();
283                 break;
284             default:
285                 break;
286         }
287         **/
289     default:
290         break;
291     }
293     if (!ret) {
294         if (((SPEventContextClass *) lpetool_parent_class)->root_handler) {
295             ret = ((SPEventContextClass *) lpetool_parent_class)->root_handler(event_context, event);
296         }
297     }
299     return ret;
302 /*
303  * Reads the limiting bounding box from preferences and draws it on the screen
304  */
305 // TODO: Note that currently the bbox is not user-settable; we simply use the page borders
306 void
307 lpetool_context_reset_limiting_bbox(SPLPEToolContext *lc)
309     if (lc->canvas_bbox) {
310         gtk_object_destroy(GTK_OBJECT(lc->canvas_bbox));
311         lc->canvas_bbox = NULL;
312     }
314     if (prefs_get_int_attribute("tools.lpetool", "show_bbox", 1) == 0)
315         return;
317     SPDocument *document = sp_desktop_document(lc->desktop);
318     Geom::Coord w = sp_document_width(document);
319     Geom::Coord h = sp_document_height(document);
321     Geom::Point A(0,0);
322     Geom::Point B(w,h);
324     Geom::Rect rect(A, B);
325     SPCurve *curve = SPCurve::new_from_rect(rect);
327     lc->canvas_bbox = sp_canvas_bpath_new (sp_desktop_controls(lc->desktop), curve);
328     sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(lc->canvas_bbox), 0x0000ffff, 0.8, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT, 5, 5);
331 /*
332   Local Variables:
333   mode:c++
334   c-file-style:"stroustrup"
335   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
336   indent-tabs-mode:nil
337   fill-column:99
338   End:
339 */
340 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :