Create tool-tip with depth/pressure for the whole profile area

Linus Torvalds torvalds at linux-foundation.org
Sun Nov 11 04:20:32 PST 2012


This extends on our current tooltip logic (which shows events when you 
mouse over them) to show tooltips for the whole profile area. 

If you mouse over an event, that is still shown in the tooltip, but 
even in the absense of events, the tooltip will be active, and mousing 
over the profile area will show the time, depth and pressure.

This can certainly be improved upon further, but even in this form it is 
useful.

Signed-off-by: Linus Torvalds <torvalds at linux-foundation.org>
---
 display.h |  6 +++++-
 gtk-gui.c | 48 +++++++++++++++++++++++++++++++++++-------------
 print.c   |  6 +++---
 profile.c | 43 +++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 84 insertions(+), 19 deletions(-)

diff --git a/display.h b/display.h
index 880a8b7be8fa..6eea822aa0b9 100644
--- a/display.h
+++ b/display.h
@@ -21,16 +21,20 @@ extern void do_print(void);
 struct graphics_context {
 	int printer;
 	cairo_t *cr;
+	cairo_rectangle_t drawing_area;
 	double maxx, maxy;
 	double leftx, rightx;
 	double topy, bottomy;
+	unsigned int maxtime;
+	void *plot_info;
 };
 
 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 plot(struct graphics_context *gc, 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);
+extern void get_plot_details(struct graphics_context *gc, int time, char *buf, size_t bufsize);
 
 struct options {
 	enum { PRETTY, TABLE, ONEPERPAGE } type;
diff --git a/gtk-gui.c b/gtk-gui.c
index 38b285fbaaea..03636790c950 100644
--- a/gtk-gui.c
+++ b/gtk-gui.c
@@ -1296,21 +1296,44 @@ void attach_tooltip(int x, int y, int w, int h, const char *text)
 				(_r.y <= _y) && (_r.y + _r.height >= _y))
 
 static gboolean profile_tooltip (GtkWidget *widget, gint x, gint y,
-			gboolean keyboard_mode, GtkTooltip *tooltip, gpointer user_data)
+			gboolean keyboard_mode, GtkTooltip *tooltip, struct graphics_context *gc)
 {
 	int i;
-	cairo_rectangle_t *drawing_area = user_data;
+	cairo_rectangle_t *drawing_area = &gc->drawing_area;
 	gint tx = x - drawing_area->x; /* get transformed coordinates */
 	gint ty = y - drawing_area->y;
+	gint width, height, time = -1;
+	char buffer[80], plot[80];
+	const char *event = "";
+
+	if (tx < 0 || ty < 0)
+		return FALSE;
+
+	width = drawing_area->width - 2*drawing_area->x;
+	height = drawing_area->height - 2*drawing_area->y;
+	if (width <= 0 || height <= 0)
+		return FALSE;
+
+	if (tx > width || ty > height)
+		return FALSE;
+
+	time = (tx * gc->maxtime) / width;
 
 	/* are we over an event marker ? */
 	for (i = 0; i < tooltips; i++) {
 		if (INSIDE_RECT(tooltip_rects[i].rect, tx, ty)) {
-			gtk_tooltip_set_text(tooltip,tooltip_rects[i].text);
-			return TRUE; /* show tooltip */
+			event = tooltip_rects[i].text;
+			break;
 		}
 	}
-	return FALSE; /* don't show tooltip */
+	get_plot_details(gc, time, plot, sizeof(plot));
+
+	snprintf(buffer, sizeof(buffer), " %d:%02d%c%s%c%s", time / 60, time % 60,
+		*plot ? '\n' : ' ', plot,
+		*event ? '\n' : ' ', event);
+	gtk_tooltip_set_text(tooltip, buffer);
+	return TRUE;
+
 }
 
 static int zoom_x = -1, zoom_y = -1;
