aboutsummaryrefslogblamecommitdiffstats
path: root/widgets/e-reflow/e-reflow.c
blob: 2cd4a1d153aaafb7bf3b7a1f82dcc6c6e747ccc7 (plain) (tree)






















                                                                           
                 










                                                                            

                                                                                                                        
















                                                            
                          

















































                                                                                      

                                                                      












                                                               


                                            









                               
                             


                      

                              






                                      













                                                          
                                  
                



                                                                  










                                                               


                                                            
























                                                                          


                                                                        










                                                                               
                                  















                                          


                                                






                                                                
           
                                                
 
               



                                         









                                                       


                                                        























                                                                                    



                                                                      
                               
                                    


                                                                                            
                                                                                                     
                                                                                                                   

                                                                                 







                                                                                                      















                                                                                                                                                                                       

                                                                  











                                                                                                                                               

                                                                   
                                                                   
                     
                                














































                                                                                                                      

                  
            
                  























                                                                                  
 



                                                                        
                              

                                           
                            


                                                                                                  

                                              




                                            




                                                 
                                                  

                                                








                                                                   
                                              

                                                



















                                                                                                                  
                                                          

















                                                                                                    
                          

                              

                                   

                                                                                               










                                           
 
































                                                                                                                  
                                                                       














                                                                                                                                     
                                                                       








                                                                                                                                     















                                                                                                          
                          
                        


                                                               


                                            
         
                        
 



                            
                               













































                                                                                    

                                      











                                              
                                               



                                               


                                                                        










                                                                                  


                                                                                

















                                                                                            

                                                                  










                                                                                  

                                                                      















                                                                    
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* 
 * e-reflow.c
 * Copyright (C) 2000  Helix Code, Inc.
 * Author: Chris Lahey <clahey@helixcode.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include <gnome.h>
#include <math.h>
#include "e-reflow.h"
#include "e-canvas-utils.h"
static void e_reflow_init       (EReflow         *card);
static void e_reflow_class_init (EReflowClass    *klass);
static void e_reflow_set_arg (GtkObject *o, GtkArg *arg, guint arg_id);
static void e_reflow_get_arg (GtkObject *object, GtkArg *arg, guint arg_id);
static gboolean e_reflow_event (GnomeCanvasItem *item, GdkEvent *event);
static void e_reflow_realize (GnomeCanvasItem *item);
static void e_reflow_unrealize (GnomeCanvasItem *item);
static void e_reflow_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
                    int x, int y, int width, int height);
static void e_reflow_update (GnomeCanvasItem *item, double affine[6], ArtSVP *clip_path, gint flags);
static double e_reflow_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item);

static void _update_reflow ( EReflow *reflow );
static void _resize( GtkObject *object, gpointer data );
static void _queue_reflow(EReflow *e_reflow);

static GnomeCanvasGroupClass *parent_class = NULL;

enum {
    E_REFLOW_RESIZE,
    E_REFLOW_LAST_SIGNAL
};

static guint e_reflow_signals[E_REFLOW_LAST_SIGNAL] = { 0 };

/* The arguments we take */
enum {
    ARG_0,
    ARG_MINIMUM_WIDTH,
    ARG_WIDTH,
    ARG_HEIGHT
};

GtkType
e_reflow_get_type (void)
{
  static GtkType reflow_type = 0;

  if (!reflow_type)
    {
      static const GtkTypeInfo reflow_info =
      {
        "EReflow",
        sizeof (EReflow),
        sizeof (EReflowClass),
        (GtkClassInitFunc) e_reflow_class_init,
        (GtkObjectInitFunc) e_reflow_init,
        /* reserved_1 */ NULL,
        /* reserved_2 */ NULL,
        (GtkClassInitFunc) NULL,
      };

      reflow_type = gtk_type_unique (gnome_canvas_group_get_type (), &reflow_info);
    }

  return reflow_type;
}

