/***********************************************************************
* map_widget.c : Implementation of the map widget.
* Includes the physical area of the map and the zoom
* control.
***********************************************************************/
/***********************************************************************
* This file is part of SpaceChart.
* Copyright (C) 2000 Miguel Coca <e970095@zipi.fi.upm.es>
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
***********************************************************************/
#include "../include/map_widget.h"
struct st_map_widget
{
GtkWidget* box;
GtkWidget* map_widget;
GdkPixmap* map;
GtkWidget* zoom_scale;
GtkObject* zoom_adj;
GtkWidget* zoom_frame;
int last_x;
int last_y;
double screen_size, x_center, y_center;
void (*redraw)(map_widget_t*, void*);
void (*rotate)( map_widget_t*, double v_ang,
double h_ang, void* data );
void (*clicked)( map_widget_t*, double x, double y, double lambda,
void* data );
void *data;
};
/* Declaration of private Functions */
static inline void get_screen_coords( double *x, double *y,
map_widget_t *map );
static gint cb_configure_event( GtkWidget *widget, GdkEventConfigure *event,
map_widget_t *map );
static gint cb_expose_event ( GtkWidget *widget, GdkEventExpose *event,
map_widget_t *map );
static void cb_button_press_event( GtkWidget *widget, GdkEventButton* event,
map_widget_t *map );
static void cb_motion_notify_event( GtkWidget *widget, GdkEventMotion* event,
map_widget_t *map );
static void cb_changed_zoom( GtkAdjustment *adj, map_widget_t* map );
/* Public Functions */
map_widget_t *map_widget_new( void (*redraw)(map_widget_t*, void*),
void (*rotate)( map_widget_t*, double v_ang,
double h_ang, void* data ),
void (*clicked)( map_widget_t*, double x,
double y, double lambda,
void* data ),
void *data )
{
map_widget_t *map;
if( (map = (map_widget_t*) malloc( sizeof(map_widget_t) )) )
{
map->last_x = 0;
map->last_y = 0;
map->rotate = rotate;
map->clicked = clicked;
map->redraw = redraw;
map->data = data;
/* Create the map UI elements */
map->map = NULL;
map->map_widget = gtk_drawing_area_new();
map->zoom_adj = gtk_adjustment_new( 1.0, 1.0, 20.0,
0.5, 2.0, 0.0 );
map->zoom_scale = gtk_vscale_new( GTK_ADJUSTMENT(
map->zoom_adj ) );
map->box = gtk_hbox_new( FALSE, 0 );
map->zoom_frame = gtk_frame_new( _("Zoom") );
/* Configure the widgets */
gtk_container_border_width( GTK_CONTAINER(map->zoom_frame),5 );
gtk_widget_set_events( map->map_widget, GDK_EXPOSURE_MASK
| GDK_LEAVE_NOTIFY_MASK
| GDK_BUTTON_PRESS_MASK
| GDK_POINTER_MOTION_MASK
| GDK_POINTER_MOTION_HINT_MASK);
gtk_signal_connect( GTK_OBJECT( map->map_widget ),
"expose_event",
GTK_SIGNAL_FUNC( cb_expose_event ), map );
gtk_signal_connect( GTK_OBJECT( map->map_widget ),
"configure_event",
GTK_SIGNAL_FUNC( cb_configure_event ),
map );
gtk_signal_connect( GTK_OBJECT( map->map_widget ),
"button_press_event",
GTK_SIGNAL_FUNC( cb_button_press_event ),
map );
gtk_signal_connect( GTK_OBJECT( map->map_widget ),
"motion_notify_event",
GTK_SIGNAL_FUNC( cb_motion_notify_event ),
map );
gtk_signal_connect( GTK_OBJECT( map->zoom_adj ),
"value_changed",
GTK_SIGNAL_FUNC( cb_changed_zoom ), map );
gtk_container_add( GTK_CONTAINER( map->zoom_frame ),
map->zoom_scale );
gtk_box_pack_start( GTK_BOX( map->box ), map->map_widget,
TRUE, TRUE, 0 );
gtk_box_pack_start( GTK_BOX( map->box ), map->zoom_frame,
FALSE, FALSE, 5 );
}
return map;
}
GtkWidget* map_widget_get_widget( map_widget_t* map_widget )
{
return map_widget->box;
}
void map_widget_draw_point( map_widget_t* map_widget, double x, double y,
int radius, double rgb[] )
{
GdkColor color;
GdkGC* gc;
gc = gdk_gc_new( map_widget->map_widget->window );
color.red = (guint16) ( rgb[0] * 65535.0 );
color.green = (guint16) ( rgb[1] * 65535.0 );
color.blue = (guint16) ( rgb[2] * 65535.0 );
color.pixel = (gulong) color.red * 65536 +
color.green * 256 + color.blue;
get_screen_coords( &x, &y, map_widget );
gdk_color_alloc( gtk_widget_get_colormap( map_widget->map_widget ),
&color );
gdk_gc_set_foreground( gc, &color );
gdk_draw_arc ( map_widget->map, gc, TRUE, x - radius,y - radius,
radius*2, radius*2, 0*64, 360*64 );
gdk_gc_destroy( gc );
}
void map_widget_draw_line( map_widget_t* map_widget, double x1, double y1,
double x2, double y2, int width, double rgb[],
GdkLineStyle style )
{
GdkColor color;
GdkGC* gc;
gc = gdk_gc_new( map_widget->map_widget->window );
color.red = (guint16) ( rgb[0] * 65535.0 );
color.green = (guint16) ( rgb[1] * 65535.0 );
color.blue = (guint16) ( rgb[2] * 65535.0 );
color.pixel = (gulong) color.red * 65536 + color.green * 256
+ color.blue;
gdk_color_alloc( gtk_widget_get_colormap( map_widget->map_widget ),
&color );
gdk_gc_set_foreground( gc, &color );
gdk_gc_set_line_attributes( gc, width, style, GDK_CAP_BUTT,
GDK_JOIN_MITER );
get_screen_coords( &x1, &y1, map_widget );
get_screen_coords( &x2, &y2, map_widget );
gdk_draw_line( map_widget->map, gc, x1, y1, x2, y2 );
gdk_gc_destroy( gc );
}
void map_widget_draw_label( map_widget_t* map_widget, double x, double y,
int displace, GdkFont *font, double rgb[],
const char label[] )
{
GdkColor color;
GdkGC* gc;
gc = gdk_gc_new( map_widget->map_widget->window );
color.red = (guint16) ( rgb[0] * 65535.0 );
color.green = (guint16) ( rgb[1] * 65535.0 );
color.blue = (guint16) ( rgb[2] * 65535.0 );
color.pixel = (gulong) color.red * 65536 +
color.green * 256 + color.blue;
get_screen_coords( &x, &y, map_widget );
gdk_color_alloc( gtk_widget_get_colormap(
map_widget->map_widget ), &color );
gdk_gc_set_foreground( gc, &color );
gdk_draw_text( map_widget->map, font, gc, x+displace, y+displace,
label, strlen(label) );
gdk_gc_destroy( gc );
}
void map_widget_clear( map_widget_t *map_widget )
{
gdk_draw_rectangle ( map_widget->map,
map_widget->map_widget->style->black_gc,
TRUE, 0, 0,
map_widget->map_widget->allocation.width,
map_widget->map_widget->allocation.height);
}
void map_widget_show( map_widget_t *map_widget )
{
gdk_draw_pixmap(map_widget->map_widget->window,
map_widget->map_widget->style->fg_gc[GTK_WIDGET_STATE
(map_widget->map_widget)],
map_widget->map,
0, 0, 0, 0,
map_widget->map_widget->allocation.width,
map_widget->map_widget->allocation.height );
}
void map_widget_destroy( map_widget_t* map_widget )
{
gtk_object_destroy( GTK_OBJECT( map_widget->box ) );
}
/* Private Functions */
inline void get_screen_coords( double *x, double *y, map_widget_t *map )
{
*x = map->x_center + (*x * map->screen_size *
GTK_ADJUSTMENT(map->zoom_adj)->value);
*y = map->y_center - (*y * map->screen_size *
GTK_ADJUSTMENT(map->zoom_adj)->value);
}
static gint cb_configure_event( GtkWidget *widget, GdkEventConfigure *event,
map_widget_t *map )
{
if( map->map )
gdk_pixmap_unref( map->map );
map->map = gdk_pixmap_new( widget->window,
widget->allocation.width,
widget->allocation.height,
-1);
map->x_center = (widget->allocation.width/2);
map->y_center = (widget->allocation.height/2);
map->screen_size = ( ( (widget->allocation.width) <
(widget->allocation.height) ) ?
(widget->allocation.width/2) :
(widget->allocation.height/2) ) - 10;
map->redraw( map, map->data );
return TRUE;
}
static gint cb_expose_event ( GtkWidget *widget, GdkEventExpose *event,
map_widget_t *map )
{
gdk_draw_pixmap(widget->window,
widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
map->map,
event->area.x, event->area.y,
event->area.x, event->area.y,
event->area.width, event->area.height);
return FALSE;
}
static void cb_button_press_event( GtkWidget *widget, GdkEventButton* event,
map_widget_t *map )
{
if( event->button == 3 )
{
map->last_x = event->x;
map->last_y = event->y;
} else if( event->button == 1 )
{
double lambda = map->screen_size *
GTK_ADJUSTMENT(map->zoom_adj)->value;
map->last_x = event->x;
map->last_y = event->y;
map->clicked( map, event->x - map->x_center,
map->y_center - event->y, lambda,
map->data);
}
}
static void cb_motion_notify_event( GtkWidget *widget, GdkEventMotion* event,
map_widget_t *map )
{
int x, y;
double v_ang, h_ang;
GdkModifierType state;
if( event->is_hint )
gdk_window_get_pointer( event->window, &x, &y, &state );
else
{
x = event->x;
y = event->y;
state = event->state;
}
if( ( state & GDK_BUTTON3_MASK ) &&
( ( abs( (int)(map->last_x - x) ) > MIN_ROT ) ||
( abs( (int)(map->last_y - y) ) > MIN_ROT ) ) )
{
v_ang = -(map->last_y - y) * (M_PI/360); /* Rotate a degree for
* each 2 pixels */
h_ang = (map->last_x - x) * (M_PI/360);
map->rotate( map, v_ang, h_ang, map->data );
map->last_x = x;
map->last_y = y;
}
}
void cb_changed_zoom( GtkAdjustment *adj, map_widget_t* map )
{
map->redraw( map, map->data );
}
syntax highlighted by Code2HTML, v. 0.9.1