sheet-object-graphic.c 29.8 KB
Newer Older
Chema Celorio's avatar
Chema Celorio committed
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 9
/*
 * sheet-object-graphic.c: Implements the drawing object manipulation for Gnumeric
 *
 * Author:
 *   Miguel de Icaza (miguel@kernel.org)
 */
#include <config.h>
10 11 12
#include <glib.h>
#include <libgnome/gnome-defs.h>
#include <libgnome/gnome-i18n.h>
13
#include <gdk/gdkkeysyms.h>
14
#include <libgnomeprint/gnome-print.h>
15
#include <math.h>
16
#include "gnumeric.h"
17
#include "sheet-control-gui.h"
18
#include "gnumeric-canvas.h"
19
#include "str.h"
20
#include "gui-util.h"
21
#include "sheet-object-graphic.h"
22 23
#include "sheet-object-impl.h"

24
#include <gal/util/e-util.h>
25 26
#include <gal/widgets/e-colors.h>
#include <gal/widgets/widget-color-combo.h>
27
#include <math.h>
28

29
/* These are persisted */
30
typedef enum {
31 32 33 34
	SHEET_OBJECT_LINE	= 1,
	SHEET_OBJECT_ARROW	= 2,
	SHEET_OBJECT_BOX	= 101,
	SHEET_OBJECT_OVAL	= 102,
35 36 37 38 39
} SheetObjectGraphicType;

#define SHEET_OBJECT_GRAPHIC_CLASS(k) (GTK_CHECK_CLASS_CAST ((k), SHEET_OBJECT_GRAPHIC_TYPE))

typedef struct {
40 41 42
	SheetObject  parent_object;
	GdkColor    *fill_color;
	double       width;
43
	double       a, b, c;
44 45 46 47 48 49
	SheetObjectGraphicType type;
} SheetObjectGraphic;
typedef struct {
	SheetObjectClass parent_class;
} SheetObjectGraphicClass;
static SheetObjectClass *sheet_object_graphic_parent_class;
50 51

static void
52 53
sheet_object_graphic_fill_color_set (SheetObjectGraphic *sog,
				     GdkColor *color)
54
{
55 56
	SheetObject *so = SHEET_OBJECT (sog);
	GList *l;
57

58
	sog->fill_color = color;
59 60

	for (l = so->realized_list; l; l = l->next)
61
		gnome_canvas_item_set (l->data, "fill_color_gdk", color, NULL);
62 63
}

64
static void
65
sheet_object_graphic_width_set (SheetObjectGraphic *sog, double width)
66
{
67 68
	SheetObject *so = SHEET_OBJECT (sog);
	GList *l;
69

70 71
	sog->width = width;
	for (l = so->realized_list; l; l = l->next)
72 73
		gnome_canvas_item_set (l->data, "width_units", width,
				       NULL);
74
}
75

76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
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);
}

92
SheetObject *
93
sheet_object_line_new (gboolean is_arrow)
94 95
{
	SheetObjectGraphic *sog;
96

97 98
	sog = gtk_type_new (SHEET_OBJECT_GRAPHIC_TYPE);
	sog->type = is_arrow ? SHEET_OBJECT_ARROW : SHEET_OBJECT_LINE;
99

100 101
	return SHEET_OBJECT (sog);
}
102

103 104 105
static void
sheet_object_graphic_destroy (GtkObject *object)
{
106 107 108
	SheetObjectGraphic *sog;
	
	sog = SHEET_OBJECT_GRAPHIC (object);
109

110
	GTK_OBJECT_CLASS (sheet_object_graphic_parent_class)->destroy (object);
111 112
}

