Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/install_deps.bash
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
set -x
sudo apt-get update -qq
sudo apt-get install -y libgirepository1.0-dev libgirepository-2.0-dev libcairo2-dev gir1.2-gtk-4.0 libffi-dev libglib2.0-dev
sudo apt-get install -y libgirepository1.0-dev libgirepository-2.0-dev libcairo2-dev gir1.2-gtk-4.0 gir1.2-adw-1 libffi-dev libglib2.0-dev
sudo apt-get install -y xvfb dbus-x11 at-spi2-core
78 changes: 64 additions & 14 deletions LuaGObject/override/Adw.lua
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,72 @@ local log = LuaGObject.log.domain "LuaGObject.Adw"

-- Constructor container support --

Adw.Carousel._container_add = Adw.Carousel.append
Adw.PreferencesDialog._container_add = Adw.PreferencesDialog._method.add
Adw.PreferencesPage._container_add = Adw.PreferencesPage._method.add
Adw.PreferencesGroup._container_add = Adw.PreferencesGroup._method.add
Adw.ExpanderRow._container_add = Adw.ExpanderRow.add_row

-- These classes were introduced in later versions of Adw, and thus may not always be available.
-- Introduced in Adw 1.7
if Adw.WrapBox then
Adw.WrapBox._container_add = Adw.WrapBox._method.append
end

--Introduced in Adw 1.8
if Adw.ShortcutsDialog then
Adw.ShortcutsDialog._container_add = Adw.ShortcutsDialog.add
end
if Adw.ShortcutsSection then
Adw.ShortcutsSection._container_add = Adw.ShortcutsSection.add
end

-- Adw.TabView overrides --

function Adw.TabView:_container_add(child)
if Gtk.Widget:is_type_of(child) then
child = { child }
end
if type(child) ~= "table" then
error("%s: Child must be table or GTK Widget", self._type.name)
end
if #child ~= 1 or not Gtk.Widget:is_type_of(child[1]) then
error("%s: Child must contain only a single GTK Widget.", self._type.name)
end
local page
if child.pinned then
page = self:append_pinned(child[1])
else
page = self:append(child[1])
end
if type(child.title) == "string" then
page.title = child.title
end
end

-- Adw.ViewStack overrides --

function Adw.ViewStack:_container_add(child)
if Gtk.Widget:is_type_of(child) then
child = { child }
end
if type(child) ~= "table" then
error("%s: Child must be table or GTK Widget", self._type.name)
end
if #child ~= 1 or not Gtk.Widget:is_type_of(child[1]) then
error("%s: Child table must contain one GTK Widget.", self._type.name)
end
if type(child.icon_name) == "string" and type(child.title) == "string" and type(child.name) == "string" then
self:add_titled_with_icon(child[1], child.name, child.title, child.icon_name)
elseif type(child.title) == "string" and type(child.name) == "string" then
self:add_titled(child[1], child.name, child.title)
elseif type(child.name) == "string" then
self:add_named(child[1], child.name)
else
self:add(child[1])
end
end

-- Adw.ActionRow overrides --

