summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJohn Smith <john.smith7545@yahoo.com>2012-08-20 12:53:17 +0000
committerJohn Smith <john.smith7545@yahoo.com>2012-08-20 12:53:17 +0000
commite92962ddc609aaba91d1b9781ea044e84bafeb1b (patch)
treedc25d7d48782832e2c8073f63a2dec4a26081cf8 /src
parentround-off incoming png resolution to 0.1 dpi (Bug 165952 comment 20) (diff)
downloadinkscape-e92962ddc609aaba91d1b9781ea044e84bafeb1b.tar.gz
inkscape-e92962ddc609aaba91d1b9781ea044e84bafeb1b.zip
Fix for 165865 : markers must take object's stroke color
(bzr r11614)
Diffstat (limited to 'src')
-rw-r--r--src/helper/stock-items.cpp12
-rw-r--r--src/helper/stock-items.h2
-rw-r--r--src/id-clash.cpp19
-rw-r--r--src/ui/cache/svg_preview_cache.cpp8
-rw-r--r--src/ui/cache/svg_preview_cache.h1
-rw-r--r--src/ui/dialog/inkscape-preferences.cpp12
-rw-r--r--src/ui/dialog/inkscape-preferences.h4
-rw-r--r--src/widgets/stroke-marker-selector.cpp102
-rw-r--r--src/widgets/stroke-marker-selector.h2
-rw-r--r--src/widgets/stroke-style.cpp291
-rw-r--r--src/widgets/stroke-style.h9
11 files changed, 398 insertions, 64 deletions
diff --git a/src/helper/stock-items.cpp b/src/helper/stock-items.cpp
index e18d56199..902aebdeb 100644
--- a/src/helper/stock-items.cpp
+++ b/src/helper/stock-items.cpp
@@ -173,7 +173,7 @@ sp_gradient_load_from_svg(gchar const *name, SPDocument *current_doc)
// if necessary it will import the object. Copes with name clashes through use of the inkscape:stockid property
// This should be set to be the same as the id in the libary file.
-SPObject *get_stock_item(gchar const *urn)
+SPObject *get_stock_item(gchar const *urn, gboolean stock)
{
g_assert(urn != NULL);
@@ -202,7 +202,7 @@ SPObject *get_stock_item(gchar const *urn)
return NULL;
}
SPObject *object = NULL;
- if (!strcmp(base, "marker")) {
+ if (!strcmp(base, "marker") && !stock) {
for ( SPObject *child = defs->firstChild(); child; child = child->getNext() )
{
if (child->getRepr()->attribute("inkscape:stockid") &&
@@ -214,7 +214,7 @@ SPObject *get_stock_item(gchar const *urn)
}
}
- else if (!strcmp(base,"pattern")) {
+ else if (!strcmp(base,"pattern") && !stock) {
for ( SPObject *child = defs->firstChild() ; child; child = child->getNext() )
{
if (child->getRepr()->attribute("inkscape:stockid") &&
@@ -226,7 +226,7 @@ SPObject *get_stock_item(gchar const *urn)
}
}
- else if (!strcmp(base,"gradient")) {
+ else if (!strcmp(base,"gradient") && !stock) {
for ( SPObject *child = defs->firstChild(); child; child = child->getNext() )
{
if (child->getRepr()->attribute("inkscape:stockid") &&
@@ -255,6 +255,10 @@ SPObject *get_stock_item(gchar const *urn)
g_free(base);
g_free(name);
+ if (object) {
+ object->getRepr()->setAttribute("inkscape:isstock", "true");
+ }
+
return object;
}
diff --git a/src/helper/stock-items.h b/src/helper/stock-items.h
index 990f45254..a0e5cc2a3 100644
--- a/src/helper/stock-items.h
+++ b/src/helper/stock-items.h
@@ -17,6 +17,6 @@
class SPObject;
-SPObject *get_stock_item(gchar const *urn);
+SPObject *get_stock_item(gchar const *urn, gboolean stock=FALSE);
#endif // SEEN_INK_STOCK_ITEMS_H
diff --git a/src/id-clash.cpp b/src/id-clash.cpp
index 12bb65a26..d8299652b 100644
--- a/src/id-clash.cpp
+++ b/src/id-clash.cpp
@@ -79,6 +79,9 @@ const char* clipboard_properties[] = {
"fill",
"filter",
"stroke",
+ "marker-end",
+ "marker-mid",
+ "marker-start"
};
#define NUM_CLIPBOARD_PROPERTIES (sizeof(clipboard_properties) / sizeof(*clipboard_properties))
@@ -111,6 +114,7 @@ find_references(SPObject *elem, refmap_type *refmap)
g_free(uri);
}
}
+
}
return; // nothing more to do for inkscape:clipboard elements
}
@@ -153,6 +157,20 @@ find_references(SPObject *elem, refmap_type *refmap)
}
}
+ /* check for url(#...) references in markers */
+ const gchar *markers[4] = { "", "marker-start", "marker-mid", "marker-end" };
+ for (unsigned i = SP_MARKER_LOC_START; i < SP_MARKER_LOC_QTY; i++) {
+ const gchar *value = style->marker[i].value;
+ if (value) {
+ gchar *uri = extract_uri(value);
+ if (uri && uri[0] == '#') {
+ IdReference idref = { REF_STYLE, elem, markers[i] };
+ (*refmap)[uri+1].push_back(idref);
+ }
+ g_free(uri);
+ }
+ }
+
/* check for other url(#...) references */
for (unsigned i = 0; i < NUM_OTHER_URL_PROPERTIES; ++i) {
const char *attr = other_url_properties[i];
@@ -244,6 +262,7 @@ fix_up_refs(const refmap_type *refmap, const id_changelist_type &id_changes)
gchar *style_string = sp_repr_css_write_string(style);
it->elem->getRepr()->setAttribute("style", style_string);
g_free(style_string);
+
} else {
g_assert(0); // shouldn't happen
}
diff --git a/src/ui/cache/svg_preview_cache.cpp b/src/ui/cache/svg_preview_cache.cpp
index f8a806a13..7842bd5b3 100644
--- a/src/ui/cache/svg_preview_cache.cpp
+++ b/src/ui/cache/svg_preview_cache.cpp
@@ -121,6 +121,14 @@ GdkPixbuf* SvgPreview::get_preview(const gchar* uri, const gchar* id, Inkscape::
return px;
}
+void SvgPreview::remove_preview_from_cache(const Glib::ustring& key) {
+ std::map<Glib::ustring, GdkPixbuf *>::iterator found = _pixmap_cache.find(key);
+ if ( found != _pixmap_cache.end() ) {
+ _pixmap_cache.erase(key);
+ }
+}
+
+
}
}
}
diff --git a/src/ui/cache/svg_preview_cache.h b/src/ui/cache/svg_preview_cache.h
index 11d26fe22..b04a82350 100644
--- a/src/ui/cache/svg_preview_cache.h
+++ b/src/ui/cache/svg_preview_cache.h
@@ -40,6 +40,7 @@ class SvgPreview {
GdkPixbuf* get_preview_from_cache(const Glib::ustring& key);
void set_preview_in_cache(const Glib::ustring& key, GdkPixbuf* px);
GdkPixbuf* get_preview(const gchar* uri, const gchar* id, Inkscape::DrawingItem *root, double scale_factor, unsigned int psize);
+ void remove_preview_from_cache(const Glib::ustring& key);
};
}; // namespace Cache
diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp
index 0e4d7fd56..d72cde42e 100644
--- a/src/ui/dialog/inkscape-preferences.cpp
+++ b/src/ui/dialog/inkscape-preferences.cpp
@@ -1073,6 +1073,18 @@ void InkscapePreferences::initPageBehavior()
_page_behavior.add_line( false, _("Simplification threshold:"), _misc_simpl, "",
_("How strong is the Node tool's Simplify command by default. If you invoke this command several times in quick succession, it will act more and more aggressively; invoking it again after a pause restores the default threshold."), false);
+ _markers_color_stock.init ( _("Color stock markers the same color as object"), "/options/markers/colorStockMarkers", true);
+ _markers_color_custom.init ( _("Color custom markers the same color as object"), "/options/markers/colorCustomMarkers", false);
+ _markers_color_update.init ( _("Update marker color when object color changes"), "/options/markers/colorUpdateMarkers", true);
+
+ _page_behavior.add_group_header( _("Markers"));
+ _page_behavior.add_line( true, "", _markers_color_stock, "",
+ _("Stroke color same as object, fill color either object fill color or marker fill color"));
+ _page_behavior.add_line( true, "", _markers_color_custom, "",
+ _("Stroke color same as object, fill color either object fill color or marker fill color"));
+ _page_behavior.add_line( true, "", _markers_color_update, "",
+ _("Update marker color when object color changes"));
+
// Selecting options
_sel_all.init ( _("Select in all layers"), "/options/kbselection/inlayer", PREFS_SELECTION_ALL, false, 0);
_sel_current.init ( _("Select only within current layer"), "/options/kbselection/inlayer", PREFS_SELECTION_LAYER, true, &_sel_all);
diff --git a/src/ui/dialog/inkscape-preferences.h b/src/ui/dialog/inkscape-preferences.h
index 6d13b9d20..c78eb08d8 100644
--- a/src/ui/dialog/inkscape-preferences.h
+++ b/src/ui/dialog/inkscape-preferences.h
@@ -281,6 +281,10 @@ protected:
UI::Widget::PrefCheckButton _sel_layer_deselects;
UI::Widget::PrefCheckButton _sel_cycle;
+ UI::Widget::PrefCheckButton _markers_color_stock;
+ UI::Widget::PrefCheckButton _markers_color_custom;
+ UI::Widget::PrefCheckButton _markers_color_update;
+
UI::Widget::PrefSpinButton _importexport_export_res;
UI::Widget::PrefSpinButton _importexport_import_res;
UI::Widget::PrefSlider _snap_delay;
diff --git a/src/widgets/stroke-marker-selector.cpp b/src/widgets/stroke-marker-selector.cpp
index cada81f7b..ad14e8510 100644
--- a/src/widgets/stroke-marker-selector.cpp
+++ b/src/widgets/stroke-marker-selector.cpp
@@ -40,6 +40,8 @@
#include <gtkmm/adjustment.h>
#include "ui/widget/spinbutton.h"
+#include "stroke-style.h"
+#include "gradient-chemistry.h"
static Inkscape::UI::Cache::SvgPreview svg_preview_cache;
@@ -205,20 +207,8 @@ void MarkerComboBox::set_current(SPObject *marker)
updating = true;
if (marker != NULL) {
- bool mark_is_stock = false;
- if (marker->getRepr()->attribute("inkscape:stockid")) {
- mark_is_stock = true;
- }
-
- gchar *markname = 0;
- if (mark_is_stock) {
- markname = g_strdup(marker->getRepr()->attribute("inkscape:stockid"));
- } else {
- markname = g_strdup(marker->getRepr()->attribute("id"));
- }
-
+ gchar *markname = g_strdup(marker->getRepr()->attribute("id"));
set_selected(markname);
-
g_free (markname);
}
else {
@@ -253,7 +243,7 @@ const gchar * MarkerComboBox::get_active_marker_uri()
{
markurn = g_strdup(markid);
}
- SPObject *mark = get_stock_item(markurn);
+ SPObject *mark = get_stock_item(markurn, stockid);
g_free(markurn);
if (mark) {
Inkscape::XML::Node *repr = mark->getRepr();
@@ -266,9 +256,22 @@ const gchar * MarkerComboBox::get_active_marker_uri()
return marker;
}
+bool MarkerComboBox::isSelectedStock()
+{
+ return get_active()->get_value(marker_columns.stock);
+}
void MarkerComboBox::set_active_history() {
- set_selected(get_active()->get_value(marker_columns.marker));
+
+ const gchar *markid = get_active()->get_value(marker_columns.marker);
+
+ // If forked from a stockid, add the stockid
+ SPObject const *marker = doc->getObjectById(markid);
+ if (marker && marker->getRepr()->attribute("inkscape:stockid")) {
+ markid = marker->getRepr()->attribute("inkscape:stockid");
+ }
+
+ set_selected(markid);
}
@@ -399,10 +402,10 @@ void MarkerComboBox::add_markers (GSList *marker_list, SPDocument *source, gbool
for (; marker_list != NULL; marker_list = marker_list->next) {
Inkscape::XML::Node *repr = reinterpret_cast<SPItem *>(marker_list->data)->getRepr();
- gchar const *markid = repr->attribute("id");
+ gchar const *markid = repr->attribute("inkscape:stockid") ? repr->attribute("inkscape:stockid") : repr->attribute("id");
// generate preview
- Gtk::Image *prv = create_marker_image (22, markid, source, drawing, visionkey);
+ Gtk::Image *prv = create_marker_image (22, repr->attribute("id"), source, drawing, visionkey);
prv->show();
// Add history before separator, others after
@@ -413,8 +416,10 @@ void MarkerComboBox::add_markers (GSList *marker_list, SPDocument *source, gbool
row = *(marker_store->append());
row[marker_columns.label] = gr_ellipsize_text(markid, 20);
+ // Non "stock" markers can also have "inkscape:stockid" (when using extension ColorMarkers),
+ // So use !is_history instead to determine is it is "stock" (ie in the markers.svg file)
row[marker_columns.stock] = !history;
- row[marker_columns.marker] = g_strdup(markid);
+ row[marker_columns.marker] = repr->attribute("id");
row[marker_columns.image] = prv;
row[marker_columns.history] = history;
row[marker_columns.separator] = false;
@@ -424,6 +429,35 @@ void MarkerComboBox::add_markers (GSList *marker_list, SPDocument *source, gbool
sandbox->getRoot()->invoke_hide(visionkey);
}
+/*
+ * Remove from the cache and recreate a marker image
+ */
+void
+MarkerComboBox::update_marker_image(gchar const *mname)
+{
+ gchar *cache_name = g_strconcat(combo_id, mname, NULL);
+ Glib::ustring key = svg_preview_cache.cache_key(doc->getURI(), cache_name, 22);
+ g_free (cache_name);
+ svg_preview_cache.remove_preview_from_cache(key);
+
+ Inkscape::Drawing drawing;
+ unsigned const visionkey = SPItem::display_key_new(1);
+ drawing.setRoot(sandbox->getRoot()->invoke_show(drawing, visionkey, SP_ITEM_SHOW_DISPLAY));
+ Gtk::Image *prv = create_marker_image(22, mname, doc, drawing, visionkey);
+ prv->show();
+ sandbox->getRoot()->invoke_hide(visionkey);
+
+ for(Gtk::TreeIter iter = marker_store->children().begin();
+ iter != marker_store->children().end(); ++iter) {
+ Gtk::TreeModel::Row row = (*iter);
+ if (row[marker_columns.marker] && row[marker_columns.history] &&
+ !strcmp(row[marker_columns.marker], mname)) {
+ row[marker_columns.image] = prv;
+ return;
+ }
+ }
+
+}
/**
* Creates a copy of the marker named mname, determines its visible and renderable
* area in the bounding box, and then renders it. This allows us to fill in
@@ -456,6 +490,38 @@ MarkerComboBox::create_marker_image(unsigned psize, gchar const *mname,
Inkscape::GC::release(mrepr);
+ // If the marker color is a url link to a pattern or gradient copy that too
+ SPObject *mk = source->getObjectById(mname);
+ SPCSSAttr *css_marker = sp_css_attr_from_object(mk->firstChild(), SP_STYLE_FLAG_ALWAYS);
+ //const char *mfill = sp_repr_css_property(css_marker, "fill", "none");
+ const char *mstroke = sp_repr_css_property(css_marker, "fill", "none");
+
+ if (!strncmp (mstroke, "url(", 4)) {
+ SPObject *linkObj = getMarkerObj(mstroke, source);
+ if (linkObj) {
+ Inkscape::XML::Node *grepr = linkObj->getRepr()->duplicate(xml_doc);
+ SPObject *oldmarker = sandbox->getObjectById(linkObj->getId());
+ if (oldmarker) {
+ oldmarker->deleteObject(false);
+ }
+ defsrepr->appendChild(grepr);
+ Inkscape::GC::release(grepr);
+
+ if (SP_IS_GRADIENT(linkObj)) {
+ SPGradient *vector = sp_gradient_get_forked_vector_if_necessary (SP_GRADIENT(linkObj), false);
+ if (vector) {
+ Inkscape::XML::Node *grepr = vector->getRepr()->duplicate(xml_doc);
+ SPObject *oldmarker = sandbox->getObjectById(vector->getId());
+ if (oldmarker) {
+ oldmarker->deleteObject(false);
+ }
+ defsrepr->appendChild(grepr);
+ Inkscape::GC::release(grepr);
+ }
+ }
+ }
+ }
+
// Uncomment this to get the sandbox documents saved (useful for debugging)
//FILE *fp = fopen (g_strconcat(combo_id, mname, ".svg", NULL), "w");
//sp_repr_save_stream(sandbox->getReprDoc(), fp);
diff --git a/src/widgets/stroke-marker-selector.h b/src/widgets/stroke-marker-selector.h
index 9f79b7c1e..14c5ad758 100644
--- a/src/widgets/stroke-marker-selector.h
+++ b/src/widgets/stroke-marker-selector.h
@@ -45,6 +45,8 @@ public:
const gchar *get_active_marker_uri();
bool update() { return updating; };
gchar const *get_id() { return combo_id; };
+ bool isSelectedStock();
+ void update_marker_image(gchar const *mname);
private:
diff --git a/src/widgets/stroke-style.cpp b/src/widgets/stroke-style.cpp
index 695c16ced..2c39945f7 100644
--- a/src/widgets/stroke-style.cpp
+++ b/src/widgets/stroke-style.cpp
@@ -18,6 +18,10 @@
#define noSP_SS_VERBOSE
#include "stroke-style.h"
+#include "../gradient-chemistry.h"
+#include "sp-gradient.h"
+#include "sp-stop.h"
+#include "svg/svg-color.h"
using Inkscape::DocumentUndo;
@@ -45,6 +49,42 @@ void sp_stroke_style_widget_set_desktop(Gtk::Widget *widget, SPDesktop *desktop)
}
}
+
+/**
+ * Extract the actual name of the link
+ * e.g. get mTriangle from url(#mTriangle).
+ * \return Buffer containing the actual name, allocated from GLib;
+ * the caller should free the buffer when they no longer need it.
+ */
+SPObject* getMarkerObj(gchar const *n, SPDocument *doc)
+{
+ gchar const *p = n;
+ while (*p != '\0' && *p != '#') {
+ p++;
+ }
+
+ if (*p == '\0' || p[1] == '\0') {
+ return NULL;
+ }
+
+ p++;
+ int c = 0;
+ while (p[c] != '\0' && p[c] != ')') {
+ c++;
+ }
+
+ if (p[c] == '\0') {
+ return NULL;
+ }
+
+ gchar* b = g_strdup(p);
+ b[c] = '\0';
+
+ // FIXME: get the document from the object and let the caller pass it in
+ SPObject *marker = doc->getObjectById(b);
+ return marker;
+}
+
namespace Inkscape {
/**
@@ -331,7 +371,6 @@ StrokeStyle::makeRadioButton(Gtk::RadioButton *tb, char const *icon,
tb->show();
tb->set_mode(false);
hb->pack_start(*tb, false, false, 0);
- // TODO
set_data(icon, tb);
tb->set_data(key, (gpointer*)data);
@@ -359,6 +398,8 @@ StrokeStyle::markerSelectCB(MarkerComboBox *marker_combo, StrokeStyle *spw, SPMa
return;
}
+ spw->update = true;
+
SPDocument *document = sp_desktop_document(spw->desktop);
if (!document) {
return;
@@ -367,6 +408,7 @@ StrokeStyle::markerSelectCB(MarkerComboBox *marker_combo, StrokeStyle *spw, SPMa
/* Get Marker */
gchar const *marker = marker_combo->get_active_marker_uri();
+
SPCSSAttr *css = sp_repr_css_attr_new();
gchar const *combo_id = marker_combo->get_id();
sp_repr_css_set_property(css, combo_id, marker);
@@ -374,7 +416,7 @@ StrokeStyle::markerSelectCB(MarkerComboBox *marker_combo, StrokeStyle *spw, SPMa
// Also update the marker combobox, so the document's markers
// show up at the top of the combobox
// sp_stroke_style_line_update( SP_WIDGET(spw), desktop ? sp_desktop_selection(desktop) : NULL);
- spw->updateMarkerHist(which);
+ //spw->updateMarkerHist(which);
Inkscape::Selection *selection = sp_desktop_selection(spw->desktop);
GSList const *items = selection->itemList();
@@ -386,7 +428,14 @@ StrokeStyle::markerSelectCB(MarkerComboBox *marker_combo, StrokeStyle *spw, SPMa
Inkscape::XML::Node *selrepr = item->getRepr();
if (selrepr) {
sp_repr_css_change_recursive(selrepr, css, "style");
+ SPObject *markerObj = getMarkerObj(marker, document);
+ if (!marker_combo->isSelectedStock()) {
+ // If arrow, marker will already be forked
+ markerObj = spw->forkMarker(item, markerObj, marker_combo);
+ }
+ spw->setMarkerColor(item, markerObj, marker_combo);
}
+
item->requestModified(SP_OBJECT_MODIFIED_FLAG);
item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
}
@@ -397,6 +446,8 @@ StrokeStyle::markerSelectCB(MarkerComboBox *marker_combo, StrokeStyle *spw, SPMa
DocumentUndo::done(document, SP_VERB_DIALOG_FILL_STROKE,
_("Set markers"));
+ spw->update = false;
+
};
void
@@ -518,6 +569,191 @@ StrokeStyle::selectionChangedCB()
updateLine();
}
+/*
+ * Make a new copy of a marker, set as auto collectable
+ * Set the referencing items url to the new marker
+ * Return the new marker
+ */
+SPObject *
+StrokeStyle::forkMarker(SPItem *item, SPObject *marker, MarkerComboBox *marker_combo)
+{
+
+ if (!item || !marker) {
+ return NULL;
+ }
+
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gboolean colorStock = prefs->getBool("/options/markers/colorStockMarkers", true);
+ gboolean colorCustom = prefs->getBool("/options/markers/colorCustomMarkers", false);
+ const gchar *stock = marker->getRepr()->attribute("inkscape:isstock");
+ gboolean isStock = (!stock || !strcmp(stock,"true"));
+ gchar const *combo_id = marker_combo->get_id();
+
+ if (isStock ? !colorStock : !colorCustom) {
+ return marker;
+ }
+
+
+ /*
+ * Optimization
+ * If this item already has this marker elsewhere (start/mid or end),
+ * then we can reuse it and dont need to fork
+ */
+ SPCSSAttr *css = sp_css_attr_from_object(item, SP_STYLE_FLAG_ALWAYS);
+ Glib::ustring urlId = Glib::ustring::format("url(#", marker->getRepr()->attribute("id"), ")");
+ const gchar *markers[3] = { "marker-start", "marker-mid", "marker-end" };
+ //gboolean exists = false;
+ for (int i = 0; i < 3; i++) {
+ if (!strcmp(marker_combo->get_id(), markers[i])) {
+ continue;
+ }
+ const char *urlMark = sp_repr_css_property(css, markers[i], "");
+ if (!strcmp(urlId.c_str(), urlMark)) {
+ return marker;
+ }
+ }
+
+
+ SPDocument *doc = SP_ACTIVE_DOCUMENT;
+ SPDefs *defs = doc->getDefs();
+ Inkscape::XML::Document *xml_doc = doc->getReprDoc();
+ // Turn off garbage-collectable or it might be collected before we can use it
+ marker->getRepr()->setAttribute("inkscape:collect", NULL);
+ Inkscape::XML::Node *mark_repr = marker->getRepr()->duplicate(xml_doc);
+ defs->getRepr()->addChild(mark_repr, NULL);
+ gchar const *markid = marker->getRepr()->attribute("inkscape:stockid") ? marker->getRepr()->attribute("inkscape:stockid") : marker->getRepr()->attribute("id");
+ mark_repr->setAttribute("inkscape:stockid", markid);
+
+ // Update the items url to new marker
+ SPCSSAttr *css_item = sp_repr_css_attr_new();
+ sp_repr_css_set_property(css_item, combo_id, g_strconcat("url(#", mark_repr->attribute("id"), ")", NULL));
+ sp_repr_css_change_recursive(item->getRepr(), css_item, "style");
+
+ // privates are garbage-collectable
+ mark_repr->setAttribute("inkscape:collect", "always");
+ marker->getRepr()->setAttribute("inkscape:collect", "always");
+
+ Inkscape::GC::release(mark_repr);
+ sp_repr_css_attr_unref(css_item);
+ css_item = 0;
+
+ return doc->getObjectById(mark_repr->attribute("id"));
+}
+
+/**
+ * Change the color of the marker to match the color of the item.
+ * Marker stroke color is set to item stroke color.
+ * Fill color :
+ * 1. If the item has fill, use that for the marker fill,
+ * 2. If the marker has same fill and stroke assume its solid, use item stroke for both fill and stroke the line stroke
+ * 3. If the marker has fill color, use the marker fill color
+ *
+ */
+void
+StrokeStyle::setMarkerColor(SPItem *item, SPObject *marker, MarkerComboBox *marker_combo)
+{
+
+ if (!item || !marker) {
+ return;
+ }
+
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gboolean colorStock = prefs->getBool("/options/markers/colorStockMarkers", true);
+ gboolean colorCustom = prefs->getBool("/options/markers/colorCustomMarkers", false);
+ const gchar *stock = marker->getRepr()->attribute("inkscape:isstock");
+ gboolean isStock = (stock && !strcmp(stock,"true"));
+
+ if (isStock ? !colorStock : !colorCustom) {
+ return;
+ }
+
+ Inkscape::XML::Node *repr = marker->getRepr()->firstChild();
+ if (!repr) {
+ return;
+ };
+
+ // Current line style
+ SPCSSAttr *css_item = sp_css_attr_from_object(item, SP_STYLE_FLAG_ALWAYS);
+ const char *lstroke = getItemColorForMarker(item, FOR_STROKE, marker_combo);
+ const char *lstroke_opacity = sp_repr_css_property(css_item, "stroke-opacity", "1");
+ const char *lfill = getItemColorForMarker(item, FOR_FILL, marker_combo);
+ const char *lfill_opacity = sp_repr_css_property(css_item, "fill-opacity", "1");
+
+ // Current marker style
+ SPCSSAttr *css_marker = sp_css_attr_from_object(marker->firstChild(), SP_STYLE_FLAG_ALWAYS);
+ const char *mfill = sp_repr_css_property(css_marker, "fill", "none");
+ const char *mstroke = sp_repr_css_property(css_marker, "fill", "none");
+
+ // Create new marker style with the lines stroke
+ SPCSSAttr *css = sp_repr_css_attr_new();
+
+ sp_repr_css_set_property(css, "stroke", lstroke);
+ sp_repr_css_set_property(css, "stroke-opacity", lstroke_opacity);
+
+ if (strcmp(lfill, "none") ) {
+ // 1. If the line has fill, use that for the marker fill
+ sp_repr_css_set_property(css, "fill", lfill);
+ sp_repr_css_set_property(css, "fill-opacity", lfill_opacity);
+ }
+ else if (mfill && mstroke && !strcmp(mfill, mstroke) && mfill[0] == '#' && strcmp(mfill, "#ffffff")) {
+ // 2. If the marker has same fill and stroke assume its solid. use line stroke for both fill and stroke the line stroke
+ sp_repr_css_set_property(css, "fill", lstroke);
+ sp_repr_css_set_property(css, "fill-opacity", lstroke_opacity);
+ }
+ else if (mfill && mfill[0] == '#' && strcmp(mfill, "#000000")) {
+ // 3. If the marker has fill color, use the marker fill color
+ sp_repr_css_set_property(css, "fill", mfill);
+ //sp_repr_css_set_property(css, "fill-opacity", mfill_opacity);
+ }
+
+ sp_repr_css_change_recursive(marker->firstChild()->getRepr(), css, "style");
+
+ // Tell the combos to update its image cache of this marker
+ gchar const *mid = marker->getRepr()->attribute("id");
+ startMarkerCombo->update_marker_image(mid);
+ midMarkerCombo->update_marker_image(mid);
+ endMarkerCombo->update_marker_image(mid);
+
+ sp_repr_css_attr_unref(css);
+ css = 0;
+
+
+}
+
+/*
+ * Get the fill or stroke color of the item
+ * If its a gradient, then return first or last stop color
+ */
+const char *
+StrokeStyle::getItemColorForMarker(SPItem *item, Inkscape::PaintTarget fill_or_stroke, MarkerComboBox *marker_combo)
+{
+ SPCSSAttr *css_item = sp_css_attr_from_object(item, SP_STYLE_FLAG_ALWAYS);
+ const char *color;
+ if (fill_or_stroke == FOR_FILL)
+ color = sp_repr_css_property(css_item, "fill", "none");
+ else
+ color = sp_repr_css_property(css_item, "stroke", "none");
+
+ if (!strncmp (color, "url(", 4)) {
+ // If the item has a gradient use the first stop color for the marker
+ SPGradient *grad = getGradient(item, fill_or_stroke);
+ if (grad) {
+ SPGradient *vector = grad->getVector(FALSE);
+ SPStop *stop = vector->getFirstStop();
+ if (marker_combo == endMarkerCombo) {
+ stop = sp_last_stop(vector);
+ }
+ if (stop) {
+ guint32 const c1 = sp_stop_get_rgba32(stop);
+ gchar c[64];
+ sp_svg_write_color(c, sizeof(c), c1);
+ color = g_strdup(c);
+ //lstroke_opacity = Glib::ustring::format(stop->opacity).c_str();
+ }
+ }
+ }
+ return color;
+}
/**
* Sets selector widgets' dash style from an SPStyle object.
*/
@@ -602,7 +838,6 @@ StrokeStyle::updateLine()
Inkscape::Selection *sel = desktop ? sp_desktop_selection(desktop) : NULL;
- // TODO
FillOrStroke kind = GPOINTER_TO_INT(get_data("kind")) ? FILL : STROKE;
// create temporary style
@@ -882,7 +1117,6 @@ void StrokeStyle::buttonToggledCB(Gtk::ToggleButton *tb, StrokeStyle *spw)
if (tb->get_active()) {
- // TODO
gchar const *join
= static_cast<gchar const *>(tb->get_data("join"));
gchar const *cap
@@ -988,10 +1222,22 @@ StrokeStyle::updateAllMarkers(GSList const *objects)
// If the object has this type of markers,
// Extract the name of the marker that the object uses
- SPObject *marker = getMarkerName(object->style->marker[keyloc[i].loc].value, object->document);
+ SPObject *marker = getMarkerObj(object->style->marker[keyloc[i].loc].value, object->document);
// Scroll the combobox to that marker
combo->set_current(marker);
+ // Set the marker color
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gboolean update = prefs->getBool("/options/markers/colorUpdateMarkers", true);
+
+ if (update) {
+ setMarkerColor(SP_ITEM(object), marker, combo);
+
+ SPDocument *document = sp_desktop_document(desktop);
+ DocumentUndo::done(document, SP_VERB_DIALOG_FILL_STROKE,
+ _("Set marker color"));
+ }
+
} else {
combo->set_current(NULL);
}
@@ -1000,41 +1246,6 @@ StrokeStyle::updateAllMarkers(GSList const *objects)
}
-/**
- * Extract the actual name of the link
- * e.g. get mTriangle from url(#mTriangle).
- * \return Buffer containing the actual name, allocated from GLib;
- * the caller should free the buffer when they no longer need it.
- */
-SPObject*
-StrokeStyle::getMarkerName(gchar const *n, SPDocument *doc)
-{
- gchar const *p = n;
- while (*p != '\0' && *p != '#') {
- p++;
- }
-
- if (*p == '\0' || p[1] == '\0') {
- return NULL;
- }
-
- p++;
- int c = 0;
- while (p[c] != '\0' && p[c] != ')') {
- c++;
- }
-
- if (p[c] == '\0') {
- return NULL;
- }
-
- gchar* b = g_strdup(p);
- b[c] = '\0';
-
- // FIXME: get the document from the object and let the caller pass it in
- SPObject *marker = doc->getObjectById(b);
- return marker;
-}
} // namespace Inkscape
diff --git a/src/widgets/stroke-style.h b/src/widgets/stroke-style.h
index fe06e5b81..546880bc2 100644
--- a/src/widgets/stroke-style.h
+++ b/src/widgets/stroke-style.h
@@ -35,6 +35,7 @@
#include "inkscape.h"
#include "io/sys.h"
#include "marker.h"
+#include "preferences.h"
#include "path-prefix.h"
#include "selection.h"
#include "sp-linear-gradient.h"
@@ -81,6 +82,8 @@ Gtk::Widget *sp_stroke_style_line_widget_new(void);
*/
void sp_stroke_style_widget_set_desktop(Gtk::Widget *widget, SPDesktop *desktop);
+SPObject *getMarkerObj(gchar const *n, SPDocument *doc);
+
namespace Inkscape {
class StrokeStyle : public Gtk::VBox
@@ -92,7 +95,7 @@ public:
private:
- SPObject *getMarkerName(gchar const *n, SPDocument *doc);
+
void updateLine();
void updateAllMarkers(GSList const *objects);
void updateMarkerHist(SPMarkerLoc const which);
@@ -103,6 +106,10 @@ private:
void setCapButtons(Gtk::ToggleButton *active);
void scaleLine();
void setScaledDash(SPCSSAttr *css, int ndash, double *dash, double offset, double scale);
+ void setMarkerColor(SPItem *item, SPObject *marker, MarkerComboBox *marker_combo);
+ SPObject *forkMarker(SPItem *item, SPObject *marker, MarkerComboBox *marker_combo);
+ const char *getItemColorForMarker(SPItem *item, Inkscape::PaintTarget fill_or_stroke, MarkerComboBox *marker_combo);
+
Gtk::RadioButton * makeRadioButton(Gtk::RadioButton *tb, char const *icon,
Gtk::HBox *hb, gchar const *key, gchar const *data);
static gboolean setStrokeWidthUnit(SPUnitSelector *,