item-bar.c 23.3 KB
Newer Older
1 2 3 4 5 6 7
/*
 * Implements the resizable guides for columns and rows
 * in the Gnumeric Spreadsheet.
 *
 * Author:
 *     Miguel de Icaza (miguel@kernel.org)
 */
8 9 10 11
#include <config.h>

#include <gnome.h>
#include "gnumeric.h"
12
#include "gnumeric-sheet.h"
13 14
#include "item-bar.h"
#include "item-debug.h"
15
#include "parse-util.h"
16
#include "gnumeric-util.h"
Jody Goldberg's avatar
Jody Goldberg committed
17
#include "selection.h"
18
#include "workbook-cmd-format.h"
19
#include "application.h"
20
#include "style.h"
21

Arturo Espinosa's avatar
Arturo Espinosa committed
22
/* Marshal forward declarations */
Arturo Espinosa's avatar
Arturo Espinosa committed
23 24 25 26
static void   item_bar_marshal      (GtkObject *,
				     GtkSignalFunc,
				     gpointer,
				     GtkArg *);
Morten Welinder's avatar
Morten Welinder committed
27

Arturo Espinosa's avatar
Arturo Espinosa committed
28 29 30 31
/* The signal signatures */
typedef void (*ItemBarSignal1) (GtkObject *, gint arg1, gpointer data);
typedef void (*ItemBarSignal2) (GtkObject *, gint arg1, gint arg2, gpointer data);

32 33
/* The signals we emit */
enum {
Arturo Espinosa's avatar
Arturo Espinosa committed
34 35 36
	SELECTION_CHANGED,
	SIZE_CHANGED,
	LAST_SIGNAL
37
};
Arturo Espinosa's avatar
Arturo Espinosa committed
38
static guint item_bar_signals [LAST_SIGNAL] = { 0 };
39 40 41 42 43 44

static GnomeCanvasItem *item_bar_parent_class;

/* The arguments we take */
enum {
	ARG_0,
Arturo Espinosa's avatar
Arturo Espinosa committed
45
	ARG_SHEET_VIEW,
46 47 48 49
	ARG_ORIENTATION,
	ARG_FIRST_ELEMENT
};

50 51
#define ITEM_BAR_RESIZING(x) (ITEM_BAR(x)->resize_pos != -1)

52 53 54 55 56 57 58 59 60 61 62 63 64 65
static void
item_bar_fonts_unref (ItemBar *item_bar)
{
	if (item_bar->normal_font != NULL) {
		style_font_unref (item_bar->normal_font);
		item_bar->normal_font = NULL;
	}

	if (item_bar->bold_font != NULL) {
		style_font_unref (item_bar->bold_font);
		item_bar->bold_font = NULL;
	}
}

66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
static void
item_bar_destroy (GtkObject *object)
{
	ItemBar *bar;

	bar = ITEM_BAR (object);

	item_bar_fonts_unref (bar);

	if (bar->tip)
		gtk_object_unref (GTK_OBJECT (bar->tip));

	if (GTK_OBJECT_CLASS (item_bar_parent_class)->destroy)
		(*GTK_OBJECT_CLASS (item_bar_parent_class)->destroy)(object);
}

82 83 84 85
/*
 * Scale the item-bar heading fonts by the pixels_per_unit of
 * th associated sheet.
 */
86
void
87
item_bar_fonts_init (ItemBar *item_bar)
88
{
89 90
	double const zoom_factor =
		item_bar->sheet_view->sheet->last_zoom_factor_used;
91
	double const res  = application_dpi_to_pixels ();
92
	StyleFont * const normal_font =
93
		style_font_new_simple (DEFAULT_FONT, DEFAULT_SIZE,
94
				       res*zoom_factor, FALSE, FALSE);
95
	StyleFont * const bold_font =
96
		style_font_new_simple (DEFAULT_FONT, DEFAULT_SIZE,
97
				       res*zoom_factor, TRUE, FALSE);
98 99 100 101 102 103 104

	/* Now that we have the new fonts unref the old ones */
	item_bar_fonts_unref (item_bar);

	/* And finish up by assigning the new fonts. */
	item_bar->normal_font = normal_font;
	item_bar->bold_font = bold_font;
105 106
}

107 108 109 110 111 112
static void
item_bar_realize (GnomeCanvasItem *item)
{
	ItemBar *item_bar;
	GdkWindow *window;
	GdkGC *gc;
113
	GdkColor c;
Arturo Espinosa's avatar
Arturo Espinosa committed
114 115 116 117

	if (GNOME_CANVAS_ITEM_CLASS (item_bar_parent_class)->realize)
		(*GNOME_CANVAS_ITEM_CLASS (item_bar_parent_class)->realize)(item);

118 119
	item_bar = ITEM_BAR (item);
	window = GTK_WIDGET (item->canvas)->window;
Morten Welinder's avatar
Morten Welinder committed
120

121 122
	/* Configure our gc */
	item_bar->gc = gc = gdk_gc_new (window);
123 124
	gnome_canvas_get_color (item->canvas, "black", &c);
	gdk_gc_set_foreground (item_bar->gc, &c);
125 126 127 128 129 130

	item_bar->normal_cursor = gdk_cursor_new (GDK_ARROW);
	if (item_bar->orientation == GTK_ORIENTATION_VERTICAL)
		item_bar->change_cursor = gdk_cursor_new (GDK_SB_V_DOUBLE_ARROW);
	else
		item_bar->change_cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
131

132
	item_bar_fonts_init (item_bar);
133 134 135 136 137 138
}

