[goffice] Allow the frame around a chart label to rotate with the text. [647147]



commit dd77e3de884f00951a8fcca60f0c28b144204d19
Author: Jean Brefort <jean brefort normalesup org>
Date:   Sat Aug 6 14:50:52 2011 +0200

    Allow the frame around a chart label to rotate with the text. [647147]

 ChangeLog                       |   15 ++++
 NEWS                            |    1 +
 goffice/graph/gog-label.c       |  177 ++++++++++++++++++++++++++++++++-------
 goffice/graph/gog-label.h       |    2 +
 goffice/graph/gog-renderer.c    |   74 ++++++++++++++++
 goffice/graph/gog-renderer.h    |    1 +
 goffice/utils/go-style-prefs.ui |   13 ++-
 7 files changed, 249 insertions(+), 34 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index ceff0d1..0acd7fb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2011-08-06  Jean Brefort  <jean brefort normalesup org>
+
+	* goffice/graph/gog-label.c (gog_text_set_property),
+	(gog_text_get_property), (gog_text_class_init), (rotate_frame_cb),
+	(rotate_bg_cb), (allow_markup_cb), (gog_label_populate_editor),
+	(gog_label_class_init), (gog_text_view_size_request),
+	(gog_text_view_render): allow rotation of the frame along with the text.
+	[#647147]
+	* goffice/graph/gog-label.h:
+	* goffice/graph/gog-renderer.c (_draw_rotated_shape),
+	(gog_renderer_fill_rectangle), (_draw_rotated_rectangle),
+	(gog_renderer_draw_rotated_rectangle):
+	* goffice/graph/gog-renderer.h:
+	* goffice/utils/go-style-prefs.ui:
+
 2011-08-05  Jean Brefort  <jean brefort normalesup org>
 
 	* goffice/graph/goffice-graph.h: add support for rich text in legends.
diff --git a/NEWS b/NEWS
index bb707eb..b9e0f2a 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,7 @@ Andreas:
 Jean:
 	* Port to gtk+-3.0.
 	* Add a plugin directory for extern plugins, independent from micro version.
+	* Allow the frame around a chart label to rotate with the text. [647147]
 
 Morten:
 	* Recognize scientific formats with longer exponents.
diff --git a/goffice/graph/gog-label.c b/goffice/graph/gog-label.c
index ba85966..07ea47a 100644
--- a/goffice/graph/gog-label.c
+++ b/goffice/graph/gog-label.c
@@ -38,7 +38,9 @@ static GType gog_text_view_get_type (void);
 
 enum {
 	TEXT_PROP_0,
-	TEXT_PROP_ALLOW_MARKUP
+	TEXT_PROP_ALLOW_MARKUP,
+	TEXT_PROP_ROTATE_FRAME,
+	TEXT_PROP_ROTATE_BG
 };
 
 static GObjectClass *text_parent_klass;
@@ -53,6 +55,12 @@ gog_text_set_property (GObject *obj, guint param_id,
 	case TEXT_PROP_ALLOW_MARKUP :
 		text->allow_markup = g_value_get_boolean (value);
 		break;
+	case TEXT_PROP_ROTATE_FRAME:
+		text->rotate_frame = g_value_get_boolean (value);
+		break;
+	case TEXT_PROP_ROTATE_BG:
+		text->rotate_bg = g_value_get_boolean (value);
+		break;
 
 	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
 		 return; /* NOTE : RETURN */
@@ -70,6 +78,12 @@ gog_text_get_property (GObject *obj, guint param_id,
 	case TEXT_PROP_ALLOW_MARKUP :
 		g_value_set_boolean (value, text->allow_markup);
 		break;
+	case TEXT_PROP_ROTATE_FRAME:
+		g_value_set_boolean (value, text->rotate_frame);
+		break;
+	case TEXT_PROP_ROTATE_BG:
+		g_value_set_boolean (value, text->rotate_bg);
+		break;
 
 	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
 		 break;
@@ -115,7 +129,20 @@ gog_text_class_init (GogTextClass *klass)
 		g_param_spec_boolean ("allow-markup",
 			_("Allow markup"),
 			_("Support basic html-ish markup"),
-			TRUE,
+			FALSE,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
+
+	g_object_class_install_property (gobject_klass, TEXT_PROP_ROTATE_FRAME,
+		g_param_spec_boolean ("rotate-frame",
+			_("Rotate the frame with the text"),
+			_("Whether the frame should be rotated with the text"),
+			FALSE,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
+	g_object_class_install_property (gobject_klass, TEXT_PROP_ROTATE_BG,
+		g_param_spec_boolean ("rotate-bg",
+			_("Rotate the background with the text"),
+			_("Whether the background should be rotated with the text"),
+			FALSE,
 			GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
 
 	gog_klass->view_type		= gog_text_view_get_type ();
@@ -169,12 +196,35 @@ struct _GogLabel {
 
 	GogDatasetElement text;
 };
+enum {
+	LABEL_PROP_0,
+};
+
 
 typedef GogTextClass GogLabelClass;
 
 static GObjectClass *label_parent_klass;
 
 #ifdef GOFFICE_WITH_GTK
+
+static void
+rotate_frame_cb (GtkToggleButton *btn, GObject *obj)
+{
+	g_object_set (obj, "rotate-frame", gtk_toggle_button_get_active (btn), NULL);
+}
+
+static void
+rotate_bg_cb (GtkToggleButton *btn, GObject *obj)
+{
+	g_object_set (obj, "rotate-bg", gtk_toggle_button_get_active (btn), NULL);
+}
+
+static void
+allow_markup_cb (GtkToggleButton *btn, GObject *obj)
+{
+	g_object_set (obj, "allow-markup", gtk_toggle_button_get_active (btn), NULL);
+}
+
 static void
 gog_label_populate_editor (GogObject *gobj,
 			   GOEditor *editor,
@@ -182,21 +232,39 @@ gog_label_populate_editor (GogObject *gobj,
 			   GOCmdContext *cc)
 {
 	static guint label_pref_page = 0;
-	GtkWidget *hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
-	GtkWidget *alignment = gtk_alignment_new (0, 0, 1, 0);
+	GtkWidget *grid = gtk_grid_new ();
 	GtkWidget *editor_widget =
 		GTK_WIDGET
 		(gog_data_allocator_editor (dalloc, GOG_DATASET (gobj),
 					    0, GOG_DATA_SCALAR));
+	GtkWidget *w;
 
-	gtk_container_set_border_width (GTK_CONTAINER (alignment), 12);
-	gtk_box_pack_start (GTK_BOX (hbox),
-		gtk_label_new_with_mnemonic (_("_Text:")), FALSE, TRUE, 0);
-	gtk_box_pack_start (GTK_BOX (hbox), editor_widget, TRUE, TRUE, 0);
-	gtk_container_add (GTK_CONTAINER (alignment), hbox);
-	gtk_widget_show_all (alignment);
-
-	go_editor_add_page (editor, alignment, _("Data"));
+	g_object_set (G_OBJECT (grid),
+	              "margin", 12,
+	              "row-spacing", 12,
+	              "column-spacing", 6,
+	              NULL);
+	g_object_set (G_OBJECT (editor_widget), "hexpand", TRUE, NULL);
+
+	gtk_grid_attach (GTK_GRID (grid),
+		gtk_label_new_with_mnemonic (_("_Text:")), 0, 0, 1, 1);
+	gtk_grid_attach (GTK_GRID (grid), editor_widget, 1, 0, 1, 1);
+	w = gtk_check_button_new_with_label (_("Rotate frame with text"));
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), GOG_TEXT (gobj)->rotate_frame);
+	g_signal_connect (w, "toggled", G_CALLBACK (rotate_frame_cb), gobj);
+	gtk_grid_attach (GTK_GRID (grid), w, 0, 1, 2, 1);
+	w = gtk_check_button_new_with_label (_("Rotate background with text"));
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), GOG_TEXT (gobj)->rotate_bg);
+	g_signal_connect (w, "toggled", G_CALLBACK (rotate_bg_cb), gobj);
+	gtk_grid_attach (GTK_GRID (grid), w, 0, 2, 2, 1);
+	w = gtk_check_button_new_with_label (_("Interpret text as markup"));
+	gtk_widget_set_tooltip_text (w, _("Interpret the text as an html like markup as described at http://developer.gnome.org/pango/stable/PangoMarkupFormat.html";));
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), GOG_TEXT (gobj)->allow_markup);
+	g_signal_connect (w, "toggled", G_CALLBACK (allow_markup_cb), gobj);
+	gtk_grid_attach (GTK_GRID (grid), w, 0, 3, 2, 1);
+	gtk_widget_show_all (grid);
+
+	go_editor_add_page (editor, grid, _("Details"));
 
 	(GOG_OBJECT_CLASS(label_parent_klass)->populate_editor) (gobj, editor, dalloc, cc);
 	go_editor_set_store_page (editor, &label_pref_page);
@@ -245,11 +313,11 @@ gog_label_class_init (GogLabelClass *klass)
 	GogObjectClass *gog_klass = (GogObjectClass *) klass;
 	gog_klass->populate_editor = gog_label_populate_editor;
 #endif
-
 	label_parent_klass = g_type_class_peek_parent (klass);
-	gobject_klass->finalize	   = gog_label_finalize;
-	got_klass->get_str	   = gog_label_get_str;
-	got_klass->get_markup	   = gog_label_get_markup;
+	gobject_klass->finalize	    = gog_label_finalize;
+
+	got_klass->get_str	    = gog_label_get_str;
+	got_klass->get_markup	    = gog_label_get_markup;
 }
 
 static void
@@ -465,15 +533,34 @@ gog_text_view_size_request (GogView *v,
 {
 	GogText *text = GOG_TEXT (v->model);
 	char *str = gog_text_get_str (text);
+	PangoAttrList *pl = text->allow_markup? NULL: gog_text_get_markup (text);
 	GOGeometryAABR aabr;
 
 	req->w = req->h = 0.;
 	if (str != NULL) {
-		gog_renderer_push_style (v->renderer, text->base.base.style);
-		gog_renderer_get_text_AABR (v->renderer, str, FALSE, &aabr);
+		GOString *gostr = pl? go_string_new_rich (str, -1, FALSE,
+		                                      gog_text_get_markup (text),
+		                                      NULL): NULL;
+		GOStyle *style = go_style_dup (text->base.base.style);
+		double rot = fabs (style->text_layout.angle / 180 * M_PI);
+		if (text->rotate_frame)
+			style->text_layout.angle = 0.;
+		gog_renderer_push_style (v->renderer, style);
+		if (gostr) {
+			gog_renderer_get_gostring_AABR (v->renderer, gostr, &aabr);
+			go_string_unref (gostr);
+		} else
+			gog_renderer_get_text_AABR (v->renderer, str, text->allow_markup, &aabr);
 		gog_renderer_pop_style (v->renderer);
-		req->w = aabr.w;
-		req->h = aabr.h;
+		g_object_unref (style);
+		if (text->rotate_frame) {
+			req->w = aabr.w * cos (rot) + aabr.h * sin (rot);
+			req->h = aabr.w * sin (rot) + aabr.h * cos (rot);
+		} else {
+			req->w = aabr.w;
+			req->h = aabr.h;
+		}
+		go_string_unref (gostr);
 		g_free (str);
 	}
 	text_view_parent_klass->size_request (v, available, req);
@@ -486,28 +573,56 @@ gog_text_view_render (GogView *view, GogViewAllocation const *bbox)
 	GogOutlinedObject *goo = GOG_OUTLINED_OBJECT (text);
 	GOStyle *style = text->base.base.style;
 	char *str = gog_text_get_str (text);
+	PangoAttrList *pl = text->allow_markup? NULL: gog_text_get_markup (text);
 
 	gog_renderer_push_style (view->renderer, style);
 	if (str != NULL) {
-		GOString *gostr = go_string_new_rich (str, -1, FALSE,
-		                                      gog_label_get_markup (text),
-		                                      NULL);
+		GOString *gostr = pl? go_string_new_rich (str, -1, FALSE,
+		                                      gog_text_get_markup (text),
+		                                      NULL): NULL;
 		double outline = gog_renderer_line_size (view->renderer,
 							 goo->base.style->line.width);
 		if (style->fill.type != GO_STYLE_FILL_NONE || outline > 0.) {
 			GogViewAllocation rect;
 			GOGeometryAABR aabr;
+			GOStyle *rect_style = NULL;
 			double pad_x = gog_renderer_pt2r_x (view->renderer, goo->padding_pts);
 			double pad_y = gog_renderer_pt2r_y (view->renderer, goo->padding_pts);
-			gog_renderer_get_gostring_AABR (view->renderer, gostr, &aabr);
-			rect = view->allocation;
-			rect.w = aabr.w + 2. * outline + pad_x;
-			rect.h = aabr.h + 2. * outline + pad_y;
-			gog_renderer_draw_rectangle (view->renderer, &rect);
+			double rot = style->text_layout.angle / 180 * M_PI;
+			if (text->rotate_frame) {
+				rect_style = go_style_dup (text->base.base.style);
+				rect_style->text_layout.angle = 0.;
+				gog_renderer_push_style (view->renderer, rect_style);
+			}
+			if (gostr)
+				gog_renderer_get_gostring_AABR (view->renderer, gostr, &aabr);
+			else
+				gog_renderer_get_text_AABR (view->renderer, str, text->allow_markup, &aabr);
+			if (text->rotate_frame) {
+				rect = view->allocation;
+				rect.w = aabr.w + 2. * outline + pad_x;
+				rect.h = aabr.h + 2. * outline + pad_y;
+				if (rot > 0.)
+					rect.y += rect.w * sin (rot);
+				else
+					rect.x -= rect.h * sin (rot);
+				gog_renderer_pop_style (view->renderer);
+				g_object_unref (rect_style);
+			} else {
+				rect = view->allocation;
+				rect.w = aabr.w + 2. * outline + pad_x;
+				rect.h = aabr.h + 2. * outline + pad_y;
+			}
+			gog_renderer_draw_rotated_rectangle (view->renderer, &rect, text->rotate_bg);
 		}
-		gog_renderer_draw_gostring (view->renderer, gostr,
-		                            &view->residual, GO_ANCHOR_NW);
-		go_string_unref (gostr);
+		if (gostr) {
+			gog_renderer_draw_gostring (view->renderer, gostr,
+		                    		&view->residual, GO_ANCHOR_NW);
+			go_string_unref (gostr);
+		} else
+			gog_renderer_draw_text (view->renderer, str,
+		                    		&view->residual, GO_ANCHOR_NW,
+			                        text->allow_markup);
 		g_free (str);
 	}
 	gog_renderer_pop_style (view->renderer);
diff --git a/goffice/graph/gog-label.h b/goffice/graph/gog-label.h
index 63378b7..813e0f3 100644
--- a/goffice/graph/gog-label.h
+++ b/goffice/graph/gog-label.h
@@ -30,6 +30,8 @@ typedef struct {
 	GogOutlinedObject base;
 
 	gboolean	  allow_markup;
+	gboolean	  rotate_frame;
+	gboolean	  rotate_bg;
 } GogText;
 
 typedef struct {
diff --git a/goffice/graph/gog-renderer.c b/goffice/graph/gog-renderer.c
index c391b1f..7ea33d9 100644
--- a/goffice/graph/gog-renderer.c
+++ b/goffice/graph/gog-renderer.c
@@ -487,6 +487,41 @@ gog_renderer_fill_shape (GogRenderer *renderer, GOPath const *path)
 	_draw_shape (renderer, path, TRUE, FALSE);
 }
 
+static void
+_draw_rotated_shape (GogRenderer *renderer, GOPath const *path, gboolean fill, gboolean stroke, gboolean rotate_bg)
+{
+	GOStyle const *style;
+	GOPathOptions line_options;
+	double width;
+
+	g_return_if_fail (GOG_IS_RENDERER (renderer));
+	g_return_if_fail (renderer->cur_style != NULL);
+	g_return_if_fail (GO_IS_PATH (path));
+
+        style = renderer->cur_style;
+
+	line_options = go_path_get_options (path);
+	width = stroke ? _grc_line_size (renderer, style->line.width,
+					 line_options & GO_PATH_OPTIONS_SNAP_WIDTH) : 0;
+
+	cairo_save (renderer->cairo);
+	cairo_rotate (renderer->cairo, -renderer->cur_style->text_layout.angle *M_PI / 180.);
+	path_interpret (renderer, path, width);
+
+	if (fill) {
+		if (rotate_bg) {
+			emit_fill (renderer, stroke);
+			cairo_restore (renderer->cairo);
+		} else {
+			cairo_restore (renderer->cairo);
+			emit_fill (renderer, stroke);
+		}
+	}
+
+	if (stroke)
+		emit_line (renderer, FALSE, go_path_get_options (path));
+}
+
 /*****************************************************************************/
 
 /**
@@ -661,6 +696,45 @@ gog_renderer_fill_rectangle (GogRenderer *rend, GogViewAllocation const *rect)
 	_draw_rectangle (rend, rect, TRUE, FALSE);
 }
 
+static void
+_draw_rotated_rectangle (GogRenderer *rend, GogViewAllocation const *rect, gboolean fill, gboolean stroke, gboolean rotate_bg)
+{
+	GOStyle const *style;
+	GOPath *path;
+	gboolean narrow = (rect->w < 3.) || (rect->h < 3.);
+	double o, o_2;
+
+	g_return_if_fail (GOG_IS_RENDERER (rend));
+	g_return_if_fail (GO_IS_STYLE (rend->cur_style));
+
+	style = rend->cur_style;
+	narrow |= !go_style_is_outline_visible (style);
+
+	path = go_path_new ();
+	go_path_set_options (path, GO_PATH_OPTIONS_SHARP);
+
+	if (!narrow) {
+		o = gog_renderer_line_size (rend, style->line.width);
+		o_2 = o / 2.;
+	} else
+		o = o_2 = 0.;
+
+	go_path_rectangle (path, 0., 0., rect->w - o, rect->h - o);
+
+	cairo_save (rend->cairo);
+	cairo_translate (rend->cairo, rect->x - o_2, rect->y - o_2);
+	_draw_rotated_shape (rend, path, fill, stroke && !narrow, rotate_bg);
+	cairo_restore (rend->cairo);
+
+	go_path_free (path);
+}
+
+void
+gog_renderer_draw_rotated_rectangle (GogRenderer *rend, GogViewAllocation const *rect, gboolean rotate_bg)
+{
+	_draw_rotated_rectangle (rend, rect, TRUE, TRUE, rotate_bg);
+}
+
 /**
  * gog_renderer_draw_grip:
  * @renderer : #GogRenderer
diff --git a/goffice/graph/gog-renderer.h b/goffice/graph/gog-renderer.h
index 9dfd1e7..2e31e6b 100644
--- a/goffice/graph/gog-renderer.h
+++ b/goffice/graph/gog-renderer.h
@@ -72,6 +72,7 @@ void  gog_renderer_stroke_circle 	(GogRenderer *rend, double x, double y, double
 void  gog_renderer_fill_circle	 	(GogRenderer *rend, double x, double y, double r);
 
 void  gog_renderer_draw_rectangle	(GogRenderer *rend, GogViewAllocation const *rect);
+void  gog_renderer_draw_rotated_rectangle (GogRenderer *rend, GogViewAllocation const *rect, gboolean rotate_bg);
 void  gog_renderer_stroke_rectangle 	(GogRenderer *rend, GogViewAllocation const *rect);
 void  gog_renderer_fill_rectangle 	(GogRenderer *rend, GogViewAllocation const *rect);
 
diff --git a/goffice/utils/go-style-prefs.ui b/goffice/utils/go-style-prefs.ui
index b6e5eae..f8ef3df 100644
--- a/goffice/utils/go-style-prefs.ui
+++ b/goffice/utils/go-style-prefs.ui
@@ -572,6 +572,13 @@
                       <object class="GtkComboBoxText" id="fill-type-menu">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
+                        <items>
+                          <item translatable="yes">None</item>
+                          <item translatable="yes">Pattern</item>
+                          <item translatable="yes">Bicolor gradient</item>
+                          <item translatable="yes">Unicolor gradient</item>
+                          <item translatable="yes">Image</item>
+                        </items>
                       </object>
                       <packing>
                         <property name="expand">False</property>
@@ -918,9 +925,6 @@
                           </packing>
                         </child>
                         <child>
-                          <placeholder/>
-                        </child>
-                        <child>
                           <object class="GtkComboBoxText" id="fill-image-fit">
                             <property name="visible">True</property>
                             <property name="can_focus">False</property>
@@ -935,6 +939,9 @@
                             <property name="right_attach">2</property>
                           </packing>
                         </child>
+                        <child>
+                          <placeholder/>
+                        </child>
                       </object>
                       <packing>
                         <property name="position">2</property>



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]