Sophie

Sophie

distrib > Fedora > 16 > i386 > by-pkgid > 9a513bb0f515a28c4c982655dfd62387 > files > 7

lua-lgi-0.6.2-5.fc16.i686.rpm

<!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 = '&lt;control&gt;O' },
   {
      Gtk.RadioAction { name = 'simple', label = "_Simple", value = 1 },
      { Gtk.RadioAction { name = 'complex', label = "_Complex",
        value = 2 }, accelerator = '&lt;control&gt;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>