static void
item_bar_unrealize (GnomeCanvasItem *item)
{
	ItemBar *item_bar = ITEM_BAR (item);
139

140 141 142
	gdk_gc_unref (item_bar->gc);
	gdk_cursor_destroy (item_bar->change_cursor);
	gdk_cursor_destroy (item_bar->normal_cursor);
143
	item_bar_fonts_unref (item_bar);
Arturo Espinosa's avatar
Arturo Espinosa committed
144 145 146

	if (GNOME_CANVAS_ITEM_CLASS (item_bar_parent_class)->unrealize)
		(*GNOME_CANVAS_ITEM_CLASS (item_bar_parent_class)->unrealize)(item);
147 148 149
}

static void
150
item_bar_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
151
{
152 153
	if (GNOME_CANVAS_ITEM_CLASS (item_bar_parent_class)->update)
		(*GNOME_CANVAS_ITEM_CLASS (item_bar_parent_class)->update)(item, affine, clip_path, flags);
154

155 156 157 158 159 160 161
	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);
}

Morten Welinder's avatar
Morten Welinder committed
162
static const char *
163 164
get_row_name (int n)
{
Arturo Espinosa's avatar
Arturo Espinosa committed
165
	static char x [4 * sizeof (int)];
166

Morten Welinder's avatar
Morten Welinder committed
167
	g_assert (n >= 0 && n < SHEET_MAX_ROWS);
168 169

	sprintf (x, "%d", n + 1);
170 171 172 173
	return x;
}

static void
174 175
bar_draw_cell (ItemBar const * const item_bar,
	       GdkDrawable *drawable, ItemBarSelectionType const type,
176
	       char const * const str, GdkRectangle * rect)
177 178
{
	GtkWidget *canvas = GTK_WIDGET (GNOME_CANVAS_ITEM (item_bar)->canvas);
179
	GdkFont *font;
180 181 182
	GdkGC *gc;
	int len, texth, shadow;

183 184 185 186 187
	switch (type){
	default:
	case ITEM_BAR_NO_SELECTION:
		shadow = GTK_SHADOW_OUT;
		gc = canvas->style->bg_gc [GTK_STATE_ACTIVE];
188
		font = style_font_gdk_font (item_bar->normal_font);
189
		break;
190

191
	case ITEM_BAR_PARTIAL_SELECTION:
192
		shadow = GTK_SHADOW_OUT;
Jody Goldberg's avatar
Jody Goldberg committed
193
		gc = canvas->style->dark_gc [GTK_STATE_PRELIGHT];
194
		font = style_font_gdk_font (item_bar->bold_font);
195
		break;
196

197 198 199
	case ITEM_BAR_FULL_SELECTION:
		shadow = GTK_SHADOW_IN;
		gc = canvas->style->dark_gc [GTK_STATE_NORMAL];
200
		font = style_font_gdk_font (item_bar->bold_font);
201
		break;
202
	}
203

204 205 206
	len = gdk_string_width (font, str);
	texth = font->ascent + font->descent;

207 208
	gdk_gc_set_clip_rectangle (gc, rect);
	gdk_draw_rectangle (drawable, gc, TRUE, rect->x + 1, rect->y + 1, rect->width-2, rect->height-2);
Morten Welinder's avatar
Morten Welinder committed
209
	gtk_draw_shadow (canvas->style, drawable, GTK_STATE_NORMAL, shadow,
210
			 rect->x, rect->y, rect->width, rect->height);
211
	gdk_draw_string (drawable, font, item_bar->gc,
212
			 rect->x + (rect->width - len) / 2,
213
			 rect->y + (rect->height - texth) / 2 + font->ascent + 1,
214 215 216 217 218 219
			 str);
}

