~ubuntu-branches/ubuntu/dapper/fpc/dapper

« back to all changes in this revision

Viewing changes to docs/gtk3.tex

  • Committer: Bazaar Package Importer
  • Author(s): Carlos Laviola
  • Date: 2004-08-12 16:29:37 UTC
  • mfrom: (1.2.1 upstream) (2.1.1 warty)
  • Revision ID: james.westby@ubuntu.com-20040812162937-moo8ulvysp1ln771
Tags: 1.9.4-5
fp-compiler: needs ld, adding dependency on binutils.  (Closes: #265265)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
\documentclass[10pt]{article}
 
2
\usepackage{a4}
 
3
\usepackage{epsfig}
 
4
\usepackage{listings}
 
5
\usepackage{tabularx}
 
6
\lstset{language=Delphi}%
 
7
\lstset{basicstyle=\sffamily\small}%
 
8
\lstset{commentstyle=\itshape}%
 
9
\lstset{keywordstyle=\bfseries}%
 
10
%\lstset{blankstring=true}%
 
11
\newif\ifpdf
 
12
\ifx\pdfoutput\undefined
 
13
  \pdffalse
 
14
\else
 
15
  \pdfoutput=1
 
16
  \pdftrue
 
17
\fi
 
18
\begin{document}
 
19
\title{Programming GTK in Free Pascal:\\ Menus 
 
20
%and Marshallers
 
21
}
 
22
\author{Florian Kl\"ampfl\\and\\Micha\"el Van Canneyt}
 
23
\date{September 2000}
 
24
\maketitle
 
25
\section{Introduction}
 
26
In the third article on programming the GTK toolkit, the us of menus in GTK
 
27
is explored.
 
28
%two topics are
 
29
%explored: The programming of menus and the use of marshallers. 
 
30
 
 
31
Menus can be built in essentially 2 ways; the easier way through the
 
32
use of a itemfactory, and the more complex way, doing all necessary calls
 
33
manually. The advantages of both ways are discussed.
 
34
 
 
35
%Marshallers can be used to replace the default signal handling mechanisms 
 
36
%of GTK. The use of marshallers will be demonstrated by building a small
 
37
%object which will have custom handlers for certain events.
 
38
 
 
39
\section{Menus the easy way: The item factory}
 
40
The easy way to construct a menu is to use an item factory. An Item factory
 
41
gets as input an array of records, which describe a menu structure, and
 
42
returns a completely built menu, ready to be added to a window.
 
43
 
 
44
The great advantage of an item factory is that it is easy to use; a
 
45
disadvantage is that 
 
46
\begin{enumerate}
 
47
\item There is less control over the produced menu items; e.g. 
 
48
displaying a menu item with a small icon is not possible.
 
49
\item The callbacks of the constructed menu is different from the usual 
 
50
signal model, making it difficult to combine a menu entry with a
 
51
speedbutton. There are also 2 types of callback, so type checking is not
 
52
possible.
 
53
\item In Pascal, constant records must be specified using the names of the
 
54
members; this makes the array with the menu items to be rendered quite
 
55
complicated.
 
56
\end{enumerate}
 
57
 
 
58
To create a menu, first the item factory must be created. The function to do 
 
59
this is defined as follows:
 
60
\begin{lstlisting}{}
 
61
gtk_item_factory_new(container_type:TGtkType; 
 
62
                     path:Pgchar;
 
63
                     accel_group:PGtkAccelGroup):PGtkItemFactory;
 
64
\end{lstlisting}
 
65
The three arguments to this function have the following meaning:
 
66
\begin{description}
 
67
\item[container\_type] This identifies the kind of menu that will be
 
68
rendered. It can have one of the following values:
 
69
\begin{description}
 
70
\item[GTK\_MENU\_BAR\_TYPE] A menu bar will be created to hold all items.
 
71
\item[GTK\_MENU\_TYPE] A menu that can be used as a popup menu, or that can be
 
72
attached as a sub-menu to another menu, will be created.
 
73
\item[GTK\_OPTION\_MENU\_TYPE] Makes everything in a drop-down style menu which
 
74
can be used to select one value.
 
75
\end{description}
 
76
\item[path] is the name of the menu to be generated.
 
77
\item[accel\_group] Is a pointer to a group of accelerators. All
 
78
accellerators for the generated menu will be attached to this group.
 
79
\end{description}
 
80
 
 
81
The accelerator group needed for the item factory can be constructed 
 
82
using a simple call to \lstinline|gtk_accel_group_new|; this function 
 
83
takes no arguments,  and returns a pointer to a new accelerator group.
 
84
 
 
85
To actually create the menu, a call to
 
86
\lstinline|gtk_item_factory_create_items| is needed; This procedure is 
 
87
defined as follows:
 
88
\begin{lstlisting}{}
 
89
gtk_item_factory_create_items(ifactory:PGtkItemFactory; 
 
90
                              n_entries:guint; 
 
91
                              entries:PGtkItemFactoryEntry; 
 
92
                              callback_data:gpointer);
 
93
\end{lstlisting}
 
94
The first argument to this call, \lstinline|ifactory|, is the itemfactory; 
 
95
the second argument, \lstinline|n_entries|, is the number of items in the 
 
96
array of records describing the menu. The third argument, \lstinline|entries|,
 
97
is the actual array describing the menu. The last argument
 
98
\lstinline|callback_data| is a pointer that will be passed to the menu
 
99
callbacks.
 
100
 
 
101
The menu structure that should be created by the item factory is an 
 
102
array of records of the type  \lstinline|TGtkItemFactoryEntry|. 
 
103
This record is defined as follows:
 
104
\begin{lstlisting}{}
 
105
 TGtkItemFactoryEntry = record
 
106
    path : Pgchar;
 
107
    accelerator : Pgchar;
 
108
    callback : TGtkItemFactoryCallback;
 
109
    callback_action : guint;
 
110
    item_type : Pgchar;
 
111
 end;
 
112
\end{lstlisting}
 
113
The fields have the following meaning:
 
114
\begin{description}
 
115
\item[path]
 
116
The first entry is the path of the menu item. This indicates the place of
 
117
the menu entry in the whole menu. For instance, the menu item \textbf{New}
 
118
in the menu \textbf{File} would be designated by \lstinline|'/File/New'|.
 
119
So, the slash is used to separate the menu levels. 
 
120
 
 
121
To make one of the letters of the menu item name active, so the item can be
 
122
selected by pressing the letter (on the keyboard) when the menu is opened, 
 
123
the key to be used should be preceded by an underscore. 
 
124
In e.g. \lstinline|'/File/_New'|, the letter \textbf{N} could be used to 
 
125
select the  \textbf{New} item if the \textbf{File} menu is active.
 
126
 
 
127
\item[accelerator] To make a shortcut to the menu item so it can be 
 
128
activated at all times, the shortcut name can be specified in the 
 
129
\lstinline|accelerator| field. This can be any key, together with some 
 
130
modifiers. e.g. \lstinline|'<control>N'| will make the key combination 
 
131
'CTRL-N' a shortcut.
 
132
 
 
133
The accelerator should be speciefied as normal text.  A list of possible
 
134
modifiers can be found in table \ref{tab:modifiers}.
 
135
\begin{table}[ht]
 
136
\begin{center}
 
137
\caption{List of modifier strings for shortcut keys}\label{tab:modifiers}
 
138
\begin{tabular}{cc}
 
139
Modifier & alias \\ \hline
 
140
\lstinline|<control>| & \lstinline|<ctl>|, \lstinline|<ctrl>| \\
 
141
\lstinline|<shift>| & \lstinline|<shft>| \\
 
142
\lstinline|<alt>| & \lstinline|<mod1>| \\ \hline
 
143
\end{tabular}
 
144
\end{center}
 
145
\end{table}
 
146
 
 
147
\item[callback] Contains a pointer to the function that should be called
 
148
when the menu item is activated. The type of the menu handler is not the 
 
149
same as a normal signal handler; The actual callback should be of the type
 
150
\lstinline|TGtkItemFactoryCallback1|:
 
151
\begin{lstlisting}{}
 
152
procedure (callback_data:gpointer; 
 
153
           callback_action:guint; 
 
154
           widget:PGtkWidget);cdecl;
 
155
\end{lstlisting}
 
156
Which is not the same as the type of the \lstinline|callback| field, so
 
157
a typecast will always be necessary.
 
158
 
 
159
\item[callback\_action] This is passed on to the callback in the
 
160
\lstinline|callback_action| parameter.
 
161
 
 
162
\item[item\_type] is the type of menu item. Several types can be used; the
 
163
complete list can be found in \ref{tab:menutypes}, but the must important
 
164
ones are \lstinline|'<Item>'|, which specifies a normal menu item, 
 
165
 and \lstinline|'<Branch>'|, which indicates a sub-menu.
 
166
\begin{table}[ht]
 
167
\begin{center}
 
168
\caption{Possible menu item types}\label{tab:menutypes}
 
169
\begin{tabularx}{\textwidth}{lX}%
 
170
Item type & Menu kind \\ \hline
 
171
\lstinline|'<Item>'| & indicates a normal item. An empty string or \lstinline|Nil|
 
172
have the same meaning. \\
 
173
\lstinline|'<CheckItem>'| & a check menu item. \\
 
174
\lstinline|'<ToggleItem>'| & a toggle menu item (same as check menu). \\
 
175
\lstinline|'<RadioItem>'| & a radio item. \\
 
176
\lstinline|'<Separator>'| & a separator bar. \\
 
177
\lstinline|'<Branch>'| & an item to hold a submenu.\\
 
178
\lstinline|'<LastBranch>'| & an item to hold a submenu, but right aligned.\\ \hline
 
179
\end{tabularx}
 
180
\end{center}
 
181
\end{table}
 
182
\end{description}
 
183
Now all elements to create a menu are introduced, and the menu can be
 
184
created. The following definitions should now be clear:
 
185
\begin{lstlisting}{}
 
186
Var
 
187
Window  : PGtkWidget;
 
188
MenuBar : PGtkWidget;
 
189
 
 
190
Type
 
191
  FC = TGtkItemFactoryCallback;
 
192
 
 
193
Const
 
194
 NrMenuItems = 21;
 
195
  TheMenu : Array[1..NrMenuItems] of TGtkItemFactoryEntry = (
 
196
    (path:'/_File';Accelerator:Nil;
 
197
     Callback:Nil;Callback_action:1;item_type:'<Branch>'),
 
198
    (path:'/File/_New';Accelerator:'<ctrl>N';
 
199
     Callback:FC(@Menu);Callback_action:1;item_type:Nil),
 
200
    { ... }
 
201
\end{lstlisting}
 
202
Here the \lstinline|FC| type is introduced to make the typecast of the
 
203
\lstinline|Menu| handler easier; the 
 
204
\lstinline|TheMenu| constant is not given completely, since it is too long
 
205
and not instructive. The complete structure can be found in the sources
 
206
accompanying this article.
 
207
 
 
208
Using the above definitions, the menu can now be constructed:
 
209
\begin{lstlisting}{}
 
210
Procedure MakeMenu;
 
211
 
 
212
Var
 
213
  Factory : PGtkItemFactory;
 
214
  Accel   : PGtkAccelGroup;
 
215
 
 
216
begin
 
217
  Accel:=gtk_accel_group_new;
 
218
  Factory :=gtk_item_factory_new(GTK_MENU_BAR_TYPE,'<main>',accel);
 
219
  gtk_item_factory_create_items(Factory,NrMenuItems,@TheMenu,Nil);
 
220
  gtk_window_add_accel_group(GTK_Window(Window),accel);
 
221
  MenuBar:=gtk_item_factory_get_widget (Factory, '<main>');
 
222
end;
 
223
\end{lstlisting}
 
224
The \lstinline|gtk_window_add_accel_group| call attaches the accelerator
 
225
group that was filled up by the item factory to the window.
 
226
 
 
227
The \lstinline|gtk_item_factory_get_widget| call finally fetches the
 
228
object created by the item factory and stores it in a widget variable.
 
229
 
 
230
The \lstinline|Menu| callback used in the menus is defined as follows:
 
231
\begin{lstlisting}{}
 
232
procedure menu(Data : GPointer; 
 
233
               Action : Guint; 
 
234
               Widget : pGtkWidget); cdecl;
 
235
    
 
236
Var 
 
237
  TheLabel : PgtkWidget;
 
238
  LabelText : Pchar;
 
239
  S : AnsiString;
 
240
     
 
241
begin
 
242
  TheLabel:=g_list_nth_data(
 
243
             gtk_container_children(
 
244
               GTK_CONTAINER(Widget)),0);
 
245
  gtk_label_get(gtk_Label(theLabel),@LabelText);
 
246
  S := 'Chosen menu : ' + Strpas(Labeltext);
 
247
  gtk_label_set_text(GTK_LABEL(DisplayLabel),pchar(S));
 
248
end;
 
249
\end{lstlisting}
 
250
The \lstinline|DisplayLabel| is a label located on the window, it is used to
 
251
give some feedback on the used menu. The code to extract the menu name from
 
252
the menu widget passed to the handler will be explained later on. 
 
253
 
 
254
The result of all this is shown in figure \ref{fig:ex1}.
 
255
\begin{figure}
 
256
\caption{The menu made by the item factory.}\label{fig:ex1}
 
257
\epsfig{file=gtk3ex/ex1.png}
 
258
\end{figure}
 
259
 
 
260
As can be seen from the code above, the creation of a menu using an item
 
261
factory in GTK is not so hard. The drawback of the above method lies mainly
 
262
in the fact that Pascal handles constant records differently than C, which 
 
263
makes the array that describes the menu structure rather difficult to read.
 
264
 
 
265
The second drawback is that there is little control over the created items.
 
266
 
 
267
\section{Menus the hard way: manually}
 
268
When creating menus manually, mainly 4 objects are involved:
 
269
\begin{itemize}
 
270
\item The menu items themselves. To a menu item, a menu can be assiciated,
 
271
creating a sub-menu.
 
272
\item Menus, which contain a collection of menu items,
 
273
\item A accelerator group. This will be used to keep a collection of
 
274
shortcut keys for the menu items.
 
275
\item A menu bar, which can hold several menu items and their associated
 
276
menus. 
 
277
\end{itemize}
 
278
The last object is optional, if e.g. a pop-up menu is wanted.
 
279
 
 
280
To create a menu in a window, the following steps are involved:
 
281
\begin{enumerate}
 
282
\item Create an accellerator group. The accelerator group should be
 
283
connected to the window. \label{stepone}
 
284
\item Create a menu bar, and attach it to the window.
 
285
\item For each menu that should appear in a menu bar, do the following:
 
286
\begin{itemize}
 
287
\item Create a menu item, which will be shown in the menu bar.
 
288
\item Create a menu to hold the items that should pop up when the menu is
 
289
activated.
 
290
\end{itemize}
 
291
\item To each menu created in the previous step, add as many menu items as
 
292
needed. Add an accelarator to the group created in step \ref{stepone}.
 
293
\end{enumerate}
 
294
 
 
295
To make these steps easier (each of them involves quite some calls to GTK
 
296
functions) some functions will be introduced that make this easier.
 
297
 
 
298
The first function is the most simple one; it attaches a separator to a
 
299
menu:
 
300
\begin{lstlisting}{}
 
301
Function AddSeparatorToMenu(Menu:PgtkMenu):PgtkMenuItem;
 
302
 
 
303
begin
 
304
  Result:=pgtkmenuitem(gtk_menu_item_new); 
 
305
  gtk_menu_append(Menu,pgtkWidget(result));
 
306
  gtk_widget_show(PgtkWidget(result));
 
307
end;
 
308
\end{lstlisting}
 
309
The function takes one parameter, \lstinline|Menu|, the menu to which the
 
310
separator will be attached. A separator is created by simply creating an
 
311
empty menu item. Creating a new (empty) menu item is done with the
 
312
\lstinline|gtk_menu_item_new| call. 
 
313
 
 
314
With the \lstinline|gtk_menu_append| call, the newly created item is then 
 
315
added to the menu. Lastly, the item is shown; it will not become actually
 
316
visible till the menu is activated. If this is omitted, it will also not
 
317
be visible when the menu is activated.
 
318
 
 
319
Adding a menu with a shortcut key to a menu is a little more involved. Some
 
320
more elements are needed:
 
321
\begin{enumerate}
 
322
\item The menu to which to attach the menu item.
 
323
\item The accelarator group to which the accelerator key should be added.
 
324
\item The caption of the menu. An underscore character will indicate the 
 
325
letter of themenu that will be used as a shortcut to activate the item.
 
326
\item The shortcut for the menu item. An empty string means no shortcut.
 
327
\item A callback function which will be called when the menu item is
 
328
activated, and callback data which will sent to the callback.
 
329
\end{enumerate}
 
330
All these elements are found in the declaration of the following function:
 
331
\begin{lstlisting}{}
 
332
Function AddItemToMenu (Menu : PGtkMenu;
 
333
                        ShortCuts : PGtkAccelGroup;
 
334
                        Caption : AnsiString;
 
335
                        ShortCut : AnsiString;
 
336
                        CallBack : TgtkSignalFunc;
 
337
                        CallBackdata : Pointer
 
338
                       ) : PGtkMenuItem; 
 
339
 
 
340
Var
 
341
  Key,Modifiers : guint;
 
342
  LocalAccelGroup : PGtkAccelGroup;
 
343
  TheLabel : PGtkLabel;
 
344
  
 
345
begin
 
346
\end{lstlisting}
 
347
The variables declared in this function will be explained as the code is
 
348
presented.
 
349
 
 
350
First of all, a menu item must be created. Since a caption for the menu is
 
351
provided, the \lstinline|gtk_menu_item_new_with_label| will be used to
 
352
create a menu that has a label as a child:
 
353
\begin{lstlisting}{}
 
354
  Result:=pgtkmenuitem(gtk_menu_item_new_with_label(''));
 
355
  TheLabel:=GTK_LABEL(GTK_BIN(Result)^.child);
 
356
  Key:=gtk_label_parse_uline(TheLabel,Pchar(Caption));
 
357
\end{lstlisting}
 
358
After the menu item is created, the child label is fetched. The label caption is
 
359
then set using the \lstinline|gtk_label_parse_uline| function. This function 
 
360
will search a text for underscore characters, remove them from the text, and
 
361
then set the label's caption with the result. All letters which had an
 
362
underscore character prepended will be underlined in the label.
 
363
 
 
364
The function returns the first letter that had an underscore prepended. It
 
365
is stored, so it can be used to make an accelerator:
 
366
\begin{lstlisting}{}
 
367
If Key<>0 then
 
368
  begin
 
369
  LocalAccelGroup:=gtk_menu_ensure_uline_accel_group(Menu);
 
370
  gtk_widget_add_accelerator(PGtkWidget(result),'activate_item',
 
371
                             LocalAccelGroup,Key,
 
372
                             0,TGtkAccelFlags(0));
 
373
  end;
 
374
\end{lstlisting}
 
375
The call to \lstinline|gtk_menu_ensure_uline_accel_group| returns the 
 
376
accelarator group associated with the menu. If no group existed yet, one
 
377
will be created. The \lstinline|gtk_widget_add_accelerator| call takes the
 
378
following parameters:
 
379
\begin{itemize}
 
380
\item A pointer to a widget to which the accelerator should be attached.
 
381
\item The name of the signal which will be triggered when the shortcut 
 
382
is activated.
 
383
\item The accelerator group to which the shortcut should be installed,
 
384
usually this will be the accelerator group for the window to which the
 
385
widget is attached, but in this case this is the accelerator group of the
 
386
menu (which will only be active when the menu is actually shown)
 
387
\item The key from the shortcut.
 
388
\item The modifiers that should be pressed together with the key. For the
 
389
menu, this should be 0, since just the key should be hit.
 
390
\item The accelerator flags.
 
391
\end{itemize}
 
392
 
 
393
After the menu item was created and it's underlined key was made into an
 
394
accelerator, the menu can be attached to the menu:
 
395
\begin{lstlisting}{}
 
396
gtk_menu_append(Menu,pgtkWidget(result));
 
397
\end{lstlisting}
 
398
 
 
399
If a shortcut key was passed along to the procedure, can be added to the
 
400
window's accelerator group with the following code:
 
401
\begin{lstlisting}{}
 
402
If (ShortCut<>'') and (ShortCuts<>Nil) then  
 
403
  begin
 
404
  gtk_accelerator_parse (pchar(ShortCut), @key, @modifiers);
 
405
  gtk_widget_add_accelerator(PGtkWidget(result),'activate_item',
 
406
                             ShortCuts,Key,
 
407
                             modifiers, GTK_ACCEL_VISIBLE);
 
408
  end;
 
409
\end{lstlisting}
 
410
The call to \lstinline|gtk_accelerator_parse| will parse a string which
 
411
describes a shortcut key, and returns the corresponding key and modifiers,
 
412
which can then be passed on to the \lstinline|gtk_widget_add_accelerator|
 
413
call.
 
414
 
 
415
After the accellerator has been installed, the only thing that remains to be
 
416
done is to connect the callback to the activation of the menu:
 
417
\begin{lstlisting}{}
 
418
If CallBack<>Nil then
 
419
  gtk_signal_connect(PGtkObject(result),'activate',
 
420
                     CallBack,CallBackdata);
 
421
gtk_widget_show(PgtkWidget(result));  
 
422
end;
 
423
\end{lstlisting}
 
424
As the last line in the procedure, the newly created menu item is shown.
 
425
If the menu isn't visible yet, this will do nothing, but will ensure that
 
426
the item is also visible when the menu is visible.
 
427
 
 
428
Now a menu-item and a separator can be added to a menu. What remains to be
 
429
done is to add a menu to a menu bar. This is done in the following
 
430
procedure, which is given in its entirety:
 
431
\begin{lstlisting}{}
 
432
Function AddMenuToMenuBar(MenuBar : PGtkMenuBar;
 
433
                          ShortCuts : PGtkAccelGroup;
 
434
                          Caption : AnsiString;
 
435
                          CallBack : TgtkSignalFunc;
 
436
                          CallBackdata : Pointer;   
 
437
                          AlignRight : Boolean;     
 
438
                          Var MenuItem : PgtkMenuItem
 
439
                          ) : PGtkMenu; 
 
440
 
 
441
Var
 
442
  Key : guint;
 
443
  TheLabel : PGtkLabel;
 
444
 
 
445
begin
 
446
  MenuItem:=pgtkmenuitem(gtk_menu_item_new_with_label(''));
 
447
  If AlignRight Then
 
448
    gtk_menu_item_right_justify(MenuItem);
 
449
  TheLabel:=GTK_LABEL(GTK_BIN(MenuItem)^.child);
 
450
  Key:=gtk_label_parse_uline(TheLabel,Pchar(Caption));
 
451
  If Key<>0 then
 
452
    gtk_widget_add_accelerator(PGtkWidget(MenuItem),'activate_item',
 
453
                               Shortcuts,Key,
 
454
                               GDK_MOD1_MASK,GTK_ACCEL_LOCKED);
 
455
  Result:=PGtkMenu(gtk_menu_new);
 
456
  If CallBack<>Nil then
 
457
    gtk_signal_connect(PGtkObject(result),'activate',
 
458
                        CallBack,CallBackdata);
 
459
  gtk_widget_show(PgtkWidget(MenuItem));  
 
460
  gtk_menu_item_set_submenu(MenuItem, PgtkWidget(Result));
 
461
  gtk_menu_bar_append(MenuBar,PgtkWidget(MenuItem));
 
462
\end{lstlisting}
 
463
The code for this procedure quite similar as the previous one. The main
 
464
differences are:
 
465
\begin{itemize}
 
466
\item The result is not a menuitem, but a whole menu. The menuitem that is
 
467
displayed in the menu bar itself is returned in the \lstinline|MenuItem|
 
468
parameter.
 
469
\item The shortcut key for the underlined item is added to the window's
 
470
accelerator group, and has the \textsc{Alt} key (or \textsf{Mod1}) as 
 
471
the modifier key.
 
472
\item the created menu is attached to the menu item as a sub menu, and it is
 
473
the menu-item which is attached to the menu bar.
 
474
\end{itemize}
 
475
 
 
476
With the above calls, a menu can be constructed with a simple set of calls:
 
477
\begin{lstlisting}{}
 
478
FileMenu:=AddMenuToMenuBar(MenuBar,accel,'_File',Nil,
 
479
                           Nil,False,TempMenuItem);
 
480
AddItemToMenu(FileMenu,accel,'_New','<control>N',
 
481
              TgtkSignalFunc(@menu),DisplayLabel);
 
482
AddItemToMenu(FileMenu,accel,'_Open','<control>O',
 
483
              TgtkSignalFunc(@menu),DisplayLabel);
 
484
AddItemToMenu(FileMenu,accel,'_Save','<control>S',
 
485
              TgtkSignalFunc(@menu),DisplayLabel);
 
486
AddSeparatorToMenu(PGtkMenu(FileMenu));
 
487
AddItemToMenu(FileMenu,accel,'_Quit','<control>Q',
 
488
              TgtkSignalFunc(@destroy),Nil);
 
489
{ ... } 
 
490
\end{lstlisting}
 
491
The complete list of calls to create the menu can be found in the sources
 
492
accompagnying this article.
 
493
 
 
494
The second program is of course bigger than the first, due to all the code
 
495
to create the menus. Nevertheless, the manual way of creating has it's
 
496
advantages: it's quite easy to extend the AddItemToMenu to add a bitmap to
 
497
the menu entry as well. Using a itemfactory, there is (currently) no way to
 
498
add images to a menu.
 
499
 
 
500
Adding a bitmap to a menu is quite easy, and requires only a few extra
 
501
lines of code. The key point is that the gtkmenuitem object is just an empty
 
502
container (it descends from gtkbin), which does not display anything by itself. The
 
503
\lstinline|gtk_menu_item_new_with_label| call creates a menu item and puts a
 
504
gtklabel in it to display the menu item caption. Instead of a label object,
 
505
almost any other object can be put in the item. This fact is used in the
 
506
following code to add a bitmap in front of the menu caption, in a new
 
507
procedure to be called \lstinline|AddImageItemToMenu|:
 
508
\begin{lstlisting}{}
 
509
  Result:=pgtkmenuitem(gtk_menu_item_new);
 
510
  hbox:=PGtkHBox(gtk_hbox_new(false,0));  
 
511
  gtk_container_add(pgtkcontainer(result),pgtkWidget(hbox));
 
512
  pixmap:=gdk_pixmap_create_from_xpm(Nil,@BitmapData,Nil,pchar(BitMap));
 
513
  Image := PgtkPixMap(gtk_pixmap_new(Pixmap,BitmapData));
 
514
  gtk_box_pack_start(PGtkBox(hbox),pgtkWidget(image),false,false,0);
 
515
  TheLabel:=PgtkLabel(gtk_label_new(''));
 
516
  gtk_box_pack_start(PGtkBox(hbox),pgtkWidget(TheLabel),True,True,0);
 
517
  Key:=gtk_label_parse_uline(TheLabel,Pchar(Caption));
 
518
\end{lstlisting}
 
519
In the first line, a plain menu item is created with
 
520
\lstinline|gtk_menu_item_new|. In the following two lines,
 
521
a \lstinline|GTKHBox| is added to the menu item, and a reference to the box
 
522
is stored in the \lstinline|hbox| variable.
 
523
 
 
524
Then, a pixmap is created from a filename. The filename is passed in the 
 
525
\lstinline|BitMap| parameter to our routine. Using the newly created pixmap,
 
526
an Image is created, which can then be added to the box.
 
527
 
 
528
Finally, a regular GTK label is created to hold the caption of the menu
 
529
item, and added to the box. After that the procedure continues as for a
 
530
normal menu.
 
531
 
 
532
The complete code for the above \lstinline|AddImageItemToMenu| routine can
 
533
be found in the sources of the third example, accompagnying this article.
 
534
The result can be seen in figure \ref{fig:pixmenu}
 
535
\begin{figure}[ht]
 
536
\caption{The menu with bitmaps}\label{fig:pixmenu}
 
537
\epsfig{file=gtk3ex/ex3.png}
 
538
\end{figure}
 
539
 
 
540
Some notes regarding this algorithm are in order:
 
541
\begin{enumerate}
 
542
\item It would be possible to have not a filename passed to the routine, but
 
543
directly pass a pixmap object as well; for instance when using a toolbar,
 
544
toolbuttons corresponding to the menu entries could share the same pixmaps
 
545
as the menu entries.
 
546
\item Some alignment issues may arise when the menu contains items with and
 
547
without bitmaps. The above code does not address these issues. To solve
 
548
them, the regular menu items should also be constructed e.g. using a hbox or a
 
549
table with an empty cell. Also, an algorithm to determine whether any item of
 
550
the menu has an image would be needed.
 
551
\item The shortcut key is no longer shown in the menu widget; The reason for
 
552
this is unknown to the authors of this article; unfortunately the lack of
 
553
documentation on GTK prevents the implementation of a remedy.
 
554
\item The menu callback can no longer retrieve the menu text using a
 
555
straightforward approach, since the label displaying the caption is 
 
556
no longer the only child widget of the menu item. The callback has been
 
557
adapted for this in the example.
 
558
\end{enumerate}
 
559
Taking into account the above arguments should make it possible to write
 
560
better menu-creating routines which would replace the item factory
 
561
completely, and which would enable the use of bitmaps in menu items.
 
562
 
 
563
\end{document}