mirror of
https://github.com/clockworkpi/PicoCalc.git
synced 2025-12-12 18:28:53 +01:00
Compare commits
2 Commits
a0b530ea7a
...
87ae62d080
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87ae62d080 | ||
|
|
162c7c46dc |
@ -41,11 +41,12 @@ const uint LEDPIN = 25;
|
|||||||
#define VTOR_OFFSET M33_VTOR_OFFSET
|
#define VTOR_OFFSET M33_VTOR_OFFSET
|
||||||
#define MAX_RAM 0x20080000
|
#define MAX_RAM 0x20080000
|
||||||
#endif
|
#endif
|
||||||
|
uint8_t status_flag;//0 no sdcard ,1 has sd card
|
||||||
bool sd_card_inserted(void)
|
bool sd_card_inserted(void)
|
||||||
{
|
{
|
||||||
|
status_flag = !gpio_get(SD_DET_PIN);
|
||||||
// Active low detection - returns true when pin is low
|
// Active low detection - returns true when pin is low
|
||||||
return !gpio_get(SD_DET_PIN);
|
return (bool)status_flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fs_init(void)
|
bool fs_init(void)
|
||||||
@ -306,7 +307,7 @@ int main()
|
|||||||
if (!sd_card_inserted())
|
if (!sd_card_inserted())
|
||||||
{
|
{
|
||||||
DEBUG_PRINT("SD card not detected\n");
|
DEBUG_PRINT("SD card not detected\n");
|
||||||
text_directory_ui_set_status("SD card not detected.");
|
text_directory_ui_set_status("Enter to exec.");
|
||||||
text_directory_ui_update_header(1);
|
text_directory_ui_update_header(1);
|
||||||
// Poll until SD card is inserted
|
// Poll until SD card is inserted
|
||||||
text_directory_ui_draw_default_app();
|
text_directory_ui_draw_default_app();
|
||||||
|
|||||||
@ -63,6 +63,8 @@ typedef struct
|
|||||||
char name[256];
|
char name[256];
|
||||||
int is_dir; // 1 if directory, 0 if file 2 == last run
|
int is_dir; // 1 if directory, 0 if file 2 == last run
|
||||||
off_t file_size; // Size of the file in bytes
|
off_t file_size; // Size of the file in bytes
|
||||||
|
uint16_t x;
|
||||||
|
uint16_t y;
|
||||||
} dir_entry_t;
|
} dir_entry_t;
|
||||||
|
|
||||||
// UI Layout Constants for file display
|
// UI Layout Constants for file display
|
||||||
@ -78,7 +80,14 @@ typedef struct
|
|||||||
static char current_path[512] = "/firmware"; // Current directory path
|
static char current_path[512] = "/firmware"; // Current directory path
|
||||||
static dir_entry_t entries[MAX_ENTRIES]; // Directory entries
|
static dir_entry_t entries[MAX_ENTRIES]; // Directory entries
|
||||||
static int entry_count = 0; // Number of entries in the current directory
|
static int entry_count = 0; // Number of entries in the current directory
|
||||||
static int selected_index = 0; // Currently selected entry index
|
static uint8_t selected_index = 0; // Currently selected entry index
|
||||||
|
static uint8_t page_index = 0;
|
||||||
|
static uint8_t last_selected_index = 0;
|
||||||
|
static uint8_t last_page_index = 0;
|
||||||
|
static uint8_t update_sel = 0;
|
||||||
|
static uint8_t update_required=0;
|
||||||
|
extern uint8_t status_flag;
|
||||||
|
static uint32_t status_repeat=0;
|
||||||
static char status_message[256] = ""; // Status message
|
static char status_message[256] = ""; // Status message
|
||||||
static final_selection_callback_t final_callback = NULL; // Callback for file selection
|
static final_selection_callback_t final_callback = NULL; // Callback for file selection
|
||||||
static uint32_t last_scrolling = 0; // for text scrolling in selected entry
|
static uint32_t last_scrolling = 0; // for text scrolling in selected entry
|
||||||
@ -88,8 +97,8 @@ static void load_directory(const char *path);
|
|||||||
static void ui_draw_title(void);
|
static void ui_draw_title(void);
|
||||||
static void ui_draw_path_header(uint8_t);
|
static void ui_draw_path_header(uint8_t);
|
||||||
static void ui_draw_directory_list(void);
|
static void ui_draw_directory_list(void);
|
||||||
static void ui_draw_directory_entry(int entry_idx, int posY, int font_height, int is_selected);
|
static void ui_draw_directory_entry(int entry_idx);
|
||||||
static void ui_update_selected_entry(void);
|
static void ui_update_selected_entry(uint8_t);
|
||||||
static void ui_draw_status_bar(void);
|
static void ui_draw_status_bar(void);
|
||||||
static void ui_draw_empty_tip(void);
|
static void ui_draw_empty_tip(void);
|
||||||
static void format_file_size(off_t size, int is_dir, char *buf, size_t buf_size);
|
static void format_file_size(off_t size, int is_dir, char *buf, size_t buf_size);
|
||||||
@ -255,7 +264,7 @@ static void ui_draw_empty_tip(){
|
|||||||
|
|
||||||
set_default_entry();
|
set_default_entry();
|
||||||
// Draw the entry using the helper function
|
// Draw the entry using the helper function
|
||||||
ui_draw_directory_entry(0, y_start, 12, 1);
|
ui_draw_directory_entry(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw the current path header
|
// Draw the current path header
|
||||||
@ -281,12 +290,18 @@ static void ui_draw_path_header(uint8_t nosd)
|
|||||||
* @param font_height Height of the font
|
* @param font_height Height of the font
|
||||||
* @param is_selected Whether this entry is currently selected
|
* @param is_selected Whether this entry is currently selected
|
||||||
*/
|
*/
|
||||||
static void ui_draw_directory_entry(int entry_idx, int posY, int font_height, int is_selected)
|
static void ui_draw_directory_entry(int entry_idx)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
int y_start = UI_Y + HEADER_TITLE_HEIGHT + PATH_HEADER_HEIGHT;
|
||||||
|
int posY = y_start + (entry_idx%ITEMS_PER_PAGE) * (FONT_HEIGHT + ENTRY_PADDING);
|
||||||
|
int is_selected = (entry_idx == selected_index);
|
||||||
|
entries[entry_idx].x = FILE_NAME_X;
|
||||||
|
entries[entry_idx].y = posY;
|
||||||
// Highlight background for selected item
|
// Highlight background for selected item
|
||||||
if (is_selected)
|
if (is_selected)
|
||||||
{
|
{
|
||||||
draw_rect_spi(UI_X, posY - 1, UI_X + UI_WIDTH - 1, posY + font_height, COLOR_HIGHLIGHT);
|
draw_rect_spi(UI_X, posY - 1, UI_X + UI_WIDTH - 1, posY + FONT_HEIGHT, COLOR_HIGHLIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare filename with directory indicator
|
// Prepare filename with directory indicator
|
||||||
@ -334,30 +349,21 @@ static void ui_draw_directory_entry(int entry_idx, int posY, int font_height, in
|
|||||||
* This is an optimization to avoid redrawing the entire directory list
|
* This is an optimization to avoid redrawing the entire directory list
|
||||||
* when only the selected entry needs to be updated (e.g., for scrolling text)
|
* when only the selected entry needs to be updated (e.g., for scrolling text)
|
||||||
*/
|
*/
|
||||||
static void ui_update_selected_entry(void)
|
static void ui_update_selected_entry(uint8_t last)
|
||||||
{
|
{
|
||||||
const int font_height = 12;
|
uint16_t y=0;
|
||||||
const int entry_padding = 2;
|
if(last) {
|
||||||
int y_start = UI_Y + HEADER_TITLE_HEIGHT + PATH_HEADER_HEIGHT;
|
y = entries[last_selected_index % ITEMS_PER_PAGE].y;
|
||||||
int available_height = UI_HEIGHT - (HEADER_TITLE_HEIGHT + PATH_HEADER_HEIGHT + STATUS_BAR_HEIGHT);
|
draw_rect_spi(UI_X, y - 1, UI_X + UI_WIDTH - 1, y + FONT_HEIGHT, COLOR_BG);
|
||||||
int max_visible = available_height / (font_height + entry_padding);
|
ui_draw_directory_entry(last_selected_index);
|
||||||
int start_index = (selected_index >= max_visible) ? selected_index - max_visible + 1 : 0;
|
|
||||||
|
|
||||||
// Calculate the position of the selected entry
|
|
||||||
int visible_index = selected_index - start_index;
|
|
||||||
if (visible_index >= 0 && visible_index < max_visible) {
|
|
||||||
int posY = y_start + visible_index * (font_height + entry_padding);
|
|
||||||
|
|
||||||
// Clear just the selected row
|
|
||||||
//draw_rect_spi(UI_X, posY - 1, UI_X + UI_WIDTH - 1, posY + font_height, COLOR_BG);
|
|
||||||
|
|
||||||
// Redraw just the selected entry
|
|
||||||
ui_draw_directory_entry(selected_index, posY, font_height, 1);
|
|
||||||
}
|
}
|
||||||
|
ui_draw_directory_entry(selected_index );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ui_clear_directory_list(void){
|
static void ui_clear_directory_list(void){
|
||||||
if(entry_count <1 ) return;
|
if(entry_count <1 ) return;
|
||||||
|
int y_start = UI_Y + HEADER_TITLE_HEIGHT + PATH_HEADER_HEIGHT;
|
||||||
|
|
||||||
for(int i=1;i<entry_count;i++){
|
for(int i=1;i<entry_count;i++){
|
||||||
strncpy(entries[entry_count].name, "", sizeof(entries[entry_count].name) - 1);
|
strncpy(entries[entry_count].name, "", sizeof(entries[entry_count].name) - 1);
|
||||||
@ -366,6 +372,8 @@ static void ui_clear_directory_list(void){
|
|||||||
entries[entry_count].file_size = 0;
|
entries[entry_count].file_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
draw_rect_spi(UI_X, y_start, UI_X + UI_WIDTH - 1, UI_Y + UI_HEIGHT - STATUS_BAR_HEIGHT - 1, COLOR_BG);
|
||||||
|
|
||||||
entry_count = 1;
|
entry_count = 1;
|
||||||
selected_index = 0;
|
selected_index = 0;
|
||||||
}
|
}
|
||||||
@ -374,30 +382,40 @@ static void ui_clear_directory_list(void){
|
|||||||
static void ui_draw_directory_list(void)
|
static void ui_draw_directory_list(void)
|
||||||
{
|
{
|
||||||
if(entry_count <=0 ) return;
|
if(entry_count <=0 ) return;
|
||||||
const int font_height = 12;
|
page_index = (selected_index / ITEMS_PER_PAGE)* ITEMS_PER_PAGE;
|
||||||
const int entry_padding = 2;
|
|
||||||
int y_start = UI_Y + HEADER_TITLE_HEIGHT + PATH_HEADER_HEIGHT;
|
int y_start = UI_Y + HEADER_TITLE_HEIGHT + PATH_HEADER_HEIGHT;
|
||||||
int available_height = UI_HEIGHT - (HEADER_TITLE_HEIGHT + PATH_HEADER_HEIGHT + STATUS_BAR_HEIGHT);
|
|
||||||
int max_visible = available_height / (font_height + entry_padding);
|
|
||||||
int start_index = (selected_index >= max_visible) ? selected_index - max_visible + 1 : 0;
|
|
||||||
|
|
||||||
draw_rect_spi(UI_X, y_start, UI_X + UI_WIDTH - 1, UI_Y + UI_HEIGHT - STATUS_BAR_HEIGHT - 1, COLOR_BG);
|
if(page_index!= last_page_index){
|
||||||
last_scrolling = time_us_64() /1000;
|
draw_rect_spi(UI_X, y_start, UI_X + UI_WIDTH - 1, UI_Y + UI_HEIGHT - STATUS_BAR_HEIGHT - 1, COLOR_BG);
|
||||||
|
last_page_index = page_index;
|
||||||
for (int i = 0; i < max_visible && (i + start_index) < entry_count; i++)
|
update_required = 1;
|
||||||
{
|
update_sel = 0;
|
||||||
int posY = y_start + i * (font_height + entry_padding);
|
|
||||||
int entry_idx = i + start_index;
|
|
||||||
int is_selected = (entry_idx == selected_index);
|
|
||||||
|
|
||||||
// Draw the entry using the helper function
|
|
||||||
ui_draw_directory_entry(entry_idx, posY, font_height, is_selected);
|
|
||||||
}
|
}
|
||||||
|
last_scrolling = time_us_64() / 1000;
|
||||||
|
if(update_required) {
|
||||||
|
|
||||||
|
for (int i = page_index; i < page_index + ITEMS_PER_PAGE; i++) {
|
||||||
|
if (i >= entry_count) break;
|
||||||
|
// Draw the entry using the helper function
|
||||||
|
ui_draw_directory_entry(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(update_sel)
|
||||||
|
{
|
||||||
|
printf("update selected entry\n");
|
||||||
|
ui_update_selected_entry(update_sel);
|
||||||
|
update_sel = 0;
|
||||||
|
}
|
||||||
|
update_required = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw the status bar
|
// Draw the status bar
|
||||||
static void ui_draw_status_bar(void)
|
static void ui_draw_status_bar(void)
|
||||||
{
|
{
|
||||||
|
if(status_repeat > 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
int y = UI_Y + UI_HEIGHT - STATUS_BAR_HEIGHT;
|
int y = UI_Y + UI_HEIGHT - STATUS_BAR_HEIGHT;
|
||||||
draw_rect_spi(UI_X, y, UI_X + UI_WIDTH - 1, UI_Y + UI_HEIGHT - 1, COLOR_BG);
|
draw_rect_spi(UI_X, y, UI_X + UI_WIDTH - 1, UI_Y + UI_HEIGHT - 1, COLOR_BG);
|
||||||
draw_line_spi(UI_X, y, UI_X + UI_WIDTH - 1, y, COLOR_FG);
|
draw_line_spi(UI_X, y, UI_X + UI_WIDTH - 1, y, COLOR_FG);
|
||||||
@ -405,6 +423,7 @@ static void ui_draw_status_bar(void)
|
|||||||
strncpy(truncated_message, status_message, sizeof(truncated_message) - 1);
|
strncpy(truncated_message, status_message, sizeof(truncated_message) - 1);
|
||||||
truncated_message[sizeof(truncated_message) - 1] = '\0';
|
truncated_message[sizeof(truncated_message) - 1] = '\0';
|
||||||
draw_text(UI_X + 2, y + 2, truncated_message, COLOR_FG, COLOR_BG);
|
draw_text(UI_X + 2, y + 2, truncated_message, COLOR_FG, COLOR_BG);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh the entire UI
|
// Refresh the entire UI
|
||||||
@ -426,16 +445,30 @@ void process_key_event(int key)
|
|||||||
switch (key)
|
switch (key)
|
||||||
{
|
{
|
||||||
case KEY_ARROW_UP:
|
case KEY_ARROW_UP:
|
||||||
if (selected_index > 0)
|
last_selected_index = selected_index;
|
||||||
selected_index--;
|
if(selected_index == 0) {
|
||||||
|
selected_index = entry_count -1;
|
||||||
|
}else{
|
||||||
|
selected_index --;
|
||||||
|
}
|
||||||
|
update_sel = 1;
|
||||||
ui_draw_directory_list();
|
ui_draw_directory_list();
|
||||||
text_directory_ui_set_status("");
|
if(status_flag) {
|
||||||
|
text_directory_ui_set_status("Up/Down to select, Enter to exec.");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case KEY_ARROW_DOWN:
|
case KEY_ARROW_DOWN:
|
||||||
if (selected_index < entry_count - 1)
|
last_selected_index = selected_index;
|
||||||
|
if(selected_index == entry_count -1) {
|
||||||
|
selected_index = 0;
|
||||||
|
}else{
|
||||||
selected_index++;
|
selected_index++;
|
||||||
|
}
|
||||||
|
update_sel = 1;
|
||||||
ui_draw_directory_list();
|
ui_draw_directory_list();
|
||||||
text_directory_ui_set_status("");
|
if(status_flag) {
|
||||||
|
text_directory_ui_set_status("Up/Down to select, Enter to exec.");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case KEY_ENTER:
|
case KEY_ENTER:
|
||||||
if(entry_count == 0) {
|
if(entry_count == 0) {
|
||||||
@ -502,10 +535,16 @@ bool text_directory_ui_pre_init(void)
|
|||||||
// Public API: Initialize the UI
|
// Public API: Initialize the UI
|
||||||
bool text_directory_ui_init(void)
|
bool text_directory_ui_init(void)
|
||||||
{
|
{
|
||||||
|
update_sel = 0;
|
||||||
|
update_required = 1;
|
||||||
draw_filled_rect(UI_X, UI_Y, UI_WIDTH, UI_HEIGHT, COLOR_BG);
|
draw_filled_rect(UI_X, UI_Y, UI_WIDTH, UI_HEIGHT, COLOR_BG);
|
||||||
strncpy(current_path, "/firmware", sizeof(current_path));
|
strncpy(current_path, "/firmware", sizeof(current_path));
|
||||||
load_directory(current_path);
|
load_directory(current_path);
|
||||||
text_directory_ui_set_status("");
|
text_directory_ui_set_status("");
|
||||||
|
if(status_flag) {
|
||||||
|
text_directory_ui_set_status("Up/Down to select, Enter to exec.");
|
||||||
|
status_repeat = 2;
|
||||||
|
}
|
||||||
ui_refresh();
|
ui_refresh();
|
||||||
last_scrolling = time_us_64()/1000;
|
last_scrolling = time_us_64()/1000;
|
||||||
return true;
|
return true;
|
||||||
@ -514,6 +553,11 @@ bool text_directory_ui_init(void)
|
|||||||
// Public API: Set a status message
|
// Public API: Set a status message
|
||||||
void text_directory_ui_set_status(const char *msg)
|
void text_directory_ui_set_status(const char *msg)
|
||||||
{
|
{
|
||||||
|
if(strcmp(status_message,msg) == 0) {
|
||||||
|
status_repeat++;
|
||||||
|
}else{
|
||||||
|
status_repeat = 0;
|
||||||
|
}
|
||||||
strncpy(status_message, msg, sizeof(status_message) - 1);
|
strncpy(status_message, msg, sizeof(status_message) - 1);
|
||||||
status_message[sizeof(status_message) - 1] = '\0';
|
status_message[sizeof(status_message) - 1] = '\0';
|
||||||
ui_draw_status_bar();
|
ui_draw_status_bar();
|
||||||
@ -524,11 +568,10 @@ void text_directory_ui_update_header(uint8_t nosd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void text_directory_ui_draw_default_app() {
|
void text_directory_ui_draw_default_app() {
|
||||||
int y_start = UI_Y + HEADER_TITLE_HEIGHT + PATH_HEADER_HEIGHT;
|
|
||||||
|
|
||||||
set_default_entry();
|
set_default_entry();
|
||||||
// Draw the entry using the helper function
|
// Draw the entry using the helper function
|
||||||
ui_draw_directory_entry(0, y_start, 12, 1);
|
ui_draw_directory_entry(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public API: Main event loop for the UI
|
// Public API: Main event loop for the UI
|
||||||
@ -552,7 +595,7 @@ void text_directory_ui_run(void)
|
|||||||
if (entry_count > 0 && selected_index >= 0 &&
|
if (entry_count > 0 && selected_index >= 0 &&
|
||||||
strlen(entries[selected_index].name) + (entries[selected_index].is_dir ? 1 : 0) > FILE_NAME_VISIBLE_CHARS)
|
strlen(entries[selected_index].name) + (entries[selected_index].is_dir ? 1 : 0) > FILE_NAME_VISIBLE_CHARS)
|
||||||
{
|
{
|
||||||
ui_update_selected_entry();
|
ui_update_selected_entry(0);
|
||||||
}
|
}
|
||||||
last_scroll_update = current_time;
|
last_scroll_update = current_time;
|
||||||
}
|
}
|
||||||
@ -562,6 +605,7 @@ void text_directory_ui_run(void)
|
|||||||
text_directory_ui_set_status("SD card removed. Please reinsert.");
|
text_directory_ui_set_status("SD card removed. Please reinsert.");
|
||||||
ui_draw_path_header(1);
|
ui_draw_path_header(1);
|
||||||
ui_clear_directory_list();
|
ui_clear_directory_list();
|
||||||
|
update_required = 1;
|
||||||
ui_draw_directory_list();
|
ui_draw_directory_list();
|
||||||
// Wait until the SD card is reinserted
|
// Wait until the SD card is reinserted
|
||||||
while (!sd_card_inserted()) {
|
while (!sd_card_inserted()) {
|
||||||
|
|||||||
@ -8,6 +8,9 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define ITEMS_PER_PAGE 16
|
||||||
|
#define FONT_HEIGHT 12
|
||||||
|
#define ENTRY_PADDING 2
|
||||||
// Callback type: invoked when the user makes a final selection. The selected path is passed as an argument.
|
// Callback type: invoked when the user makes a final selection. The selected path is passed as an argument.
|
||||||
typedef void (*final_selection_callback_t)(const char *selected_path);
|
typedef void (*final_selection_callback_t)(const char *selected_path);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user