sheet-view.c 26.6 KB
Newer Older
Arturo Espinosa's avatar
Arturo Espinosa committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * sheet-view.c: Implements a view of the Sheet.
 *
 * Author:
 *    Miguel de Icaza (miguel@kernel.org)
 *
 */
#include <config.h>

#include <gnome.h>
#include <gdk/gdkkeysyms.h>
#include <gdk/gdkx.h>
#include <string.h>
#include "gnumeric.h"
#include "gnumeric-sheet.h"
16
#include "workbook.h"
17
#include "cell.h"
Michael Meeks's avatar
Michael Meeks committed
18
#include "selection.h"
Michael Meeks's avatar
Michael Meeks committed
19
#include "sheet-object.h"
20
#include "item-cursor.h"
21
#include "gnumeric-util.h"
22
#include "parse-util.h"
23
#include "selection.h"
24
#include "application.h"
Jody Goldberg's avatar
Jody Goldberg committed
25
#include "cellspan.h"
Arturo Espinosa's avatar
Arturo Espinosa committed
26 27 28 29 30 31 32 33

static GtkTableClass *sheet_view_parent_class;

void
sheet_view_redraw_all (SheetView *sheet_view)
{
	g_return_if_fail (sheet_view != NULL);
	g_return_if_fail (IS_SHEET_VIEW (sheet_view));
34

Arturo Espinosa's avatar
Arturo Espinosa committed
35 36 37 38 39 40 41 42 43 44 45
	gnome_canvas_request_redraw (
		GNOME_CANVAS (sheet_view->sheet_view),
		0, 0, INT_MAX, INT_MAX);
	gnome_canvas_request_redraw (
		GNOME_CANVAS (sheet_view->col_canvas),
		0, 0, INT_MAX, INT_MAX);
	gnome_canvas_request_redraw (
		GNOME_CANVAS (sheet_view->row_canvas),
		0, 0, INT_MAX, INT_MAX);
}

Jody Goldberg's avatar
Jody Goldberg committed
46
/*
47
 * Redraw selected range, do not honour spans
Jody Goldberg's avatar
Jody Goldberg committed
48
 */
Arturo Espinosa's avatar
Arturo Espinosa committed
49
void
Jody Goldberg's avatar
Jody Goldberg committed
50 51 52
sheet_view_redraw_cell_region (SheetView *sheet_view,
			       int start_col, int start_row,
			       int end_col, int end_row)
Arturo Espinosa's avatar
Arturo Espinosa committed
53 54
{
	GnumericSheet *gsheet;
55
	GnomeCanvas *canvas;
Arturo Espinosa's avatar
Arturo Espinosa committed
56 57
	Sheet *sheet = sheet_view->sheet;
	int x, y, w, h;
58

Arturo Espinosa's avatar
Arturo Espinosa committed
59 60 61 62 63
	g_return_if_fail (sheet_view != NULL);
	g_return_if_fail (IS_SHEET_VIEW (sheet_view));

	gsheet = GNUMERIC_SHEET (sheet_view->sheet_view);
	g_return_if_fail (GNUMERIC_IS_SHEET (gsheet));
64
	canvas = GNOME_CANVAS (gsheet);
Arturo Espinosa's avatar
Arturo Espinosa committed
65

66 67 68 69
	if ((end_col < gsheet->col.first) ||
	    (end_row < gsheet->row.first) ||
	    (start_col > gsheet->col.last_visible) ||
	    (start_row > gsheet->row.last_visible))
70
		return;
71

72
	/* Only draw those regions that are visible */
73 74 75 76
	start_col = MAX (gsheet->col.first, start_col);
	start_row = MAX (gsheet->row.first, start_row);
	end_col =  MIN (gsheet->col.last_visible, end_col);
	end_row =  MIN (gsheet->row.last_visible, end_row);
Arturo Espinosa's avatar
Arturo Espinosa committed
77

78 79 80 81
	x = sheet_col_get_distance_pixels (sheet, gsheet->col.first, start_col);
	y = sheet_row_get_distance_pixels (sheet, gsheet->row.first, start_row);
	w = sheet_col_get_distance_pixels (sheet, start_col, end_col+1);
	h = sheet_row_get_distance_pixels (sheet, start_row, end_row+1);
Arturo Espinosa's avatar
Arturo Espinosa committed
82

83 84
	x += canvas->layout.xoffset - canvas->zoom_xofs;
	y += canvas->layout.yoffset - canvas->zoom_yofs;
Jody Goldberg's avatar
Jody Goldberg committed
85 86 87 88 89 90 91 92

#if 0
	fprintf (stderr, "%s%d:", col_name(min_col), first_row+1);
	fprintf (stderr, "%s%d\n", col_name(max_col), last_row+1);
#endif

	/* redraw a border of 1 pixel around the region to handle thick borders
	 * NOTE the 2nd coordinates are excluded so add 1 extra (+1border +1include) */
93
	gnome_canvas_request_redraw (GNOME_CANVAS (gsheet),
Jody Goldberg's avatar
Jody Goldberg committed
94 95
				     x-1, y-1,
				     x+w+1+1, y+h+1+1);
Arturo Espinosa's avatar
Arturo Espinosa committed
96 97 98
}

void
Jody Goldberg's avatar
Jody Goldberg committed
99 100 101
sheet_view_redraw_headers (SheetView *sheet_view,
			   gboolean const col, gboolean const row,
			   Range const * r /* optional == NULL */)
