[PATCH 1/2] Use GTK_UNIT_INCH when printing to provide consistency across OS

Lubomir I. Ivanov neolit123 at gmail.com
Mon Sep 10 15:30:39 PDT 2012


From: "Lubomir I. Ivanov" <neolit123 at gmail.com>

Tests have shown that the most multi-platform way to do printing with GTK is
to use GTK_UNIT_INCH (or GTK_UNIT_MM) with GtkPrintOperation. Tested on
Linux, OSX, Windows.

However this requires the appropriate scaling for Pango and Cairo to be done,
with separate plotting logic for printing and drawing on the screen. To achieve
that, profile.c:plot() now accepts a scaling parameter from type
"scale_mode_t" defined in "display.h".

Also due to new scale, small decimal numbers (such as 6.12345) cannot be well
stored in "cairo_rectangle_int_t" therefore it is replaced with
"cairo_rectangle_t", which uses doubles to provide Cairo with a drawing
area.

Signed-off-by: Lubomir I. Ivanov <neolit123 at gmail.com>
---
 display.h |  8 +++++++-
 gtk-gui.c |  4 ++--
 print.c   | 17 ++++++++++-------
 profile.c | 38 +++++++++++++++++++++++++++++---------
 4 files changed, 48 insertions(+), 19 deletions(-)

diff --git a/display.h b/display.h
index ef52e99..82d1268 100644
--- a/display.h
+++ b/display.h
@@ -3,6 +3,10 @@
 
 #include <cairo.h>
 
+#define DPI_SCREEN 72.0
+#define SCALE_SCREEN 1.0
+#define SCALE_PRINT (1.0 / DPI_SCREEN)
+
 extern void repaint_dive(void);
 extern void do_print(void);
 
@@ -22,7 +26,9 @@ struct graphics_context {
 	double topy, bottomy;
 };
 
-extern void plot(struct graphics_context *gc, cairo_rectangle_int_t *drawing_area, struct dive *dive);
+typedef enum { SC_SCREEN, SC_PRINT } scale_mode_t;
+
+extern void plot(struct graphics_context *gc, cairo_rectangle_t *drawing_area, struct dive *dive, scale_mode_t scale);
 extern void init_profile_background(struct graphics_context *gc);
 extern void attach_tooltip(int x, int y, int w, int h, const char *text);
 
diff --git a/gtk-gui.c b/gtk-gui.c
index a2f130a..5002b95 100644
--- a/gtk-gui.c
+++ b/gtk-gui.c
@@ -1014,7 +1014,7 @@ static gboolean expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer
 {
 	struct dive *dive = current_dive;
 	struct graphics_context gc = { .printer = 0 };
-	static cairo_rectangle_int_t drawing_area;
+	static cairo_rectangle_t drawing_area;
 
 	/* the drawing area gives TOTAL width * height - x,y is used as the topx/topy offset
 	 * so effective drawing area is width-2x * height-2y */
@@ -1035,7 +1035,7 @@ static gboolean expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer
 			tooltip_rects = NULL;
 		}
 		tooltips = 0;
-		plot(&gc, &drawing_area, dive);
+		plot(&gc, &drawing_area, dive, SC_SCREEN);
 	}
 	cairo_destroy(gc.cr);
 
