| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512 |
- /*
- ** Command & Conquer Renegade(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /***********************************************************************************************
- *** 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 ***
- ***********************************************************************************************
- * *
- * Project Name : Combat *
- * *
- * $Archive:: /Commando/Code/wwui/listctrl.cpp $*
- * *
- * Author:: Patrick Smith *
- * *
- * $Modtime:: 3/01/02 4:37p $*
- * *
- * $Revision:: 41 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "listctrl.h"
- #include "assetmgr.h"
- #include "refcount.h"
- #include "mousemgr.h"
- #include "ww3d.h"
- #include "dialogmgr.h"
- #include "dialogbase.h"
- #include "stylemgr.h"
- #include <commctrl.h>
- ////////////////////////////////////////////////////////////////
- // Local constants
- ////////////////////////////////////////////////////////////////
- const float PULSE_RATE = 2.0F;
- const int ROW_SPACING = 4;
- ////////////////////////////////////////////////////////////////
- //
- // ListCtrlClass
- //
- ////////////////////////////////////////////////////////////////
- ListCtrlClass::ListCtrlClass (void) :
- CurrState (NORMAL),
- ScrollPos (0),
- HeaderRect (0, 0, 0, 0),
- TextRect (0, 0, 0, 0),
- CurrSel (-1),
- RowBorderHeight (0),
- PulsePercent (1.0F),
- PulseDirection (1.0F),
- IsScrollBarDisplayed (false),
- LastPageTopEntryIndex (0),
- IsSelectionAllowed(true),
- IsNoSelectionAllowed(false),
- IsMultipleSelection (false),
- SortColumn (0),
- SortType (SORT_NONE),
- MinRowHeight (0)
- {
- //
- // Configure each renderer
- //
- StyleMgrClass::Configure_Renderer (&ControlRenderer);
- StyleMgrClass::Configure_Renderer (&UnderlineRenderer);
- StyleMgrClass::Configure_Renderer (&HilightRenderer);
- StyleMgrClass::Configure_Hilighter (&HilightRenderer);
- //
- // Set the font for each text renderer
- //
- StyleMgrClass::Assign_Font (&HeaderRenderer, StyleMgrClass::FONT_HEADER);
- StyleMgrClass::Assign_Font (&TextRenderer, StyleMgrClass::FONT_LISTS);
- TextRenderer.Set_Texture_Size_Hint (256);
- //
- // We don't want the scroll bar getting focus
- //
- ScrollBarCtrl.Set_Wants_Focus (false);
- ScrollBarCtrl.Set_Advise_Sink (this);
- ScrollBarCtrl.Set_Is_Embedded (true);
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // ~ListCtrlClass
- //
- ////////////////////////////////////////////////////////////////
- ListCtrlClass::~ListCtrlClass (void)
- {
- Delete_All_Entries ();
- if (Parent != NULL) {
- Parent->Remove_Control (&ScrollBarCtrl);
- }
- return ;
- }
- void ListCtrlClass::Set_Tabstop(float stop)
- {
- TextRenderer.Set_Tabstop(stop);
- }
- ////////////////////////////////////////////////////////////////
- //
- // Create_Control_Renderer
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::Create_Control_Renderer (void)
- {
- Render2DClass &renderer = ControlRenderer;
- //
- // Configure this renderer
- //
- renderer.Reset ();
- renderer.Enable_Texturing (false);
- //
- // Determine which color to draw the outline in
- //
- int color = StyleMgrClass::Get_Line_Color ();
- int bkcolor = StyleMgrClass::Get_Bk_Color ();
- if (CurrState == DISABLED) {
- color = StyleMgrClass::Get_Disabled_Line_Color ();
- bkcolor = StyleMgrClass::Get_Disabled_Bk_Color ();
- }
- //
- // Draw the outline
- //
- renderer.Add_Rect (Rect, 1.0F, color, bkcolor);
- //
- // Draw the selection bar if necessary
- //
- if (CurrSel != -1) {
- //
- // Calculate what percentage our pulse effect is
- //
- PulsePercent += PulseDirection * PULSE_RATE * (DialogMgrClass::Get_Frame_Time () / 1000.0F);
- if (PulsePercent < 0 || PulsePercent > 1.0F) {
- PulseDirection = -PulseDirection;
- PulsePercent = WWMath::Clamp (PulsePercent, 0, 1);
- }
- //
- // If this control has the focus then apply our pulsating effect to
- // the color of selection bar.
- //
- if (HasFocus) {
- float red = ((color & 0x00FF0000) >> 16) / 256.0F;
- float green = ((color & 0x0000FF00) >> 8) / 256.0F;
- float blue = ((color & 0x000000FF)) / 256.0F;
- float percent = (PulsePercent * 0.5F) + 0.5F;
- color = VRGB_TO_INT32 (Vector3 (red * percent, green * percent, blue * percent));
- }
- //
- // Get the hilight rect
- //
- RectClass sel_rect;
- Get_Entry_Rect (CurrSel, sel_rect);
- if (sel_rect.Top >= TextRect.Top && sel_rect.Bottom <= TextRect.Bottom) {
- //
- // Render the outline of the selection (if its on the screen)
- //
- renderer.Add_Outline (sel_rect, 1.0F, color);
- }
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Create_Text_Renderers
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::Create_Text_Renderers (void)
- {
- //
- // Configure the text renderers
- //
- HeaderRenderer.Reset ();
- TextRenderer.Reset ();
- HilightRenderer.Reset ();
- UnderlineRenderer.Reset ();
- IconMgr.Reset_Renderers ();
- //
- // Prepare the column header (if necessary)
- //
- if ((Style & LVS_NOCOLUMNHEADER) == 0) {
- //
- // Render each column header
- //
- int x_pos = HeaderRect.Left;
- for (int index = 0; index < ColList.Count (); index ++) {
- //
- // Build a bounding rectangle for this column header
- //
- RectClass rect = HeaderRect;
- rect.Left = x_pos;
- rect.Right = x_pos + (ColList[index]->Get_Width () * HeaderRect.Width ());
- //
- // Let the last column extend to the edge
- //
- if (index == ColList.Count () - 1) {
- rect.Right = HeaderRect.Right;
- }
- //
- // Get the color
- //
- int color = VRGB_TO_INT32 (ColList[index]->Get_Color ());
- //
- // Underline the header
- //
- Vector2 text_extent = HeaderRenderer.Get_Text_Extents (ColList[index]->Get_Name ());
- float y_pos = (rect.Top + (rect.Height () / 2) + (text_extent.Y / 2)) + 2.0F;
- UnderlineRenderer.Add_Line (Vector2 (rect.Left, y_pos),
- Vector2 (rect.Left + text_extent.X, y_pos), 1.0F, color);
- //
- // Draw the sort designator
- //
- if (SortType != SORT_NONE && SortColumn == index) {
- const float TRI_WIDTH = 8;
- const float TRI_SPACE = 2;
- float tri_size = TRI_WIDTH * StyleMgrClass::Get_Y_Scale ();
- float tri_half_size = tri_size * 0.5F;
- float tri_x_pos = rect.Left + text_extent.X + tri_size + (TRI_SPACE * StyleMgrClass::Get_Y_Scale ());
- float tri_y_pos = HeaderRect.Center ().Y;
- if (SortType == SORT_ASCENDING) {
- UnderlineRenderer.Add_Line (Vector2 (tri_x_pos - tri_half_size, tri_y_pos + tri_half_size),
- Vector2 (tri_x_pos + tri_half_size, tri_y_pos + tri_half_size), 1.0F, color);
- UnderlineRenderer.Add_Line (Vector2 (tri_x_pos + tri_half_size, tri_y_pos + tri_half_size),
- Vector2 (tri_x_pos, tri_y_pos - tri_half_size), 1.0F, color);
- UnderlineRenderer.Add_Line (Vector2 (tri_x_pos, tri_y_pos - tri_half_size),
- Vector2 (tri_x_pos - tri_half_size, tri_y_pos + tri_half_size), 1.0F, color);
-
- } else {
- UnderlineRenderer.Add_Line (Vector2 (tri_x_pos - tri_half_size, tri_y_pos - tri_half_size),
- Vector2 (tri_x_pos + tri_half_size, tri_y_pos - tri_half_size), 1.0F, color);
- UnderlineRenderer.Add_Line (Vector2 (tri_x_pos + tri_half_size, tri_y_pos - tri_half_size),
- Vector2 (tri_x_pos, tri_y_pos + tri_half_size), 1.0F, color);
- UnderlineRenderer.Add_Line (Vector2 (tri_x_pos, tri_y_pos + tri_half_size),
- Vector2 (tri_x_pos - tri_half_size, tri_y_pos - tri_half_size), 1.0F, color);
- }
- }
- //
- // Render the text
- //
- StyleMgrClass::Render_Text (ColList[index]->Get_Name (), &HeaderRenderer,
- color, RGB_TO_INT32 (0, 0, 0), rect, true, true);
- //
- // Move on to the next column
- //
- x_pos = rect.Right;
- }
- }
- //
- // Render the data by rows
- //
- float y_pos = TextRect.Top;
- int row_count = Get_Entry_Count ();
- for (int row_index = ScrollPos; row_index < row_count; row_index ++) {
- //
- // Get the height of this row
- //
- float row_height = RowInfoList[row_index]->Get_Height ();
- //
- // Don't render past the bottom of the control
- //
- if ((y_pos + row_height) >= TextRect.Bottom) {
- break;
- }
- //
- // Render each column in this row
- //
- float x_pos = TextRect.Left;
- for (int index = 0; index < ColList.Count (); index ++) {
- //
- // Determine how wide this column is
- //
- float col_width = (ColList[index]->Get_Width () * HeaderRect.Width ());
- if (index == ColList.Count () - 1) {
- col_width = TextRect.Right - x_pos;
- }
- //
- // Build a bounding rectangle for this entry
- //
- RectClass rect;
- rect.Left = int(x_pos);
- rect.Right = int(x_pos + col_width);
- rect.Top = int(y_pos);
- rect.Bottom = int(y_pos + row_height);
- //
- // Render the entry
- //
- Render_Entry (rect, index, row_index);
- //
- // Move on to the next column
- //
- x_pos = rect.Right;
- }
- //
- // Render a hilight on this row if necessary
- //
- if (Is_Entry_Selected (row_index)) {
- RectClass row_rect = TextRect;
- row_rect.Top = (int)max (TextRect.Top, (float)y_pos);
- row_rect.Bottom = (int)min (TextRect.Bottom, (float)(y_pos + row_height));
- StyleMgrClass::Render_Hilight (&HilightRenderer, row_rect);
- }
- //
- // Move down to the next row
- //
- y_pos += row_height;
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Render_Entry
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::Render_Entry (const RectClass &clip_rect, int col_index, int row_index)
- {
- RectClass rect = clip_rect;
- //
- // Render the icons
- //
- int icon_count = ColList[col_index]->Get_Icon_Count (row_index);
- for (int index = 0; index < icon_count; index ++) {
-
- //
- // Render this icon
- //
- const char *icon_name = ColList[col_index]->Get_Icon (row_index, index);
- IconMgr.Render_Icon (rect, icon_name);
- //
- // Move the rect by the width of the icon
- //
- rect.Left += IconMgr.Get_Icon_Width ();
- }
- //
- // Get the text
- //
- const WCHAR *text = ColList[col_index]->Get_Entry_Text (row_index);
- int text_color = VRGB_TO_INT32 (ColList[col_index]->Get_Entry_Color (row_index));
-
- //
- // Render the text
- //
- StyleMgrClass::Render_Wrapped_Text (text, &TextRenderer, text_color,
- RGB_TO_INT32 (0, 0, 0), rect, true, true);
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // On_Set_Cursor
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::On_Set_Cursor (const Vector2 &mouse_pos)
- {
- if (IsSelectionAllowed) {
- //
- // Change the mouse cursor
- //
- MouseMgrClass::Set_Cursor (MouseMgrClass::CURSOR_ACTION);
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Set_Sort_Designator
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::Set_Sort_Designator (int col_index, SORT_TYPE type)
- {
- SortColumn = col_index;
- SortType = type;
-
- Set_Dirty ();
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Sort_Alphabetically
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::Sort_Alphabetically (int col_index, SORT_TYPE type)
- {
- //
- // Sort the entries
- //
- Sort (Default_Sort_Callback, MAKELONG ((WORD)col_index, (WORD)type));
- //
- // Update the sort marker
- //
- Set_Sort_Designator (col_index, type);
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Default_Sort_Callback
- //
- ////////////////////////////////////////////////////////////////
- int CALLBACK
- ListCtrlClass::Default_Sort_Callback (ListCtrlClass *list_ctrl, int item_index1, int item_index2, uint32 user_param)
- {
- //
- // Get the sorting params
- //
- int sort_col_index = LOWORD (user_param);
- SORT_TYPE sort_type = (SORT_TYPE)HIWORD (user_param);
-
- //
- // Sort by name
- //
- const WCHAR *name1 = list_ctrl->Get_Entry_Text (item_index1, sort_col_index);
- const WCHAR *name2 = list_ctrl->Get_Entry_Text (item_index2, sort_col_index);
- int retval = ::CompareStringW (LOCALE_USER_DEFAULT, NORM_IGNORECASE, name1, -1, name2, -1);
- if (retval == 0) {
- retval = wcsicmp(name1, name2);
- } else {
- retval -= 2;
- }
- //
- // Invert the return value if we are sorting descendingly
- //
- if (sort_type == SORT_DESCENDING) {
- retval = -retval;
- }
- return retval;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Update_Client_Rect
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::Update_Client_Rect (void)
- {
- Vector2 header_size = HeaderRenderer.Get_Text_Extents (L"W");
- //
- // Set the client area
- //
- ClientRect = Rect;
- ClientRect.Inflate (Vector2 (-header_size.X, -1));
- HeaderRect = ClientRect;
- TextRect = ClientRect;
- //
- // Calculate what the header rectangle should be
- //
- if ((Style & LVS_NOCOLUMNHEADER) == 0) {
- float char_height = header_size.Y;
- HeaderRect.Bottom = HeaderRect.Top + (char_height * 3);
- } else {
- HeaderRect.Bottom = HeaderRect.Top;
- }
- //
- // Move the text rectangle down
- //
- TextRect.Top = HeaderRect.Bottom;
- //float scale_y = Render2DClass::Get_Screen_Resolution().Height () / 600;
- //
- // Choose an arbitrary width, the scroll bar
- // will snap to the only width it supports
- //
- float width = 10;
- //
- // Calculate the scroll bar's rectangle
- //
- RectClass scroll_rect;
- scroll_rect.Left = Rect.Right - width;
- scroll_rect.Top = Rect.Top;
- scroll_rect.Right = Rect.Right;
- scroll_rect.Bottom = Rect.Bottom;
- //
- // Size the scroll bar
- //
- ScrollBarCtrl.Set_Window_Rect (scroll_rect);
- Set_Dirty ();
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Find_Top_Of_Page
- //
- ////////////////////////////////////////////////////////////////
- int
- ListCtrlClass::Find_Top_Of_Page (int bottom_index)
- {
- int retval = 0;
- //int count = RowInfoList.Count ();
- float y_pos = TextRect.Bottom;
- //
- // Scan the entries until we've found the first one
- // to extend off the top of the page
- //
- for (int index = bottom_index; index >= 0; index --) {
- y_pos -= RowInfoList[index]->Get_Height ();
- //
- // If we've gone off the page, then back off one entry
- //
- if (y_pos < TextRect.Top) {
- retval = (index + 1);
- break;
- }
- }
-
- return retval;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Find_End_Of_Page
- //
- ////////////////////////////////////////////////////////////////
- int
- ListCtrlClass::Find_End_Of_Page (void)
- {
- int count = RowInfoList.Count ();
- int retval = count;
- float y_pos = TextRect.Top;
- //
- // Scan the entries until we've found the first one
- // to extend off the page
- //
- for (int index = ScrollPos; index < count; index ++) {
- y_pos += RowInfoList[index]->Get_Height ();
- //
- // If we've gone off the page, then back off one entry
- //
- if (y_pos >= TextRect.Bottom) {
- retval = (index - 1);
- break;
- }
- }
-
- return retval;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Find_Last_Page_Top_Entry
- //
- ////////////////////////////////////////////////////////////////
- int
- ListCtrlClass::Find_Last_Page_Top_Entry (void)
- {
- int retval = 0;
- float y_pos = TextRect.Bottom;
- int count = RowInfoList.Count ();
-
- //
- // Scan backwards from the bottom entry until we've
- // found one that extends off the top of the page.
- //
- for (int index = count - 1; index >= 0; index --) {
- y_pos -= RowInfoList[index]->Get_Height ();
- if (y_pos <= TextRect.Top) {
- retval = index + 1;
- break;
- }
- }
-
- return retval;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Update_Scroll_Bar_Visibility
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::Update_Scroll_Bar_Visibility (void)
- {
- LastPageTopEntryIndex = Find_Last_Page_Top_Entry ();
- //
- // Configure the scroll-bar's ranges
- //
- ScrollBarCtrl.Set_Page_Size (0);
- ScrollBarCtrl.Set_Range (0, LastPageTopEntryIndex);
- //
- // Determine if we have more entries then we can
- // display on one page
- //
- bool needs_scrollbar = false;
- float y_pos = TextRect.Top;
- for (int index = 0; index < RowInfoList.Count (); index ++) {
- y_pos += RowInfoList[index]->Get_Height ();
- if (y_pos >= TextRect.Bottom) {
- needs_scrollbar = true;
- break;
- }
- }
- float new_right = 0;
- //
- // Do we need to show a scroll bar?
- //
- bool was_scrollbar_displayed = IsScrollBarDisplayed;
- if (needs_scrollbar) {
- new_right = ScrollBarCtrl.Get_Window_Rect ().Left;
- IsScrollBarDisplayed = true;
- } else if (Parent != NULL) {
- new_right = ScrollBarCtrl.Get_Window_Rect ().Right;
- IsScrollBarDisplayed = false;
- }
- //
- // Reset our window size (as necessary)
- //
- Rect.Right = new_right;
- ClientRect.Right = Rect.Right - (ClientRect.Left - Rect.Left);
- TextRect.Right = ClientRect.Right;
- HeaderRect.Right = ClientRect.Right;
- //
- // Update the row heights of each entry if the scroll bar
- // visibility changed
- //
- if (was_scrollbar_displayed != IsScrollBarDisplayed) {
- for (index = 0; index < RowInfoList.Count (); index ++) {
- Update_Row_Height (index);
- }
- //
- // Update the last page top entry
- //
- LastPageTopEntryIndex = Find_Last_Page_Top_Entry ();
- }
- //
- // Configure the scroll-bar's ranges
- //
- ScrollBarCtrl.Set_Page_Size (0);
- ScrollBarCtrl.Set_Range (0, LastPageTopEntryIndex);
- //
- // Configure the scroll bar's position
- //
- if (ScrollBarCtrl.Get_Pos () > LastPageTopEntryIndex) {
- int new_pos = max (LastPageTopEntryIndex, 0);
- ScrollBarCtrl.Set_Pos (new_pos);
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Render
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::Render (void)
- {
- //
- // Recreate the renderers (if necessary)
- //
- if (IsDirty) {
- Update_Scroll_Bar_Visibility ();
- Create_Text_Renderers ();
- }
- if (IsScrollBarDisplayed) {
- Parent->Add_Control (&ScrollBarCtrl);
- } else {
- Parent->Remove_Control (&ScrollBarCtrl);
- }
- if (HasFocus || IsDirty) {
- Create_Control_Renderer ();
- }
- //
- // Render the background and text
- //
- IconMgr.Render_Icons ();
- TextRenderer.Render ();
- HilightRenderer.Render ();
- UnderlineRenderer.Render ();
- HeaderRenderer.Render ();
- ControlRenderer.Render ();
- DialogControlClass::Render ();
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Get_First_Selected
- //
- ////////////////////////////////////////////////////////////////
- int
- ListCtrlClass::Get_First_Selected (void) const
- {
- int retval = -1;
- //
- // Loop over all the entries in the list control
- //
- int entry_count = Get_Entry_Count ();
- for (int index = 0; index < entry_count; index ++) {
-
- //
- // Is this entry selected?
- //
- if (RowInfoList[index]->Is_Selected ()) {
- retval = index;
- break;
- }
- }
- return retval;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Get_Next_Selected
- //
- ////////////////////////////////////////////////////////////////
- int
- ListCtrlClass::Get_Next_Selected (int index) const
- {
- int retval = -1;
- //
- // Loop over all the entries in the list control
- //
- int entry_count = Get_Entry_Count ();
- for (index ++; index < entry_count; index ++) {
-
- //
- // Is this entry selected?
- //
- if (RowInfoList[index]->Is_Selected ()) {
- retval = index;
- break;
- }
- }
- return retval;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Select_All
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::Select_All (bool select)
- {
- //
- // Loop over all the entries in the list control
- //
- int entry_count = Get_Entry_Count ();
- for (int index = 0; index < entry_count; index ++) {
- RowInfoList[index]->Select (select);
- }
- Set_Dirty();
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Toggle_Entry_Selection
- //
- ////////////////////////////////////////////////////////////////
- bool
- ListCtrlClass::Toggle_Entry_Selection (int index)
- {
- if (index < 0 || index >= Get_Entry_Count ()) {
- return false;
- }
- //
- // Toggle the selection of this entry
- //
- bool selected = RowInfoList[index]->Is_Selected ();
- RowInfoList[index]->Select (!selected);
- Set_Dirty ();
- return false;
- }
- ////////////////////////////////////////////////////////////////
- //
- // On_LButton_DblClk
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::On_LButton_DblClk (const Vector2 &mouse_pos)
- {
- int sel_entry = Entry_From_Pos (mouse_pos);
- if (sel_entry == CurrSel) {
- //
- // Notify any advise sinks
- //
- ADVISE_NOTIFY (On_ListCtrl_DblClk (this, Get_ID (), sel_entry));
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // On_LButton_Down
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::On_LButton_Down (const Vector2 &mouse_pos)
- {
- if (mouse_pos.Y <= HeaderRect.Bottom) {
- //
- // Find out which column was clicked
- //
- int col_index = Col_From_Pos (mouse_pos);
- if (-1 != col_index) {
- //
- // Notify any advise sinks
- //
- ADVISE_NOTIFY (On_ListCtrl_Column_Click (this, Get_ID (), col_index));
- }
- } else {
- //
- // Change the hilighted entry to reflect the mouse click
- //
- int new_sel = Entry_From_Pos (mouse_pos);
- if (new_sel != -1) {
- Set_Sel (new_sel, true);
- } else if (IsNoSelectionAllowed) {
- Set_Sel(-1, true);
- }
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // On_LButton_Up
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::On_LButton_Up (const Vector2 &mouse_pos)
- {
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // On_Mouse_Move
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::On_Mouse_Move (const Vector2 &mouse_pos)
- {
- int sel_entry = Entry_From_Pos(mouse_pos);
- ADVISE_NOTIFY(On_ListCtrl_Mouse_Over(this, Get_ID(), sel_entry));
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // On_Set_Focus
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::On_Set_Focus (void)
- {
- Set_Dirty ();
- DialogControlClass::On_Set_Focus ();
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // On_Kill_Focus
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::On_Kill_Focus (DialogControlClass *focus)
- {
- Set_Dirty ();
- DialogControlClass::On_Kill_Focus (focus);
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // On_Key_Down
- //
- ////////////////////////////////////////////////////////////////
- bool
- ListCtrlClass::On_Key_Down (uint32 key_id, uint32 key_data)
- {
- bool handled = true;
- switch (key_id)
- {
- case VK_UP:
- case VK_LEFT:
- Set_Sel (CurrSel - 1, true);
- break;
- case VK_DOWN:
- case VK_RIGHT:
- Set_Sel (CurrSel + 1, true);
- break;
- case VK_PRIOR:
- if (CurrSel == ScrollPos) {
- Scroll_Page (-1);
- } else {
- Set_Sel (ScrollPos, true);
- }
- break;
- case VK_NEXT:
- {
- int end_of_page = Find_End_Of_Page ();
- //
- // If we are at the end of the page, then
- // scroll one page, otherwise snap to the
- // end of the page
- //
- if (CurrSel == end_of_page) {
- Scroll_Page (1);
- } else {
- Set_Sel (end_of_page, true);
- }
- break;
- }
- case VK_HOME:
- Set_Sel (0, true);
- break;
- case VK_END:
- Set_Sel (Get_Entry_Count () - 1, true);
- break;
- case VK_SPACE:
- case VK_RETURN:
- ADVISE_NOTIFY(On_ListCtrl_DblClk(this, Get_ID(), Get_Curr_Sel()));
- break;
- default:
- handled = false;
- break;
- }
- return handled;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Sort
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::Sort (LISTCTRL_SORT_CALLBACK sort_callback, uint32 user_param)
- {
- //
- // Quick sort the data
- //
- int entry_count = Get_Entry_Count ();
- if (entry_count > 1) {
- Quick_Sort (0, entry_count - 1, sort_callback, user_param);
- }
- //
- // Force a repaint
- //
- Set_Dirty ();
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Quick_Sort
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::Quick_Sort
- (
- int start_index,
- int end_index,
- LISTCTRL_SORT_CALLBACK sort_callback,
- uint32 user_param
- )
- {
- //
- // Setup a handy macro for swapping all columns of a particular row
- //
- #define QSORT_ROW_SWAP(index1, index2) \
- { \
- if (CurrSel == index1) { CurrSel = index2; } \
- else if (CurrSel == index2) { CurrSel = index1; } \
- ListRowClass *temp = RowInfoList[index1]; \
- RowInfoList[index1] = RowInfoList[index2]; \
- RowInfoList[index2] = temp; \
- for (int col_index = 0; col_index < ColList.Count (); col_index ++) { \
- ColList[col_index]->Swap_Entries (index1, index2); \
- } \
- }
- //
- // Determine our ranges
- //
- int pivot_index = start_index;
- int min_index = min (start_index + 1, end_index);
- int max_index = end_index;
- //
- // If the range is large enough, try to pick
- // a *good* pivot point.
- //
- if ((end_index - start_index) > 10) {
- int middle_index = start_index + ((end_index - start_index) / 2);
- //
- // Put the smaller of the middle and end indices into the middle slot
- //
- if ((*sort_callback) (this, end_index, middle_index, user_param) < 0) {
- QSORT_ROW_SWAP (end_index, middle_index);
- }
- //
- // Put the larger of the middle and start indices into the start slot
- //
- if ((*sort_callback) (this, middle_index, start_index, user_param) > 0) {
- QSORT_ROW_SWAP (middle_index, start_index);
- }
- //
- // Put the smaller of the start and end indices into the start slot
- //
- if ((*sort_callback) (this, end_index, start_index, user_param) < 0) {
- QSORT_ROW_SWAP (end_index, start_index);
- }
- }
- //
- // Put all the other entries in our range on either the lower or upper
- // side of the pivot entry based on their relative sort value.
- //
- bool keep_going = true;
- do
- {
- //
- // Find the first entry that is "greater-than" the pivot
- //
- for (; min_index <= max_index; min_index ++) {
- //
- // Is this entry "greater-than" the pivot?
- //
- if ((*sort_callback) (this, min_index, start_index, user_param) > 0) {
- break;
- }
- //
- // The last index that is "less-than" the pivot entry will
- // be the pivot's new index.
- //
- pivot_index = min_index;
- }
- //
- // Find the last entry that is "less-than" the pivot
- //
- for (; max_index >= min_index; max_index --) {
- //
- // Is this entry "less-than" the pivot?
- //
- if ((*sort_callback) (this, max_index, start_index, user_param) < 0) {
- break;
- }
- }
- //
- // Have we processed all the entries in our range?
- //
- if (min_index >= max_index) {
- keep_going = false;
- } else {
- //
- // Swap the entries
- //
- QSORT_ROW_SWAP (min_index, max_index);
- //
- // For efficiency's sake, skip over the entries we just swapped.
- //
- min_index ++;
- max_index --;
- pivot_index ++;
- }
- } while (keep_going);
- //
- // Insert the pivot point into its "sorted" position in the array (if necessary)
- //
- if (pivot_index > start_index) {
- QSORT_ROW_SWAP (start_index, pivot_index);
- }
- //
- // Calculate the region below the pivot
- //
- int lower_range_min = start_index;
- int lower_range_max = pivot_index - 1;
- //
- // Recurse (if necessary) into the region below the pivot
- //
- if (lower_range_max < end_index && lower_range_min < lower_range_max) {
- Quick_Sort (lower_range_min, lower_range_max, sort_callback, user_param);
- }
- //
- // Calculate the region above the pivot
- //
- int upper_range_min = pivot_index + 1;
- int upper_range_max = end_index;
- //
- // Recurse (if necessary) into the region above the pivot
- //
- if (upper_range_min > start_index && upper_range_min < upper_range_max) {
- Quick_Sort (upper_range_min, upper_range_max, sort_callback, user_param);
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // On_Create
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::On_Create (void)
- {
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // On_Destroy
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::On_Destroy (void)
- {
- Delete_All_Entries ();
- Delete_All_Columns ();
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Auto_Size_Columns_Include_Contents
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::Auto_Size_Columns_Include_Contents (float col_spacing)
- {
- float total_width = HeaderRect.Width ();
- //
- // Loop over all the columns
- //
- for (int index = 0; index < ColList.Count (); index ++) {
- float max_width = HeaderRenderer.Get_Text_Extents (ColList[index]->Get_Name ()).X;
- //
- // Now, take into consideration the largest entry we've got
- //
- int count = ColList[index]->Get_Entry_Count ();
- for (int row = 0; row < count; row ++) {
- float width = TextRenderer.Get_Text_Extents (ColList[index]->Get_Entry_Text (row)).X;
- max_width = max (width, max_width);
- //
- // Add the width of all the icons to this row's total
- //
- int icon_count = ColList[index]->Get_Icon_Count (row);
- for (int icon_index = 0; icon_index < icon_count; icon_index ++) {
- max_width += IconMgr.Get_Icon_Width ();
- }
- }
- //
- // Auto-size this column
- //
- float percent = (max_width + col_spacing) / total_width;
- ColList[index]->Set_Width (percent);
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Auto_Size_Columns
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::Auto_Size_Columns (float col_spacing)
- {
- float max_width = HeaderRect.Width ();
- for (int index = 0; index < ColList.Count (); index ++) {
- //
- // Auto-size this column
- //
- float width = HeaderRenderer.Get_Text_Extents (ColList[index]->Get_Name ()).X;
- float percent = (width + col_spacing) / max_width;
- ColList[index]->Set_Width (percent);
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Add_Icon
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::Add_Icon (int index, int col_index, const char *texture_name)
- {
- if (col_index < 0 || col_index >= ColList.Count ()) {
- return ;
- }
- //
- // Add an icon to this entry
- //
- IconMgr.Add_Icon (texture_name);
- ColList[col_index]->Add_Icon (index, texture_name);
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Reset_Icons
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::Reset_Icons (int index, int col_index)
- {
- if (col_index < 0 || col_index >= ColList.Count ()) {
- return ;
- }
- //
- // Reset all the icons in this entry
- //
- ColList[col_index]->Reset_Icons (index);
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Add_Column
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::Add_Column (const WCHAR *column_name, float width, const Vector3 &color)
- {
- //
- // Create a new column and add it to the list
- //
- ListColumnClass *column = new ListColumnClass;
- column->Set_Name (column_name);
- column->Set_Width (width);
- column->Set_Color (color);
- ColList.Add (column);
- Set_Dirty ();
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Set_Column_Color
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::Set_Column_Color (int col_index, const Vector3 &color)
- {
- if (col_index < 0 || col_index >= ColList.Count ()) {
- return ;
- }
- ColList[col_index]->Set_Color (color);
- Set_Dirty ();
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Remove_Column
- //
- ////////////////////////////////////////////////////////////////
- bool
- ListCtrlClass::Remove_Column (int index)
- {
- if (index < 0 || index >= ColList.Count ()) {
- return false;
- }
- //
- // Free the column
- //
- ListColumnClass *column = ColList[index];
- delete column;
- //
- // Remove the column from the list
- //
- ColList.Delete (index);
- Set_Dirty ();
- return true;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Delete_All_Columns
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::Delete_All_Columns (void)
- {
- for (int index = 0; index < ColList.Count (); index ++) {
- ListColumnClass *column = ColList[index];
- delete column;
- }
- ColList.Delete_All ();
- Set_Dirty ();
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Get_Column_Count
- //
- ////////////////////////////////////////////////////////////////
- int
- ListCtrlClass::Get_Column_Count (void) const
- {
- return ColList.Count ();
- }
- ////////////////////////////////////////////////////////////////
- //
- // Get_Entry_Count
- //
- ////////////////////////////////////////////////////////////////
- int
- ListCtrlClass::Get_Entry_Count (void) const
- {
- return RowInfoList.Count ();
- }
- ////////////////////////////////////////////////////////////////
- //
- // Delete_Entry
- //
- ////////////////////////////////////////////////////////////////
- bool
- ListCtrlClass::Delete_Entry (int index)
- {
- bool retval = true;
- //
- // Nofity the advise sinks that we are deleting this entry
- //
- ADVISE_NOTIFY (On_ListCtrl_Delete_Entry (this, Get_ID (), index));
- //
- // Remove this row from our data structures
- //
- if (index >= 0 && index < RowInfoList.Count ()) {
- delete RowInfoList[index];
- RowInfoList.Delete (index);
- }
- //
- // Remove this entry from each column
- //
- for (int col_index = 0; col_index < ColList.Count (); col_index ++) {
- retval &= ColList[col_index]->Delete_Entry (index);
- }
- // When an entry that is before the current selection is deleted then
- // we need to adjust the current selection to reflect that.
- if (index < CurrSel) {
- --CurrSel;
- }
- //
- // Update the current selection indicator (if necessary)
- //
- int entry_count = Get_Entry_Count ();
- if (CurrSel >= entry_count) {
- CurrSel = entry_count - 1;
- }
- //
- // Hilight the new current selection (if necessary)
- //
- if (CurrSel >= 0 && CurrSel <= RowInfoList.Count ()) {
- RowInfoList[CurrSel]->Select ((IsMultipleSelection == false));
- }
- Set_Dirty ();
- return retval;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Find_Entry
- //
- ////////////////////////////////////////////////////////////////
- int ListCtrlClass::Find_Entry(int col_index, const WCHAR* text)
- {
- int count = ColList.Count();
- if (col_index >= 0 && col_index < count) {
- ListColumnClass* list = ColList[col_index];
- count = list->Get_Entry_Count();
- for (int index = 0; index < count; index++) {
- const WCHAR* entryText = list->Get_Entry_Text(index);
- if (wcscmp(entryText, text) == 0) {
- return index;
- }
- }
- }
- return -1;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Insert_Entry
- //
- ////////////////////////////////////////////////////////////////
- int
- ListCtrlClass::Insert_Entry (int index, const WCHAR *text)
- {
- if (ColList.Count () <= 0) {
- return -1;
- }
- //
- // Insert a blank row in our data structure
- //
- if (index < RowInfoList.Count ()) {
- RowInfoList.Insert (index + 1, new ListRowClass);
- } else {
- RowInfoList.Add (new ListRowClass);
- }
- //
- // Insert a new entry in the first column with the given text
- //
- index = ColList[0]->Insert_Entry (index, text);
- //
- // Use the default text color for each new entry
- //
- int color = StyleMgrClass::Get_Text_Color ();
- float red = ((color & 0x00FF0000) >> 16) / 256.0F;
- float green = ((color & 0x0000FF00) >> 8) / 256.0F;
- float blue = ((color & 0x000000FF)) / 256.0F;
- Vector3 new_color (red, green, blue);
-
- ColList[0]->Set_Entry_Color (index, new_color);
- //
- // Add blank entries to all the other columns
- //
- for (int col_index = 1; col_index < ColList.Count (); col_index ++) {
- ListColumnClass *column = ColList[col_index];
- column->Insert_Entry (index, L"");
- column->Set_Entry_Color (index, new_color);
- }
- //
- // Update the cached row height for this entry...
- //
- Update_Row_Height (index);
- //
- // Update the last page top entry
- //
- LastPageTopEntryIndex = Find_Last_Page_Top_Entry ();
- Set_Dirty ();
- return index;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Update_Row_Height
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::Update_Row_Height (int row_index)
- {
- int border_height = (ROW_SPACING * StyleMgrClass::Get_Y_Scale ());
- float height = (TextRenderer.Get_Text_Extents (L"W").Y + border_height);
- //
- // Render each column in this row
- //
- float x_pos = TextRect.Left;
- for (int index = 0; index < ColList.Count (); index ++) {
- //
- // Determine how wide this column is
- //
- float col_width = (ColList[index]->Get_Width () * HeaderRect.Width ());
- if (index == ColList.Count () - 1) {
- col_width = TextRect.Right - x_pos;
- }
- //
- // Set the wrapping width
- //
- TextRenderer.Set_Wrapping_Width (col_width);
-
- //
- // Calculate the height of this text
- //
- const WCHAR *text = ColList[index]->Get_Entry_Text (row_index);
- Vector2 extents = TextRenderer.Get_Formatted_Text_Extents (text);
- height = max (height, extents.Y + border_height);
- //
- // Increment the x-position
- //
- x_pos += col_width;
- }
- //
- // Make sure the row is AT LEST MinRowHeight units high
- //
- float min_height = MinRowHeight * StyleMgrClass::Get_Y_Scale ();
- height = max (min_height, height);
-
- //
- // Store the row height
- //
- RowInfoList[row_index]->Set_Height (height);
- TextRenderer.Set_Wrapping_Width (0);
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Set_Icon_Size
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::Set_Icon_Size (float width, float height)
- {
- //
- // Pass these values on the icon manager
- //
- IconMgr.Set_Icon_Width (width);
- IconMgr.Set_Icon_Height (height);
- Set_Dirty ();
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Set_Min_Row_Height
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::Set_Min_Row_Height (int height)
- {
- MinRowHeight = height;
- //
- // Update each row using this new height information
- //
- for (int index = 0; index < RowInfoList.Count (); index ++) {
- Update_Row_Height (index);
- }
- Set_Dirty ();
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Select_Entry
- //
- ////////////////////////////////////////////////////////////////
- bool
- ListCtrlClass::Select_Entry (int index, bool onoff)
- {
- if (index < 0 || index >= Get_Entry_Count ()) {
- return false;
- }
- //
- // Set the selection state of the row
- //
- RowInfoList[index]->Select (onoff);
- Set_Dirty ();
- return true;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Is_Entry_Selected
- //
- ////////////////////////////////////////////////////////////////
- bool
- ListCtrlClass::Is_Entry_Selected (int index)
- {
- bool retval = false;
- if (index >= 0 && index < Get_Entry_Count ()) {
-
- //
- // Get the selection state of the row
- //
- retval = RowInfoList[index]->Is_Selected ();
- Set_Dirty ();
- }
- return retval;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Set_Entry_Text
- //
- ////////////////////////////////////////////////////////////////
- bool
- ListCtrlClass::Set_Entry_Text (int index, int col_index, const WCHAR *text)
- {
- if (col_index < 0 || col_index >= ColList.Count ()) {
- return false;
- }
- //
- // Change the text entry in this cell
- //
- ColList[col_index]->Set_Entry_Text (index, text);
- //
- // Update the cached row height for this entry...
- //
- Update_Row_Height (index);
- //
- // Update the last page top entry
- //
- LastPageTopEntryIndex = Find_Last_Page_Top_Entry ();
- Set_Dirty ();
- return true;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Set_Entry_Int
- //
- ////////////////////////////////////////////////////////////////
- bool
- ListCtrlClass::Set_Entry_Int (int index, int col_index, int value)
- {
- if (col_index < 0 || col_index >= ColList.Count ()) {
- return false;
- }
- //
- // Convert the integer to a string
- //
- WideStringClass number_str;
- number_str.Format (L"%d", value);
- //
- // Change the text entry in this cell
- //
- ColList[col_index]->Set_Entry_Text (index, number_str);
- Set_Dirty ();
- return true;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Set_Entry_Color
- //
- ////////////////////////////////////////////////////////////////
- bool
- ListCtrlClass::Set_Entry_Color (int index, int col_index, const Vector3 &color)
- {
- if (col_index < 0 || col_index >= ColList.Count ()) {
- return false;
- }
- //
- // Change the color for the entry in this cell
- //
- ColList[col_index]->Set_Entry_Color (index, color);
- Set_Dirty ();
- return true;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Set_Entry_Data
- //
- ////////////////////////////////////////////////////////////////
- bool
- ListCtrlClass::Set_Entry_Data (int index, int col_index, uint32 user_data)
- {
- //
- // Store the user data in the first column
- //
- ColList[col_index]->Set_Entry_Data (index, user_data);
- return true;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Get_Entry_Data
- //
- ////////////////////////////////////////////////////////////////
- uint32
- ListCtrlClass::Get_Entry_Data (int index, int col_index)
- {
- uint32 user_data = 0;
- //
- // Lookup the user data
- //
- if (index >= 0 && index < Get_Entry_Count () && col_index >= 0 && col_index < ColList.Count ()) {
- user_data = ColList[col_index]->Get_Entry_Data (index);
- }
- return user_data;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Get_Entry_Text
- //
- ////////////////////////////////////////////////////////////////
- const WCHAR *
- ListCtrlClass::Get_Entry_Text (int index, int col_index)
- {
- //
- // Return the string to the caller
- //
- return ColList[col_index]->Get_Entry_Text (index);
- }
- ////////////////////////////////////////////////////////////////
- //
- // Delete_All_Entries
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::Delete_All_Entries (void)
- {
- //
- // Notify the advise sinks (if necessary) that each entry
- // is being deleted
- //
- int entry_count = Get_Entry_Count ();
- for (int item_index = 0; item_index < entry_count; item_index ++) {
- ADVISE_NOTIFY (On_ListCtrl_Delete_Entry (this, Get_ID (), item_index));
- }
- //
- // Delete each of our row information sturctures
- //
- for (int index = 0; index < RowInfoList.Count (); index ++) {
- delete RowInfoList[index];
- }
- RowInfoList.Delete_All ();
- //
- // Now delete all the entries from each column
- //
- for (index = 0; index < ColList.Count (); index ++) {
- ColList[index]->Delete_All_Entries ();
- }
- Set_Dirty ();
- //
- // Reset the scroll and current selection positions
- //
- ScrollPos = 0;
- CurrSel = -1;
- Set_Dirty ();
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Scroll_To_End
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::Scroll_To_End (void)
- {
- //
- // Update the last page top entry
- //
- LastPageTopEntryIndex = Find_Last_Page_Top_Entry ();
- //
- // Force scroll to the end
- //
- ScrollPos = LastPageTopEntryIndex;
- ScrollPos = max (ScrollPos, 0);
- //
- // Update the scrollbar
- //
- ScrollBarCtrl.Set_Pos (ScrollPos, false);
- Set_Dirty ();
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Set_Curr_Sel
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::Set_Curr_Sel (int new_sel)
- {
- if (new_sel == -1) {
- Select_All(false);
- CurrSel = -1;
- } else {
- Set_Sel(new_sel, false);
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Set_Sel
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::Set_Sel (int new_sel, bool notify)
- {
- if (IsSelectionAllowed) {
- //
- // Unselect the old entry (if necessary)
- //
- if (IsMultipleSelection == false) {
- Select_Entry (CurrSel, false);
- }
- int old_sel = CurrSel;
- if ((new_sel == -1) && IsNoSelectionAllowed) {
- CurrSel = -1;
- } else {
- //
- // Bound the selection index
- //
- int count = Get_Entry_Count ();
- CurrSel = max (new_sel, 0);
- CurrSel = min (CurrSel, count - 1);
- //
- // Select the new entry
- //
- if (IsMultipleSelection) {
- Toggle_Entry_Selection (CurrSel);
- } else {
- Select_Entry (CurrSel, true);
- }
- }
- //
- // Notify anyone who cares that we have changed the selection
- //
- if (notify && (old_sel != CurrSel)) {
- ADVISE_NOTIFY(On_ListCtrl_Sel_Change(this, Get_ID(), old_sel, CurrSel));
- }
- //
- // Force a repaint
- //
- Set_Dirty ();
- Update_Scroll_Pos ();
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Update_Scroll_Pos
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::Update_Scroll_Pos (void)
- {
- if (CurrSel < 0) {
- return ;
- }
- //
- // Do we need to scroll up?
- //
- if (CurrSel < ScrollPos) {
- ScrollPos = CurrSel;
- Set_Dirty ();
- } else {
- //
- // Do we need to scroll down?
- //
- RectClass rect;
- Get_Entry_Rect (CurrSel, rect);
- if (rect.Bottom >= TextRect.Bottom) {
- //
- // Calculate where we should scroll to
- //
- ScrollPos = Find_Top_Of_Page (CurrSel);
- Set_Dirty ();
- }
- }
- //
- // Update the scrollbar
- //
- ScrollBarCtrl.Set_Pos (ScrollPos, false);
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Get_Entry_Rect
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::Get_Entry_Rect (int index, RectClass &rect)
- {
- if (index < 0 || index >= RowInfoList.Count ()) {
- return ;
- }
- //
- // Lookup the height of this row
- //
- float row_height = RowInfoList[index]->Get_Height ();
- float y_pos = -1000.0F;
- if (ScrollPos <= index) {
- //
- // Calculate the starting y-position of this entry
- //
- y_pos = TextRect.Top;
- for (int curr_index = ScrollPos; curr_index < index; curr_index ++) {
- y_pos += RowInfoList[curr_index]->Get_Height ();
- }
- }
- rect.Left = int(TextRect.Left);
- rect.Right = int(TextRect.Right);
- rect.Top = int(y_pos);
- rect.Bottom = int(rect.Top + row_height);
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Col_From_Pos
- //
- ////////////////////////////////////////////////////////////////
- int
- ListCtrlClass::Col_From_Pos (const Vector2 &mouse_pos)
- {
- int retval = -1;
- //
- // Test each column
- //
- int x_pos = HeaderRect.Left;
- int col_count = ColList.Count ();
- for (int col_index = 0; col_index < col_count; col_index ++) {
- //
- // Determine how wide this column is
- //
- int col_width = (ColList[col_index]->Get_Width () * HeaderRect.Width ());
- //
- // Let the last column extend to the edge
- //
- if (col_index == col_count - 1) {
- col_width = HeaderRect.Right - x_pos;
- }
- //
- // Is the coordinate inside this col?
- //
- if (mouse_pos.X >= x_pos && mouse_pos.X <= (x_pos + col_width)) {
- retval = col_index;
- break;
- }
- //
- // Move on to the next column
- //
- x_pos += col_width;
- }
- return retval;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Entry_From_Pos
- //
- ////////////////////////////////////////////////////////////////
- int
- ListCtrlClass::Entry_From_Pos (const Vector2 &mouse_pos)
- {
- int retval = -1;
- if (mouse_pos.Y < TextRect.Top || mouse_pos.Y > TextRect.Bottom) {
- return -1;
- }
- //
- // Test each row
- //
- int y_pos = TextRect.Top;
- int row_count = Get_Entry_Count ();
- for (int row_index = ScrollPos; row_index < row_count; row_index ++) {
- float row_height = RowInfoList[row_index]->Get_Height ();
- //
- // Is the coordinate inside this row?
- //
- if (mouse_pos.Y >= y_pos && mouse_pos.Y <= (y_pos + row_height)) {
- retval = row_index;
- break;
- }
- //
- // Move down to the next row
- //
- y_pos += row_height;
- //
- // Stop searching if we've moved off the page
- //
- if (mouse_pos.Y >= TextRect.Bottom) {
- break;
- }
- }
- return retval;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Scroll_Page
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::Scroll_Page (int direction)
- {
- int count = RowInfoList.Count ();
- float height = TextRect.Height ();
- bool found = false;
- //
- // Scan either direction from the current scroll
- // position until we've moved a whole page
- //
- for ( int index = ScrollPos;
- index >= 0 && index < count;
- index += direction)
- {
- //
- // Decrement the remaining distance
- //
- height -= RowInfoList[index]->Get_Height ();
- //
- // If we've gone of the page, then back off one entry
- //
- if (height < 0) {
- ScrollPos = (index - direction);
- ScrollPos = min (ScrollPos, LastPageTopEntryIndex);
- ScrollBarCtrl.Set_Pos (ScrollPos, false);
- Set_Dirty ();
- found = true;
- break;
- }
- }
- //
- // Check the boundary conditions
- //
- if (index < 0 && found == false) {
- ScrollPos = 0;
- ScrollBarCtrl.Set_Pos (ScrollPos, false);
- Set_Dirty ();
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // On_VScroll_Page
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::On_VScroll_Page (ScrollBarCtrlClass *scrollbar, int ctrl_id, int direction)
- {
- Scroll_Page (direction);
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // On_VScroll
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::On_VScroll (ScrollBarCtrlClass *, int , int new_position)
- {
- if (ScrollPos != new_position) {
- ScrollPos = new_position;
- Set_Dirty ();
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // On_Mouse_Wheel
- //
- ////////////////////////////////////////////////////////////////
- void
- ListCtrlClass::On_Mouse_Wheel (int direction)
- {
- if (direction < 0) {
- if (ScrollPos > 0) {
- ScrollPos --;
- ScrollBarCtrl.Set_Pos (ScrollPos, false);
- }
- } else {
- if (ScrollPos < LastPageTopEntryIndex) {
- ScrollPos ++;
- ScrollBarCtrl.Set_Pos (ScrollPos, false);
- }
- }
- Set_Dirty ();
- return ;
- }
- //********************************************************************************//
- //
- // Start of ListColumnClass
- //
- //********************************************************************************//
- ////////////////////////////////////////////////////////////////
- //
- // Free_Data
- //
- ////////////////////////////////////////////////////////////////
- void
- ListColumnClass::Free_Data (void)
- {
- Delete_All_Entries ();
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Reset_Contents
- //
- ////////////////////////////////////////////////////////////////
- void
- ListColumnClass::Reset_Contents (void)
- {
- //
- // Remove all the entries
- //
- Free_Data ();
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Insert_Entry
- //
- ////////////////////////////////////////////////////////////////
- int
- ListColumnClass::Insert_Entry (int index, const WCHAR *entry_name)
- {
- ListEntryClass *entry = new ListEntryClass (entry_name);
- //
- // Should we insert this entry in the list or add it to the end?
- //
- if (index < EntryList.Count ()) {
- EntryList.Insert (index + 1, entry);
- } else {
- EntryList.Add (entry);
- index = (EntryList.Count () - 1);
- }
- return index;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Delete_Entry
- //
- ////////////////////////////////////////////////////////////////
- bool
- ListColumnClass::Delete_Entry (int index)
- {
- bool retval = false;
- //
- // Delete the entry if we can find it in our list
- //
- if (index >= 0 && index < EntryList.Count ()) {
- delete EntryList[index];
- EntryList.Delete (index);
- }
- return retval;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Delete_All_Entries
- //
- ////////////////////////////////////////////////////////////////
- void
- ListColumnClass::Delete_All_Entries (void)
- {
- //
- // Free each of the entries in the list
- //
- for (int index = 0; index < EntryList.Count (); index ++) {
- delete EntryList[index];
- }
- EntryList.Delete_All ();
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Move_Entry
- //
- ////////////////////////////////////////////////////////////////
- void
- ListColumnClass::Move_Entry (int old_index, int new_index)
- {
- if ( old_index < 0 || (old_index >= EntryList.Count ()) &&
- new_index < 0 || (new_index >= EntryList.Count ()))
- {
- return ;
- }
- //
- // Move the entry
- //
- ListEntryClass *old_entry = EntryList[old_index];
- EntryList.Insert (new_index, old_entry);
- EntryList.Delete (old_index);
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Swap_Entries
- //
- ////////////////////////////////////////////////////////////////
- void
- ListColumnClass::Swap_Entries (int index1, int index2)
- {
- if ( index1 < 0 || (index1 >= EntryList.Count ()) &&
- index2 < 0 || (index2 >= EntryList.Count ()))
- {
- return ;
- }
- //
- // Move the entry
- //
- ListEntryClass *temp_entry = EntryList[index1];
- EntryList[index1] = EntryList[index2];
- EntryList[index2] = temp_entry;
- return ;
- }
|