static void
e_reflow_class_init (EReflowClass *klass)
{
  GtkObjectClass *object_class;
  GnomeCanvasItemClass *item_class;

  object_class = (GtkObjectClass*) klass;
  item_class = (GnomeCanvasItemClass *) klass;

  parent_class = gtk_type_class (gnome_canvas_group_get_type ());
  
  e_reflow_signals[E_REFLOW_RESIZE] =
      gtk_signal_new ("resize",
              GTK_RUN_LAST,
              object_class->type,
              GTK_SIGNAL_OFFSET (EReflowClass, resize),
              gtk_marshal_NONE__NONE,
              GTK_TYPE_NONE, 0);

  gtk_object_class_add_signals (object_class, e_reflow_signals, E_REFLOW_LAST_SIGNAL);
  
  gtk_object_add_arg_type ("EReflow::minimum_width", GTK_TYPE_DOUBLE, 
               GTK_ARG_READWRITE, ARG_MINIMUM_WIDTH); 
  gtk_object_add_arg_type ("EReflow::width", GTK_TYPE_DOUBLE, 
               GTK_ARG_READABLE, ARG_WIDTH); 
  gtk_object_add_arg_type ("EReflow::height", GTK_TYPE_DOUBLE, 
               GTK_ARG_READWRITE, ARG_HEIGHT);
 
  object_class->set_arg = e_reflow_set_arg;
  object_class->get_arg = e_reflow_get_arg;
  /*  object_class->destroy = e_reflow_destroy; */
  
  /* GnomeCanvasItem method overrides */
  item_class->event       = e_reflow_event;
  item_class->realize     = e_reflow_realize;
  item_class->unrealize   = e_reflow_unrealize;
  item_class->draw        = e_reflow_draw;
  item_class->update      = e_reflow_update;
  item_class->point       = e_reflow_point;
}

static void
e_reflow_init (EReflow *reflow)
{
  /*   reflow->card = NULL;*/
  reflow->items = NULL;
  reflow->columns = NULL;
  reflow->column_width = 150;

  reflow->minimum_width = 10;
  reflow->width = 10;
  reflow->height = 10;
  reflow->idle = 0;

  reflow->column_drag = FALSE;

  reflow->need_height_update = FALSE;
  reflow->need_column_resize = FALSE;

  reflow->default_cursor_shown = TRUE;
  reflow->arrow_cursor = NULL;
  reflow->default_cursor = NULL;
}

static void
e_reflow_set_arg (GtkObject *o, GtkArg *arg, guint arg_id)
{
    GnomeCanvasItem *item;
    EReflow *e_reflow;

    item = GNOME_CANVAS_ITEM (o);
    e_reflow = E_REFLOW (o);
    
    switch (arg_id){
    case ARG_HEIGHT:
      e_reflow->height = GTK_VALUE_DOUBLE (*arg);
      _queue_reflow(e_reflow);
      break;
    case ARG_MINIMUM_WIDTH:
        e_reflow->minimum_width = GTK_VALUE_DOUBLE (*arg);
        _queue_reflow(e_reflow);
        break;
    }
}

static void
e_reflow_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
{
    EReflow *e_reflow;

    e_reflow = E_REFLOW (object);

    switch (arg_id) {
    case ARG_MINIMUM_WIDTH:
      GTK_VALUE_DOUBLE (*arg) = e_reflow->minimum_width;
      break;
    case ARG_WIDTH:
      GTK_VALUE_DOUBLE (*arg) = e_reflow->width;
      break;
    case ARG_HEIGHT:
      GTK_VALUE_DOUBLE (*arg) = e_reflow->height;
      break;
    default:
      arg->type = GTK_TYPE_INVALID;
      break;
    }
}

static void
e_reflow_realize (GnomeCanvasItem *item)
{
    EReflow *e_reflow;
    GnomeCanvasGroup *group;
    GList *list;

    e_reflow = E_REFLOW (item);
    group = GNOME_CANVAS_GROUP( item );

    if (GNOME_CANVAS_ITEM_CLASS(parent_class)->realize)
        (* GNOME_CANVAS_ITEM_CLASS(parent_class)->realize) (item);
    
    e_reflow->arrow_cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
    e_reflow->default_cursor = gdk_cursor_new (GDK_LEFT_PTR);

    for(list = e_reflow->items; list; list = g_list_next(list)) {
        GnomeCanvasItem *item = GNOME_CANVAS_ITEM(list->data);
        gtk_signal_connect(GTK_OBJECT(item),
                   "resize",
                   GTK_SIGNAL_FUNC(_resize),
                   (gpointer) e_reflow);
        gnome_canvas_item_set(item,
                      "width", (double) e_reflow->column_width,
                      NULL);
    }

    _queue_reflow( e_reflow );
    
    if (!item->canvas->aa) {
    }
}