Arturo Espinosa's avatar
Arturo Espinosa committed
102
{
Jody Goldberg's avatar
Jody Goldberg committed
103
	GnumericSheet *gsheet;
Arturo Espinosa's avatar
Arturo Espinosa committed
104 105 106
	g_return_if_fail (sheet_view != NULL);
	g_return_if_fail (IS_SHEET_VIEW (sheet_view));

Jody Goldberg's avatar
Jody Goldberg committed
107
	gsheet = GNUMERIC_SHEET (sheet_view->sheet_view);
Arturo Espinosa's avatar
Arturo Espinosa committed
108

Jody Goldberg's avatar
Jody Goldberg committed
109
	if (col) {
110
		int left = 0, right = INT_MAX-1;
Jody Goldberg's avatar
Jody Goldberg committed
111 112 113 114 115 116 117
		if (r != NULL) {
			int const size = r->end.col - r->start.col;
/* A rough heuristic guess of the number of when the
 * trade off point of redrawing all vs calculating the
 * redraw size is crossed */
#define COL_HEURISTIC	20
			if (-COL_HEURISTIC < size && size < COL_HEURISTIC) {
118
				left = gsheet->col_offset.first +
119
				    sheet_col_get_distance_pixels (sheet_view->sheet,
120
							    gsheet->col.first, r->start.col);
Jody Goldberg's avatar
Jody Goldberg committed
121
				right = left +
122
				    sheet_col_get_distance_pixels (sheet_view->sheet,
Jody Goldberg's avatar
Jody Goldberg committed
123 124 125
							    r->start.col, r->end.col+1);
			}
		}
126
		/* Request excludes the far coordinate.  Add 1 to include them */
Jody Goldberg's avatar
Jody Goldberg committed
127 128
		gnome_canvas_request_redraw (
			GNOME_CANVAS (sheet_view->col_canvas),
129
			left, 0, right+1, INT_MAX);
Jody Goldberg's avatar
Jody Goldberg committed
130
	}
Arturo Espinosa's avatar
Arturo Espinosa committed
131

Jody Goldberg's avatar
Jody Goldberg committed
132
	if (row) {
133
		int top = 0, bottom = INT_MAX-1;
Jody Goldberg's avatar
Jody Goldberg committed
134 135 136 137 138 139 140
		if (r != NULL) {
			int const size = r->end.row - r->start.row;
/* A rough heuristic guess of the number of when the
 * trade off point of redrawing all vs calculating the
 * redraw size is crossed */
#define ROW_HEURISTIC	50
			if (-ROW_HEURISTIC < size && size < ROW_HEURISTIC) {
141
				top = gsheet->row_offset.first +
142
				    sheet_row_get_distance_pixels (sheet_view->sheet,
143
							    gsheet->row.first, r->start.row);
Jody Goldberg's avatar
Jody Goldberg committed
144
				bottom = top +
145
				    sheet_row_get_distance_pixels (sheet_view->sheet,
Jody Goldberg's avatar
Jody Goldberg committed
146 147 148
							    r->start.row, r->end.row+1);
			}
		}
149
		/* Request excludes the far coordinate.  Add 1 to include them */
Jody Goldberg's avatar
Jody Goldberg committed
150 151
		gnome_canvas_request_redraw (
			GNOME_CANVAS (sheet_view->row_canvas),
152
			0, top, INT_MAX, bottom+1);
Jody Goldberg's avatar
Jody Goldberg committed
153
	}
Arturo Espinosa's avatar
Arturo Espinosa committed
154 155 156 157 158
}

void
sheet_view_set_zoom_factor (SheetView *sheet_view, double factor)
{
159 160
	GList *l;
	GnumericSheet *gsheet;
161 162
	ItemBar *col_item, *row_item;
	int h, w;
163

Arturo Espinosa's avatar
Arturo Espinosa committed
164 165
	g_return_if_fail (sheet_view != NULL);
	g_return_if_fail (IS_SHEET_VIEW (sheet_view));
166

167
	gsheet = GNUMERIC_SHEET (sheet_view->sheet_view);
168 169
	col_item = ITEM_BAR (sheet_view->col_item);
	row_item = ITEM_BAR (sheet_view->row_item);
170

171
	/* Set pixels_per_unit before the font.  The item bars look here for the number */
172
	gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (gsheet), factor);
173

174
	/* resize the header fonts */
175 176 177 178 179 180 181
	item_bar_fonts_init (col_item);
	item_bar_fonts_init (row_item);

	/*
	 * Use the size of the bold header font to size the free dimensions
	 * No need to zoom, the size of the font takes that into consideration.
	 */
182

183 184 185 186 187 188
	/* 2 pixels above and below */
	h = 2 + 2 + style_font_get_height (col_item->bold_font);
	/* 5 pixels left and right plus the width of the widest string I can think of */
	w = 5 + 5 + gdk_string_width (style_font_gdk_font (col_item->bold_font), "88888");

	gtk_widget_set_usize (GTK_WIDGET (sheet_view->col_canvas), -1, h);
189
	gnome_canvas_set_scroll_region (GNOME_CANVAS (sheet_view->col_canvas), 0, 0,
190
					1000000*factor, h);
191

192
	gtk_widget_set_usize (GTK_WIDGET (sheet_view->row_canvas), w, -1);
193
	gnome_canvas_set_scroll_region (GNOME_CANVAS (sheet_view->row_canvas), 0, 0,
194
					w, 1200000*factor);
195

196 197
	/* Recalibrate the starting offsets */
	gsheet->col_offset.first =
198
	    sheet_col_get_distance_pixels (sheet_view->sheet, 0, gsheet->col.first);
199
	gsheet->row_offset.first =
200
	    sheet_row_get_distance_pixels (sheet_view->sheet, 0, gsheet->row.first);
201

