index 378198f050532b169931b24926e14d6fe71ff264..373ee5832e43583ea01fd3c8b74df06092da6077 100644 (file)
*
* Authors:
* Lauris Kaplinski <lauris@kaplinski.com>
- * Bryce Harrington <brycehar@bryceharrington.com>
+ * Bryce Harrington <brycehar@bryceharrington.org>
* bulia byak <buliabyak@users.sf.net>
*
* Copyright (C) 2001-2005 authors
#include "widgets/spw-utilities.h"
#include "sp-linear-gradient.h"
#include "sp-radial-gradient.h"
-#include "sp-marker.h"
-#include <sp-pattern.h>
-#include <widgets/paint-selector.h>
-#include <widgets/dash-selector.h>
+#include "marker.h"
+#include "sp-pattern.h"
+#include "widgets/paint-selector.h"
+#include "widgets/dash-selector.h"
#include "style.h"
#include "gradient-chemistry.h"
#include "sp-namedview.h"
#include "widgets/icon.h"
#include "helper/stock-items.h"
#include "io/sys.h"
+#include "ui/cache/svg_preview_cache.h"
#include "dialogs/stroke-style.h"
+
/* Paint */
static void sp_stroke_style_paint_construct(SPWidget *spw, SPPaintSelector *psel);
static void sp_stroke_style_paint_changed(SPPaintSelector *psel, SPWidget *spw);
static void sp_stroke_style_widget_change_subselection ( Inkscape::Application *inkscape, SPDesktop *desktop, SPWidget *spw );
+static void sp_stroke_style_widget_transientize_callback(Inkscape::Application *inkscape,
+ SPDesktop *desktop,
+ SPWidget *spw );
+
+/** Marker selection option menus */
+static GtkWidget * marker_start_menu = NULL;
+static GtkWidget * marker_mid_menu = NULL;
+static GtkWidget * marker_end_menu = NULL;
+
+static SPObject *ink_extract_marker_name(gchar const *n);
+static void ink_markers_menu_update(SPWidget* spw);
+static Inkscape::UI::Cache::SvgPreview svg_preview_cache;
+
+/**
+ * Create the stroke style widget, and hook up all the signals.
+ */
GtkWidget *
sp_stroke_style_paint_widget_new(void)
{
g_signal_connect (INKSCAPE, "change_subselection", G_CALLBACK (sp_stroke_style_widget_change_subselection), spw);
+ g_signal_connect (G_OBJECT(INKSCAPE), "activate_desktop", G_CALLBACK (sp_stroke_style_widget_transientize_callback), spw );
+
gtk_signal_connect(GTK_OBJECT(psel), "mode_changed",
GTK_SIGNAL_FUNC(sp_stroke_style_paint_mode_changed),
spw);
return spw;
}
+/**
+ * On construction, simply does an update of the stroke style paint object.
+ */
static void
-sp_stroke_style_paint_construct(SPWidget *spw, SPPaintSelector *psel)
+sp_stroke_style_paint_construct(SPWidget *spw, SPPaintSelector */*psel*/)
{
#ifdef SP_SS_VERBOSE
g_print( "Stroke style widget constructed: inkscape %p repr %p\n",
#endif
if (spw->inkscape) {
sp_stroke_style_paint_update (spw);
- }
+ }
}
+/**
+ * On signal modified, invokes an update of the stroke style paint object.
+ */
static void
-sp_stroke_style_paint_selection_modified ( SPWidget *spw,
- Inkscape::Selection *selection,
- guint flags,
- SPPaintSelector *psel)
+sp_stroke_style_paint_selection_modified( SPWidget *spw,
+ Inkscape::Selection */*selection*/,
+ guint flags,
+ SPPaintSelector */*psel*/ )
{
if (flags & ( SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_PARENT_MODIFIED_FLAG |
SP_OBJECT_STYLE_MODIFIED_FLAG) ) {
}
+/**
+ * On signal selection changed, invokes an update of the stroke style paint object.
+ */
static void
-sp_stroke_style_paint_selection_changed ( SPWidget *spw,
- Inkscape::Selection *selection,
- SPPaintSelector *psel )
+sp_stroke_style_paint_selection_changed( SPWidget *spw,
+ Inkscape::Selection */*selection*/,
+ SPPaintSelector */*psel*/ )
{
sp_stroke_style_paint_update (spw);
}
+
+/**
+ * On signal change subselection, invoke an update of the stroke style widget.
+ */
static void
-sp_stroke_style_widget_change_subselection ( Inkscape::Application *inkscape,
- SPDesktop *desktop,
- SPWidget *spw )
+sp_stroke_style_widget_change_subselection( Inkscape::Application */*inkscape*/,
+ SPDesktop */*desktop*/,
+ SPWidget *spw )
{
sp_stroke_style_paint_update (spw);
}
+/**
+ * Gets the active stroke style property, then sets the appropriate color, alpha, gradient,
+ * pattern, etc. for the paint-selector.
+ */
static void
sp_stroke_style_paint_update (SPWidget *spw)
{
SPPaintSelector *psel = SP_PAINT_SELECTOR(gtk_object_get_data(GTK_OBJECT(spw), "paint-selector"));
// create temporary style
- SPStyle *query = sp_style_new ();
+ SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT);
// query into it
- int result = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_STROKE);
+ int result = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_STROKE);
switch (result) {
case QUERY_STYLE_NOTHING:
SPPaintSelectorMode pselmode = sp_style_determine_paint_selector_mode (query, false);
sp_paint_selector_set_mode (psel, pselmode);
- if (query->stroke.set && query->stroke.type == SP_PAINT_TYPE_COLOR) {
- gfloat d[3];
- sp_color_get_rgb_floatv (&query->stroke.value.color, d);
- SPColor color;
- sp_color_set_rgb_float (&color, d[0], d[1], d[2]);
- sp_paint_selector_set_color_alpha (psel, &color, SP_SCALE24_TO_FLOAT (query->stroke_opacity.value));
-
- } else if (query->stroke.set && query->stroke.type == SP_PAINT_TYPE_PAINTSERVER) {
+ if (query->stroke.set && query->stroke.isPaintserver()) {
SPPaintServer *server = SP_STYLE_STROKE_SERVER (query);
SPPattern *pat = pattern_getroot (SP_PATTERN (server));
sp_update_pattern_list (psel, pat);
}
+ } else if (query->stroke.set && query->stroke.isColor()) {
+ sp_paint_selector_set_color_alpha (psel, &query->stroke.value.color, SP_SCALE24_TO_FLOAT (query->stroke_opacity.value));
+
}
break;
}
}
}
- g_free (query);
+ sp_style_unref(query);
gtk_object_set_data(GTK_OBJECT(spw), "update", GINT_TO_POINTER(FALSE));
}
+/**
+ * When the mode is changed, invoke a regular changed handler.
+ */
static void
sp_stroke_style_paint_mode_changed( SPPaintSelector *psel,
- SPPaintSelectorMode mode,
+ SPPaintSelectorMode /*mode*/,
SPWidget *spw )
{
if (gtk_object_get_data(GTK_OBJECT(spw), "update")) {
sp_stroke_style_paint_changed(psel, spw);
}
-static gchar *undo_label_1 = "stroke:flatcolor:1";
-static gchar *undo_label_2 = "stroke:flatcolor:2";
-static gchar *undo_label = undo_label_1;
+static gchar const *const undo_label_1 = "stroke:flatcolor:1";
+static gchar const *const undo_label_2 = "stroke:flatcolor:2";
+static gchar const *undo_label = undo_label_1;
+/**
+ * When a drag callback occurs on a paint selector object, if it is a RGB or CMYK
+ * color mode, then set the stroke opacity to psel's flat color.
+ */
static void
sp_stroke_style_paint_dragged(SPPaintSelector *psel, SPWidget *spw)
{
case SP_PAINT_SELECTOR_MODE_COLOR_CMYK:
{
sp_paint_selector_set_flat_color (psel, SP_ACTIVE_DESKTOP, "stroke", "stroke-opacity");
- sp_document_maybe_done (sp_desktop_document(SP_ACTIVE_DESKTOP), undo_label, SP_VERB_DIALOG_FILL_STROKE,
+ sp_document_maybe_done (sp_desktop_document(SP_ACTIVE_DESKTOP), undo_label, SP_VERB_DIALOG_FILL_STROKE,
_("Set stroke color"));
break;
}
}
}
+/**
+ * When the stroke style's paint settings change, this handler updates the
+ * repr's stroke css style and applies the style to relevant drawing items.
+ */
static void
sp_stroke_style_paint_changed(SPPaintSelector *psel, SPWidget *spw)
{
sp_repr_css_attr_unref(css);
- sp_document_done(document, SP_VERB_DIALOG_FILL_STROKE,
+ sp_document_done(document, SP_VERB_DIALOG_FILL_STROKE,
_("Remove stroke"));
break;
}
case SP_PAINT_SELECTOR_MODE_COLOR_CMYK:
{
sp_paint_selector_set_flat_color (psel, desktop, "stroke", "stroke-opacity");
- sp_document_maybe_done (sp_desktop_document(desktop), undo_label, SP_VERB_DIALOG_FILL_STROKE,
+ sp_document_maybe_done (sp_desktop_document(desktop), undo_label, SP_VERB_DIALOG_FILL_STROKE,
_("Set stroke color"));
// on release, toggle undo_label so that the next drag will not be lumped with this one
if (undo_label == undo_label_1)
undo_label = undo_label_2;
- else
+ else
undo_label = undo_label_1;
break;
if (!vector) {
/* No vector in paint selector should mean that we just changed mode */
- SPStyle *query = sp_style_new ();
- int result = objects_query_fillstroke ((GSList *) items, query, false);
+ SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT);
+ int result = objects_query_fillstroke ((GSList *) items, query, false);
guint32 common_rgb = 0;
if (result == QUERY_STYLE_MULTIPLE_SAME) {
- if (query->fill.type != SP_PAINT_TYPE_COLOR) {
+ if (!query->fill.isColor()) {
common_rgb = sp_desktop_get_color(desktop, false);
} else {
- common_rgb = sp_color_get_rgba32_ualpha(&query->stroke.value.color, 0xff);
+ common_rgb = query->stroke.value.color.toRGBA32( 0xff );
}
vector = sp_document_default_gradient_vector(document, common_rgb);
}
- g_free (query);
+ sp_style_unref(query);
for (GSList const *i = items; i != NULL; i = i->next) {
if (!vector) {
- sp_item_set_gradient(SP_ITEM(i->data),
+ sp_item_set_gradient(SP_ITEM(i->data),
sp_gradient_vector_for_object(document, desktop, SP_OBJECT(i->data), false),
gradient_type, false);
} else {
}
}
- sp_document_done(document, SP_VERB_DIALOG_FILL_STROKE,
+ sp_document_done(document, SP_VERB_DIALOG_FILL_STROKE,
_("Set gradient on stroke"));
}
break;
continue;
SPStyle *style = SP_OBJECT_STYLE (selobj);
- if (style && style->stroke.type == SP_PAINT_TYPE_PAINTSERVER) {
+ if (style && style->stroke.isPaintserver()) {
SPObject *server = SP_OBJECT_STYLE_STROKE_SERVER (selobj);
if (SP_IS_PATTERN (server) && pattern_getroot (SP_PATTERN(server)) == pattern)
// only if this object's pattern is not rooted in our selected pattern, apply
} // end if
- sp_document_done (document, SP_VERB_DIALOG_FILL_STROKE,
+ sp_document_done (document, SP_VERB_DIALOG_FILL_STROKE,
_("Set pattern on stroke"));
} // end if
if (items) {
SPCSSAttr *css = sp_repr_css_attr_new ();
sp_repr_css_unset_property (css, "stroke");
+ sp_repr_css_unset_property (css, "stroke-opacity");
+ sp_repr_css_unset_property (css, "stroke-width");
+ sp_repr_css_unset_property (css, "stroke-miterlimit");
+ sp_repr_css_unset_property (css, "stroke-linejoin");
+ sp_repr_css_unset_property (css, "stroke-linecap");
+ sp_repr_css_unset_property (css, "stroke-dashoffset");
+ sp_repr_css_unset_property (css, "stroke-dasharray");
sp_desktop_set_style (desktop, css);
sp_repr_css_attr_unref (css);
- sp_document_done (document, SP_VERB_DIALOG_FILL_STROKE,
+ sp_document_done (document, SP_VERB_DIALOG_FILL_STROKE,
_("Unset stroke"));
}
break;
static void sp_stroke_style_update_marker_menus(SPWidget *spw, GSList const *objects);
-static SPObject *ink_extract_marker_name(gchar const *n);
-
/**
* Helper function for creating radio buttons. This should probably be re-thought out
}
+static void
+sp_stroke_style_widget_transientize_callback(Inkscape::Application */*inkscape*/,
+ SPDesktop */*desktop*/,
+ SPWidget */*spw*/ )
+{
+// TODO: Either of these will cause crashes sometimes
+// sp_stroke_style_line_update( SP_WIDGET(spw), desktop ? sp_desktop_selection(desktop) : NULL);
+// ink_markers_menu_update(spw);
+}
+
+/**
+ * Creates a copy of the marker named mname, determines its visible and renderable
+ * area in menu_id's bounding box, and then renders it. This allows us to fill in
+ * preview images of each marker in the marker menu.
+ */
static GtkWidget *
-sp_marker_prev_new(unsigned size, gchar const *mname,
+sp_marker_prev_new(unsigned psize, gchar const *mname,
SPDocument *source, SPDocument *sandbox,
- gchar *menu_id, NRArena const *arena, unsigned visionkey, NRArenaItem *root)
+ gchar const *menu_id, NRArena const */*arena*/, unsigned /*visionkey*/, NRArenaItem *root)
{
- // the object of the marker
+ // Retrieve the marker named 'mname' from the source SVG document
SPObject const *marker = source->getObjectById(mname);
if (marker == NULL)
return NULL;
- // the repr of the marker; make a copy with id="sample"
- Inkscape::XML::Node *mrepr = SP_OBJECT_REPR (marker)->duplicate();
+ // Create a copy repr of the marker with id="sample"
+ Inkscape::XML::Document *xml_doc = sp_document_repr_doc(sandbox);
+ Inkscape::XML::Node *mrepr = SP_OBJECT_REPR (marker)->duplicate(xml_doc);
mrepr->setAttribute("id", "sample");
- // replace the old sample in the sandbox by the new one
+ // Replace the old sample in the sandbox by the new one
Inkscape::XML::Node *defsrepr = SP_OBJECT_REPR (sandbox->getObjectById("defs"));
SPObject *oldmarker = sandbox->getObjectById("sample");
if (oldmarker)
Inkscape::GC::release(mrepr);
// Uncomment this to get the sandbox documents saved (useful for debugging)
- //FILE *fp = fopen (g_strconcat(mname, ".svg", NULL), "w");
+ //FILE *fp = fopen (g_strconcat(menu_id, mname, ".svg", NULL), "w");
//sp_repr_save_stream (sp_document_repr_doc (sandbox), fp);
//fclose (fp);
return NULL; // sandbox broken?
// Find object's bbox in document
- NR::Matrix const i2doc(sp_item_i2doc_affine(SP_ITEM(object)));
-
- NR::Rect const dbox = SP_ITEM(object)->invokeBbox(i2doc);
+ Geom::Matrix const i2doc(sp_item_i2doc_affine(SP_ITEM(object)));
+ boost::optional<NR::Rect> dbox = SP_ITEM(object)->getBounds(i2doc);
- if (dbox.isEmpty()) {
+ if (!dbox) {
return NULL;
}
/* Update to renderable state */
- NRMatrix t;
double sf = 0.8;
- nr_matrix_set_scale(&t, sf, sf);
- nr_arena_item_set_transform(root, &t);
- NRGC gc(NULL);
- nr_matrix_set_identity(&gc.transform);
- nr_arena_item_invoke_update( root, NULL, &gc,
- NR_ARENA_ITEM_STATE_ALL,
- NR_ARENA_ITEM_STATE_NONE );
-
- /* Item integer bbox in points */
- NRRectL ibox;
- ibox.x0 = (int) floor(sf * dbox.min()[NR::X] + 0.5);
- ibox.y0 = (int) floor(sf * dbox.min()[NR::Y] + 0.5);
- ibox.x1 = (int) floor(sf * dbox.max()[NR::X] + 0.5);
- ibox.y1 = (int) floor(sf * dbox.max()[NR::Y] + 0.5);
-
- /* Find visible area */
- int width = ibox.x1 - ibox.x0;
- int height = ibox.y1 - ibox.y0;
- int dx = size;
- int dy = size;
- dx=(dx - width)/2; // watch out for size, since 'unsigned'-'signed' can cause problems if the result is negative
- dy=(dy - height)/2;
-
- NRRectL area;
- area.x0 = ibox.x0 - dx;
- area.y0 = ibox.y0 - dy;
- area.x1 = area.x0 + size;
- area.y1 = area.y0 + size;
-
- /* Actual renderable area */
- NRRectL ua;
- ua.x0 = MAX(ibox.x0, area.x0);
- ua.y0 = MAX(ibox.y0, area.y0);
- ua.x1 = MIN(ibox.x1, area.x1);
- ua.y1 = MIN(ibox.y1, area.y1);
-
- /* Set up pixblock */
- guchar *px = g_new(guchar, 4 * size * size);
- memset(px, 0x00, 4 * size * size);
-
- /* Render */
- NRPixBlock B;
- nr_pixblock_setup_extern( &B, NR_PIXBLOCK_MODE_R8G8B8A8N,
- ua.x0, ua.y0, ua.x1, ua.y1,
- px + 4 * size * (ua.y0 - area.y0) +
- 4 * (ua.x0 - area.x0),
- 4 * size, FALSE, FALSE );
- nr_arena_item_invoke_render( root, &ua, &B,
- NR_ARENA_ITEM_RENDER_NO_CACHE );
- nr_pixblock_release(&B);
+ GdkPixbuf* pixbuf = NULL;
+
+ gchar *cache_name = g_strconcat(menu_id, mname, NULL);
+ Glib::ustring key = svg_preview_cache.cache_key(source->uri, cache_name, psize);
+ g_free (cache_name);
+ pixbuf = svg_preview_cache.get_preview_from_cache(key);
+
+ if (pixbuf == NULL) {
+ pixbuf = render_pixbuf(root, sf, to_2geom(*dbox), psize);
+ svg_preview_cache.set_preview_in_cache(key, pixbuf);
+ }
// Create widget
- GtkWidget *pb = gtk_image_new_from_pixbuf(gdk_pixbuf_new_from_data(px,
- GDK_COLORSPACE_RGB,
- TRUE,
- 8, size, size, size * 4,
- (GdkPixbufDestroyNotify)g_free,
- NULL));
+ GtkWidget *pb = gtk_image_new_from_pixbuf(pixbuf);
+
return pb;
}
-#define MARKER_ITEM_MARGIN 0
-
-
/**
- * sp_marker_list_from_doc()
- *
- * \brief Pick up all markers from source, except those that are in
- * current_doc (if non-NULL), and add items to the m menu
- *
+ * Returns a list of markers in the defs of the given source document as a GSList object
+ * Returns NULL if there are no markers in the document.
*/
-static void
-sp_marker_list_from_doc (GtkWidget *m, SPDocument *current_doc, SPDocument *source, SPDocument *markers_doc, SPDocument *sandbox, gchar *menu_id)
+GSList *
+ink_marker_list_get (SPDocument *source)
{
+ if (source == NULL)
+ return NULL;
- // search through defs
- GSList *ml = NULL;
- SPDefs *defs= (SPDefs *) SP_DOCUMENT_DEFS (source);
- for ( SPObject *ochild = sp_object_first_child(SP_OBJECT(defs)) ; ochild != NULL ; ochild = SP_OBJECT_NEXT (ochild) ) {
- if (SP_IS_MARKER(ochild)) {
- ml = g_slist_prepend (ml, ochild);
+ GSList *ml = NULL;
+ SPDefs *defs = (SPDefs *) SP_DOCUMENT_DEFS (source);
+ for ( SPObject *child = sp_object_first_child(SP_OBJECT(defs));
+ child != NULL;
+ child = SP_OBJECT_NEXT (child) )
+ {
+ if (SP_IS_MARKER(child)) {
+ ml = g_slist_prepend (ml, child);
}
}
+ return ml;
+}
+#define MARKER_ITEM_MARGIN 0
+
+/**
+ * Adds previews of markers in marker_list to the given menu widget
+ */
+static void
+sp_marker_menu_build (GtkWidget *m, GSList *marker_list, SPDocument *source, SPDocument *sandbox, gchar const *menu_id)
+{
// Do this here, outside of loop, to speed up preview generation:
- /* Create new arena */
NRArena const *arena = NRArena::create();
- /* Create ArenaItem and set transform */
unsigned const visionkey = sp_item_display_key_new(1);
NRArenaItem *root = sp_item_invoke_show( SP_ITEM(SP_DOCUMENT_ROOT (sandbox)), (NRArena *) arena, visionkey, SP_ITEM_SHOW_DISPLAY );
- for (; ml != NULL; ml = ml->next) {
-
- if (!SP_IS_MARKER(ml->data))
- continue;
-
- Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) ml->data);
-
- bool stock_dupe = false;
-
- if (markers_doc && repr->attribute("inkscape:stockid")) {
- // find out if markers_doc has a marker with the same stockid, and if so, skip this
- for (SPObject *child = sp_object_first_child(SP_OBJECT(SP_DOCUMENT_DEFS(markers_doc))) ;
- child != NULL;
- child = SP_OBJECT_NEXT(child) )
- {
- if (SP_IS_MARKER(child) &&
- SP_OBJECT_REPR(child)->attribute("inkscape:stockid") &&
- !strcmp(repr->attribute("inkscape:stockid"), SP_OBJECT_REPR(child)->attribute("inkscape:stockid"))) {
- stock_dupe = true;
- }
- }
- }
-
- if (stock_dupe) // stock item, dont add to list from current doc
- continue;
-
+ for (; marker_list != NULL; marker_list = marker_list->next) {
+ Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) marker_list->data);
GtkWidget *i = gtk_menu_item_new();
gtk_widget_show(i);
@@ -693,6 +695,7 @@ sp_marker_list_from_doc (GtkWidget *m, SPDocument *current_doc, SPDocument *sour
gtk_widget_show(hb);
// generate preview
+
GtkWidget *prv = sp_marker_prev_new (22, markid, source, sandbox, menu_id, arena, visionkey, root);
gtk_widget_show(prv);
gtk_box_pack_start(GTK_BOX(hb), prv, FALSE, FALSE, 6);
@@ -709,11 +712,38 @@ sp_marker_list_from_doc (GtkWidget *m, SPDocument *current_doc, SPDocument *sour
gtk_menu_append(GTK_MENU(m), i);
}
+}
+
+/**
+ * sp_marker_list_from_doc()
+ *
+ * \brief Pick up all markers from source, except those that are in
+ * current_doc (if non-NULL), and add items to the m menu
+ *
+ */
+static void
+sp_marker_list_from_doc (GtkWidget *m, SPDocument */*current_doc*/, SPDocument *source, SPDocument */*markers_doc*/, SPDocument *sandbox, gchar const *menu_id)
+{
+ GSList *ml = ink_marker_list_get(source);
+ GSList *clean_ml = NULL;
+
+ for (; ml != NULL; ml = ml->next) {
+ if (!SP_IS_MARKER(ml->data))
+ continue;
+
+ // Add to the list of markers we really do wish to show
+ clean_ml = g_slist_prepend (clean_ml, ml->data);
+ }
+ sp_marker_menu_build (m, clean_ml, source, sandbox, menu_id);
g_slist_free (ml);
+ g_slist_free (clean_ml);
}
+/**
+ * Returns a new document containing default start, mid, and end markers.
+ */
SPDocument *
ink_markers_preview_doc ()
{
@@ -746,10 +776,63 @@ gchar const *buffer = "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:sodipodi=
return sp_document_new_from_mem (buffer, strlen(buffer), FALSE);
}
+static void
+ink_marker_menu_create_menu(GtkWidget *m, gchar const *menu_id, SPDocument *doc, SPDocument *sandbox)
+{
+ static SPDocument *markers_doc = NULL;
+
+ // add "None"
+ GtkWidget *i = gtk_menu_item_new();
+ gtk_widget_show(i);
+ g_object_set_data(G_OBJECT(i), "marker", (void *) "none");
+ GtkWidget *hb = gtk_hbox_new(FALSE, MARKER_ITEM_MARGIN);
+ gtk_widget_show(hb);
+
+ GtkWidget *l = gtk_label_new( _("None") );
+ gtk_widget_show(l);
+ gtk_misc_set_alignment(GTK_MISC(l), 0.0, 0.5);
+
+ gtk_box_pack_start(GTK_BOX(hb), l, TRUE, TRUE, 0);
+
+ gtk_widget_show(hb);
+ gtk_container_add(GTK_CONTAINER(i), hb);
+ gtk_menu_append(GTK_MENU(m), i);
+
+ // find and load markers.svg
+ if (markers_doc == NULL) {
+ char *markers_source = g_build_filename(INKSCAPE_MARKERSDIR, "markers.svg", NULL);
+ if (Inkscape::IO::file_test(markers_source, G_FILE_TEST_IS_REGULAR)) {
+ markers_doc = sp_document_new(markers_source, FALSE);
+ }
+ g_free(markers_source);
+ }
+
+ // suck in from current doc
+ sp_marker_list_from_doc ( m, NULL, doc, markers_doc, sandbox, menu_id );
+
+ // add separator
+ {
+ GtkWidget *i = gtk_separator_menu_item_new();
+ gtk_widget_show(i);
+ gtk_menu_append(GTK_MENU(m), i);
+ }
+
+ // suck in from markers.svg
+ if (markers_doc) {
+ sp_document_ensure_up_to_date(doc);
+ sp_marker_list_from_doc ( m, doc, markers_doc, NULL, sandbox, menu_id );
+ }
+
+}
+
+
+/**
+ * Creates a menu widget to display markers from markers.svg
+ */
static GtkWidget *
-ink_marker_menu( GtkWidget *tbl, gchar *menu_id, SPDocument *sandbox)
+ink_marker_menu( GtkWidget */*tbl*/, gchar const *menu_id, SPDocument *sandbox)
{
SPDesktop *desktop = inkscape_active_desktop();
SPDocument *doc = sp_desktop_document(desktop);
gtk_widget_set_sensitive(mnu, FALSE);
} else {
-
- // add "None"
- {
- GtkWidget *i = gtk_menu_item_new();
- gtk_widget_show(i);
-
- g_object_set_data(G_OBJECT(i), "marker", (void *) "none");
-
- GtkWidget *hb = gtk_hbox_new(FALSE, MARKER_ITEM_MARGIN);
- gtk_widget_show(hb);
-
- GtkWidget *l = gtk_label_new( _("None") );
- gtk_widget_show(l);
- gtk_misc_set_alignment(GTK_MISC(l), 0.0, 0.5);
-
- gtk_box_pack_start(GTK_BOX(hb), l, TRUE, TRUE, 0);
-
- gtk_widget_show(hb);
- gtk_container_add(GTK_CONTAINER(i), hb);
- gtk_menu_append(GTK_MENU(m), i);
- }
-
- // find and load markers.svg
- static SPDocument *markers_doc = NULL;
- char *markers_source = g_build_filename(INKSCAPE_MARKERSDIR, "markers.svg", NULL);
- if (Inkscape::IO::file_test(markers_source, G_FILE_TEST_IS_REGULAR)) {
- markers_doc = sp_document_new(markers_source, FALSE);
- }
- g_free(markers_source);
-
- // suck in from current doc
- sp_marker_list_from_doc ( m, NULL, doc, markers_doc, sandbox, menu_id );
-
- // add separator
- {
- GtkWidget *i = gtk_separator_menu_item_new();
- gtk_widget_show(i);
- gtk_menu_append(GTK_MENU(m), i);
- }
-
- // suck in from markers.svg
- if (markers_doc) {
- sp_document_ensure_up_to_date(doc);
- sp_marker_list_from_doc ( m, doc, markers_doc, NULL, sandbox, menu_id );
- }
+ ink_marker_menu_create_menu(m, menu_id, doc, sandbox);
gtk_widget_set_sensitive(mnu, TRUE);
}
- gtk_object_set_data(GTK_OBJECT(mnu), "menu_id", menu_id);
+ gtk_object_set_data(GTK_OBJECT(mnu), "menu_id", const_cast<gchar *>(menu_id));
gtk_option_menu_set_menu(GTK_OPTION_MENU(mnu), m);
/* Set history */
}
-/*user selected existing marker from list*/
+/**
+ * Handles when user selects one of the markers from the marker menu.
+ * Defines a uri string to refer to it, then applies it to all selected
+ * items in the current desktop.
+ */
static void
sp_marker_select(GtkOptionMenu *mnu, GtkWidget *spw)
{
}
gchar *markid = (gchar *) g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))),
"marker");
- gchar *marker = "";
+ gchar const *marker = "";
if (strcmp(markid, "none")){
gchar *stockid = (gchar *) g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))),
"stockid");
}
SPCSSAttr *css = sp_repr_css_attr_new();
- gchar *menu_id = (gchar *) g_object_get_data(G_OBJECT(mnu), "menu_id");
+ gchar const *menu_id = (gchar const *) g_object_get_data(G_OBJECT(mnu), "menu_id");
sp_repr_css_set_property(css, menu_id, marker);
- Inkscape::Selection *selection = sp_desktop_selection(desktop);
- GSList const *items = selection->itemList();
- for (; items != NULL; items = items->next) {
+ // Also update the marker dropdown menus, so the document's markers
+ // show up at the top of the menu
+// sp_stroke_style_line_update( SP_WIDGET(spw), desktop ? sp_desktop_selection(desktop) : NULL);
+ ink_markers_menu_update(SP_WIDGET(spw));
+
+ Inkscape::Selection *selection = sp_desktop_selection(desktop);
+ GSList const *items = selection->itemList();
+ for (; items != NULL; items = items->next) {
SPItem *item = (SPItem *) items->data;
if (!SP_IS_SHAPE(item) || SP_IS_RECT(item)) // can't set marker to rect, until it's converted to using <path>
continue;
sp_repr_css_attr_unref(css);
- sp_document_done(document, SP_VERB_DIALOG_FILL_STROKE,
+ sp_document_done(document, SP_VERB_DIALOG_FILL_STROKE,
_("Set markers"));
+
+};
+
+static int
+ink_marker_menu_get_pos(GtkMenu *mnu, gchar const *markname)
+{
+ if (markname == NULL)
+ markname = (gchar const *) g_object_get_data(G_OBJECT(gtk_menu_get_active(mnu)), "marker");
+
+ if (markname == NULL)
+ return 0;
+
+ GList const *kids = GTK_MENU_SHELL(mnu)->children;
+ int i = 0;
+ for (; kids != NULL; kids = kids->next) {
+ gchar const *mark = (gchar const *) g_object_get_data(G_OBJECT(kids->data), "marker");
+ if ( mark && strcmp(mark, markname) == 0 ) {
+ break;
+ }
+ i++;
+ }
+ return i;
+}
+
+static void
+ink_markers_menu_update(SPWidget* spw) {
+ SPDesktop *desktop = inkscape_active_desktop();
+ SPDocument *document = sp_desktop_document(desktop);
+ SPDocument *sandbox = ink_markers_preview_doc ();
+ GtkWidget *m;
+ int pos;
+
+ gtk_signal_handler_block_by_func( GTK_OBJECT(marker_start_menu), GTK_SIGNAL_FUNC(sp_marker_select), spw);
+ pos = ink_marker_menu_get_pos(GTK_MENU(gtk_option_menu_get_menu(GTK_OPTION_MENU(marker_start_menu))), NULL);
+ m = gtk_menu_new();
+ gtk_widget_show(m);
+ ink_marker_menu_create_menu(m, "marker-start", document, sandbox);
+ gtk_option_menu_remove_menu(GTK_OPTION_MENU(marker_start_menu));
+ gtk_option_menu_set_menu(GTK_OPTION_MENU(marker_start_menu), m);
+ gtk_option_menu_set_history(GTK_OPTION_MENU(marker_start_menu), pos);
+ gtk_signal_handler_unblock_by_func( GTK_OBJECT(marker_start_menu), GTK_SIGNAL_FUNC(sp_marker_select), spw);
+
+ gtk_signal_handler_block_by_func( GTK_OBJECT(marker_mid_menu), GTK_SIGNAL_FUNC(sp_marker_select), spw);
+ pos = ink_marker_menu_get_pos(GTK_MENU(gtk_option_menu_get_menu(GTK_OPTION_MENU(marker_mid_menu))), NULL);
+ m = gtk_menu_new();
+ gtk_widget_show(m);
+ ink_marker_menu_create_menu(m, "marker-mid", document, sandbox);
+ gtk_option_menu_remove_menu(GTK_OPTION_MENU(marker_mid_menu));
+ gtk_option_menu_set_menu(GTK_OPTION_MENU(marker_mid_menu), m);
+ gtk_option_menu_set_history(GTK_OPTION_MENU(marker_mid_menu), pos);
+ gtk_signal_handler_unblock_by_func( GTK_OBJECT(marker_mid_menu), GTK_SIGNAL_FUNC(sp_marker_select), spw);
+
+ gtk_signal_handler_block_by_func( GTK_OBJECT(marker_end_menu), GTK_SIGNAL_FUNC(sp_marker_select), spw);
+ pos = ink_marker_menu_get_pos(GTK_MENU(gtk_option_menu_get_menu(GTK_OPTION_MENU(marker_end_menu))), NULL);
+ m = gtk_menu_new();
+ gtk_widget_show(m);
+ ink_marker_menu_create_menu(m, "marker-end", document, sandbox);
+ gtk_option_menu_remove_menu(GTK_OPTION_MENU(marker_end_menu));
+ gtk_option_menu_set_menu(GTK_OPTION_MENU(marker_end_menu), m);
+ gtk_option_menu_set_history(GTK_OPTION_MENU(marker_end_menu), pos);
+ gtk_signal_handler_unblock_by_func( GTK_OBJECT(marker_end_menu), GTK_SIGNAL_FUNC(sp_marker_select), spw);
}
+/**
+ * Sets the stroke width units for all selected items.
+ * Also handles absolute and dimensionless units.
+ */
static gboolean stroke_width_set_unit(SPUnitSelector *,
SPUnit const *old,
SPUnit const *new_units,
// TRANSLATORS: Path markers are an SVG feature that allows you to attach arbitrary shapes
// (arrowheads, bullets, faces, whatever) to the start, end, or middle nodes of a path.
spw_label(t, _("Start Markers:"), 0, i);
- GtkWidget *mnu = ink_marker_menu( spw ,"marker-start", sandbox);
- gtk_signal_connect( GTK_OBJECT(mnu), "changed", GTK_SIGNAL_FUNC(sp_marker_select), spw );
- gtk_widget_show(mnu);
- gtk_table_attach( GTK_TABLE(t), mnu, 1, 4, i, i+1,
+ marker_start_menu = ink_marker_menu( spw ,"marker-start", sandbox);
+ gtk_signal_connect( GTK_OBJECT(marker_start_menu), "changed", GTK_SIGNAL_FUNC(sp_marker_select), spw );
+ gtk_widget_show(marker_start_menu);
+ gtk_table_attach( GTK_TABLE(t), marker_start_menu, 1, 4, i, i+1,
(GtkAttachOptions)( GTK_EXPAND | GTK_FILL ),
(GtkAttachOptions)0, 0, 0 );
- gtk_object_set_data(GTK_OBJECT(spw), "start_mark_menu", mnu);
+ gtk_object_set_data(GTK_OBJECT(spw), "start_mark_menu", marker_start_menu);
i++;
spw_label(t, _("Mid Markers:"), 0, i);
- mnu = NULL;
- mnu = ink_marker_menu( spw ,"marker-mid", sandbox);
- gtk_signal_connect( GTK_OBJECT(mnu), "changed", GTK_SIGNAL_FUNC(sp_marker_select), spw );
- gtk_widget_show(mnu);
- gtk_table_attach( GTK_TABLE(t), mnu, 1, 4, i, i+1,
+ marker_mid_menu = ink_marker_menu( spw ,"marker-mid", sandbox);
+ gtk_signal_connect( GTK_OBJECT(marker_mid_menu), "changed", GTK_SIGNAL_FUNC(sp_marker_select), spw );
+ gtk_widget_show(marker_mid_menu);
+ gtk_table_attach( GTK_TABLE(t), marker_mid_menu, 1, 4, i, i+1,
(GtkAttachOptions)( GTK_EXPAND | GTK_FILL ),
(GtkAttachOptions)0, 0, 0 );
- gtk_object_set_data(GTK_OBJECT(spw), "mid_mark_menu", mnu);
+ gtk_object_set_data(GTK_OBJECT(spw), "mid_mark_menu", marker_mid_menu);
i++;
spw_label(t, _("End Markers:"), 0, i);
- mnu = NULL;
- mnu = ink_marker_menu( spw ,"marker-end", sandbox);
- gtk_signal_connect( GTK_OBJECT(mnu), "changed", GTK_SIGNAL_FUNC(sp_marker_select), spw );
- gtk_widget_show(mnu);
- gtk_table_attach( GTK_TABLE(t), mnu, 1, 4, i, i+1,
+ marker_end_menu = ink_marker_menu( spw ,"marker-end", sandbox);
+ gtk_signal_connect( GTK_OBJECT(marker_end_menu), "changed", GTK_SIGNAL_FUNC(sp_marker_select), spw );
+ gtk_widget_show(marker_end_menu);
+ gtk_table_attach( GTK_TABLE(t), marker_end_menu, 1, 4, i, i+1,
(GtkAttachOptions)( GTK_EXPAND | GTK_FILL ),
(GtkAttachOptions)0, 0, 0 );
- gtk_object_set_data(GTK_OBJECT(spw), "end_mark_menu", mnu);
+ gtk_object_set_data(GTK_OBJECT(spw), "end_mark_menu", marker_end_menu);
i++;
}
-
+/**
+ * Callback for when the stroke style widget is called. It causes
+ * the stroke line style to be updated.
+ */
static void
-sp_stroke_style_line_construct(SPWidget *spw, gpointer data)
+sp_stroke_style_line_construct(SPWidget *spw, gpointer /*data*/)
{
-
#ifdef SP_SS_VERBOSE
g_print( "Stroke style widget constructed: inkscape %p repr %p\n",
spw->inkscape, spw->repr );
( SP_ACTIVE_DESKTOP
? sp_desktop_selection(SP_ACTIVE_DESKTOP)
: NULL ));
- }
+ }
}
+/**
+ * Callback for when stroke style widget is modified.
+ * Triggers update action.
+ */
static void
-sp_stroke_style_line_selection_modified ( SPWidget *spw,
- Inkscape::Selection *selection,
- guint flags,
- gpointer data )
+sp_stroke_style_line_selection_modified( SPWidget *spw,
+ Inkscape::Selection *selection,
+ guint flags,
+ gpointer /*data*/ )
{
if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_PARENT_MODIFIED_FLAG)) {
sp_stroke_style_line_update (spw, selection);
}
+/**
+ * Callback for when stroke style widget is changed.
+ * Triggers update action.
+ */
static void
-sp_stroke_style_line_selection_changed ( SPWidget *spw,
- Inkscape::Selection *selection,
- gpointer data )
+sp_stroke_style_line_selection_changed( SPWidget *spw,
+ Inkscape::Selection *selection,
+ gpointer /*data*/ )
{
sp_stroke_style_line_update (spw, selection);
}
+/**
+ * Sets selector widgets' dash style from an SPStyle object.
+ */
static void
sp_dash_selector_set_from_style (GtkWidget *dsel, SPStyle *style)
{
}
}
+/**
+ * Sets the join type for a line, and updates the stroke style widget's buttons
+ */
static void
sp_jointype_set (SPWidget *spw, unsigned const jointype)
{
sp_stroke_style_set_join_buttons (spw, tb);
}
+/**
+ * Sets the cap type for a line, and updates the stroke style widget's buttons
+ */
static void
sp_captype_set (SPWidget *spw, unsigned const captype)
{
sp_stroke_style_set_cap_buttons (spw, tb);
}
+/**
+ * Callback for when stroke style widget is updated, including markers, cap type,
+ * join type, etc.
+ */
static void
sp_stroke_style_line_update(SPWidget *spw, Inkscape::Selection *sel)
{
GtkWidget *dsel = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(spw), "dash"));
// create temporary style
- SPStyle *query = sp_style_new ();
+ SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT);
// query into it
- int result_sw = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_STROKEWIDTH);
- int result_ml = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_STROKEMITERLIMIT);
- int result_cap = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_STROKECAP);
- int result_join = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_STROKEJOIN);
+ int result_sw = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_STROKEWIDTH);
+ int result_ml = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_STROKEMITERLIMIT);
+ int result_cap = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_STROKECAP);
+ int result_join = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_STROKEJOIN);
if (result_sw == QUERY_STYLE_NOTHING) {
/* No objects stroked, set insensitive */
sp_stroke_style_set_cap_buttons(spw, NULL);
}
- g_free (query);
+ sp_style_unref(query);
+
+ if (!sel || sel->isEmpty())
+ return;
GSList const *objects = sel->itemList();
SPObject * const object = SP_OBJECT(objects->data);
GINT_TO_POINTER(FALSE));
}
+/**
+ * Sets a line's dash properties in a CSS style object.
+ */
static void
sp_stroke_style_set_scaled_dash(SPCSSAttr *css,
int ndash, double *dash, double offset,
}
}
+/**
+ * Sets line properties like width, dashes, markers, etc. on all currently selected items.
+ */
static void
sp_stroke_style_scale_line(SPWidget *spw)
{
sp_repr_css_attr_unref(css);
- sp_document_done(document, SP_VERB_DIALOG_FILL_STROKE,
+ sp_document_done(document, SP_VERB_DIALOG_FILL_STROKE,
_("Set stroke style"));
gtk_object_set_data(GTK_OBJECT(spw), "update", GINT_TO_POINTER(FALSE));
}
-
+/**
+ * Callback for when the stroke style's width changes.
+ * Causes all line styles to be applied to all selected items.
+ */
static void
-sp_stroke_style_width_changed(GtkAdjustment *adj, SPWidget *spw)
+sp_stroke_style_width_changed(GtkAdjustment */*adj*/, SPWidget *spw)
{
if (gtk_object_get_data(GTK_OBJECT(spw), "update")) {
return;
sp_stroke_style_scale_line(spw);
}
+/**
+ * Callback for when the stroke style's miterlimit changes.
+ * Causes all line styles to be applied to all selected items.
+ */
static void
-sp_stroke_style_miterlimit_changed(GtkAdjustment *adj, SPWidget *spw)
+sp_stroke_style_miterlimit_changed(GtkAdjustment */*adj*/, SPWidget *spw)
{
if (gtk_object_get_data(GTK_OBJECT(spw), "update")) {
return;
sp_stroke_style_scale_line(spw);
}
+/**
+ * Callback for when the stroke style's dash changes.
+ * Causes all line styles to be applied to all selected items.
+ */
static void
-sp_stroke_style_line_dash_changed(SPDashSelector *dsel, SPWidget *spw)
+sp_stroke_style_line_dash_changed(SPDashSelector */*dsel*/, SPWidget *spw)
{
if (gtk_object_get_data(GTK_OBJECT(spw), "update")) {
return;
}
+/**
+ * Updates the join style toggle buttons
+ */
static void
sp_stroke_style_set_join_buttons(SPWidget *spw, GtkWidget *active)
{
+/**
+ * Updates the cap style toggle buttons
+ */
static void
sp_stroke_style_set_cap_buttons(SPWidget *spw, GtkWidget *active)
{
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tb), (active == tb));
}
+/**
+ * Sets the current marker in the marker menu.
+ */
static void
ink_marker_menu_set_current(SPObject *marker, GtkOptionMenu *mnu)
{
else
markname = g_strdup(SP_OBJECT_REPR(marker)->attribute("id"));
- int markpos = 0;
- GList *kids = GTK_MENU_SHELL(m)->children;
- int i = 0;
- for (; kids != NULL; kids = kids->next) {
- gchar *mark = (gchar *) g_object_get_data(G_OBJECT(kids->data), "marker");
- if ( mark && strcmp(mark, markname) == 0 ) {
- if ( mark_is_stock && !strcmp((gchar *) g_object_get_data(G_OBJECT(kids->data), "stockid"), "true"))
- markpos = i;
- if ( !mark_is_stock && !strcmp((gchar *) g_object_get_data(G_OBJECT(kids->data), "stockid"), "false"))
- markpos = i;
- }
- i++;
- }
+ int markpos = ink_marker_menu_get_pos(m, markname);
gtk_option_menu_set_history(GTK_OPTION_MENU(mnu), markpos);
g_free (markname);
gtk_object_set_data(GTK_OBJECT(mnu), "update", GINT_TO_POINTER(FALSE));
}
+/**
+ * Updates the marker menus to highlight the appropriate marker and scroll to
+ * that marker.
+ */
static void
sp_stroke_style_update_marker_menus( SPWidget *spw,
GSList const *objects)
}
-/** Extract the actual name of the link
+/**
+ * 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.
gchar* b = g_strdup(p);
b[c] = '\0';
-
SPDesktop *desktop = inkscape_active_desktop();
SPDocument *doc = sp_desktop_document(desktop);
SPObject *marker = doc->getObjectById(b);