[glade/margins] Implemented inline margins edit mode. Now it is posible to change widget's margins using the mouse.



commit 00b1b56cac080cf6bf967286a7e3aadbb787fc8f
Author: Juan Pablo Ugarte <juanpablougarte gmail com>
Date:   Sun Apr 24 22:12:26 2011 -0300

    Implemented inline margins edit mode. Now it is posible to change widget's margins
    using the mouse.
    
     * gladeui/glade-design-layout.c:
       o fixed offscreen bg rendering bug (style context from the embedded widget should be used)
       o Implemented ACTIVITY_MARGINS
       o include widget margins on selection drawing
    
     * gladeui/glade-cursor.c:
       o made cursor->selector == NULL
       o Only set cursor if the current cursor is diferent
    
     * gladeui/glade-project.h: added GLADE_POINTER_MARGIN_MODE
    
     * gladeui/glade-placeholder.c: fixed function prototypes.

 gladeui/glade-cursor.c        |    9 +-
 gladeui/glade-design-layout.c |  549 +++++++++++++++++++++++++++++++++--------
 gladeui/glade-placeholder.c   |   93 ++++----
 gladeui/glade-project.h       |    3 +-
 4 files changed, 505 insertions(+), 149 deletions(-)
---
diff --git a/gladeui/glade-cursor.c b/gladeui/glade-cursor.c
index 1cdf43e..5ebc7d9 100644
--- a/gladeui/glade-cursor.c
+++ b/gladeui/glade-cursor.c
@@ -139,8 +139,11 @@ glade_cursor_set (GladeProject    *project,
         break;
     }
 
-  set_cursor (project, cursor->selector);
-  gdk_window_set_cursor (window, the_cursor);
+  if (the_cursor != gdk_window_get_cursor (window))
+    {
+      set_cursor (project, cursor->selector);
+      gdk_window_set_cursor (window, the_cursor);
+    }
 }
 
 /**
@@ -156,7 +159,7 @@ glade_cursor_init (void)
 
   cursor = g_new0 (GladeCursor, 1);
 
-  cursor->selector = gdk_cursor_new (GDK_TOP_LEFT_ARROW);
+  cursor->selector = NULL;
   cursor->add_widget = gdk_cursor_new (GDK_PLUS);
   cursor->resize_top_left = gdk_cursor_new (GDK_TOP_LEFT_CORNER);
   cursor->resize_top_right = gdk_cursor_new (GDK_TOP_RIGHT_CORNER);
diff --git a/gladeui/glade-design-layout.c b/gladeui/glade-design-layout.c
index 58e4bf1..58f029e 100644
--- a/gladeui/glade-design-layout.c
+++ b/gladeui/glade-design-layout.c
@@ -47,16 +47,34 @@ typedef enum
   ACTIVITY_NONE,
   ACTIVITY_RESIZE_WIDTH,
   ACTIVITY_RESIZE_HEIGHT,
-  ACTIVITY_RESIZE_WIDTH_AND_HEIGHT
+  ACTIVITY_RESIZE_WIDTH_AND_HEIGHT,
+  ACTIVITY_MARGINS,
+  ACTIVITY_MARGINS_VERTICAL, /* These activities are only used to set the cursor */
+  ACTIVITY_MARGINS_HORIZONTAL,
+  ACTIVITY_MARGINS_TOP_LEFT,
+  ACTIVITY_MARGINS_TOP_RIGHT,
+  ACTIVITY_MARGINS_BOTTOM_LEFT,
+  ACTIVITY_MARGINS_BOTTOM_RIGHT,
+  N_ACTIVITY
 } Activity;
 
+
+typedef enum
+{
+  MARGIN_TOP    = 1 << 0,
+  MARGIN_BOTTOM = 1 << 1,
+  MARGIN_LEFT   = 1 << 2,
+  MARGIN_RIGHT  = 1 << 3
+} Margins;
+
 struct _GladeDesignLayoutPrivate
 {
   GdkWindow *window, *offscreen_window;
 
   gint child_offset;
   GdkRectangle east, south, south_east;
-  GdkCursor *cursors[sizeof (Activity)];
+  GdkCursor *cursor;            /* Current cursor */
+  GdkCursor *cursors[N_ACTIVITY];
 
   gint current_width, current_height;
   PangoLayout *widget_name;
@@ -66,6 +84,11 @@ struct _GladeDesignLayoutPrivate
   GdkRGBA frame_color[2];
   GdkRGBA frame_color_active[2];
 
+  /* Margin edit mode */
+  GtkWidget *selection;
+  gint m_dy, m_dx;
+  Margins margin;
+
   /* state machine */
   Activity activity;            /* the current activity */
   gint dx;                      /* child.width - event.pointer.x   */
@@ -75,6 +98,7 @@ struct _GladeDesignLayoutPrivate
 
   /* Properties */
   GladeDesignView *view;
+  GladeProject *project;
 };
 
 enum
@@ -87,11 +111,54 @@ G_DEFINE_TYPE (GladeDesignLayout, glade_design_layout, GTK_TYPE_BIN)
 
 #define RECTANGLE_POINT_IN(rect,x,y) (x >= rect.x && x <= (rect.x + rect.width) && y >= rect.y && y <= (rect.y + rect.height))
 