Adw.ActionRow._attribute = {
Expand All @@ -34,29 +84,29 @@ Adw.ActionRow._attribute = {
}

function Adw.ActionRow._attribute.prefixes:get()
error("%s: Cannot read prefixes; attribute is write-only.", self.type.name)
error("%s: Cannot read prefixes; attribute is write-only.", self._type.name)
end
function Adw.ActionRow._attribute.prefixes:set(value)
if Gtk.Widget:is_type_of(value) then
value = { value }
end
if type(value) ~= "table" then
error("%s: Can only write table or Gtk.Widget to add_prefixes.", self.type.name)
error("%s: Can only write table or Gtk.Widget to add_prefixes.", self._type.name)
end
for _, c in ipairs(value) do
self:add_prefix(c)
end
end

function Adw.ActionRow._attribute.suffixes:get()
error("%s: Cannot read suffixes; attribute is write-only.", self.type.name)
error("%s: Cannot read suffixes; attribute is write-only.", self._type.name)
end
function Adw.ActionRow._attribute.suffixes:set(value)
if Gtk.Widget:is_type_of(value) then
value = { value }
end
if type(value) ~= "table" then
error("%s: Can only write table or Widget to add_suffixes.", self.type.name)
error("%s: Can only write table or Widget to add_suffixes.", self._type.name)
end
for _, v in ipairs(value) do
self:add_suffix(v)
Expand All @@ -71,29 +121,29 @@ Adw.HeaderBar._attribute = {
}

function Adw.HeaderBar._attribute.end_packs:get()
error("%s: Cannot read end_packs; attribute is write-only.", self.type.name)
error("%s: Cannot read end_packs; attribute is write-only.", self._type.name)
end
function Adw.HeaderBar._attribute.end_packs:set(value)
if Gtk.Widget:is_type_of(value) then
value = { value }
end
if type(value) ~= "table" then
error("%s: Can only write table or Widget to end_packs.", self.type.name)
error("%s: Can only write table or Widget to end_packs.", self._type.name)
end
for _, v in ipairs(value) do
self:pack_end(v)
end
end

function Adw.HeaderBar._attribute.start_packs:get()
error("%s: Cannot read start_packs; attribute is write-only.", self.type.name)
error("%s: Cannot read start_packs; attribute is write-only.", self._type.name)
end
function Adw.HeaderBar._attribute.start_packs:set(value)
if Gtk.Widget:is_type_of(widget) then
if Gtk.Widget:is_type_of(value) then
value = { value }
end
if type(value) ~= "table" then
error("%s: Can only write table or Widget to start_packs.", self.type.name)
error("%s: Can only write table or Widget to start_packs.", self._type.name)
end
for _, v in ipairs(value) do
self:pack_start(v)
Expand All @@ -102,37 +152,37 @@ end

-- Adw.ToolbarView overrides --

-- Adw.ToolbarView was introduced in Adw 1.4, and may not be available.
-- Adw.ToolbarView was introduced in Adw 1.4. It should only be overridden if it exists.
if Adw.ToolbarView then
Adw.ToolbarView._attribute = {
bottom_bars = {},
top_bars = {},
}

function Adw.ToolbarView._attribute.bottom_bars:get()
error("%s: Cannot read bottom_bars; attribute is write-only.", self.type.name)
error("%s: Cannot read bottom_bars; attribute is write-only.", self._type.name)
end
function Adw.ToolbarView._attribute.bottom_bars:set(value)
if Gtk.Widget:is_type_of(value) then
value = { value }
end
if type(value) ~= "table" then
error("%s: Can only write table or Gtk.Widget to add_bottom_bars.", self.type.name)
error("%s: Can only write table or Gtk.Widget to add_bottom_bars.", self._type.name)
end
for _, v in ipairs(values) do
self:add_bottom_bar(v)
end
end

function Adw.ToolbarView._attribute.top_bars:get()
error("%s: Cannot read top_bars; attribute is write-only.", self.type.name)
error("%s: Cannot read top_bars; attribute is write-only.", self._type.name)
end
function Adw.ToolbarView._attribute.top_bars:set(value)
if Gtk.Widget:is_type_of(value) then
value = { value }
end
if type(value) ~= "table" then
error("%s: Can only write table or Gtk.Widget to add_top_bars.", self.type.name)
error("%s: Can only write table or Gtk.Widget to add_top_bars.", self._type.name)
end
for _, v in ipairs(value) do
self:add_top_bar(v)
Expand Down
2 changes: 2 additions & 0 deletions LuaGObject/override/Gtk3.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ local cairo = LuaGObject.cairo

local log = LuaGObject.log.domain('LuaGObject.Gtk3')

assert(Gtk.get_major_version() <= 3)

-- Initialize GTK.
Gtk.disable_setlocale()
if not Gtk.init_check() then
Expand Down
42 changes: 41 additions & 1 deletion LuaGObject/override/Gtk4.lua
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,49 @@ function Gtk.Widget._attribute.children:get()
return setmetatable({ _widget = self }, widget_children_mt)
end

-- Constructor container support --
-- Simple container support --

Gtk.Box._container_add = Gtk.Box._method.append
Gtk.FlowBox._container_add = Gtk.FlowBox._method.append
Gtk.ListBox._container_add = Gtk.ListBox._method.append
Gtk.Stack._container_add = Gtk.Stack._method.add_child

-- Gtk.Grid container support --

function Gtk.Grid:_container_add(child)
if type(child) ~= "table" then
error("%s: Cannot add non-table child from constructor.", self._type.name)
end
if type(child.column) ~= "number" or type(child.row) ~= "number" then
error("%s: Child column and/or row are unspecified.", self._type.name)
end
if #child ~= 1 or not Gtk.Widget:is_type_of(child[1]) then
error("%s: Child table must contain only one widget.", self._type.name)
end
local column = child.column
local row = child.row
local width = child.width or 1
local height = child.height or 1
self:attach(child[1], column, row, width, height)
end

-- Gtk.Notebook container support --

function Gtk.Notebook:_container_add(child)
if type(child) ~= "table" then
error("%s: Cannot add non-table child from constructor.", self._type.name)
end
if type(child.tab_label) == "string" then
child.tab_label = Gtk.Label { label = child.tab_label }
elseif not Gtk.Widget:is_type_of(child.tab_label) then
error("%s: Child label is not a GTK Widget.", self._type.name)
end
if #child ~= 1 or not Gtk.Widget:is_type_of(child[1]) then
error("%s: Child table must have only one widget.", self._type.name)
end
if Gtk.Widget:is_type_of(child.menu_label) then
self:append_page_menu(child[1], child.tab_label, child.menu_label)
else
self:append_page(child[1], child.tab_label)
end
end
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
VERSION = 0.10.0
MAKE ?= make

ROCK = LuaGObject-$(VERSION)-1.rockspec
ROCK = luagobject-$(VERSION)-1.rockspec

.PHONY : rock all clean install check

Expand Down
74 changes: 74 additions & 0 deletions docs/gtk.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ GTK 4 gets rid of the Container class, making it somewhat more complicated to in
- `Gtk.FlowBox`
- `Gtk.ListBox`
- `Gtk.Stack`
- `Gtk.Notebook`
- `Gtk.Grid`

An example of instantiating a `Gtk.Box` with its own children:

Expand All @@ -62,6 +64,48 @@ An example of instantiating a `Gtk.Box` with its own children:

This creates a `Gtk.Box` containing four children. Note that `box`'s `orientation` property was set to `Gtk.Orientation.VERTICAL` as well in the same constructor. For specific container widgets, this creates a programmer experience not unlike using `Gtk.Builder` for creating widget hierarchies, but with a syntax ressembling Blueprint.

### `Gtk.Notebook` Children

To construct an instance of `Gtk.Notebook` with children, special consideration must be undertaken. Adding children to this widget requires a label to be provided. Additionally, an optional menu may be provided as well. To do this, each child in the constructor must be a table with a GTK widget in the first slot, a `.tab_label` item with a child widget, and optionally a `.menu_label` item with a child widget.

local notebook = Gtk.Notebook {
{
Gtk.TextView(),
tab_label = Gtk.Label { label = "Tab 1" },
},
{
Gtk.ScrolledWindow(),
tab_label = Gtk.Label { label = "Tab 2" },
menu_label = Gtk.MenuButton(),
},
}

This example creates a `Gtk.Notebook` containing two tabs, labelled "Tab 1" and "Tab 2". Tab 2 also has a menu widget.

For convenience, this override also allows a child's `.tab_label` item to be a string. In this case, LuaGObject automatically wraps this into a `Gtk.Label` with the `.label` property set the given value. Thus, the previous example can be rewritten as:

local notebook = Gtk.Notebook {
{ Gtk.TextView(), tab_label = "Tab 1" },
{
Gtk.ScrolledWindow(),
tab_label = "Tab 2",
menu = Gtk.MenuButton(),
},
}

### `Gtk.Grid` Children

Like with `Gtk.Notebook`, the `Gtk.Grid` class also requires special consideration when adding children in its constructor. Each child added this way must be a table containing a widget in the array part, as well as integer values for `.column` and `.row`. A `.width` and/or `.height` may optionally be specified, and both will default to 1 if not given.

local grid = Gtk.Grid {
{ Gtk.Button.new_with_label "1, 1", column = 1, row = 1 },
{ Gtk.Button.new_with_label "2, 1", column = 2, row = 1 },
{
Gtk.Button.new_with_label "1–2, 2 (spans two columns)",
column = 1, row = 2, width = 2,
},
}

### Advanced Example: Removing Children

Many container widgets implement a `:remove()` method which takes a child `Gtk.Widget` as its argument. Without the GTK 4 override, removing a child in this way can be somewhat tricky—one may need to call a function like `:get_child_at_index()`, including adjusting the index to account for 0-indexing.
Expand Down Expand Up @@ -89,6 +133,7 @@ Certain classes only exist in later versions of libadwaita. These version requir

Like `Gtk.Box` and related classes, LuaGObject overrides certain Adw classes to allow specifying children to be added in constructor tables. The following widgets are supported:

- `Adw.Carousel`
- `Adw.PreferencesDialog`
- Must only contain `Adw.PreferencesPage` children.
- `Adw.PreferencesPage`
Expand All @@ -100,6 +145,8 @@ Like `Gtk.Box` and related classes, LuaGObject overrides certain Adw classes to
- Must only contain `Adw.ShortcutsSection` children.
- `Adw.ShortcutsSection` (Adw 1.8 and later)
- Must only contain `Adw.ShortcutsItem` children.
- `Adw.TabView`
- `Adw.ViewStack`

As with GTK 4, these constructors may be nested. Here is a more complex example involving the creation of a preferences page:

Expand All @@ -119,6 +166,33 @@ As with GTK 4, these constructors may be nested. Here is a more complex example
},
}

