sheet-object-graphic.c 30.1 KB
Newer Older
1
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2

3 4 5 6 7 8
/*
 * sheet-object-graphic.c: Implements the drawing object manipulation for Gnumeric
 *
 * Author:
 *   Miguel de Icaza (miguel@kernel.org)
 */
9
#include <gnumeric-config.h>
10
#include "gnumeric.h"
11 12
#include "sheet-object-graphic.h"

13
#include "sheet-control-gui.h"
14
#include "gnumeric-canvas.h"
15
#include "str.h"
16
#include "gui-util.h"
17
#include "style-color.h"
18 19
#include "sheet-object-impl.h"

Jody Goldberg's avatar
Jody Goldberg committed
20 21
#include <libgnome/gnome-i18n.h>
#include <gdk/gdkkeysyms.h>
22
#include <gal/util/e-util.h>
23 24
#include <gal/widgets/e-colors.h>
#include <gal/widgets/widget-color-combo.h>
25
#include <math.h>
26

27
/* These are persisted */
28
typedef enum {
29 30 31 32
	SHEET_OBJECT_LINE	= 1,
	SHEET_OBJECT_ARROW	= 2,
	SHEET_OBJECT_BOX	= 101,
	SHEET_OBJECT_OVAL	= 102,
33 34
} SheetObjectGraphicType;

Jody Goldberg's avatar
Jody Goldberg committed
35
#define SHEET_OBJECT_GRAPHIC_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), SHEET_OBJECT_GRAPHIC_TYPE))
36 37

typedef struct {
38
	SheetObject  sheet_object;
39
	StyleColor  *fill_color;
40
	double       width;
41
	double       a, b, c;
42 43 44 45 46 47
	SheetObjectGraphicType type;
} SheetObjectGraphic;
typedef struct {
	SheetObjectClass parent_class;
} SheetObjectGraphicClass;
static SheetObjectClass *sheet_object_graphic_parent_class;
48

49 50 51
/**
 * sheet_object_graphic_fill_color_set :
 * @so :
Jody Goldberg's avatar
Jody Goldberg committed
52
 * @color :
53 54 55 56 57
 *
 * Absorb the colour reference.
 */
void
sheet_object_graphic_fill_color_set (SheetObject *so, StyleColor *color)
58
{
59 60
	SheetObjectGraphic *sog = SHEET_OBJECT_GRAPHIC (so);
	GdkColor *gdk = (color != NULL) ? &color->color : NULL;
61
	GList *l;
62

63 64 65
	g_return_if_fail (sog != NULL);

	style_color_unref (sog->fill_color);
66
	sog->fill_color = color;
67 68

	for (l = so->realized_list; l; l = l->next)
69
		gnome_canvas_item_set (l->data, "fill_color_gdk", gdk, NULL);
70 71
}

72
static void
73
sheet_object_graphic_width_set (SheetObjectGraphic *sog, double width)
74
{
75 76
	SheetObject *so = SHEET_OBJECT (sog);
	GList *l;
77

78 79
	sog->width = width;
	for (l = so->realized_list; l; l = l->next)
80 81
		gnome_canvas_item_set (l->data, "width_units", width,
				       NULL);
82
}
83

84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
static void
sheet_object_graphic_abc_set (SheetObjectGraphic *sog, double a, double b,
			      double c)
{
	SheetObject *so = SHEET_OBJECT (sog);
	GList *l;

	sog->a = a;
	sog->b = b;
	sog->c = c;
	for (l = so->realized_list; l; l = l->next)
		gnome_canvas_item_set (l->data, "arrow_shape_a", a,
						"arrow_shape_b", b,
						"arrow_shape_c", c, NULL);
}

100
SheetObject *
101
sheet_object_line_new (gboolean is_arrow)
102 103
{
	SheetObjectGraphic *sog;
104

Jody Goldberg's avatar
Jody Goldberg committed
105
	sog = g_object_new (SHEET_OBJECT_GRAPHIC_TYPE, NULL);
106
	sog->type = is_arrow ? SHEET_OBJECT_ARROW : SHEET_OBJECT_LINE;
107

108 109
	return SHEET_OBJECT (sog);
}
110

111 112 113
static void
sheet_object_graphic_destroy (GtkObject *object)
{
114
	SheetObjectGraphic *sog;
Jody Goldberg's avatar
Jody Goldberg committed
115

116
	sog = SHEET_OBJECT_GRAPHIC (object);
117
	style_color_unref (sog->fill_color);
118

119
	GTK_OBJECT_CLASS (sheet_object_graphic_parent_class)->destroy (object);
120 121
}

Jody Goldberg's avatar
Jody Goldberg committed
122
static GObject *
123
sheet_object_graphic_new_view (SheetObject *so, SheetControlGUI *scg)
124
{
125
	/* FIXME : this is bogus */
126
	GnumericCanvas *gcanvas = scg_pane (scg, 0);
127 128
	SheetObjectGraphic *sog = SHEET_OBJECT_GRAPHIC (so);
	GnomeCanvasItem *item = NULL;
129
	GdkColor *fill_color;
130

131 132
	g_return_val_if_fail (IS_SHEET_OBJECT (so), NULL);
	g_return_val_if_fail (IS_SHEET_CONTROL_GUI (scg), NULL);
133

134 135
	fill_color = (sog->fill_color != NULL) ? &sog->fill_color->color : NULL;

Michael Meeks's avatar
Michael Meeks committed
136
	switch (sog->type) {
137 138
	case SHEET_OBJECT_LINE:
		item = gnome_canvas_item_new (
139
			gcanvas->object_group,
140
			gnome_canvas_line_get_type (),
141
			"fill_color_gdk", fill_color,
142
			"width_units", sog->width,
143 144 145 146 147
			NULL);
		break;

	case SHEET_OBJECT_ARROW:
		item = gnome_canvas_item_new (
148
			gcanvas->object_group,
149
			gnome_canvas_line_get_type (),
150
			"fill_color_gdk", fill_color,
151
			"width_units", sog->width,
152 153 154
			"arrow_shape_a", sog->a,
			"arrow_shape_b", sog->b,
			"arrow_shape_c", sog->c,
155 156 157 158 159 160 161 162
			"last_arrowhead", TRUE,
			NULL);
		break;

	default:
		g_assert_not_reached ();
	}

163
	scg_object_register (so, item);
Jody Goldberg's avatar
Jody Goldberg committed
164
	return G_OBJECT (item);
165 166
}

