added cairo_anim.nim example
This commit is contained in:
parent
765ecaf9cc
commit
b0c8857651
5 changed files with 1567 additions and 26 deletions
62
README.adoc
62
README.adoc
|
|
@ -642,5 +642,67 @@ code you may catch such exceptions with Nim's `try:` blocks. (You may also modif
|
|||
an illegal CSS statement -- if the statement is seriously wrong, then you should get an exception from
|
||||
loadFromData().
|
||||
|
||||
== Drawing with Cairo graphics library
|
||||
|
||||
The next example shows how we can use the cairo graphics library for drawing on a DrawingArea widget,
|
||||
and at the same time uses glib timeoutAdd() function to create a timer which periodically calls the
|
||||
drawing function to create some animations. The code is based on a recent post to the cairo mailing list
|
||||
and shows a sine wave which is continuously moving to the left.
|
||||
|
||||
NOTE: The gobject-introspection generated cairo module was only a minimal stub, because cairo
|
||||
library does not really support introspection. Now we are using a cairo module which is generated
|
||||
directly from the cairo C header files with the tool c2nim and then modified to support an high level
|
||||
API. That modification is still work in progress, so not all cairo functionality is available already.
|
||||
|
||||
[[cairo_anim.nim]]
|
||||
[source,nim]
|
||||
.cairo_anim.nim
|
||||
----
|
||||
# nim c cairo_anim.nim
|
||||
# https://lists.cairographics.org/archives/cairo/2016-October/027791.html
|
||||
# Nim version of that plain cairo animation example
|
||||
|
||||
import gintro/[gtk, glib, gobject, gio, cairo]
|
||||
import math
|
||||
|
||||
const
|
||||
NumPoints = 1000
|
||||
Period = 100.0
|
||||
|
||||
proc invalidateCb(w: Widget): bool =
|
||||
queueDraw(w)
|
||||
return SOURCE_CONTINUE
|
||||
|
||||
proc sineToPoint(x, width, height: int): float =
|
||||
math.sin(x.float * math.TAU / Period) * height.float * 0.5 + height.float * 0.5
|
||||
|
||||
proc drawingAreaDrawCb(widget: DrawingArea; context: Context): bool =
|
||||
var redrawNumber {.global.} : int
|
||||
let width = getAllocatedWidth(widget)
|
||||
let height = getAllocatedHeight(widget)
|
||||
for i in 1 .. < NumPoints:
|
||||
context.lineTo(i.float , sineToPoint(i + redrawNumber, width, height))
|
||||
context.stroke
|
||||
inc(redrawNumber)
|
||||
return true # TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
|
||||
|
||||
proc activate(app: Application) =
|
||||
let window = newApplicationWindow(app)
|
||||
window.title = "Drawing example"
|
||||
window.defaultSize = (400, 400)
|
||||
let drawingArea = newDrawingArea()
|
||||
window.add(drawingArea)
|
||||
showAll(window)
|
||||
discard timeoutAdd(1000 div 60, invalidateCb, drawingArea)
|
||||
connect(drawingArea, "draw", drawingAreaDrawCb)
|
||||
|
||||
proc main =
|
||||
let app = newApplication("org.gtk.example")
|
||||
connect(app, "activate", activate)
|
||||
discard run(app)
|
||||
|
||||
main()
|
||||
----
|
||||
|
||||
NOTE: Related work: https://github.com/jdmansour/nim-smartgi
|
||||
|
||||
|
|
|
|||
44
examples/cairo_anim.nim
Normal file
44
examples/cairo_anim.nim
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
# https://lists.cairographics.org/archives/cairo/2016-October/027791.html
|
||||
# Nim version of that plain cairo animation example
|
||||
|
||||
import gintro/[gtk, glib, gobject, gio, cairo]
|
||||
import math
|
||||
|
||||
const
|
||||
NumPoints = 1000
|
||||
Period = 100.0
|
||||
|
||||
proc invalidateCb(w: Widget): bool =
|
||||
queueDraw(w)
|
||||
return SOURCE_CONTINUE
|
||||
|
||||
proc sineToPoint(x, width, height: int): float =
|
||||
math.sin(x.float * math.TAU / Period) * height.float * 0.5 + height.float * 0.5
|
||||
|
||||
proc drawingAreaDrawCb(widget: DrawingArea; context: Context): bool =
|
||||
var redrawNumber {.global.} : int
|
||||
let width = getAllocatedWidth(widget)
|
||||
let height = getAllocatedHeight(widget)
|
||||
for i in 1 .. < NumPoints:
|
||||
context.lineTo(i.float , sineToPoint(i + redrawNumber, width, height))
|
||||
context.stroke
|
||||
inc(redrawNumber)
|
||||
return true # TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
|
||||
|
||||
proc activate(app: Application) =
|
||||
let window = newApplicationWindow(app)
|
||||
window.title = "Drawing example"
|
||||
window.defaultSize = (400, 400)
|
||||
let drawingArea = newDrawingArea()
|
||||
window.add(drawingArea)
|
||||
showAll(window)
|
||||
discard timeoutAdd(1000 div 60, invalidateCb, drawingArea)
|
||||
connect(drawingArea, "draw", drawingAreaDrawCb)
|
||||
|
||||
proc main =
|
||||
let app = newApplication("org.gtk.example")
|
||||
connect(app, "activate", activate)
|
||||
discard run(app)
|
||||
|
||||
main()
|
||||
|
||||
|
|
@ -26,14 +26,12 @@ proc findSignal(name, obj: NimNode): string =
|
|||
n = getType(n)[1]
|
||||
|
||||
var ProcID: int
|
||||
|
||||
macro mconnect(widget: gobject.Object; signal: string; p: untyped; arg: typed; ignoreArg: bool): typed =
|
||||
#
|
||||
macro mconnect(widget: gobject.Object; signal: string; p: untyped; arg: typed; ignoreArg: bool): untyped =
|
||||
inc(ProcID)
|
||||
let wt = getType(widget)
|
||||
#echo "@@@", $(getTypeInst(widget).toStrLit)
|
||||
let at = getTypeInst(arg)
|
||||
let wts = ($(wt[1].toStrLit)).replace(":ObjectType")
|
||||
#echo wts
|
||||
let ats = $at.toStrLit
|
||||
let signalName = ($signal).replace("-", "_") # maybe we should just use plain proc names
|
||||
let procNameCdecl = "connect_for_signal_cdecl_" & signalName & $ProcID
|
||||
|
|
@ -53,14 +51,12 @@ proc $1$2 {.cdecl.} =
|
|||
r1s.add(")\n")
|
||||
else:
|
||||
(sn, wid, num, ahl, all) = sci.split("|")
|
||||
#echo ahl, all
|
||||
var resl: string
|
||||
if ahl.contains("): "):
|
||||
resl = all.rsplit("): ", 1)[1]
|
||||
var resu = " $3(cast[$4](h)"
|
||||
if all.find(";") > 0:
|
||||
var largs = all.split("; ")
|
||||
#if largs.len > 0:
|
||||
largs.delete(0)
|
||||
largs[^1] = largs[^1].split(")")[0]
|
||||
var names, types: array[10, string]
|
||||
|
|
@ -76,7 +72,6 @@ proc $1$2 {.cdecl.} =
|
|||
if h.len > 0:
|
||||
a1 = h & "(" & a1 & ")"
|
||||
plainArgs.add(a1)
|
||||
#var resu = " $3(cast[$4](h)"
|
||||
for i in 0 .. 9:
|
||||
if names[i].isNil: break
|
||||
resu.add(", " & names[i] & "1")
|
||||
|
|
@ -93,27 +88,23 @@ proc $1$2 {.cdecl.} =
|
|||
r1s.add(resu & "\n")
|
||||
all = all.replace(")", "; data: pointer)")
|
||||
r1s = r1s % [$procNameCdecl, all, $p, wts, ats]
|
||||
#echo r1s
|
||||
result = parseStmt(r1s)
|
||||
if not ignoreArg.boolVal:
|
||||
ahl = ahl.replace(")", "; arg: " & ats & ")")
|
||||
#echo ahl
|
||||
if ahl.find(";") > 0:
|
||||
ahl = "(self: " & wts & ";" & ahl.split(";", 1)[1]
|
||||
else:
|
||||
ahl = "(self: " & wts & ")" & ahl.split(")", 1)[1]
|
||||
#ahl = "(self: " & wts & ")"
|
||||
|
||||
let r2s =
|
||||
if ignoreArg.boolVal:
|
||||
"""
|
||||
proc $1(self: $2; p: proc $3) =
|
||||
proc $1(self: $2; p: proc $3): culong {.discardable.} =
|
||||
sc$4(self, $5, nil)
|
||||
$1($6, $7)
|
||||
""" % [$procName, wts, ahl, signalName, $procNameCdecl, $(widget.toStrLit), $p]
|
||||
else:
|
||||
"""
|
||||
proc $1(self: $2; p: proc $3; a: $4) =
|
||||
proc $1(self: $2; p: proc $3; a: $4): culong {.discardable.} =
|
||||
when a is RootRef:
|
||||
GC_ref(a)
|
||||
sc$5(self, $6, cast[pointer](a))
|
||||
|
|
@ -125,13 +116,71 @@ proc $1(self: $2; p: proc $3; a: $4) =
|
|||
sc$5(self, $6, cast[pointer](ar[]))
|
||||
$1($7, $8, $9)
|
||||
""" % [$procName, wts, ahl, ats, signalName, $procNameCdecl, $(widget.toStrLit), $p, $(arg.toStrLit)]
|
||||
#echo r2s
|
||||
result.add(parseStmt(r2s))
|
||||
|
||||
template connect*(widget: gobject.Object; signal: string; p: untyped; arg: typed): typed =
|
||||
template connect*(widget: gobject.Object; signal: string; p: untyped; arg: typed): untyped =
|
||||
mconnect(widget, signal, p, arg, false)
|
||||
|
||||
template connect*(widget: gobject.Object; signal: string; p: untyped): typed =
|
||||
template connect*(widget: gobject.Object; signal: string; p: untyped): untyped =
|
||||
mconnect(widget, signal, p, "", true)
|
||||
|
||||
var TimeoutID: int
|
||||
#
|
||||
macro timeoutAdd*(interval: Natural; p: untyped; arg: typed): untyped =
|
||||
inc(TimeoutID)
|
||||
let ats = $getTypeInst(arg).toStrLit
|
||||
let procName = "timeoutfunc_" & $TimeoutID
|
||||
let procNameCdecl = "timeoutfunc_cdecl_" & $TimeoutID
|
||||
var r1s = """
|
||||
proc $1(p: pointer): gboolean {.cdecl.} =
|
||||
let a = cast[$3](p)
|
||||
result = $2(a).gboolean
|
||||
#when (a is ref object) or (a is seq):
|
||||
GC_unref(a)
|
||||
""" % [$procNameCdecl, $p, ats]
|
||||
|
||||
let r2s ="""
|
||||
proc $1(a: $2): culong {.discardable.} =
|
||||
when (a is ref object) or (a is seq):
|
||||
GC_ref(a)
|
||||
return g_timeout_add_full(PRIORITY_DEFAULT, $3, $4, cast[pointer](a), nil)
|
||||
else:
|
||||
var ar: ref $2
|
||||
new(ar)
|
||||
deepCopy(ar[], a)
|
||||
GC_ref(ar)
|
||||
return g_timeout_add_full(PRIORITY_DEFAULT, $3, $4, cast[pointer](ar), nil)
|
||||
$1($5)
|
||||
""" % [$procName, ats, $interval.toStrLit, $procNameCdecl, $arg]
|
||||
result = parseStmt(r1s & r2s)
|
||||
|
||||
var IdleID: int
|
||||
#
|
||||
macro idleAdd*(p: untyped; arg: typed): untyped =
|
||||
inc(IdleID)
|
||||
let ats = $getTypeInst(arg).toStrLit
|
||||
let procName = "idlefunc_" & $IdleID
|
||||
let procNameCdecl = "idlefunc_cdecl_" & $IdleID
|
||||
var r1s = """
|
||||
proc $1(p: pointer): gboolean {.cdecl.} =
|
||||
let a = cast[$3](p)
|
||||
result = $2(a).gboolean
|
||||
#when (a is ref object) or (a is seq):
|
||||
GC_unref(a)
|
||||
""" % [$procNameCdecl, $p, ats]
|
||||
|
||||
let r2s ="""
|
||||
proc $1(a: $2): culong {.discardable.} =
|
||||
when (a is ref object) or (a is seq):
|
||||
GC_ref(a)
|
||||
return g_idle_add_full(PRIORITY_DEFAULT_IDLE, $3, cast[pointer](a), nil)
|
||||
else:
|
||||
var ar: ref $2
|
||||
new(ar)
|
||||
deepCopy(ar[], a)
|
||||
GC_ref(ar)
|
||||
return g_idle_add_full(PRIORITY_DEFAULT_IDLE, $3, cast[pointer](ar[]), nil)
|
||||
$1($4)
|
||||
""" % [$procName, ats, $procNameCdecl, $arg]
|
||||
result = parseStmt(r1s & r2s)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# High level gobject-introspection based GTK3 bindings for the Nim programming language
|
||||
# v 0.2 2017-AUG-29
|
||||
# v 0.2 2017-SEP-08
|
||||
# (c) S. Salewski 2017
|
||||
|
||||
# https://wiki.gnome.org/Projects/GObjectIntrospection
|
||||
|
|
@ -108,7 +108,6 @@ var fixedProcNames = newTable[string, string]()
|
|||
var mangledNames = newTable[string, string]()
|
||||
var gdkKeys = newTable[string, seq[string]]()
|
||||
var allSyms: HashSet[string]
|
||||
#var scfilter: HashSet[string]
|
||||
var provInt = newTable[string, seq[string]]()
|
||||
var interfaceProvider = newTable[string, seq[string]]()
|
||||
var priList: seq[string]
|
||||
|
|
@ -116,8 +115,8 @@ var knownSyms: HashSet[string]
|
|||
var suppressType = false
|
||||
var suppressRaise = false
|
||||
var droppedSyms = initSet[string]()
|
||||
var callerAlloc = initSet[string]()
|
||||
var callerAllocCollector = initSet[string]()
|
||||
var callerAlloc = initSet[string]()
|
||||
var callerAllocCollector = initSet[string]()
|
||||
var privStr = initSet[string]()
|
||||
var processedFunctions = initSet[string]()
|
||||
var delayedMethods: seq[(GIBaseInfo, GIFunctionInfo)]
|
||||
|
|
@ -142,6 +141,12 @@ mangledNames.add("2buttonPress", "twoButtonPress")
|
|||
mangledNames.add("3buttonPress", "threeButtonPress")
|
||||
mangledNames.add("result", "resu")
|
||||
|
||||
proc gBaseInfoGetName(info: GIBaseInfo): string =
|
||||
result = $(gir.gBaseInfoGetName(info))
|
||||
let h = $(gir.gBaseInfoGetNamespace(info))
|
||||
if h == "Gio" and result == "Application":
|
||||
result = "GApplication"
|
||||
|
||||
proc mangleName(s: cstring): string =
|
||||
result = mysnakeToCamel(s)
|
||||
if mangledNames.contains(result):
|
||||
|
|
@ -348,7 +353,10 @@ proc genP(info: GICallableInfo; genProxy = false; binfo: GIBaseInfo = nil): (str
|
|||
else:
|
||||
arglist = "(cast[ptr " & manglename(gBaseInfoGetName(binfo)) & "00](" & "self.impl)"
|
||||
if genProxy:
|
||||
resul = "(self: " & manglename(gBaseInfoGetName(binfo))
|
||||
var h = manglename(gBaseInfoGetName(binfo))
|
||||
if (sym.startsWith("gdk_events_get_") or sym.startsWith("gdk_event_get_")) and h == "Event":
|
||||
h = "SomeEvent"
|
||||
resul = "(self: " & h
|
||||
else:
|
||||
resul = "(self: ptr " & manglename(gBaseInfoGetName(binfo)) & "00"
|
||||
if m >= 0:
|
||||
|
|
@ -399,6 +407,10 @@ proc genP(info: GICallableInfo; genProxy = false; binfo: GIBaseInfo = nil): (str
|
|||
(h1, h2, h3) = defaultParameters[sym].split
|
||||
if name == h1 and str == h2:
|
||||
str.add(" = " & h3)
|
||||
|
||||
if (sym.startsWith("gdk_events_get_") or sym.startsWith("gdk_event_get_")) and str == "Event":
|
||||
str = "SomeEvent"
|
||||
|
||||
resul.add(name & ": " & str)
|
||||
if j < m:
|
||||
resul.add("; ")
|
||||
|
|
@ -658,6 +670,11 @@ proc writeUnion(info: GIUnionInfo) =
|
|||
output.writeLine(" ", name, ": ", genRec(t))
|
||||
output.writeLine(" ", mangleName(gBaseInfoGetName(info)) & EM & " = ref object")
|
||||
output.writeLine(" impl*: ptr " & mangleName(gBaseInfoGetName(info)) & "00")
|
||||
|
||||
if mangleName(gBaseInfoGetName(info)) == "Event" and moduleNamespace == "gdk":
|
||||
output.writeLine("type")
|
||||
output.writeLine(" SomeEvent* = Event | EventButton | EventMotion | EventTouch | EventScroll | EventCrossing | EventTouchpadSwipe | EventTouchpadPinch")
|
||||
|
||||
let nMethods = gUnionInfoGetNMethods(info)
|
||||
for j in 0 .. <nMethods:
|
||||
let mInfo = gUnionInfoGetMethod(info, j)
|
||||
|
|
@ -887,10 +904,10 @@ proc writeObj(info: GIObjectInfo) =
|
|||
var xxx = mangleName(gBaseInfoGetName(info))
|
||||
output.write("proc " & mangleName("sc_" & $gBaseInfoGetName(signalInfo)) & EM & "(self: " & xxx & "; ")
|
||||
if gCallableInfoGetNArgs(signalInfo) > 0 or gTypeInfoGetTag(zzzu) != GITypeTag.VOID:
|
||||
output.writeLine(" p: proc (self: ptr " & xxx & "00; " & h & " {.cdecl.}, xdata: pointer = nil) =")
|
||||
output.writeLine(" p: proc (self: ptr " & xxx & "00; " & h & " {.cdecl.}, xdata: pointer = nil): culong =")
|
||||
else:
|
||||
output.writeLine(" p: proc (self: ptr gobject.Object00; " & h & " {.cdecl.}, xdata: pointer = nil) =")
|
||||
output.write(" discard g_signal_connect_data(self.impl, \"")
|
||||
output.writeLine(" p: proc (self: ptr gobject.Object00; " & h & " {.cdecl.}, xdata: pointer = nil): culong =")
|
||||
output.write(" g_signal_connect_data(self.impl, \"")
|
||||
output.write($gBaseInfoGetName(signalInfo))
|
||||
output.writeLine("\", cast[GCallback](p), xdata, nil, cast[ConnectFlags](0))")
|
||||
let nMethods = gObjectInfoGetNMethods(info)
|
||||
|
|
@ -1017,8 +1034,8 @@ proc fixednewCursorFromName*(display: Display; name: string): Cursor =
|
|||
|
||||
const GIO_EPI = """
|
||||
|
||||
proc run*(self: Application): int =
|
||||
int(g_application_run(cast[ptr Application00](self.impl), 0, nil))
|
||||
proc run*(self: GApplication): int =
|
||||
int(g_application_run(cast[ptr GApplication00](self.impl), 0, nil))
|
||||
|
||||
"""
|
||||
|
||||
|
|
|
|||
1369
tests/gen.nim.oldv0.2
Normal file
1369
tests/gen.nim.oldv0.2
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue