Statistics
| Revision:

root / branches / simulator / projects / simulator / simulator / gui / gtk_environment_view.c @ 1082

History | View | Annotate | Download (11.6 KB)

1
#include <math.h>
2
#include <stdlib.h>
3
#include <stdio.h>
4
#include <sys/time.h>
5
#include <string.h>
6

    
7
#include <gtk/gtkmain.h>
8
#include <gtk/gtksignal.h>
9

    
10
#include "gtk_environment_view.h"
11

    
12
#include "robot.h"
13
#include "world.h"
14

    
15
#define ENVIRONMENT_VIEW_MIN_WIDTH                100
16
#define ENVIRONMENT_VIEW_MIN_HEIGHT                50
17

    
18
#define ROBOT_DIAMETER                                        30
19

    
20
static GtkWidgetClass* parent_class = NULL;
21

    
22
static void gtk_environment_view_class_init(GtkEnvironmentViewClass* environmentClass);
23
static void gtk_environment_view_init(GtkEnvironmentView* view);
24
static void gtk_environment_view_destroy(GtkObject* object);
25

    
26
static void gtk_environment_view_size_request(GtkWidget* widget,
27
                GtkRequisition* req);
28
static void gtk_environment_view_realize(GtkWidget* widget);
29
static void gtk_environment_view_size_allocate(GtkWidget* widget, GtkAllocation* a);
30
static gboolean gtk_environment_view_expose(GtkWidget* widget,
31
                GdkEventExpose* event);
32

    
33
static gboolean gtk_environment_view_mouse_down(GtkWidget* widget,
34
                                GdkEventButton* event);
35
static gboolean gtk_environment_view_mouse_release(GtkWidget* widget,
36
                                GdkEventButton* event);
37
static gboolean gtk_environment_view_mouse_move(GtkWidget* widget,
38
                                GdkEventMotion* event);
39

    
40

    
41
static void draw_world(GdkDrawable* drawable, GdkGC* gc, world_t* world);
42
static void draw_robot(GdkDrawable* drawable, GdkGC* gc, 
43
                        float x, float y, float angle);