167
static void
Jody Goldberg's avatar
Jody Goldberg committed
168
sheet_object_graphic_update_bounds (SheetObject *so, GObject *view,
169
				    SheetControlGUI *scg)
170
{
171
	GnomeCanvasPoints *points = gnome_canvas_points_new (2);
172

173 174 175 176 177
	scg_object_view_position (scg, so, points->coords);
	gnome_canvas_item_set (GNOME_CANVAS_ITEM (view),
			       "points", points,
			       NULL);
	gnome_canvas_points_free (points);
178 179 180 181 182

	if (so->is_visible)
		gnome_canvas_item_show (GNOME_CANVAS_ITEM (view));
	else
		gnome_canvas_item_hide (GNOME_CANVAS_ITEM (view));
183
}
184

185
static gboolean
186 187
sheet_object_graphic_read_xml (SheetObject *so,
			       XmlParseContext const *ctxt, xmlNodePtr tree)
188
{
189
	SheetObjectGraphic *sog;
190
	double width, a, b, c;
191 192 193 194 195
	int tmp = 0;

	g_return_val_if_fail (IS_SHEET_OBJECT_GRAPHIC (so), TRUE);
	sog = SHEET_OBJECT_GRAPHIC (so);

Jody Goldberg's avatar
Jody Goldberg committed
196
	sheet_object_graphic_fill_color_set (so,
197
		xml_node_get_color (tree, "FillColor"));
198

199
	if (xml_node_get_int (tree, "Type", &tmp))
200
		sog->type = tmp;
201

202
	xml_node_get_double (tree, "Width", &width);
203
	sheet_object_graphic_width_set (sog, width);
204

205 206 207
	if (xml_node_get_double (tree, "ArrowShapeA", &a) &&
	    xml_node_get_double (tree, "ArrowShapeB", &b) &&
	    xml_node_get_double (tree, "ArrowShapeC", &c))
208 209
		sheet_object_graphic_abc_set (sog, a, b, c);

210 211 212 213 214 215 216
	return FALSE;
}

static gboolean
sheet_object_graphic_write_xml (SheetObject const *so,
				XmlParseContext const *ctxt, xmlNodePtr tree)
{
217
	SheetObjectGraphic *sog;
Jody Goldberg's avatar
Jody Goldberg committed
218

219 220
	g_return_val_if_fail (IS_SHEET_OBJECT_GRAPHIC (so), TRUE);
	sog = SHEET_OBJECT_GRAPHIC (so);
221

222 223
	if (sog->fill_color)
		xml_node_set_color (tree, "FillColor", sog->fill_color);
224 225
	xml_node_set_int (tree, "Type", sog->type);
	xml_node_set_double (tree, "Width", sog->width, -1);
226

227
	if (sog->type == SHEET_OBJECT_ARROW) {
228 229 230
		xml_node_set_double (tree, "ArrowShapeA", sog->a, -1);
		xml_node_set_double (tree, "ArrowShapeB", sog->b, -1);
		xml_node_set_double (tree, "ArrowShapeC", sog->c, -1);
231 232
	}

233
	return FALSE;
234 235
}

236 237 238
static SheetObject *
sheet_object_graphic_clone (SheetObject const *so, Sheet *sheet)
{
239
	SheetObjectGraphic *sog;
240 241
	SheetObjectGraphic *new_sog;

242 243 244
	g_return_val_if_fail (IS_SHEET_OBJECT_GRAPHIC (so), NULL);
	sog = SHEET_OBJECT_GRAPHIC (so);

Jody Goldberg's avatar
Jody Goldberg committed
245
	new_sog = g_object_new (GTK_OBJECT_TYPE (sog), NULL);
246 247 248

	new_sog->type  = sog->type;
	new_sog->width = sog->width;
249
	new_sog->fill_color = style_color_ref (sog->fill_color);
250 251 252
	new_sog->a = sog->a;
	new_sog->b = sog->b;
	new_sog->c = sog->c;
253 254 255 256

	return SHEET_OBJECT (new_sog);
}

257
static void
258 259
sheet_object_graphic_print (SheetObject const *so, GnomePrintContext *ctx,
			    double base_x, double base_y)
