~ubuntu-branches/ubuntu/raring/fyre/raring

« back to all changes in this revision

Viewing changes to src/explorer-tools.c

  • Committer: Bazaar Package Importer
  • Author(s): Christoph Haas
  • Date: 2005-05-25 21:59:19 UTC
  • Revision ID: james.westby@ubuntu.com-20050525215919-jawtso5ic23qb401
Tags: upstream-1.0.0
ImportĀ upstreamĀ versionĀ 1.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: c; c-basic-offset: 4; -*-
 
2
 *
 
3
 * explorer-tools.c - Implementation for the GUI 'tools' that allow
 
4
 *                    direct interaction with the mouse.
 
5
 *
 
6
 * Fyre - rendering and interactive exploration of chaotic functions
 
7
 * Copyright (C) 2004-2005 David Trowbridge and Micah Dowty
 
8
 *
 
9
 * This program is free software; you can redistribute it and/or
 
10
 * modify it under the terms of the GNU General Public License
 
11
 * as published by the Free Software Foundation; either version 2
 
12
 * of the License, or (at your option) any later version.
 
13
 *
 
14
 * This program is distributed in the hope that it will be useful,
 
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
 * GNU General Public License for more details.
 
18
 *
 
19
 * You should have received a copy of the GNU General Public License
 
20
 * along with this program; if not, write to the Free Software
 
21
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
22
 *
 
23
 */
 
24
 
 
25
#include "explorer.h"
 
26
#include "de-jong.h"
 
27
#include <stdlib.h>
 
28
#include <string.h>
 
29
#include <math.h>
 
30
 
 
31
typedef void (ToolHandler)(Explorer *self, ToolInput *i);
 
32
 
 
33
typedef struct _ToolInfo {
 
34
    gchar *menu_name;
 
35
    ToolHandler *handler;
 
36
    ToolFlags flags;
 
37
} ToolInfo;
 
38
 
 
39
static const ToolInfo* explorer_get_current_tool(Explorer *self);
 
40
static void explorer_fill_toolinput_relative_positions(Explorer *self, ToolInput *ti);
 
41
 
 
42
static gboolean on_motion_notify(GtkWidget *widget, GdkEvent *event, gpointer user_data);
 
43
static gboolean on_button_press(GtkWidget *widget, GdkEvent *event, gpointer user_data);
 
44
static gboolean on_button_release(GtkWidget *widget, GdkEvent *event, gpointer user_data);
 
45
static void on_tool_activate(GtkWidget *widget, gpointer user_data);
 
46
 
 
47
static void tool_grab(Explorer *self, ToolInput *i);
 
48
static void tool_blur(Explorer *self, ToolInput *i);
 
49
static void tool_zoom(Explorer *self, ToolInput *i);
 
50
static void tool_rotate(Explorer *self, ToolInput *i);
 
51
static void tool_exposure_gamma(Explorer *self, ToolInput *i);
 
52
static void tool_a_b(Explorer *self, ToolInput *i);
 
53
static void tool_a_c(Explorer *self, ToolInput *i);
 
54
static void tool_a_d(Explorer *self, ToolInput *i);
 
55
static void tool_b_c(Explorer *self, ToolInput *i);
 
56
static void tool_b_d(Explorer *self, ToolInput *i);
 
57
static void tool_c_d(Explorer *self, ToolInput *i);
 
58
static void tool_ab_cd(Explorer *self, ToolInput *i);
 
59
static void tool_ac_bd(Explorer *self, ToolInput *i);
 
60
static void tool_initial_offset(Explorer *self, ToolInput *i);
 
61
static void tool_initial_scale(Explorer *self, ToolInput *i);
 
62
 
 
63
 
 
64
/* A table of tool handlers and menu item names */
 
