added gaction2.nim example, and some small fixes

This commit is contained in:
Stefan Salewski 2019-12-05 19:11:11 +01:00
commit 68f99d33cb
7 changed files with 320 additions and 7 deletions

View file

@ -1,6 +1,6 @@
= High level GTK3 (and GTK4) bindings for the Nim programming language = High level GTK3 (and GTK4) bindings for the Nim programming language
(c) Stefan Salewski (c) Stefan Salewski
//Version 0.6.0 //Version 0.6.1
:experimental: :experimental:
:imagesdir: http://ssalewski.de/tmp :imagesdir: http://ssalewski.de/tmp
:source-highlighter: pygments :source-highlighter: pygments
@ -1102,6 +1102,141 @@ While in the previous example we create only a single menu instance in proc appS
for all of our application windows, here we create a new menu for all of our instances 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 = """
<interface>
<menu id="menuModel">
<section>
<item>
<attribute name="label">Normal Menu Item</attribute>
<attribute name="action">win.normal-menu-item</attribute>
</item>
<submenu>
<attribute name="label">Submenu</attribute>
<item>
<attribute name="label">Submenu Item</attribute>
<attribute name="action">win.submenu-item</attribute>
</item>
</submenu>
<item>
<attribute name="label">Toggle Menu Item</attribute>
<attribute name="action">win.toggle-menu-item</attribute>
</item>
</section>
<section>
<item>
<attribute name="label">Radio 1</attribute>
<attribute name="action">win.radio</attribute>
<attribute name="target">1</attribute>
</item>
<item>
<attribute name="label">Radio 2</attribute>
<attribute name="action">win.radio</attribute>
<attribute name="target">2</attribute>
</item>
<item>
<attribute name="label">Radio 3</attribute>
<attribute name="action">win.radio</attribute>
<attribute name="target">3</attribute>
</item>
</section>
</menu>
</interface>
"""
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 == GSettings
GSettings provides a convenient way to permanently storing configuration data, GSettings provides a convenient way to permanently storing configuration data,

View file

@ -23,3 +23,4 @@ proc main =
discard run(app) discard run(app)
main() main()

123
examples/gtk3/gaction2.nim Normal file
View file

@ -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 = """
<interface>
<menu id="menuModel">
<section>
<item>
<attribute name="label">Normal Menu Item</attribute>
<attribute name="action">win.normal-menu-item</attribute>
</item>
<submenu>
<attribute name="label">Submenu</attribute>
<item>
<attribute name="label">Submenu Item</attribute>
<attribute name="action">win.submenu-item</attribute>
</item>
</submenu>
<item>
<attribute name="label">Toggle Menu Item</attribute>
<attribute name="action">win.toggle-menu-item</attribute>
</item>
</section>
<section>
<item>
<attribute name="label">Radio 1</attribute>
<attribute name="action">win.radio</attribute>
<attribute name="target">1</attribute>
</item>
<item>
<attribute name="label">Radio 2</attribute>
<attribute name="action">win.radio</attribute>
<attribute name="target">2</attribute>
</item>
<item>
<attribute name="label">Radio 3</attribute>
<attribute name="action">win.radio</attribute>
<attribute name="target">3</attribute>
</item>
</section>
</menu>
</interface>
"""
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()

View file

@ -7,6 +7,7 @@ nim c count_button.nim
nim c darea_test.nim nim c darea_test.nim
nim c drawingarea.nim nim c drawingarea.nim
nim c gaction.nim nim c gaction.nim
nim c gaction2.nim
nim c gsettings.nim nim c gsettings.nim
nim c label.nim nim c label.nim
nim c listview.nim nim c listview.nim
@ -19,3 +20,4 @@ nim c cairoImage.nim
nim c gstBasicTutorial1.nim nim c gstBasicTutorial1.nim
nim c sourceview_test.nim nim c sourceview_test.nim
nim c overlay_tree1.nim nim c overlay_tree1.nim
nim c celldatafunction.nim

View file

@ -1,6 +1,6 @@
# Package # Package
version = "0.6.0" version = "0.6.1"
author = "Stefan Salewski" author = "Stefan Salewski"
description = "High level GObject-Introspection based GTK3/GTK4 bindings" description = "High level GObject-Introspection based GTK3/GTK4 bindings"
license = "MIT" license = "MIT"

View file