44

    
45
GtkType gtk_environment_view_get_type(void)
46
{
47
        static GtkType environment_view_type = 0;
48
        if (!environment_view_type)
49
        {
50
                static const GtkTypeInfo environment_view_info =
51
                {
52
                        "GtkEnvironmentView",
53
                        sizeof(GtkEnvironmentView),
54
                        sizeof(GtkEnvironmentViewClass),
55
                        (GtkClassInitFunc)gtk_environment_view_class_init,
56
                        (GtkObjectInitFunc)gtk_environment_view_init,
57
                        NULL, NULL, (GtkClassInitFunc)NULL
58
                };
59

    
60
                environment_view_type = gtk_type_unique(GTK_TYPE_WIDGET,
61
                        &environment_view_info);
62
        }
63

    
64
        return environment_view_type;
65
}
66

    
67
static void gtk_environment_view_class_init(GtkEnvironmentViewClass* environmentClass)
68
{
69
        GtkObjectClass* object_class;
70
        GtkWidgetClass* widget_class;
71

    
72
        object_class = (GtkObjectClass*)environmentClass;
73
        widget_class = (GtkWidgetClass*)environmentClass;
74

    
75
        parent_class = gtk_type_class(gtk_widget_get_type());
76

    
77
        object_class->destroy = gtk_environment_view_destroy;
78

    
79
        widget_class->realize = gtk_environment_view_realize;
80
        widget_class->expose_event = gtk_environment_view_expose;
81
        widget_class->size_request = gtk_environment_view_size_request;
82
        widget_class->size_allocate = gtk_environment_view_size_allocate;
83
        widget_class->button_press_event = gtk_environment_view_mouse_down;
84
        widget_class->button_release_event = gtk_environment_view_mouse_release;
85
        widget_class->motion_notify_event = gtk_environment_view_mouse_move;
86
}
87

    
88
GtkWidget* gtk_environment_view_new(void)
89
{
90
        GtkEnvironmentView* view;
91
        view = gtk_type_new(gtk_environment_view_get_type());
92

    
93
        return GTK_WIDGET(view);
94
}
95

    
96
static void gtk_environment_view_init(GtkEnvironmentView* view)
97
{
98
        view->topLeftX = -2.0;
99
        view->topLeftY = -1.3;
100
        view->scale = 2.0 / 800.0;
101
        view->width = -1;
102
        view->height = -1;
103

    
104
        GTK_WIDGET_SET_FLAGS(&(view->widget), GTK_DOUBLE_BUFFERED);
105

    
106
        view->mouseDown = 0;
107
}
108

    
109
static void gtk_environment_view_destroy(GtkObject* object)
110
{
111
        GtkEnvironmentView* view;
112
        g_return_if_fail(object != NULL);
113
        g_return_if_fail(GTK_IS_ENVIRONMENT_VIEW(object));
114

    
115
        view = GTK_ENVIRONMENT_VIEW(object);
116

    
117
        if (GTK_OBJECT_CLASS(parent_class)->destroy)
118
                (* GTK_OBJECT_CLASS(parent_class)->destroy) (object);
119
}
120

    
121
static void gtk_environment_view_realize(GtkWidget* widget)
122
{
123
        GtkEnvironmentView* view;
124
        GdkWindowAttr attributes;
125
        gint attributes_mask;
126

    
127
        g_return_if_fail( widget != NULL);
128
        g_return_if_fail( GTK_IS_ENVIRONMENT_VIEW(widget));
129

    
130
        GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
131
        view = GTK_ENVIRONMENT_VIEW(widget);
132

    
133
        attributes.x = widget->allocation.x;
134
        attributes.y = widget->allocation.y;
135
        attributes.width = widget->allocation.width;
136
        attributes.height = widget->allocation.height;
137
        attributes.wclass = GDK_INPUT_OUTPUT;
138
        attributes.window_type = GDK_WINDOW_CHILD;
139
        attributes.event_mask = gtk_widget_get_events(widget) |
140
                GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
141
                GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
142
                GDK_POINTER_MOTION_HINT_MASK;
143
        attributes.visual = gtk_widget_get_visual(widget);
144
        attributes.colormap = gtk_widget_get_colormap(widget);
145

    
146
        attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
147
        widget->window = gdk_window_new(widget->parent->window, &attributes,
148
                        attributes_mask);
149
        gdk_window_set_user_data(widget->window, widget);
150
        widget->style = gtk_style_attach(widget->style, widget->window);
151
        gtk_style_set_background(widget->style, widget->window,
152
                        GTK_STATE_NORMAL);
153
}
154

    
155
static void gtk_environment_view_size_request(GtkWidget* widget, 
156
                GtkRequisition* req)
157
{
158
        if (req->width < ENVIRONMENT_VIEW_MIN_WIDTH)
159
                req->width = ENVIRONMENT_VIEW_MIN_WIDTH;
160
        if (req->height < ENVIRONMENT_VIEW_MIN_HEIGHT)
161
                req->height = ENVIRONMENT_VIEW_MIN_HEIGHT;
162
}
163

    
164
static void gtk_environment_view_size_allocate(GtkWidget* widget, GtkAllocation* a)
165
{
166
        GtkEnvironmentView* view;
167

    
168
        g_return_if_fail(widget != NULL);
169
        g_return_if_fail(GTK_IS_ENVIRONMENT_VIEW(widget));
170
        g_return_if_fail(a != NULL);
171

    
172
        view = GTK_ENVIRONMENT_VIEW(widget);
173
        widget->allocation = *a;
174

    
175
        view->width = a->width;
176
        view->height = a->height;
177

    
178
        if (GTK_WIDGET_REALIZED(widget))
179
        {
180
                gdk_window_move_resize(widget->window, a->x, a->y, a->width, a->height);
181
        }
182
}
183

    
184
static gboolean gtk_environment_view_expose(GtkWidget* widget,
185
                GdkEventExpose* event)
186
{
187
        GtkEnvironmentView* view;
188

    
189
        if (widget == NULL || !GTK_IS_ENVIRONMENT_VIEW(widget) || event == NULL)
190
                return FALSE;
191
        if (event->count > 0)
192
                return FALSE;
193
        
194
        view = GTK_ENVIRONMENT_VIEW(widget);
195

    
196
        draw_world(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], &world);
197
        
198
        robot_iterator_reset();
199
        Robot* r;
200
        while ((r = robot_iterator_next()) != NULL) {
201
                draw_robot(widget->window, 
202
                        widget->style->fg_gc[GTK_WIDGET_STATE(widget)], 
203
            r->pose.x, r->pose.y, r->pose.theta);
204
    }
