[PATCH 2/2] Do a minimal hook-up of the dive plan tree view to the actual planning

Linus Torvalds torvalds at linux-foundation.org
Sat Jan 5 13:07:10 PST 2013


From: Linus Torvalds <torvalds at linux-foundation.org>
Date: Sat, 5 Jan 2013 12:56:45 -0800
Subject: [PATCH 2/2] Do a minimal hook-up of the dive plan tree view to the
 actual planning

Yes, you can actually enter your segments now.

No, it's not wonderfully user-friendly.  If you don't enter enough
segments to create a dive plan, it will just silently fail, for example.
And the <tab> key that should get you to the next editable segment
doesn't.  And so on.  But it kind of works.

Signed-off-by: Linus Torvalds <torvalds at linux-foundation.org>
---

I want to repeat: this is *not* pretty. But it kind of works. 

I suspect it's actually easier to edit the source code and recompile 
subsurface to create a plan, but it's only *borderline* easier. I think 
this may actually be a reasonable start to some kind of text-input-based 
GUI. No, it doesn't allow you to drag waypoints around in the profile etc, 
but it *does* allow you to say basically

 - first waypoint at 5 minutes, 150 ft depth, using a 20/30 gasmix

 - second waypoint 5 minutes later, 150 ft, 20/30

 - third waypoint five minutes later, 100 ft, ean40.

And yes, the gas can actually be entered as "20/30" and "ean40". And the 
depth can be entered as "150 ft" or "30 m". The time is entered as 
[h:]mm[:ss], with an optional "+" sign in front to say "from the last 
time.

And none of this is hugely tested, but it does seem to at least kind of 
work. If things like <tab> actually worked while editing the waypoints, it 
would be approaching being user-friendly.

Similarly, it would be great if it remembered the last data and 
pre-populated the planning tree view with it, but it really doesn't.

Comments?

 dive.h    | 16 +++++++++++++
 gtk-gui.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 planner.c | 16 ++-----------
 3 files changed, 91 insertions(+), 22 deletions(-)

diff --git a/dive.h b/dive.h
index d58a0146e64f..d1f091e7af53 100644
--- a/dive.h
+++ b/dive.h
@@ -578,7 +578,23 @@ extern void dump_tissues(void);
 extern unsigned int deco_allowed_depth(double tissues_tolerance, double surface_pressure, struct dive *dive, gboolean smooth);
 extern void set_gf(double gflow, double gfhigh);
 
+struct divedatapoint {
+	int time;
+	int depth;
+	int o2;
+	int he;
+	struct divedatapoint *next;
+};
+
+struct diveplan {
+	timestamp_t when;
+	int surface_pressure;
+	struct divedatapoint *dp;
+};
+
 extern void test_planner(void);
+void plan(struct diveplan *diveplan);
+void plan_add_segment(struct diveplan *diveplan, int duration, int depth, int o2, int he);
 
 #ifdef DEBUGFILE
 extern char *debugfilename;
diff --git a/gtk-gui.c b/gtk-gui.c
index a454b3eaa1c9..fbaccda9367b 100644
--- a/gtk-gui.c
+++ b/gtk-gui.c
@@ -11,6 +11,7 @@
 #include <time.h>
 #include <unistd.h>
 #include <sys/stat.h>
+#include <sys/time.h>
 #include <ctype.h>
 
 #include "dive.h"
@@ -1129,6 +1130,22 @@ static void test_planner_cb(GtkWidget *w, gpointer data)
 	test_planner();
 }
 
+static void check_last_not_empty(GtkTreeModel *model, GtkTreeIter *iter, const char *text)
+{
+	/* We only add a new empty entry if the current one isn't empty.. */
+	while (isspace(*text))
+		text++;
+	if (!*text)
+		return;
+
+	/* Is there a 'next' entry? */
+	if (gtk_tree_model_iter_next(model, iter))
+		return;
+
+	/* Ok, let's add a new empty entry at the end, then.. */
+	gtk_list_store_append(GTK_LIST_STORE(model), iter);
+}
+
 /*
  * Get a value in tenths (so "10.2" == 102, "9" = 90)
  *
@@ -1165,10 +1182,13 @@ static int get_permille(char *begin, char **end)
 	return value;
 }
 
-static int get_gas(char *text, int *o2_p, int *he_p)
+static int validate_gas(char *text, int *o2_p, int *he_p)
 {
 	int o2, he;
 
+	if (!text)
+		return 0;
+
 	while (isspace(*text))
 		text++;
 
@@ -1212,11 +1232,12 @@ static void plan_gas_cb(GtkCellRendererText *cell, gchar *path, gchar *text, gpo
 		return;
 
 	/* Verify that it's an acceptable gas */