### `Adw.TabView` Constructor Children

Like with other container widgets, `Adw.TabView` can accept an arbitrary number of child widgets in the constructor table's array part. Additionally, it can also accept an arbitrary number of tables, each containing one widget in the array part and optionally also a value at `.pinned`, which will add the child widget as a pinned tab, and `.title` which is a string to be used as the tab's title. This example illustrates multiple ways to add children to a Tab View:

local tabview = Adw.TabView {
Gtk.TextView(), -- Title will be left blank
{ Gtk.TextView(), title = "Tab 2" },
{ Gtk.TextView(), title = "Tab 3", pinned = true },
}

### `Adw.ViewStack` Constructor Children

As with `Adw.TabView`, `Adw.ViewStack` children may be included in the constructor table directly, or wrapped in tables with certain additional members. These are `.name`, `.title`, and `.icon_name`. For `.title`, a `.name` must be set or it won't be used. For `.icon_name`, both a `.title` and a `.name` must be set as well. For a complete example of all ways to add children to `Adw.ViewStack` in the constructor:

local viewstack = Adw.ViewStack {
Gtk.TextView(),
{ Gtk.TextView() },
{ Gtk.TextView(), name = "Name" },
{ Gtk.TextView(), name = "Name", title = "Title" },
{
Gtk.TextView(),
name = "Name",
title = "Title",
icon_name = "icon-name",
},
}

## Constructing with Supplemental Widgets

Certain Adw classes have multiple different kinds of child widgets, preventing them from being arbitrarily added like with other container-type widgets. Widgets that work this way usually do so to distinguish between children coming before, and after, the main widget body. Each class supporting this pattern does so using class-specific methods. LuaGObject provides pseudo-properties for specific classes allowing these kinds of children to be added at construction time. Each pseudo-property is write-only and takes a value of either a single widget or a table array of widgets. Currently, these classes are:
Expand Down
Loading
Loading