sheet-view.c 26.4 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 "utils.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 48 49 50 51 52 53
/*
 * redraw a range and all of the associated spans.
 * TODO : this should have TWO cases.
 *     1) redraw just the selected region
 *         This is useful for cursor movement and the like.
 *     2) redraw including the spans.
 *         This is useful for changes to cell contents.
 */
Arturo Espinosa's avatar
Arturo Espinosa committed
54
void
Jody Goldberg's avatar
Jody Goldberg committed
55 56 57
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
58 59
{
	GnumericSheet *gsheet;
60
	GnomeCanvas *canvas;
Arturo Espinosa's avatar
Arturo Espinosa committed
61
	Sheet *sheet = sheet_view->sheet;
Arturo Espinosa's avatar
Arturo Espinosa committed
62
	int first_col, first_row, last_col, last_row;
Jody Goldberg's avatar
Jody Goldberg committed
63
	int row, min_col, max_col;
Arturo Espinosa's avatar
Arturo Espinosa committed
64
	int x, y, w, h;
65

Arturo Espinosa's avatar
Arturo Espinosa committed
66 67 68 69 70
	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));
71
	canvas = GNOME_CANVAS (gsheet);
Arturo Espinosa's avatar
Arturo Espinosa committed
72

73 74 75 76
	if ((end_col < gsheet->col.first) ||
	    (end_row < gsheet->row.first) ||
	    (start_col > gsheet->col.last_visible) ||
	    (start_row > gsheet->row.last_visible))
77
		return;
78

79
	/* The region on which we care to redraw */
80 81 82 83
	first_col = MAX (gsheet->col.first, start_col);
	first_row = MAX (gsheet->row.first, start_row);
	last_col =  MIN (gsheet->col.last_visible, end_col);
	last_row =  MIN (gsheet->row.last_visible, end_row);
84 85

	/* Initial values for min/max column computation */
Arturo Espinosa's avatar
Arturo Espinosa committed
86 87
	min_col = first_col;
	max_col = last_col;
88

Jody Goldberg's avatar
Jody Goldberg committed
89 90 91 92 93 94
	/*
	 * Check the first and last columns for spans
	 * and extend the region to include the maximum extent.
	 */
	for (row = first_row; row <= last_row; row++){
		ColRowInfo const * const ri = sheet_row_get (sheet, row);
95

Jody Goldberg's avatar
Jody Goldberg committed
96 97 98
		if (ri != NULL) {
			CellSpanInfo const * span0 =
			    row_span_get (ri, first_col);
99

Jody Goldberg's avatar
Jody Goldberg committed
100 101 102 103 104 105 106
			if (span0 != NULL) {
				min_col = MIN (span0->left, min_col);
				max_col = MAX (span0->right, max_col);
			}
			if (first_col != last_col) {
				CellSpanInfo const * span1 =
					row_span_get (ri, last_col);
Jody Goldberg's avatar
Jody Goldberg committed
107

Jody Goldberg's avatar
Jody Goldberg committed
108 109 110
				if (span1 != NULL) {
					min_col = MIN (span1->left, min_col);
					max_col = MAX (span1->right, max_col);
Jody Goldberg's avatar
Jody Goldberg committed
111
				}
112 113
			}
		}
Jody Goldberg's avatar
Jody Goldberg committed
114
	}
Arturo Espinosa's avatar
Arturo Espinosa committed
115

116
	/* Only draw those regions that are visible */
117 118
	min_col = MAX (MIN (first_col, min_col), gsheet->col.first);
	max_col = MIN (MAX (last_col, max_col), gsheet->col.last_visible);
Arturo Espinosa's avatar
Arturo Espinosa committed
119

120 121
	x = sheet_col_get_distance_pixels (sheet, gsheet->col.first, min_col);
	y = sheet_row_get_distance_pixels (sheet, gsheet->row.first, first_row);
Jody Goldberg's avatar
Jody Goldberg committed
122 123
	w = sheet_col_get_distance_pixels (sheet, min_col, max_col+1);
	h = sheet_row_get_distance_pixels (sheet, first_row, last_row+1);
Arturo Espinosa's avatar
Arturo Espinosa committed
124

125 126
	x += canvas->layout.xoffset - canvas->zoom_xofs;
	y += canvas->layout.yoffset - canvas->zoom_yofs;
Jody Goldberg's avatar
Jody Goldberg committed
127 128 129 130 131 132 133 134