static void
e_reflow_unrealize (GnomeCanvasItem *item)
{
  EReflow *e_reflow;

  e_reflow = E_REFLOW (item);

  if (!item->canvas->aa)
    {
    }
  
  gdk_cursor_destroy (e_reflow->arrow_cursor);
  gdk_cursor_destroy (e_reflow->default_cursor);

  g_list_free (e_reflow->items);
  g_list_free (e_reflow->columns);

  if (GNOME_CANVAS_ITEM_CLASS(parent_class)->unrealize)
    (* GNOME_CANVAS_ITEM_CLASS(parent_class)->unrealize) (item);
}

static gint
e_reflow_pick_line (EReflow *e_reflow, double x)
{
    x += 9;
    x /= e_reflow->column_width + 16;
    return x;
}

static gboolean
e_reflow_event (GnomeCanvasItem *item, GdkEvent *event)
{
  EReflow *e_reflow;
 
  e_reflow = E_REFLOW (item);

  switch( event->type )
    {
    case GDK_KEY_PRESS:
        if (event->key.keyval == GDK_Tab || 
        event->key.keyval == GDK_KP_Tab || 
        event->key.keyval == GDK_ISO_Left_Tab) {
            GList *list;
            for (list = e_reflow->items; list; list = list->next) {
                GnomeCanvasItem *item = GNOME_CANVAS_ITEM (list->data);
                gboolean has_focus;
                gtk_object_get(GTK_OBJECT(item),
                       "has_focus", &has_focus,
                       NULL);
                if (has_focus) {
                    if (event->key.state & GDK_SHIFT_MASK)
                        list = list->prev;
                    else
                        list = list->next;
                    if (list) {
                        item = GNOME_CANVAS_ITEM(list->data);
                        gnome_canvas_item_set(item,
                                  "has_focus", TRUE,
                                  NULL);
                        return 1;
                    } else {
                        return 0;
                    }
                }
            }
        }
        break;
    case GDK_BUTTON_PRESS:
        {
            GdkEventButton *button = (GdkEventButton *) event;
            double n_x;
            n_x = button->x;
            n_x += 9;
            n_x = fmod(n_x,(e_reflow->column_width + 16));
            if ( button->y >= 7 && button->y <= e_reflow->height - 7 && n_x < 16 ) {
                e_reflow->which_column_dragged = e_reflow_pick_line(e_reflow, button->x);
                e_reflow->start_x = e_reflow->which_column_dragged * (e_reflow->column_width + 16) - 1;
                e_reflow->temp_column_width = e_reflow->column_width;
                e_reflow->column_drag = TRUE;

                gnome_canvas_item_grab (item, 
                            GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK,
                            e_reflow->arrow_cursor,
                            button->time);

                e_reflow->previous_temp_column_width = -1;
                e_reflow->need_column_resize = TRUE;
                gnome_canvas_item_request_update(item);
                return TRUE;
            }
        }
        break;
    case GDK_BUTTON_RELEASE:
        if (e_reflow->column_drag) {
            GdkEventButton *button = (GdkEventButton *) event;
            GtkAdjustment *adjustment = gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas));
            e_reflow->temp_column_width = e_reflow->column_width +
                (button->x - e_reflow->start_x)/(e_reflow->which_column_dragged - e_reflow_pick_line(e_reflow, adjustment->value));
            if ( e_reflow->temp_column_width < 50 )
                e_reflow->temp_column_width = 50;
            gtk_adjustment_set_value(adjustment, adjustment->value + e_reflow_pick_line(e_reflow, adjustment->value) * (e_reflow->temp_column_width - e_reflow->column_width));
            e_reflow->column_width = e_reflow->temp_column_width;
            e_reflow->column_drag = FALSE;
            _queue_reflow(e_reflow);
            gnome_canvas_item_ungrab (item, button->time);
            return TRUE;
        }
        break;
    case GDK_MOTION_NOTIFY:
        if (e_reflow->column_drag) {
            double old_width = e_reflow->temp_column_width;
            GdkEventMotion *motion = (GdkEventMotion *) event;
            GtkAdjustment *adjustment = gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas));
            e_reflow->temp_column_width = e_reflow->column_width +
                (motion->x - e_reflow->start_x)/(e_reflow->which_column_dragged - e_reflow_pick_line(e_reflow, adjustment->value));
            if (e_reflow->temp_column_width < 50)
                e_reflow->temp_column_width = 50;
            if (old_width != e_reflow->temp_column_width) {
                e_reflow->need_column_resize = TRUE;
                gnome_canvas_item_request_update(item);
            }
            return TRUE;
        } else {
            GdkEventMotion *motion = (GdkEventMotion *) event;
            double n_x;
            n_x = motion->x;
            n_x += 9;
            n_x = fmod(n_x,(e_reflow->column_width + 16));
            if ( motion->y >= 7 && motion->y <= e_reflow->height - 7 && n_x < 16 ) {
                if ( e_reflow->default_cursor_shown ) {
                    gdk_window_set_cursor(GTK_WIDGET(item->canvas)->window, e_reflow->arrow_cursor);
                    e_reflow->default_cursor_shown = FALSE;
                }
            } else 
                if ( ! e_reflow->default_cursor_shown ) {
                    gdk_window_set_cursor(GTK_WIDGET(item->canvas)->window, e_reflow->default_cursor);
                    e_reflow->default_cursor_shown = TRUE;
                }
                
        }
        break;
    case GDK_ENTER_NOTIFY:
        if (!e_reflow->column_drag) {
            GdkEventCrossing *crossing = (GdkEventCrossing *) event;
            double n_x;
            n_x = crossing->x;
            n_x += 9;
            n_x = fmod(n_x,(e_reflow->column_width + 16));
            if ( crossing->y >= 7 && crossing->y <= e_reflow->height - 7 && n_x < 16 ) {
                if ( e_reflow->default_cursor_shown ) {
                    gdk_window_set_cursor(GTK_WIDGET(item->canvas)->window, e_reflow->arrow_cursor);
                    e_reflow->default_cursor_shown = FALSE;
                }
            }
        }
        break;
    case GDK_LEAVE_NOTIFY:
        if (!e_reflow->column_drag) {
            GdkEventCrossing *crossing = (GdkEventCrossing *) event;
            double n_x;
            n_x = crossing->x;
            n_x += 9;
            n_x = fmod(n_x,(e_reflow->column_width + 16));
            if ( !( crossing->y >= 7 && crossing->y <= e_reflow->height - 7 && n_x < 16 ) ) {
                if ( ! e_reflow->default_cursor_shown ) {
                    gdk_window_set_cursor(GTK_WIDGET(item->canvas)->window, e_reflow->default_cursor);
                    e_reflow->default_cursor_shown = TRUE;
                }
            }
        }
        break;
    default:
        break;
    }
  
  if (GNOME_CANVAS_ITEM_CLASS( parent_class )->event)
      return (* GNOME_CANVAS_ITEM_CLASS( parent_class )->event) (item, event);
  else
      return 0;
}

