1
/*
2
 * Copyright (C) 2008 Pierre-Luc Beaudoin <pierre-luc@pierlux.com>
3
 *
4
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
6
 * License as published by the Free Software Foundation; either
7
 * version 2.1 of the License, or (at your option) any later version.
8
 *
9
 * This library 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 GNU
12
 * Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
15
 * License along with this library; if not, write to the Free Software
16
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
 */
18
19
#include <gtk/gtk.h>
20
21
#include <champlain/champlain.h>
22
#include <champlain-gtk/champlain-gtk.h>
23
#include <clutter-gtk/clutter-gtk.h>
24
25
#include <markers.h>
26
27
#define N_COLS 2
28
#define COL_ID 0
29
#define COL_NAME 1
30
31
static ChamplainPathLayer *path_layer;
32
static ChamplainPathLayer *path;
33
static gboolean destroying = FALSE;
34
35
/*
36
 * Terminate the main loop.
37
 */
38
static void
39
on_destroy (GtkWidget *widget, gpointer data)
40
{
41
  destroying = TRUE;
42
  gtk_main_quit ();
43
}
44
45
46
static void
47
toggle_layer (GtkToggleButton *widget,
48
    ClutterActor *layer)
49
{
50
  if (gtk_toggle_button_get_active (widget))
51
    {
52
      champlain_path_layer_set_visible (path_layer, TRUE);
53
      champlain_path_layer_set_visible (path, TRUE);
54
      champlain_marker_layer_animate_in_all_markers (CHAMPLAIN_MARKER_LAYER (layer));
55
    }
56
  else
57
    {
58
      champlain_path_layer_set_visible (path_layer, FALSE);
59
      champlain_path_layer_set_visible (path, FALSE);
60
      champlain_marker_layer_animate_out_all_markers (CHAMPLAIN_MARKER_LAYER (layer));
61
    }
62
}
63
64
65
gboolean
66
mouse_click_cb (ClutterActor *actor, ClutterButtonEvent *event, ChamplainView *view)
67
{
68
  gdouble lat, lon;
69
70
  lon = champlain_view_x_to_longitude (view, event->x);
71
  lat = champlain_view_y_to_latitude (view, event->y);
72
  g_print ("Mouse click at: %f  %f\n", lat, lon);
73
74
  return TRUE;
75
}
76
77
78
static void
79
map_source_changed (GtkWidget *widget,
80
    ChamplainView *view)
81
{
82
  gchar *id;
83
  ChamplainMapSource *source;
84
  GtkTreeIter iter;
85
  GtkTreeModel *model;
86
87
  if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter))
88
    return;
89
90
  model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
91
92
  gtk_tree_model_get (model, &iter, COL_ID, &id, -1);
93
94
  ChamplainMapSourceFactory *factory = champlain_map_source_factory_dup_default ();
95
  source = champlain_map_source_factory_create_cached_source (factory, id);
96
97
  g_object_set (G_OBJECT (view), "map-source", source, NULL);
98
  g_object_unref (factory);
99
}
100
101
102
static void
103
zoom_changed (GtkSpinButton *spinbutton,
104
    ChamplainView *view)
105
{
106
  gint zoom = gtk_spin_button_get_value_as_int (spinbutton);
107
108
  g_object_set (G_OBJECT (view), "zoom-level", zoom, NULL);
109
}
110
111
112
static void
113
map_zoom_changed (ChamplainView *view,
114
    GParamSpec *gobject,
115
    GtkSpinButton *spinbutton)
116
{
117
  gint zoom;
118
119
  g_object_get (G_OBJECT (view), "zoom-level", &zoom, NULL);
120
  gtk_spin_button_set_value (spinbutton, zoom);
121
}
122
123
124
static void
125
view_state_changed (ChamplainView *view,
126
    GParamSpec *gobject,
127
    GtkImage *image)
