/* ** 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 . */ /*********************************************************************************************** *** 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 //////////////////////////////////////////////////////////////// // 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 ; }