WIP New text wrapping

This commit is contained in:
J-D-K
2018-08-18 23:22:07 -04:00
parent da7944aaa0
commit 1effe15da2
12 changed files with 139 additions and 113 deletions

View File

@@ -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

View File

@@ -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];

View File

@@ -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);

135
src/gfx.c
View File

@@ -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)

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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)
{

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -1,6 +1,8 @@
#include <string>
#include <vector>
#include <fstream>
#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();
}
}
}

View File

@@ -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();