]> git.sur5r.net Git - glabels/blobdiff - glabels2/src/view.c
2007-09-27 Jim Evins <evins@snaught.com>
[glabels] / glabels2 / src / view.c
index 9cc6243c53d4cce34f27140969db20ede07ef693..2636eb9d088b145bee344f3be2d2145a694af83c 100644 (file)
 /*==========================================================================*/
 
 #define BG_COLOR        GL_COLOR (192, 192, 192)
-#define OUTLINE_COLOR   GL_COLOR (173, 216, 230)
-#define PAPER_COLOR     GL_COLOR (255, 255, 255)
-#define GRID_COLOR      BG_COLOR
-#define MARKUP_COLOR    GL_COLOR (240, 100, 100)
 
-#define SEL_LINE_COLOR  GL_COLOR_A (0, 0, 255, 128)
-#define SEL_FILL_COLOR  GL_COLOR_A (192, 192, 255, 128)
+#define PAPER_RGB_ARGS          1.0,   1.0,   1.0
+#define GRID_RGB_ARGS           0.753, 0.753, 0.753
+#define MARKUP_RGB_ARGS         0.94,  0.39,  0.39
+#define OUTLINE_RGB_ARGS        0.68,  0.85,  0.90
+#define SELECT_LINE_RGBA_ARGS   0.0,   0.0,   1.0,   0.5
+#define SELECT_FILL_RGBA_ARGS   0.75,  0.75,  1.0,   0.5
 
-#define ARC_FINE         2 /* Resolution in degrees of large arcs */
-#define ARC_COURSE       5 /* Resolution in degrees of small arcs */
+#define GRID_LINE_WIDTH_PIXELS    1.0
+#define MARKUP_LINE_WIDTH_PIXELS  1.0
+#define OUTLINE_WIDTH_PIXELS      3.0
+#define SELECT_LINE_WIDTH_PIXELS  3.0
 
 #define ZOOMTOFIT_PAD   16
 
 #define POINTS_PER_MM    2.83464566929
 
-#define DELTA 0.01
-
 /*==========================================================================*/
 /* Private types.                                                           */
 /*==========================================================================*/
@@ -143,6 +143,9 @@ static void       label_changed_cb                (glView         *view);
 
 static void       label_resized_cb                (glView         *view);
 
+static void       label_object_added_cb           (glView         *view,
+                                                   glLabelObject  *object);
+
 static void       draw_layers                     (glView         *view,
                                                    cairo_t        *cr);
 
@@ -483,6 +486,8 @@ gl_view_construct (glView  *view,
                                   G_CALLBACK (label_changed_cb), view);
        g_signal_connect_swapped (G_OBJECT (view->label), "size_changed",
                                   G_CALLBACK (label_resized_cb), view);
+       g_signal_connect_swapped (G_OBJECT (view->label), "object_added",
+                                  G_CALLBACK (label_object_added_cb), view);
 
        gl_debug (DEBUG_VIEW, "END");
 }
@@ -539,7 +544,7 @@ get_home_scale (glView *view)
 }
 
 /*---------------------------------------------------------------------------*/
-/* PRIVATE.  Update canvas.                                                  */
+/* Schedule canvas update.                                                   */
 /*---------------------------------------------------------------------------*/
 void
 gl_view_update (glView  *view)
@@ -553,11 +558,51 @@ gl_view_update (glView  *view)
 
        if (!widget->window) return;
 
