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.
 
 

222 lines
5.3 KiB

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)
}