func DownLines(w IWidget, size gowid.IRenderSize, doPage bool, app gowid.IApp) bool {
	prev := w.CursorPos()
	twc := w.MakeText()
	caplen := utf8.RuneCountInString(w.Caption())
	cols, ok := size.(gowid.IColumns)
	if !ok {
		panic(gowid.WidgetSizeError{Widget: w, Size: size, Required: "gowid.IColumns"})
	}
	layout := text.MakeTextLayout(twc.Content(), cols.Columns(), text.WrapAny, gowid.HAlignLeft{})
	ccol, crow := text.GetCoordsFromCursorPos(w.CursorPos()+caplen, cols.Columns(), layout, w)
	offset := 1
	if rows, ok := size.(gowid.IRows); ok && doPage {
		if crow < w.LinesFromTop()+rows.Rows()-1 {
			offset = w.LinesFromTop() + rows.Rows() - (crow + 1)
		} else {
			offset = rows.Rows()
		}
	}
	targetRow := crow + offset
	newCursorPos := text.GetCursorPosFromCoords(ccol, targetRow, layout, w) - caplen
	if newCursorPos < 0 {
		return false
	} else {
		w.SetCursorPos(newCursorPos, app)
		if box, ok := size.(gowid.IRenderBox); ok && (targetRow >= box.BoxRows()+w.LinesFromTop()) {  
			w.SetLinesFromTop(w.LinesFromTop()+offset, app)
		}
		return (prev != w.CursorPos())
	}
}
Return true if done
package edit
import (
	"fmt"
	"io"
	"unicode"
	"unicode/utf8"
	"github.com/gcla/gowid"
	"github.com/gcla/gowid/gwutil"
	"github.com/gcla/gowid/widgets/text"
	"github.com/gdamore/tcell"
	"github.com/pkg/errors"
)
type IEdit interface {
	text.ISimple
	IMask
	text.ICursor
	Caption() string
	MakeText() text.IWidget
}
type IMask interface {
	UseMask() bool
	MaskChr() rune
}
type Mask struct {
	Chr    rune
	Enable bool
}
type Text struct{}
type Caption struct{}
type Cursor struct{}
func DisabledMask() Mask {
	return Mask{Chr: 'x', Enable: false}
}
func MakeMask(chr rune) Mask {
	return Mask{Chr: chr, Enable: true}
}
func (m Mask) UseMask() bool {
	return m.Enable
}
func (m Mask) MaskChr() rune {
	return m.Chr
}
type IWidget interface {
	IEdit
	text.IChrAt
	LinesFromTop() int
	SetLinesFromTop(int, gowid.IApp)
	UpLines(size gowid.IRenderSize, doPage bool, app gowid.IApp) bool
	DownLines(size gowid.IRenderSize, doPage bool, app gowid.IApp) bool
}
type Widget struct {
	IMask
	caption      string
	text         string
	cursorPos    int
	linesFromTop int
	Callbacks    *gowid.Callbacks
	gowid.IsSelectable
}
var _ fmt.Stringer = (*Widget)(nil)
var _ io.Reader = (*Widget)(nil)
var _ gowid.IWidget = (*Widget)(nil)
type Writer struct {
	*Widget
	gowid.IApp
}
type Options struct {
	Caption string
	Text    string
	Mask    IMask
}
func New(args ...Options) *Widget {
	var opt Options
	if len(args) > 0 {
		opt = args[0]
	}
	if opt.Mask == nil {
		opt.Mask = DisabledMask()
	}
	res := &Widget{
		IMask:        opt.Mask,
		caption:      opt.Caption,
		text:         opt.Text,
		cursorPos:    len(opt.Text),
		linesFromTop: 0,
		Callbacks:    gowid.NewCallbacks(),
	}
	return res
}
func (w *Widget) String() string {
	return fmt.Sprintf("edit")
}
func (w *Writer) Write(p []byte) (n int, err error) {
	w.SetText(string(p), w.IApp)
	w.cursorPos = 0
	w.linesFromTop = 0
	return len(p), nil
}
func (w *Widget) Read(p []byte) (n int, err error) {
	pl := len(p)
	num := copy(p, w.text[:])
	if num < pl {
		return num, io.EOF
	} else {
		return num, nil
	}
}
func (w *Widget) Text() string {
	return w.text
}
var InvalidRuneIndex error = errors.New("Invalid rune index for string")
func (w *Widget) ChrAt(i int) rune {
	j := 0
	for _, char := range w.caption {
		if j == i {
			return char
		}
		j++
	}
	for _, char := range w.text {
		if j == i {
			return char
		}
		j++
	}
	panic(errors.WithStack(gowid.WithKVs(InvalidRuneIndex, map[string]interface{}{"index": i, "text": w.text})))
}
func (w *Widget) SetText(text string, app gowid.IApp) {
	w.text = text
	wid := utf8.RuneCountInString(w.text)
	if w.cursorPos > wid {
		w.SetCursorPos(wid, app)
	}
	gowid.RunWidgetCallbacks(w.Callbacks, Text{}, app, w)
}
func (w *Widget) LinesFromTop() int {
	return w.linesFromTop
}
func (w *Widget) SetLinesFromTop(l int, app gowid.IApp) {
	w.linesFromTop = l
}
func (w *Widget) Caption() string {
	return w.caption
}
func (w *Widget) SetCaption(text string, app gowid.IApp) {
	w.caption = text
	gowid.RunWidgetCallbacks(w.Callbacks, Caption{}, app, w)
}
func (w *Widget) CursorEnabled() bool {
	return w.cursorPos != -1
}
func (w *Widget) SetCursorDisabled() {
	w.cursorPos = -1
}
func (w *Widget) CursorPos() int {
	if !w.CursorEnabled() {
		panic(errors.New("Cursor is disabled, cannot return!"))
	}
	return w.cursorPos
}
func (w *Widget) SetCursorPos(pos int, app gowid.IApp) {
	pos = gwutil.Min(pos, utf8.RuneCountInString(w.Text()))
	w.cursorPos = pos
	gowid.RunWidgetCallbacks(w.Callbacks, Cursor{}, app, w)
}
func (w *Widget) OnTextSet(cb gowid.IWidgetChangedCallback) {
	gowid.AddWidgetCallback(w.Callbacks, Text{}, cb)
}
func (w *Widget) RemoveOnTextSet(cb gowid.IIdentity) {
	gowid.RemoveWidgetCallback(w.Callbacks, Text{}, cb)
}
func (w *Widget) OnCaptionSet(cb gowid.IWidgetChangedCallback) {
	gowid.AddWidgetCallback(w.Callbacks, Caption{}, cb)
}
func (w *Widget) RemoveOnCaptionSet(cb gowid.IIdentity) {
	gowid.RemoveWidgetCallback(w.Callbacks, Caption{}, cb)
}
func (w *Widget) OnCursorPosSet(cb gowid.IWidgetChangedCallback) {
	gowid.AddWidgetCallback(w.Callbacks, Cursor{}, cb)
}
func (w *Widget) RemoveOnCursorPosSet(cb gowid.IIdentity) {
	gowid.RemoveWidgetCallback(w.Callbacks, Cursor{}, cb)
}
func (w *Widget) RenderSize(size gowid.IRenderSize, focus gowid.Selector, app gowid.IApp) gowid.IRenderBox {
	return gowid.CalculateRenderSizeFallback(w, size, focus, app)
}
func (w *Widget) Render(size gowid.IRenderSize, focus gowid.Selector, app gowid.IApp) gowid.ICanvas {
	return Render(w, size, focus, app)
}
func (w *Widget) MakeText() text.IWidget {
	return MakeText(w)
}
func (w *Widget) UserInput(ev interface{}, size gowid.IRenderSize, focus gowid.Selector, app gowid.IApp) bool {
	return UserInput(w, ev, size, focus, app)
}
func (w *Widget) DownLines(size gowid.IRenderSize, doPage bool, app gowid.IApp) bool {
	return DownLines(w, size, doPage, app)
}
func (w *Widget) UpLines(size gowid.IRenderSize, doPage bool, app gowid.IApp) bool {
	return UpLines(w, size, doPage, app)
}
func (w *Widget) CalculateTopMiddleBottom(size gowid.IRenderSize) (int, int, int) {
	return CalculateTopMiddleBottom(w, size)
}
func Render(w IWidget, size gowid.IRenderSize, focus gowid.Selector, app gowid.IApp) gowid.ICanvas {
	twc := w.MakeText()
	c := twc.Render(size, focus, app)
	return c
}
func MakeText(w IWidget) text.IWidget {
	var txt string
	if w.UseMask() {
		arr := make([]rune, len(w.Text()))
		for i := 0; i < len(arr); i++ {
			arr[i] = w.MaskChr()
		}
		txt = string(arr)
	} else {
		txt = w.Text()
	}
	txt = w.Caption() + txt
	tw := text.New(txt)
	tw.SetLinesFromTop(w.LinesFromTop(), nil)
	cu := &text.SimpleCursor{-1}
	cu.SetCursorPos(w.CursorPos()+utf8.RuneCountInString(w.Caption()), nil)
	twc := &text.WidgetWithCursor{tw, cu}
	return twc
}
func CalculateTopMiddleBottom(w IWidget, size gowid.IRenderSize) (int, int, int) {
	twc := w.MakeText()
	return text.CalculateTopMiddleBottom(twc, size)
}