260
{
261
	SheetObjectGraphic *sog;
262
	double coords [4];
263 264 265
	double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;

	g_return_if_fail (IS_SHEET_OBJECT_GRAPHIC (so));
266
	g_return_if_fail (GNOME_IS_PRINT_CONTEXT (ctx));
267
	sog = SHEET_OBJECT_GRAPHIC (so);
268

269
	sheet_object_position_pts_get (so, coords);
270 271 272

	gnome_print_gsave (ctx);

273
	if (sog->fill_color) {
274
		switch (so->anchor.direction) {
275 276
		case SO_DIR_UP_RIGHT:
		case SO_DIR_DOWN_RIGHT:
277 278
			x1 = base_x;
			x2 = base_x + (coords [2] - coords [0]);
279 280 281
			break;
		case SO_DIR_UP_LEFT:
		case SO_DIR_DOWN_LEFT:
282 283
			x1 = base_x + (coords [2] - coords [0]);
			x2 = base_x;
284 285 286 287 288 289 290
			break;
		default:
			g_warning ("Cannot guess direction!");
			gnome_print_grestore (ctx);
			return;
		}

291
		switch (so->anchor.direction) {
292 293
		case SO_DIR_UP_LEFT:
		case SO_DIR_UP_RIGHT:
294 295
			y1 = base_y;
			y2 = base_y + (coords [3] - coords [1]);
296 297 298
			break;
		case SO_DIR_DOWN_LEFT:
		case SO_DIR_DOWN_RIGHT:
299 300
			y1 = base_y + (coords [3] - coords [1]);
			y2 = base_y;
301 302 303 304 305 306 307
			break;
		default:
			g_warning ("Cannot guess direction!");
			gnome_print_grestore (ctx);
			return;
		}

308
		gnome_print_setrgbcolor (ctx,
309 310 311
			sog->fill_color->red   / (double) 0xffff,
			sog->fill_color->green / (double) 0xffff,
			sog->fill_color->blue  / (double) 0xffff);
312 313 314 315 316 317 318 319 320 321 322

		if (sog->type == SHEET_OBJECT_ARROW) {
			double phi;

			phi = atan2 (y2 - y1, x2 - x1) - M_PI_2;

			gnome_print_gsave (ctx);
			gnome_print_translate (ctx, x2, y2);
			gnome_print_rotate (ctx, phi / (2 * M_PI) * 360);
			gnome_print_setlinewidth (ctx, 1.0);
			gnome_print_newpath (ctx);
Jody Goldberg's avatar
Jody Goldberg committed
323
			gnome_print_moveto (ctx, 0.0, 0.0);
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
			gnome_print_lineto (ctx, -sog->c, -sog->b);
			gnome_print_lineto (ctx, 0.0, -sog->a);
			gnome_print_lineto (ctx, sog->c, -sog->b);
			gnome_print_closepath (ctx);
			gnome_print_fill (ctx);
			gnome_print_grestore (ctx);

			/*
			 * Make the line shorter so that the arrow won't be
			 * on top of a (perhaps quite fat) line.
			 */
			x2 += sog->a * sin (phi);
			y2 -= sog->a * cos (phi);
		}

339 340 341 342 343 344
		gnome_print_setlinewidth (ctx, sog->width);
		gnome_print_newpath (ctx);
		gnome_print_moveto (ctx, x1, y1);
		gnome_print_lineto (ctx, x2, y2);
		gnome_print_stroke (ctx);
	}
345

346
	gnome_print_grestore (ctx);
347 348
}

349 350 351
typedef struct
{
	SheetObjectGraphic *sog;
352 353
	GtkWidget *canvas;
	GnomeCanvasItem *arrow;
354
	GtkWidget *fill_color_combo;
355
	GtkObject *adj_width;
356
	GtkObject *adj_a, *adj_b, *adj_c; /* Only for arrows */
357
	StyleColor *fill_color;
358
	double width;
359
	double a, b, c;                   /* Only for arrows */
360 361 362 363 364 365 366 367 368 369 370 371 372 373
} DialogGraphicData;

static gboolean
cb_dialog_graphic_close (GnomeDialog *dialog, DialogGraphicData *data)
{
	g_free (data);

	return (FALSE);
}

static void
cb_dialog_graphic_clicked (GnomeDialog *dialog, int button,
			   DialogGraphicData *data)
{
374
	SheetObject *so = SHEET_OBJECT (data->sog);
375 376 377 378 379

	switch (button) {
	case 0: /* Ok */
	case 1: /* Apply */
		sheet_object_graphic_width_set (data->sog,
380
				GTK_ADJUSTMENT (data->adj_width)->value);
381 382

		sheet_object_graphic_fill_color_set (so,
383
			color_combo_get_style_color (data->fill_color_combo));
384

385
		if (data->sog->type == SHEET_OBJECT_ARROW)
Jody Goldberg's avatar
Jody Goldberg committed
386
			sheet_object_graphic_abc_set (data->sog,
387 388 389
				GTK_ADJUSTMENT (data->adj_a)->value,
				GTK_ADJUSTMENT (data->adj_b)->value,
				GTK_ADJUSTMENT (data->adj_c)->value);
390 391 392
		if (button == 0)
			gnome_dialog_close (dialog);
		break;
393

394 395
	case 2: /* Cancel */
		sheet_object_graphic_width_set (data->sog, data->width);
396 397 398
		sheet_object_graphic_fill_color_set (so,
			data->fill_color);

399
		if (data->sog->type == SHEET_OBJECT_ARROW)
400 401
			sheet_object_graphic_abc_set (data->sog,
				data->a, data->b, data->c);
402 403
		gnome_dialog_close (dialog);
		break;
404

405 406 407 408 409 410
	default:
		g_warning ("Unhandled button %i.", button);
		break;
	}
}

411 412 413 414 415 416 417 418 419 420 421
static void
cb_adjustment_value_changed (GtkAdjustment *adj, DialogGraphicData *data)
{
	gnome_canvas_item_set (data->arrow,
		"arrow_shape_a", (double) GTK_ADJUSTMENT (data->adj_a)->value,
		"arrow_shape_b", (double) GTK_ADJUSTMENT (data->adj_b)->value,
		"arrow_shape_c", (double) GTK_ADJUSTMENT (data->adj_c)->value,
		"width_units", (double) GTK_ADJUSTMENT (data->adj_width)->value,
		NULL);
}

422 423 424 425 426 427 428
static void
cb_fill_color_changed (ColorCombo *color_combo, GdkColor *color,
		       gboolean by_user, DialogGraphicData *data)
{
	gnome_canvas_item_set (data->arrow, "fill_color_gdk", color, NULL);
}

