build text-entry component
This commit is contained in:
		
							
								
								
									
										81
									
								
								ui/ui.go
									
									
									
									
									
								
							
							
						
						
									
										81
									
								
								ui/ui.go
									
									
									
									
									
								
							@@ -515,3 +515,84 @@ func (p *KeyValue) SetVisible(b bool) {
 | 
				
			|||||||
func (p *KeyValue) GetValue() string {
 | 
					func (p *KeyValue) GetValue() string {
 | 
				
			||||||
	return p.value
 | 
						return p.value
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type EditableTextLine struct {
 | 
				
			||||||
 | 
						x, y      int
 | 
				
			||||||
 | 
						h, w      int
 | 
				
			||||||
 | 
						text      string
 | 
				
			||||||
 | 
						style     tcell.Style
 | 
				
			||||||
 | 
						visible   bool
 | 
				
			||||||
 | 
						cursorPos int
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewEditableTextLine(initialText string) *EditableTextLine {
 | 
				
			||||||
 | 
						return &EditableTextLine{
 | 
				
			||||||
 | 
							text:    initialText,
 | 
				
			||||||
 | 
							visible: true,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (p *EditableTextLine) SetSize(x, y, _, _ int) {
 | 
				
			||||||
 | 
						p.x, p.y, p.h, p.w = x, y, 1, len(p.text)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (p *EditableTextLine) SetStyle(s tcell.Style) {
 | 
				
			||||||
 | 
						p.style = s
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (p *EditableTextLine) Draw(s tcell.Screen) {
 | 
				
			||||||
 | 
						if !p.visible {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for j, r := range p.text {
 | 
				
			||||||
 | 
							s.SetContent(p.x+j, p.y, r, nil, p.style)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (p *EditableTextLine) SetText(t string) {
 | 
				
			||||||
 | 
						p.text = t
 | 
				
			||||||
 | 
						if len(p.text) == 0 {
 | 
				
			||||||
 | 
							p.ResetCursor(true)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						p.ResetCursor(false)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (p *EditableTextLine) ResetCursor(beginning bool) {
 | 
				
			||||||
 | 
						if beginning {
 | 
				
			||||||
 | 
							p.cursorPos = 0
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							p.cursorPos = len(p.text)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (p *EditableTextLine) InsertAtCursor(r rune) {
 | 
				
			||||||
 | 
						if len(p.text) == 0 {
 | 
				
			||||||
 | 
							p.text = string(r)
 | 
				
			||||||
 | 
							p.cursorPos = 1
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						p.text = p.text[0:p.cursorPos] + string(r) + p.text[p.cursorPos:len(p.text)]
 | 
				
			||||||
 | 
						p.cursorPos = p.cursorPos + 1
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (p *EditableTextLine) MoveCursor(i int) {
 | 
				
			||||||
 | 
						if p.cursorPos+i < 0 {
 | 
				
			||||||
 | 
							p.cursorPos = 0
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if p.cursorPos+i > len(p.text) {
 | 
				
			||||||
 | 
							p.cursorPos = len(p.text)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						p.cursorPos = p.cursorPos + i
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (p *EditableTextLine) DeleteAtCursor() {
 | 
				
			||||||
 | 
						if len(p.text) == 0 {
 | 
				
			||||||
 | 
							p.cursorPos = 0
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						p.text = p.text[0:p.cursorPos-1] + p.text[p.cursorPos:len(p.text)]
 | 
				
			||||||
 | 
						p.cursorPos = p.cursorPos - 1
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -174,3 +174,66 @@ func TestContainerTwoBoxesPercentageVStack(t *testing.T) {
 | 
				
			|||||||
		t.Fail()
 | 
							t.Fail()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestNewEditableTextLine(t *testing.T) {
 | 
				
			||||||
 | 
						e := NewEditableTextLine("")
 | 
				
			||||||
 | 
						e.InsertAtCursor('a')
 | 
				
			||||||
 | 
						e.InsertAtCursor('b')
 | 
				
			||||||
 | 
						e.InsertAtCursor('c')
 | 
				
			||||||
 | 
						if e.text != "abc" {
 | 
				
			||||||
 | 
							fmt.Printf("expected: 'abc', actual: '%+v'", e.text)
 | 
				
			||||||
 | 
							t.Fail()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						e.MoveCursor(-1)
 | 
				
			||||||
 | 
						e.InsertAtCursor('d')
 | 
				
			||||||
 | 
						if e.text != "abdc" {
 | 
				
			||||||
 | 
							fmt.Printf("expected: 'abdc', actual: '%+v'", e.text)
 | 
				
			||||||
 | 
							t.Fail()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						e.MoveCursor(-20)
 | 
				
			||||||
 | 
						e.InsertAtCursor('e')
 | 
				
			||||||
 | 
						if e.text != "eabdc" {
 | 
				
			||||||
 | 
							fmt.Printf("expected: 'eabdc', actual: '%+v'", e.text)
 | 
				
			||||||
 | 
							t.Fail()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						e.MoveCursor(20)
 | 
				
			||||||
 | 
						e.InsertAtCursor('f')
 | 
				
			||||||
 | 
						if e.text != "eabdcf" {
 | 
				
			||||||
 | 
							fmt.Printf("expected: 'eabdcf', actual: '%+v'", e.text)
 | 
				
			||||||
 | 
							t.Fail()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						e.MoveCursor(1)
 | 
				
			||||||
 | 
						e.InsertAtCursor('g')
 | 
				
			||||||
 | 
						if e.text != "eabdcfg" {
 | 
				
			||||||
 | 
							fmt.Printf("expected: 'eabdcfg', actual: '%+v'", e.text)
 | 
				
			||||||
 | 
							t.Fail()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						e.DeleteAtCursor()
 | 
				
			||||||
 | 
						e.DeleteAtCursor()
 | 
				
			||||||
 | 
						e.MoveCursor(-1)
 | 
				
			||||||
 | 
						e.DeleteAtCursor()
 | 
				
			||||||
 | 
						if e.text != "eabc" {
 | 
				
			||||||
 | 
							fmt.Printf("expected: 'eabc', actual: '%+v'", e.text)
 | 
				
			||||||
 | 
							t.Fail()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						e.ResetCursor(false)
 | 
				
			||||||
 | 
						e.InsertAtCursor('h')
 | 
				
			||||||
 | 
						e.ResetCursor(true)
 | 
				
			||||||
 | 
						e.InsertAtCursor('g')
 | 
				
			||||||
 | 
						if e.text != "geabch" {
 | 
				
			||||||
 | 
							fmt.Printf("expected: 'geabch', actual: '%+v'", e.text)
 | 
				
			||||||
 | 
							t.Fail()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						e.SetText("the rain in spain")
 | 
				
			||||||
 | 
						e.InsertAtCursor('s')
 | 
				
			||||||
 | 
						if e.text != "the rain in spains" {
 | 
				
			||||||
 | 
							fmt.Printf("expected: 'the rain in spains', actual: '%+v'", e.text)
 | 
				
			||||||
 | 
							t.Fail()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						e.SetText("")
 | 
				
			||||||
 | 
						e.InsertAtCursor('s')
 | 
				
			||||||
 | 
						if e.text != "s" {
 | 
				
			||||||
 | 
							fmt.Printf("expected: 's', actual: '%+v'", e.text)
 | 
				
			||||||
 | 
							t.Fail()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user