Skip to content

Commit

Permalink
parameters argument for GSimpleAction, add_action, add_stateful_action (
Browse files Browse the repository at this point in the history
#51)

* allow parameter to be set in "add action" methods

* add tests, add GVariant support for tuples

* only check tuple length if the GI method works
  • Loading branch information
jwahlstrand authored Jan 29, 2024
1 parent 2c7132c commit d9771de
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 34 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "Gtk4"
uuid = "9db2cae5-386f-4011-9d63-a5602296539b"
version = "0.6.0"
version = "0.6.1"

[deps]
BitFlags = "d1d4a3ce-64b1-5f1a-9ba4-7e7e69966f35"
Expand Down
66 changes: 55 additions & 11 deletions src/GLib/actions.jl
Original file line number Diff line number Diff line change
@@ -1,43 +1,87 @@
# actions
GSimpleAction(name::AbstractString; kwargs...) = GSimpleAction(name, nothing; kwargs...)

function GSimpleAction(name::AbstractString, parameter::Type{T}; kwargs...) where T
pvtype = parameter == Nothing ? nothing : GVariantType(parameter)
GSimpleAction(name, pvtype)
end

"""
GSimpleAction(name::AbstractString,
[parameter_type::Type{T}, [initial_state]]; kwargs...) where T
Create an action with a `name` and optionally a `parameter_type` from a Julia
type (only a few simple types are supported) and an `initial_state`. If
`initial_state` is not provided, the action will be stateless.
Keyword arguments set the action's GObject properties.
"""
function GSimpleAction(name::AbstractString, parameter::Type{T},
initial_state; kwargs...) where T
pvtype = parameter == Nothing ? nothing : GVariantType(parameter)
GSimpleAction(name, pvtype, GVariant(initial_state))
end

set_state(m::GSimpleAction, v::GVariant) = G_.set_state(m,v)

# action maps
push!(m::GActionMap, a::GAction) = (G_.add_action(m,a); m)
delete!(m::GActionMap, a::AbstractString) = (G_.remove_action(m, a); m)

function add_action(m::GActionMap, name::AbstractString, handler::Function)
action = GSimpleAction(name)
push!(m,GAction(action))
function add_action(m::GActionMap, name::AbstractString,
parameter::Type{T}, handler::Function) where T
action = GSimpleAction(name, parameter)
push!(m, GAction(action))
signal_connect(handler, action, :activate)
action
end

function add_action(m::GActionMap, name::AbstractString, cb, user_data)
action = GSimpleAction(name)
function add_action(m::GActionMap, name::AbstractString, handler::Function)
add_action(m, name, Nothing, handler)
end

function add_action(m::GActionMap, name::AbstractString,
parameter::Type{T}, cb, user_data) where T
action = GSimpleAction(name, parameter)
push!(m,GAction(action))
signal_connect(cb, action, :activate, Nothing,
(Ptr{GVariant},), false, user_data)
action
end

function add_stateful_action(m::GActionMap, name::AbstractString, initial_state,
handler::Function)
action = GSimpleAction(name, nothing, GVariant(initial_state))
push!(m,GAction(action))
function add_action(m::GActionMap, name::AbstractString, cb, user_data)
add_action(m, name, Nothing, cb, user_data)
end

function add_stateful_action(m::GActionMap, name::AbstractString,
parameter::Type{T}, initial_state,
handler::Function) where T
action = GSimpleAction(name, parameter, initial_state)
push!(m, GAction(action))
signal_connect(handler, action, :change_state)
action
end

function add_stateful_action(m::GActionMap, name::AbstractString, initial_state,
cb, user_data)
action = GSimpleAction(name, nothing, GVariant(initial_state))
handler::Function)
add_stateful_action(m, name, Nothing, initial_state, handler)
end

function add_stateful_action(m::GActionMap, name::AbstractString,
parameter::Type{T}, initial_state,
cb, user_data) where T
action = GSimpleAction(name, parameter, initial_state)
push!(m,GAction(action))
signal_connect(cb, action, :change_state, Nothing,
(Ptr{GVariant},), false, user_data)
action
end