65
static const ToolInfo tool_table[] = {
 
66
 
 
67
    {"tool_grab",           tool_grab,           TOOL_USE_MOTION_EVENTS},
 
68
    {"tool_blur",           tool_blur,           TOOL_USE_MOTION_EVENTS},
 
69
    {"tool_zoom",           tool_zoom,           TOOL_USE_IDLE},
 
70
    {"tool_rotate",         tool_rotate,         TOOL_USE_MOTION_EVENTS},
 
71
    {"tool_exposure_gamma", tool_exposure_gamma, TOOL_USE_MOTION_EVENTS},
 
72
    {"tool_a_b",            tool_a_b,            TOOL_USE_MOTION_EVENTS},
 
73
    {"tool_a_c",            tool_a_c,            TOOL_USE_MOTION_EVENTS},
 
74
    {"tool_a_d",            tool_a_d,            TOOL_USE_MOTION_EVENTS},
 
75
    {"tool_b_c",            tool_b_c,            TOOL_USE_MOTION_EVENTS},
 
76
    {"tool_b_d",            tool_b_d,            TOOL_USE_MOTION_EVENTS},
 
77
    {"tool_c_d",            tool_c_d,            TOOL_USE_MOTION_EVENTS},
 
78
    {"tool_ab_cd",          tool_ab_cd,          TOOL_USE_MOTION_EVENTS},
 
79
    {"tool_ac_bd",          tool_ac_bd,          TOOL_USE_MOTION_EVENTS},
 
80
    {"tool_initial_offset", tool_initial_offset, TOOL_USE_MOTION_EVENTS},
 
81
    {"tool_initial_scale",  tool_initial_scale,  TOOL_USE_MOTION_EVENTS},
 
82
 
 
83
    {NULL,},
 
84
};
 
85
 
 
86
 
 
87
/************************************************************************************/
 
88
/**************************************************** Initialization / Finalization */
 
89
/************************************************************************************/
 
90
 
 
91
void explorer_init_tools(Explorer *self) {
 
92
    gtk_widget_add_events(self->view,
 
93
                          GDK_BUTTON_PRESS_MASK |
 
94
                          GDK_BUTTON_RELEASE_MASK |
 
95
                          GDK_BUTTON_MOTION_MASK |
 
96
                          GDK_POINTER_MOTION_HINT_MASK);
 
97
 
 
98
    glade_xml_signal_connect_data(self->xml, "on_tool_activate",  G_CALLBACK(on_tool_activate),  self);
 
99
 
 
100
    g_signal_connect(self->view, "motion_notify_event",  G_CALLBACK(on_motion_notify),  self);
 
101
    g_signal_connect(self->view, "button_press_event",   G_CALLBACK(on_button_press),   self);
 
102
    g_signal_connect(self->view, "button_release_event", G_CALLBACK(on_button_release), self);
 
103
 
 
104
    self->current_tool = "None";
 
105
}
 
106
 
 
107
 
 
108
/************************************************************************************/
 
109
/****************************************************************** Tool Invocation */
 
110
/************************************************************************************/
 
111
 
 
112
static const ToolInfo* explorer_get_current_tool(Explorer *self) {
 
113
    /* Return the current tool, or NULL if no tool is active
 
114
     */
 
115
    const ToolInfo *current = tool_table;
 
116
 
 
117
    for (current=tool_table; current->menu_name; current++) {
 
118
        GtkWidget *w = glade_xml_get_widget(self->xml, current->menu_name);
 
119
        if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)))
 
120
            return current;
 
121
    }
 
122
    return NULL;
 
123
}
 
124
 
 
125
static void explorer_fill_toolinput_relative_positions(Explorer *self, ToolInput *ti) {
 
126
    /* Fill in the delta and click-relative positions in a given toolinfo
 
127
     */
 
128
 
 
129
    /* Compute delta position */
 
130
    ti->delta_x = ti->absolute_x - self->last_mouse_x;
 
131
    ti->delta_y = ti->absolute_y - self->last_mouse_y;
 
132
 
 
133
    /* Compute click-relative position */
 
134
    ti->click_relative_x = ti->absolute_x - self->last_click_x;
 
135
    ti->click_relative_y = ti->absolute_y - self->last_click_y;
 
136
}
 
