[cairo-commit] roadster/src db.c, 1.24, 1.25 import_tiger.c, 1.18, 1.19 importwindow.c, 1.7, 1.8 layers.c, 1.15, 1.16 layers.h, 1.7, 1.8 mainwindow.c, 1.38, 1.39 map.c, 1.42, 1.43 map.h, 1.19, 1.20 map_draw_cairo.c, 1.20, 1.21 map_draw_gdk.c, 1.16, 1.17 road.c, 1.4, 1.5 scenemanager.c, 1.12, 1.13 search_road.c, 1.20, 1.21 util.c, 1.8, 1.9 util.h, 1.8, 1.9

Ian McIntosh commit at pdx.freedesktop.org
Mon Sep 5 19:44:21 PDT 2005


Committed by: ian

Update of /cvs/cairo/roadster/src
In directory gabe:/tmp/cvs-serv10455/src

Modified Files:
	db.c import_tiger.c importwindow.c layers.c layers.h 
	mainwindow.c map.c map.h map_draw_cairo.c map_draw_gdk.c 
	road.c scenemanager.c search_road.c util.c util.h 
Log Message:
	* src/db.c: Better error handling (silences "duplicate key" warning on startup).
	* src/import_tiger.c: Comment out some cleanup code that has a crasher bug somewhere (now it's just a memory leak!).
	* src/mainwindow.c: Updated comments, removed some dead code.
	* src/importwindow.c: Add a printf showing # of files received from file chooser dialog.
	* src/layers.c: Implemented new layers XML format.  Draw order is now dictated by the XML file.  Removed concept of "sublayers".  Unlimited layers are now supported.
	* src/map.c: Removed layer draw order table.  Changed scenemanager test from a rectangle to a diamond.
	* src/map_draw_cairo.c: Added map scale rendering.  Cairo rendering commented out until it can be updated to new layer style stuff.
	* src/map_draw_gdk.c: Updated for new layer format.
	* data/layers.xml: Complete rewrite for new layers format.
	* configure.ac: Remove old/incorrect tests.
	* data/roadster.glade: Removed some old/unused dialogs.


Index: db.c
===================================================================
RCS file: /cvs/cairo/roadster/src/db.c,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -d -r1.24 -r1.25
--- db.c	31 Aug 2005 08:37:53 -0000	1.24
+++ db.c	6 Sep 2005 02:44:19 -0000	1.25
@@ -48,6 +48,8 @@
 
 #define MYSQL_RESULT_SUCCESS  	(0)		// for clearer code
 
+#define MYSQL_ERROR_DUPLICATE_KEY	(1062)
+
 #define MAX_SQLBUFFER_LEN		(132000)	// must be big for lists of coordinates
 #define COORD_LIST_MAX 			(128000)
 
@@ -128,7 +130,11 @@
 
 	gint nResult = mysql_query(g_pDB->m_pMySQLConnection, pszSQL);
 	if(nResult != MYSQL_RESULT_SUCCESS) {
-		g_warning("db_query: %s (SQL: %s)\n", mysql_error(g_pDB->m_pMySQLConnection), pszSQL);
+		gint nErrorNumber = mysql_errno(g_pDB->m_pMySQLConnection);
+
+		if(nErrorNumber != MYSQL_ERROR_DUPLICATE_KEY) {
+			g_warning("db_query: %d:%s (SQL: %s)\n", mysql_errno(g_pDB->m_pMySQLConnection), mysql_error(g_pDB->m_pMySQLConnection), pszSQL);
+		}
 		return FALSE;
 	}
 

Index: import_tiger.c
===================================================================
RCS file: /cvs/cairo/roadster/src/import_tiger.c,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -d -r1.18 -r1.19
--- import_tiger.c	31 Aug 2005 08:37:53 -0000	1.18
+++ import_tiger.c	6 Sep 2005 02:44:19 -0000	1.19
@@ -265,23 +265,23 @@
 	if(chFeatureClass == 'A') {
 		if(chCode == '1') {	// primary road with "Limited access" (few connecting roads)
 			/* A19, A29, A39 are bridges */
-			*pValue = LAYER_MINORHIGHWAY;
+			*pValue = MAP_OBJECT_TYPE_MINORHIGHWAY;
 			return TRUE;
 		}
 		else if(chCode == '2') {	// "Primary Road without Limited Access"
-			*pValue = LAYER_MAJORSTREET;
+			*pValue = MAP_OBJECT_TYPE_MAJORROAD;
 			return TRUE;
 		}
 		else if(chCode == '3') {
-			*pValue = LAYER_MAJORSTREET;
+			*pValue = MAP_OBJECT_TYPE_MAJORROAD;
 			return TRUE;
 		}
 		else if(chCode == '4') {	// "Local, Neighborhood, Rural" Roads
-			*pValue = LAYER_MINORSTREET;
+			*pValue = MAP_OBJECT_TYPE_MINORROAD;
 			return TRUE;
 		}
 		else if(chCode == '5') {	// dirt roads
-			//*pValue = LAYER_TRAIL;
+			//*pValue = MAP_OBJECT_TYPE_TRAIL;
 			return FALSE;
 		}
 		else if(chCode == '6') {
@@ -289,11 +289,11 @@
 				g_print("found code A61: cul-de-sac!\n");
 			}
 			else if(chSubCode == '3') {
-				*pValue = LAYER_MINORHIGHWAY_RAMP;			
+				*pValue = MAP_OBJECT_TYPE_MINORHIGHWAY_RAMP;			
 				return TRUE;
 			}
 			else if(chSubCode == '5') {
-				//*pValue = LAYER_FERRY_ROUTE;	// where a boat carrying cars goes
+				//*pValue = MAP_OBJECT_TYPE_FERRY_ROUTE;	// where a boat carrying cars goes
 				return FALSE;
 			}
 			else if(chSubCode == '7') {
@@ -302,26 +302,26 @@
 		}
 		else if(chCode == '7') {	// "other"
 			//~ if(chSubCode == '1') {
-				//~ *pValue = LAYER_PEDESTRIAN_PATH;	// bike/walking path			
+				//~ *pValue = MAP_OBJECT_TYPE_PEDESTRIAN_PATH;	// bike/walking path			
 				//~ return TRUE;
 			//~ }
 			//~ else if(chSubCode == '2') {
-				//~ *pValue = LAYER_PEDESTRIAN_PATH;	// stairway for pedestrians...
+				//~ *pValue = MAP_OBJECT_TYPE_PEDESTRIAN_PATH;	// stairway for pedestrians...
 				//~ return TRUE;
 			//~ }
 			//~ else if(chSubCode == '4') {
-				//~ *pValue = LAYER_DRIVEWAY;			// private access roads
+				//~ *pValue = MAP_OBJECT_TYPE_DRIVEWAY;			// private access roads
 				//~ return TRUE;
 			//~ }
 		}
 	}
 	else if(chFeatureClass == 'B') {		// Railroads
-		*pValue = LAYER_RAILROAD;
+		*pValue = MAP_OBJECT_TYPE_RAILROAD;
 		return TRUE;
 	}
 	else if(chFeatureClass == 'D') {		// Landmarks
 		//~ if(chCode == '5' && chSubCode == '1') {
-			//~ *pValue = LAYER_AIRPORT;
+			//~ *pValue = MAP_OBJECT_TYPE_AIRPORT;
 			//~ return TRUE;
 		//~ }
 		//~ else
@@ -334,11 +334,11 @@
 		 D85 State or local park or forest
 		*/
 		if(chCode == '8') {
-			*pValue = LAYER_PARK;
+			*pValue = MAP_OBJECT_TYPE_PARK;
 			return TRUE;
 		}
 		else {
-			*pValue = LAYER_MISC_AREA;
+			*pValue = MAP_OBJECT_TYPE_MISC_AREA;
 			return TRUE;
 		}
 
@@ -378,48 +378,48 @@
 			// generic unknown water ...
 			// this includes charles river (cambridge/boston ma)
 			// but they are badly formed for some reason?
-//			*pValue = LAYER_LAKE;
+//			*pValue = MAP_OBJECT_TYPE_LAKE;
 //			return TRUE;
 //			return FALSE;
 			if(chSubCode == '1') {
 				// these need to be stitched by lat/lon
-				//*pValue = LAYER_LAKE;	// shoreline of perennial water feature
+				//*pValue = MAP_OBJECT_TYPE_LAKE;	// shoreline of perennial water feature
 				//return TRUE;
 			}
 		}
 		else if(chCode == '1') { 	// streams
-			*pValue = LAYER_RIVER;
+			*pValue = MAP_OBJECT_TYPE_RIVER;
 			return TRUE;
 		}
 		else if(chCode == '3') { 	// lakes
-			*pValue = LAYER_LAKE;
+			*pValue = MAP_OBJECT_TYPE_LAKE;
 			return TRUE;
 		}
 		else if(chCode == '4') { 	// reservoirs
-			*pValue = LAYER_LAKE;
+			*pValue = MAP_OBJECT_TYPE_LAKE;
 			return TRUE;
 		}
 		else if(chCode == '5') { 	// ocean
 			if(chSubCode == '1') {
-				*pValue = LAYER_LAKE;	// bay, estuary, gulf or sound
+				*pValue = MAP_OBJECT_TYPE_LAKE;	// bay, estuary, gulf or sound
 				return TRUE;				
 			}
 			else {
-//				*pValue = LAYER_LAKE;
+//				*pValue = MAP_OBJECT_TYPE_LAKE;
 //				return TRUE;
-				//~ *pValue = LAYER_OCEAN;
+				//~ *pValue = MAP_OBJECT_TYPE_OCEAN;
 				//~ return TRUE;
 			}
 		}
 		else if(chCode == '6') { 	// water-filled gravel pit
 			g_print("found code H6: water filled gravel pit!\n");
-			//~ *pValue = LAYER_LAKE;
+			//~ *pValue = MAP_OBJECT_TYPE_LAKE;
 			//~ return TRUE;
 		}
 	}
-	//~ *pValue = LAYER_TRAIL;
+	//~ *pValue = MAP_OBJECT_TYPE_TRAIL;
 	//~ return TRUE;
-	*pValue = LAYER_NONE;
+	*pValue = MAP_OBJECT_TYPE_NONE;
 	return FALSE;
 }
 
@@ -597,7 +597,7 @@
 
 		import_tiger_read_string(&pLine[25-1], TIGER_LANDMARK_NAME_LEN, &pRecord->m_achName[0]);
 
-		//if(nRecordType == LAYER_MISC_AREA) {
+		//if(nRecordType == MAP_OBJECT_TYPE_MISC_AREA) {
 			// g_print("misc area: %s\n", pRecord->m_achName);
 		//}
 // g_print("record 7: TypeID=%d LANDID=%d\n", pRecord->m_nRecordType, pRecord->m_nLANDID);
@@ -773,7 +773,7 @@
 	//
 	// Change rivers into lakes if they are circular (why doesn't this work here?)
 	//
-//     if(pRecordRT1->m_nRecordType == LAYER_RIVER) {
+//     if(pRecordRT1->m_nRecordType == MAP_OBJECT_TYPE_RIVER) {
 //         if(((gint)(pRecordRT1->m_PointA.m_fLongitude * 1000.0)) == ((gint)(pRecordRT1->m_PointB.m_fLongitude * 1000.0)) &&
 //            ((gint)(pRecordRT1->m_PointA.m_fLatitude * 1000.0)) == ((gint)(pRecordRT1->m_PointB.m_fLatitude * 1000.0)))
 //         {
@@ -784,7 +784,7 @@
 //                 g_print("OOPS: %20.20f != %20.20f\n", pRecordRT1->m_PointA.m_fLatitude, pRecordRT1->m_PointB.m_fLatitude);
 //             }
 //             g_print("converting circular river to lake: %s\n", pRecordRT1->m_achName);
-//             pRecordRT1->m_nRecordType = LAYER_LAKE;
+//             pRecordRT1->m_nRecordType = MAP_OBJECT_TYPE_LAKE;
 //         }
 //         else {
 // //          g_print("NOT converting river: %s (%f != %f)(%f != %f)\n", pRecordRT1->m_achName, pRecordRT1->m_PointA.m_fLongitude, pRecordRT1->m_PointB.m_fLongitude, pRecordRT1->m_PointA.m_fLatitude, pRecordRT1->m_PointB.m_fLatitude);
@@ -820,7 +820,7 @@
 	}
 
 	// insert, then free temp array
