1
0
mirror of https://github.com/gizak/termui.git synced 2025-04-24 13:48:50 +08:00

Merge 18ffe6685cb677147e8f07e4d1d2f758bfad8beb into 2b8f0c7960e9553acea6d579a740713066da5e13

This commit is contained in:
Pierre Roullon 2024-03-04 22:32:28 +08:00 committed by GitHub
commit 88daf1cc59
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 213 additions and 16 deletions

56
_examples/form.go Normal file
View File

@ -0,0 +1,56 @@
package main
import (
"context"
"fmt"
"log"
"os"
ui "github.com/gizak/termui/v3"
"github.com/gizak/termui/v3/widgets"
)
func main() {
if err := ui.Init(); err != nil {
log.Fatalf("failed to initialize termui: %v", err)
}
defer ui.Close()
f0 := widgets.NewForm(
context.Background(),
"Add user",
func(ctx context.Context, validated bool, fields []*widgets.Field) {
ui.Close()
fmt.Printf("Form validated: %t. Values:\n", validated)
for _, f := range fields {
fmt.Printf("%s: %s\n", f.Name, f.Text)
}
os.Exit(0)
},
widgets.NewField("First name", ""),
widgets.NewField("Surname", ""),
widgets.NewField("Test", "Default value"),
)
f0.SetRect(0, 0, 50, 20)
p2 := widgets.NewParagraph()
p2.Title = "Multiline"
p2.Text = "Simple colored text\nwith label. It [can be](fg:red) multilined with \\n or [break automatically](fg:red,fg:bold)"
p2.SetRect(0, 50, 35, 55)
p2.BorderStyle.Fg = ui.ColorYellow
ui.Render(f0, p2)
uiEvents := ui.PollEvents()
for {
e := <-uiEvents
switch e.ID {
case "<C-c>":
return
default:
if !f0.IsDone() {
f0.Handle(e)
}
}
}
}

View File

