Skip to content

Commit

Permalink
Based on file list widget changes in Next-Flip#344
Browse files Browse the repository at this point in the history
  • Loading branch information
956MB committed Jan 5, 2025
1 parent f5592ca commit cb51d40
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 33 deletions.
10 changes: 9 additions & 1 deletion applications/main/archive/scenes/archive_scene_delete.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,15 @@ void archive_scene_delete_on_enter(void* context) {
"\e#Delete %d files?\e#",
model->selected_count);
widget_add_file_list_element(
app->widget, 0, 23, 3, model->selected_files, model->selected_count);
app->widget,
0,
23,
3,
model->selected_files,
model->selected_count,
14,
FRAME_HEIGHT * 3,
false);
} else {
ArchiveFile_t* current = archive_get_current_file(browser);
FuriString* filename = furi_string_alloc();
Expand Down
14 changes: 6 additions & 8 deletions applications/services/gui/modules/widget.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,6 @@

ARRAY_DEF(ElementArray, WidgetElement*, M_PTR_OPLIST); // NOLINT

struct Widget {
View* view;
void* context;
};

typedef struct {
ElementArray_t element;
} GuiWidgetModel;
Expand Down Expand Up @@ -125,10 +120,13 @@ WidgetElement* widget_add_file_list_element(
uint8_t y,
uint8_t lines,
FuriString** files,
size_t count) {
size_t count,
uint8_t scrollbar_y,
uint8_t scrollbar_height,
bool show_size) {
furi_assert(widget);
WidgetElement* file_list_element =
widget_element_file_list_create(widget, x, y, lines, files, count);
WidgetElement* file_list_element = widget_element_file_list_create(
widget, x, y, lines, files, count, scrollbar_y, scrollbar_height, show_size);
widget_add_element(widget, file_list_element);
return file_list_element;
}
Expand Down
20 changes: 13 additions & 7 deletions applications/services/gui/modules/widget.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,26 @@ View* widget_get_view(Widget* widget);

/** Add File List Element
*
* @param widget Widget instance
* @param x x coordinate
* @param y y coordinate
* @param lines Number of lines visible
* @param files Array of FuriString pointers
* @param count Number of files
* @param widget Widget instance
* @param x x coordinate
* @param y y coordinate
* @param lines Number of lines visible
* @param files Array of FuriString pointers
* @param count Number of files
* @param scrollbar_y Y coordinate of the scrollbar
* @param scrollbar_height Height of the scrollbar
* @param show_size Show file size
*/
WidgetElement* widget_add_file_list_element(
Widget* widget,
uint8_t x,
uint8_t y,
uint8_t lines,
FuriString** files,
size_t count);
size_t count,
uint8_t scrollbar_y,
uint8_t scrollbar_height,
bool show_size);

