r3230 - in trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2: . src

abraxa at sita.openmoko.org abraxa at sita.openmoko.org
Sat Oct 20 03:30:21 CEST 2007


Author: abraxa
Date: 2007-10-20 03:30:20 +0200 (Sat, 20 Oct 2007)
New Revision: 3230

Modified:
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/TODO
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/editor_page.c
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main_page.c
Log:
Add gesture recognition (up/down=volume; left/right=ffwd/rew; stroke+hold=repeat)
Fix bug #893 by changing color for "Add Playlist" button label



Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/TODO
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/TODO	2007-10-19 17:21:31 UTC (rev 3229)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/TODO	2007-10-20 01:30:20 UTC (rev 3230)
@@ -19,3 +19,7 @@
 
 Documentation:
 	Update wiki
+
+Playlist management features:
+	Search alphabetically
+	Jump to track

Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/editor_page.c
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/editor_page.c	2007-10-19 17:21:31 UTC (rev 3229)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/editor_page.c	2007-10-20 01:30:20 UTC (rev 3230)
@@ -301,7 +301,7 @@
 	image = gtk_image_new_from_icon_name("gtk-file", GTK_ICON_SIZE_BUTTON);
 	gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(image), TRUE, TRUE, 0);
 
-	alignment = label_create(&label, "Sans 6", "black", 0, 0, 0, 0, PANGO_ELLIPSIZE_NONE);
+	alignment = label_create(&label, "Sans 6", "white", 0, 0, 0, 0, PANGO_ELLIPSIZE_NONE);
 	gtk_label_set_text(GTK_LABEL(label), _("Add Tracks"));
 	gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(alignment), TRUE, TRUE, 0);
 

Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main_page.c
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main_page.c	2007-10-19 17:21:31 UTC (rev 3229)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main_page.c	2007-10-20 01:30:20 UTC (rev 3230)
@@ -43,8 +43,10 @@
 
 
 
+#include <math.h>
+
 /// Contains all main window widgets that need to be changeable
-struct _main_widgets
+struct
 {
 	GtkWidget *cover_image;
 	GtkWidget *cover_frame;
@@ -63,6 +65,31 @@
 
 GtkWidget *omp_main_window = NULL;
 
+/// Possible gestures
+typedef enum
+{
+	OMP_MAIN_GESTURE_NONE,
+	OMP_MAIN_GESTURE_LEFT,
+	OMP_MAIN_GESTURE_RIGHT,
+	OMP_MAIN_GESTURE_UP,
+	OMP_MAIN_GESTURE_DOWN
+} omp_main_gesture;
+
+/// Holds the necessary infos to record and identify the gestures
+struct
+{
+	gboolean pressed;
+	GTimeVal start_time;
+	guint x_origin, y_origin;
+	guint last_x, last_y;
+	gboolean cursor_idle;						// TRUE if cursor isn't moving
+
+	gint radius, angle;
+	omp_main_gesture gesture;
+	gboolean repeating;
+	guint repeat_timeout;
+} main_gesture_data;
+
 // Forward declarations for internal use
 void omp_main_set_label(omp_main_label_type label_type, gchar *caption);
 void omp_main_playlist_loaded(gpointer instance, gchar *title, gpointer user_data);
@@ -77,6 +104,22 @@
 
 
 /**
+ * Self-explanatory :)
+ */
+gint min(gint a, gint b)
+{
+	return (a > b) ? b : a;
+}
+
+/**
+ * Self-explanatory :)
+ */
+gint max(gint a, gint b)
+{
+	return (a > b) ? a : b;
+}
+
+/**
  * Event handler for the expand button
  */
 void
@@ -161,6 +204,222 @@
 }
 
 /**
+ * Tries to determine which gesture the user has performed and fills the gesture data struct accordingly
+ * @param x X coordinate of current pressure point
+ * @param y Y coordinate of current pressure point
+ */
+void
+omp_main_gesture_identify(guint x, guint y)
+{
+	#define MIN_RADIUS 15
+
+	gint delta_x, delta_y, gamma;
+
+	// Perform rect->polar conversion of the differential cursor movement
+	delta_x = x - main_gesture_data.x_origin;
+	delta_y = y - main_gesture_data.y_origin;
+
+	main_gesture_data.radius = sqrt(delta_x * delta_x + delta_y * delta_y);
+
+	// angle = arccos(gamma) but arccos() is too slow to compute -> range comparison
+	// We shift the comma by 3 digits so we can use integer math
+	gamma = delta_x*1000 / main_gesture_data.radius;
+
+	if (main_gesture_data.radius > MIN_RADIUS)
+	{
+
+		// Determine direction of movement
+		if (gamma < -707)
+		{
+			main_gesture_data.gesture = OMP_MAIN_GESTURE_LEFT;
+
+		} else {
+
+			if (gamma > 707)
+			{
+				main_gesture_data.gesture = OMP_MAIN_GESTURE_RIGHT;
+			} else {
+				main_gesture_data.gesture = (delta_y < 0) ? OMP_MAIN_GESTURE_UP : OMP_MAIN_GESTURE_DOWN;
+			}
+
+		}
+
+	} else {
+
+		// Radius too small
+		main_gesture_data.gesture = OMP_MAIN_GESTURE_NONE;
+	}
+
+}
+
+/**
+ * Performs the action the current gesture commands
+ */
+void
+omp_main_gesture_trigger()
+{
+	if (main_gesture_data.gesture == OMP_MAIN_GESTURE_NONE) return;
+
+	switch (main_gesture_data.gesture)
+	{
+		case OMP_MAIN_GESTURE_LEFT:
+		{
+			omp_main_rewind_clicked(NULL, NULL);
+			break;
+		}
+
+		case OMP_MAIN_GESTURE_RIGHT:
+		{
+			omp_main_fast_forward_clicked(NULL, NULL);
+			break;
+		}
+
+		case OMP_MAIN_GESTURE_UP:
+		{
+			omp_playback_set_volume(min(100, omp_playback_get_volume()+10));
+			break;
+		}
+
+		case OMP_MAIN_GESTURE_DOWN:
+		{
+			omp_playback_set_volume(max(0, omp_playback_get_volume()-10));
+			break;
+		}
+
+		default: break;
+	}
+}
+
+/**
+ * This callback repeatedly performs the action the current gesture commands
+ */
+static gboolean
+omp_main_gesture_repeat_callback(gpointer data)
+{
+	if (!main_gesture_data.repeating) return FALSE;
+
+	omp_main_gesture_trigger();
+
+	return TRUE;
+}
+
+/**
+ * Sets up the repeat timeout if the touchscreen is being pressed for a certain amount of time
+ */
+void
+omp_main_gesture_check_repeat()
+{
+	#define REPEAT_TIME_TRESHOLD_USEC 0750000
+	#define REPEAT_INTERVAL_MSEC 1000
+
+	GTimeVal current_time, delta_t;
+
+	if (!main_gesture_data.repeating)
+	{
+		// Calculate duration of touchscreen press
+		g_get_current_time(&current_time);
+		delta_t.tv_sec  = current_time.tv_sec  - main_gesture_data.start_time.tv_sec;
+		delta_t.tv_usec = current_time.tv_usec - main_gesture_data.start_time.tv_usec;
+
+		if (delta_t.tv_usec >= REPEAT_TIME_TRESHOLD_USEC)
+		{
+			main_gesture_data.repeating = TRUE;
+			g_timeout_add(REPEAT_INTERVAL_MSEC, omp_main_gesture_repeat_callback, NULL);
+		}
+
+	}
+}
+
+/**
+ * Gets called whenever the cursor has been moved, handling gesture recognition and triggering
+ */
+gboolean
+omp_main_pointer_moved(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
+{
+	#define MAX_DELTA_LAST 3
+	gint delta_last_x, delta_last_y;
+
+//	g_printf("Pointer: X=%d /\t Y=%d /\t state=%d /\t is_hint=%d\n",
+//		(gint)event->x, (gint)event->y, event->state, event->is_hint);
+
+	if (main_gesture_data.pressed)
+	{
+		delta_last_x = abs((guint)event->x - main_gesture_data.last_x);
+		delta_last_y = abs((guint)event->y - main_gesture_data.last_y);
+
+		// Did the cursor move a substantial amount?
+		if ( (delta_last_x > MAX_DELTA_LAST) && (delta_last_y > MAX_DELTA_LAST) )
+		{
+			// Yes it did, so it's most likely being moved
+			main_gesture_data.cursor_idle = FALSE;
+			main_gesture_data.last_x = event->x;
+			main_gesture_data.last_y = event->y;
+
+			// Make sure we won't trigger anymore (if we were before, that is)
+			main_gesture_data.repeating = FALSE;
+//			g_printf("-- movement\n");
+
+		} else {
+//			g_printf("-- NO movement\n");
+
+			// Cursor is idle, so lets update the gesture data if it wasn't idle before
+			if (!main_gesture_data.cursor_idle)
+				omp_main_gesture_identify(event->x, event->y);
+
+			omp_main_gesture_check_repeat();
+
+			main_gesture_data.cursor_idle = TRUE;
+		}
+	}
+
+	return FALSE;
+}
+
+/**
+ * Gets called whenever the touchscreen has been pressed, handling gesture recognition and triggering
+ */
+gboolean
+omp_main_pointer_pressed(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
+{
+//	g_printf("- Pressed: X=%d /\t Y=%d /\t state=%d /\t button=%d\n",
+//		(gint)event->x, (gint)event->y, event->state, event->button);
+
+	main_gesture_data.pressed = TRUE;
+	g_get_current_time(&main_gesture_data.start_time);
+	main_gesture_data.x_origin = event->x;
+	main_gesture_data.y_origin = event->y;
+	main_gesture_data.last_x = event->x;
+	main_gesture_data.last_y = event->y;
+	main_gesture_data.cursor_idle = FALSE;
+	main_gesture_data.gesture = OMP_MAIN_GESTURE_NONE;
+	main_gesture_data.repeating = FALSE;
+
+	return FALSE;
+}
+
+/**
+ * Gets called whenever the touchscreen has been released, handling gesture recognition and triggering
+ */
+gboolean
+omp_main_pointer_released(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
+{
+//	g_printf("- Released: X=%d /\t Y=%d /\t state=%d /\t button=%d\n",
+//		(gint)event->x, (gint)event->y, event->state, event->button);
+
+	// Stop repeat trigger if necessary - or trigger action
+	if (main_gesture_data.repeating)
+	{
+		main_gesture_data.repeating = FALSE;
+	} else {
+		omp_main_gesture_trigger();
+	}
+
+	main_gesture_data.pressed = FALSE;
+
+	return FALSE;
+}
+
+/**
  * Resets the UI to a "no track loaded" state
  */
 void
@@ -480,6 +739,17 @@
 	g_signal_connect(G_OBJECT(omp_window), OMP_EVENT_PLAYBACK_VOLUME_CHANGED,
 		G_CALLBACK(omp_main_update_volume), NULL);
 
+	// Set up gesture recognition handlers
+	gtk_widget_add_events(eventbox,
+		GDK_POINTER_MOTION_MASK | 
+		GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
+
+	main_gesture_data.pressed = FALSE;
+
+	g_signal_connect(G_OBJECT(eventbox), "motion-notify-event", G_CALLBACK(omp_main_pointer_moved), NULL);
+	g_signal_connect(G_OBJECT(eventbox), "button-press-event", G_CALLBACK(omp_main_pointer_pressed), NULL);
+	g_signal_connect(G_OBJECT(eventbox), "button-release-event", G_CALLBACK(omp_main_pointer_released), NULL);
+
 	// Make widgets visible - can't use gtk_widget_show_all() here as some widgets should stay hidden
 	gtk_widget_show(vbox);
 	gtk_widget_show(eventbox);





More information about the commitlog mailing list