/* * Get the gradient of the selected desktop item * This is gradient containing the repeat settings, not the underlying "getVector" href linked gradient. */ void gr_get_dt_selected_gradient(Inkscape::Selection *selection, SPGradient *&gr_selected) { SPGradient *gradient = 0; for (GSList const* i = selection->itemList(); i; i = i->next) { SPItem *item = SP_ITEM(i->data); // get the items gradient, not the getVector() version SPStyle *style = item->style; SPPaintServer *server = 0; if (style && (style->fill.isPaintserver())) { server = item->style->getFillPaintServer(); } if (style && (style->stroke.isPaintserver())) { server = item->style->getStrokePaintServer(); } if ( SP_IS_GRADIENT(server) ) { gradient = SP_GRADIENT(server); } } if (gradient && gradient->isSolid()) { gradient = 0; } if (gradient) { gr_selected = gradient; } }
static void sp_grd_ed_del_stop(GtkWidget */*widget*/, GtkWidget *vb) { SPGradient *gradient = static_cast<SPGradient *>(g_object_get_data(G_OBJECT(vb), "gradient")); SPStop *stop = get_selected_stop(vb); if (!stop) { return; } if (gradient->vector.stops.size() > 2) { // 2 is the minimum // if we delete first or last stop, move the next/previous to the edge if (stop->offset == 0) { SPStop *next = stop->getNextStop(); if (next) { next->offset = 0; sp_repr_set_css_double(next->getRepr(), "offset", 0); } } else if (stop->offset == 1) { SPStop *prev = stop->getPrevStop(); if (prev) { prev->offset = 1; sp_repr_set_css_double(prev->getRepr(), "offset", 1); } } gradient->getRepr()->removeChild(stop->getRepr()); sp_gradient_vector_widget_load_gradient(vb, gradient); update_stop_list(GTK_WIDGET(vb), gradient, NULL); DocumentUndo::done(gradient->document, SP_VERB_CONTEXT_GRADIENT, _("Delete gradient stop")); } }
static void sp_gvs_rebuild_gui_full(SPGradientVectorSelector *gvs) { gvs->tree_select_connection.block(); /* Clear old list, if there is any */ gvs->store->clear(); /* Pick up all gradients with vectors */ GSList *gl = NULL; if (gvs->gr) { const GSList *gradients = gvs->gr->document->getResourceList("gradient"); for (const GSList *curr = gradients; curr; curr = curr->next) { SPGradient* grad = SP_GRADIENT(curr->data); if ( grad->hasStops() && (grad->isSwatch() == gvs->swatched) ) { gl = g_slist_prepend(gl, curr->data); } } } gl = g_slist_reverse(gl); /* Get usage count of all the gradients */ std::map<SPGradient *, gint> usageCount; gr_get_usage_counts(gvs->doc, &usageCount); if (!gvs->doc) { Gtk::TreeModel::Row row = *(gvs->store->append()); row[gvs->columns->name] = _("No document selected"); } else if (!gl) { Gtk::TreeModel::Row row = *(gvs->store->append()); row[gvs->columns->name] = _("No gradients in document"); } else if (!gvs->gr) { Gtk::TreeModel::Row row = *(gvs->store->append()); row[gvs->columns->name] = _("No gradient selected"); } else { while (gl) { SPGradient *gr; gr = SP_GRADIENT(gl->data); gl = g_slist_remove(gl, gr); unsigned long hhssll = sp_gradient_to_hhssll(gr); GdkPixbuf *pixb = sp_gradient_to_pixbuf (gr, 64, 18); Glib::ustring label = gr_prepare_label(gr); Gtk::TreeModel::Row row = *(gvs->store->append()); row[gvs->columns->name] = label.c_str(); row[gvs->columns->color] = hhssll; row[gvs->columns->refcount] = usageCount[gr]; row[gvs->columns->data] = gr; row[gvs->columns->pixbuf] = Glib::wrap(pixb); } } gvs->tree_select_connection.unblock(); }
static void sp_grd_ed_add_stop(GtkWidget */*widget*/, GtkWidget *vb) { SPGradient *gradient = static_cast<SPGradient *>(g_object_get_data(G_OBJECT(vb), "gradient")); verify_grad(gradient); SPStop *stop = get_selected_stop(vb); if (!stop) { return; } Inkscape::XML::Node *new_stop_repr = NULL; SPStop *next = stop->getNextStop(); if (next == NULL) { SPStop *prev = stop->getPrevStop(); if (prev != NULL) { next = stop; stop = prev; } } if (next != NULL) { new_stop_repr = stop->getRepr()->duplicate(gradient->getRepr()->document()); gradient->getRepr()->addChild(new_stop_repr, stop->getRepr()); } else { next = stop; new_stop_repr = stop->getPrevStop()->getRepr()->duplicate(gradient->getRepr()->document()); gradient->getRepr()->addChild(new_stop_repr, stop->getPrevStop()->getRepr()); } SPStop *newstop = reinterpret_cast<SPStop *>(gradient->document->getObjectByRepr(new_stop_repr)); newstop->offset = (stop->offset + next->offset) * 0.5 ; guint32 const c1 = stop->get_rgba32(); guint32 const c2 = next->get_rgba32(); guint32 cnew = sp_average_color(c1, c2); Inkscape::CSSOStringStream os; gchar c[64]; sp_svg_write_color(c, sizeof(c), cnew); gdouble opacity = static_cast<gdouble>(SP_RGBA32_A_F(cnew)); os << "stop-color:" << c << ";stop-opacity:" << opacity <<";"; newstop->getRepr()->setAttribute("style", os.str().c_str()); sp_repr_set_css_double( newstop->getRepr(), "offset", (double)newstop->offset); sp_gradient_vector_widget_load_gradient(vb, gradient); Inkscape::GC::release(new_stop_repr); update_stop_list(GTK_WIDGET(vb), gradient, newstop); GtkWidget *offspin = GTK_WIDGET(g_object_get_data(G_OBJECT(vb), "offspn")); GtkWidget *offslide =GTK_WIDGET(g_object_get_data(G_OBJECT(vb), "offslide")); gtk_widget_set_sensitive(offslide, TRUE); gtk_widget_set_sensitive(GTK_WIDGET(offspin), TRUE); DocumentUndo::done(gradient->document, SP_VERB_CONTEXT_GRADIENT, _("Add gradient stop")); }
// TODO: So a solid brush is a gradient with a swatch and zero stops? // Should we derive a new class for that? Or at least make this method // virtual and move it out of the way? bool SPPaintServer::isSolid() const { bool solid = false; if (swatch && SP_IS_GRADIENT(this)) { SPGradient *grad = SP_GRADIENT(this); if ( grad->hasStops() && (grad->getStopCount() == 0) ) { solid = true; } } return solid; }
static void sp_gradient_selector_add_vector_clicked (GtkWidget */*w*/, SPGradientSelector *sel) { SPDocument *doc = sp_gradient_vector_selector_get_document (SP_GRADIENT_VECTOR_SELECTOR (sel->vectors)); if (!doc) return; SPGradient *gr = sp_gradient_vector_selector_get_gradient( SP_GRADIENT_VECTOR_SELECTOR (sel->vectors)); Inkscape::XML::Document *xml_doc = doc->getReprDoc(); Inkscape::XML::Node *repr = NULL; if (gr) { repr = gr->getRepr()->duplicate(xml_doc); } else { repr = xml_doc->createElement("svg:linearGradient"); Inkscape::XML::Node *stop = xml_doc->createElement("svg:stop"); stop->setAttribute("offset", "0"); stop->setAttribute("style", "stop-color:#000;stop-opacity:1;"); repr->appendChild(stop); Inkscape::GC::release(stop); stop = xml_doc->createElement("svg:stop"); stop->setAttribute("offset", "1"); stop->setAttribute("style", "stop-color:#fff;stop-opacity:1;"); repr->appendChild(stop); Inkscape::GC::release(stop); } doc->getDefs()->getRepr()->addChild(repr, NULL); Glib::ustring old_id = gr->getId(); gr = SP_GRADIENT(doc->getObjectByRepr(repr)); // Rename the new gradients id to be similar to the cloned gradients rename_id(gr, old_id); sp_gradient_vector_selector_set_gradient( SP_GRADIENT_VECTOR_SELECTOR (sel->vectors), doc, gr); sel->selectGradientInTree(gr); Inkscape::GC::release(repr); }
static void gr_spread_change(EgeSelectOneAction *act, GtkWidget *widget) { if (blocked) { return; } SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data(G_OBJECT(widget), "desktop")); Inkscape::Selection *selection = sp_desktop_selection(desktop); SPGradient *gradient = 0; gr_get_dt_selected_gradient(selection, gradient); if (gradient) { SPGradientSpread spread = (SPGradientSpread) ege_select_one_action_get_active(act); gradient->setSpread(spread); gradient->updateRepr(); DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_GRADIENT, _("Set gradient repeat")); } }
static void sp_gradient_selector_delete_vector_clicked (GtkWidget */*w*/, SPGradientSelector *sel) { const Glib::RefPtr<Gtk::TreeSelection> selection = sel->treeview->get_selection(); if (!selection) { return; } SPGradient *obj = NULL; /* Single selection */ Gtk::TreeModel::iterator iter = selection->get_selected(); if ( iter ) { Gtk::TreeModel::Row row = *iter; obj = row[sel->columns->data]; } if (obj) { sp_gradient_unset_swatch(SP_ACTIVE_DESKTOP, obj->getId()); } }
/** Creates normalized color mesh patch array */ void SPGradient::rebuildArray() { // std::cout << "SPGradient::rebuildArray()" << std::endl; if( !SP_IS_MESH(this) ) { g_warning( "SPGradient::rebuildArray() called for non-mesh gradient" ); return; } array.read( SP_MESH( this ) ); has_patches = false; for ( SPObject *ro = firstChild() ; ro ; ro = ro->getNext() ) { if (SP_IS_MESHROW(ro)) { has_patches = true; // std::cout << " Has Patches" << std::endl; break; } } // MESH_FIXME: TO PROPERLY COPY SPGradient *reffed = ref->getObject(); if ( !hasPatches() && reffed ) { std::cout << "SPGradient::rebuildArray(): reffed array NOT IMPLEMENTED!!!" << std::endl; /* Copy array from referenced gradient */ array.built = true; // Prevent infinite recursion. reffed->ensureArray(); // if (!reffed->array.nodes.empty()) { // array.built = reffed->array.built; // for( uint i = 0; i < reffed->array.nodes.size(); ++i ) { // array.nodes[i].assign(reffed->array.nodes[i].begin(), reffed->array.nodes[i].end()); // // FILL ME // } // return; // } } }
static void select_stop_by_drag(GtkWidget *combo_box, SPGradient *gradient, ToolBase *ev, GtkWidget *data) { if (blocked || !ev || !gradient) return; GrDrag *drag = ev->get_drag(); if (!drag || !drag->selected) { blocked = TRUE; gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box) , 0); gr_stop_set_offset(GTK_COMBO_BOX(combo_box), data); blocked = FALSE; return; } gint n = 0; // for all selected draggers for (GList *i = drag->selected; i != NULL; i = i->next) { GrDragger *dragger = static_cast<GrDragger*>(i->data); // for all draggables of dragger for (GSList const* j = dragger->draggables; j != NULL; j = j->next) { GrDraggable *draggable = static_cast<GrDraggable*>(j->data); if (draggable->point_type != POINT_RG_FOCUS) { n++; } if (n > 1) { // Mulitple stops selected GtkListStore *store = (GtkListStore *)gtk_combo_box_get_model(GTK_COMBO_BOX(combo_box)); if (!store) { return; } GtkTreeIter iter; gtk_list_store_prepend(store, &iter); gtk_list_store_set(store, &iter, 0, _("Multiple stops"), 1, NULL, 2, NULL, -1); gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box) , 0); EgeAdjustmentAction* act = (EgeAdjustmentAction *)g_object_get_data( G_OBJECT(data), "offset_action"); if (act) { gtk_action_set_sensitive( GTK_ACTION(act), FALSE); } return; } SPGradient *vector = gradient->getVector(); if (!vector) return; SPStop *stop = vector->getFirstStop(); switch (draggable->point_type) { case POINT_LG_MID: case POINT_RG_MID1: case POINT_RG_MID2: { stop = sp_get_stop_i(vector, draggable->point_i); } break; case POINT_LG_END: case POINT_RG_R1: case POINT_RG_R2: { stop = sp_last_stop(vector); } break; default: break; } select_stop_in_list( combo_box, gradient, stop, data, TRUE); } } }
/* * Get the current selection and dragger status from the desktop */ void gr_read_selection( Inkscape::Selection *selection, GrDrag *drag, SPGradient *&gr_selected, bool &gr_multi, SPGradientSpread &spr_selected, bool &spr_multi ) { if (drag && drag->selected) { // GRADIENTFIXME: make this work for more than one selected dragger? GrDragger *dragger = static_cast<GrDragger*>(drag->selected->data); for (GSList const* i = dragger->draggables; i; i = i->next) { // for all draggables of dragger GrDraggable *draggable = static_cast<GrDraggable *>(i->data); SPGradient *gradient = sp_item_gradient_get_vector(draggable->item, draggable->fill_or_stroke); SPGradientSpread spread = sp_item_gradient_get_spread(draggable->item, draggable->fill_or_stroke); if (gradient && gradient->isSolid()) { gradient = 0; } if (gradient && (gradient != gr_selected)) { if (gr_selected) { gr_multi = true; } else { gr_selected = gradient; } } if (spread != spr_selected) { if (spr_selected != SP_GRADIENT_SPREAD_UNDEFINED) { spr_multi = true; } else { spr_selected = spread; } } } return; } // If no selected dragger, read desktop selection for (GSList const* i = selection->itemList(); i; i = i->next) { SPItem *item = SP_ITEM(i->data); SPStyle *style = item->style; if (style && (style->fill.isPaintserver())) { SPPaintServer *server = item->style->getFillPaintServer(); if ( SP_IS_GRADIENT(server) ) { SPGradient *gradient = SP_GRADIENT(server)->getVector(); SPGradientSpread spread = SP_GRADIENT(server)->fetchSpread(); if (gradient && gradient->isSolid()) { gradient = 0; } if (gradient && (gradient != gr_selected)) { if (gr_selected) { gr_multi = true; } else { gr_selected = gradient; } } if (spread != spr_selected) { if (spr_selected != SP_GRADIENT_SPREAD_UNDEFINED) { spr_multi = true; } else { spr_selected = spread; } } } } if (style && (style->stroke.isPaintserver())) { SPPaintServer *server = item->style->getStrokePaintServer(); if ( SP_IS_GRADIENT(server) ) { SPGradient *gradient = SP_GRADIENT(server)->getVector(); SPGradientSpread spread = SP_GRADIENT(server)->fetchSpread(); if (gradient && gradient->isSolid()) { gradient = 0; } if (gradient && (gradient != gr_selected)) { if (gr_selected) { gr_multi = true; } else { gr_selected = gradient; } } if (spread != spr_selected) { if (spr_selected != SP_GRADIENT_SPREAD_UNDEFINED) { spr_multi = true; } else { spr_selected = spread; } } } } } }
gboolean gr_vector_list(GtkWidget *combo_box, SPDesktop *desktop, bool selection_empty, SPGradient *gr_selected, bool gr_multi) { gboolean sensitive = FALSE; if (blocked) { return sensitive; } SPDocument *document = sp_desktop_document(desktop); GtkTreeIter iter; GtkListStore *store = (GtkListStore *)gtk_combo_box_get_model(GTK_COMBO_BOX(combo_box)); blocked = TRUE; /* Clear old list, if there is any */ gtk_list_store_clear(store); GSList *gl = NULL; const GSList *gradients = document->getResourceList("gradient"); for (const GSList *i = gradients; i != NULL; i = i->next) { SPGradient *grad = SP_GRADIENT(i->data); if ( grad->hasStops() && !grad->isSolid() ) { gl = g_slist_prepend(gl, i->data); } } gl = g_slist_reverse(gl); guint pos = 0; if (!gl) { // The document has no gradients gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, 0, _("No gradient"), 1, NULL, 2, NULL, -1); sensitive = FALSE; } else if (selection_empty) { // Document has gradients, but nothing is currently selected. gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, 0, _("Nothing selected"), 1, NULL, 2, NULL, -1); sensitive = FALSE; } else { if (gr_selected == NULL) { gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, 0, _("No gradient"), 1, NULL, 2, NULL, -1); sensitive = FALSE; } if (gr_multi) { gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, 0, _("Multiple gradients"), 1, NULL, 2, NULL, -1); sensitive = FALSE; } guint idx = 0; while (gl) { SPGradient *gradient = SP_GRADIENT(gl->data); gl = g_slist_remove(gl, gradient); Glib::ustring label = gr_prepare_label(gradient); GdkPixbuf *pixb = sp_gradient_to_pixbuf(gradient, 64, 16); gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, 0, label.c_str(), 1, pixb, 2, gradient, -1); if (gradient == gr_selected) { pos = idx; } idx ++; } sensitive = TRUE; } /* Select the current gradient, or the Multi/Nothing line */ if (gr_multi || gr_selected == NULL) { gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box) , 0); } else { gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box) , pos); } blocked = FALSE; return sensitive; }
static void sp_gradient_vector_color_changed(Inkscape::UI::SelectedColor *selected_color, GObject *object) { (void)selected_color; void* updating_color = g_object_get_data(G_OBJECT(object), "updating_color"); if (updating_color) { return; } if (blocked) { return; } SPGradient *gradient = static_cast<SPGradient*>(g_object_get_data(G_OBJECT(object), "gradient")); if (!gradient) { return; } blocked = TRUE; SPGradient *ngr = sp_gradient_ensure_vector_normalized(gradient); if (ngr != gradient) { /* Our master gradient has changed */ sp_gradient_vector_widget_load_gradient(GTK_WIDGET(object), ngr); } ngr->ensureVector(); /* Set start parameters */ /* We rely on normalized vector, i.e. stops HAVE to exist */ g_return_if_fail(ngr->getFirstStop() != NULL); SPStop *stop = get_selected_stop(GTK_WIDGET(object)); if (!stop) { return; } SelectedColor *csel = static_cast<SelectedColor *>(g_object_get_data(G_OBJECT(object), "cselector")); SPColor color; float alpha = 0; csel->colorAlpha(color, alpha); sp_repr_set_css_double(stop->getRepr(), "offset", stop->offset); Inkscape::CSSOStringStream os; os << "stop-color:" << color.toString() << ";stop-opacity:" << static_cast<gdouble>(alpha) <<";"; stop->getRepr()->setAttribute("style", os.str().c_str()); // g_snprintf(c, 256, "stop-color:#%06x;stop-opacity:%g;", rgb >> 8, static_cast<gdouble>(alpha)); //stop->getRepr()->setAttribute("style", c); DocumentUndo::done(ngr->document, SP_VERB_CONTEXT_GRADIENT, _("Change gradient stop color")); blocked = FALSE; // Set the color in the selected stop after change GtkWidget *combo_box = static_cast<GtkWidget *>(g_object_get_data(G_OBJECT(object), "combo_box")); if (combo_box) { GtkTreeIter iter; if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX(combo_box), &iter)) { GtkListStore *store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(combo_box))); Inkscape::UI::Widget::ColorPreview *cp = Gtk::manage(new Inkscape::UI::Widget::ColorPreview(stop->get_rgba32())); GdkPixbuf *pb = cp->toPixbuf(64, 16); gtk_list_store_set (store, &iter, 0, pb, /*1, repr->attribute("id"),*/ 2, stop, -1); } } }
/** Creates normalized color vector */ void SPGradient::rebuildVector() { gint len = 0; for ( SPObject *child = firstChild() ; child ; child = child->getNext() ) { if (SP_IS_STOP(child)) { len ++; } } has_stops = (len != 0); vector.stops.clear(); SPGradient *reffed = ref ? ref->getObject() : NULL; if ( !hasStops() && reffed ) { /* Copy vector from referenced gradient */ vector.built = true; // Prevent infinite recursion. reffed->ensureVector(); if (!reffed->vector.stops.empty()) { vector.built = reffed->vector.built; vector.stops.assign(reffed->vector.stops.begin(), reffed->vector.stops.end()); return; } } for ( SPObject *child = firstChild(); child; child = child->getNext() ) { if (SP_IS_STOP(child)) { SPStop *stop = SP_STOP(child); SPGradientStop gstop; if (!vector.stops.empty()) { // "Each gradient offset value is required to be equal to or greater than the // previous gradient stop's offset value. If a given gradient stop's offset // value is not equal to or greater than all previous offset values, then the // offset value is adjusted to be equal to the largest of all previous offset // values." gstop.offset = MAX(stop->offset, vector.stops.back().offset); } else { gstop.offset = stop->offset; } // "Gradient offset values less than 0 (or less than 0%) are rounded up to // 0%. Gradient offset values greater than 1 (or greater than 100%) are rounded // down to 100%." gstop.offset = CLAMP(gstop.offset, 0, 1); gstop.color = stop->getEffectiveColor(); gstop.opacity = stop->opacity; vector.stops.push_back(gstop); } } // Normalize per section 13.2.4 of SVG 1.1. if (vector.stops.empty()) { /* "If no stops are defined, then painting shall occur as if 'none' were specified as the * paint style." */ { SPGradientStop gstop; gstop.offset = 0.0; gstop.color.set( 0x00000000 ); gstop.opacity = 0.0; vector.stops.push_back(gstop); } { SPGradientStop gstop; gstop.offset = 1.0; gstop.color.set( 0x00000000 ); gstop.opacity = 0.0; vector.stops.push_back(gstop); } } else { /* "If one stop is defined, then paint with the solid color fill using the color defined * for that gradient stop." */ if (vector.stops.front().offset > 0.0) { // If the first one is not at 0, then insert a copy of the first at 0. SPGradientStop gstop; gstop.offset = 0.0; gstop.color = vector.stops.front().color; gstop.opacity = vector.stops.front().opacity; vector.stops.insert(vector.stops.begin(), gstop); } if (vector.stops.back().offset < 1.0) { // If the last one is not at 1, then insert a copy of the last at 1. SPGradientStop gstop; gstop.offset = 1.0; gstop.color = vector.stops.back().color; gstop.opacity = vector.stops.back().opacity; vector.stops.push_back(gstop); } } vector.built = true; }