@ -1,7 +1,7 @@
# This is the high level cairo module for Nim -- based on the low level ngtk3 module, manually tuned. # 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 # (c) S. Salewski 2017, cairo 1.15.6
# v0.6.0 # 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. # 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 = proc popGroup*(cr: Context): Pattern =
new(result, patternDestroy) new(result, patternDestroy)
result.impl = cairo_pop_group(cr.impl) result.impl = cairo_pop_group(cr.impl)
GC_Ref(result)
discard cairo_pattern_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) discard cairo_pattern_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_pop_group_to_source*(cr: ptr Context00) {.importc, libcairo.} 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) cairo_set_source_rgb(cr.impl, red.cdouble, green.cdouble, blue.cdouble)
# #
#const `source=`* = setSourceRgb #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.} 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) cairo_set_source_rgba(cr.impl, red.cdouble, green.cdouble, blue.cdouble, alpha.cdouble)
# #
#const `sourceRgba=`* = setSourceRgba #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.} 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) = proc userToDevice*(cr: Context; x, y: var float) =
var x1, y1: cdouble var x1, y1: cdouble
(x1, y1) = (x, y)
cairo_user_to_device(cr.impl, x1, y1) cairo_user_to_device(cr.impl, x1, y1)
x = x1.float x = x1.float
y = y1.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 cairo_user_to_device_distance*(cr: ptr Context00; dx, dy: var cdouble) {.importc, libcairo.}
# #
proc userToDeviceDistance*(cr: Context; dx, dy: var float) = proc userToDeviceDistance*(cr: Context; dx, dy: var float) =
var dx1, dy1: cdouble var dx1, dy1: cdouble
(dx1, dy1) = (dx, dy)
cairo_user_to_device_distance(cr.impl, dx1, dy1) cairo_user_to_device_distance(cr.impl, dx1, dy1)
dx = dx1.float dx = dx1.float
dy = dy1.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 cairo_device_to_user*(cr: ptr Context00; x, y: var cdouble) {.importc, libcairo.}
# #
proc deviceToUser*(cr: Context; x, y: var float) = proc deviceToUser*(cr: Context; x, y: var float) =
var x1, y1: cdouble var x1, y1: cdouble
(x1, y1) = (x, y)
cairo_device_to_user(cr.impl, x1, y1) cairo_device_to_user(cr.impl, x1, y1)
x = x1.float x = x1.float
y = y1.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 cairo_device_to_user_distance*(cr: ptr Context00; dx, dy: var cdouble) {.importc, libcairo.}
# #
proc deviceToUserDistance*(cr: Context; dx, dy: var float) = proc deviceToUserDistance*(cr: Context; dx, dy: var float) =
var dx1, dy1: cdouble var dx1, dy1: cdouble
(dx1, dy1) = (dx, dy)
cairo_device_to_user_distance(cr.impl, dx1, dy1) cairo_device_to_user_distance(cr.impl, dx1, dy1)
dx = dx1.float dx = dx1.float
dy = dy1.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.} proc cairo_new_path*(cr: ptr Context00) {.importc, libcairo.}
# #

View file

@ -1,5 +1,5 @@
# High level gobject-introspection based GTK3/GTK4 bindings for the Nim programming language # 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 # (c) S. Salewski 2018
# https://wiki.gnome.org/Projects/GObjectIntrospection # 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_window_new", "`type` WindowType WindowType.toplevel")
defaultParameters.add("gtk_application_new", "flags gio.ApplicationFlags {}") 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 & '`') for i in keywords: mangledNames.add(i, '`' & i & '`')
@ -1706,6 +1707,8 @@ const GTK_EPI = """
#proc loadFromData*(self: CssProvider; data: cstring): bool = #proc loadFromData*(self: CssProvider; data: cstring): bool =
# loadFromData(self, uint8Array(data), -1) # loadFromData(self, uint8Array(data), -1)
proc mainQuit*(w: Window) = mainQuit()
proc gtk_file_chooser_dialog_new*(title: cstring; parent: ptr Window00; action: FileChooserAction; proc gtk_file_chooser_dialog_new*(title: cstring; parent: ptr Window00; action: FileChooserAction;
firstButtonText: cstring = nil): ptr FileChooserDialog00 {.varargs, firstButtonText: cstring = nil): ptr FileChooserDialog00 {.varargs,
importc: "gtk_file_chooser_dialog_new", libprag.} importc: "gtk_file_chooser_dialog_new", libprag.}
@ -2036,6 +2039,18 @@ proc uint8ArrayZT2seq*(p: pointer): seq[uint8] =
assert false assert false
else: else:
provInt[name] = interf 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 obj, ifaces in provInt:
for i in ifaces: for i in ifaces:
if not interfaceProvider.contains(i): if not interfaceProvider.contains(i):
@ -2187,7 +2202,11 @@ proc init* =
else: else:
output.write("include gisup4\n") output.write("include gisup4\n")
output.write("include gimpl\n") output.write("include gimpl\n")
buildableList.add("MenuModel")
for i in buildableList: for i in buildableList:
var prefix = "gtk"
if i == "MenuModel":
prefix = "g"
if i == "": continue if i == "": continue
output.write( output.write(
""" """
@ -2207,8 +2226,9 @@ proc get$1*(builder: Builder; name: string): $1 =
g_object_set_qdata(result.impl, Quark, addr(result[])) g_object_set_qdata(result.impl, Quark, addr(result[]))
assert(toBool(g_type_check_instance_is_a(cast[ptr TypeInstance00](result.impl), gt))) 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("") output.write("")
if namespace == "Gio": if namespace == "Gio":
output.write(GIO_EPI) output.write(GIO_EPI)
@ -2336,4 +2356,4 @@ proc launch() =
supmod4.close supmod4.close
launch() launch()
# 2339 lines # 2360 lines