/** * 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; }
// 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_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; }