diff --git a/README.adoc b/README.adoc
index dd9fd46..44f65da 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.6.0
+//Version 0.6.1
:experimental:
:imagesdir: http://ssalewski.de/tmp
:source-highlighter: pygments
@@ -1100,7 +1100,142 @@ main()
While in the previous example we create only a single menu instance in proc appStartup()
for all of our application windows, here we create a new menu for all of our instances
-in proc appActivate(). That seems to work fine, so I assume it is correct.
+in proc appActivate(). That seems to work fine, so I assume it is correct.
+
+== GMenu and GAction with GTK Builder
+
+And here is an example from https://github.com/GNOME/gtk/blob/mainline/tests/
+which uses a combination of gaction and gmenu with a GTK builder XML file for
+the menu description.
+
+[[gaction2.nim]]
+[source, nim]
+.gaction2.nim
+----
+# nim c gaction2.nim
+# https://github.com/GNOME/gtk/blob/mainline/tests/testgaction.c
+# gcc -Wall gaction.c -o gaction `pkg-config --cflags --libs gtk4`
+import gintro/[gtk, glib, gobject, gio]
+
+const menuData = """
+
+
+
+"""
+
+proc changeLabelButton(action: SimpleAction; v: Variant; label: Label) =
+ label.setLabel("Text set from button")
+
+proc normalMenuItem(action: SimpleAction; v: Variant; label: Label) =
+ label.setLabel("Text set from normal menu item")
+
+proc toggleMenuItem(action: SimpleAction; v: Variant; label: Label) =
+ label.setLabel("Text set from toggle menu item")
+
+proc submenuItem(action: SimpleAction; v: Variant; label: Label) =
+ label.setLabel("Text set from submenu item")
+
+proc radio(action: SimpleAction; parameter: Variant; label: Label) =
+ var l: uint64
+ let newState: Variant = newVariantString(getString(parameter, l))
+ let str: string = "From Radio menu item " & getString(newState, l)
+ label.setLabel(str)
+
+proc bye(w: Window) =
+ mainQuit()
+ echo "Bye..."
+
+proc main =
+ gtk.init()
+ let
+ window = newWindow()
+ box = newBox(Orientation.vertical, 12)
+ menubutton = newMenuButton()
+ button1 = newButton("Change Label Text")
+ label = newLabel("Initial Text")
+ actionGroup = newSimpleActionGroup()
+
+ window.connect("destroy", gtk.mainQuit)
+ #window.connect("destroy", bye)
+
+ var action = newSimpleAction("change-label-button")
+ discard action.connect("activate", changeLabelButton, label)
+ actionGroup.addAction(action)
+
+ action = newSimpleAction("normal-menu-item")
+ discard action.connect("activate", normalMenuItem, label)
+ actionGroup.addAction(action)
+
+ var v = newVariantBoolean(true)
+ action = newSimpleActionStateful("toggle-menu-item", nil, v)
+ discard action.connect("activate", toggleMenuItem, label)
+ actionGroup.addAction(action)
+
+ action = newSimpleAction("submenu-item")
+ discard action.connect("activate", subMenuItem, label)
+ actionGroup.addAction(action)
+
+ v = newVariantString("1")
+ let vt = newVariantType("s")
+ action = newSimpleActionStateful("radio", vt, v)
+ discard action.connect("activate", radio, label)
+ actionGroup.addAction(action)
+
+ insertActionGroup(window, "win", actionGroup)
+
+ label.setMarginTop(12)
+ label.setMarginBottom(12)
+ box.add(label)
+ menubutton.setHAlign(Align.center)
+ let builder: Builder = newBuilderFromString(menuData)
+ let menuModel = builder.getMenuModel("menuModel")
+ let menu = newMenuFromModel(menuModel)
+ menuButton.setPopup(menu)
+ box.add(menubutton)
+ button1.setHalign(Align.center)
+ button1.setActionName("win.change-label-button")
+ box.add(button1)
+ window.add(box)
+ window.showAll
+ gtk.main()
+
+main()
+----
== GSettings
diff --git a/examples/gtk3/gaction.nim b/examples/gtk3/gaction.nim
index 7aa910a..d2b71db 100644
--- a/examples/gtk3/gaction.nim
+++ b/examples/gtk3/gaction.nim
@@ -23,3 +23,4 @@ proc main =
discard run(app)
main()
+
diff --git a/examples/gtk3/gaction2.nim b/examples/gtk3/gaction2.nim
new file mode 100644
index 0000000..115686e
--- /dev/null
+++ b/examples/gtk3/gaction2.nim
@@ -0,0 +1,123 @@
+# nim c gaction.nim
+# https://github.com/GNOME/gtk/blob/mainline/tests/testgaction.c
+# gcc -Wall gaction.c -o gaction `pkg-config --cflags --libs gtk4`
+import gintro/[gtk, glib, gobject, gio]
+
+const menuData = """
+
+
+
+"""
+
+proc changeLabelButton(action: SimpleAction; v: Variant; label: Label) =
+ label.setLabel("Text set from button")
+
+proc normalMenuItem(action: SimpleAction; v: Variant; label: Label) =
+ label.setLabel("Text set from normal menu item")
+
+proc toggleMenuItem(action: SimpleAction; v: Variant; label: Label) =
+ label.setLabel("Text set from toggle menu item")
+
+proc submenuItem(action: SimpleAction; v: Variant; label: Label) =
+ label.setLabel("Text set from submenu item")
+
+proc radio(action: SimpleAction; parameter: Variant; label: Label) =
+ var l: uint64
+ let newState: Variant = newVariantString(getString(parameter, l))
+ let str: string = "From Radio menu item " & getString(newState, l)
+ label.setLabel(str)
+
+proc bye(w: Window) =
+ mainQuit()
+ echo "Bye..."
+
+proc main =
+ gtk.init()
+ let
+ window = newWindow()
+ box = newBox(Orientation.vertical, 12)
+ menubutton = newMenuButton()
+ button1 = newButton("Change Label Text")
+ label = newLabel("Initial Text")
+ actionGroup = newSimpleActionGroup()
+
+ window.connect("destroy", gtk.mainQuit)
+ #window.connect("destroy", bye)
+
+ var action = newSimpleAction("change-label-button")
+ discard action.connect("activate", changeLabelButton, label)
+ actionGroup.addAction(action)
+
+ action = newSimpleAction("normal-menu-item")
+ discard action.connect("activate", normalMenuItem, label)
+ actionGroup.addAction(action)
+
+ var v = newVariantBoolean(true)
+ action = newSimpleActionStateful("toggle-menu-item", nil, v)
+ discard action.connect("activate", toggleMenuItem, label)
+ actionGroup.addAction(action)
+
+ action = newSimpleAction("submenu-item")
+ discard action.connect("activate", subMenuItem, label)
+ actionGroup.addAction(action)
+
+ v = newVariantString("1")
+ let vt = newVariantType("s")
+ action = newSimpleActionStateful("radio", vt, v)
+ discard action.connect("activate", radio, label)
+ actionGroup.addAction(action)
+
+ insertActionGroup(window, "win", actionGroup)
+
+ label.setMarginTop(12)
+ label.setMarginBottom(12)
+ box.add(label)
+ menubutton.setHAlign(Align.center)
+ let builder: Builder = newBuilderFromString(menuData)
+ let menuModel = builder.getMenuModel("menuModel")
+ let menu = newMenuFromModel(menuModel)
+ menuButton.setPopup(menu)
+ box.add(menubutton)
+ button1.setHalign(Align.center)
+ button1.setActionName("win.change-label-button")
+ box.add(button1)
+ window.add(box)
+ window.showAll
+ gtk.main()
+
+main()
diff --git a/examples/gtk3/makeAll b/examples/gtk3/makeAll
index 93212da..6731264 100644
--- a/examples/gtk3/makeAll
+++ b/examples/gtk3/makeAll
@@ -7,6 +7,7 @@ nim c count_button.nim
nim c darea_test.nim
nim c drawingarea.nim
nim c gaction.nim
+nim c gaction2.nim
nim c gsettings.nim
nim c label.nim
nim c listview.nim
@@ -19,3 +20,4 @@ nim c cairoImage.nim
nim c gstBasicTutorial1.nim
nim c sourceview_test.nim
nim c overlay_tree1.nim
+nim c celldatafunction.nim
diff --git a/gintro.nimble b/gintro.nimble
index bbf98c7..63f8c7d 100644
--- a/gintro.nimble
+++ b/gintro.nimble
@@ -1,6 +1,6 @@
# Package
-version = "0.6.0"
+version = "0.6.1"
author = "Stefan Salewski"
description = "High level GObject-Introspection based GTK3/GTK4 bindings"
license = "MIT"
diff --git a/gintro/cairoimpl.nim b/gintro/cairoimpl.nim
index ffc9d78..0c7252e 100644
--- a/gintro/cairoimpl.nim
+++ b/gintro/cairoimpl.nim
@@ -1,7 +1,7 @@
# This is the high level cairo module for Nim -- based on the low level ngtk3 module, manually tuned.
# (c) S. Salewski 2017, cairo 1.15.6
# v0.6.0
-# 28-OCT-2019
+# 03-DEC-2019
# starting with gintro v.0.6.0 we split cairo into the gobject-introspection generated cairo.nim and this file.
@@ -242,6 +242,7 @@ proc cairo_pop_group*(cr: ptr Context00): ptr Pattern00 {.importc, libcairo.}
proc popGroup*(cr: Context): Pattern =
new(result, patternDestroy)
result.impl = cairo_pop_group(cr.impl)
+ GC_Ref(result)
discard cairo_pattern_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_pop_group_to_source*(cr: ptr Context00) {.importc, libcairo.}
@@ -271,6 +272,11 @@ proc setSource*(cr: Context; red, green, blue: float) =
cairo_set_source_rgb(cr.impl, red.cdouble, green.cdouble, blue.cdouble)
#
#const `source=`* = setSourceRgb
+proc setSource*(cr: Context; rgb: array[3, float]) =
+ cairo_set_source_rgb(cr.impl, rgb[0], rgb[1], rgb[2])
+#
+proc setSource*(cr: Context; rgb: tuple[r, g, b: float]) =
+ cairo_set_source_rgb(cr.impl, rgb[0], rgb[1], rgb[2])
proc cairo_set_source_rgba*(cr: ptr Context00; red, green, blue, alpha: cdouble) {.importc, libcairo.}
#
@@ -279,6 +285,12 @@ proc setSource*(cr: Context; red, green, blue, alpha: float) =
cairo_set_source_rgba(cr.impl, red.cdouble, green.cdouble, blue.cdouble, alpha.cdouble)
#
#const `sourceRgba=`* = setSourceRgba
+#
+proc setSource*(cr: Context; rgba: array[4, float]) =
+ cairo_set_source_rgba(cr.impl, rgba[0], rgba[1], rgba[2], rgba[3])
+#
+proc setSource*(cr: Context; rgba: tuple[r, g, b, a: float]) =
+ cairo_set_source_rgba(cr.impl, rgba[0], rgba[1], rgba[2], rgba[3])
proc cairo_surface_get_reference_count*(surface: ptr Surface00): cuint {.importc, libcairo.}
#
@@ -389,33 +401,53 @@ proc cairo_user_to_device*(cr: ptr Context00; x, y: var cdouble) {.importc, libc
#
proc userToDevice*(cr: Context; x, y: var float) =
var x1, y1: cdouble
+ (x1, y1) = (x, y)
cairo_user_to_device(cr.impl, x1, y1)
x = x1.float
y = y1.float
+#
+proc userToDevice*(cr: Context; x, y: float): array[2, float] =
+ result = [x, y]
+ cairo_user_to_device(cr.impl, result[0], result[1])
proc cairo_user_to_device_distance*(cr: ptr Context00; dx, dy: var cdouble) {.importc, libcairo.}
#
proc userToDeviceDistance*(cr: Context; dx, dy: var float) =
var dx1, dy1: cdouble
+ (dx1, dy1) = (dx, dy)
cairo_user_to_device_distance(cr.impl, dx1, dy1)
dx = dx1.float
dy = dy1.float
+#
+proc userToDeviceDistance*(cr: Context; dx, dy: float): array[2, float] =
+ result = [dx, dy]
+ cairo_user_to_device_distance(cr.impl, result[0], result[1])
proc cairo_device_to_user*(cr: ptr Context00; x, y: var cdouble) {.importc, libcairo.}
#
proc deviceToUser*(cr: Context; x, y: var float) =
var x1, y1: cdouble
+ (x1, y1) = (x, y)
cairo_device_to_user(cr.impl, x1, y1)
x = x1.float
y = y1.float
+#
+proc deviceToUser*(cr: Context; x, y: float): array[2, float] =
+ result = [x, y]
+ cairo_device_to_user(cr.impl, result[0], result[1])
proc cairo_device_to_user_distance*(cr: ptr Context00; dx, dy: var cdouble) {.importc, libcairo.}
#
proc deviceToUserDistance*(cr: Context; dx, dy: var float) =
var dx1, dy1: cdouble
+ (dx1, dy1) = (dx, dy)
cairo_device_to_user_distance(cr.impl, dx1, dy1)
dx = dx1.float
dy = dy1.float
+#
+proc deviceToUserDistance*(cr: Context; dx, dy: float): array[2, float] =
+ result = [dx, dy]
+ cairo_device_to_user_distance(cr.impl, result[0], result[1])
proc cairo_new_path*(cr: ptr Context00) {.importc, libcairo.}
#
diff --git a/tests/gen.nim b/tests/gen.nim
index f2524df..c05bf2c 100644
--- a/tests/gen.nim
+++ b/tests/gen.nim
@@ -1,5 +1,5 @@
# High level gobject-introspection based GTK3/GTK4 bindings for the Nim programming language
-# v 0.6.0 2019-OCT-28
+# v 0.6.1 2019-DEC-05
# (c) S. Salewski 2018
# https://wiki.gnome.org/Projects/GObjectIntrospection
@@ -199,6 +199,7 @@ fixedProcNames.add("gst_element_factory_find", "findElementFactory")
defaultParameters.add("gtk_window_new", "`type` WindowType WindowType.toplevel")
defaultParameters.add("gtk_application_new", "flags gio.ApplicationFlags {}")
+defaultParameters.add("gtk_builder_new_from_string", "length int64 -1")
for i in keywords: mangledNames.add(i, '`' & i & '`')
@@ -1706,6 +1707,8 @@ const GTK_EPI = """
#proc loadFromData*(self: CssProvider; data: cstring): bool =
# loadFromData(self, uint8Array(data), -1)
+proc mainQuit*(w: Window) = mainQuit()
+
proc gtk_file_chooser_dialog_new*(title: cstring; parent: ptr Window00; action: FileChooserAction;
firstButtonText: cstring = nil): ptr FileChooserDialog00 {.varargs,
importc: "gtk_file_chooser_dialog_new", libprag.}
@@ -2036,6 +2039,18 @@ proc uint8ArrayZT2seq*(p: pointer): seq[uint8] =
assert false
else:
provInt[name] = interf
+
+ # Cross module interfaces -- maybe only a few, so we add it manually
+ # GSimpleActionGroup implements GActionGroup and GActionMap.
+ if namespace == "Gtk":
+ provInt["gio.SimpleActionGroup"] = @["gio.ActionGroup", "gio.ActionMap", "ActionGroup", "ActionMap"]
+ #provInt["gio.SimpleActionGroup"] = @["ActionGroup", "ActionMap"]
+ # The next two do not work, as gio does not import gtk! So we have to use converter proc.
+ # GtkApplication implements GActionGroup and GActionMap.
+ # provInt["Application"] = @["ActionGroup", "ActionMap"]
+ # GtkApplicationWindow implements AtkImplementorIface, GtkBuildable, GActionGroup and GActionMap.
+ # provInt["ApplicationWindow"] = @["ImplementorIface", "Buildable", "ActionGroup", "ActionMap"]
+
for obj, ifaces in provInt:
for i in ifaces:
if not interfaceProvider.contains(i):
@@ -2187,7 +2202,11 @@ proc init* =
else:
output.write("include gisup4\n")
output.write("include gimpl\n")
+ buildableList.add("MenuModel")
for i in buildableList:
+ var prefix = "gtk"
+ if i == "MenuModel":
+ prefix = "g"
if i == "": continue
output.write(
"""
@@ -2207,8 +2226,9 @@ proc get$1*(builder: Builder; name: string): $1 =
g_object_set_qdata(result.impl, Quark, addr(result[]))
assert(toBool(g_type_check_instance_is_a(cast[ptr TypeInstance00](result.impl), gt)))
-""" % [i, "gtk_" & myCamelToSnake(i) & "_get_type()"])
+""" % [i, prefix & "_" & myCamelToSnake(i) & "_get_type()"])
output.write("")
+
if namespace == "Gio":
output.write(GIO_EPI)
@@ -2336,4 +2356,4 @@ proc launch() =
supmod4.close
launch()
-# 2339 lines
+# 2360 lines