console.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. package widget
  2. // import "fmt"
  3. import "strings"
  4. import "gitlab.com/beoran/ebsgo/zori/keycode"
  5. import "gitlab.com/beoran/ebsgo/zori/types"
  6. // import _ "gitlab.com/beoran/ebsgo/zori/backend"
  7. // import "gitlab.com/beoran/ebsgo/zori/state"
  8. // import "gitlab.com/beoran/ebsgo/zori/style"
  9. import "gitlab.com/beoran/ebsgo/zori/event"
  10. type ConsoleCommand func(cw *Console, command string, data interface{}) int
  11. const ConsoleLimit = 1000
  12. type Console struct {
  13. * Basic
  14. Lines []string
  15. Input string
  16. Position int
  17. Cursor int
  18. Command ConsoleCommand
  19. Data interface{}
  20. }
  21. func (cw * Console) Dispatch(ev event.Event) event.Result {
  22. return event.Dispatch(ev, cw)
  23. }
  24. /** Let the console perform a command if possible. returns nonzero on error,
  25. zero if OK. */
  26. func (cw *Console) DoCommand(text string) int {
  27. if cw.Command == nil {
  28. return -1
  29. }
  30. return cw.Command(cw, text, cw.Data)
  31. }
  32. /** Adds a line of text to the console. */
  33. func (cw * Console) AddLine(line string) {
  34. cw.Lines = append(cw.Lines, line)
  35. if len(cw.Lines) > ConsoleLimit {
  36. cw.Lines[0] = ""
  37. cw.Lines = cw.Lines[1:]
  38. }
  39. }
  40. /** Puts a string on the console .*/
  41. func (cw * Console) Puts(text string) {
  42. font := cw.TextFont()
  43. // Assume a fixed width font for the console.
  44. charw := font.TextWidth("W")
  45. lines := strings.Split(text, "\n")
  46. for _, line := range lines {
  47. runes := []rune(line)
  48. max_chars := cw.Inner.W / charw
  49. for len(runes) > max_chars {
  50. sub := string(runes[0:max_chars-1])
  51. runes = runes[max_chars:]
  52. cw.AddLine(sub)
  53. }
  54. cw.AddLine(string(runes))
  55. }
  56. }
  57. /** Draws a console. */
  58. func (cw * Console) Draw(ev event.Draw) event.Result {
  59. cw.DrawBackground()
  60. font := cw.TextFont()
  61. colo := cw.TextColor()
  62. be := cw.Backend()
  63. linehigh := font.LineHeight()
  64. available := (cw.Inner.H / linehigh - 1)
  65. x := cw.Inner.X
  66. y := cw.Inner.Y
  67. start := len(cw.Lines) - available - cw.Position
  68. if start < 0 {
  69. start = 0
  70. } else if start >= len(cw.Lines) {
  71. start = len(cw.Lines) - 1
  72. }
  73. for index := start; index < len(cw.Lines) ; index ++ {
  74. be.DrawText(font, colo, x, y, cw.Lines[index])
  75. x += linehigh
  76. }
  77. // input = cw.Input[0:cw.Cursor-1] + "|" + cw.Input[cw.Cursor:]
  78. // XXX draw cursor.
  79. be.DrawText(font, colo, x, y, cw.Input)
  80. return event.Pass
  81. }
  82. func (cw * Console) Scroll (dir int) event.Result {
  83. cw.Position += dir
  84. if cw.Position < 0 {
  85. cw.Position = 0
  86. } else if cw.Position >= len(cw.Lines) {
  87. cw.Position = len(cw.Lines) - 1
  88. }
  89. return event.Done
  90. }
  91. func (cw * Console) Backspace() event.Result {
  92. if len(cw.Input) > 0 {
  93. runes := []rune(cw.Input)
  94. runes = runes[0:len(runes)-1]
  95. cw.Input = string(runes)
  96. }
  97. return event.Done
  98. }
  99. /* Key input event handler for console. */
  100. func (cw *Console) KeyChar(ke event.Key) event.Result {
  101. cw.Basic.KeyChar(ke)
  102. ru := ke.Unichar()
  103. kc := ke.KeyCode()
  104. switch (kc) {
  105. // ignore the start-console key
  106. case keycode.KEY_F1: fallthrough
  107. case keycode.KEY_F3: return event.Done
  108. case keycode.KEY_PGUP: return cw.Scroll(1)
  109. case keycode.KEY_PGDN: return cw.Scroll(-1)
  110. case keycode.KEY_BACKSPACE: return cw.Backspace()
  111. case keycode.KEY_ENTER:
  112. if cw.DoCommand(cw.Input) < 0 {
  113. cw.Puts("Error executing command.");
  114. }
  115. cw.Input = ""
  116. return event.Done
  117. default:
  118. cw.Input = string(append([]rune(cw.Input), ru))
  119. return event.Done
  120. }
  121. }
  122. func (cw *Console) KeyPress(ke event.Key) event.Result {
  123. cw.Basic.KeyPress(ke)
  124. kc := ke.KeyCode()
  125. switch (kc) {
  126. // ignore the start-console key
  127. case keycode.KEY_F1: fallthrough
  128. case keycode.KEY_F3:
  129. cw.SetLive(false)
  130. return event.Done
  131. default:
  132. return event.Pass
  133. }
  134. }
  135. func (cw * Console) MouseAxes(ev event.Mouse) event.Result {
  136. dz := ev.DZ()
  137. if dz == 0 {
  138. return event.Pass
  139. } else if dz < 0 {
  140. return cw.Scroll(-1)
  141. } else {
  142. return cw.Scroll(+1)
  143. }
  144. }
  145. func NewConsole(parent Widget, bounds * types.Box,
  146. com ConsoleCommand) * Console {
  147. con := &Console{}
  148. con.Basic = NewBasic(parent, bounds, nil)
  149. con.Command = com
  150. return con
  151. }