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

#include <gnome.h>
#include "gnumeric.h"
#include "item-grid.h"
#include "item-cursor.h"
#include "item-debug.h"
16
#include "gnumeric-sheet.h"
17
18
19

static GnomeCanvasItem *item_cursor_parent_class;

20
21
static void item_cursor_request_redraw (ItemCursor *item_cursor);

22
23
24
25
/* The argument we take */
enum {
	ARG_0,
	ARG_SHEET,		/* The Sheet * argument */
26
27
	ARG_ITEM_GRID,		/* The ItemGrid * argument */
	ARG_STYLE               /* The style type */
28
29
};

30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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);
}

55
56
57
58
59
60
61
static void
item_cursor_destroy (GtkObject *object)
{
	ItemCursor *item_cursor;

	item_cursor = ITEM_CURSOR (object);

62
	item_cursor_stop_animation (item_cursor);
63
64
65
66
67
68
69
70
71
72
73
	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;
	GdkGC      *gc;
	
Arturo Espinosa's avatar
Arturo Espinosa committed
74
75
76
	if (GNOME_CANVAS_ITEM_CLASS (item_cursor_parent_class)->realize)
		(*GNOME_CANVAS_ITEM_CLASS (item_cursor_parent_class)->realize)(item);
	
77
78
79
80
	item_cursor = ITEM_CURSOR (item);
	window = GTK_WIDGET (item->canvas)->window;

	gc = item_cursor->gc = gdk_gc_new (window);
81

82
83
84
85
	gnumeric_sheet_color_alloc (item->canvas);

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

static void
item_cursor_unrealize (GnomeCanvasItem *item)
{
	ItemCursor *item_cursor = ITEM_CURSOR (item);

	gdk_gc_unref (item_cursor->gc);
	item_cursor->gc = 0;
Arturo Espinosa's avatar
Arturo Espinosa committed
95
96
97
	
	if (GNOME_CANVAS_ITEM_CLASS (item_cursor_parent_class)->unrealize)
		(*GNOME_CANVAS_ITEM_CLASS (item_cursor_parent_class)->unrealize)(item);
98
99
100
101
102
103
104
}

static void
item_cursor_reconfigure (GnomeCanvasItem *item)
{
}

105
106
107
/*
 * Returns the bounding box cordinates for box delimited by the cursor
 */
108
109
110
111
112
113
114
115
116
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);

117
118
	*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);
119
120
}

121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
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;
	item->x2 = x + w + 1 + extra;
	item->y2 = y + h + 1 + extra;

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

147
148
149
150
151
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;
152
	int cursor_width, cursor_height, w, h;
153
	GdkPoint points [40];
Arturo Espinosa's avatar
Arturo Espinosa committed
154
	int draw_external, draw_internal, draw_handle, draw_center, draw_thick;
155
	int premove;
156
	GdkColor *fore = NULL, *back = NULL;
157
158
159
160
	
	item_cursor_get_pixel_coords (item_cursor, &xd, &yd,
				      &cursor_width, &cursor_height);

161
162
163
164
165
166
167
168
169
170
171
	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);
	}
	
172
173
174
	dx = xd - x;
	dy = yd - y;

Arturo Espinosa's avatar
Arturo Espinosa committed
175
176
177
178
179
180
	draw_external = 0;
	draw_internal = 0;
	draw_handle   = 0;
	draw_center   = 0;
	draw_thick    = 0;
	
181
	switch (item_cursor->style){
Arturo Espinosa's avatar
Arturo Espinosa committed
182
183
184
185
186
187
188
189
	case ITEM_CURSOR_AUTOFILL:
	case ITEM_CURSOR_DRAG:
		draw_center   = 1;
		draw_thick    = 1;
		fore          = &gs_black;
		back          = &gs_white;
		break;
		
190
	case ITEM_CURSOR_SELECTION:
191
192
193
194
195
196
197
198
199
200
		draw_internal = 1;
		draw_external = 1;
		draw_handle   = 1;
		break;

	case ITEM_CURSOR_EDITING:
		draw_external = 1;

	case ITEM_CURSOR_ANTED:
		draw_center   = 1;
201
202
203
204
205
206
207
		if (item_cursor->state){
			fore = &gs_light_gray;
			back = &gs_dark_gray;
		} else {
			fore = &gs_dark_gray;
			back = &gs_light_gray;
		}
208
209
210
	};

	if (draw_handle)
211
		premove = 5;
212
	else
213
		premove = 0;
214

215
216
	gdk_gc_set_line_attributes (item_cursor->gc, 1,
				    GDK_LINE_SOLID, -1, -1);
217
218
	gdk_gc_set_foreground (item_cursor->gc, &gs_black);
	gdk_gc_set_background (item_cursor->gc, &gs_white);
219
220
	if (draw_external){
		points [0].x = dx + cursor_width + 1;
221
		points [0].y = dy + cursor_height + 1 - premove;
222
		points [1].x = points [0].x;
223
224
225
226
227
		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;
228
		points [4].x = dx + cursor_width + 1 - premove;
229
230
		points [4].y = points [3].y;
		gdk_draw_lines (drawable, item_cursor->gc, points, 5);
231
232
233
234
235
236
237
238
239
240
241
242
243
	}

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

245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
	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);
262
	}
