=== modified file 'src/helper/stock-items.cpp' --- src/helper/stock-items.cpp 2012-08-04 02:20:42 +0000 +++ src/helper/stock-items.cpp 2012-08-14 12:31:15 +0000 @@ -173,7 +173,7 @@ // 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 @@ 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 @@ } } - 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 @@ } } - 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 @@ g_free(base); g_free(name); + if (object) { + object->getRepr()->setAttribute("inkscape:isstock", "true"); + } + return object; } === modified file 'src/helper/stock-items.h' --- src/helper/stock-items.h 2011-12-08 11:53:54 +0000 +++ src/helper/stock-items.h 2012-08-13 06:41:39 +0000 @@ -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 === modified file 'src/ui/cache/svg_preview_cache.cpp' --- src/ui/cache/svg_preview_cache.cpp 2011-12-08 11:53:54 +0000 +++ src/ui/cache/svg_preview_cache.cpp 2012-08-14 12:32:11 +0000 @@ -121,6 +121,14 @@ return px; } +void SvgPreview::remove_preview_from_cache(const Glib::ustring& key) { + std::map::iterator found = _pixmap_cache.find(key); + if ( found != _pixmap_cache.end() ) { + _pixmap_cache.erase(key); + } +} + + } } } === modified file 'src/ui/cache/svg_preview_cache.h' --- src/ui/cache/svg_preview_cache.h 2011-10-04 19:04:58 +0000 +++ src/ui/cache/svg_preview_cache.h 2012-08-14 03:44:05 +0000 @@ -40,6 +40,7 @@ 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 === modified file 'src/ui/dialog/inkscape-preferences.cpp' --- src/ui/dialog/inkscape-preferences.cpp 2012-07-23 18:34:01 +0000 +++ src/ui/dialog/inkscape-preferences.cpp 2012-08-13 09:59:06 +0000 @@ -1066,6 +1066,18 @@ _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); === modified file 'src/ui/dialog/inkscape-preferences.h' --- src/ui/dialog/inkscape-preferences.h 2012-07-23 18:34:01 +0000 +++ src/ui/dialog/inkscape-preferences.h 2012-08-13 09:59:03 +0000 @@ -281,6 +281,10 @@ 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; === modified file 'src/widgets/stroke-marker-selector.cpp' --- src/widgets/stroke-marker-selector.cpp 2012-08-07 13:35:25 +0000 +++ src/widgets/stroke-marker-selector.cpp 2012-08-14 12:13:21 +0000 @@ -40,6 +40,8 @@ #include #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 @@ 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 @@ { 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 @@ 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 @@ for (; marker_list != NULL; marker_list = marker_list->next) { Inkscape::XML::Node *repr = reinterpret_cast(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 @@ 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 @@ 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 @@ 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); === modified file 'src/widgets/stroke-marker-selector.h' --- src/widgets/stroke-marker-selector.h 2012-08-07 13:35:25 +0000 +++ src/widgets/stroke-marker-selector.h 2012-08-14 12:12:45 +0000 @@ -45,6 +45,8 @@ 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: === modified file 'src/widgets/stroke-style.cpp' --- src/widgets/stroke-style.cpp 2012-08-04 02:20:42 +0000 +++ src/widgets/stroke-style.cpp 2012-08-14 12:36:25 +0000 @@ -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 @@ } } + +/** + * 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 @@ 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 @@ return; } + spw->update = true; + SPDocument *document = sp_desktop_document(spw->desktop); if (!document) { return; @@ -367,6 +408,7 @@ /* 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 @@ // 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,16 @@ Inkscape::XML::Node *selrepr = item->getRepr(); if (selrepr) { sp_repr_css_change_recursive(selrepr, css, "style"); + if (marker_combo->isSelectedStock()) { + // If stock, marker will already be forked + spw->setMarkerColor(item, getMarkerObj(marker, document), marker_combo, !marker_combo->isSelectedStock()); + } + else { + // If not stock, keep the same color + spw->forkMarker(item, getMarkerObj(marker, document), marker_combo); + } } + item->requestModified(SP_OBJECT_MODIFIED_FLAG); item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); } @@ -397,6 +448,8 @@ DocumentUndo::done(document, SP_VERB_DIALOG_FILL_STROKE, _("Set markers")); + spw->update = false; + }; void @@ -518,6 +571,156 @@ updateLine(); } +/* + * Make a new copy of a marker + * Set as auto collectible + * Set the refereencing items url to the new marker + */ +void +StrokeStyle::forkMarker(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")); + gchar const *combo_id = marker_combo->get_id(); + + if (isStock ? !colorStock : !colorCustom) { + return; + } + + SPDocument *doc = SP_ACTIVE_DOCUMENT; + SPDefs *defs = doc->getDefs(); + Inkscape::XML::Document *xml_doc = doc->getReprDoc(); + 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); + // privates are garbage-collectable + mark_repr->setAttribute("inkscape:collect", "always"); + + // 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"); + + Inkscape::GC::release(mark_repr); +} +/** + * 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, gboolean fork) +{ + + 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) { + + // 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); //sp_repr_css_property(css_item, "stroke", "none"); + const char *lstroke_opacity = sp_repr_css_property(css_item, "stroke-opacity", "1"); + const char *lfill = getItemColorForMarker(item, FOR_FILL, marker_combo); //sp_repr_css_property(css_item, "fill", "none"); + 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 + startMarkerCombo->update_marker_image(marker->getRepr()->attribute("id")); + midMarkerCombo->update_marker_image(marker->getRepr()->attribute("id")); + endMarkerCombo->update_marker_image(marker->getRepr()->attribute("id")); + + } + +} + +/* + * 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 line stroke is 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 +805,6 @@ 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 +1084,6 @@ if (tb->get_active()) { - // TODO gchar const *join = static_cast(tb->get_data("join")); gchar const *cap @@ -988,10 +1189,18 @@ // 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, false); + } + } else { combo->set_current(NULL); } @@ -1000,41 +1209,6 @@ } -/** - * 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 === modified file 'src/widgets/stroke-style.h' --- src/widgets/stroke-style.h 2012-08-04 01:55:39 +0000 +++ src/widgets/stroke-style.h 2012-08-14 08:53:31 +0000 @@ -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 @@ */ 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 @@ private: - SPObject *getMarkerName(gchar const *n, SPDocument *doc); + void updateLine(); void updateAllMarkers(GSList const *objects); void updateMarkerHist(SPMarkerLoc const which); @@ -103,6 +106,10 @@ 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, gboolean update); + void 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 *,