-       region = gdk_drawable_get_clip_region (widget->window);
-       /* redraw the cairo canvas completely by exposing it */
-       gdk_window_invalidate_region (widget->window, region, TRUE);
+        if ( !view->update_scheduled_flag )
+        {
+                view->update_scheduled_flag = TRUE;
 
-       gdk_region_destroy (region);
+                region = gdk_drawable_get_clip_region (widget->window);
+                /* redraw the cairo canvas completely by exposing it */
+                gdk_window_invalidate_region (widget->window, region, TRUE);
+                gdk_region_destroy (region);
+        }
+
+       gl_debug (DEBUG_VIEW, "END");
+}
+
+/*---------------------------------------------------------------------------*/
+/* Schedule canvas region update.                                            */
+/*---------------------------------------------------------------------------*/
+void
+gl_view_update_region (glView        *view,
+                       cairo_t       *cr,
+                       glLabelRegion *region)
+{
+       GtkWidget    *widget;
+       GdkRectangle  rect;
+        gdouble       x, y, w, h;
+
+       gl_debug (DEBUG_VIEW, "START");
+
+       widget = GTK_WIDGET (view->canvas);
+
+       if (!widget->window) return;
+
+        x = MIN (region->x1, region->x2);
+        y = MIN (region->y1, region->y2);
+        w = fabs (region->x2 - region->x1);
+        h = fabs (region->y2 - region->y1);
+
+        cairo_user_to_device (cr, &x, &y);
+        cairo_user_to_device_distance (cr, &w, &h);
+
+        rect.x      = x - 3;
+        rect.y      = y - 3;
+        rect.width  = w + 6;
+        rect.height = h + 6;
+
+        gdk_window_invalidate_rect (widget->window, &rect, TRUE);
 
        gl_debug (DEBUG_VIEW, "END");
 }
@@ -573,6 +618,8 @@ expose_cb (glView         *view,
 
        gl_debug (DEBUG_VIEW, "START");
 
+        view->update_scheduled_flag = FALSE;
+
        /* get a cairo_t */
        cr = gdk_cairo_create (GTK_LAYOUT (view->canvas)->bin_window);
 
@@ -687,6 +734,39 @@ label_resized_cb (glView  *view)
 }
 
 
+/*---------------------------------------------------------------------------*/
+/* PRIVATE.  Handle new label object.                                        */
+/*---------------------------------------------------------------------------*/
+static void
+label_object_added_cb (glView         *view,
+                       glLabelObject  *object)
+{
+        glViewObject *view_object;
+
+       g_return_if_fail (view && GL_IS_VIEW (view));
+       g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
+
+        if (GL_IS_LABEL_BOX (object)) {
+                view_object = gl_view_box_new (GL_LABEL_BOX(object), view);
+        } else if (GL_IS_LABEL_ELLIPSE (object)) {
+                view_object = gl_view_ellipse_new (GL_LABEL_ELLIPSE(object), view);
+        } else if (GL_IS_LABEL_LINE (object)) {
+                view_object = gl_view_line_new (GL_LABEL_LINE(object), view);
+        } else if (GL_IS_LABEL_IMAGE (object)) {
+                view_object = gl_view_image_new (GL_LABEL_IMAGE(object), view);
+        } else if (GL_IS_LABEL_TEXT (object)) {
+                view_object = gl_view_text_new (GL_LABEL_TEXT(object), view);
+        } else if (GL_IS_LABEL_BARCODE (object)) {
+                view_object = gl_view_barcode_new (GL_LABEL_BARCODE(object), view);
+        } else {
+                /* Should not happen! */
+                view_object = NULL;
+                g_message ("Invalid label object type.");
+        }
+
+        gl_view_select_object (view, view_object);
+}
+
 /*---------------------------------------------------------------------------*/
 /* PRIVATE.  Create, draw and order layers.                                  */
 /*---------------------------------------------------------------------------*/
@@ -748,7 +828,7 @@ draw_bg_layer (glView  *view,
 
         gl_cairo_label_path (cr, view->label->template, view->label->rotate_flag, FALSE);
 
-        cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+        cairo_set_source_rgb (cr, PAPER_RGB_ARGS);
         cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
         cairo_fill (cr);
 }