137
 
 
138
static gboolean on_motion_notify(GtkWidget *widget, GdkEvent *event, gpointer user_data) {
 
139
    Explorer *self = EXPLORER(user_data);
 
140
    const ToolInfo *tool = explorer_get_current_tool(self);
 
141
    ToolInput ti;
 
142
    memset(&ti, 0, sizeof(ti));
 
143
 
 
144
    /* Fill in the absolute position and state for the ToolInput */
 
145
    if (event->motion.is_hint) {
 
146
        gint ix, iy;
 
147
        gdk_window_get_pointer(event->motion.window, &ix, &iy, &ti.state);
 
148
        ti.absolute_x = ix;
 
149
        ti.absolute_y = iy;
 
150
    }
 
151
    else {
 
152
        ti.absolute_x = event->motion.x;
 
153
        ti.absolute_y = event->motion.y;
 
154
        ti.state = event->motion.state;
 
155
    }
 
156
    explorer_fill_toolinput_relative_positions(self, &ti);
 
157
    self->last_mouse_x = ti.absolute_x;
 
158
    self->last_mouse_y = ti.absolute_y;
 
159
 
 
160
    if (tool && (tool->flags & TOOL_USE_MOTION_EVENTS)) {
 
161
        tool->handler(self, &ti);
 
162
 
 
163
        /* Always push through one frame of updates manually
 
164
         * before going on. This serves multiple purposes-
 
165
         * if we're paused, we need this to get any response
 
166
         * at all. This also forces an update to happen even
 
167
         * if the idle handler won't be run for a while, making
 
168
         * the GUI more responsive. This is especially important
 
169
         * under Windows, where the idle handler seems to have
 
170
         * a lower priority.
 
171
         */
 
172
        explorer_run_iterations(self);
 
173
    }
 
174
 
 
175
    return FALSE;
 
176
}
 
177
 
 
178
static void on_tool_activate(GtkWidget *widget, gpointer user_data) {
 
179
    Explorer *self = EXPLORER(user_data);
 
180
 
 
181
    if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)))
 
182
        gtk_label_get(GTK_LABEL(gtk_bin_get_child(GTK_BIN(widget))), &self->current_tool);
 
183
 
 
184
    self->status_dirty_flag = TRUE;
 
185
}
 
186
 
 
187
static gboolean on_button_press(GtkWidget *widget, GdkEvent *event, gpointer user_data) {
 
188
    Explorer *self = EXPLORER(user_data);
 
189
 
 
190
    self->tool_active = TRUE;
 
191
    self->last_mouse_x = event->button.x;
 
192
    self->last_mouse_y = event->button.y;
 
193
    self->last_click_x = event->button.x;
 
194
    self->last_click_y = event->button.y;
 
195
    return FALSE;
 
196
}
 
197
 
 
198
static gboolean on_button_release(GtkWidget *widget, GdkEvent *event, gpointer user_data) {
 
199
    Explorer *self = EXPLORER(user_data);
 
200
    self->tool_active = FALSE;
 
201
    return FALSE;
 
202
}
 
203
 
 
204
gboolean explorer_update_tools(Explorer *self) {
 
205
    /* If we're using a tool that needs to be updated when idle, do it.
 
206
     * Returns a boolean indicating whether a tool is active or not.
 
207
     */
 
208
    const ToolInfo *tool = explorer_get_current_tool(self);
 
209
    ToolInput ti;
 
210
    gint ix, iy;
 
211
    GTimeVal now;
 
212
    memset(&ti, 0, sizeof(ti));
 
213
 
 
214
    gdk_window_get_pointer(self->view->window, &ix, &iy, &ti.state);
 
215
    ti.absolute_x = ix;
 
216
    ti.absolute_y = iy;
 
217
    explorer_fill_toolinput_relative_positions(self, &ti);
 
218
 
 
219
    /* Compute the delta time */
 
220
    g_get_current_time(&now);
 
221
    ti.delta_time = ((now.tv_usec - self->last_tool_idle_update.tv_usec) / 1000000.0 +
 
222
                     (now.tv_sec  - self->last_tool_idle_update.tv_sec ));
 
223
    self->last_tool_idle_update = now;
 
224
 
 
225
    if (tool && self->tool_active && (tool->flags & TOOL_USE_IDLE)) {
 
226
        tool->handler(self, &ti);
 
227
        return TRUE;
 
228
    }
 
229
    else {
 
230
        return FALSE;
 
231
    }
 
232
}
 