429 430 431
static void
sheet_object_graphic_user_config (SheetObject *so, SheetControlGUI *scg)
{
Jody Goldberg's avatar
Jody Goldberg committed
432
	GtkWidget *dialog, *table, *label, *spin, *spin_a, *spin_b, *spin_c;
433 434
	GtkTooltips *tooltips;
	WorkbookControlGUI *wbcg;
435 436
	SheetObjectGraphic *sog;
	DialogGraphicData *data;
437
	GnomeCanvasPoints *points;
438 439 440 441 442

	g_return_if_fail (IS_SHEET_OBJECT_GRAPHIC (so));
	g_return_if_fail (IS_SHEET_CONTROL_GUI (scg));

	sog = SHEET_OBJECT_GRAPHIC (so);
443
	wbcg = scg_get_wbcg (scg);
444 445 446 447 448 449

	dialog = gnome_dialog_new (_("Configure line or arrow"),
				   GNOME_STOCK_BUTTON_OK,
				   GNOME_STOCK_BUTTON_APPLY,
				   GNOME_STOCK_BUTTON_CANCEL, NULL);
	gnome_dialog_set_close (GNOME_DIALOG (dialog), FALSE);
450
	gnome_dialog_set_parent (GNOME_DIALOG (dialog),
Jody Goldberg's avatar
Jody Goldberg committed
451
				 wbcg_toplevel (wbcg));
452
	tooltips = gtk_tooltips_new ();
453

454
	table = gtk_table_new (3, 5, FALSE);
455 456 457
	gtk_table_set_col_spacings (GTK_TABLE (table), 10);
	gtk_table_set_row_spacings (GTK_TABLE (table), 10);
	gtk_container_add (GTK_CONTAINER (GNOME_DIALOG (dialog)->vbox), table);
458

459 460
	label = gtk_label_new (_("Color"));
	gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 0, 1);
Jody Goldberg's avatar
Jody Goldberg committed
461
	label = gtk_label_new (_("Line Width"));
462
	gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 1, 2);
463 464

	if (sog->type == SHEET_OBJECT_ARROW) {
Jody Goldberg's avatar
Jody Goldberg committed
465
		label = gtk_label_new (_("Arrow tip"));
466
		gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 2,3);
Jody Goldberg's avatar
Jody Goldberg committed
467
		label = gtk_label_new (_("Arrow length"));
468
		gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 3,4);
Jody Goldberg's avatar
Jody Goldberg committed
469
		label = gtk_label_new (_("Arrow width"));
470 471
		gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 4,5);
	}
472

473 474 475
	data = g_new0 (DialogGraphicData, 1);
	data->sog = sog;

476 477 478 479 480
	if (sog->type == SHEET_OBJECT_ARROW) {
		data->canvas = gnome_canvas_new ();
		gtk_table_attach_defaults (GTK_TABLE (table), data->canvas,
					   2, 3, 2, 5);
	}
481

482
	data->fill_color_combo = color_combo_new (NULL, NULL, NULL,
483
					color_group_fetch ("color", so));
Jody Goldberg's avatar
Jody Goldberg committed
484
	color_combo_set_color (COLOR_COMBO (data->fill_color_combo),
485 486
			       sog->fill_color ? &sog->fill_color->color : NULL);
	data->fill_color = style_color_ref (sog->fill_color);
Jody Goldberg's avatar
Jody Goldberg committed
487

488 489 490 491 492
	data->adj_width = gtk_adjustment_new ((float) sog->width, 1.0,
					      100.0, 1.0, 5.0, 1.0);
	spin = gtk_spin_button_new (GTK_ADJUSTMENT (data->adj_width), 1, 0);
	data->width = sog->width;

493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514
	if (sog->type == SHEET_OBJECT_ARROW) {
		data->adj_a = gtk_adjustment_new (sog->a, 1., 100., 1., 5., 1.);
		data->adj_b = gtk_adjustment_new (sog->b, 1., 100., 1., 5., 1.);
		data->adj_c = gtk_adjustment_new (sog->c, 1., 100., 1., 5., 1.);
		spin_a = gtk_spin_button_new (GTK_ADJUSTMENT (data->adj_a),1,0);
		spin_b = gtk_spin_button_new (GTK_ADJUSTMENT (data->adj_b),1,0);
		spin_c = gtk_spin_button_new (GTK_ADJUSTMENT (data->adj_c),1,0);
		data->a = sog->a;
		data->b = sog->b;
		data->c = sog->c;
		gtk_tooltips_set_tip (tooltips, spin_a, _("Distance from tip "
				      "of arrowhead to the center point"),NULL);
		gtk_tooltips_set_tip (tooltips, spin_b, _("Distance from tip "
				      "of arrowhead to trailing point, "
				      "measured along shaft"), NULL);
		gtk_tooltips_set_tip (tooltips, spin_c, _("Distance of "
				      "trailing point from outside edge of "
				      "shaft"), NULL);
		gtk_table_attach_defaults (GTK_TABLE (table), spin_a, 1, 2,2,3);
		gtk_table_attach_defaults (GTK_TABLE (table), spin_b, 1, 2,3,4);
		gtk_table_attach_defaults (GTK_TABLE (table), spin_c, 1, 2,4,5);
	}
515

516
	gtk_table_attach_defaults (GTK_TABLE (table),
517 518
				   data->fill_color_combo, 1, 3, 0, 1);
	gtk_table_attach_defaults (GTK_TABLE (table), spin, 1, 3, 1, 2);
519

520
	gtk_widget_show_all (dialog);
521