@@ -763,7 +843,7 @@ draw_grid_layer (glView  *view,
        gdouble                    w, h;
        gdouble                    x, y;
        gdouble                    x0, y0;
-       const glTemplateLabelType *label_type;
+       const lglTemplateFrame    *frame;
 
        gl_debug (DEBUG_VIEW, "START");
 
@@ -773,11 +853,11 @@ draw_grid_layer (glView  *view,
         if (view->grid_visible)
         {
 
-                label_type = gl_template_get_first_label_type (view->label->template);
+                frame = lgl_template_get_first_frame (view->label->template);
 
                 gl_label_get_size (view->label, &w, &h);
        
-                if (label_type->shape == GL_TEMPLATE_SHAPE_RECT) {
+                if (frame->shape == LGL_TEMPLATE_FRAME_SHAPE_RECT) {
                         x0 = 0.0;
                         y0 = 0.0;
                 } else {
@@ -790,8 +870,8 @@ draw_grid_layer (glView  *view,
                 cairo_save (cr);
 
                 cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
-                cairo_set_line_width (cr, 1.0/(view->home_scale * view->zoom));
-                cairo_set_source_rgb (cr, 0.753, 0.753, 0.753);
+                cairo_set_line_width (cr, GRID_LINE_WIDTH_PIXELS/(view->home_scale * view->zoom));
+                cairo_set_source_rgb (cr, GRID_RGB_ARGS);
 
                 for ( x=x0+view->grid_spacing; x < w; x += view->grid_spacing )
                 {
@@ -822,9 +902,9 @@ draw_markup_layer (glView  *view,
                    cairo_t *cr)
 {
        glLabel                   *label;
-       const glTemplateLabelType *label_type;
+       const lglTemplateFrame    *frame;
        GList                     *p;
-       glTemplateMarkup          *markup;
+       lglTemplateMarkup         *markup;
 
        g_return_if_fail (view && GL_IS_VIEW (view));
        g_return_if_fail (view->label && GL_IS_LABEL (view->label));
@@ -833,21 +913,21 @@ draw_markup_layer (glView  *view,
         {
 
                 label      = view->label;
-                label_type = gl_template_get_first_label_type (label->template);
+                frame = lgl_template_get_first_frame (label->template);
 
                 cairo_save (cr);
 
-                cairo_set_line_width (cr, 1.0/(view->home_scale * view->zoom));
-                cairo_set_source_rgb (cr, 0.94, 0.39, 0.39);
+                cairo_set_line_width (cr, MARKUP_LINE_WIDTH_PIXELS/(view->home_scale * view->zoom));
+                cairo_set_source_rgb (cr, MARKUP_RGB_ARGS);
 
-                for ( p=label_type->markups; p != NULL; p=p->next )
+                for ( p=frame->all.markups; p != NULL; p=p->next )
                 {
-                        markup = (glTemplateMarkup *)p->data;
+                        markup = (lglTemplateMarkup *)p->data;
 
                         gl_cairo_markup_path (cr, markup, label);
-                }
 
-                cairo_stroke (cr);
+                        cairo_stroke (cr);
+                }
 
                 cairo_restore (cr);
         }
@@ -876,8 +956,8 @@ draw_fg_layer (glView  *view,
 
         gl_cairo_label_path (cr, view->label->template, view->label->rotate_flag, FALSE);
 
-        cairo_set_line_width (cr, 3.0/(view->home_scale * view->zoom));
-        cairo_set_source_rgb (cr, 0.68, 0.85, 0.90);
+        cairo_set_line_width (cr, OUTLINE_WIDTH_PIXELS/(view->home_scale * view->zoom));
+        cairo_set_source_rgb (cr, OUTLINE_RGB_ARGS);
         cairo_stroke (cr);
 }
 
@@ -921,19 +1001,25 @@ draw_select_region_layer (glView  *view,
 
         if (view->select_region_visible)
         {
-                x1 = MIN (view->select_region_x1, view->select_region_x2);
-                y1 = MIN (view->select_region_y1, view->select_region_y2);
-                w  = fabs (view->select_region_x2 - view->select_region_x1);
-                h  = fabs (view->select_region_y2 - view->select_region_y1);
+                x1 = MIN (view->select_region.x1, view->select_region.x2);
+                y1 = MIN (view->select_region.y1, view->select_region.y2);
+                w  = fabs (view->select_region.x2 - view->select_region.x1);
+                h  = fabs (view->select_region.y2 - view->select_region.y1);
+
+                cairo_save (cr);
+
+                cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
 
                 cairo_rectangle (cr, x1, y1, w, h);
 
-                cairo_set_source_rgba (cr, 0.75, 0.75, 1.0, 0.5);
+                cairo_set_source_rgba (cr, SELECT_FILL_RGBA_ARGS);
                 cairo_fill_preserve (cr);
 
-                cairo_set_line_width (cr, 3.0/(view->home_scale * view->zoom));
-                cairo_set_source_rgba (cr, 0, 0, 1.0, 0.5);
+                cairo_set_line_width (cr, SELECT_LINE_WIDTH_PIXELS/(view->home_scale * view->zoom));
+                cairo_set_source_rgba (cr, SELECT_LINE_RGBA_ARGS);
                 cairo_stroke (cr);
+
+                cairo_restore (cr);
         }
 }
 
@@ -1159,38 +1245,39 @@ gl_view_unselect_all (glView *view)
 /* Select all objects within given rectangular region (adding to selection). */
 /*****************************************************************************/
 void
-gl_view_select_region (glView  *view,
-                      gdouble  x1,
-                      gdouble  y1,
-                      gdouble  x2,
-                      gdouble  y2)
+gl_view_select_region (glView        *view,
+                       glLabelRegion *region)
 {
        GList         *p;
        glViewObject  *view_object;
        glLabelObject *object;
         gdouble        r_x1, r_y1;
         gdouble        r_x2, r_y2;
-       gdouble        i_x1, i_y1;
-       gdouble        i_x2, i_y2;
+        glLabelRegion  obj_extent;
 
        gl_debug (DEBUG_VIEW, "START");
 
        g_return_if_fail (view && GL_IS_VIEW (view));
 
-        r_x1 = MIN (x1, x2);
-        r_y1 = MIN (y1, y2);
-        r_x2 = MAX (x1, x2);
-        r_y2 = MAX (y1, y2);
+        r_x1 = MIN (region->x1, region->x2);
+        r_y1 = MIN (region->y1, region->y2);
+        r_x2 = MAX (region->x1, region->x2);
+        r_y2 = MAX (region->y1, region->y2);
 
-       for (p = view->object_list; p != NULL; p = p->next) {
+       for (p = view->object_list; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT(p->data);
-               if (!gl_view_is_object_selected (view, view_object)) {
+               if (!gl_view_is_object_selected (view, view_object))
+                {
 
                        object = gl_view_object_get_object (view_object);
 
-                       gl_label_object_get_extent (object, &i_x1, &i_y1, &i_x2, &i_y2);
-                       if ((i_x1 >= r_x1) && (i_x2 <= r_x2) && (i_y1 >= r_y1)
-                           && (i_y2 <= r_y2)) {
+                       gl_label_object_get_extent (object, &obj_extent);
+                       if ((obj_extent.x1 >= r_x1) &&
+                            (obj_extent.x2 <= r_x2) &&
+                            (obj_extent.y1 >= r_y1) &&
+                            (obj_extent.y2 <= r_y2))
+                        {
                                select_object_real (view, view_object);
                        }
 
@@ -1362,9 +1449,11 @@ gl_view_is_selection_atomic (glView *view)
 void
 gl_view_delete_selection (glView *view)
 {
-       GList *object_list;
-       GList *p;
-       GList *p_next;
+       GList         *object_list;
+       GList         *p;
+       GList         *p_next;
+       glViewObject  *view_object;
+       glLabelObject *object;
 
        gl_debug (DEBUG_VIEW, "START");
 
@@ -1376,10 +1465,13 @@ gl_view_delete_selection (glView *view)
 
        for (p = object_list; p != NULL; p = p_next) {
                p_next = p->next;
-               g_object_unref (G_OBJECT (p->data));
-               object_list = g_list_delete_link (object_list, p);
+               view_object = GL_VIEW_OBJECT (p->data);
+               object = gl_view_object_get_object (view_object);
+                gl_label_object_remove (object);
        }
 
+        g_list_free (object_list);
+
        gl_debug (DEBUG_VIEW, "END");
 }
 
@@ -1579,7 +1671,8 @@ gl_view_align_selection_left (glView *view)
        GList         *p;
        glViewObject  *view_object;
        glLabelObject *object;
-       gdouble        dx, x1min, x1, y1, x2, y2;
+       gdouble        dx, x1_min;
+        glLabelRegion  obj_extent;
 
        gl_debug (DEBUG_VIEW, "START");
 
@@ -1592,20 +1685,23 @@ gl_view_align_selection_left (glView *view)
        p = view->selected_object_list;
        view_object = GL_VIEW_OBJECT (p->data);
        object = gl_view_object_get_object (view_object);
-       gl_label_object_get_extent (object, &x1min, &y1, &x2, &y2);
-       for (p = p->next; p != NULL; p = p->next) {
+       gl_label_object_get_extent (object, &obj_extent);
+        x1_min = obj_extent.x1;
+       for (p = p->next; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               if ( x1 < x1min ) x1min = x1;
+               gl_label_object_get_extent (object, &obj_extent);
+               if ( obj_extent.x1 < x1_min ) x1_min = obj_extent.x1;
        }
 
        /* now adjust the object positions to line up the left edges */
-       for (p = view->selected_object_list; p != NULL; p = p->next) {
+       for (p = view->selected_object_list; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               dx = x1min - x1;
+               gl_label_object_get_extent (object, &obj_extent);
+               dx = x1_min - obj_extent.x1;
                gl_label_object_set_position_relative (object, dx, 0.0);
        }
 
@@ -1622,10 +1718,8 @@ gl_view_align_selection_right (glView *view)
        GList         *p;
        glViewObject  *view_object;
        glLabelObject *object;
-       gdouble        dx;
-       gdouble        x1, y1;
-       gdouble        x2, y2;
-       gdouble        x2max;
+       gdouble        dx, x2_max;
+        glLabelRegion  obj_extent;
 
        gl_debug (DEBUG_VIEW, "START");
 
@@ -1638,20 +1732,23 @@ gl_view_align_selection_right (glView *view)
        p = view->selected_object_list;
        view_object = GL_VIEW_OBJECT (p->data);
        object = gl_view_object_get_object (view_object);
-       gl_label_object_get_extent (object, &x1, &y1, &x2max, &y2);
-       for (p = p->next; p != NULL; p = p->next) {
+       gl_label_object_get_extent (object, &obj_extent);
+        x2_max = obj_extent.x2;
+       for (p = p->next; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               if ( x2 > x2max ) x2max = x2;
+               gl_label_object_get_extent (object, &obj_extent);
+               if ( obj_extent.x2 > x2_max ) x2_max = obj_extent.x2;
        }
 
        /* now adjust the object positions to line up the right edges */
-       for (p = view->selected_object_list; p != NULL; p = p->next) {
+       for (p = view->selected_object_list; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               dx = x2max - x2;
+               gl_label_object_get_extent (object, &obj_extent);
+               dx = x2_max - obj_extent.x2;
                gl_label_object_set_position_relative (object, dx, 0.0);
        }
 
@@ -1670,8 +1767,7 @@ gl_view_align_selection_hcenter (glView *view)
        gdouble        dx;
        gdouble        dxmin;
        gdouble        xsum, xavg;
-       gdouble        x1, y1;
-       gdouble        x2, y2;
+        glLabelRegion  obj_extent;
        gdouble        xcenter;
        gint           n;
 
@@ -1685,11 +1781,12 @@ gl_view_align_selection_hcenter (glView *view)
        /* find average center of objects */
        xsum = 0.0;
        n = 0;
-       for (p = view->selected_object_list; p != NULL; p = p->next) {
+       for (p = view->selected_object_list; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               xsum += (x1 + x2) / 2.0;
+               gl_label_object_get_extent (object, &obj_extent);
+               xsum += (obj_extent.x1 + obj_extent.x2) / 2.0;
                n++;
        }
        xavg = xsum / n;
@@ -1698,17 +1795,19 @@ gl_view_align_selection_hcenter (glView *view)
        p = view->selected_object_list;
        view_object = GL_VIEW_OBJECT (p->data);
        object = gl_view_object_get_object (view_object);
-       gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-       dxmin = fabs (xavg - (x1 + x2)/2.0);
-       xcenter = (x1 + x2)/2.0;
-       for (p = p->next; p != NULL; p = p->next) {
+       gl_label_object_get_extent (object, &obj_extent);
+       dxmin = fabs (xavg - (obj_extent.x1 + obj_extent.x2)/2.0);
+       xcenter = (obj_extent.x1 + obj_extent.x2)/2.0;
+       for (p = p->next; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               dx = fabs (xavg - (x1 + x2)/2.0);
-               if ( dx < dxmin ) {
+               gl_label_object_get_extent (object, &obj_extent);
+               dx = fabs (xavg - (obj_extent.x1 + obj_extent.x2)/2.0);
+               if ( dx < dxmin )
+                {
                        dxmin = dx;
-                       xcenter = (x1 + x2)/2.0;
+                       xcenter = (obj_extent.x1 + obj_extent.x2)/2.0;
                }
        }
 
@@ -1716,8 +1815,8 @@ gl_view_align_selection_hcenter (glView *view)
        for (p = view->selected_object_list; p != NULL; p = p->next) {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               dx = xcenter - (x1 + x2)/2.0;
+               gl_label_object_get_extent (object, &obj_extent);
+               dx = xcenter - (obj_extent.x1 + obj_extent.x2)/2.0;
                gl_label_object_set_position_relative (object, dx, 0.0);
        }
 
@@ -1733,10 +1832,8 @@ gl_view_align_selection_top (glView *view)
        GList         *p;
        glViewObject  *view_object;
        glLabelObject *object;
-       gdouble        dy;
-       gdouble        x1, y1;
-       gdouble        x2, y2;
-       gdouble        y1min;
+       gdouble        dy, y1_min;
+        glLabelRegion  obj_extent;
 
        gl_debug (DEBUG_VIEW, "START");
 
@@ -1749,20 +1846,23 @@ gl_view_align_selection_top (glView *view)
        p = view->selected_object_list;
        view_object = GL_VIEW_OBJECT (p->data);
        object = gl_view_object_get_object (view_object);
-       gl_label_object_get_extent (object, &x1, &y1min, &x2, &y2);
-       for (p = p->next; p != NULL; p = p->next) {
+       gl_label_object_get_extent (object, &obj_extent);
+        y1_min = obj_extent.y1;
+       for (p = p->next; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               if ( y1 < y1min ) y1min = y1;
+               gl_label_object_get_extent (object, &obj_extent);
+               if ( obj_extent.y1 < y1_min ) y1_min = obj_extent.y1;
        }
 
        /* now adjust the object positions to line up the top edges */
-       for (p = view->selected_object_list; p != NULL; p = p->next) {
+       for (p = view->selected_object_list; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               dy = y1min - y1;
+               gl_label_object_get_extent (object, &obj_extent);
+               dy = y1_min - obj_extent.y1;
                gl_label_object_set_position_relative (object, 0.0, dy);
        }
 
@@ -1778,10 +1878,8 @@ gl_view_align_selection_bottom (glView *view)
        GList         *p;
        glViewObject  *view_object;
        glLabelObject *object;
-       gdouble        dy;
-       gdouble        x1, y1;
-       gdouble        x2, y2;
-       gdouble        y2max;
+       gdouble        dy, y2_max;
+        glLabelRegion  obj_extent;
 
        gl_debug (DEBUG_VIEW, "START");
 
@@ -1794,20 +1892,23 @@ gl_view_align_selection_bottom (glView *view)
        p = view->selected_object_list;
        view_object = GL_VIEW_OBJECT (p->data);
        object = gl_view_object_get_object (view_object);
-       gl_label_object_get_extent (object, &x1, &y1, &x2, &y2max);
-       for (p = p->next; p != NULL; p = p->next) {
+       gl_label_object_get_extent (object, &obj_extent);
+        y2_max = obj_extent.y2;
+       for (p = p->next; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               if ( y2 > y2max ) y2max = y2;
+               gl_label_object_get_extent (object, &obj_extent);
+               if ( obj_extent.y2 > y2_max ) y2_max = obj_extent.y2;
        }
 
        /* now adjust the object positions to line up the bottom edges */
-       for (p = view->selected_object_list; p != NULL; p = p->next) {
+       for (p = view->selected_object_list; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               dy = y2max - y2;
+               gl_label_object_get_extent (object, &obj_extent);
+               dy = y2_max - obj_extent.y2;
                gl_label_object_set_position_relative (object, 0.0, dy);
        }
 
@@ -1826,8 +1927,7 @@ gl_view_align_selection_vcenter (glView *view)
        gdouble        dy;
        gdouble        dymin;
        gdouble        ysum, yavg;
-       gdouble        x1, y1;
-       gdouble        x2, y2;
+        glLabelRegion  obj_extent;
        gdouble        ycenter;
        gint           n;
 
@@ -1841,11 +1941,12 @@ gl_view_align_selection_vcenter (glView *view)
        /* find average center of objects */
        ysum = 0.0;
        n = 0;
-       for (p = view->selected_object_list; p != NULL; p = p->next) {
+       for (p = view->selected_object_list; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               ysum += (y1 + y2) / 2.0;
+               gl_label_object_get_extent (object, &obj_extent);
+               ysum += (obj_extent.y1 + obj_extent.y2) / 2.0;
                n++;
        }
        yavg = ysum / n;
@@ -1854,26 +1955,29 @@ gl_view_align_selection_vcenter (glView *view)
        p = view->selected_object_list;
        view_object = GL_VIEW_OBJECT (p->data);
        object = gl_view_object_get_object (view_object);
-       gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-       dymin = fabs (yavg - (y1 + y2)/2.0);
-       ycenter = (y1 + y2)/2.0;
-       for (p = p->next; p != NULL; p = p->next) {
+       gl_label_object_get_extent (object, &obj_extent);
+       dymin = fabs (yavg - (obj_extent.y1 + obj_extent.y2)/2.0);
+       ycenter = (obj_extent.y1 + obj_extent.y2)/2.0;
+       for (p = p->next; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               dy = fabs (yavg - (y1 + y2)/2.0);
-               if ( dy < dymin ) {
+               gl_label_object_get_extent (object, &obj_extent);
+               dy = fabs (yavg - (obj_extent.y1 + obj_extent.y2)/2.0);
+               if ( dy < dymin )
+                {
                        dymin = dy;
-                       ycenter = (y1 + y2)/2.0;
+                       ycenter = (obj_extent.y1 + obj_extent.y2)/2.0;
                }
        }
 
        /* now adjust the object positions to line up this center */
-       for (p = view->selected_object_list; p != NULL; p = p->next) {
+       for (p = view->selected_object_list; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               dy = ycenter - (y1 + y2)/2.0;
+               gl_label_object_get_extent (object, &obj_extent);
+               dy = ycenter - (obj_extent.y1 + obj_extent.y2)/2.0;
                gl_label_object_set_position_relative (object, 0.0, dy);
        }
 
@@ -1892,8 +1996,7 @@ gl_view_center_selection_horiz (glView *view)
        gdouble        dx;
        gdouble        x_label_center;
        gdouble        x_obj_center;
-       gdouble        x1, y1;
-       gdouble        x2, y2;
+       glLabelRegion  obj_extent;
        gdouble        w, h;
 
        gl_debug (DEBUG_VIEW, "START");
@@ -1906,11 +2009,12 @@ gl_view_center_selection_horiz (glView *view)
        x_label_center = w / 2.0;
 
        /* adjust the object positions */
-       for (p = view->selected_object_list; p != NULL; p = p->next) {
+       for (p = view->selected_object_list; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               x_obj_center = (x1 + x2) / 2.0;
+               gl_label_object_get_extent (object, &obj_extent);
+               x_obj_center = (obj_extent.x1 + obj_extent.x2) / 2.0;
                dx = x_label_center - x_obj_center;
                gl_label_object_set_position_relative (object, dx, 0.0);
        }
@@ -1931,8 +2035,7 @@ gl_view_center_selection_vert (glView *view)
        gdouble        dy;
        gdouble        y_label_center;
        gdouble        y_obj_center;
-       gdouble        x1, y1;
-       gdouble        x2, y2;
+       glLabelRegion  obj_extent;
        gdouble        w, h;
 
        gl_debug (DEBUG_VIEW, "START");
@@ -1945,11 +2048,12 @@ gl_view_center_selection_vert (glView *view)
        y_label_center = h / 2.0;
 
        /* adjust the object positions */
-       for (p = view->selected_object_list; p != NULL; p = p->next) {
+       for (p = view->selected_object_list; p != NULL; p = p->next)
+        {
                view_object = GL_VIEW_OBJECT (p->data);
                object = gl_view_object_get_object (view_object);
-               gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
-               y_obj_center = (y1 + y2) / 2.0;
+               gl_label_object_get_extent (object, &obj_extent);
+               y_obj_center = (obj_extent.y1 + obj_extent.y2) / 2.0;
                dy = y_label_center - y_obj_center;
                gl_label_object_set_position_relative (object, 0.0, dy);
        }
@@ -1973,7 +2077,8 @@ gl_view_move_selection (glView  *view,
 
        g_return_if_fail (view && GL_IS_VIEW (view));
 
-       for (p = view->selected_object_list; p != NULL; p = p->next) {
+       for (p = view->selected_object_list; p != NULL; p = p->next)
+        {
 
                object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
                gl_label_object_set_position_relative (object, dx, dy);
@@ -1996,10 +2101,12 @@ gl_view_can_selection_text (glView *view)
 
        g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
 
-       for (p = view->selected_object_list; p != NULL; p = p->next) {
+       for (p = view->selected_object_list; p != NULL; p = p->next)
+        {
 
                object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
-               if (gl_label_object_can_text (object)) {
+               if (gl_label_object_can_text (object))
+                {
                        return TRUE;
                }
 
@@ -3147,9 +3254,16 @@ motion_notify_event_cb (glView            *view,
                         break;
 
                 case GL_VIEW_ARROW_SELECT_REGION:
-                        view->select_region_x2 = x;
-                        view->select_region_y2 = y;
+#ifdef CLIP_UPDATES                                
+                        gl_view_update_region (view, cr, &view->select_region);
+#endif
+                        view->select_region.x2 = x;
+                        view->select_region.y2 = y;
+#ifdef CLIP_UPDATES                                
+                        gl_view_update_region (view, cr, &view->select_region);
+#else
                         gl_view_update (view);
+#endif
                         break;
 
                 case GL_VIEW_ARROW_MOVE:
@@ -3213,6 +3327,21 @@ motion_notify_event_cb (glView            *view,
 
        cairo_destroy (cr);
 
+        /*
+         * FIXME: we re-establish grabs here if the grab has been lost.  We seem to be
+         *        losing grabs when we emit signals that lead to the manipulation of
+         *        the GtkUIManager.  Needs more investigation
+         */
+        if (view->grabbed_flag && !gdk_pointer_is_grabbed ())
+        {
+                gdk_pointer_grab (GTK_LAYOUT (view->canvas)->bin_window,
+                                  FALSE,
+                                  (GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK),
+                                  NULL,
+                                  NULL,
+                                  event->time);
+        }
+
         return return_value;
 }
 
@@ -3297,11 +3426,10 @@ button_press_event_cb (glView            *view,
                                 }
 
                                 view->select_region_visible = TRUE;
-                                view->select_region_x1 = x;
-                                view->select_region_y1 = y;
-                                view->select_region_x2 = x;
-                                view->select_region_y2 = y;
-                                gl_view_update (view);
+                                view->select_region.x1 = x;
+                                view->select_region.y1 = y;
+                                view->select_region.x2 = x;
+                                view->select_region.y2 = y;
 
                                 view->state = GL_VIEW_ARROW_SELECT_REGION;
                         }
@@ -3341,6 +3469,14 @@ button_press_event_cb (glView            *view,
                 default:
                         g_message ("Invalid view mode.");      /*Should not happen!*/
                 }
+
+                view->grabbed_flag = TRUE;
+                gdk_pointer_grab (GTK_LAYOUT (view->canvas)->bin_window,
+                                  FALSE,
+                                  (GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK),
+                                  NULL,
+                                  NULL,
+                                  event->time);
                 break;
 
         case 3:
@@ -3387,6 +3523,8 @@ button_release_event_cb (glView            *view,
         {
 
         case 1:
+                view->grabbed_flag = FALSE;
+                gdk_pointer_ungrab (event->time);
                 /*
                  * Handle event as appropriate for mode
                  */
@@ -3402,17 +3540,17 @@ button_release_event_cb (glView            *view,
                                 break;
 
                         case GL_VIEW_ARROW_SELECT_REGION:
-                                view->select_region_visible = FALSE;
-                                view->select_region_x2 = x;
-                                view->select_region_y2 = y;
+#ifdef CLIP_UPDATES                                
+                                gl_view_update_region (view, cr, &view->select_region);
+#else
+                                gl_view_update (view);
+#endif
 
-                                gl_view_select_region (view,
-                                                       view->select_region_x1,
-                                                       view->select_region_y1,
-                                                       view->select_region_x2,
-                                                       view->select_region_y2);
+                                view->select_region_visible = FALSE;
+                                view->select_region.x2 = x;
+                                view->select_region.y2 = y;
 
-                                gl_view_update (view);
+                                gl_view_select_region (view, &view->select_region);
 
                                 view->state = GL_VIEW_IDLE;
                                 break;