Diff of /trunk/src/map.c

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

revision 13 by achadwick, Mon Dec 15 14:17:29 2008 UTC revision 234 by harbaum, Mon Jul 20 20:15:10 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 49  static void map_statusbar(map_t *map, ma Line 55  static void map_statusbar(map_t *map, ma
55    
56    gboolean collision = FALSE;    gboolean collision = FALSE;
57    tag_t *tags = tag;    tag_t *tags = tag;
58      while(tag) {
59    if(id == ID_ILLEGAL)      if(!collision && info_tag_key_collision(tags, tag))
60      str = g_strdup_printf(_("Unknown item"));        collision = TRUE;
61    else {      tag = tag->next;
     str = g_strdup_printf("%s #%ld", item_str, id);  
   
     /* add some tags ... */  
     while(tag) {  
       if(!collision && info_tag_key_collision(tags, tag))  
         collision = TRUE;  
   
       /* we don't have much space, so ignore created_by tag */  
       if(!osm_is_creator_tag(tag)) {  
         char *old = str;  
         str = g_strdup_printf("%s, %s=%s", old, tag->key, tag->value);  
         g_free(old);  
       }  
       tag = tag->next;  
     }  
62    }    }
63    
64      str = osm_object_get_speaking_name(&map_item->object);
65    statusbar_set(map->appdata, str, collision);    statusbar_set(map->appdata, str, collision);
66    g_free(str);    g_free(str);
67  }  }
# Line 123  static void map_node_select(appdata_t *a Line 115  static void map_node_select(appdata_t *a
115    
116    g_assert(!map->highlight);    g_assert(!map->highlight);
117    
118    map_item->type      = MAP_TYPE_NODE;    map_item->object.type      = NODE;
119    map_item->node      = node;    map_item->object.node      = node;
120    map_item->highlight = FALSE;    map_item->highlight = FALSE;
121    
122    /* 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 129  static void map_node_select(appdata_t *a
129    icon_bar_map_item_selected(appdata, map_item, TRUE);    icon_bar_map_item_selected(appdata, map_item, TRUE);
130    
131    /* highlight node */    /* highlight node */
132    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;
133    
134    /* 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 */
135    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 146  static void map_node_select(appdata_t *a Line 138  static void map_node_select(appdata_t *a
138    
139    float radius = map->style->highlight.width + map->style->node.radius;    float radius = map->style->highlight.width + map->style->node.radius;
140    if(!node->ways) radius += map->style->node.border_radius;    if(!node->ways) radius += map->style->node.border_radius;
141    if(node->icon_buf && map->style->icon.enable) {    if(node->icon_buf && map->style->icon.enable &&
142      gint w = gdk_pixbuf_get_width(map_item->node->icon_buf);       !appdata->settings->no_icons) {
143      gint h = gdk_pixbuf_get_height(map_item->node->icon_buf);      gint w = gdk_pixbuf_get_width(map_item->object.node->icon_buf);
144        gint h = gdk_pixbuf_get_height(map_item->object.node->icon_buf);
145      /* icons are technically square, so a radius slightly bigger */      /* icons are technically square, so a radius slightly bigger */
146      /* than sqrt(2)*MAX(w,h) should fit nicely */      /* than sqrt(2)*MAX(w,h) should fit nicely */
147      radius =  0.75 * map->style->icon.scale * ((w>h)?w:h);      radius = 0.75 * map->style->icon.scale * ((w>h)?w:h);
148    }    }
149    
150      radius *= map->state->detail;
151    map_hl_circle_new(map, CANVAS_GROUP_NODES_HL, new_map_item,    map_hl_circle_new(map, CANVAS_GROUP_NODES_HL, new_map_item,
152                      x, y, radius, map->style->highlight.color);                      x, y, radius, map->style->highlight.color);
153    
154    if(!map_item->item) {    if(!map_item->item) {
155      /* and draw a fake node */      /* and draw a fake node */
156      new_map_item = g_new0(map_item_t, 1);      new_map_item = g_new0(map_item_t, 1);
157      memcpy(new_map_item, map_item, sizeof(map_item_t));      memcpy(new_map_item, map_item, sizeof(map_item_t));
158      new_map_item->highlight = TRUE;      new_map_item->highlight = TRUE;
159      map_hl_circle_new(map, CANVAS_GROUP_NODES_HL, new_map_item,      map_hl_circle_new(map, CANVAS_GROUP_NODES_IHL, new_map_item,
160                        x, y, map->style->node.radius,                        x, y, map->style->node.radius,
161                        map->style->highlight.node_color);                        map->style->highlight.node_color);
162    }    }
# Line 174  void map_way_select(appdata_t *appdata, Line 168  void map_way_select(appdata_t *appdata,
168    
169    g_assert(!map->highlight);    g_assert(!map->highlight);
170    
171    map_item->type      = MAP_TYPE_WAY;    map_item->object.type      = WAY;
172    map_item->way       = way;    map_item->object.way       = way;
173    map_item->highlight = FALSE;    map_item->highlight = FALSE;
174    map_item->item      = way->map_item_chain->map_item->item;    map_item->item      = way->map_item_chain->map_item->item;
175    
176    map_statusbar(map, map_item);    map_statusbar(map, map_item);
177    icon_bar_map_item_selected(appdata, map_item, TRUE);    icon_bar_map_item_selected(appdata, map_item, TRUE);
178    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;  
179    
180    node_chain_t *node_chain = map_item->way->node_chain;    gint arrow_width = ((map_item->object.way->draw.flags & OSM_DRAW_FLAG_BG)?
181                          map->style->highlight.width + map_item->object.way->draw.bg.width/2:
182                          map->style->highlight.width + map_item->object.way->draw.width/2)
183        * map->state->detail;
184    
185      node_chain_t *node_chain = map_item->object.way->node_chain;
186    node_t *last = NULL;    node_t *last = NULL;
187    while(node_chain) {    while(node_chain) {
188      map_item_t item;      map_item_t item;
189      item.type = MAP_TYPE_NODE;      item.object.type = NODE;
190      item.node = node_chain->node;      item.object.node = node_chain->node;
191    
192      /* draw an arrow between every two nodes */      /* draw an arrow between every two nodes */
193      if(last) {      if(last) {
194        /* create a new map item for every arrow */        /* create a new map item for every arrow */
195        map_item_t *new_map_item = g_new0(map_item_t, 1);        map_item_t *new_map_item = g_new0(map_item_t, 1);
196        new_map_item->type = MAP_TYPE_WAY;        new_map_item->object.type = WAY;
197        new_map_item->way = way;        new_map_item->object.way = way;
198        new_map_item->highlight = TRUE;        new_map_item->highlight = TRUE;
199    
200        struct { float x, y;} center, diff;        struct { float x, y;} center, diff;
# Line 208  void map_way_select(appdata_t *appdata, Line 203  void map_way_select(appdata_t *appdata,
203        diff.x = node_chain->node->lpos.x - last->lpos.x;        diff.x = node_chain->node->lpos.x - last->lpos.x;
204        diff.y = node_chain->node->lpos.y - last->lpos.y;        diff.y = node_chain->node->lpos.y - last->lpos.y;
205    
206          /* only draw arrow if there's sufficient space */
207          /* TODO: what if there's not enough space anywhere? */
208        float len = sqrt(pow(diff.x, 2)+pow(diff.y, 2));        float len = sqrt(pow(diff.x, 2)+pow(diff.y, 2));
209        if(len > map->style->highlight.arrow_limit*arrow_width) {        if(len > map->style->highlight.arrow_limit*arrow_width) {
210          len /= arrow_width;          len /= arrow_width;
# Line 222  void map_way_select(appdata_t *appdata, Line 219  void map_way_select(appdata_t *appdata,
219          points->coords[2*2+0] = center.x - diff.y - diff.x;          points->coords[2*2+0] = center.x - diff.y - diff.x;
220          points->coords[2*2+1] = center.y + diff.x - diff.y;          points->coords[2*2+1] = center.y + diff.x - diff.y;
221    
222          map_hl_polygon_new(map, CANVAS_GROUP_NODES_HL, new_map_item,          map_hl_polygon_new(map, CANVAS_GROUP_WAYS_DIR, new_map_item,
223                             points, map->style->highlight.arrow_color);                             points, map->style->highlight.arrow_color);
224    
225          canvas_points_free(points);          canvas_points_free(points);
# Line 233  void map_way_select(appdata_t *appdata, Line 230  void map_way_select(appdata_t *appdata,
230    
231        /* create a new map item for every node */        /* create a new map item for every node */
232        map_item_t *new_map_item = g_new0(map_item_t, 1);        map_item_t *new_map_item = g_new0(map_item_t, 1);
233        new_map_item->type = MAP_TYPE_NODE;        new_map_item->object.type = NODE;
234        new_map_item->node = node_chain->node;        new_map_item->object.node = node_chain->node;
235        new_map_item->highlight = TRUE;        new_map_item->highlight = TRUE;
236    
237        gint x = node_chain->node->lpos.x;        gint x = node_chain->node->lpos.x;
238        gint y = node_chain->node->lpos.y;        gint y = node_chain->node->lpos.y;
239    
240        map_hl_circle_new(map, CANVAS_GROUP_NODES_HL, new_map_item,        map_hl_circle_new(map, CANVAS_GROUP_NODES_IHL, new_map_item,
241                          x, y, map->style->node.radius,                          x, y, map->style->node.radius * map->state->detail,
242                          map->style->highlight.node_color);                          map->style->highlight.node_color);
243      }      }
244    
# Line 257  void map_way_select(appdata_t *appdata, Line 254  void map_way_select(appdata_t *appdata,
254      canvas_points_t *points = canvas_points_new(nodes);      canvas_points_t *points = canvas_points_new(nodes);
255    
256      int node = 0;      int node = 0;
257      node_chain = map_item->way->node_chain;      node_chain = map_item->object.way->node_chain;
258      while(node_chain) {      while(node_chain) {
259        canvas_point_set_pos(points, node++, &node_chain->node->lpos);        canvas_point_set_pos(points, node++, &node_chain->node->lpos);
260        node_chain = node_chain->next;        node_chain = node_chain->next;
# Line 269  void map_way_select(appdata_t *appdata, Line 266  void map_way_select(appdata_t *appdata,
266      new_map_item->highlight = TRUE;      new_map_item->highlight = TRUE;
267    
268      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,
269                  (map_item->way->draw.flags & OSM_DRAW_FLAG_BG)?                   ((map_item->object.way->draw.flags & OSM_DRAW_FLAG_BG)?
270                  2*map->style->highlight.width + map_item->way->draw.bg.width:                   2*map->style->highlight.width + map_item->object.way->draw.bg.width:
271                  2*map->style->highlight.width + map_item->way->draw.width,                   2*map->style->highlight.width + map_item->object.way->draw.width)
272                  map->style->highlight.color);                  * map->state->detail, map->style->highlight.color);
273    
274      canvas_points_free(points);      canvas_points_free(points);
275    }    }
276  }  }
277    
278  static void map_item_select(appdata_t *appdata, map_item_t *map_item) {  void map_relation_select(appdata_t *appdata, relation_t *relation) {
279    switch(map_item->type) {    map_t *map = appdata->map;
280    case MAP_TYPE_NODE:  
281      map_node_select(appdata, map_item->node);    printf("highlighting relation "ITEM_ID_FORMAT"\n", relation->id);
282    
283      g_assert(!map->highlight);
284      map_highlight_t **hl = &map->highlight;
285    
286      map_item_t *map_item = &map->selected;
287      map_item->object.type      = RELATION;
288      map_item->object.relation  = relation;
289      map_item->highlight = FALSE;
290      map_item->item      = NULL;
291    
292      map_statusbar(map, map_item);
293      icon_bar_map_item_selected(appdata, map_item, TRUE);
294    
295      /* process all members */
296      member_t *member = relation->member;
297      while(member) {
298        canvas_item_t *item = NULL;
299    
300        switch(member->object.type) {
301    
302        case NODE: {
303          node_t *node = member->object.node;
304          printf("  -> node "ITEM_ID_FORMAT"\n", node->id);
305    
306          item = canvas_circle_new(map->canvas, CANVAS_GROUP_NODES_HL,
307                            node->lpos.x, node->lpos.y,
308                            map->style->highlight.width + map->style->node.radius,
309                            0, map->style->highlight.color, NO_COLOR);
310          } break;
311    
312        case WAY: {
313          way_t *way = member->object.way;
314          /* a way needs at least 2 points to be drawn */
315          guint nodes = osm_way_number_of_nodes(way);
316          if(nodes > 1) {
317    
318            /* allocate space for nodes */
319            canvas_points_t *points = canvas_points_new(nodes);
320    
321            int node = 0;
322            node_chain_t *node_chain = way->node_chain;
323            while(node_chain) {
324              canvas_point_set_pos(points, node++, &node_chain->node->lpos);
325              node_chain = node_chain->next;
326            }
327    
328            if(way->draw.flags & OSM_DRAW_FLAG_AREA)
329              item = canvas_polygon_new(map->canvas, CANVAS_GROUP_WAYS_HL, points, 0, 0,
330                                        map->style->highlight.color);
331            else
332              item = canvas_polyline_new(map->canvas, CANVAS_GROUP_WAYS_HL, points,
333                                  (way->draw.flags & OSM_DRAW_FLAG_BG)?
334                                  2*map->style->highlight.width + way->draw.bg.width:
335                                  2*map->style->highlight.width + way->draw.width,
336                                  map->style->highlight.color);
337    
338            canvas_points_free(points);
339          } } break;
340    
341        default:
342          break;
343        }
344    
345        /* attach item to item chain */
346        if(item) {
347          *hl = g_new0(map_highlight_t, 1);
348          (*hl)->item = item;
349          hl = &(*hl)->next;
350        }
351    
352        member = member->next;
353      }
354    }
355    
356    static void map_object_select(appdata_t *appdata, object_t *object) {
357      switch(object->type) {
358      case NODE:
359        map_node_select(appdata, object->node);
360        break;
361      case WAY:
362        map_way_select(appdata, object->way);
363      break;      break;
364    case MAP_TYPE_WAY:    case RELATION:
365      map_way_select(appdata, map_item->way);      map_relation_select(appdata, object->relation);
366      break;      break;
367    default:    default:
368      g_assert((map_item->type == MAP_TYPE_NODE)||      g_assert((object->type == NODE)||(object->type == RELATION)||
369               (map_item->type == MAP_TYPE_WAY));               (object->type == WAY));
370      break;      break;
371    }    }
372  }  }
# Line 296  static void map_item_select(appdata_t *a Line 374  static void map_item_select(appdata_t *a
374  void map_item_deselect(appdata_t *appdata) {  void map_item_deselect(appdata_t *appdata) {
375    
376    /* save tags for "last" function in info dialog */    /* save tags for "last" function in info dialog */
377    if(appdata->map->selected.type == MAP_TYPE_NODE) {    if(appdata->map->selected.object.type == NODE) {
378      if(appdata->map->last_node_tags)      if(appdata->map->last_node_tags)
379        osm_tags_free(appdata->map->last_node_tags);        osm_tags_free(appdata->map->last_node_tags);
380    
381      appdata->map->last_node_tags =      appdata->map->last_node_tags =
382        osm_tags_copy(appdata->map->selected.node->tag, FALSE);        osm_tags_copy(appdata->map->selected.object.node->tag);
383    } else if(appdata->map->selected.type == MAP_TYPE_WAY) {    } else if(appdata->map->selected.object.type == WAY) {
384      if(appdata->map->last_way_tags)      if(appdata->map->last_way_tags)
385        osm_tags_free(appdata->map->last_way_tags);        osm_tags_free(appdata->map->last_way_tags);
386    
387      appdata->map->last_way_tags =      appdata->map->last_way_tags =
388        osm_tags_copy(appdata->map->selected.way->tag, FALSE);        osm_tags_copy(appdata->map->selected.object.way->tag);
389    }    }
390    
391    /* remove statusbar message */    /* remove statusbar message */
# Line 321  void map_item_deselect(appdata_t *appdat Line 399  void map_item_deselect(appdata_t *appdat
399    map_hl_remove(appdata);    map_hl_remove(appdata);
400    
401    /* forget about selection */    /* forget about selection */
402    appdata->map->selected.type = MAP_TYPE_ILLEGAL;    appdata->map->selected.object.type = ILLEGAL;
403  }  }
404    
405  /* called whenever a map item is to be destroyed */  /* called whenever a map item is to be destroyed */
# Line 333  static gint map_item_destroy_event(GtkWi Line 411  static gint map_item_destroy_event(GtkWi
411  #ifdef DESTROY_WAIT_FOR_GTK  #ifdef DESTROY_WAIT_FOR_GTK
412    /* remove item from nodes/ways map_item_chain */    /* remove item from nodes/ways map_item_chain */
413    map_item_chain_t **chain = NULL;    map_item_chain_t **chain = NULL;
414    if(map_item->type == MAP_TYPE_NODE)    if(map_item->object.type == NODE)
415      chain = &map_item->node->map_item_chain;      chain = &map_item->object.node->map_item_chain;
416    else if(map_item->type == MAP_TYPE_WAY)    else if(map_item->object.type == WAY)
417      chain = &map_item->way->map_item_chain;      chain = &map_item->object.way->map_item_chain;
418    
419    /* there must be a chain with content, otherwise things are broken */    /* there must be a chain with content, otherwise things are broken */
420    g_assert(chain);    g_assert(chain);
# Line 363  static canvas_item_t *map_node_new(map_t Line 441  static canvas_item_t *map_node_new(map_t
441                     gint width, canvas_color_t fill, canvas_color_t border) {                     gint width, canvas_color_t fill, canvas_color_t border) {
442    
443    map_item_t *map_item = g_new0(map_item_t, 1);    map_item_t *map_item = g_new0(map_item_t, 1);
444    map_item->type = MAP_TYPE_NODE;    map_item->object.type = NODE;
445    map_item->node = node;    map_item->object.node = node;
446    
447    if(!node->icon_buf || !map->style->icon.enable)    if(!node->icon_buf || !map->style->icon.enable ||
448      map_item->item = canvas_circle_new(map, CANVAS_GROUP_NODES,       map->appdata->settings->no_icons)
449        map_item->item = canvas_circle_new(map->canvas, CANVAS_GROUP_NODES,
450         node->lpos.x, node->lpos.y, radius, width, fill, border);         node->lpos.x, node->lpos.y, radius, width, fill, border);
451    else    else
452      map_item->item = canvas_image_new(map, CANVAS_GROUP_NODES,      map_item->item = canvas_image_new(map->canvas, CANVAS_GROUP_NODES,
453        node->icon_buf,        node->icon_buf,
454        node->lpos.x - map->style->icon.scale/2 *        node->lpos.x - map->style->icon.scale/2 * map->state->detail *
455                        gdk_pixbuf_get_width(node->icon_buf),                        gdk_pixbuf_get_width(node->icon_buf),
456        node->lpos.y - map->style->icon.scale/2 *        node->lpos.y - map->style->icon.scale/2 * map->state->detail *
457                        gdk_pixbuf_get_height(node->icon_buf),                        gdk_pixbuf_get_height(node->icon_buf),
458                map->style->icon.scale,map->style->icon.scale);                        map->state->detail * map->style->icon.scale,
459                          map->state->detail * map->style->icon.scale);
460    
461    canvas_item_set_zoom_max(map_item->item, node->zoom_max);    canvas_item_set_zoom_max(map_item->item,
462                               node->zoom_max / (2 * map->state->detail));
463    
464    /* attach map_item to nodes map_item_chain */    /* attach map_item to nodes map_item_chain */
465    map_item_chain_t **chain = &node->map_item_chain;    map_item_chain_t **chain = &node->map_item_chain;
# Line 400  static canvas_item_t *map_way_single_new Line 481  static canvas_item_t *map_way_single_new
481                     gint width, canvas_color_t fill, canvas_color_t border) {                     gint width, canvas_color_t fill, canvas_color_t border) {
482    
483    map_item_t *map_item = g_new0(map_item_t, 1);    map_item_t *map_item = g_new0(map_item_t, 1);
484    map_item->type = MAP_TYPE_WAY;    map_item->object.type = WAY;
485    map_item->way = way;    map_item->object.way = way;
486    map_item->item = canvas_circle_new(map, CANVAS_GROUP_WAYS,    map_item->item = canvas_circle_new(map->canvas, CANVAS_GROUP_WAYS,
487            way->node_chain->node->lpos.x, way->node_chain->node->lpos.y,            way->node_chain->node->lpos.x, way->node_chain->node->lpos.y,
488                                       radius, width, fill, border);                                       radius, width, fill, border);
489    
# Line 426  static canvas_item_t *map_way_new(map_t Line 507  static canvas_item_t *map_way_new(map_t
507            way_t *way, canvas_points_t *points, gint width,            way_t *way, canvas_points_t *points, gint width,
508            canvas_color_t color, canvas_color_t fill_color) {            canvas_color_t color, canvas_color_t fill_color) {
509    map_item_t *map_item = g_new0(map_item_t, 1);    map_item_t *map_item = g_new0(map_item_t, 1);
510    map_item->type = MAP_TYPE_WAY;    map_item->object.type = WAY;
511    map_item->way = way;    map_item->object.way = way;
512    
513    if(way->draw.flags & OSM_DRAW_FLAG_AREA) {    if(way->draw.flags & OSM_DRAW_FLAG_AREA) {
514      if(map->style->area.opaque)      if(map->style->area.color & 0xff)
515        map_item->item = canvas_polygon_new(map, group, points,        map_item->item = canvas_polygon_new(map->canvas, group, points,
516                                            width, color, fill_color);                                            width, color, fill_color);
517      else      else
518        map_item->item = canvas_polyline_new(map, group, points,        map_item->item = canvas_polyline_new(map->canvas, group, points,
519                                             width, color);                                             width, color);
520    } else {    } else {
521      map_item->item = canvas_polyline_new(map, group, points, width, color);      map_item->item = canvas_polyline_new(map->canvas, group, points, width, color);
522    }    }
523    
524    canvas_item_set_zoom_max(map_item->item, way->draw.zoom_max);    canvas_item_set_zoom_max(map_item->item,
525                               way->draw.zoom_max / (2 * map->state->detail));
526    
527      /* a ways outline itself is never dashed */
528    if (group != CANVAS_GROUP_WAYS_OL)    if (group != CANVAS_GROUP_WAYS_OL)
529      if (way->draw.dashed)      if (way->draw.dashed)
530        canvas_item_set_dashed(map_item->item);        canvas_item_set_dashed(map_item->item, width, way->draw.dash_length);
531    
532    /* attach map_item to ways map_item_chain */    /* attach map_item to ways map_item_chain */
533    map_item_chain_t **chain = &way->map_item_chain;    map_item_chain_t **chain = &way->map_item_chain;
# Line 462  static canvas_item_t *map_way_new(map_t Line 545  static canvas_item_t *map_way_new(map_t
545    
546  void map_show_node(map_t *map, node_t *node) {  void map_show_node(map_t *map, node_t *node) {
547    map_node_new(map, node, map->style->node.radius, 0,    map_node_new(map, node, map->style->node.radius, 0,
548                 RGB2CANVAS(map->style->node.color), 0);                 map->style->node.color, 0);
549  }  }
550    
551  void map_way_draw(map_t *map, way_t *way) {  void map_way_draw(map_t *map, way_t *way) {
# Line 477  void map_way_draw(map_t *map, way_t *way Line 560  void map_way_draw(map_t *map, way_t *way
560    if(nodes == 1) {    if(nodes == 1) {
561      /* draw a single dot where this single node is */      /* draw a single dot where this single node is */
562      map_way_single_new(map, way, map->style->node.radius, 0,      map_way_single_new(map, way, map->style->node.radius, 0,
563                         RGB2CANVAS(map->style->node.color), 0);                         map->style->node.color, 0);
564    } else {    } else {
565      canvas_points_t *points = canvas_points_new(nodes);      canvas_points_t *points = canvas_points_new(nodes);
566    
# Line 489  void map_way_draw(map_t *map, way_t *way Line 572  void map_way_draw(map_t *map, way_t *way
572      }      }
573    
574      /* draw way */      /* draw way */
575        float width = way->draw.width * map->state->detail;
576    
577      if(way->draw.flags & OSM_DRAW_FLAG_AREA) {      if(way->draw.flags & OSM_DRAW_FLAG_AREA) {
578        map_way_new(map, CANVAS_GROUP_POLYGONS, way, points,        map_way_new(map, CANVAS_GROUP_POLYGONS, way, points,
579                    way->draw.width, way->draw.color, way->draw.area.color);                    width, way->draw.color, way->draw.area.color);
580      } else {      } else {
581        map_way_new(map, CANVAS_GROUP_WAYS, way, points,  
582                    way->draw.width, way->draw.color, NO_COLOR);        if(way->draw.flags & OSM_DRAW_FLAG_BG) {
583            map_way_new(map, CANVAS_GROUP_WAYS_INT, way, points,
584        if(way->draw.flags & OSM_DRAW_FLAG_BG)                      width, way->draw.color, NO_COLOR);
585    
586          map_way_new(map, CANVAS_GROUP_WAYS_OL, way, points,          map_way_new(map, CANVAS_GROUP_WAYS_OL, way, points,
587                      way->draw.bg.width, way->draw.bg.color, NO_COLOR);                      way->draw.bg.width * map->state->detail,
588                        way->draw.bg.color, NO_COLOR);
589    
590          } else
591            map_way_new(map, CANVAS_GROUP_WAYS, way, points,
592                        width, way->draw.color, NO_COLOR);
593      }      }
594      canvas_points_free(points);      canvas_points_free(points);
595    }    }
# Line 511  void map_node_draw(map_t *map, node_t *n Line 602  void map_node_draw(map_t *map, node_t *n
602    
603    if(!node->ways)    if(!node->ways)
604      map_node_new(map, node,      map_node_new(map, node,
605                   map->style->node.radius,                   map->style->node.radius * map->state->detail,
606                   map->style->node.border_radius,                   map->style->node.border_radius * map->state->detail,
607                   RGBA2CANVAS(map->style->node.fill_color,                   map->style->node.fill_color,
608                               map->style->node.has_fill_color?0xff:0x00),                   map->style->node.color);
                  RGB2CANVAS(map->style->node.color));  
609    
610    else if(map->style->node.show_untagged || osm_node_has_tag(node))    else if(map->style->node.show_untagged || osm_node_has_tag(node))
611      map_node_new(map, node,      map_node_new(map, node,
612                   map->style->node.radius, 0,                   map->style->node.radius * map->state->detail, 0,
613                   RGB2CANVAS(map->style->node.color), 0);                   map->style->node.color, 0);
614  }  }
615    
616  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) {
617    switch(map_item->type) {    switch(map_item->object.type) {
618    case MAP_TYPE_NODE:    case NODE:
619      map_node_draw(map, map_item->node);      map_node_draw(map, map_item->object.node);
620      break;      break;
621    case MAP_TYPE_WAY:    case WAY:
622      map_way_draw(map, map_item->way);      map_way_draw(map, map_item->object.way);
623      break;      break;
624    default:    default:
625      g_assert((map_item->type == MAP_TYPE_NODE) ||      g_assert((map_item->object.type == NODE) ||
626               (map_item->type == MAP_TYPE_WAY));               (map_item->object.type == WAY));
627    }    }
628  }  }
629    
630  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) {
631    map_item_chain_t **chainP = NULL;    map_item_chain_t **chainP = NULL;
632    
633    switch(map_item->type) {    switch(map_item->object.type) {
634    case MAP_TYPE_NODE:    case NODE:
635      chainP = &map_item->node->map_item_chain;      chainP = &map_item->object.node->map_item_chain;
636      break;      break;
637    case MAP_TYPE_WAY:    case WAY:
638      chainP = &map_item->way->map_item_chain;      chainP = &map_item->object.way->map_item_chain;
639      break;      break;
640    default:    default:
641      g_assert((map_item->type == MAP_TYPE_NODE) ||      g_assert((map_item->object.type == NODE) ||
642               (map_item->type == MAP_TYPE_WAY));               (map_item->object.type == WAY));
643    }    }
644    
645    map_item_chain_destroy(chainP);    map_item_chain_destroy(chainP);
646  }  }
647    
648  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) {
649    switch (map_item->type){    switch (map_item->object.type){
650      case MAP_TYPE_WAY:      case WAY:
651        josm_elemstyles_colorize_way(style, map_item->way);        josm_elemstyles_colorize_way(style, map_item->object.way);
652        break;        break;
653      case MAP_TYPE_NODE:      case NODE:
654        josm_elemstyles_colorize_node(style, map_item->node);        josm_elemstyles_colorize_node(style, map_item->object.node);
655        break;        break;
656      default:      default:
657        g_assert((map_item->type == MAP_TYPE_NODE) ||        g_assert((map_item->object.type == NODE) ||
658                     (map_item->type == MAP_TYPE_WAY));                     (map_item->object.type == WAY));
659    }    }
660  }  }
661    
662  void map_item_redraw(appdata_t *appdata, map_item_t *map_item) {  void map_item_redraw(appdata_t *appdata, map_item_t *map_item) {
663    map_item_t item = *map_item;    map_item_t item = *map_item;
664    
665      /* a relation cannot be redraws as it doesn't have a visual */
666      /* representation */
667      if(map_item->object.type == RELATION)
668        return;
669    
670    /* check if the item to be redrawn is the selected one */    /* check if the item to be redrawn is the selected one */
671    gboolean is_selected = FALSE;    gboolean is_selected = FALSE;
672    if(map_item->ptr == appdata->map->selected.ptr) {    if(map_item->object.ptr == appdata->map->selected.object.ptr) {
673      map_item_deselect(appdata);      map_item_deselect(appdata);
674      is_selected = TRUE;      is_selected = TRUE;
675    }    }
# Line 585  void map_item_redraw(appdata_t *appdata, Line 680  void map_item_redraw(appdata_t *appdata,
680    
681    /* restore selection if there was one */    /* restore selection if there was one */
682    if(is_selected)    if(is_selected)
683      map_item_select(appdata, &item);      map_object_select(appdata, &item.object);
684  }  }
685    
686  static void map_frisket_rectangle(canvas_points_t *points,  static void map_frisket_rectangle(canvas_points_t *points,
# Line 602  void map_frisket_draw(map_t *map, bounds Line 697  void map_frisket_draw(map_t *map, bounds
697    canvas_points_t *points = canvas_points_new(5);    canvas_points_t *points = canvas_points_new(5);
698    
699    /* don't draw frisket at all if it's completely transparent */    /* don't draw frisket at all if it's completely transparent */
700    if(map->style->frisket.opaque) {    if(map->style->frisket.color & 0xff) {
701      elemstyle_color_t color =      elemstyle_color_t color = map->style->frisket.color;
       (map->style->background.color<<8) | map->style->frisket.opaque;  
702    
703      float mult = map->style->frisket.mult;      float mult = map->style->frisket.mult;
704    
705      /* top rectangle */      /* top rectangle */
706      map_frisket_rectangle(points, mult*bounds->min.x, mult*bounds->max.x,      map_frisket_rectangle(points, mult*bounds->min.x, mult*bounds->max.x,
707                            mult*bounds->min.y, bounds->min.y);                            mult*bounds->min.y, bounds->min.y);
708      canvas_polygon_new(map, CANVAS_GROUP_NODES, points, 1, NO_COLOR, color);      canvas_polygon_new(map->canvas, CANVAS_GROUP_FRISKET, points,
709                           1, NO_COLOR, color);
710    
711      /* bottom rectangle */      /* bottom rectangle */
712      map_frisket_rectangle(points, mult*bounds->min.x, mult*bounds->max.x,      map_frisket_rectangle(points, mult*bounds->min.x, mult*bounds->max.x,
713                            bounds->max.y, mult*bounds->max.y);                            bounds->max.y, mult*bounds->max.y);
714      canvas_polygon_new(map, CANVAS_GROUP_NODES, points, 1, NO_COLOR, color);      canvas_polygon_new(map->canvas, CANVAS_GROUP_FRISKET, points,
715                           1, NO_COLOR, color);
716    
717      /* left rectangle */      /* left rectangle */
718      map_frisket_rectangle(points, mult*bounds->min.x, bounds->min.x,      map_frisket_rectangle(points, mult*bounds->min.x, bounds->min.x,
719                            mult*bounds->min.y, mult*bounds->max.y);                            mult*bounds->min.y, mult*bounds->max.y);
720      canvas_polygon_new(map, CANVAS_GROUP_NODES, points, 1, NO_COLOR, color);      canvas_polygon_new(map->canvas, CANVAS_GROUP_FRISKET, points,
721                           1, NO_COLOR, color);
722    
723      /* right rectangle */      /* right rectangle */
724      map_frisket_rectangle(points, bounds->max.x, mult*bounds->max.x,      map_frisket_rectangle(points, bounds->max.x, mult*bounds->max.x,
725                            mult*bounds->min.y, mult*bounds->max.y);                            mult*bounds->min.y, mult*bounds->max.y);
726      canvas_polygon_new(map, CANVAS_GROUP_NODES, points, 1, NO_COLOR, color);      canvas_polygon_new(map->canvas, CANVAS_GROUP_FRISKET, points,
727                           1, NO_COLOR, color);
728    
729    }    }
730    
# Line 637  void map_frisket_draw(map_t *map, bounds Line 735  void map_frisket_draw(map_t *map, bounds
735                            bounds->min.x-ew2, bounds->max.x+ew2,                            bounds->min.x-ew2, bounds->max.x+ew2,
736                            bounds->min.y-ew2, bounds->max.y+ew2);                            bounds->min.y-ew2, bounds->max.y+ew2);
737    
738      canvas_polyline_new(map, CANVAS_GROUP_NODES, points,      canvas_polyline_new(map->canvas, CANVAS_GROUP_FRISKET, points,
739                          map->style->frisket.border.width,                          map->style->frisket.border.width,
740                          map->style->frisket.border.color);                          map->style->frisket.border.color);
741    
# Line 769  map_item_t *map_item_at(map_t *map, gint Line 867  map_item_t *map_item_at(map_t *map, gint
867      return NULL;      return NULL;
868    }    }
869    
870    if(map_item->highlight)    if(map_item->highlight)
871      printf("  item is highlight\n");      printf("  item is highlight\n");
872    
873    switch(map_item->type) {    switch(map_item->object.type) {
874    case MAP_TYPE_NODE:    case NODE:
875      printf("  item is node #%ld\n", map_item->node->id);      printf("  item is node #"ITEM_ID_FORMAT"\n", map_item->object.node->id);
876      break;      break;
877    case MAP_TYPE_WAY:    case WAY:
878      printf("  item is way #%ld\n", map_item->way->id);      printf("  item is way #"ITEM_ID_FORMAT"\n", map_item->object.way->id);
879      break;      break;
880    default:    default:
881      printf("  unknown item\n");      printf("  unknown item\n");
# Line 788  map_item_t *map_item_at(map_t *map, gint Line 886  map_item_t *map_item_at(map_t *map, gint
886  }  }
887    
888  /* get the real item (no highlight) at x, y */  /* get the real item (no highlight) at x, y */
889  static map_item_t *map_real_item_at(map_t *map, gint x, gint y) {  map_item_t *map_real_item_at(map_t *map, gint x, gint y) {
890    map_item_t *map_item = map_item_at(map, x, y);    map_item_t *map_item = map_item_at(map, x, y);
891    
892    /* no item or already a real one */    /* no item or already a real one */
# Line 796  static map_item_t *map_real_item_at(map_ Line 894  static map_item_t *map_real_item_at(map_
894    
895    /* get the item (parent) this item is the highlight of */    /* get the item (parent) this item is the highlight of */
896    map_item_t *parent = NULL;    map_item_t *parent = NULL;
897    switch(map_item->type) {    switch(map_item->object.type) {
898    
899    case MAP_TYPE_NODE:    case NODE:
900      if(map_item->node->map_item_chain)      if(map_item->object.node->map_item_chain)
901        parent = map_item->node->map_item_chain->map_item;        parent = map_item->object.node->map_item_chain->map_item;
902    
903      if(parent)      if(parent)
904        printf("  using parent item node #%ld\n", parent->node->id);        printf("  using parent item node #" ITEM_ID_FORMAT "\n",
905                 parent->object.node->id);
906      break;      break;
907    
908    case MAP_TYPE_WAY:    case WAY:
909      if(map_item->way->map_item_chain)      if(map_item->object.way->map_item_chain)
910        parent = map_item->way->map_item_chain->map_item;        parent = map_item->object.way->map_item_chain->map_item;
911    
912      if(parent)      if(parent)
913        printf("  using parent item way #%ld\n", parent->way->id);        printf("  using parent item way #" ITEM_ID_FORMAT "\n",
914                 parent->object.way->id);
915      break;      break;
916    
917    default:    default:
918      g_assert((map_item->type == MAP_TYPE_NODE) ||      g_assert((map_item->object.type == NODE) ||
919               (map_item->type == MAP_TYPE_WAY));               (map_item->object.type == WAY));
920      break;      break;
921    }    }
922    
# Line 828  static map_item_t *map_real_item_at(map_ Line 928  static map_item_t *map_real_item_at(map_
928    return map_item;    return map_item;
929  }  }
930    
   
   
 #ifdef USE_GOOCANVAS  
   
931  /* 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
932   * map visible at all times */   * map visible at all times */
933  static void map_limit_scroll(map_t *map, gint *sx, gint *sy) {  static void map_limit_scroll(map_t *map, canvas_unit_t unit,
934      gdouble zoom = goo_canvas_get_scale(GOO_CANVAS(map->canvas));                               gint *sx, gint *sy) {
935    
936      gint sx_cu = *sx / zoom;    /* get scale factor for pixel->meter conversion. set to 1 if */
937      gint sy_cu = *sy / zoom;    /* given coordinates are already in meters */
938      gdouble scale = (unit == CANVAS_UNIT_METER)?1.0:canvas_get_zoom(map->canvas);
939      // Canvas viewport dimensions  
940      GtkAllocation *a = &GTK_WIDGET(map->canvas)->allocation;    /* convert pixels to meters if necessary */
941      gint aw_cu = a->width / zoom;    gdouble sx_cu = *sx / scale;
942      gint ah_cu = a->height / zoom;    gdouble sy_cu = *sy / scale;
943    
944      // Data rect minimum and maximum    /* get size of visible area in canvas units (meters) */
945      gint min_x, min_y, max_x, max_y;    gint aw_cu = canvas_get_viewport_width(map->canvas, CANVAS_UNIT_METER);
946      min_x = map->appdata->osm->bounds->min.x;    gint ah_cu = canvas_get_viewport_height(map->canvas, CANVAS_UNIT_METER);
947      min_y = map->appdata->osm->bounds->min.y;  
948      max_x = map->appdata->osm->bounds->max.x;    // Data rect minimum and maximum
949      max_y = map->appdata->osm->bounds->max.y;    gint min_x, min_y, max_x, max_y;
950      min_x = map->appdata->osm->bounds->min.x;
951      // limit stops - prevent scrolling beyond these    min_y = map->appdata->osm->bounds->min.y;
952      gint min_sy_cu = 0.95*(min_y - ah_cu);    max_x = map->appdata->osm->bounds->max.x;
953      gint min_sx_cu = 0.95*(min_x - aw_cu);    max_y = map->appdata->osm->bounds->max.y;
954      gint max_sy_cu = 0.95*(max_y);  
955      gint max_sx_cu = 0.95*(max_x);    // limit stops - prevent scrolling beyond these
956      if (sy_cu < min_sy_cu) { *sy = min_sy_cu*zoom; }    gint min_sy_cu = 0.95*(min_y - ah_cu);
957      if (sx_cu < min_sx_cu) { *sx = min_sx_cu*zoom; }    gint min_sx_cu = 0.95*(min_x - aw_cu);
958      if (sy_cu > max_sy_cu) { *sy = max_sy_cu*zoom; }    gint max_sy_cu = 0.95*(max_y);
959      if (sx_cu > max_sx_cu) { *sx = max_sx_cu*zoom; }    gint max_sx_cu = 0.95*(max_x);
960      if (sy_cu < min_sy_cu) { *sy = min_sy_cu * scale; }
961      if (sx_cu < min_sx_cu) { *sx = min_sx_cu * scale; }
962      if (sy_cu > max_sy_cu) { *sy = max_sy_cu * scale; }
963      if (sx_cu > max_sx_cu) { *sx = max_sx_cu * scale; }
964  }  }
965    
966    
# Line 874  static gboolean map_limit_zoom(map_t *ma Line 974  static gboolean map_limit_zoom(map_t *ma
974      max_x = map->appdata->osm->bounds->max.x;      max_x = map->appdata->osm->bounds->max.x;
975      max_y = map->appdata->osm->bounds->max.y;      max_y = map->appdata->osm->bounds->max.y;
976    
977      // Canvas viewport dimensions      /* get size of visible area in pixels and convert to meters of intended */
978      GtkAllocation *a = &GTK_WIDGET(map->canvas)->allocation;      /* zoom by deviding by zoom (which is basically pix/m) */
979      gint ah_cu = a->height / *zoom;      gint aw_cu =
980      gint aw_cu = a->width / *zoom;        canvas_get_viewport_width(map->canvas, CANVAS_UNIT_PIXEL) / *zoom;
981        gint ah_cu =
982          canvas_get_viewport_height(map->canvas, CANVAS_UNIT_PIXEL) / *zoom;
983    
984      gdouble oldzoom = *zoom;      gdouble oldzoom = *zoom;
985      if (ah_cu < aw_cu) {      if (ah_cu < aw_cu) {
# Line 895  static gboolean map_limit_zoom(map_t *ma Line 997  static gboolean map_limit_zoom(map_t *ma
997          }          }
998      }      }
999      if (*zoom != oldzoom) {      if (*zoom != oldzoom) {
1000          printf("Can't zoom further out\n");          printf("Can't zoom further out (%f)\n", *zoom);
1001          return 1;          return 1;
1002      }      }
1003      return 0;      return 0;
1004  }  }
1005    
1006    
 #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  
   