#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) */
135
	gnome_canvas_request_redraw (GNOME_CANVAS (gsheet),
Jody Goldberg's avatar
Jody Goldberg committed
136 137
				     x-1, y-1,
				     x+w+1+1, y+h+1+1);
Arturo Espinosa's avatar
Arturo Espinosa committed
138 139 140
}

void
Jody Goldberg's avatar
Jody Goldberg committed
141 142 143
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
144
{
Jody Goldberg's avatar
Jody Goldberg committed
145
	GnumericSheet *gsheet;
Arturo Espinosa's avatar
Arturo Espinosa committed
146 147 148
	g_return_if_fail (sheet_view != NULL);
	g_return_if_fail (IS_SHEET_VIEW (sheet_view));

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

Jody Goldberg's avatar
Jody Goldberg committed
151
	if (col) {
152
		int left = 0, right = INT_MAX-1;
Jody Goldberg's avatar
Jody Goldberg committed
153 154 155 156 157 158 159
		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) {
160
				left = gsheet->col_offset.first +
161
				    sheet_col_get_distance_pixels (sheet_view->sheet,
162
							    gsheet->col.first, r->start.col);
Jody Goldberg's avatar
Jody Goldberg committed
163
				right = left +
164
				    sheet_col_get_distance_pixels (sheet_view->sheet,
Jody Goldberg's avatar
Jody Goldberg committed
165 166 167
							    r->start.col, r->end.col+1);
			}
		}
168
		/* Request excludes the far coordinate.  Add 1 to include them */
Jody Goldberg's avatar
Jody Goldberg committed
169 170
		gnome_canvas_request_redraw (
			GNOME_CANVAS (sheet_view->col_canvas),
171
			left, 0, right+1, INT_MAX);
Jody Goldberg's avatar
Jody Goldberg committed
172
	}
Arturo Espinosa's avatar
Arturo Espinosa committed
173

Jody Goldberg's avatar
Jody Goldberg committed
174
	if (row) {
175
		int top = 0, bottom = INT_MAX-1;
Jody Goldberg's avatar
Jody Goldberg committed
176 177 178 179 180 181 182
		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) {
183
				top = gsheet->row_offset.first +
184
				    sheet_row_get_distance_pixels (sheet_view->sheet,
185
							    gsheet->row.first, r->start.row);
Jody Goldberg's avatar
Jody Goldberg committed
186
				bottom = top +
187
				    sheet_row_get_distance_pixels (sheet_view->sheet,
Jody Goldberg's avatar
Jody Goldberg committed
188 189 190
							    r->start.row, r->end.row+1);
			}
		}
191
		/* Request excludes the far coordinate.  Add 1 to include them */
Jody Goldberg's avatar
Jody Goldberg committed
192 193
		gnome_canvas_request_redraw (
			GNOME_CANVAS (sheet_view->row_canvas),
194
			0, top, INT_MAX, bottom+1);
Jody Goldberg's avatar
Jody Goldberg committed
195
	}
Arturo Espinosa's avatar
Arturo Espinosa committed
196 197 198 199 200
}

void
sheet_view_set_zoom_factor (SheetView *sheet_view, double factor)
{
201 202
	GList *l;
	GnumericSheet *gsheet;
203 204
	ItemBar *col_item, *row_item;
	int h, w;
205

Arturo Espinosa's avatar
Arturo Espinosa committed
206 207
	g_return_if_fail (sheet_view != NULL);
	g_return_if_fail (IS_SHEET_VIEW (sheet_view));
208

209
	gsheet = GNUMERIC_SHEET (sheet_view->sheet_view);
210 211
	col_item = ITEM_BAR (sheet_view->col_item);
	row_item = ITEM_BAR (sheet_view->row_item);
212

213
	/* Set pixels_per_unit before the font.  The item bars look here for the number */
214
	gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (gsheet), factor);
215

216
	/* resize the header fonts */
217 218 219 220 221 222 223
	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.
	 */
224

225 226 227 228 229 230
	/* 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);
231
	gnome_canvas_set_scroll_region (GNOME_CANVAS (sheet_view->col_canvas), 0, 0,
232
					1000000*factor, h);
233

234
	gtk_widget_set_usize (GTK_WIDGET (sheet_view->row_canvas), w, -1);
235
	gnome_canvas_set_scroll_region (GNOME_CANVAS (sheet_view->row_canvas), 0, 0,
236
					w, 1200000*factor);
237

238 239
	/* Recalibrate the starting offsets */
	gsheet->col_offset.first =
240
	    sheet_col_get_distance_pixels (sheet_view->sheet, 0, gsheet->col.first);
