/gui/vscrollbar.d

http://github.com/wilkie/djehuty · D · 681 lines · 439 code · 191 blank · 51 comment · 124 complexity · 071f80323257b0e34810b9114a968b69 MD5 · raw file

  1. module gui.vscrollbar;
  2. import gui.widget;
  3. import core.color;
  4. import core.definitions;
  5. import core.string;
  6. import core.event;
  7. import graphics.graphics;
  8. import synch.timer;
  9. template ControlPrintCSTRList() {
  10. const char[] ControlPrintCSTRList = `
  11. this(int x, int y, int width, int height) {
  12. super(x,y,width,height);
  13. }
  14. `;
  15. }
  16. // Description: This control provides a standard vertical scroll bar.
  17. class VScrollBar : Widget {
  18. public:
  19. enum Signal : uint {
  20. Selected,
  21. Unselected,
  22. Scrolled,
  23. }
  24. this(int x, int y, int width, int height) {
  25. super(x,y,width,height);
  26. m_min = 0;
  27. m_max = 30;
  28. m_value = 0;
  29. m_small_change = 1;
  30. m_large_change = 10;
  31. m_clroutline = Color.fromRGB(0x80,0x80,0x80);
  32. m_clrarea = Color.fromRGB(0xe0, 0xe0, 0xe0);
  33. m_clrbutton = Color.fromRGB(0xc0, 0xc0, 0xc0);
  34. m_clrhighlight = Color.fromRGB(0xdd, 0xdd, 0xdd);
  35. m_clrnormal = Color.fromRGB(0,0,0);
  36. m_clrthumb = Color.fromRGB(0xc0, 0xc0, 0xc0);
  37. m_clrhover = Color.fromRGB(0xdd, 0xdd, 0xdd);
  38. _readyTimer = new Timer();
  39. _clickTimer = new Timer();
  40. _clickTimer.setInterval(50);
  41. _readyTimer.setInterval(100);
  42. push(_readyTimer);
  43. push(_clickTimer);
  44. }
  45. override void onAdd() {
  46. m_whatishovered = 0;
  47. m_isclicked=0;
  48. }
  49. override bool onSignal(Dispatcher dsp, uint signal) {
  50. if (dsp is _readyTimer) {
  51. readyTimerProc();
  52. }
  53. else if (dsp is _clickTimer) {
  54. clickTimerProc();
  55. }
  56. return true;
  57. }
  58. override void onDraw(ref Graphics g) {
  59. //a scroll bar is just a few rectangles (4)
  60. //one rectangle for the min arrow, one for max arrow
  61. //one more for the body
  62. //one more for the thumb
  63. long total_value_space = m_large_change + (m_max - m_min);
  64. double percent = cast(double)m_large_change / cast(double)total_value_space;
  65. m_area = (this.height - (this.width*2))+2;
  66. m_thumb_size = cast(int)(cast(double)m_area * percent);
  67. if (m_thumb_size < 10) { m_thumb_size = 10; }
  68. m_area -= m_thumb_size;
  69. percent = cast(double)(m_value - m_min) / cast(double)(m_max - m_min);
  70. m_thumb_pos_y = cast(int)(cast(double)m_area * percent) + this.top + this.width-1;
  71. m_thumb_pos_b = m_thumb_pos_y + m_thumb_size;
  72. //BODY
  73. Brush brsh = new Brush(m_clrarea);
  74. Pen pen = new Pen(m_clroutline);
  75. g.pen = pen;
  76. g.brush = brsh;
  77. g.drawRect(this.left, this.top, this.width,this.height);
  78. brsh.setColor(m_clrbutton);
  79. g.drawRect(this.left, this.top, this.width, this.width);
  80. g.drawRect(this.left, this.bottom-this.width, this.width, this.width);
  81. //THUMB
  82. brsh.setColor(m_clrthumb);
  83. g.drawRect(this.left, m_thumb_pos_y, this.width, m_thumb_size);
  84. //Draw triangle images...
  85. //draw UP BUTTON
  86. brsh.setColor(m_clrnormal);
  87. pen.setColor(m_clrnormal);
  88. Pen pen_hlight = new Pen(m_clrhighlight);
  89. Brush brsh_hlight = new Brush(m_clrhighlight);
  90. if (m_whatishovered == 1) {
  91. g.brush = (brsh_hlight);
  92. g.pen = (pen_hlight);
  93. }
  94. int base, height;
  95. height = (this.width / 4); //height
  96. //from the 'height' we can draw a perfect triangle
  97. base = (height*2) - 1; //base
  98. int xH,yB; //main directional point of triangle:
  99. xH = this.left + ((this.width - base)/2);
  100. yB = this.top + ((this.width - height) /2);
  101. base--;
  102. height--;
  103. Coord pnt[3] = [ Coord(xH+(base/2),yB), Coord(xH,yB+height), Coord(xH+base,yB+height) ];
  104. if (m_isclicked == 1) {
  105. pnt[0].x+=1;
  106. pnt[0].y+=1;
  107. pnt[1].x+=1;
  108. pnt[1].y+=1;
  109. pnt[2].x+=1;
  110. pnt[2].y+=1;
  111. }
  112. //DRAW_TRIANGLE(pnt);
  113. //draw DOWN BUTTON
  114. yB = this.bottom - ((this.width - height + 1)/2);
  115. Coord pnt2[3] = [ Coord(xH+(base/2),yB), Coord(xH,yB-height), Coord(xH+base,yB-height) ];
  116. if (m_whatishovered == 2) {
  117. g.brush = (brsh_hlight);
  118. g.pen = (pen_hlight);
  119. }
  120. else {
  121. if (m_whatishovered == 1) {
  122. g.brush = (brsh);
  123. g.pen = (pen);
  124. }
  125. }
  126. if (m_isclicked == 2) {
  127. pnt2[0].x+=1;
  128. pnt2[0].y+=1;
  129. pnt2[1].x+=1;
  130. pnt2[1].y+=1;
  131. pnt2[2].x+=1;
  132. pnt2[2].y+=1;
  133. }
  134. //DRAW_TRIANGLE(pnt2);
  135. pen.setColor(m_clroutline);
  136. //THUMB BAR LINE DESIGN
  137. g.pen = (pen);
  138. int new_x = this.left + 2;
  139. int new_r = this.right - 2;
  140. if (m_thumb_size > 80 + base+4) {
  141. for (height = 10; height < 40; height+=4) {
  142. g.drawLine(new_x, height+m_thumb_pos_y, new_r, height+m_thumb_pos_y);
  143. }
  144. //highlight pen
  145. g.pen = (pen_hlight);
  146. for (height = 11; height < 41; height+=4) {
  147. g.drawLine(new_x, height+m_thumb_pos_y, new_r, height+m_thumb_pos_y);
  148. }
  149. //outline pen
  150. g.pen = (pen);
  151. for (height = m_thumb_size - 39; height < m_thumb_size - 9; height+=4) {
  152. g.drawLine(new_x, height+m_thumb_pos_y, new_r, height+m_thumb_pos_y);
  153. }
  154. //highlight pen
  155. g.pen = (pen_hlight);
  156. for (height = m_thumb_size - 38; height < m_thumb_size - 8; height+=4) {
  157. g.drawLine(new_x, height+m_thumb_pos_y, new_r, height+m_thumb_pos_y);
  158. }
  159. //draw rectangle
  160. yB = m_thumb_pos_y + ((m_thumb_size - base) / 2);
  161. if (m_whatishovered == 3) {
  162. g.brush = (brsh_hlight);
  163. g.drawRect(xH, yB, base, base);
  164. pen.setColor(m_clrnormal);
  165. }
  166. else {
  167. pen.setColor(m_clrnormal);
  168. g.brush = (brsh);
  169. g.pen = (pen);
  170. g.drawRect(xH, yB, base, base);
  171. }
  172. }
  173. else if (m_thumb_size > 25) {
  174. //find the rectangle's position
  175. //draw lines outward from that...
  176. yB = m_thumb_pos_y + ((m_thumb_size - base) / 2);
  177. //height = 10; height < 40
  178. //total_value_space is a counter; counts the number of lines that will fit
  179. for (total_value_space=0, height = yB + base + 2; height < m_thumb_pos_y + m_thumb_size - 9; height+=4, total_value_space++) {
  180. g.drawLine(new_x, height, new_r, height);
  181. }
  182. for (height = yB-3 ; total_value_space > 0; height-=4, total_value_space--) {
  183. g.drawLine(new_x, height, new_r, height);
  184. }
  185. //highlight pen
  186. g.pen = (pen_hlight);
  187. for (total_value_space=0, height = yB + base+3; height < m_thumb_pos_y + m_thumb_size - 8; height+=4, total_value_space++) {
  188. g.drawLine(new_x, height, new_r, height);
  189. }
  190. for (height = yB-2; total_value_space > 0; height-=4, total_value_space--) {
  191. g.drawLine(new_x, height, new_r, height);
  192. }
  193. if (m_whatishovered == 3) {
  194. g.brush = (brsh_hlight);
  195. g.drawRect(xH, yB, base, base);
  196. pen.setColor(m_clrnormal);
  197. }
  198. else {
  199. pen.setColor(m_clrnormal);
  200. g.brush = (brsh);
  201. g.pen = (pen);
  202. g.drawRect(xH, yB, base, base);
  203. }
  204. }
  205. else if(m_thumb_size > 15) {
  206. yB = m_thumb_pos_y + ((m_thumb_size - base) / 2);
  207. if (m_whatishovered == 3) {
  208. g.brush = (brsh_hlight);
  209. g.pen = (pen_hlight);
  210. g.drawRect(xH, yB, base, base);
  211. pen.setColor(m_clrnormal);
  212. }
  213. else {
  214. pen.setColor(m_clrnormal);
  215. g.brush = (brsh);
  216. g.pen = (pen);
  217. g.drawRect(xH, yB, base, base);
  218. }
  219. }
  220. g.brush = (brsh);
  221. g.pen = (pen_hlight);
  222. new_x--;
  223. new_r++;
  224. //UP BUTTON
  225. if (m_isclicked == 1) {
  226. g.pen = (pen);
  227. g.drawLine(new_x, this.top+1, new_r, this.top+1);
  228. g.drawLine(new_x, this.top+1, new_x, this.top+this.width-1);
  229. g.pen = (pen_hlight);
  230. }
  231. else
  232. {
  233. g.drawLine(new_x, this.top+1, new_r, this.top+1);
  234. g.drawLine(new_x, this.top+1, new_x, this.top+this.width-1);
  235. }
  236. //DOWN BUTTON
  237. if (m_isclicked == 2) {
  238. g.pen = (pen);
  239. g.drawLine(new_x, this.bottom-this.width+1, new_r, this.bottom-this.width+1);
  240. g.drawLine(new_x, this.bottom-this.width+1, new_x, this.bottom-1);
  241. g.pen = (pen_hlight);
  242. }
  243. else {
  244. g.drawLine(new_x, this.bottom-this.width+1, new_r, this.bottom-this.width+1);
  245. g.drawLine(new_x, this.bottom-this.width+1, new_x, this.bottom-1);
  246. }
  247. //THUMB BAR
  248. if (m_isclicked == 3) {
  249. g.pen = (pen);
  250. g.drawLine(new_x, m_thumb_pos_y+1, new_r, m_thumb_pos_y+1);
  251. g.drawLine(new_x, m_thumb_pos_y+1, new_x, m_thumb_pos_b-1);
  252. g.pen = (pen_hlight);
  253. }
  254. else {
  255. g.drawLine(new_x, m_thumb_pos_y+1, new_r, m_thumb_pos_y+1);
  256. g.drawLine(new_x, m_thumb_pos_y+1, new_x, m_thumb_pos_b-1);
  257. }
  258. }
  259. override bool onMouseMove(ref Mouse mouseProps) {
  260. if (m_isclicked == 3) {
  261. //thumb bar is moving
  262. //move thumb bar and set value accordingly
  263. mouseProps.y -= m_thumb_offset;
  264. //y is now the y position of where the thumb would be now
  265. if (mouseProps.y < this.top + this.width) {
  266. mouseProps.y = this.top + this.width;
  267. }
  268. if (mouseProps.y > this.top + this.width + m_area) {
  269. mouseProps.y = this.top + this.width + m_area;
  270. }
  271. //compute value
  272. long old_value = m_value;
  273. m_value = ( cast(int) ( ( cast(float)(mouseProps.y - this.top-this.width) / cast(float)(m_area) ) * cast(float)(m_max - m_min) ) ) + m_min;
  274. if (m_value != old_value) {
  275. raiseSignal(Signal.Scrolled);
  276. return true;
  277. } else {
  278. return false;
  279. }
  280. }
  281. //check if something is being hovered over
  282. if (mouseProps.y > this.top && mouseProps.y < this.bottom && mouseProps.x > this.left && mouseProps.x < this.right) {
  283. if (mouseProps.y - this.top < this.width) {
  284. //up button
  285. if (m_isclicked == 0 || m_isclicked == 1) {
  286. if (m_whatishovered != 1) {
  287. m_whatishovered = 1;
  288. return true;
  289. }
  290. }
  291. return false;
  292. }
  293. else if (mouseProps.y > this.bottom - this.width) {
  294. //down button
  295. if (m_isclicked == 0 || m_isclicked == 2) {
  296. if (m_whatishovered != 2) {
  297. m_whatishovered = 2;
  298. return true;
  299. }
  300. }
  301. return false;
  302. }
  303. else if (mouseProps.y > m_thumb_pos_y && mouseProps.y < m_thumb_pos_b) {
  304. //thumb bar
  305. if (m_isclicked == 0 || m_isclicked == 3) {
  306. if (m_whatishovered != 3) {
  307. m_whatishovered = 3;
  308. return true;
  309. }
  310. }
  311. return false;
  312. }
  313. else if (mouseProps.y < m_thumb_pos_y) {
  314. // inner area UP
  315. m_last_x = mouseProps.x;
  316. m_last_y = mouseProps.y;
  317. if (m_isclicked == 0 || m_isclicked == 4) {
  318. if (m_whatishovered != 4) {
  319. if (m_whatishovered != 0) {
  320. m_whatishovered = 4;
  321. return true;
  322. }
  323. m_whatishovered = 4;
  324. }
  325. }
  326. return false;
  327. }
  328. else {
  329. //inner area DOWN
  330. m_last_x = mouseProps.x;
  331. m_last_y = mouseProps.y;
  332. if (m_isclicked == 0 || m_isclicked == 5) {
  333. if (m_whatishovered != 5) {
  334. if (m_whatishovered != 0) {
  335. m_whatishovered = 5;
  336. return true;
  337. }
  338. m_whatishovered = 5;
  339. }
  340. }
  341. return false;
  342. }
  343. }
  344. //nothing
  345. if (m_whatishovered != 0) {
  346. m_whatishovered = 0;
  347. return true;
  348. }
  349. return false;
  350. }
  351. override bool onMouseLeave() {
  352. if (m_isclicked == 3) {
  353. return false;
  354. }
  355. if (m_whatishovered != 0) {
  356. m_whatishovered = 0;
  357. return true;
  358. }
  359. return false;
  360. }
  361. override bool onPrimaryMouseDown(ref Mouse mouseProps) {
  362. if (m_whatishovered != 0) {
  363. m_isclicked = m_whatishovered;
  364. requestCapture();
  365. if (m_isclicked == 3) {
  366. //thumb bar clicked
  367. //the number of pixels from the left edge of thumb bar is mouse = m_thumb_offset
  368. m_thumb_offset = mouseProps.y - m_thumb_pos_y;
  369. }
  370. else {
  371. //buttons / inner area clicked
  372. //stop timers if running
  373. _clickTimer.stop();
  374. _readyTimer.stop();
  375. _Move();
  376. _readyTimer.start();
  377. }
  378. return true;
  379. }
  380. return false;
  381. }
  382. override bool onPrimaryMouseUp(ref Mouse mouseProps) {
  383. if (m_isclicked > 0) {
  384. if (m_isclicked == 3) {
  385. m_isclicked = 0;
  386. onMouseMove(mouseProps);
  387. }
  388. requestRelease();
  389. _clickTimer.stop();
  390. _readyTimer.stop();
  391. m_isclicked = 0;
  392. return true;
  393. }
  394. return false;
  395. }
  396. protected:
  397. void readyTimerProc() {
  398. //create real timer
  399. _readyTimer.stop();
  400. _clickTimer.start();
  401. _window.redraw();
  402. }
  403. void clickTimerProc() {
  404. _Move();
  405. _window.redraw();
  406. }
  407. void _Move() {
  408. float percent;
  409. //look at what is currently being hovered over
  410. switch (m_whatishovered) {
  411. case 1: //left button
  412. m_value -= m_small_change;
  413. if (m_value<m_min) { m_value = m_min; }
  414. raiseSignal(Signal.Scrolled);
  415. break;
  416. case 2: //right button
  417. m_value += m_small_change;
  418. if (m_value>m_max) { m_value = m_max; }
  419. raiseSignal(Signal.Scrolled);
  420. break;
  421. case 4: //inner area UP
  422. m_value -= m_large_change;
  423. if (m_value<m_min) { m_value = m_min; }
  424. //must check to see if we are hovering over the thumb bar
  425. percent = cast(float)m_large_change / cast(float)(m_large_change + (m_max - m_min));
  426. m_area = (this.height - (this.width*2))+2;
  427. m_thumb_size = cast(int)(cast(float)m_area * percent);
  428. if (m_thumb_size < 10) { m_thumb_size = 10; }
  429. m_area -= m_thumb_size;
  430. percent = cast(float)(m_value - m_min) / cast(float)(m_max - m_min);
  431. m_thumb_pos_y = cast(int)(cast(float)m_area * percent) + this.top + this.width-1;
  432. m_thumb_pos_b = m_thumb_pos_y + m_thumb_size;
  433. //compare last mouse coords with this state
  434. if (m_last_y > m_thumb_pos_y && m_last_y < m_thumb_pos_b) {
  435. //hmm
  436. //stop: we are hovering the thumb bar
  437. m_whatishovered = 3;
  438. _clickTimer.stop();
  439. }
  440. raiseSignal(Signal.Scrolled);
  441. break;
  442. case 5: //inner area DOWN
  443. m_value += m_large_change;
  444. if (m_value>m_max) { m_value = m_max; }
  445. //must check to see if we are hovering over the thumb bar
  446. percent = cast(float)m_large_change / cast(float)(m_large_change + (m_max - m_min));
  447. m_area = (this.height - (this.width*2))+2;
  448. m_thumb_size = cast(int)(cast(float)m_area * percent);
  449. if (m_thumb_size < 10) { m_thumb_size = 10; }
  450. m_area -= m_thumb_size;
  451. percent = cast(float)(m_value - m_min) / cast(float)(m_max - m_min);
  452. m_thumb_pos_y = cast(int)(cast(float)m_area * percent) + this.top + this.width-1;
  453. m_thumb_pos_b = m_thumb_pos_y + m_thumb_size;
  454. //compare last mouse coords with this state
  455. if (m_last_y >= m_thumb_pos_y && m_last_y <= m_thumb_pos_b) {
  456. //hmm
  457. //stop: we are hovering the thumb bar
  458. m_whatishovered = 3;
  459. _clickTimer.stop();
  460. }
  461. raiseSignal(Signal.Scrolled);
  462. break;
  463. default:
  464. break;
  465. }
  466. }
  467. Color m_clroutline;
  468. Color m_clrarea;
  469. Color m_clrbutton;
  470. Color m_clrthumb;
  471. Color m_clrhighlight;
  472. Color m_clrhover;
  473. Color m_clrnormal;
  474. int m_thumb_pos_y; //y (top) coord
  475. int m_thumb_pos_b; //b (bottom) coord
  476. int m_thumb_size;
  477. int m_area;
  478. Timer _clickTimer;
  479. Timer _readyTimer;
  480. int m_whatishovered;
  481. int m_isclicked;
  482. int m_thumb_offset;
  483. int m_last_x;
  484. int m_last_y;
  485. long m_min=0;
  486. long m_max=30;
  487. long m_value=0;
  488. long m_large_change=5;
  489. long m_small_change=1;
  490. }