added gearsmenu.nim example

This commit is contained in:
Stefan Salewski 2019-09-01 12:54:32 +02:00
commit c79299485c
3 changed files with 258 additions and 7 deletions

View file

@ -6,7 +6,7 @@
:source-highlighter: pygments :source-highlighter: pygments
:pygments-style: monokai :pygments-style: monokai
:icons: font :icons: font
:toc: :toc: left
:GIR: GObject-Introspection :GIR: GObject-Introspection
:MAC: MacOSX :MAC: MacOSX
@ -958,6 +958,137 @@ main()
---- ----
We can easily modify the above example to get the more modern look with
a HeaderBar and the "Gears" MenuButtons:
[[gearsmenu.nim]]
[source, nim]
.gearsmenu.nim
----
# https://developer.gnome.org/glib/stable/glib-GVariant.html
# https://developer.gnome.org/glib/stable/glib-GVariantType.html
# https://wiki.gnome.org/HowDoI/GMenu
# https://wiki.gnome.org/HowDoI/GAction
# https://developer.gnome.org/gnome-devel-demos/stable/menubutton.c.html.en
# nim c gearsmenu.nim
import gintro/[gtk, glib, gobject, gio]
import strformat
# https://github.com/GNOME/glib/blob/master/gio/tests/gapplication-example-actions.c
proc activateToggleAction(action: SimpleAction; parameter: Variant; app: Application) =
app.hold # hold/release taken over from C example, there may be reasons...
block:
echo fmt"action {action.name} activated"
let state: Variant = action.state
let b = state.getBoolean
action.state = newVariantBoolean(not b)
echo fmt"state change {b} -> {not b}"
app.release
proc activateStatefulAction(action: SimpleAction; parameter: Variant; app: Application) =
app.hold
block:
echo fmt"action {action.name} activated"
let state: Variant = action.state
var l: uint64
let oldState = state.getString(l) # yes uint64 parameter is a bit ugly
let newState = parameter.getString(l)
action.state = newVariantString(newState)
echo fmt"state change {oldState} -> {newState}"
app.release
proc quitProgram(action: SimpleAction; parameter: Variant; app: Application) =
quit(app)
proc appStartup(app: Application) =
echo "appStartup"
let quit = newSimpleAction("quit") # here we create the actions for whole app
connect(quit, "activate", quitProgram, app)
app.addAction(quit)
proc appActivate(app: Application) =
echo "appActivate"
let window = newApplicationWindow(app)
# window.title = "GTK3 App with Headerbar and Gears Menu" # unused due to HeaderBar
window.defaultSize = (500, 200)
window.position = WindowPosition.center
let menu = gio.newMenu() # root of all menus
block: # plain stateless menu
let subMenu = gio.newMenu()
menu.appendSubMenu("Application", submenu)
# let section = gio.newMenu() # no separating section needed here
# submenu.appendSection(nil, section)
# section.append("Quit", "app.quit")
submenu.append("Quit", "app.quit")
block: #stateful menu with radio items
let subMenu = gio.newMenu()
menu.appendSubMenu("Layout", submenu)
let subMenu2 = gio.newMenu()
submenu.appendSubMenu("justify", submenu2)
let section = gio.newMenu()
submenu2.appendSection(nil, section)
section.append("left", "win.justify::left")
section.append("center", "win.justify::center")
section.append("right", "win.justify::right")
block: # and finally a toggle menu
let subMenu = gio.newMenu()
menu.appendSubMenu("Spelling", submenu)
let section = gio.newMenu()
submenu.appendSection(nil, section)
section.append("Check", "win.toggleSpellCheck")
let headerBar = newHeaderBar()
headerBar.setShowCloseButton
headerBar.setTitle("Title")
headerBar.setSubtitle("Subtitle")
window.setTitlebar (headerBar)
let menubar = newMenuButton()
# menubar.setDirection(ArrowType.none) # show the gears Icon
# let image = newImageFromIconName("open-menu-symbolic", IconSize.menu.ord)
let image = newImageFromIconName("document-save", IconSize.dialog.ord) # dialog is really big!
menubar.setImage(image) # this is only an example for a custom image
# menubar.setIconName("open-menu-symbolic") # only gtk4
headerBar.packEnd(menubar)
menubar.setMenuModel(menu)
block: # creat the window related actions
let v = newVariantBoolean(true)
let spellCheck = newSimpleActionStateful("toggleSpellCheck", nil, v)
connect(spellCheck, "activate", activateToggleAction, app)
window.actionMap.addAction(spellCheck)
block:
let v = newVariantString("left") # default value and
let vt = newVariantType("s") # string (value type)
let justifyAction = newSimpleActionStateful("justify", vt, v)
connect(justifyAction, "activate", activateStatefulAction, app)
window.actionMap.addAction(justifyAction)
let button = newButton()
button.label = "Justify Center"
button.setDetailedActionName("win.justify::center")
#button.setActionName("app.quit") # for a stateless action
setAccelsForAction(app, "win.justify::right", "<Control><Shift>R")
window.add(button)
showAll(window)
proc main =
let app = newApplication("app.example")
connect(app, "startup", appStartup)
connect(app, "activate", appActivate)
echo fmt"GTK Version {majorVersion()}.{minorVersion()}.{microVersion()}"
let status = run(app)
quit(status)
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.
== GSettings == GSettings
GSettings provides a convenient way to permanently storing configuration data, GSettings provides a convenient way to permanently storing configuration data,

