item-cursor.c 20.2 KB
Newer Older
1
2
3
4
5
6
/*
 * The Cursor Canvas Item: Implements a rectangular cursor
 *
 * Author:
 *     Miguel de Icaza (miguel@kernel.org)
 */
7
8
9
10
11
12
13
#include <config.h>

#include <gnome.h>
#include "gnumeric.h"
#include "item-grid.h"
#include "item-cursor.h"
#include "item-debug.h"
14
#include "gnumeric-sheet.h"
15
#include "gnumeric-util.h"
16
#include "color.h"
Arturo Espinosa's avatar
Arturo Espinosa committed
17
#include "cursors.h"
Arturo Espinosa's avatar
Arturo Espinosa committed
18
#include "sheet-autofill.h"
19
20
21

static GnomeCanvasItem *item_cursor_parent_class;

22
23
static void item_cursor_request_redraw (ItemCursor *item_cursor);

Arturo Espinosa's avatar
Arturo Espinosa committed
24
25
#define IS_LITTLE_SQUARE(item,x,y) ((x) > (item)->x2 - 6) && ((y) > (item)->y2 - 6)

26
27
28
29
/* The argument we take */
enum {
	ARG_0,
	ARG_SHEET,		/* The Sheet * argument */
30
	ARG_ITEM_GRID,		/* The ItemGrid * argument */
31
	ARG_STYLE,              /* The style type */
32
33
};

34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
static void
item_cursor_animation_callback (ItemCursor *item_cursor)
{
	item_cursor->state = !item_cursor->state;
	item_cursor_request_redraw (item_cursor);
}

static void
item_cursor_stop_animation (ItemCursor *item_cursor)
{
	if (item_cursor->tag == -1)
		return;
	
	gtk_timeout_remove (item_cursor->tag);
	item_cursor->tag = -1;
}

static void
item_cursor_start_animation (ItemCursor *item_cursor)
{
	item_cursor->tag = gtk_timeout_add (
		300, (GtkFunction)(item_cursor_animation_callback),
		item_cursor);
}

59
60
61
62
63
64
65
static void
item_cursor_destroy (GtkObject *object)
{
	ItemCursor *item_cursor;

	item_cursor = ITEM_CURSOR (object);

66
	item_cursor_stop_animation (item_cursor);
67
68
69
70
71
72
73
74
75
76
	if (GTK_OBJECT_CLASS (item_cursor_parent_class)->destroy)
		(*GTK_OBJECT_CLASS (item_cursor_parent_class)->destroy)(object);
}

static void
item_cursor_realize (GnomeCanvasItem *item)
{
	ItemCursor *item_cursor;
	GdkWindow  *window;
	
Arturo Espinosa's avatar
Arturo Espinosa committed
77
78
79
	if (GNOME_CANVAS_ITEM_CLASS (item_cursor_parent_class)->realize)
		(*GNOME_CANVAS_ITEM_CLASS (item_cursor_parent_class)->realize)(item);
	
80
81
82
	item_cursor = ITEM_CURSOR (item);
	window = GTK_WIDGET (item->canvas)->window;

83
	item_cursor->gc = gdk_gc_new (window);
84

85
86
	if (item_cursor->style == ITEM_CURSOR_ANTED)
		item_cursor_start_animation (item_cursor);
87
88
89
90
91
92
93
94
95
96

	/*
	 * Create the stipple pattern for the drag and the autofill cursors
	 */
	if (item_cursor->style == ITEM_CURSOR_DRAG || item_cursor->style == ITEM_CURSOR_AUTOFILL){
		static char stipple_data [] = { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa };
		
		item_cursor->stipple =
			gdk_bitmap_create_from_data (window, stipple_data, 8, 8);
	}
97
98
}

99
100
101
/*
 * Release all of the resources we allocated
 */
