1# Gtk support
2
3Lgi Gtk support is based on gobject-introspection support.  Some
4extensions are provided to support non-introspectable features and to
5provide easier and more Lua-like access to some important Gtk
6features.
7
8## Basic Widget and Container support
9
10### Style properties access
11
12To read style property values of the widget, a `style` attribute is
13implemented.  Following example reads `resize-grip-height` style
14property from Gtk.Window instance:
15
16    local window = Gtk.Window()
17    print(window.style.resize_grip_height)
18
19### Gtk.Widget width and height properties
20
21lgi adds new `width` and `height` properties to Gtk.Widget.  Reading them
22yields allocated size (`Gtk.Widget.get_allocated_size()`), writing them sets
23new size request (`Gtk.Widget.set_size_request()`).  These usages typically
24means what an application needs - actual allocated size to draw on when
25reading, and request for specific size when writing them.
26
27### Child properties
28
29Child properties are properties of the relation between a container
30and child.  A Lua-friendly access to these properties is implemented
31by `property` attribute of `Gtk.Container`.  Following example
32illustrates writing and reading of `width` property of `Gtk.Grid`
33and child `Gtk.Button`:
34
35    local grid, button = Gtk.Grid(), Gtk.Button()
36    grid:add(button)
37    grid.property[button].width = 2
38    print(grid.property[button].width)   -- prints 2
39
40### Adding children to container
41
42Basic method for adding child widget into container is
43`Gtk.Container.add()` method.  This method is overloaded by Lgi so
44that it accepts either widget, or table containing widget at index 1
45and the rest `name=value` pairs define child properties.  Therefore
46this method is full replacement of unintrospectable
47`gtk_container_add_with_properties()` function.  Example from previous
48chapter simplified using this technique follows:
49
50    local grid, button = Gtk.Grid(), Gtk.Button()
51    grid:add { button, width = 2 }
52    print(grid.property[button].width)    -- prints 2
53
54Another important feature of containers is that they have extended
55constructor, and array part of constructor argument table can contain
56widgets to be added.  Therefore, previous example can be written like
57this:
58
59    local button = Gtk.Button()
60    local grid = Gtk.Grid {
61       { button, width = 2 }
62    }
63    print(grid.property[button].width)    -- prints 2
64
65### 'id' property of widgets
66
67Another important feature is that all widgets support `id` property,
68which can hold an arbitrary string which is used to identify the
69widget.  `id` is assigned by caller, defaults to `nil`.  To look up
70widget with specified id in the container's widget tree (i.e. not only
71in direct container children), query `child` property of the container
72with requested id.  Previous example rewritten with this technique
73would look like this:
74
75    local grid = Gtk.Grid {
76       { Gtk.Button { id = 'button' }, width = 2 }
77    }
78    print(grid.property[grid.child.button].width)    -- prints 2
79
80The advantage of these features is that they allow using Lua's
81data-description face for describing widget hierarchies in natural
82way, instead of human-unfriendly `Gtk.Builder`'s XML.  A small example
83follows:
84
85    Gtk = lgi.Gtk
86    local window = Gtk.Window {
87       title = 'Application',
88       default_width = 640, default_height = 480,
89       Gtk.Grid {
90          orientation = Gtk.Orientation.VERTICAL,
91          Gtk.Toolbar {
92             Gtk.ToolButton { id = 'about', stock_id = Gtk.STOCK_ABOUT },
93             Gtk.ToolButton { id = 'quit', stock_id = Gtk.STOCK_QUIT },
94          },
95          Gtk.ScrolledWindow {
96             Gtk.TextView { id = 'view', expand = true }
97          },
98          Gtk.Statusbar { id = 'statusbar' }
99       }
100    }
101
102    local n = 0
103    function window.child.about:on_clicked()
104       n = n + 1
105       window.child.view.buffer.text = 'Clicked ' .. n .. ' times'
106    end
107
108    function window.child.quit:on_clicked()
109       window:destroy()
110    end
111
112    window:show_all()
113
114Run `samples/console.lua`, paste example into entry view and enjoy.
115The `samples/console.lua` example itself shows more complex usage of
116this pattern.
117
118## Gtk.Builder
119
120Although Lua's declarative style for creating widget hierarchies (as
121presented in chapter discussing `Gtk.Container` extensions) is generally
122preferred to builder's XML authoring by hand, `Gtk.Builder` can still be
123useful when widget hierarchies are designed in some external tool like
124`glade`.
125
126Original `gtk_builder_add_from_file` and `gtk_builder_add_from_string`
127return `guint` instead of `gboolean`, which would make direct usage
128from Lua awkward.  Lgi overrides these methods to return `boolean` as
129the first return value, so that typical
130`assert(builder:add_from_file(filename))` can be used.
131
132A new `objects` attribute provides direct access to loaded objects by
133their identifier, so that instead of `builder:get_object('id')` it
134is possible to use `builder.objects.id`
135
136`Gtk.Builder.connect_signals(handlers)` tries to connect all signals
137to handlers which are defined in `handlers` table.  Functions from
138`handlers` table are invoked with target object on which is signal
139defined as first argument, but it is possible to define `object`
140attribute, in this case the object instance specified in `object`
141attribute is used.  `after` attribute is honored, but `swapped` is
142completely ignored, as its semantics for lgi is unclear and not very
143useful.
144
145## Gtk.Action and Gtk.ActionGroup
146
147Lgi provides new method `Gtk.ActionGroup:add()` which generally replaces
148unintrospectable `gtk_action_group_add_actions()` family of functions.
149`Gtk.ActionGroup:add()` accepts single argument, which may be one of:
150
151- an instance of `Gtk.Action` - this is identical with calling
152  `Gtk.Action.add_action()`.
153- a table containing instance of `Gtk.Action` at index 1, and
154  optionally having attribute `accelerator`; this is a shorthand for
155  `Gtk.ActionGroup.add_action_with_accel()`
156- a table with array of `Gtk.RadioAction` instances, and optionally
157  `on_change` attribute containing function to be called when the radio
158  group state is changed.
159
160All actions or groups can be added by an array part of `Gtk.ActionGroup`
161constructor, as demonstrated by following example:
162
163    local group = Gtk.ActionGroup {
164       Gtk.Action { name = 'new', label = "_New" },
165       { Gtk.Action { name = 'open', label = "_Open" },
166         accelerator = '<control>O' },
167       {
168          Gtk.RadioAction { name = 'simple', label = "_Simple", value = 1 },
169          { Gtk.RadioAction { name = 'complex', label = "_Complex",
170            value = 2 }, accelerator = '<control>C' },
171          on_change = function(action)
172             print("Changed to: ", action.name)
173          end
174       },
175    }
176
177To access specific action from the group, a read-only attribute `action`
178is added to the group, which allows to be indexed by action name to
179retrieve.  So continuing the example above, we can implement 'new'
180action like this:
181
182    function group.action.new:on_activate()
183       print("Action 'New' invoked")
184    end
185
186## Gtk.TextTagTable
187
188It is possible to populate new instance of the tag table with tags
189during the construction, an array part of constructor argument table is
190expected to contain `Gtk.TextTag` instances which are then automatically
191added to the table.
192
193A new attribute `tag` is added, provides Lua table which can be indexed
194by string representing tag name and returns the appropriate tag (so it is
195essentially a wrapper around `Gtk.TextTagTable:lookup()` method).
196
197Following example demonstrates both capabilities:
198
199    local tag_table = Gtk.TextTagTable {
200       Gtk.TextTag { name = 'plain', color = 'blue' },
201       Gtk.TextTag { name = 'error', color = 'red' },
202    }
203
204    assert(tag_table.tag.plain == tag_table:lookup('plain'))
205
206## TreeView and related classes
207
208`Gtk.TreeView` and related classes like `Gtk.TreeModel` are one of the
209most complicated objects in the whole `Gtk`.  Lgi adds some overrides
210to simplify the work with them.
211
212### Gtk.TreeModel
213
214Lgi supports direct indexing of treemodel instances by iterators
215(i.e. `Gtk.TreeIter` instances).  To get value at specified column
216number, index the resulting value again with column number.  Note that
217although `Gtk` uses 0-based column numbers, Lgi remaps them to 1-based
218numbers, because working with 1-based arrays is much more natural for
219Lua.
220
221Another extension provided by Lgi is
222`Gtk.TreeModel:pairs([parent_iter])` method for Lua-native iteration of
223the model.  This method returns 3 values suitable to pass to generic
224`for`, so that standard Lua iteration protocol can be used.  See the
225example in the next chapter which uses this technique.
226
227### Gtk.ListStore and Gtk.TreeStore
228
229Standard `Gtk.TreeModel` implementations, `Gtk.ListStore` and
230`Gtk.TreeStore` extend the concept of indexing model instance with
231iterators also to writing values.  Indexing resulting value with
2321-based column number allows writing individual values, while
233assigning the table containing column-keyed values allows assigning
234multiple values at once.  Following example illustrates all these
235techniques:
236
237    local PersonColumn = { NAME = 1, AGE = 2, EMPLOYEE = 3 }
238    local store = Gtk.ListStore.new {
239       [PersonColumn.NAME] = GObject.Type.STRING,
240       [PersonColumn.AGE] = GObject.Type.INT,
241       [PersonColumn.EMPLOYEE] = GObject.Type.BOOLEAN,
242    }
243    local person = store:append()
244    store[person] = {
245       [PersonColumn.NAME] = "John Doe",
246       [PersonColumn.AGE] = 45,
247       [PersonColumn.EMPLOYEE] = true,
248    }
249    assert(store[person][PersonColumn.AGE] == 45)
250    store[person][PersonColumn.AGE] = 42
251    assert(store[person][PersonColumn.AGE] == 42)
252
253    -- Print all persons in the store
254    for i, p in store:pairs() do
255       print(p[PersonColumn.NAME], p[PersonColumn.AGE])
256    end
257
258Note that `append` and `insert` methods are overridden and accept
259additional parameter containing table with column/value pairs, so
260creation section of previous example can be simplified to:
261
262    local person = store:append {
263       [PersonColumn.NAME] = "John Doe",
264       [PersonColumn.AGE] = 45,
265       [PersonColumn.EMPLOYEE] = true,
266    }
267
268Note that while the example uses `Gtk.ListStore`, similar overrides
269are provided also for `Gtk.TreeStore`.
270
271### Gtk.TreeView and Gtk.TreeViewColumn
272
273Lgi provides `Gtk.TreeViewColumn:set(cell, data)` method, which allows
274assigning either a set of `cell` renderer attribute->model column
275pairs (in case that `data` argument is a table), or assigns custom
276data function for specified cell renderer (when `data` is a function).
277Note that column must already have assigned cell renderer.  See
278`gtk_tree_view_column_set_attributes()` and
279`gtk_tree_view_column_set_cell_data_func()` for precise documentation.
280
281The override `Gtk.TreeViewColumn:add(def)` composes both adding new
282cellrenderer and setting attributes or data function.  `def` argument
283is a table, containing cell renderer instance at index 1 and `data` at
284index 2.  Optionally, it can also contain `expand` attribute (set to
285`true` or `false`) and `align` (set either to `start` or `end`).  This
286method is basically combination of `gtk_tree_view_column_pack_start()`
287or `gtk_tree_view_column_pack_end()` and `set()` override method.
288
289Array part of `Gtk.TreeViewColumn` constructor call is mapped to call
290`Gtk.TreeViewColumn:add()` method, and array part of `Gtk.TreeView`
291constructor call is mapped to call `Gtk.TreeView:append_column()`, and
292this allows composing the whole initialized treeview in a declarative
293style like in the example below:
294
295    -- This example reuses 'store' model created in examples in
296    -- Gtk.TreeModel chapter.
297    local view = Gtk.TreeView {
298       model = store,
299       Gtk.TreeViewColumn {
300          title = "Name and age",
301          expand = true,
302          { Gtk.CellRendererText {}, { text = PersonColumn.NAME } },
303          { Gtk.CellRendererText {}, { text = PersonColumn.AGE } },
304       },
305       Gtk.TreeViewColumn {
306          title = "Employee",
307          { Gtk.CellRendererToggle {}, { active = PersonColumn.EMPLOYEE } }
308       },
309    }
310