X-Git-Url: https://git.street.me.uk/andy/viking.git/blobdiff_plain/dc2c040e183a7ea9bcc704921dc124557f5eb21a..d61ec067563735c651f81e6ad0f31be01a8c202b:/src/viklayer.c?ds=sidebyside diff --git a/src/viklayer.c b/src/viklayer.c index a8139b5e..76d494dd 100644 --- a/src/viklayer.c +++ b/src/viklayer.c @@ -1,7 +1,9 @@ /* * viking -- GPS Data and Topo Analyzer, Explorer, and Manager * - * Copyright (C) 2003-2005, Evan Battaglia + * Copyright (C) 2005, Alex Foobarian + * Copyright (C) 2003-2007, Evan Battaglia + * Copyright (C) 2013, Rob Norris * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,6 +29,8 @@ #include "viking.h" #include +#include +#include "viklayer_defaults.h" /* functions common to all layers. */ /* TODO longone: rename interface free -> finalize */ @@ -38,6 +42,9 @@ extern VikLayerInterface vik_coord_layer_interface; extern VikLayerInterface vik_georef_layer_interface; extern VikLayerInterface vik_gps_layer_interface; extern VikLayerInterface vik_dem_layer_interface; +#ifdef HAVE_LIBMAPNIK +extern VikLayerInterface vik_mapnik_layer_interface; +#endif enum { VL_UPDATE_SIGNAL, @@ -47,75 +54,81 @@ static guint layer_signals[VL_LAST_SIGNAL] = { 0 }; static GObjectClass *parent_class; -static void layer_class_init ( VikLayerClass *klass ); -static void layer_init ( VikLayer *vl ); -static void layer_finalize ( VikLayer *vl ); -static gboolean layer_properties_factory ( VikLayer *vl, VikViewport *vp ); - +static void vik_layer_finalize ( VikLayer *vl ); +static gboolean vik_layer_properties_factory ( VikLayer *vl, VikViewport *vp ); +static gboolean layer_defaults_register ( VikLayerTypeEnum type ); -/* TODO longone: rename vik_layer_init -> set_type */ +G_DEFINE_TYPE (VikLayer, vik_layer, G_TYPE_OBJECT) -GType vik_layer_get_type () -{ - static GType vl_type = 0; - - if (!vl_type) - { - static const GTypeInfo vl_info = - { - sizeof (VikLayerClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) layer_class_init, /* class init */ - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (VikLayer), - 0, - (GInstanceInitFunc) layer_init /* instance init */ - }; - vl_type = g_type_register_static ( G_TYPE_OBJECT, "VikLayer", &vl_info, 0 ); - } - - return vl_type; -} - -static void layer_class_init (VikLayerClass *klass) +static void vik_layer_class_init (VikLayerClass *klass) { GObjectClass *object_class; object_class = G_OBJECT_CLASS (klass); - object_class->finalize = (GObjectFinalizeFunc) layer_finalize; + object_class->finalize = (GObjectFinalizeFunc) vik_layer_finalize; parent_class = g_type_class_peek_parent (klass); layer_signals[VL_UPDATE_SIGNAL] = g_signal_new ( "update", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (VikLayerClass, update), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + + // Register all parameter defaults, early in the start up sequence + VikLayerTypeEnum layer; + for ( layer = 0; layer < VIK_LAYER_NUM_TYPES; layer++ ) + // ATM ignore the returned value + layer_defaults_register ( layer ); } +/** + * Invoke the actual drawing via signal method + */ +static gboolean idle_draw ( VikLayer *vl ) +{ + g_signal_emit ( G_OBJECT(vl), layer_signals[VL_UPDATE_SIGNAL], 0 ); + return FALSE; // Nothing else to do +} + +/** + * Draw specified layer + */ void vik_layer_emit_update ( VikLayer *vl ) { - if ( vl->visible ) { + if ( vl->visible && vl->realized ) { + GThread *thread = vik_window_get_thread ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vl)) ); + if ( !thread ) + // Do nothing + return; + vik_window_set_redraw_trigger(vl); - g_signal_emit ( G_OBJECT(vl), layer_signals[VL_UPDATE_SIGNAL], 0 ); + + // Only ever draw when there is time to do so + if ( g_thread_self() != thread ) + // Drawing requested from another (background) thread, so handle via the gdk thread method + gdk_threads_add_idle ( (GSourceFunc) idle_draw, vl ); + else + g_idle_add ( (GSourceFunc) idle_draw, vl ); } } -/* should only be done by VikLayersPanel -- need to redraw and record trigger - * when we make a layer invisible. +/** + * should only be done by VikLayersPanel (hence never used from the background) + * need to redraw and record trigger when we make a layer invisible. */ void vik_layer_emit_update_although_invisible ( VikLayer *vl ) { vik_window_set_redraw_trigger(vl); - g_signal_emit ( G_OBJECT(vl), layer_signals[VL_UPDATE_SIGNAL], 0 ); + g_idle_add ( (GSourceFunc) idle_draw, vl ); } /* doesn't set the trigger. should be done by aggregate layer when child emits update. */ void vik_layer_emit_update_secondary ( VikLayer *vl ) { if ( vl->visible ) - g_signal_emit ( G_OBJECT(vl), layer_signals[VL_UPDATE_SIGNAL], 0 ); + // TODO: this can used from the background - eg in acquire + // so will need to flow background update status through too + g_idle_add ( (GSourceFunc) idle_draw, vl ); } static VikLayerInterface *vik_layer_interfaces[VIK_LAYER_NUM_TYPES] = { @@ -126,22 +139,54 @@ static VikLayerInterface *vik_layer_interfaces[VIK_LAYER_NUM_TYPES] = { &vik_gps_layer_interface, &vik_maps_layer_interface, &vik_dem_layer_interface, +#ifdef HAVE_LIBMAPNIK + &vik_mapnik_layer_interface, +#endif }; -VikLayerInterface *vik_layer_get_interface ( gint type ) +VikLayerInterface *vik_layer_get_interface ( VikLayerTypeEnum type ) { g_assert ( type < VIK_LAYER_NUM_TYPES ); return vik_layer_interfaces[type]; } -static void layer_init ( VikLayer *vl ) +/** + * Store default values for this layer + * + * Returns whether any parameters where registered + */ +static gboolean layer_defaults_register ( VikLayerTypeEnum type ) +{ + // See if any parameters + VikLayerParam *params = vik_layer_interfaces[type]->params; + if ( ! params ) + return FALSE; + + gboolean answer = FALSE; // Incase all parameters are 'not in properties' + guint16 params_count = vik_layer_interfaces[type]->params_count; + guint16 i; + // Process each parameter + for ( i = 0; i < params_count; i++ ) { + if ( params[i].group != VIK_LAYER_NOT_IN_PROPERTIES ) { + if ( params[i].default_value ) { + VikLayerParamData paramd = params[i].default_value(); + a_layer_defaults_register ( ¶ms[i], paramd, vik_layer_interfaces[type]->fixed_layer_name ); + answer = TRUE; + } + } + } + + return answer; +} + +static void vik_layer_init ( VikLayer *vl ) { vl->visible = TRUE; vl->name = NULL; vl->realized = FALSE; } -void vik_layer_init ( VikLayer *vl, gint type ) +void vik_layer_set_type ( VikLayer *vl, VikLayerTypeEnum type ) { vl->type = type; } @@ -169,7 +214,14 @@ const gchar *vik_layer_get_name ( VikLayer *l ) return l->name; } -VikLayer *vik_layer_create ( gint type, gpointer vp, GtkWindow *w, gboolean interactive ) +time_t vik_layer_get_timestamp ( VikLayer *vl ) +{ + if ( vik_layer_interfaces[vl->type]->get_timestamp ) + return vik_layer_interfaces[vl->type]->get_timestamp ( vl ); + return 0; +} + +VikLayer *vik_layer_create ( VikLayerTypeEnum type, VikViewport *vp, gboolean interactive ) { VikLayer *new_layer = NULL; g_assert ( type < VIK_LAYER_NUM_TYPES ); @@ -194,18 +246,18 @@ VikLayer *vik_layer_create ( gint type, gpointer vp, GtkWindow *w, gboolean inte } /* returns TRUE if OK was pressed */ -gboolean vik_layer_properties ( VikLayer *layer, gpointer vp ) +gboolean vik_layer_properties ( VikLayer *layer, VikViewport *vp ) { if ( vik_layer_interfaces[layer->type]->properties ) return vik_layer_interfaces[layer->type]->properties ( layer, vp ); - return layer_properties_factory ( layer, vp ); + return vik_layer_properties_factory ( layer, vp ); } -void vik_layer_draw ( VikLayer *l, gpointer data ) +void vik_layer_draw ( VikLayer *l, VikViewport *vp ) { if ( l->visible ) if ( vik_layer_interfaces[l->type]->draw ) - vik_layer_interfaces[l->type]->draw ( l, data ); + vik_layer_interfaces[l->type]->draw ( l, vp ); } void vik_layer_change_coord_mode ( VikLayer *l, VikCoordMode mode ) @@ -215,7 +267,7 @@ void vik_layer_change_coord_mode ( VikLayer *l, VikCoordMode mode ) } typedef struct { - gint layer_type; + VikLayerTypeEnum layer_type; gint len; guint8 data[0]; } header_t; @@ -259,13 +311,20 @@ void vik_layer_marshall_params ( VikLayer *vl, guint8 **data, gint *datalen ) guint16 i, params_count = vik_layer_get_interface(vl->type)->params_count; for ( i = 0; i < params_count; i++ ) { - d = get_param(vl, i); + g_debug("%s: %s", __FUNCTION__, params[i].name); + d = get_param(vl, i, FALSE); switch ( params[i].type ) { - case VIK_LAYER_PARAM_STRING: - vlm_append(d.s, strlen(d.s)); - break; - + case VIK_LAYER_PARAM_STRING: + // Remember need braces as these are macro calls, not single statement functions! + if ( d.s ) { + vlm_append(d.s, strlen(d.s)); + } + else { + // Need to insert empty string otherwise the unmarshall will get confused + vlm_append("", 0); + } + break; /* print out the string list in the array */ case VIK_LAYER_PARAM_STRING_LIST: { GList *list = d.sl; @@ -323,6 +382,7 @@ void vik_layer_unmarshall_params ( VikLayer *vl, guint8 *data, gint datalen, Vik guint16 i, params_count = vik_layer_get_interface(vl->type)->params_count; for ( i = 0; i < params_count; i++ ) { + g_debug("%s: %s", __FUNCTION__, params[i].name); switch ( params[i].type ) { case VIK_LAYER_PARAM_STRING: @@ -330,7 +390,7 @@ void vik_layer_unmarshall_params ( VikLayer *vl, guint8 *data, gint datalen, Vik s[vlm_size]=0; vlm_read(s); d.s = s; - set_param(vl, i, d, vvp); + set_param(vl, i, d, vvp, FALSE); g_free(s); break; case VIK_LAYER_PARAM_STRING_LIST: { @@ -346,14 +406,14 @@ void vik_layer_unmarshall_params ( VikLayer *vl, guint8 *data, gint datalen, Vik list = g_list_append ( list, s ); } d.sl = list; - set_param ( vl, i, d, vvp ); + set_param(vl, i, d, vvp, FALSE); /* don't free -- string list is responsibility of the layer */ break; } default: vlm_read(&d); - set_param(vl, i, d, vvp); + set_param(vl, i, d, vvp, FALSE); break; } } @@ -373,7 +433,7 @@ VikLayer *vik_layer_unmarshall ( guint8 *data, gint len, VikViewport *vvp ) } } -static void layer_finalize ( VikLayer *vl ) +static void vik_layer_finalize ( VikLayer *vl ) { g_assert ( vl != NULL ); if ( vik_layer_interfaces[vl->type]->free ) @@ -391,6 +451,14 @@ gboolean vik_layer_sublayer_toggle_visible ( VikLayer *l, gint subtype, gpointer return TRUE; /* if unknown, will always be visible */ } +gboolean vik_layer_selected ( VikLayer *l, gint subtype, gpointer sublayer, gint type, gpointer vlp ) +{ + if ( vik_layer_interfaces[l->type]->layer_selected ) + return vik_layer_interfaces[l->type]->layer_selected ( l, subtype, sublayer, type, vlp ); + /* Since no 'layer_selected' function explicitly turn off here */ + return vik_window_clear_highlight ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l) ); +} + void vik_layer_realize ( VikLayer *l, VikTreeview *vt, GtkTreeIter *layer_iter ) { l->vt = vt; @@ -420,10 +488,10 @@ void vik_layer_add_menu_items ( VikLayer *l, GtkMenu *menu, gpointer vlp ) vik_layer_interfaces[l->type]->add_menu_items ( l, menu, vlp ); } -gboolean vik_layer_sublayer_add_menu_items ( VikLayer *l, GtkMenu *menu, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter ) +gboolean vik_layer_sublayer_add_menu_items ( VikLayer *l, GtkMenu *menu, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter, VikViewport *vvp ) { if ( vik_layer_interfaces[l->type]->sublayer_add_menu_items ) - return vik_layer_interfaces[l->type]->sublayer_add_menu_items ( l, menu, vlp, subtype, sublayer, iter ); + return vik_layer_interfaces[l->type]->sublayer_add_menu_items ( l, menu, vlp, subtype, sublayer, iter, vvp ); return FALSE; } @@ -435,7 +503,21 @@ const gchar *vik_layer_sublayer_rename_request ( VikLayer *l, const gchar *newna return NULL; } -GdkPixbuf *vik_layer_load_icon ( gint type ) +const gchar* vik_layer_sublayer_tooltip ( VikLayer *l, gint subtype, gpointer sublayer ) +{ + if ( vik_layer_interfaces[l->type]->sublayer_tooltip ) + return vik_layer_interfaces[l->type]->sublayer_tooltip ( l, subtype, sublayer ); + return NULL; +} + +const gchar* vik_layer_layer_tooltip ( VikLayer *l ) +{ + if ( vik_layer_interfaces[l->type]->layer_tooltip ) + return vik_layer_interfaces[l->type]->layer_tooltip ( l ); + return NULL; +} + +GdkPixbuf *vik_layer_load_icon ( VikLayerTypeEnum type ) { g_assert ( type < VIK_LAYER_NUM_TYPES ); if ( vik_layer_interfaces[type]->icon ) @@ -443,10 +525,10 @@ GdkPixbuf *vik_layer_load_icon ( gint type ) return NULL; } -gboolean vik_layer_set_param ( VikLayer *layer, guint16 id, VikLayerParamData data, gpointer vp ) +gboolean vik_layer_set_param ( VikLayer *layer, guint16 id, VikLayerParamData data, gpointer vp, gboolean is_file_operation ) { if ( vik_layer_interfaces[layer->type]->set_param ) - return vik_layer_interfaces[layer->type]->set_param ( layer, id, data, vp ); + return vik_layer_interfaces[layer->type]->set_param ( layer, id, data, vp, is_file_operation ); return FALSE; } @@ -456,9 +538,10 @@ void vik_layer_post_read ( VikLayer *layer, VikViewport *vp, gboolean from_file vik_layer_interfaces[layer->type]->post_read ( layer, vp, from_file ); } -static gboolean layer_properties_factory ( VikLayer *vl, VikViewport *vp ) +static gboolean vik_layer_properties_factory ( VikLayer *vl, VikViewport *vp ) { - switch ( a_uibuilder_properties_factory ( VIK_GTK_WINDOW_FROM_WIDGET(vp), + switch ( a_uibuilder_properties_factory ( _("Layer Properties"), + VIK_GTK_WINDOW_FROM_WIDGET(vp), vik_layer_interfaces[vl->type]->params, vik_layer_interfaces[vl->type]->params_count, vik_layer_interfaces[vl->type]->params_groups, @@ -467,10 +550,11 @@ static gboolean layer_properties_factory ( VikLayer *vl, VikViewport *vp ) vl, vp, (gpointer) vik_layer_interfaces[vl->type]->get_param, - vl) ) { + vl, + (gpointer) vik_layer_interfaces[vl->type]->change_param ) ) { case 0: - return FALSE; case 3: + return FALSE; /* redraw (?) */ case 2: vik_layer_post_read ( vl, vp, FALSE ); /* update any gc's */ @@ -479,3 +563,109 @@ static gboolean layer_properties_factory ( VikLayer *vl, VikViewport *vp ) } } +VikLayerTypeEnum vik_layer_type_from_string ( const gchar *str ) +{ + VikLayerTypeEnum i; + for ( i = 0; i < VIK_LAYER_NUM_TYPES; i++ ) + if ( strcasecmp ( str, vik_layer_get_interface(i)->fixed_layer_name ) == 0 ) + return i; + return VIK_LAYER_NUM_TYPES; +} + +void vik_layer_typed_param_data_free ( gpointer gp ) +{ + VikLayerTypedParamData *val = (VikLayerTypedParamData *)gp; + switch ( val->type ) { + case VIK_LAYER_PARAM_STRING: + if ( val->data.s ) + g_free ( (gpointer)val->data.s ); + break; + /* TODO: APPLICABLE TO US? NOTE: string layer works auniquely: data.sl should NOT be free'd when + * the internals call get_param -- i.e. it should be managed w/in the layer. + * The value passed by the internals into set_param should also be managed + * by the layer -- i.e. free'd by the layer. + */ + case VIK_LAYER_PARAM_STRING_LIST: + g_warning ("Param strings not implemented"); //fake it + break; + default: + break; + } + g_free ( val ); +} + +VikLayerTypedParamData *vik_layer_typed_param_data_copy_from_data (VikLayerParamType type, VikLayerParamData val) { + VikLayerTypedParamData *newval = g_new(VikLayerTypedParamData,1); + newval->data = val; + newval->type = type; + switch ( newval->type ) { + case VIK_LAYER_PARAM_STRING: { + gchar *s = g_strdup(newval->data.s); + newval->data.s = s; + break; + } + /* TODO: APPLICABLE TO US? NOTE: string layer works auniquely: data.sl should NOT be free'd when + * the internals call get_param -- i.e. it should be managed w/in the layer. + * The value passed by the internals into set_param should also be managed + * by the layer -- i.e. free'd by the layer. + */ + case VIK_LAYER_PARAM_STRING_LIST: + g_critical ( "Param strings not implemented"); //fake it + break; + default: + break; + } + return newval; +} + +#define TEST_BOOLEAN(str) (! ((str)[0] == '\0' || (str)[0] == '0' || (str)[0] == 'n' || (str)[0] == 'N' || (str)[0] == 'f' || (str)[0] == 'F') ) + +VikLayerTypedParamData *vik_layer_data_typed_param_copy_from_string ( VikLayerParamType type, const gchar *str ) +{ + VikLayerTypedParamData *rv = g_new(VikLayerTypedParamData,1); + rv->type = type; + switch ( type ) + { + case VIK_LAYER_PARAM_DOUBLE: rv->data.d = strtod(str, NULL); break; + case VIK_LAYER_PARAM_UINT: rv->data.u = strtoul(str, NULL, 10); break; + case VIK_LAYER_PARAM_INT: rv->data.i = strtol(str, NULL, 10); break; + case VIK_LAYER_PARAM_BOOLEAN: rv->data.b = TEST_BOOLEAN(str); break; + case VIK_LAYER_PARAM_COLOR: memset(&(rv->data.c), 0, sizeof(rv->data.c)); /* default: black */ + gdk_color_parse ( str, &(rv->data.c) ); break; + /* STRING or STRING_LIST -- if STRING_LIST, just set param to add a STRING */ + default: { + gchar *s = g_strdup(str); + rv->data.s = s; + } + } + return rv; +} + + +/** + * vik_layer_set_defaults: + * + * Loop around all parameters for the specified layer to call the function to get the + * default value for that parameter + */ +void vik_layer_set_defaults ( VikLayer *vl, VikViewport *vvp ) +{ + // Sneaky initialize of the viewport value here + vl->vvp = vvp; + VikLayerInterface *vli = vik_layer_get_interface ( vl->type ); + const gchar *layer_name = vli->fixed_layer_name; + VikLayerParamData data; + + int i; + for ( i = 0; i < vli->params_count; i++ ) { + // Ensure parameter is for use + if ( vli->params[i].group > VIK_LAYER_NOT_IN_PROPERTIES ) { + // ATM can't handle string lists + // only DEM files uses this currently + if ( vli->params[i].type != VIK_LAYER_PARAM_STRING_LIST ) { + data = a_layer_defaults_get ( layer_name, vli->params[i].name, vli->params[i].type ); + vik_layer_set_param ( vl, i, data, vvp, TRUE ); // Possibly come from a file + } + } + } +}