diff --git a/README.adoc b/README.adoc index fe550af..5642e7d 100644 --- a/README.adoc +++ b/README.adoc @@ -1,6 +1,6 @@ = High level GTK3 (and GTK4) bindings for the Nim programming language (c) Stefan Salewski -//Version 0.7.2 +//Version 0.7.3 :experimental: :imagesdir: http://ssalewski.de/tmp :source-highlighter: pygments @@ -25,8 +25,14 @@ with code inserted from files directly. NOTE: This work is partly based on earlier works of J. Mansour and has been supported by A. Rumpf, E. Bassi and other _Nim_ and _GTK/Gnome_ developers. The `combinatorics` module was kindly provided by R. Behrends. +NOTE: Starting with current version v0.7.3 we allow passing a type descriptor as first parameter to the +new() procs like `newButton(MyButtonSubclass)` to support subclassing and extending Widgets in OOP style. +See <> for an complete example. The init() procs which were used +before for this task are now deprecated and will be removed later. This new approach generally saves +one line of source code, allows using `let` instead of `var`, and the naming of procs is more consistent. + NOTE: Starting with version v0.7.1 we have added destructor support when compiled with `--gc:arc`, -so we have no memory leak for subclassed objects any more, see the example in `Subclassing` section. +so we have no memory leak for subclassed objects any more, see the example in <> section. When compiled with default (refc) GC finalizers are used as before. And for objects marked with `nullable` tag in gobject-introspection we now return nil value for the proxy object when the C lib has returned NULL. So according to the C API docs, you can check for nil result for the few functions which may return NULL. @@ -597,13 +603,17 @@ Remember the GTK `devhelp` tool, and use also `grep` or the `nimgrep` variant. == Extending or sub-classing Widgets -I may occur that we want to attach additional information to GTK widgets -by extending or subclassing them. Doing this is supported +It may occur that we want to attach additional information to GTK widgets +by extending or subclassing them. [line-through]#Doing this is supported by providing for each widget class not only a corresponding new() proc which returns the newly created widget, but also a init() proc, which gets an uninitialized variable of the (extended) widget type as argument and initializes that variable with a newly created -GTK widget . Initializing the added fields is +GTK widget.# +Doing this is supported +by providing for each widget class an additional new() proc which takes an type descriptor +as first argument, like `newButton(CountButton, "Counting down from 100 by 5")` in the example below. +Initializing the added fields is done separately by the user. The following code shows a GTK button, which is extended with a counter member field. That counter is decreased for each button click. The amount of decrease (5) is passed to the callback as a int parameter. @@ -621,29 +631,30 @@ to test the destructor behaviour.) .count_button.nim ---- # nim c count_button.nim -import gintro/[gtk, glib, gobject, gio] +import gintro/[gtk, gobject, gio] type CountButton = ref object of Button counter: int -when compileOption("gc", "arc"): +when defined(gcDestructors): proc `=destroy`(x: var typeof(CountButton()[])) = gtk.`=destroy`(typeof(Button()[])(x)) proc buttonClicked (button: CountButton; decrement: int) = dec(button.counter, decrement) - button.label = "Counter: " & $button.counter + button.label = "Counter: " & $button.counter echo "Counter is now: ", button.counter proc appActivate (app: Application) = - var button: CountButton + #var button: CountButton let window = newApplicationWindow(app) window.title = "Count Button" - initButton(button, "Counting down from 100 by 5") + #initButton(button, "Counting down from 100 by 5") # deprecated + let button = newButton(CountButton, "Counting down from 100 by 5") button.counter = 100 window.add(button) - button.connect("clicked", buttonClicked, 5) + button.connect("clicked", buttonClicked, 5) window.showAll proc main = diff --git a/examples/gtk3/count_button.nim b/examples/gtk3/count_button.nim index 623b9b5..eec7d77 100644 --- a/examples/gtk3/count_button.nim +++ b/examples/gtk3/count_button.nim @@ -1,27 +1,28 @@ # nim c count_button.nim -import gintro/[gtk, glib, gobject, gio] +import gintro/[gtk, gobject, gio] type CountButton = ref object of Button counter: int -when compileOption("gc", "arc"): +when defined(gcDestructors): proc `=destroy`(x: var typeof(CountButton()[])) = gtk.`=destroy`(typeof(Button()[])(x)) proc buttonClicked (button: CountButton; decrement: int) = dec(button.counter, decrement) - button.label = "Counter: " & $button.counter + button.label = "Counter: " & $button.counter echo "Counter is now: ", button.counter proc appActivate (app: Application) = - var button: CountButton + #var button: CountButton let window = newApplicationWindow(app) window.title = "Count Button" - initButton(button, "Counting down from 100 by 5") + #initButton(button, "Counting down from 100 by 5") # deprecated + let button = newButton(CountButton, "Counting down from 100 by 5") button.counter = 100 window.add(button) - button.connect("clicked", buttonClicked, 5) + button.connect("clicked", buttonClicked, 5) window.showAll proc main = diff --git a/gintro.nimble b/gintro.nimble index 0a5c2cd..48e6926 100644 --- a/gintro.nimble +++ b/gintro.nimble @@ -1,6 +1,6 @@ # Package -version = "0.7.2" +version = "0.7.3" author = "Stefan Salewski" description = "High level GObject-Introspection based GTK3/GTK4 bindings" license = "MIT" diff --git a/tests/gen.nim b/tests/gen.nim index cb56ff0..1b47551 100644 --- a/tests/gen.nim +++ b/tests/gen.nim @@ -1,6 +1,6 @@ # High level gobject-introspection based GTK3/GTK4 bindings for the Nim programming language # nimpretty --maxLineLen:130 gen.nim -# v 0.7.2 2020-FEB-23 +# v 0.7.3 2020-MAR-09 # (c) S. Salewski 2018 # https://wiki.gnome.org/Projects/GObjectIntrospection @@ -900,21 +900,29 @@ proc writeMethod(info: GIBaseInfo; minfo: GIFunctionInfo) = for j in 0.cint ..< gCallableInfoGetNArgs(minfo): let arg = gCallableInfoGetArg(minfo, j) assert gArgInfoGetDirection(arg) notin {GIDirection.OUT, INOUT} # so we can ignore this case! - for i in 0 .. 1: # generate the new() and the init() proc + for itt in 0 .. 2: # generate the new(), the new(typedesc) and the init() proc var hhh = "\nproc " & asym & EM & plist - if i > 0: + if itt == 1: # new(typedesc) + let semi = if hhh.contains("()"): "" else: "; " + let p = hhh.find("): ") + hhh.setLen(p + 1) + hhh = hhh.replace("*(", "*(tdesc: typedesc" & semi) + hhh.add(": tdesc") + if itt == 2: # init(), deprecated let semi = if hhh.contains("()"): "" else: "; " let p = hhh.find("): ") hhh.setLen(p + 1) hhh = hhh.replace("new", "init") hhh = hhh.replace("*(", "*[T](result: var T" & semi) + if itt == 2: + depStr = " {.deprecated.}" methodBuffer.writeLine(hhh & depStr & " =") methodBuffer.write(arrLex) methodBuffer.write(sss) if gCallableInfoCanThrowGerror(minfo): methodBuffer.writeLine(" var gerror: ptr glib.Error") - if i == 0: arglist.insert(", addr gerror", arglist.high) - if i > 0: + if itt == 0: arglist.insert(", addr gerror", arglist.high) + if itt == 1 or itt == 2: methodBuffer.writeLine(" assert(result is $1)" % [manglename(gBaseInfoGetName(info))]) if isGObject: # CAUTION: some procs are advertised as constructor but do not construct new objects, @@ -2604,4 +2612,4 @@ proc launch() = supmod4.close launch() -# 2607 lines +# 2615 lines