diff --git a/print.c b/print.c
index b30a8d0..ba3d0bf 100644
--- a/print.c
+++ b/print.c
@@ -34,7 +34,7 @@ static struct dive *get_dive_for_printing(int idx)
 static void set_font(PangoLayout *layout, PangoFontDescription *font,
 	double size, int align)
 {
-	pango_font_description_set_size(font, size * PANGO_SCALE);
+	pango_font_description_set_size(font, size * PANGO_SCALE * SCALE_PRINT);
 	pango_layout_set_font_description(layout, font);
 	pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
 	pango_layout_set_alignment(layout, align);
@@ -149,7 +149,8 @@ static void show_dive_text(struct dive *dive, cairo_t *cr, double w,
 static void show_table_header(cairo_t *cr, double w, double h,
 	PangoFontDescription *font)
 {
-	int maxwidth, maxheight, colwidth, i, curwidth;
+	int i;
+	double maxwidth, maxheight, colwidth, curwidth;
 	PangoLayout *layout;
 	char headers[7][80]= { "Dive#", "Date", "Depth", "Time", "Master",
 		"Buddy", "Location" };
@@ -190,7 +191,8 @@ static void show_dive_table(struct dive *dive, cairo_t *cr, double w,
 {
 	double depth;
 	const char *unit;
-	int len, decimals, maxwidth, maxheight, colwidth, curwidth;
+	int len, decimals;
+	double maxwidth, maxheight, colwidth, curwidth;
 	PangoLayout *layout;
 	struct tm *tm;
 	char buffer[160], divenr[20];
@@ -245,7 +247,7 @@ static void show_dive_table(struct dive *dive, cairo_t *cr, double w,
 	pango_layout_set_justify(layout, 1);
 	pango_cairo_show_layout(cr, layout);
 	curwidth = curwidth + (colwidth / 2);
-	
+
 	// Col 4: Time
 	len = snprintf(buffer, sizeof(buffer),
 		"%d min",(dive->duration.seconds+59) / 60);
@@ -284,13 +286,13 @@ static void show_dive_table(struct dive *dive, cairo_t *cr, double w,
 static void show_dive_profile(struct dive *dive, cairo_t *cr, double w,
 	double h)
 {
-	cairo_rectangle_int_t drawing_area = { w/20.0, h/20.0, w, h};
+	cairo_rectangle_t drawing_area = { w/20.0, h/20.0, w, h};	
 	struct graphics_context gc = {
 		.printer = 1,
 		.cr = cr
 	};
 	cairo_save(cr);
-	plot(&gc, &drawing_area, dive);
+	plot(&gc, &drawing_area, dive, SC_PRINT);
 	cairo_restore(cr);
 }
 
@@ -313,6 +315,7 @@ static void print(int divenr, cairo_t *cr, double x, double y, double w,
 	cairo_scale(cr, 0.5, 0.5);
 
 	/* Dive plot in the upper two thirds - note the scaling */
+	// show_dive_profile(dive, cr, w*2, h*1.33);
 	show_dive_profile(dive, cr, w*2, h*1.33);
 
 	/* Dive information in the lower third */
@@ -533,7 +536,7 @@ void do_print(void)
 
 	repaint_dive();
 	print = gtk_print_operation_new();
-	gtk_print_operation_set_unit(print, GTK_UNIT_POINTS);
+	gtk_print_operation_set_unit(print, GTK_UNIT_INCH);
 	if (settings != NULL)
 		gtk_print_operation_set_print_settings(print, settings);
 	g_signal_connect(print, "create-custom-widget", G_CALLBACK(print_dialog), NULL);
diff --git a/profile.c b/profile.c
index 0039867..debddae 100644
--- a/profile.c
+++ b/profile.c
@@ -16,6 +16,11 @@
 int selected_dive = 0;
 char zoomed_plot = 0;
 
+double plot_scale = SCALE_SCREEN;
+
+#define cairo_set_line_width_scaled(cr, w) \
+	cairo_set_line_width((cr), (w) * plot_scale);
+
 typedef enum { STABLE, SLOW, MODERATE, FAST, CRAZY } velocity_t;
 
 /* Plot info with smoothing, velocity indication
@@ -245,7 +250,7 @@ static void plot_text(struct graphics_context *gc, const text_render_options_t *
 	vsnprintf(buffer, sizeof(buffer), fmt, args);
 	va_end(args);
 
-	cairo_set_font_size(cr, tro->size);
+	cairo_set_font_size(cr, tro->size * plot_scale);
 	cairo_font_extents(cr, &fe);
 	cairo_text_extents(cr, buffer, &extents);
 	dx = tro->hpos * extents.width + extents.x_bearing;
@@ -485,7 +490,7 @@ static void plot_depth_profile(struct graphics_context *gc, struct plot_info *pi
 	gc->leftx = 0; gc->rightx = maxtime;
 	gc->topy = 0; gc->bottomy = 1.0;
 	set_source_rgba(gc, TIME_GRID);
-	cairo_set_line_width(gc->cr, 2);
+	cairo_set_line_width_scaled(gc->cr, 2);
 
 	for (i = incr; i < maxtime; i += incr) {
 		move_to(gc, i, 0);
@@ -542,13 +547,13 @@ static void plot_depth_profile(struct graphics_context *gc, struct plot_info *pi
 	gc->topy = 0; gc->bottomy = maxdepth;
 
 	cairo_pattern_t *pat;
-	pat = cairo_pattern_create_linear (0.0, 0.0,  0.0, 256.0);
+	pat = cairo_pattern_create_linear (0.0, 0.0,  0.0, 256.0 * plot_scale);
 	pattern_add_color_stop_rgba (gc, pat, 1, DEPTH_BOTTOM);
 	pattern_add_color_stop_rgba (gc, pat, 0, DEPTH_TOP);
 
 	cairo_set_source(gc->cr, pat);
 	cairo_pattern_destroy(pat);
-	cairo_set_line_width(gc->cr, 2);
+	cairo_set_line_width_scaled(gc->cr, 2);
 
 	entry = pi->entry;
 	move_to(gc, 0, 0);
@@ -655,7 +660,7 @@ static void plot_temperature_profile(struct graphics_context *gc, struct plot_in
 	if (!setup_temperature_limits(gc, pi))
 		return;
 
-	cairo_set_line_width(gc->cr, 2);
+	cairo_set_line_width_scaled(gc->cr, 2);
 	set_source_rgba(gc, TEMP_PLOT);
 	for (i = 0; i < pi->nr; i++) {
 		struct plot_data *entry = pi->entry + i;
@@ -730,7 +735,7 @@ static void plot_cylinder_pressure(struct graphics_context *gc, struct plot_info
 	if (!get_cylinder_pressure_range(gc, pi))
 		return;
 
-	cairo_set_line_width(gc->cr, 2);
+	cairo_set_line_width_scaled(gc->cr, 2);
 
 	for (i = 0; i < pi->nr; i++) {
 		int mbar;
@@ -1374,13 +1379,28 @@ static struct plot_info *create_plot_info(struct dive *dive, int nr_samples, str
 	return analyze_plot_info(pi);
 }
 
-void plot(struct graphics_context *gc, cairo_rectangle_int_t *drawing_area, struct dive *dive)
+static void plot_set_scale(scale_mode_t scale)
+{
+	switch (scale) {
+	default:
+	case SC_SCREEN:
+		plot_scale = SCALE_SCREEN;
+		break;
+	case SC_PRINT:
+		plot_scale = SCALE_PRINT;
+		break;
+	}
+}
+
+void plot(struct graphics_context *gc, cairo_rectangle_t *drawing_area, struct dive *dive, scale_mode_t scale)
 {
 	struct plot_info *pi;
 	static struct sample fake[4];
 	struct sample *sample = dive->sample;
 	int nr = dive->samples;
 
+	plot_set_scale(scale);
+
 	if (!nr) {
 		/* The dive has no samples, so create a few fake ones.  This assumes an
 		ascent/descent rate of 9 m/min, which is just below the limit for FAST. */
@@ -1401,7 +1421,7 @@ void plot(struct graphics_context *gc, cairo_rectangle_int_t *drawing_area, stru
 	pi = create_plot_info(dive, nr, sample);
 
 	cairo_translate(gc->cr, drawing_area->x, drawing_area->y);
-	cairo_set_line_width(gc->cr, 1);
+	cairo_set_line_width_scaled(gc->cr, 1);
 	cairo_set_line_cap(gc->cr, CAIRO_LINE_CAP_ROUND);
 	cairo_set_line_join(gc->cr, CAIRO_LINE_JOIN_ROUND);
 
@@ -1435,7 +1455,7 @@ void plot(struct graphics_context *gc, cairo_rectangle_int_t *drawing_area, stru
 	gc->topy = 0; gc->bottomy = 1.0;
 
 	set_source_rgba(gc, BOUNDING_BOX);
-	cairo_set_line_width(gc->cr, 1);
+	cairo_set_line_width_scaled(gc->cr, 1);
 	move_to(gc, 0, 0);
 	line_to(gc, 0, 1);
 	line_to(gc, 1, 1);
-- 
1.7.11.msysgit.0



More information about the subsurface mailing list