102
103
104
105
106
107
108
static void
item_cursor_unrealize (GnomeCanvasItem *item)
{
	ItemCursor *item_cursor = ITEM_CURSOR (item);

	gdk_gc_unref (item_cursor->gc);
	item_cursor->gc = 0;
109
110
111
112
113

	if (item_cursor->stipple){
		gdk_pixmap_unref (item_cursor->stipple);
		item_cursor->stipple = NULL;
	}
Arturo Espinosa's avatar
Arturo Espinosa committed
114
115
116
	
	if (GNOME_CANVAS_ITEM_CLASS (item_cursor_parent_class)->unrealize)
		(*GNOME_CANVAS_ITEM_CLASS (item_cursor_parent_class)->unrealize)(item);
117
118
119
120
121
122
123
}

static void
item_cursor_reconfigure (GnomeCanvasItem *item)
{
}

124
125
126
/*
 * Returns the bounding box cordinates for box delimited by the cursor
 */
127
128
129
130
131
132
133
134
135
static void
item_cursor_get_pixel_coords (ItemCursor *item_cursor, int *x, int *y, int *w, int *h)
{
	ItemGrid *item_grid = item_cursor->item_grid;
	Sheet *sheet = item_cursor->sheet;

	*x = sheet_col_get_distance (sheet, item_grid->left_col, item_cursor->start_col);
	*y = sheet_row_get_distance (sheet, item_grid->top_row, item_cursor->start_row);

136
137
	*w = sheet_col_get_distance (sheet, item_cursor->start_col, item_cursor->end_col+1);
	*h = sheet_row_get_distance (sheet, item_cursor->start_row, item_cursor->end_row+1);
138
139
}

140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
static void
item_cursor_configure_bounds (ItemCursor *item_cursor)
{
	GnomeCanvasItem *item = GNOME_CANVAS_ITEM (item_cursor);
	int x, y, w, h, extra;

	item_cursor_get_pixel_coords (item_cursor, &x, &y, &w, &h);

	item_cursor->cached_x = x;
	item_cursor->cached_y = y;
	item_cursor->cached_w = w;
	item_cursor->cached_h = h;
	
	item->x1 = x - 1;
	item->y1 = y - 1;

	if (item_cursor->style == ITEM_CURSOR_SELECTION)
		extra = 1;
	else
		extra = 0;
160
161
	item->x2 = x + w + 2 + extra;
	item->y2 = y + h + 2 + extra;
162
163
164
165

	gnome_canvas_group_child_bounds (GNOME_CANVAS_GROUP (item->parent), item);
}

166
167
168
169
170
static void
item_cursor_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int height)
{
	ItemCursor *item_cursor = ITEM_CURSOR (item);
	int xd, yd, dx, dy;
171
	int cursor_width, cursor_height, w, h;
172
	GdkPoint points [40];
Arturo Espinosa's avatar
Arturo Espinosa committed
173
	int draw_external, draw_internal, draw_handle, draw_center, draw_thick;
174
	int premove;
175
	GdkColor *fore = NULL, *back = NULL;
176
177
178
179
	
	item_cursor_get_pixel_coords (item_cursor, &xd, &yd,
				      &cursor_width, &cursor_height);

180
181
182
183
184
185
186
187
188
189
190
	w = cursor_width;
	h = cursor_height;
	
	/* determine if we need to recompute the bounding box */
	if (xd != item_cursor->cached_x ||
	    yd != item_cursor->cached_y ||
	    w  != item_cursor->cached_w ||
	    h  != item_cursor->cached_h){
		item_cursor_configure_bounds (item_cursor);
	}
	
191
192
193
	dx = xd - x;
	dy = yd - y;

Arturo Espinosa's avatar
Arturo Espinosa committed
194
195
196
197
198
199
	draw_external = 0;
	draw_internal = 0;
	draw_handle   = 0;
	draw_center   = 0;
	draw_thick    = 0;
	
200
	switch (item_cursor->style){
Arturo Espinosa's avatar
Arturo Espinosa committed
201
202
203
204
205
206
207
208
	case ITEM_CURSOR_AUTOFILL:
	case ITEM_CURSOR_DRAG:
		draw_center   = 1;
		draw_thick    = 1;
		fore          = &gs_black;
		back          = &gs_white;
		break;
		
209
	case ITEM_CURSOR_SELECTION:
210
211
212
213
214
215
216
217
218
219
		draw_internal = 1;
		draw_external = 1;
		draw_handle   = 1;
		break;

	case ITEM_CURSOR_EDITING:
		draw_external = 1;

	case ITEM_CURSOR_ANTED:
		draw_center   = 1;
220
221
222
223
224
225
226
		if (item_cursor->state){
			fore = &gs_light_gray;
			back = &gs_dark_gray;
		} else {
			fore = &gs_dark_gray;
			back = &gs_light_gray;
		}
227
228
229
	};

	if (draw_handle)
230
		premove = 5;
231
	else
232
		premove = 0;
233

234
235
	gdk_gc_set_line_attributes (item_cursor->gc, 1,
				    GDK_LINE_SOLID, -1, -1);
236
237
	gdk_gc_set_foreground (item_cursor->gc, &gs_black);
	gdk_gc_set_background (item_cursor->gc, &gs_white);
238
239
	if (draw_external){
		points [0].x = dx + cursor_width + 1;
240
		points [0].y = dy + cursor_height + 1 - premove;
241
		points [1].x = points [0].x;
242
243
244
245
246
		points [1].y = dy - 1;
		points [2].x = dx - 1;
		points [2].y = dy - 1;
		points [3].x = dx - 1;
		points [3].y = dy + cursor_height + 1;
247
		points [4].x = dx + cursor_width + 1 - premove;
248
249
		points [4].y = points [3].y;
		gdk_draw_lines (drawable, item_cursor->gc, points, 5);
250
251
252
253
254
255
256
257
258
259
260
261
262
	}

	if (draw_external && draw_internal){
		points [0].x -= 2;
		points [1].x -= 2;
		points [1].y += 2;
		points [2].x += 2;
		points [2].y += 2;
		points [3].x += 2;
		points [3].y -= 2;
		points [4].y -= 2;
		gdk_draw_lines (drawable, item_cursor->gc, points, 5);
	}
263

264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
	if (draw_handle){
		gdk_draw_rectangle (drawable, item_cursor->gc, TRUE,
				    dx + cursor_width - 2,
				    dy + cursor_height - 2,
				    2, 2);
		gdk_draw_rectangle (drawable, item_cursor->gc, TRUE,
				    dx + cursor_width + 1,
				    dy + cursor_height - 2,
				    2, 2);
		gdk_draw_rectangle (drawable, item_cursor->gc, TRUE,
				    dx + cursor_width - 2,
				    dy + cursor_height + 1,
				    2, 2);
		gdk_draw_rectangle (drawable, item_cursor->gc, TRUE,
				    dx + cursor_width + 1,
				    dy + cursor_height + 1,
				    2, 2);
281
	}
282
283

	if (draw_center){
284
285
		gdk_gc_set_foreground (item_cursor->gc, fore);
		gdk_gc_set_background (item_cursor->gc, back);
286
287
288
289
290
291
292
293
294
295
296

		if (draw_thick){
			gdk_gc_set_fill (item_cursor->gc, GDK_STIPPLED);
			gdk_gc_set_stipple (item_cursor->gc, item_cursor->stipple);
			gdk_gc_set_line_attributes (item_cursor->gc, 3,
						    GDK_LINE_SOLID, -1, -1);
		} else {
			gdk_gc_set_line_attributes (item_cursor->gc, 1,
						    GDK_LINE_DOUBLE_DASH, -1, -1);
		}

297
298
		gdk_draw_rectangle (drawable, item_cursor->gc, FALSE,
				    dx, dy,
299
				    cursor_width, cursor_height);
300
	}
301
302
303
304
305
306
307
308
309
}

static void
item_cursor_request_redraw (ItemCursor *item_cursor)
{
	GnomeCanvas *canvas = GNOME_CANVAS_ITEM (item_cursor)->canvas;
	int x, y, w, h;

	item_cursor_get_pixel_coords (item_cursor, &x, &y, &w, &h);
310
	gnome_canvas_request_redraw (canvas, x - 2, y - 2, x + w + 5, y + h + 5);
311
312
313
}

