mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-13 13:09:49 +04:00
Various fixes
fixes by Willy-JL nfc parser by zacharyweiss js widget and path globals by jamisonderek
This commit is contained in:
@@ -128,6 +128,15 @@ App(
|
|||||||
sources=["plugins/supported_cards/metromoney.c"],
|
sources=["plugins/supported_cards/metromoney.c"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
App(
|
||||||
|
appid="charliecard_parser",
|
||||||
|
apptype=FlipperAppType.PLUGIN,
|
||||||
|
entry_point="charliecard_plugin_ep",
|
||||||
|
targets=["f7"],
|
||||||
|
requires=["nfc"],
|
||||||
|
sources=["plugins/supported_cards/charliecard.c"],
|
||||||
|
)
|
||||||
|
|
||||||
App(
|
App(
|
||||||
appid="kazan_parser",
|
appid="kazan_parser",
|
||||||
apptype=FlipperAppType.PLUGIN,
|
apptype=FlipperAppType.PLUGIN,
|
||||||
|
|||||||
1059
applications/main/nfc/plugins/supported_cards/charliecard.c
Normal file
1059
applications/main/nfc/plugins/supported_cards/charliecard.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -33,8 +33,10 @@ static void desktop_loader_callback(const void* message, void* context) {
|
|||||||
const LoaderEvent* event = message;
|
const LoaderEvent* event = message;
|
||||||
|
|
||||||
if(event->type == LoaderEventTypeApplicationStarted) {
|
if(event->type == LoaderEventTypeApplicationStarted) {
|
||||||
|
desktop->animation_lock = api_lock_alloc_locked();
|
||||||
view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopGlobalBeforeAppStarted);
|
view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopGlobalBeforeAppStarted);
|
||||||
furi_check(furi_semaphore_acquire(desktop->animation_semaphore, 3000) == FuriStatusOk);
|
api_lock_wait_unlock_and_free(desktop->animation_lock);
|
||||||
|
desktop->animation_lock = NULL;
|
||||||
} else if(event->type == LoaderEventTypeApplicationStopped) {
|
} else if(event->type == LoaderEventTypeApplicationStopped) {
|
||||||
view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopGlobalAfterAppFinished);
|
view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopGlobalAfterAppFinished);
|
||||||
}
|
}
|
||||||
@@ -126,7 +128,7 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) {
|
|||||||
animation_manager_unload_and_stall_animation(desktop->animation_manager);
|
animation_manager_unload_and_stall_animation(desktop->animation_manager);
|
||||||
}
|
}
|
||||||
desktop_auto_lock_inhibit(desktop);
|
desktop_auto_lock_inhibit(desktop);
|
||||||
furi_semaphore_release(desktop->animation_semaphore);
|
api_lock_unlock(desktop->animation_lock);
|
||||||
return true;
|
return true;
|
||||||
case DesktopGlobalAfterAppFinished:
|
case DesktopGlobalAfterAppFinished:
|
||||||
animation_manager_load_and_continue_animation(desktop->animation_manager);
|
animation_manager_load_and_continue_animation(desktop->animation_manager);
|
||||||
@@ -276,7 +278,6 @@ void desktop_set_stealth_mode_state(Desktop* desktop, bool enabled) {
|
|||||||
Desktop* desktop_alloc(void) {
|
Desktop* desktop_alloc(void) {
|
||||||
Desktop* desktop = malloc(sizeof(Desktop));
|
Desktop* desktop = malloc(sizeof(Desktop));
|
||||||
|
|
||||||
desktop->animation_semaphore = furi_semaphore_alloc(1, 0);
|
|
||||||
desktop->animation_manager = animation_manager_alloc();
|
desktop->animation_manager = animation_manager_alloc();
|
||||||
desktop->gui = furi_record_open(RECORD_GUI);
|
desktop->gui = furi_record_open(RECORD_GUI);
|
||||||
desktop->scene_thread = furi_thread_alloc();
|
desktop->scene_thread = furi_thread_alloc();
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include <loader/loader.h>
|
#include <loader/loader.h>
|
||||||
#include <notification/notification_app.h>
|
#include <notification/notification_app.h>
|
||||||
|
#include <toolbox/api_lock.h>
|
||||||
|
|
||||||
#define STATUS_BAR_Y_SHIFT 13
|
#define STATUS_BAR_Y_SHIFT 13
|
||||||
|
|
||||||
@@ -81,7 +82,7 @@ struct Desktop {
|
|||||||
|
|
||||||
bool in_transition : 1;
|
bool in_transition : 1;
|
||||||
|
|
||||||
FuriSemaphore* animation_semaphore;
|
FuriApiLock animation_lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
Desktop* desktop_alloc(void);
|
Desktop* desktop_alloc(void);
|
||||||
|
|||||||
@@ -109,3 +109,11 @@ App(
|
|||||||
requires=["js_app"],
|
requires=["js_app"],
|
||||||
sources=["modules/js_textbox.c"],
|
sources=["modules/js_textbox.c"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
App(
|
||||||
|
appid="js_widget",
|
||||||
|
apptype=FlipperAppType.PLUGIN,
|
||||||
|
entry_point="js_widget_ep",
|
||||||
|
requires=["js_app"],
|
||||||
|
sources=["modules/js_widget.c"],
|
||||||
|
)
|
||||||
|
|||||||
9
applications/system/js_app/examples/apps/Scripts/path.js
Normal file
9
applications/system/js_app/examples/apps/Scripts/path.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
let storage = require("storage");
|
||||||
|
|
||||||
|
print("script has __dirpath of" + __dirpath);
|
||||||
|
print("script has __filepath of" + __filepath);
|
||||||
|
if (storage.exists(__dirpath + "/math.js")) {
|
||||||
|
print("math.js exist here.");
|
||||||
|
} else {
|
||||||
|
print("math.js does not exist here.");
|
||||||
|
}
|
||||||
BIN
applications/system/js_app/examples/apps/Scripts/widget-js.fxbm
Normal file
BIN
applications/system/js_app/examples/apps/Scripts/widget-js.fxbm
Normal file
Binary file not shown.
59
applications/system/js_app/examples/apps/Scripts/widget.js
Normal file
59
applications/system/js_app/examples/apps/Scripts/widget.js
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
let widget = require("widget");
|
||||||
|
|
||||||
|
let demo_seconds = 30;
|
||||||
|
|
||||||
|
print("Loading file", __filepath);
|
||||||
|
print("From directory", __dirpath);
|
||||||
|
|
||||||
|
// addText supports "Primary" and "Secondary" font sizes.
|
||||||
|
widget.addText(10, 10, "Primary", "Example JS widget");
|
||||||
|
widget.addText(10, 20, "Secondary", "Example widget from JS!");
|
||||||
|
|
||||||
|
// load a Xbm file from the same directory as this script.
|
||||||
|
widget.addText(0, 30, "Secondary", __filepath);
|
||||||
|
let logo = widget.loadImageXbm(__dirpath + "/widget-js.fxbm");
|
||||||
|
|
||||||
|
// add a line (x1, y1, x2, y2)
|
||||||
|
widget.addLine(10, 35, 120, 35);
|
||||||
|
|
||||||
|
// add a circle/disc (x, y, radius)
|
||||||
|
widget.addCircle(12, 52, 10);
|
||||||
|
widget.addDisc(12, 52, 5);
|
||||||
|
|
||||||
|
// add a frame/box (x, y, width, height)
|
||||||
|
widget.addFrame(30, 45, 10, 10);
|
||||||
|
widget.addBox(32, 47, 6, 6);
|
||||||
|
|
||||||
|
// add a rounded frame/box (x, y, width, height, radius)
|
||||||
|
widget.addRframe(50, 45, 15, 15, 3);
|
||||||
|
widget.addRbox(53, 48, 6, 6, 2);
|
||||||
|
|
||||||
|
// add a dot (x, y)
|
||||||
|
widget.addDot(100, 45);
|
||||||
|
widget.addDot(102, 44);
|
||||||
|
widget.addDot(104, 43);
|
||||||
|
|
||||||
|
// add a glyph (x, y, glyph)
|
||||||
|
widget.addGlyph(115, 50, "#".charCodeAt(0));
|
||||||
|
|
||||||
|
// Show the widget (drawing the layers in the orderer they were added)
|
||||||
|
widget.show();
|
||||||
|
|
||||||
|
let i = 1;
|
||||||
|
let bitmap = undefined;
|
||||||
|
while (widget.isOpen() && i <= demo_seconds) {
|
||||||
|
// Print statements will only show up once the widget is closed.
|
||||||
|
print("count is at", i++);
|
||||||
|
|
||||||
|
// You can call remove on any added item, it does not impact the other ids.
|
||||||
|
if (bitmap) { widget.remove(bitmap); bitmap = undefined; }
|
||||||
|
// All of the addXXX functions return an id that can be used to remove the item.
|
||||||
|
else { bitmap = widget.addXbm(77, 45, logo); }
|
||||||
|
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If user did not press the back button, close the widget.
|
||||||
|
if (widget.isOpen()) {
|
||||||
|
widget.close();
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
#include <common/cs_dbg.h>
|
#include <common/cs_dbg.h>
|
||||||
|
#include <toolbox/path.h>
|
||||||
#include <toolbox/stream/file_stream.h>
|
#include <toolbox/stream/file_stream.h>
|
||||||
#include <loader/firmware_api/firmware_api.h>
|
#include <loader/firmware_api/firmware_api.h>
|
||||||
#include <flipper_application/api_hashtable/api_hashtable.h>
|
#include <flipper_application/api_hashtable/api_hashtable.h>
|
||||||
@@ -319,6 +320,24 @@ static int32_t js_thread(void* arg) {
|
|||||||
struct mjs* mjs = mjs_create(worker);
|
struct mjs* mjs = mjs_create(worker);
|
||||||
worker->modules = js_modules_create(mjs, worker->resolver);
|
worker->modules = js_modules_create(mjs, worker->resolver);
|
||||||
mjs_val_t global = mjs_get_global(mjs);
|
mjs_val_t global = mjs_get_global(mjs);
|
||||||
|
if(worker->path) {
|
||||||
|
FuriString* dirpath = furi_string_alloc();
|
||||||
|
path_extract_dirname(furi_string_get_cstr(worker->path), dirpath);
|
||||||
|
mjs_set(
|
||||||
|
mjs,
|
||||||
|
global,
|
||||||
|
"__filepath",
|
||||||
|
~0,
|
||||||
|
mjs_mk_string(
|
||||||
|
mjs, furi_string_get_cstr(worker->path), furi_string_size(worker->path), true));
|
||||||
|
mjs_set(
|
||||||
|
mjs,
|
||||||
|
global,
|
||||||
|
"__dirpath",
|
||||||
|
~0,
|
||||||
|
mjs_mk_string(mjs, furi_string_get_cstr(dirpath), furi_string_size(dirpath), true));
|
||||||
|
furi_string_free(dirpath);
|
||||||
|
}
|
||||||
mjs_set(mjs, global, "print", ~0, MJS_MK_FN(js_print));
|
mjs_set(mjs, global, "print", ~0, MJS_MK_FN(js_print));
|
||||||
mjs_set(mjs, global, "delay", ~0, MJS_MK_FN(js_delay));
|
mjs_set(mjs, global, "delay", ~0, MJS_MK_FN(js_delay));
|
||||||
mjs_set(mjs, global, "to_string", ~0, MJS_MK_FN(js_global_to_string));
|
mjs_set(mjs, global, "to_string", ~0, MJS_MK_FN(js_global_to_string));
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ void js_math_random(struct mjs* mjs) {
|
|||||||
mjs_return(mjs, MJS_UNDEFINED);
|
mjs_return(mjs, MJS_UNDEFINED);
|
||||||
}
|
}
|
||||||
const uint32_t random_val = furi_hal_random_get();
|
const uint32_t random_val = furi_hal_random_get();
|
||||||
double rnd = (double)random_val / RAND_MAX;
|
double rnd = (double)random_val / FURI_HAL_RANDOM_MAX;
|
||||||
mjs_return(mjs, mjs_mk_number(mjs, rnd));
|
mjs_return(mjs, mjs_mk_number(mjs, rnd));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
956
applications/system/js_app/modules/js_widget.c
Normal file
956
applications/system/js_app/modules/js_widget.c
Normal file
@@ -0,0 +1,956 @@
|
|||||||
|
#include <assets_icons.h>
|
||||||
|
#include <gui/view_dispatcher.h>
|
||||||
|
#include <gui/view.h>
|
||||||
|
#include <m-array.h>
|
||||||
|
#include <m-list.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "../js_modules.h"
|
||||||
|
|
||||||
|
typedef struct WidgetComponent WidgetComponent;
|
||||||
|
ARRAY_DEF(ComponentArray, WidgetComponent*, M_PTR_OPLIST);
|
||||||
|
|
||||||
|
typedef struct XbmImage XbmImage;
|
||||||
|
LIST_DEF(XbmImageList, XbmImage*, M_POD_OPLIST);
|
||||||
|
|
||||||
|
struct WidgetComponent {
|
||||||
|
void (*draw)(Canvas* canvas, void* model);
|
||||||
|
void (*free)(WidgetComponent* component);
|
||||||
|
void* model;
|
||||||
|
uint32_t id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct XbmImage {
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
|
uint8_t data[];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t x;
|
||||||
|
uint8_t y;
|
||||||
|
uint8_t w;
|
||||||
|
uint8_t h;
|
||||||
|
} BoxElement;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t x;
|
||||||
|
uint8_t y;
|
||||||
|
uint8_t r;
|
||||||
|
} CircleElement;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t x;
|
||||||
|
uint8_t y;
|
||||||
|
uint8_t r;
|
||||||
|
} DiscElement;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t x;
|
||||||
|
uint8_t y;
|
||||||
|
} DotElement;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t x;
|
||||||
|
uint8_t y;
|
||||||
|
const Icon* icon;
|
||||||
|
} IconElement;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t x;
|
||||||
|
uint8_t y;
|
||||||
|
uint8_t w;
|
||||||
|
uint8_t h;
|
||||||
|
} FrameElement;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t x;
|
||||||
|
uint8_t y;
|
||||||
|
uint16_t ch;
|
||||||
|
} GlyphElement;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t x1;
|
||||||
|
uint8_t y1;
|
||||||
|
uint8_t x2;
|
||||||
|
uint8_t y2;
|
||||||
|
} LineElement;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t x;
|
||||||
|
uint8_t y;
|
||||||
|
uint8_t w;
|
||||||
|
uint8_t h;
|
||||||
|
uint8_t r;
|
||||||
|
} RboxElement;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t x;
|
||||||
|
uint8_t y;
|
||||||
|
uint8_t w;
|
||||||
|
uint8_t h;
|
||||||
|
uint8_t r;
|
||||||
|
} RframeElement;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t x;
|
||||||
|
uint8_t y;
|
||||||
|
Font font;
|
||||||
|
FuriString* text;
|
||||||
|
} TextElement;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t x;
|
||||||
|
uint8_t y;
|
||||||
|
uint32_t index;
|
||||||
|
View* view;
|
||||||
|
} XbmElement;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ComponentArray_t component;
|
||||||
|
XbmImageList_t image;
|
||||||
|
uint32_t max_assigned_id;
|
||||||
|
} WidgetModel;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
View* view;
|
||||||
|
ViewDispatcher* view_dispatcher;
|
||||||
|
FuriThread* thread;
|
||||||
|
} JsWidgetInst;
|
||||||
|
|
||||||
|
static JsWidgetInst* get_this_ctx(struct mjs* mjs) {
|
||||||
|
mjs_val_t obj_inst = mjs_get(mjs, mjs_get_this(mjs), INST_PROP_NAME, ~0);
|
||||||
|
JsWidgetInst* widget = mjs_get_ptr(mjs, obj_inst);
|
||||||
|
furi_assert(widget);
|
||||||
|
return widget;
|
||||||
|
}
|
||||||
|
|
||||||
|
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_widget_load_image_xbm(struct mjs* mjs) {
|
||||||
|
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||||
|
if(!check_arg_count(mjs, 1)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mjs_val_t path_arg = mjs_arg(mjs, 0);
|
||||||
|
size_t path_len = 0;
|
||||||
|
const char* path = mjs_get_string(mjs, &path_arg, &path_len);
|
||||||
|
if(!path) {
|
||||||
|
ret_bad_args(mjs, "Path must be a string");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||||
|
File* file = storage_file_alloc(storage);
|
||||||
|
XbmImage* xbm = NULL;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(!storage_file_open(file, path, FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||||
|
ret_bad_args(mjs, "Failed to open file");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t size = 0;
|
||||||
|
if(storage_file_read(file, &size, sizeof(size)) != sizeof(size)) {
|
||||||
|
ret_bad_args(mjs, "Failed to get file size");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
xbm = malloc(size);
|
||||||
|
if(storage_file_read(file, xbm, size) != size) {
|
||||||
|
ret_bad_args(mjs, "Failed to load entire file");
|
||||||
|
free(xbm);
|
||||||
|
xbm = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
storage_file_free(file);
|
||||||
|
furi_record_close(RECORD_STORAGE);
|
||||||
|
|
||||||
|
if(xbm == NULL) {
|
||||||
|
mjs_return(mjs, MJS_UNDEFINED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count = 0;
|
||||||
|
with_view_model(
|
||||||
|
widget->view,
|
||||||
|
WidgetModel * model,
|
||||||
|
{
|
||||||
|
count = XbmImageList_size(model->image);
|
||||||
|
XbmImageList_push_back(model->image, xbm);
|
||||||
|
},
|
||||||
|
false);
|
||||||
|
|
||||||
|
mjs_return(mjs, mjs_mk_number(mjs, count));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void js_widget_remove(struct mjs* mjs) {
|
||||||
|
bool removed = false;
|
||||||
|
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||||
|
if(!check_arg_count(mjs, 1)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
widget->view,
|
||||||
|
WidgetModel * model,
|
||||||
|
{
|
||||||
|
uint32_t id = mjs_get_int32(mjs, mjs_arg(mjs, 0));
|
||||||
|
ComponentArray_it_t it;
|
||||||
|
ComponentArray_it(it, model->component);
|
||||||
|
while(!ComponentArray_end_p(it)) {
|
||||||
|
WidgetComponent* component = *ComponentArray_ref(it);
|
||||||
|
if(component->id == id) {
|
||||||
|
if(component->free) {
|
||||||
|
component->free(component);
|
||||||
|
}
|
||||||
|
ComponentArray_remove(model->component, it);
|
||||||
|
removed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ComponentArray_next(it);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
|
||||||
|
mjs_return(mjs, mjs_mk_boolean(mjs, removed));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void widget_box_draw(Canvas* canvas, void* model) {
|
||||||
|
BoxElement* element = model;
|
||||||
|
canvas_draw_box(canvas, element->x, element->y, element->w, element->h);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void widget_box_free(WidgetComponent* component) {
|
||||||
|
BoxElement* element = component->model;
|
||||||
|
free(element);
|
||||||
|
free(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void js_widget_add_box(struct mjs* mjs) {
|
||||||
|
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||||
|
if(!check_arg_count(mjs, 4)) return;
|
||||||
|
|
||||||
|
int32_t x = mjs_get_int32(mjs, mjs_arg(mjs, 0));
|
||||||
|
int32_t y = mjs_get_int32(mjs, mjs_arg(mjs, 1));
|
||||||
|
int32_t w = mjs_get_int32(mjs, mjs_arg(mjs, 2));
|
||||||
|
int32_t h = mjs_get_int32(mjs, mjs_arg(mjs, 3));
|
||||||
|
|
||||||
|
WidgetComponent* component = malloc(sizeof(WidgetComponent));
|
||||||
|
component->draw = widget_box_draw;
|
||||||
|
component->free = widget_box_free;
|
||||||
|
component->model = malloc(sizeof(BoxElement));
|
||||||
|
BoxElement* element = component->model;
|
||||||
|
element->x = x;
|
||||||
|
element->y = y;
|
||||||
|
element->w = w;
|
||||||
|
element->h = h;
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
widget->view,
|
||||||
|
WidgetModel * model,
|
||||||
|
{
|
||||||
|
++model->max_assigned_id;
|
||||||
|
component->id = model->max_assigned_id;
|
||||||
|
ComponentArray_push_back(model->component, component);
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
|
||||||
|
mjs_return(mjs, mjs_mk_number(mjs, component->id));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void widget_circle_draw(Canvas* canvas, void* model) {
|
||||||
|
CircleElement* element = model;
|
||||||
|
canvas_draw_circle(canvas, element->x, element->y, element->r);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void widget_circle_free(WidgetComponent* component) {
|
||||||
|
CircleElement* element = component->model;
|
||||||
|
free(element);
|
||||||
|
free(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void js_widget_add_circle(struct mjs* mjs) {
|
||||||
|
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||||
|
if(!check_arg_count(mjs, 3)) return;
|
||||||
|
|
||||||
|
int32_t x = mjs_get_int32(mjs, mjs_arg(mjs, 0));
|
||||||
|
int32_t y = mjs_get_int32(mjs, mjs_arg(mjs, 1));
|
||||||
|
int32_t r = mjs_get_int32(mjs, mjs_arg(mjs, 2));
|
||||||
|
|
||||||
|
WidgetComponent* component = malloc(sizeof(WidgetComponent));
|
||||||
|
component->draw = widget_circle_draw;
|
||||||
|
component->free = widget_circle_free;
|
||||||
|
component->model = malloc(sizeof(CircleElement));
|
||||||
|
CircleElement* element = component->model;
|
||||||
|
element->x = x;
|
||||||
|
element->y = y;
|
||||||
|
element->r = r;
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
widget->view,
|
||||||
|
WidgetModel * model,
|
||||||
|
{
|
||||||
|
++model->max_assigned_id;
|
||||||
|
component->id = model->max_assigned_id;
|
||||||
|
ComponentArray_push_back(model->component, component);
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
|
||||||
|
mjs_return(mjs, mjs_mk_number(mjs, component->id));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void widget_disc_draw(Canvas* canvas, void* model) {
|
||||||
|
DiscElement* element = model;
|
||||||
|
canvas_draw_disc(canvas, element->x, element->y, element->r);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void widget_disc_free(WidgetComponent* component) {
|
||||||
|
DiscElement* element = component->model;
|
||||||
|
free(element);
|
||||||
|
free(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void js_widget_add_disc(struct mjs* mjs) {
|
||||||
|
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||||
|
if(!check_arg_count(mjs, 3)) return;
|
||||||
|
|
||||||
|
int32_t x = mjs_get_int32(mjs, mjs_arg(mjs, 0));
|
||||||
|
int32_t y = mjs_get_int32(mjs, mjs_arg(mjs, 1));
|
||||||
|
int32_t r = mjs_get_int32(mjs, mjs_arg(mjs, 2));
|
||||||
|
|
||||||
|
WidgetComponent* component = malloc(sizeof(WidgetComponent));
|
||||||
|
component->draw = widget_disc_draw;
|
||||||
|
component->free = widget_disc_free;
|
||||||
|
component->model = malloc(sizeof(DiscElement));
|
||||||
|
DiscElement* element = component->model;
|
||||||
|
element->x = x;
|
||||||
|
element->y = y;
|
||||||
|
element->r = r;
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
widget->view,
|
||||||
|
WidgetModel * model,
|
||||||
|
{
|
||||||
|
++model->max_assigned_id;
|
||||||
|
component->id = model->max_assigned_id;
|
||||||
|
ComponentArray_push_back(model->component, component);
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
|
||||||
|
mjs_return(mjs, mjs_mk_number(mjs, component->id));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void widget_dot_draw(Canvas* canvas, void* model) {
|
||||||
|
DotElement* element = model;
|
||||||
|
canvas_draw_dot(canvas, element->x, element->y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void widget_dot_free(WidgetComponent* component) {
|
||||||
|
DotElement* element = component->model;
|
||||||
|
free(element);
|
||||||
|
free(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void js_widget_add_dot(struct mjs* mjs) {
|
||||||
|
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||||
|
if(!check_arg_count(mjs, 2)) return;
|
||||||
|
|
||||||
|
int32_t x = mjs_get_int32(mjs, mjs_arg(mjs, 0));
|
||||||
|
int32_t y = mjs_get_int32(mjs, mjs_arg(mjs, 1));
|
||||||
|
|
||||||
|
WidgetComponent* component = malloc(sizeof(WidgetComponent));
|
||||||
|
component->draw = widget_dot_draw;
|
||||||
|
component->free = widget_dot_free;
|
||||||
|
component->model = malloc(sizeof(DotElement));
|
||||||
|
DotElement* element = component->model;
|
||||||
|
element->x = x;
|
||||||
|
element->y = y;
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
widget->view,
|
||||||
|
WidgetModel * model,
|
||||||
|
{
|
||||||
|
++model->max_assigned_id;
|
||||||
|
component->id = model->max_assigned_id;
|
||||||
|
ComponentArray_push_back(model->component, component);
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
|
||||||
|
mjs_return(mjs, mjs_mk_number(mjs, component->id));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void widget_frame_draw(Canvas* canvas, void* model) {
|
||||||
|
FrameElement* element = model;
|
||||||
|
canvas_draw_frame(canvas, element->x, element->y, element->w, element->h);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void widget_frame_free(WidgetComponent* component) {
|
||||||
|
FrameElement* element = component->model;
|
||||||
|
free(element);
|
||||||
|
free(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void js_widget_add_frame(struct mjs* mjs) {
|
||||||
|
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||||
|
if(!check_arg_count(mjs, 4)) return;
|
||||||
|
|
||||||
|
int32_t x = mjs_get_int32(mjs, mjs_arg(mjs, 0));
|
||||||
|
int32_t y = mjs_get_int32(mjs, mjs_arg(mjs, 1));
|
||||||
|
int32_t w = mjs_get_int32(mjs, mjs_arg(mjs, 2));
|
||||||
|
int32_t h = mjs_get_int32(mjs, mjs_arg(mjs, 3));
|
||||||
|
|
||||||
|
WidgetComponent* component = malloc(sizeof(WidgetComponent));
|
||||||
|
component->draw = widget_frame_draw;
|
||||||
|
component->free = widget_frame_free;
|
||||||
|
component->model = malloc(sizeof(FrameElement));
|
||||||
|
FrameElement* element = component->model;
|
||||||
|
element->x = x;
|
||||||
|
element->y = y;
|
||||||
|
element->w = w;
|
||||||
|
element->h = h;
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
widget->view,
|
||||||
|
WidgetModel * model,
|
||||||
|
{
|
||||||
|
++model->max_assigned_id;
|
||||||
|
component->id = model->max_assigned_id;
|
||||||
|
ComponentArray_push_back(model->component, component);
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
|
||||||
|
mjs_return(mjs, mjs_mk_number(mjs, component->id));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void widget_glyph_draw(Canvas* canvas, void* model) {
|
||||||
|
GlyphElement* element = model;
|
||||||
|
canvas_draw_glyph(canvas, element->x, element->y, element->ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void widget_glyph_free(WidgetComponent* component) {
|
||||||
|
GlyphElement* element = component->model;
|
||||||
|
free(element);
|
||||||
|
free(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void js_widget_add_glyph(struct mjs* mjs) {
|
||||||
|
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||||
|
if(!check_arg_count(mjs, 3)) return;
|
||||||
|
|
||||||
|
int32_t x = mjs_get_int32(mjs, mjs_arg(mjs, 0));
|
||||||
|
int32_t y = mjs_get_int32(mjs, mjs_arg(mjs, 1));
|
||||||
|
int32_t ch = mjs_get_int32(mjs, mjs_arg(mjs, 2));
|
||||||
|
|
||||||
|
WidgetComponent* component = malloc(sizeof(WidgetComponent));
|
||||||
|
component->draw = widget_glyph_draw;
|
||||||
|
component->free = widget_glyph_free;
|
||||||
|
component->model = malloc(sizeof(GlyphElement));
|
||||||
|
GlyphElement* element = component->model;
|
||||||
|
element->x = x;
|
||||||
|
element->y = y;
|
||||||
|
element->ch = ch;
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
widget->view,
|
||||||
|
WidgetModel * model,
|
||||||
|
{
|
||||||
|
++model->max_assigned_id;
|
||||||
|
component->id = model->max_assigned_id;
|
||||||
|
ComponentArray_push_back(model->component, component);
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
|
||||||
|
mjs_return(mjs, mjs_mk_number(mjs, component->id));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void widget_line_draw(Canvas* canvas, void* model) {
|
||||||
|
LineElement* element = model;
|
||||||
|
canvas_draw_line(canvas, element->x1, element->y1, element->x2, element->y2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void widget_line_free(WidgetComponent* component) {
|
||||||
|
LineElement* element = component->model;
|
||||||
|
free(element);
|
||||||
|
free(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void js_widget_add_line(struct mjs* mjs) {
|
||||||
|
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||||
|
if(!check_arg_count(mjs, 4)) return;
|
||||||
|
|
||||||
|
int32_t x1 = mjs_get_int32(mjs, mjs_arg(mjs, 0));
|
||||||
|
int32_t y1 = mjs_get_int32(mjs, mjs_arg(mjs, 1));
|
||||||
|
int32_t x2 = mjs_get_int32(mjs, mjs_arg(mjs, 2));
|
||||||
|
int32_t y2 = mjs_get_int32(mjs, mjs_arg(mjs, 3));
|
||||||
|
|
||||||
|
WidgetComponent* component = malloc(sizeof(WidgetComponent));
|
||||||
|
component->draw = widget_line_draw;
|
||||||
|
component->free = widget_line_free;
|
||||||
|
component->model = malloc(sizeof(LineElement));
|
||||||
|
LineElement* element = component->model;
|
||||||
|
element->x1 = x1;
|
||||||
|
element->y1 = y1;
|
||||||
|
element->x2 = x2;
|
||||||
|
element->y2 = y2;
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
widget->view,
|
||||||
|
WidgetModel * model,
|
||||||
|
{
|
||||||
|
++model->max_assigned_id;
|
||||||
|
component->id = model->max_assigned_id;
|
||||||
|
ComponentArray_push_back(model->component, component);
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
|
||||||
|
mjs_return(mjs, mjs_mk_number(mjs, component->id));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void widget_rbox_draw(Canvas* canvas, void* model) {
|
||||||
|
RboxElement* element = model;
|
||||||
|
canvas_draw_rbox(canvas, element->x, element->y, element->w, element->h, element->r);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void widget_rbox_free(WidgetComponent* component) {
|
||||||
|
BoxElement* element = component->model;
|
||||||
|
free(element);
|
||||||
|
free(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void js_widget_add_rbox(struct mjs* mjs) {
|
||||||
|
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||||
|
if(!check_arg_count(mjs, 5)) return;
|
||||||
|
|
||||||
|
int32_t x = mjs_get_int32(mjs, mjs_arg(mjs, 0));
|
||||||
|
int32_t y = mjs_get_int32(mjs, mjs_arg(mjs, 1));
|
||||||
|
int32_t w = mjs_get_int32(mjs, mjs_arg(mjs, 2));
|
||||||
|
int32_t h = mjs_get_int32(mjs, mjs_arg(mjs, 3));
|
||||||
|
int32_t r = mjs_get_int32(mjs, mjs_arg(mjs, 4));
|
||||||
|
|
||||||
|
WidgetComponent* component = malloc(sizeof(WidgetComponent));
|
||||||
|
component->draw = widget_rbox_draw;
|
||||||
|
component->free = widget_rbox_free;
|
||||||
|
component->model = malloc(sizeof(RboxElement));
|
||||||
|
RboxElement* element = component->model;
|
||||||
|
element->x = x;
|
||||||
|
element->y = y;
|
||||||
|
element->w = w;
|
||||||
|
element->h = h;
|
||||||
|
element->r = r;
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
widget->view,
|
||||||
|
WidgetModel * model,
|
||||||
|
{
|
||||||
|
++model->max_assigned_id;
|
||||||
|
component->id = model->max_assigned_id;
|
||||||
|
ComponentArray_push_back(model->component, component);
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
|
||||||
|
mjs_return(mjs, mjs_mk_number(mjs, component->id));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void widget_rframe_draw(Canvas* canvas, void* model) {
|
||||||
|
RframeElement* element = model;
|
||||||
|
canvas_draw_rframe(canvas, element->x, element->y, element->w, element->h, element->r);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void widget_rframe_free(WidgetComponent* component) {
|
||||||
|
RframeElement* element = component->model;
|
||||||
|
free(element);
|
||||||
|
free(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void js_widget_add_rframe(struct mjs* mjs) {
|
||||||
|
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||||
|
if(!check_arg_count(mjs, 5)) return;
|
||||||
|
|
||||||
|
int32_t x = mjs_get_int32(mjs, mjs_arg(mjs, 0));
|
||||||
|
int32_t y = mjs_get_int32(mjs, mjs_arg(mjs, 1));
|
||||||
|
int32_t w = mjs_get_int32(mjs, mjs_arg(mjs, 2));
|
||||||
|
int32_t h = mjs_get_int32(mjs, mjs_arg(mjs, 3));
|
||||||
|
int32_t r = mjs_get_int32(mjs, mjs_arg(mjs, 4));
|
||||||
|
|
||||||
|
WidgetComponent* component = malloc(sizeof(WidgetComponent));
|
||||||
|
component->draw = widget_rframe_draw;
|
||||||
|
component->free = widget_rframe_free;
|
||||||
|
component->model = malloc(sizeof(RframeElement));
|
||||||
|
RframeElement* element = component->model;
|
||||||
|
element->x = x;
|
||||||
|
element->y = y;
|
||||||
|
element->w = w;
|
||||||
|
element->h = h;
|
||||||
|
element->r = r;
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
widget->view,
|
||||||
|
WidgetModel * model,
|
||||||
|
{
|
||||||
|
++model->max_assigned_id;
|
||||||
|
component->id = model->max_assigned_id;
|
||||||
|
ComponentArray_push_back(model->component, component);
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
|
||||||
|
mjs_return(mjs, mjs_mk_number(mjs, component->id));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void widget_text_draw(Canvas* canvas, void* model) {
|
||||||
|
TextElement* element = model;
|
||||||
|
canvas_set_font(canvas, element->font);
|
||||||
|
canvas_draw_str(canvas, element->x, element->y, furi_string_get_cstr(element->text));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void widget_text_free(WidgetComponent* component) {
|
||||||
|
TextElement* element = component->model;
|
||||||
|
furi_string_free(element->text);
|
||||||
|
free(element);
|
||||||
|
free(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void js_widget_add_text(struct mjs* mjs) {
|
||||||
|
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||||
|
if(!check_arg_count(mjs, 4)) return;
|
||||||
|
|
||||||
|
int32_t x = mjs_get_int32(mjs, mjs_arg(mjs, 0));
|
||||||
|
int32_t y = mjs_get_int32(mjs, mjs_arg(mjs, 1));
|
||||||
|
|
||||||
|
mjs_val_t font_arg = mjs_arg(mjs, 2);
|
||||||
|
size_t font_name_len = 0;
|
||||||
|
const char* font_name_text = mjs_get_string(mjs, &font_arg, &font_name_len);
|
||||||
|
if(!font_name_text) {
|
||||||
|
ret_bad_args(mjs, "Font name must be a string");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Font font = FontTotalNumber;
|
||||||
|
size_t cmp_str_len = strlen("Primary");
|
||||||
|
if(font_name_len == cmp_str_len && strncmp(font_name_text, "Primary", cmp_str_len) == 0) {
|
||||||
|
font = FontPrimary;
|
||||||
|
} else {
|
||||||
|
cmp_str_len = strlen("Secondary");
|
||||||
|
if(font_name_len == cmp_str_len &&
|
||||||
|
strncmp(font_name_text, "Secondary", cmp_str_len) == 0) {
|
||||||
|
font = FontSecondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(font == FontTotalNumber) {
|
||||||
|
ret_bad_args(mjs, "Unknown font name");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mjs_val_t text_arg = mjs_arg(mjs, 3);
|
||||||
|
size_t text_len = 0;
|
||||||
|
const char* text = mjs_get_string(mjs, &text_arg, &text_len);
|
||||||
|
if(!text) {
|
||||||
|
ret_bad_args(mjs, "Text must be a string");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FuriString* text_str = furi_string_alloc_set(text);
|
||||||
|
|
||||||
|
WidgetComponent* component = malloc(sizeof(WidgetComponent));
|
||||||
|
component->draw = widget_text_draw;
|
||||||
|
component->free = widget_text_free;
|
||||||
|
component->model = malloc(sizeof(TextElement));
|
||||||
|
TextElement* element = component->model;
|
||||||
|
element->x = x;
|
||||||
|
element->y = y;
|
||||||
|
element->font = font;
|
||||||
|
element->text = text_str;
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
widget->view,
|
||||||
|
WidgetModel * model,
|
||||||
|
{
|
||||||
|
++model->max_assigned_id;
|
||||||
|
component->id = model->max_assigned_id;
|
||||||
|
ComponentArray_push_back(model->component, component);
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
|
||||||
|
mjs_return(mjs, mjs_mk_number(mjs, component->id));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void widget_xbm_draw(Canvas* canvas, void* model) {
|
||||||
|
XbmElement* element = model;
|
||||||
|
XbmImage* image = NULL;
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
element->view,
|
||||||
|
WidgetModel * widget_model,
|
||||||
|
{ image = *XbmImageList_get(widget_model->image, element->index); },
|
||||||
|
false);
|
||||||
|
|
||||||
|
if(image) {
|
||||||
|
canvas_draw_xbm(canvas, element->x, element->y, image->width, image->height, image->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void widget_xbm_free(WidgetComponent* component) {
|
||||||
|
XbmElement* element = component->model;
|
||||||
|
free(element);
|
||||||
|
free(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void js_widget_add_xbm(struct mjs* mjs) {
|
||||||
|
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||||
|
if(!check_arg_count(mjs, 3)) return;
|
||||||
|
|
||||||
|
int32_t x = mjs_get_int32(mjs, mjs_arg(mjs, 0));
|
||||||
|
int32_t y = mjs_get_int32(mjs, mjs_arg(mjs, 1));
|
||||||
|
int32_t index = mjs_get_int32(mjs, mjs_arg(mjs, 2));
|
||||||
|
with_view_model(
|
||||||
|
widget->view,
|
||||||
|
WidgetModel * widget_model,
|
||||||
|
{
|
||||||
|
size_t count = XbmImageList_size(widget_model->image);
|
||||||
|
if(index < 0 || index >= (int32_t)count) {
|
||||||
|
ret_bad_args(mjs, "Invalid image index");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false);
|
||||||
|
|
||||||
|
WidgetComponent* component = malloc(sizeof(WidgetComponent));
|
||||||
|
component->draw = widget_xbm_draw;
|
||||||
|
component->free = widget_xbm_free;
|
||||||
|
component->model = malloc(sizeof(XbmElement));
|
||||||
|
XbmElement* element = component->model;
|
||||||
|
element->x = x;
|
||||||
|
element->y = y;
|
||||||
|
element->index = index;
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
widget->view,
|
||||||
|
WidgetModel * model,
|
||||||
|
{
|
||||||
|
++model->max_assigned_id;
|
||||||
|
component->id = model->max_assigned_id;
|
||||||
|
element->view = widget->view;
|
||||||
|
ComponentArray_push_back(model->component, component);
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
|
||||||
|
mjs_return(mjs, mjs_mk_number(mjs, component->id));
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t widget_thread(void* context) {
|
||||||
|
ViewDispatcher* view_dispatcher = context;
|
||||||
|
view_dispatcher_run(view_dispatcher);
|
||||||
|
return 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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
mjs_return(mjs, MJS_UNDEFINED);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
mjs_return(mjs, MJS_UNDEFINED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void widget_draw_callback(Canvas* canvas, void* model) {
|
||||||
|
WidgetModel* widget_model = model;
|
||||||
|
canvas_clear(canvas);
|
||||||
|
|
||||||
|
ComponentArray_it_t it;
|
||||||
|
ComponentArray_it(it, widget_model->component);
|
||||||
|
while(!ComponentArray_end_p(it)) {
|
||||||
|
WidgetComponent* component = *ComponentArray_ref(it);
|
||||||
|
if(component->draw != NULL) {
|
||||||
|
component->draw(canvas, component->model);
|
||||||
|
}
|
||||||
|
ComponentArray_next(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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->free) {
|
||||||
|
component->free(component);
|
||||||
|
component->free = NULL;
|
||||||
|
}
|
||||||
|
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();
|
||||||
|
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)
|
||||||
|
mjs_set(mjs, widget_obj, "addBox", ~0, MJS_MK_FN(js_widget_add_box));
|
||||||
|
// addCircle(x: number, y: number, r: number): number (returns id of the added component)
|
||||||
|
mjs_set(mjs, widget_obj, "addCircle", ~0, MJS_MK_FN(js_widget_add_circle));
|
||||||
|
// addDisc(x: number, y: number, r: number): number (returns id of the added component)
|
||||||
|
mjs_set(mjs, widget_obj, "addDisc", ~0, MJS_MK_FN(js_widget_add_disc));
|
||||||
|
// addDot(x: number, y: number): number (returns id of the added component)
|
||||||
|
mjs_set(mjs, widget_obj, "addDot", ~0, MJS_MK_FN(js_widget_add_dot));
|
||||||
|
// addFrame(x: number, y: number, w: number, h: number): number (returns id of the added component)
|
||||||
|
mjs_set(mjs, widget_obj, "addFrame", ~0, MJS_MK_FN(js_widget_add_frame));
|
||||||
|
// addGlyph(x: number, y: number, ch: number): number (returns id of the added component)
|
||||||
|
mjs_set(mjs, widget_obj, "addGlyph", ~0, MJS_MK_FN(js_widget_add_glyph));
|
||||||
|
// addLine(x1: number, y1: number, x2: number, y2: number): number (returns id of the added component)
|
||||||
|
mjs_set(mjs, widget_obj, "addLine", ~0, MJS_MK_FN(js_widget_add_line));
|
||||||
|
// addRbox(x: number, y: number, w: number, h: number, r: number): number (returns id of the added component)
|
||||||
|
mjs_set(mjs, widget_obj, "addRbox", ~0, MJS_MK_FN(js_widget_add_rbox));
|
||||||
|
// addRframe(x: number, y: number, w: number, h: number, r: number): number (returns id of the added component)
|
||||||
|
mjs_set(mjs, widget_obj, "addRframe", ~0, MJS_MK_FN(js_widget_add_rframe));
|
||||||
|
// addText(x: number, y: number, font: string, text: string): number (returns id of the added component)
|
||||||
|
mjs_set(mjs, widget_obj, "addText", ~0, MJS_MK_FN(js_widget_add_text));
|
||||||
|
// addXbm(x: number, y: number, index: number): number (returns id of the added component)
|
||||||
|
mjs_set(mjs, widget_obj, "addXbm", ~0, MJS_MK_FN(js_widget_add_xbm));
|
||||||
|
// loadImageXbm(path: string): number (returns index of the loaded image)
|
||||||
|
mjs_set(mjs, widget_obj, "loadImageXbm", ~0, MJS_MK_FN(js_widget_load_image_xbm));
|
||||||
|
// remove(id: number): boolean (returns true if the component was removed)
|
||||||
|
mjs_set(mjs, widget_obj, "remove", ~0, MJS_MK_FN(js_widget_remove));
|
||||||
|
// isOpen(): boolean (returns true if the widget is open)
|
||||||
|
mjs_set(mjs, widget_obj, "isOpen", ~0, MJS_MK_FN(js_widget_is_open));
|
||||||
|
// show(): void (shows the widget)
|
||||||
|
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));
|
||||||
|
*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);
|
||||||
|
}
|
||||||
|
widget_remove_view(widget);
|
||||||
|
free(widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const JsModuleDescriptor js_widget_desc = {
|
||||||
|
"widget",
|
||||||
|
js_widget_create,
|
||||||
|
js_widget_destroy,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const FlipperAppPluginDescriptor widget_plugin_descriptor = {
|
||||||
|
.appid = PLUGIN_APP_ID,
|
||||||
|
.ep_api_version = PLUGIN_API_VERSION,
|
||||||
|
.entry_point = &js_widget_desc,
|
||||||
|
};
|
||||||
|
|
||||||
|
const FlipperAppPluginDescriptor* js_widget_ep(void) {
|
||||||
|
return &widget_plugin_descriptor;
|
||||||
|
}
|
||||||
@@ -612,7 +612,7 @@ void infrared_worker_set_raw_signal(
|
|||||||
furi_check(timings);
|
furi_check(timings);
|
||||||
furi_check(timings_cnt > 0);
|
furi_check(timings_cnt > 0);
|
||||||
furi_check((frequency <= INFRARED_MAX_FREQUENCY) && (frequency >= INFRARED_MIN_FREQUENCY));
|
furi_check((frequency <= INFRARED_MAX_FREQUENCY) && (frequency >= INFRARED_MIN_FREQUENCY));
|
||||||
furi_check((duty_cycle < 1.0f) && (duty_cycle > 0.0f));
|
furi_check((duty_cycle <= 1.0f) && (duty_cycle > 0.0f));
|
||||||
|
|
||||||
size_t max_copy_num = COUNT_OF(instance->signal.raw.timings) - 1;
|
size_t max_copy_num = COUNT_OF(instance->signal.raw.timings) - 1;
|
||||||
furi_check(timings_cnt <= max_copy_num);
|
furi_check(timings_cnt <= max_copy_num);
|
||||||
|
|||||||
@@ -41,7 +41,11 @@
|
|||||||
> If for any reason this test is never passed, this means there is a failure in the system and there is no other
|
> If for any reason this test is never passed, this means there is a failure in the system and there is no other
|
||||||
> way to recover than applying a device reset.
|
> way to recover than applying a device reset.
|
||||||
*/
|
*/
|
||||||
#define FURI_HAL_FLASH_C2_LOCK_TIMEOUT_MS (3000U) /* 3 seconds */
|
// Was previously 3000U, 3 seconds
|
||||||
|
// Changing furi_assert() to furi_check() brought timeout crashes
|
||||||
|
// Internal storage is very slow, and "big" files will often cause a "timeout" with 3 seconds
|
||||||
|
// 10 seconds seems fine, the file operations complete successfully, albeit slowly
|
||||||
|
#define FURI_HAL_FLASH_C2_LOCK_TIMEOUT_MS (10000U) /* 10 seconds */
|
||||||
|
|
||||||
#define IS_ADDR_ALIGNED_64BITS(__VALUE__) (((__VALUE__) & 0x7U) == (0x00UL))
|
#define IS_ADDR_ALIGNED_64BITS(__VALUE__) (((__VALUE__) & 0x7U) == (0x00UL))
|
||||||
#define IS_FLASH_PROGRAM_ADDRESS(__VALUE__) \
|
#define IS_FLASH_PROGRAM_ADDRESS(__VALUE__) \
|
||||||
|
|||||||
@@ -6,12 +6,16 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define FURI_HAL_RANDOM_MAX 0xFFFFFFFF
|
||||||
|
|
||||||
/** Initialize random subsystem */
|
/** Initialize random subsystem */
|
||||||
void furi_hal_random_init(void);
|
void furi_hal_random_init(void);
|
||||||
|
|
||||||
/** Get random value
|
/** Get random value
|
||||||
|
* furi_hal_random_get() gives up to FURI_HAL_RANDOM_MAX
|
||||||
|
* rand() and random() give up to RAND_MAX
|
||||||
*
|
*
|
||||||
* @return random value
|
* @return 32 bit random value (up to FURI_HAL_RANDOM_MAX)
|
||||||
*/
|
*/
|
||||||
uint32_t furi_hal_random_get(void);
|
uint32_t furi_hal_random_get(void);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user