diff options
| author | Liam P. White <inkscapebronyat-signgmaildotcom> | 2014-03-28 01:36:41 +0000 |
|---|---|---|
| committer | Liam P. White <inkscapebronyat-signgmaildotcom> | 2014-03-28 01:36:41 +0000 |
| commit | c1ecda53e4ce811681e6545f6158eb48c4a983a0 (patch) | |
| tree | 064de4eb4815f49ed736bc9c52c3b3d78251a61a /src | |
| parent | Update to trunk (diff) | |
| parent | Fix make check (diff) | |
| download | inkscape-c1ecda53e4ce811681e6545f6158eb48c4a983a0.tar.gz inkscape-c1ecda53e4ce811681e6545f6158eb48c4a983a0.zip | |
Update to trunk
(bzr r13090.1.35)
Diffstat (limited to 'src')
31 files changed, 2237 insertions, 1633 deletions
diff --git a/src/gradient-drag.cpp b/src/gradient-drag.cpp index 8a0d7ee26..7b9daf57e 100644 --- a/src/gradient-drag.cpp +++ b/src/gradient-drag.cpp @@ -803,7 +803,7 @@ static void gr_knot_moved_handler(SPKnot *knot, Geom::Point const &ppointer, gui m.unSetup(); if (s.getSnapped()) { p = s.getPoint(); - sp_knot_moveto (knot, p); + knot->moveto(p); } } else if (state & GDK_CONTROL_MASK) { IntermSnapResults isr; @@ -888,7 +888,7 @@ static void gr_knot_moved_handler(SPKnot *knot, Geom::Point const &ppointer, gui } //p = isr.points.front().getPoint(); p = bsp.getPoint(); - sp_knot_moveto (knot, p); + knot->moveto(p); } drag->keep_selection = (bool) g_list_find(drag->selected, dragger); @@ -989,8 +989,6 @@ static void gr_midpoint_limits(GrDragger *dragger, SPObject *server, Geom::Point *high_lim = dragger->point - (highest_dragger->point - *end); } - - /** * Called when a midpoint knot is dragged. */ @@ -1046,7 +1044,7 @@ static void gr_knot_moved_midpoint_handler(SPKnot */*knot*/, Geom::Point const & } } drg->point += this_move; - sp_knot_moveto (drgknot, drg->point); + drgknot->moveto(drg->point); drg->fireDraggables (false); drg->updateDependencies(false); } @@ -1388,7 +1386,7 @@ GrDragger::updateHandles ( Geom::Point pc_old, MeshNodeOperation op ) GrDragger *handle = drag->getDraggerFor( item, POINT_MG_HANDLE, i, fill_or_stroke ); SPKnot *knot = handle->knot; Geom::Point pk = getGradientCoords( item, POINT_MG_HANDLE, i, fill_or_stroke ); - sp_knot_moveto( knot, pk ); + knot->moveto(pk); } @@ -1397,7 +1395,7 @@ GrDragger::updateHandles ( Geom::Point pc_old, MeshNodeOperation op ) GrDragger *handle = drag->getDraggerFor( item, POINT_MG_TENSOR, i, fill_or_stroke ); SPKnot *knot = handle->knot; Geom::Point pk = getGradientCoords( item, POINT_MG_TENSOR, i, fill_or_stroke ); - sp_knot_moveto( knot, pk ); + knot->moveto(pk); } @@ -1483,7 +1481,7 @@ void GrDragger::moveThisToDraggable(SPItem *item, GrPointType point_type, gint p this->point = getGradientCoords(dr_first->item, dr_first->point_type, dr_first->point_i, dr_first->fill_or_stroke); this->point_original = this->point; - sp_knot_moveto(this->knot, this->point); + this->knot->moveto(this->point); for (GSList const* i = draggables; i != NULL; i = i->next) { GrDraggable *da = (GrDraggable *) i->data; @@ -1593,15 +1591,15 @@ GrDragger::GrDragger(GrDrag *parent, Geom::Point p, GrDraggable *draggable) this->parent = parent; // create the knot - this->knot = sp_knot_new (parent->desktop, NULL); + this->knot = new SPKnot(parent->desktop, NULL); this->knot->setMode(SP_KNOT_MODE_XOR); this->knot->setFill(GR_KNOT_COLOR_NORMAL, GR_KNOT_COLOR_MOUSEOVER, GR_KNOT_COLOR_MOUSEOVER); this->knot->setStroke(0x0000007f, 0x0000007f, 0x0000007f); - sp_knot_update_ctrl(this->knot); + this->knot->update_ctrl(); // move knot to the given point - sp_knot_set_position (this->knot, p, SP_KNOT_STATE_NORMAL); - sp_knot_show (this->knot); + this->knot->set_position(p, SP_KNOT_STATE_NORMAL); + this->knot->show(); // connect knot's signals if ( (draggable) // it can be NULL if a node in unsnapped (eg. focus point unsnapped from center) @@ -1610,18 +1608,21 @@ GrDragger::GrDragger(GrDrag *parent, Geom::Point p, GrDraggable *draggable) || (draggable->point_type == POINT_RG_MID1) || (draggable->point_type == POINT_RG_MID2) ) ) { - this->handler_id = g_signal_connect (G_OBJECT (this->knot), "moved", G_CALLBACK (gr_knot_moved_midpoint_handler), this); + this->_moved_connection = this->knot->_moved_signal.connect(sigc::bind(sigc::ptr_fun(gr_knot_moved_midpoint_handler), this)); } else { - this->handler_id = g_signal_connect (G_OBJECT (this->knot), "moved", G_CALLBACK (gr_knot_moved_handler), this); + this->_moved_connection = this->knot->_moved_signal.connect(sigc::bind(sigc::ptr_fun(gr_knot_moved_handler), this)); } - g_signal_connect (G_OBJECT (this->knot), "clicked", G_CALLBACK (gr_knot_clicked_handler), this); - g_signal_connect (G_OBJECT (this->knot), "doubleclicked", G_CALLBACK (gr_knot_doubleclicked_handler), this); - g_signal_connect (G_OBJECT (this->knot), "grabbed", G_CALLBACK (gr_knot_grabbed_handler), this); - g_signal_connect (G_OBJECT (this->knot), "ungrabbed", G_CALLBACK (gr_knot_ungrabbed_handler), this); + + this->_clicked_connection = this->knot->_click_signal.connect(sigc::bind(sigc::ptr_fun(gr_knot_clicked_handler), this)); + this->_doubleclicked_connection = this->knot->_doubleclicked_signal.connect(sigc::bind(sigc::ptr_fun(gr_knot_doubleclicked_handler), this)); + this->_grabbed_connection = this->knot->_grabbed_signal.connect(sigc::bind(sigc::ptr_fun(gr_knot_grabbed_handler), this)); + this->_ungrabbed_connection = this->knot->_ungrabbed_signal.connect(sigc::bind(sigc::ptr_fun(gr_knot_ungrabbed_handler), this)); // add the initial draggable - if (draggable) + if (draggable) { this->addDraggable (draggable); + } + updateKnotShape(); } @@ -1634,19 +1635,20 @@ GrDragger::~GrDragger() //this->parent->setDeselected(this); // disconnect signals - g_signal_handlers_disconnect_by_func(G_OBJECT(this->knot), (gpointer) G_CALLBACK (gr_knot_moved_handler), this); - g_signal_handlers_disconnect_by_func(G_OBJECT(this->knot), (gpointer) G_CALLBACK (gr_knot_clicked_handler), this); - g_signal_handlers_disconnect_by_func(G_OBJECT(this->knot), (gpointer) G_CALLBACK (gr_knot_doubleclicked_handler), this); - g_signal_handlers_disconnect_by_func(G_OBJECT(this->knot), (gpointer) G_CALLBACK (gr_knot_grabbed_handler), this); - g_signal_handlers_disconnect_by_func(G_OBJECT(this->knot), (gpointer) G_CALLBACK (gr_knot_ungrabbed_handler), this); + this->_moved_connection.disconnect(); + this->_clicked_connection.disconnect(); + this->_doubleclicked_connection.disconnect(); + this->_grabbed_connection.disconnect(); + this->_ungrabbed_connection.disconnect(); /* unref should call destroy */ - g_object_unref (G_OBJECT (this->knot)); + knot_unref(this->knot); // delete all draggables for (GSList const* i = this->draggables; i != NULL; i = i->next) { delete ((GrDraggable *) i->data); } + g_slist_free (this->draggables); this->draggables = NULL; } @@ -2043,7 +2045,7 @@ void GrDrag::addDraggersMesh(SPMeshGradient *mg, SPItem *item, Inkscape::PaintTa void GrDrag::grabKnot(GrDragger *dragger, gint x, gint y, guint32 etime) { if (dragger) { - sp_knot_start_dragging (dragger->knot, dragger->point, x, y, etime); + dragger->knot->start_dragging(dragger->point, x, y, etime); } } @@ -2055,7 +2057,7 @@ void GrDrag::grabKnot(SPItem *item, GrPointType point_type, gint point_i, Inksca { GrDragger *dragger = getDraggerFor(item, point_type, point_i, fill_or_stroke); if (dragger) { - sp_knot_start_dragging (dragger->knot, dragger->point, x, y, etime); + dragger->knot->start_dragging(dragger->point, x, y, etime); } } @@ -2358,7 +2360,7 @@ void GrDrag::selected_move(double x, double y, bool write_repr, bool scale_radia Geom::Point p_old = d->point; d->point += Geom::Point (x, y); d->point_original = d->point; - sp_knot_moveto (d->knot, d->point); + d->knot->moveto(d->point); d->fireDraggables (write_repr, scale_radial); d->updateHandles( p_old, MG_NODE_NO_SCALE ); @@ -2394,7 +2396,7 @@ void GrDrag::selected_move(double x, double y, bool write_repr, bool scale_radia GrDragger *drg = (GrDragger*) i->data; SPKnot *drgknot = drg->knot; drg->point += displacement; - sp_knot_moveto (drgknot, drg->point); + drgknot->moveto(drg->point); drg->fireDraggables (true); drg->updateDependencies(true); did = true; diff --git a/src/gradient-drag.h b/src/gradient-drag.h index 4ed13b9f7..e22b48e19 100644 --- a/src/gradient-drag.h +++ b/src/gradient-drag.h @@ -87,7 +87,13 @@ struct GrDragger { Geom::Point point_original; /** Connection to \a knot's "moved" signal, for blocking it (unused?). */ - guint handler_id; + //guint handler_id; + + sigc::connection _moved_connection; + sigc::connection _clicked_connection; + sigc::connection _doubleclicked_connection; + sigc::connection _grabbed_connection; + sigc::connection _ungrabbed_connection; GSList *draggables; diff --git a/src/knot-holder-entity.cpp b/src/knot-holder-entity.cpp index 043685460..48096489e 100644 --- a/src/knot-holder-entity.cpp +++ b/src/knot-holder-entity.cpp @@ -34,7 +34,7 @@ void KnotHolderEntity::create(SPDesktop *desktop, SPItem *item, KnotHolder *pare const gchar *tip, SPKnotShapeType shape, SPKnotModeType mode, guint32 color) { - knot = sp_knot_new(desktop, tip); + knot = new SPKnot(desktop, tip); this->parent_holder = parent; this->item = item; // TODO: remove the item either from here or from knotholder.cpp @@ -52,7 +52,7 @@ void KnotHolderEntity::create(SPDesktop *desktop, SPItem *item, KnotHolder *pare g_object_set (G_OBJECT(knot->item), "fill_color", color, NULL); update_knot(); - sp_knot_show(knot); + knot->show(); _moved_connection = knot->_moved_signal.connect(sigc::mem_fun(*parent_holder, &KnotHolder::knot_moved_handler)); _click_connection = knot->_click_signal.connect(sigc::mem_fun(*parent_holder, &KnotHolder::knot_clicked_handler)); @@ -68,7 +68,8 @@ KnotHolderEntity::~KnotHolderEntity() /* unref should call destroy */ if (knot) { - g_object_unref(knot); + //g_object_unref(knot); + knot_unref(knot); } else { // FIXME: This shouldn't occur. Perhaps it is caused by LPE PointParams being knotholder entities, too // If so, it will likely be fixed with upcoming refactoring efforts. @@ -84,7 +85,7 @@ KnotHolderEntity::update_knot() Geom::Point dp(knot_get() * i2dt); _moved_connection.block(); - sp_knot_set_position(knot, dp, SP_KNOT_STATE_NORMAL); + knot->set_position(dp, SP_KNOT_STATE_NORMAL); _moved_connection.unblock(); } diff --git a/src/knot.cpp b/src/knot.cpp index 2179bc3d5..59d048d8b 100644 --- a/src/knot.cpp +++ b/src/knot.cpp @@ -17,7 +17,6 @@ #endif #include <gdk/gdkkeysyms.h> #include <glibmm/i18n.h> -#include "helper/sp-marshal.h" #include "display/sodipodi-ctrl.h" #include "desktop.h" #include "desktop-handles.h" @@ -36,10 +35,11 @@ using Inkscape::DocumentUndo; GDK_POINTER_MOTION_HINT_MASK | \ GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK) -static bool nograb = false; +const gchar *nograbenv = getenv("INKSCAPE_NO_GRAB"); +static bool nograb = (nograbenv && *nograbenv && (*nograbenv != '0')); -static bool grabbed = FALSE; -static bool moved = FALSE; +static bool grabbed = false; +static bool moved = false; static gint xp = 0, yp = 0; // where drag started static gint tolerance = 0; @@ -47,247 +47,136 @@ static bool within_tolerance = false; static bool transform_escaped = false; // true iff resize or rotate was cancelled by esc. -enum { - EVENT, - CLICKED, - DOUBLECLICKED, - GRABBED, - UNGRABBED, - MOVED, - REQUEST, - DISTANCE, - LAST_SIGNAL -}; - -static void sp_knot_class_init(SPKnotClass *klass); -static void sp_knot_init(SPKnot *knot); -static void sp_knot_dispose(GObject *object); +void knot_ref(SPKnot* knot) { + knot->ref_count++; +} + +void knot_unref(SPKnot* knot) { + if (--knot->ref_count < 1) { + delete knot; + } +} + static int sp_knot_handler(SPCanvasItem *item, GdkEvent *event, SPKnot *knot); -static void sp_knot_set_ctrl_state(SPKnot *knot); -static GObjectClass *parent_class; -static guint knot_signals[LAST_SIGNAL] = { 0 }; +SPKnot::SPKnot(SPDesktop *desktop, const gchar *tip) : ref_count(1) { + this->desktop = NULL; + this->item = NULL; + this->owner = NULL; + this->flags = 0; -GType sp_knot_get_type() -{ - static GType type = 0; - if (!type) { - GTypeInfo info = { - sizeof(SPKnotClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) sp_knot_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (SPKnot), - 16, /* n_preallocs */ - (GInstanceInitFunc) sp_knot_init, - NULL - }; - type = g_type_register_static (G_TYPE_OBJECT, "SPKnot", &info, (GTypeFlags) 0); + this->size = 8; + this->pos = Geom::Point(0, 0); + this->grabbed_rel_pos = Geom::Point(0, 0); + this->anchor = SP_ANCHOR_CENTER; + this->shape = SP_KNOT_SHAPE_SQUARE; + this->mode = SP_KNOT_MODE_XOR; + this->tip = NULL; + this->_event_handler_id = 0; + this->pressure = 0; + + this->fill[SP_KNOT_STATE_NORMAL] = 0xffffff00; + this->fill[SP_KNOT_STATE_MOUSEOVER] = 0xff0000ff; + this->fill[SP_KNOT_STATE_DRAGGING] = 0x0000ffff; + + this->stroke[SP_KNOT_STATE_NORMAL] = 0x01000000; + this->stroke[SP_KNOT_STATE_MOUSEOVER] = 0x01000000; + this->stroke[SP_KNOT_STATE_DRAGGING] = 0x01000000; + + this->image[SP_KNOT_STATE_NORMAL] = NULL; + this->image[SP_KNOT_STATE_MOUSEOVER] = NULL; + this->image[SP_KNOT_STATE_DRAGGING] = NULL; + + this->cursor[SP_KNOT_STATE_NORMAL] = NULL; + this->cursor[SP_KNOT_STATE_MOUSEOVER] = NULL; + this->cursor[SP_KNOT_STATE_DRAGGING] = NULL; + + this->saved_cursor = NULL; + this->pixbuf = NULL; + + + this->desktop = desktop; + this->flags = SP_KNOT_VISIBLE; + + if (tip) { + this->tip = g_strdup (tip); } - return type; -} -/** - * SPKnot vtable initialization. - */ -static void sp_knot_class_init(SPKnotClass *klass) -{ - GObjectClass *object_class = (GObjectClass*)klass; - - parent_class = (GObjectClass*) g_type_class_peek_parent(klass); - - object_class->dispose = sp_knot_dispose; - - knot_signals[EVENT] = g_signal_new("event", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(SPKnotClass, event), - NULL, NULL, - sp_marshal_BOOLEAN__POINTER, - G_TYPE_BOOLEAN, 1, - GDK_TYPE_EVENT); - - knot_signals[CLICKED] = g_signal_new("clicked", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET(SPKnotClass, clicked), - NULL, NULL, - g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, 1, - G_TYPE_UINT); - - knot_signals[DOUBLECLICKED] = g_signal_new("doubleclicked", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET(SPKnotClass, doubleclicked), - NULL, NULL, - g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, 1, - G_TYPE_UINT); - - knot_signals[GRABBED] = g_signal_new("grabbed", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET(SPKnotClass, grabbed), - NULL, NULL, - g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, 1, - G_TYPE_UINT); - - knot_signals[UNGRABBED] = g_signal_new("ungrabbed", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET(SPKnotClass, ungrabbed), - NULL, NULL, - g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, 1, - G_TYPE_UINT); - - knot_signals[MOVED] = g_signal_new("moved", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET(SPKnotClass, moved), - NULL, NULL, - sp_marshal_NONE__POINTER_UINT, - G_TYPE_NONE, 2, - G_TYPE_POINTER, G_TYPE_UINT); - - knot_signals[REQUEST] = g_signal_new("request", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(SPKnotClass, request), - NULL, NULL, - sp_marshal_BOOLEAN__POINTER_UINT, - G_TYPE_BOOLEAN, 2, - G_TYPE_POINTER, G_TYPE_UINT); - - knot_signals[DISTANCE] = g_signal_new("distance", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(SPKnotClass, distance), - NULL, NULL, - sp_marshal_DOUBLE__POINTER_UINT, - G_TYPE_DOUBLE, 2, - G_TYPE_POINTER, G_TYPE_UINT); - - const gchar *nograbenv = getenv("INKSCAPE_NO_GRAB"); - nograb = (nograbenv && *nograbenv && (*nograbenv != '0')); -} + this->item = sp_canvas_item_new(sp_desktop_controls (desktop), + SP_TYPE_CTRL, + "anchor", SP_ANCHOR_CENTER, + "size", 8.0, + "filled", TRUE, + "fill_color", 0xffffff00, + "stroked", TRUE, + "stroke_color", 0x01000000, + "mode", SP_KNOT_MODE_XOR, + NULL); -/** - * Callback for SPKnot initialization. - */ -static void sp_knot_init(SPKnot *knot) -{ - knot->desktop = NULL; - knot->item = NULL; - knot->owner = NULL; - knot->flags = 0; - - knot->size = 8; - knot->pos = Geom::Point(0, 0); - knot->grabbed_rel_pos = Geom::Point(0, 0); - knot->anchor = SP_ANCHOR_CENTER; - knot->shape = SP_KNOT_SHAPE_SQUARE; - knot->mode = SP_KNOT_MODE_XOR; - knot->tip = NULL; - knot->_event_handler_id = 0; - knot->pressure = 0; - - knot->fill[SP_KNOT_STATE_NORMAL] = 0xffffff00; - knot->fill[SP_KNOT_STATE_MOUSEOVER] = 0xff0000ff; - knot->fill[SP_KNOT_STATE_DRAGGING] = 0x0000ffff; - - knot->stroke[SP_KNOT_STATE_NORMAL] = 0x01000000; - knot->stroke[SP_KNOT_STATE_MOUSEOVER] = 0x01000000; - knot->stroke[SP_KNOT_STATE_DRAGGING] = 0x01000000; - - knot->image[SP_KNOT_STATE_NORMAL] = NULL; - knot->image[SP_KNOT_STATE_MOUSEOVER] = NULL; - knot->image[SP_KNOT_STATE_DRAGGING] = NULL; - - knot->cursor[SP_KNOT_STATE_NORMAL] = NULL; - knot->cursor[SP_KNOT_STATE_MOUSEOVER] = NULL; - knot->cursor[SP_KNOT_STATE_DRAGGING] = NULL; - - knot->saved_cursor = NULL; - knot->pixbuf = NULL; + this->_event_handler_id = g_signal_connect(G_OBJECT(this->item), "event", + G_CALLBACK(sp_knot_handler), this); } -/** - * Called before SPKnot destruction. - */ -static void sp_knot_dispose(GObject *object) -{ - SPKnot *knot = static_cast<SPKnot *>(object); - +SPKnot::~SPKnot() { #if GTK_CHECK_VERSION(3,0,0) GdkDisplay *display = gdk_display_get_default(); GdkDeviceManager *dm = gdk_display_get_device_manager(display); GdkDevice *device = gdk_device_manager_get_client_pointer(dm); - if ((knot->flags & SP_KNOT_GRABBED) && gdk_display_device_is_grabbed(display, device)) { + if ((this->flags & SP_KNOT_GRABBED) && gdk_display_device_is_grabbed(display, device)) { // This happens e.g. when deleting a node in node tool while dragging it gdk_device_ungrab(device, GDK_CURRENT_TIME); } #else - if ((knot->flags & SP_KNOT_GRABBED) && gdk_pointer_is_grabbed ()) { + if ((this->flags & SP_KNOT_GRABBED) && gdk_pointer_is_grabbed ()) { // This happens e.g. when deleting a node in node tool while dragging it gdk_pointer_ungrab (GDK_CURRENT_TIME); } #endif - if (knot->_event_handler_id > 0) - { - g_signal_handler_disconnect(G_OBJECT (knot->item), knot->_event_handler_id); - knot->_event_handler_id = 0; - } + if (this->_event_handler_id > 0) { + g_signal_handler_disconnect(G_OBJECT (this->item), this->_event_handler_id); + this->_event_handler_id = 0; + } - if (knot->item) { - sp_canvas_item_destroy(knot->item); - knot->item = NULL; + if (this->item) { + sp_canvas_item_destroy(this->item); + this->item = NULL; } for (gint i = 0; i < SP_KNOT_VISIBLE_STATES; i++) { - if (knot->cursor[i]) { + if (this->cursor[i]) { #if GTK_CHECK_VERSION(3,0,0) - g_object_unref(knot->cursor[i]); + g_object_unref(this->cursor[i]); #else - gdk_cursor_unref(knot->cursor[i]); + gdk_cursor_unref(this->cursor[i]); #endif - knot->cursor[i] = NULL; + this->cursor[i] = NULL; } } - if (knot->tip) { - g_free(knot->tip); - knot->tip = NULL; - } - - if (parent_class->dispose) { - (*parent_class->dispose) (object); + if (this->tip) { + g_free(this->tip); + this->tip = NULL; } } -void sp_knot_start_dragging(SPKnot *knot, Geom::Point const &p, gint x, gint y, guint32 etime) -{ +void SPKnot::start_dragging(Geom::Point const &p, gint x, gint y, guint32 etime) { // save drag origin xp = x; yp = y; within_tolerance = true; - knot->grabbed_rel_pos = p - knot->pos; - knot->drag_origin = knot->pos; + this->grabbed_rel_pos = p - this->pos; + this->drag_origin = this->pos; + if (!nograb) { - sp_canvas_item_grab(knot->item, - KNOT_EVENT_MASK, - knot->cursor[SP_KNOT_STATE_DRAGGING], - etime); + sp_canvas_item_grab(this->item, KNOT_EVENT_MASK, this->cursor[SP_KNOT_STATE_DRAGGING], etime); } - sp_knot_set_flag(knot, SP_KNOT_GRABBED, TRUE); + + this->set_flag(SP_KNOT_GRABBED, TRUE); + grabbed = TRUE; } @@ -300,23 +189,21 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot g_assert(SP_IS_KNOT(knot)); /* Run client universal event handler, if present */ - - gboolean consumed = FALSE; - - g_signal_emit(knot, knot_signals[EVENT], 0, event, &consumed); + bool consumed = knot->_event_signal.emit(knot, event); if (consumed) { - return TRUE; + return true; } - g_object_ref(knot); + knot_ref(knot); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); switch (event->type) { case GDK_2BUTTON_PRESS: if (event->button.button == 1) { - g_signal_emit(knot, knot_signals[DOUBLECLICKED], 0, event->button.state); + knot->_doubleclicked_signal.emit(knot, event->button.state); grabbed = FALSE; moved = FALSE; @@ -326,7 +213,8 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot case GDK_BUTTON_PRESS: if ((event->button.button == 1) && knot->desktop && knot->desktop->event_context && !knot->desktop->event_context->space_panning) { Geom::Point const p = knot->desktop->w2d(Geom::Point(event->button.x, event->button.y)); - sp_knot_start_dragging(knot, p, (gint) event->button.x, (gint) event->button.y, event->button.time); + knot->start_dragging(p, (gint) event->button.x, (gint) event->button.y, event->button.time); + consumed = TRUE; } break; @@ -340,28 +228,25 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot sp_event_context_discard_delayed_snap_event(knot->desktop->event_context); knot->pressure = 0; + if (transform_escaped) { transform_escaped = false; consumed = TRUE; } else { - sp_knot_set_flag(knot, SP_KNOT_GRABBED, FALSE); + knot->set_flag(SP_KNOT_GRABBED, FALSE); + if (!nograb) { sp_canvas_item_ungrab(knot->item, event->button.time); } + if (moved) { - sp_knot_set_flag(knot, - SP_KNOT_DRAGGING, - FALSE); - g_signal_emit(knot, - knot_signals[UNGRABBED], 0, - event->button.state); - knot->_ungrabbed_signal.emit(knot); + knot->set_flag(SP_KNOT_DRAGGING, FALSE); + + knot->_ungrabbed_signal.emit(knot, event->button.state); } else { - g_signal_emit(knot, - knot_signals[CLICKED], 0, - event->button.state); knot->_click_signal.emit(knot, event->button.state); } + grabbed = FALSE; moved = FALSE; consumed = TRUE; @@ -383,27 +268,26 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot // motion notify coordinates as given (no snapping back to origin) within_tolerance = false; - if (gdk_event_get_axis (event, GDK_AXIS_PRESSURE, &knot->pressure)) + if (gdk_event_get_axis (event, GDK_AXIS_PRESSURE, &knot->pressure)) { knot->pressure = CLAMP (knot->pressure, 0, 1); - else + } else { knot->pressure = 0.5; + } if (!moved) { - g_signal_emit(knot, - knot_signals[GRABBED], 0, - event->motion.state); - sp_knot_set_flag(knot, - SP_KNOT_DRAGGING, - TRUE); + knot->_grabbed_signal.emit(knot, event->motion.state); + + knot->set_flag(SP_KNOT_DRAGGING, TRUE); } + sp_event_context_snap_delay_handler(knot->desktop->event_context, NULL, (gpointer) knot, (GdkEventMotion *)event, Inkscape::UI::Tools::DelayedSnapEvent::KNOT_HANDLER); sp_knot_handler_request_position(event, knot); moved = TRUE; } break; case GDK_ENTER_NOTIFY: - sp_knot_set_flag(knot, SP_KNOT_MOUSEOVER, TRUE); - sp_knot_set_flag(knot, SP_KNOT_GRABBED, FALSE); + knot->set_flag(SP_KNOT_MOUSEOVER, TRUE); + knot->set_flag(SP_KNOT_GRABBED, FALSE); if (knot->tip && knot->desktop && knot->desktop->event_context) { knot->desktop->event_context->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, knot->tip); @@ -414,8 +298,8 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot consumed = TRUE; break; case GDK_LEAVE_NOTIFY: - sp_knot_set_flag(knot, SP_KNOT_MOUSEOVER, FALSE); - sp_knot_set_flag(knot, SP_KNOT_GRABBED, FALSE); + knot->set_flag(SP_KNOT_MOUSEOVER, FALSE); + knot->set_flag(SP_KNOT_GRABBED, FALSE); if (knot->tip && knot->desktop && knot->desktop->event_context) { knot->desktop->event_context->defaultMessageContext()->clear(); @@ -428,24 +312,26 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot case GDK_KEY_PRESS: // keybindings for knot switch (Inkscape::UI::Tools::get_group0_keyval(&event->key)) { case GDK_KEY_Escape: - sp_knot_set_flag(knot, SP_KNOT_GRABBED, FALSE); + knot->set_flag(SP_KNOT_GRABBED, FALSE); + if (!nograb) { sp_canvas_item_ungrab(knot->item, event->button.time); } + if (moved) { - sp_knot_set_flag(knot, - SP_KNOT_DRAGGING, - FALSE); - g_signal_emit(knot, - knot_signals[UNGRABBED], 0, - event->button.state); + knot->set_flag(SP_KNOT_DRAGGING, FALSE); + + knot->_ungrabbed_signal.emit(knot, event->button.state); + DocumentUndo::undo(sp_desktop_document(knot->desktop)); knot->desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Node or handle drag canceled.")); transform_escaped = true; consumed = TRUE; } + grabbed = FALSE; moved = FALSE; + sp_event_context_discard_delayed_snap_event(knot->desktop->event_context); break; default: @@ -457,164 +343,82 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot break; } - g_object_unref(knot); + knot_unref(knot); return consumed || grabbed; } -void sp_knot_handler_request_position(GdkEvent *event, SPKnot *knot) -{ +void sp_knot_handler_request_position(GdkEvent *event, SPKnot *knot) { Geom::Point const motion_w(event->motion.x, event->motion.y); Geom::Point const motion_dt = knot->desktop->w2d(motion_w); Geom::Point p = motion_dt - knot->grabbed_rel_pos; - sp_knot_request_position (knot, p, event->motion.state); + + knot->request_position(p, event->motion.state); knot->desktop->scroll_to_point (motion_dt); knot->desktop->set_coordinate_status(knot->pos); // display the coordinate of knot, not cursor - they may be different! - if (event->motion.state & GDK_BUTTON1_MASK) - Inkscape::UI::Tools::gobble_motion_events(GDK_BUTTON1_MASK); -} - -SPKnot *sp_knot_new(SPDesktop *desktop, const gchar *tip) -{ - g_return_val_if_fail(desktop != NULL, NULL); - - SPKnot * knot = static_cast<SPKnot*>(g_object_new(SP_TYPE_KNOT, 0)); - knot->desktop = desktop; - knot->flags = SP_KNOT_VISIBLE; - if (tip) { - knot->tip = g_strdup (tip); + if (event->motion.state & GDK_BUTTON1_MASK) { + Inkscape::UI::Tools::gobble_motion_events(GDK_BUTTON1_MASK); } - - knot->item = sp_canvas_item_new(sp_desktop_controls (desktop), - SP_TYPE_CTRL, - "anchor", SP_ANCHOR_CENTER, - "size", 8.0, - "filled", TRUE, - "fill_color", 0xffffff00, - "stroked", TRUE, - "stroke_color", 0x01000000, - "mode", SP_KNOT_MODE_XOR, - NULL); - - knot->_event_handler_id = g_signal_connect(G_OBJECT(knot->item), "event", - G_CALLBACK(sp_knot_handler), knot); - - return knot; } -void sp_knot_show(SPKnot *knot) -{ - g_return_if_fail(knot != NULL); - g_return_if_fail(SP_IS_KNOT (knot)); - - sp_knot_set_flag(knot, SP_KNOT_VISIBLE, TRUE); +void SPKnot::show() { + this->set_flag(SP_KNOT_VISIBLE, TRUE); } -void sp_knot_hide(SPKnot *knot) -{ - g_return_if_fail(knot != NULL); - g_return_if_fail(SP_IS_KNOT(knot)); - - sp_knot_set_flag(knot, SP_KNOT_VISIBLE, FALSE); +void SPKnot::hide() { + this->set_flag(SP_KNOT_VISIBLE, FALSE); } -void sp_knot_request_position(SPKnot *knot, Geom::Point const &p, guint state) -{ - g_return_if_fail(knot != NULL); - g_return_if_fail(SP_IS_KNOT(knot)); - - gboolean done = FALSE; - - g_signal_emit(knot, - knot_signals[REQUEST], 0, - &p, - state, - &done); +void SPKnot::request_position(Geom::Point const &p, guint state) { + bool done = this->_request_signal.emit(this, &const_cast<Geom::Point&>(p), state); /* If user did not complete, we simply move knot to new position */ - if (!done) { - sp_knot_set_position (knot, p, state); + this->set_position(p, state); } } -gdouble sp_knot_distance(SPKnot * knot, Geom::Point const &p, guint state) -{ - g_return_val_if_fail(knot != NULL, 1e18); - g_return_val_if_fail(SP_IS_KNOT(knot), 1e18); - - gdouble distance = Geom::L2(p - knot->pos); +void SPKnot::set_position(Geom::Point const &p, guint state) { + this->pos = p; - g_signal_emit(knot, - knot_signals[DISTANCE], 0, - &p, - state, - &distance); - - return distance; -} - -void sp_knot_set_position(SPKnot *knot, Geom::Point const &p, guint state) -{ - g_return_if_fail(knot != NULL); - g_return_if_fail(SP_IS_KNOT (knot)); - - knot->pos = p; - - if (knot->item) { - SP_CTRL(knot->item)->moveto (p); + if (this->item) { + SP_CTRL(this->item)->moveto(p); } - g_signal_emit(knot, - knot_signals[MOVED], 0, - &p, - state); - knot->_moved_signal.emit(knot, p, state); + this->_moved_signal.emit(this, p, state); } -void sp_knot_moveto(SPKnot *knot, Geom::Point const &p) -{ - g_return_if_fail(knot != NULL); - g_return_if_fail(SP_IS_KNOT(knot)); - - knot->pos = p; +void SPKnot::moveto(Geom::Point const &p) { + this->pos = p; - if (knot->item) { - SP_CTRL(knot->item)->moveto (p); + if (this->item) { + SP_CTRL(this->item)->moveto(p); } } -Geom::Point sp_knot_position(SPKnot const *knot) -{ - g_assert(knot != NULL); - g_assert(SP_IS_KNOT (knot)); - - return knot->pos; +Geom::Point SPKnot::position() const { + return this->pos; } -void sp_knot_set_flag(SPKnot *knot, guint flag, bool set) -{ - g_assert(knot != NULL); - g_assert(SP_IS_KNOT(knot)); - +void SPKnot::set_flag(guint flag, bool set) { if (set) { - knot->flags |= flag; + this->flags |= flag; } else { - knot->flags &= ~flag; + this->flags &= ~flag; } switch (flag) { case SP_KNOT_VISIBLE: if (set) { - sp_canvas_item_show(knot->item); + sp_canvas_item_show(this->item); } else { - sp_canvas_item_hide(knot->item); + sp_canvas_item_hide(this->item); } break; case SP_KNOT_MOUSEOVER: case SP_KNOT_DRAGGING: - sp_knot_set_ctrl_state(knot); + this->set_ctrl_state(); break; case SP_KNOT_GRABBED: break; @@ -624,39 +428,130 @@ void sp_knot_set_flag(SPKnot *knot, guint flag, bool set) } } -void sp_knot_update_ctrl(SPKnot *knot) -{ - if (!knot->item) { +void SPKnot::update_ctrl() { + if (!this->item) { return; } - g_object_set(knot->item, "shape", knot->shape, NULL); - g_object_set(knot->item, "mode", knot->mode, NULL); - g_object_set(knot->item, "size", (gdouble) knot->size, NULL); - g_object_set(knot->item, "anchor", knot->anchor, NULL); - if (knot->pixbuf) { - g_object_set(knot->item, "pixbuf", knot->pixbuf, NULL); + g_object_set(this->item, "shape", this->shape, NULL); + g_object_set(this->item, "mode", this->mode, NULL); + g_object_set(this->item, "size", (gdouble) this->size, NULL); + g_object_set(this->item, "anchor", this->anchor, NULL); + + if (this->pixbuf) { + g_object_set(this->item, "pixbuf", this->pixbuf, NULL); } - sp_knot_set_ctrl_state(knot); + this->set_ctrl_state(); } -/** - * Set knot control state (dragging/mouseover/normal). - */ -static void sp_knot_set_ctrl_state(SPKnot *knot) -{ +void SPKnot::set_ctrl_state() { int state = SP_KNOT_STATE_NORMAL; - if (knot->flags & SP_KNOT_DRAGGING) { + + if (this->flags & SP_KNOT_DRAGGING) { state = SP_KNOT_STATE_DRAGGING; - } else if (knot->flags & SP_KNOT_MOUSEOVER) { + } else if (this->flags & SP_KNOT_MOUSEOVER) { state = SP_KNOT_STATE_MOUSEOVER; } - g_object_set(knot->item, "fill_color", knot->fill[state], NULL); - g_object_set(knot->item, "stroke_color", knot->stroke[state], NULL); + + g_object_set(this->item, "fill_color", this->fill[state], NULL); + g_object_set(this->item, "stroke_color", this->stroke[state], NULL); +} + + +void SPKnot::setSize(guint i) { + size = i; +} + +void SPKnot::setShape(guint i) { + shape = (SPKnotShapeType) i; +} + +void SPKnot::setAnchor(guint i) { + anchor = (SPAnchorType) i; +} + +void SPKnot::setMode(guint i) { + mode = (SPKnotModeType) i; +} + +void SPKnot::setPixbuf(gpointer p) { + pixbuf = p; } +void SPKnot::setFill(guint32 normal, guint32 mouseover, guint32 dragging) { + fill[SP_KNOT_STATE_NORMAL] = normal; + fill[SP_KNOT_STATE_MOUSEOVER] = mouseover; + fill[SP_KNOT_STATE_DRAGGING] = dragging; +} + +void SPKnot::setStroke(guint32 normal, guint32 mouseover, guint32 dragging) { + stroke[SP_KNOT_STATE_NORMAL] = normal; + stroke[SP_KNOT_STATE_MOUSEOVER] = mouseover; + stroke[SP_KNOT_STATE_DRAGGING] = dragging; +} +void SPKnot::setImage(guchar* normal, guchar* mouseover, guchar* dragging) { + image[SP_KNOT_STATE_NORMAL] = normal; + image[SP_KNOT_STATE_MOUSEOVER] = mouseover; + image[SP_KNOT_STATE_DRAGGING] = dragging; +} + +void SPKnot::setCursor(GdkCursor* normal, GdkCursor* mouseover, GdkCursor* dragging) { + if (cursor[SP_KNOT_STATE_NORMAL]) { +#if GTK_CHECK_VERSION(3,0,0) + g_object_unref(cursor[SP_KNOT_STATE_NORMAL]); +#else + gdk_cursor_unref(cursor[SP_KNOT_STATE_NORMAL]); +#endif + } + + cursor[SP_KNOT_STATE_NORMAL] = normal; + + if (normal) { +#if GTK_CHECK_VERSION(3,0,0) + g_object_ref(normal); +#else + gdk_cursor_ref(normal); +#endif + } + + if (cursor[SP_KNOT_STATE_MOUSEOVER]) { +#if GTK_CHECK_VERSION(3,0,0) + g_object_unref(cursor[SP_KNOT_STATE_MOUSEOVER]); +#else + gdk_cursor_unref(cursor[SP_KNOT_STATE_MOUSEOVER]); +#endif + } + + cursor[SP_KNOT_STATE_MOUSEOVER] = mouseover; + + if (mouseover) { +#if GTK_CHECK_VERSION(3,0,0) + g_object_ref(mouseover); +#else + gdk_cursor_ref(mouseover); +#endif + } + + if (cursor[SP_KNOT_STATE_DRAGGING]) { +#if GTK_CHECK_VERSION(3,0,0) + g_object_unref(cursor[SP_KNOT_STATE_DRAGGING]); +#else + gdk_cursor_unref(cursor[SP_KNOT_STATE_DRAGGING]); +#endif + } + + cursor[SP_KNOT_STATE_DRAGGING] = dragging; + + if (dragging) { +#if GTK_CHECK_VERSION(3,0,0) + g_object_ref(dragging); +#else + gdk_cursor_ref(dragging); +#endif + } +} /* Local Variables: diff --git a/src/knot.h b/src/knot.h index 4d87d703f..c8812a466 100644 --- a/src/knot.h +++ b/src/knot.h @@ -26,11 +26,8 @@ class SPDesktop; struct SPCanvasItem; -#define SP_TYPE_KNOT (sp_knot_get_type()) -#define SP_KNOT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_KNOT, SPKnot)) -#define SP_KNOT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_KNOT, SPKnotClass)) -#define SP_IS_KNOT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_KNOT)) -#define SP_IS_KNOT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_KNOT)) +#define SP_KNOT(obj) (dynamic_cast<SPKnot*>(static_cast<SPKnot*>(obj))) +#define SP_IS_KNOT(obj) (dynamic_cast<const SPKnot*>(static_cast<const SPKnot*>(obj)) != NULL) /** @@ -39,7 +36,15 @@ struct SPCanvasItem; * A knot is a draggable object, with callbacks to change something by * dragging it, visuably represented by a canvas item (mostly square). */ -struct SPKnot : GObject { +class SPKnot { +public: + SPKnot(SPDesktop *desktop, const gchar *tip); + virtual ~SPKnot(); + + + int ref_count; + + SPDesktop *desktop; /**< Desktop we are on. */ SPCanvasItem *item; /**< Our CanvasItem. */ SPItem *owner; /**< Optional Owner Item */ @@ -69,180 +74,94 @@ struct SPKnot : GObject { double pressure; /**< The tablet pen pressure when the knot is being dragged. */ - // C++ signals - /** - sigc::signal<void, Geom::Point const &, Geom::Point const &, guint> _moved_signal; - sigc::signal<void, guint> _click_signal; - sigc::signal<Geom::Point> _ungrabbed_signal; - **/ - sigc::signal<void, SPKnot *, Geom::Point const &, guint> _moved_signal; sigc::signal<void, SPKnot *, guint> _click_signal; - sigc::signal<void, SPKnot *> _ungrabbed_signal; + sigc::signal<void, SPKnot*, guint> _doubleclicked_signal; + sigc::signal<void, SPKnot*, guint> _grabbed_signal; + sigc::signal<void, SPKnot *, guint> _ungrabbed_signal; + sigc::signal<void, SPKnot *, Geom::Point const &, guint> _moved_signal; + sigc::signal<bool, SPKnot*, GdkEvent*> _event_signal; - //TODO: all the members above should eventualle become private, accessible via setters/getters - inline void setSize (guint i) {size = i;} - inline void setShape (guint i) {shape = (SPKnotShapeType) i;} - inline void setAnchor (guint i) {anchor = (SPAnchorType) i;} - inline void setMode (guint i) {mode = (SPKnotModeType) i;} - inline void setPixbuf (gpointer p) {pixbuf = p;} - inline void setFill (guint32 normal, guint32 mouseover, guint32 dragging) { - fill[SP_KNOT_STATE_NORMAL] = normal; - fill[SP_KNOT_STATE_MOUSEOVER] = mouseover; - fill[SP_KNOT_STATE_DRAGGING] = dragging; - } - inline void setStroke (guint32 normal, guint32 mouseover, guint32 dragging) { - stroke[SP_KNOT_STATE_NORMAL] = normal; - stroke[SP_KNOT_STATE_MOUSEOVER] = mouseover; - stroke[SP_KNOT_STATE_DRAGGING] = dragging; - } - inline void setImage (guchar* normal, guchar* mouseover, guchar* dragging) { - image[SP_KNOT_STATE_NORMAL] = normal; - image[SP_KNOT_STATE_MOUSEOVER] = mouseover; - image[SP_KNOT_STATE_DRAGGING] = dragging; - } - inline void setCursor (GdkCursor* normal, GdkCursor* mouseover, GdkCursor* dragging) { - if (cursor[SP_KNOT_STATE_NORMAL]) { -#if GTK_CHECK_VERSION(3,0,0) - g_object_unref(cursor[SP_KNOT_STATE_NORMAL]); -#else - gdk_cursor_unref(cursor[SP_KNOT_STATE_NORMAL]); -#endif - } - cursor[SP_KNOT_STATE_NORMAL] = normal; - if (normal) { -#if GTK_CHECK_VERSION(3,0,0) - g_object_ref(normal); -#else - gdk_cursor_ref(normal); -#endif - } - - if (cursor[SP_KNOT_STATE_MOUSEOVER]) { -#if GTK_CHECK_VERSION(3,0,0) - g_object_unref(cursor[SP_KNOT_STATE_MOUSEOVER]); -#else - gdk_cursor_unref(cursor[SP_KNOT_STATE_MOUSEOVER]); -#endif - } - cursor[SP_KNOT_STATE_MOUSEOVER] = mouseover; - if (mouseover) { -#if GTK_CHECK_VERSION(3,0,0) - g_object_ref(mouseover); -#else - gdk_cursor_ref(mouseover); -#endif - } - - if (cursor[SP_KNOT_STATE_DRAGGING]) { -#if GTK_CHECK_VERSION(3,0,0) - g_object_unref(cursor[SP_KNOT_STATE_DRAGGING]); -#else - gdk_cursor_unref(cursor[SP_KNOT_STATE_DRAGGING]); -#endif - } - cursor[SP_KNOT_STATE_DRAGGING] = dragging; - if (dragging) { -#if GTK_CHECK_VERSION(3,0,0) - g_object_ref(dragging); -#else - gdk_cursor_ref(dragging); -#endif - } - } + sigc::signal<bool, SPKnot*, Geom::Point*, guint> _request_signal; -}; -/// The SPKnot vtable. -struct SPKnotClass { - GObjectClass parent_class; - gint (* event) (SPKnot *knot, GdkEvent *event); - - /* - * These are unconditional. - */ + //TODO: all the members above should eventualle become private, accessible via setters/getters + void setSize(guint i); + void setShape(guint i); + void setAnchor(guint i); + void setMode(guint i); + void setPixbuf(gpointer p); - void (* clicked) (SPKnot *knot, guint state); - void (* doubleclicked) (SPKnot *knot, guint state); - void (* grabbed) (SPKnot *knot, guint state); - void (* ungrabbed) (SPKnot *knot, guint state); - void (* moved) (SPKnot *knot, Geom::Point const &position, guint state); - void (* stamped) (SPKnot *know, guint state); + void setFill(guint32 normal, guint32 mouseover, guint32 dragging); + void setStroke(guint32 normal, guint32 mouseover, guint32 dragging); + void setImage(guchar* normal, guchar* mouseover, guchar* dragging); - /** Request knot to move to absolute position. */ - bool (* request) (SPKnot *knot, Geom::Point const &pos, guint state); + void setCursor(GdkCursor* normal, GdkCursor* mouseover, GdkCursor* dragging); - /** Find complex distance from knot to point. */ - gdouble (* distance) (SPKnot *knot, Geom::Point const &pos, guint state); -}; + /** + * Show knot on its canvas. + */ + void show(); -/** - * Registers SPKnot class and returns its type number. - */ -GType sp_knot_get_type(); + /** + * Hide knot on its canvas. + */ + void hide(); -/** - * Return new knot object. - */ -SPKnot *sp_knot_new(SPDesktop *desktop, gchar const *tip = NULL); + /** + * Set flag in knot, with side effects. + */ + void set_flag(guint flag, bool set); -#define SP_KNOT_IS_VISIBLE(k) ((k->flags & SP_KNOT_VISIBLE) != 0) -#define SP_KNOT_IS_MOUSEOVER(k) ((k->flags & SP_KNOT_MOUSEOVER) != 0) -#define SP_KNOT_IS_DRAGGING(k) ((k->flags & SP_KNOT_DRAGGING) != 0) -#define SP_KNOT_IS_GRABBED(k) ((k->flags & SP_KNOT_GRABBED) != 0) + /** + * Update knot's pixbuf and set its control state. + */ + void update_ctrl(); -/** - * Show knot on its canvas. - */ -void sp_knot_show(SPKnot *knot); + /** + * Request or set new position for knot. + */ + void request_position(Geom::Point const &pos, guint state); -/** - * Hide knot on its canvas. - */ -void sp_knot_hide(SPKnot *knot); + /** + * Update knot for dragging and tell canvas an item was grabbed. + */ + void start_dragging(Geom::Point const &p, gint x, gint y, guint32 etime); -/** - * Set flag in knot, with side effects. - */ -void sp_knot_set_flag(SPKnot *knot, guint flag, bool set); + /** + * Move knot to new position and emits "moved" signal. + */ + void set_position(Geom::Point const &p, guint state); -/** - * Update knot's pixbuf and set its control state. - */ -void sp_knot_update_ctrl(SPKnot *knot); + /** + * Move knot to new position, without emitting a MOVED signal. + */ + void moveto(Geom::Point const &p); -/** - * Request or set new position for knot. - */ -void sp_knot_request_position(SPKnot *knot, Geom::Point const &pos, guint state); + /** + * Returns position of knot. + */ + Geom::Point position() const; -/** - * Return distance of point to knot's position; unused. - */ -gdouble sp_knot_distance(SPKnot *knot, Geom::Point const &p, guint state); +private: + SPKnot(const SPKnot&); + SPKnot& operator=(const SPKnot&); -/** - * Update knot for dragging and tell canvas an item was grabbed. - */ -void sp_knot_start_dragging(SPKnot *knot, Geom::Point const &p, gint x, gint y, guint32 etime); + /** + * Set knot control state (dragging/mouseover/normal). + */ + void set_ctrl_state(); +}; -/** - * Move knot to new position and emits "moved" signal. - */ -void sp_knot_set_position(SPKnot *knot, Geom::Point const &p, guint state); +void knot_ref(SPKnot* knot); +void knot_unref(SPKnot* knot); -/** - * Move knot to new position, without emitting a MOVED signal. - */ -void sp_knot_moveto(SPKnot *knot, Geom::Point const &p); +#define SP_KNOT_IS_VISIBLE(k) ((k->flags & SP_KNOT_VISIBLE) != 0) +#define SP_KNOT_IS_MOUSEOVER(k) ((k->flags & SP_KNOT_MOUSEOVER) != 0) +#define SP_KNOT_IS_DRAGGING(k) ((k->flags & SP_KNOT_DRAGGING) != 0) +#define SP_KNOT_IS_GRABBED(k) ((k->flags & SP_KNOT_GRABBED) != 0) void sp_knot_handler_request_position(GdkEvent *event, SPKnot *knot); -/** - * Returns position of knot. - */ -Geom::Point sp_knot_position(SPKnot const *knot); - - #endif // SEEN_SP_KNOT_H /* diff --git a/src/knotholder.cpp b/src/knotholder.cpp index bef89f3af..cf87423d4 100644 --- a/src/knotholder.cpp +++ b/src/knotholder.cpp @@ -63,14 +63,12 @@ KnotHolder::KnotHolder(SPDesktop *desktop, SPItem *item, SPKnotHolderReleasedFun g_print ("Error! Throw an exception, please!\n"); } - //g_object_ref(G_OBJECT(item)); // TODO: is this still needed after C++-ification? sp_object_ref(item); sizeUpdatedConn = ControlManager::getManager().connectCtrlSizeChanged(sigc::mem_fun(*this, &KnotHolder::updateControlSizes)); } KnotHolder::~KnotHolder() { - //g_object_unref(G_OBJECT(item)); sp_object_unref(item); for (std::list<KnotHolderEntity *>::iterator i = entity.begin(); i != entity.end(); ++i) @@ -187,7 +185,7 @@ KnotHolder::knot_moved_handler(SPKnot *knot, Geom::Point const &p, guint state) } void -KnotHolder::knot_ungrabbed_handler(SPKnot */*knot*/) +KnotHolder::knot_ungrabbed_handler(SPKnot */*knot*/, guint) { this->dragging = false; diff --git a/src/knotholder.h b/src/knotholder.h index fc91a56fc..d531ae288 100644 --- a/src/knotholder.h +++ b/src/knotholder.h @@ -48,7 +48,7 @@ public: void knot_moved_handler(SPKnot *knot, Geom::Point const &p, guint state); void knot_clicked_handler(SPKnot *knot, guint state); - void knot_ungrabbed_handler(SPKnot *knot); + void knot_ungrabbed_handler(SPKnot *knot, guint); void add(KnotHolderEntity *e); diff --git a/src/libuemf/uemf.h b/src/libuemf/uemf.h index a75ba801b..cde1b6c85 100644 --- a/src/libuemf/uemf.h +++ b/src/libuemf/uemf.h @@ -95,8 +95,8 @@ these WMF enumerations is by referencing the following table: /* File: uemf.h -Version: 0.0.25 -Date: 15-JAN-2014 +Version: 0.0.26 +Date: 27-MAR-2014 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu Copyright: 2014 David Mathog and California Institute of Technology (Caltech) @@ -129,6 +129,8 @@ extern "C" { #define U_SYSPAL_NOSTATIC 2 #define U_ELF_VENDOR_SIZE 4 + +#define UNUSED_PARAMETER(x) (void)(x) /** \endcond */ // *************************************************************************** diff --git a/src/libuemf/uemf_endian.c b/src/libuemf/uemf_endian.c index 8f2be57da..2d19361e1 100644 --- a/src/libuemf/uemf_endian.c +++ b/src/libuemf/uemf_endian.c @@ -19,8 +19,8 @@ /* File: uemf_endian.c -Version: 0.0.15 -Date: 24-MAR-2014 +Version: 0.0.16 +Date: 27-MAR-2014 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu Copyright: 2014 David Mathog and California Institute of Technology (Caltech) @@ -36,10 +36,6 @@ extern "C" { #include "uemf.h" #include "uemf_endian.h" -// Unfortunately, C does not allow unnamed function arguments, so use this macro instead... -#define UNUSED(x) (void)(x) - - // hide almost everuything in here from Doxygen //! \cond @@ -429,8 +425,7 @@ by end user code and to further that end prototypes are NOT provided and they ar // all core*_swap call this, U_EMRSETMARGN_swap and some others all it directly // numbered as core5 to be consistent with uemf.c, but must appear before the others as there is no prototype void core5_swap(char *record, int torev){ - UNUSED(torev); - + UNUSED_PARAMETER(torev); PU_ENHMETARECORD pEMR = (PU_ENHMETARECORD)(record); U_swap4(pEMR,2); // iType nSize } diff --git a/src/libuemf/upmf.c b/src/libuemf/upmf.c index 3c652c9b8..01f7ba3a4 100644 --- a/src/libuemf/upmf.c +++ b/src/libuemf/upmf.c @@ -21,8 +21,8 @@ /* File: upmf.c -Version: 0.0.5 -Date: 24-MAR-2014 +Version: 0.0.6 +Date: 26-MAR-2014 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu Copyright: 2014 David Mathog and California Institute of Technology (Caltech) diff --git a/src/libuemf/uwmf_endian.c b/src/libuemf/uwmf_endian.c index 5fbb450dc..38a321ad0 100644 --- a/src/libuemf/uwmf_endian.c +++ b/src/libuemf/uwmf_endian.c @@ -6,11 +6,11 @@ /* File: uwmf_endian.c -Version: 0.1.2 -Date: 18-FEB-2013 +Version: 0.1.3 +Date: 27-MAR-2014 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu -Copyright: 2012 David Mathog and California Institute of Technology (Caltech) +Copyright: 2014 David Mathog and California Institute of Technology (Caltech) */ #ifdef __cplusplus @@ -24,8 +24,6 @@ extern "C" { #include "uwmf.h" #include "uwmf_endian.h" -#define UNUSED(x) (void)(x) - // hide almost everything in this file from Doxygen //! \cond /* Prototypes for functions used here and defined in uemf_endian.c, but which are not supposed @@ -284,7 +282,7 @@ by end user code and to further that end prototypes are NOT provided and they ar /* Size16 EVERY record type should call this, directly or indirectly*/ void U_WMRCORE_SIZE16_swap(char *record, int torev){ - UNUSED(torev); + UNUSED_PARAMETER(torev); U_swap4(record, 1); /* Size16_4 is at offset 0 in U_METARECORD */ } @@ -309,7 +307,7 @@ void U_WMRCORE_U16_N16_swap(char *record, int torev){ /* all records that specify palette objects */ void U_WMRCORE_PALETTE_swap(char *record, int torev){ - UNUSED(torev); + UNUSED_PARAMETER(torev); U_WMRCORE_SIZE16_swap(record, torev); palette_swap(record + offsetof(U_WMRANIMATEPALETTE,Palette)); } @@ -702,7 +700,7 @@ void U_WMRDIBCREATEPATTERNBRUSH_swap(char *record, int torev){ } void U_WMRSTRETCHDIB_swap(char *record, int torev){ - UNUSED(torev); + UNUSED_PARAMETER(torev); U_WMRCORE_U32_N16_swap(record,9,torev); dibheader_swap(record + offsetof(U_WMRSTRETCHDIB,dib), torev); } diff --git a/src/menus-skeleton.h b/src/menus-skeleton.h index 273db4512..67e600edf 100644 --- a/src/menus-skeleton.h +++ b/src/menus-skeleton.h @@ -217,7 +217,7 @@ static char const menus_skeleton[] = " <separator/>\n" " <verb verb-id=\"DialogTransform\" />\n" " <verb verb-id=\"DialogAlignDistribute\" />\n" -" <verb verb-id=\"DialogGridArrange\" />\n" +" <verb verb-id=\"DialogArrange\" />\n" " </submenu>\n" " <submenu name=\"" N_("_Path") "\">\n" " <verb verb-id=\"ObjectToPath\" />\n" diff --git a/src/seltrans.cpp b/src/seltrans.cpp index a55bc3c0d..858985625 100644 --- a/src/seltrans.cpp +++ b/src/seltrans.cpp @@ -54,15 +54,15 @@ using Inkscape::ControlManager; using Inkscape::DocumentUndo; -static void sp_sel_trans_handle_grab(SPKnot *knot, guint state, gpointer data); -static void sp_sel_trans_handle_ungrab(SPKnot *knot, guint state, gpointer data); -static void sp_sel_trans_handle_click(SPKnot *knot, guint state, gpointer data); -static void sp_sel_trans_handle_new_event(SPKnot *knot, Geom::Point *position, guint32 state, gpointer data); -static gboolean sp_sel_trans_handle_request(SPKnot *knot, Geom::Point *p, guint state, gboolean *data); +static void sp_sel_trans_handle_grab(SPKnot *knot, guint state, SPSelTransHandle const* data); +static void sp_sel_trans_handle_ungrab(SPKnot *knot, guint state, SPSelTransHandle const* data); +static void sp_sel_trans_handle_click(SPKnot *knot, guint state, SPSelTransHandle const* data); +static void sp_sel_trans_handle_new_event(SPKnot *knot, Geom::Point const &position, guint32 state, SPSelTransHandle const* data); +static gboolean sp_sel_trans_handle_request(SPKnot *knot, Geom::Point *p, guint state, SPSelTransHandle const *data); extern GdkPixbuf *handles[]; -static gboolean sp_sel_trans_handle_event(SPKnot *knot, GdkEvent *event, gpointer) +static gboolean sp_sel_trans_handle_event(SPKnot *knot, GdkEvent *event, SPSelTransHandle const*) { switch (event->type) { case GDK_MOTION_NOTIFY: @@ -186,7 +186,7 @@ Inkscape::SelTrans::~SelTrans() _sel_modified_connection.disconnect(); for (int i = 0; i < NUMHANDS; i++) { - g_object_unref(G_OBJECT(knots[i])); + knot_unref(knots[i]); knots[i] = NULL; } @@ -574,7 +574,7 @@ void Inkscape::SelTrans::stamp() void Inkscape::SelTrans::_updateHandles() { for (int i = 0; i < NUMHANDS; i++) - sp_knot_hide(knots[i]); + knots[i]->hide(); if ( !_show_handles || _empty ) return; @@ -627,13 +627,13 @@ void Inkscape::SelTrans::_showHandles(SPSelTransType type) // Position knots to scale the selection bbox Geom::Point const bpos(hands[i].x, hands[i].y); Geom::Point p(_bbox->min() + (_bbox->dimensions() * Geom::Scale(bpos))); - sp_knot_moveto(knots[i], p); - sp_knot_show(knots[i]); + knots[i]->moveto(p); + knots[i]->show(); // This controls the center handle's position, because the default can // be moved and needs to be remembered. if( type == HANDLE_CENTER && _center ) - sp_knot_moveto(knots[i], *_center); + knots[i]->moveto(*_center); } } @@ -641,7 +641,7 @@ void Inkscape::SelTrans::_makeHandles() { for (int i = 0; i < NUMHANDS; i++) { SPSelTransTypeInfo info = handtypes[hands[i].type]; - knots[i] = sp_knot_new(_desktop, info.tip); + knots[i] = new SPKnot(_desktop, info.tip); knots[i]->setShape(SP_CTRL_SHAPE_BITMAP); knots[i]->setSize(13); @@ -650,50 +650,46 @@ void Inkscape::SelTrans::_makeHandles() knots[i]->setFill(info.color[0], info.color[1], info.color[2]); knots[i]->setStroke(info.color[3], info.color[4], info.color[5]); knots[i]->setPixbuf(handles[hands[i].control]); - sp_knot_update_ctrl(knots[i]); - - g_signal_connect(G_OBJECT(knots[i]), "request", - G_CALLBACK(sp_sel_trans_handle_request), (gpointer) &hands[i]); - g_signal_connect(G_OBJECT(knots[i]), "moved", - G_CALLBACK(sp_sel_trans_handle_new_event), (gpointer) &hands[i]); - g_signal_connect(G_OBJECT(knots[i]), "grabbed", - G_CALLBACK(sp_sel_trans_handle_grab), (gpointer) &hands[i]); - g_signal_connect(G_OBJECT(knots[i]), "ungrabbed", - G_CALLBACK(sp_sel_trans_handle_ungrab), (gpointer) &hands[i]); - g_signal_connect(G_OBJECT(knots[i]), "clicked", - G_CALLBACK(sp_sel_trans_handle_click), (gpointer) &hands[i]); - g_signal_connect(G_OBJECT(knots[i]), "event", - G_CALLBACK(sp_sel_trans_handle_event), (gpointer) &hands[i]); + knots[i]->update_ctrl(); + + knots[i]->_request_signal.connect(sigc::bind(sigc::ptr_fun(sp_sel_trans_handle_request), &hands[i])); + knots[i]->_moved_signal.connect(sigc::bind(sigc::ptr_fun(sp_sel_trans_handle_new_event), &hands[i])); + knots[i]->_grabbed_signal.connect(sigc::bind(sigc::ptr_fun(sp_sel_trans_handle_grab), &hands[i])); + knots[i]->_ungrabbed_signal.connect(sigc::bind(sigc::ptr_fun(sp_sel_trans_handle_ungrab), &hands[i])); + knots[i]->_click_signal.connect(sigc::bind(sigc::ptr_fun(sp_sel_trans_handle_click), &hands[i])); + knots[i]->_event_signal.connect(sigc::bind(sigc::ptr_fun(sp_sel_trans_handle_event), &hands[i])); } } -static void sp_sel_trans_handle_grab(SPKnot *knot, guint state, gpointer data) +static void sp_sel_trans_handle_grab(SPKnot *knot, guint state, SPSelTransHandle const* data) { SP_SELECT_CONTEXT(knot->desktop->event_context)->_seltrans->handleGrab( knot, state, *(SPSelTransHandle const *) data ); } -static void sp_sel_trans_handle_ungrab(SPKnot *knot, guint /*state*/, gpointer /*data*/) +static void sp_sel_trans_handle_ungrab(SPKnot *knot, guint /*state*/, SPSelTransHandle const* /*data*/) { SP_SELECT_CONTEXT(knot->desktop->event_context)->_seltrans->ungrab(); } -static void sp_sel_trans_handle_new_event(SPKnot *knot, Geom::Point *position, guint state, gpointer data) +static void sp_sel_trans_handle_new_event(SPKnot *knot, Geom::Point const& position, guint state, SPSelTransHandle const *data) { + Geom::Point pos = position; + SP_SELECT_CONTEXT(knot->desktop->event_context)->_seltrans->handleNewEvent( - knot, position, state, *(SPSelTransHandle const *) data + knot, &pos, state, *(SPSelTransHandle const *) data ); } -static gboolean sp_sel_trans_handle_request(SPKnot *knot, Geom::Point *position, guint state, gboolean *data) +static gboolean sp_sel_trans_handle_request(SPKnot *knot, Geom::Point *position, guint state, SPSelTransHandle const *data) { return SP_SELECT_CONTEXT(knot->desktop->event_context)->_seltrans->handleRequest( knot, position, state, *(SPSelTransHandle const *) data ); } -static void sp_sel_trans_handle_click(SPKnot *knot, guint state, gpointer data) +static void sp_sel_trans_handle_click(SPKnot *knot, guint state, SPSelTransHandle const* data) { SP_SELECT_CONTEXT(knot->desktop->event_context)->_seltrans->handleClick( knot, state, *(SPSelTransHandle const *) data @@ -742,7 +738,7 @@ void Inkscape::SelTrans::handleGrab(SPKnot *knot, guint /*state*/, SPSelTransHan break; } - grab(sp_knot_position(knot), handle.x, handle.y, FALSE, FALSE); + grab(knot->position(), handle.x, handle.y, FALSE, FALSE); } @@ -800,7 +796,7 @@ gboolean Inkscape::SelTrans::handleRequest(SPKnot *knot, Geom::Point *position, return TRUE; } if (request(handle, *position, state)) { - sp_knot_set_position(knot, *position, state); + knot->set_position(*position, state); SP_CTRL(_grip)->moveto(*position); if (handle.type == HANDLE_CENTER) { SP_CTRL(_norm)->moveto(*position); diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index c3e406e3f..7d80f1e36 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -69,6 +69,7 @@ set(ui_SRC dialog/floating-behavior.cpp dialog/font-substitution.cpp dialog/glyphs.cpp + dialog/grid-arrange-tab.cpp dialog/guides.cpp dialog/icon-preview.cpp dialog/inkscape-preferences.cpp @@ -83,6 +84,7 @@ set(ui_SRC dialog/object-attributes.cpp dialog/object-properties.cpp dialog/ocaldialogs.cpp + dialog/polar-arrange-tab.cpp dialog/print-colors-preview-dialog.cpp dialog/print.cpp dialog/symbols.cpp @@ -103,6 +105,7 @@ set(ui_SRC # dialog/whiteboard-sharewithchat.cpp # dialog/whiteboard-sharewithuser.cpp + widget/anchor-selector.cpp widget/button.cpp widget/color-picker.cpp widget/color-preview.cpp @@ -162,6 +165,7 @@ set(ui_SRC dialog/aboutbox.h dialog/align-and-distribute.h + dialog/arrange-tab.h dialog/behavior.h dialog/calligraphic-profile-rename.h dialog/color-item.h @@ -186,6 +190,7 @@ set(ui_SRC dialog/font-substitution.h dialog/glyphs.h dialog/guides.h + dialog/grid-arrange-tab.h dialog/icon-preview.h dialog/inkscape-preferences.h dialog/input.h @@ -200,6 +205,7 @@ set(ui_SRC dialog/object-properties.h dialog/ocaldialogs.h dialog/panel-dialog.h + dialog/polar-arrange-tab.h dialog/pixelartdialog.h dialog/print-colors-preview-dialog.h dialog/print.h @@ -259,6 +265,7 @@ set(ui_SRC tools/tweak-tool.h tools/zoom-tool.h + widget/anchor-selector.h widget/attr-widget.h widget/button.h widget/color-picker.h diff --git a/src/ui/dialog/Makefile_insert b/src/ui/dialog/Makefile_insert index 1cf667f2a..8a7a4a5dd 100644 --- a/src/ui/dialog/Makefile_insert +++ b/src/ui/dialog/Makefile_insert @@ -5,6 +5,7 @@ ink_common_sources += \ ui/dialog/aboutbox.h \ ui/dialog/align-and-distribute.cpp \ ui/dialog/align-and-distribute.h \ + ui/dialog/arrange-tab.h \ ui/dialog/behavior.h \ ui/dialog/calligraphic-profile-rename.h \ ui/dialog/calligraphic-profile-rename.cpp \ @@ -50,6 +51,8 @@ ink_common_sources += \ ui/dialog/floating-behavior.h \ ui/dialog/glyphs.cpp \ ui/dialog/glyphs.h \ + ui/dialog/grid-arrange-tab.h \ + ui/dialog/grid-arrange-tab.cpp \ ui/dialog/guides.cpp \ ui/dialog/guides.h \ ui/dialog/icon-preview.cpp \ @@ -79,6 +82,8 @@ ink_common_sources += \ ui/dialog/object-properties.cpp \ ui/dialog/object-properties.h \ ui/dialog/panel-dialog.h \ + ui/dialog/polar-arrange-tab.cpp \ + ui/dialog/polar-arrange-tab.h \ ui/dialog/print.cpp \ ui/dialog/print.h \ ui/dialog/print-colors-preview-dialog.cpp \ diff --git a/src/ui/dialog/arrange-tab.h b/src/ui/dialog/arrange-tab.h new file mode 100644 index 000000000..3ffe1ef4c --- /dev/null +++ b/src/ui/dialog/arrange-tab.h @@ -0,0 +1,54 @@ +/** + * @brief Arrange tools base class + */ +/* Authors: + * * Declara Denis + * Copyright (C) 2012 Authors + * + * Released under GNU GPL. Read the file 'COPYING' for more information. + */ + +#ifndef INKSCAPE_UI_DIALOG_ARRANGE_TAB_H +#define INKSCAPE_UI_DIALOG_ARRANGE_TAB_H + +#include <gtkmm/box.h> + +namespace Inkscape { +namespace UI { +namespace Dialog { + +/** + * This interface should be implemented by each arrange mode. + * The class is a Gtk::VBox and will be displayed as a tab in + * the dialog + */ +class ArrangeTab : public Gtk::VBox +{ +public: + ArrangeTab() {}; + virtual ~ArrangeTab() {}; + + /** + * Do the actual work! This method is invoked to actually arrange the + * selection + */ + virtual void arrange() = 0; +}; + +} //namespace Dialog +} //namespace UI +} //namespace Inkscape + + +#endif /* INKSCAPE_UI_DIALOG_ARRANGE_TAB_H */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/dialog-manager.cpp b/src/ui/dialog/dialog-manager.cpp index ddf41e0c8..ee11601f3 100644 --- a/src/ui/dialog/dialog-manager.cpp +++ b/src/ui/dialog/dialog-manager.cpp @@ -120,8 +120,8 @@ DialogManager::DialogManager() { // registerFactory("PrintColorsPreviewDialog", &create<PrintColorsPreviewDialog, FloatingBehavior>); registerFactory("SvgFontsDialog", &create<SvgFontsDialog, FloatingBehavior>); registerFactory("Swatches", &create<SwatchesPanel, FloatingBehavior>); + registerFactory("TileDialog", &create<ArrangeDialog, FloatingBehavior>); registerFactory("Symbols", &create<SymbolsDialog, FloatingBehavior>); - registerFactory("TileDialog", &create<TileDialog, FloatingBehavior>); registerFactory("Trace", &create<TraceDialog, FloatingBehavior>); registerFactory("PixelArt", &create<PixelArtDialog, FloatingBehavior>); registerFactory("Transformation", &create<Transformation, FloatingBehavior>); @@ -156,8 +156,8 @@ DialogManager::DialogManager() { // registerFactory("PrintColorsPreviewDialog", &create<PrintColorsPreviewDialog, DockBehavior>); registerFactory("SvgFontsDialog", &create<SvgFontsDialog, DockBehavior>); registerFactory("Swatches", &create<SwatchesPanel, DockBehavior>); + registerFactory("TileDialog", &create<ArrangeDialog, DockBehavior>); registerFactory("Symbols", &create<SymbolsDialog, DockBehavior>); - registerFactory("TileDialog", &create<TileDialog, DockBehavior>); registerFactory("Trace", &create<TraceDialog, DockBehavior>); registerFactory("PixelArt", &create<PixelArtDialog, DockBehavior>); registerFactory("Transformation", &create<Transformation, DockBehavior>); diff --git a/src/ui/dialog/grid-arrange-tab.cpp b/src/ui/dialog/grid-arrange-tab.cpp new file mode 100644 index 000000000..8c0a4dc66 --- /dev/null +++ b/src/ui/dialog/grid-arrange-tab.cpp @@ -0,0 +1,809 @@ +/* + * A simple dialog for creating grid type arrangements of selected objects + * + * Authors: + * Bob Jamison ( based off trace dialog) + * John Cliff + * Other dudes from The Inkscape Organization + * Abhishek Sharma + * Declara Denis + * + * Copyright (C) 2004 Bob Jamison + * Copyright (C) 2004 John Cliff + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ +//#define DEBUG_GRID_ARRANGE 1 + +#include "ui/dialog/grid-arrange-tab.h" +#include <gtk/gtk.h> //for GTK_RESPONSE* types +#include <glibmm/i18n.h> +#include <gtkmm/stock.h> + +#if WITH_GTKMM_3_0 +# include <gtkmm/grid.h> +#else +# include <gtkmm/table.h> +#endif + +#include <2geom/transforms.h> + +#include "verbs.h" +#include "preferences.h" +#include "inkscape.h" +#include "desktop-handles.h" +#include "selection.h" +#include "document.h" +#include "document-undo.h" +#include "sp-item.h" +#include "widgets/icon.h" +#include "desktop.h" +//#include "sp-item-transform.h" FIXME +#include "ui/dialog/tile.h" // for Inkscape::UI::Dialog::ArrangeDialog + +/* + * Sort items by their x co-ordinates, taking account of y (keeps rows intact) + * + * <0 *elem1 goes before *elem2 + * 0 *elem1 == *elem2 + * >0 *elem1 goes after *elem2 + */ +static int sp_compare_x_position(SPItem *first, SPItem *second) +{ + using Geom::X; + using Geom::Y; + + Geom::OptRect a = first->documentVisualBounds(); + Geom::OptRect b = second->documentVisualBounds(); + + if ( !a || !b ) { + // FIXME? + return 0; + } + + double const a_height = a->dimensions()[Y]; + double const b_height = b->dimensions()[Y]; + + bool a_in_b_vert = false; + if ((a->min()[Y] < b->min()[Y] + 0.1) && (a->min()[Y] > b->min()[Y] - b_height)) { + a_in_b_vert = true; + } else if ((b->min()[Y] < a->min()[Y] + 0.1) && (b->min()[Y] > a->min()[Y] - a_height)) { + a_in_b_vert = true; + } else if (b->min()[Y] == a->min()[Y]) { + a_in_b_vert = true; + } else { + a_in_b_vert = false; + } + + if (!a_in_b_vert) { + return -1; + } + if (a_in_b_vert && a->min()[X] > b->min()[X]) { + return 1; + } + if (a_in_b_vert && a->min()[X] < b->min()[X]) { + return -1; + } + return 0; +} + +/* + * Sort items by their y co-ordinates. + */ +static int sp_compare_y_position(SPItem *first, SPItem *second) +{ + Geom::OptRect a = first->documentVisualBounds(); + Geom::OptRect b = second->documentVisualBounds(); + + if ( !a || !b ) { + // FIXME? + return 0; + } + + if (a->min()[Geom::Y] > b->min()[Geom::Y]) { + return 1; + } + if (a->min()[Geom::Y] < b->min()[Geom::Y]) { + return -1; + } + + return 0; +} + +namespace Inkscape { +namespace UI { +namespace Dialog { + + +//######################################################################### +//## E V E N T S +//######################################################################### + +/* + * + * This arranges the selection in a grid pattern. + * + */ + +void GridArrangeTab::arrange() +{ + + int cnt,row_cnt,col_cnt,a,row,col; + double grid_left,grid_top,col_width,row_height,paddingx,paddingy,width, height, new_x, new_y; + double total_col_width,total_row_height; + col_width = 0; + row_height = 0; + total_col_width=0; + total_row_height=0; + + // check for correct numbers in the row- and col-spinners + on_col_spinbutton_changed(); + on_row_spinbutton_changed(); + + // set padding to manual values + paddingx = XPadding.getValue("px"); + paddingy = YPadding.getValue("px"); + + std::vector<double> row_heights; + std::vector<double> col_widths; + std::vector<double> row_ys; + std::vector<double> col_xs; + + int NoOfCols = NoOfColsSpinner.get_value_as_int(); + int NoOfRows = NoOfRowsSpinner.get_value_as_int(); + + width = 0; + for (a=0;a<NoOfCols; a++){ + col_widths.push_back(width); + } + + height = 0; + for (a=0;a<NoOfRows; a++){ + row_heights.push_back(height); + } + grid_left = 99999; + grid_top = 99999; + + SPDesktop *desktop = Parent->getDesktop(); + sp_desktop_document(desktop)->ensureUpToDate(); + + Inkscape::Selection *selection = sp_desktop_selection (desktop); + const GSList *items = selection ? selection->itemList() : 0; + cnt=0; + for (; items != NULL; items = items->next) { + SPItem *item = SP_ITEM(items->data); + Geom::OptRect b = item->documentVisualBounds(); + if (!b) { + continue; + } + + width = b->dimensions()[Geom::X]; + height = b->dimensions()[Geom::Y]; + + if (b->min()[Geom::X] < grid_left) { + grid_left = b->min()[Geom::X]; + } + if (b->min()[Geom::Y] < grid_top) { + grid_top = b->min()[Geom::Y]; + } + if (width > col_width) { + col_width = width; + } + if (height > row_height) { + row_height = height; + } + } + + + // require the sorting done before we can calculate row heights etc. + + g_return_if_fail(selection); + const GSList *items2 = selection->itemList(); + GSList *rev = g_slist_copy(const_cast<GSList *>(items2)); + GSList *sorted = NULL; + rev = g_slist_sort(rev, (GCompareFunc) sp_compare_y_position); + sorted = g_slist_sort(rev, (GCompareFunc) sp_compare_x_position); + + + // Calculate individual Row and Column sizes if necessary + + + cnt=0; + const GSList *sizes = sorted; + for (; sizes != NULL; sizes = sizes->next) { + SPItem *item = SP_ITEM(sizes->data); + Geom::OptRect b = item->documentVisualBounds(); + if (b) { + width = b->dimensions()[Geom::X]; + height = b->dimensions()[Geom::Y]; + if (width > col_widths[(cnt % NoOfCols)]) { + col_widths[(cnt % NoOfCols)] = width; + } + if (height > row_heights[(cnt / NoOfCols)]) { + row_heights[(cnt / NoOfCols)] = height; + } + } + + cnt++; + } + + + /// Make sure the top and left of the grid dont move by compensating for align values. + if (RowHeightButton.get_active()){ + grid_top = grid_top - (((row_height - row_heights[0]) / 2)*(VertAlign)); + } + if (ColumnWidthButton.get_active()){ + grid_left = grid_left - (((col_width - col_widths[0]) /2)*(HorizAlign)); + } + + #ifdef DEBUG_GRID_ARRANGE + g_print("\n cx = %f cy= %f gridleft=%f",cx,cy,grid_left); + #endif + + // Calculate total widths and heights, allowing for columns and rows non uniformly sized. + + if (ColumnWidthButton.get_active()){ + total_col_width = col_width * NoOfCols; + col_widths.clear(); + for (a=0;a<NoOfCols; a++){ + col_widths.push_back(col_width); + } + } else { + for (a = 0; a < (int)col_widths.size(); a++) + { + total_col_width += col_widths[a] ; + } + } + + if (RowHeightButton.get_active()){ + total_row_height = row_height * NoOfRows; + row_heights.clear(); + for (a=0;a<NoOfRows; a++){ + row_heights.push_back(row_height); + } + } else { + for (a = 0; a < (int)row_heights.size(); a++) + { + total_row_height += row_heights[a] ; + } + } + + + Geom::OptRect sel_bbox = selection->visualBounds(); + // Fit to bbox, calculate padding between rows accordingly. + if ( sel_bbox && !SpaceManualRadioButton.get_active() ){ +#ifdef DEBUG_GRID_ARRANGE +g_print("\n row = %f col = %f selection x= %f selection y = %f", total_row_height,total_col_width, b.extent(Geom::X), b.extent(Geom::Y)); +#endif + paddingx = (sel_bbox->width() - total_col_width) / (NoOfCols -1); + paddingy = (sel_bbox->height() - total_row_height) / (NoOfRows -1); + } + +/* + Horizontal align - Left = 0 + Centre = 1 + Right = 2 + + Vertical align - Top = 0 + Middle = 1 + Bottom = 2 + + X position is calculated by taking the grids left co-ord, adding the distance to the column, + then adding 1/2 the spacing multiplied by the align variable above, + Y position likewise, takes the top of the grid, adds the y to the current row then adds the padding in to align it. + +*/ + + // Calculate row and column x and y coords required to allow for columns and rows which are non uniformly sized. + + for (a=0;a<NoOfCols; a++){ + if (a<1) col_xs.push_back(0); + else col_xs.push_back(col_widths[a-1]+paddingx+col_xs[a-1]); + } + + + for (a=0;a<NoOfRows; a++){ + if (a<1) row_ys.push_back(0); + else row_ys.push_back(row_heights[a-1]+paddingy+row_ys[a-1]); + } + + cnt=0; + for (row_cnt=0; ((sorted != NULL) && (row_cnt<NoOfRows)); row_cnt++) { + + GSList *current_row = NULL; + for (col_cnt = 0; ((sorted != NULL) && (col_cnt<NoOfCols)); col_cnt++) { + current_row = g_slist_append (current_row, sorted->data); + sorted = sorted->next; + } + + for (; current_row != NULL; current_row = current_row->next) { + SPItem *item=SP_ITEM(current_row->data); + Inkscape::XML::Node *repr = item->getRepr(); + Geom::OptRect b = item->documentVisualBounds(); + Geom::Point min; + if (b) { + width = b->dimensions()[Geom::X]; + height = b->dimensions()[Geom::Y]; + min = b->min(); + } else { + width = height = 0; + min = Geom::Point(0, 0); + } + + row = cnt / NoOfCols; + col = cnt % NoOfCols; + + new_x = grid_left + (((col_widths[col] - width)/2)*HorizAlign) + col_xs[col]; + new_y = grid_top + (((row_heights[row] - height)/2)*VertAlign) + row_ys[row]; + + // signs are inverted between x and y due to y inversion + Geom::Point move = Geom::Point(new_x - min[Geom::X], min[Geom::Y] - new_y); + Geom::Affine const affine = Geom::Affine(Geom::Translate(move)); + item->set_i2d_affine(item->i2dt_affine() * affine); + item->doWriteTransform(repr, item->transform, NULL); + SP_OBJECT (current_row->data)->updateRepr(); + cnt +=1; + } + g_slist_free (current_row); + } + + DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_SELECTION_ARRANGE, + _("Arrange in a grid")); + +} + + +//######################################################################### +//## E V E N T S +//######################################################################### + +/** + * changed value in # of columns spinbox. + */ +void GridArrangeTab::on_row_spinbutton_changed() +{ + // quit if run by the attr_changed listener + if (updating) { + return; + } + + // in turn, prevent listener from responding + updating = true; + SPDesktop *desktop = Parent->getDesktop(); + + Inkscape::Selection *selection = desktop ? desktop->selection : 0; + g_return_if_fail( selection ); + + GSList const *items = selection->itemList(); + int selcount = g_slist_length((GSList *)items); + + double PerCol = ceil(selcount / NoOfColsSpinner.get_value()); + NoOfRowsSpinner.set_value(PerCol); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble("/dialogs/gridtiler/NoOfCols", NoOfColsSpinner.get_value()); + updating=false; +} + +/** + * changed value in # of rows spinbox. + */ +void GridArrangeTab::on_col_spinbutton_changed() +{ + // quit if run by the attr_changed listener + if (updating) { + return; + } + + // in turn, prevent listener from responding + updating = true; + SPDesktop *desktop = Parent->getDesktop(); + Inkscape::Selection *selection = desktop ? desktop->selection : 0; + g_return_if_fail(selection); + + GSList const *items = selection->itemList(); + int selcount = g_slist_length((GSList *)items); + + double PerRow = ceil(selcount / NoOfRowsSpinner.get_value()); + NoOfColsSpinner.set_value(PerRow); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble("/dialogs/gridtiler/NoOfCols", PerRow); + + updating=false; +} + +/** + * changed value in x padding spinbox. + */ +void GridArrangeTab::on_xpad_spinbutton_changed() +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble("/dialogs/gridtiler/XPad", XPadding.getValue("px")); + +} + +/** + * changed value in y padding spinbox. + */ +void GridArrangeTab::on_ypad_spinbutton_changed() +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble("/dialogs/gridtiler/YPad", YPadding.getValue("px")); +} + + +/** + * checked/unchecked autosize Rows button. + */ +void GridArrangeTab::on_RowSize_checkbutton_changed() +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (RowHeightButton.get_active()) { + prefs->setDouble("/dialogs/gridtiler/AutoRowSize", 20); + } else { + prefs->setDouble("/dialogs/gridtiler/AutoRowSize", -20); + } + RowHeightBox.set_sensitive ( !RowHeightButton.get_active()); +} + +/** + * checked/unchecked autosize Rows button. + */ +void GridArrangeTab::on_ColSize_checkbutton_changed() +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (ColumnWidthButton.get_active()) { + prefs->setDouble("/dialogs/gridtiler/AutoColSize", 20); + } else { + prefs->setDouble("/dialogs/gridtiler/AutoColSize", -20); + } + ColumnWidthBox.set_sensitive ( !ColumnWidthButton.get_active()); +} + +/** + * changed value in columns spinbox. + */ +void GridArrangeTab::on_rowSize_spinbutton_changed() +{ + // quit if run by the attr_changed listener + if (updating) { + return; + } + + // in turn, prevent listener from responding + updating = true; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble("/dialogs/gridtiler/RowHeight", RowHeightSpinner.get_value()); + updating=false; + +} + +/** + * changed value in rows spinbox. + */ +void GridArrangeTab::on_colSize_spinbutton_changed() +{ + // quit if run by the attr_changed listener + if (updating) { + return; + } + + // in turn, prevent listener from responding + updating = true; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble("/dialogs/gridtiler/ColWidth", ColumnWidthSpinner.get_value()); + updating=false; + +} + +/** + * changed Radio button in Spacing group. + */ +void GridArrangeTab::Spacing_button_changed() +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (SpaceManualRadioButton.get_active()) { + prefs->setDouble("/dialogs/gridtiler/SpacingType", 20); + } else { + prefs->setDouble("/dialogs/gridtiler/SpacingType", -20); + } + + XPadding.set_sensitive ( SpaceManualRadioButton.get_active()); + YPadding.set_sensitive ( SpaceManualRadioButton.get_active()); +} + +/** + * changed Anchor selection widget. + */ +void GridArrangeTab::Align_changed() +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + VertAlign = AlignmentSelector.getVerticalAlignment(); + prefs->setInt("/dialogs/gridtiler/VertAlign", VertAlign); + HorizAlign = AlignmentSelector.getHorizontalAlignment(); + prefs->setInt("/dialogs/gridtiler/HorizAlign", HorizAlign); +} + +/** + * Desktop selection changed + */ +void GridArrangeTab::updateSelection() +{ + // quit if run by the attr_changed listener + if (updating) { + return; + } + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + // in turn, prevent listener from responding + updating = true; + SPDesktop *desktop = Parent->getDesktop(); + Inkscape::Selection *selection = desktop ? desktop->selection : 0; + GSList const *items = selection ? selection->itemList() : 0; + + if (items) { + int selcount = g_slist_length((GSList *)items); + + if (NoOfColsSpinner.get_value() > 1 && NoOfRowsSpinner.get_value() > 1){ + // Update the number of rows assuming number of columns wanted remains same. + double NoOfRows = ceil(selcount / NoOfColsSpinner.get_value()); + NoOfRowsSpinner.set_value(NoOfRows); + + // if the selection has less than the number set for one row, reduce it appropriately + if (selcount < NoOfColsSpinner.get_value()) { + double NoOfCols = ceil(selcount / NoOfRowsSpinner.get_value()); + NoOfColsSpinner.set_value(NoOfCols); + prefs->setInt("/dialogs/gridtiler/NoOfCols", NoOfCols); + } + } else { + double PerRow = ceil(sqrt(selcount)); + double PerCol = ceil(sqrt(selcount)); + NoOfRowsSpinner.set_value(PerRow); + NoOfColsSpinner.set_value(PerCol); + prefs->setInt("/dialogs/gridtiler/NoOfCols", static_cast<int>(PerCol)); + } + } + + updating = false; +} + + + +/*########################## +## Experimental +##########################*/ + +static void updateSelectionCallback(Inkscape::Application */*inkscape*/, Inkscape::Selection */*selection*/, GridArrangeTab *dlg) +{ + dlg->updateSelection(); +} + + +//######################################################################### +//## C O N S T R U C T O R / D E S T R U C T O R +//######################################################################### +/** + * Constructor + */ +GridArrangeTab::GridArrangeTab(ArrangeDialog *parent) + : Parent(parent), + XPadding(_("X:"), _("Horizontal spacing between columns."), UNIT_TYPE_LINEAR, "", "object-columns", &PaddingUnitMenu), + YPadding(_("Y:"), _("Vertical spacing between rows."), XPadding, "", "object-rows", &PaddingUnitMenu), +#if WITH_GTKMM_3_0 + PaddingTable(Gtk::manage(new Gtk::Grid())) +#else + PaddingTable(Gtk::manage(new Gtk::Table(2, 2, false))) +#endif +{ + // bool used by spin button callbacks to stop loops where they change each other. + updating = false; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + // could not do this in gtkmm - there's no Gtk::SizeGroup public constructor (!) + GtkSizeGroup *_col1 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); + GtkSizeGroup *_col2 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); + GtkSizeGroup *_col3 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); + + { + // Selection Change signal + g_signal_connect ( G_OBJECT (INKSCAPE), "change_selection", G_CALLBACK (updateSelectionCallback), this); + } + + Gtk::Box *contents = this; + +#define MARGIN 2 + + //##Set up the panel + + SPDesktop *desktop = Parent->getDesktop(); + + Inkscape::Selection *selection = desktop ? desktop->selection : 0; + g_return_if_fail( selection ); + int selcount = 1; + if (!selection->isEmpty()) { + GSList const *items = selection->itemList(); + selcount = g_slist_length((GSList *)items); + } + + + /*#### Number of Rows ####*/ + + double PerRow = ceil(sqrt(selcount)); + double PerCol = ceil(sqrt(selcount)); + + #ifdef DEBUG_GRID_ARRANGE + g_print("/n PerRox = %f PerCol = %f selcount = %d",PerRow,PerCol,selcount); + #endif + + NoOfRowsLabel.set_text_with_mnemonic(_("_Rows:")); + NoOfRowsLabel.set_mnemonic_widget(NoOfRowsSpinner); + NoOfRowsBox.pack_start(NoOfRowsLabel, false, false, MARGIN); + + NoOfRowsSpinner.set_digits(0); + NoOfRowsSpinner.set_increments(1, 0); + NoOfRowsSpinner.set_range(1.0, 10000.0); + NoOfRowsSpinner.set_value(PerCol); + NoOfRowsSpinner.signal_changed().connect(sigc::mem_fun(*this, &GridArrangeTab::on_col_spinbutton_changed)); + NoOfRowsSpinner.set_tooltip_text(_("Number of rows")); + NoOfRowsBox.pack_start(NoOfRowsSpinner, false, false, MARGIN); + gtk_size_group_add_widget(_col1, (GtkWidget *) NoOfRowsBox.gobj()); + + RowHeightButton.set_label(_("Equal _height")); + RowHeightButton.set_use_underline(true); + double AutoRow = prefs->getDouble("/dialogs/gridtiler/AutoRowSize", 15); + if (AutoRow>0) + AutoRowSize=true; + else + AutoRowSize=false; + RowHeightButton.set_active(AutoRowSize); + + NoOfRowsBox.pack_start(RowHeightButton, false, false, MARGIN); + + RowHeightButton.set_tooltip_text(_("If not set, each row has the height of the tallest object in it")); + RowHeightButton.signal_toggled().connect(sigc::mem_fun(*this, &GridArrangeTab::on_RowSize_checkbutton_changed)); + + SpinsHBox.pack_start(NoOfRowsBox, false, false, MARGIN); + + + /*#### Label for X ####*/ + padXByYLabel.set_label(" "); + XByYLabelVBox.pack_start(padXByYLabel, false, false, MARGIN); + XByYLabel.set_markup(" × "); + XByYLabelVBox.pack_start(XByYLabel, false, false, MARGIN); + SpinsHBox.pack_start(XByYLabelVBox, false, false, MARGIN); + gtk_size_group_add_widget(_col2, GTK_WIDGET(XByYLabelVBox.gobj())); + + /*#### Number of columns ####*/ + + NoOfColsLabel.set_text_with_mnemonic(_("_Columns:")); + NoOfColsLabel.set_mnemonic_widget(NoOfColsSpinner); + NoOfColsBox.pack_start(NoOfColsLabel, false, false, MARGIN); + + NoOfColsSpinner.set_digits(0); + NoOfColsSpinner.set_increments(1, 0); + NoOfColsSpinner.set_range(1.0, 10000.0); + NoOfColsSpinner.set_value(PerRow); + NoOfColsSpinner.signal_changed().connect(sigc::mem_fun(*this, &GridArrangeTab::on_row_spinbutton_changed)); + NoOfColsSpinner.set_tooltip_text(_("Number of columns")); + NoOfColsBox.pack_start(NoOfColsSpinner, false, false, MARGIN); + gtk_size_group_add_widget(_col3, GTK_WIDGET(NoOfColsBox.gobj())); + + ColumnWidthButton.set_label(_("Equal _width")); + ColumnWidthButton.set_use_underline(true); + double AutoCol = prefs->getDouble("/dialogs/gridtiler/AutoColSize", 15); + if (AutoCol>0) + AutoColSize=true; + else + AutoColSize=false; + ColumnWidthButton.set_active(AutoColSize); + NoOfColsBox.pack_start(ColumnWidthButton, false, false, MARGIN); + + ColumnWidthButton.set_tooltip_text(_("If not set, each column has the width of the widest object in it")); + ColumnWidthButton.signal_toggled().connect(sigc::mem_fun(*this, &GridArrangeTab::on_ColSize_checkbutton_changed)); + + SpinsHBox.pack_start(NoOfColsBox, false, false, MARGIN); + + TileBox.pack_start(SpinsHBox, false, false, MARGIN); + + VertAlign = prefs->getInt("/dialogs/gridtiler/VertAlign", 1); + HorizAlign = prefs->getInt("/dialogs/gridtiler/HorizAlign", 1); + + // Anchor selection widget + AlignLabel.set_label("Alignment:"); + AlignLabel.set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + AlignmentSelector.setAlignment(HorizAlign, VertAlign); + AlignmentSelector.on_selectionChanged().connect(sigc::mem_fun(*this, &GridArrangeTab::Align_changed)); + TileBox.pack_start(AlignLabel, false, false, MARGIN); + TileBox.pack_start(AlignmentSelector, true, false, MARGIN); + + { + /*#### Radio buttons to control spacing manually or to fit selection bbox ####*/ + SpaceByBBoxRadioButton.set_label(_("_Fit into selection box")); + SpaceByBBoxRadioButton.set_use_underline (true); + SpaceByBBoxRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &GridArrangeTab::Spacing_button_changed)); + SpacingGroup = SpaceByBBoxRadioButton.get_group(); + + SpacingVBox.pack_start(SpaceByBBoxRadioButton, false, false, MARGIN); + + SpaceManualRadioButton.set_label(_("_Set spacing:")); + SpaceManualRadioButton.set_use_underline (true); + SpaceManualRadioButton.set_group(SpacingGroup); + SpaceManualRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &GridArrangeTab::Spacing_button_changed)); + SpacingVBox.pack_start(SpaceManualRadioButton, false, false, MARGIN); + + TileBox.pack_start(SpacingVBox, false, false, MARGIN); + } + + { + /*#### Padding ####*/ + PaddingUnitMenu.setUnitType(UNIT_TYPE_LINEAR); + PaddingUnitMenu.setUnit("px"); + + YPadding.setDigits(5); + YPadding.setIncrements(0.2, 0); + YPadding.setRange(-10000, 10000); + double yPad = prefs->getDouble("/dialogs/gridtiler/YPad", 15); + YPadding.setValue(yPad, "px"); + YPadding.signal_value_changed().connect(sigc::mem_fun(*this, &GridArrangeTab::on_ypad_spinbutton_changed)); + + XPadding.setDigits(5); + XPadding.setIncrements(0.2, 0); + XPadding.setRange(-10000, 10000); + double xPad = prefs->getDouble("/dialogs/gridtiler/XPad", 15); + XPadding.setValue(xPad, "px"); + + XPadding.signal_value_changed().connect(sigc::mem_fun(*this, &GridArrangeTab::on_xpad_spinbutton_changed)); + } + + PaddingTable->set_border_width(MARGIN); + +#if WITH_GTKMM_3_0 + PaddingTable->set_row_spacing(MARGIN); + PaddingTable->set_column_spacing(MARGIN); + PaddingTable->attach(XPadding, 0, 0, 1, 1); + PaddingTable->attach(PaddingUnitMenu, 1, 0, 1, 1); + PaddingTable->attach(YPadding, 0, 1, 1, 1); +#else + PaddingTable->set_row_spacings(MARGIN); + PaddingTable->set_col_spacings(MARGIN); + PaddingTable->attach(XPadding, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK); + PaddingTable->attach(PaddingUnitMenu, 1, 2, 0, 1, Gtk::SHRINK, Gtk::SHRINK); + PaddingTable->attach(YPadding, 0, 1, 1, 2, Gtk::SHRINK, Gtk::SHRINK); +#endif + + TileBox.pack_start(*PaddingTable, false, false, MARGIN); + + contents->pack_start(TileBox); + + double SpacingType = prefs->getDouble("/dialogs/gridtiler/SpacingType", 15); + if (SpacingType>0) { + ManualSpacing=true; + } else { + ManualSpacing=false; + } + SpaceManualRadioButton.set_active(ManualSpacing); + SpaceByBBoxRadioButton.set_active(!ManualSpacing); + XPadding.set_sensitive (ManualSpacing); + YPadding.set_sensitive (ManualSpacing); + + //## The OK button FIXME + /*TileOkButton = addResponseButton(C_("Rows and columns dialog","_Arrange"), GTK_RESPONSE_APPLY); + TileOkButton->set_use_underline(true); + TileOkButton->set_tooltip_text(_("Arrange selected objects"));*/ + + show_all_children(); +} + +} //namespace Dialog +} //namespace UI +} //namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/grid-arrange-tab.h b/src/ui/dialog/grid-arrange-tab.h new file mode 100644 index 000000000..9d6700b39 --- /dev/null +++ b/src/ui/dialog/grid-arrange-tab.h @@ -0,0 +1,154 @@ +/** + * @brief Arranges Objects into a Grid + */ +/* Authors: + * Bob Jamison ( based off trace dialog) + * John Cliff + * Other dudes from The Inkscape Organization + * Abhishek Sharma + * Declara Denis + * + * Copyright (C) 2004 Bob Jamison + * Copyright (C) 2004 John Cliff + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef INKSCAPE_UI_DIALOG_GRID_ARRANGE_TAB_H +#define INKSCAPE_UI_DIALOG_GRID_ARRANGE_TAB_H + +#include <gtkmm.h> + +#include "ui/dialog/arrange-tab.h" + +#include "ui/widget/anchor-selector.h" +#include "ui/widget/scalar-unit.h" +#include "ui/widget/spinbutton.h" + +namespace Inkscape { +namespace UI { +namespace Dialog { + +class ArrangeDialog; + +/** + * Dialog for tiling an object + */ +class GridArrangeTab : public ArrangeTab { +public: + GridArrangeTab(ArrangeDialog *parent); + virtual ~GridArrangeTab() {}; + + /** + * Do the actual work + */ + virtual void arrange(); + + /** + * Respond to selection change + */ + void updateSelection(); + + // Callbacks from spinbuttons + void on_row_spinbutton_changed(); + void on_col_spinbutton_changed(); + void on_xpad_spinbutton_changed(); + void on_ypad_spinbutton_changed(); + void on_RowSize_checkbutton_changed(); + void on_ColSize_checkbutton_changed(); + void on_rowSize_spinbutton_changed(); + void on_colSize_spinbutton_changed(); + void Spacing_button_changed(); + void Align_changed(); + + +private: + GridArrangeTab(GridArrangeTab const &d); // no copy + void operator=(GridArrangeTab const &d); // no assign + + ArrangeDialog *Parent; + + bool userHidden; + bool updating; + + Gtk::VBox TileBox; + Gtk::Button *TileOkButton; + Gtk::Button *TileCancelButton; + + // Number selected label + Gtk::Label SelectionContentsLabel; + + + Gtk::HBox AlignHBox; + Gtk::HBox SpinsHBox; + + // Number per Row + Gtk::VBox NoOfColsBox; + Gtk::Label NoOfColsLabel; + Inkscape::UI::Widget::SpinButton NoOfColsSpinner; + bool AutoRowSize; + Gtk::CheckButton RowHeightButton; + + Gtk::VBox XByYLabelVBox; + Gtk::Label padXByYLabel; + Gtk::Label XByYLabel; + + // Number per Column + Gtk::VBox NoOfRowsBox; + Gtk::Label NoOfRowsLabel; + Inkscape::UI::Widget::SpinButton NoOfRowsSpinner; + bool AutoColSize; + Gtk::CheckButton ColumnWidthButton; + + // Alignment + Gtk::Label AlignLabel; + Inkscape::UI::Widget::AnchorSelector AlignmentSelector; + double VertAlign; + double HorizAlign; + + Inkscape::UI::Widget::UnitMenu PaddingUnitMenu; + Inkscape::UI::Widget::ScalarUnit XPadding; + Inkscape::UI::Widget::ScalarUnit YPadding; + +#if WITH_GTKMM_3_0 + Gtk::Grid *PaddingTable; +#else + Gtk::Table *PaddingTable; +#endif + + // BBox or manual spacing + Gtk::VBox SpacingVBox; + Gtk::RadioButtonGroup SpacingGroup; + Gtk::RadioButton SpaceByBBoxRadioButton; + Gtk::RadioButton SpaceManualRadioButton; + bool ManualSpacing; + + // Row height + Gtk::VBox RowHeightVBox; + Gtk::HBox RowHeightBox; + Gtk::Label RowHeightLabel; + Inkscape::UI::Widget::SpinButton RowHeightSpinner; + + // Column width + Gtk::VBox ColumnWidthVBox; + Gtk::HBox ColumnWidthBox; + Gtk::Label ColumnWidthLabel; + Inkscape::UI::Widget::SpinButton ColumnWidthSpinner; +}; + +} //namespace Dialog +} //namespace UI +} //namespace Inkscape + +#endif /* INKSCAPE_UI_DIALOG_GRID_ARRANGE_TAB_H */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/polar-arrange-tab.cpp b/src/ui/dialog/polar-arrange-tab.cpp new file mode 100644 index 000000000..a00b8fc02 --- /dev/null +++ b/src/ui/dialog/polar-arrange-tab.cpp @@ -0,0 +1,414 @@ +/** + * @brief Arranges Objects into a Circle/Ellipse + */ +/* Authors: + * Declara Denis + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "ui/dialog/polar-arrange-tab.h" +#include "ui/dialog/tile.h" + +#include <2geom/transforms.h> +#include <glibmm/i18n.h> + +#include "verbs.h" +#include "preferences.h" +#include "inkscape.h" +#include "desktop-handles.h" +#include "selection.h" +#include "document.h" +#include "document-undo.h" +#include "sp-item.h" +#include "widgets/icon.h" +#include "desktop.h" +#include "sp-ellipse.h" +#include "sp-item-transform.h" + +namespace Inkscape { +namespace UI { +namespace Dialog { + +PolarArrangeTab::PolarArrangeTab(ArrangeDialog *parent_) + : parent(parent_), + parametersTable(3, 3, false), + centerY("", "Y coordinate of the center", UNIT_TYPE_LINEAR), + centerX("", "X coordinate of the center", centerY), + radiusY("", "Y coordinate of the radius", UNIT_TYPE_LINEAR), + radiusX("", "X coordinate of the radius", radiusY), + angleY("", "Starting angle", UNIT_TYPE_RADIAL), + angleX("", "End angle", angleY) +{ + anchorPointLabel.set_text(C_("Polar arrange tab", "Anchor point:")); + anchorPointLabel.set_alignment(Gtk::ALIGN_START); + pack_start(anchorPointLabel, false, false); + + anchorBoundingBoxRadio.set_label(C_("Polar arrange tab", "Object's bounding box:")); + anchorRadioGroup = anchorBoundingBoxRadio.get_group(); + anchorBoundingBoxRadio.signal_toggled().connect(sigc::mem_fun(*this, &PolarArrangeTab::on_anchor_radio_changed)); + pack_start(anchorBoundingBoxRadio, false, false); + + pack_start(anchorSelector, false, false); + + anchorObjectPivotRadio.set_label(C_("Polar arrange tab", "Object's rotational center")); + anchorObjectPivotRadio.set_group(anchorRadioGroup); + anchorObjectPivotRadio.signal_toggled().connect(sigc::mem_fun(*this, &PolarArrangeTab::on_anchor_radio_changed)); + pack_start(anchorObjectPivotRadio, false, false); + + arrangeOnLabel.set_text(C_("Polar arrange tab", "Arrange on:")); + arrangeOnLabel.set_alignment(Gtk::ALIGN_START); + pack_start(arrangeOnLabel, false, false); + + arrangeOnFirstCircleRadio.set_label(C_("Polar arrange tab", "First selected circle/ellipse/arc")); + arrangeRadioGroup = arrangeOnFirstCircleRadio.get_group(); + arrangeOnFirstCircleRadio.signal_toggled().connect(sigc::mem_fun(*this, &PolarArrangeTab::on_arrange_radio_changed)); + pack_start(arrangeOnFirstCircleRadio, false, false); + + arrangeOnLastCircleRadio.set_label(C_("Polar arrange tab", "Last selected circle/ellipse/arc")); + arrangeOnLastCircleRadio.set_group(arrangeRadioGroup); + arrangeOnLastCircleRadio.signal_toggled().connect(sigc::mem_fun(*this, &PolarArrangeTab::on_arrange_radio_changed)); + pack_start(arrangeOnLastCircleRadio, false, false); + + arrangeOnParametersRadio.set_label(C_("Polar arrange tab", "Parameterized:")); + arrangeOnParametersRadio.set_group(arrangeRadioGroup); + arrangeOnParametersRadio.signal_toggled().connect(sigc::mem_fun(*this, &PolarArrangeTab::on_arrange_radio_changed)); + pack_start(arrangeOnParametersRadio, false, false); + + centerLabel.set_text(_("Center X/Y:")); + parametersTable.attach(centerLabel, 0, 1, 0, 1, Gtk::FILL); + centerX.setDigits(2); + centerX.setIncrements(0.2, 0); + centerX.setRange(-10000, 10000); + centerX.setValue(0, "px"); + centerY.setDigits(2); + centerY.setIncrements(0.2, 0); + centerY.setRange(-10000, 10000); + centerY.setValue(0, "px"); + parametersTable.attach(centerX, 1, 2, 0, 1, Gtk::FILL); + parametersTable.attach(centerY, 2, 3, 0, 1, Gtk::FILL); + + radiusLabel.set_text(_("Radius X/Y:")); + parametersTable.attach(radiusLabel, 0, 1, 1, 2, Gtk::FILL); + radiusX.setDigits(2); + radiusX.setIncrements(0.2, 0); + radiusX.setRange(0.001, 10000); + radiusX.setValue(100, "px"); + radiusY.setDigits(2); + radiusY.setIncrements(0.2, 0); + radiusY.setRange(0.001, 10000); + radiusY.setValue(100, "px"); + parametersTable.attach(radiusX, 1, 2, 1, 2, Gtk::FILL); + parametersTable.attach(radiusY, 2, 3, 1, 2, Gtk::FILL); + + angleLabel.set_text(_("Angle X/Y:")); + parametersTable.attach(angleLabel, 0, 1, 2, 3, Gtk::FILL); + angleX.setDigits(2); + angleX.setIncrements(0.2, 0); + angleX.setRange(-10000, 10000); + angleX.setValue(0, "°"); + angleY.setDigits(2); + angleY.setIncrements(0.2, 0); + angleY.setRange(-10000, 10000); + angleY.setValue(180, "°"); + parametersTable.attach(angleX, 1, 2, 2, 3, Gtk::FILL); + parametersTable.attach(angleY, 2, 3, 2, 3, Gtk::FILL); + pack_start(parametersTable, false, false); + + rotateObjectsCheckBox.set_label(_("Rotate objects")); + rotateObjectsCheckBox.set_active(true); + pack_start(rotateObjectsCheckBox, false, false); + + centerX.set_sensitive(false); + centerY.set_sensitive(false); + angleX.set_sensitive(false); + angleY.set_sensitive(false); + radiusX.set_sensitive(false); + radiusY.set_sensitive(false); +} + +/** + * This function rotates an item around a given point by a given amount + * @param item item to rotate + * @param center center of the rotation to perform + * @param rotation amount to rotate the object by + */ +static void rotateAround(SPItem *item, Geom::Point center, Geom::Rotate const &rotation) +{ + Geom::Translate const s(center); + Geom::Affine affine = Geom::Affine(s).inverse() * Geom::Affine(rotation) * Geom::Affine(s); + + // Save old center + center = item->getCenter(); + + item->set_i2d_affine(item->i2dt_affine() * affine); + item->doWriteTransform(item->getRepr(), item->transform); + + if(item->isCenterSet()) + { + item->setCenter(center * affine); + item->updateRepr(); + } +} + +/** + * Calculates the angle at which to put an object given the total amount + * of objects, the index of the objects as well as the arc start and end + * points + * @param arcBegin angle at which the arc begins + * @param arcEnd angle at which the arc ends + * @param count number of objects in the selection + * @param n index of the object in the selection + */ +static float calcAngle(float arcBegin, float arcEnd, int count, int n) +{ + float arcLength = arcEnd - arcBegin; + float delta = std::abs(std::abs(arcLength) - 2*M_PI); + if(delta > 0.01) count--; // If not a complete circle, put an object also at the extremes of the arc; + + float angle = n / (float)count; + // Normalize for arcLength: + angle = angle * arcLength; + angle += arcBegin; + + return angle; +} + +/** + * Calculates the point at which an object needs to be, given the center of the ellipse, + * it's radius (x and y), as well as the angle + */ +static Geom::Point calcPoint(float cx, float cy, float rx, float ry, float angle) +{ + return Geom::Point(cx + cos(angle) * rx, cy + sin(angle) * ry); +} + +/** + * Returns the selected anchor point in document coordinates. If anchor + * is 0 to 8, then a bounding box point has been choosen. If it is 9 however + * the rotational center is chosen. + * @todo still using a hack to get the real coordinate space (subtracting document height + * and inverting axes) + */ +static Geom::Point getAnchorPoint(int anchor, SPItem *item) +{ + Geom::Point source; + + Geom::OptRect bbox = item->documentVisualBounds(); + + switch(anchor) + { + case 0: // Top - Left + case 3: // Middle - Left + case 6: // Bottom - Left + source[0] = bbox->min()[Geom::X]; + break; + case 1: // Top - Middle + case 4: // Middle - Middle + case 7: // Bottom - Middle + source[0] = (bbox->min()[Geom::X] + bbox->max()[Geom::X]) / 2.0f; + break; + case 2: // Top - Right + case 5: // Middle - Right + case 8: // Bottom - Right + source[0] = bbox->max()[Geom::X]; + break; + }; + + switch(anchor) + { + case 0: // Top - Left + case 1: // Top - Middle + case 2: // Top - Right + source[1] = bbox->min()[Geom::Y]; + break; + case 3: // Middle - Left + case 4: // Middle - Middle + case 5: // Middle - Right + source[1] = (bbox->min()[Geom::Y] + bbox->max()[Geom::Y]) / 2.0f; + break; + case 6: // Bottom - Left + case 7: // Bottom - Middle + case 8: // Bottom - Right + source[1] = bbox->max()[Geom::Y]; + break; + }; + + // If using center + if(anchor == 9) + source = item->getCenter(); + else + { + // FIXME: + source[1] -= item->document->getHeight().value("px"); + source[1] *= -1; + } + + return source; +} + +/** + * Moves an SPItem to a given location, the location is based on the given anchor point. + * @param anchor 0 to 8 are the various bounding box points like follows: + * 0 1 2 + * 3 4 5 + * 6 7 8 + * Anchor mode 9 is the rotational center of the object + * @param item Item to move + * @param p point at which to move the object + */ +static void moveToPoint(int anchor, SPItem *item, Geom::Point p) +{ + sp_item_move_rel(item, Geom::Translate(p - getAnchorPoint(anchor, item))); +} + +void PolarArrangeTab::arrange() +{ + Inkscape::Selection *selection = sp_desktop_selection(parent->getDesktop()); + const GSList *items, *tmp; + tmp = items = selection->itemList(); + SPGenericEllipse *referenceEllipse = NULL; // Last ellipse in selection + + bool arrangeOnEllipse = !arrangeOnParametersRadio.get_active(); + bool arrangeOnFirstEllipse = arrangeOnEllipse && arrangeOnFirstCircleRadio.get_active(); + + int count = 0; + while(tmp) + { + if(arrangeOnEllipse) + { + SPItem *item = SP_ITEM(tmp->data); + + if(arrangeOnFirstEllipse) + { + // The first selected ellipse is actually the last one in the list + if(SP_IS_GENERICELLIPSE(item)) + referenceEllipse = SP_GENERICELLIPSE(item); + } else { + // The last selected ellipse is actually the first in list + if(SP_IS_GENERICELLIPSE(item) && referenceEllipse == NULL) + referenceEllipse = SP_GENERICELLIPSE(item); + } + } + tmp = tmp->next; + ++count; + } + + float cx, cy; // Center of the ellipse + float rx, ry; // Radiuses of the ellipse in x and y direction + float arcBeg, arcEnd; // begin and end angles for arcs + Geom::Affine transformation; // Any additional transformation to apply to the objects + + if(arrangeOnEllipse) + { + if(referenceEllipse == NULL) + { + Gtk::MessageDialog dialog(_("Couldn't find an ellipse in selection"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true); + dialog.run(); + return; + } else { + cx = referenceEllipse->cx.value; + cy = referenceEllipse->cy.value; + rx = referenceEllipse->rx.value; + ry = referenceEllipse->ry.value; + arcBeg = referenceEllipse->start; + arcEnd = referenceEllipse->end; + + transformation = referenceEllipse->i2dt_affine(); + + // We decrement the count by 1 as we are not going to lay + // out the reference ellipse + --count; + } + + } else { + // Read options from UI + cx = centerX.getValue("px"); + cy = centerY.getValue("px"); + rx = radiusX.getValue("px"); + ry = radiusY.getValue("px"); + arcBeg = angleX.getValue("rad"); + arcEnd = angleY.getValue("rad"); + transformation.setIdentity(); + referenceEllipse = NULL; + } + + int anchor = 9; + if(anchorBoundingBoxRadio.get_active()) + { + anchor = anchorSelector.getHorizontalAlignment() + + anchorSelector.getVerticalAlignment() * 3; + } + + Geom::Point realCenter = Geom::Point(cx, cy) * transformation; + + tmp = items; + int i = 0; + while(tmp) + { + SPItem *item = SP_ITEM(tmp->data); + + // Ignore the reference ellipse if any + if(item != referenceEllipse) + { + float angle = calcAngle(arcBeg, arcEnd, count, i); + Geom::Point newLocation = calcPoint(cx, cy, rx, ry, angle) * transformation; + + moveToPoint(anchor, item, newLocation); + + if(rotateObjectsCheckBox.get_active()) { + // Calculate the angle by which to rotate each object + angle = -atan2f(newLocation.x() - realCenter.x(), newLocation.y() - realCenter.y()); + rotateAround(item, newLocation, Geom::Rotate(angle)); + } + + ++i; + } + tmp = tmp->next; + } + + DocumentUndo::done(sp_desktop_document(parent->getDesktop()), SP_VERB_SELECTION_ARRANGE, + _("Arrange on ellipse")); +} + +void PolarArrangeTab::updateSelection() +{ +} + +void PolarArrangeTab::on_arrange_radio_changed() +{ + bool arrangeParametric = arrangeOnParametersRadio.get_active(); + + centerX.set_sensitive(arrangeParametric); + centerY.set_sensitive(arrangeParametric); + + angleX.set_sensitive(arrangeParametric); + angleY.set_sensitive(arrangeParametric); + + radiusX.set_sensitive(arrangeParametric); + radiusY.set_sensitive(arrangeParametric); + + parametersTable.set_visible(arrangeParametric); +} + +void PolarArrangeTab::on_anchor_radio_changed() +{ + bool anchorBoundingBox = anchorBoundingBoxRadio.get_active(); + + anchorSelector.set_sensitive(anchorBoundingBox); +} + +} //namespace Dialog +} //namespace UI +} //namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/polar-arrange-tab.h b/src/ui/dialog/polar-arrange-tab.h new file mode 100644 index 000000000..bfed40bbd --- /dev/null +++ b/src/ui/dialog/polar-arrange-tab.h @@ -0,0 +1,100 @@ +/** + * @brief Arranges Objects into a Circle/Ellipse + */ +/* Authors: + * Declara Denis + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef INKSCAPE_UI_DIALOG_POLAR_ARRANGE_TAB_H +#define INKSCAPE_UI_DIALOG_POLAR_ARRANGE_TAB_H + +#include "ui/dialog/arrange-tab.h" + +#include "ui/widget/anchor-selector.h" +#include "ui/widget/scalar-unit.h" + +namespace Inkscape { +namespace UI { +namespace Dialog { + +class ArrangeDialog; + +/** + * PolarArrangeTab is a Tab displayed in the Arrange dialog and contains + * enables the user to arrange objects on a circular or elliptical shape + */ +class PolarArrangeTab : public ArrangeTab { +public: + PolarArrangeTab(ArrangeDialog *parent_); + virtual ~PolarArrangeTab() {}; + + /** + * Do the actual arrangement + */ + virtual void arrange(); + + /** + * Respond to selection change + */ + void updateSelection(); + + void on_anchor_radio_changed(); + void on_arrange_radio_changed(); + +private: + PolarArrangeTab(PolarArrangeTab const &d); // no copy + void operator=(PolarArrangeTab const &d); // no assign + + ArrangeDialog *parent; + + Gtk::Label anchorPointLabel; + + Gtk::RadioButtonGroup anchorRadioGroup; + Gtk::RadioButton anchorBoundingBoxRadio; + Gtk::RadioButton anchorObjectPivotRadio; + Inkscape::UI::Widget::AnchorSelector anchorSelector; + + Gtk::Label arrangeOnLabel; + + Gtk::RadioButtonGroup arrangeRadioGroup; + Gtk::RadioButton arrangeOnFirstCircleRadio; + Gtk::RadioButton arrangeOnLastCircleRadio; + Gtk::RadioButton arrangeOnParametersRadio; + + Gtk::Table parametersTable; + + Gtk::Label centerLabel; + Inkscape::UI::Widget::ScalarUnit centerY; + Inkscape::UI::Widget::ScalarUnit centerX; + + Gtk::Label radiusLabel; + Inkscape::UI::Widget::ScalarUnit radiusY; + Inkscape::UI::Widget::ScalarUnit radiusX; + + Gtk::Label angleLabel; + Inkscape::UI::Widget::ScalarUnit angleY; + Inkscape::UI::Widget::ScalarUnit angleX; + + Gtk::CheckButton rotateObjectsCheckBox; + + +}; + +} //namespace Dialog +} //namespace UI +} //namespace Inkscape + +#endif /* INKSCAPE_UI_DIALOG_POLAR_ARRANGE_TAB_H */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/tile.cpp b/src/ui/dialog/tile.cpp index c35d3b554..a3cffb3d4 100644 --- a/src/ui/dialog/tile.cpp +++ b/src/ui/dialog/tile.cpp @@ -6,878 +6,62 @@ * John Cliff * Other dudes from The Inkscape Organization * Abhishek Sharma + * Declara Denis * * Copyright (C) 2004 Bob Jamison * Copyright (C) 2004 John Cliff * * Released under GNU GPL, read the file 'COPYING' for more information */ -//#define DEBUG_GRID_ARRANGE 1 -#include "tile.h" -#include <gtk/gtk.h> //for GTK_RESPONSE* types -#include <glibmm/i18n.h> -#include <gtkmm/stock.h> +#include "ui/dialog/grid-arrange-tab.h" +#include "ui/dialog/polar-arrange-tab.h" -#if WITH_GTKMM_3_0 -# include <gtkmm/grid.h> -#else -# include <gtkmm/table.h> -#endif - -#include <2geom/transforms.h> +#include <glibmm/i18n.h> +#include "tile.h" #include "verbs.h" -#include "preferences.h" -#include "inkscape.h" -#include "desktop-handles.h" -#include "selection.h" -#include "document.h" -#include "document-undo.h" -#include "sp-item.h" -#include "widgets/icon.h" -#include "desktop.h" - -/* - * Sort items by their x co-ordinates, taking account of y (keeps rows intact) - * - * <0 *elem1 goes before *elem2 - * 0 *elem1 == *elem2 - * >0 *elem1 goes after *elem2 - */ -static int sp_compare_x_position(SPItem *first, SPItem *second) -{ - using Geom::X; - using Geom::Y; - - Geom::OptRect a = first->documentVisualBounds(); - Geom::OptRect b = second->documentVisualBounds(); - - if ( !a || !b ) { - // FIXME? - return 0; - } - - double const a_height = a->dimensions()[Y]; - double const b_height = b->dimensions()[Y]; - - bool a_in_b_vert = false; - if ((a->min()[Y] < b->min()[Y] + 0.1) && (a->min()[Y] > b->min()[Y] - b_height)) { - a_in_b_vert = true; - } else if ((b->min()[Y] < a->min()[Y] + 0.1) && (b->min()[Y] > a->min()[Y] - a_height)) { - a_in_b_vert = true; - } else if (b->min()[Y] == a->min()[Y]) { - a_in_b_vert = true; - } else { - a_in_b_vert = false; - } - - if (!a_in_b_vert) { - return -1; - } - if (a_in_b_vert && a->min()[X] > b->min()[X]) { - return 1; - } - if (a_in_b_vert && a->min()[X] < b->min()[X]) { - return -1; - } - return 0; -} - -/* - * Sort items by their y co-ordinates. - */ -static int -sp_compare_y_position(SPItem *first, SPItem *second) -{ - Geom::OptRect a = first->documentVisualBounds(); - Geom::OptRect b = second->documentVisualBounds(); - - if ( !a || !b ) { - // FIXME? - return 0; - } - - if (a->min()[Geom::Y] > b->min()[Geom::Y]) { - return 1; - } - if (a->min()[Geom::Y] < b->min()[Geom::Y]) { - return -1; - } - - return 0; -} namespace Inkscape { namespace UI { namespace Dialog { - -//######################################################################### -//## E V E N T S -//######################################################################### - -/* - * - * This arranges the selection in a grid pattern. - * - */ - -void TileDialog::Grid_Arrange () +ArrangeDialog::ArrangeDialog() + : UI::Widget::Panel("", "/dialogs/gridtiler", SP_VERB_SELECTION_ARRANGE), + _gridArrangeTab(new GridArrangeTab(this)), + _polarArrangeTab(new PolarArrangeTab(this)) { + Gtk::Box *contents = this->_getContents(); - int cnt,row_cnt,col_cnt,a,row,col; - double grid_left,grid_top,col_width,row_height,paddingx,paddingy,width, height, new_x, new_y; - double total_col_width,total_row_height; - col_width = 0; - row_height = 0; - total_col_width=0; - total_row_height=0; - - // check for correct numbers in the row- and col-spinners - on_col_spinbutton_changed(); - on_row_spinbutton_changed(); - - // set padding to manual values - paddingx = XPadding.getValue("px"); - paddingy = YPadding.getValue("px"); - - std::vector<double> row_heights; - std::vector<double> col_widths; - std::vector<double> row_ys; - std::vector<double> col_xs; - - int NoOfCols = NoOfColsSpinner.get_value_as_int(); - int NoOfRows = NoOfRowsSpinner.get_value_as_int(); - - width = 0; - for (a=0;a<NoOfCols; a++){ - col_widths.push_back(width); - } - - height = 0; - for (a=0;a<NoOfRows; a++){ - row_heights.push_back(height); - } - grid_left = 99999; - grid_top = 99999; - - SPDesktop *desktop = getDesktop(); - sp_desktop_document(desktop)->ensureUpToDate(); - - Inkscape::Selection *selection = sp_desktop_selection (desktop); - const GSList *items = selection ? selection->itemList() : 0; - cnt=0; - for (; items != NULL; items = items->next) { - SPItem *item = SP_ITEM(items->data); - Geom::OptRect b = item->documentVisualBounds(); - if (!b) { - continue; - } - - width = b->dimensions()[Geom::X]; - height = b->dimensions()[Geom::Y]; - - if (b->min()[Geom::X] < grid_left) { - grid_left = b->min()[Geom::X]; - } - if (b->min()[Geom::Y] < grid_top) { - grid_top = b->min()[Geom::Y]; - } - if (width > col_width) { - col_width = width; - } - if (height > row_height) { - row_height = height; - } - } - - - // require the sorting done before we can calculate row heights etc. - - g_return_if_fail(selection); - const GSList *items2 = selection->itemList(); - GSList *rev = g_slist_copy(const_cast<GSList *>(items2)); - GSList *sorted = NULL; - rev = g_slist_sort(rev, (GCompareFunc) sp_compare_y_position); - sorted = g_slist_sort(rev, (GCompareFunc) sp_compare_x_position); - - - // Calculate individual Row and Column sizes if necessary - - - cnt=0; - const GSList *sizes = sorted; - for (; sizes != NULL; sizes = sizes->next) { - SPItem *item = SP_ITEM(sizes->data); - Geom::OptRect b = item->documentVisualBounds(); - if (b) { - width = b->dimensions()[Geom::X]; - height = b->dimensions()[Geom::Y]; - if (width > col_widths[(cnt % NoOfCols)]) { - col_widths[(cnt % NoOfCols)] = width; - } - if (height > row_heights[(cnt / NoOfCols)]) { - row_heights[(cnt / NoOfCols)] = height; - } - } - - cnt++; - } - - - /// Make sure the top and left of the grid dont move by compensating for align values. - if (RowHeightButton.get_active()){ - grid_top = grid_top - (((row_height - row_heights[0]) / 2)*(VertAlign)); - } - if (ColumnWidthButton.get_active()){ - grid_left = grid_left - (((col_width - col_widths[0]) /2)*(HorizAlign)); - } - - #ifdef DEBUG_GRID_ARRANGE - g_print("\n cx = %f cy= %f gridleft=%f",cx,cy,grid_left); - #endif - - // Calculate total widths and heights, allowing for columns and rows non uniformly sized. + _notebook.append_page(*_gridArrangeTab, C_("Arrange dialog", "Rectangular grid")); + _notebook.append_page(*_polarArrangeTab, C_("Arrange dialog", "Polar Coordinates")); + _arrangeBox.pack_start(_notebook); - if (ColumnWidthButton.get_active()){ - total_col_width = col_width * NoOfCols; - col_widths.clear(); - for (a=0;a<NoOfCols; a++){ - col_widths.push_back(col_width); - } - } else { - for (a = 0; a < (int)col_widths.size(); a++) - { - total_col_width += col_widths[a] ; - } - } - - if (RowHeightButton.get_active()){ - total_row_height = row_height * NoOfRows; - row_heights.clear(); - for (a=0;a<NoOfRows; a++){ - row_heights.push_back(row_height); - } - } else { - for (a = 0; a < (int)row_heights.size(); a++) - { - total_row_height += row_heights[a] ; - } - } - - - Geom::OptRect sel_bbox = selection->visualBounds(); - // Fit to bbox, calculate padding between rows accordingly. - if ( sel_bbox && !SpaceManualRadioButton.get_active() ){ -#ifdef DEBUG_GRID_ARRANGE -g_print("\n row = %f col = %f selection x= %f selection y = %f", total_row_height,total_col_width, b.extent(Geom::X), b.extent(Geom::Y)); -#endif - paddingx = (sel_bbox->width() - total_col_width) / (NoOfCols -1); - paddingy = (sel_bbox->height() - total_row_height) / (NoOfRows -1); - } - -/* - Horizontal align - Left = 0 - Centre = 1 - Right = 2 - - Vertical align - Top = 0 - Middle = 1 - Bottom = 2 - - X position is calculated by taking the grids left co-ord, adding the distance to the column, - then adding 1/2 the spacing multiplied by the align variable above, - Y position likewise, takes the top of the grid, adds the y to the current row then adds the padding in to align it. - -*/ - - // Calculate row and column x and y coords required to allow for columns and rows which are non uniformly sized. - - for (a=0;a<NoOfCols; a++){ - if (a<1) col_xs.push_back(0); - else col_xs.push_back(col_widths[a-1]+paddingx+col_xs[a-1]); - } - - - for (a=0;a<NoOfRows; a++){ - if (a<1) row_ys.push_back(0); - else row_ys.push_back(row_heights[a-1]+paddingy+row_ys[a-1]); - } - - cnt=0; - for (row_cnt=0; ((sorted != NULL) && (row_cnt<NoOfRows)); row_cnt++) { - - GSList *current_row = NULL; - for (col_cnt = 0; ((sorted != NULL) && (col_cnt<NoOfCols)); col_cnt++) { - current_row = g_slist_append (current_row, sorted->data); - sorted = sorted->next; - } - - for (; current_row != NULL; current_row = current_row->next) { - SPItem *item=SP_ITEM(current_row->data); - Inkscape::XML::Node *repr = item->getRepr(); - Geom::OptRect b = item->documentVisualBounds(); - Geom::Point min; - if (b) { - width = b->dimensions()[Geom::X]; - height = b->dimensions()[Geom::Y]; - min = b->min(); - } else { - width = height = 0; - min = Geom::Point(0, 0); - } - - row = cnt / NoOfCols; - col = cnt % NoOfCols; - - new_x = grid_left + (((col_widths[col] - width)/2)*HorizAlign) + col_xs[col]; - new_y = grid_top + (((row_heights[row] - height)/2)*VertAlign) + row_ys[row]; - - // signs are inverted between x and y due to y inversion - Geom::Point move = Geom::Point(new_x - min[Geom::X], min[Geom::Y] - new_y); - Geom::Affine const affine = Geom::Affine(Geom::Translate(move)); - item->set_i2d_affine(item->i2dt_affine() * affine); - item->doWriteTransform(repr, item->transform, NULL); - SP_OBJECT (current_row->data)->updateRepr(); - cnt +=1; - } - g_slist_free (current_row); - } - - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_SELECTION_GRIDTILE, - _("Arrange in a grid")); - -} - - -//######################################################################### -//## E V E N T S -//######################################################################### - - -void TileDialog::_apply() -{ - Grid_Arrange(); -} - - -/** - * changed value in # of columns spinbox. - */ -void TileDialog::on_row_spinbutton_changed() -{ - // quit if run by the attr_changed listener - if (updating) { - return; - } - - // in turn, prevent listener from responding - updating = true; - SPDesktop *desktop = getDesktop(); - - Inkscape::Selection *selection = desktop ? desktop->selection : 0; - g_return_if_fail( selection ); - - GSList const *items = selection->itemList(); - int selcount = g_slist_length((GSList *)items); - - double PerCol = ceil(selcount / NoOfColsSpinner.get_value()); - NoOfRowsSpinner.set_value(PerCol); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble("/dialogs/gridtiler/NoOfCols", NoOfColsSpinner.get_value()); - updating=false; -} - -/** - * changed value in # of rows spinbox. - */ -void TileDialog::on_col_spinbutton_changed() -{ - // quit if run by the attr_changed listener - if (updating) { - return; - } - - // in turn, prevent listener from responding - updating = true; - SPDesktop *desktop = getDesktop(); - Inkscape::Selection *selection = desktop ? desktop->selection : 0; - g_return_if_fail(selection); - - GSList const *items = selection->itemList(); - int selcount = g_slist_length((GSList *)items); - - double PerRow = ceil(selcount / NoOfRowsSpinner.get_value()); - NoOfColsSpinner.set_value(PerRow); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble("/dialogs/gridtiler/NoOfCols", PerRow); - - updating=false; + _arrangeButton = this->addResponseButton(C_("Arrange dialog","_Arrange"), GTK_RESPONSE_APPLY); + _arrangeButton->set_use_underline(true); + _arrangeButton->set_tooltip_text(_("Arrange selected objects")); + contents->pack_start(_arrangeBox); + //show_all_children(); } -/** - * changed value in x padding spinbox. - */ -void TileDialog::on_xpad_spinbutton_changed() -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble("/dialogs/gridtiler/XPad", XPadding.getValue("px")); -} - -/** - * changed value in y padding spinbox. - */ -void TileDialog::on_ypad_spinbutton_changed() +void ArrangeDialog::on_show() { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble("/dialogs/gridtiler/YPad", YPadding.getValue("px")); + UI::Widget::Panel::on_show(); + _polarArrangeTab->on_arrange_radio_changed(); } - -/** - * checked/unchecked autosize Rows button. - */ -void TileDialog::on_RowSize_checkbutton_changed() +void ArrangeDialog::_apply() { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - if (RowHeightButton.get_active()) { - prefs->setDouble("/dialogs/gridtiler/AutoRowSize", 20); - } else { - prefs->setDouble("/dialogs/gridtiler/AutoRowSize", -20); - } - RowHeightBox.set_sensitive ( !RowHeightButton.get_active()); -} - -/** - * checked/unchecked autosize Rows button. - */ -void TileDialog::on_ColSize_checkbutton_changed() -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - if (ColumnWidthButton.get_active()) { - prefs->setDouble("/dialogs/gridtiler/AutoColSize", 20); - } else { - prefs->setDouble("/dialogs/gridtiler/AutoColSize", -20); - } - ColumnWidthBox.set_sensitive ( !ColumnWidthButton.get_active()); -} - -/** - * changed value in columns spinbox. - */ -void TileDialog::on_rowSize_spinbutton_changed() -{ - // quit if run by the attr_changed listener - if (updating) { - return; - } - - // in turn, prevent listener from responding - updating = true; - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble("/dialogs/gridtiler/RowHeight", RowHeightSpinner.get_value()); - updating=false; - -} - -/** - * changed value in rows spinbox. - */ -void TileDialog::on_colSize_spinbutton_changed() -{ - // quit if run by the attr_changed listener - if (updating) { - return; - } - - // in turn, prevent listener from responding - updating = true; - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble("/dialogs/gridtiler/ColWidth", ColumnWidthSpinner.get_value()); - updating=false; - -} - -/** - * changed Radio button in Spacing group. - */ -void TileDialog::Spacing_button_changed() -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - if (SpaceManualRadioButton.get_active()) { - prefs->setDouble("/dialogs/gridtiler/SpacingType", 20); - } else { - prefs->setDouble("/dialogs/gridtiler/SpacingType", -20); - } - - XPadding.set_sensitive ( SpaceManualRadioButton.get_active()); - YPadding.set_sensitive ( SpaceManualRadioButton.get_active()); -} - -/** - * changed Radio button in Vertical Align group. - */ -void TileDialog::VertAlign_changed() -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - if (VertTopRadioButton.get_active()) { - VertAlign = 0; - prefs->setInt("/dialogs/gridtiler/VertAlign", 0); - } else if (VertCentreRadioButton.get_active()){ - VertAlign = 1; - prefs->setInt("/dialogs/gridtiler/VertAlign", 1); - } else if (VertBotRadioButton.get_active()){ - VertAlign = 2; - prefs->setInt("/dialogs/gridtiler/VertAlign", 2); - } -} - -/** - * changed Radio button in Vertical Align group. - */ -void TileDialog::HorizAlign_changed() -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - if (HorizLeftRadioButton.get_active()) { - HorizAlign = 0; - prefs->setInt("/dialogs/gridtiler/HorizAlign", 0); - } else if (HorizCentreRadioButton.get_active()){ - HorizAlign = 1; - prefs->setInt("/dialogs/gridtiler/HorizAlign", 1); - } else if (HorizRightRadioButton.get_active()){ - HorizAlign = 2; - prefs->setInt("/dialogs/gridtiler/HorizAlign", 2); - } -} - -/** - * Desktop selection changed - */ -void TileDialog::updateSelection() -{ - // quit if run by the attr_changed listener - if (updating) { - return; - } - - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - // in turn, prevent listener from responding - updating = true; - SPDesktop *desktop = getDesktop(); - Inkscape::Selection *selection = desktop ? desktop->selection : 0; - GSList const *items = selection ? selection->itemList() : 0; - - if (items) { - int selcount = g_slist_length((GSList *)items); - - if (NoOfColsSpinner.get_value() > 1 && NoOfRowsSpinner.get_value() > 1){ - // Update the number of rows assuming number of columns wanted remains same. - double NoOfRows = ceil(selcount / NoOfColsSpinner.get_value()); - NoOfRowsSpinner.set_value(NoOfRows); - - // if the selection has less than the number set for one row, reduce it appropriately - if (selcount < NoOfColsSpinner.get_value()) { - double NoOfCols = ceil(selcount / NoOfRowsSpinner.get_value()); - NoOfColsSpinner.set_value(NoOfCols); - prefs->setInt("/dialogs/gridtiler/NoOfCols", NoOfCols); - } - } else { - double PerRow = ceil(sqrt(selcount)); - double PerCol = ceil(sqrt(selcount)); - NoOfRowsSpinner.set_value(PerRow); - NoOfColsSpinner.set_value(PerCol); - prefs->setInt("/dialogs/gridtiler/NoOfCols", static_cast<int>(PerCol)); - } - } - - updating = false; -} - - - -/*########################## -## Experimental -##########################*/ - -static void updateSelectionCallback(Inkscape::Application */*inkscape*/, Inkscape::Selection */*selection*/, TileDialog *dlg) -{ - dlg->updateSelection(); -} - - -//######################################################################### -//## C O N S T R U C T O R / D E S T R U C T O R -//######################################################################### -/** - * Constructor - */ -TileDialog::TileDialog() - : UI::Widget::Panel("", "/dialogs/gridtiler", SP_VERB_SELECTION_GRIDTILE), - XPadding(_("X:"), _("Horizontal spacing between columns."), UNIT_TYPE_LINEAR, "", "object-columns", &PaddingUnitMenu), - YPadding(_("Y:"), _("Vertical spacing between rows."), UNIT_TYPE_LINEAR, "", "object-rows", &PaddingUnitMenu), -#if WITH_GTKMM_3_0 - PaddingTable(Gtk::manage(new Gtk::Grid())) -#else - PaddingTable(Gtk::manage(new Gtk::Table(2, 2, false))) -#endif -{ - // bool used by spin button callbacks to stop loops where they change each other. - updating = false; - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - - // could not do this in gtkmm - there's no Gtk::SizeGroup public constructor (!) - GtkSizeGroup *_col1 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); - GtkSizeGroup *_col2 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); - GtkSizeGroup *_col3 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); - - { - // Selection Change signal - g_signal_connect ( G_OBJECT (INKSCAPE), "change_selection", G_CALLBACK (updateSelectionCallback), this); - } - - Gtk::Box *contents = _getContents(); - -#define MARGIN 2 - - //##Set up the panel - - SPDesktop *desktop = getDesktop(); - - Inkscape::Selection *selection = desktop ? desktop->selection : 0; - g_return_if_fail( selection ); - int selcount = 1; - if (!selection->isEmpty()) { - GSList const *items = selection->itemList(); - selcount = g_slist_length((GSList *)items); - } - - - /*#### Number of Rows ####*/ - - double PerRow = ceil(sqrt(selcount)); - double PerCol = ceil(sqrt(selcount)); - - #ifdef DEBUG_GRID_ARRANGE - g_print("/n PerRox = %f PerCol = %f selcount = %d",PerRow,PerCol,selcount); - #endif - - NoOfRowsLabel.set_text_with_mnemonic(_("_Rows:")); - NoOfRowsLabel.set_mnemonic_widget(NoOfRowsSpinner); - NoOfRowsBox.pack_start(NoOfRowsLabel, false, false, MARGIN); - - NoOfRowsSpinner.set_digits(0); - NoOfRowsSpinner.set_increments(1, 0); - NoOfRowsSpinner.set_range(1.0, 10000.0); - NoOfRowsSpinner.set_value(PerCol); - NoOfRowsSpinner.signal_changed().connect(sigc::mem_fun(*this, &TileDialog::on_col_spinbutton_changed)); - NoOfRowsSpinner.set_tooltip_text(_("Number of rows")); - NoOfRowsBox.pack_start(NoOfRowsSpinner, false, false, MARGIN); - gtk_size_group_add_widget(_col1, GTK_WIDGET(NoOfRowsBox.gobj())); - - RowHeightButton.set_label(_("Equal _height")); - RowHeightButton.set_use_underline(true); - double AutoRow = prefs->getDouble("/dialogs/gridtiler/AutoRowSize", 15); - if (AutoRow>0) - AutoRowSize=true; - else - AutoRowSize=false; - RowHeightButton.set_active(AutoRowSize); - - NoOfRowsBox.pack_start(RowHeightButton, false, false, MARGIN); - - RowHeightButton.set_tooltip_text(_("If not set, each row has the height of the tallest object in it")); - RowHeightButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::on_RowSize_checkbutton_changed)); - - { - /*#### Radio buttons to control vertical alignment ####*/ - - VertAlignLabel.set_label(_("Align:")); - VertAlignHBox.pack_start(VertAlignLabel, false, false, MARGIN); - - VertTopRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::VertAlign_changed)); - VertAlignGroup = VertTopRadioButton.get_group(); - VertAlignVBox.pack_start(VertTopRadioButton, false, false, 0); - - VertCentreRadioButton.set_group(VertAlignGroup); - VertCentreRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::VertAlign_changed)); - VertAlignVBox.pack_start(VertCentreRadioButton, false, false, 0); - - VertBotRadioButton.set_group(VertAlignGroup); - VertBotRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::VertAlign_changed)); - VertAlignVBox.pack_start(VertBotRadioButton, false, false, 0); - - VertAlign = prefs->getInt("/dialogs/gridtiler/VertAlign", 1); - if (VertAlign == 0) { - VertTopRadioButton.set_active(TRUE); - } - else if (VertAlign == 1) { - VertCentreRadioButton.set_active(TRUE); - } - else if (VertAlign == 2){ - VertBotRadioButton.set_active(TRUE); - } - VertAlignHBox.pack_start(VertAlignVBox, false, false, MARGIN); - NoOfRowsBox.pack_start(VertAlignHBox, false, false, MARGIN); - } - - SpinsHBox.pack_start(NoOfRowsBox, false, false, MARGIN); - - - /*#### Label for X ####*/ - padXByYLabel.set_label(" "); - XByYLabelVBox.pack_start(padXByYLabel, false, false, MARGIN); - XByYLabel.set_markup(" × "); - XByYLabelVBox.pack_start(XByYLabel, false, false, MARGIN); - SpinsHBox.pack_start(XByYLabelVBox, false, false, MARGIN); - gtk_size_group_add_widget(_col2, GTK_WIDGET(XByYLabelVBox.gobj())); - - /*#### Number of columns ####*/ - - NoOfColsLabel.set_text_with_mnemonic(_("_Columns:")); - NoOfColsLabel.set_mnemonic_widget(NoOfColsSpinner); - NoOfColsBox.pack_start(NoOfColsLabel, false, false, MARGIN); - - NoOfColsSpinner.set_digits(0); - NoOfColsSpinner.set_increments(1, 0); - NoOfColsSpinner.set_range(1.0, 10000.0); - NoOfColsSpinner.set_value(PerRow); - NoOfColsSpinner.signal_changed().connect(sigc::mem_fun(*this, &TileDialog::on_row_spinbutton_changed)); - NoOfColsSpinner.set_tooltip_text(_("Number of columns")); - NoOfColsBox.pack_start(NoOfColsSpinner, false, false, MARGIN); - gtk_size_group_add_widget(_col3, GTK_WIDGET(NoOfColsBox.gobj())); - - ColumnWidthButton.set_label(_("Equal _width")); - ColumnWidthButton.set_use_underline(true); - double AutoCol = prefs->getDouble("/dialogs/gridtiler/AutoColSize", 15); - if (AutoCol>0) - AutoColSize=true; - else - AutoColSize=false; - ColumnWidthButton.set_active(AutoColSize); - NoOfColsBox.pack_start(ColumnWidthButton, false, false, MARGIN); - - ColumnWidthButton.set_tooltip_text(_("If not set, each column has the width of the widest object in it")); - ColumnWidthButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::on_ColSize_checkbutton_changed)); - - - { - /*#### Radio buttons to control horizontal alignment ####*/ - - HorizAlignLabel.set_label(_("Align:")); - HorizAlignVBox.pack_start(HorizAlignLabel, false, false, MARGIN); - - HorizAlignHBox.pack_start(*(new Gtk::HBox()), true, true, 0); // centering strut - - HorizLeftRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::HorizAlign_changed)); - HorizAlignGroup = HorizLeftRadioButton.get_group(); - HorizAlignHBox.pack_start(HorizLeftRadioButton, false, false, 0); - - HorizCentreRadioButton.set_group(HorizAlignGroup); - HorizCentreRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::HorizAlign_changed)); - HorizAlignHBox.pack_start(HorizCentreRadioButton, false, false, 0); - - HorizRightRadioButton.set_group(HorizAlignGroup); - HorizRightRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::HorizAlign_changed)); - HorizAlignHBox.pack_start(HorizRightRadioButton, false, false, 0); - - HorizAlignHBox.pack_start(*(new Gtk::HBox()), true, true, 0); // centering strut - - HorizAlign = prefs->getInt("/dialogs/gridtiler/HorizAlign", 1); - if (HorizAlign == 0) { - HorizLeftRadioButton.set_active(TRUE); - } - else if (HorizAlign == 1) { - HorizCentreRadioButton.set_active(TRUE); - } - else if (HorizAlign == 2) { - HorizRightRadioButton.set_active(TRUE); - } - HorizAlignVBox.pack_start(HorizAlignHBox, false, false, MARGIN); - NoOfColsBox.pack_start(HorizAlignVBox, false, false, MARGIN); - } - - SpinsHBox.pack_start(NoOfColsBox, false, false, MARGIN); - - TileBox.pack_start(SpinsHBox, false, false, MARGIN); - - { - /*#### Radio buttons to control spacing manually or to fit selection bbox ####*/ - SpaceByBBoxRadioButton.set_label(_("_Fit into selection box")); - SpaceByBBoxRadioButton.set_use_underline (true); - SpaceByBBoxRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::Spacing_button_changed)); - SpacingGroup = SpaceByBBoxRadioButton.get_group(); - - SpacingVBox.pack_start(SpaceByBBoxRadioButton, false, false, MARGIN); - - SpaceManualRadioButton.set_label(_("_Set spacing:")); - SpaceManualRadioButton.set_use_underline (true); - SpaceManualRadioButton.set_group(SpacingGroup); - SpaceManualRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::Spacing_button_changed)); - SpacingVBox.pack_start(SpaceManualRadioButton, false, false, MARGIN); - - TileBox.pack_start(SpacingVBox, false, false, MARGIN); - } - - { - /*#### Padding ####*/ - PaddingUnitMenu.setUnitType(UNIT_TYPE_LINEAR); - PaddingUnitMenu.setUnit("px"); - - YPadding.setDigits(5); - YPadding.setIncrements(0.2, 0); - YPadding.setRange(-10000, 10000); - double yPad = prefs->getDouble("/dialogs/gridtiler/YPad", 15); - YPadding.setValue(yPad, "px"); - YPadding.signal_value_changed().connect(sigc::mem_fun(*this, &TileDialog::on_ypad_spinbutton_changed)); - - XPadding.setDigits(5); - XPadding.setIncrements(0.2, 0); - XPadding.setRange(-10000, 10000); - double xPad = prefs->getDouble("/dialogs/gridtiler/XPad", 15); - XPadding.setValue(xPad, "px"); - - XPadding.signal_value_changed().connect(sigc::mem_fun(*this, &TileDialog::on_xpad_spinbutton_changed)); - } - - PaddingTable->set_border_width(MARGIN); - -#if WITH_GTKMM_3_0 - PaddingTable->set_row_spacing(MARGIN); - PaddingTable->set_column_spacing(MARGIN); - PaddingTable->attach(XPadding, 0, 0, 1, 1); - PaddingTable->attach(PaddingUnitMenu, 1, 0, 1, 1); - PaddingTable->attach(YPadding, 0, 1, 1, 1); -#else - PaddingTable->set_row_spacings(MARGIN); - PaddingTable->set_col_spacings(MARGIN); - PaddingTable->attach(XPadding, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK); - PaddingTable->attach(PaddingUnitMenu, 1, 2, 0, 1, Gtk::SHRINK, Gtk::SHRINK); - PaddingTable->attach(YPadding, 0, 1, 1, 2, Gtk::SHRINK, Gtk::SHRINK); -#endif - - TileBox.pack_start(*PaddingTable, false, false, MARGIN); - - contents->pack_start(TileBox); - - double SpacingType = prefs->getDouble("/dialogs/gridtiler/SpacingType", 15); - if (SpacingType>0) { - ManualSpacing=true; - } else { - ManualSpacing=false; - } - SpaceManualRadioButton.set_active(ManualSpacing); - SpaceByBBoxRadioButton.set_active(!ManualSpacing); - XPadding.set_sensitive (ManualSpacing); - YPadding.set_sensitive (ManualSpacing); - - //## The OK button - TileOkButton = addResponseButton(C_("Rows and columns dialog","_Arrange"), GTK_RESPONSE_APPLY); - TileOkButton->set_use_underline(true); - TileOkButton->set_tooltip_text(_("Arrange selected objects")); - - show_all_children(); + switch(_notebook.get_current_page()) + { + case 0: + _gridArrangeTab->arrange(); + break; + case 1: + _polarArrangeTab->arrange(); + break; + } } } //namespace Dialog diff --git a/src/ui/dialog/tile.h b/src/ui/dialog/tile.h index 6e41723fd..2f75a8922 100644 --- a/src/ui/dialog/tile.h +++ b/src/ui/dialog/tile.h @@ -5,6 +5,7 @@ * Bob Jamison ( based off trace dialog) * John Cliff * Other dudes from The Inkscape Organization + * Declara Denis * * Copyright (C) 2004 Bob Jamison * Copyright (C) 2004 John Cliff @@ -29,8 +30,6 @@ #include <gtkmm/radiobutton.h> #include "ui/widget/panel.h" -#include "ui/widget/spinbutton.h" -#include "ui/widget/scalar-unit.h" namespace Gtk { class Button; @@ -46,134 +45,34 @@ namespace Inkscape { namespace UI { namespace Dialog { +class ArrangeTab; +class GridArrangeTab; +class PolarArrangeTab; -/** - * Dialog for tiling an object - */ -class TileDialog : public UI::Widget::Panel { -public: - TileDialog() ; - virtual ~TileDialog() {}; +class ArrangeDialog : public UI::Widget::Panel { +private: + Gtk::VBox _arrangeBox; + Gtk::Notebook _notebook; - /** - * Do the actual work - */ - void Grid_Arrange(); + GridArrangeTab *_gridArrangeTab; + PolarArrangeTab *_polarArrangeTab; - /** - * Respond to selection change - */ - void updateSelection(); + Gtk::Button *_arrangeButton; + +public: + ArrangeDialog(); + virtual ~ArrangeDialog() {}; /** * Callback from Apply */ virtual void _apply(); - // Callbacks from spinbuttons - void on_row_spinbutton_changed(); - void on_col_spinbutton_changed(); - void on_xpad_spinbutton_changed(); - void on_ypad_spinbutton_changed(); - void on_RowSize_checkbutton_changed(); - void on_ColSize_checkbutton_changed(); - void on_rowSize_spinbutton_changed(); - void on_colSize_spinbutton_changed(); - void Spacing_button_changed(); - void VertAlign_changed(); - void HorizAlign_changed(); - - static TileDialog& getInstance() { return *new TileDialog(); } - -private: - TileDialog(TileDialog const &d); // no copy - void operator=(TileDialog const &d); // no assign - - bool userHidden; - bool updating; - - Gtk::Notebook notebook; - - Gtk::VBox TileBox; - Gtk::Button *TileOkButton; - Gtk::Button *TileCancelButton; - - // Number selected label - Gtk::Label SelectionContentsLabel; - - - Gtk::HBox AlignHBox; - Gtk::HBox SpinsHBox; - - // Number per Row - Gtk::VBox NoOfColsBox; - Gtk::Label NoOfColsLabel; - Inkscape::UI::Widget::SpinButton NoOfColsSpinner; - bool AutoRowSize; - Gtk::CheckButton RowHeightButton; - - Gtk::VBox XByYLabelVBox; - Gtk::Label padXByYLabel; - Gtk::Label XByYLabel; - - // Number per Column - Gtk::VBox NoOfRowsBox; - Gtk::Label NoOfRowsLabel; - Inkscape::UI::Widget::SpinButton NoOfRowsSpinner; - bool AutoColSize; - Gtk::CheckButton ColumnWidthButton; - - // Vertical align - Gtk::Label VertAlignLabel; - Gtk::HBox VertAlignHBox; - Gtk::VBox VertAlignVBox; - Gtk::RadioButtonGroup VertAlignGroup; - Gtk::RadioButton VertCentreRadioButton; - Gtk::RadioButton VertTopRadioButton; - Gtk::RadioButton VertBotRadioButton; - double VertAlign; - - // Horizontal align - Gtk::Label HorizAlignLabel; - Gtk::VBox HorizAlignVBox; - Gtk::HBox HorizAlignHBox; - Gtk::RadioButtonGroup HorizAlignGroup; - Gtk::RadioButton HorizCentreRadioButton; - Gtk::RadioButton HorizLeftRadioButton; - Gtk::RadioButton HorizRightRadioButton; - double HorizAlign; - - Inkscape::UI::Widget::UnitMenu PaddingUnitMenu; - Inkscape::UI::Widget::ScalarUnit XPadding; - Inkscape::UI::Widget::ScalarUnit YPadding; - -#if WITH_GTKMM_3_0 - Gtk::Grid *PaddingTable; -#else - Gtk::Table *PaddingTable; -#endif + virtual void on_show(); - // BBox or manual spacing - Gtk::VBox SpacingVBox; - Gtk::RadioButtonGroup SpacingGroup; - Gtk::RadioButton SpaceByBBoxRadioButton; - Gtk::RadioButton SpaceManualRadioButton; - bool ManualSpacing; - - // Row height - Gtk::VBox RowHeightVBox; - Gtk::HBox RowHeightBox; - Gtk::Label RowHeightLabel; - Inkscape::UI::Widget::SpinButton RowHeightSpinner; - - // Column width - Gtk::VBox ColumnWidthVBox; - Gtk::HBox ColumnWidthBox; - Gtk::Label ColumnWidthLabel; - Inkscape::UI::Widget::SpinButton ColumnWidthSpinner; + static ArrangeDialog& getInstance() { return *new ArrangeDialog(); } }; - } //namespace Dialog } //namespace UI } //namespace Inkscape diff --git a/src/ui/tools/connector-tool.cpp b/src/ui/tools/connector-tool.cpp index e19f35832..4f918b483 100644 --- a/src/ui/tools/connector-tool.cpp +++ b/src/ui/tools/connector-tool.cpp @@ -201,7 +201,8 @@ ConnectorTool::~ConnectorTool() { for (int i = 0; i < 2; ++i) { if (this->endpt_handle[1]) { - g_object_unref(this->endpt_handle[i]); + //g_object_unref(this->endpt_handle[i]); + knot_unref(this->endpt_handle[i]); this->endpt_handle[i] = NULL; } } @@ -319,7 +320,7 @@ cc_clear_active_knots(SPKnotList k) // Hide the connection points if they exist. if (k.size()) { for (SPKnotList::iterator it = k.begin(); it != k.end(); ++it) { - sp_knot_hide(it->first); + it->first->hide(); } } } @@ -341,7 +342,7 @@ void ConnectorTool::cc_clear_active_conn() { // Hide the endpoint handles. for (int i = 0; i < 2; ++i) { if (this->endpt_handle[i]) { - sp_knot_hide(this->endpt_handle[i]); + this->endpt_handle[i]->hide(); } } } @@ -365,7 +366,7 @@ cc_select_handle(SPKnot* knot) knot->setSize(10); knot->setAnchor(SP_ANCHOR_CENTER); knot->setFill(0x0000ffff, 0x0000ffff, 0x0000ffff); - sp_knot_update_ctrl(knot); + knot->update_ctrl(); } static void @@ -375,7 +376,7 @@ cc_deselect_handle(SPKnot* knot) knot->setSize(8); knot->setAnchor(SP_ANCHOR_CENTER); knot->setFill(0xffffff00, 0xff0000ff, 0xff0000ff); - sp_knot_update_ctrl(knot); + knot->update_ctrl(); } bool ConnectorTool::item_handler(SPItem* item, GdkEvent* event) { @@ -969,7 +970,8 @@ cc_generic_knot_handler(SPCanvasItem *, GdkEvent *event, SPKnot *knot) { g_assert (knot != NULL); - g_object_ref(knot); + //g_object_ref(knot); + knot_ref(knot); ConnectorTool *cc = SP_CONNECTOR_CONTEXT( knot->desktop->event_context); @@ -979,7 +981,7 @@ cc_generic_knot_handler(SPCanvasItem *, GdkEvent *event, SPKnot *knot) gchar const *knot_tip = "Click to join at this point"; switch (event->type) { case GDK_ENTER_NOTIFY: - sp_knot_set_flag(knot, SP_KNOT_MOUSEOVER, TRUE); + knot->set_flag(SP_KNOT_MOUSEOVER, TRUE); cc->active_handle = knot; if (knot_tip) @@ -991,7 +993,7 @@ cc_generic_knot_handler(SPCanvasItem *, GdkEvent *event, SPKnot *knot) consumed = TRUE; break; case GDK_LEAVE_NOTIFY: - sp_knot_set_flag(knot, SP_KNOT_MOUSEOVER, FALSE); + knot->set_flag(SP_KNOT_MOUSEOVER, FALSE); /* FIXME: the following test is a workaround for LP Bug #1273510. * It seems that a signal is not correctly disconnected, maybe @@ -1010,7 +1012,8 @@ cc_generic_knot_handler(SPCanvasItem *, GdkEvent *event, SPKnot *knot) break; } - g_object_unref(knot); + //g_object_unref(knot); + knot_unref(knot); return consumed; } @@ -1066,14 +1069,14 @@ endpt_handler(SPKnot */*knot*/, GdkEvent *event, ConnectorTool *cc) } void ConnectorTool::_activeShapeAddKnot(SPItem* item) { - SPKnot *knot = sp_knot_new(desktop, 0); + SPKnot *knot = new SPKnot(desktop, 0); knot->owner = item; knot->setShape(SP_KNOT_SHAPE_SQUARE); knot->setSize(8); knot->setAnchor(SP_ANCHOR_CENTER); knot->setFill(0xffffff00, 0xff0000ff, 0xff0000ff); - sp_knot_update_ctrl(knot); + knot->update_ctrl(); // We don't want to use the standard knot handler. g_signal_handler_disconnect(G_OBJECT(knot->item), @@ -1084,8 +1087,8 @@ void ConnectorTool::_activeShapeAddKnot(SPItem* item) { g_signal_connect(G_OBJECT(knot->item), "event", G_CALLBACK(cc_generic_knot_handler), knot); - sp_knot_set_position(knot, item->avoidRef->getConnectionPointPos() * desktop->doc2dt(), 0); - sp_knot_show(knot); + knot->set_position(item->avoidRef->getConnectionPointPos() * desktop->doc2dt(), 0); + knot->show(); this->knots[knot] = 1; } @@ -1149,17 +1152,17 @@ void ConnectorTool::cc_set_active_conn(SPItem *item) { { // Connector is invisible because it is clipped to the boundary of // two overlpapping shapes. - sp_knot_hide(this->endpt_handle[0]); - sp_knot_hide(this->endpt_handle[1]); + this->endpt_handle[0]->hide(); + this->endpt_handle[1]->hide(); } else { // Just adjust handle positions. Geom::Point startpt = *(curve->first_point()) * i2dt; - sp_knot_set_position(this->endpt_handle[0], startpt, 0); + this->endpt_handle[0]->set_position(startpt, 0); Geom::Point endpt = *(curve->last_point()) * i2dt; - sp_knot_set_position(this->endpt_handle[1], endpt, 0); + this->endpt_handle[1]->set_position(endpt, 0); } return; @@ -1184,7 +1187,7 @@ void ConnectorTool::cc_set_active_conn(SPItem *item) { for (int i = 0; i < 2; ++i) { // Create the handle if it doesn't exist if ( this->endpt_handle[i] == NULL ) { - SPKnot *knot = sp_knot_new(this->desktop, + SPKnot *knot = new SPKnot(this->desktop, _("<b>Connector endpoint</b>: drag to reroute or connect to new shapes")); knot->setShape(SP_KNOT_SHAPE_SQUARE); @@ -1192,7 +1195,7 @@ void ConnectorTool::cc_set_active_conn(SPItem *item) { knot->setAnchor(SP_ANCHOR_CENTER); knot->setFill(0xffffff00, 0xff0000ff, 0xff0000ff); knot->setStroke(0x000000ff, 0x000000ff, 0x000000ff); - sp_knot_update_ctrl(knot); + knot->update_ctrl(); // We don't want to use the standard knot handler, // since we don't want this knot to be draggable. @@ -1232,13 +1235,13 @@ void ConnectorTool::cc_set_active_conn(SPItem *item) { } Geom::Point startpt = *(curve->first_point()) * i2dt; - sp_knot_set_position(this->endpt_handle[0], startpt, 0); + this->endpt_handle[0]->set_position(startpt, 0); Geom::Point endpt = *(curve->last_point()) * i2dt; - sp_knot_set_position(this->endpt_handle[1], endpt, 0); + this->endpt_handle[1]->set_position(endpt, 0); - sp_knot_show(this->endpt_handle[0]); - sp_knot_show(this->endpt_handle[1]); + this->endpt_handle[0]->show(); + this->endpt_handle[1]->show(); } void cc_create_connection_point(ConnectorTool* cc) @@ -1250,7 +1253,7 @@ void cc_create_connection_point(ConnectorTool* cc) cc_deselect_handle( cc->selected_handle ); } - SPKnot *knot = sp_knot_new(cc->desktop, 0); + SPKnot *knot = new SPKnot(cc->desktop, 0); // We do not process events on this knot. g_signal_handler_disconnect(G_OBJECT(knot->item), @@ -1260,7 +1263,7 @@ void cc_create_connection_point(ConnectorTool* cc) cc_select_handle( knot ); cc->selected_handle = knot; - sp_knot_show(cc->selected_handle); + cc->selected_handle->show(); cc->state = SP_CONNECTOR_CONTEXT_NEWCONNPOINT; } } diff --git a/src/ui/widget/Makefile_insert b/src/ui/widget/Makefile_insert index 196004df1..e18b790bd 100644 --- a/src/ui/widget/Makefile_insert +++ b/src/ui/widget/Makefile_insert @@ -1,6 +1,8 @@ ## Makefile.am fragment sourced by src/Makefile.am. ink_common_sources += \ + ui/widget/anchor-selector.h \ + ui/widget/anchor-selector.cpp \ ui/widget/attr-widget.h \ ui/widget/button.h \ ui/widget/button.cpp \ diff --git a/src/ui/widget/anchor-selector.cpp b/src/ui/widget/anchor-selector.cpp new file mode 100644 index 000000000..82e27ee89 --- /dev/null +++ b/src/ui/widget/anchor-selector.cpp @@ -0,0 +1,97 @@ +/* + * anchor-selector.cpp + * + * Created on: Mar 22, 2012 + * Author: denis + * + * Released under GNU GPL. Read the file 'COPYING' for more information. + */ + +#include "ui/widget/anchor-selector.h" +#include <iostream> +#include "widgets/icon.h" +#include "ui/icon-names.h" + +namespace Inkscape { +namespace UI { +namespace Widget { + +void AnchorSelector::setupButton(const Glib::ustring& icon, Gtk::ToggleButton& button) { + Gtk::Widget* buttonIcon = Gtk::manage(sp_icon_get_icon(icon, Inkscape::ICON_SIZE_SMALL_TOOLBAR)); + buttonIcon->show(); + + button.set_relief(Gtk::RELIEF_NONE); + button.show(); + button.add(*buttonIcon); + button.set_can_focus(false); +} + +AnchorSelector::AnchorSelector() + : Gtk::Alignment(0.5, 0, 0, 0), + _container(3, 3, true) +{ + setupButton(INKSCAPE_ICON("boundingbox_top_left"), _buttons[0]); + setupButton(INKSCAPE_ICON("boundingbox_top"), _buttons[1]); + setupButton(INKSCAPE_ICON("boundingbox_top_right"), _buttons[2]); + setupButton(INKSCAPE_ICON("boundingbox_left"), _buttons[3]); + setupButton(INKSCAPE_ICON("boundingbox_center"), _buttons[4]); + setupButton(INKSCAPE_ICON("boundingbox_right"), _buttons[5]); + setupButton(INKSCAPE_ICON("boundingbox_bottom_left"), _buttons[6]); + setupButton(INKSCAPE_ICON("boundingbox_bottom"), _buttons[7]); + setupButton(INKSCAPE_ICON("boundingbox_bottom_right"), _buttons[8]); + + for(int i = 0; i < 9; ++i) { + _buttons[i].signal_clicked().connect( + sigc::bind(sigc::mem_fun(*this, &AnchorSelector::btn_activated), i)); + _container.attach(_buttons[i], i % 3, i % 3+1, i / 3, i / 3+1, Gtk::FILL, Gtk::FILL); + } + _selection = 4; + _buttons[4].set_active(); + + this->add(_container); +} + +AnchorSelector::~AnchorSelector() +{ + // TODO Auto-generated destructor stub +} + +void AnchorSelector::btn_activated(int index) +{ + + if(_selection == index && _buttons[index].get_active() == false) + { + _buttons[index].set_active(true); + } + else if(_selection != index && _buttons[index].get_active()) + { + int old_selection = _selection; + _selection = index; + _buttons[old_selection].set_active(false); + _selectionChanged.emit(); + } +} + +void AnchorSelector::setAlignment(int horizontal, int vertical) +{ + int index = 3 * vertical + horizontal; + if(index >= 0 && index < 9) + { + _buttons[index].set_active(!_buttons[index].get_active()); + } +} + +} // namespace Widget +} // namespace UI +} // namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/ui/widget/anchor-selector.h b/src/ui/widget/anchor-selector.h new file mode 100644 index 000000000..2263438e3 --- /dev/null +++ b/src/ui/widget/anchor-selector.h @@ -0,0 +1,59 @@ +/* + * anchor-selector.h + * + * Created on: Mar 22, 2012 + * Author: denis + * + * Released under GNU GPL. Read the file 'COPYING' for more information. + */ + +#ifndef ANCHOR_SELECTOR_H_ +#define ANCHOR_SELECTOR_H_ + +#include <gtkmm.h> + +namespace Inkscape { +namespace UI { +namespace Widget { + +class AnchorSelector : public Gtk::Alignment +{ +private: + Gtk::ToggleButton _buttons[9]; + int _selection; + Gtk::Table _container; + + sigc::signal<void> _selectionChanged; + + void setupButton(const Glib::ustring &icon, Gtk::ToggleButton &button); + void btn_activated(int index); + +public: + + int getHorizontalAlignment() { return _selection % 3; } + int getVerticalAlignment() { return _selection / 3; } + + sigc::signal<void> &on_selectionChanged() { return _selectionChanged; } + + void setAlignment(int horizontal, int vertical); + + AnchorSelector(); + virtual ~AnchorSelector(); +}; + +} // namespace Widget +} // namespace UI +} // namespace Inkscape + +#endif /* ANCHOR_SELECTOR_H_ */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/vanishing-point.cpp b/src/vanishing-point.cpp index 361a7a0de..a0f3692a5 100644 --- a/src/vanishing-point.cpp +++ b/src/vanishing-point.cpp @@ -85,12 +85,12 @@ have_VPs_of_same_perspective (VPDragger *dr1, VPDragger *dr2) } static void -vp_knot_moved_handler (SPKnot *knot, Geom::Point const *ppointer, guint state, gpointer data) +vp_knot_moved_handler (SPKnot *knot, Geom::Point const &ppointer, guint state, gpointer data) { VPDragger *dragger = (VPDragger *) data; VPDrag *drag = dragger->parent; - Geom::Point p = *ppointer; + Geom::Point p = ppointer; // FIXME: take from prefs double snap_dist = SNAP_DIST / inkscape_active_desktop()->current_zoom(); @@ -188,7 +188,7 @@ vp_knot_moved_handler (SPKnot *knot, Geom::Point const *ppointer, guint state, g m.unSetup(); if (s.getSnapped()) { p = s.getPoint(); - sp_knot_moveto(knot, p); + knot->moveto(p); } } @@ -277,22 +277,22 @@ VPDragger::VPDragger(VPDrag *parent, Geom::Point p, VanishingPoint &vp) if (vp.is_finite()) { // create the knot - this->knot = sp_knot_new(inkscape_active_desktop(), NULL); + this->knot = new SPKnot(inkscape_active_desktop(), NULL); this->knot->setMode(SP_KNOT_MODE_XOR); this->knot->setFill(VP_KNOT_COLOR_NORMAL, VP_KNOT_COLOR_NORMAL, VP_KNOT_COLOR_NORMAL); this->knot->setStroke(0x000000ff, 0x000000ff, 0x000000ff); - sp_knot_update_ctrl(this->knot); + this->knot->update_ctrl(); knot->item->ctrlType = CTRL_TYPE_ANCHOR; ControlManager::getManager().track(knot->item); // move knot to the given point - sp_knot_set_position (this->knot, this->point, SP_KNOT_STATE_NORMAL); - sp_knot_show (this->knot); + this->knot->set_position(this->point, SP_KNOT_STATE_NORMAL); + this->knot->show(); // connect knot's signals - g_signal_connect (G_OBJECT (this->knot), "moved", G_CALLBACK (vp_knot_moved_handler), this); - g_signal_connect (G_OBJECT (this->knot), "grabbed", G_CALLBACK (vp_knot_grabbed_handler), this); - g_signal_connect (G_OBJECT (this->knot), "ungrabbed", G_CALLBACK (vp_knot_ungrabbed_handler), this); + this->_moved_connection = this->knot->_moved_signal.connect(sigc::bind(sigc::ptr_fun(vp_knot_moved_handler), this)); + this->_grabbed_connection = this->knot->_grabbed_signal.connect(sigc::bind(sigc::ptr_fun(vp_knot_grabbed_handler), this)); + this->_ungrabbed_connection = this->knot->_ungrabbed_signal.connect(sigc::bind(sigc::ptr_fun(vp_knot_ungrabbed_handler), this)); // add the initial VP (which may be NULL!) this->addVP (vp); @@ -302,11 +302,12 @@ VPDragger::VPDragger(VPDrag *parent, Geom::Point p, VanishingPoint &vp) VPDragger::~VPDragger() { // disconnect signals - g_signal_handlers_disconnect_by_func(G_OBJECT(this->knot), (gpointer) G_CALLBACK (vp_knot_moved_handler), this); - g_signal_handlers_disconnect_by_func(G_OBJECT(this->knot), (gpointer) G_CALLBACK (vp_knot_grabbed_handler), this); - g_signal_handlers_disconnect_by_func(G_OBJECT(this->knot), (gpointer) G_CALLBACK (vp_knot_ungrabbed_handler), this); + this->_moved_connection.disconnect(); + this->_grabbed_connection.disconnect(); + this->_ungrabbed_connection.disconnect(); + /* unref should call destroy */ - g_object_unref (G_OBJECT (this->knot)); + knot_unref(this->knot); } /** diff --git a/src/vanishing-point.h b/src/vanishing-point.h index 53366fe66..ed66aab0a 100644 --- a/src/vanishing-point.h +++ b/src/vanishing-point.h @@ -133,6 +133,10 @@ public: bool dragging_started; + sigc::connection _moved_connection; + sigc::connection _grabbed_connection; + sigc::connection _ungrabbed_connection; + std::list<VanishingPoint> vps; void addVP(VanishingPoint &vp, bool update_pos = false); diff --git a/src/verbs.cpp b/src/verbs.cpp index 94da5a866..9e6bf1c5e 100644 --- a/src/verbs.cpp +++ b/src/verbs.cpp @@ -1187,9 +1187,9 @@ void SelectionVerb::perform(SPAction *action, void *data) case SP_VERB_SELECTION_BREAK_APART: sp_selected_path_break_apart(dt); break; - case SP_VERB_SELECTION_GRIDTILE: + case SP_VERB_SELECTION_ARRANGE: inkscape_dialogs_unhide(); - dt->_dlg_mgr->showDialog("TileDialog"); + dt->_dlg_mgr->showDialog("TileDialog"); //FIXME: denis: What's this string (to be changed) break; default: break; @@ -2568,8 +2568,8 @@ Verb *Verb::_base_verbs[] = { // Advanced tutorial for more info new SelectionVerb(SP_VERB_SELECTION_BREAK_APART, "SelectionBreakApart", N_("Break _Apart"), N_("Break selected paths into subpaths"), INKSCAPE_ICON("path-break-apart")), - new SelectionVerb(SP_VERB_SELECTION_GRIDTILE, "DialogGridArrange", N_("Ro_ws and Columns..."), - N_("Arrange selected objects in a table"), INKSCAPE_ICON("dialog-rows-and-columns")), + new SelectionVerb(SP_VERB_SELECTION_ARRANGE, "DialogArrange", N_("_Arrange..."), + N_("Arrange selected objects in a table or circle"), INKSCAPE_ICON("dialog-rows-and-columns")), // Layer new LayerVerb(SP_VERB_LAYER_NEW, "LayerNew", N_("_Add Layer..."), N_("Create a new layer"), INKSCAPE_ICON("layer-new")), diff --git a/src/verbs.h b/src/verbs.h index 1533bbd50..86613b246 100644 --- a/src/verbs.h +++ b/src/verbs.h @@ -138,7 +138,7 @@ enum { SP_VERB_SELECTION_CREATE_BITMAP, SP_VERB_SELECTION_COMBINE, SP_VERB_SELECTION_BREAK_APART, - SP_VERB_SELECTION_GRIDTILE, + SP_VERB_SELECTION_ARRANGE, // Former SP_VERB_SELECTION_GRIDTILE /* Layer */ SP_VERB_LAYER_NEW, SP_VERB_LAYER_RENAME, |
