mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2024-11-27 06:50:21 +00:00
0154018363
* FBT: cdefines to env, libs order * API: strtod, modf, itoa, calloc * Apps: elk js * Apps: mjs * JS: scripts as assets * mjs: composite resolver * mjs: stack trace * ELK JS example removed * MJS thread, MJS lib modified to support script interruption * JS console UI * Module system, BadUSB bindings rework * JS notifications, simple dialog, BadUSB demo * Custom dialogs, dialog demo * MJS as system library, some dirty hacks to make it compile * Plugin-based js modules * js_uart(BadUART) module * js_uart: support for byte array arguments * Script icon and various fixes * File browser: multiple extensions filter, running js scripts from app loader * Running js scripts from archive browser * JS Runner as system app * Example scripts moved to /ext/apps/Scripts * JS bytecode listing generation * MJS builtin printf cleanup * JS examples cleanup * mbedtls version fix * Unused lib cleanup * Making PVS happy & TODOs cleanup * TODOs cleanup #2 * MJS: initial typed arrays support * JS: fix mem leak in uart destructor Co-authored-by: SG <who.just.the.doctor@gmail.com> Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
164 lines
No EOL
5.3 KiB
C
164 lines
No EOL
5.3 KiB
C
#include "../js_app_i.h"
|
|
#include "console_font.h"
|
|
|
|
#define CONSOLE_LINES 8
|
|
#define CONSOLE_CHAR_W 5
|
|
#define LINE_BREAKS_MAX 3
|
|
#define LINE_LEN_MAX (128 / CONSOLE_CHAR_W)
|
|
|
|
struct JsConsoleView {
|
|
View* view;
|
|
};
|
|
|
|
typedef struct {
|
|
FuriString* text[CONSOLE_LINES];
|
|
} JsConsoleViewModel;
|
|
|
|
static void console_view_draw_callback(Canvas* canvas, void* _model) {
|
|
JsConsoleViewModel* model = _model;
|
|
|
|
canvas_set_color(canvas, ColorBlack);
|
|
canvas_set_custom_u8g2_font(canvas, u8g2_font_spleen5x8_mr);
|
|
uint8_t line_h = canvas_current_font_height(canvas);
|
|
|
|
for(size_t i = 0; i < CONSOLE_LINES; i++) {
|
|
canvas_draw_str(canvas, 0, (i + 1) * line_h - 1, furi_string_get_cstr(model->text[i]));
|
|
if(furi_string_size(model->text[i]) > LINE_LEN_MAX) {
|
|
canvas_set_font(canvas, FontSecondary);
|
|
canvas_draw_str(canvas, 128 - 7, (i + 1) * line_h - 1, "...");
|
|
canvas_set_custom_u8g2_font(canvas, u8g2_font_spleen5x8_mr);
|
|
}
|
|
}
|
|
}
|
|
|
|
static bool console_view_input_callback(InputEvent* event, void* context) {
|
|
UNUSED(event);
|
|
UNUSED(context);
|
|
return false;
|
|
}
|
|
|
|
void console_view_push_line(JsConsoleView* console_view, const char* text, bool line_trimmed) {
|
|
with_view_model(
|
|
console_view->view,
|
|
JsConsoleViewModel * model,
|
|
{
|
|
FuriString* str_temp = model->text[0];
|
|
for(size_t i = 0; i < CONSOLE_LINES - 1; i++) {
|
|
model->text[i] = model->text[i + 1];
|
|
}
|
|
if(!line_trimmed) {
|
|
furi_string_printf(str_temp, "%.*s", LINE_LEN_MAX, text);
|
|
} else {
|
|
// Leave some space for dots
|
|
furi_string_printf(str_temp, "%.*s ", LINE_LEN_MAX - 1, text);
|
|
}
|
|
model->text[CONSOLE_LINES - 1] = str_temp;
|
|
},
|
|
true);
|
|
}
|
|
|
|
void console_view_print(JsConsoleView* console_view, const char* text) {
|
|
char line_buf[LINE_LEN_MAX + 1];
|
|
uint8_t line_buf_cnt = 0;
|
|
uint8_t utf8_bytes_left = 0;
|
|
uint8_t line_break_cnt = 0;
|
|
bool line_trim = false;
|
|
|
|
for(size_t i = 0; i < strlen(text); i++) {
|
|
if(text[i] & 0x80) { // UTF8 or another non-ascii character byte
|
|
if(utf8_bytes_left > 0) {
|
|
utf8_bytes_left--;
|
|
if(utf8_bytes_left == 0) {
|
|
line_buf[line_buf_cnt++] = '?';
|
|
}
|
|
} else {
|
|
if((text[i] & 0xE0) == 0xC0) {
|
|
utf8_bytes_left = 1;
|
|
} else if((text[i] & 0xF0) == 0xE0) {
|
|
utf8_bytes_left = 2;
|
|
} else if((text[i] & 0xF8) == 0xF0) {
|
|
utf8_bytes_left = 3;
|
|
} else {
|
|
line_buf[line_buf_cnt++] = '?';
|
|
}
|
|
}
|
|
} else {
|
|
if(utf8_bytes_left > 0) {
|
|
utf8_bytes_left = 0;
|
|
line_buf[line_buf_cnt++] = '?';
|
|
if(line_buf_cnt >= LINE_LEN_MAX) {
|
|
line_break_cnt++;
|
|
if(line_break_cnt >= LINE_BREAKS_MAX) {
|
|
line_trim = true;
|
|
break;
|
|
}
|
|
line_buf[line_buf_cnt] = '\0';
|
|
console_view_push_line(console_view, line_buf, false);
|
|
line_buf_cnt = 1;
|
|
line_buf[0] = ' ';
|
|
}
|
|
}
|
|
|
|
if(text[i] == '\n') {
|
|
line_buf[line_buf_cnt] = '\0';
|
|
line_buf_cnt = 0;
|
|
console_view_push_line(console_view, line_buf, false);
|
|
} else {
|
|
line_buf[line_buf_cnt++] = text[i];
|
|
}
|
|
|
|
if(line_buf_cnt >= LINE_LEN_MAX) {
|
|
line_break_cnt++;
|
|
if(line_break_cnt >= LINE_BREAKS_MAX) {
|
|
line_trim = true;
|
|
break;
|
|
}
|
|
line_buf[line_buf_cnt] = '\0';
|
|
console_view_push_line(console_view, line_buf, false);
|
|
line_buf_cnt = 1;
|
|
line_buf[0] = ' ';
|
|
}
|
|
}
|
|
}
|
|
if(line_buf_cnt > 0) {
|
|
line_buf[line_buf_cnt] = '\0';
|
|
console_view_push_line(console_view, line_buf, line_trim);
|
|
}
|
|
}
|
|
|
|
JsConsoleView* console_view_alloc(void) {
|
|
JsConsoleView* console_view = malloc(sizeof(JsConsoleView));
|
|
console_view->view = view_alloc();
|
|
view_set_draw_callback(console_view->view, console_view_draw_callback);
|
|
view_set_input_callback(console_view->view, console_view_input_callback);
|
|
view_allocate_model(console_view->view, ViewModelTypeLocking, sizeof(JsConsoleViewModel));
|
|
|
|
with_view_model(
|
|
console_view->view,
|
|
JsConsoleViewModel * model,
|
|
{
|
|
for(size_t i = 0; i < CONSOLE_LINES; i++) {
|
|
model->text[i] = furi_string_alloc();
|
|
}
|
|
},
|
|
true);
|
|
return console_view;
|
|
}
|
|
|
|
void console_view_free(JsConsoleView* console_view) {
|
|
with_view_model(
|
|
console_view->view,
|
|
JsConsoleViewModel * model,
|
|
{
|
|
for(size_t i = 0; i < CONSOLE_LINES; i++) {
|
|
furi_string_free(model->text[i]);
|
|
}
|
|
},
|
|
false);
|
|
view_free(console_view->view);
|
|
free(console_view);
|
|
}
|
|
|
|
View* console_view_get_view(JsConsoleView* console_view) {
|
|
return console_view->view;
|
|
} |