113 114
static GtkObject *
sheet_object_graphic_new_view (SheetObject *so, SheetControlGUI *scg)
115
{
116
	/* FIXME : this is bogus */
117
	GnumericCanvas *gcanvas = scg_pane (scg, 0);
118 119
	SheetObjectGraphic *sog = SHEET_OBJECT_GRAPHIC (so);
	GnomeCanvasItem *item = NULL;
120

121 122
	g_return_val_if_fail (IS_SHEET_OBJECT (so), NULL);
	g_return_val_if_fail (IS_SHEET_CONTROL_GUI (scg), NULL);
123

Michael Meeks's avatar
Michael Meeks committed
124
	switch (sog->type) {
125 126
	case SHEET_OBJECT_LINE:
		item = gnome_canvas_item_new (
127
			gcanvas->object_group,
128
			gnome_canvas_line_get_type (),
129 130
			"fill_color_gdk", sog->fill_color,
			"width_units", sog->width,
131 132 133 134 135
			NULL);
		break;

	case SHEET_OBJECT_ARROW:
		item = gnome_canvas_item_new (
136
			gcanvas->object_group,
137
			gnome_canvas_line_get_type (),
138 139
			"fill_color_gdk", sog->fill_color,
			"width_units", sog->width,
140 141 142
			"arrow_shape_a", sog->a,
			"arrow_shape_b", sog->b,
			"arrow_shape_c", sog->c,
143 144 145 146 147 148 149 150
			"last_arrowhead", TRUE,
			NULL);
		break;

	default:
		g_assert_not_reached ();
	}

151 152
	scg_object_register (so, item);
	return GTK_OBJECT (item);
153 154
}

155
static void
156 157
sheet_object_graphic_update_bounds (SheetObject *so, GtkObject *view,
				    SheetControlGUI *scg)
158
{
159
	GnomeCanvasPoints *points = gnome_canvas_points_new (2);
160

161 162 163 164 165 166
	scg_object_view_position (scg, so, points->coords);
	gnome_canvas_item_set (GNOME_CANVAS_ITEM (view),
			       "points", points,
			       NULL);
	gnome_canvas_points_free (points);
}
167

168
static gboolean
169 170
sheet_object_graphic_read_xml (SheetObject *so,
			       XmlParseContext const *ctxt, xmlNodePtr tree)
171
{
172
	SheetObjectGraphic *sog;
173
	double width, a, b, c;
174 175 176 177 178 179
	int tmp = 0;
	GdkColor *color = NULL;

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

180
	color = xml_node_get_gdkcolor (tree, "FillColor");
181
	sheet_object_graphic_fill_color_set (sog, color);
182

183
	if (xml_node_get_int (tree, "Type", &tmp))
184
		sog->type = tmp;
185

186
	xml_node_get_double (tree, "Width", &width);
187
	sheet_object_graphic_width_set (sog, width);
188

189 190 191
	if (xml_node_get_double (tree, "ArrowShapeA", &a) &&
	    xml_node_get_double (tree, "ArrowShapeB", &b) &&
	    xml_node_get_double (tree, "ArrowShapeC", &c))
192 193
		sheet_object_graphic_abc_set (sog, a, b, c);

194 195 196 197 198 199 200
	return FALSE;
}

static gboolean
sheet_object_graphic_write_xml (SheetObject const *so,
				XmlParseContext const *ctxt, xmlNodePtr tree)
{
201 202 203 204
	SheetObjectGraphic *sog;
	
	g_return_val_if_fail (IS_SHEET_OBJECT_GRAPHIC (so), TRUE);
	sog = SHEET_OBJECT_GRAPHIC (so);
205

206 207 208
	xml_node_set_gdkcolor (tree, "FillColor", sog->fill_color);
	xml_node_set_int (tree, "Type", sog->type);
	xml_node_set_double (tree, "Width", sog->width, -1);
209

210
	if (sog->type == SHEET_OBJECT_ARROW) {
211 212 213
		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);
214 215
	}

216
	return FALSE;
217 218
}

Chema Celorio's avatar
Chema Celorio committed
219 220 221
static SheetObject *
sheet_object_graphic_clone (SheetObject const *so, Sheet *sheet)
{
222
	SheetObjectGraphic *sog;
Chema Celorio's avatar
Chema Celorio committed
223 224
	SheetObjectGraphic *new_sog;

225 226 227
	g_return_val_if_fail (IS_SHEET_OBJECT_GRAPHIC (so), NULL);
	sog = SHEET_OBJECT_GRAPHIC (so);

Chema Celorio's avatar
Chema Celorio committed
228 229 230 231
	new_sog = SHEET_OBJECT_GRAPHIC (gtk_type_new (GTK_OBJECT_TYPE (sog)));

	new_sog->type  = sog->type;
	new_sog->width = sog->width;
232
	new_sog->fill_color = sog->fill_color;
233 234 235
	new_sog->a = sog->a;
	new_sog->b = sog->b;
	new_sog->c = sog->c;
Chema Celorio's avatar
Chema Celorio committed
236 237 238 239

	return SHEET_OBJECT (new_sog);
}