void
314
item_cursor_set_bounds (ItemCursor *item_cursor, int start_col, int start_row, int end_col, int end_row)
315
{
316
317
	GnomeCanvasItem *item;
	
318
319
	g_return_if_fail (start_col <= end_col);
	g_return_if_fail (start_row <= end_row);
320
321
322
323
	g_return_if_fail (item_cursor != NULL);
	g_return_if_fail (IS_ITEM_CURSOR (item_cursor));

	item = GNOME_CANVAS_ITEM (item_cursor);
324
325
	item_cursor_request_redraw (item_cursor);

326
327
328
329
	item_cursor->start_col = start_col;
	item_cursor->end_col   = end_col;
	item_cursor->start_row = start_row;
	item_cursor->end_row   = end_row;
330
331

	item_cursor_request_redraw (item_cursor);
332

333
	item_cursor_configure_bounds (item_cursor);
334
335
336
337
338
339
}

static double
item_cursor_point (GnomeCanvasItem *item, double x, double y, int cx, int cy,
		   GnomeCanvasItem **actual_item)
{
Arturo Espinosa's avatar
Arturo Espinosa committed
340
341
	*actual_item = NULL;

342
	if (cx < item->x1-3)
Arturo Espinosa's avatar
Arturo Espinosa committed
343
		return INT_MAX;
344
	if (cx > item->x2+3)
Arturo Espinosa's avatar
Arturo Espinosa committed
345
		return INT_MAX;
346
	if (cy < item->y1-3)
Arturo Espinosa's avatar
Arturo Espinosa committed
347
		return INT_MAX;
348
	if (cy > item->y2+3)
Arturo Espinosa's avatar
Arturo Espinosa committed
349
350
351
352
353
		return INT_MAX;

	/* FIXME: this needs to handle better the small little square case
	 * for ITEM_CURSOR_SELECTION style
	 */
354
355
356
357
	if ((cx < (item->x1 + 4)) ||
	    (cx > (item->x2 - 8)) ||
	    (cy < (item->y1 + 4)) ||
	    (cy > (item->y2 - 8))){
Arturo Espinosa's avatar
Arturo Espinosa committed
358
359
360
		*actual_item = item;
		return 0.0;
	}
Arturo Espinosa's avatar
Arturo Espinosa committed
361
	return INT_MAX;
362
363
364
365
366
367
368
369
}

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

370
371
372
373
374
375
376
377
378
379
380
381

static void
item_cursor_setup_auto_fill (ItemCursor *item_cursor, ItemCursor *parent, int x, int y)
{
	item_cursor->base_x = x;
	item_cursor->base_y = y;
	
	item_cursor->base_cols = parent->end_col - parent->start_col;
	item_cursor->base_rows = parent->end_row - parent->start_row;
	item_cursor->base_col = parent->start_col;
	item_cursor->base_row = parent->start_row;
}
Arturo Espinosa's avatar
Arturo Espinosa committed
382

Arturo Espinosa's avatar
Arturo Espinosa committed
383
static void
Arturo Espinosa's avatar
Arturo Espinosa committed
384
item_cursor_set_cursor (GnomeCanvas *canvas, GnomeCanvasItem *item, int x, int y)
Arturo Espinosa's avatar
Arturo Espinosa committed
385
386
387
388
389
390
391
{
	int cursor;
	
	if (IS_LITTLE_SQUARE (item, x, y))
		cursor = GNUMERIC_CURSOR_THIN_CROSS;
	else
		cursor = GNUMERIC_CURSOR_ARROW;
Arturo Espinosa's avatar
Arturo Espinosa committed
392
393

	cursor_set_widget (canvas, cursor);
Arturo Espinosa's avatar
Arturo Espinosa committed
394
395
}

