gnumeric-canvas.c 8.89 KB
Newer Older
1 2 3 4 5 6 7 8
/*
 * The Gnumeric Sheet widget.
 *
 * (C) 1998 The Free Software Foundation
 *
 * Author:
 *     Miguel de Icaza (miguel@kernel.org)
 */
9
#include <config.h>
10 11

#include <gnome.h>
12 13
#include <gdk/gdkkeysyms.h>
#include <gdk/gdkx.h>
14 15
#include "gnumeric.h"
#include "gnumeric-sheet.h"
16 17 18

/* Signals emited by the Gnumeric Sheet widget */
enum {
19
	LAST_SIGNAL
20 21
};

22
static guint sheet_signals [LAST_SIGNAL] = { 0 };
23 24 25 26 27 28 29 30 31

static GnomeCanvasClass *sheet_parent_class;

static void
gnumeric_sheet_destroy (GtkObject *object)
{
	GnumericSheet *gsheet;

	/* Add shutdown code here */
Arturo Espinosa's avatar
Arturo Espinosa committed
32 33
	gsheet = GNUMERIC_SHEET (object);
	
34 35 36 37
	if (GTK_OBJECT_CLASS (sheet_parent_class)->destroy)
		(*GTK_OBJECT_CLASS (sheet_parent_class)->destroy)(object);
}

Arturo Espinosa's avatar
Arturo Espinosa committed
38
static GnumericSheet *
39
gnumeric_sheet_create (Sheet *sheet, GtkWidget *entry)
Arturo Espinosa's avatar
Arturo Espinosa committed
40 41 42 43 44 45 46
{
	GnumericSheet *gsheet;
	GnomeCanvas   *canvas;
	
	gsheet = gtk_type_new (gnumeric_sheet_get_type ());
	canvas = GNOME_CANVAS (gsheet);

47 48 49
	gnome_canvas_construct (canvas,
				gtk_widget_get_default_visual (),
				gtk_widget_get_default_colormap ());
Arturo Espinosa's avatar
Arturo Espinosa committed
50 51 52 53
	
	gsheet->sheet   = sheet;
	gsheet->top_col = 0;
	gsheet->top_row = 0;
54
	gsheet->entry   = entry;
55
	
Arturo Espinosa's avatar
Arturo Espinosa committed
56 57 58
	return gsheet;
}

59 60 61
void
gnumeric_sheet_cursor_set (GnumericSheet *sheet, int col, int row)
{
Arturo Espinosa's avatar
Arturo Espinosa committed
62 63
	g_return_if_fail (GNUMERIC_IS_SHEET (sheet));

64 65 66 67
	sheet->cursor_col = col;
	sheet->cursor_row = row;
}

Arturo Espinosa's avatar
Arturo Espinosa committed
68
void
69 70
gnumeric_sheet_accept_pending_output (GnumericSheet *sheet)
{
Arturo Espinosa's avatar
Arturo Espinosa committed
71 72 73 74 75
	g_return_if_fail (GNUMERIC_IS_SHEET (sheet));

	sheet_cell_new_with_text (sheet->sheet, sheet->cursor_col, sheet->cursor_row,
				  gtk_entry_get_text (GTK_ENTRY (sheet->entry)));
	
76 77 78 79 80 81 82
	/* Destroy the object */
	if (sheet->item_editor){
		gtk_object_destroy (GTK_OBJECT (sheet->item_editor));
		sheet->item_editor = NULL;
	}
}

Arturo Espinosa's avatar
Arturo Espinosa committed
83 84
void
gnumeric_sheet_load_cell_val (GnumericSheet *gsheet)
85
{
Arturo Espinosa's avatar
Arturo Espinosa committed
86 87 88
	Sheet *sheet; 
	Workbook *wb;
	GtkWidget *entry;
89

Arturo Espinosa's avatar
Arturo Espinosa committed
90 91 92 93 94 95
	g_return_if_fail (GNUMERIC_IS_SHEET (gsheet));
	
	sheet = gsheet->sheet;
	wb = sheet->parent_workbook;
	entry = wb->ea_input;
	
96 97 98
	gtk_entry_set_text (GTK_ENTRY(entry), "");
}

