Contents of /trunk/src/misc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 185 - (hide annotations)
Sat Nov 14 16:55:33 2009 UTC (14 years, 6 months ago) by harbaum
File MIME type: text/plain
File size: 14491 byte(s)
All icons redone
1 harbaum 1 /*
2     * Copyright (C) 2008 Till Harbaum <till@harbaum.org>.
3     *
4     * This file is part of GPXView.
5     *
6     * GPXView is free software: you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation, either version 3 of the License, or
9     * (at your option) any later version.
10     *
11     * GPXView is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with GPXView. If not, see <http://www.gnu.org/licenses/>.
18     */
19    
20     #include <math.h>
21     #include <string.h>
22     #include <ctype.h>
23    
24 harbaum 77 #include <glib.h>
25     #include <glib/gstdio.h>
26    
27 harbaum 1 #include "gpxview.h"
28    
29     char strlastchr(char *str) {
30     return str[strlen(str)]-1;
31     }
32    
33     /* make sure the entire path "dir" exists and create it if not */
34     int checkdir(char *dir) {
35     struct stat filestat;
36     char *p = dir, tmp;
37    
38     /* don't try to create root dir */
39     if(p[0] == '/') p++;
40    
41     do {
42     while(*p && *p != '/') p++;
43     tmp = *p;
44     *p = 0;
45    
46     int err = stat(dir, &filestat);
47     if(err) {
48     if(mkdir(dir, S_IRWXU) != 0) {
49     perror("mkdir()");
50     *p++ = tmp;
51     return -1;
52     }
53     } else {
54     if(!filestat.st_mode & S_IFDIR) {
55     printf("File %s exists and is _no_ directory\n", dir);
56     *p++ = tmp;
57     return -1;
58     }
59     }
60    
61     *p++ = tmp;
62     } while(tmp && strchr(p, '/'));
63    
64     return 0;
65     }
66    
67     void pos_lat_str(char *str, int len, float latitude) {
68     char *c = _("N");
69     float integral, fractional;
70    
71 harbaum 13 if(isnan(latitude))
72     str[0] = 0;
73     else {
74     if(latitude < 0) { latitude = fabs(latitude); c = _("S"); }
75     fractional = modff(latitude, &integral);
76 harbaum 1
77 harbaum 13 snprintf(str, len, "%s %02d° %06.3f'", c, (int)integral, fractional*60.0);
78     }
79 harbaum 1 }
80    
81     GtkWidget *pos_lat(float latitude, int size, int strikethrough) {
82     char str[32];
83    
84     pos_lat_str(str, sizeof(str), latitude);
85     return gtk_label_attrib(str, size, strikethrough);
86     }
87    
88     void pos_lon_str(char *str, int len, float longitude) {
89     char *c = _("E");
90     float integral, fractional;
91    
92 harbaum 13 if(isnan(longitude))
93     str[0] = 0;
94     else {
95     if(longitude < 0) { longitude = fabs(longitude); c = _("W"); }
96     fractional = modff(longitude, &integral);
97 harbaum 1
98 harbaum 13 snprintf(str, len, "%s %03d° %06.3f'", c, (int)integral, fractional*60.0);
99     }
100 harbaum 1 }
101    
102     GtkWidget *pos_lon(float longitude, int size, int strikethrough) {
103     char str[32];
104    
105     pos_lon_str(str, sizeof(str), longitude);
106     return gtk_label_attrib(str, size, strikethrough);
107     }
108    
109     float pos_parse_lat(char *str) {
110     int integral_int;
111     float fractional;
112     char c;
113    
114     if(sscanf(str, "%c %d° %f'", &c, &integral_int, &fractional) == 3) {
115     c = toupper(c);
116    
117     if(c != 'S' && c != 'N')
118     return NAN;
119    
120     /* prevent -0.0 */
121     if(!integral_int && (fractional == 0.0))
122     return 0.0;
123    
124     return ((c == 'S')?-1:+1) * (integral_int + fractional/60.0);
125     }
126    
127     return NAN;
128     }
129    
130     float pos_parse_lon(char *str) {
131     int integral_int;
132     float fractional;
133     char c;
134    
135     if(sscanf(str, "%c %d° %f'", &c, &integral_int, &fractional) == 3) {
136     c = toupper(c);
137    
138     /* O is german "Ost" for "East" */
139     if(c != 'E' && c != 'W' && c != 'O')
140     return NAN;
141    
142     /* prevent -0.0 */
143     if(!integral_int && (fractional == 0.0))
144     return 0.0;
145    
146     return ((c == 'W')?-1:+1) * (integral_int + fractional/60.0);
147     }
148    
149     return NAN;
150     }
151    
152     const char *pos_get_bearing_str(pos_t from, pos_t to) {
153     static const char *bear_str[]={
154 harbaum 185 "N", "NE", "E", "SE", "S", "SW", "W", "NW", "" };
155    
156     float bearing = gpx_pos_get_bearing(from, to);
157     if(!isnan(bearing)) {
158     int idx = (bearing+22.5)/45.0;
159     /* make sure we stay in icon bounds */
160     while(idx < 0) idx += 8;
161     while(idx > 7) idx -= 8;
162     return _(bear_str[idx]);
163     }
164    
165     return bear_str[8]; // empty string
166 harbaum 1 }
167    
168     /* the maemo font size is quite huge, so we adjust some fonts */
169     /* differently on maemo and non-maemo. Basically "BIG" does nothing */
170     /* on maemo and "SMALL" only does something on maemo */
171     #ifdef USE_MAEMO
172     #define MARKUP_SMALL "<span size='small'>%s</span>"
173     GtkWidget *gtk_label_small(char *str) {
174     GtkWidget *label = gtk_label_new("");
175     char *markup = g_markup_printf_escaped(MARKUP_SMALL, str);
176     gtk_label_set_markup(GTK_LABEL(label), markup);
177     g_free(markup);
178     return label;
179     }
180     #else
181     #define MARKUP_BIG "<span size='x-large'>%s</span>"
182     GtkWidget *gtk_label_big(char *str) {
183     GtkWidget *label = gtk_label_new("");
184     char *markup = g_markup_printf_escaped(MARKUP_BIG, str);
185     gtk_label_set_markup(GTK_LABEL(label), markup);
186     g_free(markup);
187     return label;
188     }
189     #endif
190    
191     void gtk_label_attrib_set(GtkWidget *label,
192     char *str, int size, int strikethrough) {
193     char format[80];
194    
195     snprintf(format, sizeof(format), "<span%s%s%s>%%s</span>",
196     #ifdef USE_MAEMO
197     (size==SIZE_SMALL)?" size='small'":"",
198     #else
199     (size==SIZE_BIG)?" size='x-large'":"",
200     #endif
201     strikethrough?" strikethrough='yes'":"",
202     (strikethrough==STRIKETHROUGH_RED)?" strikethrough_color='red'":"");
203    
204     char *markup = g_markup_printf_escaped(format, str);
205     // printf("markup = %s\n", markup);
206     gtk_label_set_markup(GTK_LABEL(label), markup);
207     g_free(markup);
208     }
209    
210     GtkWidget *gtk_label_attrib(char *str, int size, int strikethrough) {
211     GtkWidget *label = gtk_label_new("");
212     gtk_label_attrib_set(label, str, size, strikethrough);
213     return label;
214     }
215    
216     GtkWidget *gtk_button_attrib(char *str, int size, int strikethrough) {
217     GtkWidget *button = gtk_button_new_with_label("");
218     gtk_label_attrib_set(gtk_bin_get_child(GTK_BIN(button)),
219     str, size, strikethrough);
220     return button;
221     }
222    
223     void textbox_disable(GtkWidget *widget) {
224     gtk_editable_set_editable(GTK_EDITABLE(widget), FALSE);
225     gtk_widget_set_sensitive(widget, FALSE);
226     }
227    
228     void textbox_enable(GtkWidget *widget) {
229     gtk_widget_set_sensitive(widget, TRUE);
230     gtk_editable_set_editable(GTK_EDITABLE(widget), TRUE);
231     }
232    
233     pos_t *get_pos(appdata_t *appdata) {
234     pos_t *pos = &appdata->home;
235    
236     if(appdata->active_location) {
237     int i = appdata->active_location-1;
238     location_t *loc = appdata->location;
239     while(i--) loc = loc->next;
240     pos = &loc->pos;
241     }
242    
243     if(appdata->use_gps) {
244     pos = gps_get_pos(appdata);
245    
246     if(!pos) pos = &appdata->gps; /* use saved position */
247     else appdata->gps = *pos; /* save position */
248     }
249     return pos;
250     }
251    
252     void distance_str(char *str, int len, float dist, gboolean imperial) {
253 harbaum 34 if(isnan(dist))
254     snprintf(str, len, "---");
255     else if(imperial) {
256 harbaum 1 /* 1 mil = 1760 yd = 5280 ft ... */
257     if(dist<0.018) snprintf(str, len, "%.1f ft", dist*5280.0);
258     else if(dist<0.055) snprintf(str, len, "%.1f yd", dist*1760.0);
259     else if(dist<0.55) snprintf(str, len, "%.0f yd", dist*1760.0);
260     else if(dist<10.0) snprintf(str, len, "%.2f mi", dist);
261     else if(dist<100.0) snprintf(str, len, "%.1f mi", dist);
262     else snprintf(str, len, "%.0f mi", dist);
263     } else {
264     if(dist<0.01) snprintf(str, len, "%.2f m", dist*1000.0);
265     else if(dist<0.1) snprintf(str, len, "%.1f m", dist*1000.0);
266     else if(dist<1.0) snprintf(str, len, "%.0f m", dist*1000.0);
267     else if(dist<100.0) snprintf(str, len, "%.1f km", dist);
268     else snprintf(str, len, "%.0f km", dist);
269     }
270     }
271    
272     /* return distance in miles or kilometers */
273     float distance_parse(char *str, gboolean imperial) {
274     char unit[4];
275     float val = NAN;
276    
277     if(sscanf(str, "%f %3s", &val, unit) == 2) {
278     gboolean fimp = FALSE;
279    
280     if(strcasecmp(unit, "ft") == 0) { fimp = TRUE; val /= 5280.0; }
281     else if(strcasecmp(unit, "yd") == 0) { fimp = TRUE; val /= 1760.0; }
282     else if(strcasecmp(unit, "mi") == 0) { fimp = TRUE; }
283     else if(strcasecmp(unit, "m") == 0) { fimp = FALSE; val /= 1000.0; }
284     else if(strcasecmp(unit, "km") == 0) { fimp = FALSE; }
285     else val = NAN;
286    
287     /* found imperial and metric requested? convert miles into kilometers */
288     if(fimp & !imperial) val *= 1.609344;
289    
290     /* found metric and imperial requested? convert kilometers into miles */
291     if(!fimp & imperial) val /= 1.609344;
292     }
293     return val;
294     }
295    
296     static gboolean mark(GtkWidget *widget, gboolean valid) {
297     gtk_widget_set_state(widget, valid?GTK_STATE_NORMAL:TAG_STATE);
298     return valid;
299     }
300    
301     static void callback_modified_lat(GtkWidget *widget, gpointer data ) {
302     float i = pos_parse_lat((char*)gtk_entry_get_text(GTK_ENTRY(widget)));
303     mark(widget, !isnan(i));
304     }
305    
306     /* a entry that is colored red when being "active" */
307     GtkWidget *lat_entry_new(float lat) {
308     GdkColor color;
309     GtkWidget *widget = gtk_entry_new();
310     gdk_color_parse("#ff0000", &color);
311     gtk_widget_modify_text(widget, TAG_STATE, &color);
312    
313     char str[32];
314     pos_lat_str(str, sizeof(str), lat);
315     gtk_entry_set_text(GTK_ENTRY(widget), str);
316    
317     g_signal_connect(G_OBJECT(widget), "changed",
318     G_CALLBACK(callback_modified_lat), NULL);
319    
320     return widget;
321     }
322    
323     static void callback_modified_lon(GtkWidget *widget, gpointer data ) {
324     float i = pos_parse_lon((char*)gtk_entry_get_text(GTK_ENTRY(widget)));
325     mark(widget, !isnan(i));
326     }
327    
328     /* a entry that is colored red when filled with invalid coordinate */
329     GtkWidget *lon_entry_new(float lon) {
330     GdkColor color;
331     GtkWidget *widget = gtk_entry_new();
332     gdk_color_parse("#ff0000", &color);
333     gtk_widget_modify_text(widget, TAG_STATE, &color);
334    
335     char str[32];
336     pos_lon_str(str, sizeof(str), lon);
337     gtk_entry_set_text(GTK_ENTRY(widget), str);
338    
339     g_signal_connect(G_OBJECT(widget), "changed",
340     G_CALLBACK(callback_modified_lon), NULL);
341    
342     return widget;
343     }
344    
345    
346     float lat_get(GtkWidget *widget) {
347     char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
348     return pos_parse_lat(p);
349     }
350    
351     float lon_get(GtkWidget *widget) {
352     char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
353     return pos_parse_lon(p);
354     }
355    
356     static void callback_modified_dist(GtkWidget *widget, gpointer data ) {
357     /* don't care for metric/imperial since we only want to know if this */
358     /* is parseable at all */
359     float i = distance_parse((char*)gtk_entry_get_text(GTK_ENTRY(widget)), FALSE);
360     mark(widget, !isnan(i));
361     }
362    
363     /* a entry that is colored red when filled with invalid distance */
364     GtkWidget *dist_entry_new(float dist, gboolean mil) {
365     GdkColor color;
366     GtkWidget *widget = gtk_entry_new();
367     gdk_color_parse("#ff0000", &color);
368     gtk_widget_modify_text(widget, TAG_STATE, &color);
369    
370     char str[32];
371     distance_str(str, sizeof(str), dist, mil);
372     gtk_entry_set_text(GTK_ENTRY(widget), str);
373    
374     g_signal_connect(G_OBJECT(widget), "changed",
375     G_CALLBACK(callback_modified_dist), NULL);
376    
377     return widget;
378     }
379    
380     float dist_get(GtkWidget *widget, gboolean mil) {
381     char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
382     return distance_parse(p, mil);
383     }
384    
385     #ifndef USE_MAEMO
386     #ifdef ENABLE_BROWSER_INTERFACE
387     #include <libgnome/gnome-url.h>
388    
389     int browser_url(appdata_t *appdata, char *url) {
390     /* taken from gnome-open, part of libgnome */
391     GError *err = NULL;
392     gnome_url_show(url, &err);
393     return 0;
394     }
395     #endif
396     #endif
397 harbaum 77
398     /* recursively remove an entire file system */
399     void rmdir_recursive(char *path) {
400     GDir *dir = g_dir_open(path, 0, NULL);
401     if(dir) {
402     const char *name = g_dir_read_name(dir);
403     while(name) {
404     char *fullname = g_strdup_printf("%s/%s", path, name);
405     // printf("deleting %s\n", fullname);
406    
407     if(g_file_test(fullname, G_FILE_TEST_IS_DIR))
408     rmdir_recursive(fullname);
409     else if(g_file_test(fullname, G_FILE_TEST_IS_REGULAR))
410     g_remove(fullname);
411    
412     g_free(fullname);
413     name = g_dir_read_name(dir);
414     }
415    
416     g_dir_close(dir);
417     }
418     g_rmdir(path);
419     }
420    
421 harbaum 137 #ifdef ENABLE_BROWSER_INTERFACE
422     static void on_link_clicked(GtkButton *button, gpointer data) {
423     appdata_t *appdata = (appdata_t*)data;
424     char *url = g_object_get_data(G_OBJECT(button), "url");
425     if(url) browser_url(appdata, url);
426     }
427     #endif
428    
429     /* a button containing a weblink */
430     GtkWidget *link_button_attrib(appdata_t *appdata, char *str, char *url,
431     int size, int strikethrough) {
432    
433     #ifdef ENABLE_BROWSER_INTERFACE
434     if(url) {
435     GtkWidget *button = gtk_button_attrib(str, size, strikethrough);
436     g_object_set_data(G_OBJECT(button), "url", url);
437     gtk_signal_connect(GTK_OBJECT(button), "clicked",
438     (GtkSignalFunc)on_link_clicked, appdata);
439    
440     return button;
441     }
442     #endif
443     return gtk_label_attrib(str, size, strikethrough);
444     }
445    
446     #ifdef ENABLE_BROWSER_INTERFACE
447     static void on_link_id_clicked(GtkButton *button, gpointer data) {
448     appdata_t *appdata = (appdata_t*)data;
449    
450     unsigned int id = (unsigned int)g_object_get_data(G_OBJECT(button), "id");
451     char *type = g_object_get_data(G_OBJECT(button), "type");
452    
453     char *url = g_strdup_printf("http://www.geocaching.com/%s?id=%u",
454     type, id);
455    
456     if(url) {
457     browser_url(appdata, url);
458     g_free(url);
459     }
460     }
461     #endif
462    
463     GtkWidget *link_button_by_id(appdata_t *appdata, char *str,
464     const char *type, int id) {
465    
466     #ifdef ENABLE_BROWSER_INTERFACE
467     if(id) {
468     GtkWidget *ref = gtk_button_new_with_label(str);
469     #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR == 5)
470     // hildon_gtk_widget_set_theme_size(ref,
471     // (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
472     #endif
473     g_object_set_data(G_OBJECT(ref), "id", (gpointer)id);
474     g_object_set_data(G_OBJECT(ref), "type", (gpointer)type);
475     gtk_signal_connect(GTK_OBJECT(ref), "clicked",
476     GTK_SIGNAL_FUNC(on_link_id_clicked), appdata);
477    
478     return ref;
479     }
480     #endif
481     return gtk_label_new(str);
482     }
483    
484 harbaum 138
485     GtkWidget *link_icon_button_by_id(appdata_t *appdata, GtkWidget *icon,
486     const char *type, int id) {
487    
488     #ifdef ENABLE_BROWSER_INTERFACE
489     if(id) {
490     GtkWidget *ref = gtk_button_new();
491     gtk_button_set_image(GTK_BUTTON(ref), icon);
492    
493     #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR == 5)
494     // hildon_gtk_widget_set_theme_size(ref,
495     // (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
496     #endif
497     g_object_set_data(G_OBJECT(ref), "id", (gpointer)id);
498     g_object_set_data(G_OBJECT(ref), "type", (gpointer)type);
499     gtk_signal_connect(GTK_OBJECT(ref), "clicked",
500     GTK_SIGNAL_FUNC(on_link_id_clicked), appdata);
501    
502     return ref;
503     }
504     #endif
505     return icon;
506     }
507    
508 harbaum 165 /* left aligned, word wrapped multiline widget */
509     GtkWidget *simple_text_widget(char *text) {
510     GtkWidget *label = gtk_label_new(text);
511    
512     gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
513     gtk_label_set_line_wrap_mode(GTK_LABEL(label), PANGO_WRAP_WORD);
514     gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
515    
516     return label;
517     }