#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();
}