package widget // import "fmt" import "strings" import "gitlab.com/beoran/ebsgo/zori/keycode" import "gitlab.com/beoran/ebsgo/zori/types" // import _ "gitlab.com/beoran/ebsgo/zori/backend" // import "gitlab.com/beoran/ebsgo/zori/state" // import "gitlab.com/beoran/ebsgo/zori/style" import "gitlab.com/beoran/ebsgo/zori/event" type ConsoleCommand func(cw *Console, command string, data interface{}) int const ConsoleLimit = 1000 type Console struct { * Basic Lines []string Input string Position int Cursor int Command ConsoleCommand Data interface{} } func (cw * Console) Dispatch(ev event.Event) event.Result { return event.Dispatch(ev, cw) } /** Let the console perform a command if possible. returns nonzero on error, zero if OK. */ func (cw *Console) DoCommand(text string) int { if cw.Command == nil { return -1 } return cw.Command(cw, text, cw.Data) } /** Adds a line of text to the console. */ func (cw * Console) AddLine(line string) { cw.Lines = append(cw.Lines, line) if len(cw.Lines) > ConsoleLimit { cw.Lines[0] = "" cw.Lines = cw.Lines[1:] } } /** Puts a string on the console .*/ func (cw * Console) Puts(text string) { font := cw.TextFont() // Assume a fixed width font for the console. charw := font.TextWidth("W") lines := strings.Split(text, "\n") for _, line := range lines { runes := []rune(line) max_chars := cw.Inner.W / charw for len(runes) > max_chars { sub := string(runes[0:max_chars-1]) runes = runes[max_chars:] cw.AddLine(sub) } cw.AddLine(string(runes)) } } /** Draws a console. */ func (cw * Console) Draw(ev event.Draw) event.Result { cw.DrawBackground() font := cw.TextFont() colo := cw.TextColor() be := cw.Backend() linehigh := font.LineHeight() available := (cw.Inner.H / linehigh - 1) x := cw.Inner.X y := cw.Inner.Y start := len(cw.Lines) - available - cw.Position if start < 0 { start = 0 } else if start >= len(cw.Lines) { start = len(cw.Lines) - 1 } for index := start; index < len(cw.Lines) ; index ++ { be.DrawText(font, colo, x, y, cw.Lines[index]) x += linehigh } // input = cw.Input[0:cw.Cursor-1] + "|" + cw.Input[cw.Cursor:] // XXX draw cursor. be.DrawText(font, colo, x, y, cw.Input) return event.Pass } func (cw * Console) Scroll (dir int) event.Result { cw.Position += dir if cw.Position < 0 { cw.Position = 0 } else if cw.Position >= len(cw.Lines) { cw.Position = len(cw.Lines) - 1 } return event.Done } func (cw * Console) Backspace() event.Result { if len(cw.Input) > 0 { runes := []rune(cw.Input) runes = runes[0:len(runes)-1] cw.Input = string(runes) } return event.Done } /* Key input event handler for console. */ func (cw *Console) KeyChar(ke event.Key) event.Result { cw.Basic.KeyChar(ke) ru := ke.Unichar() kc := ke.KeyCode() switch (kc) { // ignore the start-console key case keycode.KEY_F1: fallthrough case keycode.KEY_F3: return event.Done case keycode.KEY_PGUP: return cw.Scroll(1) case keycode.KEY_PGDN: return cw.Scroll(-1) case keycode.KEY_BACKSPACE: return cw.Backspace() case keycode.KEY_ENTER: if cw.DoCommand(cw.Input) < 0 { cw.Puts("Error executing command."); } cw.Input = "" return event.Done default: cw.Input = string(append([]rune(cw.Input), ru)) return event.Done } } func (cw *Console) KeyPress(ke event.Key) event.Result { cw.Basic.KeyPress(ke) kc := ke.KeyCode() switch (kc) { // ignore the start-console key case keycode.KEY_F1: fallthrough case keycode.KEY_F3: cw.SetLive(false) return event.Done default: return event.Pass } } func (cw * Console) MouseAxes(ev event.Mouse) event.Result { dz := ev.DZ() if dz == 0 { return event.Pass } else if dz < 0 { return cw.Scroll(-1) } else { return cw.Scroll(+1) } } func NewConsole(parent Widget, bounds * types.Box, com ConsoleCommand) * Console { con := &Console{} con.Basic = NewBasic(parent, bounds, nil) con.Command = com return con }