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