233
 
 
234
 
 
235
/************************************************************************************/
 
236
/******************************************************************** Tool handlers */
 
237
/************************************************************************************/
 
238
 
 
239
static void tool_grab(Explorer *self, ToolInput *i) {
 
240
    double scale = 5.0 / DE_JONG(self->map)->zoom / HISTOGRAM_IMAGER(self->map)->width;
 
241
    g_object_set(self->map,
 
242
                 "xoffset", DE_JONG(self->map)->xoffset + i->delta_x * scale,
 
243
                 "yoffset", DE_JONG(self->map)->yoffset + i->delta_y * scale,
 
244
                 NULL);
 
245
}
 
246
 
 
247
static void tool_blur(Explorer *self, ToolInput *i) {
 
248
    g_object_set(self->map,
 
249
                 "blur_ratio",  DE_JONG(self->map)->blur_ratio  + i->delta_x * 0.002,
 
250
                 "blur_radius", DE_JONG(self->map)->blur_radius - i->delta_y * 0.001,
 
251
                 NULL);
 
252
}
 
253
 
 
254
static void tool_zoom(Explorer *self, ToolInput *i) {
 
255
    double p, scaled_p;
 
256
    const double exponent = 1.4;
 
257
 
 
258
    /* Scale the zooming speed nonlinearly with the distance from click location */
 
259
    p = i->click_relative_y * 0.01;
 
260
    if (p < 0) {
 
261
        scaled_p = -pow(-p, exponent);
 
262
    }
 
263
    else {
 
264
        scaled_p = pow(p, exponent);
 
265
    }
 
266
 
 
267
    g_object_set(self->map,
 
268
                 "zoom", DE_JONG(self->map)->zoom - scaled_p * i->delta_time,
 
269
                 NULL);
 
270
}
 
271
 
 
272
static void tool_rotate(Explorer *self, ToolInput *i) {
 
273
    /* We're a bit tricky here and also rotate the X and Y offset such that we're
 
274
     * rotating around the center of the view, rather than rotating around the
 
275
     * center of rendering coordinates.
 
276
     */
 
277
    double delta_r = -i->delta_x * 0.0089;
 
278
    double sin_d_r = sin(delta_r);
 
279
    double cos_d_r = cos(delta_r);
 
280
    g_object_set(self->map,
 
281
                 "rotation", (gdouble) (DE_JONG(self->map)->rotation + delta_r),
 
282
                 "xoffset",  (gdouble) ( cos_d_r * DE_JONG(self->map)->xoffset + sin_d_r * DE_JONG(self->map)->yoffset),
 
283
                 "yoffset",  (gdouble) (-sin_d_r * DE_JONG(self->map)->xoffset + cos_d_r * DE_JONG(self->map)->yoffset),
 
284
                 NULL);
 
285
}
 
286
 
 
287
static void tool_exposure_gamma(Explorer *self, ToolInput *i) {
 
288
    g_object_set(self->map,
 
289
                 "exposure", HISTOGRAM_IMAGER(self->map)->exposure - i->delta_y * 0.001,
 
290
                 "gamma",    HISTOGRAM_IMAGER(self->map)->gamma    + i->delta_x * 0.001,
 
291
                 NULL);
 
292
}
 
293
 
 
294
static void tool_a_b(Explorer *self, ToolInput *i) {
 
295
    g_object_set(self->map,
 
296
                 "a", DE_JONG(self->map)->param.a + i->delta_x * 0.001,
 
297
                 "b", DE_JONG(self->map)->param.b + i->delta_y * 0.001,
 
298
                 NULL);
 
299
}
 
