Diff of /trunk/src/osm-gps-map.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 56 by harbaum, Fri Aug 14 12:19:45 2009 UTC revision 58 by harbaum, Mon Aug 17 10:51:56 2009 UTC
# Line 98  struct _OsmGpsMapPrivate Line 98  struct _OsmGpsMapPrivate
98      coord_t *gps;      coord_t *gps;
99      gboolean gps_valid;      gboolean gps_valid;
100    
101        //a balloon with additional info
102        struct {
103            coord_t *coo;
104            gboolean valid;
105            OsmGpsMapRect_t rect;
106            OsmGpsMapBalloonCallback cb;
107            gpointer data;
108        } balloon;
109    
110      //additional images or tracks added to the map      //additional images or tracks added to the map
111      GSList *tracks;      GSList *tracks;
112      GSList *images;      GSList *images;
# Line 631  osm_gps_map_draw_gps_point (OsmGpsMap *m Line 640  osm_gps_map_draw_gps_point (OsmGpsMap *m
640                                      (mr*2)+lw+lw);                                      (mr*2)+lw+lw);
641  #endif  #endif
642      }      }
643    }
644    
645    /* most visual effects are hardcoded by now, but may be made */
646    /* available via properties later */
647    #define BALLOON_AREA_WIDTH           250
648    #define BALLOON_AREA_HEIGHT           75
649    
650    #define BALLOON_CORNER_RADIUS         20
651    #define BALLOON_BORDER               (BALLOON_CORNER_RADIUS/4)
652    #define BALLOON_WIDTH                (BALLOON_AREA_WIDTH + 2 * BALLOON_BORDER)
653    #define BALLOON_HEIGHT               (BALLOON_AREA_HEIGHT + 2 * BALLOON_BORDER)
654    #define BALLOON_TRANSPARENCY         0.8
655    #define POINTER_HEIGHT                20
656    #define POINTER_FOOT_WIDTH            20
657    #define POINTER_OFFSET               (BALLOON_CORNER_RADIUS*3/4)
658    #define BALLOON_SHADOW                5
659    #define BALLOON_SHADOW_TRANSPARENCY  0.2
660    
661    #define CLOSE_BUTTON_RADIUS   (BALLOON_CORNER_RADIUS/3)
662    
663    
664    /* draw the bubble shape. this is used twice, once for the shape and once */
665    /* for the shadow */
666    static void
667    osm_gps_map_draw_balloon_shape (cairo_t *cr, int x0, int y0, int x1, int y1,
668           gboolean bottom, int px, int py, int px0, int px1) {
669    
670        cairo_move_to (cr, x0, y0 + BALLOON_CORNER_RADIUS);
671        cairo_curve_to (cr, x0 , y0, x0 , y0, x0 + BALLOON_CORNER_RADIUS, y0);
672        if(!bottom) {
673            /* insert top pointer */
674            cairo_line_to (cr, px1, y0);
675            cairo_line_to (cr, px, py);
676            cairo_line_to (cr, px0, y0);
677        }
678    
679        cairo_line_to (cr, x1 - BALLOON_CORNER_RADIUS, y0);
680        cairo_curve_to (cr, x1, y0, x1, y0, x1, y0 + BALLOON_CORNER_RADIUS);
681        cairo_line_to (cr, x1 , y1 - BALLOON_CORNER_RADIUS);
682        cairo_curve_to (cr, x1, y1, x1, y1, x1 - BALLOON_CORNER_RADIUS, y1);
683        if(bottom) {
684            /* insert bottom pointer */
685            cairo_line_to (cr, px0, y1);
686            cairo_line_to (cr, px, py);
687            cairo_line_to (cr, px1, y1);
688        }
689    
690        cairo_line_to (cr, x0 + BALLOON_CORNER_RADIUS, y1);
691        cairo_curve_to (cr, x0, y1, x0, y1, x0, y1 - BALLOON_CORNER_RADIUS);
692    
693        cairo_close_path (cr);
694  }  }
695    
696  /* http://cairographics.org/samples/ */  /* http://cairographics.org/samples/ */
697  static void  static void
698  osm_gps_map_draw_balloon (OsmGpsMap *map)  osm_gps_map_draw_balloon_int (OsmGpsMap *map)
699  {  {
700      OsmGpsMapPrivate *priv = map->priv;      OsmGpsMapPrivate *priv = map->priv;
701    
702      /* xyz */      if (priv->balloon.valid) {
 #define X 100  
 #define Y 100  
 #define RADIUS 20  
 #define WIDTH  150  
 #define HEIGHT 75  
 #define TRANSPARENCY  0.7  
 #define PIN_HEIGHT 20  
 #define PIN_FOOT_WIDTH 20  
 #define PIN_X  (X + EXTRA_BORDER)  
 #define PIN_X0 (X + EXTRA_BORDER + RADIUS + PIN_FOOT_WIDTH)  
 #define PIN_X1 (X + EXTRA_BORDER + RADIUS)  
 #define PIN_Y  (Y + EXTRA_BORDER + HEIGHT + PIN_HEIGHT)  
   
 #ifdef USE_CAIRO  
     cairo_t *cr = gdk_cairo_create(priv->pixmap);  
703    
704      int x0 = X + EXTRA_BORDER, y0 = Y + EXTRA_BORDER;          /* ------- convert given coordinate into screen position --------- */
705      int x1 = x0 + WIDTH, y1 = y0 + HEIGHT;          int x0 = lon2pixel(priv->map_zoom, priv->balloon.coo->rlon) -
706                priv->map_x + EXTRA_BORDER;
707            int y0 = lat2pixel(priv->map_zoom, priv->balloon.coo->rlat) -
708                priv->map_y + EXTRA_BORDER;
709    
710      cairo_move_to (cr, x0, y0 + RADIUS);          /* check position of this relative to screen center to determine */
711      cairo_curve_to (cr, x0 , y0, x0 , y0, x0 + RADIUS, y0);          /* pointer direction ... */
712      cairo_line_to (cr, x1 - RADIUS, y0);          int pointer_x = x0, pointer_x0, pointer_x1;
713      cairo_curve_to (cr, x1, y0, x1, y0, x1, y0 + RADIUS);          int pointer_y = y0;
     cairo_line_to (cr, x1 , y1 - RADIUS);  
     cairo_curve_to (cr, x1, y1, x1, y1, x1 - RADIUS, y1);  
   
     /* insert pin */  
     cairo_line_to (cr, PIN_X0, y1);  
     cairo_line_to (cr, PIN_X, PIN_Y);  
     cairo_line_to (cr, PIN_X1, y1);  
   
714    
715      cairo_line_to (cr, x0 + RADIUS, y1);          /* ... and calculate position */
716      cairo_curve_to (cr, x0, y1, x0, y1, x0, y1 - RADIUS);          if((x0 - EXTRA_BORDER) > GTK_WIDGET(map)->allocation.width/2) {
717                x0 -= BALLOON_WIDTH - POINTER_OFFSET;
718                pointer_x0 = pointer_x - (BALLOON_CORNER_RADIUS - POINTER_OFFSET);
719                pointer_x1 = pointer_x0 - POINTER_FOOT_WIDTH;
720            } else {
721                x0 -= POINTER_OFFSET;
722                pointer_x1 = pointer_x + (BALLOON_CORNER_RADIUS - POINTER_OFFSET);
723                pointer_x0 = pointer_x1 + POINTER_FOOT_WIDTH;
724            }
725    
726            gboolean bottom = FALSE;
727            if((y0 - EXTRA_BORDER) > GTK_WIDGET(map)->allocation.height/2) {
728                bottom = TRUE;
729                y0 -= BALLOON_HEIGHT + POINTER_HEIGHT;
730            } else
731                y0 += POINTER_HEIGHT;
732    
733            /* calculate bottom/right of box */
734            int x1 = x0 + BALLOON_WIDTH, y1 = y0 + BALLOON_HEIGHT;
735    
736            /* save balloon screen coordinates for later use */
737            priv->balloon.rect.x = x0 + BALLOON_BORDER;
738            priv->balloon.rect.y = y0 + BALLOON_BORDER;
739            priv->balloon.rect.w = x1 - x0 - 2*BALLOON_BORDER;
740            priv->balloon.rect.h = y1 - y0 - 2*BALLOON_BORDER;
741    
742      cairo_close_path (cr);  #ifdef USE_CAIRO
743      cairo_set_source_rgba (cr, 1, 1, 1, TRANSPARENCY);          cairo_t *cr = gdk_cairo_create(priv->pixmap);
744      cairo_fill_preserve (cr);  
745      cairo_set_source_rgba (cr, 0, 0, 0, TRANSPARENCY);          /* --------- draw shadow --------------- */
746      cairo_set_line_width (cr, 1);          osm_gps_map_draw_balloon_shape (cr,
747      cairo_stroke (cr);                      x0 + BALLOON_SHADOW, y0 + BALLOON_SHADOW,
748                        x1 + BALLOON_SHADOW, y1 + BALLOON_SHADOW,
749      gtk_widget_queue_draw_area (GTK_WIDGET(map),                      bottom, pointer_x, pointer_y,
750                                  x0,                      pointer_x0 + BALLOON_SHADOW, pointer_x1 + BALLOON_SHADOW);
751                                  y0,  
752                                  WIDTH,          cairo_set_source_rgba (cr, 0, 0, 0, BALLOON_SHADOW_TRANSPARENCY);
753                                  HEIGHT + PIN_HEIGHT);          cairo_fill_preserve (cr);
754            cairo_set_source_rgba (cr, 1, 0, 0, 1.0);
755            cairo_set_line_width (cr, 0);
756            cairo_stroke (cr);
757    
758            /* --------- draw main shape ----------- */
759            osm_gps_map_draw_balloon_shape (cr, x0, y0, x1, y1,
760                        bottom, pointer_x, pointer_y, pointer_x0, pointer_x1);
761    
762            cairo_set_source_rgba (cr, 1, 1, 1, BALLOON_TRANSPARENCY);
763            cairo_fill_preserve (cr);
764            cairo_set_source_rgba (cr, 0, 0, 0, BALLOON_TRANSPARENCY);
765            cairo_set_line_width (cr, 1);
766            cairo_stroke (cr);
767    
768    
769            /* ---------- draw close button --------- */
770    
771            int cx = x1 - BALLOON_BORDER - CLOSE_BUTTON_RADIUS;
772            int cy = y0 + BALLOON_BORDER + CLOSE_BUTTON_RADIUS;
773            int crad = CLOSE_BUTTON_RADIUS;
774    
775            cairo_arc (cr, cx, cy, crad, 0, 2 * M_PI);
776            cairo_set_source_rgba (cr, 0.8, 0, 0, 1.0);
777            cairo_fill_preserve (cr);
778            cairo_set_source_rgba (cr, 0.3, 0, 0, 1.0);
779            cairo_set_line_width (cr, 2);
780            cairo_stroke(cr);
781    
782            cairo_set_source_rgba (cr, 1, 1, 1, 1.0);
783            cairo_set_line_width (cr, 3);
784            cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
785            cairo_move_to (cr, cx - crad/2, cy - crad/2);
786            cairo_line_to (cr, cx + crad/2, cy + crad/2);
787            cairo_stroke (cr);
788            cairo_move_to (cr, cx + crad/2, cy - crad/2);
789            cairo_line_to (cr, cx - crad/2, cy + crad/2);
790            cairo_stroke (cr);
791    
792            if (priv->balloon.cb) {
793                /* clip in case application tries to draw in */
794                /* exceed of the balloon */
795                cairo_rectangle (cr, priv->balloon.rect.x, priv->balloon.rect.y,
796                                 priv->balloon.rect.w, priv->balloon.rect.h);
797                cairo_clip (cr);
798                cairo_new_path (cr);  /* current path is not
799                                         consumed by cairo_clip() */
800    
801                priv->balloon.cb(cr, &priv->balloon.rect, priv->balloon.data);
802            }
803    
804            gtk_widget_queue_draw_area (GTK_WIDGET(map),
805                                        x0, y0, BALLOON_WIDTH,
806                                        BALLOON_HEIGHT + POINTER_HEIGHT);
807    #else
808    #warning "Balloon display lacks a non-cairo implementation!"
809  #endif  #endif
810        }
811    }
812    
813    /* the user clicked into the balloons main area. handle this */
814    static void
815    osm_gps_map_handle_balloon_click(OsmGpsMap *map, gint x, gint y)
816    {
817        OsmGpsMapPrivate *priv = map->priv;
818    
819        printf("clocked at %d %d\n", x, y);
820    
821        if (!priv->balloon.valid)
822            return;
823    
824        /* check if the close button was clicked */
825        if ((x > priv->balloon.rect.w - 2*CLOSE_BUTTON_RADIUS) &&
826            (x < priv->balloon.rect.w) &&
827            (y > 0) && (y < 2*CLOSE_BUTTON_RADIUS)) {
828    
829            priv->balloon.valid = FALSE;
830            osm_gps_map_map_redraw_idle(map);
831        }
832    }
833    
834    /* return true if balloon is being displayed and if */
835    /* the given coordinate is within this balloon */
836    static gboolean
837    osm_gps_map_in_balloon(OsmGpsMapPrivate *priv, gint x, gint y)
838    {
839        return (priv->balloon.valid &&
840                (x > priv->balloon.rect.x) &&
841                (x < priv->balloon.rect.x + priv->balloon.rect.w) &&
842                (y > priv->balloon.rect.y) &&
843                (y < priv->balloon.rect.y + priv->balloon.rect.h));
844  }  }
845    
846  static void  static void
# Line 1274  osm_gps_map_map_redraw (OsmGpsMap *map) Line 1427  osm_gps_map_map_redraw (OsmGpsMap *map)
1427      osm_gps_map_print_tracks(map);      osm_gps_map_print_tracks(map);
1428      osm_gps_map_draw_gps_point(map);      osm_gps_map_draw_gps_point(map);
1429      osm_gps_map_print_images(map);      osm_gps_map_print_images(map);
1430        osm_gps_map_draw_balloon_int(map);
     osm_gps_map_draw_balloon(map);  