118
examples/gtk3/gearsmenu.nim Normal file
View file

@ -0,0 +1,118 @@
# https://developer.gnome.org/glib/stable/glib-GVariant.html
# https://developer.gnome.org/glib/stable/glib-GVariantType.html
# https://wiki.gnome.org/HowDoI/GMenu
# https://wiki.gnome.org/HowDoI/GAction
# https://developer.gnome.org/gnome-devel-demos/stable/menubutton.c.html.en
# nim c gearsmenu.nim
import gintro/[gtk, glib, gobject, gio]
import strformat
# https://github.com/GNOME/glib/blob/master/gio/tests/gapplication-example-actions.c
proc activateToggleAction(action: SimpleAction; parameter: Variant; app: Application) =
app.hold # hold/release taken over from C example, there may be reasons...
block:
echo fmt"action {action.name} activated"
let state: Variant = action.state
let b = state.getBoolean
action.state = newVariantBoolean(not b)
echo fmt"state change {b} -> {not b}"
app.release
proc activateStatefulAction(action: SimpleAction; parameter: Variant; app: Application) =
app.hold
block:
echo fmt"action {action.name} activated"
let state: Variant = action.state
var l: uint64
let oldState = state.getString(l) # yes uint64 parameter is a bit ugly
let newState = parameter.getString(l)
action.state = newVariantString(newState)
echo fmt"state change {oldState} -> {newState}"
app.release
proc quitProgram(action: SimpleAction; parameter: Variant; app: Application) =
quit(app)
proc appStartup(app: Application) =
echo "appStartup"
let quit = newSimpleAction("quit") # here we create the actions for whole app
connect(quit, "activate", quitProgram, app)
app.addAction(quit)
proc appActivate(app: Application) =
echo "appActivate"
let window = newApplicationWindow(app)
# window.title = "GTK3 App with Headerbar and Gears Menu" # unused due to HeaderBar
window.defaultSize = (500, 200)
window.position = WindowPosition.center
let menu = gio.newMenu() # root of all menus
block: # plain stateless menu
let subMenu = gio.newMenu()
menu.appendSubMenu("Application", submenu)
# let section = gio.newMenu() # no separating section needed here
# submenu.appendSection(nil, section)
# section.append("Quit", "app.quit")
submenu.append("Quit", "app.quit")
block: #stateful menu with radio items
let subMenu = gio.newMenu()
menu.appendSubMenu("Layout", submenu)
let subMenu2 = gio.newMenu()
submenu.appendSubMenu("justify", submenu2)
let section = gio.newMenu()
submenu2.appendSection(nil, section)
section.append("left", "win.justify::left")
section.append("center", "win.justify::center")
section.append("right", "win.justify::right")
block: # and finally a toggle menu
let subMenu = gio.newMenu()
menu.appendSubMenu("Spelling", submenu)
let section = gio.newMenu()
submenu.appendSection(nil, section)
section.append("Check", "win.toggleSpellCheck")
let headerBar = newHeaderBar()
headerBar.setShowCloseButton
headerBar.setTitle("Title")
headerBar.setSubtitle("Subtitle")
window.setTitlebar (headerBar)
let menubar = newMenuButton()
# menubar.setDirection(ArrowType.none) # show the gears Icon
# let image = newImageFromIconName("open-menu-symbolic", IconSize.menu.ord)
let image = newImageFromIconName("document-save", IconSize.dialog.ord) # dialog is really big!
menubar.setImage(image) # this is only an example for a custom image
# menubar.setIconName("open-menu-symbolic") # only gtk4
headerBar.packEnd(menubar)
menubar.setMenuModel(menu)
block: # creat the window related actions
let v = newVariantBoolean(true)
let spellCheck = newSimpleActionStateful("toggleSpellCheck", nil, v)
connect(spellCheck, "activate", activateToggleAction, app)
window.actionMap.addAction(spellCheck)
block:
let v = newVariantString("left") # default value and
let vt = newVariantType("s") # string (value type)
let justifyAction = newSimpleActionStateful("justify", vt, v)
connect(justifyAction, "activate", activateStatefulAction, app)
window.actionMap.addAction(justifyAction)
let button = newButton()
button.label = "Justify Center"
button.setDetailedActionName("win.justify::center")
#button.setActionName("app.quit") # for a stateless action
setAccelsForAction(app, "win.justify::right", "<Control><Shift>R")
window.add(button)
showAll(window)
proc main =
let app = newApplication("app.example")
connect(app, "startup", appStartup)
connect(app, "activate", appActivate)
echo fmt"GTK Version {majorVersion()}.{minorVersion()}.{microVersion()}"
let status = run(app)
quit(status)
main()