522 523 524 525 526 527 528 529
	if (sog->type == SHEET_OBJECT_ARROW) {
		points = gnome_canvas_points_new (2);
		points->coords [0] = data->canvas->allocation.width / 2.0;
		points->coords [1] = 0.0;
		points->coords [2] = points->coords [0];
		points->coords [3] = data->canvas->allocation.height;
		data->arrow = gnome_canvas_item_new (
				gnome_canvas_root (GNOME_CANVAS (data->canvas)),
Jody Goldberg's avatar
Jody Goldberg committed
530
				GNOME_TYPE_CANVAS_LINE, "points", points,
531 532 533 534 535
				"fill_color_gdk", sog->fill_color,
				"first_arrowhead", TRUE, NULL);
		gnome_canvas_points_free (points);
		gnome_canvas_set_scroll_region (GNOME_CANVAS (data->canvas),
					0., 0., data->canvas->allocation.width,
536
					data->canvas->allocation.height);
537 538
		cb_adjustment_value_changed (NULL, data);

Jody Goldberg's avatar
Jody Goldberg committed
539 540 541 542 543 544 545 546 547 548 549 550 551 552 553
		g_signal_connect (G_OBJECT (data->adj_width),
			"value_changed",
			G_CALLBACK (cb_adjustment_value_changed), data);
		g_signal_connect (G_OBJECT (data->adj_a),
			"value_changed",
			G_CALLBACK (cb_adjustment_value_changed), data);
		g_signal_connect (G_OBJECT (data->adj_b),
			"value_changed",
			G_CALLBACK (cb_adjustment_value_changed), data);
		g_signal_connect (G_OBJECT (data->adj_c),
			"value_changed",
			G_CALLBACK (cb_adjustment_value_changed), data);
		g_signal_connect (G_OBJECT (data->fill_color_combo),
			"changed",
			G_CALLBACK (cb_fill_color_changed), data);
554 555
	}

Jody Goldberg's avatar
Jody Goldberg committed
556 557 558 559 560 561
	g_signal_connect (G_OBJECT (dialog),
		"clicked",
		G_CALLBACK (cb_dialog_graphic_clicked), data);
	g_signal_connect (G_OBJECT (dialog),
		"close",
		G_CALLBACK (cb_dialog_graphic_close), data);
562 563
}

564 565 566
static void
sheet_object_graphic_class_init (GtkObjectClass *object_class)
{
567
	SheetObjectClass *sheet_object_class;
568

569
	sheet_object_graphic_parent_class = gtk_type_class (SHEET_OBJECT_TYPE);
570

571
	/* Object class method overrides */
572
	object_class->destroy = sheet_object_graphic_destroy;
573 574

	/* SheetObject class method overrides */
575
	sheet_object_class = SHEET_OBJECT_CLASS (object_class);
576
	sheet_object_class->new_view	  = sheet_object_graphic_new_view;
Jody Goldberg's avatar
Jody Goldberg committed
577
	sheet_object_class->update_bounds = sheet_object_graphic_update_bounds;
578
	sheet_object_class->read_xml	  = sheet_object_graphic_read_xml;
579 580
	sheet_object_class->write_xml	  = sheet_object_graphic_write_xml;
	sheet_object_class->clone         = sheet_object_graphic_clone;
581
	sheet_object_class->user_config   = sheet_object_graphic_user_config;
Jody Goldberg's avatar
Jody Goldberg committed
582
	sheet_object_class->print         = sheet_object_graphic_print;
583
	sheet_object_class->rubber_band_directly = TRUE;
584 585
}

586 587 588
static void
sheet_object_graphic_init (GtkObject *obj)
{
589 590
	SheetObjectGraphic *sog;
	SheetObject *so;
Jody Goldberg's avatar
Jody Goldberg committed
591

592
	sog = SHEET_OBJECT_GRAPHIC (obj);
593
	sog->fill_color = style_color_new_name ("black");
594
	sog->width = 1.0;
595 596 597
	sog->a = 8.0;
	sog->b = 10.0;
	sog->c = 3.0;
598 599

	so = SHEET_OBJECT (obj);
600
	so->anchor.direction = SO_DIR_NONE_MASK;
601 602
}

603 604 605
E_MAKE_TYPE (sheet_object_graphic, "SheetObjectGraphic", SheetObjectGraphic,
	     sheet_object_graphic_class_init, sheet_object_graphic_init,
	     SHEET_OBJECT_TYPE);
606

607
/************************************************************************/
608 609

/*
610
 * SheetObjectFilled
611
 *
612
 * Derivative of SheetObjectGraphic, with filled parameter
613
 */
Jody Goldberg's avatar
Jody Goldberg committed
614
#define IS_SHEET_OBJECT_FILLED_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), SHEET_OBJECT_FILLED_TYPE, SheetObjectFilledClass))
615 616

typedef struct {
617
	SheetObjectGraphic sheet_object_graphic;
618

619
	StyleColor *outline_color;
620 621 622 623 624 625 626 627
} SheetObjectFilled;

typedef struct {
	SheetObjectGraphicClass parent_class;
} SheetObjectFilledClass;

static SheetObjectGraphicClass *sheet_object_filled_parent_class;

628 629
void
sheet_object_filled_outline_color_set (SheetObject *so, StyleColor *color)
630
{
631 632
	SheetObjectFilled *sof = SHEET_OBJECT_FILLED (so);
	GdkColor *gdk = (color != NULL) ? &color->color : NULL;
633 634
	GList *l;

635 636 637
	g_return_if_fail (sof != NULL);

	style_color_unref (sof->outline_color);
638
	sof->outline_color = color;
639

640
	for (l = so->realized_list; l; l = l->next)
641
		gnome_canvas_item_set (l->data, "outline_color_gdk", gdk, NULL);
642 643
}