240
static void
241 242
sheet_object_graphic_print (SheetObject const *so, GnomePrintContext *ctx,
			    double base_x, double base_y)
243
{
244
	SheetObjectGraphic *sog;
245
	double coords [4];
246 247 248
	double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;

	g_return_if_fail (IS_SHEET_OBJECT_GRAPHIC (so));
249
	g_return_if_fail (GNOME_IS_PRINT_CONTEXT (ctx));
250
	sog = SHEET_OBJECT_GRAPHIC (so);
251

252
	sheet_object_position_pts_get (so, coords);
253 254 255

	gnome_print_gsave (ctx);

256
	if (sog->fill_color) {
257
		switch (so->anchor.direction) {
258 259
		case SO_DIR_UP_RIGHT:
		case SO_DIR_DOWN_RIGHT:
260 261
			x1 = base_x;
			x2 = base_x + (coords [2] - coords [0]);
262 263 264
			break;
		case SO_DIR_UP_LEFT:
		case SO_DIR_DOWN_LEFT:
265 266
			x1 = base_x + (coords [2] - coords [0]);
			x2 = base_x;
267 268 269 270 271 272 273
			break;
		default:
			g_warning ("Cannot guess direction!");
			gnome_print_grestore (ctx);
			return;
		}

274
		switch (so->anchor.direction) {
275 276
		case SO_DIR_UP_LEFT:
		case SO_DIR_UP_RIGHT:
277 278
			y1 = base_y;
			y2 = base_y + (coords [3] - coords [1]);
279 280 281
			break;
		case SO_DIR_DOWN_LEFT:
		case SO_DIR_DOWN_RIGHT:
282 283
			y1 = base_y + (coords [3] - coords [1]);
			y2 = base_y;
284 285 286 287 288 289 290
			break;
		default:
			g_warning ("Cannot guess direction!");
			gnome_print_grestore (ctx);
			return;
		}

291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
		gnome_print_setrgbcolor (ctx,
					 (double) sog->fill_color->red,
					 (double) sog->fill_color->green,
					 (double) sog->fill_color->blue);

		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);
			gnome_print_moveto (ctx, 0.0, 0.0); 
			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);
		}

322 323 324 325 326 327
		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);
	}
328

329
	gnome_print_grestore (ctx);
330 331
}

332 333 334
typedef struct
{
	SheetObjectGraphic *sog;
335 336
	GtkWidget *canvas;
	GnomeCanvasItem *arrow;
337
	GtkWidget *fill_color_combo;
338
	GtkObject *adj_width;
339
	GtkObject *adj_a, *adj_b, *adj_c; /* Only for arrows */
340 341
	GdkColor *fill_color;
	double width;
342
	double a, b, c;                   /* Only for arrows */
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
} 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)
{
	GdkColor *color;

	switch (button) {
	case 0: /* Ok */
	case 1: /* Apply */
		color = color_combo_get_color (
				COLOR_COMBO (data->fill_color_combo));
		sheet_object_graphic_fill_color_set (data->sog, color);
		sheet_object_graphic_width_set (data->sog,
366
				GTK_ADJUSTMENT (data->adj_width)->value);
367 368
		if (data->sog->type == SHEET_OBJECT_ARROW)
			sheet_object_graphic_abc_set (data->sog, 
369 370 371
				GTK_ADJUSTMENT (data->adj_a)->value,
				GTK_ADJUSTMENT (data->adj_b)->value,
				GTK_ADJUSTMENT (data->adj_c)->value);
372 373 374 375 376 377 378
		if (button == 0)
			gnome_dialog_close (dialog);
		break;
	case 2: /* Cancel */
		sheet_object_graphic_fill_color_set (data->sog,
						     data->fill_color);
		sheet_object_graphic_width_set (data->sog, data->width);
379 380 381
		if (data->sog->type == SHEET_OBJECT_ARROW)
			sheet_object_graphic_abc_set (data->sog, data->a,
						      data->b, data->c);
382 383 384 385 386 387 388 389
		gnome_dialog_close (dialog);
		break;
	default:
		g_warning ("Unhandled button %i.", button);
		break;
	}
}