View file

@ -7,17 +7,17 @@ import gintro/[gtk, glib, gobject, gio]
from strutils import `%`, format from strutils import `%`, format
# https://github.com/GNOME/glib/blob/master/gio/tests/gapplication-example-actions.c # https://github.com/GNOME/glib/blob/master/gio/tests/gapplication-example-actions.c
proc activateToggleAction(action: SimpleAction; parameter: Variant; app: Application) = proc activateToggleAction(action: SimpleAction; parameter: Variant; app: Application) =
app.hold # hold/release taken over from C example, there may be reasons... app.hold # hold/release taken over from C example, there may be reasons...
block: block:
echo format("action $1 activated", action.name) echo format("action $1 activated", action.name)
let state: Variant = action.state let state: Variant = action.state
let b = state.getBoolean let b = state.getBoolean
action.state = newVariantBoolean(not b) action.state = newVariantBoolean(not b)
echo format("state change $1 -> $2", b, not b) echo format("state change $1 -> $2", b, not b)
app.release app.release
proc activateStatefulAction(action: SimpleAction; parameter: Variant; app: Application) = proc activateStatefulAction(action: SimpleAction; parameter: Variant; app: Application) =
app.hold app.hold
block: block:
echo format("action $1 activated", action.name) echo format("action $1 activated", action.name)
@ -25,7 +25,7 @@ proc activateStatefulAction(action: SimpleAction; parameter: Variant; app: Appli
var l: uint64 var l: uint64
let oldState = state.getString(l) # yes uint64 parameter is a bit ugly let oldState = state.getString(l) # yes uint64 parameter is a bit ugly
let newState = parameter.getString(l) let newState = parameter.getString(l)
action.state = newVariantString(newState) action.state = newVariantString(newState)
echo format("state change $1 -> $2", oldState, newState) echo format("state change $1 -> $2", oldState, newState)
app.release app.release
@ -33,6 +33,7 @@ proc quitProgram(action: SimpleAction; parameter: Variant; app: Application) =
quit(app) quit(app)
proc appStartup(app: Application) = proc appStartup(app: Application) =
echo "appStartup"
let quit = newSimpleAction("quit") # here we create the actions for whole app let quit = newSimpleAction("quit") # here we create the actions for whole app
connect(quit, "activate", quitProgram, app) connect(quit, "activate", quitProgram, app)
app.addAction(quit) app.addAction(quit)
@ -63,10 +64,11 @@ proc appStartup(app: Application) =
let section = gio.newMenu() let section = gio.newMenu()
submenu.appendSection(nil, section) submenu.appendSection(nil, section)
section.append("Check", "win.toggleSpellCheck") section.append("Check", "win.toggleSpellCheck")
# finally add the menubar # finally add the menubar
setMenuBar(app, menu) setMenuBar(app, menu)
proc appActivate(app: Application) = proc appActivate(app: Application) =
echo "appActivate"
let window = newApplicationWindow(app) let window = newApplicationWindow(app)
window.title = "GTK3 App with Menubar" window.title = "GTK3 App with Menubar"
window.defaultSize = (500, 200) window.defaultSize = (500, 200)
@ -87,7 +89,7 @@ proc appActivate(app: Application) =
#window.add(button) # do not add it here already: (menubar:10010): Gtk-WARNING **: 22:00:33.230: actionhelper: #window.add(button) # do not add it here already: (menubar:10010): Gtk-WARNING **: 22:00:33.230: actionhelper:
# action win.justify can't be activated due to parameter type mismatch (parameter type s, target type NULL) # action win.justify can't be activated due to parameter type mismatch (parameter type s, target type NULL)
button.setDetailedActionName("win.justify::center") button.setDetailedActionName("win.justify::center")
#button.setActionName("app.quit") # for a stateless action #button.setActionName("app.quit") # for a stateless action
setAccelsForAction(app, "win.justify::right", "<Control><Shift>R") setAccelsForAction(app, "win.justify::right", "<Control><Shift>R")
window.add(button) window.add(button)
showAll(window) showAll(window)