1
mirror of https://github.com/DarkFlippers/unleashed-firmware.git synced 2025-12-12 20:49:49 +04:00
Files
Anna Antonenko d0360625d6 [FL-3925] JS views finished (#4155)
* js: value destructuring and tests

* js: temporary fix to see size impact

* js_val: reduce code size 1

* i may be stupid.

* test: js_value args

* Revert "js: temporary fix to see size impact"

This reverts commit f51d726dbafc4300d3552020de1c3b8f9ecd3ac1.

* pvs: silence warnings

* style: formatting

* pvs: silence warnings?

* pvs: silence warnings??

* js_value: redesign declaration types for less code

* js: temporary fix to see size impact

* style: formatting

* pvs: fix helpful warnings

* js_value: reduce .rodata size

* pvs: fix helpful warning

* js_value: reduce code size 1

* fix build error

* style: format

* Revert "js: temporary fix to see size impact"

This reverts commit d6a46f01794132e882e03fd273dec24386a4f8ba.

* style: format

* js: move to new arg parser

* style: format

* feat: all js views done

* js, toolbox: generalize string owning

* toolbox: silence pvs warning

---------

Co-authored-by: hedger <hedger@nanode.su>
Co-authored-by: hedger <hedger@users.noreply.github.com>
2025-09-24 23:24:28 +04:00

106 lines
3.3 KiB
C

#include "../../js_modules.h" // IWYU pragma: keep
#include "js_gui.h"
#include "../js_event_loop/js_event_loop.h"
#include <gui/modules/menu.h>
#include <toolbox/str_buffer.h>
typedef struct {
int32_t next_index;
StrBuffer str_buffer;
FuriMessageQueue* queue;
JsEventLoopContract contract;
} JsMenuCtx;
static mjs_val_t choose_transformer(struct mjs* mjs, FuriMessageQueue* queue, void* context) {
UNUSED(context);
uint32_t index;
furi_check(furi_message_queue_get(queue, &index, 0) == FuriStatusOk);
return mjs_mk_number(mjs, (double)index);
}
static void choose_callback(void* context, uint32_t index) {
JsMenuCtx* ctx = context;
furi_check(furi_message_queue_put(ctx->queue, &index, 0) == FuriStatusOk);
}
static bool
js_menu_add_child(struct mjs* mjs, Menu* menu, JsMenuCtx* context, mjs_val_t child_obj) {
static const JsValueDeclaration js_menu_string = JS_VALUE_SIMPLE(JsValueTypeString);
static const JsValueDeclaration js_menu_pointer = JS_VALUE_SIMPLE(JsValueTypeRawPointer);
static const JsValueObjectField js_menu_child_fields[] = {
{"icon", &js_menu_pointer},
{"label", &js_menu_string},
};
static const JsValueDeclaration js_menu_child = JS_VALUE_OBJECT(js_menu_child_fields);
const Icon* icon;
const char* label;
JsValueParseStatus status;
JS_VALUE_PARSE(
mjs,
JS_VALUE_PARSE_SOURCE_VALUE(&js_menu_child),
JsValueParseFlagReturnOnError,
&status,
&child_obj,
&icon,
&label);
if(status != JsValueParseStatusOk) return false;
menu_add_item(
menu,
str_buffer_make_owned_clone(&context->str_buffer, label),
icon,
context->next_index++,
choose_callback,
context);
return true;
}
static void js_menu_reset_children(Menu* menu, JsMenuCtx* context) {
context->next_index = 0;
menu_reset(menu);
str_buffer_clear_all_clones(&context->str_buffer);
}
static JsMenuCtx* ctx_make(struct mjs* mjs, Menu* input, mjs_val_t view_obj) {
UNUSED(input);
JsMenuCtx* context = malloc(sizeof(JsMenuCtx));
context->queue = furi_message_queue_alloc(1, sizeof(uint32_t));
context->contract = (JsEventLoopContract){
.magic = JsForeignMagic_JsEventLoopContract,
.object_type = JsEventLoopObjectTypeQueue,
.object = context->queue,
.non_timer =
{
.event = FuriEventLoopEventIn,
.transformer = (JsEventLoopTransformer)choose_transformer,
},
};
mjs_set(mjs, view_obj, "chosen", ~0, mjs_mk_foreign(mjs, &context->contract));
return context;
}
static void ctx_destroy(Menu* input, JsMenuCtx* context, FuriEventLoop* loop) {
UNUSED(input);
furi_event_loop_maybe_unsubscribe(loop, context->queue);
furi_message_queue_free(context->queue);
str_buffer_clear_all_clones(&context->str_buffer);
free(context);
}
static const JsViewDescriptor view_descriptor = {
.alloc = (JsViewAlloc)menu_alloc,
.free = (JsViewFree)menu_free,
.get_view = (JsViewGetView)menu_get_view,
.custom_make = (JsViewCustomMake)ctx_make,
.custom_destroy = (JsViewCustomDestroy)ctx_destroy,
.add_child = (JsViewAddChild)js_menu_add_child,
.reset_children = (JsViewResetChildren)js_menu_reset_children,
.prop_cnt = 0,
.props = {},
};
JS_GUI_VIEW_DEF(menu, &view_descriptor);