-	if(pRecordRT1->m_nRecordType != LAYER_NONE) {
+	if(pRecordRT1->m_nRecordType != MAP_OBJECT_TYPE_NONE) {
 		gchar azZIPCodeLeft[6];
 		g_snprintf(azZIPCodeLeft, 6, "%05d", pRecordRT1->m_nZIPCodeLeft);
 		gchar azZIPCodeRight[6];
@@ -931,7 +931,7 @@
 	// create a temp array to hold the points for this polygon (in order)
 	g_assert(pTempPointsArray == NULL);
 	pTempPointsArray = g_ptr_array_new();
-	
+
 	// start with the RT1Link at index 0 (and remove it)
 	tiger_rt1_link_t* pCurrentRT1Link = g_ptr_array_index(pRecordRTi->m_pRT1LinksArray, 0);
 	g_ptr_array_remove_index(pRecordRTi->m_pRT1LinksArray, 0);	// TODO: should maybe choose the last one instead? :)  easier to remove and arbitrary anyway!
@@ -1005,8 +1005,6 @@
 
 	// save this polygon
 	if(pTempPointsArray->len > 3) {	// takes 3 to make a polygon
-		// g_print("inserting polygon of len %d type %s\n", pTempPointsArray->len, g_aLayers[pRecordRT7->m_nRecordType].m_pszName);
-
 		mappoint_t* p1 = g_ptr_array_index(pTempPointsArray, 0);
 		mappoint_t* p2 = g_ptr_array_index(pTempPointsArray, pTempPointsArray->len-1);
 
@@ -1021,7 +1019,7 @@
 		gchar* pszZIPCodeRight = "";
 
 		// insert record
-		if(pRecordRT7->m_nRecordType != LAYER_NONE) {
+		if(pRecordRT7->m_nRecordType != MAP_OBJECT_TYPE_NONE) {
 			gint nRoadNameID = 0;
 			if(pRecordRT7->m_achName[0] != '\0') {
 				//g_printf("inserting area name %s\n", pRecordRT7->m_achName);
@@ -1261,10 +1259,10 @@
 	g_print("iterating over RT1 chains...\n");
 	g_hash_table_foreach(importProcess.m_pTableRT1, callback_save_rt1_chains, &importProcess);
 	g_print("done.\n");
-	
+
 	importwindow_log_append(".");
 	importwindow_progress_pulse();
-
+g_print("cleaning up\n");
 	//
 	// free up the importprocess structure
 	//
@@ -1273,7 +1271,9 @@
 	g_hash_table_destroy(importProcess.m_pTableRT7);
 	g_hash_table_destroy(importProcess.m_pTableRT8);
 	g_hash_table_destroy(importProcess.m_pTableRTc);
-	g_hash_table_destroy(importProcess.m_pTableRTi);
+	// XXX: this call sometimes segfaults:
+	g_warning("leaking some memory due to unsolved bug in import.  just restart roadster after/between imports ;)\n");
+	//g_hash_table_destroy(importProcess.m_pTableRTi);
 	g_free(importProcess.m_pszFileDescription);
 
 	return TRUE;

Index: importwindow.c
===================================================================
RCS file: /cvs/cairo/roadster/src/importwindow.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- importwindow.c	28 Mar 2005 18:49:50 -0000	1.7
+++ importwindow.c	6 Sep 2005 02:44:19 -0000	1.8
@@ -102,6 +102,8 @@
 	g_ImportWindow.m_nTotalFiles = g_slist_length(pSelectedFileList);
 	g_ImportWindow.m_nCurrentFile = 1;
 
+	g_print("Importing %d file(s)\n", g_ImportWindow.m_nTotalFiles);
+
 	gint nTotalSuccess = 0;
 	GSList* pFile = pSelectedFileList;
 	while(pFile != NULL) {

Index: layers.c
===================================================================
RCS file: /cvs/cairo/roadster/src/layers.c,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- layers.c	28 Aug 2005 22:23:14 -0000	1.15
+++ layers.c	6 Sep 2005 02:44:19 -0000	1.16
@@ -30,334 +30,330 @@
 #include "main.h"
 #include "layers.h"
 
-layer_t * g_aLayers[NUM_LAYERS+1];
+#define EACH_ATTRIBUTE_OF_NODE(a,n)		(a) = (n)->properties ; (a) != NULL ; (a) = (a)->next
+#define EACH_CHILD_OF_NODE(c,n)			(c) = (n)->children ; (c) != NULL ; (c) = (c)->next
 
-gdouble pafDash_Solid[] = {10};
-gdouble pafDash_1_14[] = {1, 14};
-gint8 panDash_1_14[] = {1, 14};
+GPtrArray* g_pLayersArray = NULL;	// XXX: globals suck. :(
+
+gdouble pafDash_1_14[] = {5, 14, 5, 14};
+gint8 panDash_1_14[] = {5, 14, 5, 14};
 
 dashstyle_t g_aDashStyles[NUM_DASH_STYLES] = {
 	{NULL, NULL, 0},
-	{pafDash_1_14, panDash_1_14, 2},
+	{pafDash_1_14, panDash_1_14, 4},
 };
 
 static void layers_load_from_file();
-static layer_t* layers_new(gint index, gchar *name);
 
-static void layers_parse_layers(xmlDocPtr doc, xmlNodePtr node);
-static void layers_parse_layer(xmlDocPtr doc, xmlNodePtr node);
-static void layers_parse_sublayer(xmlDocPtr doc, sublayerstyle_t *sublayer, xmlNodePtr node);
-static void layers_parse_sublayer_property(xmlDocPtr doc, sublayerstyle_t *sublayer, xmlNodePtr node);
-static void layers_parse_label(xmlDocPtr doc, textlabelstyle_t *label_style, xmlNodePtr node);
-static void layers_parse_label_property(xmlDocPtr doc, textlabelstyle_t *label_style, xmlNodePtr node);
-static void layers_parse_color(color_t *color, gchar *value);
+static layer_t* layers_new_layer();
+
+static void layers_parse_file(xmlDocPtr pDoc, xmlNodePtr pNode);
+static void layers_parse_layer(xmlDocPtr pDoc, xmlNodePtr pNode);
+static void layers_parse_layer_property(xmlDocPtr pDoc, layer_t *pLayer, xmlNodePtr pNode);
 
+// Debugging
 static void layers_print_layer(layer_t *layer);
-static void layers_print_sublayer(sublayerstyle_t *sublayer);
 static void layers_print_color(color_t *color);
 
-
-void
-layers_init(void)
+void layers_init(void)
 {
-	g_aLayers[LAYER_NONE] = layers_new(LAYER_NONE, "unused");
-	g_aLayers[LAYER_MINORSTREET] = layers_new(LAYER_MINORSTREET, "minor-roads");
-	g_aLayers[LAYER_MAJORSTREET] = layers_new(LAYER_MAJORSTREET, "major-roads");
-	g_aLayers[LAYER_MINORHIGHWAY] = layers_new(LAYER_MINORHIGHWAY, "minor-highways");
-	g_aLayers[LAYER_MINORHIGHWAY_RAMP] = layers_new(LAYER_MINORHIGHWAY_RAMP, "minor-highway-ramps");
-	g_aLayers[LAYER_MAJORHIGHWAY] = layers_new(LAYER_MAJORHIGHWAY, "major-highways");
-	g_aLayers[LAYER_MAJORHIGHWAY_RAMP] = layers_new(LAYER_MAJORHIGHWAY_RAMP, "major-highway-ramps");
-	g_aLayers[LAYER_RAILROAD] = layers_new(LAYER_RAILROAD, "railroads");
-	g_aLayers[LAYER_PARK] = layers_new(LAYER_PARK, "parks");
-	g_aLayers[LAYER_RIVER] = layers_new(LAYER_RIVER, "rivers");
-	g_aLayers[LAYER_LAKE] = layers_new(LAYER_LAKE, "lakes");
-	g_aLayers[LAYER_MISC_AREA] = layers_new(LAYER_MISC_AREA, "misc-area");
-
 	/* init libxml */
 	LIBXML_TEST_VERSION
 
+	// Load
+	g_pLayersArray = g_ptr_array_new();
 	layers_load_from_file();
 }
 
-void
-layers_deinit(void)
+void layers_deinit(void)
 {
 	xmlCleanupParser();
 }
 
-void
-layers_reload(void)
+void layers_reload(void)
 {
+	// XXX: do some cleanup here!
+	g_warning("reloading styles leaks memory so... don't do it very often :)\n");
+	g_pLayersArray = g_ptr_array_new();
 	layers_load_from_file();
 }
 
-static layer_t*
-layers_new(gint index, gchar *name)
+static layer_t* layers_new_layer()
 {
-	layer_t *layer;
+	layer_t *pLayer = g_new0(layer_t, 1);
 
-	layer = g_new0(layer_t, 1);
-	layer->nLayerIndex = index;
-	layer->m_pszName = name;
+	gint i;
+	for(i=0 ; i<NUM_ZOOM_LEVELS ; i++) {
+		 layerstyle_t* pLayerStyle = g_new0(layerstyle_t, 1);
 
-	return layer;
+		 pLayerStyle->m_nCapStyle = MAP_CAP_STYLE_DEFAULT;
+
+		 // XXX: need to init the layerstyle_t's?
+		 pLayer->m_paStylesAtZoomLevels[i] = pLayerStyle;
+	}
+
+	return pLayer;
 }
 
-static void
-layers_load_from_file()
+gboolean layers_parse_zoomlevel(const gchar* pszZoomLevel, gint* pnReturnMinZoomLevel, gint* pnReturnMaxZoomLevel)
 {
-	xmlDocPtr doc = NULL;
-	xmlNodePtr root_element = NULL;
-	//int i;
+	gchar* pszStr = g_strdup(pszZoomLevel);
+	gboolean bReturn = TRUE;
+
+	gint nMin,nMax;
+
+	gchar* pszSeparator = g_strrstr(pszStr, "-");
+	if(pszSeparator != NULL) {
+		// parse a "5-8"
+		*pszSeparator = '\0';
+		nMin = atoi(pszStr);
+		nMax = atoi(pszSeparator+1);
+	}
+	else {
+		// parse a "5"
+		nMin = nMax = atoi(pszStr);
+	}
+
+	if(nMin < MIN_ZOOM_LEVEL || nMin > MAX_ZOOM_LEVEL) {
+		g_warning("zoom-level '%s' out of valid range (%d to %d)\n", pszZoomLevel, MIN_ZOOM_LEVEL, MAX_ZOOM_LEVEL);
+		bReturn = FALSE;
+	}
+	else if(nMax < MIN_ZOOM_LEVEL || nMax > MAX_ZOOM_LEVEL) {
+		g_warning("zoom-level '%s' out of valid range (%d to %d)\n", pszZoomLevel, MIN_ZOOM_LEVEL, MAX_ZOOM_LEVEL);
+		bReturn = FALSE;
+	}
+	else {
+		*pnReturnMinZoomLevel = nMin;
+		*pnReturnMaxZoomLevel = nMax;
+	}
+	g_free(pszStr);
+	return bReturn;
+}
+
+static void layers_load_from_file()
+{
+	xmlDocPtr pDoc = NULL;
+	xmlNodePtr pRootElement = NULL;
 
 	// Load style definition file
 	// try source directory first (good for development)
-	doc = xmlReadFile(PACKAGE_SOURCE_DIR"/data/layers.xml", NULL, 0);
-	if (doc == NULL) {
-		doc = xmlReadFile(PACKAGE_DATA_DIR"/data/layers.xml", NULL, 0);
+	pDoc = xmlReadFile(PACKAGE_SOURCE_DIR"/data/layers.xml", NULL, 0);
+	if(pDoc == NULL) {
+		pDoc = xmlReadFile(PACKAGE_DATA_DIR"/data/layers.xml", NULL, 0);
 
-		if (doc == NULL) {
+		if(pDoc == NULL) {
 			g_message("cannot load file layers.xml\n");
 			gtk_exit(0);
 		}
 	}
 
-	root_element = xmlDocGetRootElement(doc);
-
-	layers_parse_layers(doc, root_element);
+	pRootElement = xmlDocGetRootElement(pDoc);
 
-	/*
-	for (i = 1; i <= MAX_ZOOMLEVEL; i++)
-		layers_print_layer(g_aLayers[i]);
-	*/
+	layers_parse_file(pDoc, pRootElement);
 
-	xmlFreeDoc(doc);
+	xmlFreeDoc(pDoc);
 }
 
 
 /*****************************************************************
  * layers_parse_* functions for parsing the xml
  *****************************************************************/
-static void
-layers_parse_layers(xmlDocPtr doc, xmlNodePtr node)
+static void layers_parse_file(xmlDocPtr pDoc, xmlNodePtr pParentNode)
 {
-	xmlNodePtr cur_node = NULL;
+	xmlNodePtr pChildNode = NULL;
 
-	if (node->type == XML_ELEMENT_NODE && strcmp(node->name, "roadster-layers") == 0) {
-		for (cur_node = node->children; cur_node; cur_node = cur_node->next) {
-			if (cur_node->type == XML_ELEMENT_NODE && strcmp(cur_node->name, "layer") == 0) {
-				layers_parse_layer(doc, cur_node);
+	// The one top-level "layers" guy
+	if(pParentNode->type == XML_ELEMENT_NODE && strcmp(pParentNode->name, "layers") == 0) {
+		// iterate over "layer" objects
+		for(pChildNode = pParentNode->children; pChildNode != NULL; pChildNode = pChildNode->next) {
+			if(pChildNode->type == XML_ELEMENT_NODE && strcmp(pChildNode->name, "layer") == 0) {
+				layers_parse_layer(pDoc, pChildNode);
 			}
 		}
 	}
 }
 
 static void
-layers_parse_layer(xmlDocPtr doc, xmlNodePtr node)
+layers_parse_layer(xmlDocPtr pDoc, xmlNodePtr pNode)
 {
-	xmlNodePtr cur_node = NULL;
-	xmlAttrPtr cur_attr = NULL;
-	gchar *layer_name;
-	layer_t *layer = NULL;
+	xmlAttrPtr pAttribute = NULL;
 	gint i;
 
-	for (cur_attr = node->properties; cur_attr; cur_attr = cur_attr->next) {
-		if (!strcmp(cur_attr->name, "name")) {
-			layer_name = xmlNodeListGetString(doc, cur_attr->xmlChildrenNode, 1);
-			printf("parsing layer: %s\n", layer_name);
-			for (i = 0; i <= NUM_LAYERS; i++) {
-				if (!strcmp(g_aLayers[i]->m_pszName, layer_name))
-					layer = g_aLayers[i];
+	// create new layer
+	layer_t *pLayer = layers_new_layer();
+
+	// read attributes of the 'layer' node
+	for(EACH_ATTRIBUTE_OF_NODE(pAttribute, pNode)) {
+		if(strcmp(pAttribute->name, "data-source") == 0) {
+			gchar* pszDataSource = xmlNodeListGetString(pDoc, pAttribute->xmlChildrenNode, 1);
+
+			if(!map_object_type_atoi(pszDataSource, &(pLayer->m_nDataSource))) {
+				g_error("bad data source name %s\n", pszDataSource);
 			}
 		}
-	}
+		else if(strcmp(pAttribute->name, "draw-type") == 0) {
+			gchar* pszDrawType = xmlNodeListGetString(pDoc, pAttribute->xmlChildrenNode, 1);
 
-	if (layer) {
-		i = 0;
-		for (cur_node = node->children; cur_node; cur_node = cur_node->next) {
-			if (cur_node->type == XML_ELEMENT_NODE && strcmp(cur_node->name, "sublayer") == 0) {
-				if (i < 2)
-					layers_parse_sublayer(doc, &(layer->m_Style.m_aSubLayers[i]), cur_node);
-				i++;
-			} else if (cur_node->type == XML_ELEMENT_NODE && strcmp(cur_node->name, "label") == 0) {
-				layers_parse_label(doc, &(layer->m_TextLabelStyle), cur_node);
+			if(!map_layer_render_type_atoi(pszDrawType, &(pLayer->m_nDrawType))) {
+				g_error("bad layer draw type name %s\n", pszDrawType);
 			}
 		}
 	}
-}
-
-static void
-layers_parse_sublayer(xmlDocPtr doc, sublayerstyle_t *sublayer, xmlNodePtr node)
-{
-	xmlNodePtr cur_node = NULL;
 
-	for (cur_node = node->children; cur_node; cur_node = cur_node->next) {
-		if (cur_node->type == XML_ELEMENT_NODE && strcmp(cur_node->name, "property") == 0) {
-			layers_parse_sublayer_property(doc, sublayer, cur_node);
+	// read children of the 'layer' node
+	xmlNodePtr pChild = NULL;
+	for(EACH_CHILD_OF_NODE(pChild, pNode)) {
+		if(strcmp(pChild->name, "property") == 0) {
+			layers_parse_layer_property(pDoc, pLayer, pChild);
 		}
 	}
-}
-
-static void
-layers_parse_sublayer_property(xmlDocPtr doc, sublayerstyle_t *sublayer, xmlNodePtr node)
-{
-	xmlAttrPtr cur_attr = NULL;
-	gchar *name = NULL;
-	gchar *levelstr = NULL;
-	gchar *value = NULL;
-
-	for (cur_attr = node->properties; cur_attr; cur_attr = cur_attr->next) {
-		if (!strcmp(cur_attr->name, "name"))
-			name = xmlNodeListGetString(doc, cur_attr->xmlChildrenNode, 1);
-		else if (!strcmp(cur_attr->name, "level"))
-			levelstr = xmlNodeListGetString(doc, cur_attr->xmlChildrenNode, 1);
-		else if (!strcmp(cur_attr->name, "value"))
-			value = xmlNodeListGetString(doc, cur_attr->xmlChildrenNode, 1);
-	}
-
-	if (name && value) {
-		gdouble width;
-		gint i, level;
-
-		level = (levelstr? atoi(levelstr): 0);
 
-		if (!strcmp(name, "width")) {
-			for (i = level-1; i < MAX_ZOOMLEVEL; i++)
-				sublayer->m_afLineWidths[i] = (gdouble)atof(value);
-
-		} else if (!strcmp(name, "color")) {
-			layers_parse_color(&(sublayer->m_clrColor), value);
-
-		} else if (!strcmp(name, "join-style")) {
-			if (!strcmp(value, "mitre"))
-				sublayer->m_nJoinStyle = CAIRO_LINE_JOIN_MITER;
-			else if (!strcmp(value, "round"))
-				sublayer->m_nJoinStyle = CAIRO_LINE_JOIN_ROUND;
-
-		} else if (!strcmp(name, "cap-style")) {
-			if (!strcmp(value, "butt"))
-				sublayer->m_nCapStyle = CAIRO_LINE_CAP_BUTT;
-			else if (!strcmp(value, "round"))
-				sublayer->m_nCapStyle = CAIRO_LINE_CAP_ROUND;
-
-		} else if (!strcmp(name, "dash-style")) {
-			sublayer->m_nDashStyle = (gint)atoi(value);
+	// add it to list
+	g_ptr_array_add(g_pLayersArray, pLayer);
 
-		}
-	}
+//	layers_print_layer(pLayer);
 }
 
 static void
-layers_parse_label(xmlDocPtr doc, textlabelstyle_t *label_style, xmlNodePtr node)
+layers_parse_layer_property(xmlDocPtr pDoc, layer_t *pLayer, xmlNodePtr pNode)
 {
-	xmlNodePtr cur_node = NULL;
+	gchar* pszName = NULL;
+	gchar* pszValue = NULL;
+	gchar* pszZoomLevel = NULL;
 
-	for (cur_node = node->children; cur_node; cur_node = cur_node->next) {
-		if (cur_node->type == XML_ELEMENT_NODE && strcmp(cur_node->name, "property") == 0) {
-			layers_parse_label_property(doc, label_style, cur_node);
+	// Read 'name', 'value', and 'level' attributes of this property
+	xmlAttrPtr pAttribute = NULL;
+	for(EACH_ATTRIBUTE_OF_NODE(pAttribute, pNode)) {
+		if(strcmp(pAttribute->name, "name") == 0) {
+			pszName = xmlNodeListGetString(pDoc, pAttribute->xmlChildrenNode, 1);
+		}
+		else if(strcmp(pAttribute->name, "value") == 0) {
+			pszValue = xmlNodeListGetString(pDoc, pAttribute->xmlChildrenNode, 1);
+		}
+		else if((strcmp(pAttribute->name, "zoom-level") == 0) || (strcmp(pAttribute->name, "zoom-levels") == 0)) {
+			pszZoomLevel = xmlNodeListGetString(pDoc, pAttribute->xmlChildrenNode, 1);
 		}
 	}
-}
-
-static void
-layers_parse_label_property(xmlDocPtr doc, textlabelstyle_t *label_style, xmlNodePtr node)
-{
-	xmlAttrPtr cur_attr = NULL;
-	gchar *name = NULL;
-	gchar *levelstr = NULL;
-	gchar *value = NULL;
 
-	for (cur_attr = node->properties; cur_attr; cur_attr = cur_attr->next) {
-		if (!strcmp(cur_attr->name, "name"))
-			name = xmlNodeListGetString(doc, cur_attr->xmlChildrenNode, 1);
-		else if (!strcmp(cur_attr->name, "level"))
-			levelstr = xmlNodeListGetString(doc, cur_attr->xmlChildrenNode, 1);
-		else if (!strcmp(cur_attr->name, "value"))
-			value = xmlNodeListGetString(doc, cur_attr->xmlChildrenNode, 1);
+	gint nMinZoomLevel = MIN_ZOOM_LEVEL;
+	gint nMaxZoomLevel = MAX_ZOOM_LEVEL;
+	if(pszZoomLevel != NULL) {
+		layers_parse_zoomlevel(pszZoomLevel, &nMinZoomLevel, &nMaxZoomLevel);
 	}
 
-	if (name && value) {
-		gint i, level;
-
-		level = (levelstr? atoi(levelstr): 0);
-
-		if (!strcmp(name, "font-size")) {
-			for (i = level-1; i < MAX_ZOOMLEVEL; i++)
-				label_style->m_afFontSizeAtZoomLevel[i] = (gdouble)atof(value);
-			
-		} else if (!strcmp(name, "bold")) {
-			for (i = level-1; i < MAX_ZOOMLEVEL; i++)
-				label_style->m_abBoldAtZoomLevel[i] = (strcmp(value, "yes")? 0: 1);
-			
-		} else if (!strcmp(name, "halo")) {
-			for (i = level-1; i < MAX_ZOOMLEVEL; i++)
-				label_style->m_afHaloAtZoomLevel[i] = (gdouble)atof(value);
-			
-		} else if (!strcmp(name, "color")) {
-			layers_parse_color(&(label_style->m_clrColor), value);
+	if(pszName != NULL && pszValue != NULL) {
+		gint i;
+		if(strcmp(pszName, "line-width") == 0) {
+			for(i = nMinZoomLevel - 1; i < nMaxZoomLevel ; i++) {
+				pLayer->m_paStylesAtZoomLevels[i]->m_fLineWidth = (gdouble)atof(pszValue);
+			}
+		}
+		else if(strcmp(pszName, "line-width") == 0) {
+			for(i = nMinZoomLevel - 1; i < nMaxZoomLevel ; i++) {
+				pLayer->m_paStylesAtZoomLevels[i]->m_fLineWidth = (gdouble)atof(pszValue);
+			}
+		}
+		else if(strcmp(pszName, "color") == 0) {
+			for(i = nMinZoomLevel - 1; i < nMaxZoomLevel ; i++) {
+				util_parse_hex_color(pszValue, &(pLayer->m_paStylesAtZoomLevels[i]->m_clrPrimary));
+			}
+		}
+		else if(strcmp(pszName, "halo-size") == 0) {
+			for(i = nMinZoomLevel - 1; i < nMaxZoomLevel ; i++) {
+				pLayer->m_paStylesAtZoomLevels[i]->m_fHaloSize = (gdouble)atof(pszValue);
+			}
+		}
+		else if(strcmp(pszName, "dash-style") == 0) {
+			for(i = nMinZoomLevel - 1; i < nMaxZoomLevel ; i++) {
+				pLayer->m_paStylesAtZoomLevels[i]->m_nDashStyle = (gint)atoi(pszValue);	// XXX: must validate #
+			}
+		}
+		else if(strcmp(pszName, "bold") == 0) {
+			gboolean bBold = (strcmp(pszValue, "yes") == 0);
+			for(i = nMinZoomLevel - 1; i < nMaxZoomLevel ; i++) {
+				pLayer->m_paStylesAtZoomLevels[i]->m_bFontBold = bBold;
+			}
+		}
+		else if(strcmp(pszName, "halo-color") == 0) {
+			for(i = nMinZoomLevel - 1; i < nMaxZoomLevel ; i++) {
+				util_parse_hex_color(pszValue, &(pLayer->m_paStylesAtZoomLevels[i]->m_clrHalo));
+			}
+		}
+		else if(strcmp(pszName, "font-size") == 0) {
+			for(i = nMinZoomLevel - 1; i < nMaxZoomLevel ; i++) {
+				pLayer->m_paStylesAtZoomLevels[i]->m_fFontSize = (gdouble)atof(pszValue);
+			}
+		}
+//         else if(strcmp(pszName, "join-style") == 0) {
+//             for(i = nMinZoomLevel - 1; i < nMaxZoomLevel ; i++) {
+//                 if(strcmp(pszValue, "mitre") == 0) {
+//                     pLayer->m_paStylesAtZoomLevels[i]->m_nJoinStyle = CAIRO_LINE_JOIN_MITER;
+//                 }
+//                 else if(strcmp(pszValue, "round") == 0) {
+//                     pLayer->m_paStylesAtZoomLevels[i]->m_nJoinStyle = CAIRO_LINE_JOIN_ROUND;
+//                 }
+//             }
+//         }
+		else if(strcmp(pszName, "line-cap") == 0) {
+			if(strcmp(pszValue, "square") == 0) {
+				for(i = nMinZoomLevel - 1; i < nMaxZoomLevel ; i++) {
+					pLayer->m_paStylesAtZoomLevels[i]->m_nCapStyle = MAP_CAP_STYLE_SQUARE;
+				}
+			}
+			else {
+				if(strcmp(pszValue, "round") != 0) { g_warning("bad value for line-cap found: '%s' (valid options are 'square' and 'round')\n", pszValue); }
 
+				for(i = nMinZoomLevel - 1; i < nMaxZoomLevel ; i++) {
+					pLayer->m_paStylesAtZoomLevels[i]->m_nCapStyle = MAP_CAP_STYLE_ROUND;
+				}
+			}
 		}
 	}
 }
 
+/******************************************************************
+ * layers_print_* functions for debugging
+ *****************************************************************/
 static void
-layers_parse_color(color_t *color, gchar *value)
+layers_print_color(color_t* pColor)
 {
-	gchar *ptr;
+	g_print("color: %3.2f, %3.2f, %3.2f, %3.2f\n", pColor->m_fRed, pColor->m_fGreen, pColor->m_fBlue, pColor->m_fAlpha);
+}
 
-	ptr = value;
-	if (*ptr == '#') ptr++;
+/*
+  	color_t m_clrPrimary;	// Color used for polygon fill or line stroke
+	gdouble m_fLineWidth;
 
-	if (strlen(ptr) < 8) {
-		g_warning("bad color value found: %s\n", value);
-		return;
-	}
+	gint m_nJoinStyle;
+	gint m_nCapStyle;
 
-	// Read RGBA hex doubles (eg. "H8") in reverse order
-	ptr += 6;
-	color->m_fAlpha = (gfloat)strtol(ptr, NULL, 16)/255.0;
-	*ptr = '\0';
-	ptr -= 2;
-	color->m_fBlue = (gfloat)strtol(ptr, NULL, 16)/255.0;
-	*ptr = '\0';
-	ptr -= 2;
-	color->m_fGreen = (gfloat)strtol(ptr, NULL, 16)/255.0;
-	*ptr = '\0';
-	ptr -= 2;
-	color->m_fRed = (gfloat)strtol(ptr, NULL, 16)/255.0;
-}
+	gint m_nDashStyle;
 
+	// XXX: switch to this:
+	//dashstyle_t m_pDashStyle;	// can be NULL
 
-/******************************************************************
- * layers_print_* functions for debugging
- *****************************************************************/
-static void
-layers_print_layer(layer_t *layer)
-{
-	printf("---------------\nlayer: %s (%d)\n", layer->m_pszName, layer->nLayerIndex);
-	layers_print_sublayer(&(layer->m_Style.m_aSubLayers[0]));
-	layers_print_sublayer(&(layer->m_Style.m_aSubLayers[1]));
-	//layers_print_labelstyle(&(layer->m_TextLabelStyle));
-}
+	// Used just for text
+	gdouble m_fFontSize;
+	gboolean m_bBold;
+	gdouble m_fHaloSize;	// actually a stroke width
+	color_t m_clrHalo;
+*/
 
 static void
-layers_print_sublayer(sublayerstyle_t *sublayer)
+layers_print_layer(layer_t *pLayer)
 {
 	int i;
 
-	printf("line widths: ");
-	for(i = MIN_ZOOMLEVEL; i <= MAX_ZOOMLEVEL; i++) printf(" %2.2f", sublayer->m_afLineWidths[i]);
-	printf("\n");
+	for(i = 0 ; i < NUM_ZOOM_LEVELS ; i++) {
+		g_print("\nzoom level %d\n", i+1);
+		layerstyle_t* pStyle = pLayer->m_paStylesAtZoomLevels[i];
 
-	layers_print_color(&(sublayer->m_clrColor));
-	
-	printf("join style: %d\n", sublayer->m_nJoinStyle);
-	printf("cap style: %d\n", sublayer->m_nCapStyle);
-	printf("dash style: %d\n", sublayer->m_nDashStyle);
+		g_print("  line width: %f\n", pStyle->m_fLineWidth);
+		g_print("  primary "); layers_print_color(&(pStyle->m_clrPrimary));
+		g_print("  join style: %d\n", pStyle->m_nJoinStyle);
+		g_print("  cap style: %d\n", pStyle->m_nCapStyle);
+		g_print("  dash style: %d\n", pStyle->m_nDashStyle);
+	}
 }
 
-static void
-layers_print_color(color_t *color)
-{
-	printf("color: %3.2f, %3.2f, %3.2f, %3.2f\n", color->m_fRed, color->m_fGreen, color->m_fBlue, color->m_fAlpha);
-}
+

Index: layers.h
===================================================================
RCS file: /cvs/cairo/roadster/src/layers.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- layers.h	31 Aug 2005 08:37:53 -0000	1.7
+++ layers.h	6 Sep 2005 02:44:19 -0000	1.8
@@ -29,28 +29,6 @@
 
 G_BEGIN_DECLS
 
-#define LAYER_NONE					(0)
-
-#define LAYER_MINORSTREET			(1)
-#define LAYER_MAJORSTREET			(2)
-
-#define LAYER_MINORHIGHWAY			(3)
-#define LAYER_MINORHIGHWAY_RAMP		(4)
-
-#define LAYER_MAJORHIGHWAY			(5)	// used?
-#define LAYER_MAJORHIGHWAY_RAMP		(6)	// used?
-
-#define LAYER_RAILROAD				(7)
-#define LAYER_PARK					(8)
-#define LAYER_RIVER					(9)
-#define LAYER_LAKE					(10)
-#define LAYER_MISC_AREA				(11)
-
-#define NUM_LAYERS 					(11)
-
-#define LAYER_FIRST				(1)
-#define LAYER_LAST				(11)
-
 #include "map.h"
 
 typedef struct color {
@@ -67,37 +45,37 @@
 	gint8* m_panDashList;	// the dashes, as integers (for GDK)
 	gint m_nDashCount;
 } dashstyle_t;
-dashstyle_t g_aDashStyles[NUM_DASH_STYLES];
 
-typedef struct sublayerstyle {
-	gdouble m_afLineWidths[MAX_ZOOM_LEVEL];
-	color_t m_clrColor;
-	gint m_nDashStyle;
+// defines the look of a layer
+typedef struct layerstyle {
+	color_t m_clrPrimary;	// Color used for polygon fill or line stroke
+	gdouble m_fLineWidth;
+
 	gint m_nJoinStyle;
 	gint m_nCapStyle;
-} sublayerstyle_t;
+	gint m_nDashStyle;
 
-typedef struct textlabelstyle {
-	gdouble m_afFontSizeAtZoomLevel[MAX_ZOOM_LEVEL];
-	gint m_abBoldAtZoomLevel[MAX_ZOOM_LEVEL];	// 0s or 1s
-	gint m_afHaloAtZoomLevel[MAX_ZOOM_LEVEL];	// stroke width
-	color_t m_clrColor;
-	// font family...
-} textlabelstyle_t;
+	// XXX: switch to this:
+	//dashstyle_t m_pDashStyle;	// can be NULL
 
-// defines the look of a layer
-typedef struct layerstyle {
-	sublayerstyle_t m_aSubLayers[2];
+	// Used just for text
+	gdouble m_fFontSize;
+	gboolean m_bFontBold;
+	gdouble m_fHaloSize;	// actually a stroke width
+	color_t m_clrHalo;
 } layerstyle_t;
 
 typedef struct layer {
-	gint nLayerIndex;
-	gchar* m_pszName;
-	layerstyle_t m_Style;
-	textlabelstyle_t m_TextLabelStyle;
+	gint m_nDataSource;		// which data to use (lakes, roads...)
+	gint m_nDrawType;		// as lines, polygons, etc.
+
+	// A layer has a style for each zoomlevel
+	layerstyle_t* m_paStylesAtZoomLevels[ NUM_ZOOM_LEVELS ];
 } layer_t;
 
-extern layer_t * g_aLayers[NUM_LAYERS+1];
+//extern layer_t * g_aLayers[NUM_LAYERS+1];
+extern GPtrArray* g_pLayersArray;
+extern dashstyle_t g_aDashStyles[NUM_DASH_STYLES];
 
 void layers_init(void);
 void layers_deinit(void);

Index: mainwindow.c
===================================================================
RCS file: /cvs/cairo/roadster/src/mainwindow.c,v
retrieving revision 1.38
retrieving revision 1.39
diff -u -d -r1.38 -r1.39
--- mainwindow.c	28 Aug 2005 22:23:14 -0000	1.38
+++ mainwindow.c	6 Sep 2005 02:44:19 -0000	1.39
@@ -27,6 +27,10 @@
 
 #include <gtk/gtk.h>
 #include <gtk/gtksignal.h>
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include <cairo.h>
+#include <cairo-xlib.h>
 
 #include "main.h"
 #include "search_road.h"
@@ -46,14 +50,6 @@
 #include "history.h"
 #include "tooltip.h"
 
-#include <gdk/gdk.h>
-#include <gdk/gdkx.h>
-#include <cairo.h>
-
-#ifdef HAVE_CAIRO_0_2_0
-#  include <cairo-xlib.h>
-#endif
-
 #define PROGRAM_NAME			"Roadster"
 #define PROGRAM_COPYRIGHT		"Copyright (c) 2005 Ian McIntosh"
 #define PROGRAM_DESCRIPTION		"Mapping for everyone!"
@@ -67,7 +63,7 @@
 
 #define SCROLL_TIMEOUT_MS		(80)		// how often (in MS) to move
 #define SCROLL_DISTANCE_IN_PIXELS	(100)		// how far to move every (above) MS
-#define BORDER_SCROLL_CLICK_TARGET_SIZE	(20)		// the size of the click target (distance from edge of map view) to begin scrolling
+#define BORDER_SCROLL_CLICK_TARGET_SIZE	(16)		// the size of the click target (distance from edge of map view) to begin scrolling
 
 #define SLIDE_TIMEOUT_MS		(50)	// time between frames (in MS) for smooth-sliding (on double click?)
 #define	SLIDE_TIME_IN_SECONDS		(0.4)	// how long the whole slide should take, in seconds
@@ -1037,11 +1033,11 @@
 	if(g_MainWindow.m_bMouseDragging) {
 		g_MainWindow.m_bMouseDragMovement = TRUE;
 
-		// Set it here and no when first clicking because now we know it's a drag (on click it could be a double-click)
+		// Set cursor here and not when first clicking because now we know it's a drag (on click it could be a double-click)
 		nCursor = GDK_FLEUR;
 
 		gint nDeltaX = g_MainWindow.m_ptClickLocation.m_nX - nX;
-                gint nDeltaY = g_MainWindow.m_ptClickLocation.m_nY - nY;
+		gint nDeltaY = g_MainWindow.m_ptClickLocation.m_nY - nY;
 
 		if(nDeltaX == 0 && nDeltaY == 0) return TRUE;
 
@@ -1072,8 +1068,11 @@
 		}
 	}
 	else {
+		// If not dragging or scrolling, user is just moving mouse around.
+		// Update tooltip and mouse cursor based on what we're pointing at.
+
 		EDirection eScrollDirection = match_border(nX, nY, nWidth, nHeight, BORDER_SCROLL_CLICK_TARGET_SIZE);
-  
+
 		if(eScrollDirection == DIRECTION_NONE) {
 			// get mouse position on screen
 			screenpoint_t screenpoint;
@@ -1132,11 +1131,11 @@
 		else {
 			nCursor = g_aDirectionCursors[eScrollDirection].m_nCursor;
 
-			// using a funky cursor. hide the tooltip
+			// using a funky (non-pointer) cursor so hide the tooltip
 			tooltip_hide(g_MainWindow.m_pTooltip);
 		}
 	}
-	// just set cursor based on what we're hovering over
+	// apply cursor that was chosen above
 	GdkCursor* pCursor = gdk_cursor_new(nCursor);
 	gdk_window_set_cursor(GTK_WIDGET(g_MainWindow.m_pDrawingArea)->window, pCursor);
 	gdk_cursor_unref(pCursor);
@@ -1153,7 +1152,6 @@
 	tooltip_hide(g_MainWindow.m_pTooltip);
 }
 
-
 static gboolean mainwindow_on_mouse_scroll(GtkWidget* w, GdkEventScroll *event)
 {
 	// respond to scroll wheel events by zooming in and out
@@ -1176,12 +1174,13 @@
 g_print("starting..\n");
 
 	GtkWidget* pDialog = gtk_file_chooser_dialog_new(
-				"Select Map Data for Import",
+						"Select TIGER .ZIP files for Import",
                 		g_MainWindow.m_pWindow,
 		                GTK_FILE_CHOOSER_ACTION_OPEN,
-    				GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-				"Import", GTK_RESPONSE_ACCEPT,
-				NULL);
+						GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+						"Import", GTK_RESPONSE_ACCEPT,
+						NULL);
+
 g_print("setting..\n");
 	gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(pDialog), TRUE);
 	gtk_widget_set_sensitive(GTK_WIDGET(g_MainWindow.m_pWindow), FALSE);
@@ -1223,9 +1222,10 @@
 	}
 }
 
-// Handler for ALL tool buttons
+// One handler for all 'tools' buttons
 void mainwindow_on_toolbutton_clicked(GtkToolButton *toolbutton, gpointer user_data)
 {
+	// XXX: current there are no tools!
 	mainwindow_setup_selected_tool();
 }
 
@@ -1573,7 +1573,7 @@
 	// get an iterator for this item
 	GtkTreePath *pPath = gtk_tree_path_new_from_string(pszPath);
 	GtkTreeIter iter;
-	gtk_tree_model_get_iter(g_MainWindow.m_pLocationSetsListStore, &iter, pPath);
+	gtk_tree_model_get_iter(GTK_TREE_MODEL(g_MainWindow.m_pLocationSetsListStore), &iter, pPath);
 	gtk_tree_path_free (pPath);
 
 	// get locationset ID and whether it's set or not
@@ -1601,19 +1601,6 @@
 
 #ifdef ROADSTER_DEAD_CODE
 /*
-
-void on_importmenuitem_activate(GtkMenuItem *menuitem, gpointer user_data)
-{
-	g_print("on_importmenuitem_activate\n");
-	importwindow_show();
-}
-
-
-void mainwindow_on_datasetmenuitem_activate(GtkWidget *pWidget, gpointer* p)
-{
-	datasetwindow_show();
-}
-
 static gboolean on_searchbox_key_press_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
 {
 	// Enter key?
@@ -1625,36 +1612,5 @@
 	}
 	return FALSE;
 }
-
-// Show preferences dialog
-static void on_preferencesmenuitem_activate(GtkMenuItem *menuitem, gpointer user_data)
-{
-//	gui_show_preferences_window();
-}
-
-void mainwindow_load_locationset_list(void)
-{
-	const GPtrArray* pLocationSetArray = locationset_get_set_array();
-
-	// add some data to the layers list
-	GtkTreeIter iter;
-
-	GtkListStore* pListStore = (GtkListStore*)gtk_tree_view_get_model(g_MainWindow.m_pLocationSetsTreeView);
-	g_assert(pListStore != NULL);
-
-	// Add each locationset to treeview
-	int i;
-	for(i=0 ; i<pLocationSetArray->len ; i++) {
-		locationset_t* pLocationSet = g_ptr_array_index(pLocationSetArray, i);
-
-		gboolean bEnabled = TRUE;
-
-		gtk_list_store_append(pListStore, &iter);
-		gtk_list_store_set(pListStore, &iter,
-			LAYERLIST_COLUMN_ENABLED, bEnabled,
-			LAYERLIST_COLUMN_NAME, pLocationSet->m_pszName,
-			-1);
-	}
-}
 */
 #endif /* ROADSTER_DEAD_CODE */

Index: map.c
===================================================================
RCS file: /cvs/cairo/roadster/src/map.c,v
retrieving revision 1.42
retrieving revision 1.43
diff -u -d -r1.42 -r1.43
--- map.c	31 Aug 2005 08:37:53 -0000	1.42
+++ map.c	6 Sep 2005 02:44:19 -0000	1.43
@@ -39,10 +39,9 @@
 #include "location.h"
 #include "scenemanager.h"
 
-
 #define ENABLE_RIVER_TO_LAKE_LOADTIME_HACK	// change circular rivers to lakes when loading from disk
 //#define ENABLE_SCENEMANAGER_DEBUG_TEST
-
+#define ENABLE_LABELS_WHILE_DRAGGING
 
 #ifdef THREADED_RENDERING
 #define RENDERING_THREAD_YIELD          g_thread_yield()
@@ -88,61 +87,35 @@
 void map_get_render_metrics(map_t* pMap, rendermetrics_t* pMetrics);
 
 // Each zoomlevel has a scale and an optional name (name isn't used for anything)
-zoomlevel_t g_sZoomLevels[NUM_ZOOMLEVELS+1] = {
-	{1,"undefined"},	// no zoom level 0
-
-	{ 1600000, ""},		// 1
-	{  800000, ""},		// 2
-	{  400000, ""},		// 3
+zoomlevel_t g_sZoomLevels[NUM_ZOOM_LEVELS+1] = {
+	{1,0,0,0,0,"undefined"},	// no zoom level 0
 
-	{  200000, ""},		// 4
-	{  100000, ""},		// 5
+//     { 1600000, ""},
+//     {  800000, ""},
+//     {  400000, ""},
+//     {  200000, ""},
+//     {  100000, ""},
 
-	{   35000, ""},		// 6
-	{   20000, ""}, 	// 7
-	{   10000, ""},		// 8
-	{    4000, ""},		// 9
-	{    1700, ""},		// 10
+	{  100000, UNIT_MILES, 2, 	UNIT_KILOMETERS, 2, "", },     	// 1
+	{   48000, UNIT_MILES, 1, 	UNIT_KILOMETERS, 1, "", },     	// 2
+	{   20000, UNIT_FEET, 2000, UNIT_METERS, 400, "", }, 		// 3
+	{   10000, UNIT_FEET, 1000, UNIT_METERS, 200, "", },		// 4
+	{    5000, UNIT_FEET, 500, 	UNIT_METERS, 100, "", },		// 5
 };
 
-draworder_t layerdraworder[NUM_SUBLAYER_TO_DRAW] = {
-
-	{LAYER_MISC_AREA, 0, SUBLAYER_RENDERTYPE_POLYGONS}, //map_draw_layer_polygons},
-
-//	{LAYER_PARK, 0, SUBLAYER_RENDERTYPE_LINES}, //map_draw_layer_lines},
-	{LAYER_PARK, 1, SUBLAYER_RENDERTYPE_POLYGONS}, //map_draw_layer_polygons},
-
-//	{LAYER_LAKE, 0, SUBLAYER_RENDERTYPE_LINES},	// NOTE: drawing lines BELOW polygons (and ~double width) lets us avoid drawing seams on top of multi-polygon lakes
-//	{LAYER_RIVER, 0, SUBLAYER_RENDERTYPE_LINES}, //map_draw_layer_lines},	// single-line rivers
-	
-	{LAYER_LAKE, 1, SUBLAYER_RENDERTYPE_POLYGONS},
-	{LAYER_RIVER, 1, SUBLAYER_RENDERTYPE_LINES}, //map_draw_layer_lines},	// single-line rivers
-
-	{LAYER_MINORHIGHWAY_RAMP, 0, SUBLAYER_RENDERTYPE_LINES}, //map_draw_layer_lines},
-	{LAYER_MINORSTREET, 0, SUBLAYER_RENDERTYPE_LINES}, //map_draw_layer_lines},
-	{LAYER_MAJORSTREET, 0, SUBLAYER_RENDERTYPE_LINES}, //map_draw_layer_lines},
-
-	{LAYER_MINORHIGHWAY_RAMP, 1, SUBLAYER_RENDERTYPE_LINES}, //map_draw_layer_lines},
-	{LAYER_MINORSTREET, 1, SUBLAYER_RENDERTYPE_LINES}, //map_draw_layer_lines},
-
-	{LAYER_MAJORSTREET, 1, SUBLAYER_RENDERTYPE_LINES}, //map_draw_layer_lines},
-
-	{LAYER_RAILROAD, 0, SUBLAYER_RENDERTYPE_LINES}, //map_draw_layer_lines},
-	{LAYER_RAILROAD, 1, SUBLAYER_RENDERTYPE_LINES}, //map_draw_layer_lines},
-
-	{LAYER_MINORHIGHWAY, 0, SUBLAYER_RENDERTYPE_LINES}, //map_draw_layer_lines},
-	{LAYER_MINORHIGHWAY, 1, SUBLAYER_RENDERTYPE_LINES}, //map_draw_layer_lines},
-
-	// LABELS
-	{LAYER_MINORHIGHWAY, 0, SUBLAYER_RENDERTYPE_LINE_LABELS},
-	{LAYER_MAJORSTREET, 0, SUBLAYER_RENDERTYPE_LINE_LABELS},	// important ones first
-	{LAYER_MINORSTREET, 0, SUBLAYER_RENDERTYPE_LINE_LABELS},
-	{LAYER_RAILROAD, 0, SUBLAYER_RENDERTYPE_LINE_LABELS},
-///     {LAYER_MAJORHIGHWAY, 0, SUBLAYER_RENDERTYPE_LABELS},
-
-	{LAYER_MISC_AREA, 0, SUBLAYER_RENDERTYPE_POLYGON_LABELS},
-	{LAYER_PARK, 0, SUBLAYER_RENDERTYPE_POLYGON_LABELS},
-	{LAYER_LAKE, 0, SUBLAYER_RENDERTYPE_POLYGON_LABELS},
+gchar* g_apszMapObjectTypeNames[] = {
+	"",
+	"minor-roads",
+	"major-roads",
+	"minor-highways",
+	"minor-highway-ramps",
+	"major-highways",
+	"major-highway-ramps",
+	"railroads",
+	"parks",
+	"rivers",
+	"lakes",
+	"misc-areas"
 };
 
 // ========================================================
@@ -195,7 +168,7 @@
 	scenemanager_new(&(pMap->m_pSceneManager));
 	g_assert(pMap->m_pSceneManager);
 
-	pMap->m_uZoomLevel = 8;
+	pMap->m_uZoomLevel = 1;		// XXX: better way to init this?  or should we force the GUI to reflect this #?
 
 	// init containers for geometry data
 	gint i;
@@ -248,32 +221,35 @@
 	map_get_render_metrics(pMap, &renderMetrics);
 	rendermetrics_t* pRenderMetrics = &renderMetrics;
 
-	scenemanager_clear(pMap->m_pSceneManager);
-	scenemanager_set_screen_dimensions(pMap->m_pSceneManager, pRenderMetrics->m_nWindowWidth, pRenderMetrics->m_nWindowHeight);
-
 	// Load geometry
 	TIMER_BEGIN(loadtimer, "--- BEGIN ALL DB LOAD");
 	map_data_clear(pMap);
 	map_data_load_tiles(pMap, &(pRenderMetrics->m_rWorldBoundingBox));
 	TIMER_END(loadtimer, "--- END ALL DB LOAD");
 
+	scenemanager_clear(pMap->m_pSceneManager);
+	scenemanager_set_screen_dimensions(pMap->m_pSceneManager, pRenderMetrics->m_nWindowWidth, pRenderMetrics->m_nWindowHeight);
+
 	gint nRenderMode = RENDERMODE_FAST; // RENDERMODE_PRETTY
 
+#ifdef ENABLE_LABELS_WHILE_DRAGGING
+	nDrawFlags |= DRAWFLAG_LABELS;	// always turn on labels
+#endif
+
 #ifdef ENABLE_SCENEMANAGER_DEBUG_TEST
-	GdkRectangle rect = {200,200,100,100};
-	scenemanager_claim_rectangle(pMap->m_pSceneManager, &rect);
+	GdkPoint aPoints[] = {{200,150},{250,200},{200,250},{150,200}};
+	scenemanager_claim_polygon(pMap->m_pSceneManager, aPoints, 4);
 #endif
 
 	if(nRenderMode == RENDERMODE_FAST) {
 		// 
 		if(nDrawFlags & DRAWFLAG_GEOMETRY) {
 			map_draw_gdk(pMap, pRenderMetrics, pMap->m_pPixmap, DRAWFLAG_GEOMETRY);
-			//g_print("geometry\n");
 		}
+		
 		// Always draw labels with Cairo
 		if(nDrawFlags & DRAWFLAG_LABELS) {
 			map_draw_cairo(pMap, pRenderMetrics, pMap->m_pPixmap, DRAWFLAG_LABELS);
-			//g_print("text\n");
 		}
 	}
 	else {	// nRenderMode == RENDERMODE_PRETTY
@@ -281,8 +257,8 @@
 	}
 
 #ifdef ENABLE_SCENEMANAGER_DEBUG_TEST
-        gdk_draw_rectangle(pMap->m_pPixmap, pMap->m_pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->m_pTargetWidget)],
-                           FALSE, 200,200, 100, 100);
+	gdk_draw_polygon(pMap->m_pPixmap, pMap->m_pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->m_pTargetWidget)],
+					 FALSE, aPoints, 4);
 #endif
 
 	gtk_widget_queue_draw(pMap->m_pTargetWidget);
@@ -309,8 +285,8 @@
 
 void map_set_zoomlevel(map_t* pMap, guint16 uZoomLevel)
 {
-	if(uZoomLevel > MAX_ZOOMLEVEL) uZoomLevel = MAX_ZOOMLEVEL;
-	else if(uZoomLevel < MIN_ZOOMLEVEL) uZoomLevel = MIN_ZOOMLEVEL;
+	if(uZoomLevel > MAX_ZOOM_LEVEL) uZoomLevel = MAX_ZOOM_LEVEL;
+	else if(uZoomLevel < MIN_ZOOM_LEVEL) uZoomLevel = MIN_ZOOM_LEVEL;
 
 	if(uZoomLevel != pMap->m_uZoomLevel) {
 		pMap->m_uZoomLevel = uZoomLevel;
@@ -320,7 +296,7 @@
 
 guint16 map_get_zoomlevel(map_t* pMap)
 {
-	return pMap->m_uZoomLevel;	// between MIN_ZOOMLEVEL and MAX_ZOOMLEVEL
+	return pMap->m_uZoomLevel;	// between MIN_ZOOM_LEVEL and MAX_ZOOM_LEVEL
 }
 
 guint32 map_get_zoomlevel_scale(map_t* pMap)
@@ -608,7 +584,7 @@
 
 			// Get layer type that this belongs on
 			gint nTypeID = atoi(aRow[1]);
-			if(nTypeID < LAYER_FIRST || nTypeID > LAYER_LAST) {
+			if(nTypeID < MAP_OBJECT_TYPE_FIRST || nTypeID > MAP_OBJECT_TYPE_LAST) {
 				//g_warning("geometry record '%s' has bad type '%s'\n", aRow[0], aRow[1]);
 				continue;
 			}
@@ -642,12 +618,12 @@
 			pNewRoad->m_pszName = g_strdup(azFullName);
 
 #ifdef ENABLE_RIVER_TO_LAKE_LOADTIME_HACK
-			if(nTypeID == LAYER_RIVER) {
+			if(nTypeID == MAP_OBJECT_TYPE_RIVER) {
 				mappoint_t* pPointA = g_ptr_array_index(pNewRoad->m_pPointsArray, 0);
 				mappoint_t* pPointB = g_ptr_array_index(pNewRoad->m_pPointsArray, pNewRoad->m_pPointsArray->len-1);
 
 				if(pPointA->m_fLatitude == pPointB->m_fLatitude && pPointA->m_fLongitude == pPointB->m_fLongitude) {
-					nTypeID = LAYER_LAKE;
+					nTypeID = MAP_OBJECT_TYPE_LAKE;
 				}
 			}
 #endif
@@ -675,7 +651,7 @@
 	g_return_val_if_fail(pMap != NULL, FALSE);
 	g_return_val_if_fail(pRect != NULL, FALSE);
 
-	if(map_get_zoomlevel(pMap) < MIN_ZOOMLEVEL_FOR_LOCATIONS) {
+	if(map_get_zoomlevel(pMap) < MIN_ZOOM_LEVEL_FOR_LOCATIONS) {
 		return TRUE;
 	}
 
@@ -837,6 +813,7 @@
 // XXX: perhaps make map_hit_test return a more complex structure indicating what type of hit it is?
 gboolean map_hit_test(map_t* pMap, mappoint_t* pMapPoint, maphit_t** ppReturnStruct)
 {
+#if 0	// GGGGGGGGGGGGGGGG
 	rendermetrics_t rendermetrics;
 	map_get_render_metrics(pMap, &rendermetrics);
 
@@ -872,6 +849,7 @@
 		}
 		// otherwise try next layer...
 	}
+#endif
 	return FALSE;
 }
 
@@ -1206,11 +1184,11 @@
 gboolean map_can_zoom_in(map_t* pMap)
 {
 	// can we increase zoom level?
-	return (pMap->m_uZoomLevel < MAX_ZOOMLEVEL);
+	return (pMap->m_uZoomLevel < MAX_ZOOM_LEVEL);
 }
 gboolean map_can_zoom_out(map_t* pMap)
 {
-	return (pMap->m_uZoomLevel > MIN_ZOOMLEVEL);
+	return (pMap->m_uZoomLevel > MIN_ZOOM_LEVEL);
 }
 
 
@@ -1234,7 +1212,7 @@
 {
 	locationselection_t* pA = *((locationselection_t**)ppA);
 	locationselection_t* pB = *((locationselection_t**)ppB);
-	
+
 	// we want them ordered from greatest latitude to smallest
 	return ((pA->m_Coordinates.m_fLatitude > pB->m_Coordinates.m_fLatitude) ? -1 : 1);
 }
@@ -1252,7 +1230,7 @@
 
 	pNew->m_nLocationID = nLocationID;
 	pNew->m_pAttributesArray = g_ptr_array_new();
-	
+
 	// load all attributes
 	location_load(nLocationID, &(pNew->m_Coordinates), NULL);
 	location_load_attributes(nLocationID, pNew->m_pAttributesArray);
@@ -1290,3 +1268,29 @@
 	}
 	return NULL;
 }
+
+gboolean map_object_type_atoi(const gchar* pszName, gint* pnReturnObjectTypeID)
+{
+	gint i;
+	for(i=0 ; i<MAP_NUM_OBJECT_TYPES ; i++) {
+		if(strcmp(pszName, g_apszMapObjectTypeNames[i]) == 0) {
+			*pnReturnObjectTypeID = i;
+			return TRUE;
+		}
+	}
+	return FALSE;
+}
+
+gboolean map_layer_render_type_atoi(const gchar* pszName, gint* pnReturnRenderTypeID)
+{
+	gchar* g_apszMapRenderTypeNames[] = {"lines", "polygons", "line-labels", "polygon-labels"};
+
+	gint i;
+	for(i=0 ; i<G_N_ELEMENTS(g_apszMapRenderTypeNames) ; i++) {
+		if(strcmp(pszName, g_apszMapRenderTypeNames[i]) == 0) {
+			*pnReturnRenderTypeID = i;
+			return TRUE;
+		}
+	}
+	return FALSE;
+}

Index: map.h
===================================================================
RCS file: /cvs/cairo/roadster/src/map.h,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -d -r1.19 -r1.20
--- map.h	31 Aug 2005 08:37:53 -0000	1.19
+++ map.h	6 Sep 2005 02:44:19 -0000	1.20
@@ -26,6 +26,34 @@
 
 #include "gfreelist.h"
 
+//
+// Map Object Types
+//
+#define MAP_OBJECT_TYPE_NONE					(0)
+#define MAP_OBJECT_TYPE_MINORROAD				(1)
+#define MAP_OBJECT_TYPE_MAJORROAD				(2)
+#define MAP_OBJECT_TYPE_MINORHIGHWAY			(3)
+#define MAP_OBJECT_TYPE_MINORHIGHWAY_RAMP		(4)
+#define MAP_OBJECT_TYPE_MAJORHIGHWAY			(5)	// Unused
+#define MAP_OBJECT_TYPE_MAJORHIGHWAY_RAMP		(6)	// Unused
+#define MAP_OBJECT_TYPE_RAILROAD				(7)
+#define MAP_OBJECT_TYPE_PARK					(8)
+#define MAP_OBJECT_TYPE_RIVER					(9)
+#define MAP_OBJECT_TYPE_LAKE					(10)
+#define MAP_OBJECT_TYPE_MISC_AREA				(11)
+
+#define MAP_NUM_OBJECT_TYPES 					(12)
+
+#define MAP_OBJECT_TYPE_FIRST					(1)
+#define MAP_OBJECT_TYPE_LAST					(11)
+
+//
+// Line CAP styles
+//
+#define MAP_CAP_STYLE_ROUND		(1)
+#define MAP_CAP_STYLE_SQUARE	(2)
+#define MAP_CAP_STYLE_DEFAULT	(MAP_CAP_STYLE_ROUND)	// if not specified by the style
+
 #define MIN_LATITUDE	(-90.0)
 #define MAX_LATITUDE	(90.0)
 #define MIN_LONGITUDE	(-180.0)
@@ -36,7 +64,6 @@
 	kSublayerTop,
 } ESubLayer;
 
-#define MIN_LINE_LENGTH_FOR_LABEL  	(40)
 #define LABEL_PIXELS_ABOVE_LINE 	(2)
 #define LABEL_PIXEL_RELIEF_INSIDE_LINE	(2)	// when drawing a label inside a line, only do so if we would have at least this much blank space above+below the text
 
@@ -44,21 +71,18 @@
 
 #define INCHES_PER_METER (39.37007)
 
-#define NUM_ZOOMLEVELS (10)	// the real total # in the array
-#define MIN_ZOOMLEVEL (6)	// the min/max that we allow, for now
-#define MAX_ZOOMLEVEL (9)
-
-#define WORLD_CIRCUMFERENCE_IN_METERS (40076000)
+#define WORLD_CIRCUMFERENCE_IN_METERS (40075452.7)
 #define WORLD_METERS_PER_DEGREE (WORLD_CIRCUMFERENCE_IN_METERS / 360.0)
 #define WORLD_METERS_TO_DEGREES(x)	((x) / WORLD_METERS_PER_DEGREE)
 #define WORLD_DEGREES_TO_METERS(x)	((x) * WORLD_METERS_PER_DEGREE)
-#define KILOMETERS_PER_METER 	(1000)
-#define WORLD_KILOMETERS_TO_DEGREES(x)	((x * KILOMETERS_PER_METER) / WORLD_METERS_PER_DEGREE)
+#define KILOMETERS_PER_METER 	(1000.0)
+#define WORLD_KILOMETERS_TO_DEGREES(x)	(((x) * KILOMETERS_PER_METER) / WORLD_METERS_PER_DEGREE)
 
 #define WORLD_CIRCUMFERENCE_IN_FEET (131482939.8324)
 #define WORLD_FEET_PER_DEGREE 		(WORLD_CIRCUMFERENCE_IN_FEET / 360.0)
 #define WORLD_FEET_TO_DEGREES(X)	((X) / WORLD_FEET_PER_DEGREE)
-#define FEET_PER_MILE				(5280)
+
+#define FEET_PER_MILE				(5280.0)
 #define WORLD_MILES_TO_DEGREES(x)	((x * FEET_PER_MILE) / WORLD_FEET_PER_DEGREE)
 
 // Earth is slightly egg shaped so there are infinite radius measurements:
@@ -74,8 +98,10 @@
 
 struct GtkWidget;
 
-#define MIN_ZOOM_LEVEL	1
-#define MAX_ZOOM_LEVEL	10
+#define MIN_ZOOM_LEVEL					(1)
+#define MAX_ZOOM_LEVEL					(5)
+#define NUM_ZOOM_LEVELS					(5)
+#define MIN_ZOOM_LEVEL_FOR_LOCATIONS	(6)		// don't show POI above this level
 
 #include "layers.h"
 #include "scenemanager.h"
@@ -107,13 +133,6 @@
 	guint16 m_uHeight;
 } dimensions_t;
 
-typedef struct {
-	guint32 m_uScale;		// ex. 10000 for 1:10000 scale
-	gchar* m_szName;
-} zoomlevel_t;
-
-extern zoomlevel_t g_sZoomLevels[];
-
 typedef enum {
 	UNIT_FIRST=0,	
 		UNIT_FEET=0,
@@ -122,14 +141,28 @@
 		UNIT_KILOMETERS=3,
 	UNIT_LAST=3,
 } EDistanceUnits;
+#define DEFAULT_UNIT	(UNIT_MILES)
+
+typedef struct {
+	guint32 m_uScale;		// ex. 10000 for 1:10000 scale
+
+	EDistanceUnits m_eScaleImperialUnit;	// eg. "feet"
+	gint m_nScaleImperialNumber;			// eg. 200
+
+	EDistanceUnits m_eScaleMetricUnit;
+	gint m_nScaleMetricNumber;
+
+	gchar* m_szName;
+} zoomlevel_t;
+
+extern zoomlevel_t g_sZoomLevels[];
+
 
 typedef enum {
 	SIDE_LEFT=1,
 	SIDE_RIGHT=2,
 } ESide;
 
-#define DEFAULT_UNIT	(UNIT_MILES)
-
 extern gchar* g_aDistanceUnitNames[];
 
 typedef struct {
@@ -161,7 +194,7 @@
 
 	// data
 	GArray			*m_pTracksArray;
-	maplayer_data_t		*m_apLayerData[ NUM_LAYERS + 1 ];
+	maplayer_data_t		*m_apLayerData[ MAP_NUM_OBJECT_TYPES + 1 ];
 
 	// Locationsets
 	GHashTable		*m_pLocationArrayHashTable;
@@ -211,16 +244,16 @@
 } maphit_t;
 
 typedef enum {
-	SUBLAYER_RENDERTYPE_LINES,
-	SUBLAYER_RENDERTYPE_POLYGONS,
-	SUBLAYER_RENDERTYPE_LINE_LABELS,
-	SUBLAYER_RENDERTYPE_POLYGON_LABELS
-} ESubLayerRenderType;
+	MAP_LAYER_RENDERTYPE_LINES,
+	MAP_LAYER_RENDERTYPE_POLYGONS,
+	MAP_LAYER_RENDERTYPE_LINE_LABELS,
+	MAP_LAYER_RENDERTYPE_POLYGON_LABELS
+} EMapLayerRenderType;
 
 typedef struct {
 	gint nLayer;
 	gint nSubLayer;
-	ESubLayerRenderType eSubLayerRenderType;
+	EMapLayerRenderType eSubLayerRenderType;
 
 //	void (*pFunc)(map_t*, cairo_t*, rendermetrics_t*, GPtrArray*, sublayerstyle_t*, textlabelstyle_t*);
 } draworder_t;
@@ -286,7 +319,6 @@
 
 GdkPixmap* map_get_pixmap(map_t* pMap);
 void map_release_pixmap(map_t* pMap);
-//void map_draw_thread_begin(map_t* pMap, GtkWidget* pTargetWidget);
 
 void map_draw(map_t* pMap, gint nDrawFlags);
 void map_add_track(map_t* pMap, gint hTrack);
@@ -302,4 +334,7 @@
 
 const gchar* map_location_selection_get_attribute(const map_t* pMap, const locationselection_t* pLocationSelection, const gchar* pszAttributeName);
 
+gboolean map_object_type_atoi(const gchar* pszName, gint* pnReturnObjectTypeID);
+gboolean map_layer_render_type_atoi(const gchar* pszName, gint* pnReturnRenderTypeID);
+
 #endif

Index: map_draw_cairo.c
===================================================================
RCS file: /cvs/cairo/roadster/src/map_draw_cairo.c,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -d -r1.20 -r1.21
--- map_draw_cairo.c	31 Aug 2005 08:37:53 -0000	1.20
+++ map_draw_cairo.c	6 Sep 2005 02:44:19 -0000	1.21
@@ -25,10 +25,13 @@
 
 #define ENABLE_ROUND_DOWN_TEXT_ANGLES			// draw all text at multiples of X radians to be more cache-friendly
 #define 	ROUND_DOWN_TEXT_ANGLE	(100.0)		// 10.0 to keep one decimal place or 100.0 to keep two
-#define ENABLE_LABEL_LIMIT_TO_ROAD				// don't draw labels if they would be longer than the road
-#define ENABLE_HACK_AROUND_CAIRO_LINE_CAP_BUG	// enable to ensure roads have rounded caps if the style dictates
 
-#define	ACCEPTABLE_LINE_LABEL_OVERDRAW_IN_PIXELS_SQUARED (24*24)	// XXX: make this a run-time variable
+#define ENABLE_LABEL_LIMIT_TO_ROAD				// take road line length into account when drawing labels!
+#define	ACCEPTABLE_LINE_LABEL_OVERDRAW_IN_PIXELS (15)	// XXX: make this a run-time variable
+#define ENABLE_DRAW_MAP_SCALE
+
[...1783 lines suppressed...]
-		cairo_move_to(pCairo, SCALE_X(pRenderMetrics, pPoint->m_fLongitude), SCALE_Y(pRenderMetrics, pPoint->m_fLatitude));
-
-		gint i;
-		for(i=1 ; i<pPointString->m_pPointsArray->len ; i++) {
-			pPoint = g_ptr_array_index(pPointString->m_pPointsArray, i);
-			cairo_line_to(pCairo, SCALE_X(pRenderMetrics, pPoint->m_fLongitude), SCALE_Y(pRenderMetrics, pPoint->m_fLatitude));
-		}
-
-		cairo_set_source_rgb(pCairo, 0.0, 0.0, 0.7);
-		cairo_set_alpha(pCairo, 0.6);
-		cairo_set_line_width(pCairo, 6);
-		cairo_set_line_cap(pCairo, CAIRO_LINE_CAP_ROUND);
-		cairo_set_line_join(pCairo, CAIRO_LINE_JOIN_ROUND);
-		cairo_set_miter_limit(pCairo, 5);
-		cairo_stroke(pCairo);
-	}
+//     g_ptr_array_free(pPositionsPtrArray, FALSE);
 }
 */
 #endif

Index: map_draw_gdk.c
===================================================================
RCS file: /cvs/cairo/roadster/src/map_draw_gdk.c,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -d -r1.16 -r1.17
--- map_draw_gdk.c	31 Aug 2005 08:37:53 -0000	1.16
+++ map_draw_gdk.c	6 Sep 2005 02:44:19 -0000	1.17
@@ -43,17 +43,26 @@
 #include "scenemanager.h"
 
 static void map_draw_gdk_background(map_t* pMap, GdkPixmap* pPixmap);
-static void map_draw_gdk_layer_polygons(map_t* pMap, GdkPixmap* pPixmap, rendermetrics_t* pRenderMetrics, GPtrArray* pRoadsArray, sublayerstyle_t* pSubLayerStyle, textlabelstyle_t* pLabelStyle);
-static void map_draw_gdk_layer_roads(map_t* pMap, GdkPixmap* pPixmap, rendermetrics_t* pRenderMetrics, GPtrArray* pRoadsArray, sublayerstyle_t* pSubLayerStyle, textlabelstyle_t* pLabelStyle);
+static void map_draw_gdk_layer_polygons(map_t* pMap, GdkPixmap* pPixmap, rendermetrics_t* pRenderMetrics, GPtrArray* pRoadsArray, layerstyle_t* pLayerStyle);
+static void map_draw_gdk_layer_lines(map_t* pMap, GdkPixmap* pPixmap, rendermetrics_t* pRenderMetrics, GPtrArray* pRoadsArray, layerstyle_t* pLayerStyle);
 static void map_draw_gdk_tracks(map_t* pMap, GdkPixmap* pPixmap, rendermetrics_t* pRenderMetrics);
 static void map_draw_gdk_locations(map_t* pMap, GdkPixmap* pPixmap, rendermetrics_t* pRenderMetrics);
 static void map_draw_gdk_locationset(map_t* pMap, GdkPixmap* pPixmap, rendermetrics_t* pRenderMetrics, locationset_t* pLocationSet, GPtrArray* pLocationsArray);
 
+void map_draw_gdk_set_color(GdkGC* pGC, color_t* pColor)
+{
+	GdkColor clr;
+	clr.red = pColor->m_fRed * 65535;
+	clr.green = pColor->m_fGreen * 65535;
+	clr.blue = pColor->m_fBlue * 65535;
+	gdk_gc_set_rgb_fg_color(pGC, &clr);
+}
+
 void map_draw_gdk(map_t* pMap, rendermetrics_t* pRenderMetrics, GdkPixmap* pPixmap, gint nDrawFlags)
 {
 	TIMER_BEGIN(maptimer, "BEGIN RENDER MAP (gdk)");
 
-	// 1. Setup (save values so we can restore them)
+	// 1. Save values (so we can restore them)
 	GdkGCValues gcValues;
 	gdk_gc_get_values(pMap->m_pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->m_pTargetWidget)], &gcValues);
 
@@ -67,23 +76,20 @@
 	// 2.2. Render Layers
 	if(nDrawFlags & DRAWFLAG_GEOMETRY) {
 		gint i;
-		for(i=0 ; i<NUM_ELEMS(layerdraworder) ; i++) {
-			gint nLayer = layerdraworder[i].nLayer;
-			gint nSubLayer = layerdraworder[i].nSubLayer;
 
-			if(layerdraworder[i].eSubLayerRenderType == SUBLAYER_RENDERTYPE_LINES) {
-				map_draw_gdk_layer_roads(pMap, pPixmap,
-						pRenderMetrics,
-				/* geometry */ 	pMap->m_apLayerData[nLayer]->m_pRoadsArray,
-				/* style */ 	&(g_aLayers[nLayer]->m_Style.m_aSubLayers[nSubLayer]),
-						&(g_aLayers[nLayer]->m_TextLabelStyle));
+		// draw list in reverse order (painter's algorithm: http://en.wikipedia.org/wiki/Painter's_algorithm )
+		for(i=g_pLayersArray->len-1 ; i>=0 ; i--) {
+			layer_t* pLayer = g_ptr_array_index(g_pLayersArray, i);
+
+			if(pLayer->m_nDrawType == MAP_LAYER_RENDERTYPE_LINES) {
+				map_draw_gdk_layer_lines(pMap, pPixmap,	pRenderMetrics,
+										 pMap->m_apLayerData[pLayer->m_nDataSource]->m_pRoadsArray,				// data
+										 pLayer->m_paStylesAtZoomLevels[pRenderMetrics->m_nZoomLevel-1]);		// style
 			}
-			else if(layerdraworder[i].eSubLayerRenderType == SUBLAYER_RENDERTYPE_POLYGONS) {
-				map_draw_gdk_layer_polygons(pMap, pPixmap,
-						pRenderMetrics,
-				/* geometry */ 	pMap->m_apLayerData[nLayer]->m_pRoadsArray,
-				/* style */ 	&(g_aLayers[nLayer]->m_Style.m_aSubLayers[nSubLayer]),
-						&(g_aLayers[nLayer]->m_TextLabelStyle));
+			else if(pLayer->m_nDrawType == MAP_LAYER_RENDERTYPE_POLYGONS) {
+				map_draw_gdk_layer_polygons(pMap, pPixmap, pRenderMetrics,
+											pMap->m_apLayerData[pLayer->m_nDataSource]->m_pRoadsArray,          // data
+											pLayer->m_paStylesAtZoomLevels[pRenderMetrics->m_nZoomLevel-1]); 	// style
 			}
 		}
 
@@ -94,7 +100,7 @@
 	// 3. Labels
 	// ...GDK just shouldn't attempt text. :)
 
-	// 4. Cleanup
+	// 4. Restore values
 	gdk_gc_set_values(pMap->m_pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->m_pTargetWidget)], &gcValues, GDK_GC_FOREGROUND | GDK_GC_BACKGROUND | GDK_GC_LINE_WIDTH | GDK_GC_LINE_STYLE | GDK_GC_CAP_STYLE | GDK_GC_JOIN_STYLE);
 	TIMER_END(maptimer, "END RENDER MAP (gdk)");
 }
@@ -102,40 +108,25 @@
 static void map_draw_gdk_background(map_t* pMap, GdkPixmap* pPixmap)
 {
 	GdkColor clr;
-	clr.red = 239/255.0 * 65535;
-	clr.green = 239/255.0 * 65535;
+	clr.red = 236/255.0 * 65535;
+	clr.green = 230/255.0 * 65535;
 	clr.blue = 230/255.0 * 65535;
 	gdk_gc_set_rgb_fg_color(pMap->m_pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->m_pTargetWidget)], &clr);
-	
+
 	gdk_draw_rectangle(pPixmap, pMap->m_pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->m_pTargetWidget)],
 			TRUE, 0,0, pMap->m_MapDimensions.m_uWidth, pMap->m_MapDimensions.m_uHeight);
 }
 
-static void map_draw_gdk_layer_polygons(map_t* pMap, GdkPixmap* pPixmap, rendermetrics_t* pRenderMetrics, GPtrArray* pRoadsArray, sublayerstyle_t* pSubLayerStyle, textlabelstyle_t* pLabelStyle)
+static void map_draw_gdk_layer_polygons(map_t* pMap, GdkPixmap* pPixmap, rendermetrics_t* pRenderMetrics, GPtrArray* pRoadsArray, layerstyle_t* pLayerStyle)
 {
 	mappoint_t* pPoint;
 	road_t* pRoad;
 	gint iString;
 	gint iPoint;
 
-	gdouble fLineWidth = pSubLayerStyle->m_afLineWidths[pRenderMetrics->m_nZoomLevel-1];
-	if(fLineWidth <= 0.0) return;	// Don't draw invisible lines
-	if(pSubLayerStyle->m_clrColor.m_fAlpha == 0.0) return;	// invisible?  (not that we respect it in gdk drawing anyway)
-
-	// Raise the tolerance way up for thin lines
-	gint nCapStyle = pSubLayerStyle->m_nCapStyle;
-
-	gint nLineWidth = (gint)fLineWidth;
-
-	// Set line style
-	gdk_gc_set_line_attributes(pMap->m_pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->m_pTargetWidget)],
-			   nLineWidth, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_MITER);
+	if(pLayerStyle->m_clrPrimary.m_fAlpha == 0.0) return;	// invisible?  (not that we respect it in gdk drawing anyway)
 
-	GdkColor clr;
-	clr.red = pSubLayerStyle->m_clrColor.m_fRed * 65535;
-	clr.green = pSubLayerStyle->m_clrColor.m_fGreen * 65535;
-	clr.blue = pSubLayerStyle->m_clrColor.m_fBlue * 65535;
-	gdk_gc_set_rgb_fg_color(pMap->m_pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->m_pTargetWidget)], &clr);
+	map_draw_gdk_set_color(pMap->m_pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->m_pTargetWidget)], &(pLayerStyle->m_clrPrimary));
 
 	for(iString=0 ; iString<pRoadsArray->len ; iString++) {
 		pRoad = g_ptr_array_index(pRoadsArray, iString);
@@ -180,63 +171,62 @@
 	}
 }
 
-static void map_draw_gdk_layer_roads(map_t* pMap, GdkPixmap* pPixmap, rendermetrics_t* pRenderMetrics, GPtrArray* pRoadsArray, sublayerstyle_t* pSubLayerStyle, textlabelstyle_t* pLabelStyle)
+static void map_draw_gdk_layer_lines(map_t* pMap, GdkPixmap* pPixmap, rendermetrics_t* pRenderMetrics, GPtrArray* pRoadsArray, layerstyle_t* pLayerStyle)
 {
 	road_t* pRoad;
 	mappoint_t* pPoint;
 	gint iString;
 	gint iPoint;
 
-	gdouble fLineWidth = pSubLayerStyle->m_afLineWidths[pRenderMetrics->m_nZoomLevel-1];
-	if(fLineWidth <= 0.0) return;	// Don't draw invisible lines
-	if(pSubLayerStyle->m_clrColor.m_fAlpha == 0.0) return;	// invisible?  (not that we respect it in gdk drawing anyway)
+	if(pLayerStyle->m_fLineWidth <= 0.0) return;			// Don't draw invisible lines
+	if(pLayerStyle->m_clrPrimary.m_fAlpha == 0.0) return;	// invisible?  (not that we respect it in gdk drawing anyway)
 
 	// Use GDK dash style if ANY dash pattern is set
 	gint nDashStyle = GDK_LINE_SOLID;
-	if(g_aDashStyles[pSubLayerStyle->m_nDashStyle].m_nDashCount > 1) {
+	if(g_aDashStyles[pLayerStyle->m_nDashStyle].m_nDashCount > 1) {
 		nDashStyle = GDK_LINE_ON_OFF_DASH;
 
 		gdk_gc_set_dashes(pMap->m_pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->m_pTargetWidget)],
-				0, /* offset */
-				g_aDashStyles[pSubLayerStyle->m_nDashStyle].m_panDashList,
-				g_aDashStyles[pSubLayerStyle->m_nDashStyle].m_nDashCount);
+				0, /* offset to start at */
+				g_aDashStyles[pLayerStyle->m_nDashStyle].m_panDashList,
+				g_aDashStyles[pLayerStyle->m_nDashStyle].m_nDashCount);
 	}
 
-	// XXX: Don't use round at low zoom levels
-//	gint nCapStyle = pSubLayerStyle->m_nCapStyle;
-	gint nCapStyle = GDK_CAP_ROUND;
-	//if(fLineWidth < 8) {
-	//	nCapStyle = GDK_CAP_PROJECTING;
-	//}
+	// Translate generic cap style into GDK constant
+	gint nCapStyle;
+	if(pLayerStyle->m_nCapStyle == MAP_CAP_STYLE_ROUND) {
+		nCapStyle = GDK_CAP_ROUND;
+	}
+	else {
+		nCapStyle = GDK_CAP_PROJECTING;
+	}
+
+	// Convert to integer width.  Ouch!
+	gint nLineWidth = (gint)(pLayerStyle->m_fLineWidth);
 
-	gint nLineWidth = (gint)fLineWidth;
-	
 	// Set line style
 	gdk_gc_set_line_attributes(pMap->m_pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->m_pTargetWidget)],
-			   nLineWidth, nDashStyle, nCapStyle, GDK_JOIN_MITER);
+			   nLineWidth, nDashStyle, nCapStyle, GDK_JOIN_ROUND);
 
-	GdkColor clr;
-	clr.red = pSubLayerStyle->m_clrColor.m_fRed * 65535;
-	clr.green = pSubLayerStyle->m_clrColor.m_fGreen * 65535;
-	clr.blue = pSubLayerStyle->m_clrColor.m_fBlue * 65535;
-	gdk_gc_set_rgb_fg_color(pMap->m_pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->m_pTargetWidget)], &clr);
+	map_draw_gdk_set_color(pMap->m_pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->m_pTargetWidget)], &(pLayerStyle->m_clrPrimary));
 
 	for(iString=0 ; iString<pRoadsArray->len ; iString++) {
 		pRoad = g_ptr_array_index(pRoadsArray, iString);
 
+		if(pRoad->m_pPointsArray->len > MAX_GDK_LINE_SEGMENTS) {
+			//g_warning("not drawing line with > %d segments\n", MAX_GDK_LINE_SEGMENTS);
+			continue;
+		}
+
 		gdouble fMaxLat = MIN_LATITUDE;	// init to the worst possible value so first point will override
 		gdouble fMinLat = MAX_LATITUDE;
 		gdouble fMaxLon = MIN_LONGITUDE;
 		gdouble fMinLon = MAX_LONGITUDE;
 
 		if(pRoad->m_pPointsArray->len >= 2) {
+			// Copy all points into this array.  Yuuup this is slow. :)
 			GdkPoint aPoints[MAX_GDK_LINE_SEGMENTS];
 
-			if(pRoad->m_pPointsArray->len > MAX_GDK_LINE_SEGMENTS) {
-				//g_warning("not drawing line with > %d segments\n", MAX_GDK_LINE_SEGMENTS);
-				continue;
-			}
-
 			for(iPoint=0 ; iPoint<pRoad->m_pPointsArray->len ; iPoint++) {
 				pPoint = g_ptr_array_index(pRoad->m_pPointsArray, iPoint);
 
@@ -390,4 +380,3 @@
 					3, 3);
 	}
 }
