diff --git a/README.md b/README.md index 5aac2d3..e8fb9ff 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ This is a project I've haven't worked on for a while and I'm just now getting back to it. This is a Nintendo Switch Homebrew Application and will read ePub files, or eventually, what ever MuPDF supports. ### Current State: -* Crashes your switch. +* ePubs cause a crash, PDFs dont load, idk what happends with other files. * Just about **ALL** of the code isn't even mine but taken from an old NX-Shell repo. -* Working on redoing the code and making it not crash your switch. +* Working on redoing the code ### TODO: * Use MuPDF. diff --git a/RomFs/arial-unicode-ms.ttf b/RomFs/arial-unicode-ms.ttf deleted file mode 100644 index 51a18bc..0000000 Binary files a/RomFs/arial-unicode-ms.ttf and /dev/null differ diff --git a/include/SDL_helper.h b/include/SDL_helper.h index 1e8e726..4198a9c 100644 --- a/include/SDL_helper.h +++ b/include/SDL_helper.h @@ -1,10 +1,8 @@ #ifndef EBOOK_READER_SDL_HELPER_H #define EBOOK_READER_SDL_HELPER_H -#include -#include - -static inline SDL_Color SDL_MakeColour(Uint8 r, Uint8 g, Uint8 b, Uint8 a) { +static inline SDL_Color SDL_MakeColour(Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ SDL_Color colour = {r, g, b, a}; return colour; } @@ -23,15 +21,15 @@ static inline SDL_Color SDL_MakeColour(Uint8 r, Uint8 g, Uint8 b, Uint8 a) { #define TEXT_MIN_COLOUR_LIGHT SDL_MakeColour(32, 32, 32, 255) #define TEXT_MIN_COLOUR_DARK SDL_MakeColour(185, 185, 185, 255) #define BAR_COLOUR SDL_MakeColour(200, 200, 200, 255) -#define PROGRESS_COLOUR SDL_MakeColour(48, 174, 222, 255) void SDL_ClearScreen(SDL_Renderer *renderer, SDL_Color colour); void SDL_DrawRect(SDL_Renderer *renderer, int x, int y, int w, int h, SDL_Color colour); void SDL_DrawCircle(SDL_Renderer *renderer, int x, int y, int r, SDL_Color colour); -void SDL_DrawText(SDL_Surface* window_surface, TTF_Font *font, int x, int y, SDL_Color colour, const char *text); -void SDL_DrawTextf(SDL_Surface* window_surface, TTF_Font *font, int x, int y, SDL_Color colour, const char* text, ...); +void SDL_DrawText(SDL_Renderer *renderer, TTF_Font *font, int x, int y, SDL_Color colour, const char *text); +void SDL_DrawTextf(SDL_Renderer *renderer, TTF_Font *font, int x, int y, SDL_Color colour, const char* text, ...); void SDL_LoadImage(SDL_Renderer *renderer, SDL_Texture **texture, char *path); void SDL_LoadImageBuf(SDL_Renderer *renderer, SDL_Texture **texture, void *mem, int size); -void SDL_DrawImage(SDL_Renderer *renderer, SDL_Texture *texture, int x, int y, int w, int h); +void SDL_DrawImage(SDL_Renderer *renderer, SDL_Texture *texture, int x, int y); +void SDL_DrawImageScale(SDL_Renderer *renderer, SDL_Texture *texture, int x, int y, int w, int h); #endif \ No newline at end of file diff --git a/include/common.h b/include/common.h index 9987dab..eafd8b4 100644 --- a/include/common.h +++ b/include/common.h @@ -4,10 +4,9 @@ #include #include -extern SDL_Renderer* RENDERER; -extern SDL_Window* WINDOW; -extern SDL_Surface* WINDOW_SURFACE; -extern TTF_Font* ARIAL_UNICODE; -extern SDL_Event EVENT; +extern SDL_Window *WINDOW; +extern SDL_Surface *WINDOW_SURFACE; +extern SDL_Renderer *RENDERER; +extern TTF_Font *ARIAL_UNICODE; -#endif +#endif \ No newline at end of file diff --git a/include/menu_book_reader.h b/include/menu_book_reader.h index 3f37fee..8b5c3a5 100644 --- a/include/menu_book_reader.h +++ b/include/menu_book_reader.h @@ -2,10 +2,7 @@ #define EBOOK_READER_MENU_BOOK_READER_H #include -#include -#include -//void Menu_OpenBook(SDL_Renderer *renderer, SDL_Surface* window_surface, TTF_Font *font, char *path); void Menu_OpenBook(char *path); #endif diff --git a/include/status_bar.h b/include/status_bar.h index 810acc2..0306165 100644 --- a/include/status_bar.h +++ b/include/status_bar.h @@ -1,5 +1,5 @@ -#ifndef NX_SHELL_STATUS_BAR_H -#define NX_SHELL_STATUS_BAR_H +#ifndef EBOOK_READER_STATUS_BAR_H +#define EBOOK_READER_STATUS_BAR_H void StatusBar_DisplayTime(void); diff --git a/source/BookReader.cpp b/source/BookReader.cpp deleted file mode 100644 index 5a47862..0000000 --- a/source/BookReader.cpp +++ /dev/null @@ -1,171 +0,0 @@ -#include "BookReader.hpp" -#include - -extern "C" { - #include "SDL_helper.h" - #include "status_bar.h" - //#include "common.h" - //#include "config.h" -} - -fz_context *ctx = NULL; - -static inline void FreeTextureIfNeeded(SDL_Texture **texture) { - if (texture && *texture) { - SDL_DestroyTexture(*texture); - *texture = NULL; - } -} - -BookReader::BookReader(SDL_Renderer *renderer, const char *path) { - RENDERER = renderer; - if (ctx == NULL) { - ctx = fz_new_context(NULL, NULL, 128 << 10); - fz_register_document_handlers(ctx); - } - - //doc = fz_open_document(ctx, path); - doc = fz_open_document_with_stream(ctx, path, fz_open_file(ctx, path)); - pdf = pdf_specifics(ctx, doc); - - pages_count = fz_count_pages(ctx, doc); - - SDL_Rect viewport; - SDL_RenderGetViewport(renderer, &viewport); - screen_bounds = fz_make_rect(0, 0, viewport.w, viewport.h); - - load_page(0); -} - -BookReader::~BookReader() { - fz_drop_document(ctx, doc); - - FreeTextureIfNeeded(&page_texture); -} - -void BookReader::previous_page() { - load_page(current_page - 1); -} - -void BookReader::next_page() { - load_page(current_page + 1); -} - -void BookReader::zoom_in() { - set_zoom(zoom + 0.1); -} - -void BookReader::zoom_out() { - set_zoom(zoom - 0.1); -} - -void BookReader::move_page_up() { - move_page(0, -50); -} - -void BookReader::move_page_down() { - move_page(0, 50); -} - -void BookReader::move_page_left() { - move_page(-50, 0); -} - -void BookReader::move_page_right() { - move_page(50, 0); -} - -void BookReader::reset_page() { - page_center = fz_make_point(screen_bounds.x1 / 2, screen_bounds.y1 / 2); - set_zoom(min_zoom); -} - -void BookReader::draw(SDL_Surface *window_surface, TTF_Font *font) { - float w = page_bounds.x1 * zoom, h = page_bounds.y1 * zoom; - - SDL_Rect rect; - rect.x = page_center.x - w / 2; - rect.y = page_center.y - h / 2; - rect.w = w; - rect.h = h; - - SDL_ClearScreen(RENDERER, SDL_MakeColour(33, 39, 43, 255)); - SDL_RenderClear(RENDERER); - - SDL_RenderCopy(RENDERER, page_texture, NULL, &rect); - - //if (--status_bar_visible_counter > 0) { - char title[128]; - sprintf(title, "%i/%i, %.2f%%", current_page + 1, pages_count, zoom * 100); - - int title_width = 0, title_height = 0; - TTF_SizeText(font, title, &title_width, &title_height); - - SDL_Color color = STATUS_BAR_LIGHT; - - SDL_DrawRect(RENDERER, 0, 0, 1920, 60, SDL_MakeColour(color.r, color.g, color.b, 128)); - SDL_DrawText(window_surface, font, (screen_bounds.x1 - title_width) / 2, (44 - title_height) / 2, WHITE, title); - - StatusBar_DisplayTime(); - //} - - SDL_RenderPresent(RENDERER); -} - -void BookReader::load_page(int num) { - current_page = std::min(std::max(0, num), pages_count - 1); - - fz_drop_page(ctx, page); - page = fz_load_page(ctx, doc, current_page); - - fz_rect bounds; - //fz_bound_page(ctx, page, &bounds); - fz_bound_page(ctx, page); - - if (page_bounds.x1 != bounds.x1 || page_bounds.y1 != bounds.y1) { - page_bounds = bounds; - page_center = fz_make_point(screen_bounds.x1 / 2, screen_bounds.y1 / 2); - - min_zoom = fmin(screen_bounds.x1 / bounds.x1, screen_bounds.y1 / bounds.y1); - max_zoom = fmax(screen_bounds.x1 / bounds.x1, screen_bounds.y1 / bounds.y1); - zoom = min_zoom; - } - - render_page_to_texture(); - - status_bar_visible_counter = 50; -} - -void BookReader::render_page_to_texture() { - FreeTextureIfNeeded(&page_texture); - - fz_matrix m = fz_identity; - //fz_scale(&m, zoom, zoom); - fz_scale(zoom, zoom); - - fz_pixmap *pix = fz_new_pixmap_from_page_contents(ctx, page, m, fz_device_rgb(ctx), 0); - SDL_Surface *image = SDL_CreateRGBSurfaceFrom(pix->samples, pix->w, pix->h, pix->n * 8, pix->w * pix->n, 0x000000FF, 0x0000FF00, 0x00FF0000, 0); - page_texture = SDL_CreateTextureFromSurface(RENDERER, image); - - SDL_FreeSurface(image); - fz_drop_pixmap(ctx, pix); -} - -void BookReader::set_zoom(float value) { - value = fmin(fmax(min_zoom, value), max_zoom); - - if (value == zoom) return; - - zoom = value; - - load_page(current_page); - move_page(0, 0); - status_bar_visible_counter = 50; -} - -void BookReader::move_page(float x, float y) { - float w = page_bounds.x1 * zoom, h = page_bounds.y1 * zoom; - - page_center.x = fmin(fmax(page_center.x + x, w / 2), screen_bounds.x1 - w / 2); - page_center.y = fmin(fmax(page_center.y + y, screen_bounds.y1 - h / 2), h / 2); -} diff --git a/source/BookReader.hpp b/source/BookReader.hpp deleted file mode 100644 index 20a2266..0000000 --- a/source/BookReader.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef EBOOK_READER_BOOK_READER_HPP -#define EBOOK_READER_BOOK_READER_HPP - -#include -#include -#include - -struct SDL_Texture; - -class BookReader { -public: - BookReader(SDL_Renderer *renderer, const char *path); - ~BookReader(); - - void previous_page(); - void next_page(); - void zoom_in(); - void zoom_out(); - void move_page_up(); - void move_page_down(); - void move_page_left(); - void move_page_right(); - void reset_page(); - void draw(SDL_Surface *window_surface, TTF_Font *font); - -private: - void load_page(int num); - void render_page_to_texture(); - void set_zoom(float value); - void move_page(float x, float y); - - fz_document *doc = NULL; - pdf_document *pdf = NULL; - fz_page *page = NULL; - fz_rect page_bounds = fz_empty_rect, screen_bounds = fz_empty_rect; - fz_point page_center = fz_make_point(0, 0); - - SDL_Texture *page_texture = NULL; - SDL_Renderer *RENDERER = NULL; - - int current_page = -1, pages_count = 0; - float min_zoom = 1, max_zoom = 1, zoom = 1; - - int status_bar_visible_counter = 0; -}; - -#endif diff --git a/source/SDL_helper.c b/source/SDL_helper.c index 6615e39..a16a984 100644 --- a/source/SDL_helper.c +++ b/source/SDL_helper.c @@ -1,46 +1,46 @@ +#include "common.h" #include "SDL_helper.h" -void SDL_ClearScreen(SDL_Renderer *renderer, SDL_Color colour) -{ +void SDL_ClearScreen(SDL_Renderer *renderer, SDL_Color colour) { SDL_SetRenderDrawColor(renderer, colour.r, colour.g, colour.b, colour.a); SDL_RenderClear(renderer); } -void SDL_DrawRect(SDL_Renderer *renderer, int x, int y, int w, int h, SDL_Color colour) -{ +void SDL_DrawRect(SDL_Renderer *renderer, int x, int y, int w, int h, SDL_Color colour) { SDL_Rect rect; rect.x = x; rect.y = y; rect.w = w; rect.h = h; - SDL_SetRenderDrawColor(renderer, colour.r, colour.g, colour.b, colour.a); - SDL_RenderFillRect(renderer, &rect); + SDL_SetRenderDrawColor(RENDERER, colour.r, colour.g, colour.b, colour.a); + SDL_RenderFillRect(RENDERER, &rect); } -void SDL_DrawCircle(SDL_Renderer *renderer, int x, int y, int r, SDL_Color colour) -{ +void SDL_DrawCircle(SDL_Renderer *renderer, int x, int y, int r, SDL_Color colour) { filledCircleRGBA(renderer, x, y, r, colour.r, colour.g, colour.b, colour.a); return; } -void SDL_DrawText(SDL_Surface* window_surface, TTF_Font *font, int x, int y, SDL_Color colour, const char *text) -{ +void SDL_DrawText(SDL_Renderer *renderer, TTF_Font *font, int x, int y, SDL_Color colour, const char *text) { SDL_Surface *surface = TTF_RenderText_Blended_Wrapped(font, text, colour, 1280); SDL_SetSurfaceAlphaMod(surface, colour.a); - SDL_Rect position = {x, y, surface->w, surface->h}; - SDL_BlitSurface(surface, NULL, window_surface, &position); + SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface); SDL_FreeSurface(surface); + + SDL_Rect position; + position.x = x; position.y = y; + SDL_QueryTexture(texture, NULL, NULL, &position.w, &position.h); + SDL_RenderCopy(renderer, texture, NULL, &position); + SDL_DestroyTexture(texture); } -void SDL_DrawTextf(SDL_Surface* window_surface, TTF_Font *font, int x, int y, SDL_Color colour, const char* text, ...) -{ +void SDL_DrawTextf(SDL_Renderer *renderer, TTF_Font *font, int x, int y, SDL_Color colour, const char* text, ...) { char buffer[256]; va_list args; va_start(args, text); vsnprintf(buffer, 256, text, args); - SDL_DrawText(window_surface, font, x, y, colour, buffer); + SDL_DrawText(renderer, font, x, y, colour, buffer); va_end(args); } -void SDL_LoadImage(SDL_Renderer *renderer, SDL_Texture **texture, char *path) -{ +void SDL_LoadImage(SDL_Renderer *renderer, SDL_Texture **texture, char *path) { SDL_Surface *loaded_surface = NULL; loaded_surface = IMG_Load(path); @@ -54,25 +54,15 @@ void SDL_LoadImage(SDL_Renderer *renderer, SDL_Texture **texture, char *path) SDL_FreeSurface(loaded_surface); } -void SDL_LoadImageBuf(SDL_Renderer *renderer, SDL_Texture **texture, void *mem, int size) -{ - SDL_Surface *loaded_surface = NULL; - SDL_RWops *rw = SDL_RWFromMem(mem, size); - loaded_surface = IMG_Load_RW(rw, 1); - - if (loaded_surface) - { - Uint32 colorkey = SDL_MapRGB(loaded_surface->format, 0, 0, 0); - SDL_SetColorKey(loaded_surface, SDL_TRUE, colorkey); - *texture = SDL_CreateTextureFromSurface(renderer, loaded_surface); - } - - SDL_FreeSurface(loaded_surface); +void SDL_DrawImage(SDL_Renderer *renderer, SDL_Texture *texture, int x, int y) { + SDL_Rect position; + position.x = x; position.y = y; + SDL_QueryTexture(texture, NULL, NULL, &position.w, &position.h); + SDL_RenderCopy(renderer, texture, NULL, &position); } -void SDL_DrawImage(SDL_Renderer *renderer, SDL_Texture *texture, int x, int y, int w, int h) -{ +void SDL_DrawImageScale(SDL_Renderer *renderer, SDL_Texture *texture, int x, int y, int w, int h) { SDL_Rect position; position.x = x; position.y = y; position.w = w; position.h = h; SDL_RenderCopy(renderer, texture, NULL, &position); -} \ No newline at end of file +} diff --git a/source/main.cpp b/source/main.cpp index cdb5cde..abd7fce 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -76,7 +76,7 @@ void Init_Services() { // available switch SDL2 video modes : // 1920 x 1080 @ 32 bpp (SDL_PIXELFORMAT_RGBA8888) // 1280 x 720 @ 32 bpp (SDL_PIXELFORMAT_RGBA8888) - WINDOW = SDL_CreateWindow("sdl2_gles2", 0, 0, 1920, 1080, 0); + WINDOW = SDL_CreateWindow("sdl2_gles2", 0, 0, 1280, 720, 0); if (!WINDOW) { SDL_Log("SDL_CreateWindow: %s\n", SDL_GetError()); Term_Services(); @@ -95,7 +95,7 @@ void Init_Services() { romfsInit(); - ARIAL_UNICODE = TTF_OpenFont("romfs:/arial-unicode-ms.ttf", 30); + ARIAL_UNICODE = TTF_OpenFont("romfs:/arial.ttf", 35); if (!ARIAL_UNICODE) { Term_Services(); } @@ -122,20 +122,15 @@ int main(int argc, char *argv[]) { Init_Services(); std::cout << "Opening test.epub" << std::endl; - Menu_OpenBook("/switch/eBookReader/books/test.pdf"); + Menu_OpenBook("/switch/eBookReader/books/test.epub"); //Menu_OpenBook("/switch/eBookReader/books/test.epub"); while (run) { while (SDL_PollEvent(&EVENT)) { switch (EVENT.type) { case SDL_JOYAXISMOTION: - SDL_Log("Joystick %d axis %d value: %d\n", - EVENT.jaxis.which, - EVENT.jaxis.axis, EVENT.jaxis.value); break; case SDL_JOYBUTTONDOWN: - SDL_Log("Joystick %d button %d down\n", - EVENT.jbutton.which, EVENT.jbutton.button); // https://github.com/devkitPro/SDL/blob/switch-sdl2/src/joystick/switch/SDL_sysjoystick.c#L52 // seek for joystick #0 if (EVENT.jbutton.which == 0) { @@ -158,56 +153,6 @@ int main(int argc, char *argv[]) { SDL_RenderPresent(RENDERER);*/ } - /*while (!done) { - while (SDL_PollEvent(&EVENT)) { - switch (EVENT.type) { - case SDL_JOYAXISMOTION: - SDL_Log("Joystick %d axis %d value: %d\n", - EVENT.jaxis.which, - EVENT.jaxis.axis, EVENT.jaxis.value); - break; - - case SDL_JOYBUTTONDOWN: - SDL_Log("Joystick %d button %d down\n", - EVENT.jbutton.which, EVENT.jbutton.button); - // https://github.com/devkitPro/SDL/blob/switch-sdl2/src/joystick/switch/SDL_sysjoystick.c#L52 - // seek for joystick #0 - if (EVENT.jbutton.which == 0) { - if (EVENT.jbutton.button == 0) { - // (A) button down - } else if (EVENT.jbutton.button == 10) { - // (+) button down - done = 1; - } - } - break; - - default: - break; - } - } - - SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); - SDL_RenderClear(renderer); - - // fill window bounds - SDL_SetRenderDrawColor(renderer, 111, 111, 111, 255); - SDL_GetWindowSize(window, &w, &h); - SDL_Rect f = {0, 0, w, h}; - SDL_RenderFillRect(renderer, &f); - - draw_rects(renderer, x, 0); - draw_rects(renderer, x, h - 64); - - SDL_RenderPresent(renderer); - - x++; - if (x > w - 192) { - x = 0; - } - }*/ - //SDL_Renderer *renderer, SDL_Surface* window_surface, TTF_Font *font, char *path - Term_Services(); return 0; } diff --git a/source/menu_book_reader.cpp b/source/menu_book_reader.cpp deleted file mode 100644 index b656bd7..0000000 --- a/source/menu_book_reader.cpp +++ /dev/null @@ -1,89 +0,0 @@ -#include - -extern "C" { - #include "menu_book_reader.h" - #include "common.h" - //#include "touch_helper.h" -} - -#include "BookReader.hpp" - -extern SDL_Renderer* RENDERER; -extern SDL_Window* WINDOW; -extern SDL_Surface* WINDOW_SURFACE; - -void Menu_OpenBook(char *path) { - BookReader *reader = new BookReader(RENDERER, path); - - /*TouchInfo touchInfo; - Touch_Init(&touchInfo);*/ - - while(appletMainLoop()) { - reader->draw(WINDOW_SURFACE, ARIAL_UNICODE); - - hidScanInput(); - //Touch_Process(&touchInfo); - u64 kDown = hidKeysDown(CONTROLLER_P1_AUTO); - u64 kHeld = hidKeysHeld(CONTROLLER_P1_AUTO); - - if ((kDown & KEY_B) || (kDown & KEY_PLUS)) { - std::cout << "B | PLUS" << std::endl; - break; - } - - if ((kDown & KEY_DLEFT) || (kDown & KEY_L)) { - std::cout << "B | LEFT" << std::endl; - reader->previous_page(); - } - - if ((kDown & KEY_DRIGHT) || (kDown & KEY_R)) { - std::cout << "B | RIGHT" << std::endl; - reader->next_page(); - } - - if (kDown & KEY_LSTICK) { - std::cout << "B | LEFT STICK KEY" << std::endl; - reader->reset_page(); - } - - if (kHeld & KEY_DUP) { - std::cout << "B | UP" << std::endl; - reader->zoom_in(); - } - - if (kHeld & KEY_DDOWN) { - std::cout << "B | DOWN" << std::endl; - reader->zoom_out(); - } - - if (kHeld & KEY_LSTICK_UP) { - std::cout << "B | LEFT STICK UP" << std::endl; - reader->move_page_up(); - } - - if (kHeld & KEY_LSTICK_DOWN) { - std::cout << "B | LEFT STICK DOWN" << std::endl; - reader->move_page_down(); - } - - if (kHeld & KEY_LSTICK_LEFT) { - std::cout << "B | LEFT STICK LEFT" << std::endl; - reader->move_page_left(); - } - - if (kHeld & KEY_LSTICK_RIGHT) { - std::cout << "B | LEFT STICK RIGHT" << std::endl; - reader->move_page_right(); - } - - /*if (touchInfo.state == TouchEnded && touchInfo.tapType != TapNone) - { - if (tapped_inside(touchInfo, 0, 0, 120, 720)) - reader->previous_page(); - else if (tapped_inside(touchInfo, 1160, 0, 1280, 720)) - reader->next_page(); - }*/ - } - - delete reader; -} diff --git a/source/menus/book-chooser/menu_chooser.cpp b/source/menus/book-chooser/menu_chooser.cpp new file mode 100644 index 0000000..e69de29 diff --git a/source/menus/book-chooser/menu_chooser.hpp b/source/menus/book-chooser/menu_chooser.hpp new file mode 100644 index 0000000..e69de29 diff --git a/source/menus/book/BookReader.cpp b/source/menus/book/BookReader.cpp new file mode 100644 index 0000000..4980bc3 --- /dev/null +++ b/source/menus/book/BookReader.cpp @@ -0,0 +1,183 @@ +#include "BookReader.hpp" +#include "PageLayout.hpp" +#include "LandscapePageLayout.hpp" +#include "common.h" +#include +//#include + +extern "C" { + #include "SDL_helper.h" + #include "status_bar.h" + //#include "config.h" +} + +fz_context *ctx = NULL; +/*config_t *config = NULL; + +static int load_last_page(const char *book_name) { + if (!config) { + config = (config_t *)malloc(sizeof(config_t)); + config_init(config); + config_read_file(config, "/switch/NX-Shell/last_book_pages.cfg"); + } + + config_setting_t *setting = config_setting_get_member(config_root_setting(config), book_name); + + if (setting) { + return config_setting_get_int(setting); + } + + return 0; +} + +static void save_last_page(const char *book_name, int current_page) { + config_setting_t *setting = config_setting_get_member(config_root_setting(config), book_name); + + if (!setting) { + setting = config_setting_add(config_root_setting(config), book_name, CONFIG_TYPE_INT); + } + + if (setting) { + config_setting_set_int(setting, current_page); + config_write_file(config, "/switch/NX-Shell/last_book_pages.cfg"); + } +}*/ + +BookReader::BookReader(const char *path) { + if (ctx == NULL) { + ctx = fz_new_context(NULL, NULL, 128 << 10); + fz_register_document_handlers(ctx); + } + + book_name = std::string(path).substr(std::string(path).find_last_of("/\\") + 1); + + std::string invalid_chars = " :/?#[]@!$&'()*+,;=."; + for (char& c: invalid_chars) { + book_name.erase(std::remove(book_name.begin(), book_name.end(), c), book_name.end()); + } + + doc = fz_open_document(ctx, path); + + //int current_page = load_last_page(book_name.c_str()); + int current_page = 0; + switch_current_page_layout(_currentPageLayout, current_page); + + if (current_page > 0) { + show_status_bar(); + } +} + +BookReader::~BookReader() { + fz_drop_document(ctx, doc); + + delete layout; +} + +void BookReader::previous_page(int n) { + layout->previous_page(n); + show_status_bar(); + //save_last_page(book_name.c_str(), layout->current_page()); +} + +void BookReader::next_page(int n) { + layout->next_page(n); + show_status_bar(); + //save_last_page(book_name.c_str(), layout->current_page()); +} + +void BookReader::zoom_in() { + layout->zoom_in(); + show_status_bar(); +} + +void BookReader::zoom_out() { + layout->zoom_out(); + show_status_bar(); +} + +void BookReader::move_page_up() { + layout->move_up(); +} + +void BookReader::move_page_down() { + layout->move_down(); +} + +void BookReader::move_page_left() { + layout->move_left(); +} + +void BookReader::move_page_right() { + layout->move_right(); +} + +void BookReader::reset_page() { + layout->reset(); + show_status_bar(); +} + +void BookReader::switch_page_layout() { + switch (_currentPageLayout) { + case BookPageLayoutPortrait: + switch_current_page_layout(BookPageLayoutLandscape, 0); + break; + case BookPageLayoutLandscape: + switch_current_page_layout(BookPageLayoutPortrait, 0); + break; + } +} + +void BookReader::draw() { + /*if (config_dark_theme == true) + SDL_ClearScreen(RENDERER, SDL_MakeColour(33, 39, 43, 255)); + else */ + SDL_ClearScreen(RENDERER, SDL_MakeColour(255, 255, 255, 255)); + + SDL_RenderClear(RENDERER); + + layout->draw_page(); + +#ifdef __SWITCH__ + if (--status_bar_visible_counter > 0) { + char *title = layout->info(); + + int title_width = 0, title_height = 0; + //TTF_SizeText(Roboto, title, &title_width, &title_height); + TTF_SizeText(ARIAL_UNICODE, title, &title_width, &title_height); + + //SDL_Color color = config_dark_theme ? STATUS_BAR_DARK : STATUS_BAR_LIGHT; + SDL_Color color = STATUS_BAR_LIGHT; + + SDL_DrawRect(RENDERER, 0, 0, 1280, 40, SDL_MakeColour(color.r, color.g, color.b , 128)); + //SDL_DrawText(RENDERER, Roboto, (1280 - title_width) / 2, (44 - title_height) / 2, WHITE, title); + SDL_DrawText(RENDERER, ARIAL_UNICODE, (1280 - title_width) / 2, (44 - title_height) / 2, WHITE, title); + + StatusBar_DisplayTime(); + } +#endif + + SDL_RenderPresent(RENDERER); +} + +void BookReader::show_status_bar() { + status_bar_visible_counter = 50; +} + +void BookReader::switch_current_page_layout(BookPageLayout bookPageLayout, int current_page) { + if (layout) { + current_page = layout->current_page(); + delete layout; + layout = NULL; + } + + _currentPageLayout = bookPageLayout; + + switch (bookPageLayout) { + case BookPageLayoutPortrait: + layout = new PageLayout(doc, current_page); + break; + case BookPageLayoutLandscape: + layout = new LandscapePageLayout(doc, current_page); + break; + } +} diff --git a/source/menus/book/BookReader.hpp b/source/menus/book/BookReader.hpp new file mode 100644 index 0000000..8ad0748 --- /dev/null +++ b/source/menus/book/BookReader.hpp @@ -0,0 +1,52 @@ +#ifndef EBOOK_READER_BOOK_READER_HPP +#define EBOOK_READER_BOOK_READER_HPP + +#include +#include +#include "PageLayout.hpp" + +struct SDL_Texture; + +typedef enum +{ + BookPageLayoutPortrait, + BookPageLayoutLandscape +} BookPageLayout; + +class BookReader +{ + public: + BookReader(const char *path); + ~BookReader(); + + void previous_page(int n); + void next_page(int n); + void zoom_in(); + void zoom_out(); + void move_page_up(); + void move_page_down(); + void move_page_left(); + void move_page_right(); + void reset_page(); + void switch_page_layout(); + void draw(); + + BookPageLayout currentPageLayout() + { + return _currentPageLayout; + } + + private: + void show_status_bar(); + void switch_current_page_layout(BookPageLayout bookPageLayout, int current_page); + + fz_document *doc = NULL; + int status_bar_visible_counter = 0; + + BookPageLayout _currentPageLayout = BookPageLayoutPortrait; + PageLayout *layout = NULL; + + std::string book_name; +}; + +#endif diff --git a/source/menus/book/LandscapePageLayout.cpp b/source/menus/book/LandscapePageLayout.cpp new file mode 100644 index 0000000..241442b --- /dev/null +++ b/source/menus/book/LandscapePageLayout.cpp @@ -0,0 +1,40 @@ +#include "LandscapePageLayout.hpp" +#include "common.h" +#include + +LandscapePageLayout::LandscapePageLayout(fz_document *doc, int current_page):PageLayout(doc, current_page) +{ + int w = viewport.w; + viewport.w = viewport.h; + viewport.h = w; + + render_page_to_texture(_current_page, true); + reset(); +} + +void LandscapePageLayout::reset() +{ + page_center = fz_make_point(viewport.h / 2, viewport.w / 2); + set_zoom(min_zoom); +}; + +void LandscapePageLayout::draw_page() +{ + float w = page_bounds.x1 * zoom, h = page_bounds.y1 * zoom; + + SDL_Rect rect; + rect.y = page_center.y - h / 2; + rect.x = page_center.x - w / 2; + rect.w = w; + rect.h = h; + + SDL_RenderCopyEx(RENDERER, page_texture, NULL, &rect, 90, NULL, SDL_FLIP_NONE); +} + +void LandscapePageLayout::move_page(float x, float y) +{ + float w = page_bounds.x1 * zoom, h = page_bounds.y1 * zoom; + + page_center.x = fmin(fmax(page_center.x + y, h / 2), viewport.h - h / 2); + page_center.y = fmin(fmax(page_center.y + x, viewport.w - w / 2), w / 2); +} diff --git a/source/menus/book/LandscapePageLayout.hpp b/source/menus/book/LandscapePageLayout.hpp new file mode 100644 index 0000000..672edbb --- /dev/null +++ b/source/menus/book/LandscapePageLayout.hpp @@ -0,0 +1,18 @@ +#ifndef EBOOK_READER_LANDSCAPE_PAGE_LAYOUT_HPP +#define EBOOK_READER_LANDSCAPE_PAGE_LAYOUT_HPP + +#include "PageLayout.hpp" + +class LandscapePageLayout: public PageLayout +{ + public: + LandscapePageLayout(fz_document *doc, int current_page); + + void reset(); + void draw_page(); + + protected: + void move_page(float x, float y); +}; + +#endif diff --git a/source/menus/book/PageLayout.cpp b/source/menus/book/PageLayout.cpp new file mode 100644 index 0000000..b40d561 --- /dev/null +++ b/source/menus/book/PageLayout.cpp @@ -0,0 +1,127 @@ +#include "PageLayout.hpp" +#include "common.h" +#include + +PageLayout::PageLayout(fz_document *doc, int current_page):doc(doc),pdf(pdf_specifics(ctx, doc)),pages_count(fz_count_pages(ctx, doc)) +{ + _current_page = std::min(std::max(0, current_page), pages_count - 1); + + SDL_RenderGetViewport(RENDERER, &viewport); + render_page_to_texture(_current_page, false); +} + +void PageLayout::previous_page(int n) +{ + render_page_to_texture(_current_page - n, false); +} + +void PageLayout::next_page(int n) +{ + render_page_to_texture(_current_page + n, false); +} + +void PageLayout::zoom_in() +{ + set_zoom(zoom + 0.1); +}; + +void PageLayout::zoom_out() +{ + set_zoom(zoom - 0.1); +}; + +void PageLayout::move_up() +{ + move_page(0, 50); +}; + +void PageLayout::move_down() +{ + move_page(0, -50); +}; + +void PageLayout::move_left() +{ + move_page(-50, 0); +}; + +void PageLayout::move_right() +{ + move_page(50, 0); +}; + +void PageLayout::reset() +{ + page_center = fz_make_point(viewport.w / 2, viewport.h / 2); + set_zoom(min_zoom); +}; + +void PageLayout::draw_page() +{ + float w = page_bounds.x1 * zoom, h = page_bounds.y1 * zoom; + + SDL_Rect rect; + rect.x = page_center.x - w / 2; + rect.y = page_center.y - h / 2; + rect.w = w; + rect.h = h; + + SDL_RenderCopy(RENDERER, page_texture, NULL, &rect); +} + +char* PageLayout::info() +{ + static char title[128]; + sprintf(title, "%i/%i, %.2f%%", _current_page + 1, pages_count, zoom * 100); + return title; +} + +void PageLayout::render_page_to_texture(int num, bool reset_zoom) +{ + FreeTextureIfNeeded(&page_texture); + + _current_page = std::min(std::max(0, num), pages_count - 1); + + fz_page *page = fz_load_page(ctx, doc, _current_page); + fz_rect bounds = fz_bound_page(ctx, page); + + if (page_bounds.x1 != bounds.x1 || page_bounds.y1 != bounds.y1 || reset_zoom) + { + page_bounds = bounds; + page_center = fz_make_point(viewport.w / 2, viewport.h / 2); + + min_zoom = fmin(viewport.w / bounds.x1, viewport.h / bounds.y1); + max_zoom = fmax(viewport.w / bounds.x1, viewport.h / bounds.y1); + zoom = min_zoom; + } + + fz_pixmap *pix = fz_new_pixmap_from_page_contents(ctx, page, fz_scale(zoom, zoom), fz_device_rgb(ctx), 0); + SDL_Surface *image = SDL_CreateRGBSurfaceFrom(pix->samples, pix->w, pix->h, pix->n * 8, pix->w * pix->n, 0x000000FF, 0x0000FF00, 0x00FF0000, 0); + page_texture = SDL_CreateTextureFromSurface(RENDERER, image); + + SDL_FreeSurface(image); + fz_drop_pixmap(ctx, pix); + + fz_drop_page(ctx, page); +} + +void PageLayout::set_zoom(float value) +{ + value = fmin(fmax(min_zoom, value), max_zoom); + + if (value == zoom) + return; + + zoom = value; + + render_page_to_texture(_current_page, false); + move_page(0, 0); +} + +void PageLayout::move_page(float x, float y) +{ + float w = page_bounds.x1 * zoom, h = page_bounds.y1 * zoom; + + page_center.x = fmin(fmax(page_center.x + x, w / 2), viewport.w - w / 2); + page_center.y = fmin(fmax(page_center.y + y, viewport.h - h / 2), h / 2); +} diff --git a/source/menus/book/PageLayout.hpp b/source/menus/book/PageLayout.hpp new file mode 100644 index 0000000..b7ead28 --- /dev/null +++ b/source/menus/book/PageLayout.hpp @@ -0,0 +1,58 @@ +#ifndef EBOOK_READER_PAGE_LAYOUT_HPP +#define EBOOK_READER_PAGE_LAYOUT_HPP + +#include +#include + +extern fz_context *ctx; + +static inline void FreeTextureIfNeeded(SDL_Texture **texture) +{ + if (texture && *texture) + { + SDL_DestroyTexture(*texture); + *texture = NULL; + } +} + +class PageLayout +{ + public: + PageLayout(fz_document *doc, int current_page); + + int current_page() + { + return _current_page; + } + + virtual void previous_page(int n); + virtual void next_page(int n); + virtual void zoom_in(); + virtual void zoom_out(); + virtual void move_up(); + virtual void move_down(); + virtual void move_left(); + virtual void move_right(); + virtual void reset(); + virtual void draw_page(); + virtual char* info(); + + protected: + virtual void render_page_to_texture(int num, bool reset_zoom); + virtual void set_zoom(float value); + virtual void move_page(float x, float y); + + fz_document *doc = NULL; + pdf_document *pdf = NULL; + const int pages_count = 0; + + int _current_page = 0; + fz_rect page_bounds = fz_empty_rect; + fz_point page_center = fz_make_point(0, 0); + float min_zoom = 1, max_zoom = 1, zoom = 1; + + SDL_Rect viewport; + SDL_Texture *page_texture = NULL; +}; + +#endif diff --git a/source/menus/book/menu_book_reader.cpp b/source/menus/book/menu_book_reader.cpp new file mode 100644 index 0000000..4ab27f4 --- /dev/null +++ b/source/menus/book/menu_book_reader.cpp @@ -0,0 +1,121 @@ +extern "C" { + #include "menu_book_reader.h" + #include "common.h" + //#include "touch_helper.h" +} + +#include "BookReader.hpp" + +void Menu_OpenBook(char *path) { + BookReader *reader = new BookReader(path); + + /*TouchInfo touchInfo; + Touch_Init(&touchInfo);*/ + + while(appletMainLoop()) { + reader->draw(); + + hidScanInput(); + + //Touch_Process(&touchInfo); + + u64 kDown = hidKeysDown(CONTROLLER_P1_AUTO); + u64 kHeld = hidKeysHeld(CONTROLLER_P1_AUTO); + + if (kDown & KEY_DLEFT) { + if (reader->currentPageLayout() == BookPageLayoutPortrait || (!hidGetHandheldMode())) + reader->previous_page(1); + else if ((reader->currentPageLayout() == BookPageLayoutLandscape) && (hidGetHandheldMode())) + reader->zoom_out(); + } else if (kDown & KEY_DRIGHT) { + if (reader->currentPageLayout() == BookPageLayoutPortrait || (!hidGetHandheldMode())) + reader->next_page(1); + else if ((reader->currentPageLayout() == BookPageLayoutLandscape) && (hidGetHandheldMode())) + reader->zoom_in(); + } + + if (kDown & KEY_R) { + reader->next_page(10); + } else if (kDown & KEY_L) { + reader->previous_page(10); + } + + if ((kDown & KEY_DUP) || (kHeld & KEY_RSTICK_UP)) { + if (reader->currentPageLayout() == BookPageLayoutPortrait || (!hidGetHandheldMode())) { + reader->zoom_in(); + } else if ((reader->currentPageLayout() == BookPageLayoutLandscape) && (hidGetHandheldMode())) { + reader->previous_page(1); + } + //reader->reset_page(); + } else if ((kDown & KEY_DDOWN) || (kHeld & KEY_RSTICK_DOWN)) { + if (reader->currentPageLayout() == BookPageLayoutPortrait || (!hidGetHandheldMode())) { + reader->zoom_out(); + } else if ((reader->currentPageLayout() == BookPageLayoutLandscape) && (hidGetHandheldMode())) { + reader->next_page(1); + } + //reader->reset_page(); + } + + if (kHeld & KEY_LSTICK_UP) { + if (reader->currentPageLayout() == BookPageLayoutPortrait || (!hidGetHandheldMode())) { + reader->move_page_up(); + } else if ((reader->currentPageLayout() == BookPageLayoutLandscape) && (hidGetHandheldMode())) { + reader->move_page_left(); + } + } else if (kHeld & KEY_LSTICK_DOWN) { + if (reader->currentPageLayout() == BookPageLayoutPortrait || (!hidGetHandheldMode())) { + reader->move_page_down(); + } else if ((reader->currentPageLayout() == BookPageLayoutLandscape) && (hidGetHandheldMode())) { + reader->move_page_right(); + } + } else if (kHeld & KEY_LSTICK_LEFT) { + if (reader->currentPageLayout() == BookPageLayoutPortrait || (!hidGetHandheldMode())) { + reader->move_page_left(); + } else if ((reader->currentPageLayout() == BookPageLayoutLandscape) && (hidGetHandheldMode())) { + reader->move_page_up(); + } + } else if (kHeld & KEY_LSTICK_RIGHT) { + if (reader->currentPageLayout() == BookPageLayoutPortrait || (!hidGetHandheldMode())) { + reader->move_page_right(); + } else if ((reader->currentPageLayout() == BookPageLayoutLandscape) && (hidGetHandheldMode())) { + reader->move_page_down(); + } + } + + if (kDown & KEY_B) { + break; + } + + if (kDown & KEY_LSTICK || kDown & KEY_RSTICK) { + reader->reset_page(); + } + + if (kDown & KEY_Y) { + reader->switch_page_layout(); + } + + /*if (touchInfo.state == TouchEnded && touchInfo.tapType != TapNone) + { + float tapRegion = 120; + + switch (reader->currentPageLayout()) + { + case BookPageLayoutPortrait: + if (tapped_inside(touchInfo, 0, 0, tapRegion, 720)) + reader->previous_page(1); + else if (tapped_inside(touchInfo, 1280 - tapRegion, 0, 1280, 720)) + reader->next_page(1); + break; + case BookPageLayoutLandscape: + if (tapped_inside(touchInfo, 0, 0, 1280, tapRegion)) + reader->previous_page(1); + else if (tapped_inside(touchInfo, 0, 720 - tapRegion, 1280, 720)) + reader->next_page(1); + reader->reset_page(); + break; + } + }*/ + } + + delete reader; +} diff --git a/source/status_bar.c b/source/status_bar.c index f8729f0..1e69cfa 100644 --- a/source/status_bar.c +++ b/source/status_bar.c @@ -4,37 +4,116 @@ #include "common.h" #include "SDL_helper.h" #include "status_bar.h" +#include "textures.h" -static char *Clock_GetCurrentTime(bool _12hour) { +static char *Clock_GetCurrentTime(void) +{ static char buffer[10]; - u64 current_time; - timeGetCurrentTime(TimeType_UserSystemClock, ¤t_time); - struct tm* time_struct = gmtime((const time_t *)¤t_time); - int hours = time_struct->tm_hour; - int minutes = time_struct->tm_min; - int amOrPm = 0; + time_t unixTime = time(NULL); + struct tm* timeStruct = gmtime((const time_t *)&unixTime); + int hours = (timeStruct->tm_hour); + int minutes = timeStruct->tm_min; + + bool amOrPm = false; + + if (hours < 12) + amOrPm = true; + if (hours == 0) + hours = 12; + else if (hours > 12) + hours = hours - 12; - if (_12hour) { - if (hours < 12) - amOrPm = 1; - if (hours == 0) - hours = 12; - else if (hours > 12) - hours = hours - 12; - - if ((hours >= 1) && (hours < 10)) - snprintf(buffer, 10, "%2i:%02i %s", hours, minutes, amOrPm ? "AM" : "PM"); - else - snprintf(buffer, 10, "%2i:%02i %s", hours, minutes, amOrPm ? "AM" : "PM"); - } + if ((hours >= 1) && (hours < 10)) + snprintf(buffer, 10, "%2i:%02i %s", hours, minutes, amOrPm ? "AM" : "PM"); + else + snprintf(buffer, 10, "%2i:%02i %s", hours, minutes, amOrPm ? "AM" : "PM"); return buffer; } -void StatusBar_DisplayTime(void) { - int width = 0, height = 0; - TTF_SizeText(ARIAL_UNICODE, Clock_GetCurrentTime(true), &width, &height); +static void StatusBar_GetBatteryStatus(int x, int y) +{ + u32 percent = 0; + ChargerType state; + int width = 0; + char buf[5]; - SDL_DrawText(WINDOW_SURFACE, ARIAL_UNICODE, 1900 - width, (40 - height)/2, WHITE, Clock_GetCurrentTime(true)); + if (R_FAILED(psmGetChargerType(&state))) + state = 0; + + if (R_SUCCEEDED(psmGetBatteryChargePercentage(&percent))) + { + if (percent < 20) + SDL_DrawImage(RENDERER, battery_low, x, 3); + else if ((percent >= 20) && (percent < 30)) + { + if (state != 0) + SDL_DrawImage(RENDERER, battery_20_charging, x, 3); + else + SDL_DrawImage(RENDERER, battery_20, x, 3); + } + else if ((percent >= 30) && (percent < 50)) + { + if (state != 0) + SDL_DrawImage(RENDERER, battery_50_charging, x, 3); + else + SDL_DrawImage(RENDERER, battery_50, x, 3); + } + else if ((percent >= 50) && (percent < 60)) + { + if (state != 0) + SDL_DrawImage(RENDERER, battery_50_charging, x, 3); + else + SDL_DrawImage(RENDERER, battery_50, x, 3); + } + else if ((percent >= 60) && (percent < 80)) + { + if (state != 0) + SDL_DrawImage(RENDERER, battery_60_charging, x, 3); + else + SDL_DrawImage(RENDERER, battery_60, x, 3); + } + else if ((percent >= 80) && (percent < 90)) + { + if (state != 0) + SDL_DrawImage(RENDERER, battery_80_charging, x, 3); + else + SDL_DrawImage(RENDERER, battery_80, x, 3); + } + else if ((percent >= 90) && (percent < 100)) + { + if (state != 0) + SDL_DrawImage(RENDERER, battery_90_charging, x, 3); + else + SDL_DrawImage(RENDERER, battery_90, x, 3); + } + else if (percent == 100) + { + if (state != 0) + SDL_DrawImage(RENDERER, battery_full_charging, x, 3); + else + SDL_DrawImage(RENDERER, battery_full, x, 3); + } + + snprintf(buf, 5, "%d%%", percent); + TTF_SizeText(Roboto, buf, &width, NULL); + SDL_DrawText(RENDERER, Roboto, (x - width - 10), y, WHITE, buf); + } + else + { + snprintf(buf, 5, "%d%%", percent); + TTF_SizeText(Roboto, buf, &width, NULL); + SDL_DrawText(RENDERER, Roboto, (x - width - 10), y, WHITE, buf); + SDL_DrawImage(RENDERER, battery_unknown, x, 1); + } +} + +void StatusBar_DisplayTime(void) +{ + int width = 0, height = 0; + TTF_SizeText(Roboto, Clock_GetCurrentTime(), &width, &height); + + StatusBar_GetBatteryStatus(1260 - width - 44, (40 - height) / 2); + SDL_DrawText(RENDERER, Roboto, 1260 - width, (40 - height) / 2, WHITE, Clock_GetCurrentTime()); } \ No newline at end of file