Created
April 13, 2020 21:35
-
-
Save Michael-F-Ellis/047465739c4e121da45e3338f140f69b to your computer and use it in GitHub Desktop.
Simple numeric keypad using Fyne
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} |
Author
Michael-F-Ellis
commented
Apr 13, 2020
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment