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;
|
uiprivScrollViewData *d;
|
||||||
int backgroundColumn;
|
int backgroundColumn;
|
||||||
uiTableModel *m;
|
uiTableModel *m;
|
||||||
|
void (*headerOnClicked)(uiTable *, int, void *);
|
||||||
|
void *headerOnClickedData;
|
||||||
};
|
};
|
||||||
|
|
||||||
// tablecolumn.m
|
// tablecolumn.m
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
uiTableModel *uiprivM;
|
uiTableModel *uiprivM;
|
||||||
}
|
}
|
||||||
- (id)initWithFrame:(NSRect)r uiprivT:(uiTable *)t uiprivM:(uiTableModel *)m;
|
- (id)initWithFrame:(NSRect)r uiprivT:(uiTable *)t uiprivM:(uiTableModel *)m;
|
||||||
|
- (uiTable *)uiTable;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation uiprivTableView
|
@implementation uiprivTableView
|
||||||
|
@ -30,6 +31,11 @@
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (uiTable *)uiTable
|
||||||
|
{
|
||||||
|
return self->uiprivT;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO is this correct for overflow scrolling?
|
// TODO is this correct for overflow scrolling?
|
||||||
static void setBackgroundColor(uiprivTableView *t, NSTableRowView *rv, NSInteger row)
|
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);
|
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
|
@end
|
||||||
|
|
||||||
uiTableModel *uiNewTableModel(uiTableModelHandler *mh)
|
uiTableModel *uiNewTableModel(uiTableModelHandler *mh)
|
||||||
|
@ -170,6 +182,17 @@ static void uiTableDestroy(uiControl *c)
|
||||||
uiFreeControl(uiControl(t));
|
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 *uiNewTable(uiTableParams *p)
|
||||||
{
|
{
|
||||||
uiTable *t;
|
uiTable *t;
|
||||||
|
@ -209,6 +232,8 @@ uiTable *uiNewTable(uiTableParams *p)
|
||||||
sp.VScroll = YES;
|
sp.VScroll = YES;
|
||||||
t->sv = uiprivMkScrollView(&sp, &(t->d));
|
t->sv = uiprivMkScrollView(&sp, &(t->d));
|
||||||
|
|
||||||
|
uiTableHeaderOnClicked(t, defaultHeaderOnClicked, NULL);
|
||||||
|
|
||||||
// TODO WHY DOES THIS REMOVE ALL GRAPHICAL GLITCHES?
|
// 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 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...
|
// 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;
|
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 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 *makePage16(void)
|
||||||
{
|
{
|
||||||
uiBox *page16;
|
uiBox *page16;
|
||||||
|
@ -152,6 +167,8 @@ uiBox *makePage16(void)
|
||||||
uiTableAppendProgressBarColumn(t, "Progress Bar",
|
uiTableAppendProgressBarColumn(t, "Progress Bar",
|
||||||
8);
|
8);
|
||||||
|
|
||||||
|
uiTableHeaderOnClicked(t, headerOnClicked, NULL);
|
||||||
|
|
||||||
return page16;
|
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.
|
// uiNewTable() creates a new uiTable with the specified parameters.
|
||||||
_UI_EXTERN uiTable *uiNewTable(uiTableParams *params);
|
_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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
59
unix/table.c
59
unix/table.c
|
@ -18,6 +18,8 @@ struct uiTable {
|
||||||
// TODO document this properly
|
// TODO document this properly
|
||||||
GHashTable *indeterminatePositions;
|
GHashTable *indeterminatePositions;
|
||||||
guint indeterminateTimer;
|
guint indeterminateTimer;
|
||||||
|
void (*headerOnClicked)(uiTable *, int, void *);
|
||||||
|
void *headerOnClickedData;
|
||||||
};
|
};
|
||||||
|
|
||||||
// use the same size as GtkFileChooserWidget's treeview
|
// 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);
|
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)
|
static GtkTreeViewColumn *addColumn(uiTable *t, const char *name)
|
||||||
{
|
{
|
||||||
GtkTreeViewColumn *c;
|
GtkTreeViewColumn *c;
|
||||||
|
@ -334,6 +389,8 @@ static GtkTreeViewColumn *addColumn(uiTable *t, const char *name)
|
||||||
c = gtk_tree_view_column_new();
|
c = gtk_tree_view_column_new();
|
||||||
gtk_tree_view_column_set_resizable(c, TRUE);
|
gtk_tree_view_column_set_resizable(c, TRUE);
|
||||||
gtk_tree_view_column_set_title(c, name);
|
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);
|
gtk_tree_view_append_column(t->tv, c);
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
@ -520,5 +577,7 @@ uiTable *uiNewTable(uiTableParams *p)
|
||||||
t->indeterminatePositions = g_hash_table_new_full(rowcolHash, rowcolEqual,
|
t->indeterminatePositions = g_hash_table_new_full(rowcolHash, rowcolEqual,
|
||||||
uiprivFree, uiprivFree);
|
uiprivFree, uiprivFree);
|
||||||
|
|
||||||
|
uiTableHeaderOnClicked(t, defaultHeaderOnClicked, NULL);
|
||||||
|
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
|
@ -230,6 +230,59 @@ int uiprivTableProgress(uiTable *t, int item, int subitem, int modelColumn, LONG
|
||||||
return progress;
|
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
|
// TODO properly integrate compound statements
|
||||||
static BOOL onWM_NOTIFY(uiControl *c, HWND hwnd, NMHDR *nmhdr, LRESULT *lResult)
|
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;
|
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
|
// the real list view accepts changes when scrolling or clicking column headers
|
||||||
case LVN_BEGINSCROLL:
|
case LVN_BEGINSCROLL:
|
||||||
case LVN_COLUMNCLICK:
|
|
||||||
hr = uiprivTableFinishEditingText(t);
|
hr = uiprivTableFinishEditingText(t);
|
||||||
if (hr != S_OK) {
|
if (hr != S_OK) {
|
||||||
// TODO
|
// TODO
|
||||||
|
@ -490,6 +554,7 @@ uiTable *uiNewTable(uiTableParams *p)
|
||||||
t->columns = new std::vector<uiprivTableColumnParams *>;
|
t->columns = new std::vector<uiprivTableColumnParams *>;
|
||||||
t->model = p->Model;
|
t->model = p->Model;
|
||||||
t->backgroundColumn = p->RowBackgroundColorModelColumn;
|
t->backgroundColumn = p->RowBackgroundColorModelColumn;
|
||||||
|
uiTableHeaderOnClicked(t, defaultHeaderOnClicked, NULL);
|
||||||
|
|
||||||
// WS_CLIPCHILDREN is here to prevent drawing over the edit box used for editing text
|
// WS_CLIPCHILDREN is here to prevent drawing over the edit box used for editing text
|
||||||
t->hwnd = uiWindowsEnsureCreateControlHWND(WS_EX_CLIENTEDGE,
|
t->hwnd = uiWindowsEnsureCreateControlHWND(WS_EX_CLIENTEDGE,
|
||||||
|
|
|
@ -40,6 +40,8 @@ struct uiTable {
|
||||||
HWND edit;
|
HWND edit;
|
||||||
int editedItem;
|
int editedItem;
|
||||||
int editedSubitem;
|
int editedSubitem;
|
||||||
|
void (*headerOnClicked)(uiTable *, int, void *);
|
||||||
|
void *headerOnClickedData;
|
||||||
};
|
};
|
||||||
extern int uiprivTableProgress(uiTable *t, int item, int subitem, int modelColumn, LONG *pos);
|
extern int uiprivTableProgress(uiTable *t, int item, int subitem, int modelColumn, LONG *pos);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue