mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2024-11-22 20:43:07 +00:00
JS: Refactor widget with ViewHolder, fix crash
Based on textbox refactor by nminaylov
This commit is contained in:
parent
b65741d625
commit
681b1cd069
1 changed files with 69 additions and 103 deletions
|
@ -1,6 +1,5 @@
|
|||
#include <assets_icons.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/view.h>
|
||||
#include <gui/view_holder.h>
|
||||
#include <m-array.h>
|
||||
#include <m-list.h>
|
||||
#include <string.h>
|
||||
|
@ -113,8 +112,8 @@ typedef struct {
|
|||
|
||||
typedef struct {
|
||||
View* view;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
FuriThread* thread;
|
||||
ViewHolder* view_holder;
|
||||
bool is_shown;
|
||||
} JsWidgetInst;
|
||||
|
||||
static JsWidgetInst* get_this_ctx(struct mjs* mjs) {
|
||||
|
@ -754,60 +753,34 @@ static void js_widget_is_open(struct mjs* mjs) {
|
|||
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||
if(!check_arg_count(mjs, 0)) return;
|
||||
|
||||
mjs_return(mjs, mjs_mk_boolean(mjs, !!widget->thread));
|
||||
}
|
||||
|
||||
static void widget_deinit(void* context) {
|
||||
JsWidgetInst* widget = context;
|
||||
if(widget->thread) {
|
||||
furi_thread_join(widget->thread);
|
||||
furi_thread_free(widget->thread);
|
||||
widget->thread = NULL;
|
||||
|
||||
furi_assert(widget->view_dispatcher);
|
||||
view_dispatcher_remove_view(widget->view_dispatcher, 0);
|
||||
view_dispatcher_free(widget->view_dispatcher);
|
||||
widget->view_dispatcher = NULL;
|
||||
|
||||
furi_record_close(RECORD_GUI);
|
||||
}
|
||||
mjs_return(mjs, mjs_mk_boolean(mjs, widget->is_shown));
|
||||
}
|
||||
|
||||
static void widget_callback(void* context, uint32_t arg) {
|
||||
UNUSED(arg);
|
||||
widget_deinit(context);
|
||||
}
|
||||
|
||||
static bool widget_exit(void* context) {
|
||||
JsWidgetInst* widget = context;
|
||||
view_dispatcher_stop(widget->view_dispatcher);
|
||||
furi_timer_pending_callback(widget_callback, widget, 0);
|
||||
return true;
|
||||
view_holder_stop(widget->view_holder);
|
||||
widget->is_shown = false;
|
||||
}
|
||||
|
||||
static int32_t widget_thread(void* context) {
|
||||
ViewDispatcher* view_dispatcher = context;
|
||||
view_dispatcher_run(view_dispatcher);
|
||||
return 0;
|
||||
static void widget_exit(void* context) {
|
||||
JsWidgetInst* widget = context;
|
||||
// Using timer to schedule view_holder stop, will not work under high CPU load
|
||||
furi_timer_pending_callback(widget_callback, widget, 0);
|
||||
}
|
||||
|
||||
static void js_widget_show(struct mjs* mjs) {
|
||||
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||
if(!check_arg_count(mjs, 0)) return;
|
||||
|
||||
Gui* gui = furi_record_open(RECORD_GUI);
|
||||
if(widget->is_shown) {
|
||||
mjs_prepend_errorf(mjs, MJS_INTERNAL_ERROR, "Widget is already shown");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
|
||||
widget->view_dispatcher = view_dispatcher_alloc();
|
||||
view_dispatcher_enable_queue(widget->view_dispatcher);
|
||||
view_dispatcher_add_view(widget->view_dispatcher, 0, widget->view);
|
||||
view_dispatcher_set_event_callback_context(widget->view_dispatcher, widget);
|
||||
view_dispatcher_set_navigation_event_callback(widget->view_dispatcher, widget_exit);
|
||||
view_dispatcher_attach_to_gui(widget->view_dispatcher, gui, ViewDispatcherTypeFullscreen);
|
||||
view_dispatcher_switch_to_view(widget->view_dispatcher, 0);
|
||||
|
||||
widget->thread =
|
||||
furi_thread_alloc_ex("JsWidget", 1024, widget_thread, widget->view_dispatcher);
|
||||
furi_thread_start(widget->thread);
|
||||
view_holder_start(widget->view_holder);
|
||||
widget->is_shown = true;
|
||||
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
}
|
||||
|
@ -816,10 +789,8 @@ static void js_widget_close(struct mjs* mjs) {
|
|||
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||
if(!check_arg_count(mjs, 0)) return;
|
||||
|
||||
if(widget->thread) {
|
||||
view_dispatcher_stop(widget->view_dispatcher);
|
||||
widget_deinit(widget);
|
||||
}
|
||||
view_holder_stop(widget->view_holder);
|
||||
widget->is_shown = false;
|
||||
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
}
|
||||
|
@ -839,57 +810,9 @@ static void widget_draw_callback(Canvas* canvas, void* model) {
|
|||
}
|
||||
}
|
||||
|
||||
static void widget_remove_view(void* context) {
|
||||
JsWidgetInst* widget = context;
|
||||
|
||||
if(widget->view) {
|
||||
with_view_model(
|
||||
widget->view,
|
||||
WidgetModel * model,
|
||||
{
|
||||
ComponentArray_it_t it;
|
||||
ComponentArray_it(it, model->component);
|
||||
while(!ComponentArray_end_p(it)) {
|
||||
WidgetComponent* component = *ComponentArray_ref(it);
|
||||
if(component && component->free) {
|
||||
component->free(component);
|
||||
}
|
||||
ComponentArray_next(it);
|
||||
}
|
||||
ComponentArray_reset(model->component);
|
||||
ComponentArray_clear(model->component);
|
||||
},
|
||||
false);
|
||||
with_view_model(
|
||||
widget->view, WidgetModel * model, { XbmImageList_clear(model->image); }, false);
|
||||
view_free(widget->view);
|
||||
widget->view = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static JsWidgetInst* widget_alloc(void) {
|
||||
JsWidgetInst* widget = malloc(sizeof(JsWidgetInst));
|
||||
widget->thread = NULL;
|
||||
widget->view_dispatcher = NULL;
|
||||
|
||||
widget->view = view_alloc();
|
||||
view_allocate_model(widget->view, ViewModelTypeLockFree, sizeof(WidgetModel));
|
||||
view_set_draw_callback(widget->view, widget_draw_callback);
|
||||
with_view_model(
|
||||
widget->view,
|
||||
WidgetModel * model,
|
||||
{
|
||||
ComponentArray_init(model->component);
|
||||
XbmImageList_init(model->image);
|
||||
model->max_assigned_id = 0;
|
||||
},
|
||||
true);
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
static void* js_widget_create(struct mjs* mjs, mjs_val_t* object) {
|
||||
JsWidgetInst* widget = widget_alloc();
|
||||
JsWidgetInst* widget = malloc(sizeof(JsWidgetInst));
|
||||
|
||||
mjs_val_t widget_obj = mjs_mk_object(mjs);
|
||||
mjs_set(mjs, widget_obj, INST_PROP_NAME, ~0, mjs_mk_foreign(mjs, widget));
|
||||
// addBox(x: number, y: number, w: number, h: number): number (returns id of the added component)
|
||||
|
@ -924,17 +847,60 @@ static void* js_widget_create(struct mjs* mjs, mjs_val_t* object) {
|
|||
mjs_set(mjs, widget_obj, "show", ~0, MJS_MK_FN(js_widget_show));
|
||||
// close(): void (closes the widget)
|
||||
mjs_set(mjs, widget_obj, "close", ~0, MJS_MK_FN(js_widget_close));
|
||||
|
||||
widget->view = view_alloc();
|
||||
view_allocate_model(widget->view, ViewModelTypeLockFree, sizeof(WidgetModel));
|
||||
view_set_draw_callback(widget->view, widget_draw_callback);
|
||||
with_view_model(
|
||||
widget->view,
|
||||
WidgetModel * model,
|
||||
{
|
||||
ComponentArray_init(model->component);
|
||||
XbmImageList_init(model->image);
|
||||
model->max_assigned_id = 0;
|
||||
},
|
||||
true);
|
||||
|
||||
Gui* gui = furi_record_open(RECORD_GUI);
|
||||
widget->view_holder = view_holder_alloc();
|
||||
view_holder_attach_to_gui(widget->view_holder, gui);
|
||||
view_holder_set_back_callback(widget->view_holder, widget_exit, widget);
|
||||
view_holder_set_view(widget->view_holder, widget->view);
|
||||
|
||||
*object = widget_obj;
|
||||
return widget;
|
||||
}
|
||||
|
||||
static void js_widget_destroy(void* inst) {
|
||||
JsWidgetInst* widget = inst;
|
||||
if(widget->thread) {
|
||||
view_dispatcher_stop(widget->view_dispatcher);
|
||||
widget_deinit(widget);
|
||||
|
||||
view_holder_stop(widget->view_holder);
|
||||
view_holder_free(widget->view_holder);
|
||||
widget->view_holder = NULL;
|
||||
|
||||
furi_record_close(RECORD_GUI);
|
||||
|
||||
with_view_model(
|
||||
widget->view,
|
||||
WidgetModel * model,
|
||||
{
|
||||
ComponentArray_it_t it;
|
||||
ComponentArray_it(it, model->component);
|
||||
while(!ComponentArray_end_p(it)) {
|
||||
WidgetComponent* component = *ComponentArray_ref(it);
|
||||
if(component && component->free) {
|
||||
component->free(component);
|
||||
}
|
||||
widget_remove_view(widget);
|
||||
ComponentArray_next(it);
|
||||
}
|
||||
ComponentArray_reset(model->component);
|
||||
ComponentArray_clear(model->component);
|
||||
XbmImageList_clear(model->image);
|
||||
},
|
||||
false);
|
||||
view_free(widget->view);
|
||||
widget->view = NULL;
|
||||
|
||||
free(widget);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue