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 = """ + + +
+ + Normal Menu Item + win.normal-menu-item + + + Submenu + + Submenu Item + win.submenu-item + + + + Toggle Menu Item + win.toggle-menu-item + +
+
+ + Radio 1 + win.radio + 1 + + + Radio 2 + win.radio + 2 + + + Radio 3 + win.radio + 3 + +
+
+
+""" + +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 = """ + + +
+ + Normal Menu Item + win.normal-menu-item + + + Submenu + + Submenu Item + win.submenu-item + + + + Toggle Menu Item + win.toggle-menu-item + +
+
+ + Radio 1 + win.radio + 1 + + + Radio 2 + win.radio + 2 + + + Radio 3 + win.radio + 3 + +
+
+
+""" + +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