241
	gsheet->row_offset.first =
242
	    sheet_row_get_distance_pixels (sheet_view->sheet, 0, gsheet->row.first);
243 244 245

	/* Ensure that the current cell remains visible when we zoom */
	gnumeric_sheet_make_cell_visible (gsheet,
246 247 248
					  sheet_view->sheet->cursor.edit_pos.col,
					  sheet_view->sheet->cursor.edit_pos.row,
					  TRUE);
249 250 251 252 253 254 255

	/* 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
256 257 258 259 260 261 262 263 264 265 266
}

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)
{
267 268 269 270 271 272 273 274 275 276
	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
277 278 279 280 281

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

282
	*itemp = item;
Arturo Espinosa's avatar
Arturo Espinosa committed
283
	gtk_widget_show (canvas);
284

285
	return GNOME_CANVAS(canvas);
Arturo Espinosa's avatar
Arturo Espinosa committed
286 287
}

Jody Goldberg's avatar
Jody Goldberg committed
288 289 290
/* Manages the scrollbar dimensions and paging parameters. */
void
sheet_view_scrollbar_config (SheetView const *sheet_view)
Arturo Espinosa's avatar
Arturo Espinosa committed
291 292 293 294
{
	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
295
	Sheet         *sheet = sheet_view->sheet;
296 297
	int const last_col = gsheet->col.last_full;
	int const last_row = gsheet->row.last_full;
Arturo Espinosa's avatar
Arturo Espinosa committed
298

Jody Goldberg's avatar
Jody Goldberg committed
299
	va->upper = MAX (MAX (last_row,
300
			      sheet_view->sheet->rows.max_used),
301 302
			 MAX (sheet->cursor.move_corner.row,
			      sheet->cursor.base_corner.row));
303
	va->page_size = last_row - gsheet->row.first;
304
	va->value = gsheet->row.first;
Jody Goldberg's avatar
Jody Goldberg committed
305 306
	va->step_increment = va->page_increment =
	    va->page_size / 2;
307

Jody Goldberg's avatar
Jody Goldberg committed
308
	ha->upper = MAX (MAX (last_col,
309
			      sheet_view->sheet->cols.max_used),
310 311
			 MAX (sheet->cursor.move_corner.col,
			      sheet->cursor.base_corner.col));
312
	ha->page_size = last_col - gsheet->col.first;
313
	ha->value = gsheet->col.first;
Jody Goldberg's avatar
Jody Goldberg committed
314 315
	ha->step_increment = ha->page_increment =
	    ha->page_size / 2;
Arturo Espinosa's avatar
Arturo Espinosa committed
316 317 318 319 320

	gtk_adjustment_changed (va);
	gtk_adjustment_changed (ha);
}

Jody Goldberg's avatar
Jody Goldberg committed
321 322 323 324 325 326
static void
sheet_view_size_allocate (GtkWidget *widget, GtkAllocation *alloc, SheetView *sheet_view)
{
	sheet_view_scrollbar_config (sheet_view);
}

Arturo Espinosa's avatar
Arturo Espinosa committed
327
static void
328 329
sheet_view_col_selection_changed (ItemBar *item_bar, int col, int modifiers, SheetView *sheet_view)
{
Arturo Espinosa's avatar
Arturo Espinosa committed
330
	Sheet *sheet = sheet_view->sheet;
331 332
	GnumericSheet *gsheet = GNUMERIC_SHEET (sheet_view->sheet_view);

333
	/* Ensure that the col exists, ignore result */
334 335
	sheet_col_fetch (sheet, col);

336 337 338 339
	if (modifiers){
		if ((modifiers & GDK_SHIFT_MASK) && sheet->selections){
			SheetSelection *ss = sheet->selections->data;
			int start_col, end_col;
340 341 342 343

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

344
			sheet_selection_set (sheet,
345
					     start_col, gsheet->row.first,
346 347 348 349
					     start_col, 0,
					     end_col, SHEET_MAX_ROWS-1);
			return;
		}
350

351 352
		if (!(modifiers & GDK_CONTROL_MASK))
			sheet_selection_reset_only (sheet);
353

354 355 356 357
		sheet_selection_add_range (sheet,
					   col, gsheet->row.first,
					   col, 0,
					   col, SHEET_MAX_ROWS-1);
Arturo Espinosa's avatar
Arturo Espinosa committed
358
	} else
359
		sheet_selection_extend_to (sheet, col, SHEET_MAX_ROWS - 1);
Arturo Espinosa's avatar
Arturo Espinosa committed
360 361 362 363 364 365
}

