[dia] path: add "<Selection>/Convert to Path" context menu entry



commit 67d056f1415432ae8d62f504e50ba4ba2965b60e
Author: Hans Breuer <hans breuer org>
Date:   Sat Jul 20 20:18:26 2013 +0200

    path: add "<Selection>/Convert to Path" context menu entry
    
    and fix some path segment ordering issue with the path
    renderer as well as "Standard - Path" property setting.

 app/disp_callbacks.c  |   59 ++++++++++++++++++++++++++++++++++++++++++++++++-
 lib/diapathrenderer.c |   36 ++++++++++++++++++++++++-----
 lib/standard-path.c   |   32 ++++++++++++++++++++++----
 3 files changed, 114 insertions(+), 13 deletions(-)
---
diff --git a/app/disp_callbacks.c b/app/disp_callbacks.c
index b5e25d5..088420b 100644
--- a/app/disp_callbacks.c
+++ b/app/disp_callbacks.c
@@ -46,6 +46,7 @@
 #include "dia_dirs.h"
 #include "object.h"
 #include "disp_callbacks.h"
+#include "create.h"
 
 typedef struct {
        GdkEvent *event; /* Button down event which may be holding */
@@ -163,17 +164,67 @@ _follow_link_callback (GtkAction *action, gpointer data)
 static void
 add_follow_link_menu_item (GtkMenu *menu)
 {
-  GtkWidget *menu_item = gtk_menu_item_new_with_label(_("Follow linkā€¦"));
+  GtkWidget *menu_item = gtk_menu_item_new_with_label(_("Follow link\342\200\246"));
   g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(_follow_link_callback), NULL);
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
   gtk_widget_show(menu_item);
 }
