#include #include #include /******************************************************************** * Parameters */ int value = 0; persist(value); int viewsize = 50; persist(viewsize); int maxvalue = 99; persist(maxvalue); boolean vertical = true; persist(vertical); nametype hilite = null; int previousvalue = -1; persist(scrollthreshold); persist(scrolllinedelay); persist(scrollpagedelay); persist(scrollautorepeat); #define LEN (vertical ? h : w) #define NONE 0 #define MINIMUM 1 #define ABBREVIATED 2 #define NORMAL 3 /******************************************************************** * Dimensions */ boolean fixedwidth() { return vertical; } boolean fixedheight() { return !vertical; } float preferredwidth() { return vertical ? OLScrollW : w; } float preferredheight() { return vertical ? h : OLScrollW; } /******************************************************************** * horizontal/vertical and state */ int state() { float l = LEN; if (l < OLElevH) return NONE; if (l < (OLElevH + (OLAnchorH * 2))) return MINIMUM; if (l < (OLElevatorH + (OLAnchorH * 2))) return ABBREVIATED; else return NORMAL; } int elevator_pos(int val) { int mv = maxvalue - viewsize; if (mv <= 0) return (val > 0) ? (OLAnchorH + OLCableGap) : (LEN - (OLAnchorH + OLCableGap + OLElevatorH)); if (val > mv) val = mv; else if (val < 0) val = 0; return OLAnchorH + OLCableGap + (((LEN - ((OLAnchorH + OLCableGap) * 2 + OLElevatorH)) * (mv - val)) / mv); } boolean active() { return maxvalue > 0; } /******************************************************************** * Painting */ #define MOVETO(pos) if (vertical) moveto(0,pos); else moveto(w - pos,0) void path() { if (vertical) rectpath(0,0,OLScrollW,h); else rectpath(0,0,w,OLScrollW); } void PaintAnchors() { MOVETO(0); OLAnchor(false,vertical); MOVETO(LEN - OLAnchorH); OLAnchor(false,vertical); } void PaintElevator() { int ep; switch (state()) { case NONE: break; case MINIMUM: MOVETO((LEN - OLElevH)/2); OLElevator(true,true,true,vertical); if (hilite != null) { MOVETO((LEN - OLElevH)/2); OLElevatorHilite(hilite,true,vertical); } break; case ABBREVIATED: MOVETO((LEN - OLElevH)/2); OLElevator(true,true,true,vertical); if (hilite != null) { MOVETO((LEN - OLElevH)/2); OLElevatorHilite(hilite,true,vertical); } break; case NORMAL: ep = elevator_pos(value); MOVETO(ep); OLElevator(true,true,false,vertical); if (hilite != null) { MOVETO(ep); OLElevatorHilite(hilite,false,vertical); } break; } } void UpdateElevator() { int p0 = OLAnchorH + OLCableGap; int p1 = LEN - p0 * 2; if (vertical) { rectpath(0,p0,OLScrollW,p1); rectpath(OLCableOff,p0,OLCableW,p1); } else { rectpath(p0,0,p1,OLScrollW); rectpath(p0,OLCableOff,p1,OLCableW); } setcolor(BG); eofill(); PaintElevator(); } void PaintCableParts(float e1, float e2) { float p0 = OLAnchorH + OLCableGap; float p3 = LEN - p0; float p2 = p3 - (((p3 - p0) * value) / max(1,maxvalue)); float p1 = max(p0,p2 - (((p3 - p0) * viewsize) / max(1,maxvalue))); if (p1 > (e1-3)) p1 = max(p0,e1-3); if (p2 < (e2+3)) p2 = min(p3,e2+3); /*DEBUGF("CABLE: % % % % % %",[p0,p1,e1,e2,p2,p3]);*/ if (vertical) { rectpath(OLCableOff,p0,OLCableW,p1 - p0); rectpath(OLCableOff,p2,OLCableW,p3 - p2); setcolor(BG2); fill(); rectpath(OLCableOff,p1,OLCableW,e1 - p1); rectpath(OLCableOff,e2,OLCableW,p2 - e2); setcolor(BG3); fill(); } else { rectpath(w - p0,OLCableOff,p0 - p1,OLCableW); rectpath(w - p2,OLCableOff,p2 - p3,OLCableW); setcolor(BG2); fill(); rectpath(w - p1,OLCableOff,p1 - e1,OLCableW); rectpath(w - e2,OLCableOff,e2 - p2,OLCableW); setcolor(BG3); fill(); } } void PaintCable() { int ep = elevator_pos(value); PaintCableParts(ep, ep + OLElevatorH); } void Paint() { /*path(); setrgbcolor(0.9,0.6,0.6); fill();*/ path(); setcolor(BG); fill(); switch (state()) { case NORMAL: PaintCable(); case ABBREVIATED: PaintAnchors(); case MINIMUM: PaintElevator(); case NONE: break; } } /******************************************************************** * interface */ menu @menu() { return vertical ? @scrollvmenu : @scrollhmenu; } void Preview(int val) { /*DEBUGF("VIEW(%)",[val]);*/ } void action() { Send Action(value); } void preview() { Send Preview(value); } /******************************************************************** * changing the status */ void sethilite(nametype h) { if (hilite != h) { softpromote(/hilite,h); gexec(/PaintElevator); } } void setvalue(float val) { int oldvalue; if (value != (val = max(0,min(maxvalue,cvi(round(val)))))) { oldvalue = value; value = val; if (state() == NORMAL) { gexec(/PaintCable); if (elevator_pos(oldvalue) != elevator_pos(value)) gexec(/UpdateElevator); } } } void setparameters(float val, float vwsiz, float maxval) { int oldvalue; maxval = max(-1,cvi(round(maxval))); val = max(0,min(maxval,cvi(round(val)))); vwsiz = max(0,vwsiz); if ((val != value) || (maxval != maxvalue) || (vwsiz != viewsize)) { oldvalue = value; value = val; maxvalue = maxval; viewsize = vwsiz; if (state() == NORMAL) { gexec(/PaintCable); if (elevator_pos(value) != elevator_pos(oldvalue)) gexec(/UpdateElevator); } } } void setvertical(boolean v) { if (vertical != v) { softpromote(/vertical,v); gexec(/Paint); } } void changevalue(float val) { int oldvalue = value; setvalue(val); if (oldvalue != value) preview(); } void HereToTop() { int val = value; float pos; if (vertical) pos = ((h - mouseevent.YLocation) * viewsize) / h; else pos = (mouseevent.XLocation * viewsize) / w; changevalue(value + pos + 1); if (val != value) { previousvalue = val; action(); } } void TopToHere() { int val = value; float pos; if (vertical) pos = ((h - mouseevent.YLocation) * viewsize) / h; else pos = (mouseevent.XLocation * viewsize) / w; changevalue(value - pos); if (val != value) { previousvalue = val; action(); } } void Previous() { int val = previousvalue; if ((val >= 0) && (val != value)) { previousvalue = value; changevalue(val); if (value != previousvalue) action(); } } /******************************************************************** * tracking */ void warpcursor(float pos) { if (state() == NORMAL) if (vertical) setcursorlocation(OLScrollW/2,pos); else setcursorlocation(w-pos,OLScrollW/2); } void track_ElevatorDrag() { float p, H; if (vertical) p = (h - tracky) - (OLAnchorH + OLCableGap + OLElevatorH/2); else p = trackx - (OLAnchorH + OLCableGap + OLElevatorH/2); if (H = (LEN - ((OLAnchorH + OLCableGap) * 2 + OLElevatorH))) p = (p * (maxvalue - (viewsize-1))) / H; else p = 0; changevalue(min(p,maxvalue-(viewsize-1))); } void track_ElevatorUp() { changevalue(value-1); warpcursor(elevator_pos(value) + (OLElevatorH*5)/6); } void track_ElevatorDown() { changevalue(value+1); warpcursor(elevator_pos(value) + OLElevatorH/6); } void track_PageUp() { float p; changevalue(value-(viewsize * 0.95)); if ((vertical ? tracky : w - trackx) < (p = elevator_pos(value) + OLElevatorH + 2)) warpcursor(p); } void track_PageDown() { float p; if (value < (maxvalue - (viewsize-1))) { changevalue(min(maxvalue - (viewsize-1),value+(viewsize * 0.95))); if ((vertical ? tracky : w - trackx) > (p = elevator_pos(value) + 2)) warpcursor(p); } } void track_Anchor() { } void track_repeat(name part, boolean line, name proc) { sethilite(part); if (scrollautorepeat) track_timed(scrollthreshold, line ? scrolllinedelay : scrollpagedelay,proc); else track_once(proc); sethilite(null); } nametype part_location(float cx, float cy) { float X = vertical ? cx : cy; float Y = vertical ? cy : LEN - cx; nametype W; if (active && (X >= 0) && (X <= OLScrollW)) { switch (state()) { case NONE: return null; case MINIMUM: MOVETO((LEN - OLElevH)/2); W = OLElevatorWhere(cx,cy,true,vertical); if (W == /PageUp) return /ElevatorUp; if (W == /PageDown) return /ElevatorDown; return W; case ABBREVIATED: if (Y <= OLAnchorH) return /BottomAnchor; if (Y >= (LEN - OLAnchorH)) return /TopAnchor; MOVETO((LEN - OLElevH)/2); return OLElevatorWhere(cx,cy,true,vertical); case NORMAL: if (Y <= OLAnchorH) return /BottomAnchor; if (Y >= (LEN - OLAnchorH)) return /TopAnchor; MOVETO(elevator_pos(value)); return OLElevatorWhere(cx,cy,false,vertical); } } return null; } void OnSelect() { previousvalue = value; switch(part_location(mouseevent.XLocation,mouseevent.YLocation)) { case /TopAnchor: MOVETO(LEN - OLAnchorH); OLAnchor(true,vertical); track(/track_Anchor); MOVETO(LEN - OLAnchorH); OLAnchor(false,vertical); changevalue(0); break; case /BottomAnchor: MOVETO(0); OLAnchor(true,vertical); track(/track_Anchor); MOVETO(0); OLAnchor(false,vertical); changevalue(maxvalue - (viewsize-1)); break; case /ElevatorUp: track_repeat(/ElevatorUp,true,/track_ElevatorUp); break; case /ElevatorDrag: sethilite(/ElevatorDrag); track(/track_ElevatorDrag); sethilite(null); break; case /ElevatorDown: track_repeat(/ElevatorDown,true,/track_ElevatorDown); break; case /PageUp: track_repeat(null,false,/track_PageUp); break; case /PageDown: track_repeat(null,false,/track_PageDown); break; } if (value != previousvalue) action(); }