commit 1d2e4c0bf6e0cb703a310eaa64edcd1c1098d59f Author: Noah Petherbridge Date: Wed Jul 1 15:40:38 2020 -0700 Initial commit diff --git a/main.go b/main.go new file mode 100644 index 0000000..1a02c1a --- /dev/null +++ b/main.go @@ -0,0 +1,222 @@ +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) +} diff --git a/ui/app.glade b/ui/app.glade new file mode 100644 index 0000000..d21b7f7 --- /dev/null +++ b/ui/app.glade @@ -0,0 +1,331 @@ + + + + + + False + Choose your file + dialog + + + + False + vertical + 2 + + + False + end + + + Accept + True + True + True + + + True + True + 0 + + + + + Cancel + True + True + True + + + True + True + 1 + + + + + False + False + 0 + + + + + + + + + + + + + True + False + + + True + False + Home + True + + + + + + True + False + + + + + True + False + New + True + + + + + + + True + False + Open + True + + + + + + + True + False + Save + True + + + + + + + True + False + + + + + True + False + Quit + True + + + + + + + 360 + 720 + False + False + + + + True + False + slide-left + + + True + False + vertical + + + True + False + + + True + True + 0 + + + + + True + False + vertical + + + Glade button + True + True + True + + + False + True + 0 + + + + + + + + + + + False + True + 1 + + + + + About + True + True + True + + + + False + True + 2 + + + + + page0 + page0 + + + + + stack_about + True + False + + + True + False + The About Screen! + + + 1 + 0 + + + + + Back + True + True + True + + + + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + page1 + page1 + 1 + + + + + True + False + vertical + + + True + False + label + + + + + + + False + True + 0 + + + + + Back to Menu + True + True + True + + + + False + True + 1 + + + + + + + + page2 + page2 + 2 + + + + + + + True + False + Hello world + Test + True + + + True + True + False + True + menu1 + False + + + + + + + + +