99 100 101 102 103 104
static void
gnumeric_sheet_move_cursor_horizontal (GnumericSheet *sheet, int count)
{
	ItemCursor *item_cursor = sheet->item_cursor;
	int new_left;
	
105
	new_left = sheet->cursor_col + count;
106 107 108

	if (new_left < 0)
		return;
109 110
	
	if (new_left < sheet->top_col){
111 112
		g_warning ("do scroll\n");
		return;
113 114 115 116
	}

	if (new_left < 0)
		new_left = 0;
117 118

	gnumeric_sheet_accept_pending_output (sheet);
119 120
	gnumeric_sheet_cursor_set (sheet, new_left, sheet->cursor_row);

121
	item_cursor_set_bounds (item_cursor,
122 123
				new_left, item_cursor->start_row,
				new_left, item_cursor->start_row);
Arturo Espinosa's avatar
Arturo Espinosa committed
124
	gnumeric_sheet_load_cell_val (sheet);
125 126 127 128 129 130 131
}

static void
gnumeric_sheet_move_cursor_vertical (GnumericSheet *sheet, int count)
{
	ItemCursor *item_cursor = sheet->item_cursor;
	int new_top;
132 133

	new_top = sheet->cursor_row + count;
134 135

	if (new_top < 0)
136 137 138 139 140 141
		return;

	if (new_top < sheet->top_row){
		g_warning ("do scroll\n");
		return;
	}
142 143

	gnumeric_sheet_accept_pending_output (sheet);
144
	gnumeric_sheet_cursor_set (sheet, sheet->cursor_col, new_top);
145
	item_cursor_set_bounds (item_cursor,
146 147
				item_cursor->start_col, new_top,
				item_cursor->start_col, new_top);
Arturo Espinosa's avatar
Arturo Espinosa committed
148
	gnumeric_sheet_load_cell_val (sheet);
149 150
}

151 152 153 154 155 156 157 158 159 160 161 162 163 164
void
gnumeric_sheet_set_selection (GnumericSheet *sheet, int start_col, int start_row, int end_col, int end_row)
{
	g_return_if_fail (sheet != NULL);
	g_return_if_fail (start_row <= end_row);
	g_return_if_fail (start_col <= end_col);
	g_return_if_fail (GNUMERIC_IS_SHEET (sheet));

	gnumeric_sheet_cursor_set (sheet, start_col, start_row);
	item_cursor_set_bounds (sheet->item_cursor,
				start_col, start_row,
				end_col, end_row);
}

165 166 167 168 169 170
static void
start_editing_at_cursor (GnumericSheet *sheet, GtkWidget *entry)
{
	GnomeCanvasItem *item;
	GnomeCanvas *canvas = GNOME_CANVAS (sheet);

171 172
	item = gnome_canvas_item_new (canvas,
				      GNOME_CANVAS_GROUP(canvas->root),
173 174 175
				      item_edit_get_type (),
				      "ItemEdit::Sheet",    sheet->sheet,
				      "ItemEdit::Grid",     sheet->item_grid,
176 177
				      "ItemEdit::Col",      sheet->cursor_col,
				      "ItemEdit::Row",      sheet->cursor_row,
178 179 180 181 182 183
				      "ItemEdit::GtkEntry", entry,
				      NULL);

	sheet->item_editor = ITEM_EDIT (item);
}

