Initial commit
This commit is contained in:
253
input/input.go
Normal file
253
input/input.go
Normal file
@@ -0,0 +1,253 @@
|
||||
package input
|
||||
|
||||
import "unicode"
|
||||
import "git.tebibyte.media/sashakoshka/stone"
|
||||
|
||||
var selectedInput *Input
|
||||
|
||||
func SelectNone () {
|
||||
selectedInput = nil
|
||||
}
|
||||
|
||||
type Input struct {
|
||||
cursor int
|
||||
text []rune
|
||||
X, Y, Width int
|
||||
Obscure bool
|
||||
OnDone func ()
|
||||
OnCancel func ()
|
||||
}
|
||||
|
||||
func (input *Input) HandleButton (button stone.Button, control, shift, alt bool) {
|
||||
switch button {
|
||||
case stone.KeyLeft:
|
||||
if control {
|
||||
input.cursor -= input.distanceToPreviousWordBound()
|
||||
} else if alt {
|
||||
input.cursorToBeginning()
|
||||
} else {
|
||||
input.cursor --
|
||||
}
|
||||
input.constrainCursor()
|
||||
|
||||
case stone.KeyRight:
|
||||
if control {
|
||||
input.cursor += input.distanceToNextWordBound()
|
||||
} else if alt {
|
||||
input.cursorToEnd()
|
||||
} else {
|
||||
input.cursor ++
|
||||
}
|
||||
input.constrainCursor()
|
||||
|
||||
case stone.KeyHome:
|
||||
input.cursorToBeginning()
|
||||
input.constrainCursor()
|
||||
|
||||
case stone.KeyEnd:
|
||||
input.cursorToEnd()
|
||||
input.constrainCursor()
|
||||
|
||||
case stone.KeyBackspace:
|
||||
if control {
|
||||
input.backspace(input.distanceToPreviousWordBound())
|
||||
} else if alt {
|
||||
input.backspace(input.cursor)
|
||||
} else {
|
||||
input.backspace(1)
|
||||
}
|
||||
input.constrainCursor()
|
||||
|
||||
case stone.KeyDelete:
|
||||
if control {
|
||||
input.delete(input.distanceToNextWordBound())
|
||||
} else if alt {
|
||||
input.delete(len(input.text))
|
||||
} else {
|
||||
input.delete(1)
|
||||
}
|
||||
input.constrainCursor()
|
||||
|
||||
case stone.KeyEnter:
|
||||
SelectNone()
|
||||
if input.OnDone != nil {
|
||||
input.OnDone()
|
||||
}
|
||||
|
||||
case stone.KeyEscape:
|
||||
SelectNone()
|
||||
if input.OnCancel != nil {
|
||||
input.OnCancel()
|
||||
}
|
||||
|
||||
default:
|
||||
if button.Printable() {
|
||||
input.text = append(input.text, 0)
|
||||
copy (
|
||||
input.text[input.cursor + 1:],
|
||||
input.text[input.cursor:])
|
||||
input.text[input.cursor] = rune(button)
|
||||
input.cursor ++
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (input *Input) Draw (buffer stone.Buffer) {
|
||||
buffer.SetRune(input.X, input.Y, '[')
|
||||
buffer.SetRune(input.X + 1, input.Y, 0)
|
||||
buffer.SetRune(input.X + input.Width - 2, input.Y, 0)
|
||||
buffer.SetRune(input.X + input.Width - 1, input.Y, ']')
|
||||
|
||||
actualWidth := input.Width - 4
|
||||
scroll := 0
|
||||
|
||||
x := input.X + 2
|
||||
for index := 0; index < actualWidth; index ++ {
|
||||
character := input.charAtSafe(index + scroll)
|
||||
|
||||
if input.Selected() && index == input.cursor {
|
||||
buffer.SetRune(x, input.Y, '_')
|
||||
} else if input.Obscure && character > 0 {
|
||||
buffer.SetRune(x, input.Y, '*')
|
||||
} else {
|
||||
buffer.SetRune(x, input.Y, character)
|
||||
}
|
||||
x ++
|
||||
}
|
||||
}
|
||||
|
||||
func (input *Input) charAtSafe (index int) (character rune) {
|
||||
if index < 0 { return }
|
||||
if index >= len(input.text) { return }
|
||||
character = input.text[index]
|
||||
return
|
||||
}
|
||||
|
||||
func (input *Input) constrainCursor () (constrained bool) {
|
||||
if input.cursor < 0 {
|
||||
input.cursorToBeginning()
|
||||
constrained = true
|
||||
} else if input.cursor > len(input.text) {
|
||||
input.cursorToEnd()
|
||||
constrained = true
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (input *Input) distanceToPreviousWordBound () (distance int) {
|
||||
index := input.cursor
|
||||
index --
|
||||
distance ++
|
||||
|
||||
for {
|
||||
if index < 0 { break }
|
||||
|
||||
character := input.text[index]
|
||||
isWordChar :=
|
||||
unicode.IsLetter(character) ||
|
||||
unicode.IsDigit(character)
|
||||
if !isWordChar {
|
||||
distance --
|
||||
break
|
||||
}
|
||||
|
||||
distance ++
|
||||
index --
|
||||
}
|
||||
|
||||
if distance < 1 {
|
||||
distance ++
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (input *Input) distanceToNextWordBound () (distance int) {
|
||||
index := input.cursor
|
||||
|
||||
for {
|
||||
if index >= len(input.text) { break }
|
||||
|
||||
character := input.text[index]
|
||||
isWordChar :=
|
||||
unicode.IsLetter(character) ||
|
||||
unicode.IsDigit(character)
|
||||
if !isWordChar {
|
||||
break
|
||||
}
|
||||
|
||||
distance ++
|
||||
index ++
|
||||
}
|
||||
|
||||
if distance < 1 {
|
||||
distance ++
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (input *Input) backspace (amount int) {
|
||||
if input.cursor - amount < 0 {
|
||||
amount = input.cursor
|
||||
}
|
||||
|
||||
copy (
|
||||
input.text[input.cursor - amount:],
|
||||
input.text[input.cursor:])
|
||||
input.text = input.text[:len(input.text) - amount]
|
||||
input.cursor -= amount
|
||||
}
|
||||
|
||||
func (input *Input) delete (amount int) {
|
||||
if input.cursor + amount > len(input.text) {
|
||||
amount = len(input.text) - input.cursor
|
||||
}
|
||||
|
||||
// TODO
|
||||
copy (
|
||||
input.text[input.cursor:],
|
||||
input.text[input.cursor + amount:])
|
||||
input.text = input.text[:len(input.text) - amount]
|
||||
}
|
||||
|
||||
func (input *Input) cursorToBeginning () {
|
||||
input.cursor = 0
|
||||
}
|
||||
|
||||
func (input *Input) cursorToEnd () {
|
||||
input.cursor = len(input.text)
|
||||
}
|
||||
|
||||
func (input *Input) Reset () {
|
||||
input.SetText("")
|
||||
}
|
||||
|
||||
func (input *Input) Text () (text string) {
|
||||
text = string(input.text)
|
||||
return
|
||||
}
|
||||
|
||||
func (input *Input) SetText (text string) {
|
||||
input.text = []rune(text)
|
||||
input.cursorToEnd()
|
||||
return
|
||||
}
|
||||
|
||||
func (input *Input) Selected () (selected bool) {
|
||||
selected = selectedInput == input
|
||||
return
|
||||
}
|
||||
|
||||
func (input *Input) Select () () {
|
||||
selectedInput = input
|
||||
return
|
||||
}
|
||||
|
||||
func Selected () (selected *Input) {
|
||||
selected = selectedInput
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user