/** * Navit, a modular navigation system. * Copyright (C) 2005-2009 Navit Team * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include "item.h" #include "attr.h" #include "xmlconfig.h" #include "layout.h" #include "coord.h" #include "debug.h" #include "navit.h" /** * @brief Create a new layout object and attach it to a navit parent * * @param parent The parent for this layout (a navit attr) * @param attrs An array of attributes that for this layout * @return The newly created layout object */ struct layout * layout_new(struct attr *parent, struct attr **attrs) { struct layout *l; struct navit *navit; struct color def_color = {COLOR_BACKGROUND_}; int def_underground_alpha = UNDERGROUND_ALPHA_; struct attr *name_attr,*color_attr,*order_delta_attr,*font_attr,*day_attr,*night_attr,*active_attr, *underground_alpha_attr,*icon_attr; if (! (name_attr=attr_search(attrs, attr_name))) return NULL; navit = parent->u.navit; if (navit_get_layout_by_name(navit, name_attr->u.str)) { dbg(lvl_warning, "Another layout with name '%s' has already been parsed. Discarding subsequent duplicate.", name_attr->u.str); return NULL; } l = g_new0(struct layout, 1); l->func=&layout_func; navit_object_ref((struct navit_object *)l); l->name = g_strdup(name_attr->u.str); if ((font_attr=attr_search(attrs, attr_font))) { l->font = g_strdup(font_attr->u.str); } if ((day_attr=attr_search(attrs, attr_daylayout))) { l->dayname = g_strdup(day_attr->u.str); } if ((night_attr=attr_search(attrs, attr_nightlayout))) { l->nightname = g_strdup(night_attr->u.str); } if ((color_attr=attr_search(attrs, attr_color))) l->color = *color_attr->u.color; else l->color = def_color; if ((underground_alpha_attr=attr_search(attrs, attr_underground_alpha))) { int a = underground_alpha_attr->u.num; /* for convenience, the alpha value is just 8 bit as usual if using * corresponding attr. therefore we need to shift that up */ l->underground_alpha = (a << 8) | a; } else l->underground_alpha = def_underground_alpha; if ((icon_attr=attr_search(attrs, attr_icon_w))) l->icon_w = icon_attr->u.num; else l->icon_w = -1; if ((icon_attr=attr_search(attrs, attr_icon_h))) l->icon_h = icon_attr->u.num; else l->icon_h = -1; if ((order_delta_attr=attr_search(attrs, attr_order_delta))) l->order_delta=order_delta_attr->u.num; if ((active_attr=attr_search(attrs, attr_active))) l->active = active_attr->u.num; l->navit=navit; return l; } struct attr_iter { GList *last; }; struct attr_iter * layout_attr_iter_new(void* unused) { return g_new0(struct attr_iter, 1); } void layout_attr_iter_destroy(struct attr_iter *iter) { g_free(iter); } int layout_get_attr(struct layout *layout, enum attr_type type, struct attr *attr, struct attr_iter *iter) { GList *cursor,*layer; attr->type=type; switch (type) { case attr_name: attr->u.str=layout->name; return 1; case attr_cursor: cursor=layout->cursors; while (cursor) { if (!iter || iter->last == g_list_previous(cursor)) { attr->u.cursor=cursor->data; if (iter) iter->last=cursor; return 1; } cursor=g_list_next(cursor); } break; case attr_layer: layer=layout->layers; while (layer) { if (!iter || iter->last == g_list_previous(layer)) { attr->u.layer=layer->data; if (iter) iter->last=layer; return 1; } layer=g_list_next(layer); } break; case attr_active: attr->u.num=layout->active; return 1; case attr_nightlayout: attr->u.str=layout->nightname; return 1; case attr_daylayout: attr->u.str=layout->dayname; return 1; default: break; } return 0; } int layout_add_attr(struct layout *layout, struct attr *attr) { switch (attr->type) { case attr_cursor: layout->cursors = g_list_append(layout->cursors, attr->u.cursor); break; case attr_layer: layout->layers = g_list_append(layout->layers, attr->u.layer); break; default: return 0; } layout->attrs=attr_generic_add_attr(layout->attrs, attr); return 1; } /** * Searchs the layout for a cursor with the given name. * * @param layout The layout * @param name The name * @returns A pointer to cursor with the given name or the name default or NULL. * @author Ralph Sennhauser (10/2009) */ struct cursor * layout_get_cursor(struct layout *this_, char *name) { GList *c; struct cursor *d=NULL; c=g_list_first(this_->cursors); while (c) { if (! strcmp(((struct cursor *)c->data)->name, name)) return c->data; if (! strcmp(((struct cursor *)c->data)->name, "default")) d=c->data; c=g_list_next(c); } return d; } struct cursor * cursor_new(struct attr *parent, struct attr **attrs) { struct attr *w, *h, *name, *interval, *sequence_range; struct cursor *this; w=attr_search(attrs, attr_w); h=attr_search(attrs, attr_h); if (! w || ! h) return NULL; this=g_new0(struct cursor,1); this->w=w->u.num; this->h=h->u.num; name=attr_search(attrs, attr_name); if (name) this->name=g_strdup(name->u.str); else this->name=g_strdup("default"); interval=attr_search(attrs, attr_interval); if (interval) this->interval=interval->u.num; sequence_range=attr_search(attrs, attr_sequence_range); if (sequence_range) { struct range *r=g_new0(struct range,1); r->min=sequence_range->u.range.min; r->max=sequence_range->u.range.max; this->sequence_range=r; } else { this->sequence_range=NULL; } dbg(lvl_info,"ret=%p", this); return this; } void cursor_destroy(struct cursor *this_) { if (this_->sequence_range) g_free(this_->sequence_range); if (this_->name) { g_free(this_->name); } g_free(this_); } int cursor_add_attr(struct cursor *this_, struct attr *attr) { switch (attr->type) { case attr_itemgra: this_->attrs=attr_generic_add_attr(this_->attrs, attr); return 1; default: break; } return 0; } static int layer_set_attr_do(struct layer *l, struct attr *attr, int init) { struct attr_iter *iter; struct navit_object *obj; struct attr layer; switch (attr->type) { case attr_active: l->active = attr->u.num; return 1; case attr_details: l->details = attr->u.num; return 1; case attr_name: g_free(l->name); l->name = g_strdup(attr->u.str); return 1; case attr_ref: navit_object_unref((struct navit_object *)l->ref); l->ref=NULL; obj=(struct navit_object *)l->navit; if (obj==NULL) { dbg(lvl_error, "Invalid layer reference '%s': Only layers inside a layout can use references.", attr->u.str); return 0; } iter=obj->func->iter_new(obj); while (obj->func->get_attr(obj, attr_layer, &layer, iter)) { if (!strcmp(layer.u.layer->name, attr->u.str)) { l->ref=(struct layer*)navit_object_ref(layer.u.navit_object); break; } } if (l->ref==NULL) { dbg(lvl_error, "Ignoring reference to unknown layer '%s' in layer '%s'.", attr->u.str, l->name); } obj->func->iter_destroy(iter); return 0; default: return 0; } } struct layer * layer_new(struct attr *parent, struct attr **attrs) { struct layer *l; l = g_new0(struct layer, 1); if (parent->type == attr_layout) l->navit=parent->u.layout->navit; l->func=&layer_func; navit_object_ref((struct navit_object *)l); l->active=1; for (; *attrs; attrs++) { layer_set_attr_do(l, *attrs, 1); } if (l->name==NULL) { dbg(lvl_error, "Ignoring layer without name."); g_free(l); return NULL; } return l; } int layer_get_attr(struct layer *layer, enum attr_type type, struct attr *attr, struct attr_iter *iter) { attr->type=type; switch(type) { case attr_active: attr->u.num=layer->active; return 1; case attr_details: attr->u.num=layer->details; return 1; case attr_name: if (layer->name) { attr->u.str=layer->name; return 1; } break; default: return 0; } return 0; } int layer_add_attr(struct layer *layer, struct attr *attr) { switch (attr->type) { case attr_itemgra: layer->itemgras = g_list_append(layer->itemgras, attr->u.itemgra); return 1; default: return 0; } } int layer_set_attr(struct layer *layer, struct attr *attr) { return layer_set_attr_do(layer, attr, 0); } static void layer_destroy(struct layer *layer) { attr_list_free(layer->attrs); g_free(layer->name); g_free(layer); } struct itemgra * itemgra_new(struct attr *parent, struct attr **attrs) { struct itemgra *itm; struct attr *order, *item_types, *speed_range, *angle_range, *sequence_range; enum item_type *type; struct range defrange; itm = g_new0(struct itemgra, 1); order=attr_search(attrs, attr_order); item_types=attr_search(attrs, attr_item_types); speed_range=attr_search(attrs, attr_speed_range); angle_range=attr_search(attrs, attr_angle_range); sequence_range=attr_search(attrs, attr_sequence_range); defrange.min=0; defrange.max=32767; if (order) itm->order=order->u.range; else itm->order=defrange; if (speed_range) itm->speed_range=speed_range->u.range; else itm->speed_range=defrange; if (angle_range) itm->angle_range=angle_range->u.range; else itm->angle_range=defrange; if (sequence_range) itm->sequence_range=sequence_range->u.range; else itm->sequence_range=defrange; if (item_types) { type=item_types->u.item_types; while (type && *type != type_none) { itm->type=g_list_append(itm->type, GINT_TO_POINTER(*type)); type++; } } return itm; } int itemgra_add_attr(struct itemgra *itemgra, struct attr *attr) { switch (attr->type) { case attr_polygon: case attr_polyline: case attr_circle: case attr_text: case attr_icon: case attr_image: case attr_arrows: case attr_spikes: itemgra->elements = g_list_append(itemgra->elements, attr->u.element); return 1; default: dbg(lvl_error,"unknown: %s", attr_to_name(attr->type)); return 0; } } static void element_set_oneway(struct element *e, struct attr **attrs) { struct attr *oneway; oneway=attr_search(attrs, attr_oneway); if (oneway) e->oneway=oneway->u.num; } static void element_set_color(struct element *e, struct attr **attrs) { struct attr *color; color=attr_search(attrs, attr_color); if (color) e->color=*color->u.color; } static void element_set_background_color(struct color *c, struct attr **attrs) { struct attr *color; color=attr_search(attrs, attr_background_color); if (color) *c=*color->u.color; } static void element_set_text_size(struct element *e, struct attr **attrs) { struct attr *text_size; text_size=attr_search(attrs, attr_text_size); if (text_size) e->text_size=text_size->u.num; } static void element_set_arrows_width(struct element *e, struct attr **attrs) { struct attr *width; width=attr_search(attrs, attr_width); if (width) e->u.arrows.width=width->u.num; else e->u.arrows.width=10; } static void element_set_spikes_width(struct element *e, struct attr **attrs) { struct attr *width; width=attr_search(attrs, attr_width); if (width) e->u.spikes.width=width->u.num; else e->u.spikes.width=10; } static void element_set_spikes_distance(struct element *e, struct attr **attrs) { struct attr *distance; distance=attr_search(attrs, attr_distance); if (distance) { e->u.spikes.distance=distance->u.num; /* paranoia check. We divide with that value */ if(e->u.spikes.distance < 1) e->u.spikes.distance = 1; } else e->u.spikes.distance=10; } static void element_set_polyline_width(struct element *e, struct attr **attrs) { struct attr *width; width=attr_search(attrs, attr_width); if (width) e->u.polyline.width=width->u.num; } static void element_set_polyline_directed(struct element *e, struct attr **attrs) { struct attr *directed; directed=attr_search(attrs, attr_directed); if (directed) e->u.polyline.directed=directed->u.num; } static void element_set_polyline_dash(struct element *e, struct attr **attrs) { struct attr *dash; int i; dash=attr_search(attrs, attr_dash); if (dash) { for (i=0; i<4; i++) { if (!dash->u.dash[i]) break; e->u.polyline.dash_table[i] = dash->u.dash[i]; } e->u.polyline.dash_num=i; } } static void element_set_polyline_offset(struct element *e, struct attr **attrs) { struct attr *offset; offset=attr_search(attrs, attr_offset); if (offset) e->u.polyline.offset=offset->u.num; } static void element_set_circle_width(struct element *e, struct attr **attrs) { struct attr *width; width=attr_search(attrs, attr_width); if (width) e->u.circle.width=width->u.num; } static void element_set_circle_radius(struct element *e, struct attr **attrs) { struct attr *radius; radius=attr_search(attrs, attr_radius); if (radius) e->u.circle.radius=radius->u.num; } struct polygon * polygon_new(struct attr *parent, struct attr **attrs) { struct element *e; int add_size_to_e=0; struct attr *src,*w,*h,*rotation,*x,*y; /* search fot icon src first as this increases the required memory for e*/ src=attr_search(attrs, attr_src); if (src != NULL) { add_size_to_e += strlen(src->u.str)+1; } e = g_malloc0(sizeof(*e)+add_size_to_e); e->type=element_polygon; element_set_color(e, attrs); element_set_oneway(e, attrs); e->u.polygon.src=NULL; /* copy over image url if any, and probe icon parameters */ if (src != NULL) { e->u.polygon.src=(char *)(e+1); strcpy(e->u.polygon.src,src->u.str); if ((w=attr_search(attrs, attr_w))) e->u.polygon.width=w->u.num; else e->u.polygon.width=-1; if ((h=attr_search(attrs, attr_h))) e->u.polygon.height=h->u.num; else e->u.polygon.height=-1; if ((x=attr_search(attrs, attr_x))) e->u.polygon.x=x->u.num; else e->u.polygon.x=-1; if ((y=attr_search(attrs, attr_y))) e->u.polygon.y=y->u.num; else e->u.polygon.y=-1; if ((rotation=attr_search(attrs, attr_rotation))) e->u.polygon.rotation=rotation->u.num; } return (struct polygon *)e; } struct polyline * polyline_new(struct attr *parent, struct attr **attrs) { struct element *e; e = g_new0(struct element, 1); e->type=element_polyline; element_set_color(e, attrs); element_set_oneway(e, attrs); element_set_polyline_width(e, attrs); element_set_polyline_directed(e, attrs); element_set_polyline_dash(e, attrs); element_set_polyline_offset(e, attrs); return (struct polyline *)e; } struct circle * circle_new(struct attr *parent, struct attr **attrs) { struct element *e; struct color color_black = {COLOR_BLACK_}; struct color color_white = {COLOR_WHITE_}; e = g_new0(struct element, 1); e->type=element_circle; e->color = color_black; e->u.circle.background_color = color_white; element_set_color(e, attrs); element_set_background_color(&e->u.circle.background_color, attrs); element_set_oneway(e, attrs); element_set_text_size(e, attrs); element_set_circle_width(e, attrs); element_set_circle_radius(e, attrs); return (struct circle *)e; } struct text * text_new(struct attr *parent, struct attr **attrs) { struct element *e; struct color color_black = {COLOR_BLACK_}; struct color color_white = {COLOR_WHITE_}; e = g_new0(struct element, 1); e->type=element_text; element_set_text_size(e, attrs); e->color = color_black; e->u.text.background_color = color_white; element_set_color(e, attrs); element_set_background_color(&e->u.text.background_color, attrs); element_set_oneway(e, attrs); return (struct text *)e; } struct icon * icon_new(struct attr *parent, struct attr **attrs) { struct element *e; struct attr *src,*w,*h,*rotation,*x,*y; src=attr_search(attrs, attr_src); if (! src) return NULL; e = g_malloc0(sizeof(*e)+strlen(src->u.str)+1); e->type=element_icon; e->u.icon.src=(char *)(e+1); if ((w=attr_search(attrs, attr_w))) e->u.icon.width=w->u.num; else e->u.icon.width=-1; if ((h=attr_search(attrs, attr_h))) e->u.icon.height=h->u.num; else e->u.icon.height=-1; if ((x=attr_search(attrs, attr_x))) e->u.icon.x=x->u.num; else e->u.icon.x=-1; if ((y=attr_search(attrs, attr_y))) e->u.icon.y=y->u.num; else e->u.icon.y=-1; if ((rotation=attr_search(attrs, attr_rotation))) e->u.icon.rotation=rotation->u.num; strcpy(e->u.icon.src,src->u.str); return (struct icon *)e; } struct image * image_new(struct attr *parent, struct attr **attrs) { struct element *e; e = g_malloc0(sizeof(*e)); e->type=element_image; return (struct image *)e; } struct arrows * arrows_new(struct attr *parent, struct attr **attrs) { struct element *e; e = g_malloc0(sizeof(*e)); e->type=element_arrows; element_set_color(e, attrs); element_set_oneway(e, attrs); element_set_arrows_width(e, attrs); return (struct arrows *)e; } struct spikes * spikes_new(struct attr *parent, struct attr **attrs) { struct element *e; e = g_malloc0(sizeof(*e)); e->type=element_spikes; element_set_color(e, attrs); element_set_spikes_width(e, attrs); element_set_spikes_distance(e, attrs); return (struct spikes *)e; } int element_add_attr(struct element *e, struct attr *attr) { switch (attr->type) { case attr_coord: e->coord=g_realloc(e->coord,(e->coord_count+1)*sizeof(struct coord)); e->coord[e->coord_count++]=*attr->u.coord; return 1; default: return 0; } } struct object_func layout_func = { attr_layout, (object_func_new)layout_new, (object_func_get_attr)layout_get_attr, (object_func_iter_new)layout_attr_iter_new, (object_func_iter_destroy)layout_attr_iter_destroy, (object_func_set_attr)NULL, (object_func_add_attr)layout_add_attr, (object_func_remove_attr)NULL, (object_func_init)NULL, (object_func_destroy)NULL, (object_func_dup)NULL, (object_func_ref)navit_object_ref, (object_func_unref)navit_object_unref, }; struct object_func layer_func = { attr_layer, (object_func_new)layer_new, (object_func_get_attr)layer_get_attr, (object_func_iter_new)NULL, (object_func_iter_destroy)NULL, (object_func_set_attr)layer_set_attr, (object_func_add_attr)layer_add_attr, (object_func_remove_attr)NULL, (object_func_init)NULL, (object_func_destroy)layer_destroy, (object_func_dup)NULL, (object_func_ref)navit_object_ref, (object_func_unref)navit_object_unref, };