Rudimentary text selection with keybaord keys
This commit is contained in:
parent
4bc8566820
commit
21abd147bf
@ -97,16 +97,30 @@ func (element *TextBox) HandleKeyDown(key input.Key, modifiers input.Modifiers)
|
|||||||
textChanged = true
|
textChanged = true
|
||||||
|
|
||||||
case key == input.KeyLeft:
|
case key == input.KeyLeft:
|
||||||
element.dot = textmanip.MoveLeft (
|
if modifiers.Shift {
|
||||||
element.text,
|
element.dot = textmanip.SelectLeft (
|
||||||
element.dot,
|
element.text,
|
||||||
modifiers.Control)
|
element.dot,
|
||||||
|
modifiers.Control)
|
||||||
|
} else {
|
||||||
|
element.dot = textmanip.MoveLeft (
|
||||||
|
element.text,
|
||||||
|
element.dot,
|
||||||
|
modifiers.Control)
|
||||||
|
}
|
||||||
|
|
||||||
case key == input.KeyRight:
|
case key == input.KeyRight:
|
||||||
element.dot = textmanip.MoveRight (
|
if modifiers.Shift {
|
||||||
element.text,
|
element.dot = textmanip.SelectRight (
|
||||||
element.dot,
|
element.text,
|
||||||
modifiers.Control)
|
element.dot,
|
||||||
|
modifiers.Control)
|
||||||
|
} else {
|
||||||
|
element.dot = textmanip.MoveRight (
|
||||||
|
element.text,
|
||||||
|
element.dot,
|
||||||
|
modifiers.Control)
|
||||||
|
}
|
||||||
|
|
||||||
case key.Printable():
|
case key.Printable():
|
||||||
element.text, element.dot = textmanip.Type (
|
element.text, element.dot = textmanip.Type (
|
||||||
@ -299,14 +313,28 @@ func (element *TextBox) draw () {
|
|||||||
}
|
}
|
||||||
pattern := element.theme.Pattern(theme.PatternSunken, state)
|
pattern := element.theme.Pattern(theme.PatternSunken, state)
|
||||||
artist.FillRectangle(element.core, pattern, bounds)
|
artist.FillRectangle(element.core, pattern, bounds)
|
||||||
|
offset := bounds.Min.Add (image.Point {
|
||||||
|
X: element.config.Padding() - element.scroll,
|
||||||
|
Y: element.config.Padding(),
|
||||||
|
})
|
||||||
|
|
||||||
if len(element.text) == 0 && !element.Focused() {
|
if element.Focused() && !element.dot.Empty() {
|
||||||
|
// draw selection bounds
|
||||||
|
accent := element.theme.Pattern (
|
||||||
|
theme.PatternAccent, state)
|
||||||
|
canon := element.dot.Canon()
|
||||||
|
start := element.valueDrawer.PositionOf(canon.Start).Add(offset)
|
||||||
|
end := element.valueDrawer.PositionOf(canon.End).Add(offset)
|
||||||
|
end.Y += element.valueDrawer.LineHeight().Round()
|
||||||
|
artist.FillRectangle (
|
||||||
|
element.core,
|
||||||
|
accent,
|
||||||
|
image.Rectangle { start, end })
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(element.text) == 0 {
|
||||||
// draw placeholder
|
// draw placeholder
|
||||||
textBounds := element.placeholderDrawer.LayoutBounds()
|
textBounds := element.placeholderDrawer.LayoutBounds()
|
||||||
offset := bounds.Min.Add (image.Point {
|
|
||||||
X: element.config.Padding(),
|
|
||||||
Y: element.config.Padding(),
|
|
||||||
})
|
|
||||||
foreground := element.theme.Pattern (
|
foreground := element.theme.Pattern (
|
||||||
theme.PatternForeground,
|
theme.PatternForeground,
|
||||||
theme.PatternState { Disabled: true })
|
theme.PatternState { Disabled: true })
|
||||||
@ -317,30 +345,27 @@ func (element *TextBox) draw () {
|
|||||||
} else {
|
} else {
|
||||||
// draw input value
|
// draw input value
|
||||||
textBounds := element.valueDrawer.LayoutBounds()
|
textBounds := element.valueDrawer.LayoutBounds()
|
||||||
offset := bounds.Min.Add (image.Point {
|
|
||||||
X: element.config.Padding() - element.scroll,
|
|
||||||
Y: element.config.Padding(),
|
|
||||||
})
|
|
||||||
foreground := element.theme.Pattern (
|
foreground := element.theme.Pattern (
|
||||||
theme.PatternForeground, state)
|
theme.PatternForeground, state)
|
||||||
element.valueDrawer.Draw (
|
element.valueDrawer.Draw (
|
||||||
element.core,
|
element.core,
|
||||||
foreground,
|
foreground,
|
||||||
offset.Sub(textBounds.Min))
|
offset.Sub(textBounds.Min))
|
||||||
|
}
|
||||||
|
|
||||||
if element.Focused() {
|
if element.Focused() && element.dot.Empty() {
|
||||||
// cursor
|
// draw cursor
|
||||||
// TODO: draw selection if exists
|
foreground := element.theme.Pattern (
|
||||||
cursorPosition := element.valueDrawer.PositionOf (
|
theme.PatternForeground, state)
|
||||||
element.dot.End)
|
cursorPosition := element.valueDrawer.PositionOf (
|
||||||
artist.Line (
|
element.dot.End)
|
||||||
element.core,
|
artist.Line (
|
||||||
foreground, 1,
|
element.core,
|
||||||
cursorPosition.Add(offset),
|
foreground, 1,
|
||||||
image.Pt (
|
cursorPosition.Add(offset),
|
||||||
cursorPosition.X,
|
image.Pt (
|
||||||
cursorPosition.Y + element.valueDrawer.
|
cursorPosition.X,
|
||||||
LineHeight().Round()).Add(offset))
|
cursorPosition.Y + element.valueDrawer.
|
||||||
}
|
LineHeight().Round()).Add(offset))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,12 +34,19 @@ func (dot Dot) Sub (delta int) Dot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func WordToLeft (text []rune, dot Dot) (length int) {
|
func (dot Dot) Constrain (length int) Dot {
|
||||||
cursor := dot.End
|
if dot.Start < 0 { dot.Start = 0 }
|
||||||
if cursor < 1 { return }
|
if dot.Start > length { dot.Start = length}
|
||||||
if cursor > len(text) { cursor = len(text) }
|
if dot.End < 0 { dot.End = 0 }
|
||||||
|
if dot.End > length { dot.End = length}
|
||||||
|
return dot
|
||||||
|
}
|
||||||
|
|
||||||
index := cursor - 1
|
func WordToLeft (text []rune, position int) (length int) {
|
||||||
|
if position < 1 { return }
|
||||||
|
if position > len(text) { position = len(text) }
|
||||||
|
|
||||||
|
index := position - 1
|
||||||
for index >= 0 && unicode.IsSpace(text[index]) {
|
for index >= 0 && unicode.IsSpace(text[index]) {
|
||||||
length ++
|
length ++
|
||||||
index --
|
index --
|
||||||
@ -51,12 +58,11 @@ func WordToLeft (text []rune, dot Dot) (length int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func WordToRight (text []rune, dot Dot) (length int) {
|
func WordToRight (text []rune, position int) (length int) {
|
||||||
cursor := dot.End
|
if position < 0 { return }
|
||||||
if cursor < 0 { return }
|
if position > len(text) { position = len(text) }
|
||||||
if cursor > len(text) { cursor = len(text) }
|
|
||||||
|
|
||||||
index := cursor
|
index := position
|
||||||
for index < len(text) && unicode.IsSpace(text[index]) {
|
for index < len(text) && unicode.IsSpace(text[index]) {
|
||||||
length ++
|
length ++
|
||||||
index ++
|
index ++
|
||||||
@ -68,41 +74,46 @@ func WordToRight (text []rune, dot Dot) (length int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func Backspace (text []rune, dot Dot, word bool) (result []rune, moved Dot) {
|
func WordAround (text []rune, position int) (around Dot) {
|
||||||
if dot.Empty() {
|
return Dot {
|
||||||
cursor := dot.End
|
WordToLeft(text, position),
|
||||||
if cursor < 1 { return text, dot }
|
WordToRight(text, position),
|
||||||
if cursor > len(text) { cursor = len(text) }
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Backspace (text []rune, dot Dot, word bool) (result []rune, moved Dot) {
|
||||||
|
dot = dot.Constrain(len(text))
|
||||||
|
if dot.Empty() {
|
||||||
distance := 1
|
distance := 1
|
||||||
if word {
|
if word {
|
||||||
distance = WordToLeft(text, dot)
|
distance = WordToLeft(text, dot.End)
|
||||||
}
|
}
|
||||||
result = append(result, text[:cursor - distance]...)
|
result = append (
|
||||||
result = append(result, text[cursor:]...)
|
result,
|
||||||
moved = EmptyDot(cursor - distance)
|
text[:dot.Sub(distance).Constrain(len(text)).End]...)
|
||||||
|
result = append(result, text[dot.End:]...)
|
||||||
|
moved = EmptyDot(dot.Sub(distance).Start)
|
||||||
|
return
|
||||||
} else {
|
} else {
|
||||||
return Delete(text, dot, word)
|
return Delete(text, dot, word)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Delete (text []rune, dot Dot, word bool) (result []rune, moved Dot) {
|
func Delete (text []rune, dot Dot, word bool) (result []rune, moved Dot) {
|
||||||
|
dot = dot.Constrain(len(text))
|
||||||
if dot.Empty() {
|
if dot.Empty() {
|
||||||
cursor := dot.End
|
|
||||||
if cursor < 0 { return text, dot }
|
|
||||||
if cursor > len(text) { cursor = len(text) }
|
|
||||||
|
|
||||||
distance := 1
|
distance := 1
|
||||||
if word {
|
if word {
|
||||||
distance = WordToRight(text, dot)
|
distance = WordToRight(text, dot.End)
|
||||||
}
|
}
|
||||||
result = append(result, text[:cursor]...)
|
result = append(result, text[:dot.End]...)
|
||||||
result = append(result, text[cursor + distance:]...)
|
result = append (
|
||||||
|
result,
|
||||||
|
text[dot.Add(distance).Constrain(len(text)).End:]...)
|
||||||
moved = dot
|
moved = dot
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
|
dot = dot.Canon()
|
||||||
result = append(result, text[:dot.Start]...)
|
result = append(result, text[:dot.Start]...)
|
||||||
result = append(result, text[dot.End:]...)
|
result = append(result, text[dot.End:]...)
|
||||||
moved = EmptyDot(dot.Start)
|
moved = EmptyDot(dot.Start)
|
||||||
@ -111,50 +122,61 @@ func Delete (text []rune, dot Dot, word bool) (result []rune, moved Dot) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Type (text []rune, dot Dot, character rune) (result []rune, moved Dot) {
|
func Type (text []rune, dot Dot, character rune) (result []rune, moved Dot) {
|
||||||
|
dot = dot.Constrain(len(text))
|
||||||
if dot.Empty() {
|
if dot.Empty() {
|
||||||
cursor := dot.End
|
result = append(result, text[:dot.End]...)
|
||||||
if cursor < 0 { cursor = 0 }
|
|
||||||
if cursor > len(text) { cursor = len(text) }
|
|
||||||
result = append(result, text[:cursor]...)
|
|
||||||
result = append(result, character)
|
result = append(result, character)
|
||||||
if cursor < len(text) {
|
if dot.End < len(text) {
|
||||||
result = append(result, text[cursor:]...)
|
result = append(result, text[dot.End:]...)
|
||||||
}
|
}
|
||||||
moved = EmptyDot(cursor + 1)
|
moved = EmptyDot(dot.Add(1).End)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
|
dot = dot.Canon()
|
||||||
result = append(result, text[:dot.Start]...)
|
result = append(result, text[:dot.Start]...)
|
||||||
result = append(result, character)
|
result = append(result, character)
|
||||||
result = append(result, text[dot.End:]...)
|
result = append(result, text[dot.End:]...)
|
||||||
moved = EmptyDot(dot.Start)
|
moved = EmptyDot(dot.Add(1).Start)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func MoveLeft (text []rune, dot Dot, word bool) (moved Dot) {
|
func MoveLeft (text []rune, dot Dot, word bool) (moved Dot) {
|
||||||
cursor := dot.Start
|
dot = dot.Constrain(len(text))
|
||||||
|
|
||||||
if cursor < 1 { return EmptyDot(cursor) }
|
|
||||||
if cursor > len(text) { cursor = len(text) }
|
|
||||||
|
|
||||||
distance := 1
|
distance := 1
|
||||||
if word {
|
if word {
|
||||||
distance = WordToLeft(text, dot)
|
distance = WordToLeft(text, dot.Start)
|
||||||
}
|
}
|
||||||
moved = EmptyDot(cursor - distance)
|
moved = EmptyDot(dot.Sub(distance).Start)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func MoveRight (text []rune, dot Dot, word bool) (moved Dot) {
|
func MoveRight (text []rune, dot Dot, word bool) (moved Dot) {
|
||||||
cursor := dot.End
|
dot = dot.Constrain(len(text))
|
||||||
|
|
||||||
if cursor < 0 { return EmptyDot(cursor) }
|
|
||||||
if cursor > len(text) { cursor = len(text) }
|
|
||||||
|
|
||||||
distance := 1
|
distance := 1
|
||||||
if word {
|
if word {
|
||||||
distance = WordToRight(text, dot)
|
distance = WordToRight(text, dot.End)
|
||||||
}
|
}
|
||||||
moved = EmptyDot(cursor + distance)
|
moved = EmptyDot(dot.Add(distance).End)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SelectLeft (text []rune, dot Dot, word bool) (moved Dot) {
|
||||||
|
dot = dot.Constrain(len(text))
|
||||||
|
distance := 1
|
||||||
|
if word {
|
||||||
|
distance = WordToLeft(text, dot.Start)
|
||||||
|
}
|
||||||
|
dot.Start -= distance
|
||||||
|
return dot
|
||||||
|
}
|
||||||
|
|
||||||
|
func SelectRight (text []rune, dot Dot, word bool) (moved Dot) {
|
||||||
|
dot = dot.Constrain(len(text))
|
||||||
|
distance := 1
|
||||||
|
if word {
|
||||||
|
distance = WordToRight(text, dot.End)
|
||||||
|
}
|
||||||
|
dot.Start += distance
|
||||||
|
return dot
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user