static void
item_bar_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int height)
{
220 221
	ItemBar const * const item_bar = ITEM_BAR (item);
	Sheet   const * const sheet = item_bar->sheet_view->sheet;
Jody Goldberg's avatar
Jody Goldberg committed
222
	GnumericSheet const * const gsheet = GNUMERIC_SHEET (item_bar->sheet_view->sheet_view);
223
	GtkWidget *canvas = GTK_WIDGET (GNOME_CANVAS_ITEM (item)->canvas);
224
	int pixels;
225
	GdkRectangle rect;
226 227

	if (item_bar->orientation == GTK_ORIENTATION_VERTICAL) {
228 229 230 231 232 233 234 235 236 237 238
		/* Include a 1 pixel buffer.
		 * To avoid overlaping the cells the shared pixel belongs to the cell above.
		 * This has the nice property that the bottom dark line of the
		 * shadow aligns with the grid lines.
		 * Unfortunately it also implies a 1 pixel empty space at the
		 * top of the bar.  Which we are forced to fill in with
		 * something.  For now I draw a black line there to be
		 * compatible with the default colour used on the bottom of the
		 * cell shadows.
		 */
		int total = 1 + gsheet->row_offset.first - y;
239
		int element = gsheet->row.first;
240

241 242 243 244 245 246 247 248 249 250
		rect.x = -x;
		rect.width = canvas->allocation.width;

		/* FIXME : How to avoid hard coding this color ?
		 * We need the color that will be drawn as the bottom bevel
		 * for the button shadow
		 */
		gdk_draw_line (drawable, canvas->style->black_gc,
			       rect.x, total-1,
			       rect.x + rect.width, total-1);
251
		do {
252
			ColRowInfo const *cri;
Jody Goldberg's avatar
Jody Goldberg committed
253
			if (element >= SHEET_MAX_ROWS)
254
				return;
Jody Goldberg's avatar
Jody Goldberg committed
255

256 257 258 259
			cri = sheet_row_get_info (sheet, element);
			pixels = (item_bar->resize_pos != element)
			    ? cri->size_pixels
			    : item_bar->resize_width;
Morten Welinder's avatar
Morten Welinder committed
260

261
			if (cri->visible) {
262 263 264
				total += pixels;
				if (total >= 0) {
					char const * const str = get_row_name (element);
265 266
					rect.y = total - pixels;
					rect.height = pixels;
267 268
					bar_draw_cell (item_bar, drawable,
						       sheet_row_selection_type (sheet, element),
269
						       str, &rect);
270
				}
271
			}
272 273 274
			++element;
		} while (total < height);
	} else {
275 276
		/* See comment above for explaination of the extra 1 pixel */
		int total = 1 + gsheet->col_offset.first - x;
277
		int element = gsheet->col.first;
278 279 280 281 282 283 284 285 286 287 288

		rect.y = -y;
		rect.height = canvas->allocation.height;

		/* FIXME : How to avoid hard coding this color ?
		 * We need the color that will be drawn as the right bevel
		 * for the button shadow
		 */
		gdk_draw_line (drawable, canvas->style->black_gc,
			       total-1, rect.y,
			       total-1, rect.y + rect.height);
289 290

		do {
291
			ColRowInfo const *cri;
Jody Goldberg's avatar
Jody Goldberg committed
292
			if (element >= SHEET_MAX_COLS)
293
				return;
Jody Goldberg's avatar
Jody Goldberg committed
294

295 296 297 298
			cri = sheet_col_get_info (sheet, element);
			pixels = (item_bar->resize_pos != element)
			    ? cri->size_pixels
			    : item_bar->resize_width;
299

300
			if (cri->visible) {
301
				total += pixels;
302 303 304
				if (total >= 0) {
					rect.x = total - pixels;
					rect.width = pixels;
305 306
					bar_draw_cell (item_bar, drawable,
						       sheet_col_selection_type (sheet, element),
307 308
						       col_name (element), &rect);
				}
309
			}
Morten Welinder's avatar
Morten Welinder committed
310

311 312 313
			++element;
		} while (total < width);
	}
314 315 316 317
}

static double
item_bar_point (GnomeCanvasItem *item, double x, double y, int cx, int cy,
318
		GnomeCanvasItem **actual_item)
319 320 321 322 323 324 325 326 327 328 329
{
	*actual_item = item;
	return 0.0;
}

static void
item_bar_translate (GnomeCanvasItem *item, double dx, double dy)
{
	printf ("item_bar_translate %g, %g\n", dx, dy);
}

Arturo Espinosa's avatar
Arturo Espinosa committed
330 331
static ColRowInfo *
is_pointer_on_division (ItemBar *item_bar, int pos, int *the_total, int *the_element)
332
{
333
	ColRowInfo *cri;
Arturo Espinosa's avatar
Arturo Espinosa committed
334
	Sheet *sheet;
335
	int i, total;
Morten Welinder's avatar
Morten Welinder committed
336

337
	total = 0;
Arturo Espinosa's avatar
Arturo Espinosa committed
338
	sheet = item_bar->sheet_view->sheet;
Morten Welinder's avatar
Morten Welinder committed
339

340
	for (i = item_bar->first_element; total < pos; i++){
341 342 343
		if (item_bar->orientation == GTK_ORIENTATION_VERTICAL){
			if (i >= SHEET_MAX_ROWS)
				return NULL;
Arturo Espinosa's avatar
Arturo Espinosa committed
344
			cri = sheet_row_get_info (sheet, i);
345 346 347
		} else {
			if (i >= SHEET_MAX_COLS)
				return NULL;
Arturo Espinosa's avatar
Arturo Espinosa committed
348
			cri = sheet_col_get_info (sheet, i);
349
		}
350

351 352
		if (cri->visible) {
			total += cri->size_pixels;
353 354 355 356 357
			if ((total - 4 < pos) && (pos < total + 4)) {
				if (the_total)
					*the_total = total;
				if (the_element)
					*the_element = i;
Arturo Espinosa's avatar
Arturo Espinosa committed
358

359 360
				return cri;
			}
Arturo Espinosa's avatar
Arturo Espinosa committed
361
		}
362

363
		if (total > pos) {
364 365 366 367
			if (the_element)
				*the_element = i;
			return NULL;
		}
368
	}
Arturo Espinosa's avatar
Arturo Espinosa committed
369
	return NULL;
370 371 372 373 374 375 376
}

