1(* Application main window
2 *
3 * Demonstrates a typical application window, with menubar, toolbar, statusbar.
4 *)
5
6var
7  appwindow_registered : gboolean;
8
9procedure menuitem_cb (callback_data   : gpointer;
10                       callback_action : guint;
11                       widget          : PGtkWidget);cdecl;
12var
13  dialog : PGtkWidget;
14
15
16begin
17  dialog := gtk_message_dialog_new (GTK_WINDOW (callback_data),
18                                    GTK_DIALOG_DESTROY_WITH_PARENT,
19                                    GTK_MESSAGE_INFO,
20                                    GTK_BUTTONS_CLOSE,
21                                    'You selected or toggled the menu item: "%s"',
22                                    [gtk_item_factory_path_from_widget (widget)]);
23
24  // Close dialog on user response
25  g_signal_connect (G_OBJECT (dialog),
26                    'response',
27                    G_CALLBACK (@gtk_widget_destroy),
28                    NULL);
29
30  gtk_widget_show (dialog);
31end;
32
33
34
35procedure toolbar_cb (button : PGtkWidget;
36                      data   : gpointer); cdecl;
37var
38  dialog: PGtkWidget;
39begin
40
41  dialog := gtk_message_dialog_new (GTK_WINDOW (data),
42                                    GTK_DIALOG_DESTROY_WITH_PARENT,
43                                    GTK_MESSAGE_INFO,
44                                    GTK_BUTTONS_CLOSE,
45                                    'You selected a toolbar button');
46
47  (* Close dialog on user response *)
48  g_signal_connect (G_OBJECT (dialog),
49                    'response',
50                    G_CALLBACK (@gtk_widget_destroy),
51                    NULL);
52
53  gtk_widget_show (dialog);
54end;
55
56const
57
58  menu_items :  array [1..18] of TGtkItemFactoryEntry = (
59  ( path: '/_File';     accelerator:  NULL;          callback: nil;
60    callback_action: 0;  item_type : '<Branch>'; extra_data: NULL),
61
62  ( path: '/File/_New'; accelerator:  '<control>N' ; callback: TGtkItemfactoryCallback(@menuitem_cb);
63    callback_action: 0;  item_type : '<StockItem>'; extra_data: NULL{GTK_STOCK_NEW}),
64
65  ( path: '/File/_Open'; accelerator:  '<control>O' ; callback: TGtkItemfactoryCallback(@menuitem_cb);
66    callback_action: 0;  item_type : '<StockItem>'; extra_data: NULL {GTK_STOCK_OPEN}),
67
68  ( path: '/File/_Save'; accelerator:  '<control>S' ; callback: TGtkItemfactoryCallback(@menuitem_cb);
69    callback_action: 0;  item_type : '<StockItem>'; extra_data: NULL {GTK_STOCK_SAVE}),
70
71  ( path: '/File/Save _As'; accelerator:  NULL ; callback: TGtkItemfactoryCallback(@menuitem_cb);
72    callback_action: 0;  item_type : '<StockItem>'; extra_data: NULL {GTK_STOCK_SAVE_AS}),
73
74  ( path: '/File/sep1'; accelerator:  NULL; callback: TGtkItemfactoryCallback(@menuitem_cb);
75    callback_action: 0;  item_type : '<Separator>'; extra_data: NULL),
76
77  ( path: '/File/_Quit'; accelerator:  '<control>Q' ; callback: TGtkItemfactoryCallback(@menuitem_cb);
78    callback_action: 0;  item_type : '<StockItem>'; extra_data: NULL),
79
80  ( path: '/Preferences'; accelerator:  NULL ; callback: nil;
81    callback_action: 0;  item_type : '<Branch>'; extra_data: NULL),
82
83  ( path: '/Preferences/_Color'; accelerator:  NULL ; callback: nil;
84    callback_action: 0;  item_type : '<Branch>'; extra_data: NULL),
85
86  ( path: '/Preferences/Color/_Red'; accelerator:  NULL ; callback: TGtkItemfactoryCallback(@menuitem_cb);
87    callback_action: 0;  item_type : '<RadioItem>'; extra_data: NULL),
88
89  ( path: '/Preferences/Color/_Green'; accelerator:  NULL ; callback: TGtkItemfactoryCallback(@menuitem_cb);
90    callback_action: 0;  item_type : '/Preferences/Color/Red'; extra_data: NULL),
91
92  ( path: '/Preferences/Color/_Blue'; accelerator:  NULL ; callback: TGtkItemfactoryCallback(@menuitem_cb);
93    callback_action: 0;  item_type : '/Preferences/Color/Red'; extra_data: NULL),
94
95  ( path: '/Preferences/_Shape'; accelerator:  NULL ; callback: nil;
96    callback_action: 0;  item_type : '<Branch>'; extra_data: NULL),
97
98  ( path: '/Preferences/Shape/_Square'; accelerator:  NULL ; callback: TGtkItemfactoryCallback(@menuitem_cb);
99    callback_action: 0;  item_type : '<RadioItem>'; extra_data: NULL),
100
101  ( path: '/Preferences/Shape/_Rectangle'; accelerator:  NULL ; callback: TGtkItemfactoryCallback(@menuitem_cb);
102    callback_action: 0;  item_type : '/Preferences/Shape/Square'; extra_data: NULL),
103
104  ( path: '/Preferences/Shape/_Oval'; accelerator:  NULL ; callback: TGtkItemfactoryCallback(@menuitem_cb);
105    callback_action: 0;  item_type : '/Preferences/Shape/Rectangle'; extra_data: NULL),
106
107
108  (* If you wanted this to be right justified you would use "<LastBranch>", not "<Branch>".
109   * Right justified help menu items are generally considered a bad idea now days.
110   *)
111
112  ( path: '/_Help'; accelerator:  NULL ; callback: nil;
113    callback_action: 0;  item_type : '<Branch>'; extra_data: NULL),
114
115  ( path: '/Help/_About'; accelerator:  NULL ; callback: nil;
116    callback_action: 0;  item_type : NULL; extra_data: NULL)
117
118    );
119
120
121var
122  application_window  : PGtkWidget;      // global variable (originally called window)
123
124
125
126(* This function registers our custom toolbar icons, so they can be themed.
127 *
128 * It's totally optional to do this, you could just manually insert icons
129 * and have them not be themeable, especially if you never expect people
130 * to theme your app.
131 *)
132
133const
134  items :array [1..1] of TGtkStockItem = (
135       ( stock_id: 'demo-gtk-logo'; _label: '_GTK!';
136         modifier: 0; keyval: 0; translation_domain : NULL)
137         );
138
139procedure register_stock_icons;
140
141var
142  pixbuf    : PGdkPixbuf;
143  factory   : PGtkIconFactory;
144  filename  : pgchar;
145
146  icon_set    : PGtkIconSet;
147  transparent : PGdkPixbuf;
148
149begin
150  if not appwindow_registered then
151  begin
152      appwindow_registered := TRUE;
153
154      (* Register our stock items *)
155      gtk_stock_add (@items[1], high(items));
156
157      (* Add our custom icon factory to the list of defaults *)
158      factory := gtk_icon_factory_new ();
159      gtk_icon_factory_add_default (factory);
160
161      (* demo_find_file() looks in the the current directory first,
162       * so you can run gtk-demo without installing GTK, then looks
163       * in the location where the file is installed.
164       *)
165      pixbuf := NULL;
166      filename := demo_find_file ('gtk-logo-rgb.gif', NULL);
167
168      if filename <> NULL then begin
169        pixbuf := gdk_pixbuf_new_from_file (filename, NULL);
170        g_free (filename);
171      end;
172
173      (* Register icon to accompany stock item *)
174      if pixbuf <> NULL then
175      begin
176          (* The gtk-logo-rgb icon has a white background, make it transparent *)
177          transparent := gdk_pixbuf_add_alpha (pixbuf, TRUE, $ff, $ff, $ff);
178
179          icon_set := gtk_icon_set_new_from_pixbuf (transparent);
180          gtk_icon_factory_add (factory, 'demo-gtk-logo', icon_set);
181          gtk_icon_set_unref (icon_set);
182          g_object_unref (G_OBJECT (pixbuf));
183          g_object_unref (G_OBJECT (transparent));
184      end
185      else
186        g_warning ('failed to load GTK logo for toolbar');
187
188      (* Drop our reference to the factory, GTK will hold a reference. *)
189      g_object_unref (G_OBJECT (factory));
190    end;
191end;
192
193procedure update_statusbar ( buffer    : PGtkTextBuffer;
194                             statusbar : PGtkStatusbar);
195var
196  msg   : pgchar;
197  row,
198  col   : gint;
199  count : gint;
200  iter  : TGtkTextIter;
201
202begin
203
204  gtk_statusbar_pop (statusbar, 0); (* clear any previous message, underflow is allowed *)
205
206  count := gtk_text_buffer_get_char_count (buffer);
207
208  gtk_text_buffer_get_iter_at_mark (buffer,
209                                    @iter,
210                                    gtk_text_buffer_get_insert (buffer));
211
212  row := gtk_text_iter_get_line (@iter);
213  col := gtk_text_iter_get_line_offset (@iter);
214
215  msg := g_strdup_printf ('Cursor at row %d column %d - %d chars in document',
216                         [row, col, count]);
217
218  gtk_statusbar_push (statusbar, 0, msg);
219
220  g_free (msg);
221end;
222
223procedure mark_set_callback (buffer       : PGtkTextBuffer;
224                             new_location : PGtkTextIter;
225                             mark         : PGtkTextMark;
226                             data         : gpointer); cdecl;
227begin
228  update_statusbar (buffer, GTK_STATUSBAR (data));
229end;
230
231function do_appwindow      : PGtkWidget;
232var
233  table,
234  toolbar,
235  statusbar,
236  contents,
237  sw           : PGtkWidget;
238
239  buffer       : PGtkTextBuffer;
240  accel_group  : PGtkAccelGroup;
241  item_factory : PGtkItemFactory;
242
243begin
244  if application_window  = NULL then
245  begin
246    register_stock_icons ();
247
248    (* Create the toplevel window
249     *)
250
251    application_window  := gtk_window_new (GTK_WINDOW_TOPLEVEL);
252    gtk_window_set_title (GTK_WINDOW (application_window ), 'Application Window');
253
254
255    (* NULL window variable when window is closed *)
256    g_signal_connect (G_OBJECT (application_window ), 'destroy',
257                        G_CALLBACK (@gtk_widget_destroyed),
258                        @application_window );
259
260    table := gtk_table_new (1, 4, FALSE);
261
262    gtk_container_add (GTK_CONTAINER (application_window ), table);
263
264    (* Create the menubar
265     *)
266
267    accel_group := gtk_accel_group_new ();
268    gtk_window_add_accel_group (GTK_WINDOW (application_window), accel_group);
269    g_object_unref (accel_group);
270
271    item_factory := gtk_item_factory_new (GTK_TYPE_MENU_BAR, '<main>', accel_group);
272
273    (* Set up item factory to go away with the window *)
274    g_object_ref (item_factory);
275    gtk_object_sink (GTK_OBJECT (item_factory));
276    g_object_set_data_full (G_OBJECT (application_window ),
277                              '<main>',
278                              item_factory,
279                              TGDestroyNotify (@g_object_unref));
280
281    (* create menu items *)
282    menu_items[2].extra_data:=PChar(GTK_STOCK_NEW);
283    menu_items[3].extra_data:=PChar(GTK_STOCK_OPEN);
284    menu_items[4].extra_data:=PChar(GTK_STOCK_SAVE);
285    menu_items[5].extra_data:=PChar(GTK_STOCK_SAVE_AS);
286    menu_items[7].extra_data:=PChar(GTK_STOCK_QUIT);
287
288    gtk_item_factory_create_items (item_factory, high (menu_items),
289                                   @menu_items[1], application_window );
290
291    gtk_table_attach (GTK_TABLE (table),
292                        gtk_item_factory_get_widget (item_factory, '<main>'),
293                        (* X direction *)          (* Y direction *)
294                        0, 1,                      0, 1,
295                        GTK_EXPAND or GTK_FILL,    0,
296                        0,                         0);
297
298    (* Create the toolbar
299     *)
300    toolbar := gtk_toolbar_new ();
301
302    gtk_toolbar_insert_stock (GTK_TOOLBAR (toolbar),
303                              GTK_STOCK_OPEN,
304                              'This is a demo button with an ''open'' icon',
305                              NULL,
306                              G_CALLBACK (@toolbar_cb),
307                              application_window , (* user data for callback *)
308                              -1);  (* -1 means "append" *)
309
310    gtk_toolbar_insert_stock (GTK_TOOLBAR (toolbar),
311                              GTK_STOCK_QUIT,
312                              'This is a demo button with a ''quit'' icon',
313                              NULL,
314                              G_CALLBACK (@toolbar_cb),
315                              application_window , (* user data for callback *)
316                              -1);  (* -1 means "append" *)
317
318    gtk_toolbar_append_space (GTK_TOOLBAR (toolbar));
319    gtk_toolbar_insert_stock (GTK_TOOLBAR (toolbar),
320                              'demo-gtk-logo',
321                              'This is a demo button with a ''gtk'' icon',
322                              NULL,
323                              G_CALLBACK (@toolbar_cb),
324                              application_window , (* user data for callback *)
325                              -1);  (* -1 means "append" *)
326
327    gtk_table_attach (GTK_TABLE (table),
328                      toolbar,
329                      (* X direction *)       (* Y direction *)
330                      0, 1,                   1, 2,
331                      GTK_EXPAND or GTK_FILL, 0,
332                      0,                      0);
333
334    (* Create document
335     *)
336
337    sw := gtk_scrolled_window_new (NULL, NULL);
338
339    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
340                                    GTK_POLICY_AUTOMATIC,
341                                    GTK_POLICY_AUTOMATIC);
342
343    gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
344                                         GTK_SHADOW_IN);
345
346    gtk_table_attach (GTK_TABLE (table),
347                      sw,
348                      (* X direction *)       (* Y direction *)
349                      0, 1,                   2, 3,
350                      GTK_EXPAND or GTK_FILL,  GTK_EXPAND or GTK_FILL,
351                      0,                      0);
352
353    gtk_window_set_default_size (GTK_WINDOW (application_window ),
354                                 200, 200);
355
356    contents := gtk_text_view_new ();
357
358    gtk_container_add (GTK_CONTAINER (sw),
359                       contents);
360
361    (* Create statusbar *)
362
363    statusbar := gtk_statusbar_new ();
364    gtk_table_attach (GTK_TABLE (table),
365                      statusbar,
366                      (* X direction *)       (* Y direction *)
367                        0, 1,                   3, 4,
368                        GTK_EXPAND or GTK_FILL,  0,
369                        0,                      0);
370
371    (* Show text widget info in the statusbar *)
372    buffer := gtk_text_view_get_buffer (GTK_TEXT_VIEW (contents));
373
374    g_signal_connect_object (buffer,
375                             'changed',
376                             G_CALLBACK (@update_statusbar),
377                             statusbar,
378                             0);
379
380    g_signal_connect_object (buffer,
381                             'mark_set', (* cursor moved *)
382                             G_CALLBACK (@mark_set_callback),
383                             statusbar,
384                             0);
385
386    update_statusbar (buffer, GTK_STATUSBAR (statusbar));
387  end;
388
389  if not (GTK_WIDGET_VISIBLE (application_window )) then
390    gtk_widget_show_all (application_window )
391  else begin
392    gtk_widget_destroy (application_window);
393    application_window  := NULL;
394  end;
395
396  do_appwindow := application_window ;
397end;
398
399
400