Arturo Espinosa's avatar
Arturo Espinosa committed
396
397
398
399
400
401
402
403
404
static gint
item_cursor_selection_event (GnomeCanvasItem *item, GdkEvent *event)
{
	GnomeCanvas *canvas = item->canvas;
	GnomeCanvasItem *new_item;
	ItemCursor *item_cursor = ITEM_CURSOR (item);
	int x, y;

	switch (event->type){
Arturo Espinosa's avatar
Arturo Espinosa committed
405
406
407
408
	case GDK_ENTER_NOTIFY:
		gnome_canvas_w2c (
			canvas, event->crossing.x, event->crossing.y, &x, &y);

Arturo Espinosa's avatar
Arturo Espinosa committed
409
		item_cursor_set_cursor (canvas, item, x, y);
Arturo Espinosa's avatar
Arturo Espinosa committed
410
411
412
413
414
415
		return TRUE;
		
	case GDK_MOTION_NOTIFY:
		gnome_canvas_w2c (
			canvas, event->motion.x, event->motion.y, &x, &y);

Arturo Espinosa's avatar
Arturo Espinosa committed
416
		item_cursor_set_cursor (canvas, item, x, y);
Arturo Espinosa's avatar
Arturo Espinosa committed
417
418
		return TRUE;
		
Arturo Espinosa's avatar
Arturo Espinosa committed
419
420
421
422
	case GDK_BUTTON_PRESS: {
		GnomeCanvasGroup *group;
		int style;

423
424
		gnome_canvas_w2c (
			canvas, event->button.x, event->button.y, &x, &y);
Arturo Espinosa's avatar
Arturo Espinosa committed
425
426
		
		group = GNOME_CANVAS_GROUP (canvas->root);
427
428
429
430

		/* determine which part of the cursor was clicked:
		 * the border or the handlebox
		 */
Arturo Espinosa's avatar
Arturo Espinosa committed
431
		if (IS_LITTLE_SQUARE (item, x, y))
Arturo Espinosa's avatar
Arturo Espinosa committed
432
433
434
435
436
437
438
439
440
441
442
			style = ITEM_CURSOR_AUTOFILL;
		else
			style = ITEM_CURSOR_DRAG;
		
		new_item = gnome_canvas_item_new (
			group,
			item_cursor_get_type (),
			"ItemCursor::Sheet", item_cursor->sheet,
			"ItemCursor::Grid",  item_cursor->item_grid,
			"ItemCursor::Style", style,
			NULL);
443
444
445
446
447

		if (style == ITEM_CURSOR_AUTOFILL)
			item_cursor_setup_auto_fill (
				ITEM_CURSOR (new_item), item_cursor, x, y);
		
Arturo Espinosa's avatar
Arturo Espinosa committed
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
		item_cursor_set_bounds (
			ITEM_CURSOR (new_item),
			item_cursor->start_col, item_cursor->start_row,
			item_cursor->end_col,   item_cursor->end_row);
		
		gnome_canvas_update_now (canvas);
		gnome_canvas_item_grab (
			new_item,
			GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
			NULL,
			event->button.time);
		
		return TRUE;
	}
	default:
		return FALSE;
	}
	
}

468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
static gboolean
item_cursor_target_region_ok (ItemCursor *item_cursor)
{
	/* FIXME: check the destination range and if any cell
	 * has values, ask for confirmation
	 */
	return TRUE;
}

typedef enum {
	ACTION_NONE = -1,
	ACTION_COPY_CELLS,
	ACTION_MOVE_CELLS,
	ACTION_COPY_FORMATS,
	ACTION_COPY_VALUES,
	ACTION_SHIFT_DOWN_AND_COPY,
	ACTION_SHIFT_RIGHT_AND_COPY,
	ACTION_SHIFT_DOWN_AND_MOVE,
	ACTION_SHIFT_RIGHT_AND_MOVE
} ActionType;

