Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (9.96 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

    
14
#define ENVIRONMENT_VIEW_MIN_WIDTH                100
15
#define ENVIRONMENT_VIEW_MIN_HEIGHT                50
16

    
17
#define ENVIRONMENT_PI                              3.14159
18
#define ENVIRONMENT_ROBOT_DIAMETER                50
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_robot(GdkDrawable* drawable, GdkGC* gc, 
42
                        int x, int y, int angle);
43

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

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

    
63
        return environment_view_type;
64
}
65

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

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

    
74
        parent_class = gtk_type_class(gtk_widget_get_type());
75

    
76
        object_class->destroy = gtk_environment_view_destroy;
77

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

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

    
92
        return GTK_WIDGET(view);
93
}
94

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

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

    
105
        view->mouseDown = 0;
106
}
107

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

    
114
        view = GTK_ENVIRONMENT_VIEW(object);
115

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

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

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

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

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

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

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

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

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

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

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

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

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

    
188
        if (widget == NULL || !GTK_IS_ENVIRONMENT_VIEW(widget) || event == NULL)
189
                return FALSE;
190
        if (event->count > 0)
191
                return FALSE;
192
        
193
        view = GTK_ENVIRONMENT_VIEW(widget);
194
        
195
        robot_iterator_reset();
196
        Robot* r;
197
        while ((r = robot_iterator_next()) != NULL) {
198
        printf("x: %d, y:%d, Theta: %f\n",
199
            r->pose.x, r->pose.y, r->pose.theta);
200
                draw_robot(widget->window, 
201
                        widget->style->fg_gc[GTK_WIDGET_STATE(widget)], 
202
            r->pose.x, r->pose.y, r->pose.theta);
203
    }
204

    
205
        return FALSE;
206
}
207

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

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

    
216
        view = GTK_ENVIRONMENT_VIEW(widget);
217

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

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

    
227
        return FALSE;
228
}
229

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

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

    
240
        view = GTK_ENVIRONMENT_VIEW(widget);
241

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

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

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

    
302
        return FALSE;
303
}
304

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

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

    
313
        view = GTK_ENVIRONMENT_VIEW(widget);
314

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

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

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

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

    
345
        return FALSE;
346
}
347

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

    
355
static void draw_robot(GdkDrawable* drawable, GdkGC* gc, 
356
                        int x, int y, int angle) 
357
{
358
        if (!drawable || !gc)
359
                return;
360
        double ang_rad = angle * ENVIRONMENT_PI / 180;
361
        int x_c = x - ENVIRONMENT_ROBOT_DIAMETER / 2;
362
        int y_c = y - ENVIRONMENT_ROBOT_DIAMETER / 2;
363

    
364
        gdk_draw_arc(drawable, gc, FALSE, x_c, y_c, 
365
                  ENVIRONMENT_ROBOT_DIAMETER, ENVIRONMENT_ROBOT_DIAMETER, 
366
        0, 360*64);
367

    
368
        gdk_draw_line(drawable, gc, x, y, 
369
                x + (ENVIRONMENT_ROBOT_DIAMETER - 10) * cos(ang_rad),
370
                y - (ENVIRONMENT_ROBOT_DIAMETER - 10) * sin(ang_rad));
371
}
372