void
e_reflow_add_item(EReflow *e_reflow, GnomeCanvasItem *item)
{
    e_reflow->items = g_list_append(e_reflow->items, item);
    if ( GTK_OBJECT_FLAGS( e_reflow ) & GNOME_CANVAS_ITEM_REALIZED ) {
        gtk_signal_connect(GTK_OBJECT(item),
                   "resize",
                   GTK_SIGNAL_FUNC(_resize),
                   (gpointer) e_reflow);
        gnome_canvas_item_set(item,
                      "width", (double) e_reflow->column_width,
                      NULL);
        _queue_reflow(e_reflow);
    }

}

static void e_reflow_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
                    int x, int y, int width, int height)
{
    int x_rect, y_rect, width_rect, height_rect;
    gdouble running_width;
    EReflow *e_reflow = E_REFLOW(item);
    int i;
    double column_width;

    if (GNOME_CANVAS_ITEM_CLASS(parent_class)->draw)
        GNOME_CANVAS_ITEM_CLASS(parent_class)->draw (item, drawable, x, y, width, height);
    column_width = e_reflow->column_width;
    running_width = 7 + column_width + 7;
    x_rect = running_width;
    y_rect = 7;
    width_rect = 2;
    height_rect = e_reflow->height - 14;

    /* Compute first column to draw. */
    i = x;
    i /= column_width + 16;
    running_width += i * (column_width + 16);

    for ( ; i < e_reflow->column_count; i++) {
        if ( running_width > x + width )
            break;
        x_rect = running_width;
        gtk_paint_flat_box(GTK_WIDGET(item->canvas)->style,
                   drawable,
                   GTK_STATE_ACTIVE,
                   GTK_SHADOW_NONE,
                   NULL,
                   GTK_WIDGET(item->canvas),
                   "reflow",
                   x_rect - x,
                   y_rect - y,
                   width_rect,
                   height_rect);
        running_width += 2 + 7 + column_width + 7;
    }
    if (e_reflow->column_drag) {
        int start_line = e_reflow_pick_line(e_reflow,
                            gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas))->value); 
        i = x - start_line * (column_width + 16);
        running_width = start_line * (column_width + 16);
        column_width = e_reflow->temp_column_width;
        running_width -= start_line * (column_width + 16);
        i += start_line * (column_width + 16);
        running_width += 7 + column_width + 7;
        x_rect = running_width;
        y_rect = 7;
        width_rect = 2;
        height_rect = e_reflow->height - 14;

        /* Compute first column to draw. */
        i /= column_width + 16;
        running_width += i * (column_width + 16);
        
        for ( ; i < e_reflow->column_count; i++) {
            if ( running_width > x + width )
                break;
            x_rect = running_width;
            gdk_draw_rectangle(drawable,
                       GTK_WIDGET(item->canvas)->style->fg_gc[GTK_STATE_NORMAL],
                       TRUE,
                       x_rect - x,
                       y_rect - y,
                       width_rect - 1,
                       height_rect - 1);                       
            running_width += 2 + 7 + column_width + 7;
        }
    }
}

