From 8467391931884101c881cd6a0ef19c8e1b3fb7f8 Mon Sep 17 00:00:00 2001 From: Kaj-Michael Lang Date: Mon, 28 Apr 2008 15:02:18 +0300 Subject: [PATCH] Start make a proper map widget --- src/gtkmap.c | 217 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/gtkmap.h | 173 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 390 insertions(+) create mode 100644 src/gtkmap.c create mode 100644 src/gtkmap.h diff --git a/src/gtkmap.c b/src/gtkmap.c new file mode 100644 index 0000000..b12f55f --- /dev/null +++ b/src/gtkmap.c @@ -0,0 +1,217 @@ +/* + * MapWidget: Display a map + * Copyright (C) 2007 Kaj-Michael Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include "gtkmap.h" + +G_DEFINE_TYPE(GtkMap, gtk_map, GTK_TYPE_WIDGET); + +typedef struct _GtkMapPriv GtkMapPriv; + +struct _GtkMapPriv +{ +PangoContext *context; +PangoLayout *layout; +PangoFontDescription *fontdesc; +}; + +#define GTK_MAP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_MAP, GtkMapPriv)) + +#define tile2grid(tile) ((tile) << 3) +#define grid2tile(grid) ((grid) >> 3) +#define tile2pixel(tile) ((tile) << 8) +#define pixel2tile(pixel) ((pixel) >> 8) +#define tile2unit(tile) ((tile) << (8 + _zoom)) +#define unit2tile(unit) ((unit) >> (8 + _zoom)) +#define tile2zunit(tile, zoom) ((tile) << (8 + zoom)) +#define unit2ztile(unit, zoom) ((unit) >> (8 + zoom)) + +#define grid2pixel(grid) ((grid) << 5) +#define pixel2grid(pixel) ((pixel) >> 5) +#define grid2unit(grid) ((grid) << (5 + _zoom)) +#define unit2grid(unit) ((unit) >> (5 + _zoom)) + +#define pixel2unit(pixel) ((pixel) << _zoom) +#define unit2pixel(pixel) ((pixel) >> _zoom) +#define pixel2zunit(pixel, zoom) ((pixel) << (zoom)) + +#define unit2bufx(unit) (unit2pixel(unit) - tile2pixel(_base_tilex)) +#define bufx2unit(x) (pixel2unit(x) + tile2unit(_base_tilex)) +#define unit2bufy(unit) (unit2pixel(unit) - tile2pixel(_base_tiley)) +#define bufy2unit(y) (pixel2unit(y) + tile2unit(_base_tiley)) + +#define unit2x(unit) (unit2pixel(unit) - tile2pixel(_base_tilex) - _offsetx) +#define x2unit(x) (pixel2unit(x + _offsetx) + tile2unit(_base_tilex)) +#define unit2y(unit) (unit2pixel(unit) - tile2pixel(_base_tiley) - _offsety) +#define y2unit(y) (pixel2unit(y + _offsety) + tile2unit(_base_tiley)) + +#define leadx2unit(mgps) (mgps.unitx + (_lead_ratio) * pixel2unit(mgps.vel_offsetx)) +#define leady2unit(mgps) (mgps.unity + (0.6f*_lead_ratio)*pixel2unit(mgps.vel_offsety)) + +static void gtk_map_finalize (GObject *object); +static void gtk_map_size_request (GtkWidget *widget, GtkRequisition *requisition); +static void gtk_map_size_allocate (GtkWidget *widget, GtkAllocation *allocate); +static gboolean gtk_map_expose (GtkWidget *widget, GdkEventExpose *event); +static void gtk_map_realize (GtkWidget *widget); +static void gtk_map_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void gtk_map_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); + +static void +gtk_map_class_init (GtkMapClass *class) +{ +GObjectClass *object_class; +GtkWidgetClass *widget_class; + +object_class = (GObjectClass*) class; +widget_class = (GtkWidgetClass*) class; + +object_class->finalize = gtk_map_finalize; +object_class->set_property = gtk_map_set_property; +object_class->get_property = gtk_map_get_property; + +widget_class->size_request = gtk_map_size_request; +widget_class->expose_event = gtk_map_expose; +widget_class->realize = gtk_map_realize; +widget_class->size_allocate = gtk_map_size_allocate; + +g_type_class_add_private (object_class, sizeof (GtkMapPriv)); +} + +static void +gtk_map_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ +GtkMap *map; +g_return_if_fail(GTK_IS_MAP(object)); +map=GTK_MAP(object); +switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; +} +} + +static void +gtk_map_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ +GtkMap *map; +g_return_if_fail(GTK_IS_MAP(object)); +map=GTK_MAP(object); +switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; +} +} + +static void +gtk_map_init(GtkMap *map) +{ + +} + +GtkWidget* +gtk_map_new(void) +{ +GtkMap *map; +GtkWidget *widget; + +map=gtk_type_new(gtk_map_get_type ()); +widget=GTK_WIDGET(map); +map->heading=0; + +#if 0 +g_signal_connect(G_OBJECT(widget), "button_press_event", G_CALLBACK(gtk_map_cb_button_press), NULL); +#endif + +return widget; +} + +static void +gtk_map_finalize(GObject *object) +{ +GtkMap *map; + +g_return_if_fail(GTK_IS_MAP(object)); +map=GTK_MAP(object); + +if (GTK_WIDGET(object)->parent && GTK_WIDGET_MAPPED(object)) { + gtk_widget_unmap(GTK_WIDGET(object)); +} + +G_OBJECT_CLASS(gtk_map_parent_class)->finalize(object); +} + +static void +gtk_map_size_allocate(GtkWidget *widget, GtkAllocation *allocation) +{ +GtkMap *map; + +g_return_if_fail(GTK_IS_MAP(widget)); +map=GTK_MAP(widget); +} + +static void +gtk_map_size_request(GtkWidget *widget, GtkRequisition *requisition) +{ +GtkMap *map; + +g_return_if_fail(GTK_IS_MAP(widget)); +g_return_if_fail(requisition != NULL); + +map=GTK_MAP(widget); + +requisition->width=512; +requisition->height=256; +map->width=512; +map->height=256; +} + +static void +gtk_map_realize (GtkWidget *widget) +{ +GtkMap *map; + +g_return_if_fail(GTK_IS_MAP(widget)); +map=GTK_MAP(widget); +} + +static gboolean +gtk_map_expose(GtkWidget *widget, GdkEventExpose *event) +{ +GtkMap *map; + +g_return_val_if_fail(GTK_IS_MAP(widget), FALSE); +g_return_val_if_fail(event != NULL, FALSE); + +map=GTK_MAP(widget); + +return TRUE; +} + +void +gtk_map_refresh(GtkWidget *widget) +{ +GtkMap *map; + +g_return_if_fail(GTK_IS_MAP(widget)); + +map=GTK_MAP(widget); +gtk_widget_queue_draw_area(widget, 0, 0, map->width, map->height); +} diff --git a/src/gtkmap.h b/src/gtkmap.h new file mode 100644 index 0000000..db2ccce --- /dev/null +++ b/src/gtkmap.h @@ -0,0 +1,173 @@ +/* + * MapWidget: Display a map + * Copyright (C) 2008 Kaj-Michael Lang + * Original non-widget map Copyright (C) 2006-2007 John Costigan. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_MAP_H__ +#define __GTK_MAP_H__ + +#include +#include "path.h" + +G_BEGIN_DECLS + +typedef enum { + CENTER_WAS_LATLON = -2, + CENTER_WAS_LEAD = -1, + CENTER_MANUAL = 0, + CENTER_LEAD = 1, + CENTER_LATLON = 2 +} GtkMapCenterMode; + +#define GTK_MAP_TYPE (gtk_map_get_type ()) +#define GTK_MAP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_MAP_TYPE, GtkMap)) +#define GTK_MAP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_MAP_TYPE, GtkMapClass)) +#define GTK_IS_MAP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_MAP_TYPE)) + +#define GTK_MAP_TILE_SIZE_PIXELS (256) +#define GTK_MAP_TILE_SIZE_P2 (8) +#define GTK_MAP_WORLD_SIZE_UNITS(max_zoom) (2 << (max_zoom + TILE_SIZE_P2)) + +/* Pans are done two "grids" at a time, or 64 pixels. */ +#define GTK_MAP_PAN_UNITS (grid2unit(2)) + +#define GTK_MAP_MACRO_RECALC_CENTER(center_mode, center, mgps, center_unitx, center_unity) { \ + switch(center_mode) { \ + case CENTER_LEAD: \ + center_unitx = leadx2unit(mgps); \ + center_unity = leady2unit(mgps); \ + break; \ + case CENTER_LATLON: \ + center_unitx = mgps.unitx; \ + center_unity = mgps.unity; \ + break; \ + default: \ + center_unitx = center.unitx; \ + center_unity = center.unity; \ + break; \ + } \ +}; + +#define GTK_MAP_RECALC_OFFSET(map, center) { \ + map->offsetx = grid2pixel(unit2grid(center.unitx) - map->screen_grids_halfwidth - tile2grid(map->base_tilex)); \ + map->offsety = grid2pixel(unit2grid(center.unity) - map->screen_grids_halfheight - tile2grid(map->base_tiley)); \ +} + +#define GTK_MAP_RECALC_FOCUS_BASE(map, sens) { \ + map->focus.unitx = x2unit(map->screen_width_pixels * sens / 20); \ + map->focus.unity = y2unit(map->screen_height_pixels * sens / 20); \ +} + +typedef struct _GtkMap GtkMap; +typedef struct _GtkMapClass GtkMapClass; + +struct _GtkMap { + GtkDrawingArea widget; + + GdkGC *gc_h; + GdkGC *gc_w; + GdkGC *gc_d; + guint width, height; + guint size; + guint xoffset, yoffset; + + PangoContext *context; + PangoLayout *layout; + PangoFontDescription *fontdesc; + + Point min_center; + Point max_center; + Point focus; + + /** The "base tile" is the upper-left tile in the pixmap. */ + guint base_tilex; + guint base_tiley; + + Point center; /* current center location, X. */ + GtkMapCenterMode center_mode; + guint lead_ratio; + guint center_ratio; + + gfloat heading; + gfloat speed; + + guint zoom; /* zoom level, from 0 to MAX_ZOOM. */ + + /** The "offset" defines the upper-left corner of the visible portion of the buffer pixmap. */ + guint offsetx; + guint offsety; + + /** CACHED SCREEN INFORMATION THAT IS DEPENDENT ON THE CURRENT VIEW. */ + guint screen_grids_halfwidth; + guint screen_grids_halfheight; + guint screen_width_pixels; + guint screen_height_pixels; + + guint focus_unitwidth; + guint focus_unitheight; + guint world_size_tiles; + + gint show_paths; + gboolean show_scale; + gboolean show_velvec; + gboolean show_markers; + + guint draw_width; + + guint key_zoom_new; + guint key_zoom_timeout_sid; +}; + +struct _GtkMapClass { + GtkWidgetClass parent_class; +}; + +GType gtk_map_get_type(void); +GtkWidget* gtk_map_new(void); +void gtk_map_refresh(GtkWidget *widget); + +gboolean gtk_map_key_zoom_timeout(GtkWidget *map); + +gint gtk_map_zoom(gint zdir); +guint gtk_map_get_zoom(GtkWidget *map); +gboolean gtk_map_set_zoom(guint zoom); + +gboolean gtk_map_zoom_in(GtkWidget *map); +gboolean gtk_map_zoom_out(GtkWidget *map); +void gtk_map_set_autozoom(GtkWidget *map, gboolean az, gfloat speed); +void gtk_map_render_path(Path *path, GdkGC ** gc); +void gtk_map_pan(GtkWidget *map, gint delta_unitx, gint delta_unity); +void gtk_map_move_mark(GtkWidget *map); +void gtk_map_set_mark(GtkWidget *map); +void gtk_map_render_data(GtkWidget *map); +gboolean gtk_map_render_tile(GtkWidget *map, guint tilex, guint tiley, guint destx, guint desty, gboolean fast_fail); + +void gtk_map_render_waypoint(GtkWidget *map, guint x1, guint y1, GdkGC *gc); +void gtk_map_render_paths(GtkWidget *map); +void gtk_map_force_redraw(GtkWidget *map); +void gtk_map_draw_position_icon(GtkWidget *map, Position *pos, const gchar *icon); +GdkPixmap *gtk_map_pixmap_get(GtkWidget *map); + +void gtk_map_center_unit(GtkWidget *map, guint new_center_unitx, guint new_center_unity); +void gtk_map_center_latlon(GtkWidget *map, gdouble lat, gdouble lon); + +gboolean gtk_map_goto_position(GtkWidget *map, Position *pos); +gboolean gtk_map_update_location_from_center(GtkWidget *map); + +G_END_DECLS + +#endif /* __GTK_MAP_H__ */ -- 2.39.5