Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (11.4 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
#define ENVIRONMENT_VIEW_MIN_WIDTH                100
13
#define ENVIRONMENT_VIEW_MIN_HEIGHT                50
14

    
15
static GtkWidgetClass* parent_class = NULL;
16

    
17
static void gtk_environment_view_class_init(GtkEnvironmentViewClass* environmentClass);
18
static void gtk_environment_view_init(GtkEnvironmentView* view);
19
static void gtk_environment_view_destroy(GtkObject* object);
20

    
21
static void gtk_environment_view_size_request(GtkWidget* widget,
22
                GtkRequisition* req);
23
static void gtk_environment_view_realize(GtkWidget* widget);
24
static void gtk_environment_view_size_allocate(GtkWidget* widget, GtkAllocation* a);
25
static gboolean gtk_environment_view_expose(GtkWidget* widget,
26
                GdkEventExpose* event);
27

    
28
static gboolean gtk_environment_view_mouse_down(GtkWidget* widget,
29
                                GdkEventButton* event);
30
static gboolean gtk_environment_view_mouse_release(GtkWidget* widget,
31
                                GdkEventButton* event);
32
static gboolean gtk_environment_view_mouse_move(GtkWidget* widget,
33
                                GdkEventMotion* event);
34

    
35
static void gtk_environment_view_render_begin(GtkEnvironmentView* view);
36
static void gtk_environment_view_render_abort(GtkEnvironmentView* view);
37

    
38
static void gtk_environment_view_get_pixel(GtkEnvironmentView* view,
39
                double x,double y, unsigned char* pixel);
40

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

    
56
                environment_view_type = gtk_type_unique(GTK_TYPE_WIDGET,
57
                        &environment_view_info);
58
        }
59

    
60
        return environment_view_type;
61
}
62

    
63
static void gtk_environment_view_class_init(GtkEnvironmentViewClass* environmentClass)
64
{
65
        GtkObjectClass* object_class;
66
        GtkWidgetClass* widget_class;
67

    
68
        object_class = (GtkObjectClass*)environmentClass;
69
        widget_class = (GtkWidgetClass*)environmentClass;
70

    
71
        parent_class = gtk_type_class(gtk_widget_get_type());
72

    
73
        object_class->destroy = gtk_environment_view_destroy;
74

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

    
84
GtkWidget* gtk_environment_view_new(void)
85
{
86
        GtkEnvironmentView* view;
87
        view = gtk_type_new(gtk_environment_view_get_type());
88

    
89
        return GTK_WIDGET(view);
90
}
91

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

    
101
        view->mouseDown = 0;
102
}
103

    
104
static void gtk_environment_view_destroy(GtkObject* object)
105
{
106
        GtkEnvironmentView* view;
107
        g_return_if_fail(object != NULL);
108
        g_return_if_fail(GTK_IS_ENVIRONMENT_VIEW(object));
109

    
110
        view = GTK_ENVIRONMENT_VIEW(object);
111
        gtk_environment_view_render_abort(view);
112
        
113
        if (view->buf != NULL)
114
        {
115
                free(view->buf);
116
                view->buf = NULL;
117
                view->width = -1;
118
                view->height = -1;
119
        }
120

    
121
        if (GTK_OBJECT_CLASS(parent_class)->destroy)
122
                (* GTK_OBJECT_CLASS(parent_class)->destroy) (object);
123
}
124

    
125
static void gtk_environment_view_realize(GtkWidget* widget)
126
{
127
        GtkEnvironmentView* view;
128
        GdkWindowAttr attributes;
129
        gint attributes_mask;
130

    
131
        g_return_if_fail( widget != NULL);
132
        g_return_if_fail( GTK_IS_ENVIRONMENT_VIEW(widget));
133

    
134
        GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
135
        view = GTK_ENVIRONMENT_VIEW(widget);
136

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

    
150
        attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
151
        widget->window = gdk_window_new(widget->parent->window, &attributes,
152
                        attributes_mask);
153
        gdk_window_set_user_data(widget->window, widget);
154
        widget->style = gtk_style_attach(widget->style, widget->window);
155
        gtk_style_set_background(widget->style, widget->window,
156
                        GTK_STATE_NORMAL);
157
}
158

    
159
static void gtk_environment_view_size_request(GtkWidget* widget, 
160
                GtkRequisition* req)
