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