680 lines
15 KiB
C++
680 lines
15 KiB
C++
#include <precomp.h>
|
|
|
|
#include <bfc/wasabi_std.h>
|
|
|
|
#include "scrollbar.h"
|
|
#include <tataki/canvas/canvas.h>
|
|
#include <api/wnd/notifmsg.h>
|
|
#include <api/wnd/PaintCanvas.h>
|
|
|
|
#define TIMER_ID 9871
|
|
#define TIMER_ID2 9872
|
|
|
|
#define FIRST_DELAY 350
|
|
#define NEXT_DELAY 75
|
|
|
|
ScrollBar::ScrollBar() {
|
|
leftrgn = NULL;
|
|
rightrgn = NULL;
|
|
buttonrgn = NULL;
|
|
|
|
position = 0;
|
|
moving = 0;
|
|
lefting = 0;
|
|
righting = 0;
|
|
clicked = 0;
|
|
height = DEFAULT_HEIGHT;
|
|
buttonx = 0;
|
|
|
|
shiftleft = 0;
|
|
shiftright = 0;
|
|
|
|
curmouseposition = POS_NONE;
|
|
clickmouseposition = POS_NONE;
|
|
pageing = 0;
|
|
timer = timer2 = 0;
|
|
npages = 100;
|
|
pageway = PAGE_NONE;
|
|
updown = 256;
|
|
insetpos = 0;
|
|
clickbuttonx = 0;
|
|
vertical = 0;
|
|
firstdelay = 0;
|
|
lastx = lasty = 0;
|
|
}
|
|
|
|
ScrollBar::~ScrollBar() {
|
|
deleteResources();
|
|
}
|
|
|
|
void ScrollBar::deleteResources() {
|
|
delete leftrgn; leftrgn = NULL;
|
|
delete buttonrgn; buttonrgn = NULL;
|
|
delete rightrgn; rightrgn = NULL;
|
|
}
|
|
|
|
// this one is inherited
|
|
void ScrollBar::freeResources() {
|
|
SCROLLBAR_PARENT::freeResources();
|
|
deleteResources();
|
|
}
|
|
|
|
void ScrollBar::reloadResources() {
|
|
SCROLLBAR_PARENT::reloadResources();
|
|
loadBmps();
|
|
}
|
|
|
|
|
|
int ScrollBar::onMouseMove (int x, int y) {
|
|
|
|
SCROLLBAR_PARENT::onMouseMove(x, y);
|
|
lastx = x;
|
|
lasty = y;
|
|
|
|
if (clicked && clickmouseposition == POS_BUTTON) {
|
|
|
|
POINT pt={x,y};
|
|
int x;
|
|
if (!vertical)
|
|
x = pt.x - clickpos.x;
|
|
else
|
|
x = pt.y - clickpos.y;
|
|
|
|
RECT r;
|
|
getClientRect(&r);
|
|
int maxwidth;
|
|
if (!vertical)
|
|
maxwidth = (r.right-r.left)-(shiftright+shiftleft+bmpbutton.getWidth())+1;
|
|
else
|
|
maxwidth = (r.bottom-r.top)-(shiftright+shiftleft+bmpbutton.getHeight())+1;
|
|
buttonx = MIN(MAX(clickbuttonx + x, 0), maxwidth);
|
|
calcPosition();
|
|
invalidate();
|
|
|
|
} else {
|
|
|
|
int oldposition = curmouseposition;
|
|
curmouseposition = getMousePosition();
|
|
if (oldposition != curmouseposition) invalidate();
|
|
|
|
if (curmouseposition != POS_NONE && !getCapture())
|
|
beginCapture();
|
|
|
|
if (curmouseposition == POS_NONE && getCapture() && !clicked && !pageing)
|
|
endCapture();
|
|
}
|
|
|
|
|
|
return 1;
|
|
}
|
|
|
|
int ScrollBar::getWidth() {
|
|
if (!bmpbutton) return 0;
|
|
if (!vertical)
|
|
return bmpbutton.getHeight();
|
|
else
|
|
return bmpbutton.getWidth();
|
|
return 0;
|
|
}
|
|
|
|
int ScrollBar::getMousePosition() {
|
|
int v = POS_NONE;
|
|
|
|
POINT pt={lastx, lasty};
|
|
|
|
RECT c;
|
|
getClientRect(&c);
|
|
pt.x -= c.left;
|
|
pt.y -= c.top;
|
|
|
|
api_region *l, *b, *r;
|
|
l = leftrgn->clone();
|
|
b = buttonrgn->clone();
|
|
if (!vertical)
|
|
b->offset(buttonx+shiftleft, 0);
|
|
else
|
|
b->offset(0, buttonx+shiftleft);
|
|
r = rightrgn->clone();
|
|
if (!vertical)
|
|
r->offset(c.right-c.left-bmpleft.getWidth(), 0);
|
|
else
|
|
r->offset(0, c.bottom-c.top-bmpleft.getHeight());
|
|
|
|
if (b->ptInRegion(&pt))
|
|
v = POS_BUTTON;
|
|
if (l->ptInRegion(&pt))
|
|
v = POS_LEFT;
|
|
if (r->ptInRegion(&pt))
|
|
v = POS_RIGHT;
|
|
|
|
leftrgn->disposeClone(l);
|
|
buttonrgn->disposeClone(b);
|
|
rightrgn->disposeClone(r);
|
|
|
|
return v;
|
|
}
|
|
|
|
int ScrollBar::onLeftButtonDown(int x, int y) {
|
|
clickmouseposition = getMousePosition();
|
|
if (!pageing && clickmouseposition != POS_NONE) {
|
|
clicked = 1;
|
|
if (clickmouseposition == POS_LEFT || clickmouseposition == POS_RIGHT)
|
|
handleUpDown();
|
|
if (clickmouseposition) {
|
|
clickpos.x = lastx;
|
|
clickpos.y = lasty;
|
|
clickbuttonx = buttonx;
|
|
}
|
|
} else {
|
|
clicked = 0;
|
|
pageing = 1;
|
|
handlePageUpDown();
|
|
}
|
|
invalidate();
|
|
return 1;
|
|
}
|
|
|
|
void ScrollBar::handleUpDown() {
|
|
setTimer(TIMER_ID2, FIRST_DELAY);
|
|
timer2 = 1;
|
|
firstdelay = 1;
|
|
|
|
checkUpDown();
|
|
}
|
|
|
|
int ScrollBar::checkUpDown() {
|
|
if (!clicked) {
|
|
if (timer2) {
|
|
killTimer(TIMER_ID2);
|
|
timer2 = 0;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if (getMousePosition() == clickmouseposition)
|
|
upDown(clickmouseposition);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
void ScrollBar::handlePageUpDown() {
|
|
|
|
setTimer(TIMER_ID, FIRST_DELAY);
|
|
timer = 1;
|
|
firstdelay = 1;
|
|
|
|
checkPageUpDown();
|
|
}
|
|
|
|
int ScrollBar::checkPageUpDown() {
|
|
|
|
if (!pageing) {
|
|
if (timer) {
|
|
killTimer(TIMER_ID);
|
|
timer = 0;
|
|
pageway = PAGE_NONE;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
POINT pt={lastx,lasty};
|
|
RECT c;
|
|
getClientRect(&c);
|
|
pt.x -= c.left;
|
|
pt.y -= c.top;
|
|
|
|
if (!vertical) {
|
|
int middlebutton = shiftleft + buttonx + bmpbutton.getWidth()/2;
|
|
api_region *r = buttonrgn->clone();
|
|
r->offset(buttonx+shiftleft, 0);
|
|
if (pt.x > middlebutton && !r->ptInRegion(&pt) && pageway != PAGE_DOWN)
|
|
pageUp();
|
|
if (pt.x < middlebutton && !r->ptInRegion(&pt) && pageway != PAGE_UP)
|
|
pageDown();
|
|
buttonrgn->disposeClone(r);
|
|
} else {
|
|
int middlebutton = shiftleft + buttonx + bmpbutton.getHeight()/2;
|
|
api_region *r = buttonrgn->clone();
|
|
r->offset(0, buttonx+shiftleft);
|
|
if (pt.y > middlebutton && !r->ptInRegion(&pt) && pageway != PAGE_DOWN)
|
|
pageUp();
|
|
if (pt.y < middlebutton && !r->ptInRegion(&pt) && pageway != PAGE_UP)
|
|
pageDown();
|
|
buttonrgn->disposeClone(r);
|
|
}
|
|
return 1;
|
|
|
|
}
|
|
|
|
int ScrollBar::onLeftButtonUp(int x, int y) {
|
|
clicked = 0;
|
|
clickmouseposition = POS_NONE;
|
|
curmouseposition = POS_NONE;
|
|
onMouseMove(x,y);
|
|
if (pageing) {
|
|
pageing = 0;
|
|
checkPageUpDown();
|
|
}
|
|
onSetFinalPosition();
|
|
invalidate();
|
|
return 1;
|
|
}
|
|
|
|
int ScrollBar::onRightButtonDown(int x, int y) {
|
|
return 1;
|
|
}
|
|
|
|
int ScrollBar::onRightButtonUp(int x, int y) {
|
|
return 1;
|
|
}
|
|
|
|
int ScrollBar::onMouseWheelUp(int clicked, int lines) {
|
|
return 1;
|
|
}
|
|
|
|
int ScrollBar::onMouseWheelDown(int clicked, int lines) {
|
|
return 1;
|
|
}
|
|
|
|
int ScrollBar::onPaint(Canvas *canvas) {
|
|
AutoSkinBitmap &thisleft = curmouseposition == POS_LEFT ? (clicked ? bmplpressed : bmplhilite) : bmpleft;
|
|
AutoSkinBitmap &thisbutton = curmouseposition == POS_BUTTON ? (clicked ? bmpbpressed : bmpbhilite) : bmpbutton;
|
|
AutoSkinBitmap &thisright = curmouseposition == POS_RIGHT ? (clicked ? bmprpressed : bmprhilite) : bmpright;
|
|
|
|
if (curmouseposition != clickmouseposition && clicked) {
|
|
thisleft = bmpleft;
|
|
thisbutton = bmpbutton;
|
|
thisright = bmpright;
|
|
}
|
|
|
|
RECT r;
|
|
PaintBltCanvas paintcanvas;
|
|
|
|
if (canvas == NULL) {
|
|
if (!paintcanvas.beginPaint(this)) return 0;
|
|
canvas = &paintcanvas;
|
|
}
|
|
SCROLLBAR_PARENT::onPaint(canvas);
|
|
|
|
getClientRect(&r);
|
|
|
|
renderBaseTexture(canvas, r);
|
|
|
|
if (!vertical) {
|
|
RECT c;
|
|
|
|
c.left = r.left;
|
|
c.right = r.left;
|
|
c.top = r.top;
|
|
c.bottom = r.bottom;
|
|
if (bmpbackgroundleft.getBitmap()) {
|
|
c.right = c.left + bmpbackgroundleft.getWidth();
|
|
bmpbackgroundleft.getBitmap()->stretchToRectAlpha(canvas, &c);
|
|
}
|
|
int l = c.right;
|
|
c.left = r.right;
|
|
c.right = r.right;
|
|
if (bmpbackgroundright.getBitmap()) {
|
|
c.left = r.right - bmpbackgroundright.getWidth();
|
|
bmpbackgroundright.getBitmap()->stretchToRectAlpha(canvas, &c);
|
|
}
|
|
c.right = c.left;
|
|
c.left = l;
|
|
if (bmpbackgroundmiddle.getBitmap()) {
|
|
bmpbackgroundmiddle.getBitmap()->stretchToRectAlpha(canvas, &c);
|
|
}
|
|
|
|
c.left = r.left + buttonx+shiftleft;
|
|
c.top = r.top + 0;
|
|
c.right = r.left + buttonx+thisbutton.getWidth()+shiftleft;
|
|
c.bottom = r.top + getWidth();
|
|
|
|
thisbutton.stretchToRectAlpha(canvas, &c);
|
|
|
|
c.left = r.left;
|
|
c.top = r.top;
|
|
c.right = r.left + thisleft.getWidth();
|
|
c.bottom = r.top + getWidth();
|
|
|
|
thisleft.stretchToRectAlpha(canvas, &c);
|
|
|
|
c.left = r.right-thisright.getWidth();
|
|
c.top = r.top;
|
|
c.right = r.right;
|
|
c.bottom = r.top+getWidth();
|
|
|
|
thisright.stretchToRectAlpha(canvas, &c);
|
|
} else {
|
|
RECT c;
|
|
|
|
c.top = r.top;
|
|
c.bottom = r.top;
|
|
c.left = r.left;
|
|
c.right = r.right;
|
|
if (bmpbackgroundleft.getBitmap()) {
|
|
c.bottom = c.top + bmpbackgroundleft.getHeight();
|
|
bmpbackgroundleft.getBitmap()->stretchToRectAlpha(canvas, &c);
|
|
}
|
|
int l = c.bottom;
|
|
c.top = r.bottom;
|
|
c.bottom = r.bottom;
|
|
if (bmpbackgroundright.getBitmap()) {
|
|
c.top = r.bottom - bmpbackgroundright.getHeight();
|
|
bmpbackgroundright.getBitmap()->stretchToRectAlpha(canvas, &c);
|
|
}
|
|
c.bottom = c.top;
|
|
c.top = l;
|
|
if (bmpbackgroundmiddle.getBitmap()) {
|
|
bmpbackgroundmiddle.getBitmap()->stretchToRectAlpha(canvas, &c);
|
|
}
|
|
|
|
c.left = r.right - thisleft.getWidth();
|
|
c.top = r.top+buttonx + shiftleft;
|
|
c.right = r.right;
|
|
c.bottom = r.top+buttonx+thisbutton.getHeight() + shiftleft;
|
|
|
|
thisbutton.stretchToRectAlpha(canvas, &c);
|
|
|
|
c.left = r.right - thisleft.getWidth();
|
|
c.top = r.top;
|
|
c.right = r.right;
|
|
c.bottom = r.top+thisleft.getHeight();
|
|
|
|
thisleft.stretchToRectAlpha(canvas, &c);
|
|
|
|
c.left = r.right-thisright.getWidth();
|
|
c.top = r.bottom-thisright.getHeight();
|
|
c.right = r.right;
|
|
c.bottom = r.bottom;
|
|
|
|
thisright.stretchToRectAlpha(canvas, &c);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int ScrollBar::getHeight() {
|
|
return height;
|
|
}
|
|
|
|
void ScrollBar::setHeight(int newheight) {
|
|
height = newheight;
|
|
}
|
|
|
|
int ScrollBar::onResize() {
|
|
calcXPosition();
|
|
invalidate();
|
|
return 1;
|
|
}
|
|
|
|
int ScrollBar::onInit() {
|
|
SCROLLBAR_PARENT::onInit();
|
|
return 1;
|
|
}
|
|
|
|
void ScrollBar::setBitmaps(wchar_t *left, wchar_t *lpressed, wchar_t *lhilite,
|
|
wchar_t *right, wchar_t *rpressed, wchar_t *rhilite,
|
|
wchar_t *button, wchar_t *bpressed, wchar_t *bhilite) {
|
|
|
|
deleteResources();
|
|
|
|
bmpleft = left;
|
|
bmplpressed = lpressed;
|
|
bmplhilite = lhilite;
|
|
bmpright = right;
|
|
bmprpressed = rpressed;
|
|
bmprhilite = rhilite;
|
|
bmpbutton = button;
|
|
bmpbpressed = bpressed;
|
|
bmpbhilite = bhilite;
|
|
|
|
loadBmps();
|
|
}
|
|
|
|
void ScrollBar::setBackgroundBitmaps(const wchar_t *left, const wchar_t *middle, const wchar_t *right) {
|
|
bmpbackgroundleft = left;
|
|
bmpbackgroundmiddle = middle;
|
|
bmpbackgroundright = right;
|
|
}
|
|
|
|
void ScrollBar::loadBmps() {
|
|
|
|
if (bmpleft.getBitmap()) leftrgn = new RegionI(bmpleft);
|
|
if (bmpbutton.getBitmap()) buttonrgn = new RegionI(bmpbutton);
|
|
if (bmpright.getBitmap()) rightrgn = new RegionI(bmpright);
|
|
|
|
calcOverlapping();
|
|
calcXPosition();
|
|
}
|
|
|
|
void ScrollBar::setPosition(int pos) {
|
|
setPrivatePosition(pos, FALSE);
|
|
}
|
|
|
|
void ScrollBar::setPrivatePosition(int pos, bool signal, bool smooth) {
|
|
if (insetpos) return; // helps stupid people (like me)
|
|
insetpos = 1;
|
|
position = MIN(SCROLLBAR_FULL, pos);
|
|
position = MAX(0, position);
|
|
calcXPosition();
|
|
if (signal) onSetPosition(smooth);
|
|
if (isInited() && isVisible())
|
|
invalidate();
|
|
insetpos = 0;
|
|
}
|
|
|
|
int ScrollBar::getPosition() {
|
|
return position;
|
|
}
|
|
|
|
int ScrollBar::onSetPosition(bool smooth) {
|
|
notifyParent(ChildNotify::SCROLLBAR_SETPOSITION, smooth);
|
|
return 1;
|
|
}
|
|
|
|
int ScrollBar::onSetFinalPosition() {
|
|
notifyParent(ChildNotify::SCROLLBAR_SETFINALPOSITION);
|
|
return 1;
|
|
}
|
|
|
|
void ScrollBar::calcOverlapping() {
|
|
|
|
if (!vertical) {
|
|
|
|
shiftleft = bmpleft.getWidth();
|
|
if (leftrgn && buttonrgn) {
|
|
int i;
|
|
for (i=shiftleft;i>=0;i--) {
|
|
api_region *reg = buttonrgn->clone();
|
|
reg->offset(i, 0);
|
|
if (leftrgn->doesIntersectRgn(reg)) {
|
|
i++;
|
|
buttonrgn->disposeClone(reg);
|
|
break;
|
|
}
|
|
buttonrgn->disposeClone(reg);
|
|
}
|
|
if (i >= 0)
|
|
shiftleft = i;
|
|
}
|
|
|
|
shiftright = bmpright.getWidth();
|
|
if (rightrgn && buttonrgn) {
|
|
int i;
|
|
for (i=0;i>=-shiftright;i--) {
|
|
api_region *reg = rightrgn->clone();
|
|
reg->offset(i+bmpbutton.getWidth(), 0);
|
|
if (reg->doesIntersectRgn(buttonrgn)) {
|
|
i++;
|
|
rightrgn->disposeClone(reg);
|
|
break;
|
|
}
|
|
rightrgn->disposeClone(reg);
|
|
}
|
|
if (i >= -shiftright)
|
|
shiftright += i;
|
|
}
|
|
|
|
} else {
|
|
|
|
shiftleft = bmpleft.getHeight();
|
|
if (leftrgn && buttonrgn) {
|
|
int i;
|
|
for (i=shiftleft;i>=0;i--) {
|
|
api_region *reg = buttonrgn->clone();
|
|
reg->offset(0, i);
|
|
if (leftrgn->doesIntersectRgn(reg)) {
|
|
i++;
|
|
buttonrgn->disposeClone(reg);
|
|
break;
|
|
}
|
|
buttonrgn->disposeClone(reg);
|
|
}
|
|
if (i >= 0)
|
|
shiftleft = i;
|
|
}
|
|
|
|
shiftright = bmpright.getHeight();
|
|
if (rightrgn && buttonrgn) {
|
|
int i;
|
|
for (i=0;i>=-shiftright;i--) {
|
|
api_region *reg = rightrgn->clone();
|
|
reg->offset(0, i+bmpbutton.getHeight());
|
|
if (reg->doesIntersectRgn(buttonrgn)) {
|
|
i++;
|
|
rightrgn->disposeClone(reg);
|
|
break;
|
|
}
|
|
rightrgn->disposeClone(reg);
|
|
}
|
|
if (i >= -shiftright)
|
|
shiftright += i;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void ScrollBar::calcXPosition() {
|
|
|
|
if (!isInited()) return;
|
|
|
|
RECT r;
|
|
getClientRect(&r);
|
|
|
|
int maxwidth;
|
|
|
|
if (!vertical)
|
|
maxwidth = (r.right-r.left)-(bmpbutton.getWidth()+shiftleft+shiftright)+1;
|
|
else
|
|
maxwidth = (r.bottom-r.top)-(bmpbutton.getHeight()+shiftleft+shiftright)+1;
|
|
int oldx = buttonx;
|
|
buttonx = (int)(((float)getPosition() / SCROLLBAR_FULL) * maxwidth);
|
|
if (buttonx != oldx)
|
|
invalidate();
|
|
}
|
|
|
|
void ScrollBar::calcPosition() {
|
|
|
|
if (!isInited()) return;
|
|
|
|
RECT r;
|
|
getClientRect(&r);
|
|
|
|
int maxwidth;
|
|
|
|
if (!vertical)
|
|
maxwidth = r.right-r.left-(bmpbutton.getWidth()+shiftleft+shiftright)+1;
|
|
else
|
|
maxwidth = r.bottom-r.top-(bmpbutton.getHeight()+shiftleft+shiftright)+1;
|
|
setPrivatePosition((int)((float)buttonx / maxwidth * SCROLLBAR_FULL));
|
|
//invalidate();
|
|
}
|
|
|
|
void ScrollBar::timerCallback(int id) {
|
|
switch (id) {
|
|
case TIMER_ID:
|
|
if (firstdelay) {
|
|
killTimer(TIMER_ID);
|
|
setTimer(TIMER_ID, NEXT_DELAY);
|
|
timer = 1;
|
|
firstdelay = 0;
|
|
}
|
|
checkPageUpDown();
|
|
break;
|
|
case TIMER_ID2:
|
|
if (firstdelay) {
|
|
killTimer(TIMER_ID2);
|
|
setTimer(TIMER_ID2, NEXT_DELAY);
|
|
timer2 = 1;
|
|
firstdelay = 0;
|
|
}
|
|
checkUpDown();
|
|
break;
|
|
default:
|
|
SCROLLBAR_PARENT::timerCallback(id);
|
|
}
|
|
}
|
|
|
|
// FG> smooth scrolling forced on, sorry, microsoft does it too so the user perceives IE scrolling as faster than it actually is
|
|
// eventho they tell you "The smooth-scrolling effect for list boxes should be disabled when this setting is FALSE. Your application must do this if it creates customized list boxes", they
|
|
// break their own rule so people don't bitch too much. ergo there is no reason we should not do that too.
|
|
|
|
int ScrollBar::pageUp() {
|
|
|
|
pageway = PAGE_UP;
|
|
|
|
setPrivatePosition((int)MAX(0.f, (float)getPosition() + (float)SCROLLBAR_FULL / (npages-1)), TRUE, 1/*Std::osparam_getSmoothScroll()*/);
|
|
|
|
return 1;
|
|
};
|
|
|
|
int ScrollBar::pageDown() {
|
|
|
|
pageway = PAGE_DOWN;
|
|
|
|
setPrivatePosition((int)MIN((float)SCROLLBAR_FULL, (float)getPosition() - (float)SCROLLBAR_FULL / (npages-1)), TRUE, 1/*Std::osparam_getSmoothScroll()*/);
|
|
|
|
return 1;
|
|
};
|
|
|
|
void ScrollBar::setNPages(int n) {
|
|
//ASSERT(n >= 2);
|
|
if (n < 2) n = 2;
|
|
npages = n;
|
|
}
|
|
|
|
void ScrollBar::gotoPage(int page) {
|
|
|
|
page = MIN(page, npages-1);
|
|
page = MAX(page, 0);
|
|
|
|
setPrivatePosition((int)((float)SCROLLBAR_FULL / (npages-1) * page), TRUE, FALSE);
|
|
|
|
}
|
|
|
|
void ScrollBar::setUpDownValue(int newupdown) {
|
|
updown = newupdown;
|
|
}
|
|
|
|
int ScrollBar::upDown(int which) {
|
|
switch (which) {
|
|
case POS_LEFT:
|
|
setPrivatePosition(getPosition()-updown);
|
|
break;
|
|
case POS_RIGHT:
|
|
setPrivatePosition(getPosition()+updown);
|
|
break;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
void ScrollBar::setVertical(bool isvertical) {
|
|
vertical = isvertical;
|
|
calcOverlapping();
|
|
if (isInited())
|
|
invalidate();
|
|
}
|
|
|