161
{
162
        if (req->width < ENVIRONMENT_VIEW_MIN_WIDTH)
163
                req->width = ENVIRONMENT_VIEW_MIN_WIDTH;
164
        if (req->height < ENVIRONMENT_VIEW_MIN_HEIGHT)
165
                req->height = ENVIRONMENT_VIEW_MIN_HEIGHT;
166
}
167

    
168
static void gtk_environment_view_size_allocate(GtkWidget* widget, GtkAllocation* a)
169
{
170
        GtkEnvironmentView* view;
171

    
172
        g_return_if_fail(widget != NULL);
173
        g_return_if_fail(GTK_IS_ENVIRONMENT_VIEW(widget));
174
        g_return_if_fail(a != NULL);
175

    
176
        view = GTK_ENVIRONMENT_VIEW(widget);
177
        gtk_environment_view_render_abort(view);
178
        widget->allocation = *a;
179

    
180
        // resize buffer
181
        if (view->buf != NULL)
182
        {
183
                free(view->buf);
184
                view->buf = NULL;
185
                view->width = -1;
186
                view->height = -1;
187
        }
188
        view->buf = (guchar*)malloc(a->width * a->height * 3 * sizeof(guchar));
189
        memset(view->buf, 0, a->width * a->height * 3 * sizeof(guchar));
190
        view->width = a->width;
191
        view->height = a->height;
192

    
193
        if (GTK_WIDGET_REALIZED(widget))
194
        {
195
                gdk_window_move_resize(widget->window, a->x, a->y, a->width, a->height);
196
                gtk_environment_view_render_begin(view);
197
        }
198
}
199

    
200
static gboolean gtk_environment_view_expose(GtkWidget* widget,
201
                GdkEventExpose* event)
202
{
203
        GtkEnvironmentView* view;
204

    
205
        if (widget == NULL || !GTK_IS_ENVIRONMENT_VIEW(widget) || event == NULL)
206
                return FALSE;
207
        if (event->count > 0)
208
                return FALSE;
209
        
210
        view = GTK_ENVIRONMENT_VIEW(widget);
211
        
212
        gdk_draw_rgb_image(widget->window, widget->style->fg_gc[
213
                        GTK_WIDGET_STATE(widget)], event->area.x, 
214
                        event->area.y, event->area.width, 
215
                        event->area.height, GDK_RGB_DITHER_NONE, 
216
                        view->buf + 3 * (event->area.y * view->width + event->area.x),
217
                        3 * view->width);
218
        
219
        return FALSE;
220
}
221

    
222
static gboolean gtk_environment_view_mouse_down(GtkWidget* widget,
223
                                GdkEventButton* event)
224
{
225
        GtkEnvironmentView* view;
226

    
227
        if (widget == NULL || !GTK_IS_ENVIRONMENT_VIEW(widget) || event == NULL)
228
                return FALSE;
229

    
230
        view = GTK_ENVIRONMENT_VIEW(widget);
231

    
232
        if (event->button != 1)
233
                return FALSE;
234

    
235
        view->mouseDownX = event->x;
236
        view->mouseDownY = event->y;
237
        view->mouseX = event->x;
238
        view->mouseY = event->y;
239
        view->mouseDown = 1;
240

    
241
        return FALSE;
242
}
243

    
244
static gboolean gtk_environment_view_mouse_release(GtkWidget* widget,
245
                                GdkEventButton* event)
246
{
247
        GtkEnvironmentView* view;
248
        double x1, x2, y1, y2;
249
        int w, h;
250

    
251
        if (widget == NULL || !GTK_IS_ENVIRONMENT_VIEW(widget) || event == NULL)
252
                return FALSE;
253

    
254
        view = GTK_ENVIRONMENT_VIEW(widget);
255

    
256
        if (event->button != 1 && event->button != 3)
257
                return FALSE;
258
        
259
        if (event->button == 1)
260
                view->mouseDown = 0;
261
        view->mouseX = event->x;
262
        view->mouseY = event->y;
263
        w = abs(view->mouseX - view->mouseDownX);
264
        h = abs(view->mouseY - view->mouseDownY);
265
        
266
        gtk_environment_view_render_abort(view);
267
        
268
        // if the box is big, zoom to the box
269
        if (event->button == 1 && (w >= 10 || h >= 10))
270
        {
271
                // we need to make sure the box is to scale
272
                // scale to height
273
                if (fabs((double)w / h) <= fabs((double)view->width / view->height))
274
                {
275
                        w = (int)((double)view->width / view->height * h);
276
                        if (view->mouseX < view->mouseDownX)
277
                                view->mouseX = view->mouseDownX - w;
278
                        else
279
                                view->mouseX = view->mouseDownX + w;
280
                }
281
                // scale to width
282
                else
283
                {
284
                        h = (int)((double)view->height / view->width * w);
285
                        if (view->mouseY < view->mouseDownY)
286
                                view->mouseY = view->mouseDownY - h;
287
                        else
288
                                view->mouseY = view->mouseDownY + h;
289
                }
290
        
291
                x1 = view->mouseX * view->scale + view->topLeftX;
292
                y1 = view->mouseY * view->scale + view->topLeftY;
293
                x2 = view->mouseDownX * view->scale + view->topLeftX;
294
                y2 = view->mouseDownY * view->scale + view->topLeftY;
295
                if (x2 < x1)
296
                        x1 = x2;
297
                if (y2 < y1)
298
                        y1 = y2;
299

    
300
                view->scale = (w * view->scale) / view->width;
301
                view->topLeftX = x1;
302
                view->topLeftY = y1;
303
        }
304
        else
305
        {
306
                x1 = view->mouseX * view->scale + view->topLeftX;
307
                y1 = view->mouseY * view->scale + view->topLeftY;
308

    
309
                // zoom in on left click, out on right click
310
                if (event->button == 1)
311
                        view->scale /= 2.0;
312
                else
313
                        view->scale *= 2.0;
314
                view->topLeftX = x1 - view->width / 2 * view->scale;
315
                view->topLeftY = y1 - view->height / 2 * view->scale;
316
        }
317

    
318
        gtk_environment_view_render_begin(view);
319

    
320
        return FALSE;
321
}
322

    
323
static gboolean gtk_environment_view_mouse_move(GtkWidget* widget,
324
                                GdkEventMotion* event)
