Add new API for sort related operations.
Add functions to get/set table header sort indicators: uiTableHeaderSortIndicator uiTableHeaderSetSortIndicator Add callback setter for table header clicks: uiTableHeaderOnClicked
This commit is contained in:
parent
b673b26f58
commit
844da8d312
|
@ -16,6 +16,8 @@ struct uiTable {
|
|||
uiprivScrollViewData *d;
|
||||
int backgroundColumn;
|
||||
uiTableModel *m;
|
||||
void (*headerOnClicked)(uiTable *, int, void *);
|
||||
void *headerOnClickedData;
|
||||
};
|
||||
|
||||
// tablecolumn.m
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
uiTableModel *uiprivM;
|
||||
}
|
||||
- (id)initWithFrame:(NSRect)r uiprivT:(uiTable *)t uiprivM:(uiTableModel *)m;
|
||||
- (uiTable *)uiTable;
|
||||
@end
|
||||
|
||||
@implementation uiprivTableView
|
||||
|
@ -30,6 +31,11 @@
|
|||
return self;
|
||||
}
|
||||
|
||||
- (uiTable *)uiTable
|
||||
{
|
||||
return self->uiprivT;
|
||||
}
|
||||
|
||||
// TODO is this correct for overflow scrolling?
|
||||
static void setBackgroundColor(uiprivTableView *t, NSTableRowView *rv, NSInteger row)
|
||||
{
|
||||
|
@ -88,6 +94,12 @@ static void setBackgroundColor(uiprivTableView *t, NSTableRowView *rv, NSInteger
|
|||
setBackgroundColor((uiprivTableView *) tv, rv, row);
|
||||
}
|
||||
|
||||
- (void)tableView:(uiprivTableView *)tv didClickTableColumn:(NSTableColumn *) tc
|
||||
{
|
||||
uiTable *t = [tv uiTable];
|
||||
t->headerOnClicked(t, [[tc identifier] intValue], t->headerOnClickedData);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
uiTableModel *uiNewTableModel(uiTableModelHandler *mh)
|
||||
|
@ -170,6 +182,17 @@ static void uiTableDestroy(uiControl *c)
|
|||
uiFreeControl(uiControl(t));
|
||||
}
|
||||
|
||||
void uiTableHeaderOnClicked(uiTable *t, void (*f)(uiTable *, int, void *), void *data)
|
||||
{
|
||||
t->headerOnClicked = f;
|
||||
t->headerOnClickedData = data;
|
||||
}
|
||||
|
||||
static void defaultHeaderOnClicked(uiTable *table, int column, void *data)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
uiTable *uiNewTable(uiTableParams *p)
|
||||
{
|
||||
uiTable *t;
|
||||
|
@ -209,6 +232,8 @@ uiTable *uiNewTable(uiTableParams *p)
|
|||
sp.VScroll = YES;
|
||||
t->sv = uiprivMkScrollView(&sp, &(t->d));
|
||||
|
||||
uiTableHeaderOnClicked(t, defaultHeaderOnClicked, NULL);
|
||||
|
||||
// TODO WHY DOES THIS REMOVE ALL GRAPHICAL GLITCHES?
|
||||
// I got the idea from http://jwilling.com/blog/optimized-nstableview-scrolling/ but that was on an unrelated problem I didn't seem to have (although I have small-ish tables to start with)
|
||||
// I don't get layer-backing... am I supposed to layer-back EVERYTHING manually? I need to check Interface Builder again...
|
||||
|
@ -216,3 +241,27 @@ uiTable *uiNewTable(uiTableParams *p)
|
|||
|
||||
return t;
|
||||
}
|
||||
|
||||
uiSort uiTableHeaderSortIndicator(uiTable *t, int lcol)
|
||||
{
|
||||
NSTableColumn *tc = [t->tv tableColumnWithIdentifier:[@(lcol) stringValue]];
|
||||
NSString *si = [[t->tv indicatorImageInTableColumn:tc] name];
|
||||
if ([si isEqualToString:@"NSAscendingSortIndicator"])
|
||||
return uiSortAscending;
|
||||
else if ([si isEqualToString:@"NSDescendingSortIndicator"])
|
||||
return uiSortDescending;
|
||||
return uiSortNone;
|
||||
}
|
||||
|
||||
void uiTableHeaderSetSortIndicator(uiTable *t, int lcol, uiSort order)
|
||||
{
|
||||
NSTableColumn *tc = [t->tv tableColumnWithIdentifier:[@(lcol) stringValue]];
|
||||
NSImage *img;
|
||||
if (order == uiSortAscending)
|
||||
img = [NSImage imageNamed:@"NSAscendingSortIndicator"];
|
||||
else if (order == uiSortDescending)
|
||||
img = [NSImage imageNamed:@"NSDescendingSortIndicator"];
|
||||
else
|
||||
img = nil;
|
||||
[t->tv setIndicatorImage:img inTableColumn:tc];
|
||||
}
|
||||
|
|
|
@ -100,6 +100,21 @@ static void modelSetCellValue(uiTableModelHandler *mh, uiTableModel *m, int row,
|
|||
|
||||
static uiTableModel *m;
|
||||
|
||||
static void headerOnClicked(uiTable *t, int col, void *data)
|
||||
{
|
||||
static int prev = 0;
|
||||
|
||||
if (prev != col)
|
||||
uiTableHeaderSetSortIndicator(t, prev, uiSortNone);
|
||||
|
||||
if (uiTableHeaderSortIndicator(t, col) == uiSortAscending)
|
||||
uiTableHeaderSetSortIndicator(t, col, uiSortDescending);
|
||||
else
|
||||
uiTableHeaderSetSortIndicator(t, col, uiSortAscending);
|
||||
|
||||
prev = col;
|
||||
}
|
||||
|
||||
uiBox *makePage16(void)
|
||||
{
|
||||
uiBox *page16;
|
||||
|
@ -152,6 +167,8 @@ uiBox *makePage16(void)
|
|||
uiTableAppendProgressBarColumn(t, "Progress Bar",
|
||||
8);
|
||||
|
||||
uiTableHeaderOnClicked(t, headerOnClicked, NULL);
|
||||
|
||||
return page16;
|
||||
}
|
||||
|
||||
|
|
16
ui.h
16
ui.h
|
@ -1464,6 +1464,22 @@ _UI_EXTERN void uiTableAppendButtonColumn(uiTable *t,
|
|||
// uiNewTable() creates a new uiTable with the specified parameters.
|
||||
_UI_EXTERN uiTable *uiNewTable(uiTableParams *params);
|
||||
|
||||
// uiTableHeaderSetSortIndicator() sets the sort indicator of the table
|
||||
// header to display an appropriate arrow on the column header
|
||||
_UI_EXTERN void uiTableHeaderSetSortIndicator(uiTable *t,
|
||||
int column,
|
||||
uiSort order);
|
||||
|
||||
// uiTableHeaderSortIndicator returns the sort indicator of the specified
|
||||
// column
|
||||
_UI_EXTERN uiSort uiTableHeaderSortIndicator(uiTable *t, int column);
|
||||
|
||||
// uiTableHeaderOnClicked() sets a callback function to be called
|
||||
// when a table column header is clicked
|
||||
_UI_EXTERN void uiTableHeaderOnClicked(uiTable *t,
|
||||
void (*f)(uiTable *table, int column, void *data),
|
||||
void *data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
59
unix/table.c
59
unix/table.c
|
@ -18,6 +18,8 @@ struct uiTable {
|
|||
// TODO document this properly
|
||||
GHashTable *indeterminatePositions;
|
||||
guint indeterminateTimer;
|
||||
void (*headerOnClicked)(uiTable *, int, void *);
|
||||
void *headerOnClickedData;
|
||||
};
|
||||
|
||||
// use the same size as GtkFileChooserWidget's treeview
|
||||
|
@ -327,6 +329,59 @@ static void buttonColumnClicked(GtkCellRenderer *r, gchar *pathstr, gpointer dat
|
|||
onEdited(p->m, p->modelColumn, pathstr, NULL, NULL);
|
||||
}
|
||||
|
||||
uiSort uiTableHeaderSortIndicator(uiTable *t, int lcol)
|
||||
{
|
||||
GtkTreeViewColumn *c = gtk_tree_view_get_column(t->tv, lcol);
|
||||
|
||||
if (c == NULL || gtk_tree_view_column_get_sort_indicator(c) == FALSE)
|
||||
return uiSortNone;
|
||||
|
||||
if (gtk_tree_view_column_get_sort_order(c) == GTK_SORT_ASCENDING)
|
||||
return uiSortAscending;
|
||||
else
|
||||
return uiSortDescending;
|
||||
}
|
||||
|
||||
void uiTableHeaderSetSortIndicator(uiTable *t, int lcol, uiSort order)
|
||||
{
|
||||
GtkTreeViewColumn *c = gtk_tree_view_get_column(t->tv, lcol);
|
||||
|
||||
if (c == NULL)
|
||||
return;
|
||||
|
||||
if (order == uiSortNone) {
|
||||
gtk_tree_view_column_set_sort_indicator(c, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_tree_view_column_set_sort_indicator(c, TRUE);
|
||||
if (order == uiSortAscending)
|
||||
gtk_tree_view_column_set_sort_order(c, GTK_SORT_ASCENDING);
|
||||
else
|
||||
gtk_tree_view_column_set_sort_order(c, GTK_SORT_DESCENDING);
|
||||
}
|
||||
|
||||
void uiTableHeaderOnClicked(uiTable *t, void (*f)(uiTable *, int, void *), void *data)
|
||||
{
|
||||
t->headerOnClicked = f;
|
||||
t->headerOnClickedData = data;
|
||||
}
|
||||
|
||||
static void defaultHeaderOnClicked(uiTable *table, int column, void *data)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
static void headerOnClicked(GtkTreeViewColumn *c, gpointer data)
|
||||
{
|
||||
guint i;
|
||||
uiTable *t = uiTable(data);
|
||||
|
||||
for (i = 0; i < gtk_tree_view_get_n_columns(t->tv); ++i)
|
||||
if (gtk_tree_view_get_column(t->tv, i) == c)
|
||||
t->headerOnClicked(t, i, t->headerOnClickedData);
|
||||
}
|
||||
|
||||
static GtkTreeViewColumn *addColumn(uiTable *t, const char *name)
|
||||
{
|
||||
GtkTreeViewColumn *c;
|
||||
|
@ -334,6 +389,8 @@ static GtkTreeViewColumn *addColumn(uiTable *t, const char *name)
|
|||
c = gtk_tree_view_column_new();
|
||||
gtk_tree_view_column_set_resizable(c, TRUE);
|
||||
gtk_tree_view_column_set_title(c, name);
|
||||
gtk_tree_view_column_set_clickable(c, 1);
|
||||
g_signal_connect(c, "clicked", G_CALLBACK(headerOnClicked), t);
|
||||
gtk_tree_view_append_column(t->tv, c);
|
||||
return c;
|
||||
}
|
||||
|
@ -520,5 +577,7 @@ uiTable *uiNewTable(uiTableParams *p)
|
|||
t->indeterminatePositions = g_hash_table_new_full(rowcolHash, rowcolEqual,
|
||||
uiprivFree, uiprivFree);
|
||||
|
||||
uiTableHeaderOnClicked(t, defaultHeaderOnClicked, NULL);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
|
|
@ -230,6 +230,59 @@ int uiprivTableProgress(uiTable *t, int item, int subitem, int modelColumn, LONG
|
|||
return progress;
|
||||
}
|
||||
|
||||
void uiTableHeaderSetSortIndicator(uiTable *t, int column, uiSort order)
|
||||
{
|
||||
HWND lvhdr;
|
||||
int fmt;
|
||||
|
||||
if (order == uiSortAscending)
|
||||
fmt = HDF_SORTUP;
|
||||
else if (order == uiSortDescending)
|
||||
fmt = HDF_SORTDOWN;
|
||||
else
|
||||
fmt = 0;
|
||||
|
||||
lvhdr = ListView_GetHeader(t->hwnd);
|
||||
if (lvhdr) {
|
||||
HDITEM hdri = {};
|
||||
hdri.mask = HDI_FORMAT;
|
||||
if (Header_GetItem(lvhdr, column, &hdri)) {
|
||||
hdri.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN);
|
||||
hdri.fmt |= fmt;
|
||||
Header_SetItem(lvhdr, column, &hdri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uiSort uiTableHeaderSortIndicator(uiTable *t, int column)
|
||||
{
|
||||
HWND lvhdr;
|
||||
|
||||
lvhdr = ListView_GetHeader(t->hwnd);
|
||||
if (lvhdr) {
|
||||
HDITEM hdri = {};
|
||||
hdri.mask = HDI_FORMAT;
|
||||
if (Header_GetItem(lvhdr, column, &hdri)) {
|
||||
if (hdri.fmt & HDF_SORTUP)
|
||||
return uiSortAscending;
|
||||
if (hdri.fmt & HDF_SORTDOWN)
|
||||
return uiSortDescending;
|
||||
}
|
||||
}
|
||||
return uiSortNone;
|
||||
}
|
||||
|
||||
void uiTableHeaderOnClicked(uiTable *t, void (*f)(uiTable *table, int column, void *data), void *data)
|
||||
{
|
||||
t->headerOnClicked = f;
|
||||
t->headerOnClickedData = data;
|
||||
}
|
||||
|
||||
static void defaultHeaderOnClicked(uiTable *table, int column, void *data)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
// TODO properly integrate compound statements
|
||||
static BOOL onWM_NOTIFY(uiControl *c, HWND hwnd, NMHDR *nmhdr, LRESULT *lResult)
|
||||
{
|
||||
|
@ -310,9 +363,20 @@ static BOOL onWM_NOTIFY(uiControl *c, HWND hwnd, NMHDR *nmhdr, LRESULT *lResult)
|
|||
}
|
||||
return FALSE;
|
||||
}
|
||||
case LVN_COLUMNCLICK:
|
||||
{
|
||||
NMLISTVIEW *nm = (NMLISTVIEW *) nmhdr;
|
||||
|
||||
hr = uiprivTableFinishEditingText(t);
|
||||
if (hr != S_OK) {
|
||||
// TODO
|
||||
return FALSE;
|
||||
}
|
||||
t->headerOnClicked(t, nm->iSubItem, t->headerOnClickedData);
|
||||
return TRUE;
|
||||
}
|
||||
// the real list view accepts changes when scrolling or clicking column headers
|
||||
case LVN_BEGINSCROLL:
|
||||
case LVN_COLUMNCLICK:
|
||||
hr = uiprivTableFinishEditingText(t);
|
||||
if (hr != S_OK) {
|
||||
// TODO
|
||||
|
@ -490,6 +554,7 @@ uiTable *uiNewTable(uiTableParams *p)
|
|||
t->columns = new std::vector<uiprivTableColumnParams *>;
|
||||
t->model = p->Model;
|
||||
t->backgroundColumn = p->RowBackgroundColorModelColumn;
|
||||
uiTableHeaderOnClicked(t, defaultHeaderOnClicked, NULL);
|
||||
|
||||
// WS_CLIPCHILDREN is here to prevent drawing over the edit box used for editing text
|
||||
t->hwnd = uiWindowsEnsureCreateControlHWND(WS_EX_CLIENTEDGE,
|
||||
|
|
|
@ -40,6 +40,8 @@ struct uiTable {
|
|||
HWND edit;
|
||||
int editedItem;
|
||||
int editedSubitem;
|
||||
void (*headerOnClicked)(uiTable *, int, void *);
|
||||
void *headerOnClickedData;
|
||||
};
|
||||
extern int uiprivTableProgress(uiTable *t, int item, int subitem, int modelColumn, LONG *pos);
|
||||
|
||||
|
|
Loading…
Reference in New Issue