From e64c67bcb68f4ad8ee0e05edeebd5555fd6ede65 Mon Sep 17 00:00:00 2001 From: Stefan Salewski Date: Mon, 9 Dec 2019 17:49:32 +0100 Subject: [PATCH] GTK4 headerbar example added. --- README.adoc | 143 ++++++++++++++++++++++++++++++++++++ examples/gtk4/headerbar.nim | 118 +++++++++++++++++++++++++++++ 2 files changed, 261 insertions(+) create mode 100644 examples/gtk4/headerbar.nim diff --git a/README.adoc b/README.adoc index 44f65da..9d3c7db 100644 --- a/README.adoc +++ b/README.adoc @@ -2617,5 +2617,148 @@ proc main = main() ---- +== A HeaderBar example for GTK4 + +The following code is the Nim version of a GTK4 example in C. It will work in its unmodified form +only if you have GTK4 already installed -- my GTK4 lives at /opt/gtk and I have to type these +commands before I can use GTK4 programs like gtk4-demo: + +---- +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/gtk/lib64/ +export GSETTINGS_SCHEMA_DIR=/opt/gtk/share/glib-2.0/schemas /opt/gtk/bin/gtk4-demo +#export PKG_CONFIG_PATH="/opt/gtk/lib64/pkgconfig/" # only when compiling C code directly + +---- + +The example is a bit complicated, as a custom (fake) headerbar is created, which involves a cast in C and Nim code. +The example shows how to use a default headerbar, how to open a file dialog and how to use images and CSS styling. +I guess most of the code would work in GTK3 also, but I have not tried to make a GTK3 version out of it, and I even +do not understand all of the code yet. Note that for this example destroy() is not connected to the window close +button, but called after gtk4.main(). A bit strange indeed, see forum note of Mr E.Bassi. + +[[headerbar.nim]] +[source,nim] +.headerbar.nim +---- +# https://github.com/GNOME/gtk/blob/mainline/tests/testheaderbar.c +# nim c headerbar.nim +import gintro/[gtk4, glib, gobject, gio] + +const + Css = """ + .main.background { + background-image: linear-gradient(to bottom, red, blue); + border-width: 0px; + } + .titlebar.backdrop { + background-image: none; + background-color: @bg_color; + border-radius: 10px 10px 0px 0px; + } + .titlebar { + background-image: linear-gradient(to bottom, white, @bg_color); + border-radius: 10px 10px 0px 0px; + } +""" + +# we try to avoid use of global header variable as done in C code +type + MyWindow = ref object of gtk4.Window + header: gtk4.Headerbar + +proc response(d: gtk4.FileChooserDialog; responseID: int) = gtk4.destroy(d) + +proc onBookmarkClicked(button: Button; data: MyWindow) = + let window = gtk4.Window(data) + let chooser = newFileChooserDialog("File Chooser Test", window, + FileChooserAction.open) + discard chooser.addButton("_Close", gtk4.ResponseType.close.ord) + chooser.connect("response", response) + chooser.show + +proc changeSubtitle(button: Button; w: MyWindow) = + if w.header.subtitle == "": + w.header.setSubtitle("(subtle subtitle)") + else: + w.header.setSubtitle("") # can we pass nil? + +proc toggleFullscreen(button: Button; window: MyWindow) = + var fullscreen {.global.}: bool + if fullscreen: + window.unfullscreen + fullscreen = false + else: + window.fullscreen + fullscreen = true + +proc toIntVal(i: int): Value = + let gtype = typeFromName("gint") + discard init(result, gtype) + setInt(result, i) + +proc quit(b: Button) = gtk4.mainQuit() + +proc changeHeader(button: ToggleButton; window: MyWindow) = + if button != nil and button.getActive: + window.header = cast[HeaderBar](newBox(gtk4.Orientation.horizontal, + 10)) # intended cast, see C code! + addClass(getStyleContext(window.header), "titlebar") + addClass(getStyleContext(window.header), "header-bar") + window.header.setProperty("margin", toIntVal(10)) + let label = newLabel("Label") + window.header.add(label) + let levelBar = newLevelBar() + levelBar.setValue(0.4) + levelBar.setHexpand + window.header.add(levelBar) + else: + window.header = newHeaderBar() + addClass(getStyleContext(window.header), "titlebar") + window.header.setTitle("Example header") + var button = newButton("_Close") + button.setUseUnderline + addClass(getStyleContext(button), "suggested-action") + button.connect("clicked", quit) + window.header.packEnd(button) + button = newButton() + let image = newImageFromIconName("bookmark-new-symbolic") + button.connect("clicked", onBookmarkClicked, window) + button.add(image) + window.header.packStart(button) + window.setTitlebar(window.header) + +proc main = + gtk4.init() + var window: MyWindow + initWindow(window) + addClass(getStyleContext(window), "main") + let provider = newCssProvider() + provider.loadFromData(Css) + addProviderForDisplay(getDisplay(window), provider, STYLE_PROVIDER_PRIORITY_USER) + changeHeader(nil, window) + let box = newBox(Orientation.vertical, 0) + window.add(box) + let content = newImageFromIconName("start-here-symbolic") + content.setPixelSize(512) + box.add(content) + let footer = newActionBar() + footer.setCenterWidget(newCheckButtonWithLabel("Middle")) + let button = newToggleButtonWithLabel("Custom") + button.connect("clicked", changeHeader, window) + footer.packStart(button) + var button1 = newButton("Subtitle") + button1.connect("clicked", changeSubtitle, window) + footer.packEnd(button1) + button1 = newButton("Fullscreen") + footer.packEnd(button1) + button1.connect("clicked", toggleFullscreen, window) + box.add(footer) + window.show + gtk4.main() + destroy(window) # this is special for this example, see https://discourse.gnome.org/t/tests-testgaction-c/2232/6 + +main() # 118 lines +---- + NOTE: Related work: https://github.com/jdmansour/nim-smartgi diff --git a/examples/gtk4/headerbar.nim b/examples/gtk4/headerbar.nim new file mode 100644 index 0000000..356fb8d --- /dev/null +++ b/examples/gtk4/headerbar.nim @@ -0,0 +1,118 @@ +# https://github.com/GNOME/gtk/blob/mainline/tests/testheaderbar.c +# nim c headerbar.nim +import gintro/[gtk4, glib, gobject, gio] + +const + Css = """ + .main.background { + background-image: linear-gradient(to bottom, red, blue); + border-width: 0px; + } + .titlebar.backdrop { + background-image: none; + background-color: @bg_color; + border-radius: 10px 10px 0px 0px; + } + .titlebar { + background-image: linear-gradient(to bottom, white, @bg_color); + border-radius: 10px 10px 0px 0px; + } +""" + +# we try to avoid use of global header variable as done in C code +type + MyWindow = ref object of gtk4.Window + header: gtk4.Headerbar + +proc response(d: gtk4.FileChooserDialog; responseID: int) = gtk4.destroy(d) + +proc onBookmarkClicked(button: Button; data: MyWindow) = + let window = gtk4.Window(data) + let chooser = newFileChooserDialog("File Chooser Test", window, + FileChooserAction.open) + discard chooser.addButton("_Close", gtk4.ResponseType.close.ord) + chooser.connect("response", response) + chooser.show + +proc changeSubtitle(button: Button; w: MyWindow) = + if w.header.subtitle == "": + w.header.setSubtitle("(subtle subtitle)") + else: + w.header.setSubtitle("") # can we pass nil? + +proc toggleFullscreen(button: Button; window: MyWindow) = + var fullscreen {.global.}: bool + if fullscreen: + window.unfullscreen + fullscreen = false + else: + window.fullscreen + fullscreen = true + +proc toIntVal(i: int): Value = + let gtype = typeFromName("gint") + discard init(result, gtype) + setInt(result, i) + +proc quit(b: Button) = gtk4.mainQuit() + +proc changeHeader(button: ToggleButton; window: MyWindow) = + if button != nil and button.getActive: + window.header = cast[HeaderBar](newBox(gtk4.Orientation.horizontal, + 10)) # intended cast, see C code! + addClass(getStyleContext(window.header), "titlebar") + addClass(getStyleContext(window.header), "header-bar") + window.header.setProperty("margin", toIntVal(10)) + let label = newLabel("Label") + window.header.add(label) + let levelBar = newLevelBar() + levelBar.setValue(0.4) + levelBar.setHexpand + window.header.add(levelBar) + else: + window.header = newHeaderBar() + addClass(getStyleContext(window.header), "titlebar") + window.header.setTitle("Example header") + var button = newButton("_Close") + button.setUseUnderline + addClass(getStyleContext(button), "suggested-action") + button.connect("clicked", quit) + window.header.packEnd(button) + button = newButton() + let image = newImageFromIconName("bookmark-new-symbolic") + button.connect("clicked", onBookmarkClicked, window) + button.add(image) + window.header.packStart(button) + window.setTitlebar(window.header) + +proc main = + gtk4.init() + var window: MyWindow + initWindow(window) + addClass(getStyleContext(window), "main") + let provider = newCssProvider() + provider.loadFromData(Css) + addProviderForDisplay(getDisplay(window), provider, STYLE_PROVIDER_PRIORITY_USER) + changeHeader(nil, window) + let box = newBox(Orientation.vertical, 0) + window.add(box) + let content = newImageFromIconName("start-here-symbolic") + content.setPixelSize(512) + box.add(content) + let footer = newActionBar() + footer.setCenterWidget(newCheckButtonWithLabel("Middle")) + let button = newToggleButtonWithLabel("Custom") + button.connect("clicked", changeHeader, window) + footer.packStart(button) + var button1 = newButton("Subtitle") + button1.connect("clicked", changeSubtitle, window) + footer.packEnd(button1) + button1 = newButton("Fullscreen") + footer.packEnd(button1) + button1.connect("clicked", toggleFullscreen, window) + box.add(footer) + window.show + gtk4.main() + destroy(window) # this is special for this example, see https://discourse.gnome.org/t/tests-testgaction-c/2232/6 + +main() # 118 lines