@ -3,7 +3,7 @@ package termui
import (
"image"
"github.com/gizak/termui/v3/drawille"
"github.com/proullon/termui/v3/drawille"
)
type Canvas struct {

4
go.mod
View File

@ -1,6 +1,6 @@
module github.com/gizak/termui/v3
module github.com/proullon/termui/v3
go 1.15
go 1.22
require (
github.com/mattn/go-runewidth v0.0.15

View File

@ -10,7 +10,7 @@ import (
rw "github.com/mattn/go-runewidth"
. "github.com/gizak/termui/v3"
. "github.com/proullon/termui/v3"
)
type BarChart struct {

140
widgets/form.go Normal file
View File

@ -0,0 +1,140 @@
package widgets
import (
"context"
"fmt"
. "github.com/proullon/termui/v3"
)
type Field struct {
Name string
Text string
cursor int
}
type Form struct {
Paragraph
TextFgColor Style
TextBgColor Style
Fields []*Field
Done bool
ctx context.Context
onExitCallback func(ctx context.Context, validated bool, fields []*Field)
fieldIdx int
}
func NewField(name string, value string) *Field {
f := &Field{
Name: name,
Text: value,
}
return f
}
func NewForm(ctx context.Context, name string, callback func(ctx context.Context, validated bool, fields []*Field), fields ...*Field) *Form {
f := &Form{
Paragraph: *NewParagraph(),
TextFgColor: Theme.Paragraph.Text,
ctx: ctx,
onExitCallback: callback,
}
for _, field := range fields {
f.Fields = append(f.Fields, field)
}
f.Border = true
f.Title = name
f._draw()
return f
}
// Handle input event
// <Up> or <Down> to switch field
// <Enter> will switch to next field or exit scan if last field
func (f *Form) Handle(e Event) {
switch e.ID {
case "<Down>":
if f.fieldIdx < len(f.Fields)-1 {
f.fieldIdx++
}
case "<Up>":
if f.fieldIdx > 0 {
f.fieldIdx--
}
case "<Enter>":
if f.fieldIdx < len(f.Fields)-1 {
f.fieldIdx++
} else {
f.Done = true
f.onExitCallback(f.ctx, true, f.Fields)
}
case "<Esc>":
f.Done = true
f.onExitCallback(f.ctx, false, f.Fields)
default:
f.Fields[f.fieldIdx].Handle(e)
}
f._draw()
Render(f)
}
// Handle field input
func (f *Field) Handle(e Event) {
switch e.ID {
case "<Backspace>":
if f.cursor > 0 {
f.Text = f.Text[:f.cursor-1] + f.Text[f.cursor:]
} else if len(f.Text) > 1 {
f.Text = f.Text[1:]
} else {
f.Text = ""
}
if f.cursor > 0 {
f.cursor--
}
if f.cursor > len(f.Text) {
f.cursor = len(f.Text)
}
case "<Right>":
if f.cursor < len(f.Text) {
f.cursor++
}
case "<Left>":
if f.cursor > 0 {
f.cursor--
}
case "<Space>":
f.Text = f.Text[:f.cursor] + " " + f.Text[f.cursor:]
f.cursor++
default:
f.Text = f.Text[:f.cursor] + e.ID + f.Text[f.cursor:]
f.cursor++
}
}
// IsDone return wether user has entered <Esc> or <Enter>
func (f *Form) IsDone() bool {
return f.Done
}
func (f *Form) _draw() {
cursor := "[|](bg:white)"
f.Text = ""
for i, field := range f.Fields {
txt := field.Text
if i == f.fieldIdx && field.Text != "" {
begin := field.Text[:field.cursor]
end := field.Text[field.cursor:]
txt = begin + cursor + end
} else if i == f.fieldIdx {
txt = cursor
}
f.Text += fmt.Sprintf("%s: %s\n", field.Name, txt)
}
}

View File

@ -8,7 +8,7 @@ import (
"fmt"
"image"
. "github.com/gizak/termui/v3"
. "github.com/proullon/termui/v3"
)
type Gauge struct {

View File

@ -8,7 +8,7 @@ import (
"image"
"image/color"
. "github.com/gizak/termui/v3"
. "github.com/proullon/termui/v3"
)
type Image struct {

View File

@ -9,7 +9,7 @@ import (
rw "github.com/mattn/go-runewidth"
. "github.com/gizak/termui/v3"
. "github.com/proullon/termui/v3"
)
type List struct {

View File

@ -7,7 +7,7 @@ package widgets
import (
"image"
. "github.com/gizak/termui/v3"
. "github.com/proullon/termui/v3"
)
type Paragraph struct {

View File

@ -4,7 +4,7 @@ import (
"image"
"math"
. "github.com/gizak/termui/v3"
. "github.com/proullon/termui/v3"
)
const (

View File

@ -8,7 +8,7 @@ import (
"fmt"
"image"
. "github.com/gizak/termui/v3"
. "github.com/proullon/termui/v3"
)
// Plot has two modes: line(default) and scatter.

View File

@ -7,7 +7,7 @@ package widgets
import (
"image"
. "github.com/gizak/termui/v3"
. "github.com/proullon/termui/v3"
)
// Sparkline is like: ▅▆▂▂▅▇▂▂▃▆▆▆▅▃. The data points should be non-negative integers.

View File

@ -10,7 +10,7 @@ import (
rw "github.com/mattn/go-runewidth"
. "github.com/gizak/termui/v3"
. "github.com/proullon/termui/v3"
)
type StackedBarChart struct {

View File

@ -7,10 +7,11 @@ package widgets
import (
"image"
. "github.com/gizak/termui/v3"
. "github.com/proullon/termui/v3"
)
/*Table is like:
/*
Table is like:
Awesome Table
Col0 | Col1 | Col2 | Col3 | Col4 | Col5 | Col6 |

View File

@ -7,7 +7,7 @@ package widgets
import (
"image"
. "github.com/gizak/termui/v3"
. "github.com/proullon/termui/v3"
)
// TabPane is a renderable widget which can be used to conditionally render certain tabs/views.

View File

@ -5,8 +5,8 @@ import (
"image"
"strings"
. "github.com/gizak/termui/v3"
rw "github.com/mattn/go-runewidth"
. "github.com/proullon/termui/v3"
)
const treeIndent = " "