From 1effe15da2f7e2386f2432f706d62f6d0cb63317 Mon Sep 17 00:00:00 2001 From: J-D-K Date: Sat, 18 Aug 2018 23:22:07 -0400 Subject: [PATCH] WIP New text wrapping --- inc/gfx.h | 21 +++---- src/data.cpp | 2 +- src/file.cpp | 2 - src/gfx.c | 135 ++++++++++++++++++++++++++++++++++----------- src/ui.cpp | 6 +- src/ui/advmode.cpp | 15 +---- src/ui/clsui.cpp | 2 +- src/ui/fldrsel.cpp | 2 +- src/ui/menu.cpp | 9 ++- src/ui/miscui.cpp | 13 ++--- src/ui/ttlsel.cpp | 11 +++- src/util.cpp | 34 ------------ 12 files changed, 139 insertions(+), 113 deletions(-) diff --git a/inc/gfx.h b/inc/gfx.h index 2a764b0..37b7415 100644 --- a/inc/gfx.h +++ b/inc/gfx.h @@ -20,10 +20,11 @@ typedef struct typedef struct { FT_Library lib; - FT_Face face; + FT_Face face[6]; FT_Error libRet, faceRet; //Loads to buffer for speed for TTF uint8_t *fntData; + bool external; } font; typedef struct @@ -81,12 +82,12 @@ inline uint32_t clrGetColor(const clr c) //Draws text using f void drawText(const char *str, tex *target, const font *f, int x, int y, int sz, clr c); +//Draws text wrapping lines +void drawTextWrap(const char *str, tex *target, const font *f, int x, int y, int sz, clr c, int maxWidth); + //Returns text width size_t textGetWidth(const char *str, const font *f, int sz); -//Clears framebuffer to c -void clearBufferColor(const clr c); - //Draws rectangle at x, y with w, h void drawRect(tex *target, int x, int y, int w, int h, const clr c); @@ -131,12 +132,12 @@ void texSwapColors(tex *t, const clr old, const clr newColor); //Scales tex * scale and writes to out. Can only multiply for now void texScaleToTex(const tex *in, tex *out, int scale); - -//Draws directly to Switch's framebuffer -void texDrawDirect(const tex *in, int x, int y); +/* +TEX END +*/ //Loads and returns font with Switch shared font loaded -font *fontLoadSharedFont(PlSharedFontType fontType); +font *fontLoadSharedFonts(); //Loads and returns TTF font font *fontLoadTTF(const char *path); @@ -144,10 +145,6 @@ font *fontLoadTTF(const char *path); //Frees font void fontDestroy(font *f); -/* -TEX END -*/ - //returns framebuffer tex pointer extern tex *frameBuffer; #ifdef __cplusplus diff --git a/src/data.cpp b/src/data.cpp index 5565df7..b940853 100644 --- a/src/data.cpp +++ b/src/data.cpp @@ -203,7 +203,7 @@ namespace data if(R_SUCCEEDED(res)) { title.assign(ent->name); - titleSafe = util::safeString(ent->name); + titleSafe = util::safeString(title); if(titleSafe.empty()) { char tmp[18]; diff --git a/src/file.cpp b/src/file.cpp index 69fff34..5db69d1 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -132,7 +132,6 @@ namespace fs ui::progBar prog(fileSize); std::string copyString = "Copying " + from + "..."; - copyString = util::getWrappedString(copyString, 24, 1136); for(unsigned i = 0; i < fileSize; ) { f.read((char *)buff, BUFF_SIZE); @@ -165,7 +164,6 @@ namespace fs ui::progBar prog(fileSize); std::string copyString = "Copying " + from + "..."; - copyString = util::getWrappedString(copyString, 24, 1136); for(unsigned i = 0; i < fileSize; ) { f.read((char *)buff, BUFF_SIZE); diff --git a/src/gfx.c b/src/gfx.c index b28574c..3359724 100644 --- a/src/gfx.c +++ b/src/gfx.c @@ -99,15 +99,45 @@ static void drawGlyph(const FT_Bitmap *bmp, tex *target, int _x, int _y, const c } } +static inline void resizeFont(const font *f, int sz) +{ + if(f->external) + FT_Set_Char_Size(f->face[0], 0, sz * 64, 90, 90); + else + { + for(int i = 0; i < 6; i++) + FT_Set_Char_Size(f->face[i], 0, sz * 64, 90, 90); + } +} + +static inline FT_GlyphSlot loadGlyph(const uint32_t c, const font *f) +{ + if(f->external) + { + FT_Load_Glyph(f->face[0], FT_Get_Char_Index(f->face[0], c), FT_LOAD_RENDER); + return f->face[0]->glyph; + } + for(int i = 0; i < 6; i++) + { + FT_UInt cInd = 0; + if( (cInd = FT_Get_Char_Index(f->face[i], c)) != 0 && \ + FT_Load_Glyph(f->face[i], cInd, FT_LOAD_RENDER) == 0) + { + return f->face[i]->glyph; + } + } + + return NULL; +} + void drawText(const char *str, tex *target, const font *f, int x, int y, int sz, clr c) { int tmpX = x; FT_Error ret = 0; - FT_GlyphSlot slot = f->face->glyph; uint32_t tmpChr = 0; ssize_t unitCnt = 0; - FT_Set_Char_Size(f->face, 0, sz * 64, 90, 90); + resizeFont(f, sz); size_t length = strlen(str); for(unsigned i = 0; i < length; ) @@ -124,26 +154,60 @@ void drawText(const char *str, tex *target, const font *f, int x, int y, int sz, continue; } - ret = FT_Load_Glyph(f->face, FT_Get_Char_Index(f->face, tmpChr), FT_LOAD_RENDER); - if(ret) - return; + FT_GlyphSlot slot = loadGlyph(tmpChr, f); + if(ret == 0) + { + int drawY = y + (sz - slot->bitmap_top); + drawGlyph(&slot->bitmap, target, tmpX + slot->bitmap_left, drawY, c); - int drawY = y + (sz - slot->bitmap_top); - drawGlyph(&slot->bitmap, target, tmpX + slot->bitmap_left, drawY, c); + tmpX += slot->advance.x >> 6; + } + } +} - tmpX += slot->advance.x >> 6; +void drawTextWrap(const char *str, tex *target, const font *f, int x, int y, int sz, clr c, int maxWidth) +{ + char wordBuf[128]; + size_t nextbreak = 0; + size_t strLength = strlen(str); + int tmpX = x; + for(unsigned i = 0; i < strLength; ) + { + nextbreak = strcspn(&str[i], " /"); + + if(nextbreak == strLength) + { + drawText(&str[i], target, f, tmpX, y, sz, c); + break; + } + else + { + memset(wordBuf, 0, 128); + memcpy(wordBuf, &str[i], nextbreak + 1); + + size_t width = textGetWidth(wordBuf, f, sz); + + if(tmpX + width >= x + maxWidth) + { + tmpX = x; + y += sz + 8; + } + + drawText(wordBuf, target, f, tmpX, y, sz, c); + tmpX += width; + + i += strlen(wordBuf); + } } } size_t textGetWidth(const char *str, const font *f, int sz) { size_t width = 0; - uint32_t untCnt = 0, tmpChr = 0; - FT_GlyphSlot slot = f->face->glyph; FT_Error ret = 0; - FT_Set_Char_Size(f->face, 0, 64 * sz, 90, 90); + resizeFont(f, sz); size_t length = strlen(str); for(unsigned i = 0; i < length; ) @@ -154,7 +218,7 @@ size_t textGetWidth(const char *str, const font *f, int sz) break; i += untCnt; - ret = FT_Load_Glyph(f->face, FT_Get_Char_Index(f->face, tmpChr), FT_LOAD_RENDER); + FT_GlyphSlot slot = loadGlyph(tmpChr, f); if(ret) return 0; @@ -164,14 +228,6 @@ size_t textGetWidth(const char *str, const font *f, int sz) return width; } -void clearBufferColor(const clr clr) -{ - uint32_t *fb = (uint32_t *)gfxGetFramebuffer(NULL, NULL); - uint32_t clearClr = clrGetColor(clr); - for(unsigned i = 0; i < gfxGetFramebufferSize() / 4; i++, fb++) - *fb = clearClr; -} - void drawRect(tex *target, int x, int y, int w, int h, const clr c) { uint32_t clr = clrGetColor(c); @@ -494,27 +550,33 @@ void texScaleToTex(const tex *in, tex *out, int scale) } } -font *fontLoadSharedFont(PlSharedFontType fontType) +font *fontLoadSharedFonts() { - PlFontData plFont; - - if(R_FAILED(plGetSharedFontByType(&plFont, fontType))) - return NULL; - font *ret = malloc(sizeof(font)); - if((ret->libRet = FT_Init_FreeType(&ret->lib))) { free(ret); return NULL; } - if((ret->faceRet = FT_New_Memory_Face(ret->lib, plFont.address, plFont.size, 0, &ret->face))) + + for(int i = 0; i < 6; i++) { - free(ret); - return NULL; + PlFontData plFont; + if(R_FAILED(plGetSharedFontByType(&plFont, i))) + { + free(ret); + return NULL; + } + + if((ret->faceRet = FT_New_Memory_Face(ret->lib, plFont.address, plFont.size, 0, &ret->face[i]))) + { + free(ret); + return NULL; + } } + ret->external = false; ret->fntData = NULL; return ret; @@ -538,20 +600,27 @@ font *fontLoadTTF(const char *path) fread(ret->fntData, 1, ttfSize, ttf); fclose(ttf); - if((ret->faceRet = FT_New_Memory_Face(ret->lib, ret->fntData, ttfSize, 0, &ret->face))) + if((ret->faceRet = FT_New_Memory_Face(ret->lib, ret->fntData, ttfSize, 0, &ret->face[0]))) { free(ret->fntData); free(ret); return NULL; } + ret->external = true; + return ret; } void fontDestroy(font *f) { - if(f->faceRet == 0) - FT_Done_Face(f->face); + if(f->external && f->faceRet == 0) + FT_Done_Face(f->face[0]); + else if(!f->external && f->faceRet == 0) + { + for(int i = 0; i < 6; i++) + FT_Done_Face(f->face[i]); + } if(f->libRet == 0) FT_Done_FreeType(f->lib); if(f->fntData != NULL) diff --git a/src/ui.cpp b/src/ui.cpp index f4b4711..93c4818 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -11,7 +11,7 @@ #include "util.h" #include "file.h" -#define TITLE_TEXT "JKSV - 08/15/2018" +#define TITLE_TEXT "JKSV - 08/18/2018" //background that can be drawn from "/JKSV/back.jpg" static tex *background = NULL; @@ -104,7 +104,7 @@ namespace ui if(fs::fileExists(fs::getWorkDir() + "font.ttf")) shared = fontLoadTTF(std::string(fs::getWorkDir() + "font.ttf").c_str()); else - shared = fontLoadSharedFont(PlSharedFontType_KO); + shared = fontLoadSharedFonts(); if(fs::fileExists(fs::getWorkDir() + "cls.txt")) { @@ -260,7 +260,7 @@ namespace ui texDraw(buttonY, frameBuffer, startX += 72, 672); drawText("Dump All", frameBuffer, shared, startX += 38, 680, 14, mnuTxt); texDraw(buttonX, frameBuffer, startX += 96, 672); - drawText("Classic Mode", frameBuffer, shared, startX += 38, 680, 14, mnuTxt); + drawText("Text Mode", frameBuffer, shared, startX += 38, 680, 14, mnuTxt); } break; diff --git a/src/ui/advmode.cpp b/src/ui/advmode.cpp index 321c603..afa0827 100644 --- a/src/ui/advmode.cpp +++ b/src/ui/advmode.cpp @@ -12,7 +12,7 @@ static ui::menu saveMenu, sdMenu, copyMenu; //Paths + wrapped string paths -static std::string savePath, sdPath, saveWrap, sdWrap; +static std::string savePath, sdPath; //Adv Ctrl mode static int advMenuCtrl, advPrev; @@ -327,9 +327,6 @@ namespace ui savePath = "sv:/"; sdPath = "sdmc:/"; - saveWrap = "sv:/"; - sdWrap = "sdmc:/"; - saveList.reassign(savePath); sdList.reassign(sdPath); @@ -360,8 +357,8 @@ namespace ui saveMenu.draw(mnuTxt); sdMenu.draw(mnuTxt); - drawText(saveWrap.c_str(), frameBuffer, ui::shared, 16, 668, 14, mnuTxt); - drawText(sdWrap.c_str(), frameBuffer, ui::shared, 656, 668, 14, mnuTxt); + drawTextWrap(savePath.c_str(), frameBuffer, ui::shared, 16, 668, 14, mnuTxt, 600); + drawTextWrap(sdPath.c_str(), frameBuffer, ui::shared, 656, 668, 14, mnuTxt, 600); //OH BOY HERE WE GO if(down & KEY_A) @@ -375,7 +372,6 @@ namespace ui if(saveSel == 1 && savePath != "sv:/") { util::removeLastFolderFromString(savePath); - saveWrap = util::getWrappedString(savePath, 14, 600); saveList.reassign(savePath); util::copyDirListToMenu(saveList, saveMenu); @@ -383,7 +379,6 @@ namespace ui else if(saveSel > 1 && saveList.isDir(saveSel - 2)) { savePath += saveList.getItem(saveSel - 2) + "/"; - saveWrap = util::getWrappedString(savePath, 14, 600); saveList.reassign(savePath); util::copyDirListToMenu(saveList, saveMenu); @@ -398,7 +393,6 @@ namespace ui if(sdSel == 1 && sdPath != "sdmc:/") { util::removeLastFolderFromString(sdPath); - sdWrap = util::getWrappedString(sdPath, 14, 600); sdList.reassign(sdPath); util::copyDirListToMenu(sdList, sdMenu); @@ -406,7 +400,6 @@ namespace ui else if(sdSel > 1 && sdList.isDir(sdSel - 2)) { sdPath += sdList.getItem(sdSel - 2) + "/"; - sdWrap = util::getWrappedString(sdPath, 14, 600); sdList.reassign(sdPath); util::copyDirListToMenu(sdList, sdMenu); @@ -426,7 +419,6 @@ namespace ui if(advMenuCtrl == 0 && savePath != "sv:/") { util::removeLastFolderFromString(savePath); - saveWrap = util::getWrappedString(savePath, 14, 600); saveList.reassign(savePath); util::copyDirListToMenu(saveList, saveMenu); @@ -435,7 +427,6 @@ namespace ui else if(advMenuCtrl == 1 && sdPath != "sdmc:/") { util::removeLastFolderFromString(sdPath); - sdWrap = util::getWrappedString(sdPath, 14, 600); sdList.reassign(sdPath); util::copyDirListToMenu(sdList, sdMenu); diff --git a/src/ui/clsui.cpp b/src/ui/clsui.cpp index 64664c1..6b7b76a 100644 --- a/src/ui/clsui.cpp +++ b/src/ui/clsui.cpp @@ -91,7 +91,7 @@ namespace ui { util::makeTitleDir(data::curUser, data::curData); clsFolderPrep(data::curUser, data::curData); - folderMenuInfo = util::getWrappedString(util::getInfoString(data::curUser, data::curData), 18, 256); + folderMenuInfo = util::getInfoString(data::curUser, data::curData); mstate = CLS_FLD; } diff --git a/src/ui/fldrsel.cpp b/src/ui/fldrsel.cpp index fb2fa1d..443868e 100644 --- a/src/ui/fldrsel.cpp +++ b/src/ui/fldrsel.cpp @@ -38,7 +38,7 @@ namespace ui folderMenu.draw(mnuTxt); data::curData.icon.draw(48, 88); - drawText(folderMenuInfo.c_str(), frameBuffer, ui::shared, 32, 360, 18, ui::mnuTxt); + drawTextWrap(folderMenuInfo.c_str(), frameBuffer, ui::shared, 32, 360, 18, ui::mnuTxt, 224); if(down & KEY_A || fldNav[0].getEvent() == BUTTON_RELEASED || folderMenu.getTouchEvent() == MENU_DOUBLE_REL) { diff --git a/src/ui/menu.cpp b/src/ui/menu.cpp index e7db646..1e86f4a 100644 --- a/src/ui/menu.cpp +++ b/src/ui/menu.cpp @@ -30,12 +30,15 @@ namespace ui else { std::string tmp; - for(unsigned i = 0; i < add.length(); i++) + for(unsigned i = 0; i < add.length(); ) { - tmp += add[i]; + uint32_t tmpChr = 0; + ssize_t untCnt = decode_utf8(&tmpChr, (uint8_t *)&add.c_str()[i]); + + tmp += add.substr(i, untCnt); + i += untCnt; if(textGetWidth(tmp.c_str(), ui::shared, 18) >= rW - 16) { - tmp.replace(i - 2, 3, "..."); opt.push_back(tmp); break; } diff --git a/src/ui/miscui.cpp b/src/ui/miscui.cpp index 5331b63..05ac982 100644 --- a/src/ui/miscui.cpp +++ b/src/ui/miscui.cpp @@ -29,7 +29,7 @@ namespace ui //char tmp[64]; //sprintf(tmp, "%u / %u", (unsigned)prog, (unsigned)max); - drawText(text.c_str(), frameBuffer, ui::shared, 80, 256, 24, txtClr); + drawTextWrap(text.c_str(), frameBuffer, ui::shared, 80, 256, 24, txtClr, 752); //gfx::drawText(tmp, 80, 320, 64, 0x000000FF); } @@ -144,7 +144,6 @@ namespace ui void showMessage(const std::string& mess) { button ok("OK", 256, 496, 768, 96); - std::string wrapMess = util::getWrappedString(mess, 24, 752); while(true) { hidScanInput(); @@ -159,7 +158,7 @@ namespace ui break; ui::drawTextbox(256, 128, 768, 464); - drawText(wrapMess.c_str(), frameBuffer, ui::shared, 272, 144, 24, txtClr); + drawTextWrap(mess.c_str(), frameBuffer, ui::shared, 272, 144, 24, txtClr, 752); ok.draw(); texDrawInvert(ui::buttonA, frameBuffer, ok.getTx() + 56, ok.getTy() - 4); @@ -171,9 +170,7 @@ namespace ui { button ok("OK (A)", 256, 496, 768, 96); char tmp[512]; - std::string wrapMess = util::getWrappedString(mess, 48, 752); sprintf(tmp, "%s\n0x%08X", mess.c_str(), (unsigned)r); - while(true) { hidScanInput(); @@ -188,7 +185,7 @@ namespace ui break; ui::drawTextbox(256, 128, 768, 464); - drawText(tmp, frameBuffer, shared, 272, 144, 48, txtClr); + drawTextWrap(tmp, frameBuffer, shared, 272, 144, 48, txtClr, 752); ok.draw(); gfxHandleBuffs(); @@ -202,8 +199,6 @@ namespace ui button yes("Yes ", 256, 496, 384, 96); button no("No ", 640, 496, 384, 96); - std::string wrapMess = util::getWrappedString(mess, 24, 752); - while(true) { hidScanInput(); @@ -227,7 +222,7 @@ namespace ui } ui::drawTextbox(256, 128, 768, 464); - drawText(wrapMess.c_str(), frameBuffer, ui::shared, 272, 144, 24, txtClr); + drawTextWrap(mess.c_str(), frameBuffer, ui::shared, 272, 144, 24, txtClr, 752); yes.draw(); texDrawInvert(ui::buttonA, frameBuffer, yes.getTx() + 64, yes.getTy() - 4); no.draw(); diff --git a/src/ui/ttlsel.cpp b/src/ui/ttlsel.cpp index ec8894c..3f2e818 100644 --- a/src/ui/ttlsel.cpp +++ b/src/ui/ttlsel.cpp @@ -1,6 +1,8 @@ #include #include +#include + #include "ui.h" #include "uiupdate.h" #include "file.h" @@ -114,7 +116,6 @@ namespace ui { util::makeTitleDir(data::curUser, data::curData); folderMenuPrepare(data::curUser, data::curData); - folderMenuInfo = util::getWrappedString(util::getInfoString(data::curUser, data::curData), 18, 256); mstate = FLD_SEL; } @@ -199,7 +200,7 @@ namespace ui { util::makeTitleDir(data::curUser, data::curData); folderMenuPrepare(data::curUser, data::curData); - folderMenuInfo = util::getWrappedString(util::getInfoString(data::curUser, data::curData), 18, 256); + folderMenuInfo = util::getInfoString(data::curUser, data::curData); mstate = FLD_SEL; } @@ -224,5 +225,11 @@ namespace ui mstate = USR_SEL; return; } + else if(down & KEY_MINUS) + { + std::fstream bin("/JKSV/ttl.bin", std::ios::out | std::ios::binary); + bin.write(data::curUser.titles[selected].getTitle().c_str(), data::curUser.titles[selected].getTitle().length()); + bin.close(); + } } } diff --git a/src/util.cpp b/src/util.cpp index 03d005b..6ec239d 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -37,40 +37,6 @@ namespace util return std::string(fs::getWorkDir() + t.getTitleSafe() + "/"); } - std::string getWrappedString(const std::string& s, const unsigned& sz, const unsigned& maxWidth) - { - if(textGetWidth(s.c_str(), ui::shared, sz) < maxWidth) - return s; - - std::string ret = "", tmp = ""; - unsigned first = 0, lastSpace = 0; - - for(unsigned i = 0; i < s.length(); i++) - { - tmp += s[i]; - - // slash for really long file paths with no spaces. - if(s[i] == ' ' || s[i] == '/') - lastSpace = i; - - if(textGetWidth(tmp.c_str(), ui::shared, sz) >= maxWidth) - { - tmp.assign(s, first, (lastSpace + 1) - first); - - ret += tmp + "\n"; - - first = lastSpace + 1; - i = lastSpace; - - tmp.clear(); - } - } - if(!tmp.empty()) - ret += tmp; - - return ret; - } - void copyDirListToMenu(fs::dirList& d, ui::menu& m) { m.reset();