-

Index: road.c
===================================================================
RCS file: /cvs/cairo/roadster/src/road.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- road.c	28 Aug 2005 22:23:14 -0000	1.4
+++ road.c	6 Sep 2005 02:44:19 -0000	1.5
@@ -227,7 +227,6 @@
 	{"Rte", ROAD_SUFFIX_ROUTE},
 	
 	{"Arc", ROAD_SUFFIX_ARC},
-
 };
 
 

Index: scenemanager.c
===================================================================
RCS file: /cvs/cairo/roadster/src/scenemanager.c,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -d -r1.12 -r1.13
--- scenemanager.c	31 Aug 2005 08:37:53 -0000	1.12
+++ scenemanager.c	6 Sep 2005 02:44:19 -0000	1.13
@@ -26,6 +26,8 @@
 #include "main.h"
 #include "scenemanager.h"
 
+#define ENABLE_NO_DUPLICATE_LABELS
+
 /*
 Goals:
  - Keep text labels and other screen objects from overlapping
@@ -55,6 +57,7 @@
 
 gboolean scenemanager_can_draw_label_at(scenemanager_t* pSceneManager, const gchar* pszLabel, GdkPoint* __unused_pScreenLocation, gint nFlags)
 {
+#ifdef ENABLE_NO_DUPLICATE_LABELS
 	g_assert(pSceneManager != NULL);
 	g_assert(pszLabel != NULL);
 
@@ -64,6 +67,9 @@
 
 	// Can draw if it doesn't exist in table
 	return (FALSE == g_hash_table_lookup_extended(pSceneManager->m_pLabelHash, pszLabel, &pKey, &pValue));
+#else
+	return TRUE;
+#endif
 }
 
 gboolean scenemanager_can_draw_polygon(scenemanager_t* pSceneManager, GdkPoint *pPoints, gint nNumPoints, gint nFlags)
@@ -146,10 +152,12 @@
 
 void scenemanager_claim_label(scenemanager_t* pSceneManager, const gchar* pszLabel)
 {
+#ifdef ENABLE_NO_DUPLICATE_LABELS
 	g_assert(pSceneManager != NULL);
 
 	// Just putting the label into the hash is enough
 	g_hash_table_insert(pSceneManager->m_pLabelHash, pszLabel, NULL);
+#endif
 }
 
 void scenemanager_claim_polygon(scenemanager_t* pSceneManager, GdkPoint *pPoints, gint nNumPoints)

Index: search_road.c
===================================================================
RCS file: /cvs/cairo/roadster/src/search_road.c,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -d -r1.20 -r1.21
--- search_road.c	28 Aug 2005 22:23:14 -0000	1.20
+++ search_road.c	6 Sep 2005 02:44:19 -0000	1.21
@@ -58,7 +58,6 @@
 
 	gint i;
 	for(i=0 ; i<nLen ; i++) {
-		// XXX: is g_ascii_isalnum the right function? we should be testing for numbers only
 		if(!g_ascii_isdigit(pszWord[i])) {
 			return FALSE;
 		}
@@ -481,7 +480,6 @@
 }
 #endif /* ROADSTER_DEAD_CODE */
 
