Ticket #609: osd_core.c.mod

File osd_core.c.mod, 46.2 KB (added by tegzed, 11 years ago)

Patch for initial functional version of speed_warner

Line 
1/**
2 * Navit, a modular navigation system.
3 * Copyright (C) 2005-2008 Navit Team
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * version 2 as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA  02110-1301, USA.
18 */
19
20#include <math.h>
21#include <stdio.h>
22#include <glib.h>
23#include <time.h>
24#include <stdlib.h>
25#include <string.h>
26#include "config.h"
27#include "item.h"
28#include "point.h"
29#include "coord.h"
30#include "graphics.h"
31#include "transform.h"
32#include "route.h"
33#include "navit.h"
34#include "plugin.h"
35#include "debug.h"
36#include "callback.h"
37#include "color.h"
38#include "vehicle.h"
39#include "navigation.h"
40#include "track.h"
41#include "map.h"
42#include "file.h"
43#include "attr.h"
44#include "command.h"
45#include "navit_nls.h"
46#include "messages.h"
47#include "vehicleprofile.h"
48#include "roadprofile.h"
49#include "osd.h"
50#include "speech.h"
51
52struct compass {
53        struct osd_item osd_item;
54        int width;
55        struct graphics_gc *green;
56};
57
58static void
59transform_rotate(struct point *center, int angle, struct point *p,
60                 int count)
61{
62        int i, x, y;
63        double dx, dy;
64        for (i = 0; i < count; i++) {
65                dx = sin(M_PI * angle / 180.0);
66                dy = cos(M_PI * angle / 180.0);
67                x = dy * p->x - dx * p->y;
68                y = dx * p->x + dy * p->y;
69
70                p->x = center->x + x;
71                p->y = center->y + y;
72                p++;
73        }
74}
75
76static void
77handle(struct graphics *gr, struct graphics_gc *gc, struct point *p, int r,
78       int dir)
79{
80        struct point ph[3];
81        int l = r * 0.4;
82
83        ph[0].x = 0;
84        ph[0].y = r;
85        ph[1].x = 0;
86        ph[1].y = -r;
87        transform_rotate(p, dir, ph, 2);
88        graphics_draw_lines(gr, gc, ph, 2);
89        ph[0].x = -l;
90        ph[0].y = -r + l;
91        ph[1].x = 0;
92        ph[1].y = -r;
93        ph[2].x = l;
94        ph[2].y = -r + l;
95        transform_rotate(p, dir, ph, 3);
96        graphics_draw_lines(gr, gc, ph, 3);
97}
98
99/**
100 * * Format distance, choosing the unit (m or km) and precision depending on distance
101 * *
102 * * @param distance distance in meters
103 * * @param sep separator character to be inserted between distance value and unit
104 * * @returns a pointer to a string containing the formatted distance
105 * */
106static char *
107format_distance(double distance, char *sep)
108{
109        if (distance >= 100000)
110                return g_strdup_printf("%.0f%skm", distance / 1000, sep);
111        else if (distance >= 10000)
112                return g_strdup_printf("%.1f%skm", distance / 1000, sep);
113        else if (distance >= 300)
114                return g_strdup_printf("%.0f%sm", round(distance / 25) * 25, sep);
115        else if (distance >= 50)
116                return g_strdup_printf("%.0f%sm", round(distance / 10) * 10, sep);
117        else if (distance >= 10)
118                return g_strdup_printf("%.0f%sm", distance, sep);
119        else
120                return g_strdup_printf("%.1f%sm", distance, sep);
121}
122
123/**
124 * * Format time (duration)
125 * *
126 * * @param tm pointer to a tm structure specifying the time
127 * * @param days days
128 * * @returns a pointer to a string containing the formatted time
129 * */
130static char *
131format_time(struct tm *tm, int days)
132{
133        if (days)
134                return g_strdup_printf("%d+%02d:%02d", days, tm->tm_hour, tm->tm_min);
135        else
136                return g_strdup_printf("%02d:%02d", tm->tm_hour, tm->tm_min);
137}
138
139/**
140 * * Format speed in km/h
141 * *
142 * * @param speed speed in km/h
143 * * @param sep separator character to be inserted between speed value and unit
144 * * @returns a pointer to a string containing the formatted speed
145 * */
146static char *
147format_speed(double speed, char *sep)
148{
149        return g_strdup_printf("%.0f%skm/h", speed, sep);
150}
151
152/*static char *
153format_float(double num)
154{
155        return g_strdup_printf("%f", num);
156}*/
157
158static char *
159format_float_0(double num)
160{
161        return g_strdup_printf("%.0f", num);
162}
163
164static void
165osd_compass_draw(struct compass *this, struct navit *nav,
166                 struct vehicle *v)
167{
168        struct point p,bbox[4];
169        struct attr attr_dir, destination_attr, position_attr;
170        double dir, vdir = 0;
171        char *buffer;
172        struct coord c1, c2;
173        enum projection pro;
174
175        osd_std_draw(&this->osd_item);
176        p.x = this->osd_item.w/2;
177        p.y = this->osd_item.w/2;
178        graphics_draw_circle(this->osd_item.gr,
179                             this->osd_item.graphic_fg_white, &p, this->osd_item.w*5/6);
180        if (v) {
181                if (vehicle_get_attr(v, attr_position_direction, &attr_dir, NULL)) {
182                        vdir = *attr_dir.u.numd;
183                        handle(this->osd_item.gr, this->osd_item.graphic_fg_white, &p, this->osd_item.w/3, -vdir);
184                }
185
186                if (navit_get_attr(nav, attr_destination, &destination_attr, NULL)
187                    && vehicle_get_attr(v, attr_position_coord_geo,&position_attr, NULL)) {
188                        pro = destination_attr.u.pcoord->pro;
189                        transform_from_geo(pro, position_attr.u.coord_geo, &c1);
190                        c2.x = destination_attr.u.pcoord->x;
191                        c2.y = destination_attr.u.pcoord->y;
192                        dir = atan2(c2.x - c1.x, c2.y - c1.y) * 180.0 / M_PI;
193                        dir -= vdir;
194                        handle(this->osd_item.gr, this->green, &p, this->osd_item.w/3, dir);
195                        buffer=format_distance(transform_distance(pro, &c1, &c2),"");
196                        graphics_get_text_bbox(this->osd_item.gr, this->osd_item.font, buffer, 0x10000, 0, bbox, 0);
197                        p.x=(this->osd_item.w-bbox[2].x)/2;
198                        p.y = this->osd_item.h-this->osd_item.h/10;
199                        graphics_draw_text(this->osd_item.gr, this->green, NULL, this->osd_item.font, buffer, &p, 0x10000, 0);
200                        g_free(buffer);
201                }
202        }
203        graphics_draw_mode(this->osd_item.gr, draw_mode_end);
204}
205
206
207
208static void
209osd_compass_init(struct compass *this, struct navit *nav)
210{
211        struct color c;
212
213        osd_set_std_graphic(nav, &this->osd_item, (struct osd_priv *)this);
214
215        this->green = graphics_gc_new(this->osd_item.gr);
216        c.r = 0;
217        c.g = 65535;
218        c.b = 0;
219        c.a = 65535;
220        graphics_gc_set_foreground(this->green, &c);
221        graphics_gc_set_linewidth(this->green, this->width);
222        graphics_gc_set_linewidth(this->osd_item.graphic_fg_white, this->width);
223
224        navit_add_callback(nav, callback_new_attr_1(callback_cast(osd_compass_draw), attr_position_coord_geo, this));
225
226        osd_compass_draw(this, nav, NULL);
227}
228
229static struct osd_priv *
230osd_compass_new(struct navit *nav, struct osd_methods *meth,
231                struct attr **attrs)
232{
233        struct compass *this = g_new0(struct compass, 1);
234        struct attr *attr;
235        this->osd_item.p.x = 20;
236        this->osd_item.p.y = 20;
237        this->osd_item.w = 60;
238        this->osd_item.h = 80;
239        this->osd_item.navit = nav;
240        this->osd_item.font_size = 200;
241        this->osd_item.meth.draw = osd_draw_cast(osd_compass_draw);
242        osd_set_std_attr(attrs, &this->osd_item, 2);
243        attr = attr_search(attrs, NULL, attr_width);
244        this->width=attr ? attr->u.num : 2;
245        navit_add_callback(nav, callback_new_attr_1(callback_cast(osd_compass_init), attr_graphics_ready, this));
246        return (struct osd_priv *) this;
247}
248
249struct osd_button {
250        int use_overlay;
251        struct osd_item item;
252        struct callback *draw_cb,*navit_init_cb;
253        struct graphics_image *img;
254        char *src;
255};
256
257static void
258osd_button_draw(struct osd_button *this, struct navit *nav)
259{
260        struct point bp = this->item.p;
261        osd_wrap_point(&bp, nav);
262        graphics_draw_image(this->item.gr, this->item.graphic_bg, &bp, this->img);
263}
264
265static void
266osd_button_init(struct osd_button *this, struct navit *nav)
267{
268        struct graphics *gra = navit_get_graphics(nav);
269        dbg(1, "enter\n");
270        this->img = graphics_image_new(gra, this->src);
271        if (!this->img) {
272                dbg(1, "failed to load '%s'\n", this->src);
273                return;
274        }
275        if (!this->item.w)
276                this->item.w=this->img->width;
277        if (!this->item.h)
278                this->item.h=this->img->height;
279        if (this->use_overlay) {
280                struct graphics_image *img;
281                struct point p;
282                osd_set_std_graphic(nav, &this->item, (struct osd_priv *)this);
283                img=graphics_image_new(this->item.gr, this->src);
284                p.x=(this->item.w-this->img->width)/2;
285                p.y=(this->item.h-this->img->height)/2;
286                osd_std_draw(&this->item);
287                graphics_draw_image(this->item.gr, this->item.graphic_bg, &p, img);
288                graphics_draw_mode(this->item.gr, draw_mode_end);
289                graphics_image_free(this->item.gr, img);
290        } else {
291                this->item.configured=1;
292                this->item.gr=gra;
293                this->item.graphic_bg=graphics_gc_new(this->item.gr);
294                graphics_add_callback(gra, this->draw_cb=callback_new_attr_2(callback_cast(osd_button_draw), attr_postdraw, this, nav));
295        }
296        navit_add_callback(nav, this->navit_init_cb = callback_new_attr_1(callback_cast (osd_std_click), attr_button, &this->item));
297        osd_button_draw(this,nav);
298}
299
300static struct osd_priv *
301osd_button_new(struct navit *nav, struct osd_methods *meth,
302               struct attr **attrs)
303{
304        struct osd_button *this = g_new0(struct osd_button, 1);
305        struct attr *attr;
306
307        this->item.navit = nav;
308        this->item.meth.draw = osd_draw_cast(osd_button_draw);
309
310        osd_set_std_attr(attrs, &this->item, 1);
311
312        attr=attr_search(attrs, NULL, attr_use_overlay);
313        if (attr)
314                this->use_overlay=attr->u.num;
315        if (!this->item.command) {
316                dbg(0, "no command\n");
317                goto error;
318        }
319        attr = attr_search(attrs, NULL, attr_src);
320        if (!attr) {
321                dbg(0, "no src\n");
322                goto error;
323        }
324
325        this->src = graphics_icon_path(attr->u.str);
326
327        navit_add_callback(nav, this->navit_init_cb = callback_new_attr_1(callback_cast (osd_button_init), attr_graphics_ready, this));
328
329        return (struct osd_priv *) this;
330      error:
331        g_free(this);
332        return NULL;
333}
334
335struct osd_image {
336        int use_overlay;
337        struct osd_item item;
338        struct callback *draw_cb,*navit_init_cb;
339        struct graphics_image *img;
340        char *src;
341};
342
343static void
344osd_image_draw(struct osd_image *this, struct navit *nav)
345{
346        struct point bp = this->item.p;
347        osd_wrap_point(&bp, nav);
348        graphics_draw_image(this->item.gr, this->item.graphic_bg, &bp, this->img);
349}
350
351static void
352osd_image_init(struct osd_image *this, struct navit *nav)
353{
354        struct graphics *gra = navit_get_graphics(nav);
355        dbg(1, "enter\n");
356        this->img = graphics_image_new(gra, this->src);
357        if (!this->img) {
358                dbg(1, "failed to load '%s'\n", this->src);
359                return;
360        }
361        if (!this->item.w)
362                this->item.w=this->img->width;
363        if (!this->item.h)
364                this->item.h=this->img->height;
365        if (this->use_overlay) {
366                struct graphics_image *img;
367                struct point p;
368                osd_set_std_graphic(nav, &this->item, (struct osd_priv *)this);
369                img=graphics_image_new(this->item.gr, this->src);
370                p.x=(this->item.w-this->img->width)/2;
371                p.y=(this->item.h-this->img->height)/2;
372                osd_std_draw(&this->item);
373                graphics_draw_image(this->item.gr, this->item.graphic_bg, &p, img);
374                graphics_draw_mode(this->item.gr, draw_mode_end);
375                graphics_image_free(this->item.gr, img);
376        } else {
377                this->item.configured=1;
378                this->item.gr=gra;
379                this->item.graphic_bg=graphics_gc_new(this->item.gr);
380                graphics_add_callback(gra, this->draw_cb=callback_new_attr_2(callback_cast(osd_button_draw), attr_postdraw, this, nav));
381        }
382        osd_image_draw(this,nav);
383}
384
385static struct osd_priv *
386osd_image_new(struct navit *nav, struct osd_methods *meth,
387               struct attr **attrs)
388{
389        struct osd_image *this = g_new0(struct osd_image, 1);
390        struct attr *attr;
391
392        this->item.navit = nav;
393        this->item.meth.draw = osd_draw_cast(osd_image_draw);
394
395        osd_set_std_attr(attrs, &this->item, 1);
396
397        attr=attr_search(attrs, NULL, attr_use_overlay);
398        if (attr)
399                this->use_overlay=attr->u.num;
400        attr = attr_search(attrs, NULL, attr_src);
401        if (!attr) {
402                dbg(0, "no src\n");
403                goto error;
404        }
405
406        this->src = graphics_icon_path(attr->u.str);
407
408        navit_add_callback(nav, this->navit_init_cb = callback_new_attr_1(callback_cast (osd_image_init), attr_graphics_ready, this));
409
410        return (struct osd_priv *) this;
411      error:
412        g_free(this);
413        return NULL;
414}
415
416struct nav_next_turn {
417        struct osd_item osd_item;
418        char *test_text;
419        char *icon_src;
420        int icon_h, icon_w, active;
421        char *last_name;
422        int level;
423};
424
425static void
426osd_nav_next_turn_draw(struct nav_next_turn *this, struct navit *navit,
427                       struct vehicle *v)
428{
429        struct point p;
430        int do_draw = 0;
431        struct navigation *nav = NULL;
432        struct map *map = NULL;
433        struct map_rect *mr = NULL;
434        struct item *item = NULL;
435        struct graphics_image *gr_image;
436        char *image;
437        char *name = "unknown";
438        int level = this->level;
439
440        if (navit)
441                nav = navit_get_navigation(navit);
442        if (nav)
443                map = navigation_get_map(nav);
444        if (map)
445                mr = map_rect_new(map, NULL);
446        if (mr)
447                while ((item = map_rect_get_item(mr))
448                       && (item->type == type_nav_position || item->type == type_nav_none || level-- > 0));
449        if (item) {
450                name = item_to_name(item->type);
451                dbg(1, "name=%s\n", name);
452                if (this->active != 1 || this->last_name != name) {
453                        this->active = 1;
454                        this->last_name = name;
455                        do_draw = 1;
456                }
457        } else {
458                if (this->active != 0) {
459                        this->active = 0;
460                        do_draw = 1;
461                }
462        }
463        if (mr)
464                map_rect_destroy(mr);
465
466        if (do_draw) {
467                osd_std_draw(&this->osd_item);
468                if (this->active) {
469                        image = g_strdup_printf(this->icon_src, name);
470                        dbg(1, "image=%s\n", image);
471                        gr_image =
472                            graphics_image_new_scaled(this->osd_item.gr,
473                                                      image, this->icon_w,
474                                                      this->icon_h);
475                        if (!gr_image) {
476                                g_free(image);
477                                image = graphics_icon_path("unknown.xpm");
478                                gr_image =
479                                    graphics_image_new_scaled(this->
480                                                              osd_item.gr,
481                                                              image,
482                                                              this->icon_w,
483                                                              this->
484                                                              icon_h);
485                        }
486                        dbg(1, "gr_image=%p\n", gr_image);
487                        if (gr_image) {
488                                p.x =
489                                    (this->osd_item.w -
490                                     gr_image->width) / 2;
491                                p.y =
492                                    (this->osd_item.h -
493                                     gr_image->height) / 2;
494                                graphics_draw_image(this->osd_item.gr,
495                                                    this->osd_item.
496                                                    graphic_fg_white, &p,
497                                                    gr_image);
498                                graphics_image_free(this->osd_item.gr,
499                                                    gr_image);
500                        }
501                        g_free(image);
502                }
503                graphics_draw_mode(this->osd_item.gr, draw_mode_end);
504        }
505}
506
507static void
508osd_nav_next_turn_init(struct nav_next_turn *this, struct navit *nav)
509{
510        osd_set_std_graphic(nav, &this->osd_item, (struct osd_priv *)this);
511        navit_add_callback(nav, callback_new_attr_1(callback_cast(osd_nav_next_turn_draw), attr_position_coord_geo, this));
512        navit_add_callback(nav, callback_new_attr_1(callback_cast(osd_std_click), attr_button, &this->osd_item));
513        osd_nav_next_turn_draw(this, nav, NULL);
514}
515
516static struct osd_priv *
517osd_nav_next_turn_new(struct navit *nav, struct osd_methods *meth,
518                      struct attr **attrs)
519{
520        struct nav_next_turn *this = g_new0(struct nav_next_turn, 1);
521        struct attr *attr;
522
523        this->osd_item.p.x = 20;
524        this->osd_item.p.y = -80;
525        this->osd_item.w = 70;
526        this->osd_item.navit = nav;
527        this->osd_item.h = 70;
528        this->osd_item.font_size = 200;
529        this->osd_item.meth.draw = osd_draw_cast(osd_nav_next_turn_draw);
530        osd_set_std_attr(attrs, &this->osd_item, 0);
531
532        this->icon_w = -1;
533        this->icon_h = -1;
534        this->active = -1;
535        this->level  = 0;
536
537        attr = attr_search(attrs, NULL, attr_icon_w);
538        if (attr)
539                this->icon_w = attr->u.num;
540
541        attr = attr_search(attrs, NULL, attr_icon_h);
542        if (attr)
543                this->icon_h = attr->u.num;
544
545        attr = attr_search(attrs, NULL, attr_icon_src);
546        if (attr) {
547                struct file_wordexp *we;
548                char **array;
549                we = file_wordexp_new(attr->u.str);
550                array = file_wordexp_get_array(we);
551                this->icon_src = graphics_icon_path(array[0]);
552                file_wordexp_destroy(we);
553        } else {
554                this->icon_src = graphics_icon_path("%s_wh.svg");
555        }
556       
557        attr = attr_search(attrs, NULL, attr_level);
558        if (attr)
559                this->level=attr->u.num;
560
561        navit_add_callback(nav, callback_new_attr_1(callback_cast(osd_nav_next_turn_init), attr_graphics_ready, this));
562        return (struct osd_priv *) this;
563}
564
565struct nav_toggle_announcer
566{
567        int w,h;
568        struct callback *navit_init_cb;
569        struct osd_item item;
570        char *icon_src;
571        int icon_h, icon_w, active, last_state;
572};
573
574static void
575osd_nav_toggle_announcer_draw(struct nav_toggle_announcer *this, struct navit *navit, struct vehicle *v)
576{
577        struct point p;
578        int do_draw = 0;
579        struct graphics_image *gr_image;
580        char *path;
581        char *gui_sound_off = "gui_sound_off";
582        char *gui_sound_on = "gui_sound";
583    struct attr attr, speechattr;
584
585    if (this->last_state == -1)
586    {
587        if (!navit_get_attr(navit, attr_speech, &speechattr, NULL))
588            if (!speech_get_attr(speechattr.u.speech, attr_active, &attr, NULL))
589                attr.u.num = 1;
590        this->active = attr.u.num;
591    } else
592        this->active = !this->active;
593
594    if(this->active != this->last_state)
595    {
596        this->last_state = this->active;
597        do_draw = 1;
598    }
599
600        if (do_draw)
601    {
602                graphics_draw_mode(this->item.gr, draw_mode_begin);
603                p.x = 0;
604                p.y = 0;
605                graphics_draw_rectangle(this->item.gr, this->item.graphic_bg, &p, this->item.w, this->item.h);
606
607                if (this->active)
608            path = g_strdup_printf(this->icon_src, gui_sound_on);
609        else
610            path = g_strdup_printf(this->icon_src, gui_sound_off);
611       
612        gr_image = graphics_image_new_scaled(this->item.gr, path, this->icon_w, this->icon_h);
613        if (!gr_image)
614        {
615            g_free(path);
616            path = graphics_icon_path("unknown.xpm");
617            gr_image = graphics_image_new_scaled(this->item.gr, path, this->icon_w, this->icon_h);
618        }
619       
620        dbg(1, "gr_image=%p\n", gr_image);
621       
622        if (gr_image)
623        {
624            p.x = (this->item.w - gr_image->width) / 2;
625            p.y = (this->item.h - gr_image->height) / 2;
626            graphics_draw_image(this->item.gr, this->item.graphic_fg_white, &p, gr_image);
627            graphics_image_free(this->item.gr, gr_image);
628        }
629       
630        g_free(path);
631                graphics_draw_mode(this->item.gr, draw_mode_end);
632        }
633}
634
635static void
636osd_nav_toggle_announcer_init(struct nav_toggle_announcer *this, struct navit *nav)
637{
638        osd_set_std_graphic(nav, &this->item, (struct osd_priv *)this);
639        navit_add_callback(nav, callback_new_attr_1(callback_cast(osd_nav_toggle_announcer_draw), attr_speech, this));
640    navit_add_callback(nav, this->navit_init_cb = callback_new_attr_1(callback_cast(osd_std_click), attr_button, &this->item));
641        osd_nav_toggle_announcer_draw(this, nav, NULL);
642}
643
644static struct osd_priv *
645osd_nav_toggle_announcer_new(struct navit *nav, struct osd_methods *meth, struct attr **attrs)
646{
647        struct nav_toggle_announcer *this = g_new0(struct nav_toggle_announcer, 1);
648    struct attr *attr;
649    char *command = "announcer_toggle()";
650
651        this->item.w = 48;
652        this->item.h = 48;
653        this->item.p.x = -64;
654        this->item.navit = nav;
655        this->item.p.y = 76;
656        this->item.meth.draw = osd_draw_cast(osd_nav_toggle_announcer_draw);
657
658        osd_set_std_attr(attrs, &this->item, 0);
659
660        this->icon_w = -1;
661        this->icon_h = -1;
662    this->last_state = -1;
663
664    attr = attr_search(attrs, NULL, attr_icon_src);
665        if (attr) {
666                struct file_wordexp *we;
667                char **array;
668                we = file_wordexp_new(attr->u.str);
669                array = file_wordexp_get_array(we);
670                this->icon_src = g_strdup(array[0]);
671                file_wordexp_destroy(we);
672        } else
673                this->icon_src = graphics_icon_path("%s_32.xpm");
674
675    this->item.command = g_strdup(command);
676
677        navit_add_callback(nav, callback_new_attr_1(callback_cast(osd_nav_toggle_announcer_init), attr_graphics_ready, this));
678        return (struct osd_priv *) this;
679}
680
681struct osd_speed_warner {
682        struct osd_item item;
683        struct graphics_gc *red;
684        struct graphics_gc *green;
685        struct graphics_gc *grey;
686        int width;
687        int active;
688        int d;
689    enum eAnnounceState {eNoWarn=0,eWarningTold=1};
690        enum eAnnounceState announce_state;
691};
692
693static void
694osd_speed_warner_draw(struct osd_speed_warner *this, struct navit *navit, struct vehicle *v)
695{
696        struct point p[4];
697        char *text="60";
698
699        osd_std_draw(&this->item);
700        p[0].x=this->item.w/2-this->d/4;
701        p[0].y=this->item.h/2-this->d/4;
702        graphics_draw_rectangle(this->item.gr, this->item.graphic_fg_white, p, this->d/2, this->d/2);
703        p[0].x=this->item.w/2;
704        p[0].y=this->item.h/2;
705        graphics_draw_circle(this->item.gr, this->item.graphic_fg_white, p, this->d/2);
706
707        struct tracking *tracking = NULL;
708    struct graphics_gc *osd_color=this->grey;
709
710    if (navit) {
711        tracking = navit_get_tracking(navit);
712    }
713    if (tracking) {
714
715        struct attr maxspeed_attr,speed_attr;
716        struct item *item;
717        item=tracking_get_current_item(tracking);
718        double routespeed = -1;
719        double tracking_speed = -1;
720        const double speed_exceed_limit = 15; //km/h
721
722        int *flags=tracking_get_current_flags(tracking);
723        if (flags && (*flags & AF_SPEED_LIMIT) && tracking_get_attr(tracking, attr_maxspeed, &maxspeed_attr, NULL)) {
724            routespeed = maxspeed_attr.u.num;
725        }
726        if (routespeed == -1) {
727            struct vehicleprofile *prof=navit_get_vehicleprofile(navit);
728            struct roadprofile *rprof=NULL;
729            if (prof && item)
730                rprof=vehicleprofile_get_roadprofile(prof, item->type);
731            if (rprof) {
732                routespeed=rprof->speed;
733            }
734        }
735
736        tracking_get_attr(tracking, attr_position_speed, &speed_attr, NULL);
737        tracking_speed = *speed_attr.u.numd;
738        if( -1 != tracking_speed && -1 != routespeed ) {
739            if( speed_exceed_limit+routespeed < tracking_speed) {
740                osd_color = this->red;
741                if(this->announce_state==eNoWarn) {
742                    this->announce_state=eWarningTold; //warning told
743                    navit_say(navit,_("Please decrease your speed"));
744                }
745            } else {
746                osd_color = this->green;
747            }
748
749            if( tracking_speed <= routespeed ) {
750                this->announce_state=eNoWarn; //no warning
751            }
752        } else {
753            osd_color = this->grey;
754        }
755
756    } else {
757        //when tracking is not available display grey
758            osd_color = this->grey;
759    }
760    graphics_draw_circle(this->item.gr, osd_color, p, this->d-this->width*2);
761
762        graphics_get_text_bbox(this->item.gr, this->item.font, text, 0x10000, 0, p, 0);
763        p[0].x=(this->item.w-p[2].x)/2;
764        p[0].y=(this->item.h+p[2].y)/2-p[2].y;
765        graphics_draw_text(this->item.gr, this->item.graphic_fg_text, NULL, this->item.font, text, p, 0x10000, 0);
766        graphics_draw_mode(this->item.gr, draw_mode_end);
767}
768
769static void
770osd_speed_warner_init(struct osd_speed_warner *this, struct navit *nav)
771{
772        osd_set_std_graphic(nav, &this->item, (struct osd_priv *)this);
773        navit_add_callback(nav, callback_new_attr_1(callback_cast(osd_speed_warner_draw), attr_position_coord_geo, this));
774
775        this->red=graphics_gc_new(this->item.gr);
776        graphics_gc_set_foreground(this->red, &(struct color ){0xffff,0,0,0xffff});
777        graphics_gc_set_linewidth(this->red, this->width);
778
779        this->green=graphics_gc_new(this->item.gr);
780        graphics_gc_set_foreground(this->green, &(struct color ){0,0xffff,0,0xffff});
781        graphics_gc_set_linewidth(this->green, this->width);
782
783        this->grey=graphics_gc_new(this->item.gr);
784        graphics_gc_set_foreground(this->grey, &(struct color ){0x8888,0x8888,0x8888,0x8888});
785        graphics_gc_set_linewidth(this->grey, this->width);
786
787        graphics_gc_set_linewidth(this->item.graphic_fg_white, this->d/4+2);
788        osd_speed_warner_draw(this, nav, NULL);
789}
790
791static struct osd_priv *
792osd_speed_warner_new(struct navit *nav, struct osd_methods *meth, struct attr **attrs)
793{
794        struct osd_speed_warner *this=g_new0(struct osd_speed_warner, 1);
795        this->item.p.x=-80;
796        this->item.p.y=20;
797        this->item.w=60;
798        this->item.navit = nav;
799        this->item.h=60;
800        this->active=-1;
801        this->item.meth.draw = osd_draw_cast(osd_speed_warner_draw);
802        osd_set_std_attr(attrs, &this->item, 2);
803        this->d=this->item.w;
804        if (this->item.h < this->d)
805                this->d=this->item.h;
806        this->width=this->d/10;
807        navit_add_callback(nav, callback_new_attr_1(callback_cast(osd_speed_warner_init), attr_graphics_ready, this));
808        return (struct osd_priv *) this;
809}
810
811struct osd_text_item {
812    int static_text;
813    char *text;
814    void *prev;
815    void *next;
816    enum attr_type section;
817    enum attr_type attr_typ;
818    void *root;
819    int offset;
820    char *format;
821};
822
823struct osd_text {
824        struct osd_item osd_item;
825        int active;
826        char *text;
827        int align;
828        char *last;
829        struct osd_text_item *items;
830};
831
832
833static char *
834osd_text_format_attr(struct attr *attr, char *format)
835{
836        struct tm tm, text_tm, text_tm0;
837        time_t textt;
838        int days=0;
839        char buffer[1024];
840
841        switch (attr->type) {
842        case attr_position_speed:
843                return format_speed(*attr->u.numd,"");
844        case attr_position_height:
845        case attr_position_direction:
846                return format_float_0(*attr->u.numd);
847        case attr_position_magnetic_direction:
848                return g_strdup_printf("%d",attr->u.num);
849        case attr_position_coord_geo:
850                if ((!format) || (!strcmp(format,"pos_degminsec")))
851                {
852                        coord_format(attr->u.coord_geo->lat,attr->u.coord_geo->lng,DEGREES_MINUTES_SECONDS,buffer,sizeof(buffer));
853                        return g_strdup(buffer);
854                }
855                else if (!strcmp(format,"pos_degmin"))
856                {
857                        coord_format(attr->u.coord_geo->lat,attr->u.coord_geo->lng,DEGREES_MINUTES,buffer,sizeof(buffer));
858                        return g_strdup(buffer);
859                }
860                else if (!strcmp(format,"pos_deg"))
861                {
862                        coord_format(attr->u.coord_geo->lat,attr->u.coord_geo->lng,DEGREES_DECIMAL,buffer,sizeof(buffer));
863                        return g_strdup(buffer);
864                }
865                else if (!strcmp(format,"lat_degminsec"))
866                {
867                        coord_format(attr->u.coord_geo->lat,360,DEGREES_MINUTES_SECONDS,buffer,sizeof(buffer));
868                        return g_strdup(buffer);
869                }
870                else if (!strcmp(format,"lat_degmin"))
871                {
872                        coord_format(attr->u.coord_geo->lat,360,DEGREES_MINUTES,buffer,sizeof(buffer));
873                        return g_strdup(buffer);
874                }
875                else if (!strcmp(format,"lat_deg"))
876                {
877                        coord_format(attr->u.coord_geo->lat,360,DEGREES_DECIMAL,buffer,sizeof(buffer));
878                        return g_strdup(buffer);
879                }
880                else if (!strcmp(format,"lng_degminsec"))
881                {
882                        coord_format(360,attr->u.coord_geo->lng,DEGREES_MINUTES_SECONDS,buffer,sizeof(buffer));
883                        return g_strdup(buffer);
884                }
885                else if (!strcmp(format,"lng_degmin"))
886                {
887                        coord_format(360,attr->u.coord_geo->lng,DEGREES_MINUTES,buffer,sizeof(buffer));
888                        return g_strdup(buffer);
889                }
890                else if (!strcmp(format,"lng_deg"))
891                {
892                        coord_format(360,attr->u.coord_geo->lng,DEGREES_DECIMAL,buffer,sizeof(buffer));
893                        return g_strdup(buffer);
894                }
895                else
896                { // fall back to pos_degminsec
897                        coord_format(attr->u.coord_geo->lat,attr->u.coord_geo->lng,DEGREES_MINUTES_SECONDS,buffer,sizeof(buffer));
898                        return g_strdup(buffer);
899                }
900        case attr_destination_time:
901                if (!format || (strcmp(format,"arrival") && strcmp(format,"remaining")))
902                        break;
903                textt = time(NULL);
904                tm = *localtime(&textt);
905                if (!strcmp(format,"remaining")) {
906                        textt-=tm.tm_hour*3600+tm.tm_min*60+tm.tm_sec;
907                        tm = *localtime(&textt);
908                }
909                textt += attr->u.num / 10;
910                text_tm = *localtime(&textt);
911                if (tm.tm_year != text_tm.tm_year || tm.tm_mon != text_tm.tm_mon || tm.tm_mday != text_tm.tm_mday) {
912                        text_tm0 = text_tm;
913                        text_tm0.tm_sec = 0;
914                        text_tm0.tm_min = 0;
915                        text_tm0.tm_hour = 0;
916                        tm.tm_sec = 0;
917                        tm.tm_min = 0;
918                        tm.tm_hour = 0;
919                        days = (mktime(&text_tm0) - mktime(&tm) + 43200) / 86400;
920                        }
921                return format_time(&text_tm, days);
922        case attr_length:
923        case attr_destination_length:
924                if (!format)
925                        break;
926                if (!strcmp(format,"named"))
927                        return format_distance(attr->u.num,"");
928                if (!strcmp(format,"value") || !strcmp(format,"unit")) {
929                        char *ret,*tmp=format_distance(attr->u.num," ");
930                        char *pos=strchr(tmp,' ');
931                        if (! pos)
932                                return tmp;
933                        *pos++='\0';
934                        if (!strcmp(format,"value"))
935                                return tmp;
936                        ret=g_strdup(pos);
937                        g_free(tmp);
938                        return ret;
939                }
940        default:
941                break;
942        }
943        return attr_to_text(attr, NULL, 1);
944}
945
946/**
947 * * Parse a string of the form key.subkey or key[index].subkey into its components, where subkey can itself have its own index and further subkeys
948 * *
949 * * @param in string to parse (will be modified by the function); upon returning this pointer will point to a string containing key
950 * * @param index pointer to an address that will receive a pointer to a string containing index or a null pointer if key does not have an index
951 * * @returns a pointer to a string containing subkey, i.e. everything following the first period; if no subkey was found, the return value is a pointer to an empty string; if errors are encountered (index with missing closed bracket or passing a null pointer as index argument when an index was encountered), the return value is NULL
952 * */
953static char *
954osd_text_split(char *in, char **index)
955{
956        char *pos;
957        int len;
958        if (index)
959                *index=NULL;
960        len=strcspn(in,"[.");
961        in+=len;
962        switch (in[0]) {
963        case '\0':
964                return in;
965        case '.':
966                *in++='\0';
967                return in;
968        case '[':
969                if (!index)
970                        return NULL;
971                *in++='\0';
972                *index=in;
973                pos=strchr(in,']');
974                if (pos) {
975                        *pos++='\0';
976                        if (*pos == '.') {
977                                *pos++='\0';
978                        }
979                        return pos;
980                }
981                return NULL;
982        }
983        return NULL;
984}
985
986static void
987osd_text_draw(struct osd_text *this, struct navit *navit, struct vehicle *v)
988{
989        struct point p, p2[4];
990        char *str,*last,*next,*value,*absbegin;
991        int do_draw = 0;
992        struct attr attr, vehicle_attr, maxspeed_attr;
993        struct navigation *nav = NULL;
994        struct tracking *tracking = NULL;
995        struct route *route = NULL;
996        struct map *nav_map = NULL;
997        struct map_rect *nav_mr = NULL;
998        struct item *item;
999        struct osd_text_item *oti;
1000        int offset,lines;
1001        int height=this->osd_item.font_size*13/256;
1002        int yspacing=height/2;
1003        int xspacing=height/4;
1004
1005        vehicle_attr.u.vehicle=NULL;
1006        oti=this->items;
1007        str=NULL;
1008
1009        while (oti) {
1010
1011                item=NULL;
1012                value=NULL;
1013
1014                if (oti->static_text) {
1015                        value=g_strdup(oti->text);
1016                } else if (oti->section == attr_navigation) {
1017                        if (navit && !nav)
1018                                nav = navit_get_navigation(navit);
1019                        if (nav && !nav_map)
1020                                nav_map = navigation_get_map(nav);
1021                        if (nav_map )
1022                                nav_mr = map_rect_new(nav_map, NULL);
1023                        if (nav_mr)
1024                                item = map_rect_get_item(nav_mr);
1025
1026                        offset=oti->offset;
1027                        while (item) {
1028                                if (item->type == type_nav_none)
1029                                        item=map_rect_get_item(nav_mr);
1030                                else if (!offset)
1031                                        break;
1032                                else {
1033                                        offset--;
1034                                        item=map_rect_get_item(nav_mr);
1035                                }
1036                        }
1037
1038                        if (item) {
1039                                dbg(1,"name %s\n", item_to_name(item->type));
1040                                dbg(1,"type %s\n", attr_to_name(oti->attr_typ));
1041                                if (item_attr_get(item, oti->attr_typ, &attr))
1042                                        value=osd_text_format_attr(&attr, oti->format);
1043                        }
1044                        if (nav_mr)
1045                                map_rect_destroy(nav_mr);
1046                } else if (oti->section == attr_vehicle) {
1047                        if (navit && !vehicle_attr.u.vehicle) {
1048                                navit_get_attr(navit, attr_vehicle, &vehicle_attr, NULL);
1049                        }
1050                        if (vehicle_attr.u.vehicle) {
1051                                if (vehicle_get_attr(vehicle_attr.u.vehicle, oti->attr_typ, &attr, NULL)) {
1052                                        value=osd_text_format_attr(&attr, oti->format);
1053                                }
1054                        }
1055                } else if (oti->section == attr_tracking) {
1056                        if (navit) {
1057                                tracking = navit_get_tracking(navit);
1058                                route = navit_get_route(navit);
1059                        }
1060                        if (tracking) {
1061                                item=tracking_get_current_item(tracking);
1062                                if (item && (oti->attr_typ == attr_speed)) {
1063                                        double routespeed = -1;
1064                                        int *flags=tracking_get_current_flags(tracking);
1065                                        if (flags && (*flags & AF_SPEED_LIMIT) && tracking_get_attr(tracking, attr_maxspeed, &maxspeed_attr, NULL)) {
1066                                                routespeed = maxspeed_attr.u.num;
1067                                                value = format_speed(routespeed, "");
1068                                        }
1069
1070                                        if (routespeed == -1) {
1071                                                struct vehicleprofile *prof=navit_get_vehicleprofile(navit);
1072                                                struct roadprofile *rprof=NULL;
1073                                                if (prof)
1074                                                        rprof=vehicleprofile_get_roadprofile(prof, item->type);
1075                                                if (rprof) {
1076                                                        routespeed=rprof->speed;
1077                                                        value=format_speed(routespeed,"");
1078                                                }
1079                                        }
1080                                } else if (item) {
1081                                        if (tracking_get_attr(tracking, oti->attr_typ, &attr, NULL))
1082                                                value=osd_text_format_attr(&attr, oti->format);
1083                                }
1084                        }
1085
1086                } else if (oti->section == attr_navit) {
1087                        if (oti->attr_typ == attr_message) {
1088                                struct message *msg;
1089                                int len,offset;
1090                                char *tmp;
1091
1092                                msg = navit_get_messages(navit);
1093                                len = 0;
1094                                while (msg) {
1095                                        len+= strlen(msg->text) + 2;
1096
1097                                        msg = msg->next;
1098                                }
1099
1100                                value = g_malloc(len +1);
1101
1102                                msg = navit_get_messages(navit);
1103                                offset = 0;
1104                                while (msg) {
1105                                        tmp = g_stpcpy((value+offset), msg->text);
1106                                        g_stpcpy(tmp, "\\n");
1107                                        offset += strlen(msg->text) + 2;
1108
1109                                        msg = msg->next;
1110                                }
1111
1112                                value[len] = '\0';
1113                        }
1114                }
1115
1116                next=g_strdup_printf("%s%s",str ? str:"",value ? value:" ");
1117                if (value)
1118                        g_free(value);
1119                if (str)
1120                        g_free(str);
1121                str=next;
1122                oti=oti->next;
1123        }
1124
1125        if ( this->last && str && !strcmp(this->last, str) ) {
1126                do_draw=0;
1127        } else {
1128                do_draw=1;
1129                if (this->last)
1130                        g_free(this->last);
1131                this->last = g_strdup(str);
1132        }
1133
1134        absbegin=str;
1135        if (do_draw) {
1136                lines=0;
1137                next=str;
1138                last=str;
1139                while ((next=strstr(next, "\\n"))) {
1140                        last = next;
1141                        lines++;
1142                        next++;
1143                }
1144
1145                while (*last) {
1146                        if (! g_ascii_isspace(*last)) {
1147                                lines++;
1148                                break;
1149                        }
1150                        last++;
1151                }
1152
1153                dbg(1,"this->align=%d\n", this->align);
1154                switch (this->align & 51) {
1155                case 1:
1156                        p.y=0;
1157                        break;
1158                case 2:
1159                        p.y=(this->osd_item.h-lines*(height+yspacing)-yspacing);
1160                        break;
1161                case 16: // Grow from top to bottom
1162                        p.y = 0;
1163                        if (lines != 0) {
1164                                this->osd_item.h = (lines-1) * (height+yspacing) + height;
1165                        } else {
1166                                this->osd_item.h = 0;
1167                        }
1168
1169                        if (do_draw) {
1170                                osd_std_resize(&this->osd_item);
1171                        }
1172                default:
1173                        p.y=(this->osd_item.h-lines*(height+yspacing)-yspacing)/2;
1174                }
1175
1176                osd_std_draw(&this->osd_item);
1177                while (str) {
1178                        next=strstr(str, "\\n");
1179                        if (next) {
1180                                *next='\0';
1181                                next+=2;
1182                        }
1183                        graphics_get_text_bbox(this->osd_item.gr,
1184                                               this->osd_item.font,
1185                                               str, 0x10000,
1186                                               0x0, p2, 0);
1187                        switch (this->align & 12) {
1188                        case 4:
1189                                p.x=xspacing;
1190                                break;
1191                        case 8:
1192                                p.x=this->osd_item.w-(p2[2].x-p2[0].x)-xspacing;
1193                                break;
1194                        default:
1195                                p.x = ((p2[0].x - p2[2].x) / 2) + (this->osd_item.w / 2);
1196                        }
1197                        p.y += height+yspacing;
1198                        graphics_draw_text(this->osd_item.gr,
1199                                           this->osd_item.graphic_fg_text,
1200                                           NULL, this->osd_item.font,
1201                                           str, &p, 0x10000,
1202                                           0);
1203                        str=next;
1204                }
1205                graphics_draw_mode(this->osd_item.gr, draw_mode_end);
1206        }
1207        g_free(absbegin);
1208
1209}
1210
1211struct osd_text_item *
1212oti_new(struct osd_text_item * parent)
1213{
1214    struct osd_text_item *this;
1215    this=g_new0(struct osd_text_item, 1);
1216    this->prev=parent;
1217
1218    if(!parent) {
1219        this->root=this;
1220    } else {
1221        parent->next=this;
1222        this->root=parent->root;
1223    }
1224
1225    return this;
1226}
1227
1228static void
1229osd_text_prepare(struct osd_text *this, struct navit *nav)
1230{
1231        char *absbegin,*str,*start,*end,*key,*subkey,*index;
1232        struct osd_text_item *oti;
1233
1234        oti=NULL;
1235        str=g_strdup(this->text);
1236        absbegin=str;
1237
1238        while ((start=strstr(str, "${"))) {
1239
1240                *start='\0';
1241                start+=2;
1242
1243                // find plain text before
1244                if (start!=str) {
1245                        oti = oti_new(oti);
1246                        oti->static_text=1;
1247                        oti->text=g_strdup(str);
1248
1249                }
1250
1251                end=strstr(start,"}");
1252                if (! end)
1253                        break;
1254
1255                *end++='\0';
1256                key=start;
1257
1258                subkey=osd_text_split(key,NULL);
1259
1260            oti = oti_new(oti);
1261                oti->section=attr_from_name(key);
1262
1263                if (( oti->section == attr_navigation ||
1264                                oti->section == attr_tracking) && subkey) {
1265                    key=osd_text_split(subkey,&index);
1266
1267                        if (index)
1268                                oti->offset=atoi(index);
1269
1270                        subkey=osd_text_split(key,&index);
1271
1272                        if (!strcmp(key,"route_speed")) {
1273                                oti->attr_typ=attr_speed;
1274                        } else {
1275                                oti->attr_typ=attr_from_name(key);
1276                        }
1277                        oti->format = g_strdup(index);
1278
1279                } else if ((oti->section == attr_vehicle || oti->section == attr_navit) && subkey) {
1280                        key=osd_text_split(subkey,&index);
1281                        if (!strcmp(subkey,"messages")) {
1282                                oti->attr_typ=attr_message;
1283                        } else {
1284                                oti->attr_typ=attr_from_name(subkey);
1285                        }
1286                        oti->format = g_strdup(index);
1287                }
1288
1289                switch(oti->attr_typ) {
1290                        default:
1291                                navit_add_callback(nav, callback_new_attr_1(callback_cast(osd_text_draw), attr_position_coord_geo, this));
1292                                break;
1293                }
1294
1295                str=(end);
1296        }
1297
1298        if(*str!='\0'){
1299                oti = oti_new(oti);
1300                oti->static_text=1;
1301                oti->text=g_strdup(str);
1302        }
1303
1304        if (oti)
1305                this->items=oti->root;
1306        else
1307                this->items=NULL;
1308
1309        g_free(absbegin);
1310
1311}
1312
1313static void
1314osd_text_init(struct osd_text *this, struct navit *nav)
1315{
1316
1317        osd_set_std_graphic(nav, &this->osd_item, (struct osd_priv *)this);
1318        navit_add_callback(nav, callback_new_attr_1(callback_cast(osd_std_click), attr_button, &this->osd_item));
1319        osd_text_prepare(this,nav);
1320        osd_text_draw(this, nav, NULL);
1321
1322}
1323
1324static struct osd_priv *
1325osd_text_new(struct navit *nav, struct osd_methods *meth,
1326            struct attr **attrs)
1327{
1328        struct osd_text *this = g_new0(struct osd_text, 1);
1329        struct attr *attr;
1330
1331        this->osd_item.p.x = -80;
1332        this->osd_item.p.y = 20;
1333        this->osd_item.w = 60;
1334        this->osd_item.h = 20;
1335        this->osd_item.navit = nav;
1336        this->osd_item.font_size = 200;
1337        this->osd_item.meth.draw = osd_draw_cast(osd_text_draw);
1338        osd_set_std_attr(attrs, &this->osd_item, 2);
1339
1340        this->active = -1;
1341        this->last = NULL;
1342
1343        attr = attr_search(attrs, NULL, attr_label);
1344        if (attr)
1345                this->text = g_strdup(attr->u.str);
1346        else
1347                this->text = NULL;
1348        attr = attr_search(attrs, NULL, attr_align);
1349        if (attr)
1350                this->align=attr->u.num;
1351
1352        navit_add_callback(nav, callback_new_attr_1(callback_cast(osd_text_init), attr_graphics_ready, this));
1353        return (struct osd_priv *) this;
1354}
1355
1356struct gps_status {
1357        struct osd_item osd_item;
1358        char *icon_src;
1359        int icon_h, icon_w, active;
1360        int strength;
1361};
1362
1363static void
1364osd_gps_status_draw(struct gps_status *this, struct navit *navit,
1365                       struct vehicle *v)
1366{
1367        struct point p;
1368        int do_draw = 0;
1369        struct graphics_image *gr_image;
1370        char *image;
1371        struct attr attr, vehicle_attr;
1372        int strength=-1;
1373
1374        if (navit && navit_get_attr(navit, attr_vehicle, &vehicle_attr, NULL)) {
1375                if (vehicle_get_attr(vehicle_attr.u.vehicle, attr_position_fix_type, &attr, NULL)) {
1376                        switch(attr.u.num) {
1377                        case 1:
1378                        case 2:
1379                                strength=2;
1380                                if (vehicle_get_attr(vehicle_attr.u.vehicle, attr_position_sats_used, &attr, NULL)) {
1381                                        dbg(1,"num=%d\n", attr.u.num);
1382                                        if (attr.u.num >= 3)
1383                                                strength=attr.u.num-1;
1384                                        if (strength > 5)
1385                                                strength=5;
1386                                        if (strength > 3) {
1387                                                if (vehicle_get_attr(vehicle_attr.u.vehicle, attr_position_hdop, &attr, NULL)) {
1388                                                        if (*attr.u.numd > 2.0 && strength > 4)
1389                                                                strength=4;
1390                                                        if (*attr.u.numd > 4.0 && strength > 3)
1391                                                                strength=3;
1392                                                }
1393                                        }
1394                                }
1395                                break;
1396                        default:
1397                                strength=1;
1398                        }
1399                }
1400        }       
1401        if (this->strength != strength) {
1402                this->strength=strength;
1403                do_draw=1;
1404        }
1405        if (do_draw) {
1406                osd_std_draw(&this->osd_item);
1407                if (this->active) {
1408                        image = g_strdup_printf(this->icon_src, strength);
1409                        gr_image = graphics_image_new_scaled(this->osd_item.gr, image, this->icon_w, this->icon_h);
1410                        if (gr_image) {
1411                                p.x = (this->osd_item.w - gr_image->width) / 2;
1412                                p.y = (this->osd_item.h - gr_image->height) / 2;
1413                                graphics_draw_image(this->osd_item.gr, this->osd_item.  graphic_fg_white, &p, gr_image);
1414                                graphics_image_free(this->osd_item.gr, gr_image);
1415                        }
1416                        g_free(image);
1417                }
1418                graphics_draw_mode(this->osd_item.gr, draw_mode_end);
1419        }
1420}
1421
1422static void
1423osd_gps_status_init(struct gps_status *this, struct navit *nav)
1424{
1425        osd_set_std_graphic(nav, &this->osd_item, (struct osd_priv *)this);
1426        navit_add_callback(nav, callback_new_attr_1(callback_cast(osd_gps_status_draw), attr_position_coord_geo, this));
1427        osd_gps_status_draw(this, nav, NULL);
1428}
1429
1430static struct osd_priv *
1431osd_gps_status_new(struct navit *nav, struct osd_methods *meth,
1432                      struct attr **attrs)
1433{
1434        struct gps_status *this = g_new0(struct gps_status, 1);
1435        struct attr *attr;
1436
1437        this->osd_item.p.x = 20;
1438        this->osd_item.p.y = -80;
1439        this->osd_item.w = 60;
1440        this->osd_item.navit = nav;
1441        this->osd_item.h = 40;
1442        this->osd_item.font_size = 200;
1443        this->osd_item.meth.draw = osd_draw_cast(osd_gps_status_draw);
1444        osd_set_std_attr(attrs, &this->osd_item, 0);
1445
1446        this->icon_w = -1;
1447        this->icon_h = -1;
1448        this->active = -1;
1449        this->strength = -2;
1450
1451        attr = attr_search(attrs, NULL, attr_icon_w);
1452        if (attr)
1453                this->icon_w = attr->u.num;
1454
1455        attr = attr_search(attrs, NULL, attr_icon_h);
1456        if (attr)
1457                this->icon_h = attr->u.num;
1458
1459        attr = attr_search(attrs, NULL, attr_icon_src);
1460        if (attr) {
1461                struct file_wordexp *we;
1462                char **array;
1463                we = file_wordexp_new(attr->u.str);
1464                array = file_wordexp_get_array(we);
1465                this->icon_src = g_strdup(array[0]);
1466                file_wordexp_destroy(we);
1467        } else
1468                this->icon_src = graphics_icon_path("gui_strength_%d_32_32.png");
1469
1470        navit_add_callback(nav, callback_new_attr_1(callback_cast(osd_gps_status_init), attr_graphics_ready, this));
1471        return (struct osd_priv *) this;
1472}
1473
1474
1475struct volume {
1476        struct osd_item osd_item;
1477        char *icon_src;
1478        int icon_h, icon_w, active;
1479        int strength;
1480        struct callback *click_cb;
1481};
1482
1483static void
1484osd_volume_draw(struct volume *this, struct navit *navit)
1485{
1486        struct point p;
1487        struct graphics_image *gr_image;
1488        char *image;
1489
1490        osd_std_draw(&this->osd_item);
1491        if (this->active) {
1492                image = g_strdup_printf(this->icon_src, this->strength);
1493                gr_image = graphics_image_new_scaled(this->osd_item.gr, image, this->icon_w, this->icon_h);
1494                if (gr_image) {
1495                        p.x = (this->osd_item.w - gr_image->width) / 2;
1496                        p.y = (this->osd_item.h - gr_image->height) / 2;
1497                        graphics_draw_image(this->osd_item.gr, this->osd_item.  graphic_fg_white, &p, gr_image);
1498                        graphics_image_free(this->osd_item.gr, gr_image);
1499                }
1500                g_free(image);
1501        }
1502        graphics_draw_mode(this->osd_item.gr, draw_mode_end);
1503}
1504
1505static void
1506osd_volume_click(struct volume *this, struct navit *nav, int pressed, int button, struct point *p)
1507{
1508        struct point bp = this->osd_item.p;
1509        osd_wrap_point(&bp, nav);
1510        if ((p->x < bp.x || p->y < bp.y || p->x > bp.x + this->osd_item.w || p->y > bp.y + this->osd_item.h) && !this->osd_item.pressed)
1511                return;
1512        navit_ignore_button(nav);
1513        if (pressed) {
1514                if (p->y - bp.y < this->osd_item.h/2)
1515                        this->strength++;
1516                else
1517                        this->strength--;
1518                if (this->strength < 0)
1519                        this->strength=0;
1520                if (this->strength > 5)
1521                        this->strength=5;
1522                osd_volume_draw(this, nav);
1523        }
1524}
1525static void
1526osd_volume_init(struct volume *this, struct navit *nav)
1527{
1528        osd_set_std_graphic(nav, &this->osd_item, (struct osd_priv *)this);
1529        navit_add_callback(nav, this->click_cb = callback_new_attr_1(callback_cast (osd_volume_click), attr_button, this));
1530        osd_volume_draw(this, nav);
1531}
1532
1533static struct osd_priv *
1534osd_volume_new(struct navit *nav, struct osd_methods *meth,
1535                      struct attr **attrs)
1536{
1537        struct volume *this = g_new0(struct volume, 1);
1538        struct attr *attr;
1539
1540        this->osd_item.p.x = 20;
1541        this->osd_item.p.y = -80;
1542        this->osd_item.w = 60;
1543        this->osd_item.navit = nav;
1544        this->osd_item.h = 40;
1545        this->osd_item.font_size = 200;
1546        this->osd_item.meth.draw = osd_draw_cast(osd_volume_draw);
1547        osd_set_std_attr(attrs, &this->osd_item, 0);
1548
1549        this->icon_w = -1;
1550        this->icon_h = -1;
1551        this->active = -1;
1552        this->strength = -1;
1553
1554        attr = attr_search(attrs, NULL, attr_icon_w);
1555        if (attr)
1556                this->icon_w = attr->u.num;
1557
1558        attr = attr_search(attrs, NULL, attr_icon_h);
1559        if (attr)
1560                this->icon_h = attr->u.num;
1561
1562        attr = attr_search(attrs, NULL, attr_icon_src);
1563        if (attr) {
1564                struct file_wordexp *we;
1565                char **array;
1566                we = file_wordexp_new(attr->u.str);
1567                array = file_wordexp_get_array(we);
1568                this->icon_src = g_strdup(array[0]);
1569                file_wordexp_destroy(we);
1570        } else
1571                this->icon_src = graphics_icon_path("gui_strength_%d_32_32.png");
1572
1573        navit_add_callback(nav, callback_new_attr_1(callback_cast(osd_volume_init), attr_graphics_ready, this));
1574        return (struct osd_priv *) this;
1575}
1576
1577struct osd_scale {
1578        int use_overlay;
1579        struct osd_item item;
1580        struct callback *draw_cb,*navit_init_cb;
1581        struct graphics_gc *black;
1582};
1583
1584static void
1585osd_scale_draw(struct osd_scale *this, struct navit *nav)
1586{
1587        struct point bp,bp1,bp2;
1588        struct point p[10],bbox[4];
1589        struct coord c[2];
1590        struct attr transformation;
1591        int len;
1592        double dist,exp,base,man;
1593        char *text;
1594        int w=this->item.w*9/10;
1595        int o=(this->item.w-w)/2;
1596
1597        if (!navit_get_attr(nav, attr_transformation, &transformation, NULL))
1598                return;
1599        if (this->use_overlay) {
1600                graphics_draw_mode(this->item.gr, draw_mode_begin);
1601                bp.x=0;
1602                bp.y=0;
1603                graphics_draw_rectangle(this->item.gr, this->item.graphic_bg, &bp, this->item.w, this->item.h);
1604        } else {
1605                bp=this->item.p;
1606                osd_wrap_point(&bp, nav);
1607        }
1608        bp1=bp;
1609        bp1.y+=this->item.h/2;
1610        bp1.x+=o;
1611        bp2=bp1;
1612        bp2.x+=w;
1613        p[0]=bp1;
1614        p[1]=bp2;
1615        transform_reverse(transformation.u.transformation, &p[0], &c[0]);
1616        transform_reverse(transformation.u.transformation, &p[1], &c[1]);
1617        dist=transform_distance(transform_get_projection(transformation.u.transformation), &c[0], &c[1]);
1618        exp=floor(log10(dist));
1619        base=pow(10,exp);
1620        man=dist/base;
1621        if (man >= 5)
1622                man=5;
1623        else if (man >= 2)
1624                man=2;
1625        else
1626                man=1;
1627        len=this->item.w-man*base/dist*w;
1628        p[0].x+=len/2;
1629        p[1].x-=len/2;
1630        p[2]=p[0];
1631        p[3]=p[0];
1632        p[2].y-=this->item.h/10;
1633        p[3].y+=this->item.h/10;
1634        p[4]=p[1];
1635        p[5]=p[1];
1636        p[4].y-=this->item.h/10;
1637        p[5].y+=this->item.h/10;
1638        p[6]=p[2];
1639        p[6].x-=2;
1640        p[6].y-=2;
1641        p[7]=p[0];
1642        p[7].y-=2;
1643        p[8]=p[4];
1644        p[8].x-=2;
1645        p[8].y-=2;
1646        graphics_draw_rectangle(this->item.gr, this->item.graphic_fg_white, p+6, 4,this->item.h/5+4);
1647        graphics_draw_rectangle(this->item.gr, this->item.graphic_fg_white, p+7, p[1].x-p[0].x, 4);
1648        graphics_draw_rectangle(this->item.gr, this->item.graphic_fg_white, p+8, 4,this->item.h/5+4);
1649        graphics_draw_lines(this->item.gr, this->black, p, 2);
1650        graphics_draw_lines(this->item.gr, this->black, p+2, 2);
1651        graphics_draw_lines(this->item.gr, this->black, p+4, 2);
1652        text=format_distance(man*base, "");
1653        graphics_get_text_bbox(this->item.gr, this->item.font, text, 0x10000, 0, bbox, 0);
1654        p[0].x=(this->item.w-bbox[2].x)/2+bp.x;
1655        p[0].y=bp.y+this->item.h-this->item.h/10;
1656        graphics_draw_text(this->item.gr, this->black, this->item.graphic_fg_white, this->item.font, text, &p[0], 0x10000, 0);
1657        g_free(text);
1658        if (this->use_overlay)
1659                graphics_draw_mode(this->item.gr, draw_mode_end);
1660}
1661
1662static void
1663osd_scale_init(struct osd_scale *this, struct navit *nav)
1664{
1665        struct graphics *gra = navit_get_graphics(nav);
1666        dbg(1, "enter\n");
1667        if (this->use_overlay) {
1668                osd_set_std_graphic(nav, &this->item, (struct osd_priv *)this);
1669        } else {
1670                this->item.configured=1;
1671                this->item.gr=gra;
1672                this->item.font = graphics_font_new(this->item.gr, this->item.font_size, 1);
1673                this->item.graphic_fg_white=graphics_gc_new(this->item.gr);
1674                this->item.color_white=COLOR_WHITE;
1675                graphics_gc_set_foreground(this->item.graphic_fg_white, &this->item.color_white);
1676        }
1677        this->black=graphics_gc_new(this->item.gr);
1678        graphics_gc_set_foreground(this->black, &COLOR_BLACK);
1679        graphics_add_callback(gra, this->draw_cb=callback_new_attr_2(callback_cast(osd_scale_draw), attr_postdraw, this, nav));
1680        if (navit_get_ready(nav) == 3)
1681                osd_scale_draw(this, nav);
1682}
1683
1684static struct osd_priv *
1685osd_scale_new(struct navit *nav, struct osd_methods *meth,
1686               struct attr **attrs)
1687{
1688        struct osd_scale *this = g_new0(struct osd_scale, 1);
1689        struct attr *attr;
1690
1691        this->item.navit = nav;
1692        this->item.meth.draw = osd_draw_cast(osd_scale_draw);
1693
1694        osd_set_std_attr(attrs, &this->item, 3);
1695
1696        attr=attr_search(attrs, NULL, attr_use_overlay);
1697        if (attr)
1698                this->use_overlay=attr->u.num;
1699
1700        navit_add_callback(nav, this->navit_init_cb = callback_new_attr_1(callback_cast (osd_scale_init), attr_graphics_ready, this));
1701
1702        return (struct osd_priv *) this;
1703}
1704
1705
1706void
1707plugin_init(void)
1708{
1709        plugin_register_osd_type("compass", osd_compass_new);
1710        plugin_register_osd_type("navigation_next_turn", osd_nav_next_turn_new);
1711        plugin_register_osd_type("button", osd_button_new);
1712        plugin_register_osd_type("toggle_announcer", osd_nav_toggle_announcer_new);
1713        plugin_register_osd_type("speed_warner", osd_speed_warner_new);
1714        plugin_register_osd_type("text", osd_text_new);
1715        plugin_register_osd_type("gps_status", osd_gps_status_new);
1716        plugin_register_osd_type("volume", osd_volume_new);
1717        plugin_register_osd_type("scale", osd_scale_new);
1718                plugin_register_osd_type("image", osd_image_new);
1719}