//FIXME: must work with text selection void text_remove_all_kerns() { SPDesktop *desktop = SP_ACTIVE_DESKTOP; Inkscape::Selection *selection = sp_desktop_selection(desktop); if (selection->isEmpty()) { sp_desktop_message_stack(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select <b>text(s)</b> to remove kerns from.")); return; } bool did = false; for (GSList *items = g_slist_copy((GSList *) selection->itemList()); items != NULL; items = items->next) { SPObject *obj = SP_OBJECT(items->data); if (!SP_IS_TEXT(obj) && !SP_IS_TSPAN(obj) && !SP_IS_FLOWTEXT(obj)) { continue; } text_remove_all_kerns_recursively(obj); obj->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_TEXT_LAYOUT_MODIFIED_FLAG); did = true; } if (!did) { sp_desktop_message_stack(desktop)->flash(Inkscape::ERROR_MESSAGE, _("Select <b>text(s)</b> to remove kerns from.")); } else { sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, _("Remove manual kerns")); } }
void sp_selected_path_reverse(SPDesktop *desktop) { Inkscape::Selection *selection = sp_desktop_selection(desktop); GSList *items = (GSList *) selection->itemList(); if (!items) { sp_desktop_message_stack(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select <b>path(s)</b> to reverse.")); return; } // set "busy" cursor desktop->setWaitingCursor(); bool did = false; desktop->messageStack()->flash(Inkscape::IMMEDIATE_MESSAGE, _("Reversing paths...")); for (GSList *i = items; i != NULL; i = i->next) { if (!SP_IS_PATH(i->data)) { continue; } did = true; SPPath *path = SP_PATH(i->data); SPCurve *rcurve = path->get_curve_reference()->create_reverse(); gchar *str = sp_svg_write_path(rcurve->get_pathvector()); if ( path->hasPathEffectRecursive() ) { path->getRepr()->setAttribute("inkscape:original-d", str); } else { path->getRepr()->setAttribute("d", str); } g_free(str); rcurve->unref(); // reverse nodetypes order (Bug #179866) gchar *nodetypes = g_strdup(path->getRepr()->attribute("sodipodi:nodetypes")); if ( nodetypes ) { path->getRepr()->setAttribute("sodipodi:nodetypes", g_strreverse(nodetypes)); g_free(nodetypes); } } desktop->clearWaitingCursor(); if (did) { DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_SELECTION_REVERSE, _("Reverse path")); } else { sp_desktop_message_stack(desktop)->flash(Inkscape::ERROR_MESSAGE, _("<b>No paths</b> to reverse in the selection.")); } }
void sp_selected_path_reverse(SPDesktop *desktop) { Inkscape::Selection *selection = desktop->getSelection(); std::vector<SPItem*> items = selection->itemList(); if (items.empty()) { desktop->getMessageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>path(s)</b> to reverse.")); return; } // set "busy" cursor desktop->setWaitingCursor(); bool did = false; desktop->messageStack()->flash(Inkscape::IMMEDIATE_MESSAGE, _("Reversing paths...")); for (std::vector<SPItem*>::const_iterator i = items.begin(); i != items.end(); ++i){ SPPath *path = dynamic_cast<SPPath *>(*i); if (!path) { continue; } did = true; SPCurve *rcurve = path->get_curve_reference()->create_reverse(); gchar *str = sp_svg_write_path(rcurve->get_pathvector()); if ( path->hasPathEffectRecursive() ) { path->getRepr()->setAttribute("inkscape:original-d", str); } else { path->getRepr()->setAttribute("d", str); } g_free(str); rcurve->unref(); // reverse nodetypes order (Bug #179866) gchar *nodetypes = g_strdup(path->getRepr()->attribute("sodipodi:nodetypes")); if ( nodetypes ) { path->getRepr()->setAttribute("sodipodi:nodetypes", g_strreverse(nodetypes)); g_free(nodetypes); } } desktop->clearWaitingCursor(); if (did) { DocumentUndo::done(desktop->getDocument(), SP_VERB_SELECTION_REVERSE, _("Reverse path")); } else { desktop->getMessageStack()->flash(Inkscape::ERROR_MESSAGE, _("<b>No paths</b> to reverse in the selection.")); } }
void text_remove_from_path() { SPDesktop *desktop = SP_ACTIVE_DESKTOP; Inkscape::Selection *selection = sp_desktop_selection(desktop); if (selection->isEmpty()) { sp_desktop_message_stack(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select <b>a text on path</b> to remove it from path.")); return; } bool did = false; for (GSList *items = g_slist_copy((GSList *) selection->itemList()); items != NULL; items = items->next) { if (!SP_IS_TEXT_TEXTPATH(SP_OBJECT(items->data))) { continue; } SPObject *tp = sp_object_first_child(SP_OBJECT(items->data)); did = true; sp_textpath_to_text(tp); } if (!did) { sp_desktop_message_stack(desktop)->flash(Inkscape::ERROR_MESSAGE, _("<b>No texts-on-paths</b> in the selection.")); } else { sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, _("Remove text from path")); selection->setList(g_slist_copy((GSList *) selection->itemList())); // reselect to update statusbar description } }
static void gradient_selection_changed (Inkscape::Selection *, gpointer data) { SPGradientContext *rc = (SPGradientContext *) data; GrDrag *drag = rc->_grdrag; Inkscape::Selection *selection = sp_desktop_selection(SP_EVENT_CONTEXT(rc)->desktop); guint n_obj = g_slist_length((GSList *) selection->itemList()); if (!drag->isNonEmpty() || selection->isEmpty()) return; guint n_tot = drag->numDraggers(); guint n_sel = drag->numSelected(); //The use of ngettext in the following code is intentional even if the English singular form would never be used if (n_sel == 1) { if (drag->singleSelectedDraggerNumDraggables() == 1) { gchar * message = g_strconcat( //TRANSLATORS: %s will be substituted with the point name (see previous messages); This is part of a compound message _("%s selected"), //TRANSLATORS: Mind the space in front. This is part of a compound message ngettext(" out of %d gradient handle"," out of %d gradient handles",n_tot), ngettext(" on %d selected object"," on %d selected objects",n_obj),NULL); rc->_message_context->setF(Inkscape::NORMAL_MESSAGE, message,_(gr_handle_descr[drag->singleSelectedDraggerSingleDraggableType()]), n_tot, n_obj); } else { gchar * message = g_strconcat( //TRANSLATORS: This is a part of a compound message (out of two more indicating: grandint handle count & object count) ngettext("One handle merging %d stop (drag with <b>Shift</b> to separate) selected", "One handle merging %d stops (drag with <b>Shift</b> to separate) selected",drag->singleSelectedDraggerNumDraggables()), ngettext(" out of %d gradient handle"," out of %d gradient handles",n_tot), ngettext(" on %d selected object"," on %d selected objects",n_obj),NULL); rc->_message_context->setF(Inkscape::NORMAL_MESSAGE,message,drag->singleSelectedDraggerNumDraggables(), n_tot, n_obj); } } else if (n_sel > 1) { //TRANSLATORS: The plural refers to number of selected gradient handles. This is part of a compound message (part two indicates selected object count) gchar * message = g_strconcat(ngettext("<b>%d</b> gradient handle selected out of %d","<b>%d</b> gradient handles selected out of %d",n_sel), //TRANSLATORS: Mind the space in front. (Refers to gradient handles selected). This is part of a compound message ngettext(" on %d selected object"," on %d selected objects",n_obj),NULL); rc->_message_context->setF(Inkscape::NORMAL_MESSAGE,message, n_sel, n_tot, n_obj); } else if (n_sel == 0) { rc->_message_context->setF(Inkscape::NORMAL_MESSAGE, //TRANSLATORS: The plural refers to number of selected objects ngettext("<b>No</b> gradient handles selected out of %d on %d selected object", "<b>No</b> gradient handles selected out of %d on %d selected objects",n_obj), n_tot, n_obj); } }
static void sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name, void (SPRect::*setter)(gdouble)) { SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( tbl, "desktop" )); UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" )); Unit const *unit = tracker->getActiveUnit(); g_return_if_fail(unit != NULL); if (DocumentUndo::getUndoSensitive(desktop->getDocument())) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); prefs->setDouble(Glib::ustring("/tools/shapes/rect/") + value_name, Quantity::convert(gtk_adjustment_get_value(adj), unit, "px")); } // quit if run by the attr_changed listener if (g_object_get_data( tbl, "freeze" ) || tracker->isUpdating()) { return; } // in turn, prevent listener from responding g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE)); bool modmade = false; Inkscape::Selection *selection = desktop->getSelection(); std::vector<SPItem*> itemlist=selection->itemList(); for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){ if (SP_IS_RECT(*i)) { if (gtk_adjustment_get_value(adj) != 0) { (SP_RECT(*i)->*setter)(Quantity::convert(gtk_adjustment_get_value(adj), unit, "px")); } else { (*i)->getRepr()->setAttribute(value_name, NULL); } modmade = true; } } sp_rtb_sensitivize( tbl ); if (modmade) { DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_RECT, _("Change rectangle")); } g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); }
std::set<VanishingPoint*, less_ptr> VPDragger::VPsOfSelectedBoxes() { std::set<VanishingPoint*, less_ptr> sel_vps; VanishingPoint *vp; // FIXME: Should we take the selection from the parent VPDrag? I guess it shouldn't make a difference. Inkscape::Selection *sel = sp_desktop_selection(inkscape_active_desktop()); for (GSList const* i = sel->itemList(); i != NULL; i = i->next) { if (!SP_IS_BOX3D(i->data)) continue; SPBox3D *box = SP_BOX3D(i->data); vp = this->findVPWithBox(box); if (vp) { sel_vps.insert (vp); } } return sel_vps; }
static bool sp_spray_dilate(SPSprayContext *tc, Geom::Point /*event_p*/, Geom::Point p, Geom::Point vector, bool reverse) { Inkscape::Selection *selection = sp_desktop_selection(SP_EVENT_CONTEXT(tc)->desktop); SPDesktop *desktop = SP_EVENT_CONTEXT(tc)->desktop; if (selection->isEmpty()) { return false; } bool did = false; double radius = get_dilate_radius(tc); double path_force = get_path_force(tc); if (radius == 0 || path_force == 0) { return false; } double path_mean = get_path_mean(tc); if (radius == 0 || path_mean == 0) { return false; } double path_standard_deviation = get_path_standard_deviation(tc); if (radius == 0 || path_standard_deviation == 0) { return false; } double move_force = get_move_force(tc); double move_mean = get_move_mean(tc); double move_standard_deviation = get_move_standard_deviation(tc); for (GSList *items = g_slist_copy((GSList *) selection->itemList()); items != NULL; items = items->next) { SPItem *item = (SPItem *) items->data; if (is_transform_modes(tc->mode)) { if (sp_spray_recursive(desktop, selection, item, p, vector, tc->mode, radius, move_force, tc->population, tc->scale, tc->scale_variation, reverse, move_mean, move_standard_deviation, tc->ratio, tc->tilt, tc->rotation_variation, tc->distrib)) did = true; } else { if (sp_spray_recursive(desktop, selection, item, p, vector, tc->mode, radius, path_force, tc->population, tc->scale, tc->scale_variation, reverse, path_mean, path_standard_deviation, tc->ratio, tc->tilt, tc->rotation_variation, tc->distrib)) did = true; } } return did; }
/** Converts the selected items to LPEItems if they are not already so; e.g. SPRects) */ void sp_selected_to_lpeitems(SPDesktop *desktop) { Inkscape::Selection *selection = desktop->getSelection(); if (selection->isEmpty()) { return; } std::vector<SPItem*> selected(selection->itemList()); std::vector<Inkscape::XML::Node*> to_select; selection->clear(); std::vector<SPItem*> items(selected); sp_item_list_to_curves(items, selected, to_select, true); selection->setReprList(to_select); selection->addList(selected); }
/* This function is an entry point from GUI */ void sp_selected_path_to_curves(SPDesktop *desktop, bool interactive) { Inkscape::Selection *selection = sp_desktop_selection(desktop); if (selection->isEmpty()) { if (interactive) sp_desktop_message_stack(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to convert to path.")); return; } bool did = false; if (interactive) { desktop->messageStack()->flash(Inkscape::IMMEDIATE_MESSAGE, _("Converting objects to paths...")); // set "busy" cursor desktop->setWaitingCursor(); } GSList *selected = g_slist_copy((GSList *) selection->itemList()); GSList *to_select = NULL; selection->clear(); GSList *items = g_slist_copy(selected); did = sp_item_list_to_curves(items, &selected, &to_select); g_slist_free (items); selection->setReprList(to_select); selection->addList(selected); g_slist_free (to_select); g_slist_free (selected); if (interactive) { desktop->clearWaitingCursor(); if (did) { sp_document_done(sp_desktop_document(desktop), SP_VERB_OBJECT_TO_CURVE, _("Object to path")); } else { sp_desktop_message_stack(desktop)->flash(Inkscape::ERROR_MESSAGE, _("<b>No objects</b> to convert to path in the selection.")); return; } } }
/// Setup, taking the list of items to ignore from the desktop's selection. void SnapManager::setupIgnoreSelection(SPDesktop const *desktop, bool snapindicator, std::vector<Inkscape::SnapCandidatePoint> *unselected_nodes, SPGuide *guide_to_ignore) { g_assert(desktop != NULL); if (_desktop != NULL) { // Someone has been naughty here! This is dangerous g_warning("The snapmanager has been set up before, but unSetup() hasn't been called afterwards. It possibly held invalid pointers"); } _desktop = desktop; _snapindicator = snapindicator; _unselected_nodes = unselected_nodes; _guide_to_ignore = guide_to_ignore; _rotation_center_source_items.clear(); _items_to_ignore.clear(); Inkscape::Selection *sel = _desktop->selection; std::vector<SPItem*> const items = sel->itemList(); for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i) { _items_to_ignore.push_back(*i); } }
/** Converts the selected items to LPEItems if they are not already so; e.g. SPRects) */ void sp_selected_to_lpeitems(SPDesktop *desktop) { Inkscape::Selection *selection = sp_desktop_selection(desktop); if (selection->isEmpty()) { return; } bool did = false; GSList *selected = g_slist_copy((GSList *) selection->itemList()); GSList *to_select = NULL; selection->clear(); GSList *items = g_slist_copy(selected); did = sp_item_list_to_curves(items, &selected, &to_select, true); g_slist_free (items); selection->setReprList(to_select); selection->addList(selected); g_slist_free (to_select); g_slist_free (selected); }
void text_flow_into_shape() { SPDesktop *desktop = SP_ACTIVE_DESKTOP; if (!desktop) return; SPDocument *doc = sp_desktop_document (desktop); Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc); Inkscape::Selection *selection = sp_desktop_selection(desktop); SPItem *text = text_or_flowtext_in_selection(selection); SPItem *shape = shape_in_selection(selection); if (!text || !shape || g_slist_length((GSList *) selection->itemList()) < 2) { sp_desktop_message_stack(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select <b>a text</b> and one or more <b>paths or shapes</b> to flow text into frame.")); return; } if (SP_IS_TEXT(text)) { // remove transform from text, but recursively scale text's fontsize by the expansion SP_TEXT(text)->_adjustFontsizeRecursive(text, NR::expansion(SP_ITEM(text)->transform)); SP_OBJECT_REPR(text)->setAttribute("transform", NULL); } Inkscape::XML::Node *root_repr = xml_doc->createElement("svg:flowRoot"); root_repr->setAttribute("xml:space", "preserve"); // we preserve spaces in the text objects we create root_repr->setAttribute("style", SP_OBJECT_REPR(text)->attribute("style")); // fixme: transfer style attrs too SP_OBJECT_REPR(SP_OBJECT_PARENT(shape))->appendChild(root_repr); SPObject *root_object = doc->getObjectByRepr(root_repr); g_return_if_fail(SP_IS_FLOWTEXT(root_object)); Inkscape::XML::Node *region_repr = xml_doc->createElement("svg:flowRegion"); root_repr->appendChild(region_repr); SPObject *object = doc->getObjectByRepr(region_repr); g_return_if_fail(SP_IS_FLOWREGION(object)); /* Add clones */ for (GSList *items = (GSList *) selection->itemList(); items != NULL; items = items->next) { SPItem *item = SP_ITEM(items->data); if (SP_IS_SHAPE(item)){ Inkscape::XML::Node *clone = xml_doc->createElement("svg:use"); clone->setAttribute("x", "0"); clone->setAttribute("y", "0"); clone->setAttribute("xlink:href", g_strdup_printf("#%s", SP_OBJECT_REPR(item)->attribute("id"))); // add the new clone to the region region_repr->appendChild(clone); } } if (SP_IS_TEXT(text)) { // flow from text, as string Inkscape::XML::Node *para_repr = xml_doc->createElement("svg:flowPara"); root_repr->appendChild(para_repr); object = doc->getObjectByRepr(para_repr); g_return_if_fail(SP_IS_FLOWPARA(object)); Inkscape::Text::Layout const *layout = te_get_layout(text); Glib::ustring text_ustring = sp_te_get_string_multiline(text, layout->begin(), layout->end()); Inkscape::XML::Node *text_repr = xml_doc->createTextNode(text_ustring.c_str()); // FIXME: transfer all formatting! and convert newlines into flowParas! para_repr->appendChild(text_repr); Inkscape::GC::release(para_repr); Inkscape::GC::release(text_repr); } else { // reflow an already flowed text, preserving paras for (SPObject *o = SP_OBJECT(text)->children; o != NULL; o = o->next) { if (SP_IS_FLOWPARA(o)) { Inkscape::XML::Node *para_repr = SP_OBJECT_REPR(o)->duplicate(xml_doc); root_repr->appendChild(para_repr); object = doc->getObjectByRepr(para_repr); g_return_if_fail(SP_IS_FLOWPARA(object)); Inkscape::GC::release(para_repr); } } } SP_OBJECT(text)->deleteObject (true); sp_document_done(doc, SP_VERB_CONTEXT_TEXT, _("Flow text into shape")); sp_desktop_selection(desktop)->set(SP_ITEM(root_object)); Inkscape::GC::release(root_repr); Inkscape::GC::release(region_repr); }
void sp_selected_path_combine(SPDesktop *desktop) { Inkscape::Selection *selection = desktop->getSelection(); SPDocument *doc = desktop->getDocument(); std::vector<SPItem*> items(selection->itemList()); if (items.size() < 1) { desktop->getMessageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to combine.")); return; } desktop->messageStack()->flash(Inkscape::IMMEDIATE_MESSAGE, _("Combining paths...")); // set "busy" cursor desktop->setWaitingCursor(); items = sp_degroup_list (items); // descend into any groups in selection std::vector<SPItem*> to_paths; for (std::vector<SPItem*>::const_reverse_iterator i = items.rbegin(); i != items.rend(); ++i) { if (!dynamic_cast<SPPath *>(*i) && !dynamic_cast<SPGroup *>(*i)) { to_paths.push_back(*i); } } std::vector<Inkscape::XML::Node*> converted; bool did = sp_item_list_to_curves(to_paths, items, converted); for (std::vector<Inkscape::XML::Node*>::const_iterator i = converted.begin(); i != converted.end(); ++i) items.push_back((SPItem*)doc->getObjectByRepr(*i)); items = sp_degroup_list (items); // converting to path may have added more groups, descend again sort(items.begin(),items.end(),less_than_items); assert(!items.empty()); // cannot be NULL because of list length check at top of function // remember the position, id, transform and style of the topmost path, they will be assigned to the combined one gint position = 0; char const *id = NULL; char const *transform = NULL; char const *style = NULL; char const *path_effect = NULL; SPCurve* curve = NULL; SPItem *first = NULL; Inkscape::XML::Node *parent = NULL; if (did) { selection->clear(); } for (std::vector<SPItem*>::const_reverse_iterator i = items.rbegin(); i != items.rend(); ++i){ SPItem *item = *i; SPPath *path = dynamic_cast<SPPath *>(item); if (!path) { continue; } if (!did) { selection->clear(); did = true; } SPCurve *c = path->get_curve_for_edit(); if (first == NULL) { // this is the topmost path first = item; parent = first->getRepr()->parent(); position = first->getRepr()->position(); id = first->getRepr()->attribute("id"); transform = first->getRepr()->attribute("transform"); // FIXME: merge styles of combined objects instead of using the first one's style style = first->getRepr()->attribute("style"); path_effect = first->getRepr()->attribute("inkscape:path-effect"); //c->transform(item->transform); curve = c; } else { c->transform(item->getRelativeTransform(first)); curve->append(c, false); c->unref(); // reduce position only if the same parent if (item->getRepr()->parent() == parent) { position--; } // delete the object for real, so that its clones can take appropriate action item->deleteObject(); } } if (did) { first->deleteObject(false); // delete the topmost. Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc(); Inkscape::XML::Node *repr = xml_doc->createElement("svg:path"); // restore id, transform, path effect, and style repr->setAttribute("id", id); if (transform) { repr->setAttribute("transform", transform); } repr->setAttribute("style", style); repr->setAttribute("inkscape:path-effect", path_effect); // set path data corresponding to new curve gchar *dstring = sp_svg_write_path(curve->get_pathvector()); curve->unref(); if (path_effect) { repr->setAttribute("inkscape:original-d", dstring); } else { repr->setAttribute("d", dstring); } g_free(dstring); // add the new group to the parent of the topmost parent->appendChild(repr); // move to the position of the topmost, reduced by the number of deleted items repr->setPosition(position > 0 ? position : 0); DocumentUndo::done(desktop->getDocument(), SP_VERB_SELECTION_COMBINE, _("Combine")); selection->set(repr); Inkscape::GC::release(repr); } else { desktop->getMessageStack()->flash(Inkscape::ERROR_MESSAGE, _("<b>No path(s)</b> to combine in the selection.")); } desktop->clearWaitingCursor(); }
void text_put_on_path() { SPDesktop *desktop = SP_ACTIVE_DESKTOP; if (!desktop) return; Inkscape::Selection *selection = sp_desktop_selection(desktop); SPItem *text = text_or_flowtext_in_selection(selection); SPItem *shape = shape_in_selection(selection); Inkscape::XML::Document *xml_doc = sp_document_repr_doc(desktop->doc()); if (!text || !shape || g_slist_length((GSList *) selection->itemList()) != 2) { sp_desktop_message_stack(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select <b>a text and a path</b> to put text on path.")); return; } if (SP_IS_TEXT_TEXTPATH(text)) { sp_desktop_message_stack(desktop)->flash(Inkscape::ERROR_MESSAGE, _("This text object is <b>already put on a path</b>. Remove it from the path first. Use <b>Shift+D</b> to look up its path.")); return; } if (SP_IS_RECT(shape)) { // rect is the only SPShape which is not <path> yet, and thus SVG forbids us from putting text on it sp_desktop_message_stack(desktop)->flash(Inkscape::ERROR_MESSAGE, _("You cannot put text on a rectangle in this version. Convert rectangle to path first.")); return; } // if a flowed text is selected, convert it to a regular text object if (SP_IS_FLOWTEXT(text)) { if (!SP_FLOWTEXT(text)->layout.outputExists()) { sp_desktop_message_stack(desktop)-> flash(Inkscape::WARNING_MESSAGE, _("The flowed text(s) must be <b>visible</b> in order to be put on a path.")); } Inkscape::XML::Node *repr = SP_FLOWTEXT(text)->getAsText(); if (!repr) return; Inkscape::XML::Node *parent = SP_OBJECT_REPR(text)->parent(); parent->appendChild(repr); SPItem *new_item = (SPItem *) sp_desktop_document(desktop)->getObjectByRepr(repr); sp_item_write_transform(new_item, repr, text->transform); SP_OBJECT(new_item)->updateRepr(); Inkscape::GC::release(repr); text->deleteObject(); // delete the orignal flowtext sp_document_ensure_up_to_date(sp_desktop_document(desktop)); selection->clear(); text = new_item; // point to the new text } Inkscape::Text::Layout const *layout = te_get_layout(text); Inkscape::Text::Layout::Alignment text_alignment = layout->paragraphAlignment(layout->begin()); // remove transform from text, but recursively scale text's fontsize by the expansion SP_TEXT(text)->_adjustFontsizeRecursive (text, NR::expansion(SP_ITEM(text)->transform)); SP_OBJECT_REPR(text)->setAttribute("transform", NULL); // make a list of text children GSList *text_reprs = NULL; for (SPObject *o = SP_OBJECT(text)->children; o != NULL; o = o->next) { text_reprs = g_slist_prepend(text_reprs, SP_OBJECT_REPR(o)); } // create textPath and put it into the text Inkscape::XML::Node *textpath = xml_doc->createElement("svg:textPath"); // reference the shape textpath->setAttribute("xlink:href", g_strdup_printf("#%s", SP_OBJECT_REPR(shape)->attribute("id"))); if (text_alignment == Inkscape::Text::Layout::RIGHT) textpath->setAttribute("startOffset", "100%"); else if (text_alignment == Inkscape::Text::Layout::CENTER) textpath->setAttribute("startOffset", "50%"); SP_OBJECT_REPR(text)->addChild(textpath, NULL); for ( GSList *i = text_reprs ; i ; i = i->next ) { // Make a copy of each text child Inkscape::XML::Node *copy = ((Inkscape::XML::Node *) i->data)->duplicate(xml_doc); // We cannot have multiline in textpath, so remove line attrs from tspans if (!strcmp(copy->name(), "svg:tspan")) { copy->setAttribute("sodipodi:role", NULL); copy->setAttribute("x", NULL); copy->setAttribute("y", NULL); } // remove the old repr from under text SP_OBJECT_REPR(text)->removeChild((Inkscape::XML::Node *) i->data); // put its copy into under textPath textpath->addChild(copy, NULL); // fixme: copy id } // x/y are useless with textpath, and confuse Batik 1.5 SP_OBJECT_REPR(text)->setAttribute("x", NULL); SP_OBJECT_REPR(text)->setAttribute("y", NULL); sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, _("Put text on path")); g_slist_free(text_reprs); }
void flowtext_to_text() { SPDesktop *desktop = SP_ACTIVE_DESKTOP; Inkscape::Selection *selection = sp_desktop_selection(desktop); if (selection->isEmpty()) { sp_desktop_message_stack(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select <b>flowed text(s)</b> to convert.")); return; } bool did = false; GSList *reprs = NULL; GSList *items = g_slist_copy((GSList *) selection->itemList()); for (; items != NULL; items = items->next) { SPItem *item = (SPItem *) items->data; if (!SP_IS_FLOWTEXT(item)) continue; if (!SP_FLOWTEXT(item)->layout.outputExists()) { sp_desktop_message_stack(desktop)-> flash(Inkscape::WARNING_MESSAGE, _("The flowed text(s) must be <b>visible</b> in order to be converted.")); return; } Inkscape::XML::Node *repr = SP_FLOWTEXT(item)->getAsText(); if (!repr) break; did = true; Inkscape::XML::Node *parent = SP_OBJECT_REPR(item)->parent(); parent->addChild(repr, SP_OBJECT_REPR(item)); SPItem *new_item = (SPItem *) sp_desktop_document(desktop)->getObjectByRepr(repr); sp_item_write_transform(new_item, repr, item->transform); SP_OBJECT(new_item)->updateRepr(); Inkscape::GC::release(repr); item->deleteObject(); reprs = g_slist_prepend(reprs, repr); } g_slist_free(items); if (did) { sp_document_done(sp_desktop_document(desktop), SP_VERB_OBJECT_FLOWTEXT_TO_TEXT, _("Convert flowed text to text")); selection->setReprList(reprs); } else { sp_desktop_message_stack(desktop)-> flash(Inkscape::ERROR_MESSAGE, _("<b>No flowed text(s)</b> to convert in the selection.")); } g_slist_free(reprs); }
/** Handles all keyboard and mouse input for meshs. */ static gint sp_mesh_context_root_handler(SPEventContext *event_context, GdkEvent *event) { // static int count = 0; // std::cout << "sp_mesh_context_root_handler: " << count++ << std::endl; static bool dragging; SPDesktop *desktop = event_context->desktop; Inkscape::Selection *selection = sp_desktop_selection (desktop); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); SPMeshContext *rc = SP_MESH_CONTEXT(event_context); event_context->tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); double const nudge = prefs->getDoubleLimited("/options/nudgedistance/value", 2, 0, 1000, "px"); // in px GrDrag *drag = event_context->_grdrag; g_assert (drag); gint ret = FALSE; switch (event->type) { case GDK_2BUTTON_PRESS: #ifdef DEBUG_MESH std::cout << "sp_mesh_context_root_handler: GDK_2BUTTON_PRESS" << std::endl; #endif // Double click: // If over a mesh line, divide mesh row/column // If not over a line, create new gradients for selected objects. if ( event->button.button == 1 ) { // Are we over a mesh line? bool over_line = false; SPCtrlCurve *line = NULL; if (drag->lines) { for (GSList *l = drag->lines; (l != NULL) && (!over_line); l = l->next) { line = (SPCtrlCurve*) l->data; over_line |= sp_mesh_context_is_over_line (rc, (SPItem*) line, Geom::Point(event->motion.x, event->motion.y)); } } if (over_line) { // We take the first item in selection, because with doubleclick, the first click // always resets selection to the single object under cursor sp_mesh_context_split_near_point(rc, SP_ITEM(selection->itemList()->data), rc->mousepoint_doc, event->button.time); } else { // Create a new gradient with default coordinates. for (GSList const* i = selection->itemList(); i != NULL; i = i->next) { SPItem *item = SP_ITEM(i->data); SPGradientType new_type = SP_GRADIENT_TYPE_MESH; 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; #endif SPGradient *vector = sp_gradient_vector_for_object(sp_desktop_document(desktop), desktop, item, fsmode); SPGradient *priv = sp_item_set_gradient(item, vector, new_type, fsmode); sp_gradient_reset_to_userspace(priv, item); } DocumentUndo::done(sp_desktop_document (desktop), SP_VERB_CONTEXT_MESH, _("Create default mesh")); } ret = TRUE; } break; case GDK_BUTTON_PRESS: #ifdef DEBUG_MESH std::cout << "sp_mesh_context_root_handler: GDK_BUTTON_PRESS" << std::endl; #endif // Button down // If Shift key down: do rubber band selection // Else set origin for drag. A drag creates a new gradient if one does not exist if ( event->button.button == 1 && !event_context->space_panning ) { Geom::Point button_w(event->button.x, event->button.y); // save drag origin event_context->xp = (gint) button_w[Geom::X]; event_context->yp = (gint) button_w[Geom::Y]; event_context->within_tolerance = true; dragging = true; Geom::Point button_dt = desktop->w2d(button_w); if (event->button.state & GDK_SHIFT_MASK) { Inkscape::Rubberband::get(desktop)->start(desktop, button_dt); } else { // remember clicked item, disregarding groups, honoring Alt; do nothing with Crtl to // enable Ctrl+doubleclick of exactly the selected item(s) if (!(event->button.state & GDK_CONTROL_MASK)) event_context->item_to_select = sp_event_context_find_item (desktop, button_w, event->button.state & GDK_MOD1_MASK, TRUE); if (!selection->isEmpty()) { SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop); m.freeSnapReturnByRef(button_dt, Inkscape::SNAPSOURCE_NODE_HANDLE); m.unSetup(); } rc->origin = button_dt; } ret = TRUE; } break; case GDK_MOTION_NOTIFY: // Mouse move if ( dragging && ( event->motion.state & GDK_BUTTON1_MASK ) && !event_context->space_panning ) { #ifdef DEBUG_MESH std::cout << "sp_mesh_context_root_handler: GDK_MOTION_NOTIFY: Dragging" << std::endl; #endif if ( event_context->within_tolerance && ( abs( (gint) event->motion.x - event_context->xp ) < event_context->tolerance ) && ( abs( (gint) event->motion.y - event_context->yp ) < event_context->tolerance ) ) { break; // do not drag if we're within tolerance from origin } // Once the user has moved farther than tolerance from the original location // (indicating they intend to draw, not click), then always process the // motion notify coordinates as given (no snapping back to origin) event_context->within_tolerance = false; Geom::Point const motion_w(event->motion.x, event->motion.y); Geom::Point const motion_dt = event_context->desktop->w2d(motion_w); if (Inkscape::Rubberband::get(desktop)->is_started()) { Inkscape::Rubberband::get(desktop)->move(motion_dt); event_context->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Draw around</b> handles to select them")); } else { // Create new gradient with coordinates determined by drag. sp_mesh_drag(*rc, motion_dt, event->motion.state, event->motion.time); } gobble_motion_events(GDK_BUTTON1_MASK); ret = TRUE; } else { // Not dragging // Do snapping if (!drag->mouseOver() && !selection->isEmpty()) { SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop); Geom::Point const motion_w(event->motion.x, event->motion.y); Geom::Point const motion_dt = event_context->desktop->w2d(motion_w); m.preSnap(Inkscape::SnapCandidatePoint(motion_dt, Inkscape::SNAPSOURCE_OTHER_HANDLE)); m.unSetup(); } // Highlight corner node corresponding to side or tensor node if( drag->mouseOver() ) { // MESH FIXME: Light up corresponding corner node corresponding to node we are over. // See "pathflash" in ui/tools/node-tool.cpp for ideas. // Use desktop->add_temporary_canvasitem( SPCanvasItem, milliseconds ); } // Change cursor shape if over line bool over_line = false; if (drag->lines) { for (GSList *l = drag->lines; l != NULL; l = l->next) { over_line |= sp_mesh_context_is_over_line (rc, (SPItem*) l->data, Geom::Point(event->motion.x, event->motion.y)); } } if (rc->cursor_addnode && !over_line) { event_context->cursor_shape = cursor_gradient_xpm; sp_event_context_update_cursor(event_context); rc->cursor_addnode = false; } else if (!rc->cursor_addnode && over_line) { event_context->cursor_shape = cursor_gradient_add_xpm; sp_event_context_update_cursor(event_context); rc->cursor_addnode = true; } } break; case GDK_BUTTON_RELEASE: #ifdef DEBUG_MESH std::cout << "sp_mesh_context_root_handler: GDK_BUTTON_RELEASE" << std::endl; #endif event_context->xp = event_context->yp = 0; if ( event->button.button == 1 && !event_context->space_panning ) { // Check if over line bool over_line = false; SPCtrlLine *line = NULL; if (drag->lines) { for (GSList *l = drag->lines; (l != NULL) && (!over_line); l = l->next) { line = (SPCtrlLine*) l->data; over_line = sp_mesh_context_is_over_line (rc, (SPItem*) line, Geom::Point(event->motion.x, event->motion.y)); if (over_line) break; } } if ( (event->button.state & GDK_CONTROL_MASK) && (event->button.state & GDK_MOD1_MASK ) ) { if (over_line && line) { sp_mesh_context_split_near_point(rc, line->item, rc->mousepoint_doc, 0); ret = TRUE; } } else { dragging = false; // unless clicked with Ctrl (to enable Ctrl+doubleclick). if (event->button.state & GDK_CONTROL_MASK) { ret = TRUE; break; } if (!event_context->within_tolerance) { // we've been dragging, either do nothing (grdrag handles that), // or rubberband-select if we have rubberband Inkscape::Rubberband *r = Inkscape::Rubberband::get(desktop); if (r->is_started() && !event_context->within_tolerance) { // this was a rubberband drag if (r->getMode() == RUBBERBAND_MODE_RECT) { Geom::OptRect const b = r->getRectangle(); drag->selectRect(*b); } } } else if (event_context->item_to_select) { if (over_line && line) { // Clicked on an existing mesh line, don't change selection. This stops // possible change in selection during a double click with overlapping objects } else { // no dragging, select clicked item if any if (event->button.state & GDK_SHIFT_MASK) { selection->toggle(event_context->item_to_select); } else { selection->set(event_context->item_to_select); } } } else { // click in an empty space; do the same as Esc if (drag->selected) { drag->deselectAll(); } else { selection->clear(); } } event_context->item_to_select = NULL; ret = TRUE; } Inkscape::Rubberband::get(desktop)->stop(); } break; case GDK_KEY_PRESS: #ifdef DEBUG_MESH std::cout << "sp_mesh_context_root_handler: GDK_KEY_PRESS" << std::endl; #endif // FIXME: tip switch (get_group0_keyval (&event->key)) { 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_L: // Meta is when you press Shift+Alt (at least on my machine) case GDK_KEY_Meta_R: sp_event_show_modifier_tip (event_context->defaultMessageContext(), event, _("FIXME<b>Ctrl</b>: snap mesh angle"), _("FIXME<b>Shift</b>: draw mesh around the starting point"), NULL); break; case GDK_KEY_A: case GDK_KEY_a: if (MOD__CTRL_ONLY && drag->isNonEmpty()) { drag->selectAll(); ret = TRUE; } break; case GDK_KEY_Escape: if (drag->selected) { drag->deselectAll(); } else { selection->clear(); } ret = TRUE; //TODO: make dragging escapable by Esc break; case GDK_KEY_Left: // move handle left case GDK_KEY_KP_Left: case GDK_KEY_KP_4: if (!MOD__CTRL) { // not ctrl gint mul = 1 + gobble_key_events( get_group0_keyval(&event->key), 0); // with any mask if (MOD__ALT) { // alt if (MOD__SHIFT) drag->selected_move_screen(mul*-10, 0); // shift else drag->selected_move_screen(mul*-1, 0); // no shift } else { // no alt if (MOD__SHIFT) drag->selected_move(mul*-10*nudge, 0); // shift else drag->selected_move(mul*-nudge, 0); // no shift } ret = TRUE; } break; case GDK_KEY_Up: // move handle up case GDK_KEY_KP_Up: case GDK_KEY_KP_8: if (!MOD__CTRL) { // not ctrl gint mul = 1 + gobble_key_events( get_group0_keyval(&event->key), 0); // with any mask if (MOD__ALT) { // alt if (MOD__SHIFT) drag->selected_move_screen(0, mul*10); // shift else drag->selected_move_screen(0, mul*1); // no shift } else { // no alt if (MOD__SHIFT) drag->selected_move(0, mul*10*nudge); // shift else drag->selected_move(0, mul*nudge); // no shift } ret = TRUE; } break; case GDK_KEY_Right: // move handle right case GDK_KEY_KP_Right: case GDK_KEY_KP_6: if (!MOD__CTRL) { // not ctrl gint mul = 1 + gobble_key_events( get_group0_keyval(&event->key), 0); // with any mask if (MOD__ALT) { // alt if (MOD__SHIFT) drag->selected_move_screen(mul*10, 0); // shift else drag->selected_move_screen(mul*1, 0); // no shift } else { // no alt if (MOD__SHIFT) drag->selected_move(mul*10*nudge, 0); // shift else drag->selected_move(mul*nudge, 0); // no shift } ret = TRUE; } break; case GDK_KEY_Down: // move handle down case GDK_KEY_KP_Down: case GDK_KEY_KP_2: if (!MOD__CTRL) { // not ctrl gint mul = 1 + gobble_key_events( get_group0_keyval(&event->key), 0); // with any mask if (MOD__ALT) { // alt if (MOD__SHIFT) drag->selected_move_screen(0, mul*-10); // shift else drag->selected_move_screen(0, mul*-1); // no shift } else { // no alt if (MOD__SHIFT) drag->selected_move(0, mul*-10*nudge); // shift else drag->selected_move(0, mul*-nudge); // no shift } ret = TRUE; } break; case GDK_KEY_Insert: case GDK_KEY_KP_Insert: // with any modifiers: //sp_gradient_context_add_stops_between_selected_stops (rc); std::cout << "Inserting stops between selected stops not implemented yet" << std::endl; ret = TRUE; break; case GDK_KEY_Delete: case GDK_KEY_KP_Delete: case GDK_KEY_BackSpace: if ( drag->selected ) { std::cout << "Deleting mesh stops not implemented yet" << std::endl; ret = TRUE; } break; // Mesh Operations -------------------------------------------- case GDK_KEY_b: // Toggle mesh side between lineto and curveto. case GDK_KEY_B: if (MOD__ALT && drag->isNonEmpty() && drag->hasSelection()) { sp_mesh_context_corner_operation ( rc, MG_CORNER_SIDE_TOGGLE ); ret = TRUE; } break; case GDK_KEY_c: // Convert mesh side from generic Bezier to Bezier approximating arc, case GDK_KEY_C: // preserving handle direction. if (MOD__ALT && drag->isNonEmpty() && drag->hasSelection()) { sp_mesh_context_corner_operation ( rc, MG_CORNER_SIDE_ARC ); ret = TRUE; } break; case GDK_KEY_g: // Toggle mesh tensor points on/off case GDK_KEY_G: if (MOD__ALT && drag->isNonEmpty() && drag->hasSelection()) { sp_mesh_context_corner_operation ( rc, MG_CORNER_TENSOR_TOGGLE ); ret = TRUE; } break; case GDK_KEY_j: // Smooth corner color case GDK_KEY_J: if (MOD__ALT && drag->isNonEmpty() && drag->hasSelection()) { sp_mesh_context_corner_operation ( rc, MG_CORNER_COLOR_SMOOTH ); ret = TRUE; } break; case GDK_KEY_k: // Pick corner color case GDK_KEY_K: if (MOD__ALT && drag->isNonEmpty() && drag->hasSelection()) { sp_mesh_context_corner_operation ( rc, MG_CORNER_COLOR_PICK ); ret = TRUE; } break; default: break; } break; case GDK_KEY_RELEASE: #ifdef DEBUG_MESH std::cout << "sp_mesh_context_root_handler: GDK_KEY_RELEASE" << std::endl; #endif switch (get_group0_keyval (&event->key)) { 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_L: // Meta is when you press Shift+Alt case GDK_KEY_Meta_R: event_context->defaultMessageContext()->clear(); break; default: break; } break; default: break; } if (!ret) { if (((SPEventContextClass *) parent_class)->root_handler) { ret = ((SPEventContextClass *) parent_class)->root_handler(event_context, event); } } return ret; }
void sp_selected_path_break_apart(SPDesktop *desktop) { Inkscape::Selection *selection = sp_desktop_selection(desktop); if (selection->isEmpty()) { sp_desktop_message_stack(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select <b>path(s)</b> to break apart.")); return; } desktop->messageStack()->flash(Inkscape::IMMEDIATE_MESSAGE, _("Breaking apart paths...")); // set "busy" cursor desktop->setWaitingCursor(); bool did = false; for (GSList *items = g_slist_copy((GSList *) selection->itemList()); items != NULL; items = items->next) { SPItem *item = (SPItem *) items->data; if (!SP_IS_PATH(item)) { continue; } SPPath *path = SP_PATH(item); SPCurve *curve = path->get_curve_for_edit(); if (curve == NULL) { continue; } did = true; Inkscape::XML::Node *parent = item->getRepr()->parent(); gint pos = item->getRepr()->position(); char const *id = item->getRepr()->attribute("id"); // XML Tree being used directly here while it shouldn't be... gchar *style = g_strdup(item->getRepr()->attribute("style")); // XML Tree being used directly here while it shouldn't be... gchar *path_effect = g_strdup(item->getRepr()->attribute("inkscape:path-effect")); Geom::PathVector apv = curve->get_pathvector() * path->transform; curve->unref(); // it's going to resurrect as one of the pieces, so we delete without advertisement item->deleteObject(false); curve = new SPCurve(apv); g_assert(curve != NULL); GSList *list = curve->split(); curve->unref(); GSList *reprs = NULL; for (GSList *l = list; l != NULL; l = l->next) { curve = (SPCurve *) l->data; Inkscape::XML::Node *repr = parent->document()->createElement("svg:path"); repr->setAttribute("style", style); repr->setAttribute("inkscape:path-effect", path_effect); gchar *str = sp_svg_write_path(curve->get_pathvector()); if (path_effect) repr->setAttribute("inkscape:original-d", str); else repr->setAttribute("d", str); g_free(str); // add the new repr to the parent parent->appendChild(repr); // move to the saved position repr->setPosition(pos > 0 ? pos : 0); // if it's the first one, restore id if (l == list) repr->setAttribute("id", id); reprs = g_slist_prepend (reprs, repr); Inkscape::GC::release(repr); } selection->setReprList(reprs); g_slist_free(reprs); g_slist_free(list); g_free(style); g_free(path_effect); } desktop->clearWaitingCursor(); if (did) { DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_SELECTION_BREAK_APART, _("Break apart")); } else { sp_desktop_message_stack(desktop)->flash(Inkscape::ERROR_MESSAGE, _("<b>No path(s)</b> to break apart in the selection.")); } }
static void sp_gradient_drag(SPGradientContext &rc, Geom::Point const pt, guint /*state*/, guint32 etime) { SPDesktop *desktop = SP_EVENT_CONTEXT(&rc)->desktop; Inkscape::Selection *selection = sp_desktop_selection(desktop); SPDocument *document = sp_desktop_document(desktop); SPEventContext *ec = SP_EVENT_CONTEXT(&rc); if (!selection->isEmpty()) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); int type = prefs->getInt("/tools/gradient/newgradient", 1); int fill_or_stroke = prefs->getInt("/tools/gradient/newfillorstroke", 1); SPGradient *vector; if (ec->item_to_select) { // pick color from the object where drag started vector = sp_gradient_vector_for_object(document, desktop, ec->item_to_select, fill_or_stroke); } else { // Starting from empty space: // Sort items so that the topmost comes last GSList *items = g_slist_copy ((GSList *) selection->itemList()); items = g_slist_sort(items, (GCompareFunc) sp_item_repr_compare_position); // take topmost vector = sp_gradient_vector_for_object(document, desktop, SP_ITEM(g_slist_last(items)->data), fill_or_stroke); g_slist_free (items); } // HACK: reset fill-opacity - that 0.75 is annoying; BUT remove this when we have an opacity slider for all tabs SPCSSAttr *css = sp_repr_css_attr_new(); sp_repr_css_set_property(css, "fill-opacity", "1.0"); for (GSList const *i = selection->itemList(); i != NULL; i = i->next) { //FIXME: see above sp_repr_css_change_recursive(SP_OBJECT_REPR(i->data), css, "style"); sp_item_set_gradient(SP_ITEM(i->data), vector, (SPGradientType) type, fill_or_stroke); if (type == SP_GRADIENT_TYPE_LINEAR) { sp_item_gradient_set_coords (SP_ITEM(i->data), POINT_LG_BEGIN, 0, rc.origin, fill_or_stroke, true, false); sp_item_gradient_set_coords (SP_ITEM(i->data), POINT_LG_END, 0, pt, fill_or_stroke, true, false); } else if (type == SP_GRADIENT_TYPE_RADIAL) { sp_item_gradient_set_coords (SP_ITEM(i->data), POINT_RG_CENTER, 0, rc.origin, fill_or_stroke, true, false); sp_item_gradient_set_coords (SP_ITEM(i->data), POINT_RG_R1, 0, pt, fill_or_stroke, true, false); } SP_OBJECT (i->data)->requestModified(SP_OBJECT_MODIFIED_FLAG); } if (ec->_grdrag) { ec->_grdrag->updateDraggers(); // prevent regenerating draggers by selection modified signal, which sometimes // comes too late and thus destroys the knot which we will now grab: ec->_grdrag->local_change = true; // give the grab out-of-bounds values of xp/yp because we're already dragging // and therefore are already out of tolerance ec->_grdrag->grabKnot (SP_ITEM(selection->itemList()->data), type == SP_GRADIENT_TYPE_LINEAR? POINT_LG_END : POINT_RG_R1, -1, // ignore number (though it is always 1) fill_or_stroke, 99999, 99999, etime); } // We did an undoable action, but sp_document_done will be called by the knot when released // status text; we do not track coords because this branch is run once, not all the time // during drag int n_objects = g_slist_length((GSList *) selection->itemList()); rc._message_context->setF(Inkscape::NORMAL_MESSAGE, ngettext("<b>Gradient</b> for %d object; with <b>Ctrl</b> to snap angle", "<b>Gradient</b> for %d objects; with <b>Ctrl</b> to snap angle", n_objects), n_objects); } else { sp_desktop_message_stack(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select <b>objects</b> on which to create gradient.")); } }
static gint sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event) { static bool dragging; SPDesktop *desktop = event_context->desktop; Inkscape::Selection *selection = sp_desktop_selection (desktop); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); SPGradientContext *rc = SP_GRADIENT_CONTEXT(event_context); event_context->tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); double const nudge = prefs->getDoubleLimited("/options/nudgedistance/value", 2, 0, 1000); // in px GrDrag *drag = event_context->_grdrag; g_assert (drag); gint ret = FALSE; switch (event->type) { case GDK_2BUTTON_PRESS: if ( event->button.button == 1 ) { bool over_line = false; SPCtrlLine *line = NULL; if (drag->lines) { for (GSList *l = drag->lines; (l != NULL) && (!over_line); l = l->next) { line = (SPCtrlLine*) l->data; over_line |= sp_gradient_context_is_over_line (rc, (SPItem*) line, Geom::Point(event->motion.x, event->motion.y)); } } if (over_line) { // we take the first item in selection, because with doubleclick, the first click // always resets selection to the single object under cursor sp_gradient_context_add_stop_near_point(rc, SP_ITEM(selection->itemList()->data), rc->mousepoint_doc, event->button.time); } else { for (GSList const* i = selection->itemList(); i != NULL; i = i->next) { SPItem *item = SP_ITEM(i->data); SPGradientType new_type = (SPGradientType) prefs->getInt("/tools/gradient/newgradient", SP_GRADIENT_TYPE_LINEAR); guint new_fill = prefs->getInt("/tools/gradient/newfillorstroke", 1); SPGradient *vector = sp_gradient_vector_for_object(sp_desktop_document(desktop), desktop, SP_OBJECT (item), new_fill); SPGradient *priv = sp_item_set_gradient(item, vector, new_type, new_fill); sp_gradient_reset_to_userspace(priv, item); } sp_document_done (sp_desktop_document (desktop), SP_VERB_CONTEXT_GRADIENT, _("Create default gradient")); } ret = TRUE; } break; case GDK_BUTTON_PRESS: if ( event->button.button == 1 && !event_context->space_panning ) { Geom::Point button_w(event->button.x, event->button.y); // save drag origin event_context->xp = (gint) button_w[Geom::X]; event_context->yp = (gint) button_w[Geom::Y]; event_context->within_tolerance = true; dragging = true; Geom::Point button_dt = to_2geom(desktop->w2d(button_w)); if (event->button.state & GDK_SHIFT_MASK) { Inkscape::Rubberband::get(desktop)->start(desktop, from_2geom(button_dt)); } else { // remember clicked item, disregarding groups, honoring Alt; do nothing with Crtl to // enable Ctrl+doubleclick of exactly the selected item(s) if (!(event->button.state & GDK_CONTROL_MASK)) event_context->item_to_select = sp_event_context_find_item (desktop, button_w, event->button.state & GDK_MOD1_MASK, TRUE); /* Snap center to nearest magnetic point */ SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop); m.freeSnapReturnByRef(Inkscape::SnapPreferences::SNAPPOINT_NODE, button_dt); rc->origin = from_2geom(button_dt); } ret = TRUE; } break; case GDK_MOTION_NOTIFY: if ( dragging && ( event->motion.state & GDK_BUTTON1_MASK ) && !event_context->space_panning ) { if ( event_context->within_tolerance && ( abs( (gint) event->motion.x - event_context->xp ) < event_context->tolerance ) && ( abs( (gint) event->motion.y - event_context->yp ) < event_context->tolerance ) ) { break; // do not drag if we're within tolerance from origin } // Once the user has moved farther than tolerance from the original location // (indicating they intend to draw, not click), then always process the // motion notify coordinates as given (no snapping back to origin) event_context->within_tolerance = false; Geom::Point const motion_w(event->motion.x, event->motion.y); Geom::Point const motion_dt = event_context->desktop->w2d(motion_w); if (Inkscape::Rubberband::get(desktop)->is_started()) { Inkscape::Rubberband::get(desktop)->move(motion_dt); event_context->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Draw around</b> handles to select them")); } else { sp_gradient_drag(*rc, motion_dt, event->motion.state, event->motion.time); } gobble_motion_events(GDK_BUTTON1_MASK); ret = TRUE; } else { bool over_line = false; if (drag->lines) { for (GSList *l = drag->lines; l != NULL; l = l->next) { over_line |= sp_gradient_context_is_over_line (rc, (SPItem*) l->data, Geom::Point(event->motion.x, event->motion.y)); } } if (rc->cursor_addnode && !over_line) { event_context->cursor_shape = cursor_gradient_xpm; sp_event_context_update_cursor(event_context); rc->cursor_addnode = false; } else if (!rc->cursor_addnode && over_line) { event_context->cursor_shape = cursor_gradient_add_xpm; sp_event_context_update_cursor(event_context); rc->cursor_addnode = true; } } break; case GDK_BUTTON_RELEASE: event_context->xp = event_context->yp = 0; if ( event->button.button == 1 && !event_context->space_panning ) { if ( (event->button.state & GDK_CONTROL_MASK) && (event->button.state & GDK_MOD1_MASK ) ) { bool over_line = false; SPCtrlLine *line = NULL; if (drag->lines) { for (GSList *l = drag->lines; (l != NULL) && (!over_line); l = l->next) { line = (SPCtrlLine*) l->data; over_line = sp_gradient_context_is_over_line (rc, (SPItem*) line, Geom::Point(event->motion.x, event->motion.y)); if (over_line) break; } } if (over_line && line) { sp_gradient_context_add_stop_near_point(rc, line->item, rc->mousepoint_doc, 0); ret = TRUE; } } else { dragging = false; // unless clicked with Ctrl (to enable Ctrl+doubleclick). if (event->button.state & GDK_CONTROL_MASK) { ret = TRUE; break; } if (!event_context->within_tolerance) { // we've been dragging, either do nothing (grdrag handles that), // or rubberband-select if we have rubberband Inkscape::Rubberband::Rubberband *r = Inkscape::Rubberband::get(desktop); if (r->is_started() && !event_context->within_tolerance) { // this was a rubberband drag if (r->getMode() == RUBBERBAND_MODE_RECT) { Geom::OptRect const b = r->getRectangle(); drag->selectRect(*b); } } } else if (event_context->item_to_select) { // no dragging, select clicked item if any if (event->button.state & GDK_SHIFT_MASK) { selection->toggle(event_context->item_to_select); } else { selection->set(event_context->item_to_select); } } else { // click in an empty space; do the same as Esc if (drag->selected) { drag->deselectAll(); } else { selection->clear(); } } event_context->item_to_select = NULL; ret = TRUE; } Inkscape::Rubberband::get(desktop)->stop(); } break; case GDK_KEY_PRESS: switch (get_group0_keyval (&event->key)) { case GDK_Alt_L: case GDK_Alt_R: case GDK_Control_L: case GDK_Control_R: case GDK_Shift_L: case GDK_Shift_R: case GDK_Meta_L: // Meta is when you press Shift+Alt (at least on my machine) case GDK_Meta_R: sp_event_show_modifier_tip (event_context->defaultMessageContext(), event, _("<b>Ctrl</b>: snap gradient angle"), _("<b>Shift</b>: draw gradient around the starting point"), NULL); break; case GDK_x: case GDK_X: if (MOD__ALT_ONLY) { desktop->setToolboxFocusTo ("altx-grad"); ret = TRUE; } break; case GDK_A: case GDK_a: if (MOD__CTRL_ONLY && drag->isNonEmpty()) { drag->selectAll(); ret = TRUE; } break; case GDK_L: case GDK_l: if (MOD__CTRL_ONLY && drag->isNonEmpty() && drag->hasSelection()) { sp_gradient_simplify(rc, 1e-4); ret = TRUE; } break; case GDK_Escape: if (drag->selected) { drag->deselectAll(); } else { selection->clear(); } ret = TRUE; //TODO: make dragging escapable by Esc break; case GDK_Left: // move handle left case GDK_KP_Left: case GDK_KP_4: if (!MOD__CTRL) { // not ctrl gint mul = 1 + gobble_key_events( get_group0_keyval(&event->key), 0); // with any mask if (MOD__ALT) { // alt if (MOD__SHIFT) drag->selected_move_screen(mul*-10, 0); // shift else drag->selected_move_screen(mul*-1, 0); // no shift } else { // no alt if (MOD__SHIFT) drag->selected_move(mul*-10*nudge, 0); // shift else drag->selected_move(mul*-nudge, 0); // no shift } ret = TRUE; } break; case GDK_Up: // move handle up case GDK_KP_Up: case GDK_KP_8: if (!MOD__CTRL) { // not ctrl gint mul = 1 + gobble_key_events( get_group0_keyval(&event->key), 0); // with any mask if (MOD__ALT) { // alt if (MOD__SHIFT) drag->selected_move_screen(0, mul*10); // shift else drag->selected_move_screen(0, mul*1); // no shift } else { // no alt if (MOD__SHIFT) drag->selected_move(0, mul*10*nudge); // shift else drag->selected_move(0, mul*nudge); // no shift } ret = TRUE; } break; case GDK_Right: // move handle right case GDK_KP_Right: case GDK_KP_6: if (!MOD__CTRL) { // not ctrl gint mul = 1 + gobble_key_events( get_group0_keyval(&event->key), 0); // with any mask if (MOD__ALT) { // alt if (MOD__SHIFT) drag->selected_move_screen(mul*10, 0); // shift else drag->selected_move_screen(mul*1, 0); // no shift } else { // no alt if (MOD__SHIFT) drag->selected_move(mul*10*nudge, 0); // shift else drag->selected_move(mul*nudge, 0); // no shift } ret = TRUE; } break; case GDK_Down: // move handle down case GDK_KP_Down: case GDK_KP_2: if (!MOD__CTRL) { // not ctrl gint mul = 1 + gobble_key_events( get_group0_keyval(&event->key), 0); // with any mask if (MOD__ALT) { // alt if (MOD__SHIFT) drag->selected_move_screen(0, mul*-10); // shift else drag->selected_move_screen(0, mul*-1); // no shift } else { // no alt if (MOD__SHIFT) drag->selected_move(0, mul*-10*nudge); // shift else drag->selected_move(0, mul*-nudge); // no shift } ret = TRUE; } break; case GDK_r: case GDK_R: if (MOD__SHIFT_ONLY) { // First try selected dragger if (drag && drag->selected) { drag->selected_reverse_vector(); } else { // If no drag or no dragger selected, act on selection (both fill and stroke gradients) for (GSList const* i = selection->itemList(); i != NULL; i = i->next) { sp_item_gradient_reverse_vector (SP_ITEM(i->data), true); sp_item_gradient_reverse_vector (SP_ITEM(i->data), false); } } // we did an undoable action sp_document_done (sp_desktop_document (desktop), SP_VERB_CONTEXT_GRADIENT, _("Invert gradient")); ret = TRUE; } break; case GDK_Insert: case GDK_KP_Insert: // with any modifiers: sp_gradient_context_add_stops_between_selected_stops (rc); ret = TRUE; break; case GDK_Delete: case GDK_KP_Delete: case GDK_BackSpace: if ( drag->selected ) { drag->deleteSelected(MOD__CTRL_ONLY); ret = TRUE; } break; default: break; } break; case GDK_KEY_RELEASE: switch (get_group0_keyval (&event->key)) { case GDK_Alt_L: case GDK_Alt_R: case GDK_Control_L: case GDK_Control_R: case GDK_Shift_L: case GDK_Shift_R: case GDK_Meta_L: // Meta is when you press Shift+Alt case GDK_Meta_R: event_context->defaultMessageContext()->clear(); break; default: break; } break; default: break; } if (!ret) { if (((SPEventContextClass *) parent_class)->root_handler) { ret = ((SPEventContextClass *) parent_class)->root_handler(event_context, event); } } return ret; }
void sp_selected_path_break_apart(SPDesktop *desktop, bool skip_undo) { Inkscape::Selection *selection = desktop->getSelection(); if (selection->isEmpty()) { desktop->getMessageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>path(s)</b> to break apart.")); return; } desktop->messageStack()->flash(Inkscape::IMMEDIATE_MESSAGE, _("Breaking apart paths...")); // set "busy" cursor desktop->setWaitingCursor(); bool did = false; std::vector<SPItem*> itemlist(selection->itemList()); for (std::vector<SPItem*>::const_iterator i = itemlist.begin(); i != itemlist.end(); ++i){ SPItem *item = *i; SPPath *path = dynamic_cast<SPPath *>(item); if (!path) { continue; } SPCurve *curve = path->get_curve_for_edit(); if (curve == NULL) { continue; } did = true; Inkscape::XML::Node *parent = item->getRepr()->parent(); gint pos = item->getRepr()->position(); char const *id = item->getRepr()->attribute("id"); // XML Tree being used directly here while it shouldn't be... gchar *style = g_strdup(item->getRepr()->attribute("style")); // XML Tree being used directly here while it shouldn't be... gchar *path_effect = g_strdup(item->getRepr()->attribute("inkscape:path-effect")); Geom::Affine transform = path->transform; // it's going to resurrect as one of the pieces, so we delete without advertisement item->deleteObject(false); GSList *list = curve->split(); curve->unref(); std::vector<Inkscape::XML::Node*> reprs; for (GSList *l = list; l != NULL; l = l->next) { curve = (SPCurve *) l->data; Inkscape::XML::Node *repr = parent->document()->createElement("svg:path"); repr->setAttribute("style", style); repr->setAttribute("inkscape:path-effect", path_effect); gchar *str = sp_svg_write_path(curve->get_pathvector()); if (path_effect) repr->setAttribute("inkscape:original-d", str); else repr->setAttribute("d", str); g_free(str); repr->setAttribute("transform", sp_svg_transform_write(transform)); // add the new repr to the parent parent->appendChild(repr); // move to the saved position repr->setPosition(pos > 0 ? pos : 0); // if it's the first one, restore id if (l == list) repr->setAttribute("id", id); reprs.push_back(repr); Inkscape::GC::release(repr); } selection->setReprList(reprs); g_slist_free(list); g_free(style); g_free(path_effect); } desktop->clearWaitingCursor(); if (did) { if ( !skip_undo ) { DocumentUndo::done(desktop->getDocument(), SP_VERB_SELECTION_BREAK_APART, _("Break apart")); } } else { desktop->getMessageStack()->flash(Inkscape::ERROR_MESSAGE, _("<b>No path(s)</b> to break apart in the selection.")); } }
/** * Get the selected image. Also check for any SPItems over it, in * case the user wants SIOX pre-processing. */ SPImage * Tracer::getSelectedSPImage() { SPDesktop *desktop = SP_ACTIVE_DESKTOP; if (!desktop) { g_warning("Trace: No active desktop"); return NULL; } Inkscape::MessageStack *msgStack = sp_desktop_message_stack(desktop); Inkscape::Selection *sel = sp_desktop_selection(desktop); if (!sel) { char *msg = _("Select an <b>image</b> to trace"); msgStack->flash(Inkscape::ERROR_MESSAGE, msg); //g_warning(msg); return NULL; } if (sioxEnabled) { SPImage *img = NULL; GSList const *list = sel->itemList(); std::vector<SPItem *> items; sioxShapes.clear(); /* First, things are selected top-to-bottom, so we need to invert them as bottom-to-top so that we can discover the image and any SPItems above it */ for ( ; list ; list=list->next) { if (!SP_IS_ITEM(list->data)) { continue; } SPItem *item = SP_ITEM(list->data); items.insert(items.begin(), item); } std::vector<SPItem *>::iterator iter; for (iter = items.begin() ; iter!= items.end() ; iter++) { SPItem *item = *iter; if (SP_IS_IMAGE(item)) { if (img) //we want only one { char *msg = _("Select only one <b>image</b> to trace"); msgStack->flash(Inkscape::ERROR_MESSAGE, msg); return NULL; } img = SP_IMAGE(item); } else // if (img) //# items -after- the image in tree (above it in Z) { if (SP_IS_SHAPE(item)) { SPShape *shape = SP_SHAPE(item); sioxShapes.push_back(shape); } } } if (!img || sioxShapes.size() < 1) { char *msg = _("Select one image and one or more shapes above it"); msgStack->flash(Inkscape::ERROR_MESSAGE, msg); return NULL; } return img; } else //### SIOX not enabled. We want exactly one image selected { SPItem *item = sel->singleItem(); if (!item) { char *msg = _("Select an <b>image</b> to trace"); //same as above msgStack->flash(Inkscape::ERROR_MESSAGE, msg); //g_warning(msg); return NULL; } if (!SP_IS_IMAGE(item)) { char *msg = _("Select an <b>image</b> to trace"); msgStack->flash(Inkscape::ERROR_MESSAGE, msg); //g_warning(msg); return NULL; } SPImage *img = SP_IMAGE(item); return img; } }
void sp_selected_path_combine(SPDesktop *desktop) { Inkscape::Selection *selection = sp_desktop_selection(desktop); SPDocument *doc = sp_desktop_document(desktop); if (g_slist_length((GSList *) selection->itemList()) < 1) { sp_desktop_message_stack(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to combine.")); return; } desktop->messageStack()->flash(Inkscape::IMMEDIATE_MESSAGE, _("Combining paths...")); // set "busy" cursor desktop->setWaitingCursor(); GSList *items = g_slist_copy((GSList *) selection->itemList()); items = sp_degroup_list (items); // descend into any groups in selection GSList *to_paths = NULL; for (GSList *i = items; i != NULL; i = i->next) { SPItem *item = (SPItem *) i->data; if (!SP_IS_PATH(item) && !SP_IS_GROUP(item)) to_paths = g_slist_prepend(to_paths, item); } GSList *converted = NULL; bool did = sp_item_list_to_curves(to_paths, &items, &converted); g_slist_free(to_paths); for (GSList *i = converted; i != NULL; i = i->next) items = g_slist_prepend(items, doc->getObjectByRepr((Inkscape::XML::Node*)(i->data))); items = sp_degroup_list (items); // converting to path may have added more groups, descend again items = g_slist_sort(items, (GCompareFunc) sp_item_repr_compare_position); items = g_slist_reverse(items); // remember the position, id, transform and style of the topmost path, they will be assigned to the combined one gint position = 0; char const *id = NULL; char const *transform = NULL; char const *style = NULL; char const *path_effect = NULL; SPCurve* curve = NULL; SPItem *first = NULL; Inkscape::XML::Node *parent = NULL; if (did) { selection->clear(); } for (GSList *i = items; i != NULL; i = i->next) { // going from top to bottom SPItem *item = (SPItem *) i->data; if (!SP_IS_PATH(item)) { continue; } if (!did) { selection->clear(); did = true; } SPCurve *c = SP_PATH(item)->get_curve_for_edit(); if (first == NULL) { // this is the topmost path first = item; parent = first->getRepr()->parent(); position = first->getRepr()->position(); id = first->getRepr()->attribute("id"); transform = first->getRepr()->attribute("transform"); // FIXME: merge styles of combined objects instead of using the first one's style style = first->getRepr()->attribute("style"); path_effect = first->getRepr()->attribute("inkscape:path-effect"); //c->transform(item->transform); curve = c; } else { c->transform(item->getRelativeTransform(first)); curve->append(c, false); c->unref(); // reduce position only if the same parent if (item->getRepr()->parent() == parent) { position--; } // delete the object for real, so that its clones can take appropriate action item->deleteObject(); } } g_slist_free(items); if (did) { first->deleteObject(false); // delete the topmost. Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc(); Inkscape::XML::Node *repr = xml_doc->createElement("svg:path"); // restore id, transform, path effect, and style repr->setAttribute("id", id); if (transform) { repr->setAttribute("transform", transform); } repr->setAttribute("style", style); repr->setAttribute("inkscape:path-effect", path_effect); // set path data corresponding to new curve gchar *dstring = sp_svg_write_path(curve->get_pathvector()); curve->unref(); if (path_effect) { repr->setAttribute("inkscape:original-d", dstring); } else { repr->setAttribute("d", dstring); } g_free(dstring); // add the new group to the parent of the topmost parent->appendChild(repr); // move to the position of the topmost, reduced by the number of deleted items repr->setPosition(position > 0 ? position : 0); DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_SELECTION_COMBINE, _("Combine")); selection->set(repr); Inkscape::GC::release(repr); } else { sp_desktop_message_stack(desktop)->flash(Inkscape::ERROR_MESSAGE, _("<b>No path(s)</b> to combine in the selection.")); } desktop->clearWaitingCursor(); }
void text_unflow () { SPDesktop *desktop = SP_ACTIVE_DESKTOP; if (!desktop) return; SPDocument *doc = sp_desktop_document (desktop); Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc); Inkscape::Selection *selection = sp_desktop_selection(desktop); if (!flowtext_in_selection(selection) || g_slist_length((GSList *) selection->itemList()) < 1) { sp_desktop_message_stack(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select <b>a flowed text</b> to unflow it.")); return; } GSList *new_objs = NULL; GSList *old_objs = NULL; for (GSList *items = g_slist_copy((GSList *) selection->itemList()); items != NULL; items = items->next) { if (!SP_IS_FLOWTEXT(SP_OBJECT(items->data))) { continue; } SPItem *flowtext = SP_ITEM(items->data); if (sp_te_get_string_multiline(flowtext) == NULL) { // flowtext is empty continue; } /* Create <text> */ Inkscape::XML::Node *rtext = xml_doc->createElement("svg:text"); rtext->setAttribute("xml:space", "preserve"); // we preserve spaces in the text objects we create /* Set style */ rtext->setAttribute("style", SP_OBJECT_REPR(flowtext)->attribute("style")); // fixme: transfer style attrs too; and from descendants NRRect bbox; sp_item_invoke_bbox(SP_ITEM(flowtext), &bbox, sp_item_i2doc_affine(SP_ITEM(flowtext)), TRUE); Geom::Point xy(bbox.x0, bbox.y0); if (xy[Geom::X] != 1e18 && xy[Geom::Y] != 1e18) { sp_repr_set_svg_double(rtext, "x", xy[Geom::X]); sp_repr_set_svg_double(rtext, "y", xy[Geom::Y]); } /* Create <tspan> */ Inkscape::XML::Node *rtspan = xml_doc->createElement("svg:tspan"); rtspan->setAttribute("sodipodi:role", "line"); // otherwise, why bother creating the tspan? rtext->addChild(rtspan, NULL); gchar *text_string = sp_te_get_string_multiline(flowtext); Inkscape::XML::Node *text_repr = xml_doc->createTextNode(text_string); // FIXME: transfer all formatting!!! free(text_string); rtspan->appendChild(text_repr); SP_OBJECT_REPR(SP_OBJECT_PARENT(flowtext))->appendChild(rtext); SPObject *text_object = doc->getObjectByRepr(rtext); new_objs = g_slist_prepend (new_objs, text_object); old_objs = g_slist_prepend (old_objs, flowtext); Inkscape::GC::release(rtext); Inkscape::GC::release(rtspan); Inkscape::GC::release(text_repr); } selection->clear(); selection->setList(new_objs); for (GSList *i = old_objs; i; i = i->next) { SP_OBJECT(i->data)->deleteObject (true); } g_slist_free (old_objs); g_slist_free (new_objs); sp_document_done(doc, SP_VERB_CONTEXT_TEXT, _("Unflow flowed text")); }
static gint sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) { SPItem *item = NULL; SPItem *item_at_point = NULL, *group_at_point = NULL, *item_in_group = NULL; gint ret = FALSE; SPDesktop *desktop = event_context->desktop; SPSelectContext *sc = SP_SELECT_CONTEXT(event_context); Inkscape::SelTrans *seltrans = sc->_seltrans; Inkscape::Selection *selection = sp_desktop_selection(desktop); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); // make sure we still have valid objects to move around if (sc->item && SP_OBJECT_DOCUMENT( SP_OBJECT(sc->item))==NULL) { sp_select_context_abort(event_context); } switch (event->type) { case GDK_2BUTTON_PRESS: if (event->button.button == 1) { if (!selection->isEmpty()) { SPItem *clicked_item = (SPItem *) selection->itemList()->data; if (SP_IS_GROUP(clicked_item) && !SP_IS_BOX3D(clicked_item)) { // enter group if it's not a 3D box desktop->setCurrentLayer(reinterpret_cast<SPObject *>(clicked_item)); sp_desktop_selection(desktop)->clear(); sc->dragging = false; sp_event_context_discard_delayed_snap_event(event_context); desktop->canvas->end_forced_full_redraws(); } else { // switch tool Geom::Point const button_pt(event->button.x, event->button.y); Geom::Point const p(desktop->w2d(button_pt)); tools_switch_by_item (desktop, clicked_item, p); } } else { sp_select_context_up_one_layer(desktop); } ret = TRUE; } break; case GDK_BUTTON_PRESS: if (event->button.button == 1 && !event_context->space_panning) { // save drag origin xp = (gint) event->button.x; yp = (gint) event->button.y; within_tolerance = true; Geom::Point const button_pt(event->button.x, event->button.y); Geom::Point const p(desktop->w2d(button_pt)); if (event->button.state & GDK_MOD1_MASK) Inkscape::Rubberband::get(desktop)->setMode(RUBBERBAND_MODE_TOUCHPATH); Inkscape::Rubberband::get(desktop)->start(desktop, p); if (sc->grabbed) { sp_canvas_item_ungrab(sc->grabbed, event->button.time); sc->grabbed = NULL; } sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK, NULL, event->button.time); sc->grabbed = SP_CANVAS_ITEM(desktop->acetate); // remember what modifiers were on before button press sc->button_press_shift = (event->button.state & GDK_SHIFT_MASK) ? true : false; sc->button_press_ctrl = (event->button.state & GDK_CONTROL_MASK) ? true : false; sc->button_press_alt = (event->button.state & GDK_MOD1_MASK) ? true : false; sc->moved = FALSE; rb_escaped = drag_escaped = 0; ret = TRUE; } else if (event->button.button == 3) { // right click; do not eat it so that right-click menu can appear, but cancel dragging & rubberband sp_select_context_abort(event_context); } break; case GDK_MOTION_NOTIFY: tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); if (event->motion.state & GDK_BUTTON1_MASK && !event_context->space_panning) { Geom::Point const motion_pt(event->motion.x, event->motion.y); Geom::Point const p(desktop->w2d(motion_pt)); if ( within_tolerance && ( abs( (gint) event->motion.x - xp ) < tolerance ) && ( abs( (gint) event->motion.y - yp ) < tolerance ) ) { break; // do not drag if we're within tolerance from origin } // Once the user has moved farther than tolerance from the original location // (indicating they intend to move the object, not click), then always process the // motion notify coordinates as given (no snapping back to origin) within_tolerance = false; if (sc->button_press_ctrl || (sc->button_press_alt && !sc->button_press_shift && !selection->isEmpty())) { // if it's not click and ctrl or alt was pressed (the latter with some selection // but not with shift) we want to drag rather than rubberband sc->dragging = TRUE; desktop->setCursor(SP_SELECT_D_CURSOR); desktop->canvas->force_full_redraw_after_interruptions(5); } if (sc->dragging) { /* User has dragged fast, so we get events on root (lauris)*/ // not only that; we will end up here when ctrl-dragging as well // and also when we started within tolerance, but trespassed tolerance outside of item Inkscape::Rubberband::get(desktop)->stop(); SP_EVENT_CONTEXT(sc)->defaultMessageContext()->clear(); item_at_point = desktop->item_at_point(Geom::Point(event->button.x, event->button.y), FALSE); if (!item_at_point) // if no item at this point, try at the click point (bug 1012200) item_at_point = desktop->item_at_point(Geom::Point(xp, yp), FALSE); if (item_at_point || sc->moved || sc->button_press_alt) { // drag only if starting from an item, or if something is already grabbed, or if alt-dragging if (!sc->moved) { item_in_group = desktop->item_at_point(Geom::Point(event->button.x, event->button.y), TRUE); group_at_point = desktop->group_at_point(Geom::Point(event->button.x, event->button.y)); if (SP_IS_LAYER(selection->single())) group_at_point = SP_GROUP(selection->single()); // group-at-point is meant to be topmost item if it's a group, // not topmost group of all items at point if (group_at_point != item_in_group && !(group_at_point && item_at_point && group_at_point->isAncestorOf(item_at_point))) group_at_point = NULL; // if neither a group nor an item (possibly in a group) at point are selected, set selection to the item at point if ((!item_in_group || !selection->includes(item_in_group)) && (!group_at_point || !selection->includes(group_at_point)) && !sc->button_press_alt) { // select what is under cursor if (!seltrans->isEmpty()) { seltrans->resetState(); } // when simply ctrl-dragging, we don't want to go into groups if (item_at_point && !selection->includes(item_at_point)) selection->set(item_at_point); } // otherwise, do not change selection so that dragging selected-within-group items, as well as alt-dragging, is possible seltrans->grab(p, -1, -1, FALSE, TRUE); sc->moved = TRUE; } if (!seltrans->isEmpty()) seltrans->moveTo(p, event->button.state); desktop->scroll_to_point(p); gobble_motion_events(GDK_BUTTON1_MASK); ret = TRUE; } else { sc->dragging = FALSE; sp_event_context_discard_delayed_snap_event(event_context); desktop->canvas->end_forced_full_redraws(); } } else { if (Inkscape::Rubberband::get(desktop)->is_started()) { Inkscape::Rubberband::get(desktop)->move(p); if (Inkscape::Rubberband::get(desktop)->getMode() == RUBBERBAND_MODE_TOUCHPATH) { event_context->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Draw over</b> objects to select them; release <b>Alt</b> to switch to rubberband selection")); } else { event_context->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Drag around</b> objects to select them; press <b>Alt</b> to switch to touch selection")); } gobble_motion_events(GDK_BUTTON1_MASK); } } } break; case GDK_BUTTON_RELEASE: xp = yp = 0; if ((event->button.button == 1) && (sc->grabbed) && !event_context->space_panning) { if (sc->dragging) { if (sc->moved) { // item has been moved seltrans->ungrab(); sc->moved = FALSE; } else if (sc->item && !drag_escaped) { // item has not been moved -> simply a click, do selecting if (!selection->isEmpty()) { if (event->button.state & GDK_SHIFT_MASK) { // with shift, toggle selection seltrans->resetState(); selection->toggle(sc->item); } else { SPObject* single = selection->single(); // without shift, increase state (i.e. toggle scale/rotation handles) if (selection->includes(sc->item)) { seltrans->increaseState(); } else if (SP_IS_LAYER(single) && single->isAncestorOf(sc->item)) { seltrans->increaseState(); } else { seltrans->resetState(); selection->set(sc->item); } } } else { // simple or shift click, no previous selection seltrans->resetState(); selection->set(sc->item); } } sc->dragging = FALSE; desktop->setCursor(SP_SELECT_CURSOR); sp_event_context_discard_delayed_snap_event(event_context); desktop->canvas->end_forced_full_redraws(); if (sc->item) { sp_object_unref( SP_OBJECT(sc->item), NULL); } sc->item = NULL; } else { Inkscape::Rubberband *r = Inkscape::Rubberband::get(desktop); if (r->is_started() && !within_tolerance) { // this was a rubberband drag GSList *items = NULL; if (r->getMode() == RUBBERBAND_MODE_RECT) { Geom::OptRect const b = r->getRectangle(); items = sp_document_items_in_box(sp_desktop_document(desktop), desktop->dkey, *b); } else if (r->getMode() == RUBBERBAND_MODE_TOUCHPATH) { items = sp_document_items_at_points(sp_desktop_document(desktop), desktop->dkey, r->getPoints()); } seltrans->resetState(); r->stop(); SP_EVENT_CONTEXT(sc)->defaultMessageContext()->clear(); if (event->button.state & GDK_SHIFT_MASK) { // with shift, add to selection selection->addList (items); } else { // without shift, simply select anew selection->setList (items); } g_slist_free (items); } else { // it was just a click, or a too small rubberband r->stop(); if (sc->button_press_shift && !rb_escaped && !drag_escaped) { // this was a shift+click or alt+shift+click, select what was clicked upon sc->button_press_shift = false; if (sc->button_press_ctrl) { // go into groups, honoring Alt item = sp_event_context_find_item (desktop, Geom::Point(event->button.x, event->button.y), event->button.state & GDK_MOD1_MASK, TRUE); sc->button_press_ctrl = FALSE; } else { // don't go into groups, honoring Alt item = sp_event_context_find_item (desktop, Geom::Point(event->button.x, event->button.y), event->button.state & GDK_MOD1_MASK, FALSE); } if (item) { selection->toggle(item); item = NULL; } } else if ((sc->button_press_ctrl || sc->button_press_alt) && !rb_escaped && !drag_escaped) { // ctrl+click, alt+click item = sp_event_context_find_item (desktop, Geom::Point(event->button.x, event->button.y), sc->button_press_alt, sc->button_press_ctrl); sc->button_press_ctrl = FALSE; sc->button_press_alt = FALSE; if (item) { if (selection->includes(item)) { seltrans->increaseState(); } else { seltrans->resetState(); selection->set(item); } item = NULL; } } else { // click without shift, simply deselect, unless with Alt or something was cancelled if (!selection->isEmpty()) { if (!(rb_escaped) && !(drag_escaped) && !(event->button.state & GDK_MOD1_MASK)) selection->clear(); rb_escaped = 0; ret = TRUE; } } } ret = TRUE; } if (sc->grabbed) { sp_canvas_item_ungrab(sc->grabbed, event->button.time); sc->grabbed = NULL; } desktop->updateNow(); } if (event->button.button == 1) { Inkscape::Rubberband::get(desktop)->stop(); // might have been started in another tool! } sc->button_press_shift = false; sc->button_press_ctrl = false; sc->button_press_alt = false; break; case GDK_KEY_PRESS: // keybindings for select context { { guint keyval = get_group0_keyval(&event->key); bool alt = ( MOD__ALT || (keyval == GDK_Alt_L) || (keyval == GDK_Alt_R) || (keyval == GDK_Meta_L) || (keyval == GDK_Meta_R)); if (!key_is_a_modifier (keyval)) { event_context->defaultMessageContext()->clear(); } else if (sc->grabbed || seltrans->isGrabbed()) { if (Inkscape::Rubberband::get(desktop)->is_started()) { // if Alt then change cursor to moving cursor: if (alt) { Inkscape::Rubberband::get(desktop)->setMode(RUBBERBAND_MODE_TOUCHPATH); } } else { // do not change the statusbar text when mousekey is down to move or transform the object, // because the statusbar text is already updated somewhere else. break; } } else { sp_event_show_modifier_tip (event_context->defaultMessageContext(), event, _("<b>Ctrl</b>: click to select in groups; drag to move hor/vert"), _("<b>Shift</b>: click to toggle select; drag for rubberband selection"), _("<b>Alt</b>: click to select under; drag to move selected or select by touch")); // if Alt and nonempty selection, show moving cursor ("move selected"): if (alt && !selection->isEmpty() && !desktop->isWaitingCursor()) { desktop->setCursor(SP_SELECT_D_CURSOR); } //*/ break; } } gdouble const nudge = prefs->getDoubleLimited("/options/nudgedistance/value", 2, 0, 1000); // in px gdouble const offset = prefs->getDoubleLimited("/options/defaultscale/value", 2, 0, 1000); int const snaps = prefs->getInt("/options/rotationsnapsperpi/value", 12); switch (get_group0_keyval (&event->key)) { case GDK_Left: // move selection left case GDK_KP_Left: case GDK_KP_4: if (!MOD__CTRL) { // not ctrl gint mul = 1 + gobble_key_events( get_group0_keyval(&event->key), 0); // with any mask if (MOD__ALT) { // alt if (MOD__SHIFT) sp_selection_move_screen(desktop, mul*-10, 0); // shift else sp_selection_move_screen(desktop, mul*-1, 0); // no shift } else { // no alt if (MOD__SHIFT) sp_selection_move(desktop, mul*-10*nudge, 0); // shift else sp_selection_move(desktop, mul*-nudge, 0); // no shift } ret = TRUE; } break; case GDK_Up: // move selection up case GDK_KP_Up: case GDK_KP_8: if (!MOD__CTRL) { // not ctrl gint mul = 1 + gobble_key_events( get_group0_keyval(&event->key), 0); // with any mask if (MOD__ALT) { // alt if (MOD__SHIFT) sp_selection_move_screen(desktop, 0, mul*10); // shift else sp_selection_move_screen(desktop, 0, mul*1); // no shift } else { // no alt if (MOD__SHIFT) sp_selection_move(desktop, 0, mul*10*nudge); // shift else sp_selection_move(desktop, 0, mul*nudge); // no shift } ret = TRUE; } break; case GDK_Right: // move selection right case GDK_KP_Right: case GDK_KP_6: if (!MOD__CTRL) { // not ctrl gint mul = 1 + gobble_key_events( get_group0_keyval(&event->key), 0); // with any mask if (MOD__ALT) { // alt if (MOD__SHIFT) sp_selection_move_screen(desktop, mul*10, 0); // shift else sp_selection_move_screen(desktop, mul*1, 0); // no shift } else { // no alt if (MOD__SHIFT) sp_selection_move(desktop, mul*10*nudge, 0); // shift else sp_selection_move(desktop, mul*nudge, 0); // no shift } ret = TRUE; } break; case GDK_Down: // move selection down case GDK_KP_Down: case GDK_KP_2: if (!MOD__CTRL) { // not ctrl gint mul = 1 + gobble_key_events( get_group0_keyval(&event->key), 0); // with any mask if (MOD__ALT) { // alt if (MOD__SHIFT) sp_selection_move_screen(desktop, 0, mul*-10); // shift else sp_selection_move_screen(desktop, 0, mul*-1); // no shift } else { // no alt if (MOD__SHIFT) sp_selection_move(desktop, 0, mul*-10*nudge); // shift else sp_selection_move(desktop, 0, mul*-nudge); // no shift } ret = TRUE; } break; case GDK_Escape: if (!sp_select_context_abort(event_context)) selection->clear(); ret = TRUE; break; case GDK_a: case GDK_A: if (MOD__CTRL_ONLY) { sp_edit_select_all(desktop); ret = TRUE; } break; case GDK_space: /* stamping mode: show outline mode moving */ /* FIXME: Is next condition ok? (lauris) */ if (sc->dragging && sc->grabbed) { seltrans->stamp(); ret = TRUE; } break; case GDK_x: case GDK_X: if (MOD__ALT_ONLY) { desktop->setToolboxFocusTo ("altx"); ret = TRUE; } break; case GDK_bracketleft: if (MOD__ALT) { gint mul = 1 + gobble_key_events( get_group0_keyval(&event->key), 0); // with any mask sp_selection_rotate_screen(selection, mul*1); } else if (MOD__CTRL) { sp_selection_rotate(selection, 90); } else if (snaps) { sp_selection_rotate(selection, 180.0/snaps); } ret = TRUE; break; case GDK_bracketright: if (MOD__ALT) { gint mul = 1 + gobble_key_events( get_group0_keyval(&event->key), 0); // with any mask sp_selection_rotate_screen(selection, -1*mul); } else if (MOD__CTRL) { sp_selection_rotate(selection, -90); } else if (snaps) { sp_selection_rotate(selection, -180.0/snaps); } ret = TRUE; break; case GDK_less: case GDK_comma: if (MOD__ALT) { gint mul = 1 + gobble_key_events( get_group0_keyval(&event->key), 0); // with any mask sp_selection_scale_screen(selection, -2*mul); } else if (MOD__CTRL) { sp_selection_scale_times(selection, 0.5); } else { gint mul = 1 + gobble_key_events( get_group0_keyval(&event->key), 0); // with any mask sp_selection_scale(selection, -offset*mul); } ret = TRUE; break; case GDK_greater: case GDK_period: if (MOD__ALT) { gint mul = 1 + gobble_key_events( get_group0_keyval(&event->key), 0); // with any mask sp_selection_scale_screen(selection, 2*mul); } else if (MOD__CTRL) { sp_selection_scale_times(selection, 2); } else { gint mul = 1 + gobble_key_events( get_group0_keyval(&event->key), 0); // with any mask sp_selection_scale(selection, offset*mul); } ret = TRUE; break; case GDK_Return: if (MOD__CTRL_ONLY) { if (selection->singleItem()) { SPItem *clicked_item = selection->singleItem(); if ( SP_IS_GROUP(clicked_item) || SP_IS_BOX3D(clicked_item)) { // enter group or a 3D box desktop->setCurrentLayer(reinterpret_cast<SPObject *>(clicked_item)); sp_desktop_selection(desktop)->clear(); } else { SP_EVENT_CONTEXT(sc)->desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Selected object is not a group. Cannot enter.")); } } ret = TRUE; } break; case GDK_BackSpace: if (MOD__CTRL_ONLY) { sp_select_context_up_one_layer(desktop); ret = TRUE; } break; case GDK_s: case GDK_S: if (MOD__SHIFT_ONLY) { if (!selection->isEmpty()) { seltrans->increaseState(); } ret = TRUE; } break; case GDK_g: case GDK_G: if (MOD__SHIFT_ONLY) { sp_selection_to_guides(desktop); ret = true; } break; default: break; } break; } case GDK_KEY_RELEASE: { guint keyval = get_group0_keyval(&event->key); if (key_is_a_modifier (keyval)) event_context->defaultMessageContext()->clear(); bool alt = ( MOD__ALT || (keyval == GDK_Alt_L) || (keyval == GDK_Alt_R) || (keyval == GDK_Meta_L) || (keyval == GDK_Meta_R)); if (Inkscape::Rubberband::get(desktop)->is_started()) { // if Alt then change cursor to moving cursor: if (alt) { Inkscape::Rubberband::get(desktop)->setMode(RUBBERBAND_MODE_RECT); } } } // set cursor to default. if (!desktop->isWaitingCursor()) { desktop->setCursor(event_context->cursor_shape); } break; default: break; } if (!ret) { if (((SPEventContextClass *) parent_class)->root_handler) ret = ((SPEventContextClass *) parent_class)->root_handler(event_context, event); } return ret; }
static void mesh_selection_changed (Inkscape::Selection *, gpointer data) { SPMeshContext *rc = (SPMeshContext *) data; GrDrag *drag = rc->_grdrag; Inkscape::Selection *selection = sp_desktop_selection(SP_EVENT_CONTEXT(rc)->desktop); if (selection == NULL) { return; } guint n_obj = g_slist_length((GSList *) selection->itemList()); if (!drag->isNonEmpty() || selection->isEmpty()) return; guint n_tot = drag->numDraggers(); guint n_sel = drag->numSelected(); //The use of ngettext in the following code is intentional even if the English singular form would never be used if (n_sel == 1) { if (drag->singleSelectedDraggerNumDraggables() == 1) { gchar * message = g_strconcat( //TRANSLATORS: %s will be substituted with the point name (see previous messages); This is part of a compound message _("%s selected"), //TRANSLATORS: Mind the space in front. This is part of a compound message ngettext(" out of %d mesh handle"," out of %d mesh handles",n_tot), ngettext(" on %d selected object"," on %d selected objects",n_obj),NULL); rc->_message_context->setF(Inkscape::NORMAL_MESSAGE, message,_(ms_handle_descr[drag->singleSelectedDraggerSingleDraggableType()]), n_tot, n_obj); } else { gchar * message = g_strconcat( //TRANSLATORS: This is a part of a compound message (out of two more indicating: grandint handle count & object count) ngettext("One handle merging %d stop (drag with <b>Shift</b> to separate) selected", "One handle merging %d stops (drag with <b>Shift</b> to separate) selected", drag->singleSelectedDraggerNumDraggables()), ngettext(" out of %d mesh handle"," out of %d mesh handles",n_tot), ngettext(" on %d selected object"," on %d selected objects",n_obj),NULL); rc->_message_context->setF(Inkscape::NORMAL_MESSAGE,message,drag->singleSelectedDraggerNumDraggables(), n_tot, n_obj); } } else if (n_sel > 1) { //TRANSLATORS: The plural refers to number of selected mesh handles. This is part of a compound message (part two indicates selected object count) gchar * message = g_strconcat(ngettext("<b>%d</b> mesh handle selected out of %d","<b>%d</b> mesh handles selected out of %d",n_sel), //TRANSLATORS: Mind the space in front. (Refers to gradient handles selected). This is part of a compound message ngettext(" on %d selected object"," on %d selected objects",n_obj),NULL); rc->_message_context->setF(Inkscape::NORMAL_MESSAGE,message, n_sel, n_tot, n_obj); } else if (n_sel == 0) { rc->_message_context->setF(Inkscape::NORMAL_MESSAGE, //TRANSLATORS: The plural refers to number of selected objects ngettext("<b>No</b> mesh handles selected out of %d on %d selected object", "<b>No</b> mesh handles selected out of %d on %d selected objects",n_obj), n_tot, n_obj); } // FIXME // We need to update mesh gradient handles. // Get gradient this drag belongs too.. // std::cout << "mesh_selection_changed: selection: objects: " << n_obj << std::endl; // GSList *itemList = (GSList *) selection->itemList(); // while( itemList ) { // SPItem *item = SP_ITEM( itemList->data ); // // std::cout << " item: " << SP_OBJECT(item)->getId() << std::endl; // SPStyle *style = item->style; // if (style && (style->fill.isPaintserver())) { // SPPaintServer *server = item->style->getFillPaintServer(); // if ( SP_IS_MESHGRADIENT(server) ) { // SPMeshGradient *mg = SP_MESHGRADIENT(server); // guint rows = 0;//mg->array.patches.size(); // for ( guint i = 0; i < rows; ++i ) { // guint columns = 0;//mg->array.patches[0].size(); // for ( guint j = 0; j < columns; ++j ) { // } // } // } // } // itemList = itemList->next; // } // GList* dragger_ptr = drag->draggers; // Points to GrDragger class (group of GrDraggable) // guint count = 0; // while( dragger_ptr ) { // std::cout << "mesh_selection_changed: dragger: " << ++count << std::endl; // GSList* draggable_ptr = ((GrDragger *) dragger_ptr->data)->draggables; // while( draggable_ptr ) { // std::cout << "mesh_selection_changed: draggable: " << draggable_ptr << std::endl; // GrDraggable *draggable = (GrDraggable *) draggable_ptr->data; // gint point_type = draggable->point_type; // gint point_i = draggable->point_i; // bool fill_or_stroke = draggable->fill_or_stroke; // if( point_type == POINT_MG_CORNER ) { // //std::cout << "mesh_selection_changed: POINT_MG_CORNER: " << point_i << std::endl; // // Now we must create or destroy corresponding handles. // if( g_list_find( drag->selected, dragger_ptr->data ) ) { // //std::cout << "gradient_selection_changed: Selected: " << point_i << std::endl; // // Which meshes does this point belong to? // } else { // //std::cout << "mesh_selection_changed: Not Selected: " << point_i << std::endl; // } // } // draggable_ptr = draggable_ptr->next; // } // dragger_ptr = dragger_ptr->next; // } }