202 203 204 205 206 207 208
	if (GTK_WIDGET_REALIZED (gsheet))
		/* Ensure that the current cell remains visible when we zoom */
		gnumeric_sheet_make_cell_visible
			(gsheet,
			 sheet_view->sheet->cursor.edit_pos.col,
			 sheet_view->sheet->cursor.edit_pos.row,
			 TRUE);
209 210 211 212 213 214 215

	/* Repsition the cursor */
	item_cursor_reposition (gsheet->item_cursor);

	/* Adjust the animated cursors */
	for (l = sheet_view->anted_cursors; l; l = l->next)
		item_cursor_reposition (ITEM_CURSOR (l->data));
Arturo Espinosa's avatar
Arturo Espinosa committed
216 217 218 219 220 221 222 223 224 225 226
}

static void
canvas_bar_realized (GtkWidget *widget, gpointer data)
{
	gdk_window_set_back_pixmap (GTK_LAYOUT (widget)->bin_window, NULL, FALSE);
}

static GnomeCanvas *
new_canvas_bar (SheetView *sheet_view, GtkOrientation o, GnomeCanvasItem **itemp)
{
227 228 229 230 231 232 233 234 235 236
	GtkWidget *canvas =
	    gnome_canvas_new ();
	GnomeCanvasGroup *group =
	    GNOME_CANVAS_GROUP (GNOME_CANVAS (canvas)->root);
	GnomeCanvasItem *item =
	    gnome_canvas_item_new (group,
				   item_bar_get_type (),
				   "ItemBar::SheetView", sheet_view,
				   "ItemBar::Orientation", o,
				   NULL);
Arturo Espinosa's avatar
Arturo Espinosa committed
237 238 239 240 241

	gtk_signal_connect (GTK_OBJECT (canvas), "realize",
			    (GtkSignalFunc) canvas_bar_realized,
			    NULL);

242
	*itemp = item;
Arturo Espinosa's avatar
Arturo Espinosa committed
243
	gtk_widget_show (canvas);
244

245
	return GNOME_CANVAS(canvas);
Arturo Espinosa's avatar
Arturo Espinosa committed
246 247
}

Jody Goldberg's avatar
Jody Goldberg committed
248 249 250
/* Manages the scrollbar dimensions and paging parameters. */
void
sheet_view_scrollbar_config (SheetView const *sheet_view)
Arturo Espinosa's avatar
Arturo Espinosa committed
251 252 253 254
{
	GtkAdjustment *va = GTK_ADJUSTMENT (sheet_view->va);
	GtkAdjustment *ha = GTK_ADJUSTMENT (sheet_view->ha);
	GnumericSheet *gsheet = GNUMERIC_SHEET (sheet_view->sheet_view);
Jody Goldberg's avatar
Jody Goldberg committed
255
	Sheet         *sheet = sheet_view->sheet;
256 257
	int const last_col = gsheet->col.last_full;
	int const last_row = gsheet->row.last_full;
Arturo Espinosa's avatar
Arturo Espinosa committed
258

Jody Goldberg's avatar
Jody Goldberg committed
259
	va->upper = MAX (MAX (last_row,
260
			      sheet_view->sheet->rows.max_used),
261 262
			 MAX (sheet->cursor.move_corner.row,
			      sheet->cursor.base_corner.row));
263
	va->page_size = last_row - gsheet->row.first;
264
	va->value = gsheet->row.first;
Jody Goldberg's avatar
Jody Goldberg committed
265 266
	va->step_increment = va->page_increment =
	    va->page_size / 2;
267

Jody Goldberg's avatar
Jody Goldberg committed
268
	ha->upper = MAX (MAX (last_col,
269
			      sheet_view->sheet->cols.max_used),
270 271
			 MAX (sheet->cursor.move_corner.col,
			      sheet->cursor.base_corner.col));
272
	ha->page_size = last_col - gsheet->col.first;
273
	ha->value = gsheet->col.first;
Jody Goldberg's avatar
Jody Goldberg committed
274 275
	ha->step_increment = ha->page_increment =
	    ha->page_size / 2;
Arturo Espinosa's avatar
Arturo Espinosa committed
276 277 278 279 280

	gtk_adjustment_changed (va);
	gtk_adjustment_changed (ha);
}

281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
/*
 * sheet_view_make_edit_pos_visible
 * @sheet_view  Sheet view
 *
 * Make the cell at the edit position visible.
 *
 * To be called from the "size_allocate" signal handler when the geometry of a
 * new sheet view has been configured. 
 */
static void
sheet_view_make_edit_pos_visible (SheetView const *sheet_view)
{
	GnumericSheet *gsheet = GNUMERIC_SHEET (sheet_view->sheet_view);

	gnumeric_sheet_make_cell_visible
		(gsheet,
		 sheet_view->sheet->cursor.edit_pos.col,
		 sheet_view->sheet->cursor.edit_pos.row,
		 TRUE);

}

Jody Goldberg's avatar
Jody Goldberg committed
303 304 305
static void
sheet_view_size_allocate (GtkWidget *widget, GtkAllocation *alloc, SheetView *sheet_view)
{
306
	sheet_view_make_edit_pos_visible (sheet_view);
Jody Goldberg's avatar
Jody Goldberg committed
307 308 309
	sheet_view_scrollbar_config (sheet_view);
}

