mirror of
https://github.com/Polprzewodnikowy/N64FlashcartMenu.git
synced 2024-11-21 18:19:19 +01:00
Implement vertical scrolling for text viewer
This commit is contained in:
parent
a189e139b2
commit
23af174811
@ -24,7 +24,7 @@ void component_progressbar_draw (int x0, int y0, int x1, int y1, float progress)
|
||||
void component_seekbar_draw (float progress);
|
||||
void component_loader_draw (float position);
|
||||
void component_scrollbar_draw (int x, int y, int width, int height, int position, int items, int visible_items);
|
||||
void component_file_list_scrollbar_draw (int position, int items, int visible_items);
|
||||
void component_list_scrollbar_draw (int position, int items, int visible_items);
|
||||
void component_dialog_draw (int width, int height);
|
||||
void component_messagebox_draw (char *fmt, ...);
|
||||
void component_main_text_draw (rdpq_align_t align, rdpq_valign_t valign, char *fmt, ...);
|
||||
|
@ -80,12 +80,12 @@ void component_scrollbar_draw (int x, int y, int width, int height, int position
|
||||
}
|
||||
}
|
||||
|
||||
void component_file_list_scrollbar_draw (int position, int items, int visible_items) {
|
||||
void component_list_scrollbar_draw (int position, int items, int visible_items) {
|
||||
component_scrollbar_draw(
|
||||
FILE_LIST_SCROLLBAR_X,
|
||||
FILE_LIST_SCROLLBAR_Y,
|
||||
FILE_LIST_SCROLLBAR_WIDTH,
|
||||
FILE_LIST_SCROLLBAR_HEIGHT,
|
||||
LIST_SCROLLBAR_X,
|
||||
LIST_SCROLLBAR_Y,
|
||||
LIST_SCROLLBAR_WIDTH,
|
||||
LIST_SCROLLBAR_HEIGHT,
|
||||
position,
|
||||
items,
|
||||
visible_items
|
||||
|
@ -77,19 +77,19 @@
|
||||
#define BOXART_Y (LAYOUT_ACTIONS_SEPARATOR_Y - BOXART_HEIGHT - 24)
|
||||
|
||||
/** @brief The scroll bar width. */
|
||||
#define FILE_LIST_SCROLLBAR_WIDTH (12)
|
||||
#define LIST_SCROLLBAR_WIDTH (12)
|
||||
/** @brief The scroll bar height. */
|
||||
#define FILE_LIST_SCROLLBAR_HEIGHT (LAYOUT_ACTIONS_SEPARATOR_Y - OVERSCAN_HEIGHT)
|
||||
#define LIST_SCROLLBAR_HEIGHT (LAYOUT_ACTIONS_SEPARATOR_Y - OVERSCAN_HEIGHT)
|
||||
/** @brief The scroll bar position on the X axis. */
|
||||
#define FILE_LIST_SCROLLBAR_X (VISIBLE_AREA_X1 - FILE_LIST_SCROLLBAR_WIDTH)
|
||||
#define LIST_SCROLLBAR_X (VISIBLE_AREA_X1 - LIST_SCROLLBAR_WIDTH)
|
||||
/** @brief The scroll bar position on the Y axis. */
|
||||
#define FILE_LIST_SCROLLBAR_Y (VISIBLE_AREA_Y0)
|
||||
#define LIST_SCROLLBAR_Y (VISIBLE_AREA_Y0)
|
||||
|
||||
/** @brief The maximum amount of file list entries. */
|
||||
#define FILE_LIST_ENTRIES (20)
|
||||
#define LIST_ENTRIES (20)
|
||||
/** @brief The maximum width available for a file list entry. */
|
||||
#define FILE_LIST_MAX_WIDTH (480)
|
||||
#define FILE_LIST_HIGHLIGHT_WIDTH (VISIBLE_AREA_X1 - VISIBLE_AREA_X0 - FILE_LIST_SCROLLBAR_WIDTH)
|
||||
#define FILE_LIST_HIGHLIGHT_WIDTH (VISIBLE_AREA_X1 - VISIBLE_AREA_X0 - LIST_SCROLLBAR_WIDTH)
|
||||
#define FILE_LIST_HIGHLIGHT_X (VISIBLE_AREA_X0)
|
||||
|
||||
/** @brief The default background colour. */
|
||||
|
@ -28,14 +28,14 @@ static int format_file_size (char *buffer, int64_t size) {
|
||||
void component_file_list_draw (entry_t *list, int entries, int selected) {
|
||||
int starting_position = 0;
|
||||
|
||||
if (entries > FILE_LIST_ENTRIES && selected >= (FILE_LIST_ENTRIES / 2)) {
|
||||
starting_position = selected - (FILE_LIST_ENTRIES / 2);
|
||||
if (starting_position >= entries - FILE_LIST_ENTRIES) {
|
||||
starting_position = entries - FILE_LIST_ENTRIES;
|
||||
if (entries > LIST_ENTRIES && selected >= (LIST_ENTRIES / 2)) {
|
||||
starting_position = selected - (LIST_ENTRIES / 2);
|
||||
if (starting_position >= entries - LIST_ENTRIES) {
|
||||
starting_position = entries - LIST_ENTRIES;
|
||||
}
|
||||
}
|
||||
|
||||
component_file_list_scrollbar_draw(selected, entries, FILE_LIST_ENTRIES);
|
||||
component_list_scrollbar_draw(selected, entries, LIST_ENTRIES);
|
||||
|
||||
if (entries == 0) {
|
||||
component_main_text_draw(
|
||||
@ -47,10 +47,10 @@ void component_file_list_draw (entry_t *list, int entries, int selected) {
|
||||
rdpq_paragraph_t *file_list_layout;
|
||||
rdpq_paragraph_t *layout;
|
||||
|
||||
size_t name_lengths[FILE_LIST_ENTRIES];
|
||||
size_t name_lengths[LIST_ENTRIES];
|
||||
size_t total_length = 1;
|
||||
|
||||
for (int i = 0; i < FILE_LIST_ENTRIES; i++) {
|
||||
for (int i = 0; i < LIST_ENTRIES; i++) {
|
||||
int entry_index = starting_position + i;
|
||||
|
||||
if (entry_index >= entries) {
|
||||
@ -76,7 +76,7 @@ void component_file_list_draw (entry_t *list, int entries, int selected) {
|
||||
file_list_layout
|
||||
);
|
||||
|
||||
for (int i = 0; i < FILE_LIST_ENTRIES; i++) {
|
||||
for (int i = 0; i < LIST_ENTRIES; i++) {
|
||||
int entry_index = starting_position + i;
|
||||
|
||||
entry_t *entry = &list[entry_index];
|
||||
@ -134,7 +134,7 @@ void component_file_list_draw (entry_t *list, int entries, int selected) {
|
||||
|
||||
rdpq_paragraph_builder_begin(
|
||||
&(rdpq_textparms_t) {
|
||||
.width = VISIBLE_AREA_WIDTH - FILE_LIST_SCROLLBAR_WIDTH - (TEXT_MARGIN_HORIZONTAL * 2),
|
||||
.width = VISIBLE_AREA_WIDTH - LIST_SCROLLBAR_WIDTH - (TEXT_MARGIN_HORIZONTAL * 2),
|
||||
.height = LAYOUT_ACTIONS_SEPARATOR_Y - VISIBLE_AREA_Y0 - (TEXT_MARGIN_VERTICAL * 2),
|
||||
.align = ALIGN_RIGHT,
|
||||
.wrap = WRAP_ELLIPSES,
|
||||
@ -152,7 +152,7 @@ void component_file_list_draw (entry_t *list, int entries, int selected) {
|
||||
rdpq_paragraph_builder_span(file_size, format_file_size(file_size, entry->size));
|
||||
}
|
||||
|
||||
if ((i + 1) == (starting_position + FILE_LIST_ENTRIES)) {
|
||||
if ((i + 1) == (starting_position + LIST_ENTRIES)) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -230,6 +230,7 @@ static void delete_entry (menu_t *menu, void *arg) {
|
||||
path_t *path = path_clone_push(menu->browser.directory, menu->browser.entry->name);
|
||||
|
||||
if (remove(path_get(path))) {
|
||||
menu->browser.valid = false;
|
||||
if (menu->browser.entry->type == ENTRY_TYPE_DIR) {
|
||||
menu_show_error(menu, "Couldn't delete directory\nDirectory might not be empty");
|
||||
} else {
|
||||
|
@ -50,5 +50,4 @@ void view_error_display (menu_t *menu, surface_t *display) {
|
||||
void menu_show_error (menu_t *menu, char *error_message) {
|
||||
menu->next_mode = MENU_MODE_ERROR;
|
||||
menu->error_message = error_message;
|
||||
menu->browser.valid = false;
|
||||
}
|
||||
|
@ -1,17 +1,66 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "utils/fs.h"
|
||||
#include "../components/constants.h"
|
||||
#include "../fonts.h"
|
||||
#include "utils/utils.h"
|
||||
#include "views.h"
|
||||
|
||||
|
||||
static char *text;
|
||||
#define MAX_FILE_SIZE KiB(128)
|
||||
|
||||
|
||||
typedef struct {
|
||||
FILE *f;
|
||||
char *contents;
|
||||
size_t length;
|
||||
int lines;
|
||||
int current_line;
|
||||
int offset;
|
||||
bool vertical_scroll_possible;
|
||||
} text_file_t;
|
||||
|
||||
static text_file_t *text;
|
||||
|
||||
|
||||
static void perform_vertical_scroll (int lines) {
|
||||
if (!text->vertical_scroll_possible) {
|
||||
return;
|
||||
}
|
||||
|
||||
int direction = (lines < 0) ? -1 : 1;
|
||||
int next_offset = text->offset;
|
||||
|
||||
for (int i = 0; i < abs(lines); i++) {
|
||||
while (true) {
|
||||
next_offset += direction;
|
||||
if (next_offset <= 0) {
|
||||
text->current_line = 0;
|
||||
text->offset = 0;
|
||||
return;
|
||||
}
|
||||
if (next_offset > text->length) {
|
||||
return;
|
||||
}
|
||||
if (text->contents[next_offset - 1] == '\n') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
text->current_line += direction;
|
||||
text->offset = next_offset;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void process (menu_t *menu) {
|
||||
if (menu->actions.back) {
|
||||
menu->next_mode = MENU_MODE_BROWSER;
|
||||
} else if (text) {
|
||||
if (menu->actions.go_up) {
|
||||
perform_vertical_scroll(menu->actions.go_fast ? -10 : -1);
|
||||
} else if (menu->actions.go_down) {
|
||||
perform_vertical_scroll(menu->actions.go_fast ? 10 : 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,20 +71,19 @@ static void draw (menu_t *menu, surface_t *d) {
|
||||
|
||||
component_layout_draw();
|
||||
|
||||
if (text) {
|
||||
component_main_text_draw(
|
||||
ALIGN_LEFT, VALIGN_TOP,
|
||||
"%s\n",
|
||||
text
|
||||
);
|
||||
} else {
|
||||
component_messagebox_draw("Text file is empty");
|
||||
}
|
||||
component_main_text_draw(
|
||||
ALIGN_LEFT, VALIGN_TOP,
|
||||
"%s\n",
|
||||
text->contents + text->offset
|
||||
);
|
||||
|
||||
component_list_scrollbar_draw(text->current_line, text->lines, LIST_ENTRIES);
|
||||
|
||||
component_actions_bar_text_draw(
|
||||
ALIGN_LEFT, VALIGN_TOP,
|
||||
"\n"
|
||||
"B: Back"
|
||||
"^%02XUp / Down: Scroll^00\n"
|
||||
"B: Back",
|
||||
text->vertical_scroll_possible ? STL_DEFAULT : STL_GRAY
|
||||
);
|
||||
|
||||
rdpq_detach_show();
|
||||
@ -43,6 +91,12 @@ static void draw (menu_t *menu, surface_t *d) {
|
||||
|
||||
static void deinit (void) {
|
||||
if (text) {
|
||||
if (text->f) {
|
||||
fclose(text->f);
|
||||
}
|
||||
if (text->contents) {
|
||||
free(text->contents);
|
||||
}
|
||||
free(text);
|
||||
text = NULL;
|
||||
}
|
||||
@ -50,45 +104,61 @@ static void deinit (void) {
|
||||
|
||||
|
||||
void view_text_viewer_init (menu_t *menu) {
|
||||
path_t *path = path_clone_push(menu->browser.directory, menu->browser.entry->name);
|
||||
|
||||
FILE *f;
|
||||
|
||||
if ((f = fopen(path_get(path), "r")) == NULL) {
|
||||
path_free(path);
|
||||
menu_show_error(menu, "Couldn't open text file");
|
||||
return;
|
||||
if ((text = calloc(1, sizeof(text_file_t))) == NULL) {
|
||||
return menu_show_error(menu, "Couldn't allocate memory for the text file");
|
||||
}
|
||||
|
||||
path_t *path = path_clone_push(menu->browser.directory, menu->browser.entry->name);
|
||||
text->f = fopen(path_get(path), "r");
|
||||
path_free(path);
|
||||
|
||||
if (text->f == NULL) {
|
||||
deinit();
|
||||
return menu_show_error(menu, "Couldn't open text file");
|
||||
}
|
||||
|
||||
struct stat st;
|
||||
if (fstat(fileno(f), &st)) {
|
||||
fclose(f);
|
||||
menu_show_error(menu, "Couldn't get text file size");
|
||||
return;
|
||||
if (fstat(fileno(text->f), &st)) {
|
||||
deinit();
|
||||
return menu_show_error(menu, "Couldn't get text file size");
|
||||
}
|
||||
text->length = st.st_size;
|
||||
|
||||
if (text->length <= 0) {
|
||||
deinit();
|
||||
return menu_show_error(menu, "Text file is empty");
|
||||
}
|
||||
|
||||
// TODO: Implement proper text file viewer with both vertical and horizontal scrolling
|
||||
size_t size = MIN(st.st_size, 1024);
|
||||
if (text->length > MAX_FILE_SIZE) {
|
||||
deinit();
|
||||
return menu_show_error(menu, "Text file is too big to be displayed");
|
||||
}
|
||||
|
||||
if (size) {
|
||||
if ((text = calloc(sizeof(char), size)) == NULL) {
|
||||
fclose(f);
|
||||
menu_show_error(menu, "Couldn't allocate memory for the text file contents");
|
||||
return;
|
||||
}
|
||||
if ((text->contents = malloc((text->length + 1) * sizeof(char))) == NULL) {
|
||||
deinit();
|
||||
return menu_show_error(menu, "Couldn't allocate memory for the text file contents");
|
||||
}
|
||||
|
||||
if (fread(text, size, 1, f) != 1) {
|
||||
fclose(f);
|
||||
menu_show_error(menu, "Couldn't read text file contents");
|
||||
return;
|
||||
if (fread(text->contents, text->length, 1, text->f) != 1) {
|
||||
deinit();
|
||||
return menu_show_error(menu, "Couldn't read text file contents");
|
||||
}
|
||||
text->contents[text->length] = '\0';
|
||||
|
||||
if (fclose(text->f)) {
|
||||
deinit();
|
||||
return menu_show_error(menu, "Couldn't close text file");
|
||||
}
|
||||
text->f = NULL;
|
||||
|
||||
text->lines = 1;
|
||||
for (size_t i = 0; i < text->length; i++) {
|
||||
if (text->contents[i] == '\n') {
|
||||
text->lines += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (fclose(f)) {
|
||||
menu_show_error(menu, "Couldn't close text file");
|
||||
}
|
||||
text->vertical_scroll_possible = (text->lines > LIST_ENTRIES);
|
||||
}
|
||||
|
||||
void view_text_viewer_display (menu_t *menu, surface_t *display) {
|
||||
|
Loading…
Reference in New Issue
Block a user