300
 
 
301
static void tool_a_c(Explorer *self, ToolInput *i) {
 
302
    g_object_set(self->map,
 
303
                 "a", DE_JONG(self->map)->param.a + i->delta_x * 0.001,
 
304
                 "c", DE_JONG(self->map)->param.c + i->delta_y * 0.001,
 
305
                 NULL);
 
306
}
 
307
 
 
308
static void tool_a_d(Explorer *self, ToolInput *i) {
 
309
    g_object_set(self->map,
 
310
                 "a", DE_JONG(self->map)->param.a + i->delta_x * 0.001,
 
311
                 "d", DE_JONG(self->map)->param.d + i->delta_y * 0.001,
 
312
                 NULL);
 
313
}
 
314
 
 
315
static void tool_b_c(Explorer *self, ToolInput *i) {
 
316
    g_object_set(self->map,
 
317
                 "b", DE_JONG(self->map)->param.b + i->delta_x * 0.001,
 
318
                 "c", DE_JONG(self->map)->param.c + i->delta_y * 0.001,
 
319
                 NULL);
 
320
}
 
321
 
 
322
static void tool_b_d(Explorer *self, ToolInput *i) {
 
323
    g_object_set(self->map,
 
324
                 "b", DE_JONG(self->map)->param.b + i->delta_x * 0.001,
 
325
                 "d", DE_JONG(self->map)->param.d + i->delta_y * 0.001,
 
326
                 NULL);
 
327
}
 
328
 
 
329
static void tool_c_d(Explorer *self, ToolInput *i) {
 
330
    g_object_set(self->map,
 
331
                 "c", DE_JONG(self->map)->param.c + i->delta_x * 0.001,
 
332
                 "d", DE_JONG(self->map)->param.d + i->delta_y * 0.001,
 
333
                 NULL);
 
334
}
 
335
 
 
336
static void tool_ab_cd(Explorer *self, ToolInput *i) {
 
337
    g_object_set(self->map,
 
338
                 "a", DE_JONG(self->map)->param.a + i->delta_x * 0.001,
 
339
                 "b", DE_JONG(self->map)->param.b + i->delta_x * 0.001,
 
340
                 "c", DE_JONG(self->map)->param.c + i->delta_y * 0.001,
 
341
                 "d", DE_JONG(self->map)->param.d + i->delta_y * 0.001,
 
342
                 NULL);
 
343
}
 
344
 
 
345
static void tool_ac_bd(Explorer *self, ToolInput *i) {
 
346
    g_object_set(self->map,
 
347
                 "a", DE_JONG(self->map)->param.a + i->delta_x * 0.001,
 
348
                 "b", DE_JONG(self->map)->param.b + i->delta_y * 0.001,
 
349
                 "c", DE_JONG(self->map)->param.c + i->delta_x * 0.001,
 
350
                 "d", DE_JONG(self->map)->param.d + i->delta_y * 0.001,
 
351
                 NULL);
 
352
}
 
353
 
 
354
static void tool_initial_offset(Explorer *self, ToolInput *i) {
 
355
    g_object_set(self->map,
 
356
                 "initial_xoffset", DE_JONG(self->map)->initial_xoffset + i->delta_x * 0.001,
 
357
                 "initial_yoffset", DE_JONG(self->map)->initial_yoffset + i->delta_y * 0.001,
 
358
                 NULL);
 
359
}
 
360
 
 
361
static void tool_initial_scale(Explorer *self, ToolInput *i) {
 
362
    g_object_set(self->map,
 
363
                 "initial_xscale", DE_JONG(self->map)->initial_xscale + i->delta_x * 0.001,
 
364
                 "initial_yscale", DE_JONG(self->map)->initial_yscale - i->delta_y * 0.001,
 
365
                 NULL);
 
366
}
 
367
 
 
368
/* The End */