184 185 186 187
static gint
gnumeric_sheet_key (GtkWidget *widget, GdkEventKey *event)
{
	GnumericSheet *sheet = GNUMERIC_SHEET (widget);
Arturo Espinosa's avatar
Arturo Espinosa committed
188
	Workbook *wb = sheet->sheet->parent_workbook;
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206

	switch (event->keyval){
	case GDK_Left:
		gnumeric_sheet_move_cursor_horizontal (sheet, -1);
		break;

	case GDK_Right:
		gnumeric_sheet_move_cursor_horizontal (sheet, 1);
		break;

	case GDK_Up:
		gnumeric_sheet_move_cursor_vertical (sheet, -1);
		break;

	case GDK_Down:
		gnumeric_sheet_move_cursor_vertical (sheet, 1);
		break;

Arturo Espinosa's avatar
Arturo Espinosa committed
207 208 209 210
	case GDK_F2:
		gtk_window_set_focus (GTK_WINDOW (wb->toplevel), wb->ea_input);
		/* fallback */
		
211
	default:
Arturo Espinosa's avatar
Arturo Espinosa committed
212
		if (!sheet->item_editor)
213
			start_editing_at_cursor (sheet, wb->ea_input);
Arturo Espinosa's avatar
Arturo Espinosa committed
214 215 216 217

		/* Forward the keystroke to the input line */
		gtk_widget_event (sheet->entry, (GdkEvent *) event);
		
218 219 220 221
	}
	return 1;
}

Arturo Espinosa's avatar
Arturo Espinosa committed
222 223 224
GtkWidget *
gnumeric_sheet_new (Sheet *sheet)
{
225
	GnomeCanvasItem *item;
Arturo Espinosa's avatar
Arturo Espinosa committed
226
	GnumericSheet *gsheet;
227 228 229
	GnomeCanvas   *gsheet_canvas;
	GnomeCanvasGroup *gsheet_group;
	GtkWidget *widget;
230
	GtkWidget *entry = sheet->parent_workbook->ea_input;
Arturo Espinosa's avatar
Arturo Espinosa committed
231
	
232
	gsheet = gnumeric_sheet_create (sheet, entry);
Arturo Espinosa's avatar
Arturo Espinosa committed
233
	gnome_canvas_set_size (GNOME_CANVAS (gsheet), 300, 100);
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252

	/* handy shortcuts */
	gsheet_canvas = GNOME_CANVAS (gsheet);
	gsheet_group = GNOME_CANVAS_GROUP (gsheet_canvas->root);
	
	/* The grid */
	item = gnome_canvas_item_new (gsheet_canvas, gsheet_group,
				      item_grid_get_type (),
				      "ItemGrid::Sheet", sheet,
				      NULL);
	gsheet->item_grid = ITEM_GRID (item);

	/* The cursor */
	item = gnome_canvas_item_new (gsheet_canvas, gsheet_group,
				      item_cursor_get_type (),
				      "ItemCursor::Sheet", sheet,
				      "ItemCursor::Grid", gsheet->item_grid,
				      NULL);
	gsheet->item_cursor = ITEM_CURSOR (item);
253

254 255 256 257 258 259 260 261 262 263
	widget = GTK_WIDGET (gsheet);

	return widget;
}

static void
gnumeric_sheet_realize (GtkWidget *widget)
{
	if (GTK_WIDGET_CLASS (sheet_parent_class)->realize)
		(*GTK_WIDGET_CLASS (sheet_parent_class)->realize)(widget);
Arturo Espinosa's avatar
Arturo Espinosa committed
264 265
}