Arturo Espinosa's avatar
Arturo Espinosa committed
310
static void
311 312
sheet_view_col_selection_changed (ItemBar *item_bar, int col, int modifiers, SheetView *sheet_view)
{
Arturo Espinosa's avatar
Arturo Espinosa committed
313
	Sheet *sheet = sheet_view->sheet;
314 315
	GnumericSheet *gsheet = GNUMERIC_SHEET (sheet_view->sheet_view);

316 317 318 319
	if (modifiers){
		if ((modifiers & GDK_SHIFT_MASK) && sheet->selections){
			SheetSelection *ss = sheet->selections->data;
			int start_col, end_col;
320 321 322 323

			start_col = MIN (ss->user.start.col, col);
			end_col = MAX (ss->user.end.col, col);

324
			sheet_selection_set (sheet,
325
					     start_col, gsheet->row.first,
326 327 328 329
					     start_col, 0,
					     end_col, SHEET_MAX_ROWS-1);
			return;
		}
330

331 332
		if (!(modifiers & GDK_CONTROL_MASK))
			sheet_selection_reset_only (sheet);
333

334 335 336 337
		sheet_selection_add_range (sheet,
					   col, gsheet->row.first,
					   col, 0,
					   col, SHEET_MAX_ROWS-1);
338
	} else {
339
		sheet_selection_extend_to (sheet, col, SHEET_MAX_ROWS - 1);
340 341
		gnumeric_sheet_make_cell_visible (gsheet, col, gsheet->row.first, FALSE);
	}
342 343 344

	/* The edit pos, and the selection may have changed */
	sheet_update (sheet);
Arturo Espinosa's avatar
Arturo Espinosa committed
345 346
}

347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
struct closure_colrow_resize {
	int size_pixels;
	gboolean is_cols;
};

static gboolean
cb_colrow_resize (Sheet *sheet, Range const *r, gpointer user_data)
{
	struct closure_colrow_resize const *info = user_data;
	int tmp;

	if (info->is_cols) {
		if (r->start.row == 0 && r->end.row   >= SHEET_MAX_ROWS - 1)
			for (tmp = r->start.col; tmp <= r->end.col ; ++tmp) {
				sheet_col_set_size_pixels (sheet, tmp, info->size_pixels, TRUE);
				/* FIXME should be done later */
				sheet_recompute_spans_for_col (sheet, tmp);
			}
	} else if (r->start.col == 0 && r->end.col >= SHEET_MAX_COLS - 1)
		for (tmp = r->start.row; tmp <= r->end.row ; ++tmp)
			sheet_row_set_size_pixels (sheet, tmp, info->size_pixels, TRUE);

	return TRUE;
}

Arturo Espinosa's avatar
Arturo Espinosa committed
372
static void
373 374
sheet_view_col_size_changed (ItemBar *item_bar, int col, int width,
			     SheetView *sheet_view)
Arturo Espinosa's avatar
Arturo Espinosa committed
375 376
{
	Sheet *sheet = sheet_view->sheet;
377
	ItemBarSelectionType const type = sheet_col_selection_type (sheet, col);
378

379 380 381 382
	/*
	 * If the column that changed size is completely selected (top to
	 * bottom) then resize all other columns which are fully selected too.
	 */
383
 	if (type == ITEM_BAR_FULL_SELECTION) {
384 385 386 387
		struct closure_colrow_resize	closure;
		closure.size_pixels = width;
		closure.is_cols = TRUE;
		selection_foreach_range (sheet, &cb_colrow_resize, &closure);
Jody Goldberg's avatar
Jody Goldberg committed
388
	} else {
389
 		sheet_col_set_size_pixels (sheet, col, width, TRUE);
Jody Goldberg's avatar
Jody Goldberg committed
390 391 392
		/* FIXME should be done later */
		sheet_recompute_spans_for_col (sheet, col);
	}
393

Jody Goldberg's avatar
Jody Goldberg committed
394
	sheet_update (sheet);
Arturo Espinosa's avatar
Arturo Espinosa committed
395 396 397
}

static void
398
sheet_view_row_selection_changed (ItemBar *item_bar, int row, int modifiers, SheetView *sheet_view)
Arturo Espinosa's avatar
Arturo Espinosa committed
399 400
{
	Sheet *sheet = sheet_view->sheet;
401
	GnumericSheet *gsheet = GNUMERIC_SHEET (sheet_view->sheet_view);
402 403 404 405 406

	if (modifiers){
		if ((modifiers & GDK_SHIFT_MASK) && sheet->selections){
			SheetSelection *ss = sheet->selections->data;
			int start_row, end_row;
407 408 409 410

			start_row = MIN (ss->user.start.row, row);
			end_row = MAX (ss->user.end.row, row);

411
			sheet_selection_set (sheet,
412
					     gsheet->col.first, start_row,
413 414 415 416
					     0, start_row,
					     SHEET_MAX_COLS-1, end_row);
			return;
		}
417

418 419
		if (!(modifiers & GDK_CONTROL_MASK))
 			sheet_selection_reset_only (sheet);
420 421 422 423 424

		sheet_selection_add_range (sheet,
					   gsheet->col.first, row,
					   0, row,
					   SHEET_MAX_COLS-1, row);
425
	} else {
426
		sheet_selection_extend_to (sheet, SHEET_MAX_COLS-1, row);
427 428
		gnumeric_sheet_make_cell_visible (gsheet, gsheet->col.first, row, FALSE);
	}
429 430
	/* The edit pos, and the selection may have changed */
	sheet_update (sheet);
Arturo Espinosa's avatar
Arturo Espinosa committed
431 432 433 434 435 436
}

static void
sheet_view_row_size_changed (ItemBar *item_bar, int row, int height, SheetView *sheet_view)
{
	Sheet *sheet = sheet_view->sheet;
437
	ItemBarSelectionType const type = sheet_row_selection_type (sheet, row);
438

439 440 441 442 443 444 445 446 447
	/*
	 * If the row that changed size is completely selected (left to
	 * right) then resize all other rows which are fully selected too.
	 */
 	if (type == ITEM_BAR_FULL_SELECTION) {
		struct closure_colrow_resize	closure;
		closure.size_pixels = height;
		closure.is_cols = FALSE;
		selection_foreach_range (sheet, &cb_colrow_resize, &closure);
448
	} else
449
		sheet_row_set_size_pixels (sheet, row, height, TRUE);
Jody Goldberg's avatar
Jody Goldberg committed
450 451

	sheet_update (sheet);
Arturo Espinosa's avatar
Arturo Espinosa committed
452 453 454 455 456 457
}

