#include <stdio.h>
#include <stdlib.h>
#include <cx/array_list.h>
#include "list.h"
#include "container.h"
static W32WidgetClass listview_widget_class = {
.eventproc = ui_listview_eventproc,
.enable = w32_widget_default_enable,
.show = w32_widget_default_show,
.get_preferred_size = ui_listview_get_preferred_size,
.destroy = w32_widget_default_destroy
};
static void* strmodel_getvalue(UiList *list,
void *elm,
int row,
int col,
void *userdata, UiBool *freeResult) {
return col ==
0 ? elm :
NULL;
}
static void* getvalue_wrapper(UiList *list,
void *elm,
int row,
int col,
void *userdata, UiBool *freeResult) {
ui_getvaluefunc getvalue = (ui_getvaluefunc)userdata;
return getvalue(elm, col);
}
static void* null_getvalue(UiList *list,
void *elm,
int row,
int col,
void *userdata, UiBool *freeResult) {
return NULL;
}
static UiListView* create_listview_widget(UiObject *obj, W32WidgetClass *widget_class,
HWND hwnd, UiListArgs *args, UiBool table) {
UiListView *listview = w32_widget_create(widget_class, hwnd,
sizeof(UiListView));
listview->widget.hwnd = hwnd;
listview->obj = obj;
listview->preferred_width = args->width ? args->width :
300;
listview->preferred_height = args->height ? args->height :
300;
listview->onactivate = args->onactivate;
listview->onactivatedata = args->onactivatedata;
listview->onselection = args->onselection;
listview->onselectiondata = args->onselectiondata;
listview->ondragstart = args->ondragstart;
listview->ondragstartdata = args->ondragstartdata;
listview->ondragcomplete = args->ondragcomplete;
listview->ondragcompletedata = args->ondragcompletedata;
listview->ondrop = args->ondrop;
listview->ondropdata = args->ondropdata;
listview->istable = table;
ui_getvaluefunc2 getvalue = args->getvalue2;
void *getvaluedata = args->getvalue2data;
if(!getvalue) {
if(args->getvalue) {
getvalue = getvalue_wrapper;
getvaluedata = (
void*)args->getvalue;
}
else {
getvalue = table ? null_getvalue : strmodel_getvalue;
}
}
listview->getvalue = getvalue;
listview->getvaluedata = getvaluedata;
listview->var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname,
UI_VAR_LIST);
return listview;
}
static UIWIDGET listview_create(UiObject *obj, UiListArgs *args, UiBool table) {
HINSTANCE hInstance = GetModuleHandle(
NULL);
UiContainerPrivate *container = ui_obj_container(obj);
HWND parent = ui_container_get_parent(container);
UiLayout layout =
UI_ARGS2LAYOUT(args);
HWND hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
WC_LISTVIEW,
"",
WS_CHILD |
WS_VISIBLE |
LVS_REPORT,
0,
0,
100,
100,
parent,
(
HMENU)
1337,
hInstance,
NULL);
ui_win32_set_ui_font(hwnd);
ListView_SetExtendedListViewStyle(
hwnd,
LVS_EX_FULLROWSELECT
);
UiListView *listview = create_listview_widget(obj, &listview_widget_class, hwnd, args, table);
ui_container_add(container, (W32Widget*)listview, &layout);
int numcolumns =
0;
if (table) {
if (args->model) {
listview->model = ui_model_copy(obj->ctx, args->model);
numcolumns = listview->model->columns;
}
else {
listview->model = ui_model_new(obj->ctx);
}
}
else {
UiModel *model = ui_model_new(obj->ctx);
ui_model_add_column(model,
UI_STRING,
"Test",
-1);
listview->model = model;
numcolumns =
1;
}
UiModel *model = listview->model;
for (
int i=
0;i<numcolumns;i++) {
LVCOLUMN col;
UiModelType type = model->types[i];
char *title = model->titles[i];
size_t titlelen = title ? strlen(title) :
0;
int size = model->columnsize[i];
switch (type) {
default: {
col.mask =
LVCF_TEXT |
LVCF_WIDTH;
col.pszText = title;
col.cx = size >
0 ? size : titlelen*
10+5;
break;
}
case UI_ICON: {
break;
}
}
ListView_InsertColumn(hwnd, i, &col);
}
if (listview->var) {
UiList *list = listview->var->value;
list->obj = listview;
list->update = ui_listview_update;
list->getselection = ui_listview_getselection_impl;
list->setselection = ui_listview_setselection_impl;
ui_listview_update(list,
-1);
}
else if (!table && args->static_elements && args->static_nelm >
0) {
char **static_elements = args->static_elements;
size_t static_nelm = args->static_nelm;
LVITEM item;
item.mask =
LVIF_TEXT;
item.iSubItem =
0;
for (
int i=
0;i<static_nelm;i++) {
item.iItem = i;
item.pszText = static_elements[i];
ListView_InsertItem(hwnd, &item);
}
listview->getvalue = strmodel_getvalue;
listview->getvaluedata =
NULL;
}
return (W32Widget*)listview;
}
static UiListSelection listview_get_selection2(
HWND hwnd) {
UiListSelection sel = {
0,
NULL };
CX_ARRAY_DECLARE(
int, indices);
cx_array_initialize(indices,
8);
int index =
-1;
while ((index = ListView_GetNextItem(hwnd, index,
LVNI_SELECTED)) !=
-1) {
cx_array_simple_add(indices, index);
}
if (indices_size >
0) {
sel.rows = indices;
sel.count = indices_size;
}
return sel;
}
static UiListSelection listview_get_selection(UiListView *listview) {
HWND hwnd = listview->widget.hwnd;
return listview_get_selection2(hwnd);
}
int ui_listview_eventproc(W32Widget *widget,
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam) {
UiListView *listview = (UiListView*)widget;
switch (uMsg) {
case WM_NOTIFY: {
LPNMHDR hdr = (
LPNMHDR)lParam;
switch (hdr->code) {
case LVN_ITEMCHANGED: {
LPNMLISTVIEW lv = (
LPNMLISTVIEW)lParam;
int row = lv->iItem;
if ((lv->uChanged &
LVIF_STATE) && (lv->uNewState &
LVIS_SELECTED) && listview->onselection) {
UiListSelection sel = listview_get_selection(listview);
UiEvent event;
event.obj = listview->obj;
event.window = listview->obj->window;
event.document = listview->obj->ctx->document;
event.eventdata = &sel;
event.eventdatatype =
UI_EVENT_DATA_LIST_SELECTION;
event.intval = row;
event.set = ui_get_setop();
listview->onselection(&event, listview->onselectiondata);
ui_listselection_free(sel);
}
break;
}
case LVN_ITEMACTIVATE: {
LPNMLISTVIEW lv = (
LPNMLISTVIEW)lParam;
int row = lv->iItem;
if (listview->onactivate) {
UiEvent event;
event.obj = listview->obj;
event.window = listview->obj->window;
event.document = listview->obj->ctx->document;
event.eventdata =
NULL;
event.eventdatatype =
UI_EVENT_DATA_LIST_ELM;
event.intval = row;
event.set = ui_get_setop();
if (listview->var) {
UiList *list = listview->var->value;
event.eventdata = list->get(list, row);
event.eventdatatype =
UI_EVENT_DATA_LIST_ELM;
}
listview->onactivate(&event, listview->onactivatedata);
}
break;
}
}
break;
}
}
return 0;
}
W32Size ui_listview_get_preferred_size(W32Widget *widget) {
UiListView *listview = (UiListView*)widget;
W32Size size;
size.width = listview->preferred_width;
size.height = listview->preferred_height;
return size;
}
static void insert_item(UiList *list,
int row,
void *elm) {
UiListView *listview = (UiListView*)list->obj;
HWND hwnd = listview->widget.hwnd;
UiModel *model = listview->model;
LVITEM item;
item.mask =
LVIF_TEXT;
item.iItem = row;
item.iSubItem =
0;
int idx =
-1;
for (
int col=
0;col<model->columns;col++) {
UiBool freeResult =
FALSE;
char *str = listview->getvalue(list, elm, row, col, listview->getvaluedata, &freeResult);
if (col ==
0) {
item.pszText = str;
idx = ListView_InsertItem(hwnd, &item);
}
else {
ListView_SetItemText(hwnd, idx, col, str);
}
if (freeResult) {
free(str);
}
}
}
void ui_listview_update(UiList *list,
int row) {
UiListView *listview = (UiListView*)list->obj;
HWND hwnd = listview->widget.hwnd;
UiModel *model = listview->model;
if (row <
0) {
ListView_DeleteAllItems(hwnd);
void *elm = list->first(list);
int row =
0;
while (elm) {
insert_item(list, row, elm);
elm = list->next(list);
row++;
}
}
else {
ListView_DeleteItem(hwnd, row);
void *elm = list->get(list, row);
insert_item(list, row, elm);
}
for (
int i=
0;i<model->columns;i++) {
ListView_SetColumnWidth(hwnd, i,
LVSCW_AUTOSIZE);
}
}
UiListSelection ui_listview_getselection_impl(UiList *list) {
UiListView *listview = (UiListView*)list->obj;
return listview_get_selection(listview);
}
void ui_listview_setselection_impl(UiList *list, UiListSelection selection) {
}
UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) {
return listview_create(obj, args,
FALSE);
}
UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
return listview_create(obj, args,
TRUE);
}
void ui_listview_select(
UIWIDGET listview,
int index) {
}
int ui_listview_selection(
UIWIDGET listview) {
W32Widget *w = (W32Widget*)listview;
UiListSelection sel = listview_get_selection2(w->hwnd);
int index =
-1;
if (sel.count >
0) {
index = sel.rows[
0];
}
free(sel.rows);
return index;
}
static W32WidgetClass dropdown_widget_class = {
.eventproc = ui_dropdown_eventproc,
.enable = w32_widget_default_enable,
.show = w32_widget_default_show,
.get_preferred_size = ui_dropdown_get_preferred_size,
.destroy = w32_widget_default_destroy
};
UIWIDGET ui_dropdown_create(UiObject *obj, UiListArgs *args) {
HINSTANCE hInstance = GetModuleHandle(
NULL);
UiContainerPrivate *container = ui_obj_container(obj);
HWND parent = ui_container_get_parent(container);
UiLayout layout =
UI_ARGS2LAYOUT(args);
HWND hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
WC_COMBOBOX,
"",
WS_CHILD |
WS_VISIBLE |
WS_VSCROLL |
CBS_DROPDOWNLIST,
0,
0,
100,
100,
parent,
(
HMENU)
1337,
hInstance,
NULL);
ui_win32_set_ui_font(hwnd);
UiListView *dropdown = create_listview_widget(obj, &dropdown_widget_class, hwnd, args,
FALSE);
ui_container_add(container, (W32Widget*)dropdown, &layout);
if (dropdown->var) {
UiList *list = dropdown->var->value;
list->obj = dropdown;
list->update = ui_dropdown_update;
list->getselection = ui_dropdown_getselection_impl;
list->setselection = ui_dropdown_setselection_impl;
ui_dropdown_update(list,
-1);
}
else if (args->static_elements && args->static_nelm >
0) {
char **static_elements = args->static_elements;
size_t static_nelm = args->static_nelm;
for (
int i=
0;i<static_nelm;i++) {
SendMessage(hwnd,
CB_ADDSTRING,
0, (
LPARAM)static_elements[i]);
}
dropdown->getvalue = strmodel_getvalue;
dropdown->getvaluedata =
NULL;
}
return (W32Widget*)dropdown;
}
int ui_dropdown_eventproc(W32Widget *widget,
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam) {
return 0;
}
W32Size ui_dropdown_get_preferred_size(W32Widget *widget) {
W32Size size;
size.width =
200;
size.height =
30;
return size;
}
static void dropdown_insert_item(UiList *list,
int row,
void *elm) {
UiListView *listview = (UiListView*)list->obj;
HWND hwnd = listview->widget.hwnd;
UiBool freeResult =
FALSE;
char *str = listview->getvalue(list, elm, row,
0, listview->getvaluedata, &freeResult);
SendMessage(hwnd,
CB_ADDSTRING,
0, (
LPARAM)str);
if (freeResult) {
free(str);
}
}
void ui_dropdown_update(UiList *list,
int row) {
UiListView *listview = (UiListView*)list->obj;
HWND hwnd = listview->widget.hwnd;
if (row <
0) {
SendMessage(hwnd,
CB_RESETCONTENT,
0,
0);
void *elm = list->first(list);
int row =
0;
while (elm) {
dropdown_insert_item(list, row, elm);
elm = list->next(list);
row++;
}
}
else {
SendMessage(hwnd,
CB_DELETESTRING, row,
0);
void *elm = list->get(list, row);
dropdown_insert_item(list, row, elm);
}
}
UiListSelection ui_dropdown_getselection_impl(UiList *list) {
UiListSelection sel = {
0,
NULL };
UiListView *listview = (UiListView*)list->obj;
int index = (
int)SendMessage(listview->widget.hwnd,
CB_GETCURSEL,
0,
0);
if (index >=
0) {
sel.rows = malloc(
sizeof(
int));
sel.rows[
0] = index;
sel.count =
1;
}
return sel;
}
void ui_dropdown_setselection_impl(UiList *list, UiListSelection selection) {
UiListView *listview = (UiListView*)list->obj;
SendMessage(listview->widget.hwnd,
CB_SETCURSEL,
0,
0);
}
void ui_dropdown_select(
UIWIDGET dropdown,
int index) {
SendMessage(dropdown->hwnd,
CB_SETCURSEL,
0,
0);
}
int ui_dropdown_selection(
UIWIDGET dropdown) {
return SendMessage(dropdown->hwnd,
CB_GETCURSEL,
0,
0);
}