Skip to content

Instantly share code, notes, and snippets.

@Michael-F-Ellis
Created April 13, 2020 21:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Michael-F-Ellis/047465739c4e121da45e3338f140f69b to your computer and use it in GitHub Desktop.
Save Michael-F-Ellis/047465739c4e121da45e3338f140f69b to your computer and use it in GitHub Desktop.
Simple numeric keypad using Fyne
package main
import (
"fmt"
"fyne.io/fyne"
"fyne.io/fyne/app"
"fyne.io/fyne/layout"
"fyne.io/fyne/theme"
"fyne.io/fyne/widget"
)
var (
keyPadReportChan *(chan KeyPadReport)
mainWindow *fyne.Window
)
// main opens a window with a button for testing the keypad.
func main() {
a := app.New()
w := a.NewWindow("KeyPad Test")
mainWindow = &w
result := widget.NewLabel("") // where keypad entries are shown
w.SetContent(
widget.NewVBox(
layout.NewSpacer(),
widget.NewHBox(
layout.NewSpacer(),
widget.NewButton(
"Click Me",
func() { _ = NewKeyPad(keyPadReportChan) },
),
layout.NewSpacer(),
),
layout.NewSpacer(),
result,
layout.NewSpacer(),
),
)
w.SetMainMenu(&fyne.MainMenu{})
// initialize the keypad report channel and launch
// a goroutine that listens on it.
kprc := make(chan KeyPadReport, 1)
keyPadReportChan = &kprc
go func() {
for {
report := <-*keyPadReportChan
switch report.cancelled {
case true:
result.SetText(fmt.Sprintf("you cancelled!"))
case false:
result.SetText(fmt.Sprintf("you entered: %s", report.entered))
}
result.Refresh()
}
}()
w.Resize(fyne.NewSize(300, 300))
w.ShowAndRun()
}
// What the keypad returns on its channel
type KeyPadReport struct {
entered string
cancelled bool
}
type keyPad struct {
*widget.PopUp
entered []rune
ch *chan KeyPadReport
}
// NewKPad opens a virtual numeric keypad that sends a KeyPadReport via
// via the supplied channel when the entry is cancelled or confirmed.
func NewKeyPad(ch *chan KeyPadReport) (kpad *keyPad) {
kpad = &keyPad{entered: []rune{}, ch: ch}
var valueLabel *widget.Label
valueLabel = widget.NewLabel("") // displays entries at top of keypad
// Tap event handlers: Using closures since button action funcs
// cannot take arguments.
update := func() {
valueLabel.SetText(string(kpad.entered))
kpad.PopUp.Refresh()
}
// numTapped appends a key rune to the kpad.entered slice.
numTapped := func(c rune) func() {
return func() {
kpad.entered = append(kpad.entered, c)
update()
}
}
// backspace deletes the last rune, if any.
backspace := func() {
n := len(kpad.entered)
if n >= 1 {
kpad.entered = kpad.entered[0 : n-1]
}
update()
}
// cancel reports a cancellation
cancel := func() {
r := KeyPadReport{entered: "", cancelled: true}
*kpad.ch <- r
kpad.Hide()
}
// clear erases the entry buffer
clear := func() {
kpad.entered = []rune{}
update()
}
// confirm reports the entry as a string
confirm := func() {
r := KeyPadReport{entered: string(kpad.entered), cancelled: false}
*kpad.ch <- r
kpad.Hide()
}
// negate inserts or removes a leading minus sign
negate := func() {
defer update()
if len(kpad.entered) == 0 {
kpad.entered = append(kpad.entered, '-')
return
}
switch kpad.entered[0] {
case '-': // drop it
kpad.entered = kpad.entered[1:]
default: // prepend '-'
kpad.entered = append([]rune{'-'}, kpad.entered...)
}
}
// Lay out and init the keypad
keys := widget.NewVBox(
// label that shows what's been entered
valueLabel,
// 7 8 9
widget.NewHBox(
widget.NewButton("7", numTapped('7')),
widget.NewButton("8", numTapped('8')),
widget.NewButton("9", numTapped('9')),
widget.NewButtonWithIcon("", theme.NavigateBackIcon(), backspace),
),
// 4 5 6
widget.NewHBox(
widget.NewButton("4", numTapped('4')),
widget.NewButton("5", numTapped('5')),
widget.NewButton("6", numTapped('6')),
widget.NewButtonWithIcon("", theme.ContentUndoIcon(), clear),
),
// 1 2 3
widget.NewHBox(
widget.NewButton("1", numTapped('1')),
widget.NewButton("2", numTapped('2')),
widget.NewButton("3", numTapped('3')),
widget.NewButton("±", negate),
),
// cancel, 0, ok
widget.NewHBox(
widget.NewButtonWithIcon("", theme.CancelIcon(), cancel),
widget.NewButton("0", numTapped('0')),
widget.NewButton(".", numTapped('.')),
widget.NewButtonWithIcon("", theme.ConfirmIcon(), confirm),
),
)
// make it so
kpad.PopUp = widget.NewModalPopUp(keys, (*mainWindow).Canvas())
return
}
@Michael-F-Ellis
Copy link
Author

Screen Shot 2020-04-13 at 5 37 48 PM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment