Cleanup
[speedometer] / ui.c
diff --git a/ui.c b/ui.c
index ca760f8..8e7d610 100644 (file)
--- a/ui.c
+++ b/ui.c
 
 #include <gtk/gtk.h>
 #include <glib/gprintf.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <math.h>
+#include <gconf/gconf-client.h>
 
 #include "ui.h"
 #include "callbacks.h"
 
+#define GCONF_KEY "/apps/Maemo/speedometer/disclaimer"
+
+/* This is used when converting to other units
+ * number represents a multiplier which is used
+ * when converting the base unit to other units.
+ * Base unit is m/s thus the first multiplier is
+ * one. Units are in following order:
+ *
+ * m/s, km/h, mph, f/s, knot
+ */
+gdouble conversion[] = { 1, 3.6, 2.237, 3.281, 1.944 };
+guint unit = 1;
+#define UNIT_COUNT 5
+// TODO: wrap this mess up somewhere
+
+static GdkPixbuf* big_graphics[15];
+static GdkPixbuf* small_graphics[15];
+static GtkWidget* digits[5];
+static GtkWidget* unit_graphic;
+
 #define IMAGE_PATH "/usr/share/speedometer/%d.png"
 
 static void set_widget_bg_black(GtkWidget* widget) {
@@ -33,70 +56,106 @@ static void set_widget_bg_black(GtkWidget* widget) {
        gtk_widget_modify_bg(GTK_WIDGET(widget), GTK_STATE_NORMAL, &black);
 }
 
-void load_graphix(AppData *appdata) {
-       g_assert(appdata);
-       g_print("Loading images\n");
+
+/* Loads all the graphics from the disk and
+ * scales the images down to be used in several
+ * places. Might block for few seconds depending
+ * on the load.
+ */
+void load_graphics() {
+       g_print("Loading and scaling images\n");
        guint i = 0;
-       while(i < 10) {
+
+       /* This loop will load all the images from the disk
+        * and store the pixbufs to the array. Pixbufs are
+        * correct size to be used in the big digits.
+        */
+       while(i < 15) {
                char* path = g_malloc(30);
                g_sprintf(path, IMAGE_PATH, i);
-               appdata->graphix[i] = gtk_image_new_from_file(path);
                g_print(path);
                g_print("\n");
+               GError* error = NULL;
+               big_graphics[i] = gdk_pixbuf_new_from_file_at_scale(path,
+                               160,
+                               160,
+                               FALSE,
+                               &error);
+               if(error) {
+                       g_print("Error loading big graphics: %s\n", error->message);
+                       g_error_free(error);
+                       error = NULL;
+               }
+               small_graphics[i] = gdk_pixbuf_new_from_file_at_scale(path,
+                                               120,
+                                               120,
+                                               FALSE,
+                                               &error);
+               if(error) {
+                       g_print("Error loading small graphics: %s\n", error->message);
+                       g_error_free(error);
+                       error = NULL;
+               }
                g_free(path);
                i++;
        }
+       g_print("Done\n");
 }
 
-void load_initial_pixbufs(AppData* appdata) {
-       g_assert(appdata);
-
-       GdkPixbuf* zero = gtk_image_get_pixbuf(GTK_IMAGE(appdata->graphix[0]));
-
-       appdata->big_digits[0] = GTK_WIDGET(gtk_image_new_from_pixbuf(zero));
-       appdata->big_digits[1] = GTK_WIDGET(gtk_image_new_from_pixbuf(zero));
-       appdata->big_digits[2] = GTK_WIDGET(gtk_image_new_from_pixbuf(zero));
+void set_digits_to_zero() {
+       digits[0] = gtk_image_new_from_pixbuf(big_graphics[0]);
+       digits[1] = gtk_image_new_from_pixbuf(big_graphics[0]);
+       digits[2] = gtk_image_new_from_pixbuf(big_graphics[0]);
+       digits[3] = gtk_image_new_from_pixbuf(small_graphics[0]);
+       digits[4] = gtk_image_new_from_pixbuf(small_graphics[0]);
+       // TODO: load this from GConf
+       unit_graphic = gtk_image_new_from_pixbuf(small_graphics[11]);
 }
 
-void set_nth_digit(AppData* appdata, guint n, guint value) {
-       g_assert(appdata);
+static void set_nth_digit(guint n, guint value) {
        g_assert(value < 10);
-       g_assert(n < 3);
+       g_assert(n < 5);
 
-       GtkWidget* image = appdata->big_digits[n];
-       GdkPixbuf* buf = gtk_image_get_pixbuf(GTK_IMAGE(appdata->graphix[value]));
-       gtk_image_set_from_pixbuf(GTK_IMAGE(image), buf);
+       if(n < 3) {
+               GtkWidget* image = digits[n];
+               GdkPixbuf* buf = big_graphics[value];
+               gtk_image_set_from_pixbuf(GTK_IMAGE(image), buf);
+       }
+       else {
+               GtkWidget* image = digits[n];
+               GdkPixbuf* buf = small_graphics[value];
+               gtk_image_set_from_pixbuf(GTK_IMAGE(image), buf);
+       }
 }
 
-void repaint_all_digits(AppData* appdata) {
-       g_assert(appdata);
-       gtk_widget_queue_draw(GTK_WIDGET(appdata->big_digits[0]));
-       gtk_widget_queue_draw(GTK_WIDGET(appdata->big_digits[1]));
-       gtk_widget_queue_draw(GTK_WIDGET(appdata->big_digits[2]));
+static void repaint_all_digits() {
+       gtk_widget_queue_draw(GTK_WIDGET(digits[0]));
+       gtk_widget_queue_draw(GTK_WIDGET(digits[1]));
+       gtk_widget_queue_draw(GTK_WIDGET(digits[2]));
 }
 
 void create_ui(AppData* appdata) {
        g_assert(appdata);
 
-       appdata->unit = 1; // by default use km/h display
-
-       GtkWidget *hbox;
+       GtkWidget *top_hbox;
+       GtkWidget *bottom_hbox;
        GtkWidget *vbox;
 
        vbox = gtk_vbox_new(FALSE, 0);
-       hbox = gtk_hbox_new(TRUE, 0);
+       top_hbox = gtk_hbox_new(TRUE, 0);
+       bottom_hbox = gtk_hbox_new(TRUE, 0);
 
-       GtkWidget* top_e = gtk_event_box_new();
-       GtkWidget* bottom_e = gtk_event_box_new();
+       GtkWidget* event_box = gtk_event_box_new();
 
-       g_signal_connect(G_OBJECT(top_e),
-                       "button_press_event",
-                       G_CALLBACK(top_event_box_button_press),
+       g_signal_connect(G_OBJECT(event_box),
+                       "tap_and_hold",
+                       G_CALLBACK(long_tap),
                        appdata);
+       gtk_widget_tap_and_hold_setup(event_box, NULL, NULL, 0);
 
-       g_signal_connect(G_OBJECT(bottom_e),
+       g_signal_connect(G_OBJECT(event_box),
                        "button_press_event",
-                       G_CALLBACK(bottom_event_box_button_press),
+                       G_CALLBACK(short_tap),
                        appdata);
 
        g_signal_connect(G_OBJECT(appdata->window),
@@ -104,26 +163,126 @@ void create_ui(AppData* appdata) {
                        G_CALLBACK(gtk_main_quit),
                        NULL);
 
-    g_signal_connect(G_OBJECT(appdata->window),
-               "key_press_event",
-               G_CALLBACK(key_press_cb),
-               appdata->window);
+       g_signal_connect(G_OBJECT(appdata->window),
+                       "key_press_event",
+                       G_CALLBACK(key_press_cb),
+                       appdata->window);
+
+       // add three big digits to the hbox
+       // creates the top row where big digits are placed
+       gtk_box_pack_start(GTK_BOX(top_hbox), GTK_WIDGET(digits[0]), FALSE, FALSE, 0);
+       gtk_box_pack_start(GTK_BOX(top_hbox), GTK_WIDGET(digits[1]), FALSE, FALSE, 0);
+       gtk_box_pack_start(GTK_BOX(top_hbox), GTK_WIDGET(digits[2]), FALSE, FALSE, 0);
+
+       // add small digits to another hbox
+       // creates the bottom row with decimals and unit graphic
+       gtk_box_pack_start(GTK_BOX(bottom_hbox), GTK_WIDGET(unit_graphic), FALSE, FALSE, 0);
+       gtk_box_pack_start(GTK_BOX(bottom_hbox), GTK_WIDGET(digits[3]), FALSE, FALSE, 0);
+       gtk_box_pack_start(GTK_BOX(bottom_hbox), GTK_WIDGET(digits[4]), FALSE, FALSE, 0);
 
-       // add three digits to the hbox
-       gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(appdata->big_digits[0]), FALSE, FALSE, 0);
-       gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(appdata->big_digits[1]), FALSE, FALSE, 0);
-       gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(appdata->big_digits[2]), FALSE, FALSE, 0);
+       // add event boxes to the vbox
+       gtk_box_pack_start_defaults(GTK_BOX(vbox), top_hbox);
+       gtk_box_pack_start_defaults(GTK_BOX(vbox), bottom_hbox);
 
-       gtk_box_pack_start_defaults(GTK_BOX(vbox), top_e); // add event box on top
-       gtk_box_pack_start_defaults(GTK_BOX(vbox), hbox); // numbers to the middle
-       gtk_box_pack_start_defaults(GTK_BOX(vbox), bottom_e); // add event box on bottom
+       // add vertival box to the event box
+       gtk_container_add(GTK_CONTAINER(event_box), GTK_WIDGET(vbox));
 
-       gtk_container_add(GTK_CONTAINER(appdata->window), GTK_WIDGET(vbox));
+       // finally add the event box with all the children to the window
+       gtk_container_add(GTK_CONTAINER(appdata->window), GTK_WIDGET(event_box));
 
        // set backgrounds black
        set_widget_bg_black(GTK_WIDGET(appdata->window));
-       set_widget_bg_black(bottom_e);
-       set_widget_bg_black(top_e);
+       set_widget_bg_black(event_box);
+
+       gtk_window_fullscreen(GTK_WINDOW(appdata->window));
+       gtk_widget_show_all(GTK_WIDGET(appdata->window));
+}
+
+void change_unit() {
+       unit++;
 
+       if(unit >= UNIT_COUNT) {
+               unit = 0;
+       }
+       g_print("Unit used in conversion: %f\n", conversion[unit]);
+
+       GdkPixbuf* buf = small_graphics[10 + unit];
+       gtk_image_set_from_pixbuf(GTK_IMAGE(unit_graphic), buf);
+}
+
+void interpret_and_set_speed(gdouble speed) {
+       g_assert(!isnan(speed));
+
+       /* speed is in m/s so let's convert
+        * it to the unit that we are using
+        */
+       speed *= conversion[unit];
+
+       /* we need to limit the speed down to
+        * less than 1000 whatever or else hell
+        * breaks loose in the form of assert
+        */
+       if(!(fabs(speed) < 1000)) {
+           g_print("Ahem, may I suggest to limit the speed (%f) a bit, Sir.\n", speed);
+           speed = 0;
+       }
+
+       /* Convert float to a 6 digits (including dot) wide
+        * string with leading zeros. After conversion
+        * the speed looks like:
+        *
+        * 009.20 (9,20 km/h) or
+        * 010.90 (10,90 km/h) or
+        * 120.10 (120,10 km/h)
+        *
+        * Now, regardless of speed we know the position
+        * of the digits and can access the array directly.
+        */
+       gchar* charspeed = g_malloc(10); // alloc
+       g_sprintf(charspeed, "%0*.2f", 6, speed);
+
+       g_print("Speed is %s km/h\n", charspeed);
+
+       // these three lines will set the big digits
+       set_nth_digit(0, g_ascii_digit_value(charspeed[0]));
+       set_nth_digit(1, g_ascii_digit_value(charspeed[1]));
+       set_nth_digit(2, g_ascii_digit_value(charspeed[2]));
+
+       // these two lines will set the small digits
+       set_nth_digit(3, g_ascii_digit_value(charspeed[4]));
+       set_nth_digit(4, g_ascii_digit_value(charspeed[5]));
+
+       repaint_all_digits();
+
+       g_free(charspeed);
+}
+
+static void show_dialog() {
+       GtkWidget *dialog = gtk_message_dialog_new(
+                       NULL,
+                       GTK_DIALOG_MODAL,
+                       GTK_MESSAGE_INFO,
+                       GTK_BUTTONS_OK,
+                       "This program is licensed under GNU General Public License, "
+                       "which means (among other things) that you don't have to pay "
+                       "a dime for it. "
+                       "PS. Long-tapping on the screen will quit the program.");
+       gtk_dialog_run(GTK_DIALOG(dialog));
+       gtk_widget_destroy(dialog);
+}
+
+void show_cardware_dialog() {
+       GConfClient* client = gconf_client_get_default();
+       g_assert(GCONF_IS_CLIENT(client));
+
+       GConfValue* gcvalue = NULL;
+       gcvalue = gconf_client_get_without_default(client, GCONF_KEY, NULL);
+
+       if(gcvalue == NULL) {
+               g_print("GConf key not found so show dialog.\n");
+               show_dialog();
+               gconf_client_set_bool(client, GCONF_KEY, TRUE, NULL);
+       }
+       g_object_unref(client);
 }