| 10749 | |
| 10750 | |
| 10751 | void GuiType::LV_Sort(GuiControlType &aControl, int aColumnIndex, bool aSortOnlyIfEnabled, TCHAR aForceDirection) |
| 10752 | // aForceDirection should be 'A' to force ascending, 'D' to force ascending, or '\0' to use the column's |
| 10753 | // current default direction. |
| 10754 | { |
| 10755 | if (aColumnIndex < 0 || aColumnIndex >= LV_MAX_COLUMNS) // Invalid (avoids array access violation). |
| 10756 | return; |
| 10757 | lv_attrib_type &lv_attrib = *aControl.union_lv_attrib; |
| 10758 | lv_col_type &col = lv_attrib.col[aColumnIndex]; |
| 10759 | |
| 10760 | int item_count = ListView_GetItemCount(aControl.hwnd); |
| 10761 | if ((col.sort_disabled && aSortOnlyIfEnabled) || item_count < 2) // This column cannot be sorted or doesn't need to be. |
| 10762 | return; // Below relies on having returned here when control is empty or contains 1 item. |
| 10763 | |
| 10764 | // Init any lvs members that are needed by both LV_Int32Sort and the other sorting functions. |
| 10765 | // The new sort order is determined by the column's primary order unless the user clicked the current |
| 10766 | // sort-column, in which case the direction is reversed (unless the column is unidirectional): |
| 10767 | LV_SortType lvs; |
| 10768 | if (aForceDirection) |
| 10769 | lvs.sort_ascending = (aForceDirection == 'A'); |
| 10770 | else |
| 10771 | lvs.sort_ascending = (aColumnIndex == lv_attrib.sorted_by_col && !col.unidirectional) |
| 10772 | ? !lv_attrib.is_now_sorted_ascending : !col.prefer_descending; |
| 10773 | |
| 10774 | // Init those members needed for LVM_GETITEM if it turns out to be needed. This section |
| 10775 | // also serves to permanently init cchTextMax for use by the sorting functions too: |
| 10776 | lvs.lvi.pszText = lvs.buf1; |
| 10777 | lvs.lvi.cchTextMax = LV_TEXT_BUF_SIZE - 1; // Set default. Subtracts 1 because of that nagging doubt about size vs. length. Some MSDN examples subtract one, such as TabCtrl_GetItem()'s cchTextMax. |
| 10778 | |
| 10779 | if (col.type == LV_COL_INTEGER) |
| 10780 | { |
| 10781 | // Testing indicates that the following approach is 25 times faster than the general-sort method. |
| 10782 | // Assign the 32-bit integer as the items lParam at this early stage rather than getting the text |
| 10783 | // and converting it to an integer for every call of the sort proc. |
| 10784 | for (lvs.lvi.lParam = 0, lvs.lvi.iItem = 0; lvs.lvi.iItem < item_count; ++lvs.lvi.iItem) |
| 10785 | { |
| 10786 | lvs.lvi.mask = LVIF_TEXT; |
| 10787 | lvs.lvi.iSubItem = aColumnIndex; // Which field to fetch (must be reset each time since it's set to 0 below). |
| 10788 | lvs.lvi.lParam = SendMessage(aControl.hwnd, LVM_GETITEM, 0, (LPARAM)&lvs.lvi) |
| 10789 | ? ATOI(lvs.lvi.pszText) : 0; // Must not refer to lvs.buf1 directly because MSDN says LVM_GETITEMTEXT might have changed pszText to point to some other string. |
| 10790 | lvs.lvi.mask = LVIF_PARAM; |
| 10791 | lvs.lvi.iSubItem = 0; // Indicate that an item vs. subitem is being operated on (subitems can't have an lParam). |
| 10792 | ListView_SetItem(aControl.hwnd, &lvs.lvi); |
| 10793 | } |
| 10794 | // Always use non-Ex() for this one because it's likely to perform best due to the lParam setup above. |
| 10795 | // The value of iSubItem is not reset to aColumnIndex because LV_Int32Sort() doesn't use it. |
| 10796 | SendMessage(aControl.hwnd, LVM_SORTITEMS, lvs.sort_ascending, (LPARAM)LV_Int32Sort); // Should always succeed since it uses non-Ex() version. |
| 10797 | } |
| 10798 | else // It's LV_COL_TEXT or LV_COL_FLOAT. |
| 10799 | { |
| 10800 | if (col.type == LV_COL_TEXT && col.case_sensitive == SCS_INSENSITIVE_LOGICAL) // SCS_INSENSITIVE_LOGICAL can be in effect even when type isn't LV_COL_TEXT because it allows a column to be later changed to TEXT and retain its "logical-sort" setting. |
| 10801 | { |
| 10802 | // v1.0.44.12: Support logical sorting, which treats numeric strings as true numbers like Windows XP |
| 10803 | // Explorer's sorting. This is done here rather than in LV_ModifyCol() because it seems more |
| 10804 | // maintainable/robust (plus LV_GeneralSort() relies on us to do this check). |
| 10805 | lvs.lvi.cchTextMax = lvs.lvi.cchTextMax/2 - 1; // Buffer can hold only half as many Unicode characters as non-Unicode (subtract 1 for the extra-wide NULL terminator). |
| 10806 | } |
| 10807 | // Since LVM_SORTITEMSEX requires comctl32.dll version 5.80+, the non-Ex version is used |
| 10808 | // whenever the EX version fails to work. One reason to strongly prefer the Ex version |