1
0

scrollbar.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. #include <precomp.h>
  2. #include <bfc/wasabi_std.h>
  3. #include "scrollbar.h"
  4. #include <tataki/canvas/canvas.h>
  5. #include <api/wnd/notifmsg.h>
  6. #include <api/wnd/PaintCanvas.h>
  7. #define TIMER_ID 9871
  8. #define TIMER_ID2 9872
  9. #define FIRST_DELAY 350
  10. #define NEXT_DELAY 75
  11. ScrollBar::ScrollBar() {
  12. leftrgn = NULL;
  13. rightrgn = NULL;
  14. buttonrgn = NULL;
  15. position = 0;
  16. moving = 0;
  17. lefting = 0;
  18. righting = 0;
  19. clicked = 0;
  20. height = DEFAULT_HEIGHT;
  21. buttonx = 0;
  22. shiftleft = 0;
  23. shiftright = 0;
  24. curmouseposition = POS_NONE;
  25. clickmouseposition = POS_NONE;
  26. pageing = 0;
  27. timer = timer2 = 0;
  28. npages = 100;
  29. pageway = PAGE_NONE;
  30. updown = 256;
  31. insetpos = 0;
  32. clickbuttonx = 0;
  33. vertical = 0;
  34. firstdelay = 0;
  35. lastx = lasty = 0;
  36. }
  37. ScrollBar::~ScrollBar() {
  38. deleteResources();
  39. }
  40. void ScrollBar::deleteResources() {
  41. delete leftrgn; leftrgn = NULL;
  42. delete buttonrgn; buttonrgn = NULL;
  43. delete rightrgn; rightrgn = NULL;
  44. }
  45. // this one is inherited
  46. void ScrollBar::freeResources() {
  47. SCROLLBAR_PARENT::freeResources();
  48. deleteResources();
  49. }
  50. void ScrollBar::reloadResources() {
  51. SCROLLBAR_PARENT::reloadResources();
  52. loadBmps();
  53. }
  54. int ScrollBar::onMouseMove (int x, int y) {
  55. SCROLLBAR_PARENT::onMouseMove(x, y);
  56. lastx = x;
  57. lasty = y;
  58. if (clicked && clickmouseposition == POS_BUTTON) {
  59. POINT pt={x,y};
  60. int x;
  61. if (!vertical)
  62. x = pt.x - clickpos.x;
  63. else
  64. x = pt.y - clickpos.y;
  65. RECT r;
  66. getClientRect(&r);
  67. int maxwidth;
  68. if (!vertical)
  69. maxwidth = (r.right-r.left)-(shiftright+shiftleft+bmpbutton.getWidth())+1;
  70. else
  71. maxwidth = (r.bottom-r.top)-(shiftright+shiftleft+bmpbutton.getHeight())+1;
  72. buttonx = MIN(MAX(clickbuttonx + x, 0), maxwidth);
  73. calcPosition();
  74. invalidate();
  75. } else {
  76. int oldposition = curmouseposition;
  77. curmouseposition = getMousePosition();
  78. if (oldposition != curmouseposition) invalidate();
  79. if (curmouseposition != POS_NONE && !getCapture())
  80. beginCapture();
  81. if (curmouseposition == POS_NONE && getCapture() && !clicked && !pageing)
  82. endCapture();
  83. }
  84. return 1;
  85. }
  86. int ScrollBar::getWidth() {
  87. if (!bmpbutton) return 0;
  88. if (!vertical)
  89. return bmpbutton.getHeight();
  90. else
  91. return bmpbutton.getWidth();
  92. return 0;
  93. }
  94. int ScrollBar::getMousePosition() {
  95. int v = POS_NONE;
  96. POINT pt={lastx, lasty};
  97. RECT c;
  98. getClientRect(&c);
  99. pt.x -= c.left;
  100. pt.y -= c.top;
  101. api_region *l, *b, *r;
  102. l = leftrgn->clone();
  103. b = buttonrgn->clone();
  104. if (!vertical)
  105. b->offset(buttonx+shiftleft, 0);
  106. else
  107. b->offset(0, buttonx+shiftleft);
  108. r = rightrgn->clone();
  109. if (!vertical)
  110. r->offset(c.right-c.left-bmpleft.getWidth(), 0);
  111. else
  112. r->offset(0, c.bottom-c.top-bmpleft.getHeight());
  113. if (b->ptInRegion(&pt))
  114. v = POS_BUTTON;
  115. if (l->ptInRegion(&pt))
  116. v = POS_LEFT;
  117. if (r->ptInRegion(&pt))
  118. v = POS_RIGHT;
  119. leftrgn->disposeClone(l);
  120. buttonrgn->disposeClone(b);
  121. rightrgn->disposeClone(r);
  122. return v;
  123. }
  124. int ScrollBar::onLeftButtonDown(int x, int y) {
  125. clickmouseposition = getMousePosition();
  126. if (!pageing && clickmouseposition != POS_NONE) {
  127. clicked = 1;
  128. if (clickmouseposition == POS_LEFT || clickmouseposition == POS_RIGHT)
  129. handleUpDown();
  130. if (clickmouseposition) {
  131. clickpos.x = lastx;
  132. clickpos.y = lasty;
  133. clickbuttonx = buttonx;
  134. }
  135. } else {
  136. clicked = 0;
  137. pageing = 1;
  138. handlePageUpDown();
  139. }
  140. invalidate();
  141. return 1;
  142. }
  143. void ScrollBar::handleUpDown() {
  144. setTimer(TIMER_ID2, FIRST_DELAY);
  145. timer2 = 1;
  146. firstdelay = 1;
  147. checkUpDown();
  148. }
  149. int ScrollBar::checkUpDown() {
  150. if (!clicked) {
  151. if (timer2) {
  152. killTimer(TIMER_ID2);
  153. timer2 = 0;
  154. return 1;
  155. }
  156. }
  157. if (getMousePosition() == clickmouseposition)
  158. upDown(clickmouseposition);
  159. return 1;
  160. }
  161. void ScrollBar::handlePageUpDown() {
  162. setTimer(TIMER_ID, FIRST_DELAY);
  163. timer = 1;
  164. firstdelay = 1;
  165. checkPageUpDown();
  166. }
  167. int ScrollBar::checkPageUpDown() {
  168. if (!pageing) {
  169. if (timer) {
  170. killTimer(TIMER_ID);
  171. timer = 0;
  172. pageway = PAGE_NONE;
  173. return 1;
  174. }
  175. }
  176. POINT pt={lastx,lasty};
  177. RECT c;
  178. getClientRect(&c);
  179. pt.x -= c.left;
  180. pt.y -= c.top;
  181. if (!vertical) {
  182. int middlebutton = shiftleft + buttonx + bmpbutton.getWidth()/2;
  183. api_region *r = buttonrgn->clone();
  184. r->offset(buttonx+shiftleft, 0);
  185. if (pt.x > middlebutton && !r->ptInRegion(&pt) && pageway != PAGE_DOWN)
  186. pageUp();
  187. if (pt.x < middlebutton && !r->ptInRegion(&pt) && pageway != PAGE_UP)
  188. pageDown();
  189. buttonrgn->disposeClone(r);
  190. } else {
  191. int middlebutton = shiftleft + buttonx + bmpbutton.getHeight()/2;
  192. api_region *r = buttonrgn->clone();
  193. r->offset(0, buttonx+shiftleft);
  194. if (pt.y > middlebutton && !r->ptInRegion(&pt) && pageway != PAGE_DOWN)
  195. pageUp();
  196. if (pt.y < middlebutton && !r->ptInRegion(&pt) && pageway != PAGE_UP)
  197. pageDown();
  198. buttonrgn->disposeClone(r);
  199. }
  200. return 1;
  201. }
  202. int ScrollBar::onLeftButtonUp(int x, int y) {
  203. clicked = 0;
  204. clickmouseposition = POS_NONE;
  205. curmouseposition = POS_NONE;
  206. onMouseMove(x,y);
  207. if (pageing) {
  208. pageing = 0;
  209. checkPageUpDown();
  210. }
  211. onSetFinalPosition();
  212. invalidate();
  213. return 1;
  214. }
  215. int ScrollBar::onRightButtonDown(int x, int y) {
  216. return 1;
  217. }
  218. int ScrollBar::onRightButtonUp(int x, int y) {
  219. return 1;
  220. }
  221. int ScrollBar::onMouseWheelUp(int clicked, int lines) {
  222. return 1;
  223. }
  224. int ScrollBar::onMouseWheelDown(int clicked, int lines) {
  225. return 1;
  226. }
  227. int ScrollBar::onPaint(Canvas *canvas) {
  228. AutoSkinBitmap &thisleft = curmouseposition == POS_LEFT ? (clicked ? bmplpressed : bmplhilite) : bmpleft;
  229. AutoSkinBitmap &thisbutton = curmouseposition == POS_BUTTON ? (clicked ? bmpbpressed : bmpbhilite) : bmpbutton;
  230. AutoSkinBitmap &thisright = curmouseposition == POS_RIGHT ? (clicked ? bmprpressed : bmprhilite) : bmpright;
  231. if (curmouseposition != clickmouseposition && clicked) {
  232. thisleft = bmpleft;
  233. thisbutton = bmpbutton;
  234. thisright = bmpright;
  235. }
  236. RECT r;
  237. PaintBltCanvas paintcanvas;
  238. if (canvas == NULL) {
  239. if (!paintcanvas.beginPaint(this)) return 0;
  240. canvas = &paintcanvas;
  241. }
  242. SCROLLBAR_PARENT::onPaint(canvas);
  243. getClientRect(&r);
  244. renderBaseTexture(canvas, r);
  245. if (!vertical) {
  246. RECT c;
  247. c.left = r.left;
  248. c.right = r.left;
  249. c.top = r.top;
  250. c.bottom = r.bottom;
  251. if (bmpbackgroundleft.getBitmap()) {
  252. c.right = c.left + bmpbackgroundleft.getWidth();
  253. bmpbackgroundleft.getBitmap()->stretchToRectAlpha(canvas, &c);
  254. }
  255. int l = c.right;
  256. c.left = r.right;
  257. c.right = r.right;
  258. if (bmpbackgroundright.getBitmap()) {
  259. c.left = r.right - bmpbackgroundright.getWidth();
  260. bmpbackgroundright.getBitmap()->stretchToRectAlpha(canvas, &c);
  261. }
  262. c.right = c.left;
  263. c.left = l;
  264. if (bmpbackgroundmiddle.getBitmap()) {
  265. bmpbackgroundmiddle.getBitmap()->stretchToRectAlpha(canvas, &c);
  266. }
  267. c.left = r.left + buttonx+shiftleft;
  268. c.top = r.top + 0;
  269. c.right = r.left + buttonx+thisbutton.getWidth()+shiftleft;
  270. c.bottom = r.top + getWidth();
  271. thisbutton.stretchToRectAlpha(canvas, &c);
  272. c.left = r.left;
  273. c.top = r.top;
  274. c.right = r.left + thisleft.getWidth();
  275. c.bottom = r.top + getWidth();
  276. thisleft.stretchToRectAlpha(canvas, &c);
  277. c.left = r.right-thisright.getWidth();
  278. c.top = r.top;
  279. c.right = r.right;
  280. c.bottom = r.top+getWidth();
  281. thisright.stretchToRectAlpha(canvas, &c);
  282. } else {
  283. RECT c;
  284. c.top = r.top;
  285. c.bottom = r.top;
  286. c.left = r.left;
  287. c.right = r.right;
  288. if (bmpbackgroundleft.getBitmap()) {
  289. c.bottom = c.top + bmpbackgroundleft.getHeight();
  290. bmpbackgroundleft.getBitmap()->stretchToRectAlpha(canvas, &c);
  291. }
  292. int l = c.bottom;
  293. c.top = r.bottom;
  294. c.bottom = r.bottom;
  295. if (bmpbackgroundright.getBitmap()) {
  296. c.top = r.bottom - bmpbackgroundright.getHeight();
  297. bmpbackgroundright.getBitmap()->stretchToRectAlpha(canvas, &c);
  298. }
  299. c.bottom = c.top;
  300. c.top = l;
  301. if (bmpbackgroundmiddle.getBitmap()) {
  302. bmpbackgroundmiddle.getBitmap()->stretchToRectAlpha(canvas, &c);
  303. }
  304. c.left = r.right - thisleft.getWidth();
  305. c.top = r.top+buttonx + shiftleft;
  306. c.right = r.right;
  307. c.bottom = r.top+buttonx+thisbutton.getHeight() + shiftleft;
  308. thisbutton.stretchToRectAlpha(canvas, &c);
  309. c.left = r.right - thisleft.getWidth();
  310. c.top = r.top;
  311. c.right = r.right;
  312. c.bottom = r.top+thisleft.getHeight();
  313. thisleft.stretchToRectAlpha(canvas, &c);
  314. c.left = r.right-thisright.getWidth();
  315. c.top = r.bottom-thisright.getHeight();
  316. c.right = r.right;
  317. c.bottom = r.bottom;
  318. thisright.stretchToRectAlpha(canvas, &c);
  319. }
  320. return 1;
  321. }
  322. int ScrollBar::getHeight() {
  323. return height;
  324. }
  325. void ScrollBar::setHeight(int newheight) {
  326. height = newheight;
  327. }
  328. int ScrollBar::onResize() {
  329. calcXPosition();
  330. invalidate();
  331. return 1;
  332. }
  333. int ScrollBar::onInit() {
  334. SCROLLBAR_PARENT::onInit();
  335. return 1;
  336. }
  337. void ScrollBar::setBitmaps(wchar_t *left, wchar_t *lpressed, wchar_t *lhilite,
  338. wchar_t *right, wchar_t *rpressed, wchar_t *rhilite,
  339. wchar_t *button, wchar_t *bpressed, wchar_t *bhilite) {
  340. deleteResources();
  341. bmpleft = left;
  342. bmplpressed = lpressed;
  343. bmplhilite = lhilite;
  344. bmpright = right;
  345. bmprpressed = rpressed;
  346. bmprhilite = rhilite;
  347. bmpbutton = button;
  348. bmpbpressed = bpressed;
  349. bmpbhilite = bhilite;
  350. loadBmps();
  351. }
  352. void ScrollBar::setBackgroundBitmaps(const wchar_t *left, const wchar_t *middle, const wchar_t *right) {
  353. bmpbackgroundleft = left;
  354. bmpbackgroundmiddle = middle;
  355. bmpbackgroundright = right;
  356. }
  357. void ScrollBar::loadBmps() {
  358. if (bmpleft.getBitmap()) leftrgn = new RegionI(bmpleft);
  359. if (bmpbutton.getBitmap()) buttonrgn = new RegionI(bmpbutton);
  360. if (bmpright.getBitmap()) rightrgn = new RegionI(bmpright);
  361. calcOverlapping();
  362. calcXPosition();
  363. }
  364. void ScrollBar::setPosition(int pos) {
  365. setPrivatePosition(pos, FALSE);
  366. }
  367. void ScrollBar::setPrivatePosition(int pos, bool signal, bool smooth) {
  368. if (insetpos) return; // helps stupid people (like me)
  369. insetpos = 1;
  370. position = MIN(SCROLLBAR_FULL, pos);
  371. position = MAX(0, position);
  372. calcXPosition();
  373. if (signal) onSetPosition(smooth);
  374. if (isInited() && isVisible())
  375. invalidate();
  376. insetpos = 0;
  377. }
  378. int ScrollBar::getPosition() {
  379. return position;
  380. }
  381. int ScrollBar::onSetPosition(bool smooth) {
  382. notifyParent(ChildNotify::SCROLLBAR_SETPOSITION, smooth);
  383. return 1;
  384. }
  385. int ScrollBar::onSetFinalPosition() {
  386. notifyParent(ChildNotify::SCROLLBAR_SETFINALPOSITION);
  387. return 1;
  388. }
  389. void ScrollBar::calcOverlapping() {
  390. if (!vertical) {
  391. shiftleft = bmpleft.getWidth();
  392. if (leftrgn && buttonrgn) {
  393. int i;
  394. for (i=shiftleft;i>=0;i--) {
  395. api_region *reg = buttonrgn->clone();
  396. reg->offset(i, 0);
  397. if (leftrgn->doesIntersectRgn(reg)) {
  398. i++;
  399. buttonrgn->disposeClone(reg);
  400. break;
  401. }
  402. buttonrgn->disposeClone(reg);
  403. }
  404. if (i >= 0)
  405. shiftleft = i;
  406. }
  407. shiftright = bmpright.getWidth();
  408. if (rightrgn && buttonrgn) {
  409. int i;
  410. for (i=0;i>=-shiftright;i--) {
  411. api_region *reg = rightrgn->clone();
  412. reg->offset(i+bmpbutton.getWidth(), 0);
  413. if (reg->doesIntersectRgn(buttonrgn)) {
  414. i++;
  415. rightrgn->disposeClone(reg);
  416. break;
  417. }
  418. rightrgn->disposeClone(reg);
  419. }
  420. if (i >= -shiftright)
  421. shiftright += i;
  422. }
  423. } else {
  424. shiftleft = bmpleft.getHeight();
  425. if (leftrgn && buttonrgn) {
  426. int i;
  427. for (i=shiftleft;i>=0;i--) {
  428. api_region *reg = buttonrgn->clone();
  429. reg->offset(0, i);
  430. if (leftrgn->doesIntersectRgn(reg)) {
  431. i++;
  432. buttonrgn->disposeClone(reg);
  433. break;
  434. }
  435. buttonrgn->disposeClone(reg);
  436. }
  437. if (i >= 0)
  438. shiftleft = i;
  439. }
  440. shiftright = bmpright.getHeight();
  441. if (rightrgn && buttonrgn) {
  442. int i;
  443. for (i=0;i>=-shiftright;i--) {
  444. api_region *reg = rightrgn->clone();
  445. reg->offset(0, i+bmpbutton.getHeight());
  446. if (reg->doesIntersectRgn(buttonrgn)) {
  447. i++;
  448. rightrgn->disposeClone(reg);
  449. break;
  450. }
  451. rightrgn->disposeClone(reg);
  452. }
  453. if (i >= -shiftright)
  454. shiftright += i;
  455. }
  456. }
  457. }
  458. void ScrollBar::calcXPosition() {
  459. if (!isInited()) return;
  460. RECT r;
  461. getClientRect(&r);
  462. int maxwidth;
  463. if (!vertical)
  464. maxwidth = (r.right-r.left)-(bmpbutton.getWidth()+shiftleft+shiftright)+1;
  465. else
  466. maxwidth = (r.bottom-r.top)-(bmpbutton.getHeight()+shiftleft+shiftright)+1;
  467. int oldx = buttonx;
  468. buttonx = (int)(((float)getPosition() / SCROLLBAR_FULL) * maxwidth);
  469. if (buttonx != oldx)
  470. invalidate();
  471. }
  472. void ScrollBar::calcPosition() {
  473. if (!isInited()) return;
  474. RECT r;
  475. getClientRect(&r);
  476. int maxwidth;
  477. if (!vertical)
  478. maxwidth = r.right-r.left-(bmpbutton.getWidth()+shiftleft+shiftright)+1;
  479. else
  480. maxwidth = r.bottom-r.top-(bmpbutton.getHeight()+shiftleft+shiftright)+1;
  481. setPrivatePosition((int)((float)buttonx / maxwidth * SCROLLBAR_FULL));
  482. //invalidate();
  483. }
  484. void ScrollBar::timerCallback(int id) {
  485. switch (id) {
  486. case TIMER_ID:
  487. if (firstdelay) {
  488. killTimer(TIMER_ID);
  489. setTimer(TIMER_ID, NEXT_DELAY);
  490. timer = 1;
  491. firstdelay = 0;
  492. }
  493. checkPageUpDown();
  494. break;
  495. case TIMER_ID2:
  496. if (firstdelay) {
  497. killTimer(TIMER_ID2);
  498. setTimer(TIMER_ID2, NEXT_DELAY);
  499. timer2 = 1;
  500. firstdelay = 0;
  501. }
  502. checkUpDown();
  503. break;
  504. default:
  505. SCROLLBAR_PARENT::timerCallback(id);
  506. }
  507. }
  508. // FG> smooth scrolling forced on, sorry, microsoft does it too so the user perceives IE scrolling as faster than it actually is
  509. // 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
  510. // break their own rule so people don't bitch too much. ergo there is no reason we should not do that too.
  511. int ScrollBar::pageUp() {
  512. pageway = PAGE_UP;
  513. setPrivatePosition((int)MAX(0.f, (float)getPosition() + (float)SCROLLBAR_FULL / (npages-1)), TRUE, 1/*Std::osparam_getSmoothScroll()*/);
  514. return 1;
  515. };
  516. int ScrollBar::pageDown() {
  517. pageway = PAGE_DOWN;
  518. setPrivatePosition((int)MIN((float)SCROLLBAR_FULL, (float)getPosition() - (float)SCROLLBAR_FULL / (npages-1)), TRUE, 1/*Std::osparam_getSmoothScroll()*/);
  519. return 1;
  520. };
  521. void ScrollBar::setNPages(int n) {
  522. //ASSERT(n >= 2);
  523. if (n < 2) n = 2;
  524. npages = n;
  525. }
  526. void ScrollBar::gotoPage(int page) {
  527. page = MIN(page, npages-1);
  528. page = MAX(page, 0);
  529. setPrivatePosition((int)((float)SCROLLBAR_FULL / (npages-1) * page), TRUE, FALSE);
  530. }
  531. void ScrollBar::setUpDownValue(int newupdown) {
  532. updown = newupdown;
  533. }
  534. int ScrollBar::upDown(int which) {
  535. switch (which) {
  536. case POS_LEFT:
  537. setPrivatePosition(getPosition()-updown);
  538. break;
  539. case POS_RIGHT:
  540. setPrivatePosition(getPosition()+updown);
  541. break;
  542. }
  543. return 1;
  544. }
  545. void ScrollBar::setVertical(bool isvertical) {
  546. vertical = isvertical;
  547. calcOverlapping();
  548. if (isInited())
  549. invalidate();
  550. }