|
|
1.1 root 1: #include <jerq.h>
2: #include <font.h>
3: #include "menu.h"
4:
5: static Bitmap disp = { (Word *)0x700000, 25, 0, 0, XMAX, YMAX };
6:
7: #define scale(x, inmin, inmax, outmin, outmax)\
8: (outmin + muldiv(x-inmin,outmax-outmin,inmax-inmin))
9:
10: #define bound(x, low, high) min(high, max( low, x ))
11:
12: #define SPACING (defont.height+1)
13: #define DISPLAY 16
14: #define CHARWIDTH (defont.info[' '].width)
15: #define DELTA 6
16: #define BARWIDTH 18
17: #define MAXDEPTH 16 /* don't use too much stack */
18: #define ARROWIDTH 20
19:
20: static Texture tarrow =
21: {
22: 0x0000, 0x0000, 0x0080, 0x00C0, 0x00C0, 0x00E0, 0x00F8, 0xFFFE,
23: 0xFFFE, 0x00F8, 0x00E0, 0x00C0, 0x00C0, 0x0080, 0x0000, 0x0000,
24: };
25:
26: static NMitem *
27: tablegen(i, table)
28: NMitem *table;
29: {
30: return &table[i];
31: }
32:
33: static char fill[64];
34:
35: NMitem *
36: mhit(m, but, depth)
37: register NMenu *m;
38: {
39: register int width, mwidth, i, j, top, newtop, hit, newhit;
40: register int items, lines, length, w, x;
41: Point p, q, savep, baro, barc;
42: Rectangle sr, tr, mr; /* scroll, text, menu */
43: Rectangle rside, rhit;
44: register Bitmap *b;
45: register char *from, *to;
46: Bitmap *bhelp = 0, *arrow;
47: NMitem *(*generator)(), *mi, *table, *ret = 0;
48: int dohfn;
49:
50: #define sro sr.origin
51: #define src sr.corner
52: #define tro tr.origin
53: #define trc tr.corner
54: #define mro mr.origin
55: #define mrc mr.corner
56:
57: generator = (table=m->item) ? tablegen : m->generator;
58: arrow = balloc(Rect(0, 0, 16, 16));
59: texture(arrow, arrow->rect, &tarrow, F_STORE);
60: p = mouse.xy;
61: w = x = length = 0;
62: for(items = 0; (mi=(*generator)(items, table))->text; ++items) {
63: register int s = strlen (mi->text);
64: length = max(length, s);
65: if (mi->next) {
66: w = max (w, s);
67: } else
68: x = max (x, s);
69: }
70: if(items == 0)
71: return(ret);
72: width = length*CHARWIDTH+10;
73: w *= CHARWIDTH;
74: x *= CHARWIDTH;
75: if (x <= w)
76: mwidth = w + ARROWIDTH;
77: else if (x >= w + 2*ARROWIDTH)
78: mwidth = x;
79: else
80: mwidth = w + ARROWIDTH + (x - w) / 2;
81: mwidth += 10;
82: sro.x = sro.y = src.x = tro.x = mro.x = mro.y = 0;
83: if(items <= DISPLAY)
84: 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(mwidth, min(items, lines)*SPACING));
93: src.y = mrc.y-1;
94: newtop = bound(m->prevtop, 0, items-lines);
95: p.y -= bound(m->prevhit, 0, lines-1)*SPACING+SPACING/2;
96: p.x = bound(p.x-(src.x+mwidth/2), 0, XMAX-mrc.x);
97: p.y = bound(p.y, 0, YMAX-mrc.y);
98: sr = raddp(sr, p);
99: tr = raddp(tr, p);
100: mr = raddp(mr, p);
101: rside = mr;
102: rside.origin.x = rside.corner.x-20;
103: b = balloc(mr);
104: cursinhibit();
105: if(b)
106: bitblt(&disp, mr, b, mro, F_STORE);
107: rectf(&disp, mr, F_OR);
108: cursallow();
109: PaintMenu:
110: cursinhibit();
111: rectf(&disp, inset(mr, 1), F_CLR);
112: cursallow();
113: top = newtop;
114: if(items > DISPLAY){
115: baro.y = scale(top, 0, items, sro.y, src.y);
116: baro.x = sr.origin.x;
117: barc.y = scale(top+DISPLAY, 0, items, sro.y, src.y);
118: barc.x = sr.corner.x;
119: rectf(&disp, Rpt(baro,barc), F_XOR);
120: }
121: for(p=tro, i=top; i < min(top+lines, items); ++i){
122: q = p;
123: mi = generator(i, table);
124: from = mi->text;
125: for(to = &fill[0]; *from; ++from)
126: if(*from & 0x80)
127: for(j=length-(strlen(from+1)+(to-&fill[0])); j-->0;)
128: *to++ = *from & 0x7F;
129: else
130: *to++ = *from;
131: *to = '\0';
132: q.x += (width-jstrwidth(fill))/2;
133: string(&defont, fill, &disp, q, F_XOR);
134: if(mi->next)
135: bitblt(arrow, arrow->rect, &disp, Pt(trc.x-18, p.y-2), F_OR);
136: p.y += SPACING;
137: }
138: savep = mouse.xy;
139: mi = 0;
140: for(newhit = hit = -1; button(but); nap(2)){
141: p = mouse.xy;
142: if(depth && ((p.x < mro.x) || button(5-but)))
143: {
144: ret = 0;
145: break;
146: }
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: }else if(ptinrect(savep,sr)){
157: register dx, dy;
158: if(abs(dx = p.x-savep.x) < DELTA)
159: dx = 0;
160: if(abs(dy = p.y-savep.y) < DELTA)
161: dy = 0;
162: if(abs(dy) >= abs(dx))
163: dx = 0;
164: else
165: dy = 0;
166: cursset(p = add(savep, Pt(dx,dy)));
167: }
168: savep = p;
169: newhit = -1;
170: if(ptinrect(p, tr)){
171: newhit = bound((p.y-tro.y)/SPACING, 0, lines-1);
172: if(newhit!=hit && hit>=0
173: && abs(tro.y+SPACING*newhit+SPACING/2-p.y) > SPACING/3)
174: newhit = hit;
175: rhit = tr;
176: rhit.origin.y += newhit*SPACING-ASCEND/2;
177: rhit.corner.y = rhit.origin.y + SPACING;
178: }
179: if(newhit == -1)
180: ret = 0, dohfn = 0;
181: else
182: ret = mi = (*generator)(top+newhit, table), dohfn = 1;
183: if(newhit == hit)
184: {
185: if((newhit != -1) && (bhelp == 0) && button1() && mi->help)
186: helpon(mi->help, rhit, &bhelp);
187: else if(bhelp && !button1())
188: helpoff(&bhelp);
189: }
190: else
191: {
192: flip(tr, hit);
193: helpoff(&bhelp);
194: flip(tr, newhit);
195: hit = newhit;
196: if((newhit != -1) && button1() && mi->help)
197: helpon(mi->help, rhit, &bhelp);
198: }
199: if((newhit != -1) && ptinrect(p, rside))
200: {
201: if(mi->dfn) (*mi->dfn)(mi);
202: if(mi->next && (depth <= MAXDEPTH))
203: ret = mhit(mi->next, but, depth+1), dohfn = 0;
204: if(mi->bfn) (*mi->bfn)(mi);
205: }
206: if(newhit==0 && top>0){
207: newtop = top-1;
208: p.y += SPACING;
209: cursset(p);
210: /* ->->-> */ goto PaintMenu;
211: }
212: if(newhit==DISPLAY-1 && top<items-lines){
213: newtop = top+1;
214: p.y -= SPACING;
215: cursset(p);
216: /* ->->-> */ goto PaintMenu;
217: }
218: }
219: if(bhelp)
220: helpoff(&bhelp);
221: if(b){
222: cursinhibit();
223: screenswap(b, b->rect, b->rect);
224: cursallow();
225: bfree(b);
226: }
227: if(hit>=0){
228: m->prevhit = hit;
229: m->prevtop = top;
230: if(ret && ret->hfn && dohfn) (*ret->hfn)(mi);
231: }
232: return(ret);
233: }
234:
235: static
236: flip(r,n)
237: Rectangle r;
238: {
239: if(n<0)
240: return;
241: ++r.origin.x;
242: r.corner.y = (r.origin.y += SPACING*n-1) + SPACING;
243: --r.corner.x;
244: rectf(&disp, r, F_XOR);
245: }
246:
247: static
248: helpon(msg, r, bhelp)
249: char *msg;
250: Rectangle r;
251: Bitmap **bhelp;
252: {
253: register Bitmap *b;
254: register w;
255:
256: w = strwidth(&defont, msg)+10;
257: if(r.corner.x+w < XMAX)
258: {
259: r.origin.x = r.corner.x;
260: r.corner.x += w;
261: }
262: else
263: {
264: r.corner.x = r.origin.x;
265: r.origin.x -= w;
266: }
267: if(*bhelp = b = balloc(r = inset(r, -1)))
268: {
269: rectf(b, r, F_OR);
270: rectf(b, inset(r, 1), F_XOR);
271: string(&defont, msg, b, add(b->rect.origin, Pt(5, 1)), F_XOR);
272: screenswap(b, b->rect, b->rect);
273: }
274: }
275:
276: static
277: helpoff(bhelp)
278: Bitmap **bhelp;
279: {
280: Bitmap *bh;
281:
282: if(bh = *bhelp)
283: {
284: screenswap(bh, bh->rect, bh->rect);
285: bfree(bh);
286: *bhelp = 0;
287: }
288: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.