static void
e_reflow_update (GnomeCanvasItem *item, double affine[6], ArtSVP *clip_path, gint flags)
{
    EReflow *e_reflow;
    double x0, x1, y0, y1;

    e_reflow = E_REFLOW (item);

    if (GNOME_CANVAS_ITEM_CLASS(parent_class)->update)
        GNOME_CANVAS_ITEM_CLASS(parent_class)->update (item, affine, clip_path, flags);
    
    x0 = item->x1;
    y0 = item->y1;
    x1 = item->x2;
    y1 = item->y2;
    if ( x1 < x0 + e_reflow->width )
        x1 = x0 + e_reflow->width;
    if ( y1 < y0 + e_reflow->height )
        y1 = y0 + e_reflow->height;
    item->x2 = x1;
    item->y2 = y1;

    if (e_reflow->need_height_update) {
        x0 = item->x1;
        y0 = item->y1;
        x1 = item->x2;
        y1 = item->y2;
        if ( x0 > 0 )
            x0 = 0;
        if ( y0 > 0 )
            y0 = 0;
        if ( x1 < E_REFLOW(item)->width )
            x1 = E_REFLOW(item)->width;
        if ( x1 < E_REFLOW(item)->height )
            x1 = E_REFLOW(item)->height;

        gnome_canvas_request_redraw(item->canvas, x0, y0, x1, y1);
        e_reflow->need_height_update = FALSE;
    } else if (e_reflow->need_column_resize) {
        int x_rect, y_rect, width_rect, height_rect;
        int start_line = e_reflow_pick_line(e_reflow,
                            gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas))->value); 
        gdouble running_width;
        int i;
        double column_width;
        
        if ( e_reflow->previous_temp_column_width != -1 ) {
            running_width = start_line * (e_reflow->column_width + 16);
            column_width = e_reflow->previous_temp_column_width;
            running_width -= start_line * (column_width + 16);
            running_width += 7 + column_width + 7;
            y_rect = 7;
            width_rect = 2;
            height_rect = e_reflow->height - 14;
            
            for ( i = 0; i < e_reflow->column_count; i++) {
                x_rect = running_width;
                gnome_canvas_request_redraw(item->canvas, x_rect, y_rect, x_rect + width_rect, y_rect + height_rect);
                running_width += 2 + 7 + column_width + 7;
            }
        }
        
        if ( e_reflow->temp_column_width != -1 ) {
            running_width = start_line * (e_reflow->column_width + 16);
            column_width = e_reflow->temp_column_width;
            running_width -= start_line * (column_width + 16);
            running_width += 7 + column_width + 7;
            y_rect = 7;
            width_rect = 2;
            height_rect = e_reflow->height - 14;
            
            for ( i = 0; i < e_reflow->column_count; i++) {
                x_rect = running_width;
                gnome_canvas_request_redraw(item->canvas, x_rect, y_rect, x_rect + width_rect, y_rect + height_rect);
                running_width += 2 + 7 + column_width + 7;
            }
        }
        
        e_reflow->previous_temp_column_width = e_reflow->temp_column_width;
        e_reflow->need_column_resize = FALSE;
    }
}

