Diff of /trunk/src/map.c

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

revision 105 by harbaum, Tue Mar 3 15:27:55 2009 UTC revision 194 by harbaum, Tue Jul 7 19:31:45 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 48  static void map_statusbar(map_t *map, ma Line 54  static void map_statusbar(map_t *map, ma
54    }    }
55    
56    gboolean collision = FALSE;    gboolean collision = FALSE;
57    
58    #if 0
59    tag_t *tags = tag;    tag_t *tags = tag;
60    
61    if(id == ID_ILLEGAL)    if(id == ID_ILLEGAL)
62      str = g_strdup_printf(_("Unknown item"));      str = g_strdup_printf(_("Unknown item"));
63    else {    else {
64      str = g_strdup_printf("%s #%ld", item_str, id);      str = g_strdup_printf("%s", item_str);
65    
66      /* add some tags ... */      /* add some tags ... */
67      /*      /*
68       *  XXX Should we just try to present only the name or the ref (or the       *  Should we just try to present only the name or the ref (or the
69       *  alt_name, old_name, whatever) here?  Hurling a load of tags in the       *  alt_name, old_name, whatever) here?  Hurling a load of tags in the
70       *  user's face in some unpredictable, uninformative order isn't very       *  user's face in some unpredictable, uninformative order isn't very
71       *  friendly.       *  friendly.
72       *       *
73       *  Actually, a tag_short_desc() function would be useful in dialogs       *  Actually, a tag_short_desc() function would be useful in dialogs
74       *  nd user messages too.       *  and user messages too.
75       */       */
76      while(tag) {      while(tag) {
77        if(!collision && info_tag_key_collision(tags, tag))        if(!collision && info_tag_key_collision(tags, tag))
# Line 78  static void map_statusbar(map_t *map, ma Line 86  static void map_statusbar(map_t *map, ma
86        tag = tag->next;        tag = tag->next;
87      }      }
88    }    }
89    #else
90      str = osm_object_string(&map_item->object);
91      str[0] = g_ascii_toupper(str[0]);
92    #endif
93    
94    statusbar_set(map->appdata, str, collision);    statusbar_set(map->appdata, str, collision);
95    g_free(str);    g_free(str);
# Line 132  static void map_node_select(appdata_t *a Line 144  static void map_node_select(appdata_t *a
144    
145    g_assert(!map->highlight);    g_assert(!map->highlight);
146    
147    map_item->type      = MAP_TYPE_NODE;    map_item->object.type      = NODE;
148    map_item->node      = node;    map_item->object.node      = node;
149    map_item->highlight = FALSE;    map_item->highlight = FALSE;
150    
151    /* node may not have any visible representation at all */    /* node may not have any visible representation at all */
# Line 146  static void map_node_select(appdata_t *a Line 158  static void map_node_select(appdata_t *a
158    icon_bar_map_item_selected(appdata, map_item, TRUE);    icon_bar_map_item_selected(appdata, map_item, TRUE);
159    
160    /* highlight node */    /* highlight node */
161    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;
162    
163    /* 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 */
164    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 157  static void map_node_select(appdata_t *a Line 169  static void map_node_select(appdata_t *a
169    if(!node->ways) radius += map->style->node.border_radius;    if(!node->ways) radius += map->style->node.border_radius;
170    if(node->icon_buf && map->style->icon.enable &&    if(node->icon_buf && map->style->icon.enable &&
171       !appdata->settings->no_icons) {       !appdata->settings->no_icons) {
172      gint w = gdk_pixbuf_get_width(map_item->node->icon_buf);      gint w = gdk_pixbuf_get_width(map_item->object.node->icon_buf);
173      gint h = gdk_pixbuf_get_height(map_item->node->icon_buf);      gint h = gdk_pixbuf_get_height(map_item->object.node->icon_buf);
174      /* icons are technically square, so a radius slightly bigger */      /* icons are technically square, so a radius slightly bigger */
175      /* than sqrt(2)*MAX(w,h) should fit nicely */      /* than sqrt(2)*MAX(w,h) should fit nicely */
176      radius =  0.75 * map->style->icon.scale * ((w>h)?w:h);      radius = 0.75 * map->style->icon.scale * ((w>h)?w:h);
177    }    }
178    
179      radius *= map->state->detail;
180    map_hl_circle_new(map, CANVAS_GROUP_NODES_HL, new_map_item,    map_hl_circle_new(map, CANVAS_GROUP_NODES_HL, new_map_item,
181                      x, y, radius, map->style->highlight.color);                      x, y, radius, map->style->highlight.color);
182    
# Line 172  static void map_node_select(appdata_t *a Line 185  static void map_node_select(appdata_t *a
185      new_map_item = g_new0(map_item_t, 1);      new_map_item = g_new0(map_item_t, 1);
186      memcpy(new_map_item, map_item, sizeof(map_item_t));      memcpy(new_map_item, map_item, sizeof(map_item_t));
187      new_map_item->highlight = TRUE;      new_map_item->highlight = TRUE;
188      map_hl_circle_new(map, CANVAS_GROUP_NODES_HL, new_map_item,      map_hl_circle_new(map, CANVAS_GROUP_NODES_IHL, new_map_item,
189                        x, y, map->style->node.radius,                        x, y, map->style->node.radius,
190                        map->style->highlight.node_color);                        map->style->highlight.node_color);
191    }    }
# Line 184  void map_way_select(appdata_t *appdata, Line 197  void map_way_select(appdata_t *appdata,
197    
198    g_assert(!map->highlight);    g_assert(!map->highlight);
199    
200    map_item->type      = MAP_TYPE_WAY;    map_item->object.type      = WAY;
201    map_item->way       = way;    map_item->object.way       = way;
202    map_item->highlight = FALSE;    map_item->highlight = FALSE;
203    map_item->item      = way->map_item_chain->map_item->item;    map_item->item      = way->map_item_chain->map_item->item;
204    
205    map_statusbar(map, map_item);    map_statusbar(map, map_item);
206    icon_bar_map_item_selected(appdata, map_item, TRUE);    icon_bar_map_item_selected(appdata, map_item, TRUE);
207    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;  
208    
209    node_chain_t *node_chain = map_item->way->node_chain;    gint arrow_width = ((map_item->object.way->draw.flags & OSM_DRAW_FLAG_BG)?
210                          map->style->highlight.width + map_item->object.way->draw.bg.width/2:
211                          map->style->highlight.width + map_item->object.way->draw.width/2)
212        * map->state->detail;
213    
214      node_chain_t *node_chain = map_item->object.way->node_chain;
215    node_t *last = NULL;    node_t *last = NULL;
216    while(node_chain) {    while(node_chain) {
217      map_item_t item;      map_item_t item;
218      item.type = MAP_TYPE_NODE;      item.object.type = NODE;
219      item.node = node_chain->node;      item.object.node = node_chain->node;
220    
221      /* draw an arrow between every two nodes */      /* draw an arrow between every two nodes */
222      if(last) {      if(last) {
223        /* create a new map item for every arrow */        /* create a new map item for every arrow */
224        map_item_t *new_map_item = g_new0(map_item_t, 1);        map_item_t *new_map_item = g_new0(map_item_t, 1);
225        new_map_item->type = MAP_TYPE_WAY;        new_map_item->object.type = WAY;
226        new_map_item->way = way;        new_map_item->object.way = way;
227        new_map_item->highlight = TRUE;        new_map_item->highlight = TRUE;
228    
229        struct { float x, y;} center, diff;        struct { float x, y;} center, diff;
# Line 245  void map_way_select(appdata_t *appdata, Line 259  void map_way_select(appdata_t *appdata,
259    
260        /* create a new map item for every node */        /* create a new map item for every node */
261        map_item_t *new_map_item = g_new0(map_item_t, 1);        map_item_t *new_map_item = g_new0(map_item_t, 1);
262        new_map_item->type = MAP_TYPE_NODE;        new_map_item->object.type = NODE;
263        new_map_item->node = node_chain->node;        new_map_item->object.node = node_chain->node;
264        new_map_item->highlight = TRUE;        new_map_item->highlight = TRUE;
265    
266        gint x = node_chain->node->lpos.x;        gint x = node_chain->node->lpos.x;
267        gint y = node_chain->node->lpos.y;        gint y = node_chain->node->lpos.y;
268    
269        map_hl_circle_new(map, CANVAS_GROUP_NODES_HL, new_map_item,        map_hl_circle_new(map, CANVAS_GROUP_NODES_IHL, new_map_item,
270                          x, y, map->style->node.radius,                          x, y, map->style->node.radius * map->state->detail,
271                          map->style->highlight.node_color);                          map->style->highlight.node_color);
272      }      }
273    
# Line 269  void map_way_select(appdata_t *appdata, Line 283  void map_way_select(appdata_t *appdata,
283      canvas_points_t *points = canvas_points_new(nodes);      canvas_points_t *points = canvas_points_new(nodes);
284    
285      int node = 0;      int node = 0;
286      node_chain = map_item->way->node_chain;      node_chain = map_item->object.way->node_chain;
287      while(node_chain) {      while(node_chain) {
288        canvas_point_set_pos(points, node++, &node_chain->node->lpos);        canvas_point_set_pos(points, node++, &node_chain->node->lpos);
289        node_chain = node_chain->next;        node_chain = node_chain->next;
# Line 281  void map_way_select(appdata_t *appdata, Line 295  void map_way_select(appdata_t *appdata,
295      new_map_item->highlight = TRUE;      new_map_item->highlight = TRUE;
296    
297      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,
298                  (map_item->way->draw.flags & OSM_DRAW_FLAG_BG)?                   ((map_item->object.way->draw.flags & OSM_DRAW_FLAG_BG)?
299                  2*map->style->highlight.width + map_item->way->draw.bg.width:                   2*map->style->highlight.width + map_item->object.way->draw.bg.width:
300                  2*map->style->highlight.width + map_item->way->draw.width,                   2*map->style->highlight.width + map_item->object.way->draw.width)
301                  map->style->highlight.color);                  * map->state->detail, map->style->highlight.color);
302    
303      canvas_points_free(points);      canvas_points_free(points);
304    }    }
305  }  }
306    
307  static void map_item_select(appdata_t *appdata, map_item_t *map_item) {  void map_relation_select(appdata_t *appdata, relation_t *relation) {
308    switch(map_item->type) {    map_t *map = appdata->map;
309    case MAP_TYPE_NODE:  
310      map_node_select(appdata, map_item->node);    printf("highlighting relation "ITEM_ID_FORMAT"\n", relation->id);
311    
312      g_assert(!map->highlight);
313      map_highlight_t **hl = &map->highlight;
314    
315      map_item_t *map_item = &map->selected;
316      map_item->object.type      = RELATION;
317      map_item->object.relation  = relation;
318      map_item->highlight = FALSE;
319      map_item->item      = NULL;
320    
321      map_statusbar(map, map_item);
322      icon_bar_map_item_selected(appdata, map_item, TRUE);
323    
324      /* process all members */
325      member_t *member = relation->member;
326      while(member) {
327        canvas_item_t *item = NULL;
328    
329        switch(member->object.type) {
330    
331        case NODE: {
332          node_t *node = member->object.node;
333          printf("  -> node "ITEM_ID_FORMAT"\n", node->id);
334    
335          item = canvas_circle_new(map->canvas, CANVAS_GROUP_NODES_HL,
336                            node->lpos.x, node->lpos.y,
337                            map->style->highlight.width + map->style->node.radius,
338                            0, map->style->highlight.color, NO_COLOR);
339          } break;
340    
341        case WAY: {
342          way_t *way = member->object.way;
343          /* a way needs at least 2 points to be drawn */
344          guint nodes = osm_way_number_of_nodes(way);
345          if(nodes > 1) {
346    
347            /* allocate space for nodes */
348            canvas_points_t *points = canvas_points_new(nodes);
349    
350            int node = 0;
351            node_chain_t *node_chain = way->node_chain;
352            while(node_chain) {
353              canvas_point_set_pos(points, node++, &node_chain->node->lpos);
354              node_chain = node_chain->next;
355            }
356    
357            if(way->draw.flags & OSM_DRAW_FLAG_AREA)
358              item = canvas_polygon_new(map->canvas, CANVAS_GROUP_WAYS_HL, points, 0, 0,
359                                        map->style->highlight.color);
360            else
361              item = canvas_polyline_new(map->canvas, CANVAS_GROUP_WAYS_HL, points,
362                                  (way->draw.flags & OSM_DRAW_FLAG_BG)?
363                                  2*map->style->highlight.width + way->draw.bg.width:
364                                  2*map->style->highlight.width + way->draw.width,
365                                  map->style->highlight.color);
366    
367            canvas_points_free(points);
368          } } break;
369    
370        default:
371          break;
372        }
373    
374        /* attach item to item chain */
375        if(item) {
376          *hl = g_new0(map_highlight_t, 1);
377          (*hl)->item = item;
378          hl = &(*hl)->next;
379        }
380    
381        member = member->next;
382      }
383    }
384    
385    static void map_object_select(appdata_t *appdata, object_t *object) {
386      switch(object->type) {
387      case NODE:
388        map_node_select(appdata, object->node);
389        break;
390      case WAY:
391        map_way_select(appdata, object->way);
392      break;      break;
393    case MAP_TYPE_WAY:    case RELATION:
394      map_way_select(appdata, map_item->way);      map_relation_select(appdata, object->relation);
395      break;      break;
396    default:    default:
397      g_assert((map_item->type == MAP_TYPE_NODE)||      g_assert((object->type == NODE)||(object->type == RELATION)||
398               (map_item->type == MAP_TYPE_WAY));               (object->type == WAY));
399      break;      break;
400    }    }
401  }  }
# Line 308  static void map_item_select(appdata_t *a Line 403  static void map_item_select(appdata_t *a
403  void map_item_deselect(appdata_t *appdata) {  void map_item_deselect(appdata_t *appdata) {
404    
405    /* save tags for "last" function in info dialog */    /* save tags for "last" function in info dialog */
406    if(appdata->map->selected.type == MAP_TYPE_NODE) {    if(appdata->map->selected.object.type == NODE) {
407      if(appdata->map->last_node_tags)      if(appdata->map->last_node_tags)
408        osm_tags_free(appdata->map->last_node_tags);        osm_tags_free(appdata->map->last_node_tags);
409    
410      appdata->map->last_node_tags =      appdata->map->last_node_tags =
411        osm_tags_copy(appdata->map->selected.node->tag, FALSE);        osm_tags_copy(appdata->map->selected.object.node->tag, FALSE);
412    } else if(appdata->map->selected.type == MAP_TYPE_WAY) {    } else if(appdata->map->selected.object.type == WAY) {
413      if(appdata->map->last_way_tags)      if(appdata->map->last_way_tags)
414        osm_tags_free(appdata->map->last_way_tags);        osm_tags_free(appdata->map->last_way_tags);
415    
416      appdata->map->last_way_tags =      appdata->map->last_way_tags =
417        osm_tags_copy(appdata->map->selected.way->tag, FALSE);        osm_tags_copy(appdata->map->selected.object.way->tag, FALSE);
418    }    }
419    
420    /* remove statusbar message */    /* remove statusbar message */
# Line 333  void map_item_deselect(appdata_t *appdat Line 428  void map_item_deselect(appdata_t *appdat
428    map_hl_remove(appdata);    map_hl_remove(appdata);
429    
430    /* forget about selection */    /* forget about selection */
431    appdata->map->selected.type = MAP_TYPE_ILLEGAL;    appdata->map->selected.object.type = ILLEGAL;
432  }  }
433    
434  /* called whenever a map item is to be destroyed */  /* called whenever a map item is to be destroyed */
# Line 345  static gint map_item_destroy_event(GtkWi Line 440  static gint map_item_destroy_event(GtkWi
440  #ifdef DESTROY_WAIT_FOR_GTK  #ifdef DESTROY_WAIT_FOR_GTK
441    /* remove item from nodes/ways map_item_chain */    /* remove item from nodes/ways map_item_chain */
442    map_item_chain_t **chain = NULL;    map_item_chain_t **chain = NULL;
443    if(map_item->type == MAP_TYPE_NODE)    if(map_item->object.type == NODE)
444      chain = &map_item->node->map_item_chain;      chain = &map_item->object.node->map_item_chain;
445    else if(map_item->type == MAP_TYPE_WAY)    else if(map_item->object.type == WAY)
446      chain = &map_item->way->map_item_chain;      chain = &map_item->object.way->map_item_chain;
447    
448    /* there must be a chain with content, otherwise things are broken */    /* there must be a chain with content, otherwise things are broken */
449    g_assert(chain);    g_assert(chain);
# Line 375  static canvas_item_t *map_node_new(map_t Line 470  static canvas_item_t *map_node_new(map_t
470                     gint width, canvas_color_t fill, canvas_color_t border) {                     gint width, canvas_color_t fill, canvas_color_t border) {
471    
472    map_item_t *map_item = g_new0(map_item_t, 1);    map_item_t *map_item = g_new0(map_item_t, 1);
473    map_item->type = MAP_TYPE_NODE;    map_item->object.type = NODE;
474    map_item->node = node;    map_item->object.node = node;
475    
476    if(!node->icon_buf || !map->style->icon.enable ||    if(!node->icon_buf || !map->style->icon.enable ||
477       map->appdata->settings->no_icons)       map->appdata->settings->no_icons)
# Line 385  static canvas_item_t *map_node_new(map_t Line 480  static canvas_item_t *map_node_new(map_t
480    else    else
481      map_item->item = canvas_image_new(map->canvas, CANVAS_GROUP_NODES,      map_item->item = canvas_image_new(map->canvas, CANVAS_GROUP_NODES,
482        node->icon_buf,        node->icon_buf,
483        node->lpos.x - map->style->icon.scale/2 *        node->lpos.x - map->style->icon.scale/2 * map->state->detail *
484                        gdk_pixbuf_get_width(node->icon_buf),                        gdk_pixbuf_get_width(node->icon_buf),
485        node->lpos.y - map->style->icon.scale/2 *        node->lpos.y - map->style->icon.scale/2 * map->state->detail *
486                        gdk_pixbuf_get_height(node->icon_buf),                        gdk_pixbuf_get_height(node->icon_buf),
487                map->style->icon.scale,map->style->icon.scale);                        map->state->detail * map->style->icon.scale,
488                          map->state->detail * map->style->icon.scale);
489    
490    canvas_item_set_zoom_max(map_item->item, node->zoom_max);    canvas_item_set_zoom_max(map_item->item,
491                               node->zoom_max / (2 * map->state->detail));
492    
493    /* attach map_item to nodes map_item_chain */    /* attach map_item to nodes map_item_chain */
494    map_item_chain_t **chain = &node->map_item_chain;    map_item_chain_t **chain = &node->map_item_chain;
# Line 413  static canvas_item_t *map_way_single_new Line 510  static canvas_item_t *map_way_single_new
510                     gint width, canvas_color_t fill, canvas_color_t border) {                     gint width, canvas_color_t fill, canvas_color_t border) {
511    
512    map_item_t *map_item = g_new0(map_item_t, 1);    map_item_t *map_item = g_new0(map_item_t, 1);
513    map_item->type = MAP_TYPE_WAY;    map_item->object.type = WAY;
514    map_item->way = way;    map_item->object.way = way;
515    map_item->item = canvas_circle_new(map->canvas, CANVAS_GROUP_WAYS,    map_item->item = canvas_circle_new(map->canvas, CANVAS_GROUP_WAYS,
516            way->node_chain->node->lpos.x, way->node_chain->node->lpos.y,            way->node_chain->node->lpos.x, way->node_chain->node->lpos.y,
517                                       radius, width, fill, border);                                       radius, width, fill, border);
# Line 439  static canvas_item_t *map_way_new(map_t Line 536  static canvas_item_t *map_way_new(map_t
536            way_t *way, canvas_points_t *points, gint width,            way_t *way, canvas_points_t *points, gint width,
537            canvas_color_t color, canvas_color_t fill_color) {            canvas_color_t color, canvas_color_t fill_color) {
538    map_item_t *map_item = g_new0(map_item_t, 1);    map_item_t *map_item = g_new0(map_item_t, 1);
539    map_item->type = MAP_TYPE_WAY;    map_item->object.type = WAY;
540    map_item->way = way;    map_item->object.way = way;
541    
542    if(way->draw.flags & OSM_DRAW_FLAG_AREA) {    if(way->draw.flags & OSM_DRAW_FLAG_AREA) {
543      if(map->style->area.color & 0xff)      if(map->style->area.color & 0xff)
# Line 453  static canvas_item_t *map_way_new(map_t Line 550  static canvas_item_t *map_way_new(map_t
550      map_item->item = canvas_polyline_new(map->canvas, group, points, width, color);      map_item->item = canvas_polyline_new(map->canvas, group, points, width, color);
551    }    }
552    
553    canvas_item_set_zoom_max(map_item->item, way->draw.zoom_max);    canvas_item_set_zoom_max(map_item->item,
554                               way->draw.zoom_max / (2 * map->state->detail));
555    
556      /* a ways outline itself is never dashed */
557    if (group != CANVAS_GROUP_WAYS_OL)    if (group != CANVAS_GROUP_WAYS_OL)
558      if (way->draw.dashed)      if (way->draw.dashed)
559        canvas_item_set_dashed(map_item->item, width, way->draw.dash_length);        canvas_item_set_dashed(map_item->item, width, way->draw.dash_length);
# Line 502  void map_way_draw(map_t *map, way_t *way Line 601  void map_way_draw(map_t *map, way_t *way
601      }      }
602    
603      /* draw way */      /* draw way */
604        float width = way->draw.width * map->state->detail;
605    
606      if(way->draw.flags & OSM_DRAW_FLAG_AREA) {      if(way->draw.flags & OSM_DRAW_FLAG_AREA) {
607        map_way_new(map, CANVAS_GROUP_POLYGONS, way, points,        map_way_new(map, CANVAS_GROUP_POLYGONS, way, points,
608                    way->draw.width, way->draw.color, way->draw.area.color);                    width, way->draw.color, way->draw.area.color);
609      } else {      } else {
610        map_way_new(map, CANVAS_GROUP_WAYS, way, points,  
611                    way->draw.width, way->draw.color, NO_COLOR);        if(way->draw.flags & OSM_DRAW_FLAG_BG) {
612            map_way_new(map, CANVAS_GROUP_WAYS_INT, way, points,
613        if(way->draw.flags & OSM_DRAW_FLAG_BG)                      width, way->draw.color, NO_COLOR);
614    
615          map_way_new(map, CANVAS_GROUP_WAYS_OL, way, points,          map_way_new(map, CANVAS_GROUP_WAYS_OL, way, points,
616                      way->draw.bg.width, way->draw.bg.color, NO_COLOR);                      way->draw.bg.width * map->state->detail,
617                        way->draw.bg.color, NO_COLOR);
618    
619          } else
620            map_way_new(map, CANVAS_GROUP_WAYS, way, points,
621                        width, way->draw.color, NO_COLOR);
622      }      }
623      canvas_points_free(points);      canvas_points_free(points);
624    }    }
# Line 524  void map_node_draw(map_t *map, node_t *n Line 631  void map_node_draw(map_t *map, node_t *n
631    
632    if(!node->ways)    if(!node->ways)
633      map_node_new(map, node,      map_node_new(map, node,
634                   map->style->node.radius,                   map->style->node.radius * map->state->detail,
635                   map->style->node.border_radius,                   map->style->node.border_radius * map->state->detail,
636                   map->style->node.fill_color,                   map->style->node.fill_color,
637                   map->style->node.color);                   map->style->node.color);
638    
639    else if(map->style->node.show_untagged || osm_node_has_tag(node))    else if(map->style->node.show_untagged || osm_node_has_tag(node))
640      map_node_new(map, node,      map_node_new(map, node,
641                   map->style->node.radius, 0,                   map->style->node.radius * map->state->detail, 0,
642                   map->style->node.color, 0);                   map->style->node.color, 0);
643  }  }
644    
645  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) {
646    switch(map_item->type) {    switch(map_item->object.type) {
647    case MAP_TYPE_NODE:    case NODE:
648      map_node_draw(map, map_item->node);      map_node_draw(map, map_item->object.node);
649      break;      break;
650    case MAP_TYPE_WAY:    case WAY:
651      map_way_draw(map, map_item->way);      map_way_draw(map, map_item->object.way);
652      break;      break;
653    default:    default:
654      g_assert((map_item->type == MAP_TYPE_NODE) ||      g_assert((map_item->object.type == NODE) ||
655               (map_item->type == MAP_TYPE_WAY));               (map_item->object.type == WAY));
656    }    }
657  }  }
658    
659  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) {
660    map_item_chain_t **chainP = NULL;    map_item_chain_t **chainP = NULL;
661    
662    switch(map_item->type) {    switch(map_item->object.type) {
663    case MAP_TYPE_NODE:    case NODE:
664      chainP = &map_item->node->map_item_chain;      chainP = &map_item->object.node->map_item_chain;
665      break;      break;
666    case MAP_TYPE_WAY:    case WAY:
667      chainP = &map_item->way->map_item_chain;      chainP = &map_item->object.way->map_item_chain;
668      break;      break;
669    default:    default:
670      g_assert((map_item->type == MAP_TYPE_NODE) ||      g_assert((map_item->object.type == NODE) ||
671               (map_item->type == MAP_TYPE_WAY));               (map_item->object.type == WAY));
672    }    }
673    
674    map_item_chain_destroy(chainP);    map_item_chain_destroy(chainP);
675  }  }
676    
677  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) {
678    switch (map_item->type){    switch (map_item->object.type){
679      case MAP_TYPE_WAY:      case WAY:
680        josm_elemstyles_colorize_way(style, map_item->way);        josm_elemstyles_colorize_way(style, map_item->object.way);
681        break;        break;
682      case MAP_TYPE_NODE:      case NODE:
683        josm_elemstyles_colorize_node(style, map_item->node);        josm_elemstyles_colorize_node(style, map_item->object.node);
684        break;        break;
685      default:      default:
686        g_assert((map_item->type == MAP_TYPE_NODE) ||        g_assert((map_item->object.type == NODE) ||
687                     (map_item->type == MAP_TYPE_WAY));                     (map_item->object.type == WAY));
688    }    }
689  }  }
690    
691  void map_item_redraw(appdata_t *appdata, map_item_t *map_item) {  void map_item_redraw(appdata_t *appdata, map_item_t *map_item) {
692    map_item_t item = *map_item;    map_item_t item = *map_item;
693    
694      /* a relation cannot be redraws as it doesn't have a visual */
695      /* representation */
696      if(map_item->object.type == RELATION)
697        return;
698    
699    /* check if the item to be redrawn is the selected one */    /* check if the item to be redrawn is the selected one */
700    gboolean is_selected = FALSE;    gboolean is_selected = FALSE;
701    if(map_item->ptr == appdata->map->selected.ptr) {    if(map_item->object.ptr == appdata->map->selected.object.ptr) {
702      map_item_deselect(appdata);      map_item_deselect(appdata);
703      is_selected = TRUE;      is_selected = TRUE;
704    }    }
# Line 597  void map_item_redraw(appdata_t *appdata, Line 709  void map_item_redraw(appdata_t *appdata,
709    
710    /* restore selection if there was one */    /* restore selection if there was one */
711    if(is_selected)    if(is_selected)
712      map_item_select(appdata, &item);      map_object_select(appdata, &item.object);
713  }  }
714    
715  static void map_frisket_rectangle(canvas_points_t *points,  static void map_frisket_rectangle(canvas_points_t *points,
# Line 787  map_item_t *map_item_at(map_t *map, gint Line 899  map_item_t *map_item_at(map_t *map, gint
899    if(map_item->highlight)    if(map_item->highlight)
900      printf("  item is highlight\n");      printf("  item is highlight\n");
901    
902    switch(map_item->type) {    switch(map_item->object.type) {
903    case MAP_TYPE_NODE:    case NODE:
904      printf("  item is node #%ld\n", map_item->node->id);      printf("  item is node #"ITEM_ID_FORMAT"\n", map_item->object.node->id);
905      break;      break;
906    case MAP_TYPE_WAY:    case WAY:
907      printf("  item is way #%ld\n", map_item->way->id);      printf("  item is way #"ITEM_ID_FORMAT"\n", map_item->object.way->id);
908      break;      break;
909    default:    default:
910      printf("  unknown item\n");      printf("  unknown item\n");
# Line 811  map_item_t *map_real_item_at(map_t *map, Line 923  map_item_t *map_real_item_at(map_t *map,
923    
924    /* get the item (parent) this item is the highlight of */    /* get the item (parent) this item is the highlight of */
925    map_item_t *parent = NULL;    map_item_t *parent = NULL;
926    switch(map_item->type) {    switch(map_item->object.type) {
927    
928    case MAP_TYPE_NODE:    case NODE:
929      if(map_item->node->map_item_chain)      if(map_item->object.node->map_item_chain)
930        parent = map_item->node->map_item_chain->map_item;        parent = map_item->object.node->map_item_chain->map_item;
931    
932      if(parent)      if(parent)
933        printf("  using parent item node #%ld\n", parent->node->id);        printf("  using parent item node #" ITEM_ID_FORMAT "\n",
934                 parent->object.node->id);
935      break;      break;
936    
937    case MAP_TYPE_WAY:    case WAY:
938      if(map_item->way->map_item_chain)      if(map_item->object.way->map_item_chain)
939        parent = map_item->way->map_item_chain->map_item;        parent = map_item->object.way->map_item_chain->map_item;
940    
941      if(parent)      if(parent)
942        printf("  using parent item way #%ld\n", parent->way->id);        printf("  using parent item way #" ITEM_ID_FORMAT "\n",
943                 parent->object.way->id);
944      break;      break;
945    
946    default:    default:
947      g_assert((map_item->type == MAP_TYPE_NODE) ||      g_assert((map_item->object.type == NODE) ||
948               (map_item->type == MAP_TYPE_WAY));               (map_item->object.type == WAY));
949      break;      break;
950    }    }
951    
# Line 988  void map_scroll_to_if_offscreen(map_t *m Line 1102  void map_scroll_to_if_offscreen(map_t *m
1102  /* Deselects the current way or node if its zoom_max  /* Deselects the current way or node if its zoom_max
1103   * 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. */
1104  void map_deselect_if_zoom_below_zoom_max(map_t *map) {  void map_deselect_if_zoom_below_zoom_max(map_t *map) {
1105      if (map->selected.type == MAP_TYPE_WAY) {      if (map->selected.object.type == WAY) {
1106          printf("will deselect way if zoomed below %f\n",          printf("will deselect way if zoomed below %f\n",
1107                 map->selected.way->draw.zoom_max);                 map->selected.object.way->draw.zoom_max);
1108          if (map->state->zoom < map->selected.way->draw.zoom_max) {          if (map->state->zoom < map->selected.object.way->draw.zoom_max) {
1109              printf("  deselecting way!\n");              printf("  deselecting way!\n");
1110              map_item_deselect(map->appdata);              map_item_deselect(map->appdata);
1111          }          }
1112      }      }
1113      else if (map->selected.type == MAP_TYPE_NODE) {      else if (map->selected.object.type == NODE) {
1114          printf("will deselect node if zoomed below %f\n",          printf("will deselect node if zoomed below %f\n",
1115                 map->selected.node->zoom_max);                 map->selected.object.node->zoom_max);
1116          if (map->state->zoom < map->selected.node->zoom_max) {          if (map->state->zoom < map->selected.object.node->zoom_max) {
1117              printf("  deselecting node!\n");              printf("  deselecting node!\n");
1118              map_item_deselect(map->appdata);              map_item_deselect(map->appdata);
1119          }          }
# Line 1099  gboolean map_item_is_selected_node(map_t Line 1213  gboolean map_item_is_selected_node(map_t
1213      return FALSE;      return FALSE;
1214    }    }
1215    
1216    if(map->selected.type == MAP_TYPE_ILLEGAL) {    if(map->selected.object.type == ILLEGAL) {
1217      printf("  nothing is selected\n");      printf("  nothing is selected\n");
1218      return FALSE;      return FALSE;
1219    }    }
1220    
1221    /* clicked the highlight directly */    /* clicked the highlight directly */
1222    if(map_item->type != MAP_TYPE_NODE) {    if(map_item->object.type != NODE) {
1223      printf("  didn't click node\n");      printf("  didn't click node\n");
1224      return FALSE;      return FALSE;
1225    }    }
1226    
1227    if(map->selected.type == MAP_TYPE_NODE) {    if(map->selected.object.type == NODE) {
1228      printf("  selected item is a node\n");      printf("  selected item is a node\n");
1229    
1230      if(map_item->node == map->selected.node) {      if(map_item->object.node == map->selected.object.node) {
1231        printf("  requested item is a selected node\n");        printf("  requested item is a selected node\n");
1232        return TRUE;        return TRUE;
1233      }      }
1234      printf("  but it's not the requested one\n");      printf("  but it's not the requested one\n");
1235      return FALSE;      return FALSE;
1236    
1237    } else if(map->selected.type == MAP_TYPE_WAY) {    } else if(map->selected.object.type == WAY) {
1238      printf("  selected item is a way\n");      printf("  selected item is a way\n");
1239    
1240      node_chain_t *node_chain = map->selected.way->node_chain;      node_chain_t *node_chain = map->selected.object.way->node_chain;
1241      while(node_chain) {      while(node_chain) {
1242        if(node_chain->node == map_item->node) {        if(node_chain->node == map_item->object.node) {
1243          printf("  requested item is part of selected way\n");          printf("  requested item is part of selected way\n");
1244          return TRUE;          return TRUE;
1245        }        }
# Line 1153  gboolean map_item_is_selected_way(map_t Line 1267  gboolean map_item_is_selected_way(map_t
1267      return FALSE;      return FALSE;
1268    }    }
1269    
1270    if(map->selected.type == MAP_TYPE_ILLEGAL) {    if(map->selected.object.type == ILLEGAL) {
1271      printf("  nothing is selected\n");      printf("  nothing is selected\n");
1272      return FALSE;      return FALSE;
1273    }    }
1274    
1275    /* clicked the highlight directly */    /* clicked the highlight directly */
1276    if(map_item->type != MAP_TYPE_WAY) {    if(map_item->object.type != WAY) {
1277      printf("  didn't click way\n");      printf("  didn't click way\n");
1278      return FALSE;      return FALSE;
1279    }    }
1280    
1281    if(map->selected.type == MAP_TYPE_WAY) {    if(map->selected.object.type == WAY) {
1282      printf("  selected item is a way\n");      printf("  selected item is a way\n");
1283    
1284      if(map_item->way == map->selected.way) {      if(map_item->object.way == map->selected.object.way) {
1285        printf("  requested item is a selected way\n");        printf("  requested item is a selected way\n");
1286        return TRUE;        return TRUE;
1287      }      }
# Line 1182  gboolean map_item_is_selected_way(map_t Line 1296  gboolean map_item_is_selected_way(map_t
1296    
1297  void map_highlight_refresh(appdata_t *appdata) {  void map_highlight_refresh(appdata_t *appdata) {
1298    map_t *map = appdata->map;    map_t *map = appdata->map;
1299    map_item_t old = map->selected;    object_t old = map->selected.object;
1300    
1301    printf("type to refresh is %d\n", old.type);    printf("type to refresh is %d\n", old.type);
1302    if(old.type == MAP_TYPE_ILLEGAL)    if(old.type == ILLEGAL)
1303      return;      return;
1304    
1305    map_item_deselect(appdata);    map_item_deselect(appdata);
1306    map_item_select(appdata, &old);    map_object_select(appdata, &old);
1307  }  }
1308    
1309  void map_way_delete(appdata_t *appdata, way_t *way) {  void map_way_delete(appdata_t *appdata, way_t *way) {
1310    printf("deleting way #%ld from map and osm\n", way->id);    printf("deleting way #" ITEM_ID_FORMAT " from map and osm\n", way->id);
1311    
1312    /* remove it visually from the screen */    /* remove it visually from the screen */
1313    map_item_chain_destroy(&way->map_item_chain);    map_item_chain_destroy(&way->map_item_chain);
# Line 1217  static void map_handle_click(appdata_t * Line 1331  static void map_handle_click(appdata_t *
1331    /* problem: on_item may be the highlight itself! So store it! */    /* problem: on_item may be the highlight itself! So store it! */
1332    map_item_t map_item;    map_item_t map_item;
1333    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;
1334    else                      map_item.type = MAP_TYPE_ILLEGAL;    else                      map_item.object.type = ILLEGAL;
1335    
1336    /* if we aready have something selected, then de-select it */    /* if we aready have something selected, then de-select it */
1337    map_item_deselect(appdata);    map_item_deselect(appdata);
1338    
1339    /* select the clicked item (if there was one) */    /* select the clicked item (if there was one) */
1340    if(map_item.type != MAP_TYPE_ILLEGAL) {    if(map_item.object.type != ILLEGAL) {
1341      switch(map_item.type) {      switch(map_item.object.type) {
1342      case MAP_TYPE_NODE:      case NODE:
1343        map_node_select(appdata, map_item.node);        map_node_select(appdata, map_item.object.node);
1344        break;        break;
1345    
1346      case MAP_TYPE_WAY:      case WAY:
1347        map_way_select(appdata, map_item.way);        map_way_select(appdata, map_item.object.way);
1348        break;        break;
1349    
1350      default:      default:
1351        g_assert((map_item.type == MAP_TYPE_NODE) ||        g_assert((map_item.object.type == NODE) ||
1352                 (map_item.type == MAP_TYPE_WAY));                 (map_item.object.type == WAY));
1353        break;        break;
1354      }      }
1355    }    }
# Line 1255  static void map_touchnode_update(appdata Line 1369  static void map_touchnode_update(appdata
1369      /* in idle mode the dragged node is not highlighted */      /* in idle mode the dragged node is not highlighted */
1370    case MAP_ACTION_IDLE:    case MAP_ACTION_IDLE:
1371      g_assert(map->pen_down.on_item);      g_assert(map->pen_down.on_item);
1372      g_assert(map->pen_down.on_item->type == MAP_TYPE_NODE);      g_assert(map->pen_down.on_item->object.type == NODE);
1373      cur_node = map->pen_down.on_item->node;      cur_node = map->pen_down.on_item->object.node;
1374      break;      break;
1375    
1376    default:    default:
# Line 1271  static void map_touchnode_update(appdata Line 1385  static void map_touchnode_update(appdata
1385      /* don't highlight the dragged node itself and don't highlight */      /* don't highlight the dragged node itself and don't highlight */
1386      /* deleted ones */      /* deleted ones */
1387      if((node != cur_node) && (!(node->flags & OSM_FLAG_DELETED))) {      if((node != cur_node) && (!(node->flags & OSM_FLAG_DELETED))) {
1388        gint nx = x - node->lpos.x;        gint nx = abs(x - node->lpos.x);
1389        gint ny = y - node->lpos.y;        gint ny = abs(y - node->lpos.y);
1390    
1391        if((nx < map->style->node.radius) && (ny < map->style->node.radius) &&        if((nx < map->style->node.radius) && (ny < map->style->node.radius) &&
1392           (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 1286  static void map_touchnode_update(appdata Line 1400  static void map_touchnode_update(appdata
1400    if(!map->touchnode && map->action.way) {    if(!map->touchnode && map->action.way) {
1401      node_chain_t *chain = map->action.way->node_chain;      node_chain_t *chain = map->action.way->node_chain;
1402      while(!map->touchnode && chain && chain->next) {      while(!map->touchnode && chain && chain->next) {
1403        gint nx = x - chain->node->lpos.x;        gint nx = abs(x - chain->node->lpos.x);
1404        gint ny = y - chain->node->lpos.y;        gint ny = abs(y - chain->node->lpos.y);
1405    
1406        if((nx < map->style->node.radius) && (ny < map->style->node.radius) &&        if((nx < map->style->node.radius) && (ny < map->style->node.radius) &&
1407           (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 1379  static void map_button_release(map_t *ma Line 1493  static void map_button_release(map_t *ma
1493        map_item_t old_sel = map->selected;        map_item_t old_sel = map->selected;
1494        map_handle_click(map->appdata, map);        map_handle_click(map->appdata, map);
1495    
1496        if((old_sel.type != MAP_TYPE_ILLEGAL) &&        if((old_sel.object.type != ILLEGAL) &&
1497           (old_sel.type == map->selected.type) &&           (old_sel.object.type == map->selected.object.type) &&
1498           (old_sel.ptr == map->selected.ptr)) {           (old_sel.object.ptr == map->selected.object.ptr)) {
1499          printf("re-selected same item of type %d, "          printf("re-selected same item of type %d, "
1500                 "pushing it to the bottom\n", old_sel.type);                 "pushing it to the bottom\n", old_sel.object.type);
1501    
1502          if(!map->selected.item) {          if(!map->selected.item) {
1503            printf("  item has no visible representation to push\n");            printf("  item has no visible representation to push\n");
# Line 1645  gboolean map_key_press_event(appdata_t * Line 1759  gboolean map_key_press_event(appdata_t *
1759    return FALSE;    return FALSE;
1760  }  }
1761    
1762    void map_state_reset(map_state_t *state) {
1763      if(!state) return;
1764    
1765      state->zoom = 0.25;
1766      state->detail = 1.0;
1767    
1768      /* todo: try to scroll to center of screen */
1769      state->scroll_offset.x = 0;
1770      state->scroll_offset.y = 0;
1771    }
1772    
1773    map_state_t *map_state_new(void) {
1774      map_state_t *state = g_new0(map_state_t, 1);
1775      map_state_reset(state);
1776      return state;
1777    }
1778    
1779  GtkWidget *map_new(appdata_t *appdata) {  GtkWidget *map_new(appdata_t *appdata) {
1780    map_t *map = appdata->map = g_new0(map_t, 1);    map_t *map = appdata->map = g_new0(map_t, 1);
1781    
# Line 1660  GtkWidget *map_new(appdata_t *appdata) { Line 1791  GtkWidget *map_new(appdata_t *appdata) {
1791      map->state = appdata->project->map_state;      map->state = appdata->project->map_state;
1792    } else {    } else {
1793      printf("Creating new map state\n");      printf("Creating new map state\n");
1794      map->state = g_new0(map_state_t, 1);      map->state = map_state_new();
     map->state->zoom = 0.25;  
1795    }    }
1796    
1797    map->state->refcount++;    map->state->refcount++;
# Line 1671  GtkWidget *map_new(appdata_t *appdata) { Line 1801  GtkWidget *map_new(appdata_t *appdata) {
1801    map->appdata = appdata;    map->appdata = appdata;
1802    map->action.type = MAP_ACTION_IDLE;    map->action.type = MAP_ACTION_IDLE;
1803    
1804    map->canvas = canvas_new(map->style->background.color);    map->canvas = canvas_new();
   canvas_set_antialias(map->canvas, !appdata->settings->no_antialias);  
1805    
1806    GtkWidget *canvas_widget = canvas_get_widget(map->canvas);    GtkWidget *canvas_widget = canvas_get_widget(map->canvas);
1807    
# Line 1701  GtkWidget *map_new(appdata_t *appdata) { Line 1830  GtkWidget *map_new(appdata_t *appdata) {
1830  void map_init(appdata_t *appdata) {  void map_init(appdata_t *appdata) {
1831    map_t *map = appdata->map;    map_t *map = appdata->map;
1832    
1833      /* update canvas background color */
1834      canvas_set_background(map->canvas, map->style->background.color);
1835    
1836    /* set initial zoom */    /* set initial zoom */
1837    map_set_zoom(map, map->state->zoom, FALSE);    map_set_zoom(map, map->state->zoom, FALSE);
1838    josm_elemstyles_colorize_world(map->style, appdata->osm);    josm_elemstyles_colorize_world(map->style, appdata->osm);
# Line 1724  void map_init(appdata_t *appdata) { Line 1856  void map_init(appdata_t *appdata) {
1856  }  }
1857    
1858    
 void map_item_set_flags(map_item_t *map_item, int set, int clr) {  
   
   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;  
   }  
 }  
   
1859  void map_clear(appdata_t *appdata, gint group_mask) {  void map_clear(appdata_t *appdata, gint group_mask) {
1860    map_t *map = appdata->map;    map_t *map = appdata->map;
1861    
# Line 1759  void map_clear(appdata_t *appdata, gint Line 1872  void map_clear(appdata_t *appdata, gint
1872  void map_paint(appdata_t *appdata) {  void map_paint(appdata_t *appdata) {
1873    map_t *map = appdata->map;    map_t *map = appdata->map;
1874    
   /* user may have changed antialias settings */  
   canvas_set_antialias(map->canvas, !appdata->settings->no_antialias);  
   
1875    josm_elemstyles_colorize_world(map->style, appdata->osm);    josm_elemstyles_colorize_world(map->style, appdata->osm);
1876    map_draw(map, appdata->osm);    map_draw(map, appdata->osm);
1877  }  }
# Line 1793  void map_action_set(appdata_t *appdata, Line 1903  void map_action_set(appdata_t *appdata,
1903    
1904      /* remember if there was a way selected */      /* remember if there was a way selected */
1905      way_t *way_sel = NULL;      way_t *way_sel = NULL;
1906      if(appdata->map->selected.type == MAP_TYPE_WAY)      if(appdata->map->selected.object.type == WAY)
1907        way_sel = appdata->map->selected.way;        way_sel = appdata->map->selected.object.way;
1908    
1909      map_item_deselect(appdata);      map_item_deselect(appdata);
1910      map_edit_way_add_begin(appdata->map, way_sel);      map_edit_way_add_begin(appdata->map, way_sel);
# Line 1869  void map_action_ok(appdata_t *appdata) { Line 1979  void map_action_ok(appdata_t *appdata) {
1979      /* save changes to bg_offset in project */      /* save changes to bg_offset in project */
1980      appdata->project->wms_offset.x = map->bg.offset.x;      appdata->project->wms_offset.x = map->bg.offset.x;
1981      appdata->project->wms_offset.y = map->bg.offset.y;      appdata->project->wms_offset.y = map->bg.offset.y;
     appdata->project->dirty = TRUE;  
1982      break;      break;
1983    
1984    default:    default:
# Line 1893  void map_delete_selected(appdata_t *appd Line 2002  void map_delete_selected(appdata_t *appd
2002    /* deleting the selected item de-selects it ... */    /* deleting the selected item de-selects it ... */
2003    map_item_deselect(appdata);    map_item_deselect(appdata);
2004    
2005    undo_remember_delete(appdata, item.type, item.ptr);    undo_remember_delete(appdata, &item.object);
2006    
2007    switch(item.type) {    switch(item.object.type) {
2008    case MAP_TYPE_NODE:    case NODE:
2009      printf("request to delete node #%ld\n", item.node->id);      printf("request to delete node #" ITEM_ID_FORMAT "\n",
2010               item.object.node->id);
2011    
2012      /* 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. */
2013      /* we cannot delete this as this would also delete the way */      /* we cannot delete this as this would also delete the way */
2014      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);
2015      if(way_chain) {      if(way_chain) {
2016        gboolean short_way = FALSE;        gboolean short_way = FALSE;
2017    
# Line 1927  void map_delete_selected(appdata_t *appd Line 2037  void map_delete_selected(appdata_t *appd
2037      }      }
2038    
2039      /* remove it visually from the screen */      /* remove it visually from the screen */
2040      map_item_chain_destroy(&item.node->map_item_chain);      map_item_chain_destroy(&item.object.node->map_item_chain);
2041    
2042      /* and mark it "deleted" in the database */      /* and mark it "deleted" in the database */
2043      osm_node_remove_from_relation(appdata->osm, item.node);      osm_node_remove_from_relation(appdata->osm, item.object.node);
2044      way_chain_t *chain = osm_node_delete(appdata->osm,      way_chain_t *chain = osm_node_delete(appdata->osm,
2045                           &appdata->icon, item.node, FALSE, TRUE);                           &appdata->icon, item.object.node, FALSE, TRUE);
2046    
2047      /* redraw all affected ways */      /* redraw all affected ways */
2048      while(chain) {      while(chain) {
# Line 1945  void map_delete_selected(appdata_t *appd Line 2055  void map_delete_selected(appdata_t *appd
2055          map_way_delete(appdata, chain->way);          map_way_delete(appdata, chain->way);
2056        } else {        } else {
2057          map_item_t item;          map_item_t item;
2058          item.type = MAP_TYPE_WAY;          item.object.type = WAY;
2059          item.way = chain->way;          item.object.way = chain->way;
2060          map_item_redraw(appdata, &item);          map_item_redraw(appdata, &item);
2061        }        }
2062    
# Line 1957  void map_delete_selected(appdata_t *appd Line 2067  void map_delete_selected(appdata_t *appd
2067    
2068      break;      break;
2069    
2070    case MAP_TYPE_WAY:    case WAY:
2071      printf("request to delete way #%ld\n", item.way->id);      printf("request to delete way #" ITEM_ID_FORMAT "\n", item.object.way->id);
2072      map_way_delete(appdata, item.way);      map_way_delete(appdata, item.object.way);
2073      break;      break;
2074    
2075    default:    default:
2076      g_assert((item.type == MAP_TYPE_NODE) ||      g_assert((item.object.type == NODE) ||
2077               (item.type == MAP_TYPE_WAY));               (item.object.type == WAY));
2078      break;      break;
2079    }    }
2080  }  }
2081    
2082  /* ----------------------- track related stuff ----------------------- */  /* ----------------------- track related stuff ----------------------- */
2083    
2084    static gboolean track_pos2lpos(bounds_t *bounds, pos_t *pos, lpos_t *lpos) {
2085      pos2lpos(bounds, pos, lpos);
2086    
2087      /* check if point is within bounds */
2088      return ((lpos->x >= bounds->min.x) && (lpos->x <= bounds->max.x) &&
2089              (lpos->y >= bounds->min.y) && (lpos->y <= bounds->max.y));
2090    }
2091    
2092  void map_track_draw_seg(map_t *map, track_seg_t *seg) {  void map_track_draw_seg(map_t *map, track_seg_t *seg) {
2093      bounds_t *bounds = map->appdata->osm->bounds;
2094    
2095    /* a track_seg needs at least 2 points to be drawn */    /* a track_seg needs at least 2 points to be drawn */
2096    guint pnum = track_seg_points(seg);    guint pnum = track_seg_points(seg);
2097    printf("seg of length %d\n", pnum);    printf("seg of length %d\n", pnum);
2098    
2099    if(pnum == 1) {    if(!pnum)
2100      g_assert(!seg->item);      return;
2101    
2102      seg->item = canvas_circle_new(map->canvas, CANVAS_GROUP_TRACK,    /* nothing should have been drawn by now ... */
2103            seg->track_point->lpos.x, seg->track_point->lpos.y,    g_assert(!seg->item_chain);
2104            map->style->track.width/2.0, 0, map->style->track.color, NO_COLOR);  
2105    }    track_item_chain_t **itemP = &seg->item_chain;
2106      track_point_t *track_point = seg->track_point;
2107      while(track_point) {
2108        lpos_t lpos;
2109    
2110        /* skip all points not on screen */
2111        track_point_t *last = NULL;
2112        while(track_point && !track_pos2lpos(bounds, &track_point->pos, &lpos)) {
2113          last = track_point;
2114          track_point = track_point->next;
2115        }
2116    
2117        int visible = 0;
2118    
2119        /* count nodes that _are_ on screen */
2120        track_point_t *tmp = track_point;
2121        while(tmp && track_pos2lpos(bounds, &tmp->pos, &lpos)) {
2122          tmp = tmp->next;
2123          visible++;
2124        }
2125    
2126        /* actually start drawing with the last position that was offscreen */
2127        /* so the track nicely enters the viewing area */
2128        if(last) {
2129          track_point = last;
2130          visible++;
2131        }
2132    
2133        /* also use last one that's offscreen to nicely leave the visible area */
2134        if(tmp && tmp->next)
2135          visible++;
2136    
   if(pnum > 1) {  
   
2137      /* allocate space for nodes */      /* allocate space for nodes */
2138      canvas_points_t *points = canvas_points_new(pnum);      canvas_points_t *points = canvas_points_new(visible);
2139    
2140      int point = 0;      printf("visible are %d\n", visible);
2141      track_point_t *track_point = seg->track_point;      int point;
2142      while(track_point) {      for(point=0;point<visible;point++) {
2143        points->coords[point++] = track_point->lpos.x;        track_pos2lpos(bounds, &track_point->pos, &lpos);
2144        points->coords[point++] = track_point->lpos.y;  
2145          points->coords[2*point+0] = lpos.x;
2146          points->coords[2*point+1] = lpos.y;
2147        track_point = track_point->next;        track_point = track_point->next;
2148      }      }
   
     /* there may be a circle (one point line) */  
     if(seg->item)  
       canvas_item_destroy(seg->item);  
2149    
2150      seg->item = canvas_polyline_new(map->canvas, CANVAS_GROUP_TRACK,      *itemP = g_new0(track_item_chain_t, 1);
2151            points, map->style->track.width, map->style->track.color);      (*itemP)->item = canvas_polyline_new(map->canvas, CANVAS_GROUP_TRACK,
2152                     points, map->style->track.width, map->style->track.color);
2153        itemP = &(*itemP)->next;
2154    
2155      canvas_points_free(points);      canvas_points_free(points);
2156    }    }
2157  }  }
2158    
2159    /* update the last visible fragment of this segment since a */
2160    /* gps position may have been added */
2161  void map_track_update_seg(map_t *map, track_seg_t *seg) {  void map_track_update_seg(map_t *map, track_seg_t *seg) {
2162      bounds_t *bounds = map->appdata->osm->bounds;
2163    
2164      printf("-- APPENDING TO TRACK --\n");
2165    
2166    /* a track_seg needs at least 2 points to be drawn */    /* a track_seg needs at least 2 points to be drawn */
2167    guint pnum = track_seg_points(seg);    guint pnum = track_seg_points(seg);
2168    printf("seg of length %d\n", pnum);    printf("seg of length %d\n", pnum);
2169    
2170    if(pnum > 1) {    /* there are two cases: either the second last point was on screen */
2171      /* or it wasn't. We'll have to start a new screen item if the latter */
2172      /* is the case */
2173    
2174      /* search last point */
2175      track_point_t *begin = seg->track_point, *second_last = seg->track_point;
2176      lpos_t lpos;
2177      while(second_last && second_last->next && second_last->next->next) {
2178        if(!track_pos2lpos(bounds, &second_last->pos, &lpos))
2179          begin = second_last;
2180    
2181        second_last = second_last->next;
2182      }
2183      track_point_t *last = second_last->next;
2184    
2185      /* since we are updating an existing track, it sure has at least two */
2186      /* points, second_last must be valid and its "next" (last) also */
2187      g_assert(second_last);
2188      g_assert(last);
2189    
2190      /* check if the last and second_last points are visible */
2191      gboolean last_is_visible =
2192        track_pos2lpos(bounds, &last->pos, &lpos);
2193      gboolean second_last_is_visible =
2194        track_pos2lpos(bounds, &second_last->pos, &lpos);
2195    
2196      /* if both are invisible, then nothing has changed on screen */
2197      if(!last_is_visible && !second_last_is_visible) {
2198        printf("second_last and last entry are invisible -> doing nothing\n");
2199        return;
2200      }
2201    
2202      /* search last element in item chain */
2203      track_item_chain_t *item = seg->item_chain;
2204      while(item && item->next)
2205        item = item->next;
2206    
2207      if(second_last_is_visible) {
2208        /* there must be something already on the screen and there must */
2209        /* be visible nodes in the chain */
2210        g_assert(item);
2211        g_assert(begin);
2212    
2213        printf("second_last is visible -> append\n");
2214    
2215      /* allocate space for nodes */      /* count points to be placed */
2216      canvas_points_t *points = canvas_points_new(pnum);      int npoints = 0;
2217        track_point_t *tmp = begin;
2218        while(tmp) {
2219          tmp = tmp->next;
2220          npoints++;
2221        }
2222    
2223        printf("updating last segment to %d points\n", npoints);
2224    
2225        canvas_points_t *points = canvas_points_new(npoints);
2226    
2227        gint point = 0;
2228        while(begin) {
2229          track_pos2lpos(bounds, &begin->pos, &lpos);
2230          canvas_point_set_pos(points, point++, &lpos);
2231          begin = begin->next;
2232        }
2233    
2234      int point = 0;      canvas_item_set_points(item->item, points);
2235      track_point_t *track_point = seg->track_point;      canvas_points_free(points);
2236      while(track_point) {  
2237        canvas_point_set_pos(points, point++, &track_point->lpos);    } else {
2238        track_point = track_point->next;      printf("second last is invisible -> start new screen segment\n");
2239    
2240        /* the search for the "begin" ends with the second_last item */
2241        /* verify the last one also */
2242        if(begin->next && !track_pos2lpos(bounds, &begin->next->pos, &lpos))
2243          begin = begin->next;
2244    
2245        item->next = g_new0(track_item_chain_t, 1);
2246        item = item->next;
2247    
2248        /* count points to be placed */
2249        int npoints = 0;
2250        track_point_t *tmp = begin;
2251        while(tmp) {
2252          tmp = tmp->next;
2253          npoints++;
2254        }
2255    
2256        printf("attaching new segment with %d points\n", npoints);
2257    
2258        canvas_points_t *points = canvas_points_new(npoints);
2259    
2260        gint point = 0;
2261        while(begin) {
2262          track_pos2lpos(bounds, &begin->pos, &lpos);
2263          canvas_point_set_pos(points, point++, &lpos);
2264          begin = begin->next;
2265      }      }
2266    
2267      g_assert(seg->item);      item->item = canvas_polyline_new(map->canvas, CANVAS_GROUP_TRACK,
2268      canvas_item_set_points(seg->item, points);                   points, map->style->track.width, map->style->track.color);
2269    
2270      canvas_points_free(points);      canvas_points_free(points);
2271    }    }
2272    
2273  }  }
2274    
2275  void map_track_draw(map_t *map, track_t *track) {  void map_track_draw(map_t *map, track_t *track) {
# Line 2051  void map_track_remove(appdata_t *appdata Line 2292  void map_track_remove(appdata_t *appdata
2292    /* remove all segments */    /* remove all segments */
2293    track_seg_t *seg = track->track_seg;    track_seg_t *seg = track->track_seg;
2294    while(seg) {    while(seg) {
2295      if(seg->item) {      track_item_chain_t *item = seg->item_chain;
2296        canvas_item_destroy(seg->item);      while(item) {
2297        seg->item = NULL;        track_item_chain_t *next = item->next;
2298          canvas_item_destroy(item->item);
2299          item = next;
2300      }      }
2301    
2302        seg->item_chain = NULL;
2303      seg = seg->next;      seg = seg->next;
2304    }    }
2305  }  }
2306    
2307  void map_track_pos(appdata_t *appdata, lpos_t *lpos) {  void map_track_pos(appdata_t *appdata, pos_t *pos) {
2308    if(appdata->track.gps_item) {    if(appdata->track.gps_item) {
2309      canvas_item_destroy(appdata->track.gps_item);      canvas_item_destroy(appdata->track.gps_item);
2310      appdata->track.gps_item = NULL;      appdata->track.gps_item = NULL;
2311    }    }
2312    
2313    if(lpos)    if(pos) {
2314        lpos_t lpos;
2315        pos2lpos(appdata->osm->bounds, pos, &lpos);
2316    
2317      appdata->track.gps_item =      appdata->track.gps_item =
2318        canvas_circle_new(appdata->map->canvas, CANVAS_GROUP_GPS,        canvas_circle_new(appdata->map->canvas, CANVAS_GROUP_GPS,
2319          lpos->x, lpos->y, appdata->map->style->track.width/2.0, 0,          lpos.x, lpos.y, appdata->map->style->track.width/2.0, 0,
2320                          appdata->map->style->track.gps_color, NO_COLOR);                          appdata->map->style->track.gps_color, NO_COLOR);
2321      }
2322  }  }
2323    
2324  /* ------------------- map background ------------------ */  /* ------------------- map background ------------------ */
# Line 2125  void map_hide_selected(appdata_t *appdat Line 2373  void map_hide_selected(appdata_t *appdat
2373    map_t *map = appdata->map;    map_t *map = appdata->map;
2374    if(!map) return;    if(!map) return;
2375    
2376    if(map->selected.type != MAP_TYPE_WAY) {    if(map->selected.object.type != WAY) {
2377      printf("selected item is not a way\n");      printf("selected item is not a way\n");
2378      return;      return;
2379    }    }
2380    
2381    way_t *way = map->selected.way;    way_t *way = map->selected.object.way;
2382    printf("hiding way #%ld\n", way->id);    printf("hiding way #" ITEM_ID_FORMAT "\n", way->id);
2383    
2384    map_item_deselect(appdata);    map_item_deselect(appdata);
2385    way->flags |= OSM_FLAG_HIDDEN;    way->flags |= OSM_FLAG_HIDDEN;
# Line 2156  void map_show_all(appdata_t *appdata) { Line 2404  void map_show_all(appdata_t *appdata) {
2404    
2405    gtk_widget_set_sensitive(appdata->menu_item_map_show_all, FALSE);    gtk_widget_set_sensitive(appdata->menu_item_map_show_all, FALSE);
2406  }  }
2407    
2408    static void map_detail_change(map_t *map, float detail) {
2409      appdata_t *appdata = map->appdata;
2410    
2411      /* deselecting anything allows us not to care about automatic deselection */
2412      /* as well as items becoming invisible by the detail change */
2413      map_item_deselect(appdata);
2414    
2415      map->state->detail = detail;
2416      printf("changing detail factor to %f\n", map->state->detail);
2417    
2418      banner_busy_start(appdata, 1, _("Redrawing"));
2419      map_clear(appdata, MAP_LAYER_OBJECTS_ONLY);
2420      map_paint(appdata);
2421      banner_busy_stop(appdata);
2422    }
2423    
2424    #define DETAIL_STEP 1.5
2425    
2426    void map_detail_increase(map_t *map) {
2427      if(!map) return;
2428      map_detail_change(map, map->state->detail * DETAIL_STEP);
2429    }
2430    
2431    void map_detail_decrease(map_t *map) {
2432      if(!map) return;
2433      map_detail_change(map, map->state->detail / DETAIL_STEP);
2434    }
2435    
2436    void map_detail_normal(map_t *map) {
2437      if(!map) return;
2438      map_detail_change(map, 1.0);
2439    }
2440    
2441  // vim:et:ts=8:sw=2:sts=2:ai  // vim:et:ts=8:sw=2:sts=2:ai

Legend:
Removed from v.105  
changed lines
  Added in v.194