Files
prevara/textinput.go

147 lines
3.8 KiB
Go

package gel
import (
"image"
"image/color"
"gioui.org/font"
l "gioui.org/layout"
"gioui.org/op"
"gioui.org/op/paint"
"gioui.org/text"
"gioui.org/unit"
"git.mleku.dev/mleku/prevara/f32color"
)
// TextInput is a simple text input widget
type TextInput struct {
*Window
font font.Font
textSize unit.Sp
// Color is the text color.
color color.NRGBA
// Hint contains the text displayed when the editor is empty.
hint string
// HintColor is the color of hint text.
hintColor color.NRGBA
// SelectionColor is the color of the background for selected text.
selectionColor color.NRGBA
editor *Editor
shaper *text.Shaper
}
// TextInput creates a simple text input widget
func (w *Window) TextInput(editor *Editor, hint string) *TextInput {
var fon font.Font
if f, e := w.collection.Font("bariol regular"); e == nil {
fon = f
}
ti := &TextInput{
Window: w,
editor: editor,
textSize: w.TextSize,
font: fon,
color: w.Colors.GetNRGBAFromName("DocText"),
shaper: w.shaper,
hint: hint,
hintColor: w.Colors.GetNRGBAFromName("Hint"),
selectionColor: w.Colors.GetNRGBAFromName("scrim"),
}
return ti
}
// Font sets the font for the text input widget
func (ti *TextInput) Font(fontName string) *TextInput {
var fon font.Font
var e error
if fon, e = ti.Theme.collection.Font(fontName); !E.Chk(e) {
ti.editor.font = fon
}
return ti
}
// TextScale sets the size of the text relative to the base font size
func (ti *TextInput) TextScale(scale float32) *TextInput {
ti.textSize = unit.Sp(float32(ti.Theme.TextSize) * scale)
return ti
}
// Color sets the color to render the text
func (ti *TextInput) Color(color string) *TextInput {
ti.color = ti.Theme.Colors.GetNRGBAFromName(color)
return ti
}
// SelectionColor sets the color to render the text
func (ti *TextInput) SelectionColor(color string) *TextInput {
ti.selectionColor = ti.Theme.Colors.GetNRGBAFromName(color)
return ti
}
// Hint sets the text to show when the box is empty
func (ti *TextInput) Hint(hint string) *TextInput {
ti.hint = hint
return ti
}
// HintColor sets the color of the hint text
func (ti *TextInput) HintColor(color string) *TextInput {
ti.hintColor = ti.Theme.Colors.GetNRGBAFromName(color)
return ti
}
// Fn renders the text input widget
func (ti *TextInput) Fn(gtx l.Context) l.Dimensions {
// Save state using the new Push/Pop pattern
stack := op.Offset(image.Point{}).Push(gtx.Ops)
defer stack.Pop()
disabled := !gtx.Source.Enabled()
textColor := blendDisabledColor(disabled, ti.color)
selectionColor := blendDisabledColor(disabled, ti.selectionColor)
// If editor is empty, show hint first to determine minimum size
if ti.editor.Len() == 0 {
macro := op.Record(gtx.Ops)
paint.ColorOp{Color: ti.hintColor}.Add(gtx.Ops)
var maxlines int
if ti.editor.singleLine {
maxlines = 1
}
tl := Label{
Window: ti.Window,
font: ti.font,
color: ti.hintColor,
alignment: ti.editor.alignment,
maxLines: maxlines,
text: ti.hint,
textSize: ti.textSize,
shaper: ti.shaper,
}
dims := tl.Fn(gtx)
call := macro.Stop()
if w := dims.Size.X; gtx.Constraints.Min.X < w {
gtx.Constraints.Min.X = w
}
if h := dims.Size.Y; gtx.Constraints.Min.Y < h {
gtx.Constraints.Min.Y = h
}
// Layout the editor (even if empty, to handle input)
editorDims := ti.editor.Layout(gtx, ti.shaper, ti.font, ti.textSize, textColor, selectionColor)
// Draw the hint since editor is empty
call.Add(gtx.Ops)
return editorDims
}
// Layout the editor with text and selection colors
return ti.editor.Layout(gtx, ti.shaper, ti.font, ti.textSize, textColor, selectionColor)
}
func blendDisabledColor(disabled bool, c color.NRGBA) color.NRGBA {
if disabled {
return f32color.Disabled(c)
}
return c
}