1007  /*  /*
1008   * Scroll the map to a point if that point is currently offscreen.   * Scroll the map to a point if that point is currently offscreen.
1009   */   */
# Line 990  void map_scroll_to_if_offscreen(map_t *m Line 1020  void map_scroll_to_if_offscreen(map_t *m
1020    max_y = map->appdata->osm->bounds->max.y;    max_y = map->appdata->osm->bounds->max.y;
1021    if (   (lpos->x > max_x) || (lpos->x < min_x)    if (   (lpos->x > max_x) || (lpos->x < min_x)
1022        || (lpos->y > max_y) || (lpos->y < min_y)) {        || (lpos->y > max_y) || (lpos->y < min_y)) {
1023      printf("cannot scroll to (%d, %d): outside the working area\n");      printf("cannot scroll to (%d, %d): outside the working area\n",
1024               lpos->x, lpos->y);
1025      return;      return;
1026    }    }
1027    
1028    // Viewport dimensions in canvas space    // Viewport dimensions in canvas space
1029    gdouble zoom = goo_canvas_get_scale(GOO_CANVAS(map->canvas));  
1030    GtkAllocation *a = &GTK_WIDGET(map->canvas)->allocation;    /* get size of visible area in canvas units (meters) */
1031    gdouble aw = a->width / zoom;    gdouble pix_per_meter = canvas_get_zoom(map->canvas);
1032    gdouble ah = a->height / zoom;    gdouble aw = canvas_get_viewport_width(map->canvas, CANVAS_UNIT_METER);
1033      gdouble ah = canvas_get_viewport_height(map->canvas, CANVAS_UNIT_METER);
1034    
1035    // Is the point still onscreen?    // Is the point still onscreen?
1036    gboolean vert_recentre_needed = FALSE;    gboolean vert_recentre_needed = FALSE;
1037    gboolean horiz_recentre_needed = FALSE;    gboolean horiz_recentre_needed = FALSE;
1038    gint sx, sy;    gint sx, sy;
1039    canvas_get_scroll_offsets(map->canvas, &sx, &sy);    canvas_scroll_get(map->canvas, CANVAS_UNIT_PIXEL, &sx, &sy);
1040    gint viewport_left   = (sx/zoom);    gint viewport_left   = (sx/pix_per_meter);
1041    gint viewport_right  = (sx/zoom)+aw;    gint viewport_right  = (sx/pix_per_meter)+aw;
1042    gint viewport_top    = (sy/zoom);    gint viewport_top    = (sy/pix_per_meter);
1043    gint viewport_bottom = (sy/zoom)+ah;    gint viewport_bottom = (sy/pix_per_meter)+ah;
1044    if (lpos->x > viewport_right) {    if (lpos->x > viewport_right) {
1045      printf("** off right edge (%d > %d)\n", lpos->x, viewport_right);      printf("** off right edge (%d > %d)\n", lpos->x, viewport_right);
1046      horiz_recentre_needed = TRUE;      horiz_recentre_needed = TRUE;
# Line 1028  void map_scroll_to_if_offscreen(map_t *m Line 1060  void map_scroll_to_if_offscreen(map_t *m
1060    
1061    if (horiz_recentre_needed || vert_recentre_needed) {    if (horiz_recentre_needed || vert_recentre_needed) {
1062      gint new_sx, new_sy;      gint new_sx, new_sy;
1063  #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  
1064      // Just centre both at once      // Just centre both at once
1065      new_sx = zoom * (lpos->x - (aw/2));      new_sx = pix_per_meter * (lpos->x - (aw/2));
1066      new_sy = zoom * (lpos->y - (ah/2));      new_sy = pix_per_meter * (lpos->y - (ah/2));
1067  #endif  
1068      map_limit_scroll(map, &new_sx, &new_sy);      map_limit_scroll(map, CANVAS_UNIT_PIXEL, &new_sx, &new_sy);
1069      canvas_scroll_to(map->canvas, new_sx, new_sy);      canvas_scroll_to(map->canvas, CANVAS_UNIT_PIXEL, new_sx, new_sy);
1070    }    }
1071  }  }
1072    
 #endif // #ifdef USE_GOOCANVAS  
   
1073  /* Deselects the current way or node if its zoom_max  /* Deselects the current way or node if its zoom_max
1074   * 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. */
1075  void map_deselect_if_zoom_below_zoom_max(map_t *map) {  void map_deselect_if_zoom_below_zoom_max(map_t *map) {
1076      if (map->selected.type == MAP_TYPE_WAY) {      if (map->selected.object.type == WAY) {
1077          printf("will deselect way if zoomed below %f\n",          printf("will deselect way if zoomed below %f\n",
1078                 map->selected.way->draw.zoom_max);                 map->selected.object.way->draw.zoom_max);
1079          if (map->state->zoom < map->selected.way->draw.zoom_max) {          if (map->state->zoom < map->selected.object.way->draw.zoom_max) {
1080              printf("  deselecting way!\n");              printf("  deselecting way!\n");
1081              map_item_deselect(map->appdata);              map_item_deselect(map->appdata);
1082          }          }
1083      }      }
1084      else if (map->selected.type == MAP_TYPE_NODE) {      else if (map->selected.object.type == NODE) {
1085          printf("will deselect node if zoomed below %f\n",          printf("will deselect node if zoomed below %f\n",
1086                 map->selected.node->zoom_max);                 map->selected.object.node->zoom_max);
1087          if (map->state->zoom < map->selected.node->zoom_max) {          if (map->state->zoom < map->selected.object.node->zoom_max) {
1088              printf("  deselecting node!\n");              printf("  deselecting node!\n");
1089              map_item_deselect(map->appdata);              map_item_deselect(map->appdata);
1090          }          }
# Line 1069  void map_deselect_if_zoom_below_zoom_max Line 1094  void map_deselect_if_zoom_below_zoom_max
1094  void map_set_zoom(map_t *map, double zoom,  void map_set_zoom(map_t *map, double zoom,
1095                    gboolean update_scroll_offsets) {                    gboolean update_scroll_offsets) {
1096    gboolean at_zoom_limit = 0;    gboolean at_zoom_limit = 0;
 #ifdef USE_GOOCANVAS  
1097    at_zoom_limit = map_limit_zoom(map, &zoom);    at_zoom_limit = map_limit_zoom(map, &zoom);
1098  #endif  
1099    map->state->zoom = zoom;    map->state->zoom = zoom;
1100    canvas_set_zoom(map->canvas, map->state->zoom);    canvas_set_zoom(map->canvas, map->state->zoom);
1101    
1102    map_deselect_if_zoom_below_zoom_max(map);    map_deselect_if_zoom_below_zoom_max(map);
1103    
1104    if (update_scroll_offsets) {    if(update_scroll_offsets) {
1105      if (!at_zoom_limit) {      if (!at_zoom_limit) {
1106        /* zooming affects the scroll offsets */        /* zooming affects the scroll offsets */
1107        gint sx, sy;        gint sx, sy;
1108        canvas_get_scroll_offsets(map->canvas, &sx, &sy);        canvas_scroll_get(map->canvas, CANVAS_UNIT_PIXEL, &sx, &sy);
1109  #ifdef USE_GOOCANVAS        map_limit_scroll(map, CANVAS_UNIT_PIXEL, &sx, &sy);
1110        map_limit_scroll(map, &sx, &sy);  
1111        canvas_scroll_to(map->canvas, sx, sy);  // keep the map visible        // keep the map visible
1112  #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);  
1113      }      }
1114  #endif  
1115        canvas_scroll_get(map->canvas, CANVAS_UNIT_METER,
1116                          &map->state->scroll_offset.x,
1117                          &map->state->scroll_offset.y);
1118    }    }
1119  }  }
1120    
# Line 1118  static gboolean map_scroll_event(GtkWidg Line 1139  static gboolean map_scroll_event(GtkWidg
1139  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) {
1140    gint sx, sy;    gint sx, sy;
1141    
 #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  
1142    /* add offsets generated by mouse within map and map scrolling */    /* add offsets generated by mouse within map and map scrolling */
1143    sx = (x-map->pen_down.at.x);    sx = (x-map->pen_down.at.x);
1144    sy = (y-map->pen_down.at.y);    sy = (y-map->pen_down.at.y);
 #endif  
1145    
1146    return(sx*sx + sy*sy > limit*limit);    return(sx*sx + sy*sy > limit*limit);
1147  }  }
# Line 1137  static gboolean distance_above(map_t *ma Line 1150  static gboolean distance_above(map_t *ma
1150  static void map_do_scroll(map_t *map, gint x, gint y) {  static void map_do_scroll(map_t *map, gint x, gint y) {
1151    gint sx, sy;    gint sx, sy;
1152    
1153    canvas_get_scroll_offsets(map->canvas, &sx, &sy);    canvas_scroll_get(map->canvas, CANVAS_UNIT_PIXEL, &sx, &sy);
1154    sx -= x-map->pen_down.at.x;    sx -= x-map->pen_down.at.x;
1155    sy -= y-map->pen_down.at.y;    sy -= y-map->pen_down.at.y;
1156  #ifdef USE_GOOCANVAS    map_limit_scroll(map, CANVAS_UNIT_PIXEL, &sx, &sy);
1157    map_limit_scroll(map, &sx, &sy);    canvas_scroll_to(map->canvas, CANVAS_UNIT_PIXEL, sx, sy);
1158  #endif  
1159    canvas_scroll_to(map->canvas, sx, sy);    canvas_scroll_get(map->canvas, CANVAS_UNIT_METER,
1160    map->state->scroll_offset.x = sx;                      &map->state->scroll_offset.x,
1161    map->state->scroll_offset.y = sy;                      &map->state->scroll_offset.y);
1162  }  }
1163    
1164    
1165  /* scroll a certain step */  /* scroll a certain step */
1166  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) {
1167    gint sx, sy;    gint sx, sy;
1168    canvas_get_scroll_offsets(map->canvas, &sx, &sy);    canvas_scroll_get(map->canvas, CANVAS_UNIT_PIXEL, &sx, &sy);
1169    sx += x;    sx += x;
1170    sy += y;    sy += y;
1171  #ifdef USE_GOOCANVAS    map_limit_scroll(map, CANVAS_UNIT_PIXEL, &sx, &sy);
1172    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;  
 }  
1173    
1174      canvas_scroll_get(map->canvas, CANVAS_UNIT_METER,
1175                        &map->state->scroll_offset.x,
1176                        &map->state->scroll_offset.y);
1177    }
1178    
1179  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) {
1180    printf("check if item is a selected node\n");    printf("check if item is a selected node\n");
# Line 1172  gboolean map_item_is_selected_node(map_t Line 1184  gboolean map_item_is_selected_node(map_t
1184      return FALSE;      return FALSE;
1185    }    }
1186    
1187    if(map->selected.type == MAP_TYPE_ILLEGAL) {    if(map->selected.object.type == ILLEGAL) {
1188      printf("  nothing is selected\n");      printf("  nothing is selected\n");
1189      return FALSE;      return FALSE;
1190    }    }
1191    
1192    /* clicked the highlight directly */    /* clicked the highlight directly */
1193    if(map_item->type != MAP_TYPE_NODE) {    if(map_item->object.type != NODE) {
1194      printf("  didn't click node\n");      printf("  didn't click node\n");
1195      return FALSE;      return FALSE;
1196    }    }
1197    
1198    if(map->selected.type == MAP_TYPE_NODE) {    if(map->selected.object.type == NODE) {
1199      printf("  selected item is a node\n");      printf("  selected item is a node\n");
1200    
1201      if(map_item->node == map->selected.node) {      if(map_item->object.node == map->selected.object.node) {
1202        printf("  requested item is a selected node\n");        printf("  requested item is a selected node\n");
1203        return TRUE;        return TRUE;
1204      }      }
1205      printf("  but it's not the requested one\n");      printf("  but it's not the requested one\n");
1206      return FALSE;      return FALSE;
1207    
1208    } else if(map->selected.type == MAP_TYPE_WAY) {    } else if(map->selected.object.type == WAY) {
1209      printf("  selected item is a way\n");      printf("  selected item is a way\n");
1210    
1211      node_chain_t *node_chain = map->selected.way->node_chain;      node_chain_t *node_chain = map->selected.object.way->node_chain;
1212      while(node_chain) {      while(node_chain) {
1213        if(node_chain->node == map_item->node) {        if(node_chain->node == map_item->object.node) {
1214          printf("  requested item is part of selected way\n");          printf("  requested item is part of selected way\n");
1215          return TRUE;          return TRUE;
1216        }        }
# Line 1226  gboolean map_item_is_selected_way(map_t Line 1238  gboolean map_item_is_selected_way(map_t
1238      return FALSE;      return FALSE;
1239    }    }
1240    
1241    if(map->selected.type == MAP_TYPE_ILLEGAL) {    if(map->selected.object.type == ILLEGAL) {
1242      printf("  nothing is selected\n");      printf("  nothing is selected\n");
1243      return FALSE;      return FALSE;
1244    }    }
1245    
1246    /* clicked the highlight directly */    /* clicked the highlight directly */
1247    if(map_item->type != MAP_TYPE_WAY) {    if(map_item->object.type != WAY) {
1248      printf("  didn't click way\n");      printf("  didn't click way\n");
1249      return FALSE;      return FALSE;
1250    }    }
1251    
1252    if(map->selected.type == MAP_TYPE_WAY) {    if(map->selected.object.type == WAY) {
1253      printf("  selected item is a way\n");      printf("  selected item is a way\n");
1254    
1255      if(map_item->way == map->selected.way) {      if(map_item->object.way == map->selected.object.way) {
1256        printf("  requested item is a selected way\n");        printf("  requested item is a selected way\n");
1257        return TRUE;        return TRUE;
1258      }      }
# Line 1255  gboolean map_item_is_selected_way(map_t Line 1267  gboolean map_item_is_selected_way(map_t
1267    
1268  void map_highlight_refresh(appdata_t *appdata) {  void map_highlight_refresh(appdata_t *appdata) {
1269    map_t *map = appdata->map;    map_t *map = appdata->map;
1270    map_item_t old = map->selected;    object_t old = map->selected.object;
1271    
1272    printf("type to refresh is %d\n", old.type);    printf("type to refresh is %d\n", old.type);
1273    if(old.type == MAP_TYPE_ILLEGAL)    if(old.type == ILLEGAL)
1274      return;      return;
1275    
1276    map_item_deselect(appdata);    map_item_deselect(appdata);
1277    map_item_select(appdata, &old);    map_object_select(appdata, &old);
1278  }  }
1279    
1280  void map_way_delete(appdata_t *appdata, way_t *way) {  void map_way_delete(appdata_t *appdata, way_t *way) {
1281    printf("deleting way #%ld from map and osm\n", way->id);    printf("deleting way #" ITEM_ID_FORMAT " from map and osm\n", way->id);
1282    
1283    /* remove it visually from the screen */    /* remove it visually from the screen */
1284    map_item_chain_destroy(&way->map_item_chain);    map_item_chain_destroy(&way->map_item_chain);
# Line 1290  static void map_handle_click(appdata_t * Line 1302  static void map_handle_click(appdata_t *
1302    /* problem: on_item may be the highlight itself! So store it! */    /* problem: on_item may be the highlight itself! So store it! */
1303    map_item_t map_item;    map_item_t map_item;
1304    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;
1305    else                      map_item.type = MAP_TYPE_ILLEGAL;    else                      map_item.object.type = ILLEGAL;
1306    
1307    /* if we aready have something selected, then de-select it */    /* if we aready have something selected, then de-select it */
1308    map_item_deselect(appdata);    map_item_deselect(appdata);
1309    
1310    /* select the clicked item (if there was one) */    /* select the clicked item (if there was one) */
1311    if(map_item.type != MAP_TYPE_ILLEGAL) {    if(map_item.object.type != ILLEGAL) {
1312      switch(map_item.type) {      switch(map_item.object.type) {
1313      case MAP_TYPE_NODE:      case NODE:
1314        map_node_select(appdata, map_item.node);        map_node_select(appdata, map_item.object.node);
1315        break;        break;
1316    
1317      case MAP_TYPE_WAY:      case WAY:
1318        map_way_select(appdata, map_item.way);        map_way_select(appdata, map_item.object.way);
1319        break;        break;
1320    
1321      default:      default:
1322        g_assert((map_item.type == MAP_TYPE_NODE) ||        g_assert((map_item.object.type == NODE) ||
1323                 (map_item.type == MAP_TYPE_WAY));                 (map_item.object.type == WAY));
1324        break;        break;
1325      }      }
1326    }    }
# Line 1328  static void map_touchnode_update(appdata Line 1340  static void map_touchnode_update(appdata
1340      /* in idle mode the dragged node is not highlighted */      /* in idle mode the dragged node is not highlighted */
1341    case MAP_ACTION_IDLE:    case MAP_ACTION_IDLE:
1342      g_assert(map->pen_down.on_item);      g_assert(map->pen_down.on_item);
1343      g_assert(map->pen_down.on_item->type == MAP_TYPE_NODE);      g_assert(map->pen_down.on_item->object.type == NODE);
1344      cur_node = map->pen_down.on_item->node;      cur_node = map->pen_down.on_item->object.node;
1345      break;      break;
1346    
1347    default:    default:
# Line 1344  static void map_touchnode_update(appdata Line 1356  static void map_touchnode_update(appdata
1356      /* don't highlight the dragged node itself and don't highlight */      /* don't highlight the dragged node itself and don't highlight */
1357      /* deleted ones */      /* deleted ones */
1358      if((node != cur_node) && (!(node->flags & OSM_FLAG_DELETED))) {      if((node != cur_node) && (!(node->flags & OSM_FLAG_DELETED))) {
1359        gint nx = x - node->lpos.x;        gint nx = abs(x - node->lpos.x);
1360        gint ny = y - node->lpos.y;        gint ny = abs(y - node->lpos.y);
1361    
1362        if((nx < map->style->node.radius) && (ny < map->style->node.radius) &&        if((nx < map->style->node.radius) && (ny < map->style->node.radius) &&
1363           (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 1359  static void map_touchnode_update(appdata Line 1371  static void map_touchnode_update(appdata
1371    if(!map->touchnode && map->action.way) {    if(!map->touchnode && map->action.way) {
1372      node_chain_t *chain = map->action.way->node_chain;      node_chain_t *chain = map->action.way->node_chain;
1373      while(!map->touchnode && chain && chain->next) {      while(!map->touchnode && chain && chain->next) {
1374        gint nx = x - chain->node->lpos.x;        gint nx = abs(x - chain->node->lpos.x);
1375        gint ny = y - chain->node->lpos.y;        gint ny = abs(y - chain->node->lpos.y);
1376    
1377        if((nx < map->style->node.radius) && (ny < map->style->node.radius) &&        if((nx < map->style->node.radius) && (ny < map->style->node.radius) &&
1378           (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 1381  static void map_button_press(map_t *map, Line 1393  static void map_button_press(map_t *map,
1393    map->pen_down.at.y = y;    map->pen_down.at.y = y;
1394    map->pen_down.drag = FALSE;     // don't assume drag yet    map->pen_down.drag = FALSE;     // don't assume drag yet
1395    
 #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  
   
1396    /* determine wether this press was on an item */    /* determine wether this press was on an item */
1397    map->pen_down.on_item = map_real_item_at(map, x, y);    map->pen_down.on_item = map_real_item_at(map, x, y);
1398    
# Line 1458  static void map_button_release(map_t *ma Line 1464  static void map_button_release(map_t *ma
1464        map_item_t old_sel = map->selected;        map_item_t old_sel = map->selected;
1465        map_handle_click(map->appdata, map);        map_handle_click(map->appdata, map);
1466    
1467        if((old_sel.type != MAP_TYPE_ILLEGAL) &&        if((old_sel.object.type != ILLEGAL) &&
1468           (old_sel.type == map->selected.type) &&           (old_sel.object.type == map->selected.object.type) &&
1469           (old_sel.ptr == map->selected.ptr)) {           (old_sel.object.ptr == map->selected.object.ptr)) {
1470          printf("re-selected same item of type %d, "          printf("re-selected same item of type %d, "
1471                 "pushing it to the bottom\n", old_sel.type);                 "pushing it to the bottom\n", old_sel.object.type);
1472    
1473          if(!map->selected.item) {          if(!map->selected.item) {
1474            printf("  item has no visible representation to push\n");            printf("  item has no visible representation to push\n");
# Line 1579  static gboolean map_motion_notify_event( Line 1585  static gboolean map_motion_notify_event(
1585    /* reduce update frequency on hildon to keep screen update fluid */    /* reduce update frequency on hildon to keep screen update fluid */
1586    static guint32 last_time = 0;    static guint32 last_time = 0;
1587    
1588    if(event->time - last_time < 100) return FALSE;    if(event->time - last_time < 250) return FALSE;
1589    last_time = event->time;    last_time = event->time;
1590  #endif  #endif
1591    
1592    if(!map->pen_down.is)    if(!map->pen_down.is)
1593      return FALSE;      return FALSE;
1594    
1595  #ifdef USE_GNOMECANVAS  #ifndef USE_GOOCANVAS
1596    /* handle hints, hints are handled by goocanvas directly */    /* handle hints, hints are handled by goocanvas directly */
1597    if(event->is_hint)    if(event->is_hint)
1598      gdk_window_get_pointer(event->window, &x, &y, &state);      gdk_window_get_pointer(event->window, &x, &y, &state);
# Line 1623  static gboolean map_motion_notify_event( Line 1629  static gboolean map_motion_notify_event(
1629    case MAP_ACTION_NODE_ADD:    case MAP_ACTION_NODE_ADD:
1630      map_hl_cursor_draw(map, x, y, FALSE, map->style->node.radius);      map_hl_cursor_draw(map, x, y, FALSE, map->style->node.radius);
1631      break;      break;
1632    
1633    case MAP_ACTION_WAY_ADD:    case MAP_ACTION_WAY_ADD:
1634      map_hl_cursor_draw(map, x, y, FALSE, map->style->node.radius);      map_hl_cursor_draw(map, x, y, FALSE, map->style->node.radius);
1635      map_touchnode_update(appdata, x, y);      map_touchnode_update(appdata, x, y);
# Line 1724  gboolean map_key_press_event(appdata_t * Line 1730  gboolean map_key_press_event(appdata_t *
1730    return FALSE;    return FALSE;
1731  }  }
1732    
1733    void map_state_reset(map_state_t *state) {
1734      if(!state) return;
1735    
1736      state->zoom = 0.25;
1737      state->detail = 1.0;
1738    
1739      /* todo: try to scroll to center of screen */
1740      state->scroll_offset.x = 0;
1741      state->scroll_offset.y = 0;
1742    }
1743    
1744    map_state_t *map_state_new(void) {
1745      map_state_t *state = g_new0(map_state_t, 1);
1746      map_state_reset(state);
1747      return state;
1748    }
1749    
1750  GtkWidget *map_new(appdata_t *appdata) {  GtkWidget *map_new(appdata_t *appdata) {
1751    map_t *map = appdata->map = g_new0(map_t, 1);    map_t *map = appdata->map = g_new0(map_t, 1);
1752    
1753    map->style = style_load(appdata, appdata->settings->style);    map->style = style_load(appdata, appdata->settings->style);
1754      if(!map->style) {
1755        errorf(NULL, _("Unable to load valid style, terminating."));
1756        g_free(map);
1757        return NULL;
1758      }
1759    
1760    if(appdata->project && appdata->project->map_state) {    if(appdata->project && appdata->project->map_state) {
1761      printf("Using projects map state\n");      printf("Using projects map state\n");
1762      map->state = appdata->project->map_state;      map->state = appdata->project->map_state;
1763    } else {    } else {
1764      printf("Creating new map state\n");      printf("Creating new map state\n");
1765      map->state = g_new0(map_state_t, 1);      map->state = map_state_new();
     map->state->zoom = 0.25;  
1766    }    }
1767    
1768    map->state->refcount++;    map->state->refcount++;
# Line 1745  GtkWidget *map_new(appdata_t *appdata) { Line 1772  GtkWidget *map_new(appdata_t *appdata) {
1772    map->appdata = appdata;    map->appdata = appdata;
1773    map->action.type = MAP_ACTION_IDLE;    map->action.type = MAP_ACTION_IDLE;
1774    
1775  #ifdef USE_GNOMECANVAS    map->canvas = canvas_new();
   map->canvas = gnome_canvas_new_aa();  // _aa  
1776    
1777    /* 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);  
1778    
1779    gtk_widget_modify_bg(map->canvas, GTK_STATE_NORMAL,    gtk_widget_set_events(canvas_widget,
                        &map->canvas->style->white);  
   
 #else  
   map->canvas = goo_canvas_new();  
   
   g_object_set(G_OBJECT(map->canvas), "anchor", GTK_ANCHOR_CENTER, NULL);  
   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,  
1780                            GDK_BUTTON_PRESS_MASK                            GDK_BUTTON_PRESS_MASK
1781                          | GDK_BUTTON_RELEASE_MASK                          | GDK_BUTTON_RELEASE_MASK
1782                          | GDK_SCROLL_MASK                          | GDK_SCROLL_MASK
1783                          | GDK_POINTER_MOTION_MASK                          | GDK_POINTER_MOTION_MASK
1784                          | GDK_POINTER_MOTION_HINT_MASK);                          | GDK_POINTER_MOTION_HINT_MASK);
1785    
1786    gtk_signal_connect(GTK_OBJECT(map->canvas),    gtk_signal_connect(GTK_OBJECT(canvas_widget),
1787       "button_press_event", G_CALLBACK(map_button_event), appdata);       "button_press_event", G_CALLBACK(map_button_event), appdata);
1788    gtk_signal_connect(GTK_OBJECT(map->canvas),    gtk_signal_connect(GTK_OBJECT(canvas_widget),
1789       "button_release_event", G_CALLBACK(map_button_event), appdata);       "button_release_event", G_CALLBACK(map_button_event), appdata);
1790    gtk_signal_connect(GTK_OBJECT(map->canvas),    gtk_signal_connect(GTK_OBJECT(canvas_widget),
1791       "motion_notify_event", G_CALLBACK(map_motion_notify_event), appdata);       "motion_notify_event", G_CALLBACK(map_motion_notify_event), appdata);
1792    gtk_signal_connect(GTK_OBJECT(map->canvas),    gtk_signal_connect(GTK_OBJECT(canvas_widget),
1793       "scroll_event", G_CALLBACK(map_scroll_event), appdata);       "scroll_event", G_CALLBACK(map_scroll_event), appdata);
1794    
1795    gtk_signal_connect(GTK_OBJECT(map->canvas),    gtk_signal_connect(GTK_OBJECT(canvas_widget),
1796       "destroy", G_CALLBACK(map_destroy_event), appdata);       "destroy", G_CALLBACK(map_destroy_event), appdata);
1797    
1798    return map->canvas;    return canvas_widget;
1799  }  }
1800    
1801  void map_init(appdata_t *appdata) {  void map_init(appdata_t *appdata) {
1802    map_t *map = appdata->map;    map_t *map = appdata->map;
1803    
1804      /* update canvas background color */
1805      canvas_set_background(map->canvas, map->style->background.color);
1806    
1807    /* set initial zoom */    /* set initial zoom */
1808    map_set_zoom(map, map->state->zoom, FALSE);    map_set_zoom(map, map->state->zoom, FALSE);
1809    josm_elemstyles_colorize_world(map->style, appdata->osm);    josm_elemstyles_colorize_world(map->style, appdata->osm);
# Line 1813  void map_init(appdata_t *appdata) { Line 1817  void map_init(appdata_t *appdata) {
1817                      mult*appdata->osm->bounds->max.x,                      mult*appdata->osm->bounds->max.x,
1818                      mult*appdata->osm->bounds->max.y);                      mult*appdata->osm->bounds->max.y);
1819    
1820    printf("restore scroll offsets %d/%d\n",    printf("restore scroll position %d/%d\n",
1821           map->state->scroll_offset.x, map->state->scroll_offset.y);           map->state->scroll_offset.x, map->state->scroll_offset.y);
1822    
1823    canvas_scroll_to(map->canvas,    map_limit_scroll(map, CANVAS_UNIT_METER,
1824                     map->state->scroll_offset.x, map->state->scroll_offset.y);             &map->state->scroll_offset.x, &map->state->scroll_offset.y);
1825      canvas_scroll_to(map->canvas, CANVAS_UNIT_METER,
1826               map->state->scroll_offset.x, map->state->scroll_offset.y);
1827  }  }
1828    
1829    
1830  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) {  
1831    map_t *map = appdata->map;    map_t *map = appdata->map;
1832    
1833    printf("freeing map contents\n");    printf("freeing map contents\n");
# Line 1850  void map_clear(appdata_t *appdata, gint Line 1837  void map_clear(appdata_t *appdata, gint
1837    /* remove a possibly existing highlight */    /* remove a possibly existing highlight */
1838    map_item_deselect(appdata);    map_item_deselect(appdata);
1839    
1840    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  
   }  
1841  }  }
1842    
1843  void map_paint(appdata_t *appdata) {  void map_paint(appdata_t *appdata) {
# Line 1907  void map_action_set(appdata_t *appdata, Line 1874  void map_action_set(appdata_t *appdata,
1874    
1875      /* remember if there was a way selected */      /* remember if there was a way selected */
1876      way_t *way_sel = NULL;      way_t *way_sel = NULL;
1877      if(appdata->map->selected.type == MAP_TYPE_WAY)      if(appdata->map->selected.object.type == WAY)
1878        way_sel = appdata->map->selected.way;        way_sel = appdata->map->selected.object.way;
1879    
1880      map_item_deselect(appdata);      map_item_deselect(appdata);
1881      map_edit_way_add_begin(appdata->map, way_sel);      map_edit_way_add_begin(appdata->map, way_sel);
# Line 1983  void map_action_ok(appdata_t *appdata) { Line 1950  void map_action_ok(appdata_t *appdata) {
1950      /* save changes to bg_offset in project */      /* save changes to bg_offset in project */
1951      appdata->project->wms_offset.x = map->bg.offset.x;      appdata->project->wms_offset.x = map->bg.offset.x;
1952      appdata->project->wms_offset.y = map->bg.offset.y;      appdata->project->wms_offset.y = map->bg.offset.y;
     appdata->project->dirty = TRUE;  
1953      break;      break;
1954    
1955    default:    default:
# Line 2007  void map_delete_selected(appdata_t *appd Line 1973  void map_delete_selected(appdata_t *appd
1973    /* deleting the selected item de-selects it ... */    /* deleting the selected item de-selects it ... */
1974    map_item_deselect(appdata);    map_item_deselect(appdata);
1975    
1976    switch(item.type) {    undo_remember_delete(appdata, &item.object);
1977    case MAP_TYPE_NODE:  
1978      printf("request to delete node #%ld\n", item.node->id);    switch(item.object.type) {
1979      case NODE:
1980        printf("request to delete node #" ITEM_ID_FORMAT "\n",
1981               item.object.node->id);
1982    
1983      /* 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. */
1984      /* we cannot delete this as this would also delete the way */      /* we cannot delete this as this would also delete the way */
1985      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);
1986      if(way_chain) {      if(way_chain) {
1987        gboolean short_way = FALSE;        gboolean short_way = FALSE;
1988    
# Line 2039  void map_delete_selected(appdata_t *appd Line 2008  void map_delete_selected(appdata_t *appd
2008      }      }
2009    
2010      /* remove it visually from the screen */      /* remove it visually from the screen */
2011      map_item_chain_destroy(&item.node->map_item_chain);      map_item_chain_destroy(&item.object.node->map_item_chain);
2012    
2013      /* and mark it "deleted" in the database */      /* and mark it "deleted" in the database */
2014      osm_node_remove_from_relation(appdata->osm, item.node);      osm_node_remove_from_relation(appdata->osm, item.object.node);
2015      way_chain_t *chain = osm_node_delete(appdata->osm,      way_chain_t *chain = osm_node_delete(appdata->osm,
2016                           &appdata->icon, item.node, FALSE, TRUE);                           &appdata->icon, item.object.node, FALSE, TRUE);
2017    
2018      /* redraw all affected ways */      /* redraw all affected ways */
2019      while(chain) {      while(chain) {
# Line 2057  void map_delete_selected(appdata_t *appd Line 2026  void map_delete_selected(appdata_t *appd
2026          map_way_delete(appdata, chain->way);          map_way_delete(appdata, chain->way);
2027        } else {        } else {
2028          map_item_t item;          map_item_t item;
2029          item.type = MAP_TYPE_WAY;          item.object.type = WAY;
2030          item.way = chain->way;          item.object.way = chain->way;
2031          map_item_redraw(appdata, &item);          map_item_redraw(appdata, &item);
2032        }        }
2033    
# Line 2069  void map_delete_selected(appdata_t *appd Line 2038  void map_delete_selected(appdata_t *appd
2038    
2039      break;      break;
2040    
2041    case MAP_TYPE_WAY:    case WAY:
2042      printf("request to delete way #%ld\n", item.way->id);      printf("request to delete way #" ITEM_ID_FORMAT "\n", item.object.way->id);
2043      map_way_delete(appdata, item.way);      map_way_delete(appdata, item.object.way);
2044      break;      break;
2045    
2046    default:    default:
2047      g_assert((item.type == MAP_TYPE_NODE) ||      g_assert((item.object.type == NODE) ||
2048               (item.type == MAP_TYPE_WAY));               (item.object.type == WAY));
2049      break;      break;
2050    }    }
2051  }  }
2052    
2053  /* ----------------------- track related stuff ----------------------- */  /* ----------------------- track related stuff ----------------------- */
2054    
2055    static gboolean track_pos2lpos(bounds_t *bounds, pos_t *pos, lpos_t *lpos) {
2056      pos2lpos(bounds, pos, lpos);
2057    
2058      /* check if point is within bounds */
2059      return ((lpos->x >= bounds->min.x) && (lpos->x <= bounds->max.x) &&
2060              (lpos->y >= bounds->min.y) && (lpos->y <= bounds->max.y));
2061    }
2062    
2063  void map_track_draw_seg(map_t *map, track_seg_t *seg) {  void map_track_draw_seg(map_t *map, track_seg_t *seg) {
2064      bounds_t *bounds = map->appdata->osm->bounds;
2065    
2066    /* a track_seg needs at least 2 points to be drawn */    /* a track_seg needs at least 2 points to be drawn */
2067    guint pnum = track_seg_points(seg);    guint pnum = track_seg_points(seg);
2068    printf("seg of length %d\n", pnum);    printf("seg of length %d\n", pnum);
2069    
2070    if(pnum == 1) {    if(!pnum)
2071      g_assert(!seg->item);      return;
2072    
2073      seg->item = canvas_circle_new(map, CANVAS_GROUP_TRACK,    /* nothing should have been drawn by now ... */
2074            seg->track_point->lpos.x, seg->track_point->lpos.y,    g_assert(!seg->item_chain);
2075            map->style->track.width/2.0, 0, map->style->track.color, NO_COLOR);  
2076    }    track_item_chain_t **itemP = &seg->item_chain;
2077      track_point_t *track_point = seg->track_point;
2078      while(track_point) {
2079        lpos_t lpos;
2080    
2081        /* skip all points not on screen */
2082        track_point_t *last = NULL;
2083        while(track_point && !track_pos2lpos(bounds, &track_point->pos, &lpos)) {
2084          last = track_point;
2085          track_point = track_point->next;
2086        }
2087    
2088        int visible = 0;
2089    
2090        /* count nodes that _are_ on screen */
2091        track_point_t *tmp = track_point;
2092        while(tmp && track_pos2lpos(bounds, &tmp->pos, &lpos)) {
2093          tmp = tmp->next;
2094          visible++;
2095        }
2096    
2097        /* actually start drawing with the last position that was offscreen */
2098        /* so the track nicely enters the viewing area */
2099        if(last) {
2100          track_point = last;
2101          visible++;
2102        }
2103    
2104        /* also use last one that's offscreen to nicely leave the visible area */
2105        if(tmp && tmp->next)
2106          visible++;
2107    
   if(pnum > 1) {  
   
2108      /* allocate space for nodes */      /* allocate space for nodes */
2109      canvas_points_t *points = canvas_points_new(pnum);      canvas_points_t *points = canvas_points_new(visible);
2110    
2111      int point = 0;      printf("visible are %d\n", visible);
2112      track_point_t *track_point = seg->track_point;      int point;
2113      while(track_point) {      for(point=0;point<visible;point++) {
2114        points->coords[point++] = track_point->lpos.x;        track_pos2lpos(bounds, &track_point->pos, &lpos);
2115        points->coords[point++] = track_point->lpos.y;  
2116          points->coords[2*point+0] = lpos.x;
2117          points->coords[2*point+1] = lpos.y;
2118        track_point = track_point->next;        track_point = track_point->next;
2119      }      }
   
     /* there may be a circle (one point line) */  
     if(seg->item)  
       canvas_item_destroy(seg->item);  
2120    
2121      seg->item = canvas_polyline_new(map, CANVAS_GROUP_TRACK,      *itemP = g_new0(track_item_chain_t, 1);
2122            points, map->style->track.width, map->style->track.color);      (*itemP)->item = canvas_polyline_new(map->canvas, CANVAS_GROUP_TRACK,
2123                     points, map->style->track.width, map->style->track.color);
2124        itemP = &(*itemP)->next;
2125    
2126      canvas_points_free(points);      canvas_points_free(points);
2127    }    }
2128  }  }
2129    
2130    /* update the last visible fragment of this segment since a */
2131    /* gps position may have been added */
2132  void map_track_update_seg(map_t *map, track_seg_t *seg) {  void map_track_update_seg(map_t *map, track_seg_t *seg) {
2133      bounds_t *bounds = map->appdata->osm->bounds;
2134    
2135      printf("-- APPENDING TO TRACK --\n");
2136    
2137    /* a track_seg needs at least 2 points to be drawn */    /* a track_seg needs at least 2 points to be drawn */
2138    guint pnum = track_seg_points(seg);    guint pnum = track_seg_points(seg);
2139    printf("seg of length %d\n", pnum);    printf("seg of length %d\n", pnum);
2140    
2141    if(pnum > 1) {    /* there are two cases: either the second last point was on screen */
2142      /* or it wasn't. We'll have to start a new screen item if the latter */
2143      /* is the case */
2144    
2145      /* search last point */
2146      track_point_t *begin = seg->track_point, *second_last = seg->track_point;
2147      lpos_t lpos;
2148      while(second_last && second_last->next && second_last->next->next) {
2149        if(!track_pos2lpos(bounds, &second_last->pos, &lpos))
2150          begin = second_last;
2151    
2152        second_last = second_last->next;
2153      }
2154      track_point_t *last = second_last->next;
2155    
2156      /* since we are updating an existing track, it sure has at least two */
2157      /* points, second_last must be valid and its "next" (last) also */
2158      g_assert(second_last);
2159      g_assert(last);
2160    
2161      /* check if the last and second_last points are visible */
2162      gboolean last_is_visible =
2163        track_pos2lpos(bounds, &last->pos, &lpos);
2164      gboolean second_last_is_visible =
2165        track_pos2lpos(bounds, &second_last->pos, &lpos);
2166    
2167      /* if both are invisible, then nothing has changed on screen */
2168      if(!last_is_visible && !second_last_is_visible) {
2169        printf("second_last and last entry are invisible -> doing nothing\n");
2170        return;
2171      }
2172    
2173      /* search last element in item chain */
2174      track_item_chain_t *item = seg->item_chain;
2175      while(item && item->next)
2176        item = item->next;
2177    
2178      if(second_last_is_visible) {
2179        /* there must be something already on the screen and there must */
2180        /* be visible nodes in the chain */
2181        g_assert(item);
2182        g_assert(begin);
2183    
2184        printf("second_last is visible -> append\n");
2185    
2186      /* allocate space for nodes */      /* count points to be placed */
2187      canvas_points_t *points = canvas_points_new(pnum);      int npoints = 0;
2188        track_point_t *tmp = begin;
2189        while(tmp) {
2190          tmp = tmp->next;
2191          npoints++;
2192        }
2193    
2194        printf("updating last segment to %d points\n", npoints);
2195    
2196        canvas_points_t *points = canvas_points_new(npoints);
2197    
2198        gint point = 0;
2199        while(begin) {
2200          track_pos2lpos(bounds, &begin->pos, &lpos);
2201          canvas_point_set_pos(points, point++, &lpos);
2202          begin = begin->next;
2203        }
2204    
2205      int point = 0;      canvas_item_set_points(item->item, points);
2206      track_point_t *track_point = seg->track_point;      canvas_points_free(points);
2207      while(track_point) {  
2208        canvas_point_set_pos(points, point++, &track_point->lpos);    } else {
2209        track_point = track_point->next;      printf("second last is invisible -> start new screen segment\n");
2210    
2211        /* the search for the "begin" ends with the second_last item */
2212        /* verify the last one also */
2213        if(begin->next && !track_pos2lpos(bounds, &begin->next->pos, &lpos))
2214          begin = begin->next;
2215    
2216        item->next = g_new0(track_item_chain_t, 1);
2217        item = item->next;
2218    
2219        /* count points to be placed */
2220        int npoints = 0;
2221        track_point_t *tmp = begin;
2222        while(tmp) {
2223          tmp = tmp->next;
2224          npoints++;
2225        }
2226    
2227        printf("attaching new segment with %d points\n", npoints);
2228    
2229        canvas_points_t *points = canvas_points_new(npoints);
2230    
2231        gint point = 0;
2232        while(begin) {
2233          track_pos2lpos(bounds, &begin->pos, &lpos);
2234          canvas_point_set_pos(points, point++, &lpos);
2235          begin = begin->next;
2236      }      }
2237    
2238      g_assert(seg->item);      item->item = canvas_polyline_new(map->canvas, CANVAS_GROUP_TRACK,
2239      canvas_item_set_points(seg->item, points);                   points, map->style->track.width, map->style->track.color);
2240    
2241      canvas_points_free(points);      canvas_points_free(points);
2242    }    }
2243    
2244  }  }
2245    
2246  void map_track_draw(map_t *map, track_t *track) {  void map_track_draw(map_t *map, track_t *track) {
# Line 2163  void map_track_remove(appdata_t *appdata Line 2263  void map_track_remove(appdata_t *appdata
2263    /* remove all segments */    /* remove all segments */
2264    track_seg_t *seg = track->track_seg;    track_seg_t *seg = track->track_seg;
2265    while(seg) {    while(seg) {
2266      if(seg->item) {      track_item_chain_t *item = seg->item_chain;
2267        canvas_item_destroy(seg->item);      while(item) {
2268        seg->item = NULL;        track_item_chain_t *next = item->next;
2269          canvas_item_destroy(item->item);
2270          item = next;
2271      }      }
2272    
2273        seg->item_chain = NULL;
2274      seg = seg->next;      seg = seg->next;
2275    }    }
2276  }  }
2277    
2278  void map_track_pos(appdata_t *appdata, lpos_t *lpos) {  void map_track_pos(appdata_t *appdata, pos_t *pos) {
2279    if(appdata->track.gps_item) {    if(appdata->track.gps_item) {
2280      canvas_item_destroy(appdata->track.gps_item);      canvas_item_destroy(appdata->track.gps_item);
2281      appdata->track.gps_item = NULL;      appdata->track.gps_item = NULL;
2282    }    }
2283    
2284    if(lpos)    if(pos) {
2285      appdata->track.gps_item = canvas_circle_new(appdata->map, CANVAS_GROUP_GPS,      lpos_t lpos;
2286          lpos->x, lpos->y, appdata->map->style->track.width/2.0, 0,      pos2lpos(appdata->osm->bounds, pos, &lpos);
2287                          RGB2CANVAS(appdata->map->style->track.gps_color), NO_COLOR);  
2288        appdata->track.gps_item =
2289          canvas_circle_new(appdata->map->canvas, CANVAS_GROUP_GPS,
2290            lpos.x, lpos.y, appdata->map->style->track.width/2.0, 0,
2291                            appdata->map->style->track.gps_color, NO_COLOR);
2292      }
2293  }  }
2294    
2295  /* ------------------- map background ------------------ */  /* ------------------- map background ------------------ */
# Line 2222  void map_set_bg_image(map_t *map, char * Line 2330  void map_set_bg_image(map_t *map, char *
2330    map->bg.scale.y = (float)(bounds->max.y - bounds->min.y)/    map->bg.scale.y = (float)(bounds->max.y - bounds->min.y)/
2331      (float)gdk_pixbuf_get_height(map->bg.pix);      (float)gdk_pixbuf_get_height(map->bg.pix);
2332    
2333    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,
2334            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);
2335    
2336    canvas_item_destroy_connect(map->bg.item,    canvas_item_destroy_connect(map->bg.item,
# Line 2236  void map_hide_selected(appdata_t *appdat Line 2344  void map_hide_selected(appdata_t *appdat
2344    map_t *map = appdata->map;    map_t *map = appdata->map;
2345    if(!map) return;    if(!map) return;
2346    
2347    if(map->selected.type != MAP_TYPE_WAY) {    if(map->selected.object.type != WAY) {
2348      printf("selected item is not a way\n");      printf("selected item is not a way\n");
2349      return;      return;
2350    }    }
2351    
2352    way_t *way = map->selected.way;    way_t *way = map->selected.object.way;
2353    printf("hiding way #%ld\n", way->id);    printf("hiding way #" ITEM_ID_FORMAT "\n", way->id);
2354    
2355    map_item_deselect(appdata);    map_item_deselect(appdata);
2356    way->flags |= OSM_FLAG_HIDDEN;    way->flags |= OSM_FLAG_HIDDEN;
# Line 2267  void map_show_all(appdata_t *appdata) { Line 2375  void map_show_all(appdata_t *appdata) {
2375    
2376    gtk_widget_set_sensitive(appdata->menu_item_map_show_all, FALSE);    gtk_widget_set_sensitive(appdata->menu_item_map_show_all, FALSE);
2377  }  }
2378    
2379    static void map_detail_change(map_t *map, float detail) {
2380      appdata_t *appdata = map->appdata;
2381    
2382      /* deselecting anything allows us not to care about automatic deselection */
2383      /* as well as items becoming invisible by the detail change */
2384      map_item_deselect(appdata);
2385    
2386      map->state->detail = detail;
2387      printf("changing detail factor to %f\n", map->state->detail);
2388    
2389      banner_busy_start(appdata, 1, _("Redrawing"));
2390      map_clear(appdata, MAP_LAYER_OBJECTS_ONLY);
2391      map_paint(appdata);
2392      banner_busy_stop(appdata);
2393    }
2394    
2395    #define DETAIL_STEP 1.5
2396    
2397    void map_detail_increase(map_t *map) {
2398      if(!map) return;
2399      map_detail_change(map, map->state->detail * DETAIL_STEP);
2400    }
2401    
2402    void map_detail_decrease(map_t *map) {
2403      if(!map) return;
2404      map_detail_change(map, map->state->detail / DETAIL_STEP);
2405    }
2406    
2407    void map_detail_normal(map_t *map) {
2408      if(!map) return;
2409      map_detail_change(map, 1.0);
2410    }
2411    
2412  // vim:et:ts=8:sw=2:sts=2:ai  // vim:et:ts=8:sw=2:sts=2:ai

Legend:
Removed from v.13  
changed lines
  Added in v.234