From a6358e76b3b3c6a973d2487a4be395799433c206 Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Fri, 7 Sep 2018 18:37:38 +0200 Subject: [PATCH 01/36] table models [WIP] --- package.json | 2 +- src/includes/modules.h | 1 + src/includes/napi_utils.h | 9 ++- src/module.c | 1 + src/table-model.c | 147 ++++++++++++++++++++++++++++++++++++++ tests/table-model.js | 19 +++++ 6 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 src/table-model.c create mode 100644 tests/table-model.js diff --git a/package.json b/package.json index b457250..a5e618c 100755 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "rebuild": "rimraf build *.node && node-gyp configure build", "build": "node-gyp configure build", "install": "npm run --silent download-libui && npm run --silent download-libui-napi || npm run build", - "test": "cross-env LIBUI_TARGET=test node-gyp configure build && cross-env LIBUI_TARGET=test DEBUG=ControlInternal tape tests/*.js | tap-spec", + "test": "cross-env LIBUI_TARGET=test node-gyp configure build && cross-env LIBUI_TARGET=test DEBUG=ControlInternal tape tests/table-model.js | tap-spec", "precommit": "check-clang-format \"'npm run lint'\"", "lint": "clang-format -i --glob='{tests/**/*.{h,c,m,js},example/*.js,js/**/*.js,src/**/*.{h,c,m},index.js,example.js,test.js,example/gallery/src/**/*.js,tools/**/*.js,test_ui.js}'" }, diff --git a/src/includes/modules.h b/src/includes/modules.h index 94e3f31..6e32d8a 100644 --- a/src/includes/modules.h +++ b/src/includes/modules.h @@ -39,3 +39,4 @@ napi_value _libui_init_ui_control(napi_env env, napi_value exports); napi_value _libui_init_area_stroke(napi_env env, napi_value exports); napi_value _libui_init_area_matrix(napi_env env, napi_value exports); napi_value _libui_init_dialogs(napi_env env, napi_value exports); +napi_value _libui_init_table_model(napi_env env, napi_value exports); \ No newline at end of file diff --git a/src/includes/napi_utils.h b/src/includes/napi_utils.h index 42712e7..96dff8d 100644 --- a/src/includes/napi_utils.h +++ b/src/includes/napi_utils.h @@ -140,7 +140,14 @@ extern napi_ref null_ref; ARG_NAME = null_ref; \ } else { \ status = napi_create_reference(env, argv[ARG_IDX], 1, &ARG_NAME); \ - CHECK_STATUS_THROW(status, napi_create_reference); \ + if (status != napi_ok) { \ + const napi_extended_error_info *result; \ + napi_get_last_error_info(env, &result); \ + char err[1024]; \ + snprintf(err, 1024, "Argument " #ARG_NAME ": %s", result->error_message); \ + napi_throw_type_error(env, NULL, err); \ + return NULL; \ + } \ } \ } diff --git a/src/module.c b/src/module.c index 1af3b9d..f5d9ef8 100644 --- a/src/module.c +++ b/src/module.c @@ -39,6 +39,7 @@ static napi_value init_all(napi_env env, napi_value exports) { _libui_init_area_matrix(env, exports); _libui_init_grid(env, exports); _libui_init_dialogs(env, exports); + _libui_init_table_model(env, exports); _libui_init_tests(env, exports); diff --git a/src/table-model.c b/src/table-model.c new file mode 100644 index 0000000..06a44f8 --- /dev/null +++ b/src/table-model.c @@ -0,0 +1,147 @@ +#include +#include "napi_utils.h" +#include "control.h" +#include "events.h" + +static const char *MODULE = "TableModel"; + +/* +// NumColumns returns the number of model columns in the + // uiTableModel. This value must remain constant through the + // lifetime of the uiTableModel. This method is not guaranteed + // to be called depending on the system. + // TODO strongly check column numbers and types on all platforms so these clauses can go away + int (*NumColumns)(uiTableModelHandler *, uiTableModel *); + // ColumnType returns the value type of the data stored in + // the given model column of the uiTableModel. The returned + // values must remain constant through the lifetime of the + // uiTableModel. This method is not guaranteed to be called + // depending on the system. + uiTableValueType (*ColumnType)(uiTableModelHandler *, uiTableModel *, int); + // NumRows returns the number or rows in the uiTableModel. + // This value must be non-negative. + int (*NumRows)(uiTableModelHandler *, uiTableModel *); + // CellValue returns a uiTableValue corresponding to the model + // cell at (row, column). The type of the returned uiTableValue + // must match column's value type. Under some circumstances, + // NULL may be returned; refer to the various methods that add + // columns to uiTable for details. Once returned, the uiTable + // that calls CellValue will free the uiTableValue returned. + uiTableValue *(*CellValue)(uiTableModelHandler *mh, uiTableModel *m, int row, int column); + // SetCellValue changes the model cell value at (row, column) + // in the uiTableModel. Within this function, either do nothing + // to keep the current cell value or save the new cell value as + // appropriate. After SetCellValue is called, the uiTable will + // itself reload the table cell. Under certain conditions, the + // uiTableValue passed in can be NULL; refer to the various + // methods that add columns to uiTable for details. Once + // returned, the uiTable that called SetCellValue will free the + // uiTableValue passed in. + void (*SetCellValue)(uiTableModelHandler *, uiTableModel *, int, int, const uiTableValue *); +*/ + + +LIBUI_FUNCTION(create) { + INIT_ARGS(5); + + ARG_CB_REF(numColumns, 0); + ARG_CB_REF(numRows, 1); + ARG_CB_REF(columnType, 2); + ARG_CB_REF(cellValue, 3); + ARG_CB_REF(setCellValue, 4); + + napi_value global; + napi_status status = napi_get_global(env, &global); + CHECK_STATUS_THROW(status, napi_get_global); + + napi_value function_contructor; + status = napi_get_named_property(env, global, "Function", &function_contructor); + CHECK_STATUS_THROW(status, napi_get_named_property); + + bool is_function = false; + status = napi_instanceof(env, argv[0], function_contructor, &is_function); +// printf("%d == %d, %d\n", status, napi_ok, is_function); + if (status != napi_ok || !is_function) { + napi_throw_type_error(env, NULL, "Argument numColumns: a function was expected"); + return NULL; + } + + status = napi_instanceof(env, argv[1], function_contructor, &is_function); + if (status != napi_ok || !is_function) { + napi_throw_type_error(env, NULL, "Argument numRows: a function was expected"); + return NULL; + } + + status = napi_instanceof(env, argv[2], function_contructor, &is_function); + if (status != napi_ok || !is_function) { + napi_throw_type_error(env, NULL, "Argument columnType: a function was expected"); + return NULL; + } + + status = napi_instanceof(env, argv[3], function_contructor, &is_function); + if (status != napi_ok || !is_function) { + napi_throw_type_error(env, NULL, "Argument cellValue: a function was expected"); + return NULL; + } + + + status = napi_instanceof(env, argv[4], function_contructor, &is_function); + if (status != napi_ok || !is_function) { + napi_throw_type_error(env, NULL, "Argument setCellValue: a function was expected"); + return NULL; + } + +/* + uiControl *ctrl = uiControl(uiNewButton(label)); + free(label); + return control_handle_new(env, ctrl, "button");*/ + return NULL; +} +/* +LIBUI_FUNCTION(onClicked) { + INIT_ARGS(2); + + ARG_POINTER(struct control_handle, handle, 0); + ENSURE_NOT_DESTROYED(); + ARG_CB_REF(cb_ref, 1); + + struct event_t *event = create_event(env, cb_ref, "onClicked"); + if (event == NULL) { + return NULL; + } + + install_event(handle->events, event); + + uiButtonOnClicked(uiButton(handle->control), CALLBACK_OF(uiButton, control_event_cb), event); + + return NULL; +} + +LIBUI_FUNCTION(setText) { + INIT_ARGS(2); + + ARG_POINTER(struct control_handle, handle, 0); + ENSURE_NOT_DESTROYED(); + ARG_STRING(value, 1); + uiButtonSetText(uiButton(handle->control), value); + free(value); + return NULL; +} + +LIBUI_FUNCTION(getText) { + INIT_ARGS(1); + + ARG_POINTER(struct control_handle, handle, 0); + ENSURE_NOT_DESTROYED(); + char *char_ptr = uiButtonText(uiButton(handle->control)); + napi_value result = make_utf8_string(env, char_ptr); + uiFreeText(char_ptr); + return result; +} +*/ +napi_value _libui_init_table_model(napi_env env, napi_value exports) { + DEFINE_MODULE(); + LIBUI_EXPORT(create); + + return module; +} diff --git a/tests/table-model.js b/tests/table-model.js new file mode 100644 index 0000000..0690450 --- /dev/null +++ b/tests/table-model.js @@ -0,0 +1,19 @@ +const test = require('tape'); +const {TableModel} = require('..'); + +test('TableModel has a create fn', t => { + t.equal(typeof TableModel.create, 'function'); + t.end(); +}); + +test('TableModel create fn require 5 fn args', t => { + const fn = test; + t.throws(() => TableModel.create(42), /Too few arguments/); + t.throws(() => TableModel.create({}, {}, {}, {}, {}), /Argument numColumns: a function was expected/); + t.throws(() => TableModel.create(fn, {}, {}, {}, {}), /Argument numRows: a function was expected/); + t.throws(() => TableModel.create(fn, fn, {}, {}, {}), /Argument columnType: a function was expected/); + t.throws(() => TableModel.create(fn, fn, fn, {}, {}), /Argument cellValue: a function was expected/); + t.throws(() => TableModel.create(fn, fn, fn, fn, {}), /Argument setCellValue: a function was expected/); + TableModel.create(fn, fn, fn, fn, fn); + t.end(); +}); From ed610a767ad1d28c993492ce5ab1a1a949a77864 Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Sat, 8 Sep 2018 09:42:10 +0200 Subject: [PATCH 02/36] Moved function type check to napi_utils --- src/app.c | 2 ++ src/includes/napi_utils.h | 17 ++++++++++++++- src/table-model.c | 45 --------------------------------------- 3 files changed, 18 insertions(+), 46 deletions(-) diff --git a/src/app.c b/src/app.c index dfe31d1..37bcd4d 100644 --- a/src/app.c +++ b/src/app.c @@ -10,6 +10,8 @@ static const char *MODULE = "App"; struct children_list *visible_windows = NULL; + + static int c_wrap_cb(void *data) { struct event_t *event = (struct event_t *)data; diff --git a/src/includes/napi_utils.h b/src/includes/napi_utils.h index 96dff8d..2923d7a 100644 --- a/src/includes/napi_utils.h +++ b/src/includes/napi_utils.h @@ -138,7 +138,22 @@ extern napi_ref null_ref; \ if (arg_type == napi_null) { \ ARG_NAME = null_ref; \ - } else { \ + } else { \ + napi_value global; \ + status = napi_get_global(env, &global); \ + CHECK_STATUS_THROW(status, napi_get_global); \ +\ + napi_value function_constructor; \ + status = napi_get_named_property(env, global, "Function", &function_constructor); \ + CHECK_STATUS_THROW(status, napi_get_named_property); \ + \ + bool is_function = false; \ + status = napi_instanceof(env, argv[ARG_IDX], function_constructor, &is_function); \ + if (status != napi_ok || !is_function) { \ + napi_throw_type_error(env, NULL, "Argument " #ARG_NAME ": a function was expected"); \ + return NULL; \ + } \ + \ status = napi_create_reference(env, argv[ARG_IDX], 1, &ARG_NAME); \ if (status != napi_ok) { \ const napi_extended_error_info *result; \ diff --git a/src/table-model.c b/src/table-model.c index 06a44f8..58f99b9 100644 --- a/src/table-model.c +++ b/src/table-model.c @@ -50,51 +50,6 @@ LIBUI_FUNCTION(create) { ARG_CB_REF(cellValue, 3); ARG_CB_REF(setCellValue, 4); - napi_value global; - napi_status status = napi_get_global(env, &global); - CHECK_STATUS_THROW(status, napi_get_global); - - napi_value function_contructor; - status = napi_get_named_property(env, global, "Function", &function_contructor); - CHECK_STATUS_THROW(status, napi_get_named_property); - - bool is_function = false; - status = napi_instanceof(env, argv[0], function_contructor, &is_function); -// printf("%d == %d, %d\n", status, napi_ok, is_function); - if (status != napi_ok || !is_function) { - napi_throw_type_error(env, NULL, "Argument numColumns: a function was expected"); - return NULL; - } - - status = napi_instanceof(env, argv[1], function_contructor, &is_function); - if (status != napi_ok || !is_function) { - napi_throw_type_error(env, NULL, "Argument numRows: a function was expected"); - return NULL; - } - - status = napi_instanceof(env, argv[2], function_contructor, &is_function); - if (status != napi_ok || !is_function) { - napi_throw_type_error(env, NULL, "Argument columnType: a function was expected"); - return NULL; - } - - status = napi_instanceof(env, argv[3], function_contructor, &is_function); - if (status != napi_ok || !is_function) { - napi_throw_type_error(env, NULL, "Argument cellValue: a function was expected"); - return NULL; - } - - - status = napi_instanceof(env, argv[4], function_contructor, &is_function); - if (status != napi_ok || !is_function) { - napi_throw_type_error(env, NULL, "Argument setCellValue: a function was expected"); - return NULL; - } - -/* - uiControl *ctrl = uiControl(uiNewButton(label)); - free(label); - return control_handle_new(env, ctrl, "button");*/ return NULL; } /* From ce9738a195e7a6602beddf715c61645e3727d368 Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Sat, 8 Sep 2018 12:41:44 +0200 Subject: [PATCH 03/36] model handler binding struct --- src/table-model.c | 58 ++++++++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 34 deletions(-) diff --git a/src/table-model.c b/src/table-model.c index 58f99b9..fe0f610 100644 --- a/src/table-model.c +++ b/src/table-model.c @@ -5,41 +5,31 @@ static const char *MODULE = "TableModel"; -/* -// NumColumns returns the number of model columns in the - // uiTableModel. This value must remain constant through the - // lifetime of the uiTableModel. This method is not guaranteed - // to be called depending on the system. - // TODO strongly check column numbers and types on all platforms so these clauses can go away - int (*NumColumns)(uiTableModelHandler *, uiTableModel *); - // ColumnType returns the value type of the data stored in - // the given model column of the uiTableModel. The returned - // values must remain constant through the lifetime of the - // uiTableModel. This method is not guaranteed to be called - // depending on the system. - uiTableValueType (*ColumnType)(uiTableModelHandler *, uiTableModel *, int); - // NumRows returns the number or rows in the uiTableModel. - // This value must be non-negative. - int (*NumRows)(uiTableModelHandler *, uiTableModel *); - // CellValue returns a uiTableValue corresponding to the model - // cell at (row, column). The type of the returned uiTableValue - // must match column's value type. Under some circumstances, - // NULL may be returned; refer to the various methods that add - // columns to uiTable for details. Once returned, the uiTable - // that calls CellValue will free the uiTableValue returned. - uiTableValue *(*CellValue)(uiTableModelHandler *mh, uiTableModel *m, int row, int column); - // SetCellValue changes the model cell value at (row, column) - // in the uiTableModel. Within this function, either do nothing - // to keep the current cell value or save the new cell value as - // appropriate. After SetCellValue is called, the uiTable will - // itself reload the table cell. Under certain conditions, the - // uiTableValue passed in can be NULL; refer to the various - // methods that add columns to uiTable for details. Once - // returned, the uiTable that called SetCellValue will free the - // uiTableValue passed in. - void (*SetCellValue)(uiTableModelHandler *, uiTableModel *, int, int, const uiTableValue *); -*/ +static int numColumns (uiTableModelHandler *mh, uiTableModel *m) { + +} +static uiTableValueType columnType (uiTableModelHandler *mh, uiTableModel *m, int column) { + +} +static int numRows (uiTableModelHandler *mh, uiTableModel *m) { + +} +static uiTableValue *cellValue (uiTableModelHandler *mh, uiTableModel *m, int row, int column) { + +} +static void setCellValue (uiTableModelHandler *mh, uiTableModel *m, int row, int column, const uiTableValue *value) { + +} + +struct binding_handler { + uiTableModelHandler handler; + napi_ref jsNumColumns; + napi_ref jsColumnType; + napi_ref jsNumRows; + napi_ref jsCellValue; + napi_ref jsSetCellValue; +}; LIBUI_FUNCTION(create) { INIT_ARGS(5); From 6f0d8a719e33e7e0a74acd3517b1b9d7aa2af001 Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Sun, 9 Sep 2018 17:55:11 +0200 Subject: [PATCH 04/36] model create function --- src/app.c | 2 -- src/includes/napi_utils.h | 49 ++++++++++++++++--------------- src/table-model.c | 61 ++++++++++++++++++++++++++++++--------- tests/table-model.js | 15 ++++++---- tools/libui-download.js | 17 ++++++----- 5 files changed, 92 insertions(+), 52 deletions(-) diff --git a/src/app.c b/src/app.c index 37bcd4d..dfe31d1 100644 --- a/src/app.c +++ b/src/app.c @@ -10,8 +10,6 @@ static const char *MODULE = "App"; struct children_list *visible_windows = NULL; - - static int c_wrap_cb(void *data) { struct event_t *event = (struct event_t *)data; diff --git a/src/includes/napi_utils.h b/src/includes/napi_utils.h index 2923d7a..d3a1e35 100644 --- a/src/includes/napi_utils.h +++ b/src/includes/napi_utils.h @@ -138,31 +138,32 @@ extern napi_ref null_ref; \ if (arg_type == napi_null) { \ ARG_NAME = null_ref; \ - } else { \ - napi_value global; \ - status = napi_get_global(env, &global); \ - CHECK_STATUS_THROW(status, napi_get_global); \ -\ - napi_value function_constructor; \ - status = napi_get_named_property(env, global, "Function", &function_constructor); \ - CHECK_STATUS_THROW(status, napi_get_named_property); \ - \ - bool is_function = false; \ - status = napi_instanceof(env, argv[ARG_IDX], function_constructor, &is_function); \ - if (status != napi_ok || !is_function) { \ - napi_throw_type_error(env, NULL, "Argument " #ARG_NAME ": a function was expected"); \ - return NULL; \ - } \ - \ + } else { \ + napi_value global; \ + status = napi_get_global(env, &global); \ + CHECK_STATUS_THROW(status, napi_get_global); \ + \ + napi_value function_constructor; \ + status = napi_get_named_property(env, global, "Function", &function_constructor); \ + CHECK_STATUS_THROW(status, napi_get_named_property); \ + \ + bool is_function = false; \ + status = napi_instanceof(env, argv[ARG_IDX], function_constructor, &is_function); \ + if (status != napi_ok || !is_function) { \ + napi_throw_type_error(env, NULL, \ + "Argument " #ARG_NAME ": a function was expected"); \ + return NULL; \ + } \ + \ status = napi_create_reference(env, argv[ARG_IDX], 1, &ARG_NAME); \ - if (status != napi_ok) { \ - const napi_extended_error_info *result; \ - napi_get_last_error_info(env, &result); \ - char err[1024]; \ - snprintf(err, 1024, "Argument " #ARG_NAME ": %s", result->error_message); \ - napi_throw_type_error(env, NULL, err); \ - return NULL; \ - } \ + if (status != napi_ok) { \ + const napi_extended_error_info *result; \ + napi_get_last_error_info(env, &result); \ + char err[1024]; \ + snprintf(err, 1024, "Argument " #ARG_NAME ": %s", result->error_message); \ + napi_throw_type_error(env, NULL, err); \ + return NULL; \ + } \ } \ } diff --git a/src/table-model.c b/src/table-model.c index fe0f610..db9f104 100644 --- a/src/table-model.c +++ b/src/table-model.c @@ -5,25 +5,36 @@ static const char *MODULE = "TableModel"; -static int numColumns (uiTableModelHandler *mh, uiTableModel *m) { - +static int c_numColumns(uiTableModelHandler *mh, uiTableModel *m) { + return 0; } -static uiTableValueType columnType (uiTableModelHandler *mh, uiTableModel *m, int column) { - -} -static int numRows (uiTableModelHandler *mh, uiTableModel *m) { - + +static uiTableValueType c_columnType(uiTableModelHandler *mh, uiTableModel *m, int column) { + return uiTableValueTypeInt; } -static uiTableValue *cellValue (uiTableModelHandler *mh, uiTableModel *m, int row, int column) { - + +static int c_numRows(uiTableModelHandler *mh, uiTableModel *m) { + return 0; } -static void setCellValue (uiTableModelHandler *mh, uiTableModel *m, int row, int column, const uiTableValue *value) { - + +static uiTableValue *c_cellValue(uiTableModelHandler *mh, uiTableModel *m, int row, int column) { + return NULL; } +static void c_setCellValue(uiTableModelHandler *mh, uiTableModel *m, int row, int column, + const uiTableValue *value) {} + +static void on_model_gc(napi_env env, void *finalize_data, void *finalize_hint) { + uiTableModel *model = (uiTableModel *)finalize_data; + struct binding_handler *handler = (struct binding_handler *)finalize_hint; + + uiFreeTableModel(model); + free(handler); +} struct binding_handler { uiTableModelHandler handler; + napi_ref model_ref; napi_ref jsNumColumns; napi_ref jsColumnType; napi_ref jsNumRows; @@ -40,7 +51,31 @@ LIBUI_FUNCTION(create) { ARG_CB_REF(cellValue, 3); ARG_CB_REF(setCellValue, 4); - return NULL; + struct binding_handler *model_handler = + (struct binding_handler *)malloc(sizeof(struct binding_handler)); + + model_handler->jsNumColumns = numColumns; + model_handler->jsNumRows = numRows; + model_handler->jsColumnType = columnType; + model_handler->jsCellValue = cellValue; + model_handler->jsSetCellValue = setCellValue; + model_handler->handler.NumColumns = c_numColumns; + model_handler->handler.NumRows = c_numRows; + model_handler->handler.ColumnType = c_columnType; + model_handler->handler.CellValue = c_cellValue; + model_handler->handler.SetCellValue = c_setCellValue; + + uiTableModel *model = uiNewTableModel((uiTableModelHandler *)model_handler); + + napi_value model_external; + napi_status status = + napi_create_external(env, model, on_model_gc, model_handler, &model_external); + CHECK_STATUS_THROW(status, napi_create_external); + + status = napi_create_reference(env, model_external, 0, &model_handler->model_ref); + CHECK_STATUS_THROW(status, napi_create_reference); + + return model_external; } /* LIBUI_FUNCTION(onClicked) { @@ -87,6 +122,6 @@ LIBUI_FUNCTION(getText) { napi_value _libui_init_table_model(napi_env env, napi_value exports) { DEFINE_MODULE(); LIBUI_EXPORT(create); - + return module; } diff --git a/tests/table-model.js b/tests/table-model.js index 0690450..624a418 100644 --- a/tests/table-model.js +++ b/tests/table-model.js @@ -9,11 +9,16 @@ test('TableModel has a create fn', t => { test('TableModel create fn require 5 fn args', t => { const fn = test; t.throws(() => TableModel.create(42), /Too few arguments/); - t.throws(() => TableModel.create({}, {}, {}, {}, {}), /Argument numColumns: a function was expected/); - t.throws(() => TableModel.create(fn, {}, {}, {}, {}), /Argument numRows: a function was expected/); - t.throws(() => TableModel.create(fn, fn, {}, {}, {}), /Argument columnType: a function was expected/); - t.throws(() => TableModel.create(fn, fn, fn, {}, {}), /Argument cellValue: a function was expected/); - t.throws(() => TableModel.create(fn, fn, fn, fn, {}), /Argument setCellValue: a function was expected/); + t.throws(() => TableModel.create({}, {}, {}, {}, {}), + /Argument numColumns: a function was expected/); + t.throws(() => TableModel.create(fn, {}, {}, {}, {}), + /Argument numRows: a function was expected/); + t.throws(() => TableModel.create(fn, fn, {}, {}, {}), + /Argument columnType: a function was expected/); + t.throws(() => TableModel.create(fn, fn, fn, {}, {}), + /Argument cellValue: a function was expected/); + t.throws(() => TableModel.create(fn, fn, fn, fn, {}), + /Argument setCellValue: a function was expected/); TableModel.create(fn, fn, fn, fn, fn); t.end(); }); diff --git a/tools/libui-download.js b/tools/libui-download.js index 7b57305..0b6faa0 100644 --- a/tools/libui-download.js +++ b/tools/libui-download.js @@ -35,7 +35,7 @@ function download(opts) { const version = opts.version; const symbols = opts.symbols || false; const filename = 'libui-' + version + '-' + platform + '-' + arch + '-shared' + - (platform === 'windows' ? '.zip' : '.tgz'); + (platform === 'windows' ? '.zip' : '.tgz'); if (!version) { throw new Error('must specify needed version of libui in package.json'); @@ -86,13 +86,14 @@ function main() { return download({version: process.env.npm_package_libui}).then(zipPath => { console.log('Downloaded zip:', zipPath); if (os.platform() === 'win32') { - return new Promise((resolve, reject) => unzipExtract(zipPath, {dir: process.cwd()}, err => { - if (err) { - return reject(err); - } - resolve(); - console.log('Libui binaries extracted to:', process.cwd()); - })); + return new Promise( + (resolve, reject) => unzipExtract(zipPath, {dir: process.cwd()}, err => { + if (err) { + return reject(err); + } + resolve(); + console.log('Libui binaries extracted to:', process.cwd()); + })); } else { tar.extract({file: zipPath, sync: true}); } From 706787d607250e387bd8d191f7c4f976d2dbc0eb Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Sun, 9 Sep 2018 18:49:58 +0200 Subject: [PATCH 05/36] numcolumns fn --- src/table-model.c | 80 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 66 insertions(+), 14 deletions(-) diff --git a/src/table-model.c b/src/table-model.c index db9f104..6a07ee1 100644 --- a/src/table-model.c +++ b/src/table-model.c @@ -5,8 +5,60 @@ static const char *MODULE = "TableModel"; +struct binding_handler { + uiTableModelHandler handler; + napi_ref model_ref; + napi_env env; + napi_async_context context; + napi_ref jsNumColumns; + napi_ref jsColumnType; + napi_ref jsNumRows; + napi_ref jsCellValue; + napi_ref jsSetCellValue; +}; + static int c_numColumns(uiTableModelHandler *mh, uiTableModel *m) { - return 0; + struct binding_handler *bh = (struct binding_handler *)mh; + int argc = 0; + napi_value *argv = NULL; + + napi_value fn; + napi_status status = napi_get_reference_value(bh->env, bh->jsNumColumns, &fn); + + napi_env env = bh->env; + + napi_handle_scope handle_scope; + status = napi_open_handle_scope(env, &handle_scope); + CHECK_STATUS_UNCAUGHT(status, napi_open_handle_scope, 0); + + napi_value resource_object; + status = napi_create_object(env, &resource_object); + CHECK_STATUS_UNCAUGHT(status, napi_create_object, 0); + + LIBUI_NODE_DEBUG("Calling numColumns method"); + + napi_value result; + status = napi_make_callback(env, bh->context, resource_object, fn, argc, argv, &result); + + if (status == napi_pending_exception) { + napi_value last_exception; + napi_get_and_clear_last_exception(env, &last_exception); + napi_fatal_exception(env, last_exception); + return 0; + } + + CHECK_STATUS_UNCAUGHT(status, napi_make_callback, 0); + + status = napi_close_handle_scope(env, handle_scope); + CHECK_STATUS_UNCAUGHT(status, napi_close_handle_scope, 0); + + LIBUI_NODE_DEBUG("Method called"); + + int32_t int_result; + status = napi_get_value_int32(bh->env, result, &int_result); + CHECK_STATUS_UNCAUGHT(status, napi_make_callback, 0); + + return int_result; } static uiTableValueType c_columnType(uiTableModelHandler *mh, uiTableModel *m, int column) { @@ -27,21 +79,11 @@ static void c_setCellValue(uiTableModelHandler *mh, uiTableModel *m, int row, in static void on_model_gc(napi_env env, void *finalize_data, void *finalize_hint) { uiTableModel *model = (uiTableModel *)finalize_data; struct binding_handler *handler = (struct binding_handler *)finalize_hint; - + /* TODO: decrease to 0 all fns references */ uiFreeTableModel(model); free(handler); } -struct binding_handler { - uiTableModelHandler handler; - napi_ref model_ref; - napi_ref jsNumColumns; - napi_ref jsColumnType; - napi_ref jsNumRows; - napi_ref jsCellValue; - napi_ref jsSetCellValue; -}; - LIBUI_FUNCTION(create) { INIT_ARGS(5); @@ -51,6 +93,15 @@ LIBUI_FUNCTION(create) { ARG_CB_REF(cellValue, 3); ARG_CB_REF(setCellValue, 4); + napi_value async_resource_name; + napi_status status = + napi_create_string_utf8(env, "TableModel", NAPI_AUTO_LENGTH, &async_resource_name); + CHECK_STATUS_THROW(status, napi_create_string_utf8); + + napi_async_context context; + status = napi_async_init(env, NULL, async_resource_name, &context); + CHECK_STATUS_THROW(status, napi_async_init); + struct binding_handler *model_handler = (struct binding_handler *)malloc(sizeof(struct binding_handler)); @@ -64,12 +115,13 @@ LIBUI_FUNCTION(create) { model_handler->handler.ColumnType = c_columnType; model_handler->handler.CellValue = c_cellValue; model_handler->handler.SetCellValue = c_setCellValue; + model_handler->env = env; + model_handler->context = context; uiTableModel *model = uiNewTableModel((uiTableModelHandler *)model_handler); napi_value model_external; - napi_status status = - napi_create_external(env, model, on_model_gc, model_handler, &model_external); + status = napi_create_external(env, model, on_model_gc, model_handler, &model_external); CHECK_STATUS_THROW(status, napi_create_external); status = napi_create_reference(env, model_external, 0, &model_handler->model_ref); From 5d9a714e3e8797df6b9d596c2f652500d6ab0f14 Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Sun, 9 Sep 2018 19:02:03 +0200 Subject: [PATCH 06/36] todo --- src/table-model.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/table-model.c b/src/table-model.c index 6a07ee1..53a6289 100644 --- a/src/table-model.c +++ b/src/table-model.c @@ -80,6 +80,7 @@ static void on_model_gc(napi_env env, void *finalize_data, void *finalize_hint) uiTableModel *model = (uiTableModel *)finalize_data; struct binding_handler *handler = (struct binding_handler *)finalize_hint; /* TODO: decrease to 0 all fns references */ + /* TODO: clean up async context */ uiFreeTableModel(model); free(handler); } From 9e7a3e73bb1d96353f82ae9066cfe15af8025373 Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Sun, 9 Sep 2018 19:11:03 +0200 Subject: [PATCH 07/36] refactor: extracted run_handler_fn --- src/table-model.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/table-model.c b/src/table-model.c index 53a6289..3ec2b96 100644 --- a/src/table-model.c +++ b/src/table-model.c @@ -17,11 +17,7 @@ struct binding_handler { napi_ref jsSetCellValue; }; -static int c_numColumns(uiTableModelHandler *mh, uiTableModel *m) { - struct binding_handler *bh = (struct binding_handler *)mh; - int argc = 0; - napi_value *argv = NULL; - +static napi_value run_handler_fn(struct binding_handler *bh, int argc, napi_value *argv) { napi_value fn; napi_status status = napi_get_reference_value(bh->env, bh->jsNumColumns, &fn); @@ -29,11 +25,11 @@ static int c_numColumns(uiTableModelHandler *mh, uiTableModel *m) { napi_handle_scope handle_scope; status = napi_open_handle_scope(env, &handle_scope); - CHECK_STATUS_UNCAUGHT(status, napi_open_handle_scope, 0); + CHECK_STATUS_UNCAUGHT(status, napi_open_handle_scope, NULL); napi_value resource_object; status = napi_create_object(env, &resource_object); - CHECK_STATUS_UNCAUGHT(status, napi_create_object, 0); + CHECK_STATUS_UNCAUGHT(status, napi_create_object, NULL); LIBUI_NODE_DEBUG("Calling numColumns method"); @@ -47,15 +43,28 @@ static int c_numColumns(uiTableModelHandler *mh, uiTableModel *m) { return 0; } - CHECK_STATUS_UNCAUGHT(status, napi_make_callback, 0); + CHECK_STATUS_UNCAUGHT(status, napi_make_callback, NULL); status = napi_close_handle_scope(env, handle_scope); - CHECK_STATUS_UNCAUGHT(status, napi_close_handle_scope, 0); + CHECK_STATUS_UNCAUGHT(status, napi_close_handle_scope, NULL); LIBUI_NODE_DEBUG("Method called"); + return result; +} + +static int c_numColumns(uiTableModelHandler *mh, uiTableModel *m) { + struct binding_handler *bh = (struct binding_handler *)mh; + + napi_value result = run_handler_fn(bh, 0, NULL); + napi_env env = bh->env; + + if (result == NULL) { + return 0; + } + int32_t int_result; - status = napi_get_value_int32(bh->env, result, &int_result); + napi_status status = napi_get_value_int32(env, result, &int_result); CHECK_STATUS_UNCAUGHT(status, napi_make_callback, 0); return int_result; From 47fc4dc9b51bbbd2752ab14cbc59da09d4144dd9 Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Wed, 12 Sep 2018 16:20:30 +0200 Subject: [PATCH 08/36] table & example [WIP] --- example/tables.js | 20 ++++++++++++++++++++ index.js | 5 +++-- js/table.js | 34 ++++++++++++++++++++++++++++++++++ src/includes/modules.h | 3 ++- src/module.c | 1 + src/table-model.c | 12 ++++++------ src/table.c | 25 +++++++++++++++++++++++++ 7 files changed, 91 insertions(+), 9 deletions(-) create mode 100644 example/tables.js create mode 100644 js/table.js create mode 100644 src/table.c diff --git a/example/tables.js b/example/tables.js new file mode 100644 index 0000000..520a2a0 --- /dev/null +++ b/example/tables.js @@ -0,0 +1,20 @@ +const libui = require('..'); + +const win = new libui.UiWindow('Tables example', 320, 60, true); +win.margined = true; + +const tb = new libui.UiTable({ + numColumns() { + return 2; + } +}); +win.setChild(tb); + +win.onClosing(() => { + win.close(); + libui.stopLoop(); +}); + +win.show(); + +libui.startLoop(); diff --git a/index.js b/index.js index 3295ac6..dba0641 100644 --- a/index.js +++ b/index.js @@ -48,7 +48,7 @@ const { const {UiBox} = require('./js/box'); const {SeparatorBase} = require('./js/separator-base'); const {UiControl} = require('./js/ui-control'); - +const {UiTable} = require('./js/table'); const {UiButton} = require('./js/button'); const {UiWindow} = require('./js/window'); const {UiSlider} = require('./js/slider'); @@ -146,7 +146,7 @@ function applySetterGetterAll(doSetter, ...classConstructors) { } // Takes about 3.5ms: -applySetterGetter(UiEntryBase, UiBox, SeparatorBase, UiControl, UiGrid, UiMenuItem, +applySetterGetter(UiTable, UiEntryBase, UiBox, SeparatorBase, UiControl, UiGrid, UiMenuItem, UiMenu, UiSpinbox, UiHorizontalSeparator, UiVerticalSeparator, UiRadioButtons, UiProgressBar, UiGroup, UiEntry, UiPasswordEntry, UiSearchEntry, UiEditableCombobox, UiTimePicker, UiDatePicker, @@ -159,6 +159,7 @@ applySetterGetterAll(true, Point, Color, Size); applySetterGetterAll(false, AreaDrawParams, UiAreaMouseEvent, UiAreaKeyEvent); Object.assign(libui, { + UiTable, UiFontButton, FontDescriptor, FontAttribute, diff --git a/js/table.js b/js/table.js new file mode 100644 index 0000000..7702ecb --- /dev/null +++ b/js/table.js @@ -0,0 +1,34 @@ +const {Table} = require('..'); +const {TableModel} = require('..'); +const {UiControl} = require('./ui-control'); + +const noop = () => 0; + +function mkTable(model) { + const tableModel = TableModel.create( + model.numColumns || noop, + model.numRows || noop, + model.columnType || noop, + model.cellValue || noop, + model.setCellValue || noop + ); + + return Table.create(tableModel) +} + +/** + * A data table. + * @extends UiControl + */ +class UiTable extends UiControl { + /** + * Create a new UiTable object. + * @param {object} model - data model for the new table + * @return {UiTable} + */ + constructor(model) { + super(mkTable(model)); + } +} + +module.exports = {UiTable}; diff --git a/src/includes/modules.h b/src/includes/modules.h index 6e32d8a..ab4ccef 100644 --- a/src/includes/modules.h +++ b/src/includes/modules.h @@ -39,4 +39,5 @@ napi_value _libui_init_ui_control(napi_env env, napi_value exports); napi_value _libui_init_area_stroke(napi_env env, napi_value exports); napi_value _libui_init_area_matrix(napi_env env, napi_value exports); napi_value _libui_init_dialogs(napi_env env, napi_value exports); -napi_value _libui_init_table_model(napi_env env, napi_value exports); \ No newline at end of file +napi_value _libui_init_table_model(napi_env env, napi_value exports); +napi_value _libui_init_table(napi_env env, napi_value exports); \ No newline at end of file diff --git a/src/module.c b/src/module.c index f5d9ef8..dd48d11 100644 --- a/src/module.c +++ b/src/module.c @@ -40,6 +40,7 @@ static napi_value init_all(napi_env env, napi_value exports) { _libui_init_grid(env, exports); _libui_init_dialogs(env, exports); _libui_init_table_model(env, exports); + _libui_init_table(env, exports); _libui_init_tests(env, exports); diff --git a/src/table-model.c b/src/table-model.c index 3ec2b96..67e0d46 100644 --- a/src/table-model.c +++ b/src/table-model.c @@ -17,9 +17,9 @@ struct binding_handler { napi_ref jsSetCellValue; }; -static napi_value run_handler_fn(struct binding_handler *bh, int argc, napi_value *argv) { +static napi_value run_handler_fn(struct binding_handler *bh, napi_ref fn_ref, int argc, napi_value *argv) { napi_value fn; - napi_status status = napi_get_reference_value(bh->env, bh->jsNumColumns, &fn); + napi_status status = napi_get_reference_value(bh->env, fn_ref, &fn); napi_env env = bh->env; @@ -56,7 +56,7 @@ static napi_value run_handler_fn(struct binding_handler *bh, int argc, napi_valu static int c_numColumns(uiTableModelHandler *mh, uiTableModel *m) { struct binding_handler *bh = (struct binding_handler *)mh; - napi_value result = run_handler_fn(bh, 0, NULL); + napi_value result = run_handler_fn(bh, bh->jsNumColumns, 0, NULL); napi_env env = bh->env; if (result == NULL) { @@ -75,11 +75,11 @@ static uiTableValueType c_columnType(uiTableModelHandler *mh, uiTableModel *m, i } static int c_numRows(uiTableModelHandler *mh, uiTableModel *m) { - return 0; + return 1; } static uiTableValue *c_cellValue(uiTableModelHandler *mh, uiTableModel *m, int row, int column) { - return NULL; + return uiNewTableValueInt(42); } static void c_setCellValue(uiTableModelHandler *mh, uiTableModel *m, int row, int column, @@ -134,7 +134,7 @@ LIBUI_FUNCTION(create) { status = napi_create_external(env, model, on_model_gc, model_handler, &model_external); CHECK_STATUS_THROW(status, napi_create_external); - status = napi_create_reference(env, model_external, 0, &model_handler->model_ref); + status = napi_create_reference(env, model_external, 1, &model_handler->model_ref); CHECK_STATUS_THROW(status, napi_create_reference); return model_external; diff --git a/src/table.c b/src/table.c new file mode 100644 index 0000000..d352206 --- /dev/null +++ b/src/table.c @@ -0,0 +1,25 @@ +#include +#include "napi_utils.h" +#include "control.h" +#include "events.h" + +static const char *MODULE = "Table"; + +LIBUI_FUNCTION(create) { + INIT_ARGS(1); + ARG_POINTER(uiTableModel, model, 0); + + uiTableParams params = {model, -1}; + printf("model: %p\n", params.Model); + uiControl *ctrl = uiControl(uiNewTable(¶ms)); + uiTableAppendProgressBarColumn(ctrl, "testtt", 0); + printf("ctrl: %p\n", ctrl); + return control_handle_new(env, ctrl, "table"); +} + + +napi_value _libui_init_table(napi_env env, napi_value exports) { + DEFINE_MODULE(); + LIBUI_EXPORT(create); + return module; +} From 960235f1eb69dcee1dc6fb1482807d9c95c4e6bf Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Wed, 12 Sep 2018 20:24:53 +0200 Subject: [PATCH 09/36] model handler methods --- example/tables.js | 14 +++++ js/table.js | 1 + src/table-model.c | 136 +++++++++++++++++++++++++++++++++++++++++----- src/table.c | 6 +- 4 files changed, 141 insertions(+), 16 deletions(-) diff --git a/example/tables.js b/example/tables.js index 520a2a0..9cc10c4 100644 --- a/example/tables.js +++ b/example/tables.js @@ -6,7 +6,21 @@ win.margined = true; const tb = new libui.UiTable({ numColumns() { return 2; + }, + columnType(column) { + if (column == 2) return 2; + if (column == 3) return 3; + return 0; + }, + numRows() { + return 5; + }, + cellValue(row, column) { + if (column >= 2) return 0; + const s = "val-" + row + '-' + column + return s; } + }); win.setChild(tb); diff --git a/js/table.js b/js/table.js index 7702ecb..3276fd8 100644 --- a/js/table.js +++ b/js/table.js @@ -28,6 +28,7 @@ class UiTable extends UiControl { */ constructor(model) { super(mkTable(model)); + this.model = model; } } diff --git a/src/table-model.c b/src/table-model.c index 67e0d46..bbb93c2 100644 --- a/src/table-model.c +++ b/src/table-model.c @@ -23,10 +23,6 @@ static napi_value run_handler_fn(struct binding_handler *bh, napi_ref fn_ref, in napi_env env = bh->env; - napi_handle_scope handle_scope; - status = napi_open_handle_scope(env, &handle_scope); - CHECK_STATUS_UNCAUGHT(status, napi_open_handle_scope, NULL); - napi_value resource_object; status = napi_create_object(env, &resource_object); CHECK_STATUS_UNCAUGHT(status, napi_create_object, NULL); @@ -40,13 +36,11 @@ static napi_value run_handler_fn(struct binding_handler *bh, napi_ref fn_ref, in napi_value last_exception; napi_get_and_clear_last_exception(env, &last_exception); napi_fatal_exception(env, last_exception); - return 0; + return NULL; } CHECK_STATUS_UNCAUGHT(status, napi_make_callback, NULL); - status = napi_close_handle_scope(env, handle_scope); - CHECK_STATUS_UNCAUGHT(status, napi_close_handle_scope, NULL); LIBUI_NODE_DEBUG("Method called"); @@ -56,30 +50,146 @@ static napi_value run_handler_fn(struct binding_handler *bh, napi_ref fn_ref, in static int c_numColumns(uiTableModelHandler *mh, uiTableModel *m) { struct binding_handler *bh = (struct binding_handler *)mh; - napi_value result = run_handler_fn(bh, bh->jsNumColumns, 0, NULL); napi_env env = bh->env; + napi_handle_scope handle_scope; + napi_status status = napi_open_handle_scope(env, &handle_scope); + CHECK_STATUS_UNCAUGHT(status, napi_open_handle_scope, 0); + + napi_value result = run_handler_fn(bh, bh->jsNumColumns, 0, NULL); + if (result == NULL) { + return 0; } int32_t int_result; - napi_status status = napi_get_value_int32(env, result, &int_result); - CHECK_STATUS_UNCAUGHT(status, napi_make_callback, 0); + status = napi_get_value_int32(env, result, &int_result); + CHECK_STATUS_UNCAUGHT(status, napi_get_value_int32, 0); + + status = napi_close_handle_scope(env, handle_scope); + CHECK_STATUS_UNCAUGHT(status, napi_close_handle_scope, 0); return int_result; } static uiTableValueType c_columnType(uiTableModelHandler *mh, uiTableModel *m, int column) { - return uiTableValueTypeInt; + struct binding_handler *bh = (struct binding_handler *)mh; + napi_env env = bh->env; + + napi_handle_scope handle_scope; + napi_status status = napi_open_handle_scope(env, &handle_scope); + CHECK_STATUS_UNCAUGHT(status, napi_open_handle_scope, 0); + + napi_value column_val; + status = napi_create_int32(bh->env, column, &column_val); + CHECK_STATUS_UNCAUGHT(status, napi_create_int32, 0); + + napi_value args[1] = {column_val}; + napi_value result = run_handler_fn(bh, bh->jsColumnType, 1, args); + + if (result == NULL) { + return 0; + } + + int32_t int_result; + status = napi_get_value_int32(env, result, &int_result); + CHECK_STATUS_UNCAUGHT(status, napi_get_value_int32, 0); + + status = napi_close_handle_scope(env, handle_scope); + CHECK_STATUS_UNCAUGHT(status, napi_close_handle_scope, 0); + + + return (uiTableValueType) int_result; } static int c_numRows(uiTableModelHandler *mh, uiTableModel *m) { - return 1; + struct binding_handler *bh = (struct binding_handler *)mh; + napi_env env = bh->env; + + napi_handle_scope handle_scope; + napi_status status = napi_open_handle_scope(env, &handle_scope); + CHECK_STATUS_UNCAUGHT(status, napi_open_handle_scope, 0); + + napi_value result = run_handler_fn(bh, bh->jsNumRows, 0, NULL); + + if (result == NULL) { + return 0; + } + + int32_t int_result; + status = napi_get_value_int32(env, result, &int_result); + CHECK_STATUS_UNCAUGHT(status, napi_get_value_int32, 0); + + status = napi_close_handle_scope(env, handle_scope); + CHECK_STATUS_UNCAUGHT(status, napi_close_handle_scope, 0); + + return int_result; } static uiTableValue *c_cellValue(uiTableModelHandler *mh, uiTableModel *m, int row, int column) { - return uiNewTableValueInt(42); + + struct binding_handler *bh = (struct binding_handler *)mh; + uiTableValueType type = c_columnType(mh, m, column); + + napi_env env = bh->env; + napi_handle_scope handle_scope; + napi_status status = napi_open_handle_scope(env, &handle_scope); + CHECK_STATUS_UNCAUGHT(status, napi_open_handle_scope, NULL); + + + napi_value column_val; + status = napi_create_int32(bh->env, column, &column_val); + CHECK_STATUS_UNCAUGHT(status, napi_create_int32, 0); + + napi_value row_val; + status = napi_create_int32(bh->env, row, &row_val); + CHECK_STATUS_UNCAUGHT(status, napi_create_int32, 0); + + napi_value args[2] = {row_val, column_val}; + + napi_value result = run_handler_fn(bh, bh->jsCellValue, 2, args); + + if (result == NULL) { + return 0; + } + uiTableValue* ret; + + switch (type) { + case uiTableValueTypeString: { + size_t string_len; + napi_status status = napi_get_value_string_utf8(env, result, NULL, 0, &string_len); + CHECK_STATUS_UNCAUGHT(status, napi_get_value_string_utf8, NULL); + char *string = malloc(string_len + 1); + status = napi_get_value_string_utf8(env, result, string, string_len + 1, &string_len); + CHECK_STATUS_UNCAUGHT(status, napi_get_value_string_utf8, NULL); + ret = uiNewTableValueString(string); + free(string); + break; + } + case uiTableValueTypeImage: { + ret = NULL; + break; + } + case uiTableValueTypeInt: { + int32_t int_result; + napi_status status = napi_get_value_int32(env, result, &int_result); + CHECK_STATUS_UNCAUGHT(status, napi_get_value_int32, 0); + ret = uiNewTableValueInt(int_result); + break; + } + case uiTableValueTypeColor: { + ret = NULL; + break; + } + default: { + ret = NULL; + } + } + + status = napi_close_handle_scope(env, handle_scope); + CHECK_STATUS_UNCAUGHT(status, napi_close_handle_scope, NULL); + return ret; } static void c_setCellValue(uiTableModelHandler *mh, uiTableModel *m, int row, int column, diff --git a/src/table.c b/src/table.c index d352206..127ca35 100644 --- a/src/table.c +++ b/src/table.c @@ -10,10 +10,10 @@ LIBUI_FUNCTION(create) { ARG_POINTER(uiTableModel, model, 0); uiTableParams params = {model, -1}; - printf("model: %p\n", params.Model); uiControl *ctrl = uiControl(uiNewTable(¶ms)); - uiTableAppendProgressBarColumn(ctrl, "testtt", 0); - printf("ctrl: %p\n", ctrl); + uiTableAppendTextColumn(uiTable(ctrl), "Nome", 0, 2, NULL); + uiTableAppendTextColumn(uiTable(ctrl), "Cognome", 1, 2, NULL); + return control_handle_new(env, ctrl, "table"); } From c8f5c7fa27de07b6e48e41874a0364e251eb9dd5 Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Fri, 14 Sep 2018 15:41:47 +0200 Subject: [PATCH 10/36] table method --- example/tables.js | 9 ++- src/table.c | 142 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 147 insertions(+), 4 deletions(-) diff --git a/example/tables.js b/example/tables.js index 9cc10c4..af04473 100644 --- a/example/tables.js +++ b/example/tables.js @@ -13,15 +13,20 @@ const tb = new libui.UiTable({ return 0; }, numRows() { - return 5; + return 50; }, cellValue(row, column) { - if (column >= 2) return 0; + if (column == 2 || column == 3) return 0; const s = "val-" + row + '-' + column return s; } }); + +libui.Table.appendTextColumn(tb.handle, "Nome", 0, 2, null); +libui.Table.appendTextColumn(tb.handle, "Cognome", 1, 2, null); +libui.Table.appendTextColumn(tb.handle, "Robe", 4, 2, null); + win.setChild(tb); win.onClosing(() => { diff --git a/src/table.c b/src/table.c index 127ca35..eb8445a 100644 --- a/src/table.c +++ b/src/table.c @@ -11,15 +11,153 @@ LIBUI_FUNCTION(create) { uiTableParams params = {model, -1}; uiControl *ctrl = uiControl(uiNewTable(¶ms)); - uiTableAppendTextColumn(uiTable(ctrl), "Nome", 0, 2, NULL); - uiTableAppendTextColumn(uiTable(ctrl), "Cognome", 1, 2, NULL); return control_handle_new(env, ctrl, "table"); } +LIBUI_FUNCTION(appendTextColumn) { + INIT_ARGS(5); + ARG_POINTER(struct control_handle, handle, 0); + ARG_STRING(name, 1); + ARG_INT32(textModelColumn, 2); + ARG_INT32(textEditableModelColumn, 3); + ENSURE_NOT_DESTROYED(); + + uiTableTextColumnOptionalParams textParams; + uiTableTextColumnOptionalParams *textParamsP = NULL; + + napi_valuetype arg_type; + napi_status status = napi_typeof(env, argv[4], &arg_type); + CHECK_STATUS_THROW(status, napi_typeof); + + if (arg_type == napi_number) { + ARG_INT32(colorModelColumn, 4); + textParams.ColorModelColumn = colorModelColumn; + textParamsP = &textParams; + } + + uiTableAppendTextColumn(uiTable(handle->control), name, textModelColumn, textEditableModelColumn, textParamsP); + free(name); + return NULL; +} + +LIBUI_FUNCTION(appendImageColumn) { + INIT_ARGS(3); + ARG_POINTER(struct control_handle, handle, 0); + ARG_STRING(name, 1); + ARG_INT32(imageModelColumn, 2); + ENSURE_NOT_DESTROYED(); + + uiTableAppendImageColumn(uiTable(handle->control), name, imageModelColumn); + free(name); + return NULL; +} + +LIBUI_FUNCTION(appendImageTextColumn) { + INIT_ARGS(6); + ARG_POINTER(struct control_handle, handle, 0); + ARG_STRING(name, 1); + ARG_INT32(imageModelColumn, 2); + ARG_INT32(textModelColumn, 3); + ARG_INT32(textEditableModelColumn, 4); + ARG_INT32(colorModelColumn, 5); + + ENSURE_NOT_DESTROYED(); + + uiTableTextColumnOptionalParams textParams = {colorModelColumn}; + + uiTableAppendImageTextColumn( + uiTable(handle->control), + name, + imageModelColumn, + textModelColumn, + textEditableModelColumn, + &textParams + ); + free(name); + return NULL; +} + +LIBUI_FUNCTION(appendCheckboxColumn) { + INIT_ARGS(4); + ARG_POINTER(struct control_handle, handle, 0); + ARG_STRING(name, 1); + ARG_INT32(checkboxModelColumn, 2); + ARG_INT32(checkboxEditableModelColumn, 3); + + ENSURE_NOT_DESTROYED(); + + uiTableAppendCheckboxColumn(uiTable(handle->control), name, checkboxModelColumn, checkboxEditableModelColumn); + free(name); + return NULL; +} + +LIBUI_FUNCTION(appendCheckboxTextColumn) { + INIT_ARGS(7); + ARG_POINTER(struct control_handle, handle, 0); + ARG_STRING(name, 1); + ARG_INT32(checkboxModelColumn, 2); + ARG_INT32(checkboxEditableModelColumn, 3); + ARG_INT32(textModelColumn, 4); + ARG_INT32(textEditableModelColumn, 5); + ARG_INT32(colorModelColumn, 6); + + ENSURE_NOT_DESTROYED(); + + uiTableTextColumnOptionalParams textParams = {colorModelColumn}; + + uiTableAppendCheckboxTextColumn( + uiTable(handle->control), + name, + checkboxModelColumn, + checkboxEditableModelColumn, + textModelColumn, + textEditableModelColumn, + &textParams + ); + free(name); + return NULL; +} + +LIBUI_FUNCTION(appendProgressBarColumn) { + INIT_ARGS(3); + ARG_POINTER(struct control_handle, handle, 0); + ARG_STRING(name, 1); + ARG_INT32(progressModelColumn, 2); + + ENSURE_NOT_DESTROYED(); + + uiTableAppendProgressBarColumn(uiTable(handle->control), name, progressModelColumn); + free(name); + return NULL; +} + +LIBUI_FUNCTION(appendButtonColumn) { + INIT_ARGS(4); + ARG_POINTER(struct control_handle, handle, 0); + ARG_STRING(name, 1); + ARG_INT32(buttonModelColumn, 2); + ARG_INT32(buttonClickableModelColumn, 3); + + ENSURE_NOT_DESTROYED(); + + uiTableAppendButtonColumn(uiTable(handle->control), name, buttonModelColumn, buttonClickableModelColumn); + free(name); + return NULL; + +} napi_value _libui_init_table(napi_env env, napi_value exports) { DEFINE_MODULE(); LIBUI_EXPORT(create); + + LIBUI_EXPORT(appendTextColumn); + LIBUI_EXPORT(appendImageColumn); + LIBUI_EXPORT(appendImageTextColumn); + LIBUI_EXPORT(appendCheckboxColumn); + LIBUI_EXPORT(appendCheckboxTextColumn); + LIBUI_EXPORT(appendProgressBarColumn); + LIBUI_EXPORT(appendButtonColumn); + return module; } From e08071a7143c12197edb6fe65ae6e45d5417474d Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Tue, 18 Sep 2018 20:10:32 +0200 Subject: [PATCH 11/36] add columns method in js table --- js/table.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/js/table.js b/js/table.js index 3276fd8..4877c2b 100644 --- a/js/table.js +++ b/js/table.js @@ -30,6 +30,34 @@ class UiTable extends UiControl { super(mkTable(model)); this.model = model; } + + appendTextColumn(name, textModelColumn, textEditableModelColumn) { + return Table.appendTextColumn(name, textModelColumn, textEditableModelColumn); + } + + appendImageColumn(name, imageModelColumn) { + return Table.appendImageColumn(name, imageModelColumn); + } + + appendImageTextColumn(name, imageModelColumn, textModelColumn, textEditableModelColumn, colorModelColumn) { + return Table.appendImageTextColumn(name, imageModelColumn, textModelColumn, textEditableModelColumn, colorModelColumn); + } + + appendCheckboxColumn(name, checkboxModelColumn, checkboxEditableModelColumn) { + return Table.appendCheckboxColumn(name, checkboxModelColumn, checkboxEditableModelColumn); + } + + appendCheckboxTextColumn(name, checkboxModelColumn, checkboxEditableModelColumn, textModelColumn, textEditableModelColumn, colorModelColumn) { + return Table.appendCheckboxTextColumn(name, checkboxModelColumn, checkboxEditableModelColumn, textModelColumn, textEditableModelColumn, colorModelColumn); + } + + appendProgressBarColumn(name, progressModelColumn) { + return Table.appendProgressBarColumn(name, progressModelColumn); + } + + appendButtonColumn(name, buttonModelColumn, buttonClickableModelColumn) { + return Table.appendButtonColumn(name, buttonModelColumn, buttonClickableModelColumn); + } } module.exports = {UiTable}; From 9f9a6a1bb3bd424a531ce2edbaeae48bffe1bb56 Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Tue, 18 Sep 2018 20:29:55 +0200 Subject: [PATCH 12/36] handle & option colorModelCOlumn --- example/tables.js | 6 +++--- js/table.js | 16 ++++++++-------- src/table.c | 29 +++++++++++++++++++++++++---- 3 files changed, 36 insertions(+), 15 deletions(-) diff --git a/example/tables.js b/example/tables.js index af04473..b6383bc 100644 --- a/example/tables.js +++ b/example/tables.js @@ -23,9 +23,9 @@ const tb = new libui.UiTable({ }); -libui.Table.appendTextColumn(tb.handle, "Nome", 0, 2, null); -libui.Table.appendTextColumn(tb.handle, "Cognome", 1, 2, null); -libui.Table.appendTextColumn(tb.handle, "Robe", 4, 2, null); +tb.appendTextColumn("Nome", 0, 2, null); +tb.appendTextColumn("Cognome", 1, 2, null); +tb.appendTextColumn("Robe", 4, 2, null); win.setChild(tb); diff --git a/js/table.js b/js/table.js index 4877c2b..8ef59ce 100644 --- a/js/table.js +++ b/js/table.js @@ -31,32 +31,32 @@ class UiTable extends UiControl { this.model = model; } - appendTextColumn(name, textModelColumn, textEditableModelColumn) { - return Table.appendTextColumn(name, textModelColumn, textEditableModelColumn); + appendTextColumn(name, textModelColumn, textEditableModelColumn, colorModelColumn) { + return Table.appendTextColumn(this.handle, name, textModelColumn, textEditableModelColumn, colorModelColumn); } appendImageColumn(name, imageModelColumn) { - return Table.appendImageColumn(name, imageModelColumn); + return Table.appendImageColumn(this.handle, name, imageModelColumn); } appendImageTextColumn(name, imageModelColumn, textModelColumn, textEditableModelColumn, colorModelColumn) { - return Table.appendImageTextColumn(name, imageModelColumn, textModelColumn, textEditableModelColumn, colorModelColumn); + return Table.appendImageTextColumn(this.handle, name, imageModelColumn, textModelColumn, textEditableModelColumn, colorModelColumn); } appendCheckboxColumn(name, checkboxModelColumn, checkboxEditableModelColumn) { - return Table.appendCheckboxColumn(name, checkboxModelColumn, checkboxEditableModelColumn); + return Table.appendCheckboxColumn(this.handle, name, checkboxModelColumn, checkboxEditableModelColumn); } appendCheckboxTextColumn(name, checkboxModelColumn, checkboxEditableModelColumn, textModelColumn, textEditableModelColumn, colorModelColumn) { - return Table.appendCheckboxTextColumn(name, checkboxModelColumn, checkboxEditableModelColumn, textModelColumn, textEditableModelColumn, colorModelColumn); + return Table.appendCheckboxTextColumn(this.handle, name, checkboxModelColumn, checkboxEditableModelColumn, textModelColumn, textEditableModelColumn, colorModelColumn); } appendProgressBarColumn(name, progressModelColumn) { - return Table.appendProgressBarColumn(name, progressModelColumn); + return Table.appendProgressBarColumn(this.handle, name, progressModelColumn); } appendButtonColumn(name, buttonModelColumn, buttonClickableModelColumn) { - return Table.appendButtonColumn(name, buttonModelColumn, buttonClickableModelColumn); + return Table.appendButtonColumn(this.handle, name, buttonModelColumn, buttonClickableModelColumn); } } diff --git a/src/table.c b/src/table.c index eb8445a..102960d 100644 --- a/src/table.c +++ b/src/table.c @@ -60,12 +60,22 @@ LIBUI_FUNCTION(appendImageTextColumn) { ARG_INT32(imageModelColumn, 2); ARG_INT32(textModelColumn, 3); ARG_INT32(textEditableModelColumn, 4); - ARG_INT32(colorModelColumn, 5); ENSURE_NOT_DESTROYED(); - uiTableTextColumnOptionalParams textParams = {colorModelColumn}; + + uiTableTextColumnOptionalParams textParams; + uiTableTextColumnOptionalParams *textParamsP = NULL; + + napi_valuetype arg_type; + napi_status status = napi_typeof(env, argv[5], &arg_type); + CHECK_STATUS_THROW(status, napi_typeof); + if (arg_type == napi_number) { + ARG_INT32(colorModelColumn, 5); + textParams.ColorModelColumn = colorModelColumn; + textParamsP = &textParams; + } uiTableAppendImageTextColumn( uiTable(handle->control), name, @@ -100,12 +110,23 @@ LIBUI_FUNCTION(appendCheckboxTextColumn) { ARG_INT32(checkboxEditableModelColumn, 3); ARG_INT32(textModelColumn, 4); ARG_INT32(textEditableModelColumn, 5); - ARG_INT32(colorModelColumn, 6); ENSURE_NOT_DESTROYED(); - uiTableTextColumnOptionalParams textParams = {colorModelColumn}; + + uiTableTextColumnOptionalParams textParams; + uiTableTextColumnOptionalParams *textParamsP = NULL; + + napi_valuetype arg_type; + napi_status status = napi_typeof(env, argv[6], &arg_type); + CHECK_STATUS_THROW(status, napi_typeof); + if (arg_type == napi_number) { + ARG_INT32(colorModelColumn, 6); + textParams.ColorModelColumn = colorModelColumn; + textParamsP = &textParams; + } + uiTableAppendCheckboxTextColumn( uiTable(handle->control), name, From 3d5280cced701972cc6931a27f13a0dcd5cbdc32 Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Tue, 18 Sep 2018 21:58:57 +0200 Subject: [PATCH 13/36] table model js --- example/tables.js | 8 +++---- index.js | 4 +++- js/table-model.js | 32 ++++++++++++++++++++++++++++ js/table.js | 18 ++-------------- src/table-model.c | 53 +++++++++++++++++++---------------------------- 5 files changed, 62 insertions(+), 53 deletions(-) create mode 100644 js/table-model.js diff --git a/example/tables.js b/example/tables.js index b6383bc..b66f2e0 100644 --- a/example/tables.js +++ b/example/tables.js @@ -2,8 +2,7 @@ const libui = require('..'); const win = new libui.UiWindow('Tables example', 320, 60, true); win.margined = true; - -const tb = new libui.UiTable({ +const tb = new libui.UiTable(new libui.UiTableModel({ numColumns() { return 2; }, @@ -19,9 +18,10 @@ const tb = new libui.UiTable({ if (column == 2 || column == 3) return 0; const s = "val-" + row + '-' + column return s; + }, + setCellValue(row, column, value) { } - -}); +})); tb.appendTextColumn("Nome", 0, 2, null); tb.appendTextColumn("Cognome", 1, 2, null); diff --git a/index.js b/index.js index dba0641..008a451 100644 --- a/index.js +++ b/index.js @@ -81,6 +81,7 @@ const {FontDescriptor} = require('./js/font-descriptor'); const {FontAttribute} = require('./js/font-attribute'); const {AttributedString} = require('./js/font-string'); const {OpenTypeFeatures} = require('./js/font-opentype'); +const {UiTableModel} = require('./js/table-model'); function applySetterGetter(...classConstructors) { for (const classConstructor of classConstructors) { @@ -146,7 +147,7 @@ function applySetterGetterAll(doSetter, ...classConstructors) { } // Takes about 3.5ms: -applySetterGetter(UiTable, UiEntryBase, UiBox, SeparatorBase, UiControl, UiGrid, UiMenuItem, +applySetterGetter(UiTableModel, UiTable, UiEntryBase, UiBox, SeparatorBase, UiControl, UiGrid, UiMenuItem, UiMenu, UiSpinbox, UiHorizontalSeparator, UiVerticalSeparator, UiRadioButtons, UiProgressBar, UiGroup, UiEntry, UiPasswordEntry, UiSearchEntry, UiEditableCombobox, UiTimePicker, UiDatePicker, @@ -159,6 +160,7 @@ applySetterGetterAll(true, Point, Color, Size); applySetterGetterAll(false, AreaDrawParams, UiAreaMouseEvent, UiAreaKeyEvent); Object.assign(libui, { + UiTableModel, UiTable, UiFontButton, FontDescriptor, diff --git a/js/table-model.js b/js/table-model.js new file mode 100644 index 0000000..214ff26 --- /dev/null +++ b/js/table-model.js @@ -0,0 +1,32 @@ +const {TableModel} = require('..'); + +class UiTableModel { + /** + * Create a new UiTableModel object. + * @param {object} modelHanlder - handler for the new table model + * @return {UiTable} + */ + constructor(modelHanlder) { + this.model = TableModel.create( + modelHanlder.numColumns, + modelHanlder.numRows, + modelHanlder.columnType, + modelHanlder.cellValue, + modelHanlder.setCellValue + ); + } + + rowInserted(index) { + return TableModel.rowInserted(this.model, index); + } + + rowChanged(index) { + return TableModel.rowChanged(this.model, index); + } + + rowDeleted(index) { + return TableModel.rowDeleted(this.model, index); + } +} + +module.exports = {UiTableModel}; diff --git a/js/table.js b/js/table.js index 8ef59ce..7614579 100644 --- a/js/table.js +++ b/js/table.js @@ -2,20 +2,6 @@ const {Table} = require('..'); const {TableModel} = require('..'); const {UiControl} = require('./ui-control'); -const noop = () => 0; - -function mkTable(model) { - const tableModel = TableModel.create( - model.numColumns || noop, - model.numRows || noop, - model.columnType || noop, - model.cellValue || noop, - model.setCellValue || noop - ); - - return Table.create(tableModel) -} - /** * A data table. * @extends UiControl @@ -27,8 +13,8 @@ class UiTable extends UiControl { * @return {UiTable} */ constructor(model) { - super(mkTable(model)); - this.model = model; + super(Table.create(model.model)); + this.model = model.model; } appendTextColumn(name, textModelColumn, textEditableModelColumn, colorModelColumn) { diff --git a/src/table-model.c b/src/table-model.c index bbb93c2..ecbb2dc 100644 --- a/src/table-model.c +++ b/src/table-model.c @@ -249,51 +249,40 @@ LIBUI_FUNCTION(create) { return model_external; } -/* -LIBUI_FUNCTION(onClicked) { - INIT_ARGS(2); - - ARG_POINTER(struct control_handle, handle, 0); - ENSURE_NOT_DESTROYED(); - ARG_CB_REF(cb_ref, 1); - - struct event_t *event = create_event(env, cb_ref, "onClicked"); - if (event == NULL) { - return NULL; - } - - install_event(handle->events, event); - - uiButtonOnClicked(uiButton(handle->control), CALLBACK_OF(uiButton, control_event_cb), event); +LIBUI_FUNCTION(rowInserted) { + INIT_ARGS(2); + ARG_POINTER(uiTableModel, handle, 0); + ARG_INT32(index, 1); + uiTableModelRowInserted(handle, index); return NULL; } -LIBUI_FUNCTION(setText) { - INIT_ARGS(2); - ARG_POINTER(struct control_handle, handle, 0); - ENSURE_NOT_DESTROYED(); - ARG_STRING(value, 1); - uiButtonSetText(uiButton(handle->control), value); - free(value); +LIBUI_FUNCTION(rowChanged) { + INIT_ARGS(2); + ARG_POINTER(uiTableModel, handle, 0); + ARG_INT32(index, 1); + uiTableModelRowChanged(handle, index); return NULL; } -LIBUI_FUNCTION(getText) { - INIT_ARGS(1); - ARG_POINTER(struct control_handle, handle, 0); - ENSURE_NOT_DESTROYED(); - char *char_ptr = uiButtonText(uiButton(handle->control)); - napi_value result = make_utf8_string(env, char_ptr); - uiFreeText(char_ptr); - return result; +LIBUI_FUNCTION(rowDeleted) { + INIT_ARGS(2); + ARG_POINTER(uiTableModel, handle, 0); + ARG_INT32(index, 1); + uiTableModelRowDeleted(handle, index); + return NULL; } -*/ + napi_value _libui_init_table_model(napi_env env, napi_value exports) { DEFINE_MODULE(); LIBUI_EXPORT(create); + LIBUI_EXPORT(rowInserted); + LIBUI_EXPORT(rowChanged); + LIBUI_EXPORT(rowDeleted); + return module; } From ca1b7b29e41f30199008091747f0092f86b30d85 Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Tue, 18 Sep 2018 22:00:11 +0200 Subject: [PATCH 14/36] tweaks --- js/table.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/table.js b/js/table.js index 7614579..d22917e 100644 --- a/js/table.js +++ b/js/table.js @@ -14,7 +14,7 @@ class UiTable extends UiControl { */ constructor(model) { super(Table.create(model.model)); - this.model = model.model; + this.model = model; } appendTextColumn(name, textModelColumn, textEditableModelColumn, colorModelColumn) { From 7c52cdf2b320da57e832e877ecb04b51dcf151d4 Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Wed, 19 Sep 2018 21:12:08 +0200 Subject: [PATCH 15/36] setCellValue --- example/tables.js | 58 ++++++++++++++++++++++++++++++++++++++--------- package-lock.json | 34 +++++++++++---------------- package.json | 1 + src/table-model.c | 56 +++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 115 insertions(+), 34 deletions(-) diff --git a/example/tables.js b/example/tables.js index b66f2e0..6cba8ca 100644 --- a/example/tables.js +++ b/example/tables.js @@ -1,31 +1,67 @@ const libui = require('..'); +const wd = require("@raydeck/walk-dependencies"); -const win = new libui.UiWindow('Tables example', 320, 60, true); +const dependencies = []; +const addTo = (path, {name, version, author}) => { + dependencies.push({name, version, author: author.name || author}); +}; +wd(process.cwd(), false, addTo); + +// console.log(JSON.stringify(dependencies, null, 4)); + +const win = new libui.UiWindow('Tables example', 800, 600, true); win.margined = true; const tb = new libui.UiTable(new libui.UiTableModel({ numColumns() { - return 2; + return 3; }, columnType(column) { - if (column == 2) return 2; - if (column == 3) return 3; + if (column == 3 || column == 4) return 2; return 0; }, numRows() { - return 50; + return dependencies.length; }, cellValue(row, column) { - if (column == 2 || column == 3) return 0; - const s = "val-" + row + '-' + column - return s; + switch (column) { + case 0: { + return dependencies[row].name; + } + case 1: { + return dependencies[row].version; + } + case 2: { + return dependencies[row].author; + } + case 3: { + return 0; + } + case 4: { + return 1; + } + } }, setCellValue(row, column, value) { + switch (column) { + case 0: { + dependencies[row].name = value; + break; + } + case 1: { + dependencies[row].version = value; + break; + } + case 2: { + dependencies[row].author = value; + break; + } + } } })); -tb.appendTextColumn("Nome", 0, 2, null); -tb.appendTextColumn("Cognome", 1, 2, null); -tb.appendTextColumn("Robe", 4, 2, null); +tb.appendTextColumn("name", 0, 3, null); +tb.appendTextColumn("version", 1, 3, null); +tb.appendTextColumn("author", 2, 4, null); win.setChild(tb); diff --git a/package-lock.json b/package-lock.json index 16764ee..180f314 100644 --- a/package-lock.json +++ b/package-lock.json @@ -131,6 +131,12 @@ } } }, + "@raydeck/walk-dependencies": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@raydeck/walk-dependencies/-/walk-dependencies-1.6.1.tgz", + "integrity": "sha512-Ktwf9yOh5bzAKb4RHUkB64h3zrJTCjInHVHUWZ2qgIgFzn8OwYsI8mTDuolS3b66QlOyobKi0CxxErvHW2JxXA==", + "dev": true + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -2583,14 +2589,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2605,20 +2609,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -2735,8 +2736,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -2748,7 +2748,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -2763,7 +2762,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -2771,14 +2769,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.2.4", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -2797,7 +2793,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -2878,8 +2873,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -2891,7 +2885,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -3013,7 +3006,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", diff --git a/package.json b/package.json index a5e618c..e8613b9 100755 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "tar": "^4.4.1" }, "devDependencies": { + "@raydeck/walk-dependencies": "^1.6.1", "ava": "^0.25.0", "boxen": "^1.3.0", "clang-format": "^1.2.3", diff --git a/src/table-model.c b/src/table-model.c index ecbb2dc..85f3cf9 100644 --- a/src/table-model.c +++ b/src/table-model.c @@ -128,7 +128,6 @@ static int c_numRows(uiTableModelHandler *mh, uiTableModel *m) { } static uiTableValue *c_cellValue(uiTableModelHandler *mh, uiTableModel *m, int row, int column) { - struct binding_handler *bh = (struct binding_handler *)mh; uiTableValueType type = c_columnType(mh, m, column); @@ -193,7 +192,60 @@ static uiTableValue *c_cellValue(uiTableModelHandler *mh, uiTableModel *m, int r } static void c_setCellValue(uiTableModelHandler *mh, uiTableModel *m, int row, int column, - const uiTableValue *value) {} + const uiTableValue *value) { + struct binding_handler *bh = (struct binding_handler *)mh; + uiTableValueType type = uiTableValueGetType(value); + + napi_env env = bh->env; + napi_handle_scope handle_scope; + napi_status status = napi_open_handle_scope(env, &handle_scope); + CHECK_STATUS_UNCAUGHT(status, napi_open_handle_scope, NULL); + + napi_value column_val; + status = napi_create_int32(bh->env, column, &column_val); + CHECK_STATUS_UNCAUGHT(status, napi_create_int32, 0); + + napi_value row_val; + status = napi_create_int32(bh->env, row, &row_val); + CHECK_STATUS_UNCAUGHT(status, napi_create_int32, 0); + + + napi_value ret; + + switch (type) { + case uiTableValueTypeString: { + + const char* cell_value = uiTableValueString(value); + + ret = make_utf8_string(env, cell_value); + //free(cell_value); + break; + } + case uiTableValueTypeImage: { + ret = make_uint32(env, 0); + break; + } + case uiTableValueTypeInt: { + int32_t int_result = uiTableValueInt(value); + ret = make_int32(env, int_result); + break; + } + case uiTableValueTypeColor: { + ret = make_uint32(env, 0); + break; + } + default: { + ret = make_uint32(env, 0); + } + } + + napi_value args[3] = {row_val, column_val, ret}; + + napi_value result = run_handler_fn(bh, bh->jsSetCellValue, 3, args); + status = napi_close_handle_scope(env, handle_scope); + CHECK_STATUS_UNCAUGHT(status, napi_close_handle_scope, NULL); + +} static void on_model_gc(napi_env env, void *finalize_data, void *finalize_hint) { uiTableModel *model = (uiTableModel *)finalize_data; From b869741056a6e5b2fa153d6f063e55d8c5f1217f Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Sat, 22 Sep 2018 18:28:09 +0200 Subject: [PATCH 16/36] tweaks --- src/table-model.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/table-model.c b/src/table-model.c index 3ec2b96..c18a688 100644 --- a/src/table-model.c +++ b/src/table-model.c @@ -31,7 +31,7 @@ static napi_value run_handler_fn(struct binding_handler *bh, int argc, napi_valu status = napi_create_object(env, &resource_object); CHECK_STATUS_UNCAUGHT(status, napi_create_object, NULL); - LIBUI_NODE_DEBUG("Calling numColumns method"); + LIBUI_NODE_DEBUG("Calling model handler method"); napi_value result; status = napi_make_callback(env, bh->context, resource_object, fn, argc, argv, &result); @@ -57,12 +57,13 @@ static int c_numColumns(uiTableModelHandler *mh, uiTableModel *m) { struct binding_handler *bh = (struct binding_handler *)mh; napi_value result = run_handler_fn(bh, 0, NULL); - napi_env env = bh->env; if (result == NULL) { return 0; } + napi_env env = bh->env; + int32_t int_result; napi_status status = napi_get_value_int32(env, result, &int_result); CHECK_STATUS_UNCAUGHT(status, napi_make_callback, 0); From 91cf6d4e31f72c8878fa1018b5916922548f7565 Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Sat, 22 Sep 2018 18:44:53 +0200 Subject: [PATCH 17/36] Fixed some warnings --- src/table-model.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/table-model.c b/src/table-model.c index b9bd201..188c8de 100644 --- a/src/table-model.c +++ b/src/table-model.c @@ -50,7 +50,6 @@ static napi_value run_handler_fn(struct binding_handler *bh, napi_ref fn_ref, in static int c_numColumns(uiTableModelHandler *mh, uiTableModel *m) { struct binding_handler *bh = (struct binding_handler *)mh; - napi_value result = run_handler_fn(bh, 0, NULL); napi_env env = bh->env; napi_handle_scope handle_scope; @@ -196,15 +195,15 @@ static void c_setCellValue(uiTableModelHandler *mh, uiTableModel *m, int row, in napi_env env = bh->env; napi_handle_scope handle_scope; napi_status status = napi_open_handle_scope(env, &handle_scope); - CHECK_STATUS_UNCAUGHT(status, napi_open_handle_scope, NULL); + CHECK_STATUS_UNCAUGHT(status, napi_open_handle_scope, ); napi_value column_val; status = napi_create_int32(bh->env, column, &column_val); - CHECK_STATUS_UNCAUGHT(status, napi_create_int32, 0); + CHECK_STATUS_UNCAUGHT(status, napi_create_int32, ); napi_value row_val; status = napi_create_int32(bh->env, row, &row_val); - CHECK_STATUS_UNCAUGHT(status, napi_create_int32, 0); + CHECK_STATUS_UNCAUGHT(status, napi_create_int32, ); napi_value ret; @@ -235,9 +234,9 @@ static void c_setCellValue(uiTableModelHandler *mh, uiTableModel *m, int row, in napi_value args[3] = {row_val, column_val, ret}; - napi_value result = run_handler_fn(bh, bh->jsSetCellValue, 3, args); + run_handler_fn(bh, bh->jsSetCellValue, 3, args); status = napi_close_handle_scope(env, handle_scope); - CHECK_STATUS_UNCAUGHT(status, napi_close_handle_scope, NULL); + CHECK_STATUS_UNCAUGHT(status, napi_close_handle_scope, ); } static void on_model_gc(napi_env env, void *finalize_data, void *finalize_hint) { From df07f4d01d775a5132099889437197e26d26f5bb Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Sat, 22 Sep 2018 20:05:44 +0200 Subject: [PATCH 18/36] button column --- example/tables.js | 20 +++++++++- package-lock.json | 99 +++++++++++++++++++++++++++++++++++++++++++---- src/table-model.c | 14 ++++++- src/table.c | 5 ++- 4 files changed, 126 insertions(+), 12 deletions(-) diff --git a/example/tables.js b/example/tables.js index cc837c1..2485cf5 100644 --- a/example/tables.js +++ b/example/tables.js @@ -11,12 +11,13 @@ wd(process.cwd(), false, addTo); const win = new libui.UiWindow('Tables example', 800, 600, true); win.margined = true; + const tb = new libui.UiTable(new libui.UiTableModel({ numColumns() { return 3; }, columnType(column) { - if (column == 3 || column == 4) + if (column == 3 || column == 4 || column == 6) return 2; return 0; }, @@ -40,9 +41,16 @@ const tb = new libui.UiTable(new libui.UiTableModel({ case 4: { return 1; } + case 5: { + return 'show details'; + } + case 6: { + return 1; + } } }, setCellValue(row, column, value) { + console.log(row, column, value) switch (column) { case 0: { dependencies[row].name = value; @@ -56,6 +64,11 @@ const tb = new libui.UiTable(new libui.UiTableModel({ dependencies[row].author = value; break; } + case 5: { + libui.UiDialogs.msgBox(win, 'Row details', + JSON.stringify(dependencies[row], null, 4)); + break; + } } } })); @@ -63,8 +76,11 @@ const tb = new libui.UiTable(new libui.UiTableModel({ tb.appendTextColumn('name', 0, 3, null); tb.appendTextColumn('version', 1, 3, null); tb.appendTextColumn('author', 2, 4, null); +tb.appendButtonColumn('details', 5, 6); -win.setChild(tb); +const vbox = new libui.UiVerticalBox(); +vbox.append(tb, true); +win.setChild(vbox); win.onClosing(() => { win.close(); diff --git a/package-lock.json b/package-lock.json index 180f314..7024b98 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1912,6 +1912,18 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, "concordance": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/concordance/-/concordance-3.0.0.tgz", @@ -2373,6 +2385,35 @@ "is-extglob": "^1.0.0" } }, + "extract-zip": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz", + "integrity": "sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=", + "dev": true, + "requires": { + "concat-stream": "1.6.2", + "debug": "2.6.9", + "mkdirp": "0.5.1", + "yauzl": "2.4.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -2394,6 +2435,15 @@ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, + "fd-slicer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", + "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", + "dev": true, + "requires": { + "pend": "~1.2.0" + } + }, "figures": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", @@ -2589,12 +2639,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2609,17 +2661,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -2736,7 +2791,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -2748,6 +2804,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -2762,6 +2819,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -2769,12 +2827,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.2.4", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -2793,6 +2853,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -2873,7 +2934,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -2885,6 +2947,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -3006,6 +3069,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -5028,6 +5092,12 @@ "pify": "^2.0.0" } }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -6869,6 +6939,12 @@ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "optional": true }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, "typical": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/typical/-/typical-2.6.1.tgz", @@ -7203,6 +7279,15 @@ "optional": true } } + }, + "yauzl": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", + "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", + "dev": true, + "requires": { + "fd-slicer": "~1.0.1" + } } } } diff --git a/src/table-model.c b/src/table-model.c index 188c8de..ee2dd5d 100644 --- a/src/table-model.c +++ b/src/table-model.c @@ -187,10 +187,17 @@ static uiTableValue *c_cellValue(uiTableModelHandler *mh, uiTableModel *m, int r return ret; } +#define HACK_uiTableValueTypeNull 424242 + static void c_setCellValue(uiTableModelHandler *mh, uiTableModel *m, int row, int column, const uiTableValue *value) { struct binding_handler *bh = (struct binding_handler *)mh; - uiTableValueType type = uiTableValueGetType(value); + uiTableValueType type; + if (value == NULL) { + type = HACK_uiTableValueTypeNull; + } else { + type = uiTableValueGetType(value); + } napi_env env = bh->env; napi_handle_scope handle_scope; @@ -208,6 +215,11 @@ static void c_setCellValue(uiTableModelHandler *mh, uiTableModel *m, int row, in napi_value ret; switch (type) { + case HACK_uiTableValueTypeNull: { + napi_status status = napi_get_null(env, &ret); + CHECK_STATUS_UNCAUGHT(status, napi_get_null, ); + break; + } case uiTableValueTypeString: { const char *cell_value = uiTableValueString(value); diff --git a/src/table.c b/src/table.c index cff631c..cb165e1 100644 --- a/src/table.c +++ b/src/table.c @@ -77,7 +77,7 @@ LIBUI_FUNCTION(appendImageTextColumn) { textParamsP = &textParams; } uiTableAppendImageTextColumn(uiTable(handle->control), name, imageModelColumn, textModelColumn, - textEditableModelColumn, &textParams); + textEditableModelColumn, textParamsP); free(name); return NULL; } @@ -123,7 +123,7 @@ LIBUI_FUNCTION(appendCheckboxTextColumn) { uiTableAppendCheckboxTextColumn(uiTable(handle->control), name, checkboxModelColumn, checkboxEditableModelColumn, textModelColumn, - textEditableModelColumn, &textParams); + textEditableModelColumn, textParamsP); free(name); return NULL; } @@ -150,6 +150,7 @@ LIBUI_FUNCTION(appendButtonColumn) { ENSURE_NOT_DESTROYED(); + printf("appendButtonColumn %s: %d %d", name, buttonModelColumn, buttonClickableModelColumn); uiTableAppendButtonColumn(uiTable(handle->control), name, buttonModelColumn, buttonClickableModelColumn); free(name); From 5ffce086293647eb88b507bd75f93d19e2940a03 Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Sat, 22 Sep 2018 20:15:54 +0200 Subject: [PATCH 19/36] checkbox column --- example/tables.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/example/tables.js b/example/tables.js index 2485cf5..ce1eb99 100644 --- a/example/tables.js +++ b/example/tables.js @@ -17,7 +17,7 @@ const tb = new libui.UiTable(new libui.UiTableModel({ return 3; }, columnType(column) { - if (column == 3 || column == 4 || column == 6) + if (column == 3 || column == 4 || column == 41 || column == 6) return 2; return 0; }, @@ -25,6 +25,7 @@ const tb = new libui.UiTable(new libui.UiTableModel({ return dependencies.length; }, cellValue(row, column) { + console.log('cellValue', (row, column)) switch (column) { case 0: { return dependencies[row].name; @@ -39,6 +40,9 @@ const tb = new libui.UiTable(new libui.UiTableModel({ return 0; } case 4: { + return Number(!dependencies[row].version.startsWith('0')); + } + case 41: { return 1; } case 5: { @@ -64,6 +68,14 @@ const tb = new libui.UiTable(new libui.UiTableModel({ dependencies[row].author = value; break; } + case 4: { + if (value) { + dependencies[row].version = '1' + dependencies[row].version.slice(1); + } else { + dependencies[row].version = '0' + dependencies[row].version.slice(1); + } + break; + } case 5: { libui.UiDialogs.msgBox(win, 'Row details', JSON.stringify(dependencies[row], null, 4)); @@ -75,7 +87,9 @@ const tb = new libui.UiTable(new libui.UiTableModel({ tb.appendTextColumn('name', 0, 3, null); tb.appendTextColumn('version', 1, 3, null); -tb.appendTextColumn('author', 2, 4, null); +tb.appendTextColumn('author', 2, 41, null); +tb.appendCheckboxColumn('semver', 4, 41); +tb.appendCheckboxTextColumn('version+semver', 4, 41, 1, 3, null); tb.appendButtonColumn('details', 5, 6); const vbox = new libui.UiVerticalBox(); From 1b67455022c2bc6781f309592659c180c23b4847 Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Sat, 22 Sep 2018 20:29:23 +0200 Subject: [PATCH 20/36] progressbar column --- example/tables.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/example/tables.js b/example/tables.js index ce1eb99..6a5d65c 100644 --- a/example/tables.js +++ b/example/tables.js @@ -17,7 +17,7 @@ const tb = new libui.UiTable(new libui.UiTableModel({ return 3; }, columnType(column) { - if (column == 3 || column == 4 || column == 41 || column == 6) + if (column == 3 || column == 4 || column == 41 || column == 6 || column == 50) return 2; return 0; }, @@ -48,6 +48,10 @@ const tb = new libui.UiTable(new libui.UiTableModel({ case 5: { return 'show details'; } + case 50: { + return dependencies[row].version.split('.').map(Number).reduce((a, b) => + a + b); + } case 6: { return 1; } @@ -91,6 +95,7 @@ tb.appendTextColumn('author', 2, 41, null); tb.appendCheckboxColumn('semver', 4, 41); tb.appendCheckboxTextColumn('version+semver', 4, 41, 1, 3, null); tb.appendButtonColumn('details', 5, 6); +tb.appendProgressBarColumn('sum version', 50, 6); const vbox = new libui.UiVerticalBox(); vbox.append(tb, true); From 555ec4880ca571e6dd3ae0bf88461bf163b1daad Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Tue, 25 Sep 2018 17:02:47 +0200 Subject: [PATCH 21/36] UiTableModel.ValueTypes enumeration --- example/tables.js | 8 ++++++-- js/table-model.js | 7 +++++++ package-lock.json | 28 +++++++--------------------- 3 files changed, 20 insertions(+), 23 deletions(-) diff --git a/example/tables.js b/example/tables.js index ce1eb99..db3c9f6 100644 --- a/example/tables.js +++ b/example/tables.js @@ -11,6 +11,10 @@ wd(process.cwd(), false, addTo); const win = new libui.UiWindow('Tables example', 800, 600, true); win.margined = true; +const {ValueTypes} = libui.UiTableModel; + +console.log(ValueTypes.String) +console.log(ValueTypes.Int) const tb = new libui.UiTable(new libui.UiTableModel({ numColumns() { @@ -18,8 +22,8 @@ const tb = new libui.UiTable(new libui.UiTableModel({ }, columnType(column) { if (column == 3 || column == 4 || column == 41 || column == 6) - return 2; - return 0; + return ValueTypes.Int; + return ValueTypes.String; }, numRows() { return dependencies.length; diff --git a/js/table-model.js b/js/table-model.js index 4a392f1..db4fcb5 100644 --- a/js/table-model.js +++ b/js/table-model.js @@ -25,4 +25,11 @@ class UiTableModel { } } +UiTableModel.ValueTypes = { + String: 0, + Image: 1, + Int: 2, + Color: 3 +}; + module.exports = {UiTableModel}; diff --git a/package-lock.json b/package-lock.json index 7024b98..b545ea1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2639,14 +2639,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2661,20 +2659,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -2791,8 +2786,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -2804,7 +2798,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -2819,7 +2812,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -2827,14 +2819,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.2.4", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -2853,7 +2843,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -2934,8 +2923,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -2947,7 +2935,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -3069,7 +3056,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", From 3bcab20f0531f50909d27940ecc6d59b9c38c25b Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Tue, 25 Sep 2018 20:58:05 +0200 Subject: [PATCH 22/36] images [WIP] --- example/lightning-orb.png | Bin 0 -> 24555 bytes example/tables.js | 9 +++++++ index.js | 5 +++- js/image.js | 21 +++++++++++++++++ package-lock.json | 15 ++++++++++++ package.json | 3 ++- src/image.c | 48 ++++++++++++++++++++++++++++++++++++++ src/includes/modules.h | 3 ++- src/includes/napi_utils.h | 16 +++++++++++++ src/module.c | 1 + src/table-model.c | 12 +++++++--- 11 files changed, 127 insertions(+), 6 deletions(-) create mode 100644 example/lightning-orb.png create mode 100644 js/image.js create mode 100644 src/image.c diff --git a/example/lightning-orb.png b/example/lightning-orb.png new file mode 100644 index 0000000000000000000000000000000000000000..a6b2017b09457ceed9395738842704c2e86e4036 GIT binary patch literal 24555 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 +#include "napi_utils.h" +#include "control.h" +#include "events.h" + +static const char *MODULE = "Image"; + +static void on_img_gc(napi_env env, void *finalize_data, void *finalize_hint) { + uiImage *img = (uiImage *) finalize_data; + /* TODO: uiFreeImage when? */ +} + +LIBUI_FUNCTION(create) { + INIT_ARGS(2); + + ARG_DOUBLE(width, 0); + ARG_DOUBLE(height, 1); + + uiImage *img = uiNewImage(width, height); + napi_value img_external; + + napi_status status = napi_create_external(env, img, on_img_gc, NULL, &img_external); + CHECK_STATUS_THROW(status, napi_create_external); + + return img_external; +} + +LIBUI_FUNCTION(append) { + INIT_ARGS(5); + + ARG_POINTER(uiImage, image, 0); + ARG_BUFFER(pixels, 1); + ARG_INT32(pixelWidth, 2); + ARG_INT32(pixelHeight, 3); + ARG_INT32(byteStride, 4); + printf("%d x %d : %d (len = %d)\n", pixelWidth, pixelHeight, byteStride, pixels__len); + uiImageAppend(image, pixels__ptr, pixelWidth, pixelHeight, byteStride); + return NULL; +} + + +napi_value _libui_init_image(napi_env env, napi_value exports) { + DEFINE_MODULE(); + LIBUI_EXPORT(create); + LIBUI_EXPORT(append); + + return module; +} diff --git a/src/includes/modules.h b/src/includes/modules.h index ab4ccef..df88362 100644 --- a/src/includes/modules.h +++ b/src/includes/modules.h @@ -40,4 +40,5 @@ napi_value _libui_init_area_stroke(napi_env env, napi_value exports); napi_value _libui_init_area_matrix(napi_env env, napi_value exports); napi_value _libui_init_dialogs(napi_env env, napi_value exports); napi_value _libui_init_table_model(napi_env env, napi_value exports); -napi_value _libui_init_table(napi_env env, napi_value exports); \ No newline at end of file +napi_value _libui_init_table(napi_env env, napi_value exports); +napi_value _libui_init_image(napi_env env, napi_value exports); diff --git a/src/includes/napi_utils.h b/src/includes/napi_utils.h index d3a1e35..d734f1b 100644 --- a/src/includes/napi_utils.h +++ b/src/includes/napi_utils.h @@ -59,6 +59,22 @@ } \ } +#define ARG_BUFFER(ARG_NAME, ARG_IDX) \ + void *ARG_NAME ## __ptr; \ + size_t ARG_NAME ## __len; \ + { \ + napi_status status = napi_get_buffer_info(env, argv[ARG_IDX], \ + &ARG_NAME ## __ptr, &ARG_NAME ## __len); \ + if (status != napi_ok) { \ + const napi_extended_error_info *result; \ + napi_get_last_error_info(env, &result); \ + char err[1024]; \ + snprintf(err, 1024, "Argument " #ARG_NAME ": %s", result->error_message); \ + napi_throw_type_error(env, NULL, err); \ + return NULL; \ + } \ + } + #define ARG_DOUBLE(ARG_NAME, ARG_IDX) \ double ARG_NAME; \ { \ diff --git a/src/module.c b/src/module.c index dd48d11..c8a7161 100644 --- a/src/module.c +++ b/src/module.c @@ -41,6 +41,7 @@ static napi_value init_all(napi_env env, napi_value exports) { _libui_init_dialogs(env, exports); _libui_init_table_model(env, exports); _libui_init_table(env, exports); + _libui_init_image(env, exports); _libui_init_tests(env, exports); diff --git a/src/table-model.c b/src/table-model.c index ee2dd5d..d2244f6 100644 --- a/src/table-model.c +++ b/src/table-model.c @@ -165,13 +165,20 @@ static uiTableValue *c_cellValue(uiTableModelHandler *mh, uiTableModel *m, int r break; } case uiTableValueTypeImage: { - ret = NULL; + napi_value image_ext; + napi_status status = napi_get_named_property(env, result, "_img", &image_ext); + CHECK_STATUS_UNCAUGHT(status, napi_get_named_property, NULL); + + uiImage *img; + status = napi_get_value_external(env, image_ext, (void **)&img); + CHECK_STATUS_UNCAUGHT(status, napi_get_value_external, NULL); + ret = uiNewTableValueImage(img); break; } case uiTableValueTypeInt: { int32_t int_result; napi_status status = napi_get_value_int32(env, result, &int_result); - CHECK_STATUS_UNCAUGHT(status, napi_get_value_int32, 0); + CHECK_STATUS_UNCAUGHT(status, napi_get_value_int32, NULL); ret = uiNewTableValueInt(int_result); break; } @@ -223,7 +230,6 @@ static void c_setCellValue(uiTableModelHandler *mh, uiTableModel *m, int row, in case uiTableValueTypeString: { const char *cell_value = uiTableValueString(value); - ret = make_utf8_string(env, cell_value); // free(cell_value); break; From 862e7a2eaef26d1a726f3174b86b14a9b79f17f4 Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Tue, 25 Sep 2018 21:45:37 +0200 Subject: [PATCH 23/36] uiimage --- example/lightning-orb.png | Bin 24555 -> 1272 bytes example/tables.js | 13 +++++++++---- js/image.js | 19 +++++++++++++++++++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/example/lightning-orb.png b/example/lightning-orb.png index a6b2017b09457ceed9395738842704c2e86e4036..b8f2b7dc62e9b955b6b9955b9101cf7ae83f9fab 100644 GIT binary patch delta 1239 zcmV;|1StFKzXA9OA&F2@(mwUsm&(pH*6T9JUYAy%<9q`@@RJZwUe-R7~6nSIRbdhTSEqV$9M z4`*lQa?kJn=iGBA0{*46Q_j7tP=9_^Fa%lD-~fY@hTWE8I#;h{KDYxgypDcqgKl+e zz?m&JEYUTY49pI{+b!3;l6XrLM3YslG3iPhL819U;K{ZGXUUpzf~7 zhlgKgFYah-q?hmlA}vod*vb!39_R=1Gq9ZzOiB}M*+_lWo9f!#WgaBJBB$hlVgF;n zxzA7T=-*k=_B`PAPzDWCu*?jU`XN{W-G<2=Mpt7_$Nobb7mr-J9-^5mHipF0Q0lGS z*WG+>Z&fjkyJ-y}0hm!ReSZo{-4&QY)2OC{mknSt|ynd#TQ&8j56~(!Ekl zrK3BVlP~H)&}-RYu75=dwe{u_igFpnPkJE;!kRcG_ zL_rIik_NsqIj|#3K^s8(iqt~{6KPYpJB=YZmc}mwD#~a>)^k5Rj|`*@ncLy#24Xaw zKLNfv4-TVY(=S17@!2r@byEz>ms6PjF@qW(gNMJ#pE(p`%76ObfrEB0iUZN|L6!sA z&NfI;+I_S^YtGn;g{l4|Qj;3Ns1axmpJxZ<#8WPeD8WngWJ`=>Js%yLss~a8qc%}q zpd%-*^_~K38 z8onPX(B@6}8=MeLfzB*L=7x@&ePn6WKry*?^3o72o^auv>1|V|W7Tx{hp31Cp>R=W zTjO+cW*t-J3YhY(k4;)w_qCx8I3_)l zZuT5EGjI;~_}uObOQ@5wDB#DD`j5BALdJ`prBJLh+VJ(HR`43_?6RGFn{1%g=V;U_ zoP&{@*21TsWse>@Tk##x_QYmSv^A7>%b&6wj(OcXGpqT3n$`ln1R{5L5PKgL%2Da! zm#<5mO)O=oqapr3;=e0>0FUepfj-gp$LoIz_yb+S?`7QIM+yJ{002ovPDHLkV1l1x BK&t=% literal 24555 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 { libui.stopLoop(); }); -win.show(); + + +libui.UiImage.loadFromPng(__dirname + '/lightning-orb.png').then(image => { + img = image + win.show(); +}).catch(err => console.error(err)); libui.startLoop(); diff --git a/js/image.js b/js/image.js index e02e2dc..ca3c0c6 100644 --- a/js/image.js +++ b/js/image.js @@ -1,4 +1,6 @@ const {Image} = require('..'); +const {readFile} = require('fs'); +const parsePng = require('parse-png'); /** * An image. @@ -16,6 +18,23 @@ class UiImage { Image.append(this._img, pixels, pixelWidth, pixelHeight, byteStride); } + static loadFromPng(pngPath) { + return new Promise((resolve, reject) => { + readFile(pngPath, (err, data) => { + if (err) { + return reject(err); + } + + parsePng(data) + .then(png => { + const img = new UiImage(png.width, png.height); + img.append(png.data, png.width, png.height, png.width * 4); + resolve(img); + }) + .catch(reject); + }); + }); + } } module.exports = {UiImage}; From 511836daf649bad779d24ed36760f94987f9a73b Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Tue, 25 Sep 2018 21:52:27 +0200 Subject: [PATCH 24/36] tweaks --- example/tables.js | 16 ++++++---------- src/table.c | 1 - 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/example/tables.js b/example/tables.js index 0cd0ac7..5c45c6a 100644 --- a/example/tables.js +++ b/example/tables.js @@ -7,14 +7,11 @@ const addTo = (path, {name, version, author}) => { }; wd(process.cwd(), false, addTo); -// console.log(JSON.stringify(dependencies, null, 4)); const win = new libui.UiWindow('Tables example', 800, 600, true); win.margined = true; const {ValueTypes} = libui.UiTableModel; -console.log(ValueTypes.String) -console.log(ValueTypes.Int) let img; @@ -34,7 +31,6 @@ const tb = new libui.UiTable(new libui.UiTableModel({ return dependencies.length; }, cellValue(row, column) { - console.log('cellValue', (row, column)) switch (column) { case 0: { return dependencies[row].name; @@ -66,7 +62,6 @@ const tb = new libui.UiTable(new libui.UiTableModel({ } }, setCellValue(row, column, value) { - console.log(row, column, value) switch (column) { case 0: { dependencies[row].name = value; @@ -114,11 +109,12 @@ win.onClosing(() => { libui.stopLoop(); }); +async function run() { + img = await libui.UiImage.loadFromPng(__dirname + '/lightning-orb.png'); + win.show(); + libui.startLoop(); +} -libui.UiImage.loadFromPng(__dirname + '/lightning-orb.png').then(image => { - img = image - win.show(); -}).catch(err => console.error(err)); +run().catch(err => console.error(err)); -libui.startLoop(); diff --git a/src/table.c b/src/table.c index cb165e1..850d85f 100644 --- a/src/table.c +++ b/src/table.c @@ -150,7 +150,6 @@ LIBUI_FUNCTION(appendButtonColumn) { ENSURE_NOT_DESTROYED(); - printf("appendButtonColumn %s: %d %d", name, buttonModelColumn, buttonClickableModelColumn); uiTableAppendButtonColumn(uiTable(handle->control), name, buttonModelColumn, buttonClickableModelColumn); free(name); From d0e8d95e88a0ba45c0996ea238aabd90bbbbd4b9 Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Fri, 28 Sep 2018 11:38:28 +0200 Subject: [PATCH 25/36] advanced model [WIP] --- example/tables.js | 116 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 114 insertions(+), 2 deletions(-) diff --git a/example/tables.js b/example/tables.js index 5c45c6a..8291ec2 100644 --- a/example/tables.js +++ b/example/tables.js @@ -12,10 +12,121 @@ const win = new libui.UiWindow('Tables example', 800, 600, true); win.margined = true; const {ValueTypes} = libui.UiTableModel; -let img; +const always = val => () => val; +const noop = () => undefined; +function objectsTableModel(model) { + const numColumns = Object.keys(model).length; + const columnTypes = []; + const cellGetters = []; + const cellSetters = []; + for (const [key, column] of Object.entries(model)) { + const idx = columnTypes.length; + + if (column.type === String) { + columnTypes[idx] = ValueTypes.String; + cellGetters[idx] = (data, row) => { + debugger + return data[row][key] + }; + cellSetters[idx] = (data, row, value) => { + debugger + data[row][key] = value + }; + column.adder = tb => tb.appendTextColumn(column.header, idx, idx + 1, null); + + } else if (column.type === 'Image') { + columnTypes[idx] = ValueTypes.Image; + debugger + if (column.value instanceof libui.UiImage) { + cellGetters[idx] = () => { + debugger + return column.value; + }; + } else if (typeof column.value === 'function') { + cellGetters[idx] = column.value; + } else { + cellGetters[idx] = (data, row) => data[row][key]; + } + column.adder = tb => tb.appendImageColumn(column.header, idx); + + cellSetters[idx] = noop; + } + + if (typeof column.editable === 'function') { + columnTypes[idx + 1] = ValueTypes.Int; + cellGetters[idx + 1] = (data, row) => column.editable(data[row]); + + } else { + columnTypes[idx + 1] = ValueTypes.Int; + cellGetters[idx + 1] = always(Number(Boolean(column.editable))); + } + cellSetters[idx + 1] = noop; + + if (column.header === undefined) { + column.header = key; + } + + + } + + return { + fields: model, + addColumns(tb, ...columnNames) { + for (const columnName of columnNames) { + debugger + this.fields[columnName].adder(tb); + } + }, + bind(data) { + return new libui.UiTableModel({ + numColumns: () => numColumns, + columnType: column => columnTypes[column], + numRows: () => data.length, + cellValue: (row, column) => { + console.log({row, column}) + const value = cellGetters[column](data, row) + console.log(value) + return value; + }, + setCellValue: (row, column, value) => cellSetters[column](data, row, value) + }); + } + }; + +} + +const model = objectsTableModel({ + name: { + type: String, + editable: true, + header: 'Name' + }, + surname: { + type: String + }, + picture: { + type: 'Image', + value: () => { + debugger + return img + } + } +}); +const data = [{ + name: 'Andrea', + surname: 'Parodi' +}, { + name: 'Giorgio', + surname: 'Parodi' +}]; + + +const tb = new libui.UiTable(model.bind(data)); +model.addColumns(tb, 'name', 'surname', 'picture'); +/* const tb = new libui.UiTable(new libui.UiTableModel({ numColumns() { return 3; @@ -99,7 +210,7 @@ tb.appendCheckboxColumn('semver', 4, 41); tb.appendCheckboxTextColumn('version+semver', 4, 41, 1, 3, null); tb.appendButtonColumn('details', 5, 6); tb.appendImageColumn('img', 7); - +*/ const vbox = new libui.UiVerticalBox(); vbox.append(tb, true); win.setChild(vbox); @@ -109,6 +220,7 @@ win.onClosing(() => { libui.stopLoop(); }); +let img = null; async function run() { img = await libui.UiImage.loadFromPng(__dirname + '/lightning-orb.png'); win.show(); From 1646a1b40a4630221772d0592fceb6d6f99a9dfc Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Fri, 28 Sep 2018 16:10:19 +0200 Subject: [PATCH 26/36] extracted fromMetadata method to own file --- example/tables.js | 87 +---------------------------- index.js | 3 + js/table-model-from-metadata.js | 97 +++++++++++++++++++++++++++++++++ js/table-model.js | 7 +-- 4 files changed, 102 insertions(+), 92 deletions(-) create mode 100644 js/table-model-from-metadata.js diff --git a/example/tables.js b/example/tables.js index 8291ec2..de5fd75 100644 --- a/example/tables.js +++ b/example/tables.js @@ -10,95 +10,10 @@ wd(process.cwd(), false, addTo); const win = new libui.UiWindow('Tables example', 800, 600, true); win.margined = true; -const {ValueTypes} = libui.UiTableModel; -const always = val => () => val; -const noop = () => undefined; -function objectsTableModel(model) { - const numColumns = Object.keys(model).length; - const columnTypes = []; - const cellGetters = []; - const cellSetters = []; - - for (const [key, column] of Object.entries(model)) { - const idx = columnTypes.length; - - if (column.type === String) { - columnTypes[idx] = ValueTypes.String; - cellGetters[idx] = (data, row) => { - debugger - return data[row][key] - }; - cellSetters[idx] = (data, row, value) => { - debugger - data[row][key] = value - }; - column.adder = tb => tb.appendTextColumn(column.header, idx, idx + 1, null); - - } else if (column.type === 'Image') { - columnTypes[idx] = ValueTypes.Image; - debugger - if (column.value instanceof libui.UiImage) { - cellGetters[idx] = () => { - debugger - return column.value; - }; - } else if (typeof column.value === 'function') { - cellGetters[idx] = column.value; - } else { - cellGetters[idx] = (data, row) => data[row][key]; - } - column.adder = tb => tb.appendImageColumn(column.header, idx); - - cellSetters[idx] = noop; - } - - if (typeof column.editable === 'function') { - columnTypes[idx + 1] = ValueTypes.Int; - cellGetters[idx + 1] = (data, row) => column.editable(data[row]); - - } else { - columnTypes[idx + 1] = ValueTypes.Int; - cellGetters[idx + 1] = always(Number(Boolean(column.editable))); - } - cellSetters[idx + 1] = noop; - - if (column.header === undefined) { - column.header = key; - } - - - } - - return { - fields: model, - addColumns(tb, ...columnNames) { - for (const columnName of columnNames) { - debugger - this.fields[columnName].adder(tb); - } - }, - bind(data) { - return new libui.UiTableModel({ - numColumns: () => numColumns, - columnType: column => columnTypes[column], - numRows: () => data.length, - cellValue: (row, column) => { - console.log({row, column}) - const value = cellGetters[column](data, row) - console.log(value) - return value; - }, - setCellValue: (row, column, value) => cellSetters[column](data, row, value) - }); - } - }; - -} - -const model = objectsTableModel({ +const model = libui.UiTableModel.fromMetadata({ name: { type: String, editable: true, diff --git a/index.js b/index.js index afeb2d3..4220f05 100644 --- a/index.js +++ b/index.js @@ -83,7 +83,10 @@ const {AttributedString} = require('./js/font-string'); const {OpenTypeFeatures} = require('./js/font-opentype'); const {UiTableModel} = require('./js/table-model'); const {UiImage} = require('./js/image'); +const fromMetadata = require('./js/table-model-from-metadata'); +UiTableModel.fromMetadata = fromMetadata; +UiTableModel.ValueTypes = fromMetadata.ValueTypes; function applySetterGetter(...classConstructors) { for (const classConstructor of classConstructors) { diff --git a/js/table-model-from-metadata.js b/js/table-model-from-metadata.js new file mode 100644 index 0000000..f319175 --- /dev/null +++ b/js/table-model-from-metadata.js @@ -0,0 +1,97 @@ +const {UiImage} = require('./image'); +const {UiTableModel} = require('./table-model'); + +const always = val => () => val; +const noop = () => undefined; + +const ValueTypes = { + String: 0, + Image: 1, + Int: 2, + Color: 3 +}; + +function fromMetadata(model) { + const numColumns = Object.keys(model).length; + const columnTypes = []; + const cellGetters = []; + const cellSetters = []; + + for (const [key, column] of Object.entries(model)) { + const idx = columnTypes.length; + + if (column.type === String) { + columnTypes[idx] = ValueTypes.String; + cellGetters[idx] = (data, row) => { + debugger + return data[row][key] + }; + cellSetters[idx] = (data, row, value) => { + debugger + data[row][key] = value + }; + column.adder = tb => tb.appendTextColumn(column.header, idx, idx + 1, null); + + } else if (column.type === 'Image') { + columnTypes[idx] = ValueTypes.Image; + debugger + if (column.value instanceof UiImage) { + cellGetters[idx] = () => { + debugger + return column.value; + }; + } else if (typeof column.value === 'function') { + cellGetters[idx] = column.value; + } else { + cellGetters[idx] = (data, row) => data[row][key]; + } + column.adder = tb => tb.appendImageColumn(column.header, idx); + + cellSetters[idx] = noop; + } + + if (typeof column.editable === 'function') { + columnTypes[idx + 1] = ValueTypes.Int; + cellGetters[idx + 1] = (data, row) => column.editable(data[row]); + + } else { + columnTypes[idx + 1] = ValueTypes.Int; + cellGetters[idx + 1] = always(Number(Boolean(column.editable))); + } + cellSetters[idx + 1] = noop; + + if (column.header === undefined) { + column.header = key; + } + + + } + + return { + fields: model, + addColumns(tb, ...columnNames) { + for (const columnName of columnNames) { + debugger + this.fields[columnName].adder(tb); + } + }, + bind(data) { + return new UiTableModel({ + numColumns: () => numColumns, + columnType: column => columnTypes[column], + numRows: () => data.length, + cellValue: (row, column) => { + console.log({row, column}) + const value = cellGetters[column](data, row) + console.log(value) + return value; + }, + setCellValue: (row, column, value) => cellSetters[column](data, row, value) + }); + } + }; + +} + +fromMetadata.ValueTypes = ValueTypes; +module.exports = fromMetadata; \ No newline at end of file diff --git a/js/table-model.js b/js/table-model.js index db4fcb5..cba30ec 100644 --- a/js/table-model.js +++ b/js/table-model.js @@ -25,11 +25,6 @@ class UiTableModel { } } -UiTableModel.ValueTypes = { - String: 0, - Image: 1, - Int: 2, - Color: 3 -}; + module.exports = {UiTableModel}; From b3120181685d6ea8694eb21d8814b2645d3be79f Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Fri, 28 Sep 2018 18:19:06 +0200 Subject: [PATCH 27/36] Boolean [WIP] --- example/tables.js | 24 +++++++---- index.js | 1 + js/table-model-from-metadata.js | 74 ++++++++++++++++++++------------- 3 files changed, 62 insertions(+), 37 deletions(-) diff --git a/example/tables.js b/example/tables.js index de5fd75..86af84d 100644 --- a/example/tables.js +++ b/example/tables.js @@ -11,19 +11,27 @@ wd(process.cwd(), false, addTo); const win = new libui.UiWindow('Tables example', 800, 600, true); win.margined = true; +const {Text, Image, Bool} = libui.UiTableModel.Fields; + + const model = libui.UiTableModel.fromMetadata({ name: { - type: String, + type: Text, editable: true, header: 'Name' }, surname: { - type: String + type: Text + }, + male: { + type: Bool, + editable: true, + header: 'Is a male?' }, picture: { - type: 'Image', + type: Image, value: () => { debugger return img @@ -32,15 +40,17 @@ const model = libui.UiTableModel.fromMetadata({ }); const data = [{ name: 'Andrea', - surname: 'Parodi' + surname: 'Parodi', + male: true }, { - name: 'Giorgio', - surname: 'Parodi' + name: 'Giorgia', + surname: 'Parodi', + male: false }]; const tb = new libui.UiTable(model.bind(data)); -model.addColumns(tb, 'name', 'surname', 'picture'); +model.addColumns(tb, 'name', 'surname', 'picture', 'male'); /* const tb = new libui.UiTable(new libui.UiTableModel({ numColumns() { diff --git a/index.js b/index.js index 4220f05..461f9fa 100644 --- a/index.js +++ b/index.js @@ -87,6 +87,7 @@ const fromMetadata = require('./js/table-model-from-metadata'); UiTableModel.fromMetadata = fromMetadata; UiTableModel.ValueTypes = fromMetadata.ValueTypes; +UiTableModel.Fields = fromMetadata.Fields; function applySetterGetter(...classConstructors) { for (const classConstructor of classConstructors) { diff --git a/js/table-model-from-metadata.js b/js/table-model-from-metadata.js index f319175..73f9ab6 100644 --- a/js/table-model-from-metadata.js +++ b/js/table-model-from-metadata.js @@ -11,6 +11,38 @@ const ValueTypes = { Color: 3 }; +const Text = { + getter: ({key}) => (data, row) => data[row][key], + setter: ({key}) => (data, row, value) => data[row][key] = value, + cellType: () => ValueTypes.String, + adder: (column) => tb => tb.appendTextColumn(column.header, column.idx, column.idx + 1, null) +}; + +const Image = { + getter: ({value}) => { + if (value instanceof UiImage) { + return always(column.value); + }; + + if (typeof value === 'function') { + return value; + } + + return (data, row) => data[row][key]; + + }, + setter: () => noop, + cellType: () => ValueTypes.Image, + adder: (column) => tb => tb.appendImageColumn(column.header, column.idx) +}; + +const Bool = { + getter: ({key}) => (data, row) => Number(data[row][key]), + setter: ({key}) => (data, row, value) => data[row][key] = Boolean(value), + cellType: () => ValueTypes.Int, + adder: (column) => tb => tb.appendCheckboxColumn(column.header, column.idx, column.idx + 1) +}; + function fromMetadata(model) { const numColumns = Object.keys(model).length; const columnTypes = []; @@ -19,41 +51,17 @@ function fromMetadata(model) { for (const [key, column] of Object.entries(model)) { const idx = columnTypes.length; - - if (column.type === String) { - columnTypes[idx] = ValueTypes.String; - cellGetters[idx] = (data, row) => { - debugger - return data[row][key] - }; - cellSetters[idx] = (data, row, value) => { - debugger - data[row][key] = value - }; - column.adder = tb => tb.appendTextColumn(column.header, idx, idx + 1, null); + column.key = key; + column.idx = idx; - } else if (column.type === 'Image') { - columnTypes[idx] = ValueTypes.Image; - debugger - if (column.value instanceof UiImage) { - cellGetters[idx] = () => { - debugger - return column.value; - }; - } else if (typeof column.value === 'function') { - cellGetters[idx] = column.value; - } else { - cellGetters[idx] = (data, row) => data[row][key]; - } - column.adder = tb => tb.appendImageColumn(column.header, idx); - - cellSetters[idx] = noop; - } + columnTypes[idx] = column.type.cellType(column); + cellGetters[idx] = column.type.getter(column); + cellSetters[idx] = column.type.setter(column); + column.adder = column.type.adder(column); if (typeof column.editable === 'function') { columnTypes[idx + 1] = ValueTypes.Int; cellGetters[idx + 1] = (data, row) => column.editable(data[row]); - } else { columnTypes[idx + 1] = ValueTypes.Int; cellGetters[idx + 1] = always(Number(Boolean(column.editable))); @@ -94,4 +102,10 @@ function fromMetadata(model) { } fromMetadata.ValueTypes = ValueTypes; +fromMetadata.Fields = { + Text, + Image, + Bool +}; + module.exports = fromMetadata; \ No newline at end of file From f732140419072de041fbc1e1329a5b2e1f0d1c84 Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Thu, 25 Oct 2018 12:36:25 +0200 Subject: [PATCH 28/36] Bool -> Checkbox --- example/tables.js | 4 ++-- js/table-model-from-metadata.js | 9 +++++---- package-lock.json | 28 +++++++++++++++++++++------- 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/example/tables.js b/example/tables.js index 9ca789e..007f79e 100644 --- a/example/tables.js +++ b/example/tables.js @@ -10,12 +10,12 @@ wd(process.cwd(), false, addTo); const win = new libui.UiWindow('Tables example', 800, 600, true); win.margined = true; -const {Text, Image, Bool} = libui.UiTableModel.Fields; +const {Text, Image, Checkbox} = libui.UiTableModel.Fields; const model = libui.UiTableModel.fromMetadata({ name: {type: Text, editable: true, header: 'Name'}, surname: {type: Text}, - male: {type: Bool, editable: true, header: 'Is a male?'}, + male: {type: Checkbox, editable: true, header: 'Is a male?'}, picture: { type: Image, value: () => { diff --git a/js/table-model-from-metadata.js b/js/table-model-from-metadata.js index 571bbf1..946ca10 100644 --- a/js/table-model-from-metadata.js +++ b/js/table-model-from-metadata.js @@ -36,7 +36,7 @@ const Image = { adder: (column) => tb => tb.appendImageColumn(column.header, column.idx) }; -const Bool = { +const Checkbox = { getter: ({key}) => (data, row) => Number(data[row][key]), setter: ({key}) => (data, row, value) => data[row][key] = Boolean(value), cellType: () => ValueTypes.Int, @@ -78,7 +78,8 @@ function fromMetadata(model) { fields: model, addColumns(tb, ...columnNames) { for (const columnName of columnNames) { - debugger this.fields[columnName].adder(tb); + debugger; + this.fields[columnName].adder(tb); } }, bind(data) { @@ -103,7 +104,7 @@ fromMetadata.ValueTypes = ValueTypes; fromMetadata.Fields = { Text, Image, - Bool + Checkbox }; -module.exports = fromMetadata; \ No newline at end of file +module.exports = fromMetadata; diff --git a/package-lock.json b/package-lock.json index 25c83b7..a393f66 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2639,12 +2639,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2659,17 +2661,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -2786,7 +2791,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -2798,6 +2804,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -2812,6 +2819,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -2819,12 +2827,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.2.4", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -2843,6 +2853,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -2923,7 +2934,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -2935,6 +2947,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -3056,6 +3069,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", From 74eabe00e1a6bd335af5e59899003d347d4694d2 Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Wed, 7 Nov 2018 20:55:12 +0100 Subject: [PATCH 29/36] tweak --- example/tables.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/example/tables.js b/example/tables.js index 007f79e..3c0aa27 100644 --- a/example/tables.js +++ b/example/tables.js @@ -16,14 +16,9 @@ const model = libui.UiTableModel.fromMetadata({ name: {type: Text, editable: true, header: 'Name'}, surname: {type: Text}, male: {type: Checkbox, editable: true, header: 'Is a male?'}, - picture: { - type: Image, - value: () => { - debugger - return img - } - } + picture: {type: Image, value: () => img} }); + const data = [ {name: 'Andrea', surname: 'Parodi', male: true}, {name: 'Giorgia', surname: 'Parodi', male: false} From 6319174450d111c626f80aed8d87ecfc216b4e3f Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Thu, 8 Nov 2018 10:45:01 +0100 Subject: [PATCH 30/36] LabeledCheckbox & ProgressBar column types --- example/tables.js | 11 +++++---- js/table-model-from-metadata.js | 41 +++++++++++++++++++++++++-------- 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/example/tables.js b/example/tables.js index 3c0aa27..1458438 100644 --- a/example/tables.js +++ b/example/tables.js @@ -10,22 +10,23 @@ wd(process.cwd(), false, addTo); const win = new libui.UiWindow('Tables example', 800, 600, true); win.margined = true; -const {Text, Image, Checkbox} = libui.UiTableModel.Fields; +const {Text, Image, Checkbox, ProgressBar} = libui.UiTableModel.Fields; const model = libui.UiTableModel.fromMetadata({ name: {type: Text, editable: true, header: 'Name'}, surname: {type: Text}, male: {type: Checkbox, editable: true, header: 'Is a male?'}, - picture: {type: Image, value: () => img} + picture: {type: Image, value: () => img}, + completed: {type: ProgressBar}, }); const data = [ - {name: 'Andrea', surname: 'Parodi', male: true}, - {name: 'Giorgia', surname: 'Parodi', male: false} + {name: 'Andrea', surname: 'Parodi', male: true, completed: 30}, + {name: 'Giorgia', surname: 'Parodi', male: false, completed: 75} ]; const tb = new libui.UiTable(model.bind(data)); -model.addColumns(tb, 'name', 'surname', 'picture', 'male'); +model.addColumns(tb, 'name', 'surname', 'picture', 'male', 'completed'); /* const tb = new libui.UiTable(new libui.UiTableModel({ numColumns() { diff --git a/js/table-model-from-metadata.js b/js/table-model-from-metadata.js index 946ca10..2afa8f8 100644 --- a/js/table-model-from-metadata.js +++ b/js/table-model-from-metadata.js @@ -13,9 +13,9 @@ const ValueTypes = { const Text = { getter: ({key}) => (data, row) => data[row][key], - setter: ({key}) => (data, row, value) => data[row][key] = value, + setter: ({key}) => (data, row, value) => (data[row][key] = value), cellType: () => ValueTypes.String, - adder: (column) => tb => + adder: column => tb => tb.appendTextColumn(column.header, column.idx, column.idx + 1, null) }; @@ -23,7 +23,7 @@ const Image = { getter: ({value}) => { if (value instanceof UiImage) { return always(column.value); - }; + } if (typeof value === 'function') { return value; @@ -33,17 +33,37 @@ const Image = { }, setter: () => noop, cellType: () => ValueTypes.Image, - adder: (column) => tb => tb.appendImageColumn(column.header, column.idx) + adder: column => tb => tb.appendImageColumn(column.header, column.idx) }; const Checkbox = { getter: ({key}) => (data, row) => Number(data[row][key]), - setter: ({key}) => (data, row, value) => data[row][key] = Boolean(value), + setter: ({key}) => (data, row, value) => (data[row][key] = Boolean(value)), cellType: () => ValueTypes.Int, - adder: (column) => tb => + adder: column => tb => tb.appendCheckboxColumn(column.header, column.idx, column.idx + 1) }; +const LabeledCheckbox = { + getter: ({key}) => (data, row) => Number(data[row][key]), + setter: ({key}) => (data, row, value) => (data[row][key] = Boolean(value)), + cellType: () => ValueTypes.Int, + adder: column => tb => { + const textModelColumn = -1; + const textEditableModelColumn = -1; + + tb.appendCheckboxTextColumn(column.header, column.idx, column.idx + 1, + textModelColumn, textEditableModelColumn, null); + } +}; + +const ProgressBar = { + getter: ({key}) => (data, row) => Number(data[row][key]), + setter: ({key}) => (data, row, value) => (data[row][key] = Number(value)), + cellType: () => ValueTypes.Int, + adder: column => tb => tb.appendProgressBarColumn(column.header, column.idx) +}; + function fromMetadata(model) { const numColumns = Object.keys(model).length; const columnTypes = []; @@ -88,9 +108,9 @@ function fromMetadata(model) { columnType: column => columnTypes[column], numRows: () => data.length, cellValue: (row, column) => { - console.log({row, column}) - const value = cellGetters[column](data, row) - console.log(value) + console.log({row, column}); + const value = cellGetters[column](data, row); + console.log(value); return value; }, setCellValue: (row, column, value) => @@ -104,7 +124,8 @@ fromMetadata.ValueTypes = ValueTypes; fromMetadata.Fields = { Text, Image, - Checkbox + Checkbox, + ProgressBar }; module.exports = fromMetadata; From 14fb2927ab5d37778264ea73c8677da699d73584 Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Thu, 8 Nov 2018 12:55:45 +0100 Subject: [PATCH 31/36] WIP - remaining column types --- example/tables.js | 9 +++++++-- js/table-model-from-metadata.js | 35 ++++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/example/tables.js b/example/tables.js index 1458438..d247845 100644 --- a/example/tables.js +++ b/example/tables.js @@ -10,7 +10,7 @@ wd(process.cwd(), false, addTo); const win = new libui.UiWindow('Tables example', 800, 600, true); win.margined = true; -const {Text, Image, Checkbox, ProgressBar} = libui.UiTableModel.Fields; +const {Text, Image, Checkbox, ProgressBar, Button} = libui.UiTableModel.Fields; const model = libui.UiTableModel.fromMetadata({ name: {type: Text, editable: true, header: 'Name'}, @@ -18,6 +18,11 @@ const model = libui.UiTableModel.fromMetadata({ male: {type: Checkbox, editable: true, header: 'Is a male?'}, picture: {type: Image, value: () => img}, completed: {type: ProgressBar}, + sayhi: { + type: Button, + editable: () => 1, + click: obj => console.log(obj.name, obj.surname) + } }); const data = [ @@ -26,7 +31,7 @@ const data = [ ]; const tb = new libui.UiTable(model.bind(data)); -model.addColumns(tb, 'name', 'surname', 'picture', 'male', 'completed'); +model.addColumns(tb, /*'name', 'surname', 'picture', 'male', 'completed',*/ 'sayhi'); /* const tb = new libui.UiTable(new libui.UiTableModel({ numColumns() { diff --git a/js/table-model-from-metadata.js b/js/table-model-from-metadata.js index 2afa8f8..c7711b9 100644 --- a/js/table-model-from-metadata.js +++ b/js/table-model-from-metadata.js @@ -57,6 +57,29 @@ const LabeledCheckbox = { } }; +const LabeledImage = { + getter: ({value}) => { + if (value instanceof UiImage) { + return always(column.value); + } + + if (typeof value === 'function') { + return value; + } + + return (data, row) => data[row][key]; + }, + setter: ({key}) => () => 0, + cellType: () => ValueTypes.Image, + adder: column => tb => { + const textModelColumn = -1; + const textEditableModelColumn = -1; + + tb.appendImageTextColumn(column.header, column.idx, column.idx + 1, + textModelColumn, textEditableModelColumn, null); + } +}; + const ProgressBar = { getter: ({key}) => (data, row) => Number(data[row][key]), setter: ({key}) => (data, row, value) => (data[row][key] = Number(value)), @@ -64,6 +87,14 @@ const ProgressBar = { adder: column => tb => tb.appendProgressBarColumn(column.header, column.idx) }; +const Button = { + getter: ({label}) => () => 1, + setter: ({key, click}) => (data, row) => click(data[row]), + cellType: () => ValueTypes.Int, + adder: column => tb => + tb.appendButtonColumn(column.header, column.idx, column.idx + 1) +}; + function fromMetadata(model) { const numColumns = Object.keys(model).length; const columnTypes = []; @@ -125,7 +156,9 @@ fromMetadata.Fields = { Text, Image, Checkbox, - ProgressBar + ProgressBar, + LabeledCheckbox, + Button }; module.exports = fromMetadata; From 6b82ec5797187218fbc976f08d232a11a3e829f1 Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Thu, 8 Nov 2018 21:43:25 +0100 Subject: [PATCH 32/36] Fix label code on Button column --- example/tables.js | 5 +++-- js/table-model-from-metadata.js | 4 ++-- package-lock.json | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/example/tables.js b/example/tables.js index d247845..03d043f 100644 --- a/example/tables.js +++ b/example/tables.js @@ -21,7 +21,8 @@ const model = libui.UiTableModel.fromMetadata({ sayhi: { type: Button, editable: () => 1, - click: obj => console.log(obj.name, obj.surname) + label: 'Say Hi', + click: obj => libui.UiDialogs.msgBox(win, 'HI', obj.name + ' ' + obj.surname) } }); @@ -31,7 +32,7 @@ const data = [ ]; const tb = new libui.UiTable(model.bind(data)); -model.addColumns(tb, /*'name', 'surname', 'picture', 'male', 'completed',*/ 'sayhi'); +model.addColumns(tb, 'name', 'surname', 'picture', 'male', 'completed', 'sayhi'); /* const tb = new libui.UiTable(new libui.UiTableModel({ numColumns() { diff --git a/js/table-model-from-metadata.js b/js/table-model-from-metadata.js index c7711b9..42dc859 100644 --- a/js/table-model-from-metadata.js +++ b/js/table-model-from-metadata.js @@ -88,9 +88,9 @@ const ProgressBar = { }; const Button = { - getter: ({label}) => () => 1, + getter: ({label}) => () => String(label), setter: ({key, click}) => (data, row) => click(data[row]), - cellType: () => ValueTypes.Int, + cellType: () => ValueTypes.String, adder: column => tb => tb.appendButtonColumn(column.header, column.idx, column.idx + 1) }; diff --git a/package-lock.json b/package-lock.json index 77fc06c..cc60506 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2604,7 +2604,7 @@ "fsevents": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", - "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", + "integrity": "sha1-9B3LGvJYKvNpLaNvxVy9jhBBxCY=", "dev": true, "optional": true, "requires": { From fcd152335be79e81e4e25bf16769bbffe06f4dcd Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Thu, 8 Nov 2018 21:51:42 +0100 Subject: [PATCH 33/36] removed old table example --- example/tables.js | 100 +--------------------------------------------- package.json | 1 - 2 files changed, 1 insertion(+), 100 deletions(-) diff --git a/example/tables.js b/example/tables.js index 03d043f..cee1e88 100644 --- a/example/tables.js +++ b/example/tables.js @@ -1,17 +1,9 @@ const libui = require('..'); -const wd = require('@raydeck/walk-dependencies'); - -const dependencies = []; -const addTo = (path, {name, version, author}) => { - dependencies.push({name, version, author: author.name || author}); -}; -wd(process.cwd(), false, addTo); +const {Text, Image, Checkbox, ProgressBar, Button} = libui.UiTableModel.Fields; const win = new libui.UiWindow('Tables example', 800, 600, true); win.margined = true; -const {Text, Image, Checkbox, ProgressBar, Button} = libui.UiTableModel.Fields; - const model = libui.UiTableModel.fromMetadata({ name: {type: Text, editable: true, header: 'Name'}, surname: {type: Text}, @@ -33,97 +25,7 @@ const data = [ const tb = new libui.UiTable(model.bind(data)); model.addColumns(tb, 'name', 'surname', 'picture', 'male', 'completed', 'sayhi'); -/* -const tb = new libui.UiTable(new libui.UiTableModel({ - numColumns() { - return 3; - }, - columnType(column) { - - if (column == 3 || column == 4 || column == 41 || column == 6) - return ValueTypes.Int; - if (column == 7) - return ValueTypes.Image; - return ValueTypes.String; - }, - numRows() { - return dependencies.length; - }, - cellValue(row, column) { - switch (column) { - case 0: { - return dependencies[row].name; - } - case 1: { - return dependencies[row].version; - } - case 2: { - return dependencies[row].author; - } - case 3: { - return 0; - } - case 4: { - return Number(!dependencies[row].version.startsWith('0')); - } - case 41: { - return 1; - } - case 5: { - return 'show details'; - } - case 50: { - return dependencies[row].version.split('.').map(Number).reduce((a, b) => - a + b); - } - case 6: { - return 1; - } - case 7: { - return img; - } - } - }, - setCellValue(row, column, value) { - switch (column) { - case 0: { - dependencies[row].name = value; - break; - } - case 1: { - dependencies[row].version = value; - break; - } - case 2: { - dependencies[row].author = value; - break; - } - case 4: { - if (value) { - dependencies[row].version = '1' + dependencies[row].version.slice(1); - } else { - dependencies[row].version = '0' + dependencies[row].version.slice(1); - } - break; - } - case 5: { - libui.UiDialogs.msgBox(win, 'Row details', - JSON.stringify(dependencies[row], null, 4)); - break; - } - } - } -})); -tb.appendTextColumn('name', 0, 3, null); -tb.appendTextColumn('version', 1, 3, null); -tb.appendTextColumn('author', 2, 41, null); -tb.appendCheckboxColumn('semver', 4, 41); -tb.appendCheckboxTextColumn('version+semver', 4, 41, 1, 3, null); -tb.appendButtonColumn('details', 5, 6); -tb.appendProgressBarColumn('sum version', 50, 6); -tb.appendImageColumn('img', 7); -*/ const vbox = new libui.UiVerticalBox(); vbox.append(tb, true); win.setChild(vbox); diff --git a/package.json b/package.json index 248ff9e..9f4f22a 100755 --- a/package.json +++ b/package.json @@ -41,7 +41,6 @@ "tar": "^4.4.1" }, "devDependencies": { - "@raydeck/walk-dependencies": "^1.6.1", "ava": "^0.25.0", "boxen": "^1.3.0", "clang-format": "^1.2.3", From f1bca0727973ec54900322ee039d292686f902f3 Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Tue, 4 Dec 2018 09:39:49 +0100 Subject: [PATCH 34/36] metadata model completed... --- example/tables.js | 12 +++++++---- js/table-model-from-metadata.js | 38 +++++++++++++++++++++++++++++---- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/example/tables.js b/example/tables.js index cee1e88..d6e5ffc 100644 --- a/example/tables.js +++ b/example/tables.js @@ -1,5 +1,6 @@ const libui = require('..'); -const {Text, Image, Checkbox, ProgressBar, Button} = libui.UiTableModel.Fields; +const {Text, Image, Checkbox, ProgressBar, Button, LabeledCheckbox, LabeledImage} = + libui.UiTableModel.Fields; const win = new libui.UiWindow('Tables example', 800, 600, true); win.margined = true; @@ -10,6 +11,8 @@ const model = libui.UiTableModel.fromMetadata({ male: {type: Checkbox, editable: true, header: 'Is a male?'}, picture: {type: Image, value: () => img}, completed: {type: ProgressBar}, + someProp: {type: LabeledCheckbox, editable: true, label: 'some props'}, + otherProp: {type: LabeledImage, value: () => img, label: 'an Image'}, sayhi: { type: Button, editable: () => 1, @@ -19,12 +22,13 @@ const model = libui.UiTableModel.fromMetadata({ }); const data = [ - {name: 'Andrea', surname: 'Parodi', male: true, completed: 30}, - {name: 'Giorgia', surname: 'Parodi', male: false, completed: 75} + {name: 'Andrea', surname: 'Parodi', male: true, completed: 30, someProp: true}, + {name: 'Giorgia', surname: 'Parodi', male: false, completed: 75, someProp: false} ]; const tb = new libui.UiTable(model.bind(data)); -model.addColumns(tb, 'name', 'surname', 'picture', 'male', 'completed', 'sayhi'); +model.addColumns(tb, 'name', 'surname', 'picture', 'male', 'completed', 'sayhi', + 'someProp', 'otherProp'); const vbox = new libui.UiVerticalBox(); vbox.append(tb, true); diff --git a/js/table-model-from-metadata.js b/js/table-model-from-metadata.js index 42dc859..2766111 100644 --- a/js/table-model-from-metadata.js +++ b/js/table-model-from-metadata.js @@ -48,9 +48,21 @@ const LabeledCheckbox = { getter: ({key}) => (data, row) => Number(data[row][key]), setter: ({key}) => (data, row, value) => (data[row][key] = Boolean(value)), cellType: () => ValueTypes.Int, + addFurtherColumns: ({column, columnTypes, cellGetters, cellSetters}) => { + const labelIdx = column.idx + 1000; + columnTypes[labelIdx] = ValueTypes.String; + cellGetters[labelIdx] = () => column.label; + cellSetters[labelIdx] = noop; + + columnTypes[labelIdx + 1] = ValueTypes.Int; + cellGetters[labelIdx + 1] = () => 0; + cellSetters[labelIdx + 1] = noop; + + column.labelIdx = labelIdx; + }, adder: column => tb => { - const textModelColumn = -1; - const textEditableModelColumn = -1; + const textModelColumn = column.labelIdx; + const textEditableModelColumn = column.labelIdx + 1; tb.appendCheckboxTextColumn(column.header, column.idx, column.idx + 1, textModelColumn, textEditableModelColumn, null); @@ -71,9 +83,21 @@ const LabeledImage = { }, setter: ({key}) => () => 0, cellType: () => ValueTypes.Image, + addFurtherColumns: ({column, columnTypes, cellGetters, cellSetters}) => { + const labelIdx = column.idx + 1000; + columnTypes[labelIdx] = ValueTypes.String; + cellGetters[labelIdx] = () => column.label; + cellSetters[labelIdx] = noop; + + columnTypes[labelIdx + 1] = ValueTypes.Int; + cellGetters[labelIdx + 1] = () => 0; + cellSetters[labelIdx + 1] = noop; + + column.labelIdx = labelIdx; + }, adder: column => tb => { - const textModelColumn = -1; - const textEditableModelColumn = -1; + const textModelColumn = column.labelIdx; + const textEditableModelColumn = column.labelIdx + 1; tb.appendImageTextColumn(column.header, column.idx, column.idx + 1, textModelColumn, textEditableModelColumn, null); @@ -111,6 +135,11 @@ function fromMetadata(model) { cellSetters[idx] = column.type.setter(column); column.adder = column.type.adder(column); + if (typeof column.type.addFurtherColumns === 'function') { + column.type.addFurtherColumns( + {columnTypes, cellGetters, cellSetters, column}); + } + if (typeof column.editable === 'function') { columnTypes[idx + 1] = ValueTypes.Int; cellGetters[idx + 1] = (data, row) => column.editable(data[row]); @@ -158,6 +187,7 @@ fromMetadata.Fields = { Checkbox, ProgressBar, LabeledCheckbox, + LabeledImage, Button }; From 776f4a6ef35b01801c6ce51e37cd8d6fc7b20927 Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Mon, 10 Dec 2018 19:45:40 +0100 Subject: [PATCH 35/36] Fix image index calculation --- js/table-model-from-metadata.js | 30 +++++++++++++++++------------- package-lock.json | 6 ------ 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/js/table-model-from-metadata.js b/js/table-model-from-metadata.js index 2766111..0bb4d7b 100644 --- a/js/table-model-from-metadata.js +++ b/js/table-model-from-metadata.js @@ -49,7 +49,8 @@ const LabeledCheckbox = { setter: ({key}) => (data, row, value) => (data[row][key] = Boolean(value)), cellType: () => ValueTypes.Int, addFurtherColumns: ({column, columnTypes, cellGetters, cellSetters}) => { - const labelIdx = column.idx + 1000; + const labelIdx = columnTypes.length; + console.log('LabeledCheckbox labelIdx', column.idx, labelIdx); columnTypes[labelIdx] = ValueTypes.String; cellGetters[labelIdx] = () => column.label; cellSetters[labelIdx] = noop; @@ -84,10 +85,13 @@ const LabeledImage = { setter: ({key}) => () => 0, cellType: () => ValueTypes.Image, addFurtherColumns: ({column, columnTypes, cellGetters, cellSetters}) => { - const labelIdx = column.idx + 1000; + const labelIdx = columnTypes.length; + console.log('LabeledImage labelIdx', column.idx, labelIdx); columnTypes[labelIdx] = ValueTypes.String; - cellGetters[labelIdx] = () => column.label; - cellSetters[labelIdx] = noop; + cellGetters[labelIdx] = () => { + console.log('column.label', column.label); + return column.label; + } cellSetters[labelIdx] = noop; columnTypes[labelIdx + 1] = ValueTypes.Int; cellGetters[labelIdx + 1] = () => 0; @@ -96,11 +100,12 @@ const LabeledImage = { column.labelIdx = labelIdx; }, adder: column => tb => { + console.log('adder', column.labelIdx) const textModelColumn = column.labelIdx; const textEditableModelColumn = column.labelIdx + 1; - tb.appendImageTextColumn(column.header, column.idx, column.idx + 1, - textModelColumn, textEditableModelColumn, null); + tb.appendImageTextColumn(column.header, column.idx, textModelColumn, + textEditableModelColumn, null); } }; @@ -135,11 +140,6 @@ function fromMetadata(model) { cellSetters[idx] = column.type.setter(column); column.adder = column.type.adder(column); - if (typeof column.type.addFurtherColumns === 'function') { - column.type.addFurtherColumns( - {columnTypes, cellGetters, cellSetters, column}); - } - if (typeof column.editable === 'function') { columnTypes[idx + 1] = ValueTypes.Int; cellGetters[idx + 1] = (data, row) => column.editable(data[row]); @@ -149,6 +149,12 @@ function fromMetadata(model) { } cellSetters[idx + 1] = noop; + if (typeof column.type.addFurtherColumns === 'function') { + + column.type.addFurtherColumns( + {columnTypes, cellGetters, cellSetters, column}); + } + if (column.header === undefined) { column.header = key; } @@ -168,9 +174,7 @@ function fromMetadata(model) { columnType: column => columnTypes[column], numRows: () => data.length, cellValue: (row, column) => { - console.log({row, column}); const value = cellGetters[column](data, row); - console.log(value); return value; }, setCellValue: (row, column, value) => diff --git a/package-lock.json b/package-lock.json index cc60506..28ab021 100644 --- a/package-lock.json +++ b/package-lock.json @@ -131,12 +131,6 @@ } } }, - "@raydeck/walk-dependencies": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@raydeck/walk-dependencies/-/walk-dependencies-1.6.1.tgz", - "integrity": "sha512-Ktwf9yOh5bzAKb4RHUkB64h3zrJTCjInHVHUWZ2qgIgFzn8OwYsI8mTDuolS3b66QlOyobKi0CxxErvHW2JxXA==", - "dev": true - }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", From 8d87b161d79231d4cf74f9d1737bbe084136302c Mon Sep 17 00:00:00 2001 From: Andrea Parodi Date: Mon, 10 Dec 2018 20:06:36 +0100 Subject: [PATCH 36/36] fix ; --- js/table-model-from-metadata.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/table-model-from-metadata.js b/js/table-model-from-metadata.js index 0bb4d7b..d9d049b 100644 --- a/js/table-model-from-metadata.js +++ b/js/table-model-from-metadata.js @@ -91,7 +91,8 @@ const LabeledImage = { cellGetters[labelIdx] = () => { console.log('column.label', column.label); return column.label; - } cellSetters[labelIdx] = noop; + }; + cellSetters[labelIdx] = noop; columnTypes[labelIdx + 1] = ValueTypes.Int; cellGetters[labelIdx + 1] = () => 0;