OSCROLL.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  1. /*
  2. * Seven Kingdoms: Ancient Adversaries
  3. *
  4. * Copyright 1997,1998 Enlight Software Ltd.
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. *
  19. */
  20. //Filename : OSCROLL.CPP
  21. //Description : Object scroll bar
  22. #include <ALL.h>
  23. #include <KEY.h>
  24. #include <OSYS.h>
  25. #include <OMOUSE.h>
  26. #include <OVGA.h>
  27. #include <OINFO.h>
  28. #include <OIMGRES.h>
  29. #include <OSCROLL.h>
  30. //------- Define constant -----------//
  31. #define PRESS_INT_TIME 200 // Press interval time, prevent too fast
  32. // and uncontrollable scrolling, 200ms
  33. #define MINI_INDICATOR_HEIGHT 10 // Minimum height of scroll bar indicator
  34. //------ Begin of function ScrollBar::init -------//
  35. //
  36. // <int> type = 1-Vertical scroll bar (VERTICAL)
  37. // 2-Horizontal scroll bar (HORIZONTAL)
  38. //
  39. // <int> x1,y1,x2,y2 = the coordination of the scroll bar
  40. //
  41. // <int> pageSkipRec = no. of records when page skip up or down
  42. // <int> dispMaxRec = no. of records can be displayed on a page
  43. // <int> totalRec = total no. of records
  44. // [int] pageType = yes or no, refered when down button is pressed
  45. // (default : 1)
  46. // [int] ifFlag = if call vga.d3_panel_down instead of VgaBuf::d3_panel_down
  47. // (default: 0)
  48. // [int] vgaFrontOnly = do all the bitmap processing on the front buffer only
  49. // (default: 0)
  50. void ScrollBar::init(int itype, int ix1, int iy1, int ix2, int iy2,
  51. int pageSkipRec, int dispMaxRec, int totalRec, int pageType, int ifFlag, int vgaFrontOnly)
  52. {
  53. x1 = ix1;
  54. y1 = iy1;
  55. x2 = ix2;
  56. y2 = iy2;
  57. type = itype;
  58. skip_rec_num = pageSkipRec;
  59. disp_rec_num = dispMaxRec;
  60. total_rec_num = totalRec;
  61. page_type = pageType;
  62. if_flag = ifFlag;
  63. vga_front_only = vgaFrontOnly;
  64. if( total_rec_num==0 ) // at must at least be 1, otherwise divided by zero error will appear
  65. total_rec_num=1;
  66. if( type == VERTICAL )
  67. slot_height = y2-y1-28;
  68. else
  69. slot_height = x2-x1-28;
  70. indicator_height = slot_height * disp_rec_num / total_rec_num;
  71. if( indicator_height < MINI_INDICATOR_HEIGHT )
  72. indicator_height = MINI_INDICATOR_HEIGHT;
  73. next_press_time = 0;
  74. }
  75. //------- End of function ScrollBar::init -------//
  76. //------- Begin of function ScrollBar::paint -------//
  77. //
  78. // [int] topRecNo = the top record no. (default : 1)
  79. //
  80. void ScrollBar::paint(int topRecNo)
  81. {
  82. err_when( type == -1 ); // haven't been init()
  83. if( if_flag )
  84. {
  85. vga.d3_panel_down( x1, y1, x2, y2, vga_front_only ); // scroll panel
  86. //-------- cursor button --------//
  87. if( type == VERTICAL )
  88. {
  89. vga.d3_panel_up( x1+2, y1+2 , x2-2, y1+13, vga_front_only); // up button
  90. vga.d3_panel_up( x1+2, y2-13, x2-2, y2-2 , vga_front_only); // down button
  91. }
  92. else
  93. {
  94. vga.d3_panel_up( x1+2 , y1+2, x1+13, y2-2, vga_front_only); // left button
  95. vga.d3_panel_up( x2-13, y1+2, x2-2, y2-2 , vga_front_only); // right button
  96. }
  97. }
  98. else
  99. {
  100. Vga::active_buf->d3_panel_down( x1, y1, x2, y2 ); // scroll panel
  101. //-------- cursor button --------//
  102. if( type == VERTICAL )
  103. {
  104. Vga::active_buf->d3_panel_up( x1+2, y1+2 , x2-2, y1+13); // up button
  105. Vga::active_buf->d3_panel_up( x1+2, y2-13, x2-2, y2-2 ); // down button
  106. }
  107. else
  108. {
  109. Vga::active_buf->d3_panel_up( x1+2 , y1+2, x1+13, y2-2); // left button
  110. Vga::active_buf->d3_panel_up( x2-13, y1+2, x2-2, y2-2 ); // right button
  111. }
  112. }
  113. //--------- display cursor bitmap ----------//
  114. if( type == VERTICAL )
  115. {
  116. image_icon.put_front( x1+4, y1+4 , "SCROLL_U" );
  117. image_icon.put_front( x1+4, y2-11, "SCROLL_D" );
  118. }
  119. else
  120. {
  121. image_icon.put_front( x1+4 , y1+4, "SCROLL_L" );
  122. image_icon.put_front( x2-11, y1+4, "SCROLL_R" );
  123. }
  124. }
  125. //--------- End of function ScrollBar::paint ------------//
  126. //------- Begin of function ScrollBar::refresh -------//
  127. //
  128. // <int> topRecNo = the new top record no.
  129. // [int] forceRefresh = in normal case, only refresh when new top record
  130. // no. <> current top record no.
  131. // but forceRefresh will force refreshing anyway
  132. // ( default : 0)
  133. //
  134. // [int] pageSkipRec = no. of records when page skip up or down
  135. // [int] dispMaxRec = no. of records can be displayed on a page
  136. // [int] totalRec = total no. of records
  137. // ( default: no change for the above 3 parameters )
  138. //
  139. void ScrollBar::refresh(int topRecNo, int forceRefresh, int pageSkipRec, int dispMaxRec, int totalRec)
  140. {
  141. int oldTotalRec = total_rec_num;
  142. err_when( type == -1 ); // haven't been init()
  143. if( pageSkipRec >= 0 )
  144. skip_rec_num = pageSkipRec;
  145. if( dispMaxRec >= 0 )
  146. disp_rec_num = dispMaxRec;
  147. if( totalRec >= 0 )
  148. total_rec_num = totalRec;
  149. if( total_rec_num==0 ) // at must at least be 1, otherwise divided by zero error will appear
  150. total_rec_num=1;
  151. if( type == VERTICAL )
  152. slot_height = y2-y1-28;
  153. else
  154. slot_height = x2-x1-28;
  155. indicator_height = slot_height * disp_rec_num / total_rec_num;
  156. if( indicator_height < MINI_INDICATOR_HEIGHT )
  157. indicator_height = MINI_INDICATOR_HEIGHT;
  158. //------------- refresh display ----------------//
  159. int newY;
  160. if( (newY=rec_to_y(topRecNo)) != indicator_y ||
  161. total_rec_num != oldTotalRec || forceRefresh )
  162. {
  163. indicator_y = newY;
  164. if( if_flag )
  165. {
  166. if( type == VERTICAL )
  167. {
  168. if( !vga.use_back_buf && !vga_front_only )
  169. vga.blt_buf( x1, y1+12, x2, y2-13, 0 );
  170. Vga::active_buf->draw_d3_up_border( x1+2, indicator_y, x2-2, indicator_y+indicator_height-1 );
  171. }
  172. else
  173. {
  174. if( !vga.use_back_buf && !vga_front_only )
  175. vga.blt_buf( x1+12, y1, x2-13, y2, 0 );
  176. Vga::active_buf->draw_d3_up_border( indicator_y, y1+2, indicator_y+indicator_height-1, y2-2 );
  177. }
  178. }
  179. else
  180. {
  181. if( type == VERTICAL )
  182. {
  183. Vga::active_buf->d3_panel_down_clear( x1, y1+12, x2, y2-13 );
  184. Vga::active_buf->d3_panel_up( x1+2, indicator_y, x2-2, indicator_y+indicator_height-1 );
  185. }
  186. else
  187. {
  188. Vga::active_buf->d3_panel_down_clear( x1+12, y1, x2-13, y2 );
  189. Vga::active_buf->d3_panel_up( indicator_y, y1+2, indicator_y+indicator_height-1, y2-2 );
  190. }
  191. }
  192. top_rec_no = topRecNo;
  193. }
  194. }
  195. //--------- End of function ScrollBar::refresh ------------//
  196. //------- Begin of function ScrollBar::detect -------//
  197. //
  198. // Return : =0 if not pressed on scroll bar
  199. // >0 the top record no.
  200. //
  201. int ScrollBar::detect()
  202. {
  203. int pos, topRecNo=top_rec_no;
  204. top_rec_flag = 1; // whether the recno returned by detect()
  205. // is the top_recno or only current recno, is returned by detect_is_top()
  206. //----------- detect for pressing up button --------------//
  207. if( type==VERTICAL && mouse.any_click( x1+2, y1+2, x2-2 , y1+13 ) ||
  208. type==HORIZONTAL && mouse.any_click( x1+2, y1+2, x1+13, y2-2 ) )
  209. {
  210. if( --topRecNo < 1 )
  211. topRecNo = 1;
  212. top_rec_flag=0; // return by detect_is_top()
  213. }
  214. //----------- detect for pressing down button ------------//
  215. if( type==VERTICAL && mouse.any_click( x1+2, y2-13, x2-2, y2-2 ) ||
  216. type==HORIZONTAL && mouse.any_click( x2-13,y1+2 , x2-2, y2-2 ) )
  217. {
  218. if( page_type ) // top record can't be the last record
  219. {
  220. if( ++topRecNo > total_rec_num - disp_rec_num+1 )
  221. topRecNo = total_rec_num - disp_rec_num + 1;
  222. }
  223. else // top record can be the last record
  224. {
  225. if( ++topRecNo > total_rec_num )
  226. topRecNo = total_rec_num;
  227. }
  228. top_rec_flag=0;
  229. }
  230. //------ detect for pressing on scroll slot but not indicator -------//
  231. if( type==VERTICAL && mouse.any_click( x1+2 , y1+14, x2-2 , y2-14 ) ||
  232. type==HORIZONTAL && mouse.any_click( x1+14, y1+2 , x2-14, y2-2 ) ||
  233. mouse.key_code == KEY_PGUP || mouse.key_code == KEY_PGDN )
  234. {
  235. if( type==VERTICAL )
  236. pos = mouse.click_y();
  237. else
  238. pos = mouse.click_x();
  239. if( pos < indicator_y || mouse.key_code == KEY_PGUP ) // page up
  240. {
  241. if( ( topRecNo -= skip_rec_num ) < 1 )
  242. topRecNo = 1;
  243. }
  244. else if( pos >= indicator_y+indicator_height || mouse.key_code == KEY_PGDN ) // page down
  245. {
  246. if( (topRecNo += skip_rec_num) > total_rec_num - disp_rec_num+1 )
  247. {
  248. topRecNo = total_rec_num - disp_rec_num + 1;
  249. if ( topRecNo < 1 )
  250. topRecNo = 1;
  251. }
  252. }
  253. }
  254. //--------- check if display all needed -----------//
  255. if( topRecNo != top_rec_no )
  256. {
  257. if( m.get_time() >= next_press_time ) // prevent too fast scrolling
  258. {
  259. refresh(topRecNo,1);
  260. next_press_time = m.get_time() + PRESS_INT_TIME;
  261. return topRecNo;
  262. }
  263. }
  264. //-------- detect for pulling indicator ------------//
  265. if( type==VERTICAL && mouse.any_click( x1+2 , indicator_y, x2-2, indicator_y+indicator_height-1 ) ||
  266. type==HORIZONTAL && mouse.any_click( indicator_y, y1+2, indicator_y+indicator_height-1, y2-2 ) )
  267. {
  268. int lastMouseY = -1;
  269. while( mouse.left_press )
  270. {
  271. sys.yield();
  272. if( type==VERTICAL )
  273. {
  274. if( mouse.left_press && lastMouseY != mouse.cur_y )
  275. {
  276. indicator_y = mouse.cur_y-indicator_height/2;
  277. if( indicator_y < y1+14 )
  278. indicator_y = y1+14;
  279. if( indicator_y > y2-14-indicator_height )
  280. indicator_y = y2-14-indicator_height;
  281. if( if_flag )
  282. {
  283. if( !vga.use_back_buf && !vga_front_only )
  284. vga.blt_buf( x1, y1+12, x2, y2-13, 0 );
  285. Vga::active_buf->draw_d3_up_border( x1+2, indicator_y, x2-2, indicator_y+indicator_height-1 );
  286. }
  287. else
  288. {
  289. Vga::active_buf->d3_panel_down_clear( x1, y1+12, x2, y2-13 ); // scroll panel
  290. Vga::active_buf->d3_panel_down( x1+2, indicator_y, x2-2, indicator_y+indicator_height-1 );
  291. }
  292. lastMouseY = mouse.cur_y;
  293. }
  294. }
  295. else
  296. {
  297. if( mouse.left_press && lastMouseY != mouse.cur_x )
  298. {
  299. indicator_y = mouse.cur_x-indicator_height/2;
  300. if( indicator_y < x1+14 )
  301. indicator_y = x1+14;
  302. if( indicator_y > x2-14-indicator_height )
  303. indicator_y = x2-14-indicator_height;
  304. if( if_flag )
  305. {
  306. if( !vga.use_back_buf && !vga_front_only )
  307. vga.blt_buf( x1+12, y1, x2-13, y2, 0 );
  308. Vga::active_buf->draw_d3_up_border( indicator_y, y1+2, indicator_y+indicator_height-1, y2-2 );
  309. }
  310. else
  311. {
  312. Vga::active_buf->d3_panel_down_clear( x1+12, y1, x2-13, y2 );
  313. Vga::active_buf->d3_panel_down ( indicator_y, y1+2, indicator_y+indicator_height-1, y2-2 );
  314. }
  315. lastMouseY = mouse.cur_x;
  316. }
  317. }
  318. }
  319. refresh(y_to_rec(indicator_y),1);
  320. return top_rec_no;
  321. }
  322. //-----------------------------------------------------------//
  323. return 0;
  324. }
  325. //--------- End of function ScrollBar::detect ------------//
  326. //--------- Begin of function ScrollBar::page_up -------//
  327. //
  328. // Asked by client function to page up
  329. //
  330. // [int] skipLess - no. of record number should skip less
  331. // (default : 0)
  332. // (e.g. when scrolling text, want the last line of
  333. // previous page be the first line of current page,
  334. // then pass 1 as skipLess)
  335. //
  336. // return : <int> the top recno after scrolling
  337. //
  338. int ScrollBar::page_up(int skipLess)
  339. {
  340. if( top_rec_no > 1 )
  341. {
  342. if( (top_rec_no-=skip_rec_num-skipLess) < 1 )
  343. top_rec_no = 1;
  344. refresh(top_rec_no,1);
  345. }
  346. return top_rec_no;
  347. }
  348. //--------- End of function ScrollBar::page_up ----------//
  349. //--------- Begin of function ScrollBar::page_down -------//
  350. //
  351. // Asked by client function to page up
  352. //
  353. // [int] skipLess - no. of record number should skip less
  354. // (default : 0)
  355. // (e.g. when scrolling text, want the last line of
  356. // previous page be the first line of current page,
  357. // then pass 1 as skipLess)
  358. //
  359. // return : <int> the top recno after scrolling
  360. //
  361. int ScrollBar::page_down(int skipLess)
  362. {
  363. if( top_rec_no < total_rec_num - disp_rec_num + 1 )
  364. {
  365. if( (top_rec_no += skip_rec_num-skipLess) > total_rec_num - disp_rec_num + 1 )
  366. {
  367. top_rec_no = total_rec_num - disp_rec_num + 1;
  368. if( top_rec_no < 1 )
  369. top_rec_no = 1;
  370. }
  371. refresh(top_rec_no,1);
  372. }
  373. return top_rec_no;
  374. }
  375. //--------- End of function ScrollBar::page_down ----------//
  376. //--------- Begin of function ScrollBar::detect_top_rec -------//
  377. //
  378. // return whether the recno returned by detect()
  379. // is the top_recno or only current recno
  380. //
  381. int ScrollBar::detect_top_rec()
  382. {
  383. if( top_rec_flag )
  384. {
  385. if( top_rec_no > total_rec_num - disp_rec_num+1 )
  386. return total_rec_num - disp_rec_num + 1;
  387. else
  388. return top_rec_no;
  389. }
  390. else
  391. return 0;
  392. }
  393. //--------- End of function ScrollBar::detect_top_rec ----------//
  394. //--------- Begin of function ScrollBar::rec_to_y -------//
  395. //
  396. // Convert from record no. to y position of scroll bar indicator
  397. //
  398. int ScrollBar::rec_to_y(int recNo)
  399. {
  400. int t;
  401. if( total_rec_num <= 1 || disp_rec_num == total_rec_num )
  402. t = 0;
  403. else
  404. {
  405. t = (slot_height-indicator_height) * (recNo-1) / (total_rec_num-disp_rec_num);
  406. if( t+indicator_height > slot_height )
  407. t = slot_height-indicator_height;
  408. }
  409. if( type == VERTICAL )
  410. return y1 + 14 + t;
  411. else
  412. return x1 + 14 + t;
  413. }
  414. //---------- End of function ScrollBar::rec_to_y ----------//
  415. //--------- Begin of function ScrollBar::y_to_rec -------//
  416. //
  417. // Convert from y position of scroll bar indicator to record no.
  418. //
  419. int ScrollBar::y_to_rec(int y)
  420. {
  421. int t;
  422. if( total_rec_num == 0 )
  423. return 0;
  424. if( slot_height-indicator_height == 0 || disp_rec_num == total_rec_num )
  425. return 1;
  426. if( type == VERTICAL )
  427. t = y1;
  428. else
  429. t = x1;
  430. return (y-t-14) * (total_rec_num-disp_rec_num) / (slot_height-indicator_height) + 1;
  431. }
  432. //---------- End of function ScrollBar::y_to_rec ----------//