static void
item_cursor_do_action (ItemCursor *item_cursor, ActionType action)
{
	Sheet *sheet = item_cursor->sheet;
	int   col = item_cursor->start_col;
	int   row = item_cursor->start_row;
	
	switch (action){
	case ACTION_NONE:
		return;
		
	case ACTION_COPY_CELLS:
		if (!item_cursor_target_region_ok (item_cursor))
			return;
		if (!sheet_selection_copy (sheet))
			return;
		sheet_selection_paste (sheet, col, row, PASTE_ALL_TYPES);
		return;
		
	case ACTION_MOVE_CELLS:
		if (!item_cursor_target_region_ok (item_cursor))
			return;
		if (!sheet_selection_cut (sheet))
			return;
		sheet_selection_paste (sheet, col, row, PASTE_ALL_TYPES);
		return;
		
	case ACTION_COPY_FORMATS:
		if (!item_cursor_target_region_ok (item_cursor))
			return;
		if (!sheet_selection_copy (sheet))
			return;
		sheet_selection_paste (sheet, col, row, PASTE_FORMATS);
		return;
		
	case ACTION_COPY_VALUES:
		if (!item_cursor_target_region_ok (item_cursor))
			return;
		if (!sheet_selection_copy (sheet))
			return;
		sheet_selection_paste (sheet, col, row, PASTE_VALUES);
		return;
		
	case ACTION_SHIFT_DOWN_AND_COPY:
	case ACTION_SHIFT_RIGHT_AND_COPY:
	case ACTION_SHIFT_DOWN_AND_MOVE:
	case ACTION_SHIFT_RIGHT_AND_MOVE:
		g_warning ("Operation not yet implemeneted\n");
	}
}

static char *drop_context_actions [] = {
	N_("Copy"),
	N_("Move"),
	N_("Copy formats"),
	N_("Copy values"),
	N_("Shift cells down and copy"),
	N_("Shift cells right and copy"),
	N_("Shift cells down and move"),
	N_("Shift cells right and move"),
	NULL,
};

552
553
554
/*
 * Invoked when the item has been dropped
 */
Arturo Espinosa's avatar
Arturo Espinosa committed
555
static void
556
item_cursor_do_drop (ItemCursor *item_cursor, GdkEvent *event)
Arturo Espinosa's avatar
Arturo Espinosa committed
557
{
558
559
560
561
	ActionType action;

	/* Find out what to do */
	if (event->button.button == 3)
562
		action = (ActionType) run_popup_menu (event, 1, drop_context_actions);
563
564
565
566
567
568
	else if (event->button.state & GDK_CONTROL_MASK)
		action = ACTION_COPY_CELLS;
	else
		action = ACTION_MOVE_CELLS;

	item_cursor_do_action (item_cursor, action);
Arturo Espinosa's avatar
Arturo Espinosa committed
569
570
}

571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
static void
item_cursor_set_bounds_visibly (ItemCursor *item_cursor,
				int start_col, int start_row,
				int end_col,   int end_row)
{
	GnomeCanvasItem *item = GNOME_CANVAS_ITEM (item_cursor);
	GnumericSheet   *gsheet = GNUMERIC_SHEET (item->canvas);
	int watch_col, watch_row;
	
	item_cursor_set_bounds (item_cursor, start_col, start_row, end_col, end_row);

	/* Now, make the range visible as well as we can guess */
	if (start_col < item_cursor->start_col)
		watch_col = start_col;
	else 
		watch_col = end_col;
	
	if (start_row < item_cursor->start_row)
		watch_row = start_row;
	else 
		watch_row = end_row;

	gnumeric_sheet_make_cell_visible (gsheet, watch_col, watch_row);
Miguel de Icaza's avatar
Today:    
Miguel de Icaza committed
594
	gnome_canvas_update_now (GNOME_CANVAS (gsheet));
595
596
}

Arturo Espinosa's avatar
Arturo Espinosa committed
597
598
599
static gint
item_cursor_drag_event (GnomeCanvasItem *item, GdkEvent *event)
{
600
	GnomeCanvas *canvas = GNOME_CANVAS_ITEM (item)->canvas;
Arturo Espinosa's avatar
Arturo Espinosa committed
601
	ItemCursor *item_cursor = ITEM_CURSOR (item);
602
603
604
	int x, y, w, h;
	int col, row;
		
Arturo Espinosa's avatar
Arturo Espinosa committed
605
606
607
	switch (event->type){
	case GDK_BUTTON_RELEASE:
		gnome_canvas_item_ungrab (item, event->button.time);
608
		item_cursor_do_drop (item_cursor, event);
Arturo Espinosa's avatar
Arturo Espinosa committed
609
610
611
612
		gtk_object_destroy (GTK_OBJECT (item));
		return TRUE;

	case GDK_BUTTON_PRESS:
613
614
615
		/* We actually never get this event: this kind of
		 * cursor is created and grabbed
		 */
Arturo Espinosa's avatar
Arturo Espinosa committed
616
617
618
		return TRUE;

	case GDK_MOTION_NOTIFY:
619
		gnome_canvas_w2c (canvas, event->button.x, event->button.y, &x, &y);
620
621
622
623
		if (x < 0)
			x = 0;
		if (y < 0)
			y = 0;
624
625
626
627
628
629
630
		col = item_grid_find_col (item_cursor->item_grid, x, NULL);
		row = item_grid_find_row (item_cursor->item_grid, y, NULL);
		
		w   = (item_cursor->end_col - item_cursor->start_col);
		h   = (item_cursor->end_row - item_cursor->start_row);

		item_cursor_set_bounds_visibly (item_cursor, col, row, col + w, row + h);
Arturo Espinosa's avatar
Arturo Espinosa committed
631
632
633
634
635
636
637
		return TRUE;

	default:
		return FALSE;
	}
}

