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  }