-	if (!get_gas(text, &o2, &he))
+	if (!validate_gas(text, &o2, &he))
 		return;
 
 	/* Ok, looks fine, accept the string */
 	gtk_list_store_set(GTK_LIST_STORE(model), &iter, 2, text, -1);
+	check_last_not_empty(model, &iter, text);
 }
 
 static int validate_time(char *text, int *sec_p, int *rel_p)
@@ -1224,6 +1245,9 @@ static int validate_time(char *text, int *sec_p, int *rel_p)
 	int min, sec, rel;
 	char *end;
 
+	if (!text)
+		return 0;
+
 	while (isspace(*text))
 		text++;
 
@@ -1295,12 +1319,16 @@ static void plan_time_cb(GtkCellRendererText *cell, gchar *path, gchar *text, gp
 
 	/* Ok, looks fine, accept the string */
 	gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, text, -1);
+	check_last_not_empty(model, &iter, text);
 }
 
 static int validate_depth(char *text, int *mm_p)
 {
 	int depth, imperial;
 
+	if (!text)
+		return 0;
+
 	depth = get_tenths(text, &text);
 	if (depth < 0)
 		return 0;
@@ -1346,8 +1374,49 @@ static void plan_depth_cb(GtkCellRendererText *cell, gchar *path, gchar *text, g
 
 	/* Ok, looks fine, accept the string */
 	gtk_list_store_set(GTK_LIST_STORE(model), &iter, 1, text, -1);
+	check_last_not_empty(model, &iter, text);
 }
 
+static void run_diveplan(GtkListStore *store)
+{
+	GtkTreeModel *model = GTK_TREE_MODEL(store);
+	struct diveplan diveplan = {};
+	struct timeval tv;
+	GtkTreeIter iter;
+	int ok;
+	int lasttime = 0;
+
+	gettimeofday(&tv, NULL);
+	diveplan.when = tv.tv_sec;
+	diveplan.surface_pressure = 1013;
+
+	ok = gtk_tree_model_get_iter_first(model, &iter);
+	while (ok) {
+		gchar *time, *depth, *gas;
+		int sec, rel, mm, o2, he;
+
+		gtk_tree_model_get(model, &iter,
+			0, &time,
+			1, &depth,
+			2, &gas,
+			-1);
+		if (!validate_time(time, &sec, &rel))
+			goto next;
+		if (rel)
+			sec += lasttime;
+		if (!validate_depth(depth, &mm))
+			goto next;
+		if (!validate_gas(gas, &o2, &he))
+			goto next;
+
+		plan_add_segment(&diveplan, sec, mm, o2, he);
+next:
+		lasttime = sec;
+		g_free(time); g_free(depth); g_free(gas);
+		ok = gtk_tree_model_iter_next(model, &iter);
+	}
+	plan(&diveplan);
+}
 
 void input_plan()
 {
@@ -1365,12 +1434,8 @@ void input_plan()
 	container = gtk_dialog_get_content_area(GTK_DIALOG(planner));
 
 	store = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+	/* We always have an empty entry at the end */
 	gtk_list_store_append(store, &iter);
-	gtk_list_store_set(store, &iter,
-		0, "7:30",
-		1, "100 ft",
-		2, "20/30",
-		-1);
 
 	view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
 	g_object_unref(store);
@@ -1383,7 +1448,7 @@ void input_plan()
 
 	gtk_widget_show_all(planner);
 	if (gtk_dialog_run(GTK_DIALOG(planner)) == GTK_RESPONSE_ACCEPT) {
-		// run plan
+		run_diveplan(store);
 	}
 	gtk_widget_destroy(planner);
 }
diff --git a/planner.c b/planner.c
index 9d407a7c4844..02c746989d43 100644
--- a/planner.c
+++ b/planner.c
@@ -10,20 +10,6 @@
 
 int stoplevels[] = { 3000, 6000, 9000, 12000, 15000, 21000, 30000, 42000, 60000, 90000 };
 
-struct divedatapoint {
-	int time;
-	int depth;
-	int o2;
-	int he;
-	struct divedatapoint *next;
-};
-
-struct diveplan {
-	timestamp_t when;
-	int surface_pressure;
-	struct divedatapoint *dp;
-};
-
 /* returns the tissue tolerance at the end of this (partial) dive */
 double tissue_at_end(struct dive *dive)
 {
@@ -189,6 +175,8 @@ void plan(struct diveplan *diveplan)
 	if (!diveplan->surface_pressure)
 		diveplan->surface_pressure = 1013;
 	dive = create_dive_from_plan(diveplan);
+	if (!dive)
+		return;
 	record_dive(dive);
 
 	sample = &dive->dc.sample[dive->dc.samples - 1];
-- 
1.8.1.rc2.6.g18499ba



More information about the subsurface mailing list