638
static gint
639
item_cursor_autofill_event (GnomeCanvasItem *item, GdkEvent *event)
640
{
641
642
643
644
	GnomeCanvas *canvas = item->canvas;
	ItemCursor *item_cursor = ITEM_CURSOR (item);
	int col, row, x, y;
	
645
	switch (event->type){
646
647
	case GDK_BUTTON_RELEASE: {
		Sheet *sheet = item_cursor->sheet;
Arturo Espinosa's avatar
Arturo Espinosa committed
648

649
		gnome_canvas_item_ungrab (item, event->button.time);
Arturo Espinosa's avatar
Arturo Espinosa committed
650

651
#if DEBUG_AUTOFILL
Arturo Espinosa's avatar
Arturo Espinosa committed
652
653
654
655
		g_warning ("Temporary flush after ungrap here\n");

		gnome_canvas_update_now (canvas);
		gdk_flush ();
656
#endif
Arturo Espinosa's avatar
Arturo Espinosa committed
657
		
Arturo Espinosa's avatar
Arturo Espinosa committed
658
		if (!((item_cursor->end_col == item_cursor->base_col + item_cursor->base_cols) &&
659
660
		      (item_cursor->end_row == item_cursor->base_row + item_cursor->base_rows))){

661
			sheet_accept_pending_input (sheet);
Arturo Espinosa's avatar
Arturo Espinosa committed
662
663
664
665
			sheet_autofill (sheet, 
					item_cursor->base_col,    item_cursor->base_row,
					item_cursor->base_cols+1, item_cursor->base_rows+1,
					item_cursor->end_col,     item_cursor->end_row);
666
		}
Arturo Espinosa's avatar
Arturo Espinosa committed
667
668
669
670
671
672
673
		sheet_cursor_set (sheet,
				  item_cursor->base_col, item_cursor->base_row,
				  item_cursor->end_col,  item_cursor->end_row);
		sheet_selection_reset_only (sheet);
		sheet_selection_append (sheet, item_cursor->base_col, item_cursor->base_row);
		sheet_selection_extend_to (sheet, item_cursor->end_col, item_cursor->end_row);
		
674
		gtk_object_destroy (GTK_OBJECT (item));
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
		
		return TRUE;
	}

	case GDK_MOTION_NOTIFY:
		gnome_canvas_w2c (canvas, event->button.x, event->button.y, &x, &y);
		col = item_grid_find_col (item_cursor->item_grid, x, NULL);
		row = item_grid_find_row (item_cursor->item_grid, y, NULL);


		if ((item_cursor->base_x - x) > (item_cursor->base_y - y)){
			item_cursor_set_bounds_visibly (
				item_cursor,
				item_cursor->base_col,
				item_cursor->base_row,
				item_cursor->base_col + item_cursor->base_cols,
				row);
		} else {
			item_cursor_set_bounds_visibly (
				item_cursor,
				item_cursor->base_col,
				item_cursor->base_row,
				col,
				item_cursor->base_row + item_cursor->base_rows);
		}
700
701
702
703
704
705
706
		return TRUE;

	default:
		return FALSE;
	}	
}

