/* * Return a "HHSSLL" version of the first stop color so we can sort by it */ unsigned long sp_gradient_to_hhssll(SPGradient *gr) { SPStop *stop = gr->getFirstStop(); unsigned long rgba = stop->get_rgba32(); float hsl[3]; sp_color_rgb_to_hsl_floatv (hsl, SP_RGBA32_R_F(rgba), SP_RGBA32_G_F(rgba), SP_RGBA32_B_F(rgba)); return ((int)(hsl[0]*100 * 10000)) + ((int)(hsl[1]*100 * 100)) + ((int)(hsl[2]*100 * 1)); }
int SPGradient::getStopCount() const { int count = 0; for (SPStop *stop = const_cast<SPGradient*>(this)->getFirstStop(); stop && stop->getNextStop(); stop = stop->getNextStop()) { count++; } return count; }
// user selected existing stop from list static void sp_grad_edit_combo_box_changed (GtkComboBox * /*widget*/, GtkWidget *tbl) { SPStop *stop = get_selected_stop(tbl); if (!stop) { return; } blocked = TRUE; SelectedColor *csel = static_cast<SelectedColor*>(g_object_get_data(G_OBJECT(tbl), "cselector")); // set its color, from the stored array g_object_set_data(G_OBJECT(tbl), "updating_color", reinterpret_cast<void*>(1)); csel->setColorAlpha(stop->getEffectiveColor(), stop->opacity); g_object_set_data(G_OBJECT(tbl), "updating_color", reinterpret_cast<void*>(0)); GtkWidget *offspin = GTK_WIDGET(g_object_get_data(G_OBJECT(tbl), "offspn")); GtkWidget *offslide =GTK_WIDGET(g_object_get_data(G_OBJECT(tbl), "offslide")); GtkAdjustment *adj = static_cast<GtkAdjustment*>(g_object_get_data(G_OBJECT(tbl), "offset")); bool isEndStop = false; SPStop *prev = NULL; prev = stop->getPrevStop(); if (prev != NULL ) { gtk_adjustment_set_lower (adj, prev->offset); } else { isEndStop = true; gtk_adjustment_set_lower (adj, 0); } SPStop *next = NULL; next = stop->getNextStop(); if (next != NULL ) { gtk_adjustment_set_upper (adj, next->offset); } else { isEndStop = true; gtk_adjustment_set_upper (adj, 1.0); } //fixme: does this work on all possible input gradients? if (!isEndStop) { gtk_widget_set_sensitive(offslide, TRUE); gtk_widget_set_sensitive(GTK_WIDGET(offspin), TRUE); } else { gtk_widget_set_sensitive(offslide, FALSE); gtk_widget_set_sensitive(GTK_WIDGET(offspin), FALSE); } gtk_adjustment_set_value(adj, stop->offset); gtk_adjustment_changed(adj); blocked = FALSE; }
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 offadjustmentChanged( GtkAdjustment *adjustment, GtkWidget *vb) { if (!blocked) { blocked = TRUE; SPStop *stop = get_selected_stop(vb); if (stop) { stop->offset = gtk_adjustment_get_value (adjustment); sp_repr_set_css_double(stop->getRepr(), "offset", stop->offset); DocumentUndo::maybeDone(stop->document, "gradient:stop:offset", SP_VERB_CONTEXT_GRADIENT, _("Change gradient stop offset")); } blocked = FALSE; } }
static void verify_grad(SPGradient *gradient) { int i = 0; SPStop *stop = NULL; /* count stops */ for ( SPObject *ochild = gradient->firstChild() ; ochild ; ochild = ochild->getNext() ) { if (SP_IS_STOP(ochild)) { i++; stop = SP_STOP(ochild); } } Inkscape::XML::Document *xml_doc; xml_doc = gradient->getRepr()->document(); if (i < 1) { Inkscape::CSSOStringStream os; os << "stop-color: #000000;stop-opacity:" << 1.0 << ";"; Inkscape::XML::Node *child; child = xml_doc->createElement("svg:stop"); sp_repr_set_css_double(child, "offset", 0.0); child->setAttribute("style", os.str().c_str()); gradient->getRepr()->addChild(child, NULL); Inkscape::GC::release(child); child = xml_doc->createElement("svg:stop"); sp_repr_set_css_double(child, "offset", 1.0); child->setAttribute("style", os.str().c_str()); gradient->getRepr()->addChild(child, NULL); Inkscape::GC::release(child); return; } if (i < 2) { sp_repr_set_css_double(stop->getRepr(), "offset", 0.0); Inkscape::XML::Node *child = stop->getRepr()->duplicate(gradient->getRepr()->document()); sp_repr_set_css_double(child, "offset", 1.0); gradient->getRepr()->addChild(child, stop->getRepr()); Inkscape::GC::release(child); } }
/* * User changed the offset */ static void gr_stop_offset_adjustment_changed(GtkAdjustment *adj, GObject *tbl) { if (blocked) { return; } blocked = TRUE; SPStop *stop = get_selected_stop(GTK_WIDGET(tbl)); if (stop) { stop->offset = gtk_adjustment_get_value(adj); sp_repr_set_css_double(stop->getRepr(), "offset", stop->offset); DocumentUndo::maybeDone(stop->document, "gradient:stop:offset", SP_VERB_CONTEXT_GRADIENT, _("Change gradient stop offset")); } blocked = FALSE; }
static void gr_stop_set_offset(GtkComboBox * /*widget*/, GtkWidget *data) { SPStop *stop = get_selected_stop(data); if (!stop) { return; } EgeAdjustmentAction* act = (EgeAdjustmentAction *)g_object_get_data( G_OBJECT(data), "offset_action"); if (!act) { return; } GtkAdjustment *adj = ege_adjustment_action_get_adjustment(act); bool isEndStop = false; SPStop *prev = NULL; prev = stop->getPrevStop(); if (prev != NULL ) { gtk_adjustment_set_lower(adj, prev->offset); } else { isEndStop = true; gtk_adjustment_set_lower(adj, 0); } SPStop *next = NULL; next = stop->getNextStop(); if (next != NULL ) { gtk_adjustment_set_upper(adj, next->offset); } else { isEndStop = true; gtk_adjustment_set_upper(adj, 1.0); } blocked = TRUE; gtk_adjustment_set_value(adj, stop->offset); gtk_action_set_sensitive( GTK_ACTION(act), !isEndStop ); gtk_adjustment_changed(adj); blocked = FALSE; }
/** * return true if this gradient is "equivalent" to that gradient. * Equivalent meaning they have the same stop count, same stop colors and same stop opacity * @param that - A gradient to compare this to */ bool SPGradient::isEquivalent(SPGradient *that) { //TODO Make this work for mesh gradients bool status = false; while(1){ // not really a loop, used to avoid deep nesting or multiple exit points from function if (this->getStopCount() != that->getStopCount()) { break; } if (this->hasStops() != that->hasStops()) { break; } if (!this->getVector() || !that->getVector()) { break; } if (this->isSwatch() != that->isSwatch()) { break; } if ( this->isSwatch() ){ // drop down to check stops. } else if ( (SP_IS_LINEARGRADIENT(this) && SP_IS_LINEARGRADIENT(that)) || (SP_IS_RADIALGRADIENT(this) && SP_IS_RADIALGRADIENT(that)) || (SP_IS_MESH(this) && SP_IS_MESH(that))) { if(!this->isAligned(that))break; } else { break; } // this should never happen, some unhandled type of gradient SPStop *as = this->getVector()->getFirstStop(); SPStop *bs = that->getVector()->getFirstStop(); bool effective = true; while (effective && (as && bs)) { if (!as->getEffectiveColor().isClose(bs->getEffectiveColor(), 0.001) || as->offset != bs->offset) { effective = false; break; } else { as = as->getNextStop(); bs = bs->getNextStop(); } } if (!effective) break; status = true; break; } return status; }
static gboolean update_stop_list( GtkWidget *stop_combo, SPGradient *gradient, SPStop *new_stop, GtkWidget *widget, bool gr_multi) { gboolean sensitive = FALSE; if (!stop_combo) { return sensitive; } GtkListStore *store = (GtkListStore *)gtk_combo_box_get_model(GTK_COMBO_BOX(stop_combo)); if (!store) { return sensitive; } blocked = TRUE; /* Clear old list, if there is any */ gtk_list_store_clear(store); GtkTreeIter iter; if (!SP_IS_GRADIENT(gradient)) { gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, 0, _("No gradient"), 1, NULL, 2, NULL, -1); gtk_combo_box_set_active(GTK_COMBO_BOX(stop_combo) , 0); sensitive = FALSE; blocked = FALSE; return sensitive; } /* Populate the combobox store */ GSList *sl = NULL; if ( gradient->hasStops() ) { for ( SPObject *ochild = gradient->firstChild() ; ochild ; ochild = ochild->getNext() ) { if (SP_IS_STOP(ochild)) { sl = g_slist_append(sl, ochild); } } } if (!sl) { gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, 0, _("No stops in gradient"), 1, NULL, 2, NULL, -1); sensitive = FALSE; } else { for (; sl != NULL; sl = sl->next){ if (SP_IS_STOP(sl->data)){ SPStop *stop = SP_STOP(sl->data); Inkscape::XML::Node *repr = reinterpret_cast<SPItem *>(sl->data)->getRepr(); Inkscape::UI::Widget::ColorPreview *cpv = Gtk::manage(new Inkscape::UI::Widget::ColorPreview(stop->get_rgba32())); GdkPixbuf *pb = cpv->toPixbuf(32, 16); Glib::ustring label = gr_ellipsize_text(repr->attribute("id"), 25); gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, 0, label.c_str(), 1, pb, 2, stop, -1); sensitive = FALSE; } } sensitive = TRUE; } if (gr_multi) { sensitive = FALSE; } if (new_stop == NULL) { gtk_combo_box_set_active(GTK_COMBO_BOX(stop_combo) , 0); } else { select_stop_in_list(stop_combo, gradient, new_stop, widget, TRUE); } blocked = FALSE; return sensitive; }
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")); }
static void update_stop_list( GtkWidget *vb, SPGradient *gradient, SPStop *new_stop) { if (!SP_IS_GRADIENT(gradient)) { return; } blocked = TRUE; /* Clear old list, if there is any */ GtkWidget *combo_box = static_cast<GtkWidget *>(g_object_get_data(G_OBJECT(vb), "combo_box")); if (!combo_box) { return; } GtkListStore *store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(combo_box))); if (!store) { return; } gtk_list_store_clear(store); GtkTreeIter iter; /* Populate the combobox store */ GSList *sl = NULL; if ( gradient->hasStops() ) { for ( SPObject *ochild = gradient->firstChild() ; ochild ; ochild = ochild->getNext() ) { if (SP_IS_STOP(ochild)) { sl = g_slist_append(sl, ochild); } } } if (!sl) { gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, 0, NULL, 1, _("No stops in gradient"), 2, NULL, -1); gtk_widget_set_sensitive (combo_box, FALSE); } else { for (; sl != NULL; sl = sl->next){ if (SP_IS_STOP(sl->data)){ SPStop *stop = SP_STOP(sl->data); Inkscape::XML::Node *repr = reinterpret_cast<SPItem *>(sl->data)->getRepr(); Inkscape::UI::Widget::ColorPreview *cpv = Gtk::manage(new Inkscape::UI::Widget::ColorPreview(stop->get_rgba32())); GdkPixbuf *pb = cpv->toPixbuf(64, 16); gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, 0, pb, 1, repr->attribute("id"), 2, stop, -1); gtk_widget_set_sensitive (combo_box, FALSE); } } gtk_widget_set_sensitive(combo_box, TRUE); } /* Set history */ if (new_stop == NULL) { gtk_combo_box_set_active (GTK_COMBO_BOX(combo_box) , 0); } else { select_stop_in_list(vb, gradient, new_stop); } blocked = FALSE; }
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); } } }
static void sp_gradient_vector_widget_load_gradient(GtkWidget *widget, SPGradient *gradient) { blocked = TRUE; SPGradient *old; old = static_cast<SPGradient*>(g_object_get_data(G_OBJECT(widget), "gradient")); if (old != gradient) { sigc::connection *release_connection; sigc::connection *modified_connection; release_connection = static_cast<sigc::connection *>(g_object_get_data(G_OBJECT(widget), "gradient_release_connection")); modified_connection = static_cast<sigc::connection *>(g_object_get_data(G_OBJECT(widget), "gradient_modified_connection")); if (old) { g_assert( release_connection != NULL ); g_assert( modified_connection != NULL ); release_connection->disconnect(); modified_connection->disconnect(); sp_signal_disconnect_by_data(old, widget); } if (gradient) { if (!release_connection) { release_connection = new sigc::connection(); } if (!modified_connection) { modified_connection = new sigc::connection(); } *release_connection = gradient->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gradient_vector_gradient_release), widget)); *modified_connection = gradient->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_gradient_vector_gradient_modified), widget)); } else { if (release_connection) { delete release_connection; release_connection = NULL; } if (modified_connection) { delete modified_connection; modified_connection = NULL; } } g_object_set_data(G_OBJECT(widget), "gradient_release_connection", release_connection); g_object_set_data(G_OBJECT(widget), "gradient_modified_connection", modified_connection); } g_object_set_data(G_OBJECT(widget), "gradient", gradient); if (gradient) { gtk_widget_set_sensitive(widget, TRUE); gradient->ensureVector(); SPStop *stop = get_selected_stop(widget); if (!stop) { return; } // get the color selector SelectedColor *csel = static_cast<SelectedColor*>(g_object_get_data(G_OBJECT(widget), "cselector")); g_object_set_data(G_OBJECT(widget), "updating_color", reinterpret_cast<void*>(1)); csel->setColorAlpha(stop->getEffectiveColor(), stop->opacity); g_object_set_data(G_OBJECT(widget), "updating_color", reinterpret_cast<void*>(0)); /* Fill preview */ GtkWidget *w = static_cast<GtkWidget *>(g_object_get_data(G_OBJECT(widget), "preview")); sp_gradient_image_set_gradient(SP_GRADIENT_IMAGE(w), gradient); update_stop_list(GTK_WIDGET(widget), gradient, NULL); // Once the user edits a gradient, it stops being auto-collectable if (gradient->getRepr()->attribute("inkscape:collect")) { SPDocument *document = gradient->document; bool saved = DocumentUndo::getUndoSensitive(document); DocumentUndo::setUndoSensitive(document, false); gradient->getRepr()->setAttribute("inkscape:collect", NULL); DocumentUndo::setUndoSensitive(document, saved); } } else { // no gradient, disable everything gtk_widget_set_sensitive(widget, FALSE); } blocked = FALSE; }
/** 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; }