]> Pileus Git - ~andy/gtk/blob - demos/gtk-demo/main.c
change demo install dir to datadir/gtk+-2.0/demo
[~andy/gtk] / demos / gtk-demo / main.c
1 #include <errno.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <ctype.h>
5
6 #include <gtk/gtk.h>
7
8 #include <demos.h>
9
10 static GtkTextBuffer *info_buffer;
11 static GtkTextBuffer *source_buffer;
12
13 static gchar *current_file = NULL;
14
15 enum {
16   TITLE_COLUMN,
17   FILENAME_COLUMN,
18   FUNC_COLUMN,
19   ITALIC_COLUMN,
20   NUM_COLUMNS
21 };
22
23 gboolean
24 read_line (FILE *stream, GString *str)
25 {
26   int n_read = 0;
27   
28   flockfile (stream);
29
30   g_string_truncate (str, 0);
31   
32   while (1)
33     {
34       int c;
35       
36       c = getc_unlocked (stream);
37
38       if (c == EOF)
39         goto done;
40       else
41         n_read++;
42
43       switch (c)
44         {
45         case '\r':
46         case '\n':
47           {
48             int next_c = getc_unlocked (stream);
49             
50             if (!(next_c == EOF ||
51                   (c == '\r' && next_c == '\n') ||
52                   (c == '\n' && next_c == '\r')))
53               ungetc (next_c, stream);
54             
55             goto done;
56           }
57         default:
58           g_string_append_c (str, c);
59         }
60     }
61
62  done:
63
64   funlockfile (stream);
65
66   return n_read > 0;
67 }
68
69 void
70 load_file (const gchar *filename)
71 {
72   FILE *file;
73   GtkTextIter start, end;
74   GString *buffer = g_string_new (NULL);
75   int state = 0;
76   gboolean in_para = 0;
77
78   if (current_file && !strcmp (current_file, filename))
79     return;
80
81   g_free (current_file);
82   current_file = g_strdup (filename);
83   
84   gtk_text_buffer_get_bounds (info_buffer, &start, &end);
85   gtk_text_buffer_delete (info_buffer, &start, &end);
86
87   gtk_text_buffer_get_bounds (source_buffer, &start, &end);
88   gtk_text_buffer_delete (source_buffer, &start, &end);
89
90   file = fopen (filename, "r");
91
92   if (!file)
93     {
94       char *installed = g_strconcat (DEMOCODEDIR,
95                                      G_DIR_SEPARATOR_S,
96                                      filename,
97                                      NULL);
98
99       file = fopen (installed, "r");
100
101       g_free (installed);
102     }
103   
104   if (!file)
105     {
106       g_warning ("Cannot open %s: %s\n", filename, g_strerror (errno));
107       return;
108     }
109
110   gtk_text_buffer_get_iter_at_offset (info_buffer, &start, 0);
111   while (read_line (file, buffer))
112     {
113       gchar *p = buffer->str;
114       gchar *q;
115       
116       switch (state)
117         {
118         case 0:
119           /* Reading title */
120           while (*p == '/' || *p == '*' || isspace (*p))
121             p++;
122           q = p + strlen (p);
123           while (q > p && isspace (*(q - 1)))
124             q--;
125
126           if (q > p)
127             {
128               int len_chars = g_utf8_pointer_to_offset (p, q);
129
130               end = start;
131
132               g_assert (strlen (p) >= q - p);
133               gtk_text_buffer_insert (info_buffer, &end, p, q - p);
134               start = end;
135
136               gtk_text_iter_backward_chars (&start, len_chars);
137               gtk_text_buffer_apply_tag_by_name (info_buffer, "title", &start, &end);
138
139               start = end;
140               
141               state++;
142             }
143           break;
144             
145         case 1:
146           /* Reading body of info section */
147           while (isspace (*p))
148             p++;
149           if (*p == '*' && *(p + 1) == '/')
150             {
151               gtk_text_buffer_get_iter_at_offset (source_buffer, &start, 0);
152               state++;
153             }
154           else
155             {
156               int len;
157               
158               while (*p == '*' || isspace (*p))
159                 p++;
160
161               len = strlen (p);
162               while (isspace (*(p + len - 1)))
163                 len--;
164               
165               if (len > 0)
166                 {
167                   if (in_para)
168                     gtk_text_buffer_insert (info_buffer, &start, " ", 1);
169
170                   g_assert (strlen (p) >= len);
171                   gtk_text_buffer_insert (info_buffer, &start, p, len);
172                   in_para = 1;
173                 }
174               else
175                 {
176                   gtk_text_buffer_insert (info_buffer, &start, "\n", 1);
177                   in_para = 0;
178                 }
179             }
180           break;
181
182         case 2:
183           /* Skipping blank lines */
184           while (isspace (*p))
185             p++;
186           if (*p)
187             {
188               p = buffer->str;
189               state++;
190               /* Fall through */
191             }
192           else
193             break;
194           
195         case 3:
196           /* Reading program body */
197           gtk_text_buffer_insert (source_buffer, &start, p, -1);
198           gtk_text_buffer_insert (info_buffer, &start, "\n", 1);
199           break;
200         }
201     }
202
203   gtk_text_buffer_get_bounds (source_buffer, &start, &end);
204   gtk_text_buffer_apply_tag_by_name (info_buffer, "source", &start, &end);
205 }
206
207 gboolean
208 button_press_event_cb (GtkTreeView    *tree_view,
209                        GdkEventButton *event,
210                        GtkTreeModel   *model)
211 {
212   if (event->type == GDK_2BUTTON_PRESS)
213     {
214       GtkTreePath *path = NULL;
215
216       gtk_tree_view_get_path_at_pos (tree_view,
217                                      event->window,
218                                      event->x,
219                                      event->y,
220                                      &path,
221                                      NULL);
222
223       if (path)
224         {
225           GtkTreeIter iter;
226           gboolean italic;
227           GVoidFunc func;
228
229           gtk_tree_model_get_iter (model, &iter, path);
230           gtk_tree_store_get (GTK_TREE_STORE (model),
231                               &iter,
232                               FUNC_COLUMN, &func,
233                               ITALIC_COLUMN, &italic,
234                               -1);
235           (func) ();
236           gtk_tree_store_set (GTK_TREE_STORE (model),
237                               &iter,
238                               ITALIC_COLUMN, !italic,
239                               -1);
240           gtk_tree_path_free (path);
241         }
242
243       gtk_signal_emit_stop_by_name (GTK_OBJECT (tree_view),
244                                     "button_press_event");
245       return TRUE;
246     }
247   
248   return FALSE;
249 }
250
251 static void
252 selection_cb (GtkTreeSelection *selection,
253               GtkTreeModel     *model)
254 {
255   GtkTreeIter iter;
256   GValue value = {0, };
257
258   if (! gtk_tree_selection_get_selected (selection, NULL, &iter))
259     return;
260
261   gtk_tree_model_get_value (model, &iter,
262                             FILENAME_COLUMN,
263                             &value);
264   load_file (g_value_get_string (&value));
265   g_value_unset (&value);
266 }
267
268 static GtkWidget *
269 create_text (GtkTextBuffer **buffer,
270              gboolean        is_source)
271 {
272   GtkWidget *scrolled_window;
273   GtkWidget *text_view;
274   PangoFontDescription *font_desc;
275
276   scrolled_window = gtk_scrolled_window_new (NULL, NULL);
277   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
278                                   GTK_POLICY_AUTOMATIC,
279                                   GTK_POLICY_AUTOMATIC);
280   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
281                                        GTK_SHADOW_IN);
282   
283   text_view = gtk_text_view_new ();
284   gtk_container_add (GTK_CONTAINER (scrolled_window), text_view);
285   
286   *buffer = gtk_text_buffer_new (NULL);
287   gtk_text_view_set_buffer (GTK_TEXT_VIEW (text_view), *buffer);
288   gtk_text_view_set_editable (GTK_TEXT_VIEW (text_view), FALSE);
289   gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (text_view), FALSE);
290
291   if (is_source)
292     {
293       font_desc = pango_font_description_from_string ("Courier 10");
294       gtk_widget_modify_font (text_view, font_desc);
295       pango_font_description_free (font_desc);
296     }
297   
298   gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view), !is_source);
299   
300   return scrolled_window;
301 }
302
303 /* Technically a list, but if we do go to 80 demos, we may want to move to a tree */
304 static GtkWidget *
305 create_tree (void)
306 {
307   GtkTreeSelection *selection;
308   GtkCellRenderer *cell;
309   GtkWidget *tree_view;
310   GtkTreeViewColumn *column;
311   GtkTreeStore *model;
312   GtkTreeIter iter;
313   gint i;
314
315   model = gtk_tree_store_new_with_types (NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN);
316   tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
317   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
318
319   gtk_tree_selection_set_type (GTK_TREE_SELECTION (selection),
320                                GTK_TREE_SELECTION_SINGLE);
321   gtk_widget_set_usize (tree_view, 200, -1);
322
323   for (i=0; i < G_N_ELEMENTS (testgtk_demos); i++)
324     {
325       gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
326
327       gtk_tree_store_set (GTK_TREE_STORE (model),
328                           &iter,
329                           TITLE_COLUMN, testgtk_demos[i].title,
330                           FILENAME_COLUMN, testgtk_demos[i].filename,
331                           FUNC_COLUMN, testgtk_demos[i].func,
332                           ITALIC_COLUMN, FALSE,
333                           -1);
334     }
335
336   cell = gtk_cell_renderer_text_new ();
337   column = gtk_tree_view_column_new_with_attributes ("Widget (double click for demo)",
338                                                      cell,
339                                                      "text", TITLE_COLUMN,
340                                                      "italic", ITALIC_COLUMN,
341                                                      NULL);
342   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
343                                GTK_TREE_VIEW_COLUMN (column));
344
345   gtk_signal_connect (GTK_OBJECT (selection), "selection_changed", selection_cb, model);
346   gtk_signal_connect (GTK_OBJECT (tree_view), "button_press_event", GTK_SIGNAL_FUNC (button_press_event_cb), model);
347
348   return tree_view;
349 }
350
351 int
352 main (int argc, char **argv)
353 {
354   GtkWidget *window;
355   GtkWidget *notebook;
356   GtkWidget *hbox;
357   GtkWidget *tree;
358   GtkTextTag *tag;
359
360   gtk_init (&argc, &argv);
361   
362   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
363   gtk_signal_connect (GTK_OBJECT (window), "destroy",
364                       GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
365
366   hbox = gtk_hbox_new (FALSE, 0);
367   gtk_container_add (GTK_CONTAINER (window), hbox);
368
369   tree = create_tree ();
370   gtk_box_pack_start (GTK_BOX (hbox), tree, FALSE, FALSE, 0);
371
372   notebook = gtk_notebook_new ();
373   gtk_box_pack_start (GTK_BOX (hbox), notebook, TRUE, TRUE, 0);
374
375   gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
376                             create_text (&info_buffer, FALSE),
377                             gtk_label_new ("Info"));
378
379
380   gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
381                             create_text (&source_buffer, TRUE),
382                             gtk_label_new ("Source"));
383
384   tag = gtk_text_buffer_create_tag (info_buffer, "title");
385   gtk_object_set (GTK_OBJECT (tag),
386                  "font", "Sans 18",
387                  NULL);
388
389   tag = gtk_text_buffer_create_tag (info_buffer, "source");
390   gtk_object_set (GTK_OBJECT (tag),
391                   "font", "Courier 10",
392                   "pixels_above_lines", 0,
393                   "pixels_below_lines", 0,
394                  NULL);
395
396   gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
397   gtk_widget_show_all (window);
398   
399
400   load_file (testgtk_demos[0].filename);
401   
402   gtk_main ();
403
404   return 0;
405 }