+static Margins
+gdl_get_margins_from_pointer (GtkWidget *widget, gint x, gint y)
+{
+  gint xx, yy, top, bottom, left, right;
+  GtkAllocation alloc;
+  Margins margin = 0;
+  GdkRectangle rec;
+
+  gtk_widget_get_allocation (widget, &alloc);
+  xx = alloc.x;
+  yy = alloc.y;
+
+  top = gtk_widget_get_margin_top (widget);
+  bottom = gtk_widget_get_margin_bottom (widget);
+  left = gtk_widget_get_margin_left (widget);
+  right = gtk_widget_get_margin_right (widget);
+
+  rec.x = xx - left - OUTLINE_WIDTH;
+  rec.y = yy - top - OUTLINE_WIDTH;
+  rec.width = alloc.width + left + right + (OUTLINE_WIDTH * 2);
+  rec.height = alloc.height + top + bottom + (OUTLINE_WIDTH * 2);
+
+  if (RECTANGLE_POINT_IN (rec, x, y))
+    {      
+      if (y <= yy + OUTLINE_WIDTH) margin |= MARGIN_TOP;
+      else if (y >= yy + alloc.height - OUTLINE_WIDTH) margin |= MARGIN_BOTTOM;
+      
+      if (x <= xx + OUTLINE_WIDTH) margin |= MARGIN_LEFT;
+      else if (x >= xx + alloc.width - OUTLINE_WIDTH) margin |= MARGIN_RIGHT;
+    }
+
+  return margin;
+}
+
 static Activity
 gdl_get_activity_from_pointer (GladeDesignLayout *layout, gint x, gint y)
 {
   GladeDesignLayoutPrivate *priv = GLADE_DESIGN_LAYOUT_GET_PRIVATE (layout);
-
+  
+  if (priv->selection)
+    {
+      priv->margin = gdl_get_margins_from_pointer (priv->selection,
+                                                   x - priv->child_offset,
+                                                   y - priv->child_offset);
+      
+      if (priv->margin) return ACTIVITY_MARGINS;
+    }
+  
   if (RECTANGLE_POINT_IN (priv->south_east, x, y)) return ACTIVITY_RESIZE_WIDTH_AND_HEIGHT;
 
   if (RECTANGLE_POINT_IN (priv->east, x, y)) return ACTIVITY_RESIZE_WIDTH;
@@ -101,6 +168,43 @@ gdl_get_activity_from_pointer (GladeDesignLayout *layout, gint x, gint y)
   return ACTIVITY_NONE;
 }
 
+static void
+gdl_set_cursor (GladeDesignLayoutPrivate *priv, GdkCursor *cursor)
+{
+  if (cursor != priv->cursor)
+    {
+      priv->cursor = cursor;
+      gdk_window_set_cursor (priv->window, cursor);
+    }
+}
+
+static Activity
+gdl_margin_get_activity (Margins margin)
+{
+  if (margin & MARGIN_TOP)
+    {
+      if (margin & MARGIN_LEFT)
+        return ACTIVITY_MARGINS_TOP_LEFT;
+      else if (margin & MARGIN_RIGHT)
+        return ACTIVITY_MARGINS_TOP_RIGHT;
+      else
+        return ACTIVITY_MARGINS_VERTICAL;
+    }
+  else if (margin & MARGIN_BOTTOM)
+    {
+      if (margin & MARGIN_LEFT)
+        return ACTIVITY_MARGINS_BOTTOM_LEFT;
+      else if (margin & MARGIN_RIGHT)
+        return ACTIVITY_MARGINS_BOTTOM_RIGHT;
+      else
+        return ACTIVITY_MARGINS_VERTICAL;
+    }
+  else if (margin & MARGIN_LEFT || margin & MARGIN_RIGHT)
+    return ACTIVITY_MARGINS_HORIZONTAL;
+
+  return ACTIVITY_NONE;
+}
+
 static gboolean
 glade_design_layout_leave_notify_event (GtkWidget *widget, GdkEventCrossing *ev)
 {
@@ -114,7 +218,7 @@ glade_design_layout_leave_notify_event (GtkWidget *widget, GdkEventCrossing *ev)
   priv = GLADE_DESIGN_LAYOUT_GET_PRIVATE (widget);
 
   if (priv->activity == ACTIVITY_NONE)
-    gdk_window_set_cursor (priv->window, NULL);
+    gdl_set_cursor (priv, NULL);
 
   return FALSE;
 }