390 391 392 393 394 395 396 397 398 399 400
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);
}

401 402 403 404 405 406 407
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);
}

408 409 410
static void
sheet_object_graphic_user_config (SheetObject *so, SheetControlGUI *scg)
{
411 412 413
	GtkWidget *dialog, *table, *label, *spin, *spin_a, *spin_b, *spin_c; 
	GtkTooltips *tooltips;
	WorkbookControlGUI *wbcg;
414 415
	SheetObjectGraphic *sog;
	DialogGraphicData *data;
416
	GnomeCanvasPoints *points;
417 418 419 420 421

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

	sog = SHEET_OBJECT_GRAPHIC (so);
422
	wbcg = scg_get_wbcg (scg);
423 424 425 426 427 428

	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);
429 430 431
	gnome_dialog_set_parent (GNOME_DIALOG (dialog),
				 wb_control_gui_toplevel (wbcg));
	tooltips = gtk_tooltips_new ();
432

433
	table = gtk_table_new (3, 5, FALSE);
434 435 436 437
	gtk_table_set_col_spacings (GTK_TABLE (table), 10);
	gtk_table_set_row_spacings (GTK_TABLE (table), 10);
	gtk_widget_show (table);
	gtk_container_add (GTK_CONTAINER (GNOME_DIALOG (dialog)->vbox), table);
438

439 440 441 442 443
	label = gtk_label_new (_("Color"));
	gtk_widget_show (label);
	gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 0, 1);
	label = gtk_label_new (_("Border width"));
	gtk_widget_show (label);
444
	gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 1, 2);
445 446 447 448 449 450 451 452 453 454 455 456

	if (sog->type == SHEET_OBJECT_ARROW) {
		label = gtk_label_new (_("Arrow shape a"));
		gtk_widget_show (label);
		gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 2,3);
		label = gtk_label_new (_("Arrow shape b"));
		gtk_widget_show (label);
		gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 3,4);
		label = gtk_label_new (_("Arrow shape c"));
		gtk_widget_show (label);
		gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 4,5);
	}
457

458 459 460
	data = g_new0 (DialogGraphicData, 1);
	data->sog = sog;

461 462 463 464 465 466
	if (sog->type == SHEET_OBJECT_ARROW) {
		data->canvas = gnome_canvas_new ();
		gtk_widget_show (data->canvas);
		gtk_table_attach_defaults (GTK_TABLE (table), data->canvas,
					   2, 3, 2, 5);
	}
467

468 469 470 471 472 473
	data->fill_color_combo = color_combo_new (NULL, _("Transparent"), NULL,
					color_group_fetch ("color", so));
	color_combo_set_color (COLOR_COMBO (data->fill_color_combo), 
			       sog->fill_color);
	data->fill_color = sog->fill_color;
	
474 475 476 477 478
	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;

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
	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_widget_show (spin_a);
		gtk_widget_show (spin_b);
		gtk_widget_show (spin_c);
		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);
	}
504

505
	gtk_widget_show (data->fill_color_combo);
506 507
	gtk_widget_show (spin);

508
	gtk_table_attach_defaults (GTK_TABLE (table),
509 510
				   data->fill_color_combo, 1, 3, 0, 1);
	gtk_table_attach_defaults (GTK_TABLE (table), spin, 1, 3, 1, 2);
511

512 513
	gtk_widget_show (dialog);

514 515 516 517 518 519 520 521 522 523 524 525 526 527
	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)),
				GNOME_TYPE_CANVAS_LINE, "points", points, 
				"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,