1431    
1432      //osm_gps_map_osd_speed(map, 1.5);      //osm_gps_map_osd_speed(map, 1.5);
1433      osm_gps_map_purge_cache(map);      osm_gps_map_purge_cache(map);
# Line 1307  osm_gps_map_init (OsmGpsMap *object) Line 1459  osm_gps_map_init (OsmGpsMap *object)
1459      priv->gps = g_new0(coord_t, 1);      priv->gps = g_new0(coord_t, 1);
1460      priv->gps_valid = FALSE;      priv->gps_valid = FALSE;
1461    
1462        priv->balloon.coo = g_new0(coord_t, 1);
1463        priv->balloon.valid = FALSE;
1464        priv->balloon.cb = NULL;
1465    
1466      priv->tracks = NULL;      priv->tracks = NULL;
1467      priv->images = NULL;      priv->images = NULL;
1468    
# Line 1464  osm_gps_map_dispose (GObject *object) Line 1620  osm_gps_map_dispose (GObject *object)
1620      if (priv->idle_map_redraw != 0)      if (priv->idle_map_redraw != 0)
1621          g_source_remove (priv->idle_map_redraw);          g_source_remove (priv->idle_map_redraw);
1622    
1623        g_free(priv->gps);
1624        g_free(priv->balloon.coo);
1625    
1626      G_OBJECT_CLASS (osm_gps_map_parent_class)->dispose (object);      G_OBJECT_CLASS (osm_gps_map_parent_class)->dispose (object);
1627  }  }
1628    
# Line 1679  osm_gps_map_button_press (GtkWidget *wid Line 1838  osm_gps_map_button_press (GtkWidget *wid
1838  {  {
1839      OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(widget);      OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(widget);
1840    
1841        /* don't drag if the user clicked within the balloon */
1842        if (osm_gps_map_in_balloon(priv,
1843                       event->x + EXTRA_BORDER,
1844                       event->y + EXTRA_BORDER))
1845        {
1846            priv->drag_counter = -1;
1847            return FALSE;
1848        }
1849    
1850      priv->drag_counter = 0;      priv->drag_counter = 0;
1851      priv->drag_start_mouse_x = (int) event->x;      priv->drag_start_mouse_x = (int) event->x;
1852      priv->drag_start_mouse_y = (int) event->y;      priv->drag_start_mouse_y = (int) event->y;
# Line 1693  osm_gps_map_button_release (GtkWidget *w Line 1861  osm_gps_map_button_release (GtkWidget *w
1861  {  {
1862      OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(widget);      OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(widget);
1863    
1864        /* released inside the balloon? */
1865        if (osm_gps_map_in_balloon(priv,
1866                       event->x + EXTRA_BORDER,
1867                       event->y + EXTRA_BORDER))
1868        {
1869            osm_gps_map_handle_balloon_click(OSM_GPS_MAP(widget),
1870                 event->x - priv->balloon.rect.x + EXTRA_BORDER,
1871                 event->y - priv->balloon.rect.y + EXTRA_BORDER);
1872            return FALSE;
1873        }
1874    
1875        if (priv->drag_counter < 0)
1876            return FALSE;
1877    
1878      if (priv->dragging)      if (priv->dragging)
1879      {      {
1880          priv->dragging = FALSE;          priv->dragging = FALSE;
# Line 1710  osm_gps_map_button_release (GtkWidget *w Line 1892  osm_gps_map_button_release (GtkWidget *w
1892    
1893      priv->drag_mouse_dx = 0;      priv->drag_mouse_dx = 0;
1894      priv->drag_mouse_dy = 0;      priv->drag_mouse_dy = 0;
1895      priv->drag_counter = 0;      priv->drag_counter = -1;
1896    
1897      return FALSE;      return FALSE;
1898  }  }
# Line 1735  osm_gps_map_motion_notify (GtkWidget *wi Line 1917  osm_gps_map_motion_notify (GtkWidget *wi
1917      if (!(state & GDK_BUTTON1_MASK))      if (!(state & GDK_BUTTON1_MASK))
1918          return FALSE;          return FALSE;
1919    
1920        if (priv->drag_counter < 0)
1921            return FALSE;
1922    
1923      priv->drag_counter++;      priv->drag_counter++;
1924    
1925      // we havent dragged more than 6 pixels      // we havent dragged more than 6 pixels
# Line 1837  osm_gps_map_expose (GtkWidget *widget, G Line 2022  osm_gps_map_expose (GtkWidget *widget, G
2022                         widget->window,                         widget->window,
2023                         widget->style->fg_gc[GTK_WIDGET_STATE (widget)],                         widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
2024                         priv->pixmap,                         priv->pixmap,
2025                         event->area.x + EXTRA_BORDER, event->area.y + EXTRA_BORDER,                         event->area.x + EXTRA_BORDER,
2026                           event->area.y + EXTRA_BORDER,
2027                         event->area.x, event->area.y,                         event->area.x, event->area.y,
2028                         event->area.width, event->area.height);                         event->area.width, event->area.height);
2029    
# Line 2612  osm_gps_map_get_scale(OsmGpsMap *map) Line 2798  osm_gps_map_get_scale(OsmGpsMap *map)
2798      return osm_gps_map_get_scale_at_point(priv->map_zoom, priv->center_rlat, priv->center_rlon);      return osm_gps_map_get_scale_at_point(priv->map_zoom, priv->center_rlat, priv->center_rlon);
2799  }  }
2800    
2801    void
2802    osm_gps_map_draw_balloon (OsmGpsMap *map, float latitude, float longitude,
2803                              OsmGpsMapBalloonCallback cb, gpointer data)
2804    {
2805        OsmGpsMapPrivate *priv;
2806    
2807        /* remove and previously installed balloon */
2808        osm_gps_map_clear_balloon (map);
2809    
2810        g_return_if_fail (OSM_IS_GPS_MAP (map));
2811        priv = map->priv;
2812    
2813        priv->balloon.coo->rlat = deg2rad(latitude);
2814        priv->balloon.coo->rlon = deg2rad(longitude);
2815        priv->balloon.valid = TRUE;
2816    
2817        priv->balloon.cb = cb;
2818        priv->balloon.data = data;
2819    
2820        // this redraws the map
2821        osm_gps_map_map_redraw_idle(map);
2822    }
2823    
2824    void
2825    osm_gps_map_clear_balloon (OsmGpsMap *map)
2826    {
2827        OsmGpsMapPrivate *priv;
2828    
2829        g_return_if_fail (OSM_IS_GPS_MAP (map));
2830        priv = map->priv;
2831    
2832        priv->balloon.valid = FALSE;
2833    
2834        osm_gps_map_map_redraw_idle(map);
2835    }

Legend:
Removed from v.56  
changed lines
  Added in v.58