@@ -1318,19 +1341,18 @@ static int zoom_x = -1, zoom_y = -1;
 static gboolean expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
 {
 	struct dive *dive = current_dive;
-	struct graphics_context gc = { .printer = 0 };
-	static cairo_rectangle_t drawing_area;
+	static struct graphics_context gc = { .printer = 0 };
 
 	/* 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 */
-	drawing_area.width = widget->allocation.width;
-	drawing_area.height = widget->allocation.height;
-	drawing_area.x = MIN(50,drawing_area.width / 20.0);
-	drawing_area.y = MIN(50,drawing_area.height / 20.0);
+	gc.drawing_area.width = widget->allocation.width;
+	gc.drawing_area.height = widget->allocation.height;
+	gc.drawing_area.x = MIN(50,gc.drawing_area.width / 20.0);
+	gc.drawing_area.y = MIN(50,gc.drawing_area.height / 20.0);
 
 	gc.cr = gdk_cairo_create(widget->window);
 	g_object_set(widget, "has-tooltip", TRUE, NULL);
-	g_signal_connect(widget, "query-tooltip", G_CALLBACK(profile_tooltip), &drawing_area);
+	g_signal_connect(widget, "query-tooltip", G_CALLBACK(profile_tooltip), &gc);
 	init_profile_background(&gc);
 	cairo_paint(gc.cr);
 
@@ -1345,7 +1367,7 @@ static gboolean expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer
 			tooltip_rects = NULL;
 		}
 		tooltips = 0;
-		plot(&gc, &drawing_area, dive, SC_SCREEN);
+		plot(&gc, dive, SC_SCREEN);
 	}
 	cairo_destroy(gc.cr);
 
diff --git a/print.c b/print.c
index 62317c15e35d..9ce367508105 100644
--- a/print.c
+++ b/print.c
@@ -300,13 +300,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_t drawing_area = { w/20.0, h/20.0, w, h};
 	struct graphics_context gc = {
 		.printer = 1,
-		.cr = cr
+		.cr = cr,
+		.drawing_area = { w/20.0, h/20.0, w, h},
 	};
 	cairo_save(cr);
-	plot(&gc, &drawing_area, dive, SC_PRINT);
+	plot(&gc, dive, SC_PRINT);
 	cairo_restore(cr);
 }
 
diff --git a/profile.c b/profile.c
index 065934746309..c8ce440d6917 100644
--- a/profile.c
+++ b/profile.c
@@ -900,6 +900,8 @@ static void plot_depth_profile(struct graphics_context *gc, struct plot_info *pi
 	maxtime = get_maxtime(pi);
 	maxdepth = get_maxdepth(pi);
 
+	gc->maxtime = maxtime;
+
 	/* Time markers: at most every 10 seconds, but no more than 12 markers.
 	 * We start out with 10 seconds and increment up to 30 minutes,
 	 * depending on the dive time.
@@ -1908,11 +1910,12 @@ static void plot_set_scale(scale_mode_t scale)
 	}
 }
 
-void plot(struct graphics_context *gc, cairo_rectangle_t *drawing_area, struct dive *dive, scale_mode_t scale)
+void plot(struct graphics_context *gc, struct dive *dive, scale_mode_t scale)
 {
 	struct plot_info *pi;
 	static struct sample fake[4];
 	struct sample *sample = dive->sample;
+	cairo_rectangle_t *drawing_area = &gc->drawing_area;
 	int nr = dive->samples;
 
 	plot_set_scale(scale);
@@ -1994,5 +1997,41 @@ void plot(struct graphics_context *gc, cairo_rectangle_t *drawing_area, struct d
 
 	plot_depth_scale(gc, pi);
 
-	free(pi);
+	if (gc->printer) {
+		free(pi);
+	} else {
+		free(gc->plot_info);
+		gc->plot_info = pi;
+	}
+}
+
+static void plot_string(struct plot_data *entry, char *buf, size_t bufsize)
+{
+	int depth_decimals, pressure;
+	const char *depth_unit, *pressure_unit;
+	double depth;
+
+	depth = get_depth_units(entry->depth, &depth_decimals, &depth_unit);
+	pressure = get_pressure_units(GET_PRESSURE(entry), &pressure_unit);
+
+	snprintf(buf, bufsize, "%.*f %s\n%d %s",
+		depth_decimals, depth, depth_unit,
+		pressure, pressure_unit);
+}
+
+void get_plot_details(struct graphics_context *gc, int time, char *buf, size_t bufsize)
+{
+	struct plot_info *pi = gc->plot_info;
+
+	*buf = 0;
+	if (pi) {
+		int i;
+		for (i = 0; i < pi->nr; i++) {
+			struct plot_data *entry = pi->entry + i;
+			if (entry->sec >= time) {
+				plot_string(entry, buf, bufsize);
+				break;
+			}
+		}
+	}
 }


More information about the subsurface mailing list