528
					data->canvas->allocation.height);
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
		cb_adjustment_value_changed (NULL, data);

		gtk_signal_connect (GTK_OBJECT (data->adj_width),
				"value_changed",
				GTK_SIGNAL_FUNC (cb_adjustment_value_changed),
				data);
		gtk_signal_connect (GTK_OBJECT (data->adj_a), "value_changed",
				GTK_SIGNAL_FUNC (cb_adjustment_value_changed),
				data);
		gtk_signal_connect (GTK_OBJECT (data->adj_b), "value_changed",
				GTK_SIGNAL_FUNC (cb_adjustment_value_changed),
				data);
		gtk_signal_connect (GTK_OBJECT (data->adj_c), "value_changed",
				GTK_SIGNAL_FUNC (cb_adjustment_value_changed),
				data);
		gtk_signal_connect (GTK_OBJECT (data->fill_color_combo),
				"changed", 
				GTK_SIGNAL_FUNC (cb_fill_color_changed), data);
	}

549 550 551 552 553 554
	gtk_signal_connect (GTK_OBJECT (dialog), "clicked",
			    GTK_SIGNAL_FUNC (cb_dialog_graphic_clicked), data);
	gtk_signal_connect (GTK_OBJECT (dialog), "close",
			    GTK_SIGNAL_FUNC (cb_dialog_graphic_close), data);
}

555 556 557
static void
sheet_object_graphic_class_init (GtkObjectClass *object_class)
{
558
	SheetObjectClass *sheet_object_class;
559

560
	sheet_object_graphic_parent_class = gtk_type_class (SHEET_OBJECT_TYPE);
561

562
	/* Object class method overrides */
563
	object_class->destroy = sheet_object_graphic_destroy;
564 565

	/* SheetObject class method overrides */
566
	sheet_object_class = SHEET_OBJECT_CLASS (object_class);
567 568 569
	sheet_object_class->update_bounds = sheet_object_graphic_update_bounds;
	sheet_object_class->new_view	  = sheet_object_graphic_new_view;
	sheet_object_class->read_xml	  = sheet_object_graphic_read_xml;
Chema Celorio's avatar
Chema Celorio committed
570
	sheet_object_class->write_xml	  = sheet_object_graphic_write_xml;
571
	sheet_object_class->print         = sheet_object_graphic_print;
Chema Celorio's avatar
Chema Celorio committed
572
	sheet_object_class->clone         = sheet_object_graphic_clone;
573
	sheet_object_class->user_config   = sheet_object_graphic_user_config;
574
	sheet_object_class->rubber_band_directly = TRUE;
575 576
}

577 578 579
static void
sheet_object_graphic_init (GtkObject *obj)
{
580 581
	SheetObjectGraphic *sog;
	SheetObject *so;
582
	
583
	sog = SHEET_OBJECT_GRAPHIC (obj);
584 585
	sog->fill_color = g_new (GdkColor, 1);
	e_color_alloc_name ("white", sog->fill_color);
586
	sog->width = 1.0;
587 588 589
	sog->a = 8.0;
	sog->b = 10.0;
	sog->c = 3.0;
590 591

	so = SHEET_OBJECT (obj);
592
	so->anchor.direction = SO_DIR_NONE_MASK;
593 594
}

595 596 597
E_MAKE_TYPE (sheet_object_graphic, "SheetObjectGraphic", SheetObjectGraphic,
	     sheet_object_graphic_class_init, sheet_object_graphic_init,
	     SHEET_OBJECT_TYPE);
598

599
/************************************************************************/
600 601

/*
602
 * SheetObjectFilled
603
 *
604
 * Derivative of SheetObjectGraphic, with filled parameter
605
 */
606
#define IS_SHEET_OBJECT_FILLED_CLASS(k) (GTK_CHECK_CLASS_CAST ((k), SHEET_OBJECT_FILLED_TYPE, SheetObjectFilledClass))
607 608 609 610

typedef struct {
	SheetObjectGraphic parent_object;

611
	GdkColor *outline_color;
612 613 614 615 616 617 618 619 620
} SheetObjectFilled;

typedef struct {
	SheetObjectGraphicClass parent_class;
} SheetObjectFilledClass;

static SheetObjectGraphicClass *sheet_object_filled_parent_class;

