mesh-tool.cpp revision 769a6887551cf7ff7bce4b48d3ac303cbea69507
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * Mesh drawing and editing tool
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * bulia byak <buliabyak@users.sf.net>
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * Johan Engelen <j.b.c.engelen@ewi.utwente.nl>
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * Abhishek Sharma
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * Tavmjong Bah <tavmjong@free.fr>
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * Copyright (C) 2012 Tavmjong Bah
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * Copyright (C) 2007 Johan Engelen
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * Copyright (C) 2005 Authors
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * Released under GNU GPL, read the file 'COPYING' for more information
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis//#define DEBUG_MESH
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis// Gradient specific
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis// Mesh specific
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisstatic void sp_mesh_drag(MeshTool &rc, Geom::Point const pt, guint state, guint32 etime);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis bool meshContextRegistered = ToolFactory::instance().registerObject("/tools/mesh", createMeshContext);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisconst std::string& MeshTool::getPrefsPath() {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisconst std::string MeshTool::prefsPath = "/tools/mesh";
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis// TODO: The gradient tool class looks like a 1:1 copy.
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis// TODO: Why are these connections stored as pointers?
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis // TODO: This value is overwritten in the root handler
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisvoid MeshTool::selection_changed(Inkscape::Selection* /*sel*/) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis Inkscape::Selection *selection = this->desktop->getSelection();
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis guint n_obj = g_slist_length((GSList *) selection->itemList());
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (!drag->isNonEmpty() || selection->isEmpty()) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis //The use of ngettext in the following code is intentional even if the English singular form would never be used
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (drag->singleSelectedDraggerNumDraggables() == 1) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis //TRANSLATORS: %s will be substituted with the point name (see previous messages); This is part of a compound message
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis _("%s selected"),
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis //TRANSLATORS: Mind the space in front. This is part of a compound message
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis ngettext(" out of %d mesh handle"," out of %d mesh handles",n_tot),
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis ngettext(" on %d selected object"," on %d selected objects",n_obj),NULL);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis this->message_context->setF(Inkscape::NORMAL_MESSAGE,
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis message,_(ms_handle_descr[drag->singleSelectedDraggerSingleDraggableType()]), n_tot, n_obj);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis //TRANSLATORS: This is a part of a compound message (out of two more indicating: grandint handle count & object count)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis ngettext("One handle merging %d stop (drag with <b>Shift</b> to separate) selected",
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis "One handle merging %d stops (drag with <b>Shift</b> to separate) selected",
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis drag->singleSelectedDraggerNumDraggables()),
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis ngettext(" out of %d mesh handle"," out of %d mesh handles",n_tot),
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis ngettext(" on %d selected object"," on %d selected objects",n_obj),NULL);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis this->message_context->setF(Inkscape::NORMAL_MESSAGE,message,drag->singleSelectedDraggerNumDraggables(), n_tot, n_obj);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis //TRANSLATORS: The plural refers to number of selected mesh handles. This is part of a compound message (part two indicates selected object count)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis g_strconcat(ngettext("<b>%d</b> mesh handle selected out of %d","<b>%d</b> mesh handles selected out of %d",n_sel),
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis //TRANSLATORS: Mind the space in front. (Refers to gradient handles selected). This is part of a compound message
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis ngettext(" on %d selected object"," on %d selected objects",n_obj),NULL);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis this->message_context->setF(Inkscape::NORMAL_MESSAGE,message, n_sel, n_tot, n_obj);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis } else if (n_sel == 0) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis this->message_context->setF(Inkscape::NORMAL_MESSAGE,
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis //TRANSLATORS: The plural refers to number of selected objects
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis ngettext("<b>No</b> mesh handles selected out of %d on %d selected object",
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis "<b>No</b> mesh handles selected out of %d on %d selected objects",n_obj), n_tot, n_obj);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis // We need to update mesh gradient handles.
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis // Get gradient this drag belongs too..
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis // std::cout << "mesh_selection_changed: selection: objects: " << n_obj << std::endl;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis // GSList *itemList = (GSList *) selection->itemList();
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis // while( itemList ) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis // SPItem *item = SP_ITEM( itemList->data );
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis // // std::cout << " item: " << SP_OBJECT(item)->getId() << std::endl;
// guint rows = 0;//mg->array.patches.size();
// guint columns = 0;//mg->array.patches[0].size();
this->enableSelectionCue();
this->enableGrDrag();
return close;
static void sp_mesh_context_split_near_point(MeshTool *rc, SPItem *item, Geom::Point mouse_p, guint32 /*etime*/)
#ifdef DEBUG_MESH
#ifdef DEBUG_MESH
for( std::map<SPMeshGradient*, std::vector<guint> >::const_iterator iter = points.begin(); iter != points.end(); ++iter) {
switch (operation) {
case MG_CORNER_SIDE_TOGGLE:
case MG_CORNER_SIDE_ARC:
case MG_CORNER_TENSOR_TOGGLE:
case MG_CORNER_COLOR_SMOOTH:
case MG_CORNER_COLOR_PICK:
if( noperation > 0 ) {
switch (operation) {
case MG_CORNER_SIDE_TOGGLE:
case MG_CORNER_SIDE_ARC:
case MG_CORNER_TENSOR_TOGGLE:
case MG_CORNER_COLOR_SMOOTH:
case MG_CORNER_COLOR_PICK:
static bool dragging;
double const nudge = prefs->getDoubleLimited("/options/nudgedistance/value", 2, 0, 1000, "px"); // in px
case GDK_2BUTTON_PRESS:
#ifdef DEBUG_MESH
bool over_line = false;
over_line |= sp_mesh_context_is_over_line (this, (SPItem*) line, Geom::Point(event->motion.x, event->motion.y));
if (over_line) {
sp_mesh_context_split_near_point(this, SP_ITEM(selection->itemList()->data), this->mousepoint_doc, event->button.time);
Inkscape::PaintTarget fsmode = (prefs->getInt("/tools/gradient/newfillorstroke", 1) != 0) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE;
#ifdef DEBUG_MESH
std::cout << "sp_mesh_context_root_handler: creating new mesh on: " << (fsmode == Inkscape::FOR_FILL ? "Fill" : "Stroke") << std::endl;
SPGradient *vector = sp_gradient_vector_for_object(sp_desktop_document(desktop), desktop, item, fsmode);
case GDK_BUTTON_PRESS:
#ifdef DEBUG_MESH
this->within_tolerance = true;
dragging = true;
this->item_to_select = sp_event_context_find_item (desktop, button_w, event->button.state & GDK_MOD1_MASK, TRUE);
m.unSetup();
case GDK_MOTION_NOTIFY:
#ifdef DEBUG_MESH
if ( this->within_tolerance
this->within_tolerance = false;
this->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Draw around</b> handles to select them"));
m.unSetup();
// See "pathflash" in ui/tools/node-tool.cpp for ideas.
bool over_line = false;
over_line |= sp_mesh_context_is_over_line (this, (SPItem*) l->data, Geom::Point(event->motion.x, event->motion.y));
this->sp_event_context_update_cursor();
this->cursor_addnode = false;
this->sp_event_context_update_cursor();
this->cursor_addnode = true;
case GDK_BUTTON_RELEASE:
#ifdef DEBUG_MESH
bool over_line = false;
over_line = sp_mesh_context_is_over_line (this, (SPItem*) line, Geom::Point(event->motion.x, event->motion.y));
if (over_line) {
dragging = false;
if (!this->within_tolerance) {
} else if (this->item_to_select) {
case GDK_KEY_PRESS:
#ifdef DEBUG_MESH
case GDK_KEY_Alt_L:
case GDK_KEY_Alt_R:
case GDK_KEY_Control_L:
case GDK_KEY_Control_R:
case GDK_KEY_Shift_L:
case GDK_KEY_Shift_R:
case GDK_KEY_Meta_R:
NULL);
case GDK_KEY_A:
case GDK_KEY_a:
case GDK_KEY_Escape:
case GDK_KEY_KP_Left:
case GDK_KEY_KP_4:
case GDK_KEY_KP_Up:
case GDK_KEY_KP_8:
case GDK_KEY_KP_Right:
case GDK_KEY_KP_6:
case GDK_KEY_KP_Down:
case GDK_KEY_KP_2:
case GDK_KEY_Insert:
case GDK_KEY_KP_Insert:
case GDK_KEY_Delete:
case GDK_KEY_KP_Delete:
case GDK_KEY_BackSpace:
case GDK_KEY_B:
case GDK_KEY_G:
case GDK_KEY_J:
case GDK_KEY_K:
case GDK_KEY_RELEASE:
#ifdef DEBUG_MESH
case GDK_KEY_Alt_L:
case GDK_KEY_Alt_R:
case GDK_KEY_Control_L:
case GDK_KEY_Control_R:
case GDK_KEY_Shift_L:
case GDK_KEY_Shift_R:
case GDK_KEY_Meta_R:
if (!ret) {
return ret;
static void sp_mesh_drag(MeshTool &rc, Geom::Point const /*pt*/, guint /*state*/, guint32 /*etime*/) {
Inkscape::PaintTarget fill_or_stroke = (prefs->getInt("/tools/gradient/newfillorstroke", 1) != 0) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE;
vector = sp_gradient_vector_for_object(document, desktop, SP_ITEM(g_slist_last(items)->data), fill_or_stroke);
// HACK: reset fill-opacity - that 0.75 is annoying; BUT remove this when we have an opacity slider for all tabs
sp_desktop_message_stack(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select <b>objects</b> on which to create gradient."));