/** Add Multi String Element
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

#pragma once

#include "input/input.h"

#ifdef __cplusplus
extern "C" {
#endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,16 @@
#include "archive/archive_i.h"
#include "assets_icons.h"

#define SCROLL_INTERVAL (333)
#define SCROLL_DELAY (2)

const char* units_short[] = {"B", "K", "M", "G", "T"};

typedef struct {
FuriString* name;
FuriString* path;
const Icon* icon;
char size_num[8];
char size_unit[2];
} FileListItem;

typedef struct {
Expand All @@ -18,8 +25,35 @@ typedef struct {
FileListItem* files;
size_t count;
size_t offset;
uint8_t scrollbar_y;
bool show_size;
uint8_t scrollbar_height;
size_t scroll_counter;
FuriTimer* scroll_timer;
} FileListModel;

static void format_file_size(
uint64_t size,
char* num_buf,
size_t num_size,
char* unit_buf,
size_t unit_size) {
double formatted_size = size;
uint8_t unit = 0;

while(formatted_size >= 1024 && unit < COUNT_OF(units_short) - 1) {
formatted_size /= 1024;
unit++;
}

if(unit == 0) {
snprintf(num_buf, num_size, "%d", (int)formatted_size);
} else {
snprintf(num_buf, num_size, "%.1f", (double)formatted_size);
}
snprintf(unit_buf, unit_size, "%s", units_short[unit]);
}

static void widget_element_file_list_draw(Canvas* canvas, WidgetElement* element) {
furi_assert(canvas);
furi_assert(element);
Expand All @@ -32,22 +66,53 @@ static void widget_element_file_list_draw(Canvas* canvas, WidgetElement* element
if(idx < model->count) {
canvas_draw_icon(
canvas, model->x + 2, model->y + (i * FRAME_HEIGHT) - 9, model->files[idx].icon);
canvas_draw_str(

size_t inner_x = 123;
if(model->show_size && model->files[idx].size_num[0] != '\0') {
canvas_set_font(canvas, FontPrimary);
uint16_t num_width = canvas_string_width(canvas, model->files[idx].size_num);
canvas_set_font(canvas, FontSecondary);
uint16_t unit_width = canvas_string_width(canvas, model->files[idx].size_unit);
uint16_t total_width = num_width + unit_width;
inner_x = model->x + (128 - model->x) - total_width - 5;
inner_x--;

canvas_set_font(canvas, FontPrimary);
canvas_draw_str(
canvas, inner_x, model->y + (i * FRAME_HEIGHT), model->files[idx].size_num);
canvas_set_font(canvas, FontSecondary);
canvas_draw_str(
canvas,
inner_x + num_width + 1,
model->y + (i * FRAME_HEIGHT),
model->files[idx].size_unit);
}

size_t scroll_counter = model->scroll_counter;
scroll_counter =
i == 0 ? (model->count > model->lines &&
(scroll_counter < SCROLL_DELAY ? 0 : scroll_counter - SCROLL_DELAY)) :
0;

elements_scrollable_text_line(
canvas,
model->x + 15,
model->y + (i * FRAME_HEIGHT),
furi_string_get_cstr(model->files[idx].name));
inner_x - 19,
model->files[idx].path,
scroll_counter,
i != 0 || model->count <= model->lines);
}
}

if(model->count > model->lines) {
elements_scrollbar_pos(
canvas,
128,
model->y - 9,
model->lines * FRAME_HEIGHT,
model->scrollbar_y,
model->scrollbar_height,
model->offset,
model->count - 2);
model->count - (model->lines - 1));
}
}

Expand All @@ -56,24 +121,37 @@ static bool widget_element_file_list_input(InputEvent* event, WidgetElement* ele
FileListModel* model = element->model;
bool consumed = false;

if(event->type == InputTypeShort || event->type == InputTypeRepeat) {
if(model->count > model->lines &&
(event->type == InputTypeShort || event->type == InputTypeRepeat)) {
if(event->key == InputKeyUp) {
model->offset = (model->offset > 0) ? model->offset - 1 : model->count - 3;
model->offset = (model->offset > 0) ? model->offset - 1 : model->count - model->lines;
model->scroll_counter = 0;
consumed = true;
} else if(event->key == InputKeyDown) {
model->offset = ((model->offset + 3) < model->count) ? model->offset + 1 : 0;
model->offset = ((model->offset + model->lines) < model->count) ? model->offset + 1 :
0;
model->scroll_counter = 0;
consumed = true;
}
}

return consumed;
}

static void widget_element_file_list_timer_callback(void* context) {
WidgetElement* element = context;
FileListModel* file_model = element->model;
file_model->scroll_counter++;
with_view_model(element->parent->view, void* _model, { UNUSED(_model); }, true);
}

static void widget_element_file_list_free(WidgetElement* element) {
furi_assert(element);
FileListModel* model = element->model;
furi_timer_stop(model->scroll_timer);
furi_timer_free(model->scroll_timer);
for(size_t i = 0; i < model->count; i++) {
furi_string_free(model->files[i].name);
furi_string_free(model->files[i].path);
}
free(model->files);
free(model);
Expand All @@ -86,26 +164,48 @@ WidgetElement* widget_element_file_list_create(
uint8_t y,
uint8_t lines,
FuriString** files,
size_t count) {
size_t count,
uint8_t scrollbar_y,
uint8_t scrollbar_height,
bool show_size) {
// Allocate and init model
FileListModel* model = malloc(sizeof(FileListModel));
model->x = x;
model->y = y;
model->lines = lines;
model->count = count;
model->scrollbar_y = scrollbar_y;
model->scrollbar_height = scrollbar_height;
model->show_size = show_size;
model->offset = 0;
model->scroll_counter = 0;
model->files = malloc(sizeof(FileListItem) * count);

Storage* storage = furi_record_open(RECORD_STORAGE);
FileInfo info;
for(size_t i = 0; i < count; i++) {
model->files[i].name = furi_string_alloc();
path_extract_filename(files[i], model->files[i].name, false);
model->files[i].path = furi_string_alloc();
path_extract_filename(files[i], model->files[i].path, false);
model->files[i].size_num[0] = '\0';
model->files[i].size_unit[0] = '\0';

if(storage_dir_exists(storage, furi_string_get_cstr(files[i]))) {
model->files[i].icon = &I_dir_10px;
} else {
const char* ext = strrchr(furi_string_get_cstr(model->files[i].name), '.');
const char* ext = strrchr(furi_string_get_cstr(model->files[i].path), '.');
model->files[i].icon = (ext && strcasecmp(ext, ".js") == 0) ? &I_js_script_10px :
&I_unknown_10px;
}

if(show_size) {
storage_common_stat(storage, furi_string_get_cstr(files[i]), &info);
format_file_size(
info.size,
model->files[i].size_num,
sizeof(model->files[i].size_num),
model->files[i].size_unit,
sizeof(model->files[i].size_unit));
}
}
furi_record_close(RECORD_STORAGE);

Expand All @@ -116,5 +216,10 @@ WidgetElement* widget_element_file_list_create(
element->free = widget_element_file_list_free;
element->parent = widget;
element->model = model;

model->scroll_timer =
furi_timer_alloc(widget_element_file_list_timer_callback, FuriTimerTypePeriodic, element);
furi_timer_start(model->scroll_timer, SCROLL_INTERVAL);

return element;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

#pragma once

#include "../widget.h"
#include "../widget_i.h"
#include "widget_element.h"
#include <furi.h>
#include <gui/view.h>
Expand Down Expand Up @@ -41,7 +41,10 @@ WidgetElement* widget_element_file_list_create(
uint8_t y,
uint8_t lines,
FuriString** files,
size_t count);
size_t count,
uint8_t scrollbar_y,
uint8_t scrollbar_height,
bool show_size);

/** Create multi string element */
WidgetElement* widget_element_string_multiline_create(
Expand Down
10 changes: 10 additions & 0 deletions applications/services/gui/modules/widget_i.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once

#include "widget.h"
#include <furi.h>
#include <m-array.h>

struct Widget {
View* view;
void* context;
};
2 changes: 1 addition & 1 deletion targets/f7/api_symbols.csv
Original file line number Diff line number Diff line change
Expand Up @@ -3836,7 +3836,7 @@ Function,-,vsscanf,int,"const char*, const char*, __gnuc_va_list"
Function,-,wcstombs,size_t,"char*, const wchar_t*, size_t"
Function,-,wctomb,int,"char*, wchar_t"
Function,+,widget_add_button_element,WidgetElement*,"Widget*, GuiButtonType, const char*, ButtonCallback, void*"
Function,+,widget_add_file_list_element,WidgetElement*,"Widget*, uint8_t, uint8_t, uint8_t, FuriString**, size_t"
Function,+,widget_add_file_list_element,WidgetElement*,"Widget*, uint8_t, uint8_t, uint8_t, FuriString**, size_t, uint8_t, uint8_t, _Bool"
Function,+,widget_add_frame_element,WidgetElement*,"Widget*, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t"
Function,+,widget_add_icon_element,WidgetElement*,"Widget*, uint8_t, uint8_t, const Icon*"
Function,+,widget_add_string_element,WidgetElement*,"Widget*, uint8_t, uint8_t, Align, Align, Font, const char*"
Expand Down

0 comments on commit cb51d40

Please sign in to comment.