static void
set_cursor (ItemBar *item_bar, int pos)
{
	GtkWidget *canvas = GTK_WIDGET (GNOME_CANVAS_ITEM (item_bar)->canvas);

377 378 379
	/* We might be invoked before we are realized */
	if (!canvas->window)
		return;
Morten Welinder's avatar
Morten Welinder committed
380

Arturo Espinosa's avatar
Arturo Espinosa committed
381
	if (is_pointer_on_division (item_bar, pos, NULL, NULL))
382
		gdk_window_set_cursor (canvas->window, item_bar->change_cursor);
383
	else
384
		gdk_window_set_cursor (canvas->window, item_bar->normal_cursor);
385 386
}

Jody Goldberg's avatar
Jody Goldberg committed
387 388
static void
item_bar_start_resize (ItemBar *bar)
389
{
Jody Goldberg's avatar
Jody Goldberg committed
390
	Sheet const * const sheet = bar->sheet_view->sheet;
391 392 393 394 395 396 397 398 399
#if 0
	/*
	 * handle the zoom from the item-grid canvas, the resolution scaling is
	 * handled elsewhere
	 */
	double const res  = application_display_dpi_get (bar->orientation ==
							 GTK_ORIENTATION_VERTICAL);
#endif
	double const zoom = sheet->last_zoom_factor_used; /* * res / 72.; */
Jody Goldberg's avatar
Jody Goldberg committed
400 401 402 403 404
	GnumericSheet const * const gsheet = GNUMERIC_SHEET (bar->sheet_view->sheet_view);
	GnomeCanvas const * const canvas = GNOME_CANVAS (gsheet);
	GnomeCanvasGroup * const group = GNOME_CANVAS_GROUP (canvas->root);
	GnomeCanvasPoints * const points =
	    bar->resize_points = gnome_canvas_points_new (2);
405
	GnomeCanvasItem * item =
Jody Goldberg's avatar
Jody Goldberg committed
406 407 408 409 410 411 412
	    gnome_canvas_item_new ( group,
				    gnome_canvas_line_get_type (),
				    "fill_color", "black",
				    "width_pixels", 1,
				    NULL);
	bar->resize_guide = GTK_OBJECT (item);

413 414
	/* NOTE : Set the position of the stationary line here.
	 * Set the guide line later based on the motion coordinates.
Jody Goldberg's avatar
Jody Goldberg committed
415 416
	 */
	if (bar->orientation == GTK_ORIENTATION_VERTICAL) {
417
		double const y =
418
		    sheet_row_get_distance_pixels (sheet, 0, bar->resize_pos) / zoom;
Jody Goldberg's avatar
Jody Goldberg committed
419
		points->coords [0] =
420
		    sheet_col_get_distance_pixels (sheet, 0, gsheet->col.first) / zoom;
421
		points->coords [1] = y;
Jody Goldberg's avatar
Jody Goldberg committed
422
		points->coords [2] =
423
		    sheet_col_get_distance_pixels (sheet, 0, gsheet->col.last_visible+1) / zoom;
424
		points->coords [3] = y;
425
	} else {
426
		double const x =
427
		    sheet_col_get_distance_pixels (sheet, 0, bar->resize_pos) / zoom;
428
		points->coords [0] = x;
Jody Goldberg's avatar
Jody Goldberg committed
429
		points->coords [1] =
430
		    sheet_row_get_distance_pixels (sheet, 0, gsheet->row.first) / zoom;
431
		points->coords [2] = x;
Jody Goldberg's avatar
Jody Goldberg committed
432
		points->coords [3] =
433
		    sheet_row_get_distance_pixels (sheet, 0, gsheet->row.last_visible+1) / zoom;
434
	}
435 436 437 438 439 440 441 442

	item = gnome_canvas_item_new ( group,
				       gnome_canvas_line_get_type (),
				       "points", points,
				       "fill_color", "black",
				       "width_pixels", 1,
				       NULL);
	bar->resize_start = GTK_OBJECT (item);
Arturo Espinosa's avatar
Arturo Espinosa committed
443 444
}

Arturo Espinosa's avatar
Arturo Espinosa committed
445
static int
446
get_element_from_pixel (ItemBar *item_bar, int pos)
Arturo Espinosa's avatar
Arturo Espinosa committed
447 448
{
	ColRowInfo *cri;
Arturo Espinosa's avatar
Arturo Espinosa committed
449
	Sheet *sheet;
450
	int i, total;
Morten Welinder's avatar
Morten Welinder committed
451

Arturo Espinosa's avatar
Arturo Espinosa committed
452
	total = 0;
Arturo Espinosa's avatar
Arturo Espinosa committed
453
	sheet = item_bar->sheet_view->sheet;
Arturo Espinosa's avatar
Arturo Espinosa committed
454
	for (i = item_bar->first_element; total < pos; i++){
455 456 457
		if (item_bar->orientation == GTK_ORIENTATION_VERTICAL){
			if (i >= SHEET_MAX_ROWS)
				return i-1;
Arturo Espinosa's avatar
Arturo Espinosa committed
458
			cri = sheet_row_get_info (sheet, i);
459 460 461
		} else {
			if (i >= SHEET_MAX_COLS)
				return i-1;
Arturo Espinosa's avatar
Arturo Espinosa committed
462
			cri = sheet_col_get_info (sheet, i);
463
		}
Arturo Espinosa's avatar
Arturo Espinosa committed
464

465 466
		if (cri->visible) {
			total += cri->size_pixels;
467 468 469
			if (total > pos)
				return i;
		}
Arturo Espinosa's avatar
Arturo Espinosa committed
470 471 472 473
	}
	return i;
}

