listctrl.cpp 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Combat *
  23. * *
  24. * $Archive:: /Commando/Code/wwui/listctrl.cpp $*
  25. * *
  26. * Author:: Patrick Smith *
  27. * *
  28. * $Modtime:: 3/01/02 4:37p $*
  29. * *
  30. * $Revision:: 41 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "listctrl.h"
  36. #include "assetmgr.h"
  37. #include "refcount.h"
  38. #include "mousemgr.h"
  39. #include "ww3d.h"
  40. #include "dialogmgr.h"
  41. #include "dialogbase.h"
  42. #include "stylemgr.h"
  43. #include <commctrl.h>
  44. ////////////////////////////////////////////////////////////////
  45. // Local constants
  46. ////////////////////////////////////////////////////////////////
  47. const float PULSE_RATE = 2.0F;
  48. const int ROW_SPACING = 4;
  49. ////////////////////////////////////////////////////////////////
  50. //
  51. // ListCtrlClass
  52. //
  53. ////////////////////////////////////////////////////////////////
  54. ListCtrlClass::ListCtrlClass (void) :
  55. CurrState (NORMAL),
  56. ScrollPos (0),
  57. HeaderRect (0, 0, 0, 0),
  58. TextRect (0, 0, 0, 0),
  59. CurrSel (-1),
  60. RowBorderHeight (0),
  61. PulsePercent (1.0F),
  62. PulseDirection (1.0F),
  63. IsScrollBarDisplayed (false),
  64. LastPageTopEntryIndex (0),
  65. IsSelectionAllowed(true),
  66. IsNoSelectionAllowed(false),
  67. IsMultipleSelection (false),
  68. SortColumn (0),
  69. SortType (SORT_NONE),
  70. MinRowHeight (0)
  71. {
  72. //
  73. // Configure each renderer
  74. //
  75. StyleMgrClass::Configure_Renderer (&ControlRenderer);
  76. StyleMgrClass::Configure_Renderer (&UnderlineRenderer);
  77. StyleMgrClass::Configure_Renderer (&HilightRenderer);
  78. StyleMgrClass::Configure_Hilighter (&HilightRenderer);
  79. //
  80. // Set the font for each text renderer
  81. //
  82. StyleMgrClass::Assign_Font (&HeaderRenderer, StyleMgrClass::FONT_HEADER);
  83. StyleMgrClass::Assign_Font (&TextRenderer, StyleMgrClass::FONT_LISTS);
  84. TextRenderer.Set_Texture_Size_Hint (256);
  85. //
  86. // We don't want the scroll bar getting focus
  87. //
  88. ScrollBarCtrl.Set_Wants_Focus (false);
  89. ScrollBarCtrl.Set_Advise_Sink (this);
  90. ScrollBarCtrl.Set_Is_Embedded (true);
  91. return ;
  92. }
  93. ////////////////////////////////////////////////////////////////
  94. //
  95. // ~ListCtrlClass
  96. //
  97. ////////////////////////////////////////////////////////////////
  98. ListCtrlClass::~ListCtrlClass (void)
  99. {
  100. Delete_All_Entries ();
  101. if (Parent != NULL) {
  102. Parent->Remove_Control (&ScrollBarCtrl);
  103. }
  104. return ;
  105. }
  106. void ListCtrlClass::Set_Tabstop(float stop)
  107. {
  108. TextRenderer.Set_Tabstop(stop);
  109. }
  110. ////////////////////////////////////////////////////////////////
  111. //
  112. // Create_Control_Renderer
  113. //
  114. ////////////////////////////////////////////////////////////////
  115. void
  116. ListCtrlClass::Create_Control_Renderer (void)
  117. {
  118. Render2DClass &renderer = ControlRenderer;
  119. //
  120. // Configure this renderer
  121. //
  122. renderer.Reset ();
  123. renderer.Enable_Texturing (false);
  124. //
  125. // Determine which color to draw the outline in
  126. //
  127. int color = StyleMgrClass::Get_Line_Color ();
  128. int bkcolor = StyleMgrClass::Get_Bk_Color ();
  129. if (CurrState == DISABLED) {
  130. color = StyleMgrClass::Get_Disabled_Line_Color ();
  131. bkcolor = StyleMgrClass::Get_Disabled_Bk_Color ();
  132. }
  133. //
  134. // Draw the outline
  135. //
  136. renderer.Add_Rect (Rect, 1.0F, color, bkcolor);
  137. //
  138. // Draw the selection bar if necessary
  139. //
  140. if (CurrSel != -1) {
  141. //
  142. // Calculate what percentage our pulse effect is
  143. //
  144. PulsePercent += PulseDirection * PULSE_RATE * (DialogMgrClass::Get_Frame_Time () / 1000.0F);
  145. if (PulsePercent < 0 || PulsePercent > 1.0F) {
  146. PulseDirection = -PulseDirection;
  147. PulsePercent = WWMath::Clamp (PulsePercent, 0, 1);
  148. }
  149. //
  150. // If this control has the focus then apply our pulsating effect to
  151. // the color of selection bar.
  152. //
  153. if (HasFocus) {
  154. float red = ((color & 0x00FF0000) >> 16) / 256.0F;
  155. float green = ((color & 0x0000FF00) >> 8) / 256.0F;
  156. float blue = ((color & 0x000000FF)) / 256.0F;
  157. float percent = (PulsePercent * 0.5F) + 0.5F;
  158. color = VRGB_TO_INT32 (Vector3 (red * percent, green * percent, blue * percent));
  159. }
  160. //
  161. // Get the hilight rect
  162. //
  163. RectClass sel_rect;
  164. Get_Entry_Rect (CurrSel, sel_rect);
  165. if (sel_rect.Top >= TextRect.Top && sel_rect.Bottom <= TextRect.Bottom) {
  166. //
  167. // Render the outline of the selection (if its on the screen)
  168. //
  169. renderer.Add_Outline (sel_rect, 1.0F, color);
  170. }
  171. }
  172. return ;
  173. }
  174. ////////////////////////////////////////////////////////////////
  175. //
  176. // Create_Text_Renderers
  177. //
  178. ////////////////////////////////////////////////////////////////
  179. void
  180. ListCtrlClass::Create_Text_Renderers (void)
  181. {
  182. //
  183. // Configure the text renderers
  184. //
  185. HeaderRenderer.Reset ();
  186. TextRenderer.Reset ();
  187. HilightRenderer.Reset ();
  188. UnderlineRenderer.Reset ();
  189. IconMgr.Reset_Renderers ();
  190. //
  191. // Prepare the column header (if necessary)
  192. //
  193. if ((Style & LVS_NOCOLUMNHEADER) == 0) {
  194. //
  195. // Render each column header
  196. //
  197. int x_pos = HeaderRect.Left;
  198. for (int index = 0; index < ColList.Count (); index ++) {
  199. //
  200. // Build a bounding rectangle for this column header
  201. //
  202. RectClass rect = HeaderRect;
  203. rect.Left = x_pos;
  204. rect.Right = x_pos + (ColList[index]->Get_Width () * HeaderRect.Width ());
  205. //
  206. // Let the last column extend to the edge
  207. //
  208. if (index == ColList.Count () - 1) {
  209. rect.Right = HeaderRect.Right;
  210. }
  211. //
  212. // Get the color
  213. //
  214. int color = VRGB_TO_INT32 (ColList[index]->Get_Color ());
  215. //
  216. // Underline the header
  217. //
  218. Vector2 text_extent = HeaderRenderer.Get_Text_Extents (ColList[index]->Get_Name ());
  219. float y_pos = (rect.Top + (rect.Height () / 2) + (text_extent.Y / 2)) + 2.0F;
  220. UnderlineRenderer.Add_Line (Vector2 (rect.Left, y_pos),
  221. Vector2 (rect.Left + text_extent.X, y_pos), 1.0F, color);
  222. //
  223. // Draw the sort designator
  224. //
  225. if (SortType != SORT_NONE && SortColumn == index) {
  226. const float TRI_WIDTH = 8;
  227. const float TRI_SPACE = 2;
  228. float tri_size = TRI_WIDTH * StyleMgrClass::Get_Y_Scale ();
  229. float tri_half_size = tri_size * 0.5F;
  230. float tri_x_pos = rect.Left + text_extent.X + tri_size + (TRI_SPACE * StyleMgrClass::Get_Y_Scale ());
  231. float tri_y_pos = HeaderRect.Center ().Y;
  232. if (SortType == SORT_ASCENDING) {
  233. UnderlineRenderer.Add_Line (Vector2 (tri_x_pos - tri_half_size, tri_y_pos + tri_half_size),
  234. Vector2 (tri_x_pos + tri_half_size, tri_y_pos + tri_half_size), 1.0F, color);
  235. UnderlineRenderer.Add_Line (Vector2 (tri_x_pos + tri_half_size, tri_y_pos + tri_half_size),
  236. Vector2 (tri_x_pos, tri_y_pos - tri_half_size), 1.0F, color);
  237. UnderlineRenderer.Add_Line (Vector2 (tri_x_pos, tri_y_pos - tri_half_size),
  238. Vector2 (tri_x_pos - tri_half_size, tri_y_pos + tri_half_size), 1.0F, color);
  239. } else {
  240. UnderlineRenderer.Add_Line (Vector2 (tri_x_pos - tri_half_size, tri_y_pos - tri_half_size),
  241. Vector2 (tri_x_pos + tri_half_size, tri_y_pos - tri_half_size), 1.0F, color);
  242. UnderlineRenderer.Add_Line (Vector2 (tri_x_pos + tri_half_size, tri_y_pos - tri_half_size),
  243. Vector2 (tri_x_pos, tri_y_pos + tri_half_size), 1.0F, color);
  244. UnderlineRenderer.Add_Line (Vector2 (tri_x_pos, tri_y_pos + tri_half_size),
  245. Vector2 (tri_x_pos - tri_half_size, tri_y_pos - tri_half_size), 1.0F, color);
  246. }
  247. }
  248. //
  249. // Render the text
  250. //
  251. StyleMgrClass::Render_Text (ColList[index]->Get_Name (), &HeaderRenderer,
  252. color, RGB_TO_INT32 (0, 0, 0), rect, true, true);
  253. //
  254. // Move on to the next column
  255. //
  256. x_pos = rect.Right;
  257. }
  258. }
  259. //
  260. // Render the data by rows
  261. //
  262. float y_pos = TextRect.Top;
  263. int row_count = Get_Entry_Count ();
  264. for (int row_index = ScrollPos; row_index < row_count; row_index ++) {
  265. //
  266. // Get the height of this row
  267. //
  268. float row_height = RowInfoList[row_index]->Get_Height ();
  269. //
  270. // Don't render past the bottom of the control
  271. //
  272. if ((y_pos + row_height) >= TextRect.Bottom) {
  273. break;
  274. }
  275. //
  276. // Render each column in this row
  277. //
  278. float x_pos = TextRect.Left;
  279. for (int index = 0; index < ColList.Count (); index ++) {
  280. //
  281. // Determine how wide this column is
  282. //
  283. float col_width = (ColList[index]->Get_Width () * HeaderRect.Width ());
  284. if (index == ColList.Count () - 1) {
  285. col_width = TextRect.Right - x_pos;
  286. }
  287. //
  288. // Build a bounding rectangle for this entry
  289. //
  290. RectClass rect;
  291. rect.Left = int(x_pos);
  292. rect.Right = int(x_pos + col_width);
  293. rect.Top = int(y_pos);
  294. rect.Bottom = int(y_pos + row_height);
  295. //
  296. // Render the entry
  297. //
  298. Render_Entry (rect, index, row_index);
  299. //
  300. // Move on to the next column
  301. //
  302. x_pos = rect.Right;
  303. }
  304. //
  305. // Render a hilight on this row if necessary
  306. //
  307. if (Is_Entry_Selected (row_index)) {
  308. RectClass row_rect = TextRect;
  309. row_rect.Top = (int)max (TextRect.Top, (float)y_pos);
  310. row_rect.Bottom = (int)min (TextRect.Bottom, (float)(y_pos + row_height));
  311. StyleMgrClass::Render_Hilight (&HilightRenderer, row_rect);
  312. }
  313. //
  314. // Move down to the next row
  315. //
  316. y_pos += row_height;
  317. }
  318. return ;
  319. }
  320. ////////////////////////////////////////////////////////////////
  321. //
  322. // Render_Entry
  323. //
  324. ////////////////////////////////////////////////////////////////
  325. void
  326. ListCtrlClass::Render_Entry (const RectClass &clip_rect, int col_index, int row_index)
  327. {
  328. RectClass rect = clip_rect;
  329. //
  330. // Render the icons
  331. //
  332. int icon_count = ColList[col_index]->Get_Icon_Count (row_index);
  333. for (int index = 0; index < icon_count; index ++) {
  334. //
  335. // Render this icon
  336. //
  337. const char *icon_name = ColList[col_index]->Get_Icon (row_index, index);
  338. IconMgr.Render_Icon (rect, icon_name);
  339. //
  340. // Move the rect by the width of the icon
  341. //
  342. rect.Left += IconMgr.Get_Icon_Width ();
  343. }
  344. //
  345. // Get the text
  346. //
  347. const WCHAR *text = ColList[col_index]->Get_Entry_Text (row_index);
  348. int text_color = VRGB_TO_INT32 (ColList[col_index]->Get_Entry_Color (row_index));
  349. //
  350. // Render the text
  351. //
  352. StyleMgrClass::Render_Wrapped_Text (text, &TextRenderer, text_color,
  353. RGB_TO_INT32 (0, 0, 0), rect, true, true);
  354. return ;
  355. }
  356. ////////////////////////////////////////////////////////////////
  357. //
  358. // On_Set_Cursor
  359. //
  360. ////////////////////////////////////////////////////////////////
  361. void
  362. ListCtrlClass::On_Set_Cursor (const Vector2 &mouse_pos)
  363. {
  364. if (IsSelectionAllowed) {
  365. //
  366. // Change the mouse cursor
  367. //
  368. MouseMgrClass::Set_Cursor (MouseMgrClass::CURSOR_ACTION);
  369. }
  370. return ;
  371. }
  372. ////////////////////////////////////////////////////////////////
  373. //
  374. // Set_Sort_Designator
  375. //
  376. ////////////////////////////////////////////////////////////////
  377. void
  378. ListCtrlClass::Set_Sort_Designator (int col_index, SORT_TYPE type)
  379. {
  380. SortColumn = col_index;
  381. SortType = type;
  382. Set_Dirty ();
  383. return ;
  384. }
  385. ////////////////////////////////////////////////////////////////
  386. //
  387. // Sort_Alphabetically
  388. //
  389. ////////////////////////////////////////////////////////////////
  390. void
  391. ListCtrlClass::Sort_Alphabetically (int col_index, SORT_TYPE type)
  392. {
  393. //
  394. // Sort the entries
  395. //
  396. Sort (Default_Sort_Callback, MAKELONG ((WORD)col_index, (WORD)type));
  397. //
  398. // Update the sort marker
  399. //
  400. Set_Sort_Designator (col_index, type);
  401. return ;
  402. }
  403. ////////////////////////////////////////////////////////////////
  404. //
  405. // Default_Sort_Callback
  406. //
  407. ////////////////////////////////////////////////////////////////
  408. int CALLBACK
  409. ListCtrlClass::Default_Sort_Callback (ListCtrlClass *list_ctrl, int item_index1, int item_index2, uint32 user_param)
  410. {
  411. //
  412. // Get the sorting params
  413. //
  414. int sort_col_index = LOWORD (user_param);
  415. SORT_TYPE sort_type = (SORT_TYPE)HIWORD (user_param);
  416. //
  417. // Sort by name
  418. //
  419. const WCHAR *name1 = list_ctrl->Get_Entry_Text (item_index1, sort_col_index);
  420. const WCHAR *name2 = list_ctrl->Get_Entry_Text (item_index2, sort_col_index);
  421. int retval = ::CompareStringW (LOCALE_USER_DEFAULT, NORM_IGNORECASE, name1, -1, name2, -1);
  422. if (retval == 0) {
  423. retval = wcsicmp(name1, name2);
  424. } else {
  425. retval -= 2;
  426. }
  427. //
  428. // Invert the return value if we are sorting descendingly
  429. //
  430. if (sort_type == SORT_DESCENDING) {
  431. retval = -retval;
  432. }
  433. return retval;
  434. }
  435. ////////////////////////////////////////////////////////////////
  436. //
  437. // Update_Client_Rect
  438. //
  439. ////////////////////////////////////////////////////////////////
  440. void
  441. ListCtrlClass::Update_Client_Rect (void)
  442. {
  443. Vector2 header_size = HeaderRenderer.Get_Text_Extents (L"W");
  444. //
  445. // Set the client area
  446. //
  447. ClientRect = Rect;
  448. ClientRect.Inflate (Vector2 (-header_size.X, -1));
  449. HeaderRect = ClientRect;
  450. TextRect = ClientRect;
  451. //
  452. // Calculate what the header rectangle should be
  453. //
  454. if ((Style & LVS_NOCOLUMNHEADER) == 0) {
  455. float char_height = header_size.Y;
  456. HeaderRect.Bottom = HeaderRect.Top + (char_height * 3);
  457. } else {
  458. HeaderRect.Bottom = HeaderRect.Top;
  459. }
  460. //
  461. // Move the text rectangle down
  462. //
  463. TextRect.Top = HeaderRect.Bottom;
  464. //float scale_y = Render2DClass::Get_Screen_Resolution().Height () / 600;
  465. //
  466. // Choose an arbitrary width, the scroll bar
  467. // will snap to the only width it supports
  468. //
  469. float width = 10;
  470. //
  471. // Calculate the scroll bar's rectangle
  472. //
  473. RectClass scroll_rect;
  474. scroll_rect.Left = Rect.Right - width;
  475. scroll_rect.Top = Rect.Top;
  476. scroll_rect.Right = Rect.Right;
  477. scroll_rect.Bottom = Rect.Bottom;
  478. //
  479. // Size the scroll bar
  480. //
  481. ScrollBarCtrl.Set_Window_Rect (scroll_rect);
  482. Set_Dirty ();
  483. return ;
  484. }
  485. ////////////////////////////////////////////////////////////////
  486. //
  487. // Find_Top_Of_Page
  488. //
  489. ////////////////////////////////////////////////////////////////
  490. int
  491. ListCtrlClass::Find_Top_Of_Page (int bottom_index)
  492. {
  493. int retval = 0;
  494. //int count = RowInfoList.Count ();
  495. float y_pos = TextRect.Bottom;
  496. //
  497. // Scan the entries until we've found the first one
  498. // to extend off the top of the page
  499. //
  500. for (int index = bottom_index; index >= 0; index --) {
  501. y_pos -= RowInfoList[index]->Get_Height ();
  502. //
  503. // If we've gone off the page, then back off one entry
  504. //
  505. if (y_pos < TextRect.Top) {
  506. retval = (index + 1);
  507. break;
  508. }
  509. }
  510. return retval;
  511. }
  512. ////////////////////////////////////////////////////////////////
  513. //
  514. // Find_End_Of_Page
  515. //
  516. ////////////////////////////////////////////////////////////////
  517. int
  518. ListCtrlClass::Find_End_Of_Page (void)
  519. {
  520. int count = RowInfoList.Count ();
  521. int retval = count;
  522. float y_pos = TextRect.Top;
  523. //
  524. // Scan the entries until we've found the first one
  525. // to extend off the page
  526. //
  527. for (int index = ScrollPos; index < count; index ++) {
  528. y_pos += RowInfoList[index]->Get_Height ();
  529. //
  530. // If we've gone off the page, then back off one entry
  531. //
  532. if (y_pos >= TextRect.Bottom) {
  533. retval = (index - 1);
  534. break;
  535. }
  536. }
  537. return retval;
  538. }
  539. ////////////////////////////////////////////////////////////////
  540. //
  541. // Find_Last_Page_Top_Entry
  542. //
  543. ////////////////////////////////////////////////////////////////
  544. int
  545. ListCtrlClass::Find_Last_Page_Top_Entry (void)
  546. {
  547. int retval = 0;
  548. float y_pos = TextRect.Bottom;
  549. int count = RowInfoList.Count ();
  550. //
  551. // Scan backwards from the bottom entry until we've
  552. // found one that extends off the top of the page.
  553. //
  554. for (int index = count - 1; index >= 0; index --) {
  555. y_pos -= RowInfoList[index]->Get_Height ();
  556. if (y_pos <= TextRect.Top) {
  557. retval = index + 1;
  558. break;
  559. }
  560. }
  561. return retval;
  562. }
  563. ////////////////////////////////////////////////////////////////
  564. //
  565. // Update_Scroll_Bar_Visibility
  566. //
  567. ////////////////////////////////////////////////////////////////
  568. void
  569. ListCtrlClass::Update_Scroll_Bar_Visibility (void)
  570. {
  571. LastPageTopEntryIndex = Find_Last_Page_Top_Entry ();
  572. //
  573. // Configure the scroll-bar's ranges
  574. //
  575. ScrollBarCtrl.Set_Page_Size (0);
  576. ScrollBarCtrl.Set_Range (0, LastPageTopEntryIndex);
  577. //
  578. // Determine if we have more entries then we can
  579. // display on one page
  580. //
  581. bool needs_scrollbar = false;
  582. float y_pos = TextRect.Top;
  583. for (int index = 0; index < RowInfoList.Count (); index ++) {
  584. y_pos += RowInfoList[index]->Get_Height ();
  585. if (y_pos >= TextRect.Bottom) {
  586. needs_scrollbar = true;
  587. break;
  588. }
  589. }
  590. float new_right = 0;
  591. //
  592. // Do we need to show a scroll bar?
  593. //
  594. bool was_scrollbar_displayed = IsScrollBarDisplayed;
  595. if (needs_scrollbar) {
  596. new_right = ScrollBarCtrl.Get_Window_Rect ().Left;
  597. IsScrollBarDisplayed = true;
  598. } else if (Parent != NULL) {
  599. new_right = ScrollBarCtrl.Get_Window_Rect ().Right;
  600. IsScrollBarDisplayed = false;
  601. }
  602. //
  603. // Reset our window size (as necessary)
  604. //
  605. Rect.Right = new_right;
  606. ClientRect.Right = Rect.Right - (ClientRect.Left - Rect.Left);
  607. TextRect.Right = ClientRect.Right;
  608. HeaderRect.Right = ClientRect.Right;
  609. //
  610. // Update the row heights of each entry if the scroll bar
  611. // visibility changed
  612. //
  613. if (was_scrollbar_displayed != IsScrollBarDisplayed) {
  614. for (index = 0; index < RowInfoList.Count (); index ++) {
  615. Update_Row_Height (index);
  616. }
  617. //
  618. // Update the last page top entry
  619. //
  620. LastPageTopEntryIndex = Find_Last_Page_Top_Entry ();
  621. }
  622. //
  623. // Configure the scroll-bar's ranges
  624. //
  625. ScrollBarCtrl.Set_Page_Size (0);
  626. ScrollBarCtrl.Set_Range (0, LastPageTopEntryIndex);
  627. //
  628. // Configure the scroll bar's position
  629. //
  630. if (ScrollBarCtrl.Get_Pos () > LastPageTopEntryIndex) {
  631. int new_pos = max (LastPageTopEntryIndex, 0);
  632. ScrollBarCtrl.Set_Pos (new_pos);
  633. }
  634. return ;
  635. }
  636. ////////////////////////////////////////////////////////////////
  637. //
  638. // Render
  639. //
  640. ////////////////////////////////////////////////////////////////
  641. void
  642. ListCtrlClass::Render (void)
  643. {
  644. //
  645. // Recreate the renderers (if necessary)
  646. //
  647. if (IsDirty) {
  648. Update_Scroll_Bar_Visibility ();
  649. Create_Text_Renderers ();
  650. }
  651. if (IsScrollBarDisplayed) {
  652. Parent->Add_Control (&ScrollBarCtrl);
  653. } else {
  654. Parent->Remove_Control (&ScrollBarCtrl);
  655. }
  656. if (HasFocus || IsDirty) {
  657. Create_Control_Renderer ();
  658. }
  659. //
  660. // Render the background and text
  661. //
  662. IconMgr.Render_Icons ();
  663. TextRenderer.Render ();
  664. HilightRenderer.Render ();
  665. UnderlineRenderer.Render ();
  666. HeaderRenderer.Render ();
  667. ControlRenderer.Render ();
  668. DialogControlClass::Render ();
  669. return ;
  670. }
  671. ////////////////////////////////////////////////////////////////
  672. //
  673. // Get_First_Selected
  674. //
  675. ////////////////////////////////////////////////////////////////
  676. int
  677. ListCtrlClass::Get_First_Selected (void) const
  678. {
  679. int retval = -1;
  680. //
  681. // Loop over all the entries in the list control
  682. //
  683. int entry_count = Get_Entry_Count ();
  684. for (int index = 0; index < entry_count; index ++) {
  685. //
  686. // Is this entry selected?
  687. //
  688. if (RowInfoList[index]->Is_Selected ()) {
  689. retval = index;
  690. break;
  691. }
  692. }
  693. return retval;
  694. }
  695. ////////////////////////////////////////////////////////////////
  696. //
  697. // Get_Next_Selected
  698. //
  699. ////////////////////////////////////////////////////////////////
  700. int
  701. ListCtrlClass::Get_Next_Selected (int index) const
  702. {
  703. int retval = -1;
  704. //
  705. // Loop over all the entries in the list control
  706. //
  707. int entry_count = Get_Entry_Count ();
  708. for (index ++; index < entry_count; index ++) {
  709. //
  710. // Is this entry selected?
  711. //
  712. if (RowInfoList[index]->Is_Selected ()) {
  713. retval = index;
  714. break;
  715. }
  716. }
  717. return retval;
  718. }
  719. ////////////////////////////////////////////////////////////////
  720. //
  721. // Select_All
  722. //
  723. ////////////////////////////////////////////////////////////////
  724. void
  725. ListCtrlClass::Select_All (bool select)
  726. {
  727. //
  728. // Loop over all the entries in the list control
  729. //
  730. int entry_count = Get_Entry_Count ();
  731. for (int index = 0; index < entry_count; index ++) {
  732. RowInfoList[index]->Select (select);
  733. }
  734. Set_Dirty();
  735. return ;
  736. }
  737. ////////////////////////////////////////////////////////////////
  738. //
  739. // Toggle_Entry_Selection
  740. //
  741. ////////////////////////////////////////////////////////////////
  742. bool
  743. ListCtrlClass::Toggle_Entry_Selection (int index)
  744. {
  745. if (index < 0 || index >= Get_Entry_Count ()) {
  746. return false;
  747. }
  748. //
  749. // Toggle the selection of this entry
  750. //
  751. bool selected = RowInfoList[index]->Is_Selected ();
  752. RowInfoList[index]->Select (!selected);
  753. Set_Dirty ();
  754. return false;
  755. }
  756. ////////////////////////////////////////////////////////////////
  757. //
  758. // On_LButton_DblClk
  759. //
  760. ////////////////////////////////////////////////////////////////
  761. void
  762. ListCtrlClass::On_LButton_DblClk (const Vector2 &mouse_pos)
  763. {
  764. int sel_entry = Entry_From_Pos (mouse_pos);
  765. if (sel_entry == CurrSel) {
  766. //
  767. // Notify any advise sinks
  768. //
  769. ADVISE_NOTIFY (On_ListCtrl_DblClk (this, Get_ID (), sel_entry));
  770. }
  771. return ;
  772. }
  773. ////////////////////////////////////////////////////////////////
  774. //
  775. // On_LButton_Down
  776. //
  777. ////////////////////////////////////////////////////////////////
  778. void
  779. ListCtrlClass::On_LButton_Down (const Vector2 &mouse_pos)
  780. {
  781. if (mouse_pos.Y <= HeaderRect.Bottom) {
  782. //
  783. // Find out which column was clicked
  784. //
  785. int col_index = Col_From_Pos (mouse_pos);
  786. if (-1 != col_index) {
  787. //
  788. // Notify any advise sinks
  789. //
  790. ADVISE_NOTIFY (On_ListCtrl_Column_Click (this, Get_ID (), col_index));
  791. }
  792. } else {
  793. //
  794. // Change the hilighted entry to reflect the mouse click
  795. //
  796. int new_sel = Entry_From_Pos (mouse_pos);
  797. if (new_sel != -1) {
  798. Set_Sel (new_sel, true);
  799. } else if (IsNoSelectionAllowed) {
  800. Set_Sel(-1, true);
  801. }
  802. }
  803. return ;
  804. }
  805. ////////////////////////////////////////////////////////////////
  806. //
  807. // On_LButton_Up
  808. //
  809. ////////////////////////////////////////////////////////////////
  810. void
  811. ListCtrlClass::On_LButton_Up (const Vector2 &mouse_pos)
  812. {
  813. return ;
  814. }
  815. ////////////////////////////////////////////////////////////////
  816. //
  817. // On_Mouse_Move
  818. //
  819. ////////////////////////////////////////////////////////////////
  820. void
  821. ListCtrlClass::On_Mouse_Move (const Vector2 &mouse_pos)
  822. {
  823. int sel_entry = Entry_From_Pos(mouse_pos);
  824. ADVISE_NOTIFY(On_ListCtrl_Mouse_Over(this, Get_ID(), sel_entry));
  825. return ;
  826. }
  827. ////////////////////////////////////////////////////////////////
  828. //
  829. // On_Set_Focus
  830. //
  831. ////////////////////////////////////////////////////////////////
  832. void
  833. ListCtrlClass::On_Set_Focus (void)
  834. {
  835. Set_Dirty ();
  836. DialogControlClass::On_Set_Focus ();
  837. return ;
  838. }
  839. ////////////////////////////////////////////////////////////////
  840. //
  841. // On_Kill_Focus
  842. //
  843. ////////////////////////////////////////////////////////////////
  844. void
  845. ListCtrlClass::On_Kill_Focus (DialogControlClass *focus)
  846. {
  847. Set_Dirty ();
  848. DialogControlClass::On_Kill_Focus (focus);
  849. return ;
  850. }
  851. ////////////////////////////////////////////////////////////////
  852. //
  853. // On_Key_Down
  854. //
  855. ////////////////////////////////////////////////////////////////
  856. bool
  857. ListCtrlClass::On_Key_Down (uint32 key_id, uint32 key_data)
  858. {
  859. bool handled = true;
  860. switch (key_id)
  861. {
  862. case VK_UP:
  863. case VK_LEFT:
  864. Set_Sel (CurrSel - 1, true);
  865. break;
  866. case VK_DOWN:
  867. case VK_RIGHT:
  868. Set_Sel (CurrSel + 1, true);
  869. break;
  870. case VK_PRIOR:
  871. if (CurrSel == ScrollPos) {
  872. Scroll_Page (-1);
  873. } else {
  874. Set_Sel (ScrollPos, true);
  875. }
  876. break;
  877. case VK_NEXT:
  878. {
  879. int end_of_page = Find_End_Of_Page ();
  880. //
  881. // If we are at the end of the page, then
  882. // scroll one page, otherwise snap to the
  883. // end of the page
  884. //
  885. if (CurrSel == end_of_page) {
  886. Scroll_Page (1);
  887. } else {
  888. Set_Sel (end_of_page, true);
  889. }
  890. break;
  891. }
  892. case VK_HOME:
  893. Set_Sel (0, true);
  894. break;
  895. case VK_END:
  896. Set_Sel (Get_Entry_Count () - 1, true);
  897. break;
  898. case VK_SPACE:
  899. case VK_RETURN:
  900. ADVISE_NOTIFY(On_ListCtrl_DblClk(this, Get_ID(), Get_Curr_Sel()));
  901. break;
  902. default:
  903. handled = false;
  904. break;
  905. }
  906. return handled;
  907. }
  908. ////////////////////////////////////////////////////////////////
  909. //
  910. // Sort
  911. //
  912. ////////////////////////////////////////////////////////////////
  913. void
  914. ListCtrlClass::Sort (LISTCTRL_SORT_CALLBACK sort_callback, uint32 user_param)
  915. {
  916. //
  917. // Quick sort the data
  918. //
  919. int entry_count = Get_Entry_Count ();
  920. if (entry_count > 1) {
  921. Quick_Sort (0, entry_count - 1, sort_callback, user_param);
  922. }
  923. //
  924. // Force a repaint
  925. //
  926. Set_Dirty ();
  927. return ;
  928. }
  929. ////////////////////////////////////////////////////////////////
  930. //
  931. // Quick_Sort
  932. //
  933. ////////////////////////////////////////////////////////////////
  934. void
  935. ListCtrlClass::Quick_Sort
  936. (
  937. int start_index,
  938. int end_index,
  939. LISTCTRL_SORT_CALLBACK sort_callback,
  940. uint32 user_param
  941. )
  942. {
  943. //
  944. // Setup a handy macro for swapping all columns of a particular row
  945. //
  946. #define QSORT_ROW_SWAP(index1, index2) \
  947. { \
  948. if (CurrSel == index1) { CurrSel = index2; } \
  949. else if (CurrSel == index2) { CurrSel = index1; } \
  950. ListRowClass *temp = RowInfoList[index1]; \
  951. RowInfoList[index1] = RowInfoList[index2]; \
  952. RowInfoList[index2] = temp; \
  953. for (int col_index = 0; col_index < ColList.Count (); col_index ++) { \
  954. ColList[col_index]->Swap_Entries (index1, index2); \
  955. } \
  956. }
  957. //
  958. // Determine our ranges
  959. //
  960. int pivot_index = start_index;
  961. int min_index = min (start_index + 1, end_index);
  962. int max_index = end_index;
  963. //
  964. // If the range is large enough, try to pick
  965. // a *good* pivot point.
  966. //
  967. if ((end_index - start_index) > 10) {
  968. int middle_index = start_index + ((end_index - start_index) / 2);
  969. //
  970. // Put the smaller of the middle and end indices into the middle slot
  971. //
  972. if ((*sort_callback) (this, end_index, middle_index, user_param) < 0) {
  973. QSORT_ROW_SWAP (end_index, middle_index);
  974. }
  975. //
  976. // Put the larger of the middle and start indices into the start slot
  977. //
  978. if ((*sort_callback) (this, middle_index, start_index, user_param) > 0) {
  979. QSORT_ROW_SWAP (middle_index, start_index);
  980. }
  981. //
  982. // Put the smaller of the start and end indices into the start slot
  983. //
  984. if ((*sort_callback) (this, end_index, start_index, user_param) < 0) {
  985. QSORT_ROW_SWAP (end_index, start_index);
  986. }
  987. }
  988. //
  989. // Put all the other entries in our range on either the lower or upper
  990. // side of the pivot entry based on their relative sort value.
  991. //
  992. bool keep_going = true;
  993. do
  994. {
  995. //
  996. // Find the first entry that is "greater-than" the pivot
  997. //
  998. for (; min_index <= max_index; min_index ++) {
  999. //
  1000. // Is this entry "greater-than" the pivot?
  1001. //
  1002. if ((*sort_callback) (this, min_index, start_index, user_param) > 0) {
  1003. break;
  1004. }
  1005. //
  1006. // The last index that is "less-than" the pivot entry will
  1007. // be the pivot's new index.
  1008. //
  1009. pivot_index = min_index;
  1010. }
  1011. //
  1012. // Find the last entry that is "less-than" the pivot
  1013. //
  1014. for (; max_index >= min_index; max_index --) {
  1015. //
  1016. // Is this entry "less-than" the pivot?
  1017. //
  1018. if ((*sort_callback) (this, max_index, start_index, user_param) < 0) {
  1019. break;
  1020. }
  1021. }
  1022. //
  1023. // Have we processed all the entries in our range?
  1024. //
  1025. if (min_index >= max_index) {
  1026. keep_going = false;
  1027. } else {
  1028. //
  1029. // Swap the entries
  1030. //
  1031. QSORT_ROW_SWAP (min_index, max_index);
  1032. //
  1033. // For efficiency's sake, skip over the entries we just swapped.
  1034. //
  1035. min_index ++;
  1036. max_index --;
  1037. pivot_index ++;
  1038. }
  1039. } while (keep_going);
  1040. //
  1041. // Insert the pivot point into its "sorted" position in the array (if necessary)
  1042. //
  1043. if (pivot_index > start_index) {
  1044. QSORT_ROW_SWAP (start_index, pivot_index);
  1045. }
  1046. //
  1047. // Calculate the region below the pivot
  1048. //
  1049. int lower_range_min = start_index;
  1050. int lower_range_max = pivot_index - 1;
  1051. //
  1052. // Recurse (if necessary) into the region below the pivot
  1053. //
  1054. if (lower_range_max < end_index && lower_range_min < lower_range_max) {
  1055. Quick_Sort (lower_range_min, lower_range_max, sort_callback, user_param);
  1056. }
  1057. //
  1058. // Calculate the region above the pivot
  1059. //
  1060. int upper_range_min = pivot_index + 1;
  1061. int upper_range_max = end_index;
  1062. //
  1063. // Recurse (if necessary) into the region above the pivot
  1064. //
  1065. if (upper_range_min > start_index && upper_range_min < upper_range_max) {
  1066. Quick_Sort (upper_range_min, upper_range_max, sort_callback, user_param);
  1067. }
  1068. return ;
  1069. }
  1070. ////////////////////////////////////////////////////////////////
  1071. //
  1072. // On_Create
  1073. //
  1074. ////////////////////////////////////////////////////////////////
  1075. void
  1076. ListCtrlClass::On_Create (void)
  1077. {
  1078. return ;
  1079. }
  1080. ////////////////////////////////////////////////////////////////
  1081. //
  1082. // On_Destroy
  1083. //
  1084. ////////////////////////////////////////////////////////////////
  1085. void
  1086. ListCtrlClass::On_Destroy (void)
  1087. {
  1088. Delete_All_Entries ();
  1089. Delete_All_Columns ();
  1090. return ;
  1091. }
  1092. ////////////////////////////////////////////////////////////////
  1093. //
  1094. // Auto_Size_Columns_Include_Contents
  1095. //
  1096. ////////////////////////////////////////////////////////////////
  1097. void
  1098. ListCtrlClass::Auto_Size_Columns_Include_Contents (float col_spacing)
  1099. {
  1100. float total_width = HeaderRect.Width ();
  1101. //
  1102. // Loop over all the columns
  1103. //
  1104. for (int index = 0; index < ColList.Count (); index ++) {
  1105. float max_width = HeaderRenderer.Get_Text_Extents (ColList[index]->Get_Name ()).X;
  1106. //
  1107. // Now, take into consideration the largest entry we've got
  1108. //
  1109. int count = ColList[index]->Get_Entry_Count ();
  1110. for (int row = 0; row < count; row ++) {
  1111. float width = TextRenderer.Get_Text_Extents (ColList[index]->Get_Entry_Text (row)).X;
  1112. max_width = max (width, max_width);
  1113. //
  1114. // Add the width of all the icons to this row's total
  1115. //
  1116. int icon_count = ColList[index]->Get_Icon_Count (row);
  1117. for (int icon_index = 0; icon_index < icon_count; icon_index ++) {
  1118. max_width += IconMgr.Get_Icon_Width ();
  1119. }
  1120. }
  1121. //
  1122. // Auto-size this column
  1123. //
  1124. float percent = (max_width + col_spacing) / total_width;
  1125. ColList[index]->Set_Width (percent);
  1126. }
  1127. return ;
  1128. }
  1129. ////////////////////////////////////////////////////////////////
  1130. //
  1131. // Auto_Size_Columns
  1132. //
  1133. ////////////////////////////////////////////////////////////////
  1134. void
  1135. ListCtrlClass::Auto_Size_Columns (float col_spacing)
  1136. {
  1137. float max_width = HeaderRect.Width ();
  1138. for (int index = 0; index < ColList.Count (); index ++) {
  1139. //
  1140. // Auto-size this column
  1141. //
  1142. float width = HeaderRenderer.Get_Text_Extents (ColList[index]->Get_Name ()).X;
  1143. float percent = (width + col_spacing) / max_width;
  1144. ColList[index]->Set_Width (percent);
  1145. }
  1146. return ;
  1147. }
  1148. ////////////////////////////////////////////////////////////////
  1149. //
  1150. // Add_Icon
  1151. //
  1152. ////////////////////////////////////////////////////////////////
  1153. void
  1154. ListCtrlClass::Add_Icon (int index, int col_index, const char *texture_name)
  1155. {
  1156. if (col_index < 0 || col_index >= ColList.Count ()) {
  1157. return ;
  1158. }
  1159. //
  1160. // Add an icon to this entry
  1161. //
  1162. IconMgr.Add_Icon (texture_name);
  1163. ColList[col_index]->Add_Icon (index, texture_name);
  1164. return ;
  1165. }
  1166. ////////////////////////////////////////////////////////////////
  1167. //
  1168. // Reset_Icons
  1169. //
  1170. ////////////////////////////////////////////////////////////////
  1171. void
  1172. ListCtrlClass::Reset_Icons (int index, int col_index)
  1173. {
  1174. if (col_index < 0 || col_index >= ColList.Count ()) {
  1175. return ;
  1176. }
  1177. //
  1178. // Reset all the icons in this entry
  1179. //
  1180. ColList[col_index]->Reset_Icons (index);
  1181. return ;
  1182. }
  1183. ////////////////////////////////////////////////////////////////
  1184. //
  1185. // Add_Column
  1186. //
  1187. ////////////////////////////////////////////////////////////////
  1188. void
  1189. ListCtrlClass::Add_Column (const WCHAR *column_name, float width, const Vector3 &color)
  1190. {
  1191. //
  1192. // Create a new column and add it to the list
  1193. //
  1194. ListColumnClass *column = new ListColumnClass;
  1195. column->Set_Name (column_name);
  1196. column->Set_Width (width);
  1197. column->Set_Color (color);
  1198. ColList.Add (column);
  1199. Set_Dirty ();
  1200. return ;
  1201. }
  1202. ////////////////////////////////////////////////////////////////
  1203. //
  1204. // Set_Column_Color
  1205. //
  1206. ////////////////////////////////////////////////////////////////
  1207. void
  1208. ListCtrlClass::Set_Column_Color (int col_index, const Vector3 &color)
  1209. {
  1210. if (col_index < 0 || col_index >= ColList.Count ()) {
  1211. return ;
  1212. }
  1213. ColList[col_index]->Set_Color (color);
  1214. Set_Dirty ();
  1215. return ;
  1216. }
  1217. ////////////////////////////////////////////////////////////////
  1218. //
  1219. // Remove_Column
  1220. //
  1221. ////////////////////////////////////////////////////////////////
  1222. bool
  1223. ListCtrlClass::Remove_Column (int index)
  1224. {
  1225. if (index < 0 || index >= ColList.Count ()) {
  1226. return false;
  1227. }
  1228. //
  1229. // Free the column
  1230. //
  1231. ListColumnClass *column = ColList[index];
  1232. delete column;
  1233. //
  1234. // Remove the column from the list
  1235. //
  1236. ColList.Delete (index);
  1237. Set_Dirty ();
  1238. return true;
  1239. }
  1240. ////////////////////////////////////////////////////////////////
  1241. //
  1242. // Delete_All_Columns
  1243. //
  1244. ////////////////////////////////////////////////////////////////
  1245. void
  1246. ListCtrlClass::Delete_All_Columns (void)
  1247. {
  1248. for (int index = 0; index < ColList.Count (); index ++) {
  1249. ListColumnClass *column = ColList[index];
  1250. delete column;
  1251. }
  1252. ColList.Delete_All ();
  1253. Set_Dirty ();
  1254. return ;
  1255. }
  1256. ////////////////////////////////////////////////////////////////
  1257. //
  1258. // Get_Column_Count
  1259. //
  1260. ////////////////////////////////////////////////////////////////
  1261. int
  1262. ListCtrlClass::Get_Column_Count (void) const
  1263. {
  1264. return ColList.Count ();
  1265. }
  1266. ////////////////////////////////////////////////////////////////
  1267. //
  1268. // Get_Entry_Count
  1269. //
  1270. ////////////////////////////////////////////////////////////////
  1271. int
  1272. ListCtrlClass::Get_Entry_Count (void) const
  1273. {
  1274. return RowInfoList.Count ();
  1275. }
  1276. ////////////////////////////////////////////////////////////////
  1277. //
  1278. // Delete_Entry
  1279. //
  1280. ////////////////////////////////////////////////////////////////
  1281. bool
  1282. ListCtrlClass::Delete_Entry (int index)
  1283. {
  1284. bool retval = true;
  1285. //
  1286. // Nofity the advise sinks that we are deleting this entry
  1287. //
  1288. ADVISE_NOTIFY (On_ListCtrl_Delete_Entry (this, Get_ID (), index));
  1289. //
  1290. // Remove this row from our data structures
  1291. //
  1292. if (index >= 0 && index < RowInfoList.Count ()) {
  1293. delete RowInfoList[index];
  1294. RowInfoList.Delete (index);
  1295. }
  1296. //
  1297. // Remove this entry from each column
  1298. //
  1299. for (int col_index = 0; col_index < ColList.Count (); col_index ++) {
  1300. retval &= ColList[col_index]->Delete_Entry (index);
  1301. }
  1302. // When an entry that is before the current selection is deleted then
  1303. // we need to adjust the current selection to reflect that.
  1304. if (index < CurrSel) {
  1305. --CurrSel;
  1306. }
  1307. //
  1308. // Update the current selection indicator (if necessary)
  1309. //
  1310. int entry_count = Get_Entry_Count ();
  1311. if (CurrSel >= entry_count) {
  1312. CurrSel = entry_count - 1;
  1313. }
  1314. //
  1315. // Hilight the new current selection (if necessary)
  1316. //
  1317. if (CurrSel >= 0 && CurrSel <= RowInfoList.Count ()) {
  1318. RowInfoList[CurrSel]->Select ((IsMultipleSelection == false));
  1319. }
  1320. Set_Dirty ();
  1321. return retval;
  1322. }
  1323. ////////////////////////////////////////////////////////////////
  1324. //
  1325. // Find_Entry
  1326. //
  1327. ////////////////////////////////////////////////////////////////
  1328. int ListCtrlClass::Find_Entry(int col_index, const WCHAR* text)
  1329. {
  1330. int count = ColList.Count();
  1331. if (col_index >= 0 && col_index < count) {
  1332. ListColumnClass* list = ColList[col_index];
  1333. count = list->Get_Entry_Count();
  1334. for (int index = 0; index < count; index++) {
  1335. const WCHAR* entryText = list->Get_Entry_Text(index);
  1336. if (wcscmp(entryText, text) == 0) {
  1337. return index;
  1338. }
  1339. }
  1340. }
  1341. return -1;
  1342. }
  1343. ////////////////////////////////////////////////////////////////
  1344. //
  1345. // Insert_Entry
  1346. //
  1347. ////////////////////////////////////////////////////////////////
  1348. int
  1349. ListCtrlClass::Insert_Entry (int index, const WCHAR *text)
  1350. {
  1351. if (ColList.Count () <= 0) {
  1352. return -1;
  1353. }
  1354. //
  1355. // Insert a blank row in our data structure
  1356. //
  1357. if (index < RowInfoList.Count ()) {
  1358. RowInfoList.Insert (index + 1, new ListRowClass);
  1359. } else {
  1360. RowInfoList.Add (new ListRowClass);
  1361. }
  1362. //
  1363. // Insert a new entry in the first column with the given text
  1364. //
  1365. index = ColList[0]->Insert_Entry (index, text);
  1366. //
  1367. // Use the default text color for each new entry
  1368. //
  1369. int color = StyleMgrClass::Get_Text_Color ();
  1370. float red = ((color & 0x00FF0000) >> 16) / 256.0F;
  1371. float green = ((color & 0x0000FF00) >> 8) / 256.0F;
  1372. float blue = ((color & 0x000000FF)) / 256.0F;
  1373. Vector3 new_color (red, green, blue);
  1374. ColList[0]->Set_Entry_Color (index, new_color);
  1375. //
  1376. // Add blank entries to all the other columns
  1377. //
  1378. for (int col_index = 1; col_index < ColList.Count (); col_index ++) {
  1379. ListColumnClass *column = ColList[col_index];
  1380. column->Insert_Entry (index, L"");
  1381. column->Set_Entry_Color (index, new_color);
  1382. }
  1383. //
  1384. // Update the cached row height for this entry...
  1385. //
  1386. Update_Row_Height (index);
  1387. //
  1388. // Update the last page top entry
  1389. //
  1390. LastPageTopEntryIndex = Find_Last_Page_Top_Entry ();
  1391. Set_Dirty ();
  1392. return index;
  1393. }
  1394. ////////////////////////////////////////////////////////////////
  1395. //
  1396. // Update_Row_Height
  1397. //
  1398. ////////////////////////////////////////////////////////////////
  1399. void
  1400. ListCtrlClass::Update_Row_Height (int row_index)
  1401. {
  1402. int border_height = (ROW_SPACING * StyleMgrClass::Get_Y_Scale ());
  1403. float height = (TextRenderer.Get_Text_Extents (L"W").Y + border_height);
  1404. //
  1405. // Render each column in this row
  1406. //
  1407. float x_pos = TextRect.Left;
  1408. for (int index = 0; index < ColList.Count (); index ++) {
  1409. //
  1410. // Determine how wide this column is
  1411. //
  1412. float col_width = (ColList[index]->Get_Width () * HeaderRect.Width ());
  1413. if (index == ColList.Count () - 1) {
  1414. col_width = TextRect.Right - x_pos;
  1415. }
  1416. //
  1417. // Set the wrapping width
  1418. //
  1419. TextRenderer.Set_Wrapping_Width (col_width);
  1420. //
  1421. // Calculate the height of this text
  1422. //
  1423. const WCHAR *text = ColList[index]->Get_Entry_Text (row_index);
  1424. Vector2 extents = TextRenderer.Get_Formatted_Text_Extents (text);
  1425. height = max (height, extents.Y + border_height);
  1426. //
  1427. // Increment the x-position
  1428. //
  1429. x_pos += col_width;
  1430. }
  1431. //
  1432. // Make sure the row is AT LEST MinRowHeight units high
  1433. //
  1434. float min_height = MinRowHeight * StyleMgrClass::Get_Y_Scale ();
  1435. height = max (min_height, height);
  1436. //
  1437. // Store the row height
  1438. //
  1439. RowInfoList[row_index]->Set_Height (height);
  1440. TextRenderer.Set_Wrapping_Width (0);
  1441. return ;
  1442. }
  1443. ////////////////////////////////////////////////////////////////
  1444. //
  1445. // Set_Icon_Size
  1446. //
  1447. ////////////////////////////////////////////////////////////////
  1448. void
  1449. ListCtrlClass::Set_Icon_Size (float width, float height)
  1450. {
  1451. //
  1452. // Pass these values on the icon manager
  1453. //
  1454. IconMgr.Set_Icon_Width (width);
  1455. IconMgr.Set_Icon_Height (height);
  1456. Set_Dirty ();
  1457. return ;
  1458. }
  1459. ////////////////////////////////////////////////////////////////
  1460. //
  1461. // Set_Min_Row_Height
  1462. //
  1463. ////////////////////////////////////////////////////////////////
  1464. void
  1465. ListCtrlClass::Set_Min_Row_Height (int height)
  1466. {
  1467. MinRowHeight = height;
  1468. //
  1469. // Update each row using this new height information
  1470. //
  1471. for (int index = 0; index < RowInfoList.Count (); index ++) {
  1472. Update_Row_Height (index);
  1473. }
  1474. Set_Dirty ();
  1475. return ;
  1476. }
  1477. ////////////////////////////////////////////////////////////////
  1478. //
  1479. // Select_Entry
  1480. //
  1481. ////////////////////////////////////////////////////////////////
  1482. bool
  1483. ListCtrlClass::Select_Entry (int index, bool onoff)
  1484. {
  1485. if (index < 0 || index >= Get_Entry_Count ()) {
  1486. return false;
  1487. }
  1488. //
  1489. // Set the selection state of the row
  1490. //
  1491. RowInfoList[index]->Select (onoff);
  1492. Set_Dirty ();
  1493. return true;
  1494. }
  1495. ////////////////////////////////////////////////////////////////
  1496. //
  1497. // Is_Entry_Selected
  1498. //
  1499. ////////////////////////////////////////////////////////////////
  1500. bool
  1501. ListCtrlClass::Is_Entry_Selected (int index)
  1502. {
  1503. bool retval = false;
  1504. if (index >= 0 && index < Get_Entry_Count ()) {
  1505. //
  1506. // Get the selection state of the row
  1507. //
  1508. retval = RowInfoList[index]->Is_Selected ();
  1509. Set_Dirty ();
  1510. }
  1511. return retval;
  1512. }
  1513. ////////////////////////////////////////////////////////////////
  1514. //
  1515. // Set_Entry_Text
  1516. //
  1517. ////////////////////////////////////////////////////////////////
  1518. bool
  1519. ListCtrlClass::Set_Entry_Text (int index, int col_index, const WCHAR *text)
  1520. {
  1521. if (col_index < 0 || col_index >= ColList.Count ()) {
  1522. return false;
  1523. }
  1524. //
  1525. // Change the text entry in this cell
  1526. //
  1527. ColList[col_index]->Set_Entry_Text (index, text);
  1528. //
  1529. // Update the cached row height for this entry...
  1530. //
  1531. Update_Row_Height (index);
  1532. //
  1533. // Update the last page top entry
  1534. //
  1535. LastPageTopEntryIndex = Find_Last_Page_Top_Entry ();
  1536. Set_Dirty ();
  1537. return true;
  1538. }
  1539. ////////////////////////////////////////////////////////////////
  1540. //
  1541. // Set_Entry_Int
  1542. //
  1543. ////////////////////////////////////////////////////////////////
  1544. bool
  1545. ListCtrlClass::Set_Entry_Int (int index, int col_index, int value)
  1546. {
  1547. if (col_index < 0 || col_index >= ColList.Count ()) {
  1548. return false;
  1549. }
  1550. //
  1551. // Convert the integer to a string
  1552. //
  1553. WideStringClass number_str;
  1554. number_str.Format (L"%d", value);
  1555. //
  1556. // Change the text entry in this cell
  1557. //
  1558. ColList[col_index]->Set_Entry_Text (index, number_str);
  1559. Set_Dirty ();
  1560. return true;
  1561. }
  1562. ////////////////////////////////////////////////////////////////
  1563. //
  1564. // Set_Entry_Color
  1565. //
  1566. ////////////////////////////////////////////////////////////////
  1567. bool
  1568. ListCtrlClass::Set_Entry_Color (int index, int col_index, const Vector3 &color)
  1569. {
  1570. if (col_index < 0 || col_index >= ColList.Count ()) {
  1571. return false;
  1572. }
  1573. //
  1574. // Change the color for the entry in this cell
  1575. //
  1576. ColList[col_index]->Set_Entry_Color (index, color);
  1577. Set_Dirty ();
  1578. return true;
  1579. }
  1580. ////////////////////////////////////////////////////////////////
  1581. //
  1582. // Set_Entry_Data
  1583. //
  1584. ////////////////////////////////////////////////////////////////
  1585. bool
  1586. ListCtrlClass::Set_Entry_Data (int index, int col_index, uint32 user_data)
  1587. {
  1588. //
  1589. // Store the user data in the first column
  1590. //
  1591. ColList[col_index]->Set_Entry_Data (index, user_data);
  1592. return true;
  1593. }
  1594. ////////////////////////////////////////////////////////////////
  1595. //
  1596. // Get_Entry_Data
  1597. //
  1598. ////////////////////////////////////////////////////////////////
  1599. uint32
  1600. ListCtrlClass::Get_Entry_Data (int index, int col_index)
  1601. {
  1602. uint32 user_data = 0;
  1603. //
  1604. // Lookup the user data
  1605. //
  1606. if (index >= 0 && index < Get_Entry_Count () && col_index >= 0 && col_index < ColList.Count ()) {
  1607. user_data = ColList[col_index]->Get_Entry_Data (index);
  1608. }
  1609. return user_data;
  1610. }
  1611. ////////////////////////////////////////////////////////////////
  1612. //
  1613. // Get_Entry_Text
  1614. //
  1615. ////////////////////////////////////////////////////////////////
  1616. const WCHAR *
  1617. ListCtrlClass::Get_Entry_Text (int index, int col_index)
  1618. {
  1619. //
  1620. // Return the string to the caller
  1621. //
  1622. return ColList[col_index]->Get_Entry_Text (index);
  1623. }
  1624. ////////////////////////////////////////////////////////////////
  1625. //
  1626. // Delete_All_Entries
  1627. //
  1628. ////////////////////////////////////////////////////////////////
  1629. void
  1630. ListCtrlClass::Delete_All_Entries (void)
  1631. {
  1632. //
  1633. // Notify the advise sinks (if necessary) that each entry
  1634. // is being deleted
  1635. //
  1636. int entry_count = Get_Entry_Count ();
  1637. for (int item_index = 0; item_index < entry_count; item_index ++) {
  1638. ADVISE_NOTIFY (On_ListCtrl_Delete_Entry (this, Get_ID (), item_index));
  1639. }
  1640. //
  1641. // Delete each of our row information sturctures
  1642. //
  1643. for (int index = 0; index < RowInfoList.Count (); index ++) {
  1644. delete RowInfoList[index];
  1645. }
  1646. RowInfoList.Delete_All ();
  1647. //
  1648. // Now delete all the entries from each column
  1649. //
  1650. for (index = 0; index < ColList.Count (); index ++) {
  1651. ColList[index]->Delete_All_Entries ();
  1652. }
  1653. Set_Dirty ();
  1654. //
  1655. // Reset the scroll and current selection positions
  1656. //
  1657. ScrollPos = 0;
  1658. CurrSel = -1;
  1659. Set_Dirty ();
  1660. return ;
  1661. }
  1662. ////////////////////////////////////////////////////////////////
  1663. //
  1664. // Scroll_To_End
  1665. //
  1666. ////////////////////////////////////////////////////////////////
  1667. void
  1668. ListCtrlClass::Scroll_To_End (void)
  1669. {
  1670. //
  1671. // Update the last page top entry
  1672. //
  1673. LastPageTopEntryIndex = Find_Last_Page_Top_Entry ();
  1674. //
  1675. // Force scroll to the end
  1676. //
  1677. ScrollPos = LastPageTopEntryIndex;
  1678. ScrollPos = max (ScrollPos, 0);
  1679. //
  1680. // Update the scrollbar
  1681. //
  1682. ScrollBarCtrl.Set_Pos (ScrollPos, false);
  1683. Set_Dirty ();
  1684. return ;
  1685. }
  1686. ////////////////////////////////////////////////////////////////
  1687. //
  1688. // Set_Curr_Sel
  1689. //
  1690. ////////////////////////////////////////////////////////////////
  1691. void
  1692. ListCtrlClass::Set_Curr_Sel (int new_sel)
  1693. {
  1694. if (new_sel == -1) {
  1695. Select_All(false);
  1696. CurrSel = -1;
  1697. } else {
  1698. Set_Sel(new_sel, false);
  1699. }
  1700. return ;
  1701. }
  1702. ////////////////////////////////////////////////////////////////
  1703. //
  1704. // Set_Sel
  1705. //
  1706. ////////////////////////////////////////////////////////////////
  1707. void
  1708. ListCtrlClass::Set_Sel (int new_sel, bool notify)
  1709. {
  1710. if (IsSelectionAllowed) {
  1711. //
  1712. // Unselect the old entry (if necessary)
  1713. //
  1714. if (IsMultipleSelection == false) {
  1715. Select_Entry (CurrSel, false);
  1716. }
  1717. int old_sel = CurrSel;
  1718. if ((new_sel == -1) && IsNoSelectionAllowed) {
  1719. CurrSel = -1;
  1720. } else {
  1721. //
  1722. // Bound the selection index
  1723. //
  1724. int count = Get_Entry_Count ();
  1725. CurrSel = max (new_sel, 0);
  1726. CurrSel = min (CurrSel, count - 1);
  1727. //
  1728. // Select the new entry
  1729. //
  1730. if (IsMultipleSelection) {
  1731. Toggle_Entry_Selection (CurrSel);
  1732. } else {
  1733. Select_Entry (CurrSel, true);
  1734. }
  1735. }
  1736. //
  1737. // Notify anyone who cares that we have changed the selection
  1738. //
  1739. if (notify && (old_sel != CurrSel)) {
  1740. ADVISE_NOTIFY(On_ListCtrl_Sel_Change(this, Get_ID(), old_sel, CurrSel));
  1741. }
  1742. //
  1743. // Force a repaint
  1744. //
  1745. Set_Dirty ();
  1746. Update_Scroll_Pos ();
  1747. }
  1748. return ;
  1749. }
  1750. ////////////////////////////////////////////////////////////////
  1751. //
  1752. // Update_Scroll_Pos
  1753. //
  1754. ////////////////////////////////////////////////////////////////
  1755. void
  1756. ListCtrlClass::Update_Scroll_Pos (void)
  1757. {
  1758. if (CurrSel < 0) {
  1759. return ;
  1760. }
  1761. //
  1762. // Do we need to scroll up?
  1763. //
  1764. if (CurrSel < ScrollPos) {
  1765. ScrollPos = CurrSel;
  1766. Set_Dirty ();
  1767. } else {
  1768. //
  1769. // Do we need to scroll down?
  1770. //
  1771. RectClass rect;
  1772. Get_Entry_Rect (CurrSel, rect);
  1773. if (rect.Bottom >= TextRect.Bottom) {
  1774. //
  1775. // Calculate where we should scroll to
  1776. //
  1777. ScrollPos = Find_Top_Of_Page (CurrSel);
  1778. Set_Dirty ();
  1779. }
  1780. }
  1781. //
  1782. // Update the scrollbar
  1783. //
  1784. ScrollBarCtrl.Set_Pos (ScrollPos, false);
  1785. return ;
  1786. }
  1787. ////////////////////////////////////////////////////////////////
  1788. //
  1789. // Get_Entry_Rect
  1790. //
  1791. ////////////////////////////////////////////////////////////////
  1792. void
  1793. ListCtrlClass::Get_Entry_Rect (int index, RectClass &rect)
  1794. {
  1795. if (index < 0 || index >= RowInfoList.Count ()) {
  1796. return ;
  1797. }
  1798. //
  1799. // Lookup the height of this row
  1800. //
  1801. float row_height = RowInfoList[index]->Get_Height ();
  1802. float y_pos = -1000.0F;
  1803. if (ScrollPos <= index) {
  1804. //
  1805. // Calculate the starting y-position of this entry
  1806. //
  1807. y_pos = TextRect.Top;
  1808. for (int curr_index = ScrollPos; curr_index < index; curr_index ++) {
  1809. y_pos += RowInfoList[curr_index]->Get_Height ();
  1810. }
  1811. }
  1812. rect.Left = int(TextRect.Left);
  1813. rect.Right = int(TextRect.Right);
  1814. rect.Top = int(y_pos);
  1815. rect.Bottom = int(rect.Top + row_height);
  1816. return ;
  1817. }
  1818. ////////////////////////////////////////////////////////////////
  1819. //
  1820. // Col_From_Pos
  1821. //
  1822. ////////////////////////////////////////////////////////////////
  1823. int
  1824. ListCtrlClass::Col_From_Pos (const Vector2 &mouse_pos)
  1825. {
  1826. int retval = -1;
  1827. //
  1828. // Test each column
  1829. //
  1830. int x_pos = HeaderRect.Left;
  1831. int col_count = ColList.Count ();
  1832. for (int col_index = 0; col_index < col_count; col_index ++) {
  1833. //
  1834. // Determine how wide this column is
  1835. //
  1836. int col_width = (ColList[col_index]->Get_Width () * HeaderRect.Width ());
  1837. //
  1838. // Let the last column extend to the edge
  1839. //
  1840. if (col_index == col_count - 1) {
  1841. col_width = HeaderRect.Right - x_pos;
  1842. }
  1843. //
  1844. // Is the coordinate inside this col?
  1845. //
  1846. if (mouse_pos.X >= x_pos && mouse_pos.X <= (x_pos + col_width)) {
  1847. retval = col_index;
  1848. break;
  1849. }
  1850. //
  1851. // Move on to the next column
  1852. //
  1853. x_pos += col_width;
  1854. }
  1855. return retval;
  1856. }
  1857. ////////////////////////////////////////////////////////////////
  1858. //
  1859. // Entry_From_Pos
  1860. //
  1861. ////////////////////////////////////////////////////////////////
  1862. int
  1863. ListCtrlClass::Entry_From_Pos (const Vector2 &mouse_pos)
  1864. {
  1865. int retval = -1;
  1866. if (mouse_pos.Y < TextRect.Top || mouse_pos.Y > TextRect.Bottom) {
  1867. return -1;
  1868. }
  1869. //
  1870. // Test each row
  1871. //
  1872. int y_pos = TextRect.Top;
  1873. int row_count = Get_Entry_Count ();
  1874. for (int row_index = ScrollPos; row_index < row_count; row_index ++) {
  1875. float row_height = RowInfoList[row_index]->Get_Height ();
  1876. //
  1877. // Is the coordinate inside this row?
  1878. //
  1879. if (mouse_pos.Y >= y_pos && mouse_pos.Y <= (y_pos + row_height)) {
  1880. retval = row_index;
  1881. break;
  1882. }
  1883. //
  1884. // Move down to the next row
  1885. //
  1886. y_pos += row_height;
  1887. //
  1888. // Stop searching if we've moved off the page
  1889. //
  1890. if (mouse_pos.Y >= TextRect.Bottom) {
  1891. break;
  1892. }
  1893. }
  1894. return retval;
  1895. }
  1896. ////////////////////////////////////////////////////////////////
  1897. //
  1898. // Scroll_Page
  1899. //
  1900. ////////////////////////////////////////////////////////////////
  1901. void
  1902. ListCtrlClass::Scroll_Page (int direction)
  1903. {
  1904. int count = RowInfoList.Count ();
  1905. float height = TextRect.Height ();
  1906. bool found = false;
  1907. //
  1908. // Scan either direction from the current scroll
  1909. // position until we've moved a whole page
  1910. //
  1911. for ( int index = ScrollPos;
  1912. index >= 0 && index < count;
  1913. index += direction)
  1914. {
  1915. //
  1916. // Decrement the remaining distance
  1917. //
  1918. height -= RowInfoList[index]->Get_Height ();
  1919. //
  1920. // If we've gone of the page, then back off one entry
  1921. //
  1922. if (height < 0) {
  1923. ScrollPos = (index - direction);
  1924. ScrollPos = min (ScrollPos, LastPageTopEntryIndex);
  1925. ScrollBarCtrl.Set_Pos (ScrollPos, false);
  1926. Set_Dirty ();
  1927. found = true;
  1928. break;
  1929. }
  1930. }
  1931. //
  1932. // Check the boundary conditions
  1933. //
  1934. if (index < 0 && found == false) {
  1935. ScrollPos = 0;
  1936. ScrollBarCtrl.Set_Pos (ScrollPos, false);
  1937. Set_Dirty ();
  1938. }
  1939. return ;
  1940. }
  1941. ////////////////////////////////////////////////////////////////
  1942. //
  1943. // On_VScroll_Page
  1944. //
  1945. ////////////////////////////////////////////////////////////////
  1946. void
  1947. ListCtrlClass::On_VScroll_Page (ScrollBarCtrlClass *scrollbar, int ctrl_id, int direction)
  1948. {
  1949. Scroll_Page (direction);
  1950. return ;
  1951. }
  1952. ////////////////////////////////////////////////////////////////
  1953. //
  1954. // On_VScroll
  1955. //
  1956. ////////////////////////////////////////////////////////////////
  1957. void
  1958. ListCtrlClass::On_VScroll (ScrollBarCtrlClass *, int , int new_position)
  1959. {
  1960. if (ScrollPos != new_position) {
  1961. ScrollPos = new_position;
  1962. Set_Dirty ();
  1963. }
  1964. return ;
  1965. }
  1966. ////////////////////////////////////////////////////////////////
  1967. //
  1968. // On_Mouse_Wheel
  1969. //
  1970. ////////////////////////////////////////////////////////////////
  1971. void
  1972. ListCtrlClass::On_Mouse_Wheel (int direction)
  1973. {
  1974. if (direction < 0) {
  1975. if (ScrollPos > 0) {
  1976. ScrollPos --;
  1977. ScrollBarCtrl.Set_Pos (ScrollPos, false);
  1978. }
  1979. } else {
  1980. if (ScrollPos < LastPageTopEntryIndex) {
  1981. ScrollPos ++;
  1982. ScrollBarCtrl.Set_Pos (ScrollPos, false);
  1983. }
  1984. }
  1985. Set_Dirty ();
  1986. return ;
  1987. }
  1988. //********************************************************************************//
  1989. //
  1990. // Start of ListColumnClass
  1991. //
  1992. //********************************************************************************//
  1993. ////////////////////////////////////////////////////////////////
  1994. //
  1995. // Free_Data
  1996. //
  1997. ////////////////////////////////////////////////////////////////
  1998. void
  1999. ListColumnClass::Free_Data (void)
  2000. {
  2001. Delete_All_Entries ();
  2002. return ;
  2003. }
  2004. ////////////////////////////////////////////////////////////////
  2005. //
  2006. // Reset_Contents
  2007. //
  2008. ////////////////////////////////////////////////////////////////
  2009. void
  2010. ListColumnClass::Reset_Contents (void)
  2011. {
  2012. //
  2013. // Remove all the entries
  2014. //
  2015. Free_Data ();
  2016. return ;
  2017. }
  2018. ////////////////////////////////////////////////////////////////
  2019. //
  2020. // Insert_Entry
  2021. //
  2022. ////////////////////////////////////////////////////////////////
  2023. int
  2024. ListColumnClass::Insert_Entry (int index, const WCHAR *entry_name)
  2025. {
  2026. ListEntryClass *entry = new ListEntryClass (entry_name);
  2027. //
  2028. // Should we insert this entry in the list or add it to the end?
  2029. //
  2030. if (index < EntryList.Count ()) {
  2031. EntryList.Insert (index + 1, entry);
  2032. } else {
  2033. EntryList.Add (entry);
  2034. index = (EntryList.Count () - 1);
  2035. }
  2036. return index;
  2037. }
  2038. ////////////////////////////////////////////////////////////////
  2039. //
  2040. // Delete_Entry
  2041. //
  2042. ////////////////////////////////////////////////////////////////
  2043. bool
  2044. ListColumnClass::Delete_Entry (int index)
  2045. {
  2046. bool retval = false;
  2047. //
  2048. // Delete the entry if we can find it in our list
  2049. //
  2050. if (index >= 0 && index < EntryList.Count ()) {
  2051. delete EntryList[index];
  2052. EntryList.Delete (index);
  2053. }
  2054. return retval;
  2055. }
  2056. ////////////////////////////////////////////////////////////////
  2057. //
  2058. // Delete_All_Entries
  2059. //
  2060. ////////////////////////////////////////////////////////////////
  2061. void
  2062. ListColumnClass::Delete_All_Entries (void)
  2063. {
  2064. //
  2065. // Free each of the entries in the list
  2066. //
  2067. for (int index = 0; index < EntryList.Count (); index ++) {
  2068. delete EntryList[index];
  2069. }
  2070. EntryList.Delete_All ();
  2071. return ;
  2072. }
  2073. ////////////////////////////////////////////////////////////////
  2074. //
  2075. // Move_Entry
  2076. //
  2077. ////////////////////////////////////////////////////////////////
  2078. void
  2079. ListColumnClass::Move_Entry (int old_index, int new_index)
  2080. {
  2081. if ( old_index < 0 || (old_index >= EntryList.Count ()) &&
  2082. new_index < 0 || (new_index >= EntryList.Count ()))
  2083. {
  2084. return ;
  2085. }
  2086. //
  2087. // Move the entry
  2088. //
  2089. ListEntryClass *old_entry = EntryList[old_index];
  2090. EntryList.Insert (new_index, old_entry);
  2091. EntryList.Delete (old_index);
  2092. return ;
  2093. }
  2094. ////////////////////////////////////////////////////////////////
  2095. //
  2096. // Swap_Entries
  2097. //
  2098. ////////////////////////////////////////////////////////////////
  2099. void
  2100. ListColumnClass::Swap_Entries (int index1, int index2)
  2101. {
  2102. if ( index1 < 0 || (index1 >= EntryList.Count ()) &&
  2103. index2 < 0 || (index2 >= EntryList.Count ()))
  2104. {
  2105. return ;
  2106. }
  2107. //
  2108. // Move the entry
  2109. //
  2110. ListEntryClass *temp_entry = EntryList[index1];
  2111. EntryList[index1] = EntryList[index2];
  2112. EntryList[index2] = temp_entry;
  2113. return ;
  2114. }