commit 954446b2fe51c79b5e834d0c76644753f1f01007
parent 7058021674a9f0050a461f284e5e3bf59c90f176
Author: cfillion <cfillion@users.noreply.github.com>
Date: Wed, 3 Feb 2016 01:57:21 -0500
implement sorting in list view
Diffstat:
5 files changed, 134 insertions(+), 23 deletions(-)
diff --git a/src/about.cpp b/src/about.cpp
@@ -63,6 +63,8 @@ void About::onInit()
{AUTO_STR("Author"), 90},
});
+ m_packages->sortByColumn(0);
+
m_installedFiles = getControl(IDC_LIST);
m_tabs = createControl<TabBar>(IDC_TABS, TabBar::Tabs{
@@ -132,6 +134,8 @@ void About::populate()
for(Category *cat : m_index->categories())
m_cats->addRow({make_autostring(cat->name())});
+ m_cats->sortByColumn(0);
+
updatePackages();
updateInstalledFiles();
@@ -170,6 +174,7 @@ void About::updatePackages()
}
m_currentCat = catIndex;
+ m_packages->sort();
}
void About::updateInstalledFiles()
diff --git a/src/listview.cpp b/src/listview.cpp
@@ -24,7 +24,8 @@
using namespace std;
ListView::ListView(const Columns &columns, HWND handle)
- : Control(handle), m_columnSize(0), m_rowSize(0)
+ : Control(handle), m_columnSize(0),
+ m_sortColumn(-1), m_sortOrder(AscendingOrder)
{
for(const Column &col : columns)
addColumn(col);
@@ -58,10 +59,14 @@ void ListView::addColumn(const Column &col)
int ListView::addRow(const Row &content)
{
LVITEM item{};
- item.iItem = m_rowSize++;
+ item.iItem = rowCount();
+
+ item.mask |= LVIF_PARAM;
+ item.lParam = item.iItem;
ListView_InsertItem(handle(), &item);
+ m_rows.resize(item.iItem + 1); // make room for the new row
replaceRow(item.iItem, content);
return item.iItem;
@@ -69,20 +74,30 @@ int ListView::addRow(const Row &content)
void ListView::replaceRow(const int index, const Row &content)
{
- LVITEM item{};
- item.iItem = index;
+ m_rows[index] = content;
const int cols = min(m_columnSize, (int)content.size());
for(int i = 0; i < cols; i++) {
auto_char *text = const_cast<auto_char *>(content[i].c_str());
- ListView_SetItemText(handle(), item.iItem, i, text);
+ ListView_SetItemText(handle(), index, i, text);
}
}
void ListView::removeRow(const int index)
{
ListView_DeleteItem(handle(), index);
+ m_rows.erase(m_rows.begin() + index);
+
+ // shift lParam to reflect the new row indexes
+ const int size = rowCount();
+ for(int i = index; i < size; i++) {
+ LVITEM item{};
+ item.iItem = i;
+ item.mask |= LVIF_PARAM;
+ item.lParam = i;
+ ListView_SetItem(handle(), &item);
+ }
}
void ListView::resizeColumn(const int index, const int width)
@@ -90,24 +105,73 @@ void ListView::resizeColumn(const int index, const int width)
ListView_SetColumnWidth(handle(), index, width);
}
-ListView::Row ListView::getRow(const int rowIndex) const
+void ListView::sort()
+{
+ if(m_sortColumn > -1)
+ sortByColumn(m_sortColumn, m_sortOrder);
+}
+
+void ListView::sortByColumn(const int index, const SortOrder order)
+{
+ static const auto compare = [](LPARAM aRow, LPARAM bRow, LPARAM param)
+ {
+ ListView *view = reinterpret_cast<ListView *>(param);
+ const int column = view->m_sortColumn;
+
+ const auto_string &a = view->m_rows[aRow][column];
+ const auto_string &b = view->m_rows[bRow][column];
+
+ const int ret = a.compare(b);
+
+ switch(view->m_sortOrder) {
+ case AscendingOrder:
+ return ret;
+ case DescendingOrder:
+ default: // for MSVC
+ return -ret;
+ }
+ };
+
+ if(m_sortColumn > -1)
+ setSortArrow(false);
+
+ m_sortColumn = index;
+ m_sortOrder = order;
+ setSortArrow(true);
+
+ ListView_SortItems(handle(), compare, (LPARAM)this);
+}
+
+void ListView::setSortArrow(const bool set)
{
- Row row(m_columnSize);
+ HWND header = ListView_GetHeader(handle());
- for(int i = 0; i < m_columnSize; i++) {
- auto_char buf[4096];
- ListView_GetItemText(handle(), rowIndex, i, buf, sizeof(buf));
- row[i] = buf;
+ HDITEM item{};
+ item.mask |= HDI_FORMAT;
+
+ if(!Header_GetItem(header, m_sortColumn, &item))
+ return;
+
+ item.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP); // clear
+
+ if(set) {
+ switch(m_sortOrder) {
+ case AscendingOrder:
+ item.fmt |= HDF_SORTUP;
+ break;
+ case DescendingOrder:
+ item.fmt |= HDF_SORTDOWN;
+ }
}
- return row;
+ Header_SetItem(header, m_sortColumn, &item);
}
void ListView::clear()
{
ListView_DeleteAllItems(handle());
- m_rowSize = 0;
+ m_rows.clear();
}
bool ListView::hasSelection() const
@@ -117,10 +181,20 @@ bool ListView::hasSelection() const
int ListView::currentIndex() const
{
- return ListView_GetNextItem(handle(), -1, LVNI_SELECTED);
+ const int internalIndex = ListView_GetNextItem(handle(), -1, LVNI_SELECTED);
+
+ if(internalIndex < 0)
+ return -1;
+
+ LVITEM item{};
+ item.iItem = internalIndex;
+ item.mask |= LVIF_PARAM;
+ ListView_GetItem(handle(), &item);
+
+ return (int)item.lParam;
}
-void ListView::onNotify(LPNMHDR info, LPARAM)
+void ListView::onNotify(LPNMHDR info, LPARAM lParam)
{
switch(info->code) {
case LVN_ITEMCHANGED:
@@ -129,5 +203,28 @@ void ListView::onNotify(LPNMHDR info, LPARAM)
case NM_DBLCLK:
m_onDoubleClick();
break;
+ case LVN_COLUMNCLICK:
+ onColumnClick(lParam);
+ break;
};
}
+
+void ListView::onColumnClick(LPARAM lParam)
+{
+ auto info = (LPNMLISTVIEW)lParam;
+ const int col = info->iSubItem;
+ SortOrder order = AscendingOrder;
+
+ if(col == m_sortColumn) {
+ switch(m_sortOrder) {
+ case AscendingOrder:
+ order = DescendingOrder;
+ break;
+ case DescendingOrder:
+ order = AscendingOrder;
+ break;
+ }
+ }
+
+ sortByColumn(col, order);
+}
diff --git a/src/listview.hpp b/src/listview.hpp
@@ -27,6 +27,8 @@
class ListView : public Control {
public:
+ enum SortOrder { AscendingOrder, DescendingOrder };
+
struct Column { auto_string text; int width; };
typedef std::vector<Column> Columns;
typedef std::vector<auto_string> Row;
@@ -37,14 +39,17 @@ public:
ListView(const Columns &, HWND handle);
int addRow(const Row &);
- Row getRow(const int index) const;
- void replaceRow(const int index, const Row &);
- void removeRow(const int index);
- void resizeColumn(const int index, const int width);
+ const Row &row(int index) const { return m_rows[index]; }
+ void replaceRow(int index, const Row &);
+ void removeRow(int index);
+ void resizeColumn(int index, const int width);
+ void sort();
+ void sortByColumn(int index, SortOrder order = AscendingOrder);
void clear();
bool hasSelection() const;
int currentIndex() const;
+ int rowCount() { return (int)m_rows.size(); }
void onSelect(const Callback &callback) { m_onSelect.connect(callback); }
void onDoubleClick(const Callback &callback)
@@ -56,9 +61,13 @@ protected:
private:
void setExStyle(int style, bool enable);
void addColumn(const Column &);
+ void setSortArrow(bool);
+ void onColumnClick(LPARAM lpnmlistview);
int m_columnSize;
- int m_rowSize;
+ int m_sortColumn;
+ SortOrder m_sortOrder;
+ std::vector<Row> m_rows;
Signal m_onSelect;
Signal m_onDoubleClick;
diff --git a/src/manager.cpp b/src/manager.cpp
@@ -292,7 +292,7 @@ Remote Manager::currentRemote() const
if(index < 0)
return {};
- const ListView::Row &row = m_list->getRow(index);
+ const ListView::Row &row = m_list->row(index);
const string &remoteName = from_autostring(row[0]);
return m_reapack->config()->remotes()->get(remoteName);
diff --git a/src/resource.rc b/src/resource.rc
@@ -31,8 +31,8 @@ FONT DIALOG_FONT
CAPTION "ReaPack Configuration"
BEGIN
LTEXT "Remote repositories:", IDC_LABEL, 5, 5, 320, 10
- CONTROL "", IDC_LIST, WC_LISTVIEW, LVS_REPORT | LVS_SINGLESEL |
- LVS_SHOWSELALWAYS | WS_BORDER | WS_TABSTOP, 5, 18, 320, 136
+ CONTROL "", IDC_LIST, WC_LISTVIEW, WS_BORDER | LVS_REPORT | LVS_SINGLESEL |
+ LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_TABSTOP, 5, 18, 320, 136
PUSHBUTTON "&Import...", IDC_IMPORT, 5, 160, 45, 14
DEFPUSHBUTTON "&OK", IDOK, 240, 160, 40, 14
PUSHBUTTON "&Cancel", IDCANCEL, 284, 160, 40, 14