644
SheetObject *
645
sheet_object_box_new (gboolean is_oval)
646
{
647
	SheetObjectFilled *sof;
648 649
	SheetObjectGraphic *sog;

Jody Goldberg's avatar
Jody Goldberg committed
650
	sof = g_object_new (SHEET_OBJECT_FILLED_TYPE, NULL);
651

652 653
	sog = SHEET_OBJECT_GRAPHIC (sof);
	sog->type = is_oval ? SHEET_OBJECT_OVAL : SHEET_OBJECT_BOX;
654

655
	return SHEET_OBJECT (sof);
656 657 658 659 660
}

static void
sheet_object_filled_destroy (GtkObject *object)
{
661
	SheetObjectFilled *sof;
Jody Goldberg's avatar
Jody Goldberg committed
662

663
	sof = SHEET_OBJECT_FILLED (object);
664
	style_color_unref (sof->outline_color);
665

666 667 668
	GTK_OBJECT_CLASS (sheet_object_filled_parent_class)->destroy (object);
}

669
static void
Jody Goldberg's avatar
Jody Goldberg committed
670
sheet_object_filled_update_bounds (SheetObject *so, GObject *view,
671
				   SheetControlGUI *scg)
672
{
673
	double coords [4];
674

675
	scg_object_view_position (scg, so, coords);
Jody Goldberg's avatar
Jody Goldberg committed
676

677
	gnome_canvas_item_set (GNOME_CANVAS_ITEM (view),
678 679 680 681
		"x1", MIN (coords [0], coords [2]),
		"x2", MAX (coords [0], coords [2]),
		"y1", MIN (coords [1], coords [3]),
		"y2", MAX (coords [1], coords [3]),
682
		NULL);
683 684 685 686 687

	if (so->is_visible)
		gnome_canvas_item_show (GNOME_CANVAS_ITEM (view));
	else
		gnome_canvas_item_hide (GNOME_CANVAS_ITEM (view));
688 689
}

Jody Goldberg's avatar
Jody Goldberg committed
690
static GObject *
691
sheet_object_filled_new_view (SheetObject *so, SheetControlGUI *scg)
692
{
693
	/* FIXME : this is bogus */
694
	GnumericCanvas *gcanvas = scg_pane (scg, 0);
695 696 697
	SheetObjectGraphic *sog;
	SheetObjectFilled  *sof;
	GnomeCanvasItem *item;
698
	GdkColor *fill_color, *outline_color;
699

700
	g_return_val_if_fail (IS_SHEET_OBJECT_FILLED (so), NULL);
701
	g_return_val_if_fail (IS_SHEET_CONTROL_GUI (scg), NULL);
702 703
	sof = SHEET_OBJECT_FILLED (so);
	sog = SHEET_OBJECT_GRAPHIC (so);
704

705 706 707
	fill_color = (sog->fill_color != NULL) ? &sog->fill_color->color : NULL;
	outline_color = (sof->outline_color != NULL) ? &sof->outline_color->color : NULL;

708
	item = gnome_canvas_item_new (
709 710
		gcanvas->object_group,
		(sog->type == SHEET_OBJECT_OVAL) ?
Jody Goldberg's avatar
Jody Goldberg committed
711 712
					GNOME_TYPE_CANVAS_ELLIPSE :
					GNOME_TYPE_CANVAS_RECT,
713 714 715 716
		"fill_color_gdk",	fill_color,
		"outline_color_gdk",	outline_color,
		"width_units",		sog->width,
		NULL);
717

718
	scg_object_register (so, item);
Jody Goldberg's avatar
Jody Goldberg committed
719
	return G_OBJECT (item);
720 721 722
}

static gboolean
723 724
sheet_object_filled_read_xml (SheetObject *so,
			      XmlParseContext const *ctxt, xmlNodePtr tree)
725
{
726
	SheetObjectFilled *sof;
727

728 729
	g_return_val_if_fail (IS_SHEET_OBJECT_FILLED (so), TRUE);
	sof = SHEET_OBJECT_FILLED (so);
730

Jody Goldberg's avatar
Jody Goldberg committed
731
	sheet_object_filled_outline_color_set (so,
732
		xml_node_get_color (tree, "OutlineColor"));
733

734 735 736 737
	return sheet_object_graphic_read_xml (so, ctxt, tree);
}

static gboolean
Jody Goldberg's avatar
Jody Goldberg committed
738
sheet_object_filled_write_xml (SheetObject const *so,
739 740
			       XmlParseContext const *ctxt, xmlNodePtr tree)
{
741
	SheetObjectFilled *sof;
Jody Goldberg's avatar
Jody Goldberg committed
742

743 744 745
	g_return_val_if_fail (IS_SHEET_OBJECT_FILLED (so), TRUE);
	sof = SHEET_OBJECT_FILLED (so);

746 747
	if (sof->outline_color)
		xml_node_set_color (tree, "OutlineColor", sof->outline_color);
748 749

	return sheet_object_graphic_write_xml (so, ctxt, tree);
750 751
}

752 753 754
static SheetObject *
sheet_object_filled_clone (SheetObject const *so, Sheet *sheet)
{
755
	SheetObjectFilled *sof;
756 757 758
	SheetObjectFilled *new_sof;
	SheetObject *new_so;

759 760 761
	g_return_val_if_fail (IS_SHEET_OBJECT_FILLED (so), NULL);
	sof = SHEET_OBJECT_FILLED (so);

762 763 764
	new_so = sheet_object_graphic_clone (so, sheet);
	new_sof = SHEET_OBJECT_FILLED (new_so);

765
	new_sof->outline_color = sof->outline_color;
766 767 768 769

	return SHEET_OBJECT (new_sof);
}

Jody Goldberg's avatar
Jody Goldberg committed
770
typedef struct
771 772 773 774
{
	SheetObjectFilled *sof;
	GtkWidget *fill_color_combo;
	GtkWidget *outline_color_combo;
775
	GtkObject *adj_width;
776 777
	StyleColor *outline_color;
	StyleColor *fill_color;
778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793
	double width;
} DialogFilledData;