static void
621
sheet_object_filled_outline_color_set (SheetObjectFilled *sof, GdkColor *color)
622 623 624 625
{
	SheetObject *so = SHEET_OBJECT (sof);
	GList *l;

626
	sof->outline_color = color;
627
	for (l = so->realized_list; l; l = l->next)
628 629
		gnome_canvas_item_set (l->data, "outline_color_gdk", color,
				       NULL);
630 631
}

632
SheetObject *
633
sheet_object_box_new (gboolean is_oval)
634
{
635
	SheetObjectFilled *sof;
636 637
	SheetObjectGraphic *sog;

638
	sof = gtk_type_new (SHEET_OBJECT_FILLED_TYPE);
639

640 641
	sog = SHEET_OBJECT_GRAPHIC (sof);
	sog->type = is_oval ? SHEET_OBJECT_OVAL : SHEET_OBJECT_BOX;
642

643
	return SHEET_OBJECT (sof);
644 645 646 647 648
}

static void
sheet_object_filled_destroy (GtkObject *object)
{
649 650 651
	SheetObjectFilled *sof;
	
	sof = SHEET_OBJECT_FILLED (object);
652

653 654 655
	GTK_OBJECT_CLASS (sheet_object_filled_parent_class)->destroy (object);
}

656
static void
657 658
sheet_object_filled_update_bounds (SheetObject *so, GtkObject *view,
				   SheetControlGUI *scg)
659
{
660
	double coords [4];
661

662
	scg_object_view_position (scg, so, coords);
663
	
664
	gnome_canvas_item_set (GNOME_CANVAS_ITEM (view),
665 666 667 668
		"x1", MIN (coords [0], coords [2]),
		"x2", MAX (coords [0], coords [2]),
		"y1", MIN (coords [1], coords [3]),
		"y2", MAX (coords [1], coords [3]),
669
		NULL);
670 671
}

672 673
static GtkObject *
sheet_object_filled_new_view (SheetObject *so, SheetControlGUI *scg)
674
{
675
	/* FIXME : this is bogus */
676
	GnumericCanvas *gcanvas = scg_pane (scg, 0);
677 678 679
	SheetObjectGraphic *sog;
	SheetObjectFilled  *sof;
	GnomeCanvasItem *item;
680

681
	g_return_val_if_fail (IS_SHEET_OBJECT_FILLED (so), NULL);
682
	g_return_val_if_fail (IS_SHEET_CONTROL_GUI (scg), NULL);
683 684
	sof = SHEET_OBJECT_FILLED (so);
	sog = SHEET_OBJECT_GRAPHIC (so);
685

686
	item = gnome_canvas_item_new (
687 688 689 690 691 692 693
		gcanvas->object_group,
		(sog->type == SHEET_OBJECT_OVAL) ?
					gnome_canvas_ellipse_get_type () : 
					gnome_canvas_rect_get_type (),
		"fill_color_gdk", sog->fill_color,
		"outline_color_gdk", sof->outline_color,
		"width_units", sog->width, NULL);
694

695 696 697 698 699
	scg_object_register (so, item);
	return GTK_OBJECT (item);
}

static gboolean
700 701
sheet_object_filled_read_xml (SheetObject *so,
			      XmlParseContext const *ctxt, xmlNodePtr tree)
702
{
703 704
	SheetObjectFilled *sof;
	GdkColor *color = NULL;
705

706 707
	g_return_val_if_fail (IS_SHEET_OBJECT_FILLED (so), TRUE);
	sof = SHEET_OBJECT_FILLED (so);
708

709
	color = xml_node_get_gdkcolor (tree, "OutlineColor");
710
	sheet_object_filled_outline_color_set (sof, color);
711

712 713 714 715 716 717 718
	return sheet_object_graphic_read_xml (so, ctxt, tree);
}

static gboolean
sheet_object_filled_write_xml (SheetObject const *so, 
			       XmlParseContext const *ctxt, xmlNodePtr tree)
{
719 720 721 722 723
	SheetObjectFilled *sof;
	
	g_return_val_if_fail (IS_SHEET_OBJECT_FILLED (so), TRUE);
	sof = SHEET_OBJECT_FILLED (so);

724
	xml_node_set_gdkcolor (tree, "OutlineColor", sof->outline_color);
725 726

	return sheet_object_graphic_write_xml (so, ctxt, tree);
727 728
}