static void
sheet_view_col_size_changed (ItemBar *item_bar, int col, int width, SheetView *sheet_view)
{
	Sheet *sheet = sheet_view->sheet;
366 367 368 369
	ItemBarSelectionType type;

	type = sheet_col_selection_type (sheet, col);

370 371 372
 	if (type == ITEM_BAR_FULL_SELECTION) {
		int i = sheet->cols.max_used;
		for (;i >= 0 ; --i) {
Jody Goldberg's avatar
Jody Goldberg committed
373
 			ColRowInfo const * const ci = sheet_col_get (sheet, i);
374 375
			if (ci == NULL)
				continue;
376

Jody Goldberg's avatar
Jody Goldberg committed
377 378 379 380 381
 			if (sheet_col_selection_type (sheet, ci->pos) == ITEM_BAR_FULL_SELECTION) {
 				sheet_col_set_size_pixels (sheet, i, width, TRUE);
				/* FIXME should be done later */
				sheet_recompute_spans_for_col (sheet, i);
			}
382
 		}
Jody Goldberg's avatar
Jody Goldberg committed
383
	} else {
384
 		sheet_col_set_size_pixels (sheet, col, width, TRUE);
Jody Goldberg's avatar
Jody Goldberg committed
385 386 387
		/* FIXME should be done later */
		sheet_recompute_spans_for_col (sheet, col);
	}
388

Jody Goldberg's avatar
Jody Goldberg committed
389
	sheet_update (sheet);
Arturo Espinosa's avatar
Arturo Espinosa committed
390 391 392
}

static void
393
sheet_view_row_selection_changed (ItemBar *item_bar, int row, int modifiers, SheetView *sheet_view)
Arturo Espinosa's avatar
Arturo Espinosa committed
394 395
{
	Sheet *sheet = sheet_view->sheet;
396
	GnumericSheet *gsheet = GNUMERIC_SHEET (sheet_view->sheet_view);
397

398 399
	/* Ensure that the row exists, ignore result */
	sheet_row_fetch (sheet, row);
400

401 402 403 404
	if (modifiers){
		if ((modifiers & GDK_SHIFT_MASK) && sheet->selections){
			SheetSelection *ss = sheet->selections->data;
			int start_row, end_row;
405 406 407 408

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

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

416 417
		if (!(modifiers & GDK_CONTROL_MASK))
 			sheet_selection_reset_only (sheet);
418 419 420 421 422

		sheet_selection_add_range (sheet,
					   gsheet->col.first, row,
					   0, row,
					   SHEET_MAX_COLS-1, row);
Arturo Espinosa's avatar
Arturo Espinosa committed
423
	} else
424
		sheet_selection_extend_to (sheet, SHEET_MAX_COLS-1, row);
Arturo Espinosa's avatar
Arturo Espinosa committed
425 426 427 428 429 430
}

static void
sheet_view_row_size_changed (ItemBar *item_bar, int row, int height, SheetView *sheet_view)
{
	Sheet *sheet = sheet_view->sheet;
431 432 433 434
	ItemBarSelectionType type;

	type = sheet_row_selection_type (sheet, row);

435 436 437
	if (type == ITEM_BAR_FULL_SELECTION) {
		int i;
		for (i = sheet->rows.max_used; i >= 0 ; --i) {
Jody Goldberg's avatar
Jody Goldberg committed
438
 			ColRowInfo const * const ri = sheet_row_get (sheet, i);
439 440
			if (ri == NULL)
				continue;
441

442
			if (sheet_row_selection_type (sheet, ri->pos) == ITEM_BAR_FULL_SELECTION)
Jody Goldberg's avatar
Jody Goldberg committed
443
				sheet_row_set_size_pixels (sheet, ri->pos, height, TRUE);
444
		}
445
	} else
446
		sheet_row_set_size_pixels (sheet, row, height, TRUE);
Jody Goldberg's avatar
Jody Goldberg committed
447 448

	sheet_update (sheet);
Arturo Espinosa's avatar
Arturo Espinosa committed
449 450 451 452 453 454
}

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

static void
vertical_scroll_change (GtkAdjustment *adj, SheetView *sheet_view)
{
461 462 463 464 465
	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
466 467 468 469 470
}

static void
horizontal_scroll_change (GtkAdjustment *adj, SheetView *sheet_view)
{
471 472 473 474
	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
475 476 477 478 479 480 481
	}
}

