|
|
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.