/* * The Grid Gnome Canvas Item: Implements the grid and * spreadsheet information display. * * Author: * Miguel de Icaza (miguel@kernel.org) */ #include #include #include "gnumeric.h" #include "gnumeric-sheet.h" #include "item-debug.h" #include "color.h" #include "dialogs.h" #include "cursors.h" static GnomeCanvasItem *item_grid_parent_class; /* The arguments we take */ enum { ARG_0, ARG_SHEET_VIEW, }; enum { SELECTING_CELL_RANGE }; static void item_grid_destroy (GtkObject *object) { ItemGrid *grid; grid = ITEM_GRID (object); if (GTK_OBJECT_CLASS (item_grid_parent_class)->destroy) (*GTK_OBJECT_CLASS (item_grid_parent_class)->destroy)(object); } static void item_grid_realize (GnomeCanvasItem *item) { GnomeCanvas *canvas = item->canvas; GdkVisual *visual; GdkWindow *window; ItemGrid *item_grid; GdkGC *gc; if (GNOME_CANVAS_ITEM_CLASS (item_grid_parent_class)->realize) (*GNOME_CANVAS_ITEM_CLASS (item_grid_parent_class)->realize)(item); item_grid = ITEM_GRID (item); window = GTK_WIDGET (item->canvas)->window; /* Configure the default grid gc */ item_grid->grid_gc = gc = gdk_gc_new (window); item_grid->fill_gc = gdk_gc_new (window); item_grid->gc = gdk_gc_new (window); /* Allocate the default colors */ item_grid->background = gs_white; item_grid->grid_color = gs_light_gray; item_grid->default_color = gs_black; gdk_gc_set_foreground (gc, &item_grid->grid_color); gdk_gc_set_background (gc, &item_grid->background); gdk_gc_set_foreground (item_grid->fill_gc, &item_grid->background); gdk_gc_set_background (item_grid->fill_gc, &item_grid->grid_color); /* Find out how we need to draw the selection with the current visual */ visual = gtk_widget_get_visual (GTK_WIDGET (canvas)); switch (visual->type){ case GDK_VISUAL_STATIC_GRAY: case GDK_VISUAL_TRUE_COLOR: case GDK_VISUAL_STATIC_COLOR: item_grid->visual_is_paletted = 0; break; default: item_grid->visual_is_paletted = 1; } } static void item_grid_unrealize (GnomeCanvasItem *item) { ItemGrid *item_grid = ITEM_GRID (item); gdk_gc_unref (item_grid->grid_gc); gdk_gc_unref (item_grid->fill_gc); gdk_gc_unref (item_grid->gc); item_grid->grid_gc = 0; item_grid->fill_gc = 0; item_grid->gc = 0; if (GNOME_CANVAS_ITEM_CLASS (item_grid_parent_class)->unrealize) (*GNOME_CANVAS_ITEM_CLASS (item_grid_parent_class)->unrealize)(item); } static void item_grid_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags) { if (GNOME_CANVAS_ITEM_CLASS (item_grid_parent_class)->update) (* GNOME_CANVAS_ITEM_CLASS (item_grid_parent_class)->update) (item, affine, clip_path, flags); item->x1 = 0; item->y1 = 0; item->x2 = INT_MAX; item->y2 = INT_MAX; gnome_canvas_group_child_bounds (GNOME_CANVAS_GROUP (item->parent), item); } /* * item_grid_find_col: return the column where x belongs to */ int item_grid_find_col (ItemGrid *item_grid, int x, int *col_origin) { int col = item_grid->left_col; int pixel = item_grid->left_offset; /* * FIXME: This should probably take negative numbers * as well to provide sliding when moving backwards (look * in item-cursor.c */ g_return_val_if_fail (x >= 0, 0); do { ColRowInfo *ci = sheet_col_get_info (item_grid->sheet, col); if (x >= pixel && x <= pixel + ci->pixels){ if (col_origin) *col_origin = pixel; return col; } col++; pixel += ci->pixels; } while (1); } /* * item_grid_find_row: return the row where y belongs to */ int item_grid_find_row (ItemGrid *item_grid, int y, int *row_origin) { int row = item_grid->top_row; int pixel = item_grid->top_offset; /* * FIXME: This should probably take negative numbers * as well to provide sliding when moving backwards (look * in item-cursor.c */ g_return_val_if_fail (y >= 0, 0); do { ColRowInfo *ri = sheet_row_get_info (item_grid->sheet, row); if (y >= pixel && y <= pixel + ri->pixels){ if (row_origin) *row_origin = pixel; return row; } row++; pixel += ri->pixels; } while (1); } /* * Sets the gc appropiately for inverting the color of a region * in the ItemGrid. * * We are mainly interested in getting accurrated black/white * inversion. * * On palleted displays, we play the trick of XORing the value * (this will render other colors sometimes randomly, depending on the * pallette contents). On non-palleted displays, we can use the * GDK_INVERT operation to invert the pixel value. */ static void item_grid_invert_gc (ItemGrid *item_grid) { GdkGC *gc; gc = item_grid->gc; gdk_gc_set_clip_rectangle (gc, NULL); if (item_grid->visual_is_paletted){ gdk_gc_set_function (gc, GDK_XOR); gdk_gc_set_foreground (gc, &gs_white); } else { gdk_gc_set_function (gc, GDK_INVERT); gdk_gc_set_foreground (gc, &gs_black); } } /* * Draw a cell. It gets pixel level coordinates * * Returns the number of columns used by the cell. */ static int item_grid_draw_cell (GdkDrawable *drawable, ItemGrid *item_grid, Cell *cell, int x1, int y1) { GdkGC *gc = item_grid->gc; int count; /* setup foreground */ gdk_gc_set_foreground (gc, &item_grid->default_color); if (cell->render_color) gdk_gc_set_foreground (gc, &cell->render_color->color); else { if (cell->style->valid_flags & STYLE_FORE_COLOR) gdk_gc_set_foreground (gc, &cell->style->fore_color->color); } if (cell->style->valid_flags & STYLE_BACK_COLOR){ gdk_gc_set_background (gc, &cell->style->back_color->color); } if ((cell->style->valid_flags & STYLE_PATTERN) && cell->style->pattern){ GnomeCanvasItem *item = GNOME_CANVAS_ITEM (item_grid); int p = cell->style->pattern - 1; /* * Next two lines are commented since the pattern display code of the cell * have not been tested (written?) */ /* gdk_gc_set_stipple (gc, GNUMERIC_SHEET (item->canvas)->patterns [p]); */ /* gdk_gc_set_fill (gc, GDK_STIPPLED); */ gdk_draw_rectangle (drawable, gc, TRUE, x1, y1, cell->col->pixels, cell->row->pixels); gdk_gc_set_fill (gc, GDK_SOLID); gdk_gc_set_stipple (gc, NULL); } count = cell_draw (cell, item_grid->sheet_view, gc, drawable, x1, y1); return count; } static void item_grid_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int height) { ItemGrid *item_grid = ITEM_GRID (item); Sheet *sheet = item_grid->sheet; GdkGC *grid_gc = item_grid->grid_gc; Cell *cell; int end_x, end_y; int paint_col, paint_row, max_paint_col, max_paint_row; int col, row; int x_paint, y_paint, real_x; int diff_x, diff_y; if (x < 0){ g_warning ("x < 0\n"); return; } if (y < 0){ g_warning ("y < 0\n"); return; } max_paint_col = max_paint_row = 0; paint_col = item_grid_find_col (item_grid, x, &x_paint); paint_row = item_grid_find_row (item_grid, y, &y_paint); col = paint_col; diff_x = x - x_paint; end_x = width + diff_x; diff_y = y - y_paint; end_y = height + diff_y; /* 1. The default background */ gdk_draw_rectangle (drawable, item_grid->fill_gc, TRUE, 0, 0, width, height); /* 2. the grids */ for (x_paint = -diff_x; x_paint < end_x; col++){ ColRowInfo *ci; ci = sheet_col_get_info (sheet, col); g_assert (ci->pixels != 0); gdk_draw_line (drawable, grid_gc, x_paint, 0, x_paint, height); x_paint += ci->pixels; max_paint_col = col; } row = paint_row; for (y_paint = -diff_y; y_paint < end_y; row++){ ColRowInfo *ri; ri = sheet_row_get_info (sheet, row); gdk_draw_line (drawable, grid_gc, 0, y_paint, width, y_paint); y_paint += ri->pixels; max_paint_row = row; } gdk_gc_set_function (item_grid->gc, GDK_COPY); row = paint_row; for (y_paint = -diff_y; y_paint < end_y; row++){ ColRowInfo *ri; ri = sheet_row_get_info (sheet, row); col = paint_col; for (x_paint = -diff_x; x_paint < end_x; col++){ ColRowInfo *ci; ci = sheet_col_get_info (sheet, col); cell = sheet_cell_get (sheet, col, row); if (cell){ item_grid_draw_cell (drawable, item_grid, cell, x_paint, y_paint); } else if (ri->pos != -1){ /* * If there was no cell, and the row has any cell allocated * (indicated by ri->pos != -1) */ real_x = x_paint; cell = row_cell_get_displayed_at (ri, col); /* * We found the cell that paints over this * cell, adjust x to point to the beginning * of that cell. */ if (cell){ int i, count, end_col; /* * Either adjust the left part */ for (i = cell->col->pos; i < col; i++){ ColRowInfo *tci; tci = sheet_col_get_info (sheet, i); real_x -= tci->pixels; } /* * Or adjust the right part */ for (i = col; i < cell->col->pos; i++){ ColRowInfo *tci; tci = sheet_col_get_info ( sheet, i); real_x += tci->pixels; } /* * Draw the cell */ count = item_grid_draw_cell ( drawable, item_grid, cell, real_x, y_paint); /* * Optimization: advance over every * cell we already painted on */ end_col = cell->col->pos + count; for (i = col+1; i < end_col; i++, col++){ ColRowInfo *tci; tci = sheet_col_get_info ( sheet, i); x_paint += tci->pixels; } } /* if cell */ } x_paint += ci->pixels; } y_paint += ri->pixels; } /* Now invert any selected cells */ item_grid_invert_gc (item_grid); row = paint_row; for (y_paint = -diff_y; y_paint < end_y; row++){ ColRowInfo *ri, *ci; ri = sheet_row_get_info (sheet, row); col = paint_col; for (x_paint = -diff_x; x_paint < end_x; col++, x_paint += ci->pixels){ ci = sheet_col_get_info (sheet, col); if (sheet->cursor_col == col && sheet->cursor_row == row) continue; if (!sheet_selection_is_cell_selected (sheet, col, row)) continue; gdk_draw_rectangle (drawable, item_grid->gc, TRUE, x_paint+1, y_paint+1, ci->pixels-1, ri->pixels-1); } y_paint += ri->pixels; } } static double item_grid_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item) { *actual_item = item; return 0.0; } static void item_grid_translate (GnomeCanvasItem *item, double dx, double dy) { printf ("item_grid_translate %g, %g\n", dx, dy); } static void context_destroy_menu (GtkWidget *widget) { gtk_widget_destroy (gtk_widget_get_toplevel (widget)); } static void context_cut_cmd (GtkWidget *widget, ItemGrid *item_grid) { sheet_selection_cut (item_grid->sheet); context_destroy_menu (widget); } static void context_copy_cmd (GtkWidget *widget, ItemGrid *item_grid) { sheet_selection_copy (item_grid->sheet); context_destroy_menu (widget); } static void context_paste_cmd (GtkWidget *widget, ItemGrid *item_grid) { Sheet *sheet = item_grid->sheet; sheet_selection_paste (sheet, sheet->cursor_col, sheet->cursor_row, PASTE_DEFAULT, GDK_CURRENT_TIME); context_destroy_menu (widget); } static void context_paste_special_cmd (GtkWidget *widget, ItemGrid *item_grid) { Sheet *sheet = item_grid->sheet; int flags; flags = dialog_paste_special (sheet->workbook); sheet_selection_paste (sheet, sheet->cursor_col, sheet->cursor_row, flags, GDK_CURRENT_TIME); context_destroy_menu (widget); } static void context_insert_cmd (GtkWidget *widget, ItemGrid *item_grid) { dialog_insert_cells (item_grid->sheet->workbook, item_grid->sheet); context_destroy_menu (widget); } static void context_delete_cmd (GtkWidget *widget, ItemGrid *item_grid) { dialog_delete_cells (item_grid->sheet->workbook, item_grid->sheet); context_destroy_menu (widget); } static void context_clear_cmd (GtkWidget *widget, ItemGrid *item_grid) { sheet_selection_clear_content (item_grid->sheet); context_destroy_menu (widget); } static void context_cell_format_cmd (GtkWidget *widget, ItemGrid *item_grid) { dialog_cell_format (item_grid->sheet->workbook, item_grid->sheet); context_destroy_menu (widget); } typedef enum { IG_ALWAYS, IG_HAVE_SELECTION, IG_SEPARATOR, } popup_types; static struct { char *name; void (*fn)(GtkWidget *widget, ItemGrid *item_grid); popup_types type; } item_grid_context_menu [] = { { N_("Cut"), context_cut_cmd, IG_ALWAYS }, { N_("Copy"), context_copy_cmd, IG_ALWAYS }, { N_("Paste"), context_paste_cmd, IG_HAVE_SELECTION }, { N_("Paste special"), context_paste_special_cmd, IG_HAVE_SELECTION }, { "", NULL, IG_SEPARATOR }, { N_("Insert"), context_insert_cmd, IG_ALWAYS }, { N_("Delete"), context_delete_cmd, IG_ALWAYS }, { N_("Erase content"), context_clear_cmd, IG_ALWAYS }, { "", NULL, IG_SEPARATOR }, { N_("Cell format"), context_cell_format_cmd, IG_ALWAYS }, { NULL, NULL, 0 } }; static GtkWidget * create_popup_menu (ItemGrid *item_grid, int include_paste) { GtkWidget *menu, *item; int i; menu = gtk_menu_new (); item = NULL; for (i = 0; item_grid_context_menu [i].name; i++){ switch (item_grid_context_menu [i].type){ case IG_SEPARATOR: item = gtk_menu_item_new (); break; case IG_HAVE_SELECTION: if (!include_paste) continue; /* fall down */ case IG_ALWAYS: item = gtk_menu_item_new_with_label ( _(item_grid_context_menu [i].name)); break; default: g_warning ("Never reached"); } gtk_signal_connect ( GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (item_grid_context_menu [i].fn), item_grid); gtk_widget_show (item); gtk_menu_append (GTK_MENU (menu), item); } return menu; } static void item_grid_popup_menu (ItemGrid *item_grid, GdkEvent *event, int col, int row) { GtkWidget *menu; int show_paste; show_paste = item_grid->sheet->workbook->clipboard_contents != NULL; menu = create_popup_menu (item_grid, show_paste); gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 3, event->button.time); } static int item_grid_button_1 (Sheet *sheet, GdkEvent *event, ItemGrid *item_grid, int col, int row, int x, int y) { GnomeCanvasItem *item = GNOME_CANVAS_ITEM (item_grid); GnomeCanvas *canvas = item->canvas; GnumericSheet *gsheet = GNUMERIC_SHEET (canvas); /* * Range check first */ if (col > SHEET_MAX_COLS-1) return 1; if (row > SHEET_MAX_ROWS-1) return 1; /* * If we were already selecting a range of cells for a formula, * just reset the location to a new place. */ if (gsheet->selecting_cell){ gnumeric_sheet_selection_cursor_place (gsheet, col, row); return 1; } /* * If the user is editing a formula (gnumeric_sheet_can_move_cursor) * then we enable the dynamic cell selection mode. */ if (gnumeric_sheet_can_move_cursor (gsheet)){ gnumeric_sheet_start_cell_selection (gsheet, col, row); item_grid->selecting = ITEM_GRID_SELECTING_FORMULA_RANGE; gnumeric_sheet_selection_cursor_place (gsheet, col, row); return 1; } /* * This was a regular click on a cell on the spreadsheet. Select it. */ sheet_accept_pending_input (sheet); if (!(event->button.state & GDK_SHIFT_MASK)) { sheet_make_cell_visible (sheet, col, row); sheet_cursor_move (sheet, col, row); } if (!(event->button.state & (GDK_CONTROL_MASK|GDK_SHIFT_MASK))) sheet_selection_reset_only (sheet); item_grid->selecting = ITEM_GRID_SELECTING_CELL_RANGE; if ((event->button.state & GDK_SHIFT_MASK) && sheet->selections) sheet_selection_extend_to (sheet, col, row); else sheet_selection_append (sheet, col, row); gnome_canvas_item_grab (item, GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, NULL, event->button.time); return 1; } static void item_grid_stop_sliding (ItemGrid *item_grid) { if (item_grid->sliding == -1) return; gtk_timeout_remove (item_grid->sliding); item_grid->sliding = -1; } static gint item_grid_sliding_callback (gpointer data) { GnomeCanvasItem *item = data; GnomeCanvas *canvas = item->canvas; ItemGrid *item_grid = ITEM_GRID (item); GnumericSheet *gsheet = GNUMERIC_SHEET (canvas); int change = 0; int col, row; col = item_grid->sliding_col; row = item_grid->sliding_row; if (item_grid->sliding_x < 0){ if (gsheet->top_col){ change = 1; if (item_grid->sliding_x >= -8) col = 1; else if (item_grid->sliding_x >= -16) col = 10; else col = 50; col = gsheet->top_col - col; if (col < 0) col = 0; } else col = 0; } if (item_grid->sliding_x > 0){ if (gsheet->last_full_col < SHEET_MAX_COLS-1){ change = 1; if (item_grid->sliding_x <= 7) col = 1; else if (item_grid->sliding_x <= 14) col = 10; else col = 50; col = gsheet->last_visible_col + col; if (col >= SHEET_MAX_COLS) col = SHEET_MAX_COLS-1; } else col = SHEET_MAX_COLS-1; } if (item_grid->sliding_y < 0){ if (gsheet->top_row){ change = 1; if (item_grid->sliding_y >= -8) row = 1; else if (item_grid->sliding_y >= -16) row = 25; else if (item_grid->sliding_y >= -64) row = 250; else row = 1000; row = gsheet->top_row - row; if (row < 0) row = 0; } else row = 0; } if (item_grid->sliding_y > 0){ if (gsheet->last_full_row < SHEET_MAX_ROWS-1){ change = 1; if (item_grid->sliding_y <= 8) row = 1; else if (item_grid->sliding_y <= 16) row = 25; else if (item_grid->sliding_y <= 64) row = 250; else row = 1000; row = gsheet->last_visible_row + row; if (row >= SHEET_MAX_ROWS) row = SHEET_MAX_ROWS-1; } else row = SHEET_MAX_ROWS-1; } if (!change){ item_grid_stop_sliding (item_grid); return TRUE; } if (item_grid->selecting == ITEM_GRID_SELECTING_CELL_RANGE) sheet_selection_extend_to (item_grid->sheet, col, row); else if (item_grid->selecting == ITEM_GRID_SELECTING_FORMULA_RANGE) gnumeric_sheet_selection_extend (gsheet, col, row); gnumeric_sheet_make_cell_visible (gsheet, col, row); return TRUE; } static void item_grid_start_sliding (GnomeCanvasItem *item) { ItemGrid *item_grid = ITEM_GRID (item); item_grid->sliding = gtk_timeout_add ( 100, item_grid_sliding_callback, item); } /* * Handle the selection */ #define convert(c,sx,sy,x,y) gnome_canvas_w2c (c,sx,sy,x,y) static gint item_grid_event (GnomeCanvasItem *item, GdkEvent *event) { GnomeCanvas *canvas = item->canvas; ItemGrid *item_grid = ITEM_GRID (item); GnumericSheet *gsheet = GNUMERIC_SHEET (canvas); Sheet *sheet = item_grid->sheet; int col, row, x, y; int width, height; switch (event->type){ case GDK_ENTER_NOTIFY: { int cursor; if (sheet->mode == SHEET_MODE_SHEET) cursor = GNUMERIC_CURSOR_FAT_CROSS; else cursor = GNUMERIC_CURSOR_ARROW; cursor_set_widget (canvas, cursor); return TRUE; } case GDK_BUTTON_RELEASE: item_grid_stop_sliding (item_grid); if (event->button.button == 1){ if (item_grid->selecting == ITEM_GRID_SELECTING_FORMULA_RANGE) sheet_make_cell_visible (sheet, sheet->cursor_col, sheet->cursor_row); item_grid->selecting = ITEM_GRID_NO_SELECTION; gnome_canvas_item_ungrab (item, event->button.time); return 1; } break; case GDK_MOTION_NOTIFY: convert (canvas, event->motion.x, event->motion.y, &x, &y); gnome_canvas_get_scroll_offsets (canvas, &col, &row); width = GTK_WIDGET (canvas)->allocation.width; height = GTK_WIDGET (canvas)->allocation.height; if (x < col || y < row || x >= col + width || y >= row + height){ int dx = 0, dy = 0; if (item_grid->selecting == ITEM_GRID_NO_SELECTION) return 1; if (x < col) dx = x - col; else if (x >= col + width) dx = x - width - col; if (y < row) dy = y - row; else if (y >= row + height) dy = y - height - row; if ((!dx || (dx < 0 && !gsheet->top_col) || (dx >= 0 && gsheet->last_full_col == SHEET_MAX_COLS-1)) && (!dy || (dy < 0 && !gsheet->top_row) || (dy >= 0 && gsheet->last_full_row == SHEET_MAX_ROWS-1))){ item_grid_stop_sliding (item_grid); return 1; } item_grid->sliding_x = dx/5; item_grid->sliding_y = dy/5; if (!dx){ item_grid->sliding_col = item_grid_find_col (item_grid, x, NULL); if (item_grid->sliding_col >= SHEET_MAX_COLS) item_grid->sliding_col = SHEET_MAX_COLS-1; } if (!dy){ item_grid->sliding_row = item_grid_find_row (item_grid, y, NULL); if (item_grid->sliding_row >= SHEET_MAX_ROWS) item_grid->sliding_row = SHEET_MAX_ROWS-1; } if (item_grid->sliding != -1) return 1; item_grid_sliding_callback (item); item_grid_start_sliding (item); return 1; } item_grid_stop_sliding (item_grid); col = item_grid_find_col (item_grid, x, NULL); row = item_grid_find_row (item_grid, y, NULL); if (item_grid->selecting == ITEM_GRID_NO_SELECTION) return 1; if (col > SHEET_MAX_COLS-1) col = SHEET_MAX_COLS-1; if (row > SHEET_MAX_ROWS-1) row = SHEET_MAX_ROWS-1; if (item_grid->selecting == ITEM_GRID_SELECTING_FORMULA_RANGE){ gnumeric_sheet_selection_extend (gsheet, col, row); return 1; } if (event->motion.x < 0) event->motion.x = 0; if (event->motion.y < 0) event->motion.y = 0; sheet_selection_extend_to (sheet, col, row); return 1; case GDK_BUTTON_PRESS: sheet_set_mode_type (sheet, SHEET_MODE_SHEET); item_grid_stop_sliding (item_grid); convert (canvas, event->button.x, event->button.y, &x, &y); col = item_grid_find_col (item_grid, x, NULL); row = item_grid_find_row (item_grid, y, NULL); switch (event->button.button){ case 1: return item_grid_button_1 (sheet, event, item_grid, col, row, x, y); case 3: item_grid_popup_menu (item_grid, event, col, row); return 1; } default: return 0; } return 0; } /* * Instance initialization */ static void item_grid_init (ItemGrid *item_grid) { GnomeCanvasItem *item = GNOME_CANVAS_ITEM (item_grid); item->x1 = 0; item->y1 = 0; item->x2 = 0; item->y2 = 0; item_grid->left_col = 0; item_grid->top_row = 0; item_grid->top_offset = 0; item_grid->left_offset = 0; item_grid->selecting = ITEM_GRID_NO_SELECTION; item_grid->sliding = -1; } static void item_grid_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) { GnomeCanvasItem *item; ItemGrid *item_grid; item = GNOME_CANVAS_ITEM (o); item_grid = ITEM_GRID (o); switch (arg_id){ case ARG_SHEET_VIEW: item_grid->sheet_view = GTK_VALUE_POINTER (*arg); item_grid->sheet = item_grid->sheet_view->sheet; break; } } /* * ItemGrid class initialization */ static void item_grid_class_init (ItemGridClass *item_grid_class) { GtkObjectClass *object_class; GnomeCanvasItemClass *item_class; item_grid_parent_class = gtk_type_class (gnome_canvas_item_get_type()); object_class = (GtkObjectClass *) item_grid_class; item_class = (GnomeCanvasItemClass *) item_grid_class; gtk_object_add_arg_type ("ItemGrid::SheetView", GTK_TYPE_POINTER, GTK_ARG_WRITABLE, ARG_SHEET_VIEW); object_class->set_arg = item_grid_set_arg; object_class->destroy = item_grid_destroy; /* GnomeCanvasItem method overrides */ item_class->update = item_grid_update; item_class->realize = item_grid_realize; item_class->unrealize = item_grid_unrealize; item_class->draw = item_grid_draw; item_class->point = item_grid_point; item_class->translate = item_grid_translate; item_class->event = item_grid_event; } GtkType item_grid_get_type (void) { static GtkType item_grid_type = 0; if (!item_grid_type) { GtkTypeInfo item_grid_info = { "ItemGrid", sizeof (ItemGrid), sizeof (ItemGridClass), (GtkClassInitFunc) item_grid_class_init, (GtkObjectInitFunc) item_grid_init, NULL, /* reserved_1 */ NULL, /* reserved_2 */ (GtkClassInitFunc) NULL }; item_grid_type = gtk_type_unique (gnome_canvas_item_get_type (), &item_grid_info); } return item_grid_type; }