static int
horizontal_scroll_event (GtkScrollbar *scroll, GdkEvent *event, SheetView *sheet_view)
{
	if (event->type == GDK_BUTTON_PRESS){
482 483 484
		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
485
		gtk_widget_show_all (gtk_widget_get_toplevel (sheet_view->tip));
486 487 488 489
	}
	else if (event->type == GDK_BUTTON_RELEASE)
	{
		GnumericSheet  *gsheet = GNUMERIC_SHEET (sheet_view->sheet_view);
490
		int col;
491

492 493 494 495 496 497
		/* 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
498

499 500
		col = GTK_ADJUSTMENT (sheet_view->ha)->value;

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

Arturo Espinosa's avatar
Arturo Espinosa committed
505 506 507 508 509 510 511
	return FALSE;
}

static int
vertical_scroll_event (GtkScrollbar *scroll, GdkEvent *event, SheetView *sheet_view)
{
	if (event->type == GDK_BUTTON_PRESS){
512 513 514
		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
515
		gtk_widget_show_all (gtk_widget_get_toplevel (sheet_view->tip));
516 517 518 519
	}
	else if (event->type == GDK_BUTTON_RELEASE)
	{
		GnumericSheet  *gsheet = GNUMERIC_SHEET (sheet_view->sheet_view);
520
		int row;
521

522 523 524 525 526 527
		/* 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
528

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

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

	return FALSE;
}

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

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

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

Arturo Espinosa's avatar
Arturo Espinosa committed
554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569
	/* 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);
570

Arturo Espinosa's avatar
Arturo Espinosa committed
571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
	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
588

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

593 594 595
	/* Create the object group inside the GnumericSheet */
	root_group = GNOME_CANVAS_GROUP (
		GNOME_CANVAS (sheet_view->sheet_view)->root);
596 597 598 599 600 601 602
	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));
603

Arturo Espinosa's avatar
Arturo Espinosa committed
604 605 606 607 608 609 610 611
	/* 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);

612 613 614 615 616 617 618 619 620 621
	/*
	 * 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));
622

Arturo Espinosa's avatar
Arturo Espinosa committed
623
	/* The select-all button */
624 625 626 627
	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
628
			    GTK_SIGNAL_FUNC (button_select_all), sheet_view);
629

Arturo Espinosa's avatar
Arturo Espinosa committed
630
	/* Scroll bars and their adjustments */
631 632
	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
633 634 635 636 637 638 639 640 641 642 643
	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);
644

Arturo Espinosa's avatar
Arturo Espinosa committed
645 646 647 648 649 650 651 652 653 654 655 656 657
	/* 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);
658
	sheet_view_set_zoom_factor (sheet_view, 1.);
659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675
}

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));
	}
676

677 678 679 680 681 682 683
	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
684 685 686 687 688 689 690 691 692
}

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

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

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

Arturo Espinosa's avatar
Arturo Espinosa committed
697 698 699 700 701 702 703 704 705 706
	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)
707
		gtk_object_unref (GTK_OBJECT (sheet_view->tip));
708

Arturo Espinosa's avatar
Arturo Espinosa committed
709 710 711 712 713
	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
714
sheet_view_class_init (SheetViewClass *Class)
Arturo Espinosa's avatar
Arturo Espinosa committed
715 716 717
{
	GtkObjectClass *object_class;

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

	sheet_view_parent_class = gtk_type_class (gtk_table_get_type ());
721

Arturo Espinosa's avatar
Arturo Espinosa committed
722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746
	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;
}
747

Miguel de Icaza's avatar
New:  
Miguel de Icaza committed
748 749 750 751 752 753 754 755 756 757 758 759 760 761 762
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);
}
763 764 765

#define TRIANGLE_WIDTH 6

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

	points = gnome_canvas_points_new (3);

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

	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;

784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799
	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;
800

801 802 803 804 805 806
	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);

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

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

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);
}

831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854
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;
855

856 857
	g_return_if_fail (sheet_view != NULL);
	g_return_if_fail (IS_SHEET_VIEW (sheet_view));
858

859 860 861 862 863
	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;
864

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

869 870 871 872 873 874 875 876 877 878 879 880 881 882 883
		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);
	}
}

884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900
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)
901
		gtk_widget_show (sheet_view->select_all_btn);
902
	else
903
		gtk_widget_hide (sheet_view->select_all_btn);
904 905 906 907 908 909 910 911 912 913 914

	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);
}
915

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

	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);
}

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

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

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