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

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

revision 55 by harbaum, Thu Aug 13 12:01:52 2009 UTC revision 60 by harbaum, Mon Aug 17 19:44:00 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           290
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/ */
697    static void
698    osm_gps_map_draw_balloon_int (OsmGpsMap *map)
699    {
700        OsmGpsMapPrivate *priv = map->priv;
701    
702        if (priv->balloon.valid) {
703    
704            /* ------- convert given coordinate into screen position --------- */
705            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            /* check position of this relative to screen center to determine */
711            /* pointer direction ... */
712            int pointer_x = x0, pointer_x0, pointer_x1;
713            int pointer_y = y0;
714    
715            /* ... and calculate position */
716            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    #ifdef USE_CAIRO
743            cairo_t *cr = gdk_cairo_create(priv->pixmap);
744    
745            /* --------- draw shadow --------------- */
746            osm_gps_map_draw_balloon_shape (cr,
747                        x0 + BALLOON_SHADOW, y0 + BALLOON_SHADOW,
748                        x1 + BALLOON_SHADOW, y1 + BALLOON_SHADOW,
749                        bottom, pointer_x, pointer_y,
750                        pointer_x0 + BALLOON_SHADOW, pointer_x1 + BALLOON_SHADOW);
751    
752            cairo_set_source_rgba (cr, 0, 0, 0, BALLOON_SHADOW_TRANSPARENCY);
753            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
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        if (!priv->balloon.valid)
820            return;
821    
822        /* check if the close button was clicked */
823        if ((x > priv->balloon.rect.w - 2*CLOSE_BUTTON_RADIUS) &&
824            (x < priv->balloon.rect.w) &&
825            (y > 0) && (y < 2*CLOSE_BUTTON_RADIUS)) {
826    
827            priv->balloon.valid = FALSE;
828            osm_gps_map_map_redraw_idle(map);
829        }
830    }
831    
832    /* return true if balloon is being displayed and if */
833    /* the given coordinate is within this balloon */
834    static gboolean
835    osm_gps_map_in_balloon(OsmGpsMapPrivate *priv, gint x, gint y)
836    {
837        return (priv->balloon.valid &&
838                (x > priv->balloon.rect.x) &&
839                (x < priv->balloon.rect.x + priv->balloon.rect.w) &&
840                (y > priv->balloon.rect.y) &&
841                (y < priv->balloon.rect.y + priv->balloon.rect.h));
842  }  }
843    
844  static void  static void
# Line 1217  osm_gps_map_map_redraw (OsmGpsMap *map) Line 1425  osm_gps_map_map_redraw (OsmGpsMap *map)
1425      osm_gps_map_print_tracks(map);      osm_gps_map_print_tracks(map);
1426      osm_gps_map_draw_gps_point(map);      osm_gps_map_draw_gps_point(map);
1427      osm_gps_map_print_images(map);      osm_gps_map_print_images(map);
1428        osm_gps_map_draw_balloon_int(map);
1429    
1430      //osm_gps_map_osd_speed(map, 1.5);      //osm_gps_map_osd_speed(map, 1.5);
1431      osm_gps_map_purge_cache(map);      osm_gps_map_purge_cache(map);
# Line 1248  osm_gps_map_init (OsmGpsMap *object) Line 1457  osm_gps_map_init (OsmGpsMap *object)
1457      priv->gps = g_new0(coord_t, 1);      priv->gps = g_new0(coord_t, 1);
1458      priv->gps_valid = FALSE;      priv->gps_valid = FALSE;
1459    
1460        priv->balloon.coo = g_new0(coord_t, 1);
1461        priv->balloon.valid = FALSE;
1462        priv->balloon.cb = NULL;
1463    
1464      priv->tracks = NULL;      priv->tracks = NULL;
1465      priv->images = NULL;      priv->images = NULL;
1466    
# Line 1405  osm_gps_map_dispose (GObject *object) Line 1618  osm_gps_map_dispose (GObject *object)
1618      if (priv->idle_map_redraw != 0)      if (priv->idle_map_redraw != 0)
1619          g_source_remove (priv->idle_map_redraw);          g_source_remove (priv->idle_map_redraw);
1620    
1621        g_free(priv->gps);
1622        g_free(priv->balloon.coo);
1623    
1624      G_OBJECT_CLASS (osm_gps_map_parent_class)->dispose (object);      G_OBJECT_CLASS (osm_gps_map_parent_class)->dispose (object);
1625  }  }
1626    
# Line 1620  osm_gps_map_button_press (GtkWidget *wid Line 1836  osm_gps_map_button_press (GtkWidget *wid
1836  {  {
1837      OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(widget);      OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(widget);
1838    
1839        /* don't drag if the user clicked within the balloon */
1840        if (osm_gps_map_in_balloon(priv,
1841                       event->x + EXTRA_BORDER,
1842                       event->y + EXTRA_BORDER))
1843        {
1844            priv->drag_counter = -1;
1845            return FALSE;
1846        }
1847    
1848      priv->drag_counter = 0;      priv->drag_counter = 0;
1849      priv->drag_start_mouse_x = (int) event->x;      priv->drag_start_mouse_x = (int) event->x;
1850      priv->drag_start_mouse_y = (int) event->y;      priv->drag_start_mouse_y = (int) event->y;
# Line 1634  osm_gps_map_button_release (GtkWidget *w Line 1859  osm_gps_map_button_release (GtkWidget *w
1859  {  {
1860      OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(widget);      OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(widget);
1861    
1862        /* released inside the balloon? */
1863        if (osm_gps_map_in_balloon(priv,
1864                       event->x + EXTRA_BORDER,
1865                       event->y + EXTRA_BORDER))
1866        {
1867            osm_gps_map_handle_balloon_click(OSM_GPS_MAP(widget),
1868                 event->x - priv->balloon.rect.x + EXTRA_BORDER,
1869                 event->y - priv->balloon.rect.y + EXTRA_BORDER);
1870            return FALSE;
1871        }
1872    
1873        if (priv->drag_counter < 0)
1874            return FALSE;
1875    
1876      if (priv->dragging)      if (priv->dragging)
1877      {      {
1878          priv->dragging = FALSE;          priv->dragging = FALSE;
# Line 1651  osm_gps_map_button_release (GtkWidget *w Line 1890  osm_gps_map_button_release (GtkWidget *w
1890    
1891      priv->drag_mouse_dx = 0;      priv->drag_mouse_dx = 0;
1892      priv->drag_mouse_dy = 0;      priv->drag_mouse_dy = 0;
1893      priv->drag_counter = 0;      priv->drag_counter = -1;
1894    
1895      return FALSE;      return FALSE;
1896  }  }
# Line 1676  osm_gps_map_motion_notify (GtkWidget *wi Line 1915  osm_gps_map_motion_notify (GtkWidget *wi
1915      if (!(state & GDK_BUTTON1_MASK))      if (!(state & GDK_BUTTON1_MASK))
1916          return FALSE;          return FALSE;
1917    
1918        if (priv->drag_counter < 0)
1919            return FALSE;
1920    
1921      priv->drag_counter++;      priv->drag_counter++;
1922    
1923      // we havent dragged more than 6 pixels      // we havent dragged more than 6 pixels
# Line 1778  osm_gps_map_expose (GtkWidget *widget, G Line 2020  osm_gps_map_expose (GtkWidget *widget, G
2020                         widget->window,                         widget->window,
2021                         widget->style->fg_gc[GTK_WIDGET_STATE (widget)],                         widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
2022                         priv->pixmap,                         priv->pixmap,
2023                         event->area.x + EXTRA_BORDER, event->area.y + EXTRA_BORDER,                         event->area.x + EXTRA_BORDER,
2024                           event->area.y + EXTRA_BORDER,
2025                         event->area.x, event->area.y,                         event->area.x, event->area.y,
2026                         event->area.width, event->area.height);                         event->area.width, event->area.height);
2027    
# Line 2553  osm_gps_map_get_scale(OsmGpsMap *map) Line 2796  osm_gps_map_get_scale(OsmGpsMap *map)
2796      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);
2797  }  }
2798    
2799    void
2800    osm_gps_map_draw_balloon (OsmGpsMap *map, float latitude, float longitude,
2801                              OsmGpsMapBalloonCallback cb, gpointer data)
2802    {
2803        OsmGpsMapPrivate *priv;
2804    
2805        /* remove and previously installed balloon */
2806        osm_gps_map_clear_balloon (map);
2807    
2808        g_return_if_fail (OSM_IS_GPS_MAP (map));
2809        priv = map->priv;
2810    
2811        priv->balloon.coo->rlat = deg2rad(latitude);
2812        priv->balloon.coo->rlon = deg2rad(longitude);
2813        priv->balloon.valid = TRUE;
2814    
2815        priv->balloon.cb = cb;
2816        priv->balloon.data = data;
2817    
2818        // this redraws the map
2819        osm_gps_map_map_redraw_idle(map);
2820    }
2821    
2822    void
2823    osm_gps_map_clear_balloon (OsmGpsMap *map)
2824    {
2825        OsmGpsMapPrivate *priv;
2826    
2827        g_return_if_fail (OSM_IS_GPS_MAP (map));
2828        priv = map->priv;
2829    
2830        priv->balloon.valid = FALSE;
2831    
2832        osm_gps_map_map_redraw_idle(map);
2833    }

Legend:
Removed from v.55  
changed lines
  Added in v.60