static double
e_reflow_point (GnomeCanvasItem *item,
        double x, double y, int cx, int cy,
        GnomeCanvasItem **actual_item)
{
    EReflow *e_reflow = E_REFLOW(item);
    double distance = 1;

    if (GNOME_CANVAS_ITEM_CLASS(parent_class)->point)
        distance = GNOME_CANVAS_ITEM_CLASS(parent_class)->point (item, x, y, cx, cy, actual_item);
    if (*actual_item)
        return 0;

    if (y >= 7 && y <= e_reflow->height - 7) {
            float n_x;
        n_x = x;
        n_x += 9.0;
        n_x = fmod(n_x, (e_reflow->column_width + 16));
        if (n_x < 16.0) {
            *actual_item = item;
            return 0;
        }
    }
    return distance;
}

static void
_reflow( EReflow *e_reflow )
{
    gdouble running_height;
    GList *list;
    double item_height;

    if (e_reflow->columns) {
        g_list_free (e_reflow->columns);
        e_reflow->columns = NULL;
    }

    e_reflow->column_count = 0;

    if (e_reflow->items == NULL) {
        e_reflow->columns = NULL;
        e_reflow->column_count = 1;
        return;
    }

    list = e_reflow->items;
    
    gtk_object_get (GTK_OBJECT(list->data),
            "height", &item_height,
            NULL);
    running_height = 7 + item_height + 7;
    e_reflow->columns = g_list_append (e_reflow->columns, list);
    e_reflow->column_count = 1;

    list = g_list_next(list);

    for ( ; list; list = g_list_next(list)) {
        gtk_object_get (GTK_OBJECT(list->data),
                "height", &item_height,
                NULL);
        if (running_height + item_height + 7 > e_reflow->height) {
            running_height = 7 + item_height + 7;
            e_reflow->columns = g_list_append (e_reflow->columns, list);
            e_reflow->column_count ++;
        } else {
            running_height += item_height + 7;
        }
    }
}

static void
_update_reflow( EReflow *e_reflow )
{
    if ( GTK_OBJECT_FLAGS( e_reflow ) & GNOME_CANVAS_ITEM_REALIZED ) {

        gdouble old_width;
        gdouble running_width;

        _reflow (e_reflow);
        
        old_width = e_reflow->width;
        
        running_width = 7;

        if (e_reflow->items == NULL) {
        } else {
            GList *list;
            GList *next_column;
            gdouble item_height;
            gdouble running_height;

            running_height = 7;
            
            list = e_reflow->items;
            gtk_object_set (GTK_OBJECT(list->data),
                    "width", e_reflow->column_width,
                    NULL);
            gtk_object_get (GTK_OBJECT(list->data),
                    "height", &item_height,
                    NULL);
            e_canvas_item_move_absolute(GNOME_CANVAS_ITEM(list->data),
                            (double) running_width,
                            (double) running_height);
            running_height += item_height + 7;
            next_column = g_list_next(e_reflow->columns);
            list = g_list_next(list);
            
            for( ; list; list = g_list_next(list)) {
                gtk_object_set (GTK_OBJECT(list->data),
                        "width", e_reflow->column_width,
                        NULL);
                gtk_object_get (GTK_OBJECT(list->data),
                        "height", &item_height,
                        NULL);

                if (next_column && (next_column->data == list)) {
                    next_column = g_list_next (next_column);
                    running_height = 7;
                    running_width += e_reflow->column_width + 7 + 2 + 7;
                }
                e_canvas_item_move_absolute(GNOME_CANVAS_ITEM(list->data),
                                (double) running_width,
                                (double) running_height);

                running_height += item_height + 7;
            }
                 
        }
        e_reflow->width = running_width + e_reflow->column_width + 7;
        if ( e_reflow->width < e_reflow->minimum_width )
            e_reflow->width = e_reflow->minimum_width;
        if (old_width != e_reflow->width)
            gtk_signal_emit_by_name (GTK_OBJECT (e_reflow), "resize");
    }
}


static gboolean
_idle_reflow(gpointer data)
{
    EReflow *e_reflow = E_REFLOW(data);
    _update_reflow(e_reflow);
    e_reflow->need_height_update = TRUE;
    gnome_canvas_item_request_update(GNOME_CANVAS_ITEM(e_reflow));
    e_reflow->idle = 0;
    return FALSE;
}

static void
_queue_reflow(EReflow *e_reflow)
{
    if (e_reflow->idle == 0)
        e_reflow->idle = g_idle_add(_idle_reflow, e_reflow);
}

static void
_resize( GtkObject *object, gpointer data )
{
    _queue_reflow(E_REFLOW(data));
}