func windowWidget() *gtk.Widget { grid, err := gtk.GridNew() if err != nil { log.Fatal("Unable to create grid:", err) } grid.SetOrientation(gtk.ORIENTATION_VERTICAL) entry, err := gtk.EntryNew() if err != nil { log.Fatal("Unable to create entry:", err) } s, _ := entry.GetText() label, err := gtk.LabelNew(s) if err != nil { log.Fatal("Unable to create label:", err) } grid.Add(entry) entry.SetHExpand(true) grid.AttachNextTo(label, entry, gtk.POS_RIGHT, 1, 1) label.SetHExpand(true) // Connects this entry's "activate" signal (which is emitted whenever // Enter is pressed when the Entry is activated) to an anonymous // function that gets the current text of the entry and sets the text of // the label beside it with it. Unlike with native GTK callbacks, // (*glib.Object).Connect() supports closures. In this example, this is // demonstrated by using the label variable. Without closures, a // pointer to the label would need to be passed in as user data // (demonstrated in the next example). entry.Connect("activate", func() { s, _ := entry.GetText() label.SetText(s) }) sb, err := gtk.SpinButtonNewWithRange(0, 1, 0.1) if err != nil { log.Fatal("Unable to create spin button:", err) } pb, err := gtk.ProgressBarNew() if err != nil { log.Fatal("Unable to create progress bar:", err) } grid.Add(sb) sb.SetHExpand(true) grid.AttachNextTo(pb, sb, gtk.POS_RIGHT, 1, 1) label.SetHExpand(true) // Pass in a ProgressBar and the target SpinButton as user data rather // than using the sb and pb variables scoped to the anonymous func. // This can be useful when passing in a closure that has already been // generated, but when you still wish to connect the callback with some // variables only visible in this scope. sb.Connect("value-changed", func(obj *glib.Object, pb *gtk.ProgressBar) { sb := >k.SpinButton{gtk.Entry{gtk.Widget{ glib.InitiallyUnowned{obj}}}} pb.SetFraction(sb.GetValue() / 1) }, pb) label, err = gtk.LabelNew("") if err != nil { log.Fatal("Unable to create label:", err) } s = "Hyperlink to <a href=\"https://www.cyphertite.com/\">Cyphertite</a> for your clicking pleasure" label.SetMarkup(s) grid.AttachNextTo(label, sb, gtk.POS_BOTTOM, 2, 1) // Some GTK callback functions require arguments, such as the // 'gchar *uri' argument of GtkLabel's "activate-link" signal. To use // these arguments, pass in a *glib.CallbackContext as an argument, and // access by calling (*glib.CallbackContext).Arg(n) for the nth // argument. label.Connect("activate-link", func(_ *glib.Object, uri string) { fmt.Println("you clicked a link to:", uri) }) return &grid.Container.Widget }
func main() { gtk.Init(nil) win, err := gtk.WindowNew(gtk.WINDOW_TOPLEVEL) if err != nil { log.Fatal("Unable to create window:", err) } win.SetTitle("Grid Example") win.Connect("destroy", func() { gtk.MainQuit() }) // Create a new grid widget to arrange child widgets grid, err := gtk.GridNew() if err != nil { log.Fatal("Unable to create grid:", err) } // gtk.Grid embeds an Orientable struct to simulate the GtkOrientable // GInterface. Set the orientation from the default horizontal to // vertical. grid.SetOrientation(gtk.ORIENTATION_VERTICAL) // Create some widgets to put in the grid. lab, err := gtk.LabelNew("Just a label") if err != nil { log.Fatal("Unable to create label:", err) } btn, err := gtk.ButtonNewWithLabel("Button with label") if err != nil { log.Fatal("Unable to create button:", err) } entry, err := gtk.EntryNew() if err != nil { log.Fatal("Unable to create entry:", err) } spnBtn, err := gtk.SpinButtonNewWithRange(0.0, 1.0, 0.001) if err != nil { log.Fatal("Unable to create spin button:", err) } nb, err := gtk.NotebookNew() if err != nil { log.Fatal("Unable to create notebook:", err) } // Calling (*gtk.Container).Add() with a gtk.Grid will add widgets next // to each other, in the order they were added, to the right side of the // last added widget when the grid is in a horizontal orientation, and // at the bottom of the last added widget if the grid is in a vertial // orientation. Using a grid in this manner works similar to a gtk.Box, // but unlike gtk.Box, a gtk.Grid will respect its child widget's expand // and margin properties. grid.Add(btn) grid.Add(lab) grid.Add(entry) grid.Add(spnBtn) // Widgets may also be added by calling (*gtk.Grid).Attach() to specify // where to place the widget in the grid, and optionally how many rows // and columns to span over. // // Additional rows and columns are automatically added to the grid as // necessary when new widgets are added with (*gtk.Container).Add(), or, // as shown in this case, using (*gtk.Grid).Attach(). // // In this case, a notebook is added beside the widgets inserted above. // The notebook widget is inserted with a left position of 1, a top // position of 1 (starting at the same vertical position as the button), // a width of 1 column, and a height of 2 rows (spanning down to the // same vertical position as the entry). // // This example also demonstrates how not every area of the grid must // contain a widget. In particular, the area to the right of the label // and the right of spin button have contain no widgets. grid.Attach(nb, 1, 1, 1, 2) nb.SetHExpand(true) nb.SetVExpand(true) // Add a child widget and tab label to the notebook so it renders. nbChild, err := gtk.LabelNew("Notebook content") if err != nil { log.Fatal("Unable to create button:", err) } nbTab, err := gtk.LabelNew("Tab label") if err != nil { log.Fatal("Unable to create label:", err) } nb.AppendPage(nbChild, nbTab) // Add the grid to the window, and show all widgets. win.Add(grid) win.ShowAll() gtk.Main() }
// createUnlockDialog creates a dialog to enter a passphrase and unlock // an encrypted wallet. If an OK response is received, the passphrase will // be used to attempt a wallet unlock. // // If success is non-nil, the caller may pass in a channel to receive a // notification for whether the unlock was successful. If the dialog is // closed without sending a request to btcwallet and the channel is // non-nil, the channel is closed. func createUnlockDialog(reason *UnlockText, success chan bool) (*gtk.Dialog, error) { dialog, err := gtk.DialogNew() if err != nil { return nil, err } dialog.SetTitle(reason.Title) dialog.AddButton("_OK", gtk.RESPONSE_OK) dialog.AddButton("_Cancel", gtk.RESPONSE_CANCEL) grid, err := gtk.GridNew() if err != nil { return nil, err } grid.SetHExpand(true) grid.SetVExpand(true) b, err := dialog.GetContentArea() if err != nil { return nil, err } b.Add(grid) b.SetHExpand(true) b.SetVExpand(true) lbl, err := gtk.LabelNew(reason.Message) if err != nil { return nil, err } grid.Attach(lbl, 0, 0, 2, 1) lbl, err = gtk.LabelNew("Passphrase") if err != nil { return nil, err } grid.Attach(lbl, 0, 1, 1, 1) passphrase, err := gtk.EntryNew() if err != nil { return nil, err } passphrase.SetVisibility(false) passphrase.SetHExpand(true) passphrase.SetVExpand(true) passphrase.Connect("activate", func() { dialog.Emit("response", gtk.RESPONSE_OK, nil) }) grid.Attach(passphrase, 1, 1, 1, 1) lbl, err = gtk.LabelNew("Timeout (s)") if err != nil { return nil, err } grid.Attach(lbl, 0, 2, 1, 1) timeout, err := gtk.SpinButtonNewWithRange(0, float64(1<<64-1), 1) if err != nil { return nil, err } timeout.SetValue(60) timeout.Connect("activate", func() { dialog.Emit("response", gtk.RESPONSE_OK, nil) }) grid.Attach(timeout, 1, 2, 1, 1) dialog.SetTransientFor(mainWindow) dialog.SetPosition(gtk.WIN_POS_CENTER_ON_PARENT) dialog.ShowAll() dialog.Connect("response", func(_ *glib.Object, rt gtk.ResponseType) { switch rt { case gtk.RESPONSE_OK: pStr, err := passphrase.GetText() if err != nil { log.Print(err) return } timeoutSecs := timeout.GetValueAsInt() go func() { triggers.unlockWallet <- &UnlockParams{ pStr, int64(timeoutSecs), } if ok := <-triggerReplies.unlockSuccessful; ok { if success != nil { success <- true } glib.IdleAdd(func() { dialog.Destroy() }) } else { if success != nil { success <- false } glib.IdleAdd(func() { mDialog := gtk.MessageDialogNew(dialog, 0, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, "Wallet decryption failed.") mDialog.SetTitle("Wallet decryption failed") mDialog.Run() mDialog.Destroy() }) } }() case gtk.RESPONSE_CANCEL: if success != nil { close(success) } dialog.Destroy() } }) return dialog, nil }
func createTxFeeDialog() (*gtk.Dialog, error) { dialog, err := gtk.DialogNew() if err != nil { return nil, err } dialog.SetTitle("Set Transaction Fee") dialog.AddButton("_OK", gtk.RESPONSE_OK) dialog.AddButton("_Cancel", gtk.RESPONSE_CANCEL) grid, err := gtk.GridNew() if err != nil { return nil, err } grid.SetHExpand(true) grid.SetVExpand(true) grid.SetOrientation(gtk.ORIENTATION_VERTICAL) b, err := dialog.GetContentArea() if err != nil { return nil, err } b.Add(grid) b.SetHExpand(true) b.SetVExpand(true) l, err := gtk.LabelNew(txFeeMessage) if err != nil { return nil, err } l.SetHExpand(true) l.SetVExpand(true) l.SetHAlign(gtk.ALIGN_START) grid.Add(l) spinb, err := gtk.SpinButtonNewWithRange(0, 21000000, 0.00000001) if err != nil { return nil, err } grid.Add(spinb) dialog.SetTransientFor(mainWindow) dialog.SetPosition(gtk.WIN_POS_CENTER_ON_PARENT) dialog.ShowAll() dialog.Connect("response", func(_ *glib.Object, rt gtk.ResponseType) { switch rt { case gtk.RESPONSE_OK: fee := spinb.GetValue() go func() { triggers.setTxFee <- fee if err := <-triggerReplies.setTxFeeErr; err != nil { d := errorDialog("Error setting transaction fee:", err.Error()) d.Run() d.Destroy() } else { glib.IdleAdd(func() { dialog.Destroy() }) } }() case gtk.RESPONSE_CANCEL: dialog.Destroy() } }) return dialog, nil }
func createRecipient(rmFn func(*glib.Object, *recipient)) *recipient { ret := new(recipient) ret.n = recipients.Len() grid, err := gtk.GridNew() if err != nil { log.Fatal(err) } ret.Widget = grid.Container.Widget l, err := gtk.LabelNew("Pay To:") if err != nil { log.Fatal(err) } grid.Attach(l, 0, 0, 1, 1) l, err = gtk.LabelNew("Amount:") if err != nil { log.Fatal(err) } grid.Attach(l, 0, 1, 1, 1) payTo, err := gtk.EntryNew() if err != nil { log.Fatal(err) } payTo.SetHExpand(true) ret.payTo = payTo grid.Attach(payTo, 1, 0, 1, 1) remove, err := gtk.ButtonNew() if err != nil { log.Fatal(err) } img, err := gtk.ImageNewFromIconName("_Delete", gtk.ICON_SIZE_MENU) if err != nil { log.Fatal(err) } remove.SetImage(img) remove.SetTooltipText("Remove this recipient") remove.Connect("clicked", rmFn, ret) grid.Attach(remove, 2, 0, 1, 1) // TODO(jrick): Label doesn't do anything currently, so don't add // to gui. /* l, err = gtk.LabelNew("Label:") if err != nil { log.Fatal(err) } grid.Attach(l, 0, 1, 1, 1) label, err := gtk.EntryNew() if err != nil { log.Fatal(err) } label.SetHExpand(true) ret.label = label grid.Attach(label, 1, 1, 2, 1) */ amounts, err := gtk.GridNew() if err != nil { log.Fatal(err) } amount, err := gtk.SpinButtonNewWithRange(0, 21000000, 0.00000001) if err != nil { log.Fatal(err) } amount.SetHAlign(gtk.ALIGN_START) ret.amount = amount amounts.Add(amount) ls, err := gtk.ListStoreNew(glib.TYPE_STRING) if err != nil { log.Fatal(err) } iter := ls.Append() choices := []string{"BTC", "mBTC", "μBTC"} s := make([]interface{}, len(choices)) for i, v := range choices { s[i] = v } if err := ls.Set(iter, []int{0}, []interface{}{"BTC"}); err != nil { fmt.Println(err) } iter = ls.Append() if err := ls.Set(iter, []int{0}, []interface{}{"mBTC"}); err != nil { fmt.Println(err) } iter = ls.Append() if err := ls.Set(iter, []int{0}, []interface{}{"μBTC"}); err != nil { fmt.Println(err) } // TODO(jrick): add back when this works. /* combo, err := gtk.ComboBoxNewWithModel(ls) if err != nil { log.Fatal(err) } cell, err := gtk.CellRendererTextNew() if err != nil { log.Fatal(err) } combo.PackStart(cell, true) combo.AddAttribute(cell, "text", 0) combo.SetActive(0) combo.Connect("changed", func() { val := amount.GetValue() fmt.Println(val) switch combo.GetActive() { case 0: fmt.Println("btc") case 1: fmt.Println("mbtc") case 2: fmt.Println("ubtc") } }) ret.combo = combo amounts.Add(combo) */ l, err = gtk.LabelNew("BTC") if err != nil { log.Fatal(err) } amounts.Add(l) grid.Attach(amounts, 1, 1, 1, 1) return ret }