Chema Celorio's avatar
Chema Celorio committed
729 730 731
static SheetObject *
sheet_object_filled_clone (SheetObject const *so, Sheet *sheet)
{
732
	SheetObjectFilled *sof;
Chema Celorio's avatar
Chema Celorio committed
733 734 735
	SheetObjectFilled *new_sof;
	SheetObject *new_so;

736 737 738
	g_return_val_if_fail (IS_SHEET_OBJECT_FILLED (so), NULL);
	sof = SHEET_OBJECT_FILLED (so);

Chema Celorio's avatar
Chema Celorio committed
739 740 741
	new_so = sheet_object_graphic_clone (so, sheet);
	new_sof = SHEET_OBJECT_FILLED (new_so);

742
	new_sof->outline_color = sof->outline_color;
Chema Celorio's avatar
Chema Celorio committed
743 744 745 746

	return SHEET_OBJECT (new_sof);
}

747 748 749 750 751
typedef struct 
{
	SheetObjectFilled *sof;
	GtkWidget *fill_color_combo;
	GtkWidget *outline_color_combo;
752
	GtkObject *adj_width;
753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782
	GdkColor *outline_color;
	GdkColor *fill_color;
	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);
	GdkColor *color;

	switch (button) {
	case 0: /* Ok */
	case 1: /* Apply */
		color = color_combo_get_color (
				COLOR_COMBO (data->outline_color_combo));
		sheet_object_filled_outline_color_set (data->sof, color);
		color = color_combo_get_color (
				COLOR_COMBO (data->fill_color_combo));
		sheet_object_graphic_fill_color_set (sog, color);
		sheet_object_graphic_width_set (sog, 
783
				GTK_ADJUSTMENT (data->adj_width)->value);
784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802
		if (button == 0)
			gnome_dialog_close (dialog);
		break;
	case 2: /* Cancel */
		sheet_object_graphic_fill_color_set (sog, data->fill_color);
		sheet_object_graphic_width_set (sog, data->width);
		sheet_object_filled_outline_color_set (data->sof, 
						       data->outline_color);
		gnome_dialog_close (dialog);
		break;
	default:
		g_warning ("Unhandled button %i.", button);
		break;
	}
}

static void
sheet_object_filled_user_config (SheetObject *so, SheetControlGUI *scg)
{
803
	WorkbookControlGUI *wbcg;
804 805 806 807 808 809 810 811 812 813
	GtkWidget *dialog, *table, *label, *spin; 
	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);
814
	wbcg = scg_get_wbcg (scg);
815 816 817 818 819 820

	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);
821 822
	gnome_dialog_set_parent (GNOME_DIALOG (dialog),
				 wb_control_gui_toplevel (wbcg));
823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853

	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_widget_show (table);
	gtk_container_add (GTK_CONTAINER (GNOME_DIALOG (dialog)->vbox), table);
	label = gtk_label_new (_("Outline color"));
	gtk_widget_show (label);
	gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 0, 1);
	label = gtk_label_new (_("Fill color"));
	gtk_widget_show (label);
	gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 1, 2);
	label = gtk_label_new (_("Border width"));
	gtk_widget_show (label);
	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),
			       sof->outline_color);
	data->outline_color = sof->outline_color;

	data->fill_color_combo = color_combo_new (NULL, _("Transparent"),
				NULL, color_group_fetch ("fill_color", so));
	color_combo_set_color (COLOR_COMBO (data->fill_color_combo), 
			       sog->fill_color);
	data->fill_color = sog->fill_color;
	
854 855 856
	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);
857 858 859 860 861 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 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 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
	data->width = sog->width;

	gtk_widget_show (data->fill_color_combo);
	gtk_widget_show (data->outline_color_combo);
	gtk_widget_show (spin);

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

	gtk_signal_connect (GTK_OBJECT (dialog), "clicked",
			    GTK_SIGNAL_FUNC (cb_dialog_filled_clicked), data);
	gtk_signal_connect (GTK_OBJECT (dialog), "close",
			    GTK_SIGNAL_FUNC (cb_dialog_filled_close), data);

	gtk_widget_show (dialog);
}

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

