source: trunk/src/gtk/editor.cpp @ 159

Last change on this file since 159 was 159, checked in by sam, 10 years ago

Allow the sprite viewer window to pan.

  • Property svn:keywords set to Id
File size: 7.2 KB
Line 
1//
2// Deus Hax (working title)
3// Copyright (c) 2010 Sam Hocevar <sam@hocevar.net>
4//
5
6#if defined HAVE_CONFIG_H
7#   include "config.h"
8#endif
9
10#include <cstdio>
11#include <cstdlib>
12#include <cmath>
13
14#include <gtk/gtk.h>
15#include <gtkgl/gtkglarea.h>
16
17#include "core.h"
18#include "debugfps.h"
19
20static volatile int quit = 0;
21
22static int ticking = 0;
23static int panning = 0;
24static double xpan = 0.0f, ypan = 0.0f;
25static float const FPS = 30.0f;
26
27static MapViewer *mv;
28static GtkWidget *glarea;
29static GtkAdjustment *hadj, *vadj;
30
31static gint main_quit(GtkWidget *widget, GdkEventExpose *event)
32{
33    (void)widget;
34    (void)event;
35
36    quit = 1;
37    gtk_main_quit();
38    return FALSE;
39}
40
41static gboolean tick(void *widget)
42{
43    // FIXME: do not do anything if the previous tick was too recent?
44
45    // FIXME: only quit if all entities have been cleaned
46    if (quit)
47        return FALSE;
48
49    ticking = 1;
50
51    mv->SetPOV(gtk_adjustment_get_value(hadj), gtk_adjustment_get_value(vadj));
52
53    /* Tick the game */
54    Ticker::TickGame();
55
56    gtk_widget_draw(GTK_WIDGET(widget), NULL);
57
58    return TRUE;
59}
60
61static gboolean mouse_button(GtkWidget *widget, GdkEventButton *event,
62                                                gpointer user_data)
63{
64    if (event->type == GDK_BUTTON_PRESS && event->button == 2)
65    {
66        panning = 1;
67        xpan = event->x;
68        ypan = event->y;
69        GdkCursor *cursor = gdk_cursor_new(GDK_HAND1);
70        gdk_window_set_cursor(widget->window, cursor);
71        gdk_cursor_unref(cursor);
72        return FALSE;
73    }
74    else if (event->type == GDK_BUTTON_RELEASE && event->button == 2)
75    {
76        panning = 0;
77        gdk_window_set_cursor(widget->window, NULL);
78        return FALSE;
79    }
80
81    return TRUE;
82}
83
84static gboolean mouse_motion(GtkWidget *widget, GdkEventMotion *event,
85                                                gpointer user_data)
86{
87    if (panning)
88    {
89        if (event->x != xpan)
90        {
91            double val = gtk_adjustment_get_value(hadj);
92            val += xpan - event->x;
93            xpan = event->x;
94            if (val + widget->allocation.width > mv->GetWidth())
95                val = mv->GetWidth() - widget->allocation.width;
96            gtk_adjustment_set_value(hadj, val);
97            gtk_adjustment_value_changed(hadj);
98        }
99
100        if (event->y != ypan)
101        {
102            double val = gtk_adjustment_get_value(vadj);
103            val += ypan - event->y;
104            ypan = event->y;
105            if (val + widget->allocation.height > mv->GetHeight())
106                val = mv->GetHeight() - widget->allocation.height;
107            gtk_adjustment_set_value(vadj, val);
108            gtk_adjustment_value_changed(vadj);
109        }
110    }
111
112    return TRUE;
113}
114
115static gint init(GtkWidget *widget)
116{
117    /* Manage adjustments */
118    struct
119    {
120        GtkAdjustment *adj;
121        float map_size, sw_size;
122    }
123    s[2] =
124    {
125        { hadj, mv->GetWidth(), widget->allocation.width },
126        { vadj, mv->GetHeight(), widget->allocation.height },
127    };
128
129    for (int i = 0; i < 2; i++)
130    {
131        gtk_adjustment_set_lower(s[i].adj, 0);
132        gtk_adjustment_set_upper(s[i].adj, s[i].map_size);
133        gtk_adjustment_set_step_increment(s[i].adj, 1);
134        gtk_adjustment_set_page_increment(s[i].adj, s[i].sw_size);
135        gtk_adjustment_set_page_size(s[i].adj, s[i].sw_size);
136
137        float val = gtk_adjustment_get_value(s[i].adj);
138        if (val + s[i].sw_size > s[i].map_size)
139        {
140            gtk_adjustment_set_value(s[i].adj, s[i].map_size - s[i].sw_size);
141            gtk_adjustment_value_changed(s[i].adj);
142        }
143    }
144
145    /* Set up display */
146    if (gtk_gl_area_make_current(GTK_GL_AREA(widget)))
147        Video::Setup(widget->allocation.width, widget->allocation.height);
148
149    return TRUE;
150}
151
152static gint reshape(GtkWidget *widget, GdkEventConfigure *event)
153{
154    (void)event;
155
156    return init(widget);
157}
158
159static gint draw(GtkWidget *widget, GdkEventExpose *event)
160{
161    if (event->count > 0)
162        return TRUE;
163
164    /* OpenGL functions can be called only if make_current returns true */
165    if (ticking && gtk_gl_area_make_current(GTK_GL_AREA(widget)))
166    {
167        ticking = 0;
168
169        /* Clear the screen, tick the renderer, show the frame and
170         * clamp to desired framerate */
171        Video::Clear();
172        Ticker::TickDraw();
173        gtk_gl_area_swapbuffers(GTK_GL_AREA(widget));
174        while (g_main_context_iteration(NULL, FALSE))
175            ;
176        Ticker::ClampFps(1000.0f / FPS);
177    }
178
179    return TRUE;
180}
181
182int main(int argc, char **argv)
183{
184    /* Initialize GTK */
185    g_thread_init(NULL);
186    gtk_init(&argc, &argv);
187
188    if (gdk_gl_query() == FALSE)
189    {
190        g_print("OpenGL not supported\n");
191        return EXIT_FAILURE;
192    }
193
194    /* Build the application interface and keep a few member pointers */
195    GtkBuilder *builder = gtk_builder_new();
196    if (!gtk_builder_add_from_file(builder, "src/gtk/editor.xml", NULL))
197    {
198        g_print("Cannot build from XML\n");
199        return EXIT_FAILURE;
200    }
201
202    GtkWidget *window = GTK_WIDGET(gtk_builder_get_object(builder, "window1"));
203    GtkWidget *viewport = GTK_WIDGET(
204                              gtk_builder_get_object(builder, "viewport1"));
205    hadj = gtk_range_get_adjustment(GTK_RANGE(
206                              gtk_builder_get_object(builder, "hscrollbar1")));
207    vadj = gtk_range_get_adjustment(GTK_RANGE(
208                              gtk_builder_get_object(builder, "vscrollbar1")));
209    g_object_unref(G_OBJECT(builder));
210
211    /* Create new OpenGL widget */
212    int attrlist[] =
213    {
214        GDK_GL_RGBA,
215        GDK_GL_RED_SIZE, 1,
216        GDK_GL_GREEN_SIZE, 1,
217        GDK_GL_BLUE_SIZE, 1,
218        GDK_GL_DOUBLEBUFFER,
219        GDK_GL_NONE
220    };
221
222    glarea = gtk_gl_area_new(attrlist);
223    gtk_widget_set_usize(glarea, 400, 300);
224    gtk_widget_set_events(glarea, GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK
225                           | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
226    gtk_container_add(GTK_CONTAINER(viewport), glarea);
227
228    /* We tick from the idle function instead of a timeout to avoid
229     * stealing time from the GTK loop when the callback time exceeds
230     * the timeout value. */
231    gtk_idle_add(tick, glarea);
232
233    /* Connect signals and show window */
234    gtk_signal_connect(GTK_OBJECT(window), "delete_event",
235                       GTK_SIGNAL_FUNC(main_quit), NULL);
236
237    gtk_signal_connect(GTK_OBJECT(glarea), "expose_event",
238                       GTK_SIGNAL_FUNC(draw), NULL);
239    gtk_signal_connect(GTK_OBJECT(glarea), "configure_event",
240                       GTK_SIGNAL_FUNC(reshape), NULL);
241    gtk_signal_connect(GTK_OBJECT(glarea), "realize",
242                       GTK_SIGNAL_FUNC(init), NULL);
243    gtk_signal_connect(GTK_OBJECT(glarea), "button_press_event",
244                       GTK_SIGNAL_FUNC(mouse_button), NULL);
245    gtk_signal_connect(GTK_OBJECT(glarea), "button_release_event",
246                       GTK_SIGNAL_FUNC(mouse_button), NULL);
247    gtk_signal_connect(GTK_OBJECT(glarea), "motion_notify_event",
248                       GTK_SIGNAL_FUNC(mouse_motion), NULL);
249
250    // FIXME: detect when the map viewer is killed
251    mv = new MapViewer("maps/testmap.tmx");
252    new DebugFps();
253
254    gtk_widget_show_all(window);
255    gtk_main();
256
257    return EXIT_SUCCESS;
258}
259
Note: See TracBrowser for help on using the repository browser.