static gboolean
cb_dialog_filled_close (GnomeDialog *dialog, DialogFilledData *data)
{
	g_free (data);

	return (FALSE);
}

static void
cb_dialog_filled_clicked (GnomeDialog *dialog, int button,
			  DialogFilledData *data)
{
	SheetObjectGraphic *sog = SHEET_OBJECT_GRAPHIC (data->sof);
794
	SheetObject *so = SHEET_OBJECT (data->sof);
Jody Goldberg's avatar
Jody Goldberg committed
795

796 797 798
	switch (button) {
	case 0: /* Ok */
	case 1: /* Apply */
Jody Goldberg's avatar
Jody Goldberg committed
799
		sheet_object_graphic_width_set (sog,
800 801 802
			GTK_ADJUSTMENT (data->adj_width)->value);

		sheet_object_graphic_fill_color_set (so,
803
			color_combo_get_style_color (data->fill_color_combo));
804
		sheet_object_filled_outline_color_set (so,
805
			color_combo_get_style_color (data->outline_color_combo));
806

807 808 809
		if (button == 0)
			gnome_dialog_close (dialog);
		break;
810

811 812
	case 2: /* Cancel */
		sheet_object_graphic_width_set (sog, data->width);
813 814 815 816
		sheet_object_graphic_fill_color_set (so,
			data->fill_color);
		sheet_object_filled_outline_color_set (so,
			data->outline_color);
817 818
		gnome_dialog_close (dialog);
		break;
819

820 821 822 823 824 825 826 827 828
	default:
		g_warning ("Unhandled button %i.", button);
		break;
	}
}

static void
sheet_object_filled_user_config (SheetObject *so, SheetControlGUI *scg)
{
829
	WorkbookControlGUI *wbcg;
Jody Goldberg's avatar
Jody Goldberg committed
830
	GtkWidget *dialog, *table, *label, *spin;
831 832 833 834 835 836 837 838 839
	SheetObjectFilled *sof;
	SheetObjectGraphic *sog;
	DialogFilledData *data;

	g_return_if_fail (IS_SHEET_OBJECT_FILLED (so));
	g_return_if_fail (IS_SHEET_CONTROL_GUI (scg));

	sof = SHEET_OBJECT_FILLED (so);
	sog = SHEET_OBJECT_GRAPHIC (so);
840
	wbcg = scg_get_wbcg (scg);
841 842 843 844 845 846

	dialog = gnome_dialog_new (_("Configure filled object"),
				   GNOME_STOCK_BUTTON_OK,
				   GNOME_STOCK_BUTTON_APPLY,
				   GNOME_STOCK_BUTTON_CANCEL, NULL);
	gnome_dialog_set_close (GNOME_DIALOG (dialog), FALSE);
847
	gnome_dialog_set_parent (GNOME_DIALOG (dialog),
Jody Goldberg's avatar
Jody Goldberg committed
848
				 wbcg_toplevel (wbcg));
849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866

	table = gtk_table_new (2, 3, FALSE);
	gtk_table_set_col_spacings (GTK_TABLE (table), 10);
	gtk_table_set_row_spacings (GTK_TABLE (table), 10);
	gtk_container_add (GTK_CONTAINER (GNOME_DIALOG (dialog)->vbox), table);
	label = gtk_label_new (_("Outline color"));
	gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 0, 1);
	label = gtk_label_new (_("Fill color"));
	gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 1, 2);
	label = gtk_label_new (_("Border width"));
	gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 2, 3);

	data = g_new0 (DialogFilledData, 1);
	data->sof = sof;

	data->outline_color_combo = color_combo_new (NULL, _("Transparent"),
				NULL, color_group_fetch ("outline_color", so));
	color_combo_set_color (COLOR_COMBO (data->outline_color_combo),
867 868
			       sof->outline_color ? &sof->outline_color->color : NULL);
	data->outline_color = style_color_ref (sof->outline_color);
869 870 871

	data->fill_color_combo = color_combo_new (NULL, _("Transparent"),
				NULL, color_group_fetch ("fill_color", so));
Jody Goldberg's avatar
Jody Goldberg committed
872
	color_combo_set_color (COLOR_COMBO (data->fill_color_combo),
873 874
			       sog->fill_color ? &sog->fill_color->color : NULL);
	data->fill_color = style_color_ref (sog->fill_color);
Jody Goldberg's avatar
Jody Goldberg committed
875

876 877 878
	data->adj_width = gtk_adjustment_new ((float) sog->width, 1.0,
					      100.0, 1.0, 5.0, 1.0);
	spin = gtk_spin_button_new (GTK_ADJUSTMENT (data->adj_width), 1, 0);
879 880 881 882 883 884 885 886
	data->width = sog->width;

	gtk_table_attach_defaults (GTK_TABLE (table),
				   data->outline_color_combo, 1, 2, 0, 1);
	gtk_table_attach_defaults (GTK_TABLE (table),
				   data->fill_color_combo, 1, 2, 1, 2);
	gtk_table_attach_defaults (GTK_TABLE (table), spin, 1, 2, 2, 3);

Jody Goldberg's avatar
Jody Goldberg committed
887 888 889 890 891 892
	g_signal_connect (G_OBJECT (dialog),
		"clicked",
		G_CALLBACK (cb_dialog_filled_clicked), data);
	g_signal_connect (G_OBJECT (dialog),
		"close",
		G_CALLBACK (cb_dialog_filled_close), data);
893

894
	gtk_widget_show_all (dialog);
895 896 897 898 899 900 901 902 903 904 905 906 907
}

static void
make_rect (GnomePrintContext *ctx, double x1, double x2, double y1, double y2)
{
	gnome_print_moveto (ctx, x1, y1);
	gnome_print_lineto (ctx, x2, y1);
	gnome_print_lineto (ctx, x2, y2);
	gnome_print_lineto (ctx, x1, y2);
	gnome_print_lineto (ctx, x1, y1);
}

