package main import ( "errors" "fmt" "log" "os" "github.com/gotk3/gotk3/glib" "github.com/gotk3/gotk3/gtk" ) const appId = "com.github.gotk3.gotk3-examples.glade" type App struct { app *gtk.Application mw *gtk.ApplicationWindow // The stack holds the views of the main window stack *gtk.Stack stackMain *gtk.Box stackAbout *gtk.Grid // Detail stack variables stackDetail *gtk.Box detail struct { header *gtk.Label } dynBtnBox *gtk.Box dlgNew *gtk.FileChooserDialog listbox *gtk.ListBox } func New() *App { return &App{} } func main() { app := New() // Create a new application. application, err := gtk.ApplicationNew(appId, glib.APPLICATION_FLAGS_NONE) errorCheck(err) app.app = application // Connect function to application startup event, this is not required. application.Connect("startup", func() { log.Println("application startup") }) // Connect function to application activate event application.Connect("activate", func() { log.Println("application activate") // Get the GtkBuilder UI definition in the glade file. builder, err := gtk.BuilderNewFromFile("ui/app.glade") errorCheck(err) // Map the handlers to callback functions, and connect the signals // to the Builder. signals := map[string]interface{}{ "on_main_window_destroy": app.onMainWindowDestroy, "on_menu_home_activate": app.onBtnAboutBackClicked, "on_menu_new_activate": app.onMenuNewActivate, "on_menu_open_activate": app.onMenuOpenActivate, "on_menu_quit_activate": app.onMenuQuitActivate, "on_btn_about_clicked": app.onBtnAboutClicked, "on_btn_about_back_clicked": app.onBtnAboutBackClicked, "on_btn_detail_back_clicked": app.onBtnAboutBackClicked, } builder.ConnectSignals(signals) // Get the object with the id of "main_window". obj, err := builder.GetObject("main_window") errorCheck(err) // Verify that the object is a pointer to a gtk.ApplicationWindow. win, err := isWindow(obj) errorCheck(err) app.mw = win stack, _ := builder.GetObject("mw_stack") app.stack = stack.(*gtk.Stack) app.stackMain, _ = get(builder, "box_main").(*gtk.Box) app.stackAbout, _ = get(builder, "box_about").(*gtk.Grid) app.stackDetail, _ = get(builder, "box_detail").(*gtk.Box) app.detail.header, _ = get(builder, "box_detail_header").(*gtk.Label) app.dlgNew, _ = get(builder, "dlg_new_file").(*gtk.FileChooserDialog) app.listbox, _ = get(builder, "mw_list").(*gtk.ListBox) app.dynBtnBox, _ = get(builder, "dyn_btn_box").(*gtk.Box) for _, row := range []string{"First Button", "Second", "Third"} { app.AddButton(row) } // for _, row := range []string{"First", "Second", "Third"} { // lbRow, err := gtk.ListBoxRowNew() // errorCheck(err) // // } // Show the Window and all of its components. win.Show() application.AddWindow(win) }) // Connect function to application shutdown event, this is not required. application.Connect("shutdown", func() { log.Println("application shutdown") }) // Launch the application os.Exit(application.Run(os.Args)) } func isWindow(obj glib.IObject) (*gtk.ApplicationWindow, error) { // Make type assertion (as per gtk.go). if win, ok := obj.(*gtk.ApplicationWindow); ok { return win, nil } return nil, errors.New("not a *gtk.Window") } func get(builder *gtk.Builder, name string) glib.IObject { v, err := builder.GetObject(name) errorCheck(err) return v } func errorCheck(e error) { if e != nil { // panic for any errors. log.Panic(e) } } // adds a button to the dynBtnBox func (a *App) AddButton(label string) { btn, err := gtk.ButtonNewWithLabel(label) errorCheck(err) btn.Connect("clicked", func() { a.gotoDetailScreen(label) }) // PackEnd(widget, expand, fill, padding) a.dynBtnBox.PackStart(btn, false, true, 0) btn.Show() } // onMainWindowDestory is the callback that is linked to the // on_main_window_destroy handler. It is not required to map this, // and is here to simply demo how to hook-up custom callbacks. func (a *App) onMainWindowDestroy() { log.Println("onMainWindowDestroy") } func (a *App) onMenuNewActivate() { log.Println("new clicked") a.dlgNew.Show() } func (a *App) onMenuOpenActivate() { log.Println("open clicked") dialog, err := gtk.FileChooserDialogNewWith2Buttons( "Open File...", a.mw, gtk.FILE_CHOOSER_ACTION_OPEN, "Cancel", gtk.RESPONSE_DELETE_EVENT, "Open", gtk.RESPONSE_ACCEPT) errorCheck(err) filter, _ := gtk.FileFilterNew() filter.AddPattern("*.jpg") filter.SetName("JPEG images") dialog.AddFilter(filter) switcher := dialog.Run() log.Printf("switcher: %d\n", switcher) filename := dialog.GetFilename() dialog.Destroy() if switcher != -3 { fmt.Printf("user canceled\n") return } fmt.Printf("chosen: %s\n", filename) } func (a *App) onMenuQuitActivate() { a.mw.Destroy() // os.Exit(0) // TODO: more graceful } func (a *App) onBtnAboutClicked() { fmt.Println("about clicked") a.stack.SetTransitionType(gtk.STACK_TRANSITION_TYPE_SLIDE_LEFT) a.stack.SetVisibleChild(a.stackAbout) } func (a *App) onBtnAboutBackClicked() { a.stack.SetTransitionType(gtk.STACK_TRANSITION_TYPE_SLIDE_RIGHT) a.stack.SetVisibleChild(a.stackMain) } func (a *App) gotoDetailScreen(label string) { a.detail.header.SetText("Detail: " + label) a.stack.SetTransitionType(gtk.STACK_TRANSITION_TYPE_SLIDE_LEFT) a.stack.SetVisibleChild(a.stackDetail) }