128
{
129
  ChamplainState state;
130
131
  if (destroying)
132
    return;
133
134
  g_object_get (G_OBJECT (view), "state", &state, NULL);
135
  if (state == CHAMPLAIN_STATE_LOADING)
136
    {
137
      gtk_image_set_from_stock (image, GTK_STOCK_NETWORK, GTK_ICON_SIZE_BUTTON);
138
    }
139
  else
140
    {
141
      gtk_image_clear (image);
142
    }
143
}
144
145
146
static void
147
zoom_in (GtkWidget *widget,
148
    ChamplainView *view)
149
{
150
  champlain_view_zoom_in (view);
151
}
152
153
154
static void
155
zoom_out (GtkWidget *widget,
156
    ChamplainView *view)
157
{
158
  champlain_view_zoom_out (view);
159
}
160
161
162
static void
163
build_combo_box (GtkComboBox *box)
164
{
165
  ChamplainMapSourceFactory *factory;
166
  GSList *sources, *iter;
167
  gint i = 0;
168
  GtkTreeStore *store;
169
  GtkTreeIter parent;
170
  GtkCellRenderer *cell;
171
172
  store = gtk_tree_store_new (N_COLS, G_TYPE_STRING, /* id */
173
        G_TYPE_STRING, /* name */
174
        -1);
175
176
  factory = champlain_map_source_factory_dup_default ();
177
  sources = champlain_map_source_factory_get_registered (factory);
178
179
  iter = sources;
180
  while (iter != NULL)
181
    {
182
      ChamplainMapSourceDesc *desc = CHAMPLAIN_MAP_SOURCE_DESC (iter->data);
183
      const gchar *id = champlain_map_source_desc_get_id (desc);
184
      const gchar *name = champlain_map_source_desc_get_name (desc);
185
186
      gtk_tree_store_append (store, &parent, NULL);
187
      gtk_tree_store_set (store, &parent, COL_ID, id,
188
          COL_NAME, name, -1);
189
190
      iter = g_slist_next (iter);
191
    }
192
193
  g_slist_free (sources);
194
  g_object_unref (factory);
195
196
  gtk_combo_box_set_model (box, GTK_TREE_MODEL (store));
197
198
  cell = gtk_cell_renderer_text_new ();
199
  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (box), cell, FALSE);
200
  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (box), cell,
201
      "text", COL_NAME, NULL);
202
}
203
204
205
static void
206
append_point (ChamplainPathLayer *layer, gdouble lon, gdouble lat)
207
{
208
  ChamplainCoordinate *coord;  
209
  
210
  coord = champlain_coordinate_new_full (lon, lat);
211
  champlain_path_layer_add_node (layer, CHAMPLAIN_LOCATION (coord));
212
}
213
214
215
int
216
main (int argc,
217
    char *argv[])