/*
 * The following lines are copy and paste from dia. The ellipse logic has been 
 * 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,
			     x1,             center_y); 
}

static void
959 960
sheet_object_filled_print (SheetObject const *so, GnomePrintContext *ctx,
			   double base_x, double base_y)
961 962 963 964
{
	SheetObjectFilled *sof;
	SheetObjectGraphic *sog;
	double coords [4];
965 966
	double start_x, start_y;
	double end_x, end_y;
967 968

	g_return_if_fail (IS_SHEET_OBJECT_FILLED (so));
969
	g_return_if_fail (GNOME_IS_PRINT_CONTEXT (ctx));
970 971 972
	sof = SHEET_OBJECT_FILLED (so);
	sog = SHEET_OBJECT_GRAPHIC (so);

973
	sheet_object_position_pts_get (so, coords);
974

975 976 977 978
	start_x = base_x;
	start_y = base_y;
	end_x = start_x + (coords [2] - coords [0]);
	end_y = start_y + (coords [3] - coords [1]);
979 980 981 982 983 984 985 986 987 988 989

	gnome_print_gsave (ctx);

	if (sof->outline_color) {
		gnome_print_setlinewidth (ctx, sog->width);
		gnome_print_setrgbcolor (ctx,
					 (double) sof->outline_color->red,
					 (double) sof->outline_color->green,
					 (double) sof->outline_color->blue); 
		gnome_print_newpath (ctx);
		if (sog->type == SHEET_OBJECT_OVAL)
990
			make_ellipse (ctx, start_x, end_x, start_y, end_y);
991
		else
992
			make_rect (ctx, start_x, end_x, start_y, end_y);
993 994 995 996 997 998 999 1000 1001 1002 1003
		gnome_print_closepath (ctx);
		gnome_print_stroke (ctx);
	}

	if (sog->fill_color) {
		gnome_print_setrgbcolor (ctx,
					 (double) sog->fill_color->red,
					 (double) sog->fill_color->green,
					 (double) sog->fill_color->blue);
		gnome_print_newpath (ctx);
		if (sog->type == SHEET_OBJECT_OVAL)
1004
			make_ellipse (ctx, start_x, end_x, start_y, end_y);
1005
		else
1006
			make_rect (ctx, start_x, end_x, start_y, end_y);
1007 1008 1009 1010 1011 1012
		gnome_print_fill (ctx);
	}

	gnome_print_grestore (ctx);
}

1013 1014 1015
static void
sheet_object_filled_class_init (GtkObjectClass *object_class)
{
1016 1017 1018
	SheetObjectClass *sheet_object_class;

	sheet_object_filled_parent_class = gtk_type_class (SHEET_OBJECT_GRAPHIC_TYPE);
1019

1020
	object_class->destroy		  = sheet_object_filled_destroy;
1021 1022

	sheet_object_class = SHEET_OBJECT_CLASS (object_class);
1023
	sheet_object_class->new_view	  = sheet_object_filled_new_view;
1024
	sheet_object_class->update_bounds = sheet_object_filled_update_bounds;
1025
	sheet_object_class->read_xml	  = sheet_object_filled_read_xml;
1026
	sheet_object_class->write_xml	  = sheet_object_filled_write_xml;
Chema Celorio's avatar
Chema Celorio committed
1027
	sheet_object_class->clone         = sheet_object_filled_clone;
1028 1029
	sheet_object_class->user_config   = sheet_object_filled_user_config;
	sheet_object_class->print         = sheet_object_filled_print;
1030
	sheet_object_class->rubber_band_directly = TRUE;
1031 1032
}

1033 1034 1035
static void
sheet_object_filled_init (GtkObject *obj)
{
1036 1037 1038 1039 1040
	SheetObjectFilled *sof;
	
	sof = SHEET_OBJECT_FILLED (obj);
	sof->outline_color = g_new0 (GdkColor, 1);
	e_color_alloc_gdk (sof->outline_color);
1041
}
1042

1043 1044 1045
E_MAKE_TYPE (sheet_object_filled, "SheetObjectFilled", SheetObjectFilled,
	     sheet_object_filled_class_init, sheet_object_filled_init,
	     SHEET_OBJECT_GRAPHIC_TYPE);