function add_stateful_action(m::GActionMap, name::AbstractString, initial_state,
cb, user_data)
add_stateful_action(m, name, Nothing, initial_state, cb, user_data)
end

# action groups
push!(g::GSimpleActionGroup, a) = (push!(GActionMap(g), GAction(a)); g)
delete!(g::GSimpleActionGroup, a::AbstractString) = (delete!(GActionMap(g), a); g)
Expand Down
58 changes: 36 additions & 22 deletions src/GLib/gvariant.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,21 @@ let variant_fns = Expr(:block)
Core.eval(GLib, variant_fns)
end

# tuples
function GVariant(x::T) where T <: Tuple
vs = [GVariant(xi).handle for xi in x]
G_.Variant_new_tuple(vs)
end
function getindex(gv::GVariant, ::Type{T}) where T <: Tuple
t=fieldtypes(T)
if Sys.WORD_SIZE == 64 # GI method doesn't work on 32 bit CPU's -- should probably wrap the ccall by hand instead of this
n = G_.n_children(gv)
@assert n == length(t)
end
vs = [G_.get_child_value(gv, i-1)[t[i]] for i=1:length(t)]
tuple(vs...)
end

GVariant(::Type{T},x) where T = GVariant(convert(T, x))

Base.:(==)(lhs::GVariant, rhs::GVariant) = G_.equal(lhs,rhs)
Expand All @@ -20,34 +35,33 @@ Base.:(<=)(lhs::GVariant, rhs::GVariant) = G_.compare(lhs, rhs) <= 0
Base.:(>)(lhs::GVariant, rhs::GVariant) = G_.compare(lhs, rhs) > 0
Base.:(>=)(lhs::GVariant, rhs::GVariant) = G_.compare(lhs, rhs) >= 0

variant_type_string(::Type{Bool}) = "b"
variant_type_string(::Type{UInt8}) = "y"
variant_type_string(::Type{Int16}) = "n"
variant_type_string(::Type{UInt16}) = "q"
variant_type_string(::Type{Int32}) = "i"
variant_type_string(::Type{UInt32}) = "u"
variant_type_string(::Type{Int64}) = "x"
variant_type_string(::Type{UInt64}) = "t"
variant_type_string(::Type{Float64}) = "d"
variant_type_string(::Type{String}) = "s"
function variant_type_string(::Type{T}) where T <: Tuple
type_string = "("
for t in fieldtypes(T)
type_string *= variant_type_string(t)
end
type_string *= ")"
end

function variant_type_string(::Type{T}) where T
type_string = ""
if T == Bool
type_string = "b"
elseif T == UInt8
type_string = "y"
elseif T == Int16
type_string = "n"
elseif T == UInt16
type_string = "q"
elseif T == Int32
type_string = "i"
elseif T == UInt32
type_string = "u"
elseif T == Int64
type_string = "x"
elseif T == UInt64
type_string = "t"
elseif T == Float64
type_string = "d"
elseif T == String
type_string = "s"
elseif T == Any
if T == Any
type_string = "*"
else
error("Type not implemented")
end
# TODO:
# array
# tuple
# maybe
# dictionary
type_string
Expand Down
8 changes: 8 additions & 0 deletions test/action-group.jl
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ function cb(ac,va)
end

add_action(GActionMap(g), "new-action", cb)
add_action(GActionMap(g), "new-action-with-parameter", Bool, cb)

end

Expand Down Expand Up @@ -153,6 +154,8 @@ a5 = add_stateful_action(GActionMap(g), "new-action3", true, cb)
GLib.set_state(a5, GVariant(false))
@test a5.state == GVariant(false)

a5 = add_stateful_action(GActionMap(g), "new-action3-par", Bool, true, cb)

end

@testset "add stateful action cfunction" begin
Expand Down Expand Up @@ -219,4 +222,9 @@ gv2 = GLib.GVariant(UInt8,2)
@test gv2 > gv1
@test gv2 >= gv1

# test tuples
gvt = GLib.GVariant((true,3,6.5))
@test GLib.GVariantType(Tuple{Bool,Int,Float64}) == GLib.G_.get_type(gvt)
@test gvt[Tuple{Bool,Int,Float64}] == (true,3,6.5)

end

0 comments on commit d9771de

Please sign in to comment.