325
{
326
        GtkEnvironmentView* view;
327

    
328
        if (widget == NULL || !GTK_IS_ENVIRONMENT_VIEW(widget) || event == NULL)
329
                return FALSE;
330

    
331
        view = GTK_ENVIRONMENT_VIEW(widget);
332

    
333
        view->mouseX = event->x;
334
        view->mouseY = event->y;
335

    
336
        if (!view->mouseDown)
337
                return FALSE;
338

    
339
        // we need to make sure the new view is to scale
340
        int w = abs(view->mouseX - view->mouseDownX);
341
        int h = abs(view->mouseY - view->mouseDownY);
342
        // scale to height
343
        if (fabs((double)w / h) <= fabs((double)view->width / view->height))
344
        {
345
                w = (int)((double)view->width / view->height * h);
346
                if (view->mouseX < view->mouseDownX)
347
                        view->mouseX = view->mouseDownX - w;
348
                else
349
                        view->mouseX = view->mouseDownX + w;
350
        }
351
        // scale to width
352
        else
353
        {
354
                h = (int)((double)view->height / view->width * w);
355
                if (view->mouseY < view->mouseDownY)
356
                        view->mouseY = view->mouseDownY - h;
357
                else
358
                        view->mouseY = view->mouseDownY + h;
359
        }
360

    
361
        gtk_widget_queue_draw_area(widget, 0, 0, view->width, view->height);
362

    
363
        return FALSE;
364
}
365

    
366
static void* gtk_environment_view_do_work(void* arg)
367
{
368
        GtkEnvironmentView* view = (GtkEnvironmentView*)arg;
369
        GtkWidget* widget = GTK_WIDGET(view);
370
        int row, col;
371
        while ((row = gtk_environment_view_acquire_row(view)) >= 0 && view->working)
372
        {
373
                int pos = 3 * row * view->width;
374
                double y = row * view->scale + view->topLeftY;
375
                double x = view->topLeftX;
376
                for (col = 0; col < view->width && view->working; col++)
377
                {
378
                        gtk_environment_view_get_pixel(view, x, y, &view->buf[pos]);
379
                        pos += 3;
380
                        x += view->scale;
381
                }
382
                gdk_threads_enter();
383
                gtk_widget_queue_draw_area(widget, 0, row, view->width, 1);
384
                gdk_threads_leave();
385
        }
386
        view->num_active_threads--;
387
        // print out time in milliseconds
388
        if (view->num_active_threads == 0)
389
        {
390
                struct timeval t;
391
                gettimeofday(&t, NULL);
392
                unsigned int diff = (t.tv_sec - view->starttime.tv_sec) * 1000 +
393
                                                        (t.tv_usec - view->starttime.tv_usec) / 1000;
394
                printf("Generated in %d milliseconds.\n", diff);
395
        }
396

    
397
        return NULL;
398
}
399

    
400
// spawn worker threads
401
static void gtk_environment_view_render_begin(GtkEnvironmentView* view)
402
{
403
        int i;
404
        view->working = 1;
405
        view->cur_row = 0;
406
        view->num_active_threads = NUM_THREADS;
407
        gettimeofday(&view->starttime, NULL);
408
        for (i = 0; i < NUM_THREADS; i++)
409
                view->worker_threads[i] = g_thread_create(
410
                                gtk_environment_view_do_work, view, TRUE, NULL);
411
}
412

    
413
static void gtk_environment_view_render_abort(GtkEnvironmentView* view)
414
{
415
        int i;
416
        if (view->working)
417
        {
418
                view->working = 0;
419
                gdk_threads_leave();
420
                for (i = 0; i < NUM_THREADS; i++)
421
                        g_thread_join(view->worker_threads[i]);
422
                gdk_threads_enter();
423
        }
424
}
425