]> Pileus Git - ~andy/gtk/blob - demos/gtk-demo/main.c
added more fields to allow more interesting iterators. Also, made the
[~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   if (!file)
92     {
93       g_warning ("Cannot open %s: %s\n", filename, g_strerror (errno));
94       return;
95     }
96
97   gtk_text_buffer_get_iter_at_offset (info_buffer, &start, 0);
98   while (read_line (file, buffer))
99     {
100       gchar *p = buffer->str;
101       gchar *q;
102       
103       switch (state)
104         {
105         case 0:
106           /* Reading title */
107           while (*p == '/' || *p == '*' || isspace (*p))
108             p++;
109           q = p + strlen (p);
110           while (q > p && isspace (*(q - 1)))
111             q--;
112
113           if (q > p)
114             {
115               int len_chars = g_utf8_pointer_to_offset (p, q);
116
117               end = start;
118
119               g_assert (strlen (p) >= q - p);
120               gtk_text_buffer_insert (info_buffer, &end, p, q - p);
121               start = end;
122
123               gtk_text_iter_backward_chars (&start, len_chars);
124               gtk_text_buffer_apply_tag_by_name (info_buffer, "title", &start, &end);
125
126               start = end;
127               
128               state++;
129             }
130           break;
131             
132         case 1:
133           /* Reading body of info section */
134           while (isspace (*p))
135             p++;
136           if (*p == '*' && *(p + 1) == '/')
137             {
138               gtk_text_buffer_get_iter_at_offset (source_buffer, &start, 0);
139               state++;
140             }
141           else
142             {
143               int len;
144               
145               while (*p == '*' || isspace (*p))
146                 p++;
147
148               len = strlen (p);
149               while (isspace (*(p + len - 1)))
150                 len--;
151               
152               if (len > 0)
153                 {
154                   if (in_para)
155                     gtk_text_buffer_insert (info_buffer, &start, " ", 1);
156
157                   g_assert (strlen (p) >= len);
158                   gtk_text_buffer_insert (info_buffer, &start, p, len);
159                   in_para = 1;
160                 }
161               else
162                 {
163                   gtk_text_buffer_insert (info_buffer, &start, "\n", 1);
164                   in_para = 0;
165                 }
166             }
167           break;
168
169         case 2:
170           /* Skipping blank lines */
171           while (isspace (*p))
172             p++;
173           if (*p)
174             {
175               p = buffer->str;
176               state++;
177               /* Fall through */
178             }
179           else
180             break;
181           
182         case 3:
183           /* Reading program body */
184           gtk_text_buffer_insert (source_buffer, &start, p, -1);
185           gtk_text_buffer_insert (info_buffer, &start, "\n", 1);
186           break;
187         }
188     }
189
190   gtk_text_buffer_get_bounds (source_buffer, &start, &end);
191   gtk_text_buffer_apply_tag_by_name (info_buffer, "source", &start, &end);
192 }
193
194 gboolean
195 button_press_event_cb (GtkTreeView    *tree_view,
196                        GdkEventButton *event,
197                        GtkTreeModel   *model)
198 {
199   if (event->type == GDK_2BUTTON_PRESS)
200     {
201       GtkTreePath *path = NULL;
202
203       gtk_tree_view_get_path_at_pos (tree_view,
204                                      event->window,
205                                      event->x,
206                                      event->y,
207                                      &path,
208                                      NULL);
209
210       if (path)
211         {
212           GtkTreeIter iter;
213           gboolean italic;
214           GVoidFunc func;
215
216           gtk_tree_model_get_iter (model, &iter, path);
217           gtk_tree_store_get (GTK_TREE_STORE (model),
218                               &iter,
219                               FUNC_COLUMN, &func,
220                               ITALIC_COLUMN, &italic,
221                               -1);
222           (func) ();
223           gtk_tree_store_set (GTK_TREE_STORE (model),
224                               &iter,
225                               ITALIC_COLUMN, !italic,
226                               -1);
227           gtk_tree_path_free (path);
228         }
229
230       gtk_signal_emit_stop_by_name (GTK_OBJECT (tree_view),
231                                     "button_press_event");
232       return TRUE;
233     }
234   
235   return FALSE;
236 }
237
238 static void
239 selection_cb (GtkTreeSelection *selection,
240               GtkTreeModel     *model)
241 {
242   GtkTreeIter iter;
243   GValue value = {0, };
244
245   if (! gtk_tree_selection_get_selected (selection, NULL, &iter))
246     return;
247
248   gtk_tree_model_get_value (model, &iter,
249                             FILENAME_COLUMN,
250                             &value);
251   load_file (g_value_get_string (&value));
252   g_value_unset (&value);
253 }
254
255 static GtkWidget *
256 create_text (GtkTextBuffer **buffer,
257              gboolean        is_source)
258 {
259   GtkWidget *scrolled_window;
260   GtkWidget *text_view;
261   PangoFontDescription *font_desc;
262
263   scrolled_window = gtk_scrolled_window_new (NULL, NULL);
264   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
265                                   GTK_POLICY_AUTOMATIC,
266                                   GTK_POLICY_AUTOMATIC);
267   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
268                                        GTK_SHADOW_IN);
269   
270   text_view = gtk_text_view_new ();
271   gtk_container_add (GTK_CONTAINER (scrolled_window), text_view);
272   
273   *buffer = gtk_text_buffer_new (NULL);
274   gtk_text_view_set_buffer (GTK_TEXT_VIEW (text_view), *buffer);
275   gtk_text_view_set_editable (GTK_TEXT_VIEW (text_view), FALSE);
276   gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (text_view), FALSE);
277
278   if (is_source)
279     {
280       font_desc = pango_font_description_from_string ("Courier 10");
281       gtk_widget_modify_font (text_view, font_desc);
282       pango_font_description_free (font_desc);
283     }
284   
285   gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view), !is_source);
286   
287   return scrolled_window;
288 }
289
290 /* Technically a list, but if we do go to 80 demos, we may want to move to a tree */
291 static GtkWidget *
292 create_tree (void)
293 {
294   GtkTreeSelection *selection;
295   GtkCellRenderer *cell;
296   GtkWidget *tree_view;
297   GtkObject *column;
298   GtkObject *model;
299   GtkTreeIter iter;
300   gint i;
301
302   model = gtk_tree_store_new_with_values (NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN);
303   tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
304   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
305
306   gtk_tree_selection_set_type (GTK_TREE_SELECTION (selection),
307                                GTK_TREE_SELECTION_SINGLE);
308   gtk_widget_set_usize (tree_view, 200, -1);
309
310   for (i=0; i < G_N_ELEMENTS (testgtk_demos); i++)
311     {
312       gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
313
314       gtk_tree_store_set (GTK_TREE_STORE (model),
315                           &iter,
316                           TITLE_COLUMN, testgtk_demos[i].title,
317                           FILENAME_COLUMN, testgtk_demos[i].filename,
318                           FUNC_COLUMN, testgtk_demos[i].func,
319                           ITALIC_COLUMN, FALSE,
320                           -1);
321     }
322
323   cell = gtk_cell_renderer_text_new ();
324   column = gtk_tree_view_column_new_with_attributes ("Widget",
325                                                      cell,
326                                                      "text", TITLE_COLUMN,
327                                                      "italic", ITALIC_COLUMN,
328                                                      NULL);
329   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
330                                GTK_TREE_VIEW_COLUMN (column));
331
332   gtk_signal_connect (GTK_OBJECT (selection), "selection_changed", selection_cb, model);
333   gtk_signal_connect (GTK_OBJECT (tree_view), "button_press_event", GTK_SIGNAL_FUNC (button_press_event_cb), model);
334
335   return tree_view;
336 }
337
338 int
339 main (int argc, char **argv)
340 {
341   GtkWidget *window;
342   GtkWidget *notebook;
343   GtkWidget *hbox;
344   GtkWidget *tree;
345   GtkTextTag *tag;
346
347   gtk_init (&argc, &argv);
348   
349   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
350   gtk_signal_connect (GTK_OBJECT (window), "destroy",
351                       GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
352
353   hbox = gtk_hbox_new (FALSE, 0);
354   gtk_container_add (GTK_CONTAINER (window), hbox);
355
356   tree = create_tree ();
357   gtk_box_pack_start (GTK_BOX (hbox), tree, FALSE, FALSE, 0);
358
359   notebook = gtk_notebook_new ();
360   gtk_box_pack_start (GTK_BOX (hbox), notebook, TRUE, TRUE, 0);
361
362   gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
363                             create_text (&info_buffer, FALSE),
364                             gtk_label_new ("Info"));
365
366
367   gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
368                             create_text (&source_buffer, TRUE),
369                             gtk_label_new ("Source"));
370
371   tag = gtk_text_buffer_create_tag (info_buffer, "title");
372   gtk_object_set (GTK_OBJECT (tag),
373                  "font", "Sans 18",
374                  NULL);
375
376   tag = gtk_text_buffer_create_tag (info_buffer, "source");
377   gtk_object_set (GTK_OBJECT (tag),
378                   "font", "Courier 10",
379                   "pixels_above_lines", 0,
380                   "pixels_below_lines", 0,
381                  NULL);
382
383   gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
384   gtk_widget_show_all (window);
385   
386
387   load_file (testgtk_demos[0].filename);
388   
389   gtk_main ();
390
391   return 0;
392 }