-
 //
 // XXX: the SQL doesn't require all fields be set for THE SAME SIDE
 // 		do we need to filter out records where each side matches some of the criteria but not all?

Index: util.c
===================================================================
RCS file: /cvs/cairo/roadster/src/util.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- util.c	31 Aug 2005 08:37:53 -0000	1.8
+++ util.c	6 Sep 2005 02:44:19 -0000	1.9
@@ -47,7 +47,7 @@
 
 	gchar **argv = g_malloc0(sizeof(gchar*) * 3);
 	argv[0] = "gnome-open";
-	argv[1] = pszDangerousURI;
+	argv[1] = (gchar*)pszDangerousURI;
 	argv[2] = NULL;
 
 	if(!g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &pError)) {
@@ -181,6 +181,30 @@
 	return aLines;
 }
 
+gboolean util_parse_hex_color(const gchar* pszString, color_t* pReturnColor)
+{
+	gchar *p = pszString;
+	if (*p == '#') p++;
+
+	if(strlen(p) != 8) {
+		g_warning("bad color value found: %s\n", pszString);
+		return FALSE;
+	}
+
+	// Read RGBA hex doubles (eg. "H8") into buffer and parse
+	gchar azBuffer[3] = {0,0,0};
+
+	azBuffer[0] = *p++; azBuffer[1] = *p++;
+	pReturnColor->m_fRed = (gfloat)strtol(azBuffer, NULL, 16)/255.0;
+	azBuffer[0] = *p++; azBuffer[1] = *p++;
+	pReturnColor->m_fGreen = (gfloat)strtol(azBuffer, NULL, 16)/255.0;
+	azBuffer[0] = *p++; azBuffer[1] = *p++;
+	pReturnColor->m_fBlue = (gfloat)strtol(azBuffer, NULL, 16)/255.0;
+	azBuffer[0] = *p++; azBuffer[1] = *p++;
+	pReturnColor->m_fAlpha = (gfloat)strtol(azBuffer, NULL, 16)/255.0;
+}
+
+
 #if(!GLIB_CHECK_VERSION(2,6,0))
 // if glib < 2.6 we need to provide this function ourselves
 gint g_strv_length(const gchar** a)

Index: util.h
===================================================================
RCS file: /cvs/cairo/roadster/src/util.h,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- util.h	23 Apr 2005 18:13:39 -0000	1.8
+++ util.h	6 Sep 2005 02:44:19 -0000	1.9
@@ -25,6 +25,7 @@
 #define _UTIL_H_
 
 #include <gtk/gtk.h>
+#include "layers.h"
 
 #define GTK_PROCESS_MAINLOOP  while (gtk_events_pending ()) { gtk_main_iteration (); }
 
@@ -33,7 +34,7 @@
 #define SWAP(x, y)                   { (x) ^= (y) ^= (x) ^= (y); }
 
 void util_random_color(void* pColor);
-
+gboolean util_parse_hex_color(const gchar* pszString, color_t* pReturnColor);
 
 #ifdef ENABLE_TIMING
 #define TIMER_BEGIN(name, str)	GTimer* name = g_timer_new(); g_print("\n%s (%f)\n", str, g_timer_elapsed(name, NULL))



More information about the cairo-commit mailing list