#include #include #include #include "../js_modules.h" typedef struct { TextBox* text_box; ViewDispatcher* view_dispatcher; FuriThread* thread; } JsTextboxInst; static JsTextboxInst* get_this_ctx(struct mjs* mjs) { mjs_val_t obj_inst = mjs_get(mjs, mjs_get_this(mjs), INST_PROP_NAME, ~0); JsTextboxInst* textbox = mjs_get_ptr(mjs, obj_inst); furi_assert(textbox); return textbox; } static void ret_bad_args(struct mjs* mjs, const char* error) { mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "%s", error); mjs_return(mjs, MJS_UNDEFINED); } static bool check_arg_count(struct mjs* mjs, size_t count) { size_t num_args = mjs_nargs(mjs); if(num_args != count) { ret_bad_args(mjs, "Wrong argument count"); return false; } return true; } static void js_textbox_set_config(struct mjs* mjs) { JsTextboxInst* textbox = get_this_ctx(mjs); if(!check_arg_count(mjs, 2)) return; TextBoxFocus set_focus = TextBoxFocusStart; mjs_val_t focus_arg = mjs_arg(mjs, 0); const char* focus = mjs_get_string(mjs, &focus_arg, NULL); if(!focus) { ret_bad_args(mjs, "Focus must be a string"); return; } else { if(!strncmp(focus, "start", strlen("start"))) { set_focus = TextBoxFocusStart; } else if(!strncmp(focus, "end", strlen("end"))) { set_focus = TextBoxFocusEnd; } else { ret_bad_args(mjs, "Bad focus value"); return; } } TextBoxFont set_font = TextBoxFontText; mjs_val_t font_arg = mjs_arg(mjs, 1); const char* font = mjs_get_string(mjs, &font_arg, NULL); if(!font) { ret_bad_args(mjs, "Font must be a string"); return; } else { if(!strncmp(font, "text", strlen("text"))) { set_font = TextBoxFontText; } else if(!strncmp(font, "hex", strlen("hex"))) { set_font = TextBoxFontHex; } else { ret_bad_args(mjs, "Bad font value"); return; } } text_box_set_focus(textbox->text_box, set_focus); text_box_set_font(textbox->text_box, set_font); mjs_return(mjs, MJS_UNDEFINED); } static void js_textbox_set_text(struct mjs* mjs) { JsTextboxInst* textbox = get_this_ctx(mjs); if(!check_arg_count(mjs, 1)) return; mjs_val_t text_arg = mjs_arg(mjs, 0); const char* text = mjs_get_string(mjs, &text_arg, NULL); if(!text) { ret_bad_args(mjs, "Text must be a string"); return; } text_box_set_text(textbox->text_box, text); mjs_return(mjs, MJS_UNDEFINED); } static void js_textbox_is_open(struct mjs* mjs) { JsTextboxInst* textbox = get_this_ctx(mjs); if(!check_arg_count(mjs, 0)) return; mjs_return(mjs, mjs_mk_boolean(mjs, !!textbox->thread)); } static void textbox_deinit(void* context) { JsTextboxInst* textbox = context; furi_thread_join(textbox->thread); furi_thread_free(textbox->thread); textbox->thread = NULL; view_dispatcher_remove_view(textbox->view_dispatcher, 0); view_dispatcher_free(textbox->view_dispatcher); textbox->view_dispatcher = NULL; furi_record_close(RECORD_GUI); text_box_reset(textbox->text_box); } static void textbox_callback(void* context, uint32_t arg) { UNUSED(arg); textbox_deinit(context); } static bool textbox_exit(void* context) { JsTextboxInst* textbox = context; view_dispatcher_stop(textbox->view_dispatcher); furi_timer_pending_callback(textbox_callback, textbox, 0); return true; } static int32_t textbox_thread(void* context) { ViewDispatcher* view_dispatcher = context; view_dispatcher_run(view_dispatcher); return 0; } static void js_textbox_show(struct mjs* mjs) { JsTextboxInst* textbox = get_this_ctx(mjs); if(!check_arg_count(mjs, 0)) return; Gui* gui = furi_record_open(RECORD_GUI); textbox->view_dispatcher = view_dispatcher_alloc(); view_dispatcher_enable_queue(textbox->view_dispatcher); view_dispatcher_add_view(textbox->view_dispatcher, 0, text_box_get_view(textbox->text_box)); view_dispatcher_set_event_callback_context(textbox->view_dispatcher, textbox); view_dispatcher_set_navigation_event_callback(textbox->view_dispatcher, textbox_exit); view_dispatcher_attach_to_gui(textbox->view_dispatcher, gui, ViewDispatcherTypeFullscreen); view_dispatcher_switch_to_view(textbox->view_dispatcher, 0); textbox->thread = furi_thread_alloc_ex("JsTextbox", 1024, textbox_thread, textbox->view_dispatcher); furi_thread_start(textbox->thread); mjs_return(mjs, MJS_UNDEFINED); } static void js_textbox_close(struct mjs* mjs) { JsTextboxInst* textbox = get_this_ctx(mjs); if(!check_arg_count(mjs, 0)) return; if(textbox->thread) { view_dispatcher_stop(textbox->view_dispatcher); textbox_deinit(textbox); } mjs_return(mjs, MJS_UNDEFINED); } static void* js_textbox_create(struct mjs* mjs, mjs_val_t* object) { JsTextboxInst* textbox = malloc(sizeof(JsTextboxInst)); mjs_val_t textbox_obj = mjs_mk_object(mjs); mjs_set(mjs, textbox_obj, INST_PROP_NAME, ~0, mjs_mk_foreign(mjs, textbox)); mjs_set(mjs, textbox_obj, "setConfig", ~0, MJS_MK_FN(js_textbox_set_config)); mjs_set(mjs, textbox_obj, "setText", ~0, MJS_MK_FN(js_textbox_set_text)); mjs_set(mjs, textbox_obj, "isOpen", ~0, MJS_MK_FN(js_textbox_is_open)); mjs_set(mjs, textbox_obj, "show", ~0, MJS_MK_FN(js_textbox_show)); mjs_set(mjs, textbox_obj, "close", ~0, MJS_MK_FN(js_textbox_close)); textbox->text_box = text_box_alloc(); *object = textbox_obj; return textbox; } static void js_textbox_destroy(void* inst) { JsTextboxInst* textbox = inst; if(textbox->thread) { view_dispatcher_stop(textbox->view_dispatcher); textbox_deinit(textbox); } text_box_free(textbox->text_box); free(textbox); } static const JsModuleDescriptor js_textbox_desc = { "textbox", js_textbox_create, js_textbox_destroy, }; static const FlipperAppPluginDescriptor textbox_plugin_descriptor = { .appid = PLUGIN_APP_ID, .ep_api_version = PLUGIN_API_VERSION, .entry_point = &js_textbox_desc, }; const FlipperAppPluginDescriptor* js_textbox_ep(void) { return &textbox_plugin_descriptor; }