PageRenderTime 44ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/CS/migrated/branches/R0_90/libs/csws/csscrbar.cpp

#
C++ | 458 lines | 390 code | 33 blank | 35 comment | 117 complexity | a0f363cf89bb46344a6f8422767913a4 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, LGPL-2.0
  1. /*
  2. Crystal Space Windowing System: scroll bar class
  3. Copyright (C) 1998,1999 by Andrew Zabolotny <bit@eltech.ru>
  4. This library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Library General Public
  6. License as published by the Free Software Foundation; either
  7. version 2 of the License, or (at your option) any later version.
  8. This library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Library General Public License for more details.
  12. You should have received a copy of the GNU Library General Public
  13. License along with this library; if not, write to the Free
  14. Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. */
  16. #include "cssysdef.h"
  17. #include "csws/csscrbar.h"
  18. #include "csws/csapp.h"
  19. // Minimal scroll button size
  20. #define CSSB_MINIMAL_KNOBSIZE (3+3+8)
  21. /// Minimal scroll bar size
  22. #define CSSB_MINIMAL_SIZE (2+2+7)
  23. // Scrolling state
  24. #define SCROLL_UL 1001 // scroll up or left (h/v scrollbars)
  25. #define SCROLL_DR 1002 // scroll down or right
  26. #define SCROLL_PAGE_UL 1003 // scroll up or left by pages
  27. #define SCROLL_PAGE_DR 1004 // scroll down or right by pages
  28. // Period of time to wait before scroll autorepeat
  29. #define SCROLL_START_INTERVAL 500
  30. // Scroll time interval in milliseconds
  31. #define SCROLL_REPEAT_INTERVAL 100
  32. #define SCROLLBAR_TEXTURE_NAME "csws::ScrollBar"
  33. csPixmap *csScrollBar::sprarrows[12] =
  34. { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
  35. csPixmap *csScrollBar::sprscroller[2] =
  36. { NULL, NULL };
  37. static int scrbarref = 0;
  38. csScrollBar::csScrollBar (csComponent *iParent, csScrollBarFrameStyle iFrameStyle)
  39. : csComponent (iParent)
  40. {
  41. active_button = status.value = status.maxvalue = status.size = status.maxsize
  42. = status.step = status.pagestep = 0;
  43. scrbarref++;
  44. if (app && !sprscroller[0])
  45. {
  46. // Load arrow and scroller images
  47. iTextureHandle *scrolltex = app->GetTexture (SCROLLBAR_TEXTURE_NAME);
  48. int i;
  49. for (i = 0; i < 12; i++)
  50. sprarrows [i] = new csSimplePixmap (scrolltex, i * 9, 0, 9, 9);
  51. sprscroller [0] = new csSimplePixmap (scrolltex, 12 * 9 + 0, 0, 7, 8);
  52. sprscroller [1] = new csSimplePixmap (scrolltex, 12 * 9 + 7, 0, 8, 7);
  53. } /* endif */
  54. TrackScroller = false;
  55. FrameStyle = iFrameStyle;
  56. SetPalette (CSPAL_SCROLLBAR);
  57. // create both scroll buttons
  58. csButtonFrameStyle bfs = (FrameStyle == cssfsThickRect ? csbfsThickRect : csbfsThinRect);
  59. const int bs = CSBS_NOMOUSEFOCUS | CSBS_NODEFAULTBORDER;
  60. scroller = new csButton (this, cscmdNothing, bs, bfs);
  61. topleft = new csButton (this, cscmdNothing, bs, bfs);
  62. topleft->id = SCROLL_UL;
  63. botright = new csButton (this, cscmdNothing, bs, bfs);
  64. botright->id = SCROLL_DR;
  65. // create repeat timer
  66. timer = new csTicksr (this, SCROLL_REPEAT_INTERVAL);
  67. ApplySkin (GetSkin ());
  68. }
  69. csScrollBar::~csScrollBar ()
  70. {
  71. if (--scrbarref == 0)
  72. {
  73. int i;
  74. for (i = 0; i < 12; i++)
  75. {
  76. delete sprarrows [i];
  77. sprarrows [i] = NULL;
  78. } /* endfor */
  79. delete sprscroller [0]; sprscroller[0] = NULL;
  80. delete sprscroller [1]; sprscroller[1] = NULL;
  81. } /* endif */
  82. }
  83. bool csScrollBar::HandleEvent (iEvent &Event)
  84. {
  85. switch (Event.Type)
  86. {
  87. case csevMouseMove:
  88. // track mouse motion when scroller button is pressed
  89. if (TrackScroller)
  90. {
  91. int x = Event.Mouse.x - scroller->bound.xmin;
  92. int y = Event.Mouse.y - scroller->bound.ymin;
  93. if ((x != scrollerdx)
  94. || (y != scrollerdy))
  95. {
  96. int delta = (IsHorizontal ? x - scrollerdx : y - scrollerdy)
  97. * status.maxvalue / activepixlen;
  98. SetValue (status.value + delta);
  99. } /* endif */
  100. return true;
  101. } /* endif */
  102. if (app->MouseOwner == this)
  103. {
  104. if (!bound.ContainsRel (Event.Mouse.x, Event.Mouse.y))
  105. {
  106. active_button = 0;
  107. Invalidate ();
  108. } else if (active_button == 0)
  109. goto pagescroll;
  110. return true;
  111. } /* endif */
  112. break;
  113. case csevMouseDown:
  114. if (GetState (CSS_DISABLED))
  115. return true;
  116. if (csComponent::HandleEvent (Event))
  117. {
  118. // Switch mouse owner to us if scroller captured it
  119. if (app->MouseOwner == scroller)
  120. {
  121. app->CaptureMouse (this);
  122. TrackScroller = true;
  123. } /* endif */
  124. return true;
  125. } /* endif */
  126. if ((Event.Mouse.Button == 1)
  127. && bound.ContainsRel (Event.Mouse.x, Event.Mouse.y)
  128. && (status.maxvalue > 0))
  129. {
  130. pagescroll:
  131. int cmp;
  132. if (scroller->bound.IsEmpty ())
  133. if (IsHorizontal)
  134. cmp = bound.Width () / 2;
  135. else
  136. cmp = bound.Height () / 2;
  137. else
  138. if (IsHorizontal)
  139. cmp = scroller->bound.xmin;
  140. else
  141. cmp = scroller->bound.ymin;
  142. if ((IsHorizontal ? Event.Mouse.x : Event.Mouse.y) <= cmp)
  143. active_button = SCROLL_PAGE_UL;
  144. else
  145. active_button = SCROLL_PAGE_DR;
  146. Invalidate ();
  147. if (app->MouseOwner != this)
  148. app->CaptureMouse (this);
  149. // Emulate timeout
  150. timer->Pause (SCROLL_START_INTERVAL);
  151. SendCommand (cscmdTimerPulse, timer);
  152. return true;
  153. } else
  154. {
  155. active_button = 0;
  156. Invalidate ();
  157. } /* endif */
  158. return true;
  159. case csevMouseUp:
  160. if (Event.Mouse.Button == 1)
  161. {
  162. if (TrackScroller)
  163. {
  164. app->CaptureMouse (scroller);
  165. TrackScroller = false;
  166. return scroller->HandleEvent (Event);
  167. } /* endif */
  168. if (app->MouseOwner == this)
  169. {
  170. app->CaptureMouse (NULL);
  171. active_button = 0;
  172. Invalidate ();
  173. } /* endif */
  174. } /* endif */
  175. break;
  176. case csevCommand:
  177. switch (Event.Command.Code)
  178. {
  179. case cscmdButtonUp:
  180. active_button = 0;
  181. Invalidate ();
  182. return true;
  183. case cscmdButtonDown:
  184. if (Event.Command.Info == scroller)
  185. {
  186. scroller->GetMousePosition (scrollerdx, scrollerdy);
  187. return true;
  188. } /* endif */
  189. active_button = ((csComponent *)Event.Command.Info)->id;
  190. timer->Pause (SCROLL_START_INTERVAL);
  191. // fallback to timer pulse
  192. goto pulse;
  193. case cscmdTimerPulse:
  194. if (Event.Command.Info == timer)
  195. {
  196. pulse: if (active_button == SCROLL_UL)
  197. SetValue (status.value - status.step);
  198. else if (active_button == SCROLL_DR)
  199. SetValue (status.value + status.step);
  200. else if (active_button == SCROLL_PAGE_UL)
  201. SetValue (status.value - status.pagestep);
  202. else if (active_button == SCROLL_PAGE_DR)
  203. SetValue (status.value + status.pagestep);
  204. return true;
  205. }
  206. break;
  207. case cscmdScrollBarSet:
  208. {
  209. status = *((csScrollBarStatus *)Event.Command.Info);
  210. if (status.size > status.maxsize)
  211. status.size = status.maxsize;
  212. int oldvalue = status.value;
  213. status.value = -1;
  214. SetValue (oldvalue);
  215. Event.Command.Info = NULL;
  216. return true;
  217. }
  218. case cscmdScrollBarGetStatus:
  219. *((csScrollBarStatus *)Event.Command.Info) = status;
  220. Event.Command.Info = NULL;
  221. return true;
  222. case cscmdScrollBarQueryValue:
  223. Event.Command.Info = (void *)status.value;
  224. return true;
  225. case cscmdScrollBarSetValue:
  226. SetValue (int (Event.Command.Info));
  227. return true;
  228. } /* endswitch */
  229. break;
  230. case csevKeyDown:
  231. switch (Event.Key.Code)
  232. {
  233. case CSKEY_UP:
  234. case CSKEY_LEFT:
  235. case CSKEY_DOWN:
  236. case CSKEY_RIGHT:
  237. if (Event.Key.Modifiers & (CSMASK_ALT | CSMASK_SHIFT))
  238. break;
  239. if (IsHorizontal != ((Event.Key.Code == CSKEY_LEFT) || (Event.Key.Code == CSKEY_RIGHT)))
  240. break;
  241. if (!app->MouseOwner)
  242. {
  243. if (!app->KeyboardOwner)
  244. app->CaptureKeyboard (this);
  245. int delta = (Event.Key.Code == CSKEY_UP) || (Event.Key.Code == CSKEY_LEFT) ? -1 : +1;
  246. delta *= (Event.Key.Modifiers & CSMASK_CTRL) ? status.pagestep : status.step;
  247. SetValue (status.value + delta);
  248. } /* endif */
  249. return true;
  250. } /* endswitch */
  251. case csevKeyUp:
  252. switch (Event.Key.Code)
  253. {
  254. case CSKEY_UP:
  255. case CSKEY_LEFT:
  256. case CSKEY_DOWN:
  257. case CSKEY_RIGHT:
  258. if (IsHorizontal != ((Event.Key.Code == CSKEY_LEFT) || (Event.Key.Code == CSKEY_RIGHT)))
  259. break;
  260. if (app->KeyboardOwner == this)
  261. app->CaptureKeyboard (NULL);
  262. return true;
  263. } /* endswitch */
  264. } /* endswitch */
  265. return csComponent::HandleEvent (Event);
  266. }
  267. bool csScrollBar::SetRect (int xmin, int ymin, int xmax, int ymax)
  268. {
  269. if (csComponent::SetRect (xmin, ymin, xmax, ymax))
  270. {
  271. int w = bound.Width ();
  272. int h = bound.Height ();
  273. if (w > h)
  274. {
  275. // horizontal scroll bar
  276. IsHorizontal = true;
  277. if ((w / 2 < h) || (h < CSSB_MINIMAL_SIZE))
  278. {
  279. // make buttons invisible
  280. if (topleft)
  281. topleft->SetRect (0, 0, -1, h);
  282. if (botright)
  283. botright->SetRect (w, 0, w, h);
  284. } else
  285. {
  286. if (topleft)
  287. topleft->SetRect (0, 0, h, h);
  288. if (botright)
  289. botright->SetRect (w - h, 0, w, h);
  290. } /* endif */
  291. } else
  292. {
  293. // vertical scroll bar
  294. IsHorizontal = false;
  295. if ((h / 2 < w) || (w < CSSB_MINIMAL_SIZE))
  296. {
  297. // make buttons invisible
  298. if (topleft)
  299. topleft->SetRect (0, 0, w, -1);
  300. if (botright)
  301. botright->SetRect (0, h, w, h);
  302. } else
  303. {
  304. if (topleft)
  305. topleft->SetRect (0, 0, w, w);
  306. if (botright)
  307. botright->SetRect (0, h - w, w, h);
  308. } /* endif */
  309. } /* endif */
  310. SetValue (status.value);
  311. return true;
  312. } else
  313. return false;
  314. }
  315. void csScrollBar::SetValue (int iValue)
  316. {
  317. if (iValue < 0)
  318. iValue = 0;
  319. if (iValue > status.maxvalue)
  320. iValue = status.maxvalue;
  321. if (status.value == iValue)
  322. return;
  323. status.value = iValue;
  324. bool disable = GetState (CSS_DISABLED);
  325. scroller->SetState (CSS_DISABLED, disable);
  326. if (disable || (status.maxvalue <= 0))
  327. {
  328. noscrollbut:
  329. if (IsHorizontal)
  330. scroller->SetRect (bound.Width () / 2, 0, bound.Width () / 2, -1);
  331. else
  332. scroller->SetRect (0, bound.Height () / 2, -1, bound.Height () / 2);
  333. }
  334. else
  335. {
  336. int pixmin, pixmax;
  337. if (IsHorizontal)
  338. {
  339. pixmin = topleft->bound.xmax;
  340. pixmax = botright->bound.xmin;
  341. } else
  342. {
  343. pixmin = topleft->bound.ymax;
  344. pixmax = botright->bound.ymin;
  345. } /* endif */
  346. activepixlen = pixmax - pixmin;
  347. if ((activepixlen + 2 < CSSB_MINIMAL_KNOBSIZE) || (status.maxsize <= 0))
  348. goto noscrollbut;
  349. int pixsize = (status.size * activepixlen) / status.maxsize;
  350. if (pixsize < CSSB_MINIMAL_KNOBSIZE)
  351. pixsize = CSSB_MINIMAL_KNOBSIZE;
  352. if (pixsize >= activepixlen)
  353. goto noscrollbut;
  354. pixmin += pixsize / 2;
  355. pixmax -= ((pixsize + 1) / 2);
  356. activepixlen = pixmax - pixmin;
  357. int spix = pixmin + (status.value * activepixlen) / status.maxvalue
  358. - pixsize / 2;
  359. int epix = spix + pixsize;
  360. if (IsHorizontal)
  361. scroller->SetRect (spix, 0, epix, bound.Height ());
  362. else
  363. scroller->SetRect (0, spix, bound.Width (), epix);
  364. } /* endif */
  365. // Set up arrows on scroll buttons
  366. if (IsHorizontal)
  367. {
  368. scroller->SetBitmap (sprscroller[1], NULL, false);
  369. if (disable || (status.maxvalue <= 0) || (status.value <= 0))
  370. {
  371. topleft->SetBitmap (sprarrows[8], NULL, false);
  372. topleft->SetState (CSS_DISABLED, true);
  373. } else
  374. {
  375. topleft->SetBitmap (sprarrows[6], sprarrows[10], false);
  376. topleft->SetState (CSS_DISABLED, false);
  377. } /* endif */
  378. if (disable || (status.maxvalue <= 0) || (status.value >= status.maxvalue))
  379. {
  380. botright->SetBitmap (sprarrows[9], NULL, false);
  381. botright->SetState (CSS_DISABLED, true);
  382. } else
  383. {
  384. botright->SetBitmap (sprarrows[7], sprarrows[11], false);
  385. botright->SetState (CSS_DISABLED, false);
  386. } /* endif */
  387. }
  388. else
  389. {
  390. scroller->SetBitmap (sprscroller[0], NULL, false);
  391. if (disable || (status.maxvalue <= 0) || (status.value <= 0))
  392. {
  393. topleft->SetBitmap (sprarrows[2], NULL, false);
  394. topleft->SetState (CSS_DISABLED, true);
  395. } else
  396. {
  397. topleft->SetBitmap (sprarrows[0], sprarrows[4], false);
  398. topleft->SetState (CSS_DISABLED, false);
  399. } /* endif */
  400. if (disable || (status.maxvalue <= 0) || (status.value >= status.maxvalue))
  401. {
  402. botright->SetBitmap (sprarrows[3], NULL, false);
  403. botright->SetState (CSS_DISABLED, true);
  404. } else
  405. {
  406. botright->SetBitmap (sprarrows[1], sprarrows[5], false);
  407. botright->SetState (CSS_DISABLED, false);
  408. } /* endif */
  409. } /* endif */
  410. if (parent)
  411. parent->SendCommand (cscmdScrollBarValueChanged, (void *)this);
  412. }
  413. void csScrollBar::SetState (int mask, bool enable)
  414. {
  415. int oldstate = state;
  416. csComponent::SetState (mask, enable);
  417. if ((oldstate ^ state) & CSS_DISABLED)
  418. {
  419. int oldval = status.value--;
  420. SetValue (oldval);
  421. }
  422. }