474
static void
475
colrow_tip_setlabel (ItemBar *item_bar, gboolean const is_vertical, int size_pixels)
476 477 478
{
	if (item_bar->tip) {
		char buffer [20 + sizeof (long) * 4];
479
		double const scale = 72. / application_display_dpi_get (is_vertical);
480
		if (is_vertical)
481 482
			snprintf (buffer, sizeof (buffer), _("Height: %.2f (%d pixels)"),
				  scale*size_pixels, size_pixels);
483
		else
484 485
			snprintf (buffer, sizeof (buffer), _("Width: %.2f (%d pixels)"),
				  scale*size_pixels, size_pixels);
486 487 488 489 490 491 492
		gtk_label_set_text (GTK_LABEL (item_bar->tip), buffer);
	}
}

static void
item_bar_end_resize (ItemBar *item_bar, int new_size)
{
493
	if (new_size != 0)
494 495 496 497
		gtk_signal_emit (GTK_OBJECT (item_bar),
				 item_bar_signals [SIZE_CHANGED],
				 item_bar->resize_pos,
				 new_size);
498

Jody Goldberg's avatar
Jody Goldberg committed
499 500 501 502
	if (item_bar->resize_points) {
		gnome_canvas_points_free (item_bar->resize_points);
		item_bar->resize_points = NULL;
	}
503
	if (item_bar->resize_guide) {
504 505
		gtk_object_destroy (item_bar->resize_start);
		item_bar->resize_start = NULL;
506 507 508 509 510 511 512
		gtk_object_destroy (item_bar->resize_guide);
		item_bar->resize_guide = NULL;
	}
	if (item_bar->tip) {
		gtk_widget_destroy (gtk_widget_get_toplevel (item_bar->tip));
		item_bar->tip = NULL;
	}
513

514 515 516
	item_bar->resize_pos = -1;
}

517 518 519 520 521 522 523 524 525 526 527
static gboolean
cb_extend_selection (SheetView *sheet_view, int col, int row, gpointer user_data)
{
	ItemBar * const item_bar = user_data;
	gboolean const is_vertical = (item_bar->orientation == GTK_ORIENTATION_VERTICAL);
	gtk_signal_emit (GTK_OBJECT (item_bar),
			 item_bar_signals [SELECTION_CHANGED],
			 is_vertical ? row : col, 0);
	return TRUE;
}