205

    
206
        return FALSE;
207
}
208

    
209
static gboolean gtk_environment_view_mouse_down(GtkWidget* widget,
210
                                GdkEventButton* event)
211
{
212
        GtkEnvironmentView* view;
213

    
214
        if (widget == NULL || !GTK_IS_ENVIRONMENT_VIEW(widget) || event == NULL)
215
                return FALSE;
216

    
217
        view = GTK_ENVIRONMENT_VIEW(widget);
218

    
219
        if (event->button != 1)
220
                return FALSE;
221

    
222
        view->mouseDownX = event->x;
223
        view->mouseDownY = event->y;
224
        view->mouseX = event->x;
225
        view->mouseY = event->y;
226
        view->mouseDown = 1;
227

    
228
        return FALSE;
229
}
230

    
231
static gboolean gtk_environment_view_mouse_release(GtkWidget* widget,
232
                                GdkEventButton* event)
233
{
234
        GtkEnvironmentView* view;
235
        double x1, x2, y1, y2;
236
        int w, h;
237

    
238
        if (widget == NULL || !GTK_IS_ENVIRONMENT_VIEW(widget) || event == NULL)
239
                return FALSE;
240

    
241
        view = GTK_ENVIRONMENT_VIEW(widget);
242

    
243
        if (event->button != 1 && event->button != 3)
244
                return FALSE;
245
        
246
        if (event->button == 1)
247
                view->mouseDown = 0;
248
        view->mouseX = event->x;
249
        view->mouseY = event->y;
250
        w = abs(view->mouseX - view->mouseDownX);
251
        h = abs(view->mouseY - view->mouseDownY);
252
        
253
        // if the box is big, zoom to the box
254
        if (event->button == 1 && (w >= 10 || h >= 10))
255
        {
256
                // we need to make sure the box is to scale
257
                // scale to height
258
                if (fabs((double)w / h) <= fabs((double)view->width / view->height))
259
                {
260
                        w = (int)((double)view->width / view->height * h);
261
                        if (view->mouseX < view->mouseDownX)
262
                                view->mouseX = view->mouseDownX - w;
263
                        else
264
                                view->mouseX = view->mouseDownX + w;
265
                }
266
                // scale to width
267
                else
268
                {
269
                        h = (int)((double)view->height / view->width * w);
270
                        if (view->mouseY < view->mouseDownY)
271
                                view->mouseY = view->mouseDownY - h;
272
                        else
273
                                view->mouseY = view->mouseDownY + h;
274
                }
275
        
276
                x1 = view->mouseX * view->scale + view->topLeftX;
277
                y1 = view->mouseY * view->scale + view->topLeftY;
278
                x2 = view->mouseDownX * view->scale + view->topLeftX;
279
                y2 = view->mouseDownY * view->scale + view->topLeftY;
280
                if (x2 < x1)
281
                        x1 = x2;
282
                if (y2 < y1)
283
                        y1 = y2;
284

    
285
                view->scale = (w * view->scale) / view->width;
286
                view->topLeftX = x1;
287
                view->topLeftY = y1;
288
        }
289
        else
290
        {
291
                x1 = view->mouseX * view->scale + view->topLeftX;
292
                y1 = view->mouseY * view->scale + view->topLeftY;
293

    
294
                // zoom in on left click, out on right click
295
                if (event->button == 1)
296
                        view->scale /= 2.0;
297
                else
298
                        view->scale *= 2.0;
299
                view->topLeftX = x1 - view->width / 2 * view->scale;
300
                view->topLeftY = y1 - view->height / 2 * view->scale;
301
        }
302

    
303
        return FALSE;
304
}
305

    
306
static gboolean gtk_environment_view_mouse_move(GtkWidget* widget,
307
                                GdkEventMotion* event)
