Diff of /trunk/src/map.c

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

revision 15 by harbaum, Tue Dec 16 17:00:20 2008 UTC revision 191 by harbaum, Tue Jul 7 07:36:27 2009 UTC
# Line 30  static void map_statusbar(map_t *map, ma Line 30  static void map_statusbar(map_t *map, ma
30    tag_t *tag = NULL;    tag_t *tag = NULL;
31    char *str = NULL;    char *str = NULL;
32    
33    switch(map_item->type) {    switch(map_item->object.type) {
34    case MAP_TYPE_NODE:    case NODE:
35      item_str = "Node";      item_str = "Node";
36      id = map_item->node->id;      id = map_item->object.node->id;
37      tag = map_item->node->tag;      tag = map_item->object.node->tag;
38      break;      break;
39    
40    case MAP_TYPE_WAY:    case WAY:
41      item_str = "Way";      item_str = "Way";
42      id = map_item->way->id;      id = map_item->object.way->id;
43      tag = map_item->way->tag;      tag = map_item->object.way->tag;
44        break;
45    
46      case RELATION:
47        item_str = "Relation";
48        id = map_item->object.relation->id;
49        tag = map_item->object.relation->tag;
50      break;      break;
51    
52    default:    default:
# Line 53  static void map_statusbar(map_t *map, ma Line 59  static void map_statusbar(map_t *map, ma
59    if(id == ID_ILLEGAL)    if(id == ID_ILLEGAL)
60      str = g_strdup_printf(_("Unknown item"));      str = g_strdup_printf(_("Unknown item"));
61    else {    else {
62      str = g_strdup_printf("%s #%ld", item_str, id);      str = g_strdup_printf("%s #" ITEM_ID_FORMAT, item_str, id);
63    
64      /* add some tags ... */      /* add some tags ... */
65        /*
66         *  XXX Should we just try to present only the name or the ref (or the
67         *  alt_name, old_name, whatever) here?  Hurling a load of tags in the
68         *  user's face in some unpredictable, uninformative order isn't very
69         *  friendly.
70         *
71         *  Actually, a tag_short_desc() function would be useful in dialogs
72         *  nd user messages too.
73         */
74      while(tag) {      while(tag) {
75        if(!collision && info_tag_key_collision(tags, tag))        if(!collision && info_tag_key_collision(tags, tag))
76          collision = TRUE;          collision = TRUE;
# Line 123  static void map_node_select(appdata_t *a Line 138  static void map_node_select(appdata_t *a
138    
139    g_assert(!map->highlight);    g_assert(!map->highlight);
140    
141    map_item->type      = MAP_TYPE_NODE;    map_item->object.type      = NODE;
142    map_item->node      = node;    map_item->object.node      = node;
143    map_item->highlight = FALSE;    map_item->highlight = FALSE;
144    
145    /* node may not have any visible representation at all */    /* node may not have any visible representation at all */
# Line 137  static void map_node_select(appdata_t *a Line 152  static void map_node_select(appdata_t *a
152    icon_bar_map_item_selected(appdata, map_item, TRUE);    icon_bar_map_item_selected(appdata, map_item, TRUE);
153    
154    /* highlight node */    /* highlight node */
155    gint x = map_item->node->lpos.x, y = map_item->node->lpos.y;    gint x = map_item->object.node->lpos.x, y = map_item->object.node->lpos.y;
156    
157    /* create a copy of this map item and mark it as being a highlight */    /* create a copy of this map item and mark it as being a highlight */
158    map_item_t *new_map_item = g_new0(map_item_t, 1);    map_item_t *new_map_item = g_new0(map_item_t, 1);
# Line 148  static void map_node_select(appdata_t *a Line 163  static void map_node_select(appdata_t *a
163    if(!node->ways) radius += map->style->node.border_radius;    if(!node->ways) radius += map->style->node.border_radius;
164    if(node->icon_buf && map->style->icon.enable &&    if(node->icon_buf && map->style->icon.enable &&
165       !appdata->settings->no_icons) {       !appdata->settings->no_icons) {
166      gint w = gdk_pixbuf_get_width(map_item->node->icon_buf);      gint w = gdk_pixbuf_get_width(map_item->object.node->icon_buf);
167      gint h = gdk_pixbuf_get_height(map_item->node->icon_buf);      gint h = gdk_pixbuf_get_height(map_item->object.node->icon_buf);
168      /* icons are technically square, so a radius slightly bigger */      /* icons are technically square, so a radius slightly bigger */
169      /* than sqrt(2)*MAX(w,h) should fit nicely */      /* than sqrt(2)*MAX(w,h) should fit nicely */
170      radius =  0.75 * map->style->icon.scale * ((w>h)?w:h);      radius = 0.75 * map->style->icon.scale * ((w>h)?w:h);
171    }    }
172    
173      radius *= map->state->detail;
174    map_hl_circle_new(map, CANVAS_GROUP_NODES_HL, new_map_item,    map_hl_circle_new(map, CANVAS_GROUP_NODES_HL, new_map_item,
175                      x, y, radius, map->style->highlight.color);                      x, y, radius, map->style->highlight.color);
176    
177    if(!map_item->item) {    if(!map_item->item) {
178      /* and draw a fake node */      /* and draw a fake node */
179      new_map_item = g_new0(map_item_t, 1);      new_map_item = g_new0(map_item_t, 1);
180      memcpy(new_map_item, map_item, sizeof(map_item_t));      memcpy(new_map_item, map_item, sizeof(map_item_t));
181      new_map_item->highlight = TRUE;      new_map_item->highlight = TRUE;
182      map_hl_circle_new(map, CANVAS_GROUP_NODES_HL, new_map_item,      map_hl_circle_new(map, CANVAS_GROUP_NODES_IHL, new_map_item,
183                        x, y, map->style->node.radius,                        x, y, map->style->node.radius,
184                        map->style->highlight.node_color);                        map->style->highlight.node_color);
185    }    }
# Line 175  void map_way_select(appdata_t *appdata, Line 191  void map_way_select(appdata_t *appdata,
191    
192    g_assert(!map->highlight);    g_assert(!map->highlight);
193    
194    map_item->type      = MAP_TYPE_WAY;    map_item->object.type      = WAY;
195    map_item->way       = way;    map_item->object.way       = way;
196    map_item->highlight = FALSE;    map_item->highlight = FALSE;
197    map_item->item      = way->map_item_chain->map_item->item;    map_item->item      = way->map_item_chain->map_item->item;
198    
199    map_statusbar(map, map_item);    map_statusbar(map, map_item);
200    icon_bar_map_item_selected(appdata, map_item, TRUE);    icon_bar_map_item_selected(appdata, map_item, TRUE);
201    gtk_widget_set_sensitive(appdata->menu_item_map_hide_sel, TRUE);    gtk_widget_set_sensitive(appdata->menu_item_map_hide_sel, TRUE);
   
   gint arrow_width = (map_item->way->draw.flags & OSM_DRAW_FLAG_BG)?  
     map->style->highlight.width + map_item->way->draw.bg.width/2:  
     map->style->highlight.width + map_item->way->draw.width/2;  
202    
203    node_chain_t *node_chain = map_item->way->node_chain;    gint arrow_width = ((map_item->object.way->draw.flags & OSM_DRAW_FLAG_BG)?
204                          map->style->highlight.width + map_item->object.way->draw.bg.width/2:
205                          map->style->highlight.width + map_item->object.way->draw.width/2)
206        * map->state->detail;
207    
208      node_chain_t *node_chain = map_item->object.way->node_chain;
209    node_t *last = NULL;    node_t *last = NULL;
210    while(node_chain) {    while(node_chain) {
211      map_item_t item;      map_item_t item;
212      item.type = MAP_TYPE_NODE;      item.object.type = NODE;
213      item.node = node_chain->node;      item.object.node = node_chain->node;
214    
215      /* draw an arrow between every two nodes */      /* draw an arrow between every two nodes */
216      if(last) {      if(last) {
217        /* create a new map item for every arrow */        /* create a new map item for every arrow */
218        map_item_t *new_map_item = g_new0(map_item_t, 1);        map_item_t *new_map_item = g_new0(map_item_t, 1);
219        new_map_item->type = MAP_TYPE_WAY;        new_map_item->object.type = WAY;
220        new_map_item->way = way;        new_map_item->object.way = way;
221        new_map_item->highlight = TRUE;        new_map_item->highlight = TRUE;
222    
223        struct { float x, y;} center, diff;        struct { float x, y;} center, diff;
# Line 225  void map_way_select(appdata_t *appdata, Line 242  void map_way_select(appdata_t *appdata,
242          points->coords[2*2+0] = center.x - diff.y - diff.x;          points->coords[2*2+0] = center.x - diff.y - diff.x;
243          points->coords[2*2+1] = center.y + diff.x - diff.y;          points->coords[2*2+1] = center.y + diff.x - diff.y;
244    
245          map_hl_polygon_new(map, CANVAS_GROUP_NODES_HL, new_map_item,          map_hl_polygon_new(map, CANVAS_GROUP_WAYS_DIR, new_map_item,
246                             points, map->style->highlight.arrow_color);                             points, map->style->highlight.arrow_color);
247    
248          canvas_points_free(points);          canvas_points_free(points);
# Line 236  void map_way_select(appdata_t *appdata, Line 253  void map_way_select(appdata_t *appdata,
253    
254        /* create a new map item for every node */        /* create a new map item for every node */
255        map_item_t *new_map_item = g_new0(map_item_t, 1);        map_item_t *new_map_item = g_new0(map_item_t, 1);
256        new_map_item->type = MAP_TYPE_NODE;        new_map_item->object.type = NODE;
257        new_map_item->node = node_chain->node;        new_map_item->object.node = node_chain->node;
258        new_map_item->highlight = TRUE;        new_map_item->highlight = TRUE;
259    
260        gint x = node_chain->node->lpos.x;        gint x = node_chain->node->lpos.x;
261        gint y = node_chain->node->lpos.y;        gint y = node_chain->node->lpos.y;
262    
263        map_hl_circle_new(map, CANVAS_GROUP_NODES_HL, new_map_item,        map_hl_circle_new(map, CANVAS_GROUP_NODES_IHL, new_map_item,
264                          x, y, map->style->node.radius,                          x, y, map->style->node.radius * map->state->detail,
265                          map->style->highlight.node_color);                          map->style->highlight.node_color);
266      }      }
267    
# Line 260  void map_way_select(appdata_t *appdata, Line 277  void map_way_select(appdata_t *appdata,
277      canvas_points_t *points = canvas_points_new(nodes);      canvas_points_t *points = canvas_points_new(nodes);
278    
279      int node = 0;      int node = 0;
280      node_chain = map_item->way->node_chain;      node_chain = map_item->object.way->node_chain;
281      while(node_chain) {      while(node_chain) {
282        canvas_point_set_pos(points, node++, &node_chain->node->lpos);        canvas_point_set_pos(points, node++, &node_chain->node->lpos);
283        node_chain = node_chain->next;        node_chain = node_chain->next;
# Line 272  void map_way_select(appdata_t *appdata, Line 289  void map_way_select(appdata_t *appdata,
289      new_map_item->highlight = TRUE;      new_map_item->highlight = TRUE;
290    
291      map_hl_polyline_new(map, CANVAS_GROUP_WAYS_HL, new_map_item, points,      map_hl_polyline_new(map, CANVAS_GROUP_WAYS_HL, new_map_item, points,
292                  (map_item->way->draw.flags & OSM_DRAW_FLAG_BG)?                   ((map_item->object.way->draw.flags & OSM_DRAW_FLAG_BG)?
293                  2*map->style->highlight.width + map_item->way->draw.bg.width:                   2*map->style->highlight.width + map_item->object.way->draw.bg.width:
294                  2*map->style->highlight.width + map_item->way->draw.width,                   2*map->style->highlight.width + map_item->object.way->draw.width)
295                  map->style->highlight.color);                  * map->state->detail, map->style->highlight.color);
296    
297      canvas_points_free(points);      canvas_points_free(points);
298    }    }
299  }  }
300    
301  static void map_item_select(appdata_t *appdata, map_item_t *map_item) {  void map_relation_select(appdata_t *appdata, relation_t *relation) {
302    switch(map_item->type) {    map_t *map = appdata->map;
303    case MAP_TYPE_NODE:  
304      map_node_select(appdata, map_item->node);    printf("highlighting relation "ITEM_ID_FORMAT"\n", relation->id);
305    
306      g_assert(!map->highlight);
307      map_highlight_t **hl = &map->highlight;
308    
309      map_item_t *map_item = &map->selected;
310      map_item->object.type      = RELATION;
311      map_item->object.relation  = relation;
312      map_item->highlight = FALSE;
313      map_item->item      = NULL;
314    
315      map_statusbar(map, map_item);
316      icon_bar_map_item_selected(appdata, map_item, TRUE);
317    
318      /* process all members */
319      member_t *member = relation->member;
320      while(member) {
321        canvas_item_t *item = NULL;
322    
323        switch(member->object.type) {
324    
325        case NODE: {
326          node_t *node = member->object.node;
327          printf("  -> node "ITEM_ID_FORMAT"\n", node->id);
328    
329          item = canvas_circle_new(map->canvas, CANVAS_GROUP_NODES_HL,
330                            node->lpos.x, node->lpos.y,
331                            map->style->highlight.width + map->style->node.radius,
332                            0, map->style->highlight.color, NO_COLOR);
333          } break;
334    
335        case WAY: {
336          way_t *way = member->object.way;
337          /* a way needs at least 2 points to be drawn */
338          guint nodes = osm_way_number_of_nodes(way);
339          if(nodes > 1) {
340    
341            /* allocate space for nodes */
342            canvas_points_t *points = canvas_points_new(nodes);
343    
344            int node = 0;
345            node_chain_t *node_chain = way->node_chain;
346            while(node_chain) {
347              canvas_point_set_pos(points, node++, &node_chain->node->lpos);
348              node_chain = node_chain->next;
349            }
350    
351            if(way->draw.flags & OSM_DRAW_FLAG_AREA)
352              item = canvas_polygon_new(map->canvas, CANVAS_GROUP_WAYS_HL, points, 0, 0,
353                                        map->style->highlight.color);
354            else
355              item = canvas_polyline_new(map->canvas, CANVAS_GROUP_WAYS_HL, points,
356                                  (way->draw.flags & OSM_DRAW_FLAG_BG)?
357                                  2*map->style->highlight.width + way->draw.bg.width:
358                                  2*map->style->highlight.width + way->draw.width,
359                                  map->style->highlight.color);
360    
361            canvas_points_free(points);
362          } } break;
363    
364        default:
365          break;
366        }
367    
368        /* attach item to item chain */
369        if(item) {
370          *hl = g_new0(map_highlight_t, 1);
371          (*hl)->item = item;
372          hl = &(*hl)->next;
373        }
374    
375        member = member->next;
376      }
377    }
378    
379    static void map_object_select(appdata_t *appdata, object_t *object) {
380      switch(object->type) {
381      case NODE:
382        map_node_select(appdata, object->node);
383        break;
384      case WAY:
385        map_way_select(appdata, object->way);
386      break;      break;
387    case MAP_TYPE_WAY:    case RELATION:
388      map_way_select(appdata, map_item->way);      map_relation_select(appdata, object->relation);
389      break;      break;
390    default:    default:
391      g_assert((map_item->type == MAP_TYPE_NODE)||      g_assert((object->type == NODE)||(object->type == RELATION)||
392               (map_item->type == MAP_TYPE_WAY));               (object->type == WAY));
393      break;      break;
394    }    }
395  }  }
# Line 299  static void map_item_select(appdata_t *a Line 397  static void map_item_select(appdata_t *a
397  void map_item_deselect(appdata_t *appdata) {  void map_item_deselect(appdata_t *appdata) {
398    
399    /* save tags for "last" function in info dialog */    /* save tags for "last" function in info dialog */
400    if(appdata->map->selected.type == MAP_TYPE_NODE) {    if(appdata->map->selected.object.type == NODE) {
401      if(appdata->map->last_node_tags)      if(appdata->map->last_node_tags)
402        osm_tags_free(appdata->map->last_node_tags);        osm_tags_free(appdata->map->last_node_tags);
403    
404      appdata->map->last_node_tags =      appdata->map->last_node_tags =
405        osm_tags_copy(appdata->map->selected.node->tag, FALSE);        osm_tags_copy(appdata->map->selected.object.node->tag, FALSE);
406    } else if(appdata->map->selected.type == MAP_TYPE_WAY) {    } else if(appdata->map->selected.object.type == WAY) {
407      if(appdata->map->last_way_tags)      if(appdata->map->last_way_tags)
408        osm_tags_free(appdata->map->last_way_tags);        osm_tags_free(appdata->map->last_way_tags);
409    
410      appdata->map->last_way_tags =      appdata->map->last_way_tags =
411        osm_tags_copy(appdata->map->selected.way->tag, FALSE);        osm_tags_copy(appdata->map->selected.object.way->tag, FALSE);
412    }    }
413    
414    /* remove statusbar message */    /* remove statusbar message */
# Line 324  void map_item_deselect(appdata_t *appdat Line 422  void map_item_deselect(appdata_t *appdat
422    map_hl_remove(appdata);    map_hl_remove(appdata);
423    
424    /* forget about selection */    /* forget about selection */
425    appdata->map->selected.type = MAP_TYPE_ILLEGAL;    appdata->map->selected.object.type = ILLEGAL;
426  }  }
427    
428  /* called whenever a map item is to be destroyed */  /* called whenever a map item is to be destroyed */
# Line 336  static gint map_item_destroy_event(GtkWi Line 434  static gint map_item_destroy_event(GtkWi
434  #ifdef DESTROY_WAIT_FOR_GTK  #ifdef DESTROY_WAIT_FOR_GTK
435    /* remove item from nodes/ways map_item_chain */    /* remove item from nodes/ways map_item_chain */
436    map_item_chain_t **chain = NULL;    map_item_chain_t **chain = NULL;
437    if(map_item->type == MAP_TYPE_NODE)    if(map_item->object.type == NODE)
438      chain = &map_item->node->map_item_chain;      chain = &map_item->object.node->map_item_chain;
439    else if(map_item->type == MAP_TYPE_WAY)    else if(map_item->object.type == WAY)
440      chain = &map_item->way->map_item_chain;      chain = &map_item->object.way->map_item_chain;
441    
442    /* there must be a chain with content, otherwise things are broken */    /* there must be a chain with content, otherwise things are broken */
443    g_assert(chain);    g_assert(chain);
# Line 366  static canvas_item_t *map_node_new(map_t Line 464  static canvas_item_t *map_node_new(map_t
464                     gint width, canvas_color_t fill, canvas_color_t border) {                     gint width, canvas_color_t fill, canvas_color_t border) {
465    
466    map_item_t *map_item = g_new0(map_item_t, 1);    map_item_t *map_item = g_new0(map_item_t, 1);
467    map_item->type = MAP_TYPE_NODE;    map_item->object.type = NODE;
468    map_item->node = node;    map_item->object.node = node;
469    
470    if(!node->icon_buf || !map->style->icon.enable ||    if(!node->icon_buf || !map->style->icon.enable ||
471       map->appdata->settings->no_icons)       map->appdata->settings->no_icons)
472      map_item->item = canvas_circle_new(map, CANVAS_GROUP_NODES,      map_item->item = canvas_circle_new(map->canvas, CANVAS_GROUP_NODES,
473         node->lpos.x, node->lpos.y, radius, width, fill, border);         node->lpos.x, node->lpos.y, radius, width, fill, border);
474    else    else
475      map_item->item = canvas_image_new(map, CANVAS_GROUP_NODES,      map_item->item = canvas_image_new(map->canvas, CANVAS_GROUP_NODES,
476        node->icon_buf,        node->icon_buf,
477        node->lpos.x - map->style->icon.scale/2 *        node->lpos.x - map->style->icon.scale/2 * map->state->detail *
478                        gdk_pixbuf_get_width(node->icon_buf),                        gdk_pixbuf_get_width(node->icon_buf),
479        node->lpos.y - map->style->icon.scale/2 *        node->lpos.y - map->style->icon.scale/2 * map->state->detail *
480                        gdk_pixbuf_get_height(node->icon_buf),                        gdk_pixbuf_get_height(node->icon_buf),
481                map->style->icon.scale,map->style->icon.scale);                        map->state->detail * map->style->icon.scale,
482                          map->state->detail * map->style->icon.scale);
483    
484    canvas_item_set_zoom_max(map_item->item, node->zoom_max);    canvas_item_set_zoom_max(map_item->item,
485                               node->zoom_max / (2 * map->state->detail));
486    
487    /* attach map_item to nodes map_item_chain */    /* attach map_item to nodes map_item_chain */
488    map_item_chain_t **chain = &node->map_item_chain;    map_item_chain_t **chain = &node->map_item_chain;
# Line 404  static canvas_item_t *map_way_single_new Line 504  static canvas_item_t *map_way_single_new
504                     gint width, canvas_color_t fill, canvas_color_t border) {                     gint width, canvas_color_t fill, canvas_color_t border) {
505    
506    map_item_t *map_item = g_new0(map_item_t, 1);    map_item_t *map_item = g_new0(map_item_t, 1);
507    map_item->type = MAP_TYPE_WAY;    map_item->object.type = WAY;
508    map_item->way = way;    map_item->object.way = way;
509    map_item->item = canvas_circle_new(map, CANVAS_GROUP_WAYS,    map_item->item = canvas_circle_new(map->canvas, CANVAS_GROUP_WAYS,
510            way->node_chain->node->lpos.x, way->node_chain->node->lpos.y,            way->node_chain->node->lpos.x, way->node_chain->node->lpos.y,
511                                       radius, width, fill, border);                                       radius, width, fill, border);
512    
# Line 430  static canvas_item_t *map_way_new(map_t Line 530  static canvas_item_t *map_way_new(map_t
530            way_t *way, canvas_points_t *points, gint width,            way_t *way, canvas_points_t *points, gint width,
531            canvas_color_t color, canvas_color_t fill_color) {            canvas_color_t color, canvas_color_t fill_color) {
532    map_item_t *map_item = g_new0(map_item_t, 1);    map_item_t *map_item = g_new0(map_item_t, 1);
533    map_item->type = MAP_TYPE_WAY;    map_item->object.type = WAY;
534    map_item->way = way;    map_item->object.way = way;
535    
536    if(way->draw.flags & OSM_DRAW_FLAG_AREA) {    if(way->draw.flags & OSM_DRAW_FLAG_AREA) {
537      if(map->style->area.opaque)      if(map->style->area.color & 0xff)
538        map_item->item = canvas_polygon_new(map, group, points,        map_item->item = canvas_polygon_new(map->canvas, group, points,
539                                            width, color, fill_color);                                            width, color, fill_color);
540      else      else
541        map_item->item = canvas_polyline_new(map, group, points,        map_item->item = canvas_polyline_new(map->canvas, group, points,
542                                             width, color);                                             width, color);
543    } else {    } else {
544      map_item->item = canvas_polyline_new(map, group, points, width, color);      map_item->item = canvas_polyline_new(map->canvas, group, points, width, color);
545    }    }
546    
547    canvas_item_set_zoom_max(map_item->item, way->draw.zoom_max);    canvas_item_set_zoom_max(map_item->item,
548                               way->draw.zoom_max / (2 * map->state->detail));
549    
550      /* a ways outline itself is never dashed */
551    if (group != CANVAS_GROUP_WAYS_OL)    if (group != CANVAS_GROUP_WAYS_OL)
552      if (way->draw.dashed)      if (way->draw.dashed)
553        canvas_item_set_dashed(map_item->item);        canvas_item_set_dashed(map_item->item, width, way->draw.dash_length);
554    
555    /* attach map_item to ways map_item_chain */    /* attach map_item to ways map_item_chain */
556    map_item_chain_t **chain = &way->map_item_chain;    map_item_chain_t **chain = &way->map_item_chain;
# Line 466  static canvas_item_t *map_way_new(map_t Line 568  static canvas_item_t *map_way_new(map_t
568    
569  void map_show_node(map_t *map, node_t *node) {  void map_show_node(map_t *map, node_t *node) {
570    map_node_new(map, node, map->style->node.radius, 0,    map_node_new(map, node, map->style->node.radius, 0,
571                 RGB2CANVAS(map->style->node.color), 0);                 map->style->node.color, 0);
572  }  }
573    
574  void map_way_draw(map_t *map, way_t *way) {  void map_way_draw(map_t *map, way_t *way) {
# Line 481  void map_way_draw(map_t *map, way_t *way Line 583  void map_way_draw(map_t *map, way_t *way
583    if(nodes == 1) {    if(nodes == 1) {
584      /* draw a single dot where this single node is */      /* draw a single dot where this single node is */
585      map_way_single_new(map, way, map->style->node.radius, 0,      map_way_single_new(map, way, map->style->node.radius, 0,
586                         RGB2CANVAS(map->style->node.color), 0);                         map->style->node.color, 0);
587    } else {    } else {
588      canvas_points_t *points = canvas_points_new(nodes);      canvas_points_t *points = canvas_points_new(nodes);
589    
# Line 493  void map_way_draw(map_t *map, way_t *way Line 595  void map_way_draw(map_t *map, way_t *way
595      }      }
596    
597      /* draw way */      /* draw way */
598        float width = way->draw.width * map->state->detail;
599    
600      if(way->draw.flags & OSM_DRAW_FLAG_AREA) {      if(way->draw.flags & OSM_DRAW_FLAG_AREA) {
601        map_way_new(map, CANVAS_GROUP_POLYGONS, way, points,        map_way_new(map, CANVAS_GROUP_POLYGONS, way, points,
602                    way->draw.width, way->draw.color, way->draw.area.color);                    width, way->draw.color, way->draw.area.color);
603      } else {      } else {
604        map_way_new(map, CANVAS_GROUP_WAYS, way, points,  
605                    way->draw.width, way->draw.color, NO_COLOR);        if(way->draw.flags & OSM_DRAW_FLAG_BG) {
606            map_way_new(map, CANVAS_GROUP_WAYS_INT, way, points,
607        if(way->draw.flags & OSM_DRAW_FLAG_BG)                      width, way->draw.color, NO_COLOR);
608    
609          map_way_new(map, CANVAS_GROUP_WAYS_OL, way, points,          map_way_new(map, CANVAS_GROUP_WAYS_OL, way, points,
610                      way->draw.bg.width, way->draw.bg.color, NO_COLOR);                      way->draw.bg.width * map->state->detail,
611                        way->draw.bg.color, NO_COLOR);
612    
613          } else
614            map_way_new(map, CANVAS_GROUP_WAYS, way, points,
615                        width, way->draw.color, NO_COLOR);
616      }      }
617      canvas_points_free(points);      canvas_points_free(points);
618    }    }
# Line 515  void map_node_draw(map_t *map, node_t *n Line 625  void map_node_draw(map_t *map, node_t *n
625    
626    if(!node->ways)    if(!node->ways)
627      map_node_new(map, node,      map_node_new(map, node,
628                   map->style->node.radius,                   map->style->node.radius * map->state->detail,
629                   map->style->node.border_radius,                   map->style->node.border_radius * map->state->detail,
630                   RGBA2CANVAS(map->style->node.fill_color,                   map->style->node.fill_color,
631                               map->style->node.has_fill_color?0xff:0x00),                   map->style->node.color);
                  RGB2CANVAS(map->style->node.color));  
632    
633    else if(map->style->node.show_untagged || osm_node_has_tag(node))    else if(map->style->node.show_untagged || osm_node_has_tag(node))
634      map_node_new(map, node,      map_node_new(map, node,
635                   map->style->node.radius, 0,                   map->style->node.radius * map->state->detail, 0,
636                   RGB2CANVAS(map->style->node.color), 0);                   map->style->node.color, 0);
637  }  }
638    
639  static void map_item_draw(map_t *map, map_item_t *map_item) {  static void map_item_draw(map_t *map, map_item_t *map_item) {
640    switch(map_item->type) {    switch(map_item->object.type) {
641    case MAP_TYPE_NODE:    case NODE:
642      map_node_draw(map, map_item->node);      map_node_draw(map, map_item->object.node);
643      break;      break;
644    case MAP_TYPE_WAY:    case WAY:
645      map_way_draw(map, map_item->way);      map_way_draw(map, map_item->object.way);
646      break;      break;
647    default:    default:
648      g_assert((map_item->type == MAP_TYPE_NODE) ||      g_assert((map_item->object.type == NODE) ||
649               (map_item->type == MAP_TYPE_WAY));               (map_item->object.type == WAY));
650    }    }
651  }  }
652    
653  static void map_item_remove(map_t *map, map_item_t *map_item) {  static void map_item_remove(map_t *map, map_item_t *map_item) {
654    map_item_chain_t **chainP = NULL;    map_item_chain_t **chainP = NULL;
655    
656    switch(map_item->type) {    switch(map_item->object.type) {
657    case MAP_TYPE_NODE:    case NODE:
658      chainP = &map_item->node->map_item_chain;      chainP = &map_item->object.node->map_item_chain;
659      break;      break;
660    case MAP_TYPE_WAY:    case WAY:
661      chainP = &map_item->way->map_item_chain;      chainP = &map_item->object.way->map_item_chain;
662      break;      break;
663    default:    default:
664      g_assert((map_item->type == MAP_TYPE_NODE) ||      g_assert((map_item->object.type == NODE) ||
665               (map_item->type == MAP_TYPE_WAY));               (map_item->object.type == WAY));
666    }    }
667    
668    map_item_chain_destroy(chainP);    map_item_chain_destroy(chainP);
669  }  }
670    
671  static void map_item_init(style_t *style, map_item_t *map_item) {  static void map_item_init(style_t *style, map_item_t *map_item) {
672    switch (map_item->type){    switch (map_item->object.type){
673      case MAP_TYPE_WAY:      case WAY:
674        josm_elemstyles_colorize_way(style, map_item->way);        josm_elemstyles_colorize_way(style, map_item->object.way);
675        break;        break;
676      case MAP_TYPE_NODE:      case NODE:
677        josm_elemstyles_colorize_node(style, map_item->node);        josm_elemstyles_colorize_node(style, map_item->object.node);
678        break;        break;
679      default:      default:
680        g_assert((map_item->type == MAP_TYPE_NODE) ||        g_assert((map_item->object.type == NODE) ||
681                     (map_item->type == MAP_TYPE_WAY));                     (map_item->object.type == WAY));
682    }    }
683  }  }
684    
685  void map_item_redraw(appdata_t *appdata, map_item_t *map_item) {  void map_item_redraw(appdata_t *appdata, map_item_t *map_item) {
686    map_item_t item = *map_item;    map_item_t item = *map_item;
687    
688      /* a relation cannot be redraws as it doesn't have a visual */
689      /* representation */
690      if(map_item->object.type == RELATION)
691        return;
692    
693    /* check if the item to be redrawn is the selected one */    /* check if the item to be redrawn is the selected one */
694    gboolean is_selected = FALSE;    gboolean is_selected = FALSE;
695    if(map_item->ptr == appdata->map->selected.ptr) {    if(map_item->object.ptr == appdata->map->selected.object.ptr) {
696      map_item_deselect(appdata);      map_item_deselect(appdata);
697      is_selected = TRUE;      is_selected = TRUE;
698    }    }
# Line 589  void map_item_redraw(appdata_t *appdata, Line 703  void map_item_redraw(appdata_t *appdata,
703    
704    /* restore selection if there was one */    /* restore selection if there was one */
705    if(is_selected)    if(is_selected)
706      map_item_select(appdata, &item);      map_object_select(appdata, &item.object);
707  }  }
708    
709  static void map_frisket_rectangle(canvas_points_t *points,  static void map_frisket_rectangle(canvas_points_t *points,
# Line 606  void map_frisket_draw(map_t *map, bounds Line 720  void map_frisket_draw(map_t *map, bounds
720    canvas_points_t *points = canvas_points_new(5);    canvas_points_t *points = canvas_points_new(5);
721    
722    /* don't draw frisket at all if it's completely transparent */    /* don't draw frisket at all if it's completely transparent */
723    if(map->style->frisket.opaque) {    if(map->style->frisket.color & 0xff) {
724      elemstyle_color_t color =      elemstyle_color_t color = map->style->frisket.color;
       (map->style->background.color<<8) | map->style->frisket.opaque;  
725    
726      float mult = map->style->frisket.mult;      float mult = map->style->frisket.mult;
727    
728      /* top rectangle */      /* top rectangle */
729      map_frisket_rectangle(points, mult*bounds->min.x, mult*bounds->max.x,      map_frisket_rectangle(points, mult*bounds->min.x, mult*bounds->max.x,
730                            mult*bounds->min.y, bounds->min.y);                            mult*bounds->min.y, bounds->min.y);
731      canvas_polygon_new(map, CANVAS_GROUP_NODES, points, 1, NO_COLOR, color);      canvas_polygon_new(map->canvas, CANVAS_GROUP_FRISKET, points,
732                           1, NO_COLOR, color);
733    
734      /* bottom rectangle */      /* bottom rectangle */
735      map_frisket_rectangle(points, mult*bounds->min.x, mult*bounds->max.x,      map_frisket_rectangle(points, mult*bounds->min.x, mult*bounds->max.x,
736                            bounds->max.y, mult*bounds->max.y);                            bounds->max.y, mult*bounds->max.y);
737      canvas_polygon_new(map, CANVAS_GROUP_NODES, points, 1, NO_COLOR, color);      canvas_polygon_new(map->canvas, CANVAS_GROUP_FRISKET, points,
738                           1, NO_COLOR, color);
739    
740      /* left rectangle */      /* left rectangle */
741      map_frisket_rectangle(points, mult*bounds->min.x, bounds->min.x,      map_frisket_rectangle(points, mult*bounds->min.x, bounds->min.x,
742                            mult*bounds->min.y, mult*bounds->max.y);                            mult*bounds->min.y, mult*bounds->max.y);
743      canvas_polygon_new(map, CANVAS_GROUP_NODES, points, 1, NO_COLOR, color);      canvas_polygon_new(map->canvas, CANVAS_GROUP_FRISKET, points,
744                           1, NO_COLOR, color);
745    
746      /* right rectangle */      /* right rectangle */
747      map_frisket_rectangle(points, bounds->max.x, mult*bounds->max.x,      map_frisket_rectangle(points, bounds->max.x, mult*bounds->max.x,
748                            mult*bounds->min.y, mult*bounds->max.y);                            mult*bounds->min.y, mult*bounds->max.y);
749      canvas_polygon_new(map, CANVAS_GROUP_NODES, points, 1, NO_COLOR, color);      canvas_polygon_new(map->canvas, CANVAS_GROUP_FRISKET, points,
750                           1, NO_COLOR, color);
751    
752    }    }
753    
# Line 641  void map_frisket_draw(map_t *map, bounds Line 758  void map_frisket_draw(map_t *map, bounds
758                            bounds->min.x-ew2, bounds->max.x+ew2,                            bounds->min.x-ew2, bounds->max.x+ew2,
759                            bounds->min.y-ew2, bounds->max.y+ew2);                            bounds->min.y-ew2, bounds->max.y+ew2);
760    
761      canvas_polyline_new(map, CANVAS_GROUP_NODES, points,      canvas_polyline_new(map->canvas, CANVAS_GROUP_FRISKET, points,
762                          map->style->frisket.border.width,                          map->style->frisket.border.width,
763                          map->style->frisket.border.color);                          map->style->frisket.border.color);
764    
# Line 776  map_item_t *map_item_at(map_t *map, gint Line 893  map_item_t *map_item_at(map_t *map, gint
893    if(map_item->highlight)    if(map_item->highlight)
894      printf("  item is highlight\n");      printf("  item is highlight\n");
895    
896    switch(map_item->type) {    switch(map_item->object.type) {
897    case MAP_TYPE_NODE:    case NODE:
898      printf("  item is node #%ld\n", map_item->node->id);      printf("  item is node #"ITEM_ID_FORMAT"\n", map_item->object.node->id);
899      break;      break;
900    case MAP_TYPE_WAY:    case WAY:
901      printf("  item is way #%ld\n", map_item->way->id);      printf("  item is way #"ITEM_ID_FORMAT"\n", map_item->object.way->id);
902      break;      break;
903    default:    default:
904      printf("  unknown item\n");      printf("  unknown item\n");
# Line 800  map_item_t *map_real_item_at(map_t *map, Line 917  map_item_t *map_real_item_at(map_t *map,
917    
918    /* get the item (parent) this item is the highlight of */    /* get the item (parent) this item is the highlight of */
919    map_item_t *parent = NULL;    map_item_t *parent = NULL;
920    switch(map_item->type) {    switch(map_item->object.type) {
921    
922    case MAP_TYPE_NODE:    case NODE:
923      if(map_item->node->map_item_chain)      if(map_item->object.node->map_item_chain)
924        parent = map_item->node->map_item_chain->map_item;        parent = map_item->object.node->map_item_chain->map_item;
925    
926      if(parent)      if(parent)
927        printf("  using parent item node #%ld\n", parent->node->id);        printf("  using parent item node #" ITEM_ID_FORMAT "\n",
928                 parent->object.node->id);
929      break;      break;
930    
931    case MAP_TYPE_WAY:    case WAY:
932      if(map_item->way->map_item_chain)      if(map_item->object.way->map_item_chain)
933        parent = map_item->way->map_item_chain->map_item;        parent = map_item->object.way->map_item_chain->map_item;
934    
935      if(parent)      if(parent)
936        printf("  using parent item way #%ld\n", parent->way->id);        printf("  using parent item way #" ITEM_ID_FORMAT "\n",
937                 parent->object.way->id);
938      break;      break;
939    
940    default:    default:
941      g_assert((map_item->type == MAP_TYPE_NODE) ||      g_assert((map_item->object.type == NODE) ||
942               (map_item->type == MAP_TYPE_WAY));               (map_item->object.type == WAY));
943      break;      break;
944    }    }
945    
# Line 832  map_item_t *map_real_item_at(map_t *map, Line 951  map_item_t *map_real_item_at(map_t *map,
951    return map_item;    return map_item;
952  }  }
953    
   
   
 #ifdef USE_GOOCANVAS  
   
954  /* Limitations on the amount by which we can scroll. Keeps part of the  /* Limitations on the amount by which we can scroll. Keeps part of the
955   * map visible at all times */   * map visible at all times */
956  static void map_limit_scroll(map_t *map, gint *sx, gint *sy) {  static void map_limit_scroll(map_t *map, canvas_unit_t unit,
957      gdouble zoom = goo_canvas_get_scale(GOO_CANVAS(map->canvas));                               gint *sx, gint *sy) {
   
     gint sx_cu = *sx / zoom;  
     gint sy_cu = *sy / zoom;  
   
     // Canvas viewport dimensions  
     GtkAllocation *a = &GTK_WIDGET(map->canvas)->allocation;  
     gint aw_cu = a->width / zoom;  
     gint ah_cu = a->height / zoom;  
   
     // Data rect minimum and maximum  
     gint min_x, min_y, max_x, max_y;  
     min_x = map->appdata->osm->bounds->min.x;  
     min_y = map->appdata->osm->bounds->min.y;  
     max_x = map->appdata->osm->bounds->max.x;  
     max_y = map->appdata->osm->bounds->max.y;  
958    
959      // limit stops - prevent scrolling beyond these    /* get scale factor for pixel->meter conversion. set to 1 if */
960      gint min_sy_cu = 0.95*(min_y - ah_cu);    /* given coordinates are already in meters */
961      gint min_sx_cu = 0.95*(min_x - aw_cu);    gdouble scale = (unit == CANVAS_UNIT_METER)?1.0:canvas_get_zoom(map->canvas);
962      gint max_sy_cu = 0.95*(max_y);  
963      gint max_sx_cu = 0.95*(max_x);    /* convert pixels to meters if necessary */
964      if (sy_cu < min_sy_cu) { *sy = min_sy_cu*zoom; }    gdouble sx_cu = *sx / scale;
965      if (sx_cu < min_sx_cu) { *sx = min_sx_cu*zoom; }    gdouble sy_cu = *sy / scale;
966      if (sy_cu > max_sy_cu) { *sy = max_sy_cu*zoom; }  
967      if (sx_cu > max_sx_cu) { *sx = max_sx_cu*zoom; }    /* get size of visible area in canvas units (meters) */
968      gint aw_cu = canvas_get_viewport_width(map->canvas, CANVAS_UNIT_METER);
969      gint ah_cu = canvas_get_viewport_height(map->canvas, CANVAS_UNIT_METER);
970    
971      // Data rect minimum and maximum
972      gint min_x, min_y, max_x, max_y;
973      min_x = map->appdata->osm->bounds->min.x;
974      min_y = map->appdata->osm->bounds->min.y;
975      max_x = map->appdata->osm->bounds->max.x;
976      max_y = map->appdata->osm->bounds->max.y;
977    
978      // limit stops - prevent scrolling beyond these
979      gint min_sy_cu = 0.95*(min_y - ah_cu);
980      gint min_sx_cu = 0.95*(min_x - aw_cu);
981      gint max_sy_cu = 0.95*(max_y);
982      gint max_sx_cu = 0.95*(max_x);
983      if (sy_cu < min_sy_cu) { *sy = min_sy_cu * scale; }
984      if (sx_cu < min_sx_cu) { *sx = min_sx_cu * scale; }
985      if (sy_cu > max_sy_cu) { *sy = max_sy_cu * scale; }
986      if (sx_cu > max_sx_cu) { *sx = max_sx_cu * scale; }
987  }  }
988    
989    
# Line 878  static gboolean map_limit_zoom(map_t *ma Line 997  static gboolean map_limit_zoom(map_t *ma
997      max_x = map->appdata->osm->bounds->max.x;      max_x = map->appdata->osm->bounds->max.x;
998      max_y = map->appdata->osm->bounds->max.y;      max_y = map->appdata->osm->bounds->max.y;
999    
1000      // Canvas viewport dimensions      /* get size of visible area in pixels and convert to meters of intended */
1001      GtkAllocation *a = &GTK_WIDGET(map->canvas)->allocation;      /* zoom by deviding by zoom (which is basically pix/m) */
1002      gint ah_cu = a->height / *zoom;      gint aw_cu =
1003      gint aw_cu = a->width / *zoom;        canvas_get_viewport_width(map->canvas, CANVAS_UNIT_PIXEL) / *zoom;
1004        gint ah_cu =
1005          canvas_get_viewport_height(map->canvas, CANVAS_UNIT_PIXEL) / *zoom;
1006    
1007      gdouble oldzoom = *zoom;      gdouble oldzoom = *zoom;
1008      if (ah_cu < aw_cu) {      if (ah_cu < aw_cu) {
# Line 906  static gboolean map_limit_zoom(map_t *ma Line 1027  static gboolean map_limit_zoom(map_t *ma
1027  }  }
1028    
1029    
 #if 0  
 /* Scroll the map a little towards the centre from where it is right now.  
  * This is used as a cute recentring trick when the map is at its outer  
  * scroll limit. */  
 static void map_scroll_towards_centre(map_t *map, gdouble amt) {  
     gint sx, sy, sx_orig, sy_orig;  
     canvas_get_scroll_offsets(map->canvas, &sx, &sy);  
     gdouble zoom = goo_canvas_get_scale(GOO_CANVAS(map->canvas));  
     sx_orig=sx;  
     sy_orig=sy;  
   
     // Work in canvas units  
     gdouble sx_cu = sx / zoom;  
     gdouble sy_cu = sy / zoom;  
   
     // Map bounds  
     gdouble bmin_x_cu, bmin_y_cu, bmax_x_cu, bmax_y_cu;  
     bmin_x_cu = map->appdata->osm->bounds->min.x;  
     bmin_y_cu = map->appdata->osm->bounds->min.y;  
     bmax_x_cu = map->appdata->osm->bounds->max.x;  
     bmax_y_cu = map->appdata->osm->bounds->max.y;  
   
     // Canvas viewport dimensions  
     GtkAllocation *a = &GTK_WIDGET(map->canvas)->allocation;  
     gdouble ah_cu = a->height / zoom;  
     gdouble aw_cu = a->width / zoom;  
   
     // Scroll offsets that would recentre the map  
     gdouble centre_sx_cu, centre_sy_cu;  
     centre_sx_cu = - (aw_cu/2);  
     centre_sy_cu = - (ah_cu/2);  
   
     // Move towards centre by a given fraction of the whole map  
     if (sx_cu > centre_sx_cu) {  
         sx_cu -= ((bmax_x_cu - bmin_x_cu) * amt);  
         if (sx_cu < centre_sx_cu) {  
             printf("force-centre-x\n");  
             sx_cu = centre_sx_cu;  
         }  
     }  
     if (sx_cu < centre_sx_cu) {  
         sx_cu += ((bmax_x_cu - bmin_x_cu) * amt);  
         if (sx_cu > centre_sx_cu) {  
             printf("force-centre-x\n");  
             sx_cu = centre_sx_cu;  
         }  
     }  
   
     if (sy_cu > centre_sy_cu) {  
         sy_cu -= ((bmax_y_cu - bmin_y_cu) * amt);  
         if (sy_cu < centre_sy_cu) {  
             printf("force-centre-y\n");  
             sy_cu = centre_sy_cu;  
         }  
     }  
     if (sy_cu < centre_sy_cu) {  
         sy_cu += ((bmax_y_cu - bmin_y_cu) * amt);  
         if (sy_cu > centre_sy_cu) {  
             printf("force-centre-y\n");  
             sy_cu = centre_sy_cu;  
         }  
     }  
   
     // Back to pixels for setting the scroll  
     sx = (gint)(sx_cu * zoom);  
     sy = (gint)(sy_cu * zoom);  
     canvas_scroll_to(map->canvas, sx, sy);  
     map->state->scroll_offset.x = sx;  
     map->state->scroll_offset.y = sy;  
 }  
 #endif // #if 0  
   
1030  /*  /*
1031   * Scroll the map to a point if that point is currently offscreen.   * Scroll the map to a point if that point is currently offscreen.
1032   */   */
# Line 1000  void map_scroll_to_if_offscreen(map_t *m Line 1049  void map_scroll_to_if_offscreen(map_t *m
1049    }    }
1050    
1051    // Viewport dimensions in canvas space    // Viewport dimensions in canvas space
1052    gdouble zoom = goo_canvas_get_scale(GOO_CANVAS(map->canvas));  
1053    GtkAllocation *a = &GTK_WIDGET(map->canvas)->allocation;    /* get size of visible area in canvas units (meters) */
1054    gdouble aw = a->width / zoom;    gdouble pix_per_meter = canvas_get_zoom(map->canvas);
1055    gdouble ah = a->height / zoom;    gdouble aw = canvas_get_viewport_width(map->canvas, CANVAS_UNIT_METER);
1056      gdouble ah = canvas_get_viewport_height(map->canvas, CANVAS_UNIT_METER);
1057    
1058    // Is the point still onscreen?    // Is the point still onscreen?
1059    gboolean vert_recentre_needed = FALSE;    gboolean vert_recentre_needed = FALSE;
1060    gboolean horiz_recentre_needed = FALSE;    gboolean horiz_recentre_needed = FALSE;
1061    gint sx, sy;    gint sx, sy;
1062    canvas_get_scroll_offsets(map->canvas, &sx, &sy);    canvas_scroll_get(map->canvas, CANVAS_UNIT_PIXEL, &sx, &sy);
1063    gint viewport_left   = (sx/zoom);    gint viewport_left   = (sx/pix_per_meter);
1064    gint viewport_right  = (sx/zoom)+aw;    gint viewport_right  = (sx/pix_per_meter)+aw;
1065    gint viewport_top    = (sy/zoom);    gint viewport_top    = (sy/pix_per_meter);
1066    gint viewport_bottom = (sy/zoom)+ah;    gint viewport_bottom = (sy/pix_per_meter)+ah;
1067    if (lpos->x > viewport_right) {    if (lpos->x > viewport_right) {
1068      printf("** off right edge (%d > %d)\n", lpos->x, viewport_right);      printf("** off right edge (%d > %d)\n", lpos->x, viewport_right);
1069      horiz_recentre_needed = TRUE;      horiz_recentre_needed = TRUE;
# Line 1033  void map_scroll_to_if_offscreen(map_t *m Line 1083  void map_scroll_to_if_offscreen(map_t *m
1083    
1084    if (horiz_recentre_needed || vert_recentre_needed) {    if (horiz_recentre_needed || vert_recentre_needed) {
1085      gint new_sx, new_sy;      gint new_sx, new_sy;
1086  #if 0  
     // Only recentre the drifting axis.  
     new_sx = horiz_recentre_needed ? zoom*(lpos->x - (aw/2)) : sx;  
     new_sy = vert_recentre_needed  ? zoom*(lpos->y - (ah/2)) : sy;  
     // Not sure about this. I don't think it really buys us anything.  
 #else  
1087      // Just centre both at once      // Just centre both at once
1088      new_sx = zoom * (lpos->x - (aw/2));      new_sx = pix_per_meter * (lpos->x - (aw/2));
1089      new_sy = zoom * (lpos->y - (ah/2));      new_sy = pix_per_meter * (lpos->y - (ah/2));
1090  #endif  
1091      map_limit_scroll(map, &new_sx, &new_sy);      map_limit_scroll(map, CANVAS_UNIT_PIXEL, &new_sx, &new_sy);
1092      canvas_scroll_to(map->canvas, new_sx, new_sy);      canvas_scroll_to(map->canvas, CANVAS_UNIT_PIXEL, new_sx, new_sy);
1093    }    }
1094  }  }
1095    
 #endif // #ifdef USE_GOOCANVAS  
   
1096  /* Deselects the current way or node if its zoom_max  /* Deselects the current way or node if its zoom_max
1097   * means that it's not going to render at the current map zoom. */   * means that it's not going to render at the current map zoom. */
1098  void map_deselect_if_zoom_below_zoom_max(map_t *map) {  void map_deselect_if_zoom_below_zoom_max(map_t *map) {
1099      if (map->selected.type == MAP_TYPE_WAY) {      if (map->selected.object.type == WAY) {
1100          printf("will deselect way if zoomed below %f\n",          printf("will deselect way if zoomed below %f\n",
1101                 map->selected.way->draw.zoom_max);                 map->selected.object.way->draw.zoom_max);
1102          if (map->state->zoom < map->selected.way->draw.zoom_max) {          if (map->state->zoom < map->selected.object.way->draw.zoom_max) {
1103              printf("  deselecting way!\n");              printf("  deselecting way!\n");
1104              map_item_deselect(map->appdata);              map_item_deselect(map->appdata);
1105          }          }
1106      }      }
1107      else if (map->selected.type == MAP_TYPE_NODE) {      else if (map->selected.object.type == NODE) {
1108          printf("will deselect node if zoomed below %f\n",          printf("will deselect node if zoomed below %f\n",
1109                 map->selected.node->zoom_max);                 map->selected.object.node->zoom_max);
1110          if (map->state->zoom < map->selected.node->zoom_max) {          if (map->state->zoom < map->selected.object.node->zoom_max) {
1111              printf("  deselecting node!\n");              printf("  deselecting node!\n");
1112              map_item_deselect(map->appdata);              map_item_deselect(map->appdata);
1113          }          }
# Line 1074  void map_deselect_if_zoom_below_zoom_max Line 1117  void map_deselect_if_zoom_below_zoom_max
1117  void map_set_zoom(map_t *map, double zoom,  void map_set_zoom(map_t *map, double zoom,
1118                    gboolean update_scroll_offsets) {                    gboolean update_scroll_offsets) {
1119    gboolean at_zoom_limit = 0;    gboolean at_zoom_limit = 0;
 #ifdef USE_GOOCANVAS  
1120    at_zoom_limit = map_limit_zoom(map, &zoom);    at_zoom_limit = map_limit_zoom(map, &zoom);
1121  #endif  
1122    map->state->zoom = zoom;    map->state->zoom = zoom;
1123    canvas_set_zoom(map->canvas, map->state->zoom);    canvas_set_zoom(map->canvas, map->state->zoom);
1124    
1125    map_deselect_if_zoom_below_zoom_max(map);    map_deselect_if_zoom_below_zoom_max(map);
1126    
1127    if (update_scroll_offsets) {    if(update_scroll_offsets) {
1128      if (!at_zoom_limit) {      if (!at_zoom_limit) {
1129        /* zooming affects the scroll offsets */        /* zooming affects the scroll offsets */
1130        gint sx, sy;        gint sx, sy;
1131        canvas_get_scroll_offsets(map->canvas, &sx, &sy);        canvas_scroll_get(map->canvas, CANVAS_UNIT_PIXEL, &sx, &sy);
1132  #ifdef USE_GOOCANVAS        map_limit_scroll(map, CANVAS_UNIT_PIXEL, &sx, &sy);
1133        map_limit_scroll(map, &sx, &sy);  
1134        canvas_scroll_to(map->canvas, sx, sy);  // keep the map visible        // keep the map visible
1135  #endif        canvas_scroll_to(map->canvas, CANVAS_UNIT_PIXEL, sx, sy);
       map->state->scroll_offset.x = sx;  
       map->state->scroll_offset.y = sy;  
     }  
 #ifdef USE_GOOCANVAS  
     else {  
       //      map_scroll_towards_centre(map, 0.20);  
1136      }      }
1137  #endif  
1138        canvas_scroll_get(map->canvas, CANVAS_UNIT_METER,
1139                          &map->state->scroll_offset.x,
1140                          &map->state->scroll_offset.y);
1141    }    }
1142  }  }
1143    
# Line 1123  static gboolean map_scroll_event(GtkWidg Line 1162  static gboolean map_scroll_event(GtkWidg
1162  static gboolean distance_above(map_t *map, gint x, gint y, gint limit) {  static gboolean distance_above(map_t *map, gint x, gint y, gint limit) {
1163    gint sx, sy;    gint sx, sy;
1164    
 #ifdef USE_GNOMECANVAS  
   gnome_canvas_get_scroll_offsets(GNOME_CANVAS(map->canvas), &sx, &sy);  
   
   /* add offsets generated by mouse within map and map scrolling */  
   sx = (x-map->pen_down.at.x) + (map->pen_down.so.x-sx);  
   sy = (y-map->pen_down.at.y) + (map->pen_down.so.y-sy);  
 #else  
1165    /* add offsets generated by mouse within map and map scrolling */    /* add offsets generated by mouse within map and map scrolling */
1166    sx = (x-map->pen_down.at.x);    sx = (x-map->pen_down.at.x);
1167    sy = (y-map->pen_down.at.y);    sy = (y-map->pen_down.at.y);
 #endif  
1168    
1169    return(sx*sx + sy*sy > limit*limit);    return(sx*sx + sy*sy > limit*limit);
1170  }  }
# Line 1142  static gboolean distance_above(map_t *ma Line 1173  static gboolean distance_above(map_t *ma
1173  static void map_do_scroll(map_t *map, gint x, gint y) {  static void map_do_scroll(map_t *map, gint x, gint y) {
1174    gint sx, sy;    gint sx, sy;
1175    
1176    canvas_get_scroll_offsets(map->canvas, &sx, &sy);    canvas_scroll_get(map->canvas, CANVAS_UNIT_PIXEL, &sx, &sy);
1177    sx -= x-map->pen_down.at.x;    sx -= x-map->pen_down.at.x;
1178    sy -= y-map->pen_down.at.y;    sy -= y-map->pen_down.at.y;
1179  #ifdef USE_GOOCANVAS    map_limit_scroll(map, CANVAS_UNIT_PIXEL, &sx, &sy);
1180    map_limit_scroll(map, &sx, &sy);    canvas_scroll_to(map->canvas, CANVAS_UNIT_PIXEL, sx, sy);
1181  #endif  
1182    canvas_scroll_to(map->canvas, sx, sy);    canvas_scroll_get(map->canvas, CANVAS_UNIT_METER,
1183    map->state->scroll_offset.x = sx;                      &map->state->scroll_offset.x,
1184    map->state->scroll_offset.y = sy;                      &map->state->scroll_offset.y);
1185  }  }
1186    
1187    
1188  /* scroll a certain step */  /* scroll a certain step */
1189  static void map_do_scroll_step(map_t *map, gint x, gint y) {  static void map_do_scroll_step(map_t *map, gint x, gint y) {
1190    gint sx, sy;    gint sx, sy;
1191    canvas_get_scroll_offsets(map->canvas, &sx, &sy);    canvas_scroll_get(map->canvas, CANVAS_UNIT_PIXEL, &sx, &sy);
1192    sx += x;    sx += x;
1193    sy += y;    sy += y;
1194  #ifdef USE_GOOCANVAS    map_limit_scroll(map, CANVAS_UNIT_PIXEL, &sx, &sy);
1195    map_limit_scroll(map, &sx, &sy);    canvas_scroll_to(map->canvas, CANVAS_UNIT_PIXEL, sx, sy);
 #endif  
   canvas_scroll_to(map->canvas, sx, sy);  
   map->state->scroll_offset.x = sx;  
   map->state->scroll_offset.y = sy;  
 }  
1196    
1197      canvas_scroll_get(map->canvas, CANVAS_UNIT_METER,
1198                        &map->state->scroll_offset.x,
1199                        &map->state->scroll_offset.y);
1200    }
1201    
1202  gboolean map_item_is_selected_node(map_t *map, map_item_t *map_item) {  gboolean map_item_is_selected_node(map_t *map, map_item_t *map_item) {
1203    printf("check if item is a selected node\n");    printf("check if item is a selected node\n");
# Line 1177  gboolean map_item_is_selected_node(map_t Line 1207  gboolean map_item_is_selected_node(map_t
1207      return FALSE;      return FALSE;
1208    }    }
1209    
1210    if(map->selected.type == MAP_TYPE_ILLEGAL) {    if(map->selected.object.type == ILLEGAL) {
1211      printf("  nothing is selected\n");      printf("  nothing is selected\n");
1212      return FALSE;      return FALSE;
1213    }    }
1214    
1215    /* clicked the highlight directly */    /* clicked the highlight directly */
1216    if(map_item->type != MAP_TYPE_NODE) {    if(map_item->object.type != NODE) {
1217      printf("  didn't click node\n");      printf("  didn't click node\n");
1218      return FALSE;      return FALSE;
1219    }    }
1220    
1221    if(map->selected.type == MAP_TYPE_NODE) {    if(map->selected.object.type == NODE) {
1222      printf("  selected item is a node\n");      printf("  selected item is a node\n");
1223    
1224      if(map_item->node == map->selected.node) {      if(map_item->object.node == map->selected.object.node) {
1225        printf("  requested item is a selected node\n");        printf("  requested item is a selected node\n");
1226        return TRUE;        return TRUE;
1227      }      }
1228      printf("  but it's not the requested one\n");      printf("  but it's not the requested one\n");
1229      return FALSE;      return FALSE;
1230    
1231    } else if(map->selected.type == MAP_TYPE_WAY) {    } else if(map->selected.object.type == WAY) {
1232      printf("  selected item is a way\n");      printf("  selected item is a way\n");
1233    
1234      node_chain_t *node_chain = map->selected.way->node_chain;      node_chain_t *node_chain = map->selected.object.way->node_chain;
1235      while(node_chain) {      while(node_chain) {
1236        if(node_chain->node == map_item->node) {        if(node_chain->node == map_item->object.node) {
1237          printf("  requested item is part of selected way\n");          printf("  requested item is part of selected way\n");
1238          return TRUE;          return TRUE;
1239        }        }
# Line 1231  gboolean map_item_is_selected_way(map_t Line 1261  gboolean map_item_is_selected_way(map_t
1261      return FALSE;      return FALSE;
1262    }    }
1263    
1264    if(map->selected.type == MAP_TYPE_ILLEGAL) {    if(map->selected.object.type == ILLEGAL) {
1265      printf("  nothing is selected\n");      printf("  nothing is selected\n");
1266      return FALSE;      return FALSE;
1267    }    }
1268    
1269    /* clicked the highlight directly */    /* clicked the highlight directly */
1270    if(map_item->type != MAP_TYPE_WAY) {    if(map_item->object.type != WAY) {
1271      printf("  didn't click way\n");      printf("  didn't click way\n");
1272      return FALSE;      return FALSE;
1273    }    }
1274    
1275    if(map->selected.type == MAP_TYPE_WAY) {    if(map->selected.object.type == WAY) {
1276      printf("  selected item is a way\n");      printf("  selected item is a way\n");
1277    
1278      if(map_item->way == map->selected.way) {      if(map_item->object.way == map->selected.object.way) {
1279        printf("  requested item is a selected way\n");        printf("  requested item is a selected way\n");
1280        return TRUE;        return TRUE;
1281      }      }
# Line 1260  gboolean map_item_is_selected_way(map_t Line 1290  gboolean map_item_is_selected_way(map_t
1290    
1291  void map_highlight_refresh(appdata_t *appdata) {  void map_highlight_refresh(appdata_t *appdata) {
1292    map_t *map = appdata->map;    map_t *map = appdata->map;
1293    map_item_t old = map->selected;    object_t old = map->selected.object;
1294    
1295    printf("type to refresh is %d\n", old.type);    printf("type to refresh is %d\n", old.type);
1296    if(old.type == MAP_TYPE_ILLEGAL)    if(old.type == ILLEGAL)
1297      return;      return;
1298    
1299    map_item_deselect(appdata);    map_item_deselect(appdata);
1300    map_item_select(appdata, &old);    map_object_select(appdata, &old);
1301  }  }
1302    
1303  void map_way_delete(appdata_t *appdata, way_t *way) {  void map_way_delete(appdata_t *appdata, way_t *way) {
1304    printf("deleting way #%ld from map and osm\n", way->id);    printf("deleting way #" ITEM_ID_FORMAT " from map and osm\n", way->id);
1305    
1306    /* remove it visually from the screen */    /* remove it visually from the screen */
1307    map_item_chain_destroy(&way->map_item_chain);    map_item_chain_destroy(&way->map_item_chain);
# Line 1295  static void map_handle_click(appdata_t * Line 1325  static void map_handle_click(appdata_t *
1325    /* problem: on_item may be the highlight itself! So store it! */    /* problem: on_item may be the highlight itself! So store it! */
1326    map_item_t map_item;    map_item_t map_item;
1327    if(map->pen_down.on_item) map_item = *map->pen_down.on_item;    if(map->pen_down.on_item) map_item = *map->pen_down.on_item;
1328    else                      map_item.type = MAP_TYPE_ILLEGAL;    else                      map_item.object.type = ILLEGAL;
1329    
1330    /* if we aready have something selected, then de-select it */    /* if we aready have something selected, then de-select it */
1331    map_item_deselect(appdata);    map_item_deselect(appdata);
1332    
1333    /* select the clicked item (if there was one) */    /* select the clicked item (if there was one) */
1334    if(map_item.type != MAP_TYPE_ILLEGAL) {    if(map_item.object.type != ILLEGAL) {
1335      switch(map_item.type) {      switch(map_item.object.type) {
1336      case MAP_TYPE_NODE:      case NODE:
1337        map_node_select(appdata, map_item.node);        map_node_select(appdata, map_item.object.node);
1338        break;        break;
1339    
1340      case MAP_TYPE_WAY:      case WAY:
1341        map_way_select(appdata, map_item.way);        map_way_select(appdata, map_item.object.way);
1342        break;        break;
1343    
1344      default:      default:
1345        g_assert((map_item.type == MAP_TYPE_NODE) ||        g_assert((map_item.object.type == NODE) ||
1346                 (map_item.type == MAP_TYPE_WAY));                 (map_item.object.type == WAY));
1347        break;        break;
1348      }      }
1349    }    }
# Line 1333  static void map_touchnode_update(appdata Line 1363  static void map_touchnode_update(appdata
1363      /* in idle mode the dragged node is not highlighted */      /* in idle mode the dragged node is not highlighted */
1364    case MAP_ACTION_IDLE:    case MAP_ACTION_IDLE:
1365      g_assert(map->pen_down.on_item);      g_assert(map->pen_down.on_item);
1366      g_assert(map->pen_down.on_item->type == MAP_TYPE_NODE);      g_assert(map->pen_down.on_item->object.type == NODE);
1367      cur_node = map->pen_down.on_item->node;      cur_node = map->pen_down.on_item->object.node;
1368      break;      break;
1369    
1370    default:    default:
# Line 1349  static void map_touchnode_update(appdata Line 1379  static void map_touchnode_update(appdata
1379      /* don't highlight the dragged node itself and don't highlight */      /* don't highlight the dragged node itself and don't highlight */
1380      /* deleted ones */      /* deleted ones */
1381      if((node != cur_node) && (!(node->flags & OSM_FLAG_DELETED))) {      if((node != cur_node) && (!(node->flags & OSM_FLAG_DELETED))) {
1382        gint nx = x - node->lpos.x;        gint nx = abs(x - node->lpos.x);
1383        gint ny = y - node->lpos.y;        gint ny = abs(y - node->lpos.y);
1384    
1385        if((nx < map->style->node.radius) && (ny < map->style->node.radius) &&        if((nx < map->style->node.radius) && (ny < map->style->node.radius) &&
1386           (nx*nx + ny*ny < map->style->node.radius * map->style->node.radius))           (nx*nx + ny*ny < map->style->node.radius * map->style->node.radius))
# Line 1364  static void map_touchnode_update(appdata Line 1394  static void map_touchnode_update(appdata
1394    if(!map->touchnode && map->action.way) {    if(!map->touchnode && map->action.way) {
1395      node_chain_t *chain = map->action.way->node_chain;      node_chain_t *chain = map->action.way->node_chain;
1396      while(!map->touchnode && chain && chain->next) {      while(!map->touchnode && chain && chain->next) {
1397        gint nx = x - chain->node->lpos.x;        gint nx = abs(x - chain->node->lpos.x);
1398        gint ny = y - chain->node->lpos.y;        gint ny = abs(y - chain->node->lpos.y);
1399    
1400        if((nx < map->style->node.radius) && (ny < map->style->node.radius) &&        if((nx < map->style->node.radius) && (ny < map->style->node.radius) &&
1401           (nx*nx + ny*ny < map->style->node.radius * map->style->node.radius))           (nx*nx + ny*ny < map->style->node.radius * map->style->node.radius))
# Line 1386  static void map_button_press(map_t *map, Line 1416  static void map_button_press(map_t *map,
1416    map->pen_down.at.y = y;    map->pen_down.at.y = y;
1417    map->pen_down.drag = FALSE;     // don't assume drag yet    map->pen_down.drag = FALSE;     // don't assume drag yet
1418    
 #ifdef USE_GNOMECANVAS  
   /* save initial scroll offset */  
   gnome_canvas_get_scroll_offsets(GNOME_CANVAS(map->canvas),  
                   &map->pen_down.so.x, &map->pen_down.so.y);  
 #endif  
   
1419    /* determine wether this press was on an item */    /* determine wether this press was on an item */
1420    map->pen_down.on_item = map_real_item_at(map, x, y);    map->pen_down.on_item = map_real_item_at(map, x, y);
1421    
# Line 1463  static void map_button_release(map_t *ma Line 1487  static void map_button_release(map_t *ma
1487        map_item_t old_sel = map->selected;        map_item_t old_sel = map->selected;
1488        map_handle_click(map->appdata, map);        map_handle_click(map->appdata, map);
1489    
1490        if((old_sel.type != MAP_TYPE_ILLEGAL) &&        if((old_sel.object.type != ILLEGAL) &&
1491           (old_sel.type == map->selected.type) &&           (old_sel.object.type == map->selected.object.type) &&
1492           (old_sel.ptr == map->selected.ptr)) {           (old_sel.object.ptr == map->selected.object.ptr)) {
1493          printf("re-selected same item of type %d, "          printf("re-selected same item of type %d, "
1494                 "pushing it to the bottom\n", old_sel.type);                 "pushing it to the bottom\n", old_sel.object.type);
1495    
1496          if(!map->selected.item) {          if(!map->selected.item) {
1497            printf("  item has no visible representation to push\n");            printf("  item has no visible representation to push\n");
# Line 1584  static gboolean map_motion_notify_event( Line 1608  static gboolean map_motion_notify_event(
1608    /* reduce update frequency on hildon to keep screen update fluid */    /* reduce update frequency on hildon to keep screen update fluid */
1609    static guint32 last_time = 0;    static guint32 last_time = 0;
1610    
1611    if(event->time - last_time < 100) return FALSE;    if(event->time - last_time < 250) return FALSE;
1612    last_time = event->time;    last_time = event->time;
1613  #endif  #endif
1614    
1615    if(!map->pen_down.is)    if(!map->pen_down.is)
1616      return FALSE;      return FALSE;
1617    
1618  #ifdef USE_GNOMECANVAS  #ifndef USE_GOOCANVAS
1619    /* handle hints, hints are handled by goocanvas directly */    /* handle hints, hints are handled by goocanvas directly */
1620    if(event->is_hint)    if(event->is_hint)
1621      gdk_window_get_pointer(event->window, &x, &y, &state);      gdk_window_get_pointer(event->window, &x, &y, &state);
# Line 1636  static gboolean map_motion_notify_event( Line 1660  static gboolean map_motion_notify_event(
1660    
1661    case MAP_ACTION_WAY_NODE_ADD:    case MAP_ACTION_WAY_NODE_ADD:
1662      map_hl_cursor_clear(map);      map_hl_cursor_clear(map);
1663      map_item_t *item = map_real_item_at(map, x, y);      map_item_t *item = map_item_at(map, x, y);
1664      if(item) map_edit_way_node_add_highlight(map, item, x, y);      if(item) map_edit_way_node_add_highlight(map, item, x, y);
1665      break;      break;
1666    
1667    case MAP_ACTION_WAY_CUT:    case MAP_ACTION_WAY_CUT:
1668      map_hl_cursor_clear(map);      map_hl_cursor_clear(map);
1669      item = map_real_item_at(map, x, y);      item = map_item_at(map, x, y);
1670      if(item) map_edit_way_cut_highlight(map, item, x, y);      if(item) map_edit_way_cut_highlight(map, item, x, y);
1671      break;      break;
1672    
# Line 1729  gboolean map_key_press_event(appdata_t * Line 1753  gboolean map_key_press_event(appdata_t *
1753    return FALSE;    return FALSE;
1754  }  }
1755    
1756    void map_state_reset(map_state_t *state) {
1757      if(!state) return;
1758    
1759      state->zoom = 0.25;
1760      state->detail = 1.0;
1761    
1762      /* todo: try to scroll to center of screen */
1763      state->scroll_offset.x = 0;
1764      state->scroll_offset.y = 0;
1765    }
1766    
1767    map_state_t *map_state_new(void) {
1768      map_state_t *state = g_new0(map_state_t, 1);
1769      map_state_reset(state);
1770      return state;
1771    }
1772    
1773  GtkWidget *map_new(appdata_t *appdata) {  GtkWidget *map_new(appdata_t *appdata) {
1774    map_t *map = appdata->map = g_new0(map_t, 1);    map_t *map = appdata->map = g_new0(map_t, 1);
1775    
1776    map->style = style_load(appdata, appdata->settings->style);    map->style = style_load(appdata, appdata->settings->style);
1777      if(!map->style) {
1778        errorf(NULL, _("Unable to load valid style, terminating."));
1779        g_free(map);
1780        return NULL;
1781      }
1782    
1783    if(appdata->project && appdata->project->map_state) {    if(appdata->project && appdata->project->map_state) {
1784      printf("Using projects map state\n");      printf("Using projects map state\n");
1785      map->state = appdata->project->map_state;      map->state = appdata->project->map_state;
1786    } else {    } else {
1787      printf("Creating new map state\n");      printf("Creating new map state\n");
1788      map->state = g_new0(map_state_t, 1);      map->state = map_state_new();
     map->state->zoom = 0.25;  
1789    }    }
1790    
1791    map->state->refcount++;    map->state->refcount++;
# Line 1750  GtkWidget *map_new(appdata_t *appdata) { Line 1795  GtkWidget *map_new(appdata_t *appdata) {
1795    map->appdata = appdata;    map->appdata = appdata;
1796    map->action.type = MAP_ACTION_IDLE;    map->action.type = MAP_ACTION_IDLE;
1797    
1798  #ifdef USE_GNOMECANVAS    map->canvas = canvas_new(map->style->background.color);
   map->canvas = gnome_canvas_new_aa();  // _aa  
1799    
1800    /* create the groups */    GtkWidget *canvas_widget = canvas_get_widget(map->canvas);
   canvas_group_t group;  
   for(group = 0; group < CANVAS_GROUPS; group++)  
     map->group[group] = gnome_canvas_item_new(  
                 gnome_canvas_root(GNOME_CANVAS(map->canvas)),  
                 GNOME_TYPE_CANVAS_GROUP,  
                 NULL);  
   
   gtk_widget_modify_bg(map->canvas, GTK_STATE_NORMAL,  
                        &map->canvas->style->white);  
   
 #else  
   map->canvas = goo_canvas_new();  
1801    
1802    g_object_set(G_OBJECT(map->canvas), "anchor", GTK_ANCHOR_CENTER, NULL);    gtk_widget_set_events(canvas_widget,
   g_object_set(G_OBJECT(map->canvas), "background-color-rgb",  
                map->style->background.color, NULL);  
   
   GooCanvasItem *root = goo_canvas_get_root_item(GOO_CANVAS(map->canvas));  
   
   /* create the groups */  
   canvas_group_t group;  
   for(group = 0; group < CANVAS_GROUPS; group++)  
     map->group[group] = goo_canvas_group_new(root, NULL);  
   
 #endif  
   
   gtk_widget_set_events(map->canvas,  
1803                            GDK_BUTTON_PRESS_MASK                            GDK_BUTTON_PRESS_MASK
1804                          | GDK_BUTTON_RELEASE_MASK                          | GDK_BUTTON_RELEASE_MASK
1805                          | GDK_SCROLL_MASK                          | GDK_SCROLL_MASK
1806                          | GDK_POINTER_MOTION_MASK                          | GDK_POINTER_MOTION_MASK
1807                          | GDK_POINTER_MOTION_HINT_MASK);                          | GDK_POINTER_MOTION_HINT_MASK);
1808    
1809    gtk_signal_connect(GTK_OBJECT(map->canvas),    gtk_signal_connect(GTK_OBJECT(canvas_widget),
1810       "button_press_event", G_CALLBACK(map_button_event), appdata);       "button_press_event", G_CALLBACK(map_button_event), appdata);
1811    gtk_signal_connect(GTK_OBJECT(map->canvas),    gtk_signal_connect(GTK_OBJECT(canvas_widget),
1812       "button_release_event", G_CALLBACK(map_button_event), appdata);       "button_release_event", G_CALLBACK(map_button_event), appdata);
1813    gtk_signal_connect(GTK_OBJECT(map->canvas),    gtk_signal_connect(GTK_OBJECT(canvas_widget),
1814       "motion_notify_event", G_CALLBACK(map_motion_notify_event), appdata);       "motion_notify_event", G_CALLBACK(map_motion_notify_event), appdata);
1815    gtk_signal_connect(GTK_OBJECT(map->canvas),    gtk_signal_connect(GTK_OBJECT(canvas_widget),
1816       "scroll_event", G_CALLBACK(map_scroll_event), appdata);       "scroll_event", G_CALLBACK(map_scroll_event), appdata);
1817    
1818    gtk_signal_connect(GTK_OBJECT(map->canvas),    gtk_signal_connect(GTK_OBJECT(canvas_widget),
1819       "destroy", G_CALLBACK(map_destroy_event), appdata);       "destroy", G_CALLBACK(map_destroy_event), appdata);
1820    
1821    return map->canvas;    return canvas_widget;
1822  }  }
1823    
1824  void map_init(appdata_t *appdata) {  void map_init(appdata_t *appdata) {
# Line 1818  void map_init(appdata_t *appdata) { Line 1837  void map_init(appdata_t *appdata) {
1837                      mult*appdata->osm->bounds->max.x,                      mult*appdata->osm->bounds->max.x,
1838                      mult*appdata->osm->bounds->max.y);                      mult*appdata->osm->bounds->max.y);
1839    
1840    printf("restore scroll offsets %d/%d\n",    printf("restore scroll position %d/%d\n",
1841           map->state->scroll_offset.x, map->state->scroll_offset.y);           map->state->scroll_offset.x, map->state->scroll_offset.y);
1842    
1843    canvas_scroll_to(map->canvas,    map_limit_scroll(map, CANVAS_UNIT_METER,
1844                     map->state->scroll_offset.x, map->state->scroll_offset.y);             &map->state->scroll_offset.x, &map->state->scroll_offset.y);
1845      canvas_scroll_to(map->canvas, CANVAS_UNIT_METER,
1846               map->state->scroll_offset.x, map->state->scroll_offset.y);
1847  }  }
1848    
1849    
1850  void map_item_set_flags(map_item_t *map_item, int set, int clr) {  void map_clear(appdata_t *appdata, gint group_mask) {
   
   switch(map_item->type) {  
   case MAP_TYPE_NODE:  
     map_item->node->flags |=  set;  
     map_item->node->flags &= ~clr;  
     break;  
   
   case MAP_TYPE_WAY:  
     map_item->way->flags |=  set;  
     map_item->way->flags &= ~clr;  
     break;  
   
   default:  
     g_assert(0);  
     break;  
   }  
 }  
   
 void map_clear(appdata_t *appdata, gint layer_mask) {  
1851    map_t *map = appdata->map;    map_t *map = appdata->map;
1852    
1853    printf("freeing map contents\n");    printf("freeing map contents\n");
# Line 1855  void map_clear(appdata_t *appdata, gint Line 1857  void map_clear(appdata_t *appdata, gint
1857    /* remove a possibly existing highlight */    /* remove a possibly existing highlight */
1858    map_item_deselect(appdata);    map_item_deselect(appdata);
1859    
1860    canvas_group_t group;    canvas_erase(map->canvas, group_mask);
   for(group=0;group<CANVAS_GROUPS;group++) {  
   
 #ifdef USE_GNOMECANVAS  
     /* destroy the entire group */  
     canvas_item_destroy(map->group[group]);  
   
     /* and create an empty new one */  
     map->group[group] = gnome_canvas_item_new(  
                       gnome_canvas_root(GNOME_CANVAS(map->canvas)),  
                       GNOME_TYPE_CANVAS_GROUP,  
                       NULL);  
 #else  
     if(layer_mask & (1<<group)) {  
       gint children = goo_canvas_item_get_n_children(map->group[group]);  
       printf("Removing %d children from layer %d\n", children, group);  
       while(children--)  
         goo_canvas_item_remove_child(map->group[group], children);  
     }  
 #endif  
   }  
1861  }  }
1862    
1863  void map_paint(appdata_t *appdata) {  void map_paint(appdata_t *appdata) {
# Line 1912  void map_action_set(appdata_t *appdata, Line 1894  void map_action_set(appdata_t *appdata,
1894    
1895      /* remember if there was a way selected */      /* remember if there was a way selected */
1896      way_t *way_sel = NULL;      way_t *way_sel = NULL;
1897      if(appdata->map->selected.type == MAP_TYPE_WAY)      if(appdata->map->selected.object.type == WAY)
1898        way_sel = appdata->map->selected.way;        way_sel = appdata->map->selected.object.way;
1899    
1900      map_item_deselect(appdata);      map_item_deselect(appdata);
1901      map_edit_way_add_begin(appdata->map, way_sel);      map_edit_way_add_begin(appdata->map, way_sel);
# Line 1988  void map_action_ok(appdata_t *appdata) { Line 1970  void map_action_ok(appdata_t *appdata) {
1970      /* save changes to bg_offset in project */      /* save changes to bg_offset in project */
1971      appdata->project->wms_offset.x = map->bg.offset.x;      appdata->project->wms_offset.x = map->bg.offset.x;
1972      appdata->project->wms_offset.y = map->bg.offset.y;      appdata->project->wms_offset.y = map->bg.offset.y;
     appdata->project->dirty = TRUE;  
1973      break;      break;
1974    
1975    default:    default:
# Line 2012  void map_delete_selected(appdata_t *appd Line 1993  void map_delete_selected(appdata_t *appd
1993    /* deleting the selected item de-selects it ... */    /* deleting the selected item de-selects it ... */
1994    map_item_deselect(appdata);    map_item_deselect(appdata);
1995    
1996    switch(item.type) {    undo_remember_delete(appdata, &item.object);
1997    case MAP_TYPE_NODE:  
1998      printf("request to delete node #%ld\n", item.node->id);    switch(item.object.type) {
1999      case NODE:
2000        printf("request to delete node #" ITEM_ID_FORMAT "\n",
2001               item.object.node->id);
2002    
2003      /* check if this node is part of a way with two nodes only. */      /* check if this node is part of a way with two nodes only. */
2004      /* we cannot delete this as this would also delete the way */      /* we cannot delete this as this would also delete the way */
2005      way_chain_t *way_chain = osm_node_to_way(appdata->osm, item.node);      way_chain_t *way_chain = osm_node_to_way(appdata->osm, item.object.node);
2006      if(way_chain) {      if(way_chain) {
2007        gboolean short_way = FALSE;        gboolean short_way = FALSE;
2008    
# Line 2044  void map_delete_selected(appdata_t *appd Line 2028  void map_delete_selected(appdata_t *appd
2028      }      }
2029    
2030      /* remove it visually from the screen */      /* remove it visually from the screen */
2031      map_item_chain_destroy(&item.node->map_item_chain);      map_item_chain_destroy(&item.object.node->map_item_chain);
2032    
2033      /* and mark it "deleted" in the database */      /* and mark it "deleted" in the database */
2034      osm_node_remove_from_relation(appdata->osm, item.node);      osm_node_remove_from_relation(appdata->osm, item.object.node);
2035      way_chain_t *chain = osm_node_delete(appdata->osm,      way_chain_t *chain = osm_node_delete(appdata->osm,
2036                           &appdata->icon, item.node, FALSE, TRUE);                           &appdata->icon, item.object.node, FALSE, TRUE);
2037    
2038      /* redraw all affected ways */      /* redraw all affected ways */
2039      while(chain) {      while(chain) {
# Line 2062  void map_delete_selected(appdata_t *appd Line 2046  void map_delete_selected(appdata_t *appd
2046          map_way_delete(appdata, chain->way);          map_way_delete(appdata, chain->way);
2047        } else {        } else {
2048          map_item_t item;          map_item_t item;
2049          item.type = MAP_TYPE_WAY;          item.object.type = WAY;
2050          item.way = chain->way;          item.object.way = chain->way;
2051          map_item_redraw(appdata, &item);          map_item_redraw(appdata, &item);
2052        }        }
2053    
# Line 2074  void map_delete_selected(appdata_t *appd Line 2058  void map_delete_selected(appdata_t *appd
2058    
2059      break;      break;
2060    
2061    case MAP_TYPE_WAY:    case WAY:
2062      printf("request to delete way #%ld\n", item.way->id);      printf("request to delete way #" ITEM_ID_FORMAT "\n", item.object.way->id);
2063      map_way_delete(appdata, item.way);      map_way_delete(appdata, item.object.way);
2064      break;      break;
2065    
2066    default:    default:
2067      g_assert((item.type == MAP_TYPE_NODE) ||      g_assert((item.object.type == NODE) ||
2068               (item.type == MAP_TYPE_WAY));               (item.object.type == WAY));
2069      break;      break;
2070    }    }
2071  }  }
2072    
2073  /* ----------------------- track related stuff ----------------------- */  /* ----------------------- track related stuff ----------------------- */
2074    
2075    static gboolean track_pos2lpos(bounds_t *bounds, pos_t *pos, lpos_t *lpos) {
2076      pos2lpos(bounds, pos, lpos);
2077    
2078      /* check if point is within bounds */
2079      return ((lpos->x >= bounds->min.x) && (lpos->x <= bounds->max.x) &&
2080              (lpos->y >= bounds->min.y) && (lpos->y <= bounds->max.y));
2081    }
2082    
2083  void map_track_draw_seg(map_t *map, track_seg_t *seg) {  void map_track_draw_seg(map_t *map, track_seg_t *seg) {
2084      bounds_t *bounds = map->appdata->osm->bounds;
2085    
2086    /* a track_seg needs at least 2 points to be drawn */    /* a track_seg needs at least 2 points to be drawn */
2087    guint pnum = track_seg_points(seg);    guint pnum = track_seg_points(seg);
2088    printf("seg of length %d\n", pnum);    printf("seg of length %d\n", pnum);
2089    
2090    if(pnum == 1) {    if(!pnum)
2091      g_assert(!seg->item);      return;
2092    
2093      seg->item = canvas_circle_new(map, CANVAS_GROUP_TRACK,    /* nothing should have been drawn by now ... */
2094            seg->track_point->lpos.x, seg->track_point->lpos.y,    g_assert(!seg->item_chain);
2095            map->style->track.width/2.0, 0, map->style->track.color, NO_COLOR);  
2096    }    track_item_chain_t **itemP = &seg->item_chain;
2097      track_point_t *track_point = seg->track_point;
2098      while(track_point) {
2099        lpos_t lpos;
2100    
2101        /* skip all points not on screen */
2102        track_point_t *last = NULL;
2103        while(track_point && !track_pos2lpos(bounds, &track_point->pos, &lpos)) {
2104          last = track_point;
2105          track_point = track_point->next;
2106        }
2107    
2108        int visible = 0;
2109    
2110        /* count nodes that _are_ on screen */
2111        track_point_t *tmp = track_point;
2112        while(tmp && track_pos2lpos(bounds, &tmp->pos, &lpos)) {
2113          tmp = tmp->next;
2114          visible++;
2115        }
2116    
2117        /* actually start drawing with the last position that was offscreen */
2118        /* so the track nicely enters the viewing area */
2119        if(last) {
2120          track_point = last;
2121          visible++;
2122        }
2123    
2124        /* also use last one that's offscreen to nicely leave the visible area */
2125        if(tmp && tmp->next)
2126          visible++;
2127    
   if(pnum > 1) {  
   
2128      /* allocate space for nodes */      /* allocate space for nodes */
2129      canvas_points_t *points = canvas_points_new(pnum);      canvas_points_t *points = canvas_points_new(visible);
2130    
2131      int point = 0;      printf("visible are %d\n", visible);
2132      track_point_t *track_point = seg->track_point;      int point;
2133      while(track_point) {      for(point=0;point<visible;point++) {
2134        points->coords[point++] = track_point->lpos.x;        track_pos2lpos(bounds, &track_point->pos, &lpos);
2135        points->coords[point++] = track_point->lpos.y;  
2136          points->coords[2*point+0] = lpos.x;
2137          points->coords[2*point+1] = lpos.y;
2138        track_point = track_point->next;        track_point = track_point->next;
2139      }      }
   
     /* there may be a circle (one point line) */  
     if(seg->item)  
       canvas_item_destroy(seg->item);  
2140    
2141      seg->item = canvas_polyline_new(map, CANVAS_GROUP_TRACK,      *itemP = g_new0(track_item_chain_t, 1);
2142            points, map->style->track.width, map->style->track.color);      (*itemP)->item = canvas_polyline_new(map->canvas, CANVAS_GROUP_TRACK,
2143                     points, map->style->track.width, map->style->track.color);
2144        itemP = &(*itemP)->next;
2145    
2146      canvas_points_free(points);      canvas_points_free(points);
2147    }    }
2148  }  }
2149    
2150    /* update the last visible fragment of this segment since a */
2151    /* gps position may have been added */
2152  void map_track_update_seg(map_t *map, track_seg_t *seg) {  void map_track_update_seg(map_t *map, track_seg_t *seg) {
2153      bounds_t *bounds = map->appdata->osm->bounds;
2154    
2155      printf("-- APPENDING TO TRACK --\n");
2156    
2157    /* a track_seg needs at least 2 points to be drawn */    /* a track_seg needs at least 2 points to be drawn */
2158    guint pnum = track_seg_points(seg);    guint pnum = track_seg_points(seg);
2159    printf("seg of length %d\n", pnum);    printf("seg of length %d\n", pnum);
2160    
2161    if(pnum > 1) {    /* there are two cases: either the second last point was on screen */
2162      /* or it wasn't. We'll have to start a new screen item if the latter */
2163      /* is the case */
2164    
2165      /* search last point */
2166      track_point_t *begin = seg->track_point, *second_last = seg->track_point;
2167      lpos_t lpos;
2168      while(second_last && second_last->next && second_last->next->next) {
2169        if(!track_pos2lpos(bounds, &second_last->pos, &lpos))
2170          begin = second_last;
2171    
2172        second_last = second_last->next;
2173      }
2174      track_point_t *last = second_last->next;
2175    
2176      /* since we are updating an existing track, it sure has at least two */
2177      /* points, second_last must be valid and its "next" (last) also */
2178      g_assert(second_last);
2179      g_assert(last);
2180    
2181      /* check if the last and second_last points are visible */
2182      gboolean last_is_visible =
2183        track_pos2lpos(bounds, &last->pos, &lpos);
2184      gboolean second_last_is_visible =
2185        track_pos2lpos(bounds, &second_last->pos, &lpos);
2186    
2187      /* if both are invisible, then nothing has changed on screen */
2188      if(!last_is_visible && !second_last_is_visible) {
2189        printf("second_last and last entry are invisible -> doing nothing\n");
2190        return;
2191      }
2192    
2193      /* search last element in item chain */
2194      track_item_chain_t *item = seg->item_chain;
2195      while(item && item->next)
2196        item = item->next;
2197    
2198      if(second_last_is_visible) {
2199        /* there must be something already on the screen and there must */
2200        /* be visible nodes in the chain */
2201        g_assert(item);
2202        g_assert(begin);
2203    
2204        printf("second_last is visible -> append\n");
2205    
2206      /* allocate space for nodes */      /* count points to be placed */
2207      canvas_points_t *points = canvas_points_new(pnum);      int npoints = 0;
2208        track_point_t *tmp = begin;
2209        while(tmp) {
2210          tmp = tmp->next;
2211          npoints++;
2212        }
2213    
2214        printf("updating last segment to %d points\n", npoints);
2215    
2216        canvas_points_t *points = canvas_points_new(npoints);
2217    
2218        gint point = 0;
2219        while(begin) {
2220          track_pos2lpos(bounds, &begin->pos, &lpos);
2221          canvas_point_set_pos(points, point++, &lpos);
2222          begin = begin->next;
2223        }
2224    
2225      int point = 0;      canvas_item_set_points(item->item, points);
2226      track_point_t *track_point = seg->track_point;      canvas_points_free(points);
2227      while(track_point) {  
2228        canvas_point_set_pos(points, point++, &track_point->lpos);    } else {
2229        track_point = track_point->next;      printf("second last is invisible -> start new screen segment\n");
2230    
2231        /* the search for the "begin" ends with the second_last item */
2232        /* verify the last one also */
2233        if(begin->next && !track_pos2lpos(bounds, &begin->next->pos, &lpos))
2234          begin = begin->next;
2235    
2236        item->next = g_new0(track_item_chain_t, 1);
2237        item = item->next;
2238    
2239        /* count points to be placed */
2240        int npoints = 0;
2241        track_point_t *tmp = begin;
2242        while(tmp) {
2243          tmp = tmp->next;
2244          npoints++;
2245        }
2246    
2247        printf("attaching new segment with %d points\n", npoints);
2248    
2249        canvas_points_t *points = canvas_points_new(npoints);
2250    
2251        gint point = 0;
2252        while(begin) {
2253          track_pos2lpos(bounds, &begin->pos, &lpos);
2254          canvas_point_set_pos(points, point++, &lpos);
2255          begin = begin->next;
2256      }      }
2257    
2258      g_assert(seg->item);      item->item = canvas_polyline_new(map->canvas, CANVAS_GROUP_TRACK,
2259      canvas_item_set_points(seg->item, points);                   points, map->style->track.width, map->style->track.color);
2260    
2261      canvas_points_free(points);      canvas_points_free(points);
2262    }    }
2263    
2264  }  }
2265    
2266  void map_track_draw(map_t *map, track_t *track) {  void map_track_draw(map_t *map, track_t *track) {
# Line 2168  void map_track_remove(appdata_t *appdata Line 2283  void map_track_remove(appdata_t *appdata
2283    /* remove all segments */    /* remove all segments */
2284    track_seg_t *seg = track->track_seg;    track_seg_t *seg = track->track_seg;
2285    while(seg) {    while(seg) {
2286      if(seg->item) {      track_item_chain_t *item = seg->item_chain;
2287        canvas_item_destroy(seg->item);      while(item) {
2288        seg->item = NULL;        track_item_chain_t *next = item->next;
2289          canvas_item_destroy(item->item);
2290          item = next;
2291      }      }
2292    
2293        seg->item_chain = NULL;
2294      seg = seg->next;      seg = seg->next;
2295    }    }
2296  }  }
2297    
2298  void map_track_pos(appdata_t *appdata, lpos_t *lpos) {  void map_track_pos(appdata_t *appdata, pos_t *pos) {
2299    if(appdata->track.gps_item) {    if(appdata->track.gps_item) {
2300      canvas_item_destroy(appdata->track.gps_item);      canvas_item_destroy(appdata->track.gps_item);
2301      appdata->track.gps_item = NULL;      appdata->track.gps_item = NULL;
2302    }    }
2303    
2304    if(lpos)    if(pos) {
2305      appdata->track.gps_item = canvas_circle_new(appdata->map, CANVAS_GROUP_GPS,      lpos_t lpos;
2306          lpos->x, lpos->y, appdata->map->style->track.width/2.0, 0,      pos2lpos(appdata->osm->bounds, pos, &lpos);
2307                          RGB2CANVAS(appdata->map->style->track.gps_color), NO_COLOR);  
2308        appdata->track.gps_item =
2309          canvas_circle_new(appdata->map->canvas, CANVAS_GROUP_GPS,
2310            lpos.x, lpos.y, appdata->map->style->track.width/2.0, 0,
2311                            appdata->map->style->track.gps_color, NO_COLOR);
2312      }
2313  }  }
2314    
2315  /* ------------------- map background ------------------ */  /* ------------------- map background ------------------ */
# Line 2227  void map_set_bg_image(map_t *map, char * Line 2350  void map_set_bg_image(map_t *map, char *
2350    map->bg.scale.y = (float)(bounds->max.y - bounds->min.y)/    map->bg.scale.y = (float)(bounds->max.y - bounds->min.y)/
2351      (float)gdk_pixbuf_get_height(map->bg.pix);      (float)gdk_pixbuf_get_height(map->bg.pix);
2352    
2353    map->bg.item = canvas_image_new(map, CANVAS_GROUP_BG, map->bg.pix,    map->bg.item = canvas_image_new(map->canvas, CANVAS_GROUP_BG, map->bg.pix,
2354            bounds->min.x, bounds->min.y, map->bg.scale.x, map->bg.scale.y);            bounds->min.x, bounds->min.y, map->bg.scale.x, map->bg.scale.y);
2355    
2356    canvas_item_destroy_connect(map->bg.item,    canvas_item_destroy_connect(map->bg.item,
# Line 2241  void map_hide_selected(appdata_t *appdat Line 2364  void map_hide_selected(appdata_t *appdat
2364    map_t *map = appdata->map;    map_t *map = appdata->map;
2365    if(!map) return;    if(!map) return;
2366    
2367    if(map->selected.type != MAP_TYPE_WAY) {    if(map->selected.object.type != WAY) {
2368      printf("selected item is not a way\n");      printf("selected item is not a way\n");
2369      return;      return;
2370    }    }
2371    
2372    way_t *way = map->selected.way;    way_t *way = map->selected.object.way;
2373    printf("hiding way #%ld\n", way->id);    printf("hiding way #" ITEM_ID_FORMAT "\n", way->id);
2374    
2375    map_item_deselect(appdata);    map_item_deselect(appdata);
2376    way->flags |= OSM_FLAG_HIDDEN;    way->flags |= OSM_FLAG_HIDDEN;
# Line 2272  void map_show_all(appdata_t *appdata) { Line 2395  void map_show_all(appdata_t *appdata) {
2395    
2396    gtk_widget_set_sensitive(appdata->menu_item_map_show_all, FALSE);    gtk_widget_set_sensitive(appdata->menu_item_map_show_all, FALSE);
2397  }  }
2398    
2399    static void map_detail_change(map_t *map, float detail) {
2400      appdata_t *appdata = map->appdata;
2401    
2402      /* deselecting anything allows us not to care about automatic deselection */
2403      /* as well as items becoming invisible by the detail change */
2404      map_item_deselect(appdata);
2405    
2406      map->state->detail = detail;
2407      printf("changing detail factor to %f\n", map->state->detail);
2408    
2409      banner_busy_start(appdata, 1, _("Redrawing"));
2410      map_clear(appdata, MAP_LAYER_OBJECTS_ONLY);
2411      map_paint(appdata);
2412      banner_busy_stop(appdata);
2413    }
2414    
2415    #define DETAIL_STEP 1.5
2416    
2417    void map_detail_increase(map_t *map) {
2418      if(!map) return;
2419      map_detail_change(map, map->state->detail * DETAIL_STEP);
2420    }
2421    
2422    void map_detail_decrease(map_t *map) {
2423      if(!map) return;
2424      map_detail_change(map, map->state->detail / DETAIL_STEP);
2425    }
2426    
2427    void map_detail_normal(map_t *map) {
2428      if(!map) return;
2429      map_detail_change(map, 1.0);
2430    }
2431    
2432  // vim:et:ts=8:sw=2:sts=2:ai  // vim:et:ts=8:sw=2:sts=2:ai

Legend:
Removed from v.15  
changed lines
  Added in v.191