Initial commit, lots of cleanup and stuff to do, it may not work.
This commit is contained in:
25
uiterm/attributes.go
Normal file
25
uiterm/attributes.go
Normal file
@ -0,0 +1,25 @@
|
||||
package uiterm
|
||||
|
||||
/*
|
||||
* Source: https://godoc.org/github.com/nsf/termbox-go
|
||||
*/
|
||||
|
||||
type Attribute int
|
||||
|
||||
const (
|
||||
ColorDefault Attribute = iota
|
||||
ColorBlack
|
||||
ColorRed
|
||||
ColorGreen
|
||||
ColorYellow
|
||||
ColorBlue
|
||||
ColorMagenta
|
||||
ColorCyan
|
||||
ColorWhite
|
||||
)
|
||||
|
||||
const (
|
||||
AttrBold Attribute = 1 << (iota + 4)
|
||||
AttrUnderline
|
||||
AttrReverse
|
||||
)
|
1
uiterm/doc.go
Normal file
1
uiterm/doc.go
Normal file
@ -0,0 +1 @@
|
||||
package uiterm // import "git.2mb.codes/~cmb/barnard/uiterm"
|
253
uiterm/key_enumer.go
Normal file
253
uiterm/key_enumer.go
Normal file
@ -0,0 +1,253 @@
|
||||
// Code generated by "enumer -type=Key -trimprefix=Key -yaml -json -transform=snake"; DO NOT EDIT.
|
||||
|
||||
//
|
||||
package uiterm
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
_KeyName_0 = "ctrl_tildectrl_actrl_bctrl_cctrl_dctrl_ectrl_fctrl_gbackspacetabctrl_jctrl_kctrl_lenterctrl_nctrl_octrl_pctrl_qctrl_rctrl_sctrl_tctrl_uctrl_vctrl_wctrl_xctrl_yctrl_zescctrl4ctrl5ctrl6ctrl7space"
|
||||
_KeyName_1 = "backspace2"
|
||||
_KeyName_2 = "mouse_rightmouse_middlemouse_leftarrow_rightarrow_leftarrow_downarrow_uppgdnpgupendhomedeleteinsertf12f11f10f9f8f7f6f5f4f3f2f1alt_ctrl_tildealt_ctrl_aalt_ctrl_balt_ctrl_calt_ctrl_dalt_ctrl_ealt_ctrl_falt_ctrl_galt_backspacealt_tabalt_ctrl_jalt_ctrl_kalt_ctrl_lalt_enteralt_ctrl_nalt_ctrl_oalt_ctrl_palt_ctrl_qalt_ctrl_ralt_ctrl_salt_ctrl_talt_ctrl_ualt_ctrl_valt_ctrl_walt_ctrl_xalt_ctrl_yalt_ctrl_zalt_escalt_ctrl4alt_ctrl5alt_ctrl6alt_ctrl7alt_space"
|
||||
_KeyName_3 = "alt_aalt_balt_calt_dalt_ealt_falt_galt_halt_ialt_jalt_kalt_lalt_malt_nalt_oalt_palt_qalt_ralt_salt_talt_ualt_valt_walt_xalt_yalt_z"
|
||||
_KeyName_4 = "alt_backspace2"
|
||||
_KeyName_5 = "alt_arrow_rightalt_arrow_leftalt_arrow_downalt_arrow_upalt_pgdnalt_pgupalt_endalt_homealt_deletealt_insertalt_f12alt_f11alt_f10alt_f9alt_f8alt_f7alt_f6alt_f5alt_f4alt_f3alt_f2alt_f1"
|
||||
)
|
||||
|
||||
var (
|
||||
_KeyIndex_0 = [...]uint8{0, 10, 16, 22, 28, 34, 40, 46, 52, 61, 64, 70, 76, 82, 87, 93, 99, 105, 111, 117, 123, 129, 135, 141, 147, 153, 159, 165, 168, 173, 178, 183, 188, 193}
|
||||
_KeyIndex_1 = [...]uint8{0, 10}
|
||||
_KeyIndex_2 = [...]uint16{0, 11, 23, 33, 44, 54, 64, 72, 76, 80, 83, 87, 93, 99, 102, 105, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 140, 150, 160, 170, 180, 190, 200, 210, 223, 230, 240, 250, 260, 269, 279, 289, 299, 309, 319, 329, 339, 349, 359, 369, 379, 389, 399, 406, 415, 424, 433, 442, 451}
|
||||
_KeyIndex_3 = [...]uint8{0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 105, 110, 115, 120, 125, 130}
|
||||
_KeyIndex_4 = [...]uint8{0, 14}
|
||||
_KeyIndex_5 = [...]uint8{0, 15, 29, 43, 55, 63, 71, 78, 86, 96, 106, 113, 120, 127, 133, 139, 145, 151, 157, 163, 169, 175, 181}
|
||||
)
|
||||
|
||||
func (i Key) String() string {
|
||||
switch {
|
||||
case 0 <= i && i <= 32:
|
||||
return _KeyName_0[_KeyIndex_0[i]:_KeyIndex_0[i+1]]
|
||||
case i == 127:
|
||||
return _KeyName_1
|
||||
case 65511 <= i && i <= 65568:
|
||||
i -= 65511
|
||||
return _KeyName_2[_KeyIndex_2[i]:_KeyIndex_2[i+1]]
|
||||
case 65633 <= i && i <= 65658:
|
||||
i -= 65633
|
||||
return _KeyName_3[_KeyIndex_3[i]:_KeyIndex_3[i+1]]
|
||||
case i == 65663:
|
||||
return _KeyName_4
|
||||
case 131050 <= i && i <= 131071:
|
||||
i -= 131050
|
||||
return _KeyName_5[_KeyIndex_5[i]:_KeyIndex_5[i+1]]
|
||||
default:
|
||||
return fmt.Sprintf("Key(%d)", i)
|
||||
}
|
||||
}
|
||||
|
||||
var _KeyValues = []Key{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 127, 65511, 65512, 65513, 65514, 65515, 65516, 65517, 65518, 65519, 65520, 65521, 65522, 65523, 65524, 65525, 65526, 65527, 65528, 65529, 65530, 65531, 65532, 65533, 65534, 65535, 65536, 65537, 65538, 65539, 65540, 65541, 65542, 65543, 65544, 65545, 65546, 65547, 65548, 65549, 65550, 65551, 65552, 65553, 65554, 65555, 65556, 65557, 65558, 65559, 65560, 65561, 65562, 65563, 65564, 65565, 65566, 65567, 65568, 65633, 65634, 65635, 65636, 65637, 65638, 65639, 65640, 65641, 65642, 65643, 65644, 65645, 65646, 65647, 65648, 65649, 65650, 65651, 65652, 65653, 65654, 65655, 65656, 65657, 65658, 65663, 131050, 131051, 131052, 131053, 131054, 131055, 131056, 131057, 131058, 131059, 131060, 131061, 131062, 131063, 131064, 131065, 131066, 131067, 131068, 131069, 131070, 131071}
|
||||
|
||||
var _KeyNameToValueMap = map[string]Key{
|
||||
_KeyName_0[0:10]: 0,
|
||||
_KeyName_0[10:16]: 1,
|
||||
_KeyName_0[16:22]: 2,
|
||||
_KeyName_0[22:28]: 3,
|
||||
_KeyName_0[28:34]: 4,
|
||||
_KeyName_0[34:40]: 5,
|
||||
_KeyName_0[40:46]: 6,
|
||||
_KeyName_0[46:52]: 7,
|
||||
_KeyName_0[52:61]: 8,
|
||||
_KeyName_0[61:64]: 9,
|
||||
_KeyName_0[64:70]: 10,
|
||||
_KeyName_0[70:76]: 11,
|
||||
_KeyName_0[76:82]: 12,
|
||||
_KeyName_0[82:87]: 13,
|
||||
_KeyName_0[87:93]: 14,
|
||||
_KeyName_0[93:99]: 15,
|
||||
_KeyName_0[99:105]: 16,
|
||||
_KeyName_0[105:111]: 17,
|
||||
_KeyName_0[111:117]: 18,
|
||||
_KeyName_0[117:123]: 19,
|
||||
_KeyName_0[123:129]: 20,
|
||||
_KeyName_0[129:135]: 21,
|
||||
_KeyName_0[135:141]: 22,
|
||||
_KeyName_0[141:147]: 23,
|
||||
_KeyName_0[147:153]: 24,
|
||||
_KeyName_0[153:159]: 25,
|
||||
_KeyName_0[159:165]: 26,
|
||||
_KeyName_0[165:168]: 27,
|
||||
_KeyName_0[168:173]: 28,
|
||||
_KeyName_0[173:178]: 29,
|
||||
_KeyName_0[178:183]: 30,
|
||||
_KeyName_0[183:188]: 31,
|
||||
_KeyName_0[188:193]: 32,
|
||||
_KeyName_1[0:10]: 127,
|
||||
_KeyName_2[0:11]: 65511,
|
||||
_KeyName_2[11:23]: 65512,
|
||||
_KeyName_2[23:33]: 65513,
|
||||
_KeyName_2[33:44]: 65514,
|
||||
_KeyName_2[44:54]: 65515,
|
||||
_KeyName_2[54:64]: 65516,
|
||||
_KeyName_2[64:72]: 65517,
|
||||
_KeyName_2[72:76]: 65518,
|
||||
_KeyName_2[76:80]: 65519,
|
||||
_KeyName_2[80:83]: 65520,
|
||||
_KeyName_2[83:87]: 65521,
|
||||
_KeyName_2[87:93]: 65522,
|
||||
_KeyName_2[93:99]: 65523,
|
||||
_KeyName_2[99:102]: 65524,
|
||||
_KeyName_2[102:105]: 65525,
|
||||
_KeyName_2[105:108]: 65526,
|
||||
_KeyName_2[108:110]: 65527,
|
||||
_KeyName_2[110:112]: 65528,
|
||||
_KeyName_2[112:114]: 65529,
|
||||
_KeyName_2[114:116]: 65530,
|
||||
_KeyName_2[116:118]: 65531,
|
||||
_KeyName_2[118:120]: 65532,
|
||||
_KeyName_2[120:122]: 65533,
|
||||
_KeyName_2[122:124]: 65534,
|
||||
_KeyName_2[124:126]: 65535,
|
||||
_KeyName_2[126:140]: 65536,
|
||||
_KeyName_2[140:150]: 65537,
|
||||
_KeyName_2[150:160]: 65538,
|
||||
_KeyName_2[160:170]: 65539,
|
||||
_KeyName_2[170:180]: 65540,
|
||||
_KeyName_2[180:190]: 65541,
|
||||
_KeyName_2[190:200]: 65542,
|
||||
_KeyName_2[200:210]: 65543,
|
||||
_KeyName_2[210:223]: 65544,
|
||||
_KeyName_2[223:230]: 65545,
|
||||
_KeyName_2[230:240]: 65546,
|
||||
_KeyName_2[240:250]: 65547,
|
||||
_KeyName_2[250:260]: 65548,
|
||||
_KeyName_2[260:269]: 65549,
|
||||
_KeyName_2[269:279]: 65550,
|
||||
_KeyName_2[279:289]: 65551,
|
||||
_KeyName_2[289:299]: 65552,
|
||||
_KeyName_2[299:309]: 65553,
|
||||
_KeyName_2[309:319]: 65554,
|
||||
_KeyName_2[319:329]: 65555,
|
||||
_KeyName_2[329:339]: 65556,
|
||||
_KeyName_2[339:349]: 65557,
|
||||
_KeyName_2[349:359]: 65558,
|
||||
_KeyName_2[359:369]: 65559,
|
||||
_KeyName_2[369:379]: 65560,
|
||||
_KeyName_2[379:389]: 65561,
|
||||
_KeyName_2[389:399]: 65562,
|
||||
_KeyName_2[399:406]: 65563,
|
||||
_KeyName_2[406:415]: 65564,
|
||||
_KeyName_2[415:424]: 65565,
|
||||
_KeyName_2[424:433]: 65566,
|
||||
_KeyName_2[433:442]: 65567,
|
||||
_KeyName_2[442:451]: 65568,
|
||||
_KeyName_3[0:5]: 65633,
|
||||
_KeyName_3[5:10]: 65634,
|
||||
_KeyName_3[10:15]: 65635,
|
||||
_KeyName_3[15:20]: 65636,
|
||||
_KeyName_3[20:25]: 65637,
|
||||
_KeyName_3[25:30]: 65638,
|
||||
_KeyName_3[30:35]: 65639,
|
||||
_KeyName_3[35:40]: 65640,
|
||||
_KeyName_3[40:45]: 65641,
|
||||
_KeyName_3[45:50]: 65642,
|
||||
_KeyName_3[50:55]: 65643,
|
||||
_KeyName_3[55:60]: 65644,
|
||||
_KeyName_3[60:65]: 65645,
|
||||
_KeyName_3[65:70]: 65646,
|
||||
_KeyName_3[70:75]: 65647,
|
||||
_KeyName_3[75:80]: 65648,
|
||||
_KeyName_3[80:85]: 65649,
|
||||
_KeyName_3[85:90]: 65650,
|
||||
_KeyName_3[90:95]: 65651,
|
||||
_KeyName_3[95:100]: 65652,
|
||||
_KeyName_3[100:105]: 65653,
|
||||
_KeyName_3[105:110]: 65654,
|
||||
_KeyName_3[110:115]: 65655,
|
||||
_KeyName_3[115:120]: 65656,
|
||||
_KeyName_3[120:125]: 65657,
|
||||
_KeyName_3[125:130]: 65658,
|
||||
_KeyName_4[0:14]: 65663,
|
||||
_KeyName_5[0:15]: 131050,
|
||||
_KeyName_5[15:29]: 131051,
|
||||
_KeyName_5[29:43]: 131052,
|
||||
_KeyName_5[43:55]: 131053,
|
||||
_KeyName_5[55:63]: 131054,
|
||||
_KeyName_5[63:71]: 131055,
|
||||
_KeyName_5[71:78]: 131056,
|
||||
_KeyName_5[78:86]: 131057,
|
||||
_KeyName_5[86:96]: 131058,
|
||||
_KeyName_5[96:106]: 131059,
|
||||
_KeyName_5[106:113]: 131060,
|
||||
_KeyName_5[113:120]: 131061,
|
||||
_KeyName_5[120:127]: 131062,
|
||||
_KeyName_5[127:133]: 131063,
|
||||
_KeyName_5[133:139]: 131064,
|
||||
_KeyName_5[139:145]: 131065,
|
||||
_KeyName_5[145:151]: 131066,
|
||||
_KeyName_5[151:157]: 131067,
|
||||
_KeyName_5[157:163]: 131068,
|
||||
_KeyName_5[163:169]: 131069,
|
||||
_KeyName_5[169:175]: 131070,
|
||||
_KeyName_5[175:181]: 131071,
|
||||
}
|
||||
|
||||
// KeyString retrieves an enum value from the enum constants string name.
|
||||
// Throws an error if the param is not part of the enum.
|
||||
func KeyString(s string) (Key, error) {
|
||||
if val, ok := _KeyNameToValueMap[s]; ok {
|
||||
return val, nil
|
||||
}
|
||||
return 0, fmt.Errorf("%s does not belong to Key values", s)
|
||||
}
|
||||
|
||||
// KeyValues returns all values of the enum
|
||||
func KeyValues() []Key {
|
||||
return _KeyValues
|
||||
}
|
||||
|
||||
// IsAKey returns "true" if the value is listed in the enum definition. "false" otherwise
|
||||
func (i Key) IsAKey() bool {
|
||||
for _, v := range _KeyValues {
|
||||
if i == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface for Key
|
||||
func (i Key) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(i.String())
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaler interface for Key
|
||||
func (i *Key) UnmarshalJSON(data []byte) error {
|
||||
var s string
|
||||
if err := json.Unmarshal(data, &s); err != nil {
|
||||
return fmt.Errorf("Key should be a string, got %s", data)
|
||||
}
|
||||
|
||||
var err error
|
||||
*i, err = KeyString(s)
|
||||
return err
|
||||
}
|
||||
|
||||
// MarshalYAML implements a YAML Marshaler for Key
|
||||
func (i Key) MarshalYAML() (interface{}, error) {
|
||||
return i.String(), nil
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements a YAML Unmarshaler for Key
|
||||
func (i *Key) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
var s string
|
||||
if err := unmarshal(&s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var err error
|
||||
*i, err = KeyString(s)
|
||||
return err
|
||||
}
|
186
uiterm/keys.go
Normal file
186
uiterm/keys.go
Normal file
@ -0,0 +1,186 @@
|
||||
package uiterm
|
||||
|
||||
//go:generate enumer -type=Key -trimprefix=Key -yaml -json -transform=snake
|
||||
|
||||
/*
|
||||
* Source: https://godoc.org/github.com/nsf/termbox-go
|
||||
*/
|
||||
|
||||
type Key uint32
|
||||
|
||||
const (
|
||||
KeyF1 Key = 0xFFFF - iota
|
||||
KeyF2
|
||||
KeyF3
|
||||
KeyF4
|
||||
KeyF5
|
||||
KeyF6
|
||||
KeyF7
|
||||
KeyF8
|
||||
KeyF9
|
||||
KeyF10
|
||||
KeyF11
|
||||
KeyF12
|
||||
KeyInsert
|
||||
KeyDelete
|
||||
KeyHome
|
||||
KeyEnd
|
||||
KeyPgup
|
||||
KeyPgdn
|
||||
KeyArrowUp
|
||||
KeyArrowDown
|
||||
KeyArrowLeft
|
||||
KeyArrowRight
|
||||
|
||||
MouseLeft
|
||||
MouseMiddle
|
||||
MouseRight
|
||||
)
|
||||
|
||||
const (
|
||||
KeyCtrlTilde Key = 0x00
|
||||
KeyCtrl2 Key = 0x00
|
||||
KeyCtrlSpace Key = 0x00
|
||||
KeyCtrlA Key = 0x01
|
||||
KeyCtrlB Key = 0x02
|
||||
KeyCtrlC Key = 0x03
|
||||
KeyCtrlD Key = 0x04
|
||||
KeyCtrlE Key = 0x05
|
||||
KeyCtrlF Key = 0x06
|
||||
KeyCtrlG Key = 0x07
|
||||
KeyBackspace Key = 0x08
|
||||
KeyCtrlH Key = 0x08
|
||||
KeyTab Key = 0x09
|
||||
KeyCtrlI Key = 0x09
|
||||
KeyCtrlJ Key = 0x0A
|
||||
KeyCtrlK Key = 0x0B
|
||||
KeyCtrlL Key = 0x0C
|
||||
KeyEnter Key = 0x0D
|
||||
KeyCtrlM Key = 0x0D
|
||||
KeyCtrlN Key = 0x0E
|
||||
KeyCtrlO Key = 0x0F
|
||||
KeyCtrlP Key = 0x10
|
||||
KeyCtrlQ Key = 0x11
|
||||
KeyCtrlR Key = 0x12
|
||||
KeyCtrlS Key = 0x13
|
||||
KeyCtrlT Key = 0x14
|
||||
KeyCtrlU Key = 0x15
|
||||
KeyCtrlV Key = 0x16
|
||||
KeyCtrlW Key = 0x17
|
||||
KeyCtrlX Key = 0x18
|
||||
KeyCtrlY Key = 0x19
|
||||
KeyCtrlZ Key = 0x1A
|
||||
KeyEsc Key = 0x1B
|
||||
KeyCtrlLsqBracket Key = 0x1B
|
||||
KeyCtrl3 Key = 0x1B
|
||||
KeyCtrl4 Key = 0x1C
|
||||
KeyCtrlBackslash Key = 0x1C
|
||||
KeyCtrl5 Key = 0x1D
|
||||
KeyCtrlRsqBracket Key = 0x1D
|
||||
KeyCtrl6 Key = 0x1E
|
||||
KeyCtrl7 Key = 0x1F
|
||||
KeyCtrlSlash Key = 0x1F
|
||||
KeyCtrlUnderscore Key = 0x1F
|
||||
KeySpace Key = 0x20
|
||||
KeyBackspace2 Key = 0x7F
|
||||
KeyCtrl8 Key = 0x7F
|
||||
)
|
||||
|
||||
//##altkeys##
|
||||
|
||||
const(
|
||||
KeyAltF1 Key = KeyF1 + (1<<16)
|
||||
KeyAltF2 Key = KeyF2 + (1<<16)
|
||||
KeyAltF3 Key = KeyF3 + (1<<16)
|
||||
KeyAltF4 Key = KeyF4 + (1<<16)
|
||||
KeyAltF5 Key = KeyF5 + (1<<16)
|
||||
KeyAltF6 Key = KeyF6 + (1<<16)
|
||||
KeyAltF7 Key = KeyF7 + (1<<16)
|
||||
KeyAltF8 Key = KeyF8 + (1<<16)
|
||||
KeyAltF9 Key = KeyF9 + (1<<16)
|
||||
KeyAltF10 Key = KeyF10 + (1<<16)
|
||||
KeyAltF11 Key = KeyF11 + (1<<16)
|
||||
KeyAltF12 Key = KeyF12 + (1<<16)
|
||||
KeyAltInsert Key = KeyInsert + (1<<16)
|
||||
KeyAltDelete Key = KeyDelete + (1<<16)
|
||||
KeyAltHome Key = KeyHome + (1<<16)
|
||||
KeyAltEnd Key = KeyEnd + (1<<16)
|
||||
KeyAltPgup Key = KeyPgup + (1<<16)
|
||||
KeyAltPgdn Key = KeyPgdn + (1<<16)
|
||||
KeyAltArrowUp Key = KeyArrowUp + (1<<16)
|
||||
KeyAltArrowDown Key = KeyArrowDown + (1<<16)
|
||||
KeyAltArrowLeft Key = KeyArrowLeft + (1<<16)
|
||||
KeyAltArrowRight Key = KeyArrowRight + (1<<16)
|
||||
KeyAltCtrlTilde Key = KeyCtrlTilde + (1<<16)
|
||||
KeyAltCtrl2 Key = KeyCtrl2 + (1<<16)
|
||||
KeyAltCtrlSpace Key = KeyCtrlSpace + (1<<16)
|
||||
KeyAltCtrlA Key = KeyCtrlA + (1<<16)
|
||||
KeyAltCtrlB Key = KeyCtrlB + (1<<16)
|
||||
KeyAltCtrlC Key = KeyCtrlC + (1<<16)
|
||||
KeyAltCtrlD Key = KeyCtrlD + (1<<16)
|
||||
KeyAltCtrlE Key = KeyCtrlE + (1<<16)
|
||||
KeyAltCtrlF Key = KeyCtrlF + (1<<16)
|
||||
KeyAltCtrlG Key = KeyCtrlG + (1<<16)
|
||||
KeyAltBackspace Key = KeyBackspace + (1<<16)
|
||||
KeyAltCtrlH Key = KeyCtrlH + (1<<16)
|
||||
KeyAltTab Key = KeyTab + (1<<16)
|
||||
KeyAltCtrlI Key = KeyCtrlI + (1<<16)
|
||||
KeyAltCtrlJ Key = KeyCtrlJ + (1<<16)
|
||||
KeyAltCtrlK Key = KeyCtrlK + (1<<16)
|
||||
KeyAltCtrlL Key = KeyCtrlL + (1<<16)
|
||||
KeyAltEnter Key = KeyEnter + (1<<16)
|
||||
KeyAltCtrlM Key = KeyCtrlM + (1<<16)
|
||||
KeyAltCtrlN Key = KeyCtrlN + (1<<16)
|
||||
KeyAltCtrlO Key = KeyCtrlO + (1<<16)
|
||||
KeyAltCtrlP Key = KeyCtrlP + (1<<16)
|
||||
KeyAltCtrlQ Key = KeyCtrlQ + (1<<16)
|
||||
KeyAltCtrlR Key = KeyCtrlR + (1<<16)
|
||||
KeyAltCtrlS Key = KeyCtrlS + (1<<16)
|
||||
KeyAltCtrlT Key = KeyCtrlT + (1<<16)
|
||||
KeyAltCtrlU Key = KeyCtrlU + (1<<16)
|
||||
KeyAltCtrlV Key = KeyCtrlV + (1<<16)
|
||||
KeyAltCtrlW Key = KeyCtrlW + (1<<16)
|
||||
KeyAltCtrlX Key = KeyCtrlX + (1<<16)
|
||||
KeyAltCtrlY Key = KeyCtrlY + (1<<16)
|
||||
KeyAltCtrlZ Key = KeyCtrlZ + (1<<16)
|
||||
KeyAltEsc Key = KeyEsc + (1<<16)
|
||||
KeyAltCtrlLsqBracket Key = KeyCtrlLsqBracket + (1<<16)
|
||||
KeyAltCtrl3 Key = KeyCtrl3 + (1<<16)
|
||||
KeyAltCtrl4 Key = KeyCtrl4 + (1<<16)
|
||||
KeyAltCtrlBackslash Key = KeyCtrlBackslash + (1<<16)
|
||||
KeyAltCtrl5 Key = KeyCtrl5 + (1<<16)
|
||||
KeyAltCtrlRsqBracket Key = KeyCtrlRsqBracket + (1<<16)
|
||||
KeyAltCtrl6 Key = KeyCtrl6 + (1<<16)
|
||||
KeyAltCtrl7 Key = KeyCtrl7 + (1<<16)
|
||||
KeyAltCtrlSlash Key = KeyCtrlSlash + (1<<16)
|
||||
KeyAltCtrlUnderscore Key = KeyCtrlUnderscore + (1<<16)
|
||||
KeyAltSpace Key = KeySpace + (1<<16)
|
||||
KeyAltBackspace2 Key = KeyBackspace2 + (1<<16)
|
||||
KeyAltCtrl8 Key = KeyCtrl8 + (1<<16)
|
||||
KeyAltA Key = 0x61 + (1<<16)
|
||||
KeyAltB Key = 0x62 + (1<<16)
|
||||
KeyAltC Key = 0x63 + (1<<16)
|
||||
KeyAltD Key = 0x64 + (1<<16)
|
||||
KeyAltE Key = 0x65 + (1<<16)
|
||||
KeyAltF Key = 0x66 + (1<<16)
|
||||
KeyAltG Key = 0x67 + (1<<16)
|
||||
KeyAltH Key = 0x68 + (1<<16)
|
||||
KeyAltI Key = 0x69 + (1<<16)
|
||||
KeyAltJ Key = 0x6a + (1<<16)
|
||||
KeyAltK Key = 0x6b + (1<<16)
|
||||
KeyAltL Key = 0x6c + (1<<16)
|
||||
KeyAltM Key = 0x6d + (1<<16)
|
||||
KeyAltN Key = 0x6e + (1<<16)
|
||||
KeyAltO Key = 0x6f + (1<<16)
|
||||
KeyAltP Key = 0x70 + (1<<16)
|
||||
KeyAltQ Key = 0x71 + (1<<16)
|
||||
KeyAltR Key = 0x72 + (1<<16)
|
||||
KeyAltS Key = 0x73 + (1<<16)
|
||||
KeyAltT Key = 0x74 + (1<<16)
|
||||
KeyAltU Key = 0x75 + (1<<16)
|
||||
KeyAltV Key = 0x76 + (1<<16)
|
||||
KeyAltW Key = 0x77 + (1<<16)
|
||||
KeyAltX Key = 0x78 + (1<<16)
|
||||
KeyAltY Key = 0x79 + (1<<16)
|
||||
KeyAltZ Key = 0x7a + (1<<16)
|
||||
)
|
54
uiterm/label.go
Normal file
54
uiterm/label.go
Normal file
@ -0,0 +1,54 @@
|
||||
package uiterm
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/nsf/termbox-go"
|
||||
)
|
||||
|
||||
type Label struct {
|
||||
Text string
|
||||
Fg, Bg Attribute
|
||||
|
||||
ui *Ui
|
||||
x0, y0, x1, y1 int
|
||||
}
|
||||
|
||||
func (l *Label) uiInitialize(ui *Ui) {
|
||||
l.ui = ui
|
||||
}
|
||||
|
||||
func (l *Label) uiSetActive(active bool) {
|
||||
}
|
||||
|
||||
func (l *Label) uiSetBounds(x0, y0, x1, y1 int) {
|
||||
l.x0 = x0
|
||||
l.y0 = y0
|
||||
l.x1 = x1
|
||||
l.y1 = y1
|
||||
l.uiDraw()
|
||||
}
|
||||
|
||||
func (l *Label) uiDraw() {
|
||||
l.ui.beginDraw()
|
||||
defer l.ui.endDraw()
|
||||
|
||||
reader := strings.NewReader(l.Text)
|
||||
for y := l.y0; y < l.y1; y++ {
|
||||
for x := l.x0; x < l.x1; x++ {
|
||||
var chr rune
|
||||
if ch, _, err := reader.ReadRune(); err != nil {
|
||||
chr = ' '
|
||||
} else {
|
||||
chr = ch
|
||||
}
|
||||
termbox.SetCell(x, y, chr, termbox.Attribute(l.Fg), termbox.Attribute(l.Bg))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Label) uiKeyEvent(key Key) {
|
||||
}
|
||||
|
||||
func (l *Label) uiCharacterEvent(chr rune) {
|
||||
}
|
138
uiterm/textbox.go
Normal file
138
uiterm/textbox.go
Normal file
@ -0,0 +1,138 @@
|
||||
package uiterm
|
||||
|
||||
import (
|
||||
"strings"
|
||||
// "unicode/utf8"
|
||||
|
||||
"github.com/nsf/termbox-go"
|
||||
)
|
||||
|
||||
type Textbox struct {
|
||||
Text string
|
||||
Fg, Bg Attribute
|
||||
|
||||
Input func(ui *Ui, textbox *Textbox, text string)
|
||||
|
||||
ui *Ui
|
||||
active bool
|
||||
x0, y0, x1, y1 int
|
||||
pos int
|
||||
}
|
||||
|
||||
func (t *Textbox) uiInitialize(ui *Ui) {
|
||||
t.ui = ui
|
||||
t.pos = 0
|
||||
}
|
||||
|
||||
func (t *Textbox) uiSetActive(active bool) {
|
||||
t.active = active
|
||||
t.uiDraw()
|
||||
}
|
||||
|
||||
func (t *Textbox) uiSetBounds(x0, y0, x1, y1 int) {
|
||||
t.x0 = x0
|
||||
t.y0 = y0
|
||||
t.x1 = x1
|
||||
t.y1 = y1
|
||||
t.uiDraw()
|
||||
}
|
||||
|
||||
func (t *Textbox) uiDraw() {
|
||||
t.ui.beginDraw()
|
||||
defer t.ui.endDraw()
|
||||
|
||||
reader := strings.NewReader(t.Text)
|
||||
if t.pos < 0 {
|
||||
t.pos = 0
|
||||
}
|
||||
if t.pos > len(t.Text) {
|
||||
t.pos = len(t.Text)
|
||||
}
|
||||
for y := t.y0; y < t.y1; y++ {
|
||||
for x := t.x0; x < t.x1; x++ {
|
||||
var chr rune
|
||||
if ch, _, err := reader.ReadRune(); err != nil {
|
||||
chr = ' '
|
||||
} else {
|
||||
chr = ch
|
||||
}
|
||||
termbox.SetCell(x, y, chr, termbox.Attribute(t.Fg), termbox.Attribute(t.Bg))
|
||||
}
|
||||
}
|
||||
if t.active {
|
||||
var x = 0
|
||||
var y = 0
|
||||
var idx = -1
|
||||
var flag = false
|
||||
for y = t.y0; y < t.y1; y++ {
|
||||
for x = t.x0; x < t.x1; x++ {
|
||||
idx += 1
|
||||
if idx == t.pos {
|
||||
flag = true
|
||||
}
|
||||
if flag == true {
|
||||
break
|
||||
}
|
||||
}
|
||||
if flag == true {
|
||||
break
|
||||
}
|
||||
}
|
||||
termbox.SetCursor(x, y)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Textbox) uiKeyEvent(key Key) {
|
||||
redraw := false
|
||||
switch key {
|
||||
case KeyHome:
|
||||
t.pos = 0
|
||||
redraw = true
|
||||
case KeyEnd:
|
||||
t.pos = len(t.Text)
|
||||
redraw = true
|
||||
case KeyArrowLeft:
|
||||
t.pos -= 1
|
||||
redraw = true
|
||||
case KeyArrowRight:
|
||||
t.pos += 1
|
||||
redraw = true
|
||||
case KeyCtrlC:
|
||||
t.Text = ""
|
||||
t.pos = 0
|
||||
redraw = true
|
||||
case KeyEnter:
|
||||
if t.Input != nil {
|
||||
t.Input(t.ui, t, t.Text)
|
||||
}
|
||||
t.Text = ""
|
||||
t.pos = 0
|
||||
redraw = true
|
||||
case KeySpace:
|
||||
t.uiCharacterEvent(' ')
|
||||
case KeyBackspace:
|
||||
case KeyBackspace2:
|
||||
if len(t.Text) > 0 {
|
||||
if t.pos > 0 {
|
||||
t.Text = t.Text[:t.pos-1] + t.Text[t.pos:]
|
||||
t.pos -= 1
|
||||
}
|
||||
}
|
||||
// if r, size := utf8.DecodeLastRuneInString(t.Text); r != utf8.RuneError {
|
||||
// t.Text = t.Text[:len(t.Text)-size]
|
||||
//t.pos-=size
|
||||
redraw = true
|
||||
// }
|
||||
// }
|
||||
}
|
||||
if redraw {
|
||||
t.uiDraw()
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Textbox) uiCharacterEvent(chr rune) {
|
||||
var s = string(chr)
|
||||
t.Text = t.Text[:t.pos] + s + t.Text[t.pos:]
|
||||
t.pos += len(s)
|
||||
t.uiDraw()
|
||||
}
|
160
uiterm/textview.go
Normal file
160
uiterm/textview.go
Normal file
@ -0,0 +1,160 @@
|
||||
package uiterm
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/nsf/termbox-go"
|
||||
)
|
||||
|
||||
type Textview struct {
|
||||
Lines []string
|
||||
CurrentLine int
|
||||
Fg, Bg Attribute
|
||||
showTimestamps bool
|
||||
parsedLines []string
|
||||
|
||||
ui *Ui
|
||||
x0, y0, x1, y1 int
|
||||
}
|
||||
|
||||
func (t *Textview) uiInitialize(ui *Ui) {
|
||||
t.ui = ui
|
||||
t.showTimestamps = true
|
||||
}
|
||||
|
||||
func (t *Textview) ToggleTimestamps() {
|
||||
if t.showTimestamps == true {
|
||||
t.showTimestamps = false
|
||||
} else {
|
||||
t.showTimestamps = true
|
||||
}
|
||||
t.updateParsedLines()
|
||||
t.uiDraw()
|
||||
}
|
||||
|
||||
func (t *Textview) uiSetActive(active bool) {
|
||||
}
|
||||
|
||||
func (t *Textview) uiSetBounds(x0, y0, x1, y1 int) {
|
||||
t.x0 = x0
|
||||
t.y0 = y0
|
||||
t.x1 = x1
|
||||
t.y1 = y1
|
||||
t.updateParsedLines()
|
||||
t.uiDraw()
|
||||
}
|
||||
|
||||
func (t *Textview) ScrollUp() {
|
||||
if newLine := t.CurrentLine + 1; newLine < len(t.parsedLines) {
|
||||
t.CurrentLine = newLine
|
||||
}
|
||||
t.uiDraw()
|
||||
}
|
||||
|
||||
func (t *Textview) ScrollDown() {
|
||||
if newLine := t.CurrentLine - 1; newLine >= 0 {
|
||||
t.CurrentLine = newLine
|
||||
}
|
||||
t.uiDraw()
|
||||
}
|
||||
|
||||
func (t *Textview) ScrollTop() {
|
||||
if newLine := len(t.parsedLines) - 1; newLine > 0 {
|
||||
t.CurrentLine = newLine
|
||||
} else {
|
||||
t.CurrentLine = 0
|
||||
}
|
||||
t.uiDraw()
|
||||
}
|
||||
|
||||
func (t *Textview) ScrollBottom() {
|
||||
t.CurrentLine = 0
|
||||
t.uiDraw()
|
||||
}
|
||||
|
||||
func (t *Textview) updateParsedLines() {
|
||||
width := t.x1 - t.x0
|
||||
|
||||
if t.Lines == nil || width <= 0 {
|
||||
t.parsedLines = nil
|
||||
return
|
||||
}
|
||||
|
||||
parsed := make([]string, 0, len(t.Lines))
|
||||
for _, line := range t.Lines {
|
||||
var l = line
|
||||
if t.showTimestamps == false {
|
||||
l = strings.TrimSpace(strings.Split(line, "]")[1])
|
||||
}
|
||||
current := ""
|
||||
chars := 0
|
||||
reader := strings.NewReader(l)
|
||||
for {
|
||||
if chars >= width {
|
||||
parsed = append(parsed, current)
|
||||
chars = 0
|
||||
current = ""
|
||||
}
|
||||
if reader.Len() <= 0 {
|
||||
if chars > 0 {
|
||||
parsed = append(parsed, current)
|
||||
}
|
||||
break
|
||||
}
|
||||
if ch, _, err := reader.ReadRune(); err == nil {
|
||||
current = current + string(ch)
|
||||
chars++
|
||||
}
|
||||
}
|
||||
}
|
||||
t.parsedLines = parsed
|
||||
}
|
||||
|
||||
func (t *Textview) AddLine(line string) {
|
||||
t.Lines = append(t.Lines, line)
|
||||
t.updateParsedLines()
|
||||
t.uiDraw()
|
||||
}
|
||||
|
||||
func (t *Textview) Clear() {
|
||||
t.Lines = nil
|
||||
t.CurrentLine = 0
|
||||
t.parsedLines = nil
|
||||
t.uiDraw()
|
||||
}
|
||||
|
||||
func (t *Textview) uiDraw() {
|
||||
t.ui.beginDraw()
|
||||
defer t.ui.endDraw()
|
||||
|
||||
var reader *strings.Reader
|
||||
writeableLines := t.y1 - t.y0
|
||||
lineNum := 0
|
||||
if writeableLines < len(t.parsedLines) {
|
||||
lineNum = len(t.parsedLines) - writeableLines
|
||||
}
|
||||
//Beep()
|
||||
for y := t.y0; y < writeableLines; y++ {
|
||||
if lineNum < len(t.parsedLines) {
|
||||
reader = strings.NewReader(t.parsedLines[lineNum])
|
||||
} else {
|
||||
reader = nil
|
||||
}
|
||||
for x := t.x0; x < t.x1; x++ {
|
||||
var chr rune = ' '
|
||||
if reader != nil {
|
||||
if ch, _, err := reader.ReadRune(); err == nil {
|
||||
chr = ch
|
||||
} //no err
|
||||
} //reader != nil
|
||||
termbox.SetCell(x, y, chr, termbox.Attribute(t.Fg), termbox.Attribute(t.Bg))
|
||||
} //each x
|
||||
lineNum++
|
||||
} //each y
|
||||
} //func
|
||||
|
||||
func (t *Textview) uiKeyEvent(key Key) {
|
||||
}
|
||||
|
||||
func (t *Textview) uiCharacterEvent(chr rune) {
|
||||
}
|
185
uiterm/tree.go
Normal file
185
uiterm/tree.go
Normal file
@ -0,0 +1,185 @@
|
||||
package uiterm
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/nsf/termbox-go"
|
||||
)
|
||||
|
||||
type TreeItem interface {
|
||||
TreeItemStyle(fg, bg Attribute, active bool) (Attribute, Attribute)
|
||||
String() string
|
||||
}
|
||||
|
||||
type renderedTreeItem struct {
|
||||
//String string
|
||||
Level int
|
||||
Item TreeItem
|
||||
}
|
||||
|
||||
type Tree struct {
|
||||
Fg, Bg Attribute
|
||||
Generator func(item TreeItem) []TreeItem
|
||||
KeyListener func(ui *Ui, tree *Tree, item TreeItem, key Key)
|
||||
CharacterListener func(ui *Ui, tree *Tree, item TreeItem, chr rune)
|
||||
|
||||
lines []renderedTreeItem
|
||||
activeLine int
|
||||
|
||||
ui *Ui
|
||||
active bool
|
||||
x0, y0, x1, y1 int
|
||||
}
|
||||
|
||||
func bounded(i, lower, upper int) int {
|
||||
if i < lower {
|
||||
return lower
|
||||
}
|
||||
if i > upper {
|
||||
return upper
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func (t *Tree) uiInitialize(ui *Ui) {
|
||||
t.ui = ui
|
||||
}
|
||||
|
||||
func (t *Tree) uiSetActive(active bool) {
|
||||
t.active = active
|
||||
t.uiDraw()
|
||||
}
|
||||
|
||||
func (t *Tree) uiSetBounds(x0, y0, x1, y1 int) {
|
||||
t.x0 = x0
|
||||
t.y0 = y0
|
||||
t.x1 = x1
|
||||
t.y1 = y1
|
||||
t.uiDraw()
|
||||
}
|
||||
|
||||
func (t *Tree) Rebuild() {
|
||||
if t.Generator == nil {
|
||||
t.lines = []renderedTreeItem{}
|
||||
return
|
||||
}
|
||||
|
||||
lines := []renderedTreeItem{}
|
||||
for _, item := range t.Generator(nil) {
|
||||
children := t.rebuild_rec(item, 0)
|
||||
if children != nil {
|
||||
lines = append(lines, children...)
|
||||
}
|
||||
}
|
||||
t.lines = lines
|
||||
t.SetActiveLine(0, true)
|
||||
t.uiDraw()
|
||||
}
|
||||
|
||||
func (t *Tree) rebuild_rec(parent TreeItem, level int) []renderedTreeItem {
|
||||
if parent == nil {
|
||||
return nil
|
||||
}
|
||||
lines := []renderedTreeItem{
|
||||
renderedTreeItem{
|
||||
Level: level,
|
||||
Item: parent,
|
||||
},
|
||||
}
|
||||
for _, item := range t.Generator(parent) {
|
||||
children := t.rebuild_rec(item, level+1)
|
||||
if children != nil {
|
||||
lines = append(lines, children...)
|
||||
}
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
func (t *Tree) uiDraw() {
|
||||
t.ui.beginDraw()
|
||||
defer t.ui.endDraw()
|
||||
|
||||
if t.lines == nil {
|
||||
t.Rebuild()
|
||||
}
|
||||
|
||||
if t.y1-t.y0 <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
var line = t.activeLine
|
||||
var height = t.y1 - t.y0
|
||||
var startline = 0
|
||||
//var total = len(t.lines)
|
||||
//I'd welcome a better algorithm for this; for that matter, I'd love a book or reference for all sorts of GUI algorithms.
|
||||
//if (startline+height) < line {
|
||||
for startline = 0; (startline + height) <= line; startline += height {
|
||||
}
|
||||
//}
|
||||
//if startline+height >= total {
|
||||
//var rem=(startline+height)-total
|
||||
//startline-=rem
|
||||
//}
|
||||
if startline < 0 {
|
||||
startline = 0
|
||||
}
|
||||
line = startline
|
||||
for y := t.y0; y < t.y1; y++ {
|
||||
var reader *strings.Reader
|
||||
var item TreeItem
|
||||
level := 0
|
||||
if line < len(t.lines) {
|
||||
item = t.lines[line].Item
|
||||
level = t.lines[line].Level
|
||||
reader = strings.NewReader(item.String())
|
||||
}
|
||||
for x := t.x0; x < t.x1; x++ {
|
||||
var chr rune = ' '
|
||||
fg := t.Fg
|
||||
bg := t.Bg
|
||||
dx := x - t.x0
|
||||
dy := y - t.y0
|
||||
if reader != nil && level*2 <= dx {
|
||||
if ch, _, err := reader.ReadRune(); err == nil {
|
||||
chr = ch
|
||||
fg, bg = item.TreeItemStyle(fg, bg, t.active && t.activeLine == dy)
|
||||
}
|
||||
}
|
||||
termbox.SetCell(x, y, chr, termbox.Attribute(fg), termbox.Attribute(bg))
|
||||
}
|
||||
if t.activeLine == (line) {
|
||||
termbox.SetCursor(t.x0, y)
|
||||
}
|
||||
line++
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tree) SetActiveLine(num int, relative bool) {
|
||||
if relative {
|
||||
t.activeLine = bounded(t.activeLine+num, 0, len(t.lines)-1)
|
||||
} else {
|
||||
t.activeLine = bounded(num, 0, len(t.lines)-1)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tree) uiKeyEvent(key Key) {
|
||||
var runHandler = true
|
||||
switch key {
|
||||
case KeyArrowUp:
|
||||
t.SetActiveLine(-1, true)
|
||||
runHandler = false
|
||||
case KeyArrowDown:
|
||||
t.SetActiveLine(1, true)
|
||||
runHandler = false
|
||||
}
|
||||
if runHandler == true && t.KeyListener != nil {
|
||||
t.KeyListener(t.ui, t, t.lines[t.activeLine].Item, key)
|
||||
}
|
||||
t.uiDraw()
|
||||
}
|
||||
|
||||
func (t *Tree) uiCharacterEvent(ch rune) {
|
||||
if t.CharacterListener != nil {
|
||||
t.CharacterListener(t.ui, t, t.lines[t.activeLine].Item, ch)
|
||||
}
|
||||
}
|
218
uiterm/ui.go
Normal file
218
uiterm/ui.go
Normal file
@ -0,0 +1,218 @@
|
||||
package uiterm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/nsf/termbox-go"
|
||||
)
|
||||
|
||||
type KeyListener func(ui *Ui, key Key)
|
||||
type CommandListener func(ui *Ui, cmd string)
|
||||
|
||||
type UiManager interface {
|
||||
OnUiInitialize(ui *Ui)
|
||||
OnUiDoneInitialize(ui *Ui)
|
||||
OnUiResize(ui *Ui, width, height int)
|
||||
}
|
||||
|
||||
type Ui struct {
|
||||
Fg, Bg Attribute
|
||||
|
||||
close chan bool
|
||||
manager UiManager
|
||||
|
||||
drawCount int32
|
||||
elements map[string]*uiElement
|
||||
activeElement *uiElement
|
||||
|
||||
keyListeners map[Key][]KeyListener
|
||||
commandListeners map[string][]CommandListener
|
||||
}
|
||||
|
||||
type uiElement struct {
|
||||
Name string
|
||||
X0, Y0, X1, Y1 int
|
||||
View View
|
||||
}
|
||||
|
||||
func New(manager UiManager) *Ui {
|
||||
ui := &Ui{
|
||||
close: make(chan bool, 10),
|
||||
elements: make(map[string]*uiElement),
|
||||
manager: manager,
|
||||
keyListeners: make(map[Key][]KeyListener),
|
||||
commandListeners: make(map[string][]CommandListener),
|
||||
}
|
||||
return ui
|
||||
}
|
||||
|
||||
func (ui *Ui) Close() {
|
||||
if termbox.IsInit {
|
||||
ui.close <- true
|
||||
}
|
||||
}
|
||||
|
||||
func (ui *Ui) Refresh() {
|
||||
if termbox.IsInit {
|
||||
ui.beginDraw()
|
||||
defer ui.endDraw()
|
||||
|
||||
termbox.Clear(termbox.Attribute(ui.Fg), termbox.Attribute(ui.Bg))
|
||||
termbox.HideCursor()
|
||||
for _, element := range ui.elements {
|
||||
element.View.uiDraw()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (ui *Ui) beginDraw() {
|
||||
atomic.AddInt32(&ui.drawCount, 1)
|
||||
}
|
||||
|
||||
func (ui *Ui) endDraw() {
|
||||
if count := atomic.AddInt32(&ui.drawCount, -1); count == 0 {
|
||||
termbox.Flush()
|
||||
}
|
||||
}
|
||||
|
||||
func (ui *Ui) Active() string {
|
||||
return ui.activeElement.Name
|
||||
}
|
||||
|
||||
func (ui *Ui) SetActive(name string) {
|
||||
element, _ := ui.elements[name]
|
||||
if ui.activeElement != nil {
|
||||
ui.activeElement.View.uiSetActive(false)
|
||||
}
|
||||
ui.activeElement = element
|
||||
if element != nil {
|
||||
element.View.uiSetActive(true)
|
||||
}
|
||||
}
|
||||
|
||||
func (ui *Ui) Run(cmds chan string) error {
|
||||
if termbox.IsInit {
|
||||
return nil
|
||||
}
|
||||
if err := termbox.Init(); err != nil {
|
||||
return nil
|
||||
}
|
||||
defer termbox.Close()
|
||||
termbox.SetInputMode(termbox.InputAlt)
|
||||
|
||||
events := make(chan termbox.Event)
|
||||
go func() {
|
||||
for {
|
||||
events <- termbox.PollEvent()
|
||||
}
|
||||
}()
|
||||
|
||||
ui.manager.OnUiInitialize(ui)
|
||||
ui.manager.OnUiDoneInitialize(ui)
|
||||
width, height := termbox.Size()
|
||||
ui.manager.OnUiResize(ui, width, height)
|
||||
ui.Refresh()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ui.close:
|
||||
return nil
|
||||
case cmd := <-cmds:
|
||||
ui.onCommandEvent(cmd)
|
||||
case event := <-events:
|
||||
switch event.Type {
|
||||
case termbox.EventResize:
|
||||
ui.manager.OnUiResize(ui, event.Width, event.Height)
|
||||
ui.Refresh()
|
||||
case termbox.EventKey:
|
||||
var k = uint32(event.Key)
|
||||
if event.Ch != 0 && event.Mod != 0 {
|
||||
k = uint32(event.Ch)
|
||||
}
|
||||
if event.Ch != 0 && event.Mod == 0 {
|
||||
ui.onCharacterEvent(event.Ch)
|
||||
} else {
|
||||
if event.Mod > 0 {
|
||||
k = k + (uint32(event.Mod) << 16)
|
||||
}
|
||||
ui.onKeyEvent(Key(k))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (ui *Ui) onCharacterEvent(ch rune) {
|
||||
if ui.activeElement != nil {
|
||||
ui.activeElement.View.uiCharacterEvent(ch)
|
||||
}
|
||||
}
|
||||
|
||||
func (ui *Ui) onKeyEvent(key Key) {
|
||||
if ui.keyListeners[key] != nil {
|
||||
for _, listener := range ui.keyListeners[key] {
|
||||
listener(ui, key)
|
||||
}
|
||||
}
|
||||
if ui.activeElement != nil {
|
||||
ui.activeElement.View.uiKeyEvent(key)
|
||||
}
|
||||
}
|
||||
|
||||
func (ui *Ui) onCommandEvent(cmd string) {
|
||||
ta := strings.SplitN(cmd, " ", 2)
|
||||
t := ta[0]
|
||||
rest := ""
|
||||
if len(ta) == 2 {
|
||||
rest = ta[1]
|
||||
}
|
||||
if ui.commandListeners[t] != nil {
|
||||
for _, listener := range ui.commandListeners[t] {
|
||||
listener(ui, rest)
|
||||
}
|
||||
}
|
||||
if ui.commandListeners["*"] != nil {
|
||||
for _, listener := range ui.commandListeners["*"] {
|
||||
listener(ui, cmd)
|
||||
}
|
||||
}
|
||||
// if ui.activeElement != nil {
|
||||
// ui.activeElement.View.uiKeyEvent(key)
|
||||
// }
|
||||
}
|
||||
|
||||
func (ui *Ui) Add(name string, view View) error {
|
||||
if _, ok := ui.elements[name]; ok {
|
||||
return errors.New("view already exists")
|
||||
}
|
||||
ui.elements[name] = &uiElement{
|
||||
Name: name,
|
||||
View: view,
|
||||
}
|
||||
view.uiInitialize(ui)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ui *Ui) SetBounds(name string, x0, y0, x1, y1 int) error {
|
||||
element, ok := ui.elements[name]
|
||||
if !ok {
|
||||
return errors.New("view does not exist")
|
||||
}
|
||||
element.X0, element.Y0, element.X1, element.Y1 = x0, y0, x1, y1
|
||||
element.View.uiSetBounds(x0, y0, x1, y1)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ui *Ui) AddKeyListener(listener KeyListener, key *Key) {
|
||||
if key != nil {
|
||||
ui.keyListeners[*key] = append(ui.keyListeners[*key], listener)
|
||||
}
|
||||
}
|
||||
|
||||
func (ui *Ui) AddCommandListener(listener CommandListener, cmd string) {
|
||||
//if cmd!=nil {
|
||||
ui.commandListeners[cmd] = append(ui.commandListeners[cmd], listener)
|
||||
//}
|
||||
}
|
11
uiterm/view.go
Normal file
11
uiterm/view.go
Normal file
@ -0,0 +1,11 @@
|
||||
package uiterm
|
||||
|
||||
type View interface {
|
||||
uiInitialize(ui *Ui)
|
||||
uiSetActive(active bool)
|
||||
uiSetBounds(x0, y0, x1, y1 int)
|
||||
uiDraw()
|
||||
uiKeyEvent(key Key)
|
||||
uiCharacterEvent(ch rune)
|
||||
// commandEvent(cmd string)
|
||||
}
|
Reference in New Issue
Block a user