/*
Jody Goldberg's avatar
Jody Goldberg committed
908
 * The following lines are copy and paste from dia. The ellipse logic has been
909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974
 * slightly adapted. I have _no_ idea what's going on...
 */

/* This constant is equal to sqrt(2)/3*(8*cos(pi/8) - 4 - 1/sqrt(2)) - 1.
 * Its use should be quite obvious.
 */
#define ELLIPSE_CTRL1 0.26521648984
/* this constant is equal to 1/sqrt(2)*(1-ELLIPSE_CTRL1).
 * Its use should also be quite obvious.
 */
#define ELLIPSE_CTRL2 0.519570402739
#define ELLIPSE_CTRL3 M_SQRT1_2
/* this constant is equal to 1/sqrt(2)*(1+ELLIPSE_CTRL1).
 * Its use should also be quite obvious.
 */
#define ELLIPSE_CTRL4 0.894643159635

static void
make_ellipse (GnomePrintContext *ctx,
	      double x1, double x2, double y1, double y2)
{
	double width  = x2 - x1;
	double height = y2 - y1;
	double center_x = x1 + width / 2.0;
	double center_y = y1 + height / 2.0;
	double cw1 = ELLIPSE_CTRL1 * width / 2.0;
	double cw2 = ELLIPSE_CTRL2 * width / 2.0;
	double cw3 = ELLIPSE_CTRL3 * width / 2.0;
	double cw4 = ELLIPSE_CTRL4 * width / 2.0;
	double ch1 = ELLIPSE_CTRL1 * height / 2.0;
	double ch2 = ELLIPSE_CTRL2 * height / 2.0;
	double ch3 = ELLIPSE_CTRL3 * height / 2.0;
	double ch4 = ELLIPSE_CTRL4 * height / 2.0;

	gnome_print_moveto (ctx, x1, center_y);
	gnome_print_curveto (ctx,
			     x1,             center_y - ch1,
			     center_x - cw4, center_y - ch2,
			     center_x - cw3, center_y - ch3);
	gnome_print_curveto (ctx,
			     center_x - cw2, center_y - ch4,
			     center_x - cw1, y1,
			     center_x,       y1);
	gnome_print_curveto (ctx,
			     center_x + cw1, y1,
			     center_x + cw2, center_y - ch4,
			     center_x + cw3, center_y - ch3);
	gnome_print_curveto (ctx,
			     center_x + cw4, center_y - ch2,
			     x2,             center_y - ch1,
			     x2,             center_y);
	gnome_print_curveto (ctx,
			     x2,             center_y + ch1,
			     center_x + cw4, center_y + ch2,
			     center_x + cw3, center_y + ch3);
	gnome_print_curveto (ctx,
			     center_x + cw2, center_y + ch4,
			     center_x + cw1, y2,
			     center_x,       y2);
	gnome_print_curveto (ctx,
			     center_x - cw1, y2,
			     center_x - cw2, center_y + ch4,
			     center_x - cw3, center_y + ch3);
	gnome_print_curveto (ctx,
			     center_x - cw4, center_y + ch2,
			     x1,             center_y + ch1,
Jody Goldberg's avatar
Jody Goldberg committed
975
			     x1,             center_y);
976 977 978
}

static void
979 980
sheet_object_filled_print (SheetObject const *so, GnomePrintContext *ctx,
			   double base_x, double base_y)
981 982 983 984
{
	SheetObjectFilled *sof;
	SheetObjectGraphic *sog;
	double coords [4];
985 986
	double start_x, start_y;
	double end_x, end_y;
987 988

	g_return_if_fail (IS_SHEET_OBJECT_FILLED (so));
989
	g_return_if_fail (GNOME_IS_PRINT_CONTEXT (ctx));
990 991 992
	sof = SHEET_OBJECT_FILLED (so);
	sog = SHEET_OBJECT_GRAPHIC (so);

993
	sheet_object_position_pts_get (so, coords);
994

995 996 997 998
	start_x = base_x;
	start_y = base_y;
	end_x = start_x + (coords [2] - coords [0]);
	end_y = start_y + (coords [3] - coords [1]);
999 1000 1001 1002 1003 1004

	gnome_print_gsave (ctx);

	if (sof->outline_color) {
		gnome_print_setlinewidth (ctx, sog->width);
		gnome_print_setrgbcolor (ctx,
1005 1006 1007
			sof->outline_color->red   / (double) 0xffff,
			sof->outline_color->green / (double) 0xffff,
			sof->outline_color->blue  / (double) 0xffff);
1008 1009
		gnome_print_newpath (ctx);
		if (sog->type == SHEET_OBJECT_OVAL)
1010
			make_ellipse (ctx, start_x, end_x, start_y, end_y);
1011
		else
1012
			make_rect (ctx, start_x, end_x, start_y, end_y);
1013 1014 1015 1016 1017 1018
		gnome_print_closepath (ctx);
		gnome_print_stroke (ctx);
	}

	if (sog->fill_color) {
		gnome_print_setrgbcolor (ctx,
1019 1020 1021
			sog->fill_color->red   / (double) 0xffff,
			sog->fill_color->green / (double) 0xffff,
			sog->fill_color->blue  / (double) 0xffff);
1022 1023
		gnome_print_newpath (ctx);
		if (sog->type == SHEET_OBJECT_OVAL)
1024
			make_ellipse (ctx, start_x, end_x, start_y, end_y);
1025
		else
1026
			make_rect (ctx, start_x, end_x, start_y, end_y);
1027 1028 1029 1030 1031 1032
		gnome_print_fill (ctx);
	}

	gnome_print_grestore (ctx);
<