707
708
709
static gint
item_cursor_event (GnomeCanvasItem *item, GdkEvent *event)
{
Arturo Espinosa's avatar
Arturo Espinosa committed
710
711
712
713
714
715
716
717
718
719
	ItemCursor *item_cursor = ITEM_CURSOR (item);
	
	switch (item_cursor->style){
	case ITEM_CURSOR_SELECTION:
		return item_cursor_selection_event (item, event);
		
	case ITEM_CURSOR_DRAG:
		return item_cursor_drag_event (item, event);
		
	case ITEM_CURSOR_AUTOFILL:
720
		return item_cursor_autofill_event (item, event);
Arturo Espinosa's avatar
Arturo Espinosa committed
721
722
723
724
		
	default:
		return FALSE;
	}
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
}

/*
 * Instance initialization
 */
static void
item_cursor_init (ItemCursor *item_cursor)
{
	GnomeCanvasItem *item = GNOME_CANVAS_ITEM (item_cursor);

	item->x1 = 0;
	item->y1 = 0;
	item->x2 = 1;
	item->y2 = 1;

	item_cursor->start_col = 0;
741
	item_cursor->end_col   = 0;
742
	item_cursor->start_row = 0;
743
	item_cursor->end_row   = 0;
744
	item_cursor->start_row = ITEM_CURSOR_SELECTION;
745
	item_cursor->tag = -1;
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
}

static void
item_cursor_set_arg (GtkObject *o, GtkArg *arg, guint arg_id)
{
	GnomeCanvasItem *item;
	ItemCursor *item_cursor;

	item = GNOME_CANVAS_ITEM (o);
	item_cursor = ITEM_CURSOR (o);

	switch (arg_id){
	case ARG_SHEET:
		item_cursor->sheet = GTK_VALUE_POINTER (*arg);
		break;
	case ARG_ITEM_GRID:
		item_cursor->item_grid = GTK_VALUE_POINTER (*arg);
		break;
764
765
766
	case ARG_STYLE:
		item_cursor->style = GTK_VALUE_INT (*arg);
		break;
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
	}
}

/*
 * ItemCursor class initialization
 */
static void
item_cursor_class_init (ItemCursorClass *item_cursor_class)
{
	GtkObjectClass  *object_class;
	GnomeCanvasItemClass *item_class;

	item_cursor_parent_class = gtk_type_class (gnome_canvas_item_get_type());
	
	object_class = (GtkObjectClass *) item_cursor_class;
	item_class = (GnomeCanvasItemClass *) item_cursor_class;

	gtk_object_add_arg_type ("ItemCursor::Sheet", GTK_TYPE_POINTER,
				 GTK_ARG_WRITABLE, ARG_SHEET);
	gtk_object_add_arg_type ("ItemCursor::Grid", GTK_TYPE_POINTER,
				 GTK_ARG_WRITABLE, ARG_ITEM_GRID);
788
789
	gtk_object_add_arg_type ("ItemCursor::Style", GTK_TYPE_INT,
				 GTK_ARG_WRITABLE, ARG_STYLE);
790

791
	object_class->set_arg = item_cursor_set_arg;
792
	object_class->destroy = item_cursor_destroy;
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825

	/* GnomeCanvasItem method overrides */
	item_class->realize     = item_cursor_realize;
	item_class->unrealize   = item_cursor_unrealize;
	item_class->reconfigure = item_cursor_reconfigure;
	item_class->draw        = item_cursor_draw;
	item_class->point       = item_cursor_point;
	item_class->translate   = item_cursor_translate;
	item_class->event       = item_cursor_event;
}

GtkType
item_cursor_get_type (void)
{
	static GtkType item_cursor_type = 0;

	if (!item_cursor_type) {
		GtkTypeInfo item_cursor_info = {
			"ItemCursor",
			sizeof (ItemCursor),
			sizeof (ItemCursorClass),
			(GtkClassInitFunc) item_cursor_class_init,
			(GtkObjectInitFunc) item_cursor_init,
			NULL, /* reserved_1 */
			NULL, /* reserved_2 */
			(GtkClassInitFunc) NULL
		};

		item_cursor_type = gtk_type_unique (gnome_canvas_item_get_type (), &item_cursor_info);
	}

	return item_cursor_type;
}