<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <title>Gtk support</title> <link rel="stylesheet" type="text/css" href="default.css" /> </head> <body> <h1>Gtk support</h1> <p>Lgi Gtk support is based on gobject-introspection support. Some extensions are provided to support non-introspectable features and to provide easier and more Lua-like access to some important Gtk features.</p> <h2>Basic Widget and Container support</h2> <h3>Style properties access</h3> <p>To read style property values of the widget, a <code>style</code> attribute is implemented. Following example reads <code>resize-grip-height</code> style property from Gtk.Window instance:</p> <pre><code>local window = Gtk.Window() print(window.style.resize_grip_height) </code></pre> <h3>Gtk.Widget width and height properties</h3> <p>lgi adds new <code>width</code> and <code>height</code> properties to Gtk.Widget. Reading them yields allocated size (<code>Gtk.Widget.get_allocated_size()</code>), writing them sets new size request (<code>Gtk.Widget.set_size_request()</code>). These usages typically means what an application needs - actual allocated size to draw on when reading, and request for specific size when writing them.</p> <h3>Child properties</h3> <p>Child properties are properties of the relation between a container and child. A Lua-friendly access to these properties is implemented by <code>property</code> attribute of <code>Gtk.Container</code>. Following example illustrates writing and reading of <code>width</code> property of <code>Gtk.Grid</code> and child <code>Gtk.Button</code>:</p> <pre><code>local grid, button = Gtk.Grid(), Gtk.Button() grid:add(button) grid.property[button].width = 2 print(grid.property[button].width) -- prints 2 </code></pre> <h3>Adding children to container</h3> <p>Basic method for adding child widget into container is <code>Gtk.Container.add()</code> method. This method is overloaded by Lgi so that it accepts either widget, or table containing widget at index 1 and the rest <code>name=value</code> pairs define child properties. Therefore this method is full replacement of unintrospectable <code>gtk_container_add_with_properties()</code> function. Example from previous chapter simplified using this technique follows:</p> <pre><code>local grid, button = Gtk.Grid(), Gtk.Button() grid:add { button, width = 2 } print(grid.property[button].width) -- prints 2 </code></pre> <p>Another important feature of containers is that they have extended constructor, and array part of constructor argument table can contain widgets to be added. Therefore, previous example can be written like this:</p> <pre><code>local button = Gtk.Button() local grid = Gtk.Grid { { button, width = 2 } } print(grid.property[button].width) -- prints 2 </code></pre> <h3>'id' property of widgets</h3> <p>Another important feature is that all widgets support <code>id</code> property, which can hold an arbitrary string which is used to identify the widget. <code>id</code> is assigned by caller, defaults to <code>nil</code>. To look up widget with specified id in the container's widget tree (i.e. not only in direct container children), query <code>child</code> property of the container with requested id. Previous example rewritten with this technique would look like this:</p> <pre><code>local grid = Gtk.Grid { { Gtk.Button { id = 'button' }, width = 2 } } print(grid.property[grid.child.button].width) -- prints 2 </code></pre> <p>The advantage of these features is that they allow using Lua's data-description face for describing widget hierarchies in natural way, instead of human-unfriendly <code>Gtk.Builder</code>'s XML. A small example follows:</p> <pre><code>Gtk = lgi.Gtk local window = Gtk.Window { title = 'Application', default_width = 640, default_height = 480, Gtk.Grid { orientation = Gtk.Orientation.VERTICAL, Gtk.Toolbar { Gtk.ToolButton { id = 'about', stock_id = Gtk.STOCK_ABOUT }, Gtk.ToolButton { id = 'quit', stock_id = Gtk.STOCK_QUIT }, }, Gtk.ScrolledWindow { Gtk.TextView { id = 'view', expand = true } }, Gtk.Statusbar { id = 'statusbar' } } } local n = 0 function window.child.about:on_clicked() n = n + 1 window.child.view.buffer.text = 'Clicked ' .. n .. ' times' end function window.child.quit:on_clicked() window:destroy() end window:show_all() </code></pre> <p>Run <code>samples/console.lua</code>, paste example into entry view and enjoy. The <code>samples/console.lua</code> example itself shows more complex usage of this pattern.</p> <h2>Gtk.Builder</h2> <p>Although Lua's declarative style for creating widget hierarchies (as presented in chapter discussing <code>Gtk.Container</code> extensions) is generally preferred to builder's XML authoring by hand, <code>Gtk.Builder</code> can still be useful when widget hierarchies are designed in some external tool like <code>glade</code>.</p> <p>Original <code>gtk_builder_add_from_file</code> and <code>gtk_builder_add_from_string</code> return <code>guint</code> instead of <code>gboolean</code>, which would make direct usage from Lua awkward. Lgi overrides these methods to return <code>boolean</code> as the first return value, so that typical <code>assert(builder:add_from_file(filename))</code> can be used.</p> <p>A new <code>objects</code> attribute provides direct access to loaded objects by their identifier, so that instead of <code>builder:get_object('id')</code> it is possible to use <code>builder.objects.id</code></p> <p><code>Gtk.Builder.connect_signals(handlers)</code> tries to connect all signals to handlers which are defined in <code>handlers</code> table. Functions from <code>handlers</code> table are invoked with target object on which is signal defined as first argument, but it is possible to define <code>object</code> attribute, in this case the object instance specified in <code>object</code> attribute is used. <code>after</code> attribute is honored, but <code>swapped</code> is completely ignored, as its semantics for lgi is unclear and not very useful.</p> <h2>Gtk.Action and Gtk.ActionGroup</h2> <p>Lgi provides new method <code>Gtk.ActionGroup:add()</code> which generally replaces unintrospectable <code>gtk_action_group_add_actions()</code> family of functions. <code>Gtk.ActionGroup:add()</code> accepts single argument, which may be one of:</p> <ul> <li>an instance of <code>Gtk.Action</code> - this is identical with calling <code>Gtk.Action.add_action()</code>.</li> <li>a table containing instance of <code>Gtk.Action</code> at index 1, and optionally having attribute <code>accelerator</code>; this is a shorthand for <code>Gtk.ActionGroup.add_action_with_accel()</code></li> <li>a table with array of <code>Gtk.RadioAction</code> instances, and optionally <code>on_change</code> attribute containing function to be called when the radio group state is changed.</li> </ul> <p>All actions or groups can be added by an array part of <code>Gtk.ActionGroup</code> constructor, as demonstrated by following example:</p> <pre><code>local group = Gtk.ActionGroup { Gtk.Action { name = 'new', label = "_New" }, { Gtk.Action { name = 'open', label = "_Open" }, accelerator = '<control>O' }, { Gtk.RadioAction { name = 'simple', label = "_Simple", value = 1 }, { Gtk.RadioAction { name = 'complex', label = "_Complex", value = 2 }, accelerator = '<control>C' }, on_change = function(action) print("Changed to: ", action.name) end }, } </code></pre> <p>To access specific action from the group, a read-only attribute <code>action</code> is added to the group, which allows to be indexed by action name to retrieve. So continuing the example above, we can implement 'new' action like this:</p> <pre><code>function group.action.new:on_activate() print("Action 'New' invoked") end </code></pre> <h2>Gtk.TextTagTable</h2> <p>It is possible to populate new instance of the tag table with tags during the construction, an array part of constructor argument table is expected to contain <code>Gtk.TextTag</code> instances which are then automatically added to the table.</p> <p>A new attribute <code>tag</code> is added, provides Lua table which can be indexed by string representing tag name and returns the appropriate tag (so it is essentially a wrapper around <code>Gtk.TextTagTable:lookup()</code> method).</p> <p>Following example demonstrates both capabilities:</p> <pre><code>local tag_table = Gtk.TextTagTable { Gtk.TextTag { name = 'plain', color = 'blue' }, Gtk.TextTag { name = 'error', color = 'red' }, } assert(tag_table.tag.plain == tag_table:lookup('plain')) </code></pre> <h2>TreeView and related classes</h2> <p><code>Gtk.TreeView</code> and related classes like <code>Gtk.TreeModel</code> are one of the most complicated objects in the whole <code>Gtk</code>. Lgi adds some overrides to simplify the work with them.</p> <h3>Gtk.TreeModel</h3> <p>Lgi supports direct indexing of treemodel instances by iterators (i.e. <code>Gtk.TreeIter</code> instances). To get value at specified column number, index the resulting value again with column number. Note that although <code>Gtk</code> uses 0-based column numbers, Lgi remaps them to 1-based numbers, because working with 1-based arrays is much more natural for Lua.</p> <p>Another extension provided by Lgi is <code>Gtk.TreeModel:pairs([parent_iter])</code> method for Lua-native iteration of the model. This method returns 3 values suitable to pass to generic <code>for</code>, so that standard Lua iteration protocol can be used. See the example in the next chapter which uses this technique.</p> <h3>Gtk.ListStore and Gtk.TreeStore</h3> <p>Standard <code>Gtk.TreeModel</code> implementations, <code>Gtk.ListStore</code> and <code>Gtk.TreeStore</code> extend the concept of indexing model instance with iterators also to writing values. Indexing resulting value with 1-based column number allows writing individual values, while assigning the table containing column-keyed values allows assigning multiple values at once. Following example illustrates all these techniques:</p> <pre><code>local PersonColumn = { NAME = 1, AGE = 2, EMPLOYEE = 3 } local store = Gtk.ListStore.new { [PersonColumn.NAME] = GObject.Type.STRING, [PersonColumn.AGE] = GObject.Type.INT, [PersonColumn.EMPLOYEE] = GObject.Type.BOOLEAN, } local person = store:append() store[person] = { [PersonColumn.NAME] = "John Doe", [PersonColumn.AGE] = 45, [PersonColumn.EMPLOYEE] = true, } assert(store[person][PersonColumn.AGE] == 45) store[person][PersonColumn.AGE] = 42 assert(store[person][PersonColumn.AGE] == 42) -- Print all persons in the store for i, p in store:pairs() do print(p[PersonColumn.NAME], p[PersonColumn.AGE]) end </code></pre> <p>Note that <code>append</code> and <code>insert</code> methods are overridden and accept additional parameter containing table with column/value pairs, so creation section of previous example can be simplified to:</p> <pre><code>local person = store:append { [PersonColumn.NAME] = "John Doe", [PersonColumn.AGE] = 45, [PersonColumn.EMPLOYEE] = true, } </code></pre> <p>Note that while the example uses <code>Gtk.ListStore</code>, similar overrides are provided also for <code>Gtk.TreeStore</code>.</p> <h3>Gtk.TreeView and Gtk.TreeViewColumn</h3> <p>Lgi provides <code>Gtk.TreeViewColumn:set(cell, data)</code> method, which allows assigning either a set of <code>cell</code> renderer attribute->model column pairs (in case that <code>data</code> argument is a table), or assigns custom data function for specified cell renderer (when <code>data</code> is a function). Note that column must already have assigned cell renderer. See <code>gtk_tree_view_column_set_attributes()</code> and <code>gtk_tree_view_column_set_cell_data_func()</code> for precise documentation.</p> <p>The override <code>Gtk.TreeViewColumn:add(def)</code> composes both adding new cellrenderer and setting attributes or data function. <code>def</code> argument is a table, containing cell renderer instance at index 1 and <code>data</code> at index 2. Optionally, it can also contain <code>expand</code> attribute (set to <code>true</code> or <code>false</code>) and <code>align</code> (set either to <code>start</code> or <code>end</code>). This method is basically combination of <code>gtk_tree_view_column_pack_start()</code> or <code>gtk_tree_view_column_pack_end()</code> and <code>set()</code> override method.</p> <p>Array part of <code>Gtk.TreeViewColumn</code> constructor call is mapped to call <code>Gtk.TreeViewColumn:add()</code> method, and array part of <code>Gtk.TreeView</code> constructor call is mapped to call <code>Gtk.TreeView:append_column()</code>, and this allows composing the whole initialized treeview in a declarative style like in the example below:</p> <pre><code>-- This example reuses 'store' model created in examples in -- Gtk.TreeModel chapter. local view = Gtk.TreeView { model = store, Gtk.TreeViewColumn { title = "Name and age", expand = true, { Gtk.CellRendererText {}, { text = PersonColumn.NAME } }, { Gtk.CellRendererText {}, { text = PersonColumn.AGE } }, }, Gtk.TreeViewColumn { title = "Employee", { Gtk.CellRendererToggle {}, { active = PersonColumn.EMPLOYEE } } }, } </code></pre> </body></html>