263
264

	if (draw_center){
265
266
		gdk_gc_set_foreground (item_cursor->gc, fore);
		gdk_gc_set_background (item_cursor->gc, back);
Arturo Espinosa's avatar
Arturo Espinosa committed
267
		gdk_gc_set_line_attributes (item_cursor->gc, draw_thick ? 3 : 1,
268
269
270
					    GDK_LINE_DOUBLE_DASH, -1, -1);
		gdk_draw_rectangle (drawable, item_cursor->gc, FALSE,
				    dx, dy,
271
				    cursor_width, cursor_height);
272
	}
273
274
275
276
277
278
279
280
281
}

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);
282
283
284
285
#if 0
	printf ("Requesting redraw: %d %d %d %d\n",
		x - 2, y - 2, x + w + 5, y + h + 5);
#endif
286
	gnome_canvas_request_redraw (canvas, x - 2, y - 2, x + w + 5, y + h + 5);
287
288
289
}

void
290
item_cursor_set_bounds (ItemCursor *item_cursor, int start_col, int start_row, int end_col, int end_row)
291
{
292
293
	GnomeCanvasItem *item;
	
294
295
	g_return_if_fail (start_col <= end_col);
	g_return_if_fail (start_row <= end_row);
296
297
298
299
	g_return_if_fail (item_cursor != NULL);
	g_return_if_fail (IS_ITEM_CURSOR (item_cursor));

	item = GNOME_CANVAS_ITEM (item_cursor);
300
301
	item_cursor_request_redraw (item_cursor);

302
303
304
305
	item_cursor->start_col = start_col;
	item_cursor->end_col   = end_col;
	item_cursor->start_row = start_row;
	item_cursor->end_row   = end_row;
306
307

	item_cursor_request_redraw (item_cursor);
308

309
	item_cursor_configure_bounds (item_cursor);
310
311
312
313
314
315
}

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
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
	*actual_item = NULL;

	if (cx < item->x1)
		return INT_MAX;
	if (cx > item->x2)
		return INT_MAX;
	if (cy < item->y1)
		return INT_MAX;
	if (cy > item->y2)
		return INT_MAX;

	/* FIXME: this needs to handle better the small little square case
	 * for ITEM_CURSOR_SELECTION style
	 */
	if ((cx < (item->x1 + 3)) ||
	    (cx > (item->x2 - 3)) ||
	    (cy < (item->y1 + 3)) ||
	    (cy > (item->y2 - 3))){
		*actual_item = item;
		return 0.0;
	}
Arturo Espinosa's avatar
Arturo Espinosa committed
337
	return INT_MAX;
338
339
340
341
342
343
344
345
}

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

Arturo Espinosa's avatar
Arturo Espinosa committed
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
#define convert(c,sx,sy,x,y) gnome_canvas_w2c (c,sx,sy,x,y)

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){
	case GDK_BUTTON_PRESS: {
		GnomeCanvasGroup *group;
		int style;

		printf ("cursor: got event\n");
		convert (canvas, event->button.x, event->button.y, &x, &y);
		
		group = GNOME_CANVAS_GROUP (canvas->root);
		if ((x > item->x2 - 6) && (y > item->y2 - 6))
			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);
		item_cursor_set_bounds (
			ITEM_CURSOR (new_item),
			item_cursor->start_col, item_cursor->start_row,
			item_cursor->end_col,   item_cursor->end_row);
		
		printf ("Creating new cursor!\n");
		
		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;
	}
	
}

static void
item_cursor_do_drop (ItemCursor *item_cursor)
{
	printf ("DROP!\n");
}

static gint
item_cursor_drag_event (GnomeCanvasItem *item, GdkEvent *event)
{
	ItemCursor *item_cursor = ITEM_CURSOR (item);

	switch (event->type){
	case GDK_BUTTON_RELEASE:
		gnome_canvas_item_ungrab (item, event->button.time);
		item_cursor_do_drop (item_cursor);
		gtk_object_destroy (GTK_OBJECT (item));
		return TRUE;

	case GDK_BUTTON_PRESS:
		printf ("Strange.  I got a button press\n");
		return TRUE;

	case GDK_MOTION_NOTIFY:
		printf ("Moving!\n");
		return TRUE;

	default:
		return FALSE;
	}
}

430
431
432
static gint
item_cursor_event (GnomeCanvasItem *item, GdkEvent *event)
{
Arturo Espinosa's avatar
Arturo Espinosa committed
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
	ItemCursor *item_cursor = ITEM_CURSOR (item);
	
	printf ("getting events!\n");
	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:
		return FALSE;
		
	default:
		return FALSE;
	}
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
}

/*
 * 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;
465
	item_cursor->end_col   = 0;
466
	item_cursor->start_row = 0;
467
	item_cursor->end_row   = 0;
468
	item_cursor->start_row = ITEM_CURSOR_SELECTION;
469
	item_cursor->tag = -1;
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
}

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;
488
489
490
	case ARG_STYLE:
		item_cursor->style = GTK_VALUE_INT (*arg);
		break;
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
	}
}

/*
 * 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);
512
513
	gtk_object_add_arg_type ("ItemCursor::Style", GTK_TYPE_INT,
				 GTK_ARG_WRITABLE, ARG_STYLE);
514
515
	
	object_class->set_arg = item_cursor_set_arg;
516
	object_class->destroy = item_cursor_destroy;
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

	/* 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;
}