Code

Marker menus now display custom markers in a document that are present
authorbryce <bryce@users.sourceforge.net>
Thu, 7 Dec 2006 04:41:04 +0000 (04:41 +0000)
committerbryce <bryce@users.sourceforge.net>
Thu, 7 Dec 2006 04:41:04 +0000 (04:41 +0000)
when the document is loaded.  The menus won't update with new markers,
though, and there's a couple other issues that need to be addressed
before its 100% reliable.

doc/markers_design.txt [new file with mode: 0644]
src/dialogs/stroke-style.cpp
src/marker.cpp

diff --git a/doc/markers_design.txt b/doc/markers_design.txt
new file mode 100644 (file)
index 0000000..f41eaa8
--- /dev/null
@@ -0,0 +1,98 @@
+                             Markers Design
+                          Bryce W. Harrington
+                              -----------
+
+Markers (or "arrowheads") are drawing elements specified by the SVG
+standard that can be placed on lines at one of three positions: Start,
+End, or Midpoints.  This document isn't intended to be an exhaustive
+guide to Markers, but rather to simply capture notes about the
+implementation of them within Inkscape.
+
+History
+=======
+The marker code was originally developed by Lauris for Sodipodi, but due
+to various issues, the code was not hooked to the interface.  Thus
+there was no way for users to actually put markers on lines.
+
+Early in Inkscape, I dug through the code and reactivated the markers
+function, and then hammered on a few of the main issues to get markers
+to (mostly) work.  There were a variety of remaining issues (e.g., you
+couldn't change marker colors, updates didn't work very well, and snap
+points were messed up.)  But at least they no longer crashed when you
+used them.  ;-)
+
+Simarilius and others did the work of getting the UI hooked up for
+markers, and other assorted fixes.  A set of stock markers were created
+and distributed with Inkscape.
+
+Since then, though, the code has sat mostly idle, as no one has had
+time/inclination to put more work on it.  Despite this, the remaining
+marker issues (color setting in particular) remain popular requests
+among users.
+
+I'm hoping this document assists anyone wishing to work on markers to
+come up to speed with the code more easily than otherwise.
+
+Implementation Files
+====================
+The following files contain code of relevance to markers:
+
+marker.h:  tbd
+
+marker.cpp: Implements the sp_marker class, providing functionality for
+ managing the relationship of markers to lines or other objects they've
+ been applied to.  Updates reprs and properties as the marker's
+ definition changes.  Handles updates/changes to marker views as well.
+
+sp-shape.cpp:  tbd
+
+selection-chemistry.cpp:  tbd
+
+sp-marker-loc.h:  tbd
+
+display/nr-arena-shape.cpp:  tbd
+
+stock-items.cpp:  tbd
+
+dialogs/stroke-style.h:  tbd
+
+dialogs/stroke-style.cpp:  Implements the stroke style dialog, which
+includes the widgets for displaying stock markers that can be applied to
+lines.
+
+
+Marker Architecture
+===================
+A marker is a distinct drawing element that exists in the <defs> section
+of an SVG document.  Markers often appear multiple places in a document
+- for instance, you might have a diagram with dozens of lines, each
+tipped by a copy of the same arrow.  Rather than paste a copy of the
+arrowhead in at each point it's used, a single definition is made, and a
+reference, or 'href', is attached at each place its used.
+
+In Inkscape, the marker definition is implemented as a 'SPMarker'
+object, and each reference is a 'SPMarkerView' object.  Each SPMarker
+has a listing of all its SPMarkerViews, which it can use for update
+purposes when it changes.
+
+
+
+Stroke Dialog
+=============
+In the stroke style dialog, several routines allow for setting and
+interacting with the stroke markers.  Most of these routines are already
+documented, but a few are worth some additional attention.
+
+sp_marker_prev_new():  Generates the preview images of markers for
+display in the marker menu.
+
+sp_marker_list_from_doc():  Generates a listing of non-stock markers in
+the document.  Generates preview and label for the marker.
+
+ink_markers_preview_doc(): Returns a new document containing default
+start, mid, and end markers by creating the SVG text and running it
+through sp_document_new_from_mem.  I'm not entirely sure why this
+exists, but it's called from sp_stroke_style_line_widget_new() so
+presumably is needed.
+
+ink_marker_menu():  Generates the marker menu.
index 5e3319ffc48f5b04e42d41a7cf668c688162f8d4..152569a5afff59c0d39a9ed63091e0c41ae0bd03 100644 (file)
@@ -5,7 +5,7 @@
  *
  * 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
@@ -546,7 +546,8 @@ sp_stroke_radio_button(GtkWidget *tb, char const *icon,
 
 /**
  * Creates a copy of the marker named mname, determines its visible and renderable
- * area in menu_id's bounding box, and then renders it.
+ * 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,
@@ -657,62 +658,44 @@ sp_marker_prev_new(unsigned size, gchar const *mname,
 }
 
 
-#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 *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);
 
@@ -744,8 +727,52 @@ 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 *menu_id)
+{
+    GSList *ml = ink_marker_list_get(source);
+    GSList *clean_ml = NULL;
+
+    // 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;
+
+        GSList * markers_doc_ml = ink_marker_list_get(markers_doc);
+        for (; markers_doc_ml != NULL; markers_doc_ml = markers_doc_ml->next) {
+            const gchar* stockid = SP_OBJECT_REPR(markers_doc_ml->data)->attribute("inkscape:stockid");
+            if (stockid && !strcmp(repr->attribute("inkscape:stockid"), stockid))
+                stock_dupe = true;
+        }
+
+        if (stock_dupe) // stock item, dont add to list from current doc
+            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);
 }
 
 
index 68b630920fa6a56a1f01af9127c66bc0626520f1..65ed3789fde1126979e36ee93135494a70bba660 100644 (file)
@@ -1,12 +1,14 @@
-#define __SP_MARKER_C__
+#define __MARKER_C__
 
 /*
  * SVG <marker> implementation
  *
  * Authors:
  *   Lauris Kaplinski <lauris@kaplinski.com>
+ *   Bryce Harrington <bryce@bryceharrington.org>
  *
  * Copyright (C) 1999-2003 Lauris Kaplinski
+ *               2004-2006 Bryce Harrington
  *
  * Released under GNU GPL, read the file 'COPYING' for more information
  */