summaryrefslogtreecommitdiffstats
path: root/src/widgets/stroke-marker-selector.cpp
diff options
context:
space:
mode:
authorMartin Owens <doctormo@gmail.com>2014-03-27 01:33:44 +0000
committerMartin Owens <doctormo@gmail.com>2014-03-27 01:33:44 +0000
commit5a4fb2325f60d292b47330f540b26a3279341c90 (patch)
treed2aa7967be25450b83e625025366c618101ae49f /src/widgets/stroke-marker-selector.cpp
parentThe Polar Arrange Tab of the Arrange Dialog now hides the parametric (diff)
parentRemove Snap menu item and improve grid menu item text (diff)
downloadinkscape-5a4fb2325f60d292b47330f540b26a3279341c90.tar.gz
inkscape-5a4fb2325f60d292b47330f540b26a3279341c90.zip
Commit a merge to trunk, with probabal errors
(bzr r11073.1.36)
Diffstat (limited to 'src/widgets/stroke-marker-selector.cpp')
-rw-r--r--src/widgets/stroke-marker-selector.cpp340
1 files changed, 248 insertions, 92 deletions
diff --git a/src/widgets/stroke-marker-selector.cpp b/src/widgets/stroke-marker-selector.cpp
index 9b2c3bb42..00b6b5c91 100644
--- a/src/widgets/stroke-marker-selector.cpp
+++ b/src/widgets/stroke-marker-selector.cpp
@@ -36,35 +36,39 @@
#include "sp-root.h"
#include "ui/cache/svg_preview_cache.h"
#include "helper/stock-items.h"
+#include "gradient-vector.h"
+#include <gtkmm/icontheme.h>
#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;
-MarkerComboBox::MarkerComboBox(gchar const *id) :
+MarkerComboBox::MarkerComboBox(gchar const *id, int l) :
Gtk::ComboBox(),
combo_id(id),
+ loc(l),
updating(false),
- is_history(false)
+ markerCount(0)
{
marker_store = Gtk::ListStore::create(marker_columns);
set_model(marker_store);
pack_start(image_renderer, false);
- pack_end(label_renderer, true);
- label_renderer.set_padding(5, 0);
- image_renderer.set_padding(5, 0);
- set_cell_data_func(label_renderer, sigc::mem_fun(*this, &MarkerComboBox::prepareLabelRenderer));
set_cell_data_func(image_renderer, sigc::mem_fun(*this, &MarkerComboBox::prepareImageRenderer));
gtk_combo_box_set_row_separator_func(GTK_COMBO_BOX(gobj()), MarkerComboBox::separator_cb, NULL, NULL);
- empty_image = new Gtk::Image();
+ empty_image = new Gtk::Image( Glib::wrap(
+ sp_pixbuf_new( Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON("no-marker") ) ) );
sandbox = ink_markers_preview_doc ();
desktop = inkscape_active_desktop();
doc = sp_desktop_document(desktop);
+ modified_connection = doc->getDefs()->connectModified( sigc::hide(sigc::hide(sigc::bind(sigc::ptr_fun(&MarkerComboBox::handleDefsModified), this))) );
+
init_combo();
show();
@@ -73,6 +77,62 @@ MarkerComboBox::MarkerComboBox(gchar const *id) :
MarkerComboBox::~MarkerComboBox() {
delete combo_id;
delete sandbox;
+
+ if (doc) {
+ modified_connection.disconnect();
+ }
+}
+
+void MarkerComboBox::setDesktop(SPDesktop *desktop)
+{
+ if (this->desktop != desktop) {
+
+ if (doc) {
+ modified_connection.disconnect();
+ }
+
+ this->desktop = desktop;
+ doc = sp_desktop_document(desktop);
+
+ if (doc) {
+ modified_connection = doc->getDefs()->connectModified( sigc::hide(sigc::hide(sigc::bind(sigc::ptr_fun(&MarkerComboBox::handleDefsModified), this))) );
+ }
+
+ refreshHistory();
+ }
+}
+
+void
+MarkerComboBox::handleDefsModified(MarkerComboBox *self)
+{
+ self->refreshHistory();
+}
+
+void
+MarkerComboBox::refreshHistory()
+{
+ if (updating)
+ return;
+
+ updating = true;
+
+ GSList *ml = get_marker_list(doc);
+
+ /*
+ * Seems to be no way to get notified of changes just to markers,
+ * so listen to changes in all defs and check if the number of markers has changed here
+ * to avoid unnecessary refreshes when things like gradients change
+ */
+ if (markerCount != g_slist_length(ml)) {
+ const char *active = get_active()->get_value(marker_columns.marker);
+ sp_marker_list_from_doc(doc, true);
+ set_selected(active);
+ markerCount = g_slist_length(ml);
+ }
+
+ g_slist_free (ml);
+
+ updating = false;
}
/**
@@ -81,12 +141,22 @@ MarkerComboBox::~MarkerComboBox() {
void
MarkerComboBox::init_combo()
{
- updating = false;
+ if (updating)
+ return;
+
+ const gchar *active = NULL;
+ if (get_active()) {
+ active = get_active()->get_value(marker_columns.marker);
+ }
if (!doc) {
Gtk::TreeModel::Row row = *(marker_store->append());
row[marker_columns.label] = _("No document selected");
+ row[marker_columns.marker] = g_strdup("None");
row[marker_columns.image] = NULL;
+ row[marker_columns.stock] = false;
+ row[marker_columns.history] = false;
+ row[marker_columns.separator] = false;
set_sensitive(false);
set_current(NULL);
return;
@@ -94,11 +164,17 @@ MarkerComboBox::init_combo()
static SPDocument *markers_doc = NULL;
- // add "None"
- Gtk::TreeModel::Row row = *(marker_store->append());
- row[marker_columns.label] = _("None");
- row[marker_columns.marker] = g_strdup("none");
- row[marker_columns.image] = NULL;
+ // add separator
+ Gtk::TreeModel::Row row_sep = *(marker_store->append());
+ row_sep[marker_columns.label] = "Separator";
+ row_sep[marker_columns.marker] = g_strdup("None");
+ row_sep[marker_columns.image] = NULL;
+ row_sep[marker_columns.stock] = false;
+ row_sep[marker_columns.history] = false;
+ row_sep[marker_columns.separator] = true;
+
+ // load markers from the current doc
+ sp_marker_list_from_doc(doc, true);
// find and load markers.svg
if (markers_doc == NULL) {
@@ -109,27 +185,17 @@ MarkerComboBox::init_combo()
g_free(markers_source);
}
- // suck in from current doc
- is_history = true;
- sp_marker_list_from_doc(doc);
- is_history = false;
-
- // add separator
- Gtk::TreeModel::Row row_sep = *(marker_store->append());
- row_sep[marker_columns.label] = "Separator";
- row_sep[marker_columns.isseparator] = true;
- row_sep[marker_columns.image] = NULL;
-
- // suck in from markers.svg
+ // load markers from markers.svg
if (markers_doc) {
doc->ensureUpToDate();
- sp_marker_list_from_doc(markers_doc);
+ sp_marker_list_from_doc(markers_doc, false);
}
set_sensitive(true);
/* Set history */
- set_current(NULL);
+ set_selected(active);
+
}
/**
@@ -140,20 +206,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 {
@@ -177,7 +231,7 @@ const gchar * MarkerComboBox::get_active_marker_uri()
gchar const *marker = "";
if (strcmp(markid, "none")) {
- bool stockid = get_active()->get_value(marker_columns.isstock);
+ bool stockid = get_active()->get_value(marker_columns.stock);
gchar *markurn;
if (stockid)
@@ -188,7 +242,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();
@@ -201,13 +255,21 @@ const gchar * MarkerComboBox::get_active_marker_uri()
return marker;
}
-
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);
}
-void MarkerComboBox::set_selected(const gchar *name) {
+void MarkerComboBox::set_selected(const gchar *name, gboolean retry/*=true*/) {
if (!name) {
set_active(0);
@@ -220,42 +282,23 @@ void MarkerComboBox::set_selected(const gchar *name) {
if (row[marker_columns.marker] &&
!strcmp(row[marker_columns.marker], name)) {
set_active(iter);
- if (strcmp(name, "none"))
- set_history(row);
return;
}
}
-}
-void MarkerComboBox::set_history(Gtk::TreeModel::Row match_row) {
-
- if (!match_row) {
- return;
- }
-
- for(Gtk::TreeIter iter = marker_store->children().begin();
- iter != marker_store->children().end(); ++iter) {
- Gtk::TreeModel::Row row = (*iter);
- if (row[marker_columns.history] &&
- !strcmp(row[marker_columns.marker], match_row[marker_columns.marker])) {
- return;
- }
+ // Didn't find it in the list, try refreshing from the doc
+ if (retry) {
+ sp_marker_list_from_doc(doc, true);
+ set_selected(name, false);
}
-
- // Add a new row to the history
- Gtk::TreeModel::Row row = *(marker_store->insert_after(marker_store->children().begin()));
- row[marker_columns.marker] = g_strdup(match_row.get_value(marker_columns.marker));
- row[marker_columns.label] = match_row.get_value(marker_columns.label);
- row[marker_columns.isstock] = match_row.get_value(marker_columns.isstock);
- row[marker_columns.image] = match_row.get_value(marker_columns.image);
- row[marker_columns.history] = true;
}
+
/**
* Pick up all markers from source, except those that are in
* current_doc (if non-NULL), and add items to the combo.
*/
-void MarkerComboBox::sp_marker_list_from_doc(SPDocument *source)
+void MarkerComboBox::sp_marker_list_from_doc(SPDocument *source, gboolean history)
{
GSList *ml = get_marker_list(source);
GSList *clean_ml = NULL;
@@ -267,10 +310,14 @@ void MarkerComboBox::sp_marker_list_from_doc(SPDocument *source)
// Add to the list of markers we really do wish to show
clean_ml = g_slist_prepend (clean_ml, ml->data);
}
- add_markers(clean_ml, source);
+
+ remove_markers(history); // Seem to need to remove 2x
+ remove_markers(history);
+ add_markers(clean_ml, source, history);
g_slist_free (ml);
g_slist_free (clean_ml);
+
}
/**
@@ -284,6 +331,10 @@ GSList *MarkerComboBox::get_marker_list (SPDocument *source)
GSList *ml = NULL;
SPDefs *defs = source->getDefs();
+ if (!defs) {
+ return NULL;
+ }
+
for ( SPObject *child = defs->firstChild(); child; child = child->getNext() )
{
if (SP_IS_MARKER(child)) {
@@ -294,37 +345,115 @@ GSList *MarkerComboBox::get_marker_list (SPDocument *source)
}
/**
- * Adds previews of markers in marker_list to the combo
+ * Remove history or non-history markers from the combo
+ */
+void MarkerComboBox::remove_markers (gboolean history)
+{
+ // Having the model set causes assertions when erasing rows, temporarily disconnect
+ unset_model();
+ for(Gtk::TreeIter iter = marker_store->children().begin();
+ iter != marker_store->children().end(); ++iter) {
+ Gtk::TreeModel::Row row = (*iter);
+ if (row[marker_columns.history] == history && row[marker_columns.separator] == false) {
+ marker_store->erase(iter);
+ iter = marker_store->children().begin();
+ }
+ }
+
+ set_model(marker_store);
+}
+
+/**
+ * Adds markers in marker_list to the combo
*/
-void MarkerComboBox::add_markers (GSList *marker_list, SPDocument *source)
+void MarkerComboBox::add_markers (GSList *marker_list, SPDocument *source, gboolean history)
{
// Do this here, outside of loop, to speed up preview generation:
Inkscape::Drawing drawing;
unsigned const visionkey = SPItem::display_key_new(1);
drawing.setRoot(sandbox->getRoot()->invoke_show(drawing, visionkey, SP_ITEM_SHOW_DISPLAY));
+ // Find the separator,
+ Gtk::TreeIter sep_iter;
+ for(Gtk::TreeIter iter = marker_store->children().begin();
+ iter != marker_store->children().end(); ++iter) {
+ Gtk::TreeModel::Row row = (*iter);
+ if (row[marker_columns.separator]) {
+ sep_iter = iter;
+ }
+ }
+
+ if (history) {
+ // add "None"
+ Gtk::TreeModel::Row row = *(marker_store->prepend());
+ row[marker_columns.label] = _("None");
+ row[marker_columns.stock] = false;
+ row[marker_columns.marker] = g_strdup("None");
+ row[marker_columns.image] = NULL;
+ row[marker_columns.history] = true;
+ row[marker_columns.separator] = false;
+ }
for (; marker_list != NULL; marker_list = marker_list->next) {
Inkscape::XML::Node *repr = reinterpret_cast<SPItem *>(marker_list->data)->getRepr();
- bool isstock = (repr->attribute("inkscape:stockid"));
- 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();
- Gtk::TreeModel::Row row = *(marker_store->append());
- row[marker_columns.label] = g_strdup(markid);
- row[marker_columns.marker] = g_strdup(markid);
- row[marker_columns.isstock] = isstock;
+ // Add history before separator, others after
+ Gtk::TreeModel::Row row;
+ if (history)
+ row = *(marker_store->insert(sep_iter));
+ else
+ 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] = repr->attribute("id");
row[marker_columns.image] = prv;
- row[marker_columns.history] = is_history;
+ row[marker_columns.history] = history;
+ row[marker_columns.separator] = false;
}
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);
+ if (prv) {
+ 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
@@ -357,6 +486,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);
@@ -383,24 +544,19 @@ MarkerComboBox::create_marker_image(unsigned psize, gchar const *mname,
gchar *cache_name = g_strconcat(combo_id, mname, NULL);
Glib::ustring key = svg_preview_cache.cache_key(source->getURI(), cache_name, psize);
g_free (cache_name);
- Glib::RefPtr<Gdk::Pixbuf> pixbuf = Glib::wrap(svg_preview_cache.get_preview_from_cache(key));
+ GdkPixbuf *pixbuf = svg_preview_cache.get_preview_from_cache(key); // no ref created
if (!pixbuf) {
- pixbuf = Glib::wrap(render_pixbuf(drawing, 0.8, *dbox, psize));
- svg_preview_cache.set_preview_in_cache(key, pixbuf->gobj());
+ pixbuf = render_pixbuf(drawing, 0.8, *dbox, psize);
+ svg_preview_cache.set_preview_in_cache(key, pixbuf);
+ g_object_unref(pixbuf); // reference is held by svg_preview_cache
}
// Create widget
- Gtk::Image *pb = new Gtk::Image(pixbuf);
-
+ Gtk::Image *pb = Glib::wrap(GTK_IMAGE(gtk_image_new_from_pixbuf(pixbuf)));
return pb;
}
-void MarkerComboBox::prepareLabelRenderer( Gtk::TreeModel::const_iterator const &row ) {
- Glib::ustring name=(*row)[marker_columns.label];
- label_renderer.property_markup() = name.c_str();
-}
-
void MarkerComboBox::prepareImageRenderer( Gtk::TreeModel::const_iterator const &row ) {
Gtk::Image *image = (*row)[marker_columns.image];
@@ -413,7 +569,7 @@ void MarkerComboBox::prepareImageRenderer( Gtk::TreeModel::const_iterator const
gboolean MarkerComboBox::separator_cb (GtkTreeModel *model, GtkTreeIter *iter, gpointer /*data*/) {
gboolean sep = FALSE;
- gtk_tree_model_get(model, iter, 5, &sep, -1);
+ gtk_tree_model_get(model, iter, 4, &sep, -1);
return sep;
}