static void
button_select_all (GtkWidget *the_button, SheetView *sheet_view)
{
	sheet_select_all (sheet_view->sheet);
458
	sheet_redraw_all (sheet_view->sheet);
Arturo Espinosa's avatar
Arturo Espinosa committed
459 460 461 462 463
}

static void
vertical_scroll_change (GtkAdjustment *adj, SheetView *sheet_view)
{
464 465 466 467 468
	if (sheet_view->tip) {
		char buffer [20 + sizeof (long) * 4];
		snprintf (buffer, sizeof (buffer), _("Row: %d"), (int) adj->value + 1);
		gtk_label_set_text (GTK_LABEL (sheet_view->tip), buffer);
	}
Arturo Espinosa's avatar
Arturo Espinosa committed
469 470 471 472 473
}

static void
horizontal_scroll_change (GtkAdjustment *adj, SheetView *sheet_view)
{
474 475 476 477
	if (sheet_view->tip) {
		char buffer [20 + sizeof (long) * 4];
		snprintf (buffer, sizeof (buffer), _("Column: %s"), col_name (adj->value));
		gtk_label_set_text (GTK_LABEL (sheet_view->tip), buffer);
Arturo Espinosa's avatar
Arturo Espinosa committed
478 479 480 481 482 483 484
	}
}

static int
horizontal_scroll_event (GtkScrollbar *scroll, GdkEvent *event, SheetView *sheet_view)
{
	if (event->type == GDK_BUTTON_PRESS){
485 486 487
		sheet_view->tip = gnumeric_create_tooltip ();
		horizontal_scroll_change (GTK_ADJUSTMENT (sheet_view->ha), sheet_view);
		gnumeric_position_tooltip (sheet_view->tip, 1);
Arturo Espinosa's avatar
Arturo Espinosa committed
488
		gtk_widget_show_all (gtk_widget_get_toplevel (sheet_view->tip));
489 490

	} else if (event->type == GDK_BUTTON_RELEASE) {
491
		GnumericSheet  *gsheet = GNUMERIC_SHEET (sheet_view->sheet_view);
492
		int col;
493

494 495 496 497 498 499
		/* A button release can be generated without a press by people
		 * with mouse wheels */
		if (sheet_view->tip) {
			gtk_widget_destroy (gtk_widget_get_toplevel (sheet_view->tip));
			sheet_view->tip = NULL;
		}
Arturo Espinosa's avatar
Arturo Espinosa committed
500

501 502
		col = GTK_ADJUSTMENT (sheet_view->ha)->value;

503
		gnumeric_sheet_set_left_col (gsheet, col);
504
		/* NOTE : Excel does not move the cursor, just scrolls the sheet. */
Arturo Espinosa's avatar
Arturo Espinosa committed
505
	}
506

Arturo Espinosa's avatar
Arturo Espinosa committed
507 508 509 510 511 512 513
	return FALSE;
}

static int
vertical_scroll_event (GtkScrollbar *scroll, GdkEvent *event, SheetView *sheet_view)
{
	if (event->type == GDK_BUTTON_PRESS){
514 515 516
		sheet_view->tip = gnumeric_create_tooltip ();
		vertical_scroll_change (GTK_ADJUSTMENT (sheet_view->va), sheet_view);
		gnumeric_position_tooltip (sheet_view->tip, 0);
Arturo Espinosa's avatar
Arturo Espinosa committed
517
		gtk_widget_show_all (gtk_widget_get_toplevel (sheet_view->tip));
518 519

	} else if (event->type == GDK_BUTTON_RELEASE) {
520
		GnumericSheet  *gsheet = GNUMERIC_SHEET (sheet_view->sheet_view);
521
		int row;
522

523 524 525 526 527 528
		/* A button release can be generated without a press by people
		 * with mouse wheels */
		if (sheet_view->tip) {
			gtk_widget_destroy (gtk_widget_get_toplevel (sheet_view->tip));
			sheet_view->tip = NULL;
		}
Arturo Espinosa's avatar
Arturo Espinosa committed
529

530
		row = GTK_ADJUSTMENT (sheet_view->va)->value;
531

532
		gnumeric_sheet_set_top_row (gsheet, row);
533
		/* NOTE : Excel does not move the cursor, just scrolls the sheet. */
Arturo Espinosa's avatar
Arturo Espinosa committed
534 535 536 537 538
	}

	return FALSE;
}

539 540 541 542
static void
sheet_view_init (SheetView *sheet_view)
{
	GtkTable *table = GTK_TABLE (sheet_view);
543

544 545 546 547
	table->homogeneous = FALSE;
	gtk_table_resize (table, 4, 4);
}