@@ -141,11 +245,10 @@ glade_design_layout_update_child (GladeDesignLayout *layout,
 static gboolean
 glade_design_layout_motion_notify_event (GtkWidget *widget, GdkEventMotion *ev)
 {
-  GtkWidget *child;
   GladeDesignLayoutPrivate *priv;
-  GladeWidget *child_glade_widget;
   GtkAllocation allocation;
-  gint x, y, new_width, new_height;
+  GtkWidget *child;
+  gint x, y;
 
   if ((child = gtk_bin_get_child (GTK_BIN (widget))) == NULL)
     return FALSE;
@@ -154,38 +257,69 @@ glade_design_layout_motion_notify_event (GtkWidget *widget, GdkEventMotion *ev)
 
   x = ev->x;
   y = ev->y;
-
-  child_glade_widget = glade_widget_get_from_gobject (child);
+  
   gtk_widget_get_allocation (child, &allocation);
 
   allocation.x += priv->child_offset;
   allocation.y += priv->child_offset;
-    
-  if (priv->activity == ACTIVITY_RESIZE_WIDTH)
-    {
-      new_width = x - priv->dx - PADDING - OUTLINE_WIDTH;
 
-      allocation.width = MAX (0, new_width);
-    }
-  else if (priv->activity == ACTIVITY_RESIZE_HEIGHT)
+  switch (priv->activity)
     {
-      new_height = y - priv->dy - PADDING - OUTLINE_WIDTH;
+    case ACTIVITY_RESIZE_WIDTH:
+        allocation.width = MAX (0, x - priv->dx - PADDING - OUTLINE_WIDTH);
+      break;
+    case ACTIVITY_RESIZE_HEIGHT:
+        allocation.height = MAX (0, y - priv->dy - PADDING - OUTLINE_WIDTH);
+      break;
+    case ACTIVITY_RESIZE_WIDTH_AND_HEIGHT:
+        allocation.height = MAX (0, y - priv->dy - PADDING - OUTLINE_WIDTH);
+        allocation.width = MAX (0, x - priv->dx - PADDING - OUTLINE_WIDTH);
+      break;
+    case ACTIVITY_MARGINS:
+        {
+          gboolean shift = ev->state & GDK_SHIFT_MASK;
+          GtkWidget *selection = priv->selection;
+          Margins margin = priv->margin;
 
-      allocation.height = MAX (0, new_height);
-    }
-  else if (priv->activity == ACTIVITY_RESIZE_WIDTH_AND_HEIGHT)
-    {
-      new_width = x - priv->dx - PADDING - OUTLINE_WIDTH;
-      new_height = y - priv->dy - PADDING - OUTLINE_WIDTH;
+          if (margin & MARGIN_TOP)
+            {
+              gint val = MAX (0, priv->m_dy - y);
+              gtk_widget_set_margin_top (selection, val);
+              if (shift) gtk_widget_set_margin_bottom (selection, val);
+            }
+          else if (margin & MARGIN_BOTTOM)
+            {
+              gint val = MAX (0, y - priv->m_dy);
+              gtk_widget_set_margin_bottom (selection, val);
+              if (shift) gtk_widget_set_margin_top (selection, val);
+            }
 
-      allocation.height = MAX (0, new_height);
-      allocation.width = MAX (0, new_width);
-    }
-  else
-    {
-      Activity activity = gdl_get_activity_from_pointer (GLADE_DESIGN_LAYOUT (widget), x, y);
-      gdk_window_set_cursor (priv->window, priv->cursors[activity]);
-      return FALSE;
+          if (margin & MARGIN_LEFT)
+            {
+              gint val = MAX (0, priv->m_dx - x);
+              gtk_widget_set_margin_left (selection, val);
+              if (shift) gtk_widget_set_margin_right (selection, val);
+            }
+          else if (margin & MARGIN_RIGHT)
+            {
+              gint val = MAX (0, x - priv->m_dx);
+              gtk_widget_set_margin_right (selection, val);
+              if (shift) gtk_widget_set_margin_left (selection, val);
+            }
+        }
+      break;
+    default:
+        {
+          Activity activity = gdl_get_activity_from_pointer (GLADE_DESIGN_LAYOUT (widget), x, y);
+
+          if (activity == ACTIVITY_MARGINS)
+            activity = gdl_margin_get_activity (priv->margin);
+
+          /* Only set the cursor if changed */
+          gdl_set_cursor (priv, priv->cursors[activity]);
+          return TRUE;
+        }
+      break;
     }
 
   glade_design_layout_update_child (GLADE_DESIGN_LAYOUT (widget), child, &allocation);
@@ -206,8 +340,7 @@ glade_design_layout_find_inside_container (GtkWidget                *widget,
                                            GladeFindInContainerData *data)
 {
   GtkAllocation allocation;
-  gint x;
-  gint y;
+  gint x, y;
 
   if (data->gwidget || !gtk_widget_get_mapped (widget))
     return;
@@ -250,9 +383,8 @@ glade_project_is_toplevel_active (GladeProject *project, GtkWidget *toplevel)
 static gboolean
 glade_design_layout_button_press_event (GtkWidget *widget, GdkEventButton *ev)
 {
-  GtkWidget *child;
-  GtkAllocation child_allocation;
   GladeDesignLayoutPrivate *priv;
+  GtkWidget *child;
   gint x, y;
 
   if (ev->button != 1 ||
@@ -266,26 +398,47 @@ glade_design_layout_button_press_event (GtkWidget *widget, GdkEventButton *ev)
 
   if (ev->type == GDK_BUTTON_PRESS)
     {
-      GladeWidget *gchild;
+      GtkAllocation child_allocation;
+
+      priv->activity = gdl_get_activity_from_pointer (GLADE_DESIGN_LAYOUT (widget), x, y);
       
+      /* Check if we are in margin edit mode */
+      if (priv->selection)
+        {
+          if (priv->activity == ACTIVITY_NONE)
+            {
+              priv->selection = NULL;
+              gdl_set_cursor (priv, NULL);
+              glade_project_set_pointer_mode (priv->project, GLADE_POINTER_SELECT);
+              gtk_widget_queue_draw (widget);
+              return FALSE;
+            }
+          else if (priv->activity == ACTIVITY_MARGINS)
+            gdl_set_cursor (priv, priv->cursors[gdl_margin_get_activity (priv->margin)]);
+          else
+            gdl_set_cursor (priv, priv->cursors[priv->activity]);
+
+          priv->m_dx = x + ((priv->margin & MARGIN_LEFT) ? 
+                            gtk_widget_get_margin_left (priv->selection) :
+                              gtk_widget_get_margin_right (priv->selection) * -1);
+          priv->m_dy = y + ((priv->margin & MARGIN_TOP) ?
+                            gtk_widget_get_margin_top (priv->selection) :
+                              gtk_widget_get_margin_bottom (priv->selection) * -1);
+
+          return FALSE;
+        }
+
       gtk_widget_get_allocation (child, &child_allocation);
+
       priv->dx = x - (child_allocation.x + child_allocation.width + priv->child_offset);
       priv->dy = y - (child_allocation.y + child_allocation.height + priv->child_offset);
-
-      priv->activity = gdl_get_activity_from_pointer (GLADE_DESIGN_LAYOUT (widget), x, y);
-      gdk_window_set_cursor (priv->window, priv->cursors[priv->activity]);
       
       if (priv->activity != ACTIVITY_NONE &&
-          (gchild = glade_widget_get_from_gobject (G_OBJECT (child))))
+          !glade_project_is_toplevel_active (priv->project, child))
         {
-          GladeProject *project = glade_widget_get_project (gchild);
-
-          if (project && !glade_project_is_toplevel_active (project, child))
-            {
-              _glade_design_view_freeze (priv->view);
-              glade_project_selection_set (project, G_OBJECT (gtk_bin_get_child (GTK_BIN (widget))), TRUE);
-              _glade_design_view_thaw (priv->view);
-            }
+          _glade_design_view_freeze (priv->view);
+          glade_project_selection_set (priv->project, G_OBJECT (child), TRUE);
+          _glade_design_view_thaw (priv->view);
         }
     }
 
@@ -305,7 +458,7 @@ glade_design_layout_button_release_event (GtkWidget *widget,
   priv = GLADE_DESIGN_LAYOUT_GET_PRIVATE (widget);
 
   priv->activity = ACTIVITY_NONE;
-  gdk_window_set_cursor (priv->window, NULL);
+  gdl_set_cursor (priv, NULL);
 
   return FALSE;
 }
@@ -527,12 +680,6 @@ glade_design_layout_remove (GtkContainer *container, GtkWidget *widget)
   gtk_widget_queue_draw (GTK_WIDGET (container));
 }
 
-static void
-glade_design_layout_finalize (GObject *object)
-{
-  G_OBJECT_CLASS (glade_design_layout_parent_class)->finalize (object);
-}
-
 static gboolean
 glade_design_layout_damage (GtkWidget *widget, GdkEventExpose *event)
 {
@@ -604,13 +751,41 @@ draw_frame (cairo_t *cr, GladeDesignLayoutPrivate *priv, gboolean selected,
   cairo_restore (cr);
 }
 
+static void
+draw_margin_selection (cairo_t *cr,
+                       gint x1, gint x2, gint x3, gint x4, 
+                       gint y1, gint y2, gint y3, gint y4,
+                       gdouble r, gdouble g, gdouble b,
+                       gint x5, gint y5)
+{
+  cairo_pattern_t *gradient = cairo_pattern_create_linear (x1, y1, x5, y5);
+
+  cairo_pattern_add_color_stop_rgba (gradient, 0, r+.24, g+.24, b+.24, .08);
+  cairo_pattern_add_color_stop_rgba (gradient, 1, r, g, b, .16);
+  
+  cairo_set_source (cr, gradient);
+  
+  cairo_move_to (cr, x1, y1);
+  cairo_line_to (cr, x2, y2);
+  cairo_line_to (cr, x3, y3);
+  cairo_line_to (cr, x4, y4);
+  cairo_close_path (cr);
+  cairo_fill (cr);
+
+  cairo_pattern_destroy (gradient);
+}
+
 static inline void
-draw_selection (cairo_t *cr, GtkWidget *parent, GtkWidget *widget, GdkRGBA *color)
+draw_selection (cairo_t *cr,
+                GtkWidget *parent,
+                GtkWidget *widget,
+                GdkRGBA *color)
 {
+  gint x, y, w, h, xw, yh, y_top, yh_bottom, x_left, xw_right;
+  gint top, bottom, left, right;
   cairo_pattern_t *gradient;
   gdouble r, g, b, cx, cy;
   GtkAllocation alloc;
-  gint x, y;
 
   gtk_widget_get_allocation (widget, &alloc);
 
@@ -619,22 +794,120 @@ draw_selection (cairo_t *cr, GtkWidget *parent, GtkWidget *widget, GdkRGBA *colo
   r = color->red; g = color->green; b = color->blue;
   gtk_widget_translate_coordinates (widget, parent, 0, 0, &x, &y);
 
-  cx = x + alloc.width/2;
-  cy = y + alloc.height/2;
-  gradient = cairo_pattern_create_radial (cx, cy, MIN (alloc.width, alloc.height)/6,
-                                          cx, cy, MAX (alloc.width, alloc.height)/2);
+  w = alloc.width;
+  h = alloc.height;
+  xw = x + w;
+  yh = y + h;
+
+  top = gtk_widget_get_margin_top (widget);
+  bottom = gtk_widget_get_margin_bottom (widget);
+  left = gtk_widget_get_margin_left (widget);
+  right = gtk_widget_get_margin_right (widget);
+  
+  y_top = y - top;
+  yh_bottom = yh + bottom;
+  x_left = x - left;
+  xw_right = xw + right;
+  
+  /* Draw widget area overlay */
+  cx = x + w/2;
+  cy = y + h/2;
+  gradient = cairo_pattern_create_radial (cx, cy, MIN (w, h)/6, cx, cy, MAX (w, h)/2);
   cairo_pattern_add_color_stop_rgba (gradient, 0, r+.24, g+.24, b+.24, .16);
   cairo_pattern_add_color_stop_rgba (gradient, 1, r, g, b, .28);
   cairo_set_source (cr, gradient);
 
-  cairo_rectangle (cr, x, y, alloc.width, alloc.height);
+  cairo_rectangle (cr, x, y, w, h);
   cairo_fill (cr);
 
-  cairo_rectangle (cr, x, y, alloc.width, alloc.height);
+  cairo_pattern_destroy (gradient);
+
+  /* Draw margins overlays */
+  if (top)
+    draw_margin_selection (cr, x, xw, xw_right, x_left, y, y, y_top, y_top,
+                           r, g, b, x, y_top);
+
+  if (bottom)
+    draw_margin_selection (cr, x, xw, xw_right, x_left, yh, yh, yh_bottom, yh_bottom,
+                           r, g, b, x, yh_bottom);
+
+  if (left)
+    draw_margin_selection (cr, x, x, x_left, x_left, y, yh, yh_bottom, y_top,
+                           r, g, b, x_left, y);
+
+  if (right)
+    draw_margin_selection (cr, xw, xw, xw_right, xw_right, y, yh, yh_bottom, y_top,
+                           r, g, b, xw_right, y);
+
+  /* Draw Boxes */
   cairo_set_source_rgba (cr, r, g, b, .75);
+  if (top || bottom || left || right)
+    {
+      gdouble dashes[] = { 4.0, 4.0 };
+      cairo_rectangle (cr,
+                       x - left,
+                       y - top,
+                       w + left + right,
+                       h + top + bottom);
+      cairo_stroke (cr);
+      cairo_set_dash (cr, dashes, 2, 0);
+    }
+
+  /* Draw Widget allocation box */
+  cairo_rectangle (cr, x, y, w, h);
   cairo_stroke (cr);
 
-  cairo_pattern_destroy (gradient);
+  cairo_set_dash (cr, NULL, 0, 0);
+}
+
+static void 
+draw_nodes (cairo_t *cr,
+            gint x1, gint x2, gint x3,
+            gint y1, gint y2, gint y3,
+            gint radius,
+            GdkRGBA *color)
+{
+  gdk_cairo_set_source_rgba (cr, color);
+
+  cairo_arc (cr, x2, y1, radius, 0, 2*G_PI);
+  cairo_fill (cr);
+  cairo_arc (cr, x2, y3, radius, 0, 2*G_PI);
+  cairo_fill (cr);
+  cairo_arc (cr, x1, y2, radius, 0, 2*G_PI);
+  cairo_fill (cr);
+  cairo_arc (cr, x3, y2, radius, 0, 2*G_PI);
+  cairo_fill (cr);
+}
+
+static inline void
+draw_selection_nodes (cairo_t *cr,
+                      GtkWidget *parent,
+                      GtkWidget *widget,
+                      GdkRGBA *color,
+                      GdkRGBA *bg_color)
+{
+  gint x1, x2, x3, y1, y2, y3;
+  GtkAllocation alloc;
+  gint x, y, w, h;
+
+  gtk_widget_get_allocation (widget, &alloc);
+  w = alloc.width;
+  h = alloc.height;
+  
+  if (x < 0 || y < 0) return;
+  
+  gtk_widget_translate_coordinates (widget, parent, 0, 0, &x, &y);
+  
+  /* Draw nodes */
+  x1 = x - gtk_widget_get_margin_left (widget);
+  x2 = x + w/2;
+  x3 = x + w + gtk_widget_get_margin_right (widget);
+  y1 = y - gtk_widget_get_margin_top (widget);
+  y2 = y + h/2;
+  y3 = y + h + gtk_widget_get_margin_bottom (widget);
+      
+  draw_nodes (cr, x1, x2, x3, y1, y2, y3, OUTLINE_WIDTH + 2, bg_color);
+  draw_nodes (cr, x1, x2, x3, y1, y2, y3, OUTLINE_WIDTH, color);
 }
 
 static gboolean
@@ -645,19 +918,15 @@ glade_design_layout_draw (GtkWidget * widget, cairo_t * cr)
 
   if (gtk_cairo_should_draw_window (cr, window))
     {
-      GladeProject *project;
-      GladeWidget *gchild;
       GtkWidget *child;
 
       if ((child = gtk_bin_get_child (GTK_BIN (widget))) &&
-          gtk_widget_get_visible (child) &&
-          (gchild = glade_widget_get_from_gobject (G_OBJECT (child))) &&
-          (project = glade_widget_get_project (gchild)))
+          gtk_widget_get_visible (child))
         {
           gint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
           gboolean selected = FALSE;
           GList *l;
-
+          
           /* draw offscreen widgets */
           gdk_cairo_set_source_window (cr, priv->offscreen_window,
                                        priv->child_offset, priv->child_offset);
@@ -669,7 +938,7 @@ glade_design_layout_draw (GtkWidget * widget, cairo_t * cr)
           cairo_set_line_width (cr, OUTLINE_WIDTH/2);
           cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
           cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
-          for (l = glade_project_selection_get (project); l; l = g_list_next (l))
+          for (l = glade_project_selection_get (priv->project); l; l = g_list_next (l))
             {
               GtkWidget *selection = l->data;
               
@@ -693,13 +962,19 @@ glade_design_layout_draw (GtkWidget * widget, cairo_t * cr)
                       border_width + PADDING,
                       priv->current_width + 2 * OUTLINE_WIDTH,
                       priv->current_height + 2 * OUTLINE_WIDTH);
+
+          /* Draw selection nodes if we are in margins edit mode */
+          if (priv->selection)
+            draw_selection_nodes (cr, widget, priv->selection,
+                                  &priv->frame_color_active[0],
+                                  &priv->frame_color_active[1]);
         }
     }
   else if (gtk_cairo_should_draw_window (cr, priv->offscreen_window))
     {
       GtkWidget *child = gtk_bin_get_child (GTK_BIN (widget));
 
-      gtk_render_background (gtk_widget_get_style_context (widget),
+      gtk_render_background (gtk_widget_get_style_context (child),
                              cr,
                              0, 0,
                              gdk_window_get_width (priv->offscreen_window),
@@ -755,7 +1030,7 @@ pick_offscreen_child (GdkWindow     *offscreen_window,
       gtk_widget_get_allocation (child, &child_area);
 
       if (x >= 0 && x < child_area.width && y >= 0 && y < child_area.height)
-        return priv->offscreen_window;
+        return (priv->selection) ? NULL : priv->offscreen_window;
     }
 
   return NULL;
@@ -861,12 +1136,22 @@ glade_design_layout_realize (GtkWidget * widget)
   gtk_style_context_set_background (context, priv->offscreen_window);
   gdk_window_show (priv->offscreen_window);
 
+  gdk_window_set_cursor (priv->window, NULL);
+  gdk_window_set_cursor (priv->offscreen_window, NULL);
+  
   /* Allocate cursors */
   display = gtk_widget_get_display (widget);
   priv->cursors[ACTIVITY_RESIZE_HEIGHT] = gdk_cursor_new_for_display (display, GDK_BOTTOM_SIDE);
   priv->cursors[ACTIVITY_RESIZE_WIDTH] = gdk_cursor_new_for_display (display, GDK_RIGHT_SIDE);
   priv->cursors[ACTIVITY_RESIZE_WIDTH_AND_HEIGHT] = gdk_cursor_new_for_display (display, GDK_BOTTOM_RIGHT_CORNER);
 
+  priv->cursors[ACTIVITY_MARGINS_VERTICAL] = gdk_cursor_new_for_display (display, GDK_SB_V_DOUBLE_ARROW);
+  priv->cursors[ACTIVITY_MARGINS_HORIZONTAL] = gdk_cursor_new_for_display (display, GDK_SB_H_DOUBLE_ARROW);
+  priv->cursors[ACTIVITY_MARGINS_TOP_LEFT] = gdk_cursor_new_for_display (display, GDK_TOP_LEFT_CORNER);
+  priv->cursors[ACTIVITY_MARGINS_TOP_RIGHT] = gdk_cursor_new_for_display (display, GDK_TOP_RIGHT_CORNER);
+  priv->cursors[ACTIVITY_MARGINS_BOTTOM_LEFT] = gdk_cursor_new_for_display (display, GDK_BOTTOM_LEFT_CORNER);
+  priv->cursors[ACTIVITY_MARGINS_BOTTOM_RIGHT] = gdk_cursor_ref (priv->cursors[ACTIVITY_RESIZE_WIDTH_AND_HEIGHT]);
+  
   priv->widget_name = pango_layout_new (gtk_widget_get_pango_context (widget));
 }
 
@@ -874,7 +1159,8 @@ static void
 glade_design_layout_unrealize (GtkWidget * widget)
 {
   GladeDesignLayoutPrivate *priv;
-
+  gint i;
+  
   priv = GLADE_DESIGN_LAYOUT_GET_PRIVATE (widget);
 
   if (priv->offscreen_window)
@@ -883,23 +1169,19 @@ glade_design_layout_unrealize (GtkWidget * widget)
       gdk_window_destroy (priv->offscreen_window);
       priv->offscreen_window = NULL;
     }
-    
-  if (priv->cursors[ACTIVITY_RESIZE_HEIGHT])
-    {
-      gdk_cursor_unref (priv->cursors[ACTIVITY_RESIZE_HEIGHT]);
-      priv->cursors[ACTIVITY_RESIZE_HEIGHT] = NULL;
-    }
-  if (priv->cursors[ACTIVITY_RESIZE_WIDTH])
-    {
-      gdk_cursor_unref (priv->cursors[ACTIVITY_RESIZE_WIDTH]);
-      priv->cursors[ACTIVITY_RESIZE_WIDTH] = NULL;
-    }
-  if (priv->cursors[ACTIVITY_RESIZE_WIDTH_AND_HEIGHT])
+
+  /* Free cursors */
+  for (i = 0; i < N_ACTIVITY; i++)
     {
-      gdk_cursor_unref (priv->cursors[ACTIVITY_RESIZE_WIDTH_AND_HEIGHT]);
-      priv->cursors[ACTIVITY_RESIZE_WIDTH_AND_HEIGHT] = NULL;
+      if (priv->cursors[i])
+        {
+          gdk_cursor_unref (priv->cursors[i]);
+          priv->cursors[i] = NULL;
+        }
     }
 
+  priv->cursor = NULL;
+
   if (priv->widget_name)
     {
       g_object_unref (priv->widget_name);
@@ -947,15 +1229,13 @@ static void
 glade_design_layout_init (GladeDesignLayout *layout)
 {
   GladeDesignLayoutPrivate *priv;
-
+  gint i;
+  
   layout->priv = priv = GLADE_DESIGN_LAYOUT_GET_PRIVATE (layout);
 
   priv->activity = ACTIVITY_NONE;
 
-  priv->cursors[ACTIVITY_NONE] = NULL;
-  priv->cursors[ACTIVITY_RESIZE_HEIGHT] = NULL;
-  priv->cursors[ACTIVITY_RESIZE_WIDTH] = NULL;
-  priv->cursors[ACTIVITY_RESIZE_WIDTH_AND_HEIGHT] = NULL;
+  for (i = 0; i < N_ACTIVITY; i++) priv->cursors[i] = NULL;
 
   priv->new_width = -1;
   priv->new_height = -1;
@@ -976,7 +1256,11 @@ glade_design_layout_set_property (GObject *object,
   switch (prop_id)
     {
       case PROP_DESIGN_VIEW:
-        GLADE_DESIGN_LAYOUT_GET_PRIVATE (object)->view = GLADE_DESIGN_VIEW (g_value_get_object (value));
+        {
+          GladeDesignLayoutPrivate *priv = GLADE_DESIGN_LAYOUT_GET_PRIVATE (object);
+          priv->view = GLADE_DESIGN_VIEW (g_value_get_object (value));
+          priv->project = glade_design_view_get_project (priv->view);
+        }
         break;
 
       default:
@@ -1004,6 +1288,48 @@ glade_design_layout_get_property (GObject * object,
 }
 
 static void
+on_project_selection_changed (GladeProject *project, GladeDesignLayout *layout)
+{
+  layout->priv->selection = NULL;
+  glade_project_set_pointer_mode (layout->priv->project, GLADE_POINTER_SELECT);
+  gtk_widget_queue_draw (GTK_WIDGET (layout));
+}
+
+static GObject *
+glade_design_layout_constructor (GType                  type,
+                                 guint                  n_construct_params,
+                                 GObjectConstructParam *construct_params)
+{
+  GladeDesignLayoutPrivate *priv;
+  GObject *object;
+    
+  object = G_OBJECT_CLASS (glade_design_layout_parent_class)->constructor (type,
+                                                                           n_construct_params,
+                                                                           construct_params);
+
+  priv = GLADE_DESIGN_LAYOUT_GET_PRIVATE (object);
+
+  g_signal_connect (priv->project,
+                    "selection-changed",
+                    G_CALLBACK (on_project_selection_changed),
+                    GLADE_DESIGN_LAYOUT (object));
+                    
+  return object;
+}
+
+static void
+glade_design_layout_finalize (GObject *object)
+{
+  GladeDesignLayoutPrivate *priv = GLADE_DESIGN_LAYOUT_GET_PRIVATE (object);
+
+  g_signal_handlers_disconnect_by_func (priv->project,
+                                        on_project_selection_changed,
+                                        GLADE_DESIGN_LAYOUT (object));
+  
+  G_OBJECT_CLASS (glade_design_layout_parent_class)->finalize (object);
+}
+
+static void
 glade_design_layout_class_init (GladeDesignLayoutClass * klass)
 {
   GObjectClass *object_class;
@@ -1014,6 +1340,7 @@ glade_design_layout_class_init (GladeDesignLayoutClass * klass)
   widget_class = GTK_WIDGET_CLASS (klass);
   container_class = GTK_CONTAINER_CLASS (klass);
 
+  object_class->constructor = glade_design_layout_constructor;
   object_class->finalize = glade_design_layout_finalize;
   object_class->set_property = glade_design_layout_set_property;
   object_class->get_property = glade_design_layout_get_property;
@@ -1068,27 +1395,47 @@ _glade_design_layout_new (GladeDesignView *view)
  * Returns: true if the event was handled.
  */
 gboolean
-_glade_design_layout_do_event (GladeDesignLayout * layout, GdkEvent * event)
+_glade_design_layout_do_event (GladeDesignLayout *layout, GdkEvent *event)
 {
   GladeFindInContainerData data = { 0, };
   GladeDesignLayoutPrivate *priv;
   GtkWidget *child;
   gboolean retval;
-    
+  GList *l;
+  
   if ((child = gtk_bin_get_child (GTK_BIN (layout))) == NULL)
     return FALSE;
 
   priv = GLADE_DESIGN_LAYOUT_GET_PRIVATE (layout);
 
-  data.toplevel = GTK_WIDGET (layout);
-  gtk_widget_get_pointer (GTK_WIDGET (layout), &data.x, &data.y);
+  data.toplevel = GTK_WIDGET (child);
+  gtk_widget_get_pointer (GTK_WIDGET (child), &data.x, &data.y);
 
-  glade_design_layout_find_inside_container (child, &data);
+  /* Check if we want to enter in margin edit mode */
+  if (event->type == GDK_BUTTON_PRESS &&
+      (l = glade_project_selection_get (priv->project)) &&
+      g_list_next (l) == NULL && GTK_IS_WIDGET (l->data) && 
+      gtk_widget_is_ancestor (l->data, child))
+    {
+      if (gdl_get_margins_from_pointer (l->data, data.x, data.y))
+        {
+          if (priv->selection == NULL)
+            {
+              priv->selection = l->data;
+              glade_project_set_pointer_mode (priv->project, GLADE_POINTER_MARGIN_MODE);
+              gtk_widget_queue_draw (GTK_WIDGET (layout));
+              return TRUE;
+            }
+          return FALSE;
+        }
+    }
 
   _glade_design_view_freeze (priv->view);
-
+  
+  glade_design_layout_find_inside_container (child, &data);
+  
   /* Try the placeholder first */
-  if (data.placeholder && gtk_widget_event (data.placeholder, event))
+  if (data.placeholder && gtk_widget_event (data.placeholder, event)) 
     retval = TRUE;
   else if (data.gwidget) /* Then we try a GladeWidget */
     retval = glade_widget_event (data.gwidget, event);
diff --git a/gladeui/glade-placeholder.c b/gladeui/glade-placeholder.c
index 8a1d2a4..1efbcf4 100644
--- a/gladeui/glade-placeholder.c
+++ b/gladeui/glade-placeholder.c
@@ -50,31 +50,32 @@
 #define WIDTH_REQUISITION    20
 #define HEIGHT_REQUISITION   20
 
-static void glade_placeholder_finalize (GObject * object);
-static void glade_placeholder_set_property (GObject * object,
+static void glade_placeholder_finalize (GObject *object);
+static void glade_placeholder_set_property (GObject *object,
                                             guint prop_id,
-                                            const GValue * value,
-                                            GParamSpec * pspec);
-static void glade_placeholder_get_property (GObject * object,
+                                            const GValue *value,
+                                            GParamSpec *pspec);
+static void glade_placeholder_get_property (GObject *object,
                                             guint prop_id,
-                                            GValue * value, GParamSpec * pspec);
-static void glade_placeholder_realize (GtkWidget * widget);
-static void glade_placeholder_unrealize (GtkWidget * widget);
-static void glade_placeholder_map (GtkWidget * widget);
-static void glade_placeholder_unmap (GtkWidget * widget);
+                                            GValue *value,
+                                            GParamSpec *pspec);
+static void glade_placeholder_realize (GtkWidget *widget);
+static void glade_placeholder_unrealize (GtkWidget *widget);
+static void glade_placeholder_map (GtkWidget *widget);
+static void glade_placeholder_unmap (GtkWidget *widget);
 
-static void glade_placeholder_size_allocate (GtkWidget * widget,
-                                             GtkAllocation * allocation);
+static void glade_placeholder_size_allocate (GtkWidget *widget,
+                                             GtkAllocation *allocation);
 
-static gboolean glade_placeholder_draw (GtkWidget * widget, cairo_t * cr);
+static gboolean glade_placeholder_draw (GtkWidget *widget, cairo_t *cr);
 
-static gboolean glade_placeholder_motion_notify_event (GtkWidget * widget,
-                                                       GdkEventMotion * event);
+static gboolean glade_placeholder_motion_notify_event (GtkWidget *widget,
+                                                       GdkEventMotion *event);
 
-static gboolean glade_placeholder_button_press (GtkWidget * widget,
-                                                GdkEventButton * event);
+static gboolean glade_placeholder_button_press (GtkWidget *widget,
+                                                GdkEventButton *event);
 
-static gboolean glade_placeholder_popup_menu (GtkWidget * widget);
+static gboolean glade_placeholder_popup_menu (GtkWidget *widget);
 
 
 static cairo_pattern_t *placeholder_pattern = NULL;
@@ -95,10 +96,14 @@ enum
   PROP_VSCROLL_POLICY
 };
 
+#define GLADE_PLACEHOLDER_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), \
+                                               GLADE_TYPE_PLACEHOLDER,                \
+                                               GladePlaceholderPrivate))
+
 G_DEFINE_TYPE_WITH_CODE (GladePlaceholder, glade_placeholder, GTK_TYPE_WIDGET,
                          G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
 
-static void glade_placeholder_class_init (GladePlaceholderClass * klass)
+static void glade_placeholder_class_init (GladePlaceholderClass *klass)
 {
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
@@ -146,8 +151,9 @@ static void glade_placeholder_class_init (GladePlaceholderClass * klass)
 }
 
 static void
-glade_placeholder_notify_parent (GObject * gobject,
-                                 GParamSpec * arg1, gpointer user_data)
+glade_placeholder_notify_parent (GObject *gobject,
+                                 GParamSpec *arg1,
+                                 gpointer user_data)
 {
   GladePlaceholder *placeholder = GLADE_PLACEHOLDER (gobject);
   GladeWidgetAdaptor *parent_adaptor = NULL;
@@ -170,12 +176,9 @@ glade_placeholder_notify_parent (GObject * gobject,
 }
 
 static void
-glade_placeholder_init (GladePlaceholder * placeholder)
+glade_placeholder_init (GladePlaceholder *placeholder)
 {
-  placeholder->priv = 
-    G_TYPE_INSTANCE_GET_PRIVATE (placeholder,
-				 GLADE_TYPE_PLACEHOLDER,
-				 GladePlaceholderPrivate);
+  placeholder->priv =  GLADE_PLACEHOLDER_GET_PRIVATE (placeholder);
 
   placeholder->priv->packing_actions = NULL;
 
@@ -194,7 +197,7 @@ glade_placeholder_init (GladePlaceholder * placeholder)
 }
 
 static void
-glade_placeholder_finalize (GObject * object)
+glade_placeholder_finalize (GObject *object)
 {
   GladePlaceholder *placeholder;
 
@@ -211,9 +214,10 @@ glade_placeholder_finalize (GObject * object)
 }
 
 static void
-glade_placeholder_set_property (GObject * object,
+glade_placeholder_set_property (GObject *object,
                                 guint prop_id,
-                                const GValue * value, GParamSpec * pspec)
+                                const GValue *value,
+                                GParamSpec *pspec)
 {
 
   switch (prop_id)
@@ -230,9 +234,10 @@ glade_placeholder_set_property (GObject * object,
 }
 
 static void
-glade_placeholder_get_property (GObject * object,
+glade_placeholder_get_property (GObject *object,
                                 guint prop_id,
-                                GValue * value, GParamSpec * pspec)
+                                GValue *value,
+                                GParamSpec *pspec)
 {
   switch (prop_id)
     {
@@ -251,7 +256,7 @@ glade_placeholder_get_property (GObject * object,
 }
 
 static void
-glade_placeholder_realize (GtkWidget * widget)
+glade_placeholder_realize (GtkWidget *widget)
 {
   GladePlaceholder *placeholder;
   GtkAllocation allocation;
@@ -291,7 +296,7 @@ glade_placeholder_realize (GtkWidget * widget)
 }
 
 static void
-glade_placeholder_unrealize (GtkWidget * widget)
+glade_placeholder_unrealize (GtkWidget *widget)
 {
   GladePlaceholder *placeholder;
 
@@ -308,7 +313,7 @@ glade_placeholder_unrealize (GtkWidget * widget)
 }
 
 static void
-glade_placeholder_map (GtkWidget * widget)
+glade_placeholder_map (GtkWidget *widget)
 {
   GladePlaceholder *placeholder;
 
@@ -323,7 +328,7 @@ glade_placeholder_map (GtkWidget * widget)
 }
 
 static void
-glade_placeholder_unmap (GtkWidget * widget)
+glade_placeholder_unmap (GtkWidget *widget)
 {
   GladePlaceholder *placeholder;
 
@@ -338,7 +343,7 @@ glade_placeholder_unmap (GtkWidget * widget)
 }
 
 static void
-glade_placeholder_size_allocate (GtkWidget * widget, GtkAllocation * allocation)
+glade_placeholder_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
 {
   GladePlaceholder *placeholder;
 
@@ -355,7 +360,7 @@ glade_placeholder_size_allocate (GtkWidget * widget, GtkAllocation * allocation)
 }
 
 static gboolean
-glade_placeholder_draw (GtkWidget * widget, cairo_t * cr)
+glade_placeholder_draw (GtkWidget *widget, cairo_t *cr)
 {
   GtkStyle *style;
   GdkColor *light;
@@ -389,9 +394,9 @@ glade_placeholder_draw (GtkWidget * widget, cairo_t * cr)
 }
 
 static gboolean
-glade_placeholder_motion_notify_event (GtkWidget * widget,
-                                       GdkEventMotion * event)
+glade_placeholder_motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
 {
+  GladePlaceholder *placeholder = GLADE_PLACEHOLDER (widget);
   GladePointerMode pointer_mode;
   GladeWidget *gparent, *gparent_parent = NULL;
   GladeProject *project;
@@ -402,7 +407,7 @@ glade_placeholder_motion_notify_event (GtkWidget * widget,
   if (gparent)
     gparent_parent = glade_widget_get_parent (gparent);
 
-  project      = glade_placeholder_get_project (GLADE_PLACEHOLDER (widget));
+  project      = glade_placeholder_get_project (placeholder);
   pointer_mode = glade_project_get_pointer_mode (project);
 
   if (pointer_mode == GLADE_POINTER_SELECT)
@@ -414,7 +419,7 @@ glade_placeholder_motion_notify_event (GtkWidget * widget,
 }
 
 static gboolean
-glade_placeholder_button_press (GtkWidget * widget, GdkEventButton * event)
+glade_placeholder_button_press (GtkWidget *widget, GdkEventButton *event)
 {
   GladePlaceholder   *placeholder;
   GladeProject       *project;
@@ -463,7 +468,7 @@ glade_placeholder_button_press (GtkWidget * widget, GdkEventButton * event)
 }
 
 static gboolean
-glade_placeholder_popup_menu (GtkWidget * widget)
+glade_placeholder_popup_menu (GtkWidget *widget)
 {
   g_return_val_if_fail (GLADE_IS_PLACEHOLDER (widget), FALSE);
 
@@ -485,7 +490,7 @@ glade_placeholder_new (void)
 }
 
 GladeProject *
-glade_placeholder_get_project (GladePlaceholder * placeholder)
+glade_placeholder_get_project (GladePlaceholder *placeholder)
 {
   GladeWidget *parent;
   parent = glade_placeholder_get_parent (placeholder);
@@ -493,7 +498,7 @@ glade_placeholder_get_project (GladePlaceholder * placeholder)
 }
 
 GladeWidget *
-glade_placeholder_get_parent (GladePlaceholder * placeholder)
+glade_placeholder_get_parent (GladePlaceholder *placeholder)
 {
   GtkWidget *widget;
   GladeWidget *parent = NULL;
diff --git a/gladeui/glade-project.h b/gladeui/glade-project.h
index 1b9eb83..a4c8f9a 100644
--- a/gladeui/glade-project.h
+++ b/gladeui/glade-project.h
@@ -35,7 +35,8 @@ enum _GladePointerMode
 {
   GLADE_POINTER_SELECT = 0,
   GLADE_POINTER_ADD_WIDGET,
-  GLADE_POINTER_DRAG_RESIZE
+  GLADE_POINTER_DRAG_RESIZE,
+  GLADE_POINTER_MARGIN_MODE
 };
 
 enum _GladeSupportMask



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