summaryrefslogtreecommitdiff
path: root/lua/astal/widget.lua
blob: ade000eade2d77dabed4341fb8e5e0c0b8a4ea0d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
local lgi = require("lgi")
local Astal = lgi.require("Astal", "0.1")
local Gtk = lgi.require("Gtk", "3.0")
local GObject = lgi.require("GObject", "2.0")
local Binding = require("astal.binding")

local function filter(tbl, fn)
    local copy = {}
    for key, value in pairs(tbl) do
        if fn(value, key) then
            copy[key] = value
        end
    end
    return copy
end

Gtk.Widget._attribute.css = {
    get = Astal.widget_get_css,
    set = Astal.widget_set_css,
}

Gtk.Widget._attribute.class_name = {
    get = function(self)
        local result = ""
        local strings = Astal.widget_set_class_names(self)
        for i, str in ipairs(strings) do
            result = result .. str
            if i < #strings then
                result = result .. " "
            end
        end
        return result
    end,
    set = function(self, class_name)
        local names = {}
        for word in class_name:gmatch("%S+") do
            table.insert(names, word)
        end
        Astal.widget_set_class_names(self, names)
    end,
}

Gtk.Widget._attribute.cursor = {
    get = Astal.widget_get_cursor,
    set = Astal.widget_set_cursor,
}

Astal.Box._attribute.children = {
    get = Astal.Box.get_children,
    set = Astal.Box.set_children,
}

local function astalify(ctor)
    function ctor:hook(object, signalOrCallback, callback)
        if type(object.subscribe) == "function" then
            local unsub = object.subscribe(function(...)
                signalOrCallback(self, ...)
            end)
            self.on_destroy = unsub
            return
        end
        local id = object["on_" .. signalOrCallback](function(_, ...)
            callback(self, ...)
        end)
        self.on_destroy = function()
            GObject.signal_handler_disconnect(object, id)
        end
    end

    return function(tbl)
        local bindings = {}
        local setup = tbl.setup

        local visible
        if type(tbl.visible) == "boolean" then
            visible = tbl.visible
        else
            visible = true
        end

        local props = filter(tbl, function(_, key)
            return key ~= "visible" and key ~= "setup"
        end)

        for prop, value in pairs(props) do
            if getmetatable(value) == Binding then
                bindings[prop] = value
                props[prop] = value:get()
            end
        end

        local widget = ctor(props)

        for prop, binding in pairs(bindings) do
            widget.on_destroy = binding:subscribe(function(v)
                widget[prop] = v
            end)
        end

        widget.visible = visible
        if type(setup) == "function" then
            setup(widget)
        end
        return widget
    end
end

local Widget = {
    astalify = astalify,
    Box = astalify(Astal.Box),
    Button = astalify(Astal.Button),
    CenterBox = astalify(Astal.CenterBox),
    Label = astalify(Gtk.Label),
    Icon = astalify(Astal.Icon),
    Window = astalify(Astal.Window),
    EventBox = astalify(Astal.EventBox),
}

return setmetatable(Widget, {
    __call = function(_, ctor)
        return astalify(ctor)
    end,
})