Arturo Espinosa's avatar
Arturo Espinosa committed
548 549 550
static void
sheet_view_construct (SheetView *sheet_view)
{
551
	GnomeCanvasGroup *root_group;
Arturo Espinosa's avatar
Arturo Espinosa committed
552 553
	GtkTable  *table = GTK_TABLE (sheet_view);
	Sheet *sheet = sheet_view->sheet;
554

Arturo Espinosa's avatar
Arturo Espinosa committed
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570
	/* Column canvas */
	sheet_view->col_canvas = new_canvas_bar (sheet_view, GTK_ORIENTATION_HORIZONTAL, &sheet_view->col_item);
	gtk_table_attach (table, GTK_WIDGET (sheet_view->col_canvas),
			  1, 2, 0, 1,
			  GTK_EXPAND | GTK_FILL | GTK_SHRINK,
			  GTK_FILL,
			  0, 0);
	gtk_signal_connect (GTK_OBJECT (sheet_view->col_item), "selection_changed",
			    GTK_SIGNAL_FUNC (sheet_view_col_selection_changed),
			    sheet_view);
	gtk_signal_connect (GTK_OBJECT (sheet_view->col_item), "size_changed",
			    GTK_SIGNAL_FUNC (sheet_view_col_size_changed),
			    sheet_view);

	/* Row canvas */
	sheet_view->row_canvas = new_canvas_bar (sheet_view, GTK_ORIENTATION_VERTICAL, &sheet_view->row_item);
571

Arturo Espinosa's avatar
Arturo Espinosa committed
572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
	gtk_table_attach (table, GTK_WIDGET (sheet_view->row_canvas),
			  0, 1, 1, 2,
			  GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK,
			  0, 0);
	gtk_signal_connect (GTK_OBJECT (sheet_view->row_item), "selection_changed",
			    GTK_SIGNAL_FUNC (sheet_view_row_selection_changed),
			    sheet_view);
	gtk_signal_connect (GTK_OBJECT (sheet_view->row_item), "size_changed",
			    GTK_SIGNAL_FUNC (sheet_view_row_size_changed),
			    sheet_view);


	/* Create the gnumeric sheet canvas */
	sheet_view->sheet_view = gnumeric_sheet_new (
		sheet_view,
		ITEM_BAR (sheet_view->col_item),
		ITEM_BAR (sheet_view->row_item));
Michael Meeks's avatar
Michael Meeks committed
589

Arturo Espinosa's avatar
Arturo Espinosa committed
590 591 592 593
	gtk_signal_connect_after (
		GTK_OBJECT (sheet_view), "size_allocate",
		GTK_SIGNAL_FUNC (sheet_view_size_allocate), sheet_view);

594 595 596
	/* Create the object group inside the GnumericSheet */
	root_group = GNOME_CANVAS_GROUP (
		GNOME_CANVAS (sheet_view->sheet_view)->root);
597 598 599 600 601 602 603
	sheet_view->object_group = GNOME_CANVAS_GROUP (
		gnome_canvas_item_new (
			root_group,
			gnome_canvas_group_get_type (),
			"x", 0.0,
			"y", 0.0,
			NULL));
604

Arturo Espinosa's avatar
Arturo Espinosa committed
605 606 607 608 609 610 611 612
	/* Attach the GnumericSheet */
	gtk_table_attach (table, sheet_view->sheet_view,
			  1, 2, 1, 2,
			  GTK_EXPAND | GTK_FILL | GTK_SHRINK,
			  GTK_EXPAND | GTK_FILL | GTK_SHRINK,
			  0, 0);
	gtk_widget_show (sheet_view->sheet_view);

613 614 615 616 617 618 619 620 621 622
	/*
	 * The selection group
	 */
	sheet_view->selection_group = GNOME_CANVAS_GROUP (
		gnome_canvas_item_new (
			root_group,
			gnome_canvas_group_get_type (),
			"x", 0.0,
			"y", 0.0,
			NULL));
623

Arturo Espinosa's avatar
Arturo Espinosa committed
624
	/* The select-all button */
625 626 627 628
	sheet_view->select_all_btn = gtk_button_new ();
	GTK_WIDGET_UNSET_FLAGS (sheet_view->select_all_btn, GTK_CAN_FOCUS);
	gtk_table_attach (table, sheet_view->select_all_btn, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
	gtk_signal_connect (GTK_OBJECT (sheet_view->select_all_btn), "clicked",
Arturo Espinosa's avatar
Arturo Espinosa committed
629
			    GTK_SIGNAL_FUNC (button_select_all), sheet_view);
630

Arturo Espinosa's avatar
Arturo Espinosa committed
631
	/* Scroll bars and their adjustments */
632 633
	sheet_view->va = gtk_adjustment_new (0.0, 0.0, sheet->rows.max_used, 1.0, 1.0, 1.0);
	sheet_view->ha = gtk_adjustment_new (0.0, 0.0, sheet->cols.max_used, 1.0, 1.0, 1.0);
Arturo Espinosa's avatar
Arturo Espinosa committed
634 635 636 637 638 639 640 641 642 643 644
	sheet_view->hs = gtk_hscrollbar_new (GTK_ADJUSTMENT (sheet_view->ha));
	sheet_view->vs = gtk_vscrollbar_new (GTK_ADJUSTMENT (sheet_view->va));

	gtk_signal_connect (GTK_OBJECT (sheet_view->ha), "value_changed",
			    GTK_SIGNAL_FUNC (horizontal_scroll_change), sheet_view);
	gtk_signal_connect (GTK_OBJECT (sheet_view->va), "value_changed",
			    GTK_SIGNAL_FUNC (vertical_scroll_change), sheet_view);
	gtk_signal_connect (GTK_OBJECT (sheet_view->hs), "event",
			    GTK_SIGNAL_FUNC (horizontal_scroll_event), sheet_view);
	gtk_signal_connect (GTK_OBJECT (sheet_view->vs), "event",
			    GTK_SIGNAL_FUNC (vertical_scroll_event), sheet_view);
645

Arturo Espinosa's avatar
Arturo Espinosa committed
646 647 648 649 650 651 652 653 654 655 656 657 658
	/* Attach the horizontal scroll */
	gtk_table_attach (table, sheet_view->hs,
			  1, 2, 2, 3,
			  GTK_EXPAND | GTK_FILL | GTK_SHRINK,
			  GTK_FILL,
			  0, 0);

	/* Attach the vertical scroll */
	gtk_table_attach (table, sheet_view->vs,
			  2, 3, 1, 2,
			  GTK_FILL,
			  GTK_EXPAND | GTK_FILL | GTK_SHRINK,
			  0, 0);
659
	sheet_view_set_zoom_factor (sheet_view, 1.);
660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676
}

void
sheet_view_set_header_visibility (SheetView *sheet_view,
				  gboolean col_headers_visible,
				  gboolean row_headers_visible)
{
	g_return_if_fail (sheet_view != NULL);
	g_return_if_fail (IS_SHEET_VIEW (sheet_view));

	if (col_headers_visible){
		if (!GTK_WIDGET_VISIBLE (GTK_WIDGET (sheet_view->col_canvas)))
			gtk_widget_show (GTK_WIDGET (sheet_view->col_canvas));
	} else {
		if (GTK_WIDGET_VISIBLE (GTK_WIDGET (sheet_view->col_canvas)))
			gtk_widget_hide (GTK_WIDGET (sheet_view->col_canvas));
	}
677

678 679 680 681 682 683 684
	if (row_headers_visible){
		if (!GTK_WIDGET_VISIBLE (GTK_WIDGET (sheet_view->row_canvas)))
			gtk_widget_show (GTK_WIDGET (sheet_view->row_canvas));
	} else {
		if (GTK_WIDGET_VISIBLE (GTK_WIDGET (sheet_view->row_canvas)))
			gtk_widget_hide (GTK_WIDGET (sheet_view->row_canvas));
	}
Arturo Espinosa's avatar
Arturo Espinosa committed
685 686 687 688 689 690 691 692 693
}

GtkWidget *
sheet_view_new (Sheet *sheet)
{
	SheetView *sheet_view;

	sheet_view = gtk_type_new (sheet_view_get_type ());
	sheet_view->sheet = sheet;
694
	sheet_view->tip = NULL;
695

Arturo Espinosa's avatar
Arturo Espinosa committed
696
	sheet_view_construct (sheet_view);
697

Arturo Espinosa's avatar
Arturo Espinosa committed
698 699 700 701 702 703 704 705 706 707
	return GTK_WIDGET (sheet_view);
}

static void
sheet_view_destroy (GtkObject *object)
{
	SheetView *sheet_view = SHEET_VIEW (object);

	/* Add shutdown code here */
	if (sheet_view->tip)
708
		gtk_object_unref (GTK_OBJECT (sheet_view->tip));
709

Arturo Espinosa's avatar
Arturo Espinosa committed
710 711 712 713 714
	if (GTK_OBJECT_CLASS (sheet_view_parent_class)->destroy)
		(*GTK_OBJECT_CLASS (sheet_view_parent_class)->destroy)(object);
}

static void
Jody Goldberg's avatar
Jody Goldberg committed
715
sheet_view_class_init (SheetViewClass *Class)
Arturo Espinosa's avatar
Arturo Espinosa committed
716 717 718
{
	GtkObjectClass *object_class;

Jody Goldberg's avatar
Jody Goldberg committed
719
	object_class = (GtkObjectClass *) Class;
Arturo Espinosa's avatar
Arturo Espinosa committed
720 721

	sheet_view_parent_class = gtk_type_class (gtk_table_get_type ());
722

Arturo Espinosa's avatar
Arturo Espinosa committed
723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747
	object_class->destroy = sheet_view_destroy;
}

GtkType
sheet_view_get_type (void)
{
	static GtkType sheet_view_type = 0;

	if (!sheet_view_type){
		GtkTypeInfo sheet_view_info = {
			"SheetView",
			sizeof (SheetView),
			sizeof (SheetViewClass),
			(GtkClassInitFunc) sheet_view_class_init,
			(GtkObjectInitFunc) sheet_view_init,
			NULL, /* reserved 1 */
			NULL, /* reserved 2 */
			(GtkClassInitFunc) NULL
		};

		sheet_view_type = gtk_type_unique (gtk_table_get_type (), &sheet_view_info);
	}

	return sheet_view_type;
}
748

Miguel de Icaza's avatar
New:  
Miguel de Icaza committed
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763
void
sheet_view_hide_cursor (SheetView *sheet_view)
{
	GnumericSheet *gsheet = GNUMERIC_SHEET (sheet_view->sheet_view);

	item_cursor_set_visibility (gsheet->item_cursor, FALSE);
}

void
sheet_view_show_cursor (SheetView *sheet_view)
{
	GnumericSheet *gsheet = GNUMERIC_SHEET (sheet_view->sheet_view);

	item_cursor_set_visibility (gsheet->item_cursor, TRUE);
}
764 765 766

#define TRIANGLE_WIDTH 6

767 768
static GnomeCanvasPoints *
sheet_view_comment_get_points (SheetView *sheet_view, int col, int row)
769 770
{
	GnomeCanvasPoints *points;
771
	int x, y, i;
772 773 774

	points = gnome_canvas_points_new (3);

775 776
	x = sheet_col_get_distance_pixels (sheet_view->sheet, 0, col+1);
	y = 1+sheet_row_get_distance_pixels (sheet_view->sheet, 0, row);
777 778 779 780 781 782 783 784

	points->coords [0] = x - TRIANGLE_WIDTH;
	points->coords [1] = y;
	points->coords [2] = x;
	points->coords [3] = y;
	points->coords [4] = x;
	points->coords [5] = y + TRIANGLE_WIDTH;

785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800
	for (i = 0; i < 3; i++){
		gnome_canvas_c2w (GNOME_CANVAS (sheet_view->sheet_view),
				  points->coords [i*2],
				  points->coords [i*2+1],
				  &(points->coords [i*2]),
				  &(points->coords [i*2+1]));
	}
	return points;
}

GnomeCanvasItem *
sheet_view_comment_create_marker (SheetView *sheet_view, int col, int row)
{
	GnomeCanvasPoints *points;
	GnomeCanvasGroup *group;
	GnomeCanvasItem *i;
801

802 803 804 805 806 807
	g_return_val_if_fail (sheet_view != NULL, NULL);
	g_return_val_if_fail (IS_SHEET_VIEW (sheet_view), NULL);

	group = GNOME_CANVAS_GROUP (GNOME_CANVAS (sheet_view->sheet_view)->root);
	points = sheet_view_comment_get_points (sheet_view, col, row);

808 809 810 811 812 813 814 815
	i = gnome_canvas_item_new (
		group, gnome_canvas_polygon_get_type (),
		"points",     points,
		"fill_color", "red",
		NULL);

	return i;
}
816 817 818 819 820 821 822 823 824 825 826 827 828 829

void
sheet_view_comment_relocate (SheetView *sheet_view, int col, int row, GnomeCanvasItem *o)
{
	GnomeCanvasPoints *points;

	g_return_if_fail (sheet_view != NULL);
	g_return_if_fail (IS_SHEET_VIEW (sheet_view));
	g_return_if_fail (o != NULL);
	g_return_if_fail (GNOME_IS_CANVAS_ITEM (o));

	points = sheet_view_comment_get_points (sheet_view, col, row);

	gnome_canvas_item_set (o, "points", points, NULL);
Morten Welinder's avatar
Morten Welinder committed
830
	gnome_canvas_points_free (points);
831 832
}

833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856
void
sheet_view_selection_unant (SheetView *sheet_view)
{
	GList *l;

	g_return_if_fail (sheet_view != NULL);
	g_return_if_fail (IS_SHEET_VIEW (sheet_view));

	if (sheet_view->anted_cursors == NULL)
		return;

	for (l = sheet_view->anted_cursors; l; l = l->next)
		gtk_object_destroy (GTK_OBJECT (l->data));

	g_list_free (sheet_view->anted_cursors);
	sheet_view->anted_cursors = NULL;
}

void
sheet_view_selection_ant (SheetView *sheet_view)
{
	GnomeCanvasGroup *group;
	ItemGrid *grid;
	GList *l;
857

858 859
	g_return_if_fail (sheet_view != NULL);
	g_return_if_fail (IS_SHEET_VIEW (sheet_view));
860

861 862 863 864 865
	if (sheet_view->anted_cursors)
		sheet_view_selection_unant (sheet_view);

	group = sheet_view->selection_group;
	grid = GNUMERIC_SHEET (sheet_view->sheet_view)->item_grid;
866

867 868 869
	for (l = sheet_view->sheet->selections; l; l = l->next){
		SheetSelection *ss = l->data;
		ItemCursor *item_cursor;
870

871 872 873 874 875 876 877 878 879 880 881 882 883 884 885
		item_cursor = ITEM_CURSOR (gnome_canvas_item_new (
			group, item_cursor_get_type (),
			"Sheet", sheet_view->sheet,
			"Grid",  grid,
			"Style", ITEM_CURSOR_ANTED,
			NULL));
		item_cursor_set_bounds (
			item_cursor,
			ss->user.start.col, ss->user.start.row,
			ss->user.end.col, ss->user.end.row);

		sheet_view->anted_cursors = g_list_prepend (sheet_view->anted_cursors, item_cursor);
	}
}

886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902
void
sheet_view_adjust_preferences (SheetView *sheet_view)
{
	Sheet *sheet = sheet_view->sheet;
	Workbook *wb = sheet->workbook;

	if (sheet->show_col_header)
		gtk_widget_show (GTK_WIDGET (sheet_view->col_canvas));
	else
		gtk_widget_hide (GTK_WIDGET (sheet_view->col_canvas));

	if (sheet->show_row_header)
		gtk_widget_show (GTK_WIDGET (sheet_view->row_canvas));
	else
		gtk_widget_hide (GTK_WIDGET (sheet_view->row_canvas));

	if (sheet->show_col_header && sheet->show_row_header)
903
		gtk_widget_show (sheet_view->select_all_btn);
904
	else
905
		gtk_widget_hide (sheet_view->select_all_btn);
906 907 908 909 910 911 912 913 914 915 916

	if (wb->show_horizontal_scrollbar)
		gtk_widget_show (sheet_view->hs);
	else
		gtk_widget_hide (sheet_view->hs);

	if (wb->show_vertical_scrollbar)
		gtk_widget_show (sheet_view->vs);
	else
		gtk_widget_hide (sheet_view->vs);
}
917

918
StyleFont *
919
sheet_view_get_style_font (const Sheet *sheet, MStyle const * const mstyle)
920 921
{
	/* Scale the font size by the average scaling factor for the
922
	 * display.  72dpi is base size
923 924 925 926 927 928 929 930 931
	 */

	double const zoom = sheet->last_zoom_factor_used;
	double const res  = MIN(application_display_dpi_get (FALSE),
				application_display_dpi_get (TRUE)) / 72.;

	return mstyle_get_font (mstyle, zoom * res);
}

932
#if 0
933 934
#ifdef ENABLE_BONOBO
void
935
sheet_view_insert_object (SheetView *sheet_view, BonoboObjectClient *object)
936
{
Michael Meeks's avatar
Michael Meeks committed
937
/*	GtkWidget *view;*/
938 939 940 941 942

	/*
	 * Commented out because the new_view api changed and it isn't
	 * used anyways.
	 */
943

944
	/* view = gnome_bonobo_object_new_view (object); */
945 946 947
	g_warning ("Stick this into the SheetView");
}
#endif
948
#endif