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