528
static gint
529
item_bar_event (GnomeCanvasItem *item, GdkEvent *e)
530
{
Arturo Espinosa's avatar
Arturo Espinosa committed
531
	ColRowInfo *cri;
Jody Goldberg's avatar
Jody Goldberg committed
532 533 534
	GnomeCanvas * const canvas = item->canvas;
	ItemBar * const item_bar = ITEM_BAR (item);
	Sheet   * const sheet = item_bar->sheet_view->sheet;
535 536
	GnumericSheet * const gsheet = GNUMERIC_SHEET (item_bar->sheet_view->sheet_view);
	gboolean const is_vertical = (item_bar->orientation == GTK_ORIENTATION_VERTICAL);
537 538 539 540 541
#if 0
	/*
	 * handle the zoom from the item-grid canvas, the resolution scaling is
	 * handled elsewhere
	 */
542
	double const res  = application_display_dpi_get (is_vertical);
543 544
#endif
	double const zoom = sheet->last_zoom_factor_used; /* * res / 72.; */
Jody Goldberg's avatar
Jody Goldberg committed
545
	int pos, start, element;
546

Jody Goldberg's avatar
Jody Goldberg committed
547 548 549 550
	/* NOTE :
	 * No need to map coordinates since we do the zooming of the item bars manually
	 * there is no transform needed.
	 */
551
	switch (e->type){
552
	case GDK_ENTER_NOTIFY:
553
		if (is_vertical)
Jody Goldberg's avatar
Jody Goldberg committed
554
			pos = e->crossing.y;
555
		else
Jody Goldberg's avatar
Jody Goldberg committed
556
			pos = e->crossing.x;
557
		set_cursor (item_bar, pos);
558
		break;
Morten Welinder's avatar
Morten Welinder committed
559

560
	case GDK_MOTION_NOTIFY:
561
		if (is_vertical)
Jody Goldberg's avatar
Jody Goldberg committed
562
			pos = e->motion.y;
563
		else
Jody Goldberg's avatar
Jody Goldberg committed
564
			pos = e->motion.x;
Arturo Espinosa's avatar
Arturo Espinosa committed
565

566
		/* Do col/row resizing or incremental marking */
567
		if (item_bar->resize_pos != -1) {
568
			GnomeCanvasItem *resize_guide;
Jody Goldberg's avatar
Jody Goldberg committed
569
			GnomeCanvasPoints *points;
Arturo Espinosa's avatar
Arturo Espinosa committed
570 571
			int npos;

Jody Goldberg's avatar
Jody Goldberg committed
572 573
			if (item_bar->resize_guide == NULL) {
				item_bar_start_resize (item_bar);
574 575 576 577 578 579 580
				gnome_canvas_item_grab (item,
							GDK_POINTER_MOTION_MASK |
							GDK_BUTTON_RELEASE_MASK,
							item_bar->change_cursor,
							e->button.time);
			}
			
Arturo Espinosa's avatar
Arturo Espinosa committed
581
			npos = pos - item_bar->resize_start_pos;
582 583
			if (npos <= 0)
				break;
584

585
			item_bar->resize_width = npos;
586

587
			colrow_tip_setlabel (item_bar, is_vertical, item_bar->resize_width);
588
			resize_guide = GNOME_CANVAS_ITEM (item_bar->resize_guide);
Jody Goldberg's avatar
Jody Goldberg committed
589
			points = item_bar->resize_points;
Morten Welinder's avatar
Morten Welinder committed
590

Jody Goldberg's avatar
Jody Goldberg committed
591 592 593 594
			if (is_vertical)
				points->coords [1] = points->coords [3] = pos / zoom;
			else
				points->coords [0] = points->coords [2] = pos / zoom;
Morten Welinder's avatar
Morten Welinder committed
595

596 597 598 599 600
			gnome_canvas_item_set (resize_guide, "points",  points, NULL);

			/* Redraw the ItemBar to show nice incremental progress */
			gnome_canvas_request_redraw (
				canvas, 0, 0, INT_MAX, INT_MAX);
Morten Welinder's avatar
Morten Welinder committed
601

602
		} else if (ITEM_BAR_IS_SELECTING (item_bar)) {
603 604
			int x, y, left, top, width, height, col, row;
			element = get_element_from_pixel (item_bar, pos);
Arturo Espinosa's avatar
Arturo Espinosa committed
605

606 607 608
			gtk_signal_emit (
				GTK_OBJECT (item),
				item_bar_signals [SELECTION_CHANGED],
609
				element, 0);
610

611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640
			gnome_canvas_w2c (canvas, e->motion.x, e->motion.y, &x, &y);
			gnome_canvas_get_scroll_offsets (canvas, &left, &top);

			width = GTK_WIDGET (canvas)->allocation.width;
			height = GTK_WIDGET (canvas)->allocation.height;

			col = gnumeric_sheet_find_col (gsheet, x, NULL);
			row = gnumeric_sheet_find_row (gsheet, y, NULL);

			if (x < left || y < top || x >= left + width || y >= top + height) {
				int dx = 0, dy = 0;

				if (is_vertical) {
					if (y < top)
						dy = y - top;
					else if (y >= top + height)
						dy = y - height - top;
				} else {
					if (x < left)
						dx = x - left;
					else if (x >= left + width)
						dx = x - width - left;
				}

				sheet_view_start_sliding (item_bar->sheet_view,
							  &cb_extend_selection, item_bar,
							  col, row, dx, dy);
			} else
				sheet_view_stop_sliding (item_bar->sheet_view);

Arturo Espinosa's avatar
Arturo Espinosa committed
641
			set_cursor (item_bar, pos);
642
		} else
643
			set_cursor (item_bar, pos);
644
		break;
645 646

	case GDK_BUTTON_PRESS:
647 648 649 650
		/* Ignore scroll wheel events */
		if (e->button.button > 3)
			return FALSE;

651
		if (is_vertical)
Jody Goldberg's avatar
Jody Goldberg committed
652
			pos = e->button.y;
653
		else
Jody Goldberg's avatar
Jody Goldberg committed
654
			pos = e->button.x;
Arturo Espinosa's avatar
Arturo Espinosa committed
655

656
		cri = is_pointer_on_division (item_bar, pos, &start, &element);
657

658
		if (is_vertical) {
659 660 661 662 663 664
			if (element > SHEET_MAX_ROWS-1)
				break;
		} else {
			if (element > SHEET_MAX_COLS-1)
				break;
		}
Morten Welinder's avatar
Morten Welinder committed
665

666 667 668 669 670 671 672 673 674 675
		if (e->button.button == 3) {
			/* If the selection does not contain the current row/col
			 * then clear the selection and add it.
			 */
			if (!selection_contains_colrow (sheet, element, !is_vertical))
				gtk_signal_emit (GTK_OBJECT (item),
						 item_bar_signals [SELECTION_CHANGED],
						 element, e->button.state | GDK_BUTTON1_MASK);

			if (is_vertical)
676
				item_grid_popup_menu (sheet, e, 0, element, FALSE, TRUE);
677
			else
678
				item_grid_popup_menu (sheet, e, element, 0, TRUE, FALSE);
679
		} else if (cri) {
680 681 682 683 684 685 686
			/*
			 * Record the important bits.
			 *
			 * By setting resize_pos to a non -1 value,
			 * we know that we are being resized (used in the
			 * other event handlers).
			 */
687
			item_bar->resize_pos = element;
688 689
			item_bar->resize_start_pos = start - cri->size_pixels;
			item_bar->resize_width = cri->size_pixels;
690 691 692 693 694 695 696

			if (item_bar->tip == NULL) {
				item_bar->tip = gnumeric_create_tooltip ();
				colrow_tip_setlabel (item_bar, is_vertical, item_bar->resize_width);
				gnumeric_position_tooltip (item_bar->tip, !is_vertical);
				gtk_widget_show_all (gtk_widget_get_toplevel (item_bar->tip));
			}
Arturo Espinosa's avatar
Arturo Espinosa committed
697
		} else {
698

699
			item_bar->start_selection = element;
700 701 702 703 704
			gnome_canvas_item_grab (item,
						GDK_POINTER_MOTION_MASK |
						GDK_BUTTON_RELEASE_MASK,
						item_bar->normal_cursor,
						e->button.time);
Arturo Espinosa's avatar
Arturo Espinosa committed
705 706
			gtk_signal_emit (GTK_OBJECT (item),
					 item_bar_signals [SELECTION_CHANGED],
707
					 element, e->button.state | GDK_BUTTON1_MASK);
Arturo Espinosa's avatar
Arturo Espinosa committed
708
		}
709
		break;
Arturo Espinosa's avatar
Arturo Espinosa committed
710

Jody Goldberg's avatar
Jody Goldberg committed
711 712
	case GDK_2BUTTON_PRESS:
	{
713 714 715 716
		/* Ignore scroll wheel events */
		if (e->button.button > 3)
			return FALSE;

717 718
		if (e->button.button == 3)
			break;
719

720
		item_bar_end_resize (item_bar, -1);
721
		break;
Jody Goldberg's avatar
Jody Goldberg committed
722
	}
723
		
Arturo Espinosa's avatar
Arturo Espinosa committed
724
	case GDK_BUTTON_RELEASE:
725 726
	{
		gboolean needs_ungrab = FALSE;
727

728 729 730 731
		/* Ignore scroll wheel events */
		if (e->button.button > 3)
			return FALSE;

732 733
		sheet_view_stop_sliding (item_bar->sheet_view);

Jody Goldberg's avatar
Jody Goldberg committed
734
		if (item_bar->start_selection >= 0) {
735 736 737
			needs_ungrab = TRUE;
			item_bar->start_selection = -1;
		}
738
		if (item_bar->resize_pos >= 0) {
739 740 741 742 743 744 745 746 747
			if (item_bar->resize_guide != NULL) {
				needs_ungrab = TRUE;
				item_bar_end_resize (item_bar, item_bar->resize_width);
			} else
				/*
				 * No need to resize, nothing changed.
				 * This will handle the case of a double click.
				 */
				item_bar_end_resize (item_bar, 0);
748
		}
749 750
		if (needs_ungrab)
			gnome_canvas_item_ungrab (item, e->button.time);
Arturo Espinosa's avatar
Arturo Espinosa committed
751
		break;
752
	}
Morten Welinder's avatar
Morten Welinder committed
753

754 755 756 757 758 759 760 761 762 763 764 765 766
	default:
		return FALSE;
	}
	return TRUE;
}

