]> Pileus Git - grits/blob - src/gis-viewer.c
Remove properties from gis-viewer
[grits] / src / gis-viewer.c
1 /*
2  * Copyright (C) 2009 Andy Spencer <spenceal@rose-hulman.edu>
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <config.h>
19 #include <gtk/gtk.h>
20 #include <gdk/gdkkeysyms.h>
21
22 #include "gis-marshal.h"
23 #include "gis-viewer.h"
24
25 #include "gis-util.h"
26
27
28 /* Constants */
29 enum {
30         SIG_TIME_CHANGED,
31         SIG_SITE_CHANGED,
32         SIG_LOCATION_CHANGED,
33         SIG_ROTATION_CHANGED,
34         SIG_REFRESH,
35         SIG_OFFLINE,
36         NUM_SIGNALS,
37 };
38 static guint signals[NUM_SIGNALS];
39
40
41 /***********
42  * Helpers *
43  ***********/
44 /* Misc helpers */
45 static void _gis_viewer_fix_location(GisViewer *self)
46 {
47         while (self->location[0] <  -90) self->location[0] += 180;
48         while (self->location[0] >   90) self->location[0] -= 180;
49         while (self->location[1] < -180) self->location[1] += 360;
50         while (self->location[1] >  180) self->location[1] -= 360;
51         self->location[2] = ABS(self->location[2]);
52 }
53
54 /* Signal helpers */
55 static void _gis_viewer_emit_location_changed(GisViewer *self)
56 {
57         g_signal_emit(self, signals[SIG_LOCATION_CHANGED], 0,
58                         self->location[0],
59                         self->location[1],
60                         self->location[2]);
61 }
62 static void _gis_viewer_emit_rotation_changed(GisViewer *self)
63 {
64         g_signal_emit(self, signals[SIG_ROTATION_CHANGED], 0,
65                         self->rotation[0],
66                         self->rotation[1],
67                         self->rotation[2]);
68 }
69 static void _gis_viewer_emit_time_changed(GisViewer *self)
70 {
71         g_signal_emit(self, signals[SIG_TIME_CHANGED], 0,
72                         self->time);
73 }
74 static void _gis_viewer_emit_site_changed(GisViewer *self)
75 {
76         g_signal_emit(self, signals[SIG_SITE_CHANGED], 0,
77                         self->site);
78 }
79 static void _gis_viewer_emit_refresh(GisViewer *self)
80 {
81         g_signal_emit(self, signals[SIG_REFRESH], 0);
82 }
83 static void _gis_viewer_emit_offline(GisViewer *self)
84 {
85         g_signal_emit(self, signals[SIG_OFFLINE], 0,
86                         self->offline);
87 }
88
89 /*************
90  * Callbacks *
91  *************/
92 static gboolean on_button_press(GisViewer *self, GdkEventButton *event, gpointer _)
93 {
94         g_debug("GisViewer: on_button_press - Grabbing focus");
95         gtk_widget_grab_focus(GTK_WIDGET(self));
96         return TRUE;
97 }
98 static gboolean on_key_press(GisViewer *self, GdkEventKey *event, gpointer _)
99 {
100         g_debug("GisViewer: on_key_press - key=%x, state=%x, plus=%x",
101                         event->keyval, event->state, GDK_plus);
102
103         double lat, lon, elev, pan;
104         gis_viewer_get_location(self, &lat, &lon, &elev);
105         pan = MIN(elev/(EARTH_R/2), 30);
106         guint kv = event->keyval;
107         gdk_threads_leave();
108         if      (kv == GDK_Left  || kv == GDK_h) gis_viewer_pan(self,  0,  -pan, 0);
109         else if (kv == GDK_Down  || kv == GDK_j) gis_viewer_pan(self, -pan, 0,   0);
110         else if (kv == GDK_Up    || kv == GDK_k) gis_viewer_pan(self,  pan, 0,   0);
111         else if (kv == GDK_Right || kv == GDK_l) gis_viewer_pan(self,  0,   pan, 0);
112         else if (kv == GDK_minus || kv == GDK_o) gis_viewer_zoom(self, 10./9);
113         else if (kv == GDK_plus  || kv == GDK_i) gis_viewer_zoom(self, 9./10);
114         else if (kv == GDK_H) gis_viewer_rotate(self,  0, 0, -2);
115         else if (kv == GDK_J) gis_viewer_rotate(self,  2, 0,  0);
116         else if (kv == GDK_K) gis_viewer_rotate(self, -2, 0,  0);
117         else if (kv == GDK_L) gis_viewer_rotate(self,  0, 0,  2);
118         return FALSE;
119 }
120 static void on_view_changed(GisViewer *self,
121                 gdouble _1, gdouble _2, gdouble _3)
122 {
123         gtk_widget_queue_draw(GTK_WIDGET(self));
124 }
125
126 /***********
127  * Methods *
128  ***********/
129 void gis_viewer_set_time(GisViewer *self, const char *time)
130 {
131         g_assert(GIS_IS_VIEWER(self));
132         g_debug("GisViewer: set_time - time=%s", time);
133         g_free(self->time);
134         self->time = g_strdup(time);
135         _gis_viewer_emit_time_changed(self);
136 }
137
138 gchar *gis_viewer_get_time(GisViewer *self)
139 {
140         g_assert(GIS_IS_VIEWER(self));
141         g_debug("GisViewer: get_time");
142         return self->time;
143 }
144
145 void gis_viewer_set_location(GisViewer *self, gdouble lat, gdouble lon, gdouble elev)
146 {
147         g_assert(GIS_IS_VIEWER(self));
148         g_debug("GisViewer: set_location");
149         self->location[0] = lat;
150         self->location[1] = lon;
151         self->location[2] = elev;
152         _gis_viewer_fix_location(self);
153         _gis_viewer_emit_location_changed(self);
154 }
155
156 void gis_viewer_get_location(GisViewer *self, gdouble *lat, gdouble *lon, gdouble *elev)
157 {
158         g_assert(GIS_IS_VIEWER(self));
159         //g_debug("GisViewer: get_location");
160         *lat  = self->location[0];
161         *lon  = self->location[1];
162         *elev = self->location[2];
163 }
164
165 void gis_viewer_pan(GisViewer *self, gdouble lat, gdouble lon, gdouble elev)
166 {
167         g_assert(GIS_IS_VIEWER(self));
168         g_debug("GisViewer: pan - lat=%8.3f, lon=%8.3f, elev=%8.3f", lat, lon, elev);
169         self->location[0] += lat;
170         self->location[1] += lon;
171         self->location[2] += elev;
172         _gis_viewer_fix_location(self);
173         _gis_viewer_emit_location_changed(self);
174 }
175
176 void gis_viewer_zoom(GisViewer *self, gdouble scale)
177 {
178         g_assert(GIS_IS_VIEWER(self));
179         g_debug("GisViewer: zoom");
180         self->location[2] *= scale;
181         _gis_viewer_emit_location_changed(self);
182 }
183
184 void gis_viewer_set_rotation(GisViewer *self, gdouble x, gdouble y, gdouble z)
185 {
186         g_assert(GIS_IS_VIEWER(self));
187         g_debug("GisViewer: set_rotation");
188         self->rotation[0] = x;
189         self->rotation[1] = y;
190         self->rotation[2] = z;
191         _gis_viewer_emit_rotation_changed(self);
192 }
193
194 void gis_viewer_get_rotation(GisViewer *self, gdouble *x, gdouble *y, gdouble *z)
195 {
196         g_assert(GIS_IS_VIEWER(self));
197         g_debug("GisViewer: get_rotation");
198         *x = self->rotation[0];
199         *y = self->rotation[1];
200         *z = self->rotation[2];
201 }
202
203 void gis_viewer_rotate(GisViewer *self, gdouble x, gdouble y, gdouble z)
204 {
205         g_assert(GIS_IS_VIEWER(self));
206         g_debug("GisViewer: rotate - x=%.0f, y=%.0f, z=%.0f", x, y, z);
207         self->rotation[0] += x;
208         self->rotation[1] += y;
209         self->rotation[2] += z;
210         _gis_viewer_emit_rotation_changed(self);
211 }
212
213 /* To be deprecated, use {get,set}_location */
214 void gis_viewer_set_site(GisViewer *self, const gchar *site)
215 {
216         g_assert(GIS_IS_VIEWER(self));
217         g_debug("GisViewer: set_site");
218         g_free(self->site);
219         self->site = g_strdup(site);
220         _gis_viewer_emit_site_changed(self);
221 }
222
223 gchar *gis_viewer_get_site(GisViewer *self)
224 {
225         g_assert(GIS_IS_VIEWER(self));
226         g_debug("GisViewer: get_site - %s", self->site);
227         return self->site;
228 }
229
230 void gis_viewer_refresh(GisViewer *self)
231 {
232         g_debug("GisViewer: refresh");
233         _gis_viewer_emit_refresh(self);
234 }
235
236 void gis_viewer_set_offline(GisViewer *self, gboolean offline)
237 {
238         g_assert(GIS_IS_VIEWER(self));
239         g_debug("GisViewer: set_offline - %d", offline);
240         self->offline = offline;
241         _gis_viewer_emit_offline(self);
242 }
243
244 gboolean gis_viewer_get_offline(GisViewer *self)
245 {
246         g_assert(GIS_IS_VIEWER(self));
247         g_debug("GisViewer: get_offline - %d", self->offline);
248         return self->offline;
249 }
250
251 /* To be implemented by subclasses */
252 void gis_viewer_center_position(GisViewer *self,
253                 gdouble lat, gdouble lon, gdouble elev)
254 {
255         GisViewerClass *klass = GIS_VIEWER_GET_CLASS(self);
256         if (!klass->center_position)
257                 g_warning("GisViewer: center_position - Unimplemented");
258         klass->center_position(self, lat, lon, elev);
259 }
260
261 void gis_viewer_project(GisViewer *self,
262                 gdouble lat, gdouble lon, gdouble elev,
263                 gdouble *px, gdouble *py, gdouble *pz)
264 {
265         GisViewerClass *klass = GIS_VIEWER_GET_CLASS(self);
266         if (!klass->project)
267                 g_warning("GisViewer: project - Unimplemented");
268         klass->project(self, lat, lon, elev, px, py, pz);
269 }
270
271 void gis_viewer_clear_height_func(GisViewer *self)
272 {
273         GisViewerClass *klass = GIS_VIEWER_GET_CLASS(self);
274         if (!klass->clear_height_func)
275                 g_warning("GisViewer: clear_height_func - Unimplemented");
276         klass->clear_height_func(self);
277 }
278
279 void gis_viewer_set_height_func(GisViewer *self, GisTile *tile,
280                 GisHeightFunc height_func, gpointer user_data,
281                 gboolean update)
282 {
283         GisViewerClass *klass = GIS_VIEWER_GET_CLASS(self);
284         if (!klass->set_height_func)
285                 g_warning("GisViewer: set_height_func - Unimplemented");
286         klass->set_height_func(self, tile, height_func, user_data, update);
287 }
288
289 void gis_viewer_render_tile(GisViewer *self, GisTile *tile)
290 {
291         GisViewerClass *klass = GIS_VIEWER_GET_CLASS(self);
292         if (!klass->render_tile)
293                 g_warning("GisViewer: render_tile - Unimplemented");
294         klass->render_tile(self, tile);
295 }
296
297 void gis_viewer_render_tiles(GisViewer *self, GisTile *root)
298 {
299         GisViewerClass *klass = GIS_VIEWER_GET_CLASS(self);
300         if (!klass->render_tiles)
301                 g_warning("GisViewer: render_tiles - Unimplemented");
302         klass->render_tiles(self, root);
303 }
304
305 void gis_viewer_begin(GisViewer *self)
306 {
307         GisViewerClass *klass = GIS_VIEWER_GET_CLASS(self);
308         if (!klass->begin)
309                 g_warning("GisViewer: begin - Unimplemented");
310         klass->begin(self);
311 }
312
313 void gis_viewer_end(GisViewer *self)
314 {
315         GisViewerClass *klass = GIS_VIEWER_GET_CLASS(self);
316         if (!klass->end)
317                 g_warning("GisViewer: end - Unimplemented");
318         klass->end(self);
319 }
320
321 void gis_viewer_add(GisViewer *self, GisObject *object)
322 {
323         GisViewerClass *klass = GIS_VIEWER_GET_CLASS(self);
324         if (!klass->add)
325                 g_warning("GisViewer: add - Unimplemented");
326         klass->add(self, object);
327 }
328
329 void gis_viewer_remove(GisViewer *self, GisObject *object)
330 {
331         GisViewerClass *klass = GIS_VIEWER_GET_CLASS(self);
332         if (!klass->remove)
333                 g_warning("GisViewer: remove - Unimplemented");
334         klass->remove(self, object);
335 }
336
337 /****************
338  * GObject code *
339  ****************/
340 G_DEFINE_ABSTRACT_TYPE(GisViewer, gis_viewer, GTK_TYPE_DRAWING_AREA);
341 static void gis_viewer_init(GisViewer *self)
342 {
343         g_debug("GisViewer: init");
344         /* Default values */
345         self->time = g_strdup("");
346         self->site = g_strdup("");
347         self->location[0] = 40;
348         self->location[1] = -100;
349         self->location[2] = 1.5*EARTH_R;
350         self->rotation[0] = 0;
351         self->rotation[1] = 0;
352         self->rotation[2] = 0;
353
354         g_signal_connect(self, "key-press-event",    G_CALLBACK(on_key_press),    NULL);
355         g_signal_connect(self, "button-press-event", G_CALLBACK(on_button_press), NULL);
356
357         g_signal_connect(self, "location-changed",   G_CALLBACK(on_view_changed), NULL);
358         g_signal_connect(self, "rotation-changed",   G_CALLBACK(on_view_changed), NULL);
359 }
360 static void gis_viewer_finalize(GObject *gobject)
361 {
362         g_debug("GisViewer: finalize");
363         GisViewer *self = GIS_VIEWER(gobject);
364         g_free(self->time);
365         g_free(self->site);
366         G_OBJECT_CLASS(gis_viewer_parent_class)->finalize(gobject);
367 }
368 static void gis_viewer_class_init(GisViewerClass *klass)
369 {
370         g_debug("GisViewer: class_init");
371         GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
372         gobject_class->finalize     = gis_viewer_finalize;
373         signals[SIG_TIME_CHANGED] = g_signal_new(
374                         "time-changed",
375                         G_TYPE_FROM_CLASS(gobject_class),
376                         G_SIGNAL_RUN_LAST,
377                         0,
378                         NULL,
379                         NULL,
380                         g_cclosure_marshal_VOID__STRING,
381                         G_TYPE_NONE,
382                         1,
383                         G_TYPE_STRING);
384         signals[SIG_SITE_CHANGED] = g_signal_new(
385                         "site-changed",
386                         G_TYPE_FROM_CLASS(gobject_class),
387                         G_SIGNAL_RUN_LAST,
388                         0,
389                         NULL,
390                         NULL,
391                         g_cclosure_marshal_VOID__STRING,
392                         G_TYPE_NONE,
393                         1,
394                         G_TYPE_STRING);
395         signals[SIG_LOCATION_CHANGED] = g_signal_new(
396                         "location-changed",
397                         G_TYPE_FROM_CLASS(gobject_class),
398                         G_SIGNAL_RUN_LAST,
399                         0,
400                         NULL,
401                         NULL,
402                         gis_cclosure_marshal_VOID__DOUBLE_DOUBLE_DOUBLE,
403                         G_TYPE_NONE,
404                         3,
405                         G_TYPE_DOUBLE,
406                         G_TYPE_DOUBLE,
407                         G_TYPE_DOUBLE);
408         signals[SIG_ROTATION_CHANGED] = g_signal_new(
409                         "rotation-changed",
410                         G_TYPE_FROM_CLASS(gobject_class),
411                         G_SIGNAL_RUN_LAST,
412                         0,
413                         NULL,
414                         NULL,
415                         gis_cclosure_marshal_VOID__DOUBLE_DOUBLE_DOUBLE,
416                         G_TYPE_NONE,
417                         3,
418                         G_TYPE_DOUBLE,
419                         G_TYPE_DOUBLE,
420                         G_TYPE_DOUBLE);
421         signals[SIG_REFRESH] = g_signal_new(
422                         "refresh",
423                         G_TYPE_FROM_CLASS(gobject_class),
424                         G_SIGNAL_RUN_LAST,
425                         0,
426                         NULL,
427                         NULL,
428                         g_cclosure_marshal_VOID__VOID,
429                         G_TYPE_NONE,
430                         0);
431         signals[SIG_OFFLINE] = g_signal_new(
432                         "offline",
433                         G_TYPE_FROM_CLASS(gobject_class),
434                         G_SIGNAL_RUN_LAST,
435                         0,
436                         NULL,
437                         NULL,
438                         g_cclosure_marshal_VOID__BOOLEAN,
439                         G_TYPE_NONE,
440                         1,
441                         G_TYPE_BOOLEAN);
442 }