266 267 268
static void
gnumeric_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
{
Arturo Espinosa's avatar
Arturo Espinosa committed
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
	GnumericSheet *gsheet = GNUMERIC_SHEET (widget);
	GnomeCanvas   *canvas = GNOME_CANVAS (widget);
	int pixels, col, row;

	(*GTK_WIDGET_CLASS (sheet_parent_class)->size_allocate)(widget, allocation);

	/* Find out the last visible col and the last full visible column */
	pixels = 0;
	col = gsheet->top_col;
	do {
		ColRowInfo *ci;
		int cb;
		
		ci = sheet_col_get_info (gsheet->sheet, col);
		cb = pixels + ci->pixels;
		
		if (cb == canvas->width){
			gsheet->last_visible_col = col;
			gsheet->last_full_col = col;
		} if (cb > canvas->width){
			gsheet->last_visible_col = col;
			if (col == gsheet->top_col)
				gsheet->last_full_col = gsheet->top_col;
			else
				gsheet->last_full_col = col - 1;
		}
		pixels = cb;
		col++;
	} while (pixels < canvas->width);

	/* Find out the last visible row and the last fully visible row */
	pixels = 0;
	row = gsheet->top_row;
	do {
		ColRowInfo *ri;
		int cb;
		
		ri = sheet_row_get_info (gsheet->sheet, row);
		cb = pixels + ri->pixels;
		
		if (cb == canvas->height){
			gsheet->last_visible_row = row;
			gsheet->last_full_row = row;
		} if (cb > canvas->width){
			gsheet->last_visible_row = row;
			if (col == gsheet->top_row)
				gsheet->last_full_row = gsheet->top_row;
			else
				gsheet->last_full_row = row - 1;
		}
		pixels = cb;
		row++;
	} while (pixels < canvas->width);

	printf ("COLS: %d %d %d\n",
		gsheet->top_col,
		gsheet->last_full_row,
		gsheet->last_visible_col);
		
	printf ("ROWS: %d %d %d\n",
		gsheet->top_row,
		gsheet->last_full_row,
		gsheet->last_visible_row);
332 333
}

Arturo Espinosa's avatar
Arturo Espinosa committed
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
static void
gnumeric_sheet_class_init (GnumericSheetClass *class)
{
	GtkObjectClass *object_class;
	GtkWidgetClass *widget_class;
	GnomeCanvasClass *canvas_class;

	object_class = (GtkObjectClass *) class;
	widget_class = (GtkWidgetClass *) class;
	canvas_class = (GnomeCanvasClass *) class;
	
	sheet_parent_class = gtk_type_class (gnome_canvas_get_type());

	/* Method override */
	object_class->destroy = gnumeric_sheet_destroy;
349
	widget_class->realize = gnumeric_sheet_realize;
Arturo Espinosa's avatar
Arturo Espinosa committed
350
/* 	widget_class->size_allocate = gnumeric_size_allocate; */
351
	widget_class->key_press_event = gnumeric_sheet_key;
Arturo Espinosa's avatar
Arturo Espinosa committed
352 353
}

Arturo Espinosa's avatar
Arturo Espinosa committed
354 355 356 357 358
static void
gnumeric_sheet_init (GnumericSheet *gsheet)
{
	GnomeCanvas *canvas = GNOME_CANVAS (gsheet);

359 360
	GTK_WIDGET_SET_FLAGS (canvas, GTK_CAN_FOCUS);
	GTK_WIDGET_SET_FLAGS (canvas, GTK_CAN_DEFAULT);
Arturo Espinosa's avatar
Arturo Espinosa committed
361 362
}

363 364 365 366 367 368 369 370 371 372 373
GtkType
gnumeric_sheet_get_type (void)
{
	static GtkType gnumeric_sheet_type = 0;

	if (!gnumeric_sheet_type){
		GtkTypeInfo gnumeric_sheet_info = {
			"GnumericSheet",
			sizeof (GnumericSheet),
			sizeof (GnumericSheetClass),
			(GtkClassInitFunc) gnumeric_sheet_class_init,
Arturo Espinosa's avatar
Arturo Espinosa committed
374
			(GtkObjectInitFunc) gnumeric_sheet_init,
375 376 377 378 379
			NULL, /* reserved 1 */
			NULL, /* reserved 2 */
			(GtkClassInitFunc) NULL
		};

Arturo Espinosa's avatar
Arturo Espinosa committed
380
		gnumeric_sheet_type = gtk_type_unique (gnome_canvas_get_type (), &gnumeric_sheet_info);
381 382 383 384
	}

	return gnumeric_sheet_type;
}