9fans.net/go@v0.0.7/cmd/samterm/menu.go (about) 1 package main 2 3 import ( 4 "image" 5 "unicode/utf8" 6 7 "9fans.net/go/draw" 8 ) 9 10 var name [][]uint8 /* first byte is ' ' or '\'': modified state */ 11 var text []*Text /* pointer to Text associated with file */ 12 var tag []int /* text[i].tag, even if text[i] not defined */ 13 var mw int 14 15 const ( 16 Cut = iota 17 Paste 18 Snarf 19 Plumb 20 Look 21 Exch 22 Search 23 Send 24 NMENU2C 25 NMENU2 = Search 26 ) 27 28 const ( 29 New = iota 30 Zerox 31 Resize 32 Close 33 Write 34 NMENU3 35 ) 36 37 var menu2str = []string{ 38 "cut", 39 "paste", 40 "snarf", 41 "plumb", 42 "look", 43 "<rio>", 44 "", /* storage for last pattern */ 45 } 46 47 var menu3str = []string{ 48 "new", 49 "zerox", 50 "resize", 51 "close", 52 "write", 53 } 54 55 var menu2 = draw.Menu{Gen: genmenu2} 56 var menu2c = draw.Menu{Gen: genmenu2c} 57 var menu3 = draw.Menu{Gen: genmenu3} 58 59 func menu2hit() { 60 t := which.text 61 w := t.find(which) 62 if hversion == 0 || plumbfd == nil { 63 menu2str[Plumb] = "(plumb)" 64 } 65 menu := &menu2 66 if t == &cmd { 67 menu = &menu2c 68 } 69 m := draw.MenuHit(2, mousectl, menu, nil) 70 if hostlock != 0 || t.lock != 0 { 71 return 72 } 73 74 switch m { 75 case Cut: 76 cut(t, w, true, true) 77 78 case Paste: 79 paste(t, w) 80 81 case Snarf: 82 snarf(t, w) 83 84 case Plumb: 85 if hversion > 0 { 86 outTsll(Tplumb, t.tag, which.p0, which.p1) 87 } 88 89 case Exch: 90 snarf(t, w) 91 outT0(Tstartsnarf) 92 setlock() 93 94 case Look: 95 outTsll(Tlook, t.tag, which.p0, which.p1) 96 setlock() 97 98 case Search: 99 outcmd() 100 if t == &cmd { 101 outTsll(Tsend, 0, which.p0, which.p1) /*ignored*/ 102 } else { 103 outT0(Tsearch) 104 } 105 setlock() 106 } 107 } 108 109 func menu3hit() { 110 mw = -1 111 m := draw.MenuHit(3, mousectl, &menu3, nil) 112 var r image.Rectangle 113 var l *Flayer 114 var i int 115 var t *Text 116 switch m { 117 case -1: 118 break 119 120 case New: 121 if hostlock == 0 { 122 sweeptext(true, 0) 123 } 124 125 case Zerox, 126 Resize: 127 if hostlock == 0 { 128 display.SwitchCursor(&bullseye) 129 buttons(Down) 130 if mousep.Buttons&4 != 0 && func() bool { l = flwhich(mousep.Point); return l != nil }() && getr(&r) { 131 duplicate(l, r, l.f.Font, m == Resize) 132 } else { 133 display.SwitchCursor(cursor) 134 } 135 buttons(Up) 136 } 137 138 case Close: 139 if hostlock == 0 { 140 display.SwitchCursor(&bullseye) 141 buttons(Down) 142 if mousep.Buttons&4 != 0 { 143 l = flwhich(mousep.Point) 144 if l != nil && hostlock == 0 { 145 t = l.text 146 if t.nwin > 1 { 147 closeup(l) 148 } else if t != &cmd { 149 outTs(Tclose, t.tag) 150 setlock() 151 } 152 } 153 } 154 display.SwitchCursor(cursor) 155 buttons(Up) 156 } 157 158 case Write: 159 if hostlock == 0 { 160 display.SwitchCursor(&bullseye) 161 buttons(Down) 162 if mousep.Buttons&4 != 0 && func() bool { l = flwhich(mousep.Point); return l != nil }() { 163 outTs(Twrite, l.text.tag) 164 setlock() 165 } else { 166 display.SwitchCursor(cursor) 167 } 168 buttons(Up) 169 } 170 171 default: 172 t = text[m-NMENU3] 173 if t != nil { 174 i = t.front 175 if t.nwin == 0 || t.l[i].textfn == nil { 176 return /* not ready yet; try again later */ 177 } 178 if t.nwin > 1 && which == &t.l[i] { 179 for { 180 i++ 181 if i == NL { 182 i = 0 183 } 184 if !(i != t.front) || !(t.l[i].textfn == nil) { 185 break 186 } 187 } 188 } 189 current(&t.l[i]) 190 } else if hostlock == 0 { 191 sweeptext(false, tag[m-NMENU3]) 192 } 193 } 194 } 195 196 func sweeptext(isNew bool, tag int) *Text { 197 var r image.Rectangle 198 if !getr(&r) { 199 return nil 200 } 201 202 t := new(Text) 203 current(nil) 204 flnew(&t.l[0], gettext, t) 205 flinit(&t.l[0], r, font, maincols[:]) /*bnl*/ 206 textID++ 207 t.id = textID 208 textByID[t.id] = t 209 t.nwin = 1 210 rinit(&t.rasp) 211 if isNew { 212 startnewfile(Tstartnewfile, t) 213 } else { 214 rinit(&t.rasp) 215 t.tag = tag 216 startfile(t) 217 } 218 return t 219 } 220 221 func whichmenu(tg int) int { 222 for i := range tag { 223 if tag[i] == tg { 224 return i 225 } 226 } 227 return -1 228 } 229 230 func menuins(n int, s []byte, t *Text, m byte, tg int) { 231 name = append(name, nil) 232 text = append(text, nil) 233 tag = append(tag, 0) 234 copy(name[n+1:], name[n:]) 235 copy(text[n+1:], text[n:]) 236 copy(tag[n+1:], tag[n:]) 237 text[n] = t 238 tag[n] = tg 239 name[n] = make([]byte, 1+len(s)) 240 name[n][0] = m 241 copy(name[n][1:], s) 242 menu3.LastHit = n + NMENU3 243 } 244 245 func menudel(n int) { 246 if n >= len(text) || text[n] != nil { 247 panic("menudel") 248 } 249 copy(name[n:], name[n+1:]) 250 copy(text[n:], text[n+1:]) 251 copy(tag[n:], tag[n+1:]) 252 name = name[:len(name)-1] 253 text = text[:len(text)-1] 254 tag = tag[:len(tag)-1] 255 } 256 257 func setpat(s []byte) { 258 if len(s) > 15 { 259 s = s[:15] 260 } 261 menu2str[Search] = "/" + string(s) 262 } 263 264 func paren(buf []byte, s string) []byte { 265 buf = append(buf, '(') 266 buf = append(buf, s...) 267 buf = append(buf, ')') 268 return buf 269 } 270 271 func genmenu2(n int, buf []byte) ([]byte, bool) { 272 t := which.text 273 if n >= NMENU2+1 || menu2str[Search] == "" && n >= NMENU2 { 274 return nil, false 275 } 276 p := menu2str[n] 277 if hostlock == 0 && t.lock == 0 || n == Search || n == Look { 278 return append(buf, p...), true 279 } 280 return paren(buf, p), true 281 } 282 283 func genmenu2c(n int, buf []byte) ([]byte, bool) { 284 t := which.text 285 if n >= NMENU2C { 286 return nil, false 287 } 288 var p string 289 if n == Send { 290 p = "send" 291 } else { 292 p = menu2str[n] 293 } 294 if hostlock == 0 && t.lock == 0 { 295 return append(buf, p...), true 296 } 297 return paren(buf, p), true 298 } 299 300 func genmenu3(n int, buf []byte) ([]byte, bool) { 301 if n >= NMENU3+len(name) { 302 return nil, false 303 } 304 if n < NMENU3 { 305 p := menu3str[n] 306 if hostlock != 0 { 307 return paren(buf, p), true 308 } 309 return append(buf, p...), true 310 } 311 n -= NMENU3 312 if n == 0 { /* unless we've been fooled, this is cmd */ 313 return append(buf, name[n][1:]...), true 314 } 315 if mw == -1 { 316 mw = 7 /* strlen("~~sam~~"); */ 317 for i := 1; i < len(name); i++ { 318 w := utf8.RuneCount(name[i][1:]) + 4 /* include "'+. " */ 319 if w > mw { 320 mw = w 321 } 322 } 323 } 324 const NBUF = 64 325 if mw > NBUF { 326 mw = NBUF 327 } 328 t := text[n] 329 buf = append(buf, name[n][0], '-', ' ', ' ') 330 if t != nil { 331 if t.nwin == 1 { 332 buf[1] = '+' 333 } else if t.nwin > 1 { 334 buf[1] = '*' 335 } 336 if work != nil && t == work.text { 337 buf[2] = '.' 338 if modified { 339 buf[0] = '\'' 340 } 341 } 342 } 343 l := utf8.RuneCount(name[n][1:]) 344 var k int 345 if l > NBUF-4-2 { 346 i := 4 347 k = 1 348 for i < NBUF/2 { 349 _, w := utf8.DecodeRune(name[n][k:]) 350 k += w 351 i++ 352 } 353 buf = append(buf, name[n][1:k]...) 354 buf = append(buf, "..."...) 355 for (l - i) >= NBUF/2-4 { 356 _, w := utf8.DecodeRune(name[n][k:]) 357 k += w 358 i++ 359 } 360 buf = append(buf, name[n][k:]...) 361 } else { 362 buf = append(buf, name[n][1:]...) 363 } 364 i := utf8.RuneCount(buf) 365 for i < mw { 366 buf = append(buf, ' ') 367 i++ 368 } 369 return buf, true 370 }