+
+static void
+_convert_to_path_callback (GtkAction *action, gpointer data)
+{
+  DiaObject *obj;
+  DDisplay *ddisp = ddisplay_active();
+  GList *selected, *list;
+  ObjectChange *change_list = NULL;
+
+  if (!ddisp) return;
+
+  /* copy the list before modifying it */
+  list = selected = diagram_get_sorted_selected (ddisp->diagram);
+  while (list) {
+    DiaObject *obj = (DiaObject *)list->data;
+
+    if (obj) { /* paranoid */
+      DiaObject *path = create_standard_path_from_object (obj);
+
+      if (path) { /* not so paranoid */
+       ObjectChange *change = object_substitute (obj, path);
+
+       if (!change_list)
+         change_list = change_list_create ();
+       if (change)
+         change_list_add (change_list, change);
+      }
+    }
+    list = g_list_next(list);
+  }
+  g_list_free (selected);
+  if (change_list) {
+    undo_object_change(ddisp->diagram, NULL, change_list);
+
+    diagram_modified(ddisp->diagram);
+    diagram_update_extents(ddisp->diagram);
+
+    undo_set_transactionpoint(ddisp->diagram->undo);
+    diagram_flush(ddisp->diagram);
+  }
+}
+static void
+add_convert_to_path_menu_item (GtkMenu *menu)
+{
+  GtkWidget *menu_item = gtk_menu_item_new_with_label(_("Convert to Path"));
+  g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(_convert_to_path_callback), NULL);
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
+  gtk_widget_show(menu_item);
+}
 static void
 create_object_menu(DiaMenu *dia_menu, gboolean root_menu)
 {
   int i;
   GtkWidget *menu;
   GtkWidget *menu_item;
+  gboolean native_convert_to_path = FALSE;
 
   menu = gtk_menu_new();
 
@@ -192,6 +243,10 @@ create_object_menu(DiaMenu *dia_menu, gboolean root_menu)
   for (i=0;i<dia_menu->num_items;i++) {
     DiaMenuItem *item = &dia_menu->items[i];
 
+    /* HACK: rely on object menu naming convention to avoid duplicated menu entry/functionality */
+    if (item->text && strcmp (item->text, "Convert to Path") == 0)
+      native_convert_to_path = TRUE;
+
     if (item->active & DIAMENU_TOGGLE) {
       if (item->text)
         menu_item = gtk_check_menu_item_new_with_label(gettext(item->text));
@@ -231,6 +286,8 @@ create_object_menu(DiaMenu *dia_menu, gboolean root_menu)
     /* Finally add a Properties... menu item for objects*/
     add_properties_menu_item(GTK_MENU (menu), i > 0);
     add_follow_link_menu_item(GTK_MENU (menu));
+    if (!native_convert_to_path)
+      add_convert_to_path_menu_item(GTK_MENU (menu));
   }
 
   dia_menu->app_data = menu;
diff --git a/lib/diapathrenderer.c b/lib/diapathrenderer.c
index 2eea0b9..04380df 100644
--- a/lib/diapathrenderer.c
+++ b/lib/diapathrenderer.c
@@ -139,6 +139,15 @@ static void
 end_render(DiaRenderer *self)
 {
 }
+static gboolean
+is_capable_to (DiaRenderer *renderer, RenderCapability cap)
+{
+  if (RENDER_HOLES == cap)
+    return TRUE;
+  else if (RENDER_ALPHA == cap)
+    return TRUE;
+  return FALSE;
+}
 static void
 set_linewidth(DiaRenderer *self, real linewidth)
 {  /* 0 == hairline **/
@@ -344,18 +353,24 @@ _arc (DiaRenderer *self,
   GArray *path = _get_current_path (renderer, stroke, fill);
   Point start;
   real radius = sqrt(width * height) / 2.0;
-  real ar1 = (M_PI / 180.0) * angle1;
-  real ar2 = (M_PI / 180.0) * angle2;
+  real ar1;
+  real ar2;
   int i, segs;
   real ars;
-  
+
+  while (angle1 > angle2)
+    angle1 -= 360;
+
+  ar1 = (M_PI / 180.0) * angle2;
+  ar2 = (M_PI / 180.0) * angle1;
   /* one segment for ever 90 degrees */
   segs = (int)(fabs(ar2 - ar1) / (M_PI/2)) + 1;
   ars = - (ar2 - ar1) / segs;
 
   /* move to start point */
-  start.x = center->x + (width / 2.0)  * cos(ar1);  
+  start.x = center->x + (width / 2.0)  * cos(ar1);
   start.y = center->y - (height / 2.0) * sin(ar1);
+
   /* Dia and Cairo don't agree on arc definitions, so it needs
    * to be converted, i.e. mirrored at the x axis
    */
@@ -478,9 +493,15 @@ _bezier (DiaRenderer *self,
 {
   DiaPathRenderer *renderer = DIA_PATH_RENDERER (self);
   GArray *path = _get_current_path (renderer, stroke, fill);
-  int i;
+  int i = 0;
 
-  for (i = 0; i < numpoints; ++i)
+  /* get rid of the first move-to if we can attach to the previous point */
+  if (path->len > 0) {
+    BezPoint *bp = &g_array_index (path, BezPoint, path->len-1);
+    if (distance_point_point(&bp->p3, &points[0].p1) < 0.001)
+      i = 1;
+  }
+  for (i; i < numpoints; ++i)
     g_array_append_val (path, points[i]);
   if (fill)
     _path_lineto (path, &points[0].p1);
@@ -640,7 +661,8 @@ dia_path_renderer_class_init (DiaPathRendererClass *klass)
   renderer_class->draw_bezier   = draw_bezier;
   renderer_class->fill_bezier   = fill_bezier;
   renderer_class->draw_text     = draw_text;
-
+  /* other */
+  renderer_class->is_capable_to = is_capable_to;
 }
 
 #include "object.h"
diff --git a/lib/standard-path.c b/lib/standard-path.c
index 26efbff..896fdec 100644
--- a/lib/standard-path.c
+++ b/lib/standard-path.c
@@ -37,6 +37,7 @@
 #include "diarenderer.h"
 #include "attributes.h"
 #include "properties.h"
+#include "propinternals.h"
 #include "boundingbox.h"
 #include "standard-path.h"
 #include "create.h"
@@ -185,6 +186,7 @@ static void stdpath_destroy (StdPath *stdpath);
 static DiaObject *stdpath_copy (StdPath *stdpath);
 static DiaMenu *stdpath_get_object_menu(StdPath *stdpath,
                                        Point *clickedpoint);
+static void stdpath_get_props(StdPath *stdpath, GPtrArray *props);
 static void stdpath_set_props(StdPath *stdpath, GPtrArray *props);
 
 static ObjectOps stdpath_ops = {
@@ -199,7 +201,7 @@ static ObjectOps stdpath_ops = {
   (ApplyPropertiesDialogFunc) object_apply_props_from_dialog,
   (ObjectMenuFunc)      stdpath_get_object_menu,
   (DescribePropsFunc)   object_describe_props,
-  (GetPropsFunc)        object_get_props,
+  (GetPropsFunc)        stdpath_get_props,
   (SetPropsFunc)        stdpath_set_props,
   (TextEditFunc) 0,
   (ApplyPropertiesListFunc) object_apply_props,
@@ -484,18 +486,38 @@ stdpath_get_object_menu(StdPath *stdpath, Point *clickedpoint)
   return &_stdpath_menu;
 }
 /*!
+ * \brief Initialize the given property vector from the object state.
+ *
+ * If  offsets and props are part of the object type this does not to be
+ * implemented usually. Just object_get_props in the 'vtable' would be enough.
+ * We want to ensure that stroke_or_fill and show_background are in sync, though.
+ */
+static void
+stdpath_get_props(StdPath *stdpath, GPtrArray *props)
+{
+  stdpath->show_background = (stdpath->stroke_or_fill & PDO_FILL) != 0;
+  object_get_props(&stdpath->object, props);
+}
+/*!
  * \brief Set the object state from the given proeprty vector
  * \memberof StdPath
  */
 static void 
 stdpath_set_props (StdPath *stdpath, GPtrArray *props)
 {
+  Property *prop;
   stdpath->show_background = (stdpath->stroke_or_fill & PDO_FILL) != 0;
   object_set_props_from_offsets(&stdpath->object, stdpath_offsets, props);
-  if (stdpath->show_background)
-    stdpath->stroke_or_fill |= PDO_FILL;
-  else
-    stdpath->stroke_or_fill &= ~PDO_FILL;
+  /* Usually the list wont contain "show_background", but if it
+   * it set let it take precedence
+   */
+  if (   (prop = find_prop_by_name (props, "show_background")) != NULL
+      && (prop->experience & PXP_NOTSET) == 0) {
+    if (stdpath->show_background)
+      stdpath->stroke_or_fill |= PDO_FILL;
+    else
+      stdpath->stroke_or_fill &= ~PDO_FILL;
+  }
   /* now when transfering properties from text we'll loose stroke and fill
    * Instead of drawing nothing maket it just fill.
    */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]