218
{
219
  GtkWidget *window;
220
  GtkWidget *widget, *vbox, *bbox, *button, *viewport;
221
  ChamplainView *view;
222
  ChamplainMarkerLayer *layer;
223
  ClutterActor *scale;
224
  ChamplainLicense *license_actor;
225
226
  if (gtk_clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
227
    return 1;
228
229
  /* create the main, top level, window */
230
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
231
232
  /* give the window a 10px wide border */
233
  gtk_container_set_border_width (GTK_CONTAINER (window), 10);
234
235
  /* give it the title */
236
  gtk_window_set_title (GTK_WINDOW (window), "libchamplain Gtk+ demo");
237
238
  /* Connect the destroy event of the window with our on_destroy function
239
   * When the window is about to be destroyed we get a notificaiton and
240
   * stop the main GTK loop
241
   */
242
  g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (on_destroy),
243
      NULL);
244
245
  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
246
247
  widget = gtk_champlain_embed_new ();
248
  view = gtk_champlain_embed_get_view (GTK_CHAMPLAIN_EMBED (widget));
249
  clutter_actor_set_reactive (CLUTTER_ACTOR (view), TRUE);
250
  g_signal_connect (view, "button-release-event", G_CALLBACK (mouse_click_cb), view);
251
252
253
  g_object_set (G_OBJECT (view),
254
      "kinetic-mode", TRUE,
255
      "zoom-level", 5,
256
      NULL);
257
      
258
  scale = champlain_scale_new ();
259
  champlain_scale_connect_view (CHAMPLAIN_SCALE (scale), view);
260
  
261
  /* align to the bottom left */
262
  champlain_view_bin_layout_add (view, scale,
263
                                 CLUTTER_BIN_ALIGNMENT_START,
264
                                 CLUTTER_BIN_ALIGNMENT_END);
265
  
266
  license_actor = champlain_view_get_license_actor (view);
267
  champlain_license_set_extra_text (license_actor, "Don't eat cereals with orange juice\nIt tastes bad");
268
  
269
  champlain_view_center_on (CHAMPLAIN_VIEW (view), 45.466, -73.75);
270
271
  layer = create_marker_layer (view, &path);
272
  champlain_view_add_layer (view, CHAMPLAIN_LAYER (path));
273
  champlain_view_add_layer (view, CHAMPLAIN_LAYER (layer));
274
275
  path_layer = champlain_path_layer_new ();
276
  /* Cheap approx of Highway 10 */
277
  append_point (path_layer, 45.4095, -73.3197);
278
  append_point (path_layer, 45.4104, -73.2846);
279
  append_point (path_layer, 45.4178, -73.2239);
280
  append_point (path_layer, 45.4176, -73.2181);
281
  append_point (path_layer, 45.4151, -73.2126);
282
  append_point (path_layer, 45.4016, -73.1926);
283
  append_point (path_layer, 45.3994, -73.1877);
284
  append_point (path_layer, 45.4000, -73.1815);
285
  append_point (path_layer, 45.4151, -73.1218);
286
  champlain_view_add_layer (view, CHAMPLAIN_LAYER (path_layer));
287
288
  gtk_widget_set_size_request (widget, 640, 480);
289
290
  bbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
291
  button = gtk_button_new_from_stock (GTK_STOCK_ZOOM_IN);
292
  g_signal_connect (button, "clicked", G_CALLBACK (zoom_in), view);
293
  gtk_container_add (GTK_CONTAINER (bbox), button);
294
295
  button = gtk_button_new_from_stock (GTK_STOCK_ZOOM_OUT);
296
  g_signal_connect (button, "clicked", G_CALLBACK (zoom_out), view);
297
  gtk_container_add (GTK_CONTAINER (bbox), button);
298
299
  button = gtk_toggle_button_new_with_label ("Markers");
300
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
301
  g_signal_connect (button, "toggled", G_CALLBACK (toggle_layer), layer);
302
  gtk_container_add (GTK_CONTAINER (bbox), button);
303
304
  button = gtk_combo_box_new ();
305
  build_combo_box (GTK_COMBO_BOX (button));
306
  gtk_combo_box_set_active (GTK_COMBO_BOX (button), 0);
307
  g_signal_connect (button, "changed", G_CALLBACK (map_source_changed), view);
308
  gtk_container_add (GTK_CONTAINER (bbox), button);
309
310
  button = gtk_spin_button_new_with_range (0, 20, 1);
311
  gtk_spin_button_set_value (GTK_SPIN_BUTTON (button),
312
      champlain_view_get_zoom_level (view));
313
  g_signal_connect (button, "changed", G_CALLBACK (zoom_changed), view);
314
  g_signal_connect (view, "notify::zoom-level", G_CALLBACK (map_zoom_changed),
315
      button);
316
  gtk_container_add (GTK_CONTAINER (bbox), button);
317
318
  button = gtk_image_new ();
319
  gtk_widget_set_size_request (button, 22, -1);
320
  g_signal_connect (view, "notify::state", G_CALLBACK (view_state_changed),
321
      button);
322
  gtk_box_pack_end (GTK_BOX (bbox), button, FALSE, FALSE, 0);
323
324
  viewport = gtk_frame_new (NULL);
325
  gtk_container_add (GTK_CONTAINER (viewport), widget);
326
327
  gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
328
  gtk_container_add (GTK_CONTAINER (vbox), viewport);
329
330
  /* and insert it into the main window  */
331
  gtk_container_add (GTK_CONTAINER (window), vbox);
332
333
  /* make sure that everything, window and label, are visible */
334
  gtk_widget_show_all (window);
335
  /* start the main loop */
336
  gtk_main ();
337
338
  return 0;
339
}