|
|
1.1 root 1: #include "univ.h"
2:
3: #define scale( x, inmin, inmax, outmin, outmax )\
4: ( outmin + muldiv(x-inmin,outmax-outmin,inmax-inmin) )
5:
6: #define bound( x, low, high ) ( min( high, max( low, x ) ) )
7:
8: #define SPACING fontheight(&defont)
9: #define DISPLAY 13
10: #define CHARWIDTH fontwidth(&defont)
11:
12: #define DELTA 6
13: #define BARWIDTH 18
14:
15: int MenuNest;
16:
17: Entry *EntryGen(i, s)
18: register Script *s;
19: {
20: register Entry *e;
21:
22: for( ; s; s = s->more ){
23: CIndex = s->cindex;
24: if( i < s->items )
25: return (s->generator)(i);
26: i -= s->items;
27: }
28: return 0;
29: }
30:
31: Limits(s)
32: register Script *s;
33: {
34: register i, l;
35: register Entry *e;
36:
37: s->items = s->width = 0;
38: for( i = 0; e = (s->generator)(i); ++i ){
39: ++s->items;
40: l = strlen(e->text);
41: if( l > s->width ) s->width = l;
42: }
43: }
44:
45: Entry *ScriptHit(sh, but, rl)
46: register Script *sh;
47: RectList *rl;
48: {
49: register int width, i, j, top, newtop, hit, newhit, items, lines, charswide;
50: Point p, q, savep, baro, barc;
51: Rectangle sr, tr, mr; /* scroll, text, menu */
52: register Bitmap *b;
53: register char *s, *from, *to, fill[64];
54: register Script *m;
55: register Entry *e;
56: RectList lrl, *l;
57:
58: #define sro sr.origin
59: #define src sr.corner
60: #define tro tr.origin
61: #define trc tr.corner
62: #define mro mr.origin
63: #define mrc mr.corner
64:
65: charswide = items = 0;
66: for( m = sh; m; m = m->more ){
67: CIndex = m->cindex;
68: m->items = m->width = 0;
69: if( m->limits )
70: m->limits(m);
71: else
72: Limits(m);
73: items += m->items;
74: if( m->width > charswide ){
75: charswide = m->width;
76: if( charswide >= sizeof(fill) )
77: charswide = sizeof(fill) - 1;
78: }
79: }
80: p = mouse.xy;
81: if( items == 0 ) return 0;
82: width = charswide*CHARWIDTH+10;
83: sro.x = sro.y = src.x = tro.x = mro.x = mro.y = 0;
84: if( items <= DISPLAY ) lines = items;
85: else {
86: lines = DISPLAY;
87: tro.x = src.x = BARWIDTH;
88: sro.x = sro.y = 1;
89: }
90: #define ASCEND 2
91: tro.y = ASCEND;
92: mrc = trc = add(tro, Pt(width,min(items,lines)*SPACING) );
93: src.y = mrc.y-1;
94: newtop = bound(sh->prevtop, 0, items-lines );
95: p.y -= bound(sh->prevhit, 0, lines-1)*SPACING+SPACING/2;
96: p.x = bound(p.x-(src.x+width/2), 0, display.rect.corner.x-mrc.x);
97: p.y = bound(p.y, 0, display.rect.corner.y-mrc.y);
98: sr = raddp(sr,p);
99: tr = raddp(tr, p);
100: mr = raddp(mr, p);
101: b = balloc(mr);
102: if( b ) bitblt(&display, mr, b, mro, F_STORE);
103: rectf( &display, mr, F_STORE );
104: PaintMenu:
105: rectf( &display, inset(mr,1), F_CLR );
106: top = newtop;
107: if( items > DISPLAY ){
108: baro.y = scale(top, 0, items, sro.y, src.y);
109: baro.x = sr.origin.x;
110: barc.y = scale(top+DISPLAY, 0, items, sro.y, src.y);
111: barc.x = sr.corner.x;
112: rectf(&display, Rpt(baro,barc), F_XOR);
113: }
114: for( p = tro, i = top; i < min(top+lines,items); ++i ){
115: q = p;
116: e = EntryGen(i, sh);
117: from = e->text;
118: for( to = &fill[0]; *from; ++from ){
119: if( *from & 0x80 )
120: for(j=charswide-(strlen(from+1)+(to-&fill[0])); j-->0;)
121: *to++ = *from & 0x7F;
122: else
123: *to++ = *from;
124: }
125: if( e->script ){
126: static Bitmap *bb;
127: Point qq;
128: qq.y = q.y+1;
129: qq.x = q.x+width-15;
130: if( !bb ){
131: bb = balloc(Rect(0,0,15,15));
132: assert(bb);
133: texture(bb, bb->rect, &Arrow, F_STORE);
134: }
135: bitblt(bb, bb->rect, &display, qq, F_XOR);
136: }
137: *to = '\0';
138: q.x += ( width-strwidth(&defont, fill) )/2;
139: string( &defont, fill, &display, q, F_XOR );
140: p.y += SPACING;
141: }
142: savep = mouse.xy;
143: newhit = hit = -1;
144: e = 0;
145: for( ; button(but); jnap(2) ){
146: p = mouse.xy;
147: if( ptinrect(p, sr) ){
148: if( ptinrect(savep,tr) ){
149: p.y = (baro.y+barc.y)/2;
150: cursset( p );
151: }
152: newtop = scale( p.y, sro.y, src.y, 0, items );
153: newtop = bound( newtop-DISPLAY/2, 0, items-DISPLAY );
154: if( newtop != top )
155: goto PaintMenu;
156: }
157: savep = p;
158: newhit = -1;
159: if( ptinrect(p, tr) ){
160: newhit = bound((p.y-tro.y)/SPACING, 0, lines-1);
161: if( hit >= 0
162: && abs(tro.y+SPACING*newhit+SPACING/2-p.y) > SPACING/3 )
163: newhit = hit;
164: }
165: if( newhit != hit ){
166: flip(tr, hit);
167: flip(tr, hit = newhit);
168: e = hit>=0 ? EntryGen(hit+top, sh) : 0;
169: }
170: if( !ptinrect(p, mr) ){
171: assert(!e);
172: for( l = rl; l; l = l->more )
173: if( ptinrect(p, *l->rp) )
174: goto Done;
175: }
176: if(newhit==0 && top>0){
177: newtop = top-1;
178: p.y += SPACING;
179: cursset(p);
180: goto PaintMenu;
181: }
182: if(newhit==DISPLAY-1 && top<items-lines){
183: newtop = top+1;
184: p.y -= SPACING;
185: cursset(p);
186: goto PaintMenu;
187: }
188: if( e && e->script
189: && p.x > trc.x-CHARWIDTH ){
190: p.x = trc.x;
191: cursset(p);
192: lrl.rp = &mr;
193: lrl.more = rl;
194: ++MenuNest;
195: e = ScriptHit(e->script, but, &lrl);
196: --MenuNest;
197: if( e ) goto Done;
198: goto PaintMenu;
199: }
200: }
201: Done:
202: if( b ){
203: bitblt(b, b->rect, &display, b->rect.origin, F_STORE);
204: bfree(b);
205: }
206: jerqsync();
207: sh->prevhit = hit;
208: sh->prevtop = top;
209: return e;
210: }
211:
212: static flip(r,n)
213: Rectangle r;
214: {
215: if( n<0 ) return;
216: ++r.origin.x;
217: r.corner.y = (r.origin.y += SPACING*n-1) + SPACING;
218: --r.corner.x;
219: rectf( &display, r, F_XOR );
220: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.