308
{
309
        GtkEnvironmentView* view;
310

    
311
        if (widget == NULL || !GTK_IS_ENVIRONMENT_VIEW(widget) || event == NULL)
312
                return FALSE;
313

    
314
        view = GTK_ENVIRONMENT_VIEW(widget);
315

    
316
        view->mouseX = event->x;
317
        view->mouseY = event->y;
318

    
319
        if (!view->mouseDown)
320
                return FALSE;
321

    
322
        // we need to make sure the new view is to scale
323
        int w = abs(view->mouseX - view->mouseDownX);
324
        int h = abs(view->mouseY - view->mouseDownY);
325
        // scale to height
326
        if (fabs((double)w / h) <= fabs((double)view->width / view->height))
327
        {
328
                w = (int)((double)view->width / view->height * h);
329
                if (view->mouseX < view->mouseDownX)
330
                        view->mouseX = view->mouseDownX - w;
331
                else
332
                        view->mouseX = view->mouseDownX + w;
333
        }
334
        // scale to width
335
        else
336
        {
337
                h = (int)((double)view->height / view->width * w);
338
                if (view->mouseY < view->mouseDownY)
339
                        view->mouseY = view->mouseDownY - h;
340
                else
341
                        view->mouseY = view->mouseDownY + h;
342
        }
343

    
344
        gtk_widget_queue_draw_area(widget, 0, 0, view->width, view->height);
345

    
346
        return FALSE;
347
}
348

    
349
void gtk_environment_view_refresh(GtkWidget* view)
350
{
351
        gdk_threads_enter();
352
        gtk_widget_queue_draw(view);
353
        gdk_threads_leave();
354
}
355

    
356
static void draw_world(GdkDrawable* drawable, GdkGC* gc, world_t* world)
357
{
358
        int i, j;
359
        GdkPoint* points;
360
        poly_t* p;
361

    
362
        if (!drawable || !gc || !world)
363
                return;
364

    
365
        double leftx = world->win.p1.x;
366
        double upy = world->win.p1.x;
367
        double xwidth = world->win.p2.x - leftx;
368
        double yheight = world->win.p2.y - upy;
369
        int width, height;
370
        gdk_drawable_get_size(drawable, &width, &height);
371
        if (xwidth / width < yheight / height)
372
                width = (int)(height / yheight * xwidth);
373
        else
374
                height = (int)(width / xwidth * yheight);
375

    
376
        for (i = 0 ; i < world->max_objs; i++)
377
        {
378
                object_t* o = &(world->objs[i]);
379
                switch (o->id)
380
                {
381
                        case ID_POLY:
382
                                p = (poly_t*)o->props;
383
                                points = (GdkPoint*)malloc(sizeof(GdkPoint) * p->num_pts);
384
                                for (j = 0; j < p->num_pts; j++)
385
                                {
386
                                        points[j].x = (int)((p->pts[j].x - leftx) / xwidth * width);
387
                                        points[j].y = (int)((p->pts[j].y - upy) / yheight * height);
388
                                }
389
                                switch(p->type)
390
                                {
391
                                        case POLY_CONNECTED:
392
                                                gdk_draw_polygon(drawable, gc, 1, points, p->num_pts);
393
                                                break;
394
                                        default:
395
                                                fprintf(stderr, "Detected unexpected type of polygon.\n");
396
                                                break;
397
                                }
398
                                free(points);
399
                                break;
400
                        // no object
401
                        case ID_NULL:
402
                                break;
403
                        default:
404
                                fprintf(stderr, "Unexpected object type %d in world.\n", o->id);
405
                                break;
406
                }
407
        }
408
}
409

    
410
static void draw_robot(GdkDrawable* drawable, GdkGC* gc, 
411
                        float x, float y, float angle)
412
{
413
        double leftx = world.win.p1.x;
414
        double upy = world.win.p1.x;
415
        double xwidth = world.win.p2.x - leftx;
416
        double yheight = world.win.p2.y - upy;
417
        double rx, ry;
418
        int width, height;
419
        
420
        if (!drawable || !gc)
421
                return;
422
        gdk_drawable_get_size(drawable, &width, &height);
423
        if (xwidth / width < yheight / height)
424
                width = (int)(height / yheight * xwidth);
425
        else
426
                height = (int)(width / xwidth * yheight);
427
        
428
        rx = (double)ROBOT_DIAMETER / xwidth * width;
429
        ry = (double)ROBOT_DIAMETER / yheight * height;
430

    
431
        x = ((x - leftx) / xwidth * width);
432
        y = ((y - upy) / yheight * height);
433

    
434
        gdk_draw_arc(drawable, gc, FALSE, (int)(x - rx / 2), (int)(y - ry / 2), 
435
                rx, ry, 0, 360*64);
436

    
437
        gdk_draw_line(drawable, gc, x, y, 
438
                x + (rx / 1.8) * cos(-angle),
439
                y - (ry / 1.8) * sin(-angle));
440
}
441