/*
 * Instance initialization
 */
static void
item_bar_init (ItemBar *item_bar)
{
	GnomeCanvasItem *item = GNOME_CANVAS_ITEM (item_bar);
Morten Welinder's avatar
Morten Welinder committed
767

768 769 770 771
	item->x1 = 0;
	item->y1 = 0;
	item->x2 = 0;
	item->y2 = 0;
Morten Welinder's avatar
Morten Welinder committed
772

773 774
	item_bar->first_element = 0;
	item_bar->orientation = GTK_ORIENTATION_VERTICAL;
Arturo Espinosa's avatar
Arturo Espinosa committed
775
	item_bar->resize_pos = -1;
Arturo Espinosa's avatar
Arturo Espinosa committed
776
	item_bar->start_selection = -1;
777
	item_bar->tip = NULL;
778 779
	item_bar->normal_font = NULL;
	item_bar->bold_font = NULL;
Jody Goldberg's avatar
Jody Goldberg committed
780
	item_bar->resize_guide = NULL;
781
	item_bar->resize_start = NULL;
Jody Goldberg's avatar
Jody Goldberg committed
782
	item_bar->resize_points = NULL;
783 784 785 786 787 788 789 790
}

static void
item_bar_set_arg (GtkObject *o, GtkArg *arg, guint arg_id)
{
	GnomeCanvasItem *item;
	ItemBar *item_bar;
	int v;
Morten Welinder's avatar
Morten Welinder committed
791

792 793
	item = GNOME_CANVAS_ITEM (o);
	item_bar = ITEM_BAR (o);
Morten Welinder's avatar
Morten Welinder committed
794

795
	switch (arg_id){
Arturo Espinosa's avatar
Arturo Espinosa committed
796 797
	case ARG_SHEET_VIEW:
		item_bar->sheet_view = GTK_VALUE_POINTER (*arg);
798 799 800 801 802 803 804 805 806 807 808 809
		break;
	case ARG_ORIENTATION:
		item_bar->orientation = GTK_VALUE_INT (*arg);
		break;
	case ARG_FIRST_ELEMENT:
		v = GTK_VALUE_INT (*arg);
		if (item_bar->first_element != v){
			item_bar->first_element = v;
			g_warning ("ARG_FIRST_ELEMENT: do scroll\n");
		}
		break;
	}
810
	item_bar_update (item, NULL, NULL, 0);
811 812 813 814 815 816 817 818 819 820 821
}

