// CreateTutorialDialog opens a tutorial dialog explaining usage for a // first-time user. If appWindow is non-nil, it will be used as the // parent window of the dialog. If nil, the tutorial dialog will open as // a top-level window and a new application main window will be created // and opened after the final tutorial message is shown. func CreateTutorialDialog(appWindow *gtk.Window) (*gtk.Dialog, error) { d, err := gtk.DialogNew() if err != nil { return nil, err } d.SetTitle("btcgui First Start Tutorial") box, err := d.GetContentArea() if err != nil { return nil, err } grid, err := gtk.GridNew() if err != nil { return nil, err } grid.SetOrientation(gtk.ORIENTATION_VERTICAL) box.Add(grid) d.SetDefaultGeometry(500, 100) if appWindow != nil { d.SetTransientFor(appWindow) d.SetPosition(gtk.WIN_POS_CENTER_ON_PARENT) } else { d.Connect("destroy", func() { go StartMainApplication() }) d.SetPosition(gtk.WIN_POS_CENTER) } // Add a notebook and tab for each dialog message. nb, err := gtk.NotebookNew() if err != nil { return nil, err } // Because the labels added below will wrap and their final minimum // heights and widths will be absurdly large, first give a size request // and show the notebook (allocating space for the requested size). // This will make text wrapping labels size nicely inside the notebook. nb.SetSizeRequest(500, 100) nb.Show() // Create messages and append each in a notebook page. for _, msg := range dialogMessages { lbl, err := gtk.LabelNew("") if err != nil { return nil, err } lbl.SetMarkup(msg) lbl.SetLineWrap(true) lbl.Show() lbl.SetAlignment(0, 0) nb.AppendPage(lbl, nil) } nb.SetShowTabs(false) grid.Add(nb) prevPage, err := d.AddButton("_Previous", gtk.RESPONSE_NONE) if err != nil { return nil, err } prevPage.SetSensitive(false) nextPage, err := d.AddButton("_Next", gtk.RESPONSE_NONE) if err != nil { return nil, err } prevPage.Connect("clicked", func() { nb.PrevPage() pagen := nb.GetCurrentPage() if pagen == 0 { prevPage.SetSensitive(false) } nextPage.SetSensitive(true) }) nextPage.Connect("clicked", func() { nb.NextPage() pagen := nb.GetCurrentPage() if pagen == len(dialogMessages)-1 { nextPage.SetSensitive(false) } prevPage.SetSensitive(true) }) _, err = d.AddButton("_Close", gtk.RESPONSE_CLOSE) if err != nil { return nil, err } d.Connect("response", func(_ *glib.Object, rt gtk.ResponseType) { if rt == gtk.RESPONSE_CLOSE { // Using w.Close() would be nice but it needs GTK 3.10. d.Hide() d.Destroy() } }) return d, nil }
func createNewWalletDialog() (*gtk.Dialog, error) { dialog, err := gtk.DialogNew() if err != nil { return nil, err } dialog.SetTitle("New wallet") dialog.AddButton("_OK", gtk.RESPONSE_OK) dialog.SetDefaultGeometry(500, 100) 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) // Because the label will wrap and the final minimum heights // and widths will be absurdly large, first give a size request and // show the grid (allocating space for the requested size). This will // make text wrapping labels size nicely inside the grid. grid.SetSizeRequest(500, 100) grid.Show() l, err := gtk.LabelNew("") if err != nil { return nil, err } l.SetLineWrap(true) l.SetMarkup(newWalletMessage) l.SetAlignment(0, 0) grid.Attach(l, 0, 0, 2, 1) b.SetHExpand(true) b.SetVExpand(true) l, err = gtk.LabelNew("Enter passphrase:") if err != nil { return nil, err } l.SetAlignment(1.0, 0.5) grid.Attach(l, 0, 1, 1, 1) passphrase, err := gtk.EntryNew() if err != nil { return nil, err } passphrase.SetVisibility(false) passphrase.SetHExpand(true) passphrase.Connect("activate", func() { dialog.Emit("response", gtk.RESPONSE_OK, nil) }) grid.Attach(passphrase, 1, 1, 1, 1) l, err = gtk.LabelNew("Confirm passphrase:") if err != nil { return nil, err } l.SetAlignment(1.0, 0.5) grid.Attach(l, 0, 2, 1, 1) repeated, err := gtk.EntryNew() if err != nil { return nil, err } repeated.SetVisibility(false) repeated.SetVAlign(gtk.ALIGN_START) repeated.Connect("activate", func() { dialog.Emit("response", gtk.RESPONSE_OK, nil) }) grid.Attach(repeated, 1, 2, 1, 1) showEntryText, err := gtk.CheckButtonNewWithLabel("Show passphrase") if err != nil { return nil, err } showEntryText.Connect("toggled", func() { active := showEntryText.GetActive() passphrase.SetVisibility(active) repeated.SetVisibility(active) }) grid.Attach(showEntryText, 1, 3, 2, 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 } rStr, err := repeated.GetText() if err != nil { log.Print(err) return } if len(pStr) == 0 { mDialog := gtk.MessageDialogNew(dialog, 0, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, "A passphrase must be entered to create a wallet.") mDialog.SetTitle("Wallet creation failed") mDialog.Run() mDialog.Destroy() return } if pStr == rStr { go func() { triggers.newWallet <- &NewWalletParams{ passphrase: pStr, } if err := <-triggerReplies.walletCreationErr; err != nil { glib.IdleAdd(func() { mDialog := gtk.MessageDialogNew(dialog, 0, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, err.Error()) mDialog.SetTitle("Wallet creation failed") mDialog.Run() mDialog.Destroy() }) } else { glib.IdleAdd(func() { dialog.Destroy() }) } }() } else { msg := "The supplied passphrases do not match." mDialog := gtk.MessageDialogNew(dialog, 0, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, msg) mDialog.SetTitle("Wallet creation failed") mDialog.Run() mDialog.Destroy() } case gtk.RESPONSE_CANCEL: dialog.Destroy() } }) dialog.Connect("delete-event", func() { mDialog := gtk.MessageDialogNew(mainWindow, 0, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, "btcgui cannot be used without a wallet and will now close.") mDialog.Show() mDialog.Run() mDialog.Destroy() gtk.MainQuit() }) 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 createEncryptionDialog() (*gtk.Dialog, error) { dialog, err := gtk.DialogNew() if err != nil { return nil, err } dialog.SetTitle("Encrypt wallet") 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) l, err := gtk.LabelNew("") if err != nil { return nil, err } l.SetMarkup(encryptMessage) l.SetHExpand(true) l.SetVExpand(true) l.SetHAlign(gtk.ALIGN_START) grid.Attach(l, 0, 0, 2, 1) l, err = gtk.LabelNew("New passphrase") if err != nil { return nil, err } grid.Attach(l, 0, 1, 1, 1) passphrase, err := gtk.EntryNew() if err != nil { return nil, err } passphrase.SetVisibility(false) passphrase.SetHExpand(true) passphrase.Connect("activate", func() { dialog.Emit("response", gtk.RESPONSE_OK, nil) }) grid.Attach(passphrase, 1, 1, 1, 1) l, err = gtk.LabelNew("Repeat new passphrase") if err != nil { return nil, err } l.SetVExpand(true) l.SetVAlign(gtk.ALIGN_START) grid.Attach(l, 0, 2, 1, 1) repeated, err := gtk.EntryNew() if err != nil { return nil, err } repeated.SetVisibility(false) repeated.SetVExpand(true) repeated.SetVAlign(gtk.ALIGN_START) repeated.Connect("activate", func() { dialog.Emit("response", gtk.RESPONSE_OK, nil) }) grid.Attach(repeated, 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 } rStr, err := repeated.GetText() if err != nil { log.Print(err) return } if pStr == rStr { // use the passphrase, encrypt wallet... dialog.Destroy() } else { msg := "The supplied passphrases do not match." mDialog := gtk.MessageDialogNew(dialog, 0, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, msg) mDialog.SetTitle("Wallet encryption failed") mDialog.Run() mDialog.Destroy() } case gtk.RESPONSE_CANCEL: dialog.Destroy() } }) return dialog, nil }
// 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 }