Experimenting with Go GTK+
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

223 lines
5.3 KiB

  1. package main
  2. import (
  3. "errors"
  4. "fmt"
  5. "log"
  6. "os"
  7. "github.com/gotk3/gotk3/glib"
  8. "github.com/gotk3/gotk3/gtk"
  9. )
  10. const appId = "com.github.gotk3.gotk3-examples.glade"
  11. type App struct {
  12. app *gtk.Application
  13. mw *gtk.ApplicationWindow
  14. // The stack holds the views of the main window
  15. stack *gtk.Stack
  16. stackMain *gtk.Box
  17. stackAbout *gtk.Grid
  18. // Detail stack variables
  19. stackDetail *gtk.Box
  20. detail struct {
  21. header *gtk.Label
  22. }
  23. dynBtnBox *gtk.Box
  24. dlgNew *gtk.FileChooserDialog
  25. listbox *gtk.ListBox
  26. }
  27. func New() *App {
  28. return &App{}
  29. }
  30. func main() {
  31. app := New()
  32. // Create a new application.
  33. application, err := gtk.ApplicationNew(appId, glib.APPLICATION_FLAGS_NONE)
  34. errorCheck(err)
  35. app.app = application
  36. // Connect function to application startup event, this is not required.
  37. application.Connect("startup", func() {
  38. log.Println("application startup")
  39. })
  40. // Connect function to application activate event
  41. application.Connect("activate", func() {
  42. log.Println("application activate")
  43. // Get the GtkBuilder UI definition in the glade file.
  44. builder, err := gtk.BuilderNewFromFile("ui/app.glade")
  45. errorCheck(err)
  46. // Map the handlers to callback functions, and connect the signals
  47. // to the Builder.
  48. signals := map[string]interface{}{
  49. "on_main_window_destroy": app.onMainWindowDestroy,
  50. "on_menu_home_activate": app.onBtnAboutBackClicked,
  51. "on_menu_new_activate": app.onMenuNewActivate,
  52. "on_menu_open_activate": app.onMenuOpenActivate,
  53. "on_menu_quit_activate": app.onMenuQuitActivate,
  54. "on_btn_about_clicked": app.onBtnAboutClicked,
  55. "on_btn_about_back_clicked": app.onBtnAboutBackClicked,
  56. "on_btn_detail_back_clicked": app.onBtnAboutBackClicked,
  57. }
  58. builder.ConnectSignals(signals)
  59. // Get the object with the id of "main_window".
  60. obj, err := builder.GetObject("main_window")
  61. errorCheck(err)
  62. // Verify that the object is a pointer to a gtk.ApplicationWindow.
  63. win, err := isWindow(obj)
  64. errorCheck(err)
  65. app.mw = win
  66. stack, _ := builder.GetObject("mw_stack")
  67. app.stack = stack.(*gtk.Stack)
  68. app.stackMain, _ = get(builder, "box_main").(*gtk.Box)
  69. app.stackAbout, _ = get(builder, "box_about").(*gtk.Grid)
  70. app.stackDetail, _ = get(builder, "box_detail").(*gtk.Box)
  71. app.detail.header, _ = get(builder, "box_detail_header").(*gtk.Label)
  72. app.dlgNew, _ = get(builder, "dlg_new_file").(*gtk.FileChooserDialog)
  73. app.listbox, _ = get(builder, "mw_list").(*gtk.ListBox)
  74. app.dynBtnBox, _ = get(builder, "dyn_btn_box").(*gtk.Box)
  75. for _, row := range []string{"First Button", "Second", "Third"} {
  76. app.AddButton(row)
  77. }
  78. // for _, row := range []string{"First", "Second", "Third"} {
  79. // lbRow, err := gtk.ListBoxRowNew()
  80. // errorCheck(err)
  81. //
  82. // }
  83. // Show the Window and all of its components.
  84. win.Show()
  85. application.AddWindow(win)
  86. })
  87. // Connect function to application shutdown event, this is not required.
  88. application.Connect("shutdown", func() {
  89. log.Println("application shutdown")
  90. })
  91. // Launch the application
  92. os.Exit(application.Run(os.Args))
  93. }
  94. func isWindow(obj glib.IObject) (*gtk.ApplicationWindow, error) {
  95. // Make type assertion (as per gtk.go).
  96. if win, ok := obj.(*gtk.ApplicationWindow); ok {
  97. return win, nil
  98. }
  99. return nil, errors.New("not a *gtk.Window")
  100. }
  101. func get(builder *gtk.Builder, name string) glib.IObject {
  102. v, err := builder.GetObject(name)
  103. errorCheck(err)
  104. return v
  105. }
  106. func errorCheck(e error) {
  107. if e != nil {
  108. // panic for any errors.
  109. log.Panic(e)
  110. }
  111. }
  112. // adds a button to the dynBtnBox
  113. func (a *App) AddButton(label string) {
  114. btn, err := gtk.ButtonNewWithLabel(label)
  115. errorCheck(err)
  116. btn.Connect("clicked", func() {
  117. a.gotoDetailScreen(label)
  118. })
  119. // PackEnd(widget, expand, fill, padding)
  120. a.dynBtnBox.PackStart(btn, false, true, 0)
  121. btn.Show()
  122. }
  123. // onMainWindowDestory is the callback that is linked to the
  124. // on_main_window_destroy handler. It is not required to map this,
  125. // and is here to simply demo how to hook-up custom callbacks.
  126. func (a *App) onMainWindowDestroy() {
  127. log.Println("onMainWindowDestroy")
  128. }
  129. func (a *App) onMenuNewActivate() {
  130. log.Println("new clicked")
  131. a.dlgNew.Show()
  132. }
  133. func (a *App) onMenuOpenActivate() {
  134. log.Println("open clicked")
  135. dialog, err := gtk.FileChooserDialogNewWith2Buttons(
  136. "Open File...",
  137. a.mw,
  138. gtk.FILE_CHOOSER_ACTION_OPEN,
  139. "Cancel",
  140. gtk.RESPONSE_DELETE_EVENT,
  141. "Open",
  142. gtk.RESPONSE_ACCEPT)
  143. errorCheck(err)
  144. filter, _ := gtk.FileFilterNew()
  145. filter.AddPattern("*.jpg")
  146. filter.SetName("JPEG images")
  147. dialog.AddFilter(filter)
  148. switcher := dialog.Run()
  149. log.Printf("switcher: %d\n", switcher)
  150. filename := dialog.GetFilename()
  151. dialog.Destroy()
  152. if switcher != -3 {
  153. fmt.Printf("user canceled\n")
  154. return
  155. }
  156. fmt.Printf("chosen: %s\n", filename)
  157. }
  158. func (a *App) onMenuQuitActivate() {
  159. a.mw.Destroy()
  160. // os.Exit(0) // TODO: more graceful
  161. }
  162. func (a *App) onBtnAboutClicked() {
  163. fmt.Println("about clicked")
  164. a.stack.SetTransitionType(gtk.STACK_TRANSITION_TYPE_SLIDE_LEFT)
  165. a.stack.SetVisibleChild(a.stackAbout)
  166. }
  167. func (a *App) onBtnAboutBackClicked() {
  168. a.stack.SetTransitionType(gtk.STACK_TRANSITION_TYPE_SLIDE_RIGHT)
  169. a.stack.SetVisibleChild(a.stackMain)
  170. }
  171. func (a *App) gotoDetailScreen(label string) {
  172. a.detail.header.SetText("Detail: " + label)
  173. a.stack.SetTransitionType(gtk.STACK_TRANSITION_TYPE_SLIDE_LEFT)
  174. a.stack.SetVisibleChild(a.stackDetail)
  175. }