-
Notifications
You must be signed in to change notification settings - Fork 2
/
cairo.jl
133 lines (110 loc) · 4.06 KB
/
cairo.jl
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
124
125
126
127
128
129
130
131
132
133
import Cairo: CairoSurface, CairoContext, CairoARGBSurface
using Cairo_jll
function _canvas_draw_backing_store(w, cr, width, height, user_data) # cr is a Cairo context, user_data is a Cairo surface
user_data==C_NULL && return
ccall((:cairo_set_source_surface, libcairo), Nothing,
(Ptr{Nothing}, Ptr{Nothing}, Float64, Float64), cr, user_data, 0, 0)
ccall((:cairo_paint, libcairo), Nothing, (Ptr{Nothing},), cr)
end
function _init_canvas!(widget, w, h)
widget.back = CairoARGBSurface(w, h)
widget.backcc = CairoContext(widget.back)
end
function _canvas_on_realize(::Ptr, canvas)
canvas.is_sized && _canvas_on_resize(da,1,1)
nothing
end
function _canvas_on_resize(::Ptr, width, height, canvas)
canvas.is_sized = true
if G_.get_realized(canvas)
_init_canvas!(canvas, width, height)
if isa(canvas.resize, Function)
canvas.resize(canvas)
end
draw_back = @cfunction(_canvas_draw_backing_store, Nothing, (Ptr{GObject}, Ptr{Nothing}, Cint, Cint, Ptr{Nothing}))
ccall((:gtk_drawing_area_set_draw_func, libgtk4), Nothing, (Ptr{GObject}, Ptr{Nothing}, Ptr{Nothing}, Ptr{Nothing}), getfield(canvas,:handle), draw_back, canvas.back.ptr, C_NULL)
draw(canvas)
end
nothing
end
"""
GtkCanvas(w = -1, h = -1, init_back = false; kwargs...)
Create a `GtkCanvas` widget for drawing using Cairo (based on
`GtkDrawingArea`). Optional arguments `w` and `h` can be used to set the
minimum width and height of the drawing area in pixels. If `init_back` is set
to true, the canvas's image CairoSurface will be initialized immediately, which
is useful for precompilation.
Keyword arguments can be used to set properties of the `GtkDrawingArea` widget.
"""
mutable struct GtkCanvas <: GtkDrawingArea # NOT a GType
handle::Ptr{GObject}
is_sized::Bool
resize::Union{Function, Nothing}
draw::Union{Function, Nothing}
back::CairoSurface # backing store
backcc::CairoContext
function GtkCanvas(w = -1, h = -1, init_back = false; kwargs...)
da = GtkDrawingArea(; kwargs...)
if w > 0 && h > 0
G_.set_content_height(da, h)
G_.set_content_width(da, w)
elseif init_back
error("Width and height arguments must be provided to immediately initialize GtkCanvas.")
end
widget = new(getfield(da,:handle), false, nothing, nothing)
if init_back
_init_canvas!(widget, w, h)
end
widget = GLib.gobject_move_ref(widget, da)
signal_connect(Base.inferencebarrier(_canvas_on_realize), widget, "realize", Nothing, (), false, widget)
signal_connect(Base.inferencebarrier(_canvas_on_resize), widget, "resize", Nothing, (Cint, Cint), false, widget)
return widget
end
end
const GtkCanvasLeaf = GtkCanvas
function resize(config::Function, widget::GtkCanvas)
widget.resize = config
if G_.get_realized(widget) && widget.is_sized
widget.resize(widget)
draw(widget)
end
nothing
end
"""
draw(redraw::Function, widget::GtkCanvas)
Set a function `redraw` to be called whenever the `GtkCanvas`'s `CairoSurface`
needs to be redrawn. The function should have a single argument, the
`GtkCanvas`, from which the `CairoSurface` can be retrieved using
[`getgc`](@ref).
"""
function draw(redraw::Function, widget::GtkCanvas)
widget.draw = redraw
draw(widget)
nothing
end
function draw(widget::GtkCanvas)
if !isdefined(widget, :back)
#@warn("backing store not defined")
return
end
if isa(widget.draw, Function)
widget.draw(widget)
end
G_.queue_draw(widget)
end
"""
getgc(c::GtkCanvas)
Return the CairoContext of the `CairoSurface` backing store of a `GtkCanvas`.
"""
function getgc(c::GtkCanvas)
isdefined(c,:backcc) || error("GtkCanvas not yet initialized.")
return c.backcc
end
"""
cairo_surface(c::GtkCanvas)
Return the image `CairoSurface` backing store for a `GtkCanvas`.
"""
function cairo_surface(c::GtkCanvas)
isdefined(c,:back) || error("GtkCanvas not yet initialized.")
return c.back
end