/*
 * ItemBar class initialization
 */
static void
item_bar_class_init (ItemBarClass *item_bar_class)
{
	GtkObjectClass  *object_class;
	GnomeCanvasItemClass *item_class;

822
	item_bar_parent_class = gtk_type_class (gnome_canvas_item_get_type ());
Morten Welinder's avatar
Morten Welinder committed
823

824 825 826
	object_class = (GtkObjectClass *) item_bar_class;
	item_class = (GnomeCanvasItemClass *) item_bar_class;

Morten Welinder's avatar
Morten Welinder committed
827
	gtk_object_add_arg_type ("ItemBar::SheetView", GTK_TYPE_POINTER,
Arturo Espinosa's avatar
Arturo Espinosa committed
828
				 GTK_ARG_WRITABLE, ARG_SHEET_VIEW);
Morten Welinder's avatar
Morten Welinder committed
829
	gtk_object_add_arg_type ("ItemBar::Orientation", GTK_TYPE_INT,
830
				 GTK_ARG_WRITABLE, ARG_ORIENTATION);
Arturo Espinosa's avatar
Arturo Espinosa committed
831 832 833 834 835 836

	item_bar_signals [SELECTION_CHANGED] =
		gtk_signal_new ("selection_changed",
				GTK_RUN_LAST,
				object_class->type,
				GTK_SIGNAL_OFFSET (ItemBarClass, selection_changed),
Arturo Espinosa's avatar
Arturo Espinosa committed
837
				item_bar_marshal,
Arturo Espinosa's avatar
Arturo Espinosa committed
838
				GTK_TYPE_NONE,
Arturo Espinosa's avatar
Arturo Espinosa committed
839 840
				2,
				GTK_TYPE_INT, GTK_TYPE_INT);
Arturo Espinosa's avatar
Arturo Espinosa committed
841 842 843 844 845
	item_bar_signals [SIZE_CHANGED] =
		gtk_signal_new ("size_changed",
				GTK_RUN_LAST,
				object_class->type,
				GTK_SIGNAL_OFFSET (ItemBarClass, size_changed),
Arturo Espinosa's avatar
Arturo Espinosa committed
846
				item_bar_marshal,
Arturo Espinosa's avatar
Arturo Espinosa committed
847 848 849 850 851 852 853 854
				GTK_TYPE_NONE,
				2,
				GTK_TYPE_INT,
				GTK_TYPE_INT);

	/* Register our signals */
	gtk_object_class_add_signals (object_class, item_bar_signals,
				      LAST_SIGNAL);
Morten Welinder's avatar
Morten Welinder committed
855

Arturo Espinosa's avatar
Arturo Espinosa committed
856
	/* Method overrides */
857
	object_class->destroy = item_bar_destroy;
858 859 860
	object_class->set_arg = item_bar_set_arg;

	/* GnomeCanvasItem method overrides */
861
	item_class->update      = item_bar_update;
862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891
	item_class->realize     = item_bar_realize;
	item_class->unrealize   = item_bar_unrealize;
	item_class->draw        = item_bar_draw;
	item_class->point       = item_bar_point;
	item_class->translate   = item_bar_translate;
	item_class->event       = item_bar_event;
}

GtkType
item_bar_get_type (void)
{
	static GtkType item_bar_type = 0;

	if (!item_bar_type) {
		GtkTypeInfo item_bar_info = {
			"ItemBar",
			sizeof (ItemBar),
			sizeof (ItemBarClass),
			(GtkClassInitFunc) item_bar_class_init,
			(GtkObjectInitFunc) item_bar_init,
			NULL, /* reserved_1 */
			NULL, /* reserved_2 */
			(GtkClassInitFunc) NULL
		};

		item_bar_type = gtk_type_unique (gnome_canvas_item_get_type (), &item_bar_info);
	}

	return item_bar_type;
}
Arturo Espinosa's avatar
Arturo Espinosa committed
892 893 894 895 896 897


/*
 * Marshaling routines for our signals
 */
static void
Arturo Espinosa's avatar
Arturo Espinosa committed
898 899 900 901
item_bar_marshal (GtkObject     *object,
		  GtkSignalFunc func,
		  gpointer      func_data,
		  GtkArg        *args)
Arturo Espinosa's avatar
Arturo Espinosa committed
902 903
{
	ItemBarSignal2 rfunc;
Morten Welinder's avatar
Morten Welinder committed
904

Arturo Espinosa's avatar
Arturo Espinosa committed
905 906 907 908 909 910 911
	rfunc = (ItemBarSignal2) func;
	(*rfunc) (object,
		  GTK_VALUE_INT (args [0]),
		  GTK_VALUE_INT (args [1]),
		  func_data);
}