Update + some cleaning

This commit is contained in:
J-D-K 2018-07-08 05:33:06 -04:00
parent d34bf96f83
commit 570ee8884e
31 changed files with 863 additions and 482 deletions

View File

@ -38,7 +38,7 @@ INCLUDES := inc
EXEFS_SRC := exefs_src
APP_TITLE := JKSV
APP_AUTHOR := JK_
APP_VERSION := 07/01/2018
APP_VERSION := 07/08/2018
ROMFS := romfs
#---------------------------------------------------------------------------------
@ -159,6 +159,8 @@ clean:
#---------------------------------------------------------------------------------
send: $(BUILD)
@nxlink $(TARGET).nro
else
.PHONY: all

View File

@ -1,15 +1,16 @@
# JKSV
JKSV for Switch. Mostly to get familiar with libnx. **This is still a WIP. Nothing is final yet!**
JKSV for Switch. Mostly to get familiar with libnx. **This is still a WIP. Nothing is final yet!** **You will have to build the newer UI yourself. I'm not providing binaries until I consider it usable**
<img src="https://dl.dropboxusercontent.com/s/wk5igkkdt89ytob/JKSV.jpg" alt="JKSV" width="240"></img>
<img src="https://dl.dropboxusercontent.com/s/xaqycf724p8ut2n/JKSV_3.jpg" alt="JKSV" width="240"></img>
<img src="https://dl.dropboxusercontent.com/s/e5qvbiz88hsrtbc/JKSV_2.jpg" alt="JKSV" width="240"></img>
# Building:
1. Requires [devkitPro](https://devkitpro.org/) and [libnx](https://github.com/switchbrew/libnx)
2. Requires switch-freetype, libpng, and libjpeg-turbo
# Credits and Thanks:
* [shared-font](https://github.com/switchbrew/switch-portlibs-examples) example by yellows8
* Authors of switch-examples for account and save mounting code.
* Authors of switch-examples for account and save mounting code.

15
inc/clsui.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef CLSUI_H
#define CLSUI_H
#include "data.h"
namespace ui
{
void clsUserPrep();
void clsTitlePrep(data::user& u);
void classicUserMenuUpdate(const uint64_t& down, const uint64_t& held, const touchPosition& p);
void classicTitleMenuUpdate(const uint64_t& down, const uint64_t& held, const touchPosition& p);
}
#endif // CLSUI_H

View File

@ -10,7 +10,7 @@
namespace data
{
extern bool sysSave, forceMountable;
extern bool sysSave, forceMountable, smoothIcns;
//Loads user + title info
void loadDataInfo();
@ -20,11 +20,19 @@ namespace data
class icn
{
public:
//Loads jpeg icon from jpegData
void load(const uint64_t& _id, const uint8_t *jpegData, const size_t& jpegSize);
//Sets icon from image already loaded. Only used for default
void setIcon(const uint64_t& _id, const gfx::tex& _set);
//Draw
void draw(unsigned x, unsigned y);
//Draws skipping pixels for half size
void drawHalf(unsigned x, unsigned y);
uint64_t getTitleID();
uint64_t getTitleID() { return titleID;}
void deleteData();
@ -44,16 +52,16 @@ namespace data
bool isMountable(const u128& uID);
//Returns title + title without forbidden chars
std::string getTitle();
std::string getTitleSafe();
std::string getTitle() { return title;}
std::string getTitleSafe() { return titleSafe;}
//Returns ID
uint64_t getID();
uint64_t getID() {return id;}
//Game icon
icn icon;
FsSaveDataType getType();
FsSaveDataType getType() { return type;}
private:
FsSaveDataType type;
@ -73,11 +81,11 @@ namespace data
bool initNoChk(const u128& _id);
//Returns user ID
u128 getUID();
u128 getUID() {return userID;}
//Returns username
std::string getUsername();
std::string getUsernameSafe();
std::string getUsername() {return username;}
std::string getUsernameSafe() {return userSafe;}
//Vector for storing save data info for user
std::vector<titledata> titles;

View File

@ -31,6 +31,8 @@ namespace fs
//returns file properties as C++ string
std::string getFileProps(const std::string& _path);
bool fileExists(const std::string& _path);
//Just retrieves a listing for _path and stores it in item vector
class dirList
{

View File

@ -5,32 +5,27 @@
namespace gfx
{
//Inits graphics and shared font. Code for shared font is from switch-portlibs examples
bool init();
bool exit();
class color
{
public:
void fromRGBA(const uint8_t& _r, const uint8_t& _g, const uint8_t& _b, const uint8_t& _a);
void fromU32(const uint32_t& _px);
void invert();
//Changes gfx mode to linear double
void switchMode();
void setR(const uint8_t& _r) { rgb[3] = _r; }
void setG(const uint8_t& _g) { rgb[2] = _g; }
void setB(const uint8_t& _b) { rgb[1] = _b; }
void setA(const uint8_t& _a) { rgb[0] = _a; }
void handleBuffs();
uint8_t r() { return rgb[3]; }
uint8_t g() { return rgb[2]; }
uint8_t b() { return rgb[1]; }
uint8_t a() { return rgb[0]; }
uint32_t clr() { return rgb[0] << 24 | rgb[1] << 16 | rgb[2] << 8 | rgb[3]; }
//Clears framebuffer to clr. RGBA8
void clearBufferColor(const uint32_t& clr);
//Blends two pixels. Clr is the color to be drawn. FB should be the framebuffer pixel
uint32_t blend(const uint32_t& clr, const uint32_t& fb);
//Draws text using shared font.
void drawText(const std::string& str, unsigned x, unsigned y, const uint32_t& sz, const uint32_t& clr);
//Returns width of str
unsigned getTextWidth(const std::string& str, const uint32_t& sz);
//Returns height of text if using sz
unsigned getTextHeight(const uint32_t& sz);
//Draws a rectangle. clr = RGBA8. Be careful not to go outside framebuffer
void drawRectangle(uint32_t x, uint32_t y, const uint32_t& width, const uint32_t& height, const uint32_t& clr);
private:
uint8_t rgb[4];
};
//Old 3DS code for loading raw RGBA8 data
class tex
@ -41,21 +36,23 @@ namespace gfx
Only accepts RGBA8 PNGs
Others will have issues.
*/
void loadFromFile(const std::string& path);
//Icons
void loadJpegMem(const uint8_t *txData, const uint32_t& jpegSz);
void loadPNGFile(const std::string& path);
void loadJpegMem(const uint8_t *txData, const size_t& jpegSz);
void loadJpegFile(const std::string& path);
//Frees memory used by data
void deleteData();
uint16_t getWidth();
uint16_t getHeight();
const uint32_t *getDataPointer();
uint16_t getWidth() { return width;}
uint16_t getHeight() {return height;}
const uint32_t *getDataPointer() {return data;}
void draw(uint32_t x, uint32_t y);
void drawInvert(uint32_t x, uint32_t y);
void drawNoBlend(uint32_t x, uint32_t y);
//For lazy-scaling icons
//Skips every-other pixel and row, so 1/2 scale
void drawNoBlendSkip(unsigned x, unsigned y);
void drawNoBlendSkipSmooth(unsigned x, unsigned y);
//These only repeat pixels.
void drawRepeatHori(uint32_t x, uint32_t y, uint32_t w);
@ -69,6 +66,34 @@ namespace gfx
uint16_t width, height;
uint32_t *data = NULL;
};
//Inits graphics and shared font. Code for shared font is from switch-portlibs examples
bool init();
bool exit();
//Changes gfx mode to linear double
void switchMode();
void handleBuffs();
//Clears framebuffer to clr. RGBA8
void clearBufferColor(const uint32_t& clr);
//Blends two pixels. Clr is the color to be drawn. FB should be the framebuffer pixel
uint32_t blend(color& px, color& fb);
//Draws text using shared font.
void drawText(const std::string& str, unsigned x, unsigned y, const uint32_t& sz, const uint32_t& clr);
//Returns width of str
unsigned getTextWidth(const std::string& str, const uint32_t& sz);
//Returns height of text if using sz
unsigned getTextHeight(const uint32_t& sz);
//Draws a rectangle. clr = RGBA8. Be careful not to go outside framebuffer
void drawRectangle(uint32_t x, uint32_t y, const uint32_t& width, const uint32_t& height, const uint32_t& clr);
}
#endif // GFX_H

View File

@ -4,42 +4,38 @@
#include <string>
#include <vector>
#include "miscui.h"
namespace ui
{
class key
//The way it should have been. Inheritance drives me insane sometimes, but they're basically the same thing.
class key : button
{
public:
//Key constructor. Txt = what text is drawn. _let = letter, _txtSz = font size, _w, _h = width, height
key(const std::string& txt, const char& _let, const unsigned& _txtSz, const unsigned& _x, const unsigned& _y, const unsigned& _w, const unsigned& _h);
//Updates the text shown
key(const std::string& _txt, const char& _l, unsigned _x, unsigned _y, unsigned _w, unsigned _h);
//Returns char assigned to key
char getLet() { return let; }
//Updates displayed text
void updateText(const std::string& txt);
//Draws key
void draw();
//Tells if user is touching screen at key's position
bool isOver(const touchPosition& p);
//Tells if user has stopped touching
bool released(const touchPosition& p);
//returns character in 'let;
char getLet();
//toUpper
void toCaps();
//toLower
void toLower();
//Return properties about key
unsigned getX();
unsigned getY();
unsigned getW();
unsigned getH();
void draw() { button::draw();}
void update(const touchPosition& p) { button::update(p);}
int getEvent() { return button::getEvent(); }
int getX() { return button::getX(); }
int getY() { return button::getY(); }
int getW() { return w; }
int getH() { return h; }
private:
bool pressed;
char let;
unsigned x, y, w, h;
unsigned tX, tY;
unsigned txtSz;
std::string text;
touchPosition prev;
};
class keyboard

View File

@ -4,36 +4,53 @@
#include <string>
#include <vector>
#include "miscui.h"
enum menuTouch
{
MENU_NOTHING,
MENU_DOUBLE_REL
};
namespace ui
{
class menu
{
public:
void setParams(const unsigned& _x, const unsigned& _y, const unsigned& _rW);
//Adds option
void addOpt(const std::string& add);
//Clears menu stuff
~menu();
//Handles controller input
void handleInput(const uint64_t& down, const uint64_t& held);
void handleInput(const uint64_t& down, const uint64_t& held, const touchPosition& p);
//Returns selected option
int getSelected();
int getSelected() { return selected; }
//Returns touch event from buttons
int getTouchEvent() { return retEvent; }
//Draws the menu at x and y. rectWidth is the width of the rectangle drawn under the selected
void print(const unsigned& x, const unsigned& y, const uint32_t& textClr, const uint32_t& rectWidth);
void draw(const uint32_t& textClr);
//Clears and resets menu
void reset();
private:
//drawing x and y + rectangle width
unsigned x, y, rW, rY;
//Options vector
std::vector<std::string> opt;
//Selected + frame counting for auto-scroll
int selected = 0, fc = 0, start = 0;
int selected = 0, fc = 0, start = 0, retEvent = MENU_NOTHING;
//How much we shift the color of the rectangle
uint8_t clrSh = 0;
bool clrAdd = true;
ui::touchTrack track;
std::vector<ui::button> optButtons;
};
}

View File

@ -1,13 +1,20 @@
#ifndef MISCUI_H
#define MISCUI_H
enum touchTracks
enum buttonEvents
{
TOUCH_SWIPE_UP,
TOUCH_SWIPE_DOWN,
TOUCH_SWIPE_LEFT,
TOUCH_SWIPE_RIGHT,
TOUCH_NOTHING
BUTTON_NOTHING,
BUTTON_PRESSED,
BUTTON_RELEASED
};
enum trackEvents
{
TRACK_NOTHING,
TRACK_SWIPE_UP,
TRACK_SWIPE_DOWN,
TRACK_SWIPE_LEFT,
TRACK_SWIPE_RIGHT
};
//For smaller classes that aren't easy to get lost in and general functions
@ -34,33 +41,37 @@ namespace ui
{
public:
button(const std::string& _txt, unsigned _x, unsigned _y, unsigned _w, unsigned _h);
void update(const touchPosition& p);
bool isOver();
bool wasOver();
int getEvent() { return retEvent; }
void draw();
unsigned getX();
unsigned getY();
unsigned getX() { return x; }
unsigned getY() { return y; }
unsigned getTx() { return tx; }
unsigned getTy() { return ty; }
bool isOver(const touchPosition& p);
bool released(const touchPosition& p);
private:
bool pressed = false;
protected:
bool pressed = false, first = false;
int retEvent = BUTTON_NOTHING;
unsigned x, y, w, h;
unsigned tx, ty;
std::string text;
touchPosition prev;
touchPosition prev, cur;
};
//Not ready yet.
class touchTrack
{
public:
void trackTouch(const touchPosition& p);
void update(const touchPosition& p);
int getDifX();
int getDifY();
int getEvent() { return retTrack; }
private:
touchPosition prev, cur;
touchPosition pos[5];
int retTrack = TRACK_NOTHING;
int curPos = 0, avX = 0, avY = 0;
};
@ -70,7 +81,6 @@ namespace ui
bool confirm(const std::string& q);
bool confirmTransfer(const std::string& f, const std::string& t);
bool confirmDelete(const std::string& p);
void debShowTex(gfx::tex tx);
void drawTextbox(unsigned x, unsigned y, unsigned w, unsigned h);
}

View File

@ -14,9 +14,12 @@
namespace ui
{
extern bool clsMode;
//Colors to use now that I added theme detection
extern uint32_t clearClr, mnuTxt, txtClr, rectLt, rectSh, tboxClr;
//Button tex
extern gfx::tex buttonA, buttonB, buttonX, buttonY, buttonMin;
//Textbox graphics
extern gfx::tex cornerTopLeft, cornerTopRight, cornerBottomLeft, cornerBottomRight, horEdgeTop, horEdgeBot, vertEdgeLeft, vertEdgeRight;
@ -32,11 +35,11 @@ namespace ui
//Clears, draws UI + menus
void drawUI();
//Handles input and actions for UI menus. Sometimes draw thing specific to each
//Handles input and actions for UI menus. Sometimes draw things specific to each
void updateUserMenu(const uint64_t& down, const uint64_t& held, const touchPosition& p);
void updateTitleMenu(const uint64_t& down, const uint64_t& held, const touchPosition& p);
void updateFolderMenu(const uint64_t& down, const uint64_t& held);
void updateAdvMode(const uint64_t& down, const uint64_t& held);
void updateFolderMenu(const uint64_t& down, const uint64_t& held, const touchPosition& p);
void updateAdvMode(const uint64_t& down, const uint64_t& held, const touchPosition& p);
//switch case so we don't have problems with multiple main loops like 3DS
void runApp(const uint64_t& down, const uint64_t& held, const touchPosition& p);

View File

@ -27,6 +27,6 @@ namespace util
std::string safeString(const std::string& s);
std::string retTypeString(data::titledata& d);
std::string getInfoString(data::user& u, data::titledata& d);
}
#endif // UTIL_H

Binary file not shown.

After

Width:  |  Height:  |  Size: 729 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 707 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 692 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 557 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 548 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 778 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 767 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 713 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 693 B

89
src/clsui.cpp Normal file
View File

@ -0,0 +1,89 @@
#include <string>
#include <vector>
#include <switch.h>
#include "ui.h"
#include "data.h"
#include "file.h"
#include "util.h"
static ui::menu userMenu, titleMenu;
//So we can change state from here
extern int mstate;
//Set folderMenuInfo
extern std::string folderMenuInfo;
namespace ui
{
void clsUserPrep()
{
userMenu.reset();
userMenu.setParams(16, 88, 424);
for(unsigned i = 0; i < data::users.size(); i++)
userMenu.addOpt(data::users[i].getUsername());
}
void clsTitlePrep(data::user& u)
{
titleMenu.reset();
titleMenu.setParams(16, 88, 424);
for(unsigned i = 0; i < u.titles.size(); i++)
titleMenu.addOpt(u.titles[i].getTitle());
}
void classicUserMenuUpdate(const uint64_t& down, const uint64_t& held, const touchPosition& p)
{
userMenu.handleInput(down, held, p);
userMenu.draw(mnuTxt);
if(down & KEY_A)
{
data::curUser = data::users[userMenu.getSelected()];
clsTitlePrep(data::curUser);
mstate = 5;
}
else if(down & KEY_Y)
{
for(unsigned i = 0; i < data::users.size(); i++)
fs::dumpAllUserSaves(data::users[i]);
}
else if(down & KEY_X)
{
std::remove("cls.txt");
clsMode = false;
mstate = 0;//USR_SEL
}
}
void classicTitleMenuUpdate(const uint64_t& down, const uint64_t& held, const touchPosition& p)
{
titleMenu.handleInput(down, held, p);
titleMenu.draw(mnuTxt);
if(down & KEY_A)
{
data::curData = data::curUser.titles[titleMenu.getSelected()];
if(fs::mountSave(data::curUser, data::curData))
{
util::makeTitleDir(data::curUser, data::curData);
folderMenuPrepare(data::curUser, data::curData);
folderMenuInfo = util::getWrappedString(util::getInfoString(data::curUser, data::curData), 38, 256);
mstate = 2; //FLD_SEL
}
}
else if(down & KEY_Y)
{
fs::dumpAllUserSaves(data::curUser);
}
else if(down & KEY_B)
mstate = 4;//CLS_USR
}
}

View File

@ -47,12 +47,12 @@ namespace data
user curUser;
std::vector<icn> icons;
std::vector<user> users;
bool sysSave = false, forceMountable = true;
bool sysSave = false, forceMountable = true, smoothIcns = false;
void loadDataInfo()
{
//Load default icon
defIcn.loadFromFile("romfs:/img/icn/icnDefault.png");
defIcn.loadPNGFile("romfs:/img/icn/icnDefault.png");
//Create icon for it
icn defIcnIcon;
@ -95,7 +95,9 @@ namespace data
u = getUserIndex(info.userID);
titledata newData;
if(newData.init(info) && (!forceMountable || newData.isMountable(newUser.getUID())))
{
users[u].titles.push_back(newData);
}
}
}
else
@ -146,13 +148,9 @@ namespace data
void icn::drawHalf(unsigned x, unsigned y)
{
iconTex.drawNoBlendSkip(x, y);
iconTex.drawNoBlendSkipSmooth(x, y);
}
uint64_t icn::getTitleID()
{
return titleID;
}
void icn::deleteData()
{
@ -248,26 +246,6 @@ namespace data
return false;
}
std::string titledata::getTitle()
{
return title;
}
std::string titledata::getTitleSafe()
{
return titleSafe;
}
uint64_t titledata::getID()
{
return id;
}
FsSaveDataType titledata::getType()
{
return type;
}
bool user::init(const u128& _id)
{
Result res = 0;
@ -332,19 +310,4 @@ namespace data
return true;
}
u128 user::getUID()
{
return userID;
}
std::string user::getUsername()
{
return username;
}
std::string user::getUsernameSafe()
{
return userSafe;
}
}

View File

@ -29,7 +29,7 @@ namespace fs
if(r == -1)
return false;
}
else if(data::sysSave && open.getType() == FsSaveDataType_SystemSaveData)
else if(data::sysSave)
{
res = fsMount_SystemSaveData(&sv, open.getID());
if(R_FAILED(res))
@ -295,4 +295,16 @@ namespace fs
}
return ret;
}
bool fileExists(const std::string& path)
{
std::fstream chk(path, std::ios::in);
if(chk.is_open())
{
chk.close();
return true;
}
return false;
}
}

View File

@ -17,7 +17,7 @@
static FT_Error ret = 0, libret = 1, faceret = 1;
static FT_Library lib;
static FT_Face face;
static uint32_t frameBufWidth = 0;
static uint32_t fbw = 0;
namespace gfx
{
@ -86,59 +86,49 @@ namespace gfx
}
//switch-portlibs examples.
void drawGlyph(FT_Bitmap& bmp, uint32_t *frameBuf, unsigned x, unsigned y, const uint8_t& r, const uint8_t& g, const uint8_t& b)
void drawGlyph(const FT_Bitmap& bmp, uint32_t *fb, unsigned _x, unsigned _y, color& txtClr)
{
uint32_t frameX, frameY, tmpX, tmpY;
uint8_t *imgPtr = bmp.buffer;
if(bmp.pixel_mode != FT_PIXEL_MODE_GRAY)
return;
for(tmpY = 0; tmpY < bmp.rows; tmpY++)
uint8_t *imgPtr = bmp.buffer;
color fbPx;
for(unsigned y = _y; y < _y + bmp.rows; y++)
{
for(tmpX = 0; tmpX < bmp.width; tmpX++)
uint32_t *rowPtr = &fb[y * fbw + _x];
for(unsigned x = _x; x < _x + bmp.width; x++, imgPtr++, rowPtr++)
{
frameX = x + tmpX;
frameY = y + tmpY;
if(imgPtr[tmpX] > 0)
if(*imgPtr > 0)
{
uint32_t fbPx = frameBuf[frameY * frameBufWidth + frameX];
uint32_t txPx = imgPtr[tmpX] << 24 | b << 16 | g << 8 | r;
frameBuf[frameY * frameBufWidth + frameX] = blend(txPx, fbPx);
fbPx.fromU32(*rowPtr);
txtClr.setA(*imgPtr);
*rowPtr = blend(txtClr, fbPx);
}
}
imgPtr += bmp.pitch;
}
}
void drawText(const std::string& str, unsigned x, unsigned y, const uint32_t& sz, const uint32_t& clr)
{
//This offset needs to be fixed better
y = y + 27;
uint32_t tmpX = x;
int tmpX = x;
FT_Error ret = 0;
FT_UInt glyphIndex;
FT_GlyphSlot slot = face->glyph;
uint32_t tmpChr;
ssize_t unitCount = 0;
y += 27;
FT_Set_Char_Size(face, 0, 8 * sz, 300, 300);
uint32_t *frameBuffer = (uint32_t *)gfxGetFramebuffer(&frameBufWidth, NULL);
uint32_t *fb = (uint32_t *)gfxGetFramebuffer(&fbw, NULL);
uint8_t tmpStr[1024];
sprintf((char *)tmpStr, "%s", str.c_str());
uint8_t r, g, b;
r = clr & 0xFF;
g = clr >> 8 & 0xFF;
b = clr >> 16 & 0xFF;
color textColor;
textColor.fromU32(clr);
for(unsigned i = 0; i < str.length(); )
{
unitCount = decode_utf8(&tmpChr, &tmpStr[i]);
unitCount = decode_utf8(&tmpChr, (uint8_t *)&str.data()[i]);
if(unitCount <= 0)
break;
@ -150,15 +140,13 @@ namespace gfx
continue;
}
glyphIndex = FT_Get_Char_Index(face, tmpChr);
ret = FT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER);
ret = FT_Load_Glyph(face, FT_Get_Char_Index(face, tmpChr), FT_LOAD_RENDER);
if(ret)
return;
drawGlyph(slot->bitmap, frameBuffer, tmpX + slot->bitmap_left, y - slot->bitmap_top, r, g, b);
drawGlyph(slot->bitmap, fb, tmpX + slot->bitmap_left, y - slot->bitmap_top, textColor);
tmpX += slot->advance.x >> 6;
y += slot->advance.y >> 6;
}
}
@ -171,14 +159,11 @@ namespace gfx
FT_GlyphSlot slot = face->glyph;
FT_Error ret = 0;
uint8_t tmpstr[1024];
sprintf((char *)tmpstr, "%s", str.c_str());
FT_Set_Char_Size(face, 0, 8 * sz, 300, 300);
for(unsigned i = 0; i < str.length(); )
{
unitCount = decode_utf8(&tmpChr, &tmpstr[i]);
unitCount = decode_utf8(&tmpChr, (uint8_t *)&str.data()[i]);
if(unitCount <= 0)
break;
@ -218,25 +203,19 @@ namespace gfx
std::memset(fb, clr, fbSize);
}
uint32_t blend(const uint32_t& clr, const uint32_t& fb)
uint32_t blend(color& px, color& fb)
{
uint8_t r1, g1, b1, al;
r1 = clr & 0xFF;
g1 = clr >> 8 & 0xFF;
b1 = clr >> 16 & 0xFF;
al = clr >> 24 & 0xFF;
//Skip fully transparent and solid pixels and not waste time
if(px.a() == 0)
return fb.clr();
else if(px.a() == 0xFF)
return px.clr();
//Assuming this is FB
uint8_t r2, g2, b2;
r2 = fb & 0xFF;
g2 = fb >> 8 & 0xFF;
b2 = fb >> 16 & 0xFF;
uint8_t subAl = (uint8_t)0xFF - px.a();
uint8_t subAl = (uint8_t)0xFF - al;
uint8_t finalRed = (r1 * al + r2 * subAl) / 0xFF;
uint8_t finalGreen = (g1 * al + g2 * subAl) / 0xFF;
uint8_t finalBlue = (b1 * al + b2 * subAl) / 0xFF;
uint8_t finalRed = (px.r() * px.a() + fb.r() * subAl) / 0xFF;
uint8_t finalGreen = (px.g() * px.a() + fb.g() * subAl) / 0xFF;
uint8_t finalBlue = (px.b() * px.a() + fb.b() * subAl) / 0xFF;
return (0xFF << 24 | finalBlue << 16 | finalGreen << 8 | finalRed);
}
@ -244,18 +223,42 @@ namespace gfx
void drawRectangle(uint32_t x, uint32_t y, const uint32_t& width, const uint32_t& height, const uint32_t& clr)
{
uint32_t tX, tY;
uint32_t *frameBuffer = (uint32_t *)gfxGetFramebuffer(NULL, NULL);
uint32_t *fb = (uint32_t *)gfxGetFramebuffer(NULL, NULL);
for(tY = y; tY < y + height; tY++)
{
uint32_t *rowPtr = &fb[tY * fbw + x];
for(tX = x; tX < x + width; tX++)
{
frameBuffer[tY * frameBufWidth + tX] = clr;
*rowPtr++ = clr;
}
}
}
void tex::loadFromFile(const std::string& path)
void color::fromRGBA(const uint8_t& _r, const uint8_t& _g, const uint8_t& _b, const uint8_t& _a)
{
rgb[0] = _a;
rgb[1] = _b;
rgb[2] = _g;
rgb[3] = _r;
}
void color::fromU32(const uint32_t& _px)
{
rgb[0] = _px >> 24 & 0xFF;
rgb[1] = _px >> 16 & 0xFF;
rgb[2] = _px >> 8 & 0xFF;
rgb[3] = _px & 0xFF;
}
void color::invert()
{
rgb[3] = 0xFF - rgb[3];
rgb[2] = 0xFF - rgb[2];
rgb[1] = 0xFF - rgb[1];
}
void tex::loadPNGFile(const std::string& path)
{
FILE *pngIn = fopen(path.c_str(), "rb");
if(pngIn != NULL)
@ -276,8 +279,7 @@ namespace gfx
png_read_info(png, pngInfo);
unsigned clrType = png_get_color_type(png, pngInfo);
if(clrType != PNG_COLOR_TYPE_RGBA)
if(png_get_color_type(png, pngInfo) != PNG_COLOR_TYPE_RGBA)
return;
width = png_get_image_width(png, pngInfo);
@ -291,11 +293,12 @@ namespace gfx
png_read_image(png, rows);
for(unsigned y = 0, i = 0; y < height; y++)
uint32_t *dataPtr = &data[0];
for(unsigned y = 0; y < height; y++)
{
png_bytep row = rows[y];
for(unsigned x = 0; x < width * 4; x += 4, i++)
std::memcpy(&data[i], &row[x], sizeof(uint32_t));
uint32_t *rowPtr = (uint32_t *)rows[y];
for(unsigned x = 0; x < width; x++)
*dataPtr++ = *rowPtr++;
}
for(unsigned i = 0; i < height; i++)
@ -309,7 +312,7 @@ namespace gfx
}
}
void tex::loadJpegMem(const uint8_t *txData, const uint32_t& jpegSz)
void tex::loadJpegMem(const uint8_t *txData, const size_t& jpegSz)
{
struct jpeg_decompress_struct jpegInfo;
struct jpeg_error_mgr error;
@ -331,23 +334,20 @@ namespace gfx
jpeg_start_decompress(&jpegInfo);
//Do it line by line. All at once doesn't seem to work?
JSAMPARRAY row = (JSAMPARRAY)new JSAMPARRAY[sizeof(JSAMPROW)];
row[0] = (JSAMPROW)new JSAMPROW[(sizeof(JSAMPLE) * width) * 3];
//Makes stuff easier
uint8_t *ptr;
for(unsigned y = 0, i = 0; y < height; y++)
uint32_t *dataPtr = &data[0];
for(unsigned y = 0; y < height; y++)
{
jpeg_read_scanlines(&jpegInfo, row, 1);
unsigned x;
for(x = 0, ptr = row[0]; x < width; x++, ptr += 3, i++)
jpeg_read_scanlines(&jpegInfo, row, 1);
for(x = 0, ptr = row[0]; x < width; x++, ptr += 3)
{
uint8_t r, g, b;
r = ptr[0];
g = ptr[1];
b = ptr[2];
data[i] = 0xFF << 24 | b << 16 | g << 8 | r;
*dataPtr++ = (0xFF << 24 | ptr[2] << 16 | ptr[1] << 8 | ptr[0]);
}
}
@ -358,6 +358,57 @@ namespace gfx
delete[] row;
}
void tex::loadJpegFile(const std::string& path)
{
FILE *jpegFile = fopen(path.c_str(), "rb");
if(jpegFile != NULL)
{
struct jpeg_decompress_struct jpegInfo;
struct jpeg_error_mgr error;
jpegInfo.err = jpeg_std_error(&error);
jpeg_create_decompress(&jpegInfo);
jpeg_stdio_src(&jpegInfo, jpegFile);
jpeg_read_header(&jpegInfo, true);
//make sure we have RGB
if(jpegInfo.jpeg_color_space == JCS_YCbCr)
jpegInfo.out_color_space = JCS_RGB;
width = jpegInfo.image_width;
height = jpegInfo.image_height;
data = new uint32_t[width * height];
jpeg_start_decompress(&jpegInfo);
//Do it line by line. All at once doesn't seem to work?
JSAMPARRAY row = (JSAMPARRAY)new JSAMPARRAY[sizeof(JSAMPROW)];
row[0] = (JSAMPROW)new JSAMPROW[(sizeof(JSAMPLE) * width) * 3];
//Makes stuff easier
uint8_t *ptr;
uint32_t *dataPtr = &data[0];
for(unsigned y = 0; y < height; y++)
{
unsigned x;
jpeg_read_scanlines(&jpegInfo, row, 1);
for(x = 0, ptr = row[0]; x < width; x++, ptr += 3)
{
*dataPtr++ = (0xFF << 24 | ptr[2] << 16 | ptr[1] << 8 | ptr[0]);
}
}
jpeg_finish_decompress(&jpegInfo);
jpeg_destroy_decompress(&jpegInfo);
fclose(jpegFile);
delete row[0];
delete[] row;
}
}
void tex::deleteData()
{
if(data != NULL)
@ -367,34 +418,47 @@ namespace gfx
}
}
uint16_t tex::getWidth()
{
return width;
}
uint16_t tex::getHeight()
{
return height;
}
const uint32_t *tex::getDataPointer()
{
return data;
}
void tex::draw(uint32_t x, uint32_t y)
{
if(data != NULL)
{
uint32_t tY, tX, i = 0;
uint32_t *frameBuffer = (uint32_t *)gfxGetFramebuffer(NULL, NULL);
uint32_t tY, tX;
uint32_t *fb = (uint32_t *)gfxGetFramebuffer(NULL, NULL);
color dataClr, fbClr;
uint32_t *dataPtr = &data[0];
for(tY = y; tY < y + height; tY++)
{
for(tX = x; tX < x + width; tX++, i++)
uint32_t *rowPtr = &fb[tY * fbw + x];
for(tX = x; tX < x + width; tX++, rowPtr++)
{
uint32_t buf = frameBuffer[tY * frameBufWidth + tX];
frameBuffer[tY * frameBufWidth + tX] = blend(data[i], buf);
dataClr.fromU32(*dataPtr++);
fbClr.fromU32(*rowPtr);
*rowPtr = blend(dataClr, fbClr);
}
}
}
}
void tex::drawInvert(uint32_t x, uint32_t y)
{
if(data != NULL)
{
uint32_t tX, tY;
uint32_t *fb = (uint32_t *)gfxGetFramebuffer(NULL, NULL);
color dataClr, fbClr;
uint32_t *dataPtr = &data[0];
for(tY = y; tY < y + height; tY++)
{
uint32_t *rowPtr = &fb[tY * fbw + x];
for(tX = x; tX < x + width; tX++, rowPtr++)
{
dataClr.fromU32(*dataPtr++);
dataClr.invert();
fbClr.fromU32(*rowPtr);
*rowPtr = blend(dataClr, fbClr);
}
}
}
@ -404,14 +468,16 @@ namespace gfx
{
if(data != NULL)
{
uint32_t tY, tX, i = 0;
uint32_t tY, tX;
uint32_t *fb = (uint32_t *)gfxGetFramebuffer(NULL, NULL);
uint32_t *dataPtr = &data[0];
for(tY = y; tY < y + height; tY++)
{
for(tX = x; tX < x + width; tX++, i++)
uint32_t *rowPtr = &fb[tY * fbw + x];
for(tX = x; tX < x + width; tX++)
{
fb[tY * frameBufWidth + tX] = data[i];
*rowPtr++ = *dataPtr++;
}
}
}
@ -421,14 +487,47 @@ namespace gfx
{
if(data != NULL)
{
unsigned tY, tX, i = 0;
unsigned tY, tX;
uint32_t *fb = (uint32_t *)gfxGetFramebuffer(NULL, NULL);
for(tY = y; tY < y + (height / 2); tY++, i += width)
uint32_t *dataPtr = &data[0];
for(tY = y; tY < y + (height / 2); tY++, dataPtr += width)
{
for(tX = x; tX < x + (width / 2); tX++, i += 2)
uint32_t *rowPtr = &fb[tY * fbw + x];
for(tX = x; tX < x + (width / 2); tX++, dataPtr += 2)
{
fb[tY * frameBufWidth + tX] = data[i];
*rowPtr++ = *dataPtr;
}
}
}
}
uint32_t smooth(color& px1, color& px2)
{
uint8_t fR = (px1.r() + px2.r()) / 2;
uint8_t fG = (px1.g() + px2.g()) / 2;
uint8_t fB = (px1.b() + px2.b()) / 2;
return 0xFF << 24 | fB << 16 | fG << 8 | fR;
}
void tex::drawNoBlendSkipSmooth(unsigned x, unsigned y)
{
if(data != NULL)
{
unsigned tY, tX;
uint32_t *fb = (uint32_t *)gfxGetFramebuffer(NULL, NULL);
uint32_t *dataPtr = &data[0];
color px1, px2;
for(tY = y; tY < y + (height / 2); tY++, dataPtr += width)
{
uint32_t *rowPtr = &fb[tY * fbw + x];
for(tX = x; tX < x + (width / 2); tX++)
{
px1.fromU32(*dataPtr++);
px2.fromU32(*dataPtr++);
*rowPtr++ = smooth(px1, px2);
}
}
}
@ -438,15 +537,19 @@ namespace gfx
{
if(data != NULL)
{
uint32_t tY, tX, i = 0;
uint32_t tY, tX;
uint32_t *fb = (uint32_t *)gfxGetFramebuffer(NULL, NULL);
for(tY = y; tY < y + height; tY++, i++)
uint32_t *dataPtr = &data[0];
color dataClr, fbClr;
for(tY = y; tY < y + height; tY++, dataPtr++)
{
for(tX = x; tX < x + w; tX++)
uint32_t *rowPtr = &fb[tY * fbw + x];
for(tX = x; tX < x + w; tX++, rowPtr++)
{
uint32_t fbPx = fb[tY * frameBufWidth + tX];
fb[tY * frameBufWidth + tX] = blend(data[i], fbPx);
dataClr.fromU32(*dataPtr);
fbClr.fromU32(*rowPtr);
*rowPtr = blend(dataClr, fbClr);
}
}
}
@ -456,16 +559,17 @@ namespace gfx
{
if(data != NULL)
{
uint32_t tY, tX, i = 0;
uint32_t tY, tX;
uint32_t *fb = (uint32_t *)gfxGetFramebuffer(NULL, NULL);
for(tY = y; tY < y + height; tY++, i++)
uint32_t *dataPtr = &data[0];
for(tY = y; tY < y + height; tY++, dataPtr++)
{
uint32_t *rowPtr = &fb[tY * fbw + x];
for(tX = x; tX < x + w; tX++)
{
fb[tY * frameBufWidth + tX] = data[i];
*rowPtr++ = *dataPtr;
}
}
}
}
@ -474,17 +578,21 @@ namespace gfx
{
if(data != NULL)
{
uint32_t tY, tX, i = 0;
uint32_t tY, tX;
uint32_t *fb = (uint32_t *)gfxGetFramebuffer(NULL, NULL);
uint32_t *dataPtr = &data[0];
color dataClr, fbClr;
for(tY = y; tY < y + h; tY++)
{
for(tX = x; tX < x + width; tX++, i++)
uint32_t *rowPtr = &fb[tY * fbw + x];
dataPtr = &data[0];
for(tX = x; tX < x + width; tX++, dataPtr++, rowPtr++)
{
uint32_t fbPx = fb[tY * frameBufWidth + tX];
fb[tY * frameBufWidth + tX] = blend(data[i], fbPx);
dataClr.fromU32(*dataPtr);
fbClr.fromU32(*rowPtr);
*rowPtr = blend(dataClr, fbClr);
}
i = 0;
}
}
}
@ -493,16 +601,18 @@ namespace gfx
{
if(data != NULL)
{
uint32_t tY, tX, i = 0;
uint32_t tY, tX;
uint32_t *fb = (uint32_t *)gfxGetFramebuffer(NULL, NULL);
uint32_t *dataPtr = &data[0];
for(tY = y; tY < y + h; tY++)
{
for(tX = x; tX < x + width; tX++, i++)
uint32_t *rowPtr = &fb[tY * fbw + x];
dataPtr = &data[0];
for(tX = x; tX < x + width; tX++, dataPtr++)
{
fb[tY * frameBufWidth + tX] = data[i];
*rowPtr++ = *dataPtr;
}
i = 0;
}
}
}

View File

@ -14,21 +14,9 @@ static const char qwerty[] =
namespace ui
{
key::key(const std::string& txt, const char& _let, const unsigned& _txtSz, const unsigned& _x, const unsigned& _y, const unsigned& _w, const unsigned& _h)
key::key(const std::string& _txt, const char& _l, unsigned _x, unsigned _y, unsigned _w, unsigned _h) : button(_txt, _x, _y, _w, _h)
{
x = _x;
y = _y;
w = _w;
h = _h;
txtSz = _txtSz;
let = _let;
text = txt;
tX = x + 16;
tY = y + 16;
pressed = false;
let = _l;
}
void key::updateText(const std::string& txt)
@ -36,51 +24,11 @@ namespace ui
text = txt;
}
void key::draw()
{
if(pressed)
gfx::drawRectangle(x, y, w, h, 0xFF2D2D2D);
else
gfx::drawRectangle(x, y, w, h, 0xFFEBEBEB);
gfx::drawText(text, tX, tY, txtSz, 0xFF000000);
}
bool key::isOver(const touchPosition& p)
{
return (p.px > x && p.px < x + w) && (p.py > y && p.py < y + h);
}
bool key::released(const touchPosition& p)
{
prev = p;
if(isOver(p))
pressed = true;
else
{
uint32_t touchCount = hidTouchCount();
if(pressed && touchCount == 0)
{
pressed = false;
return true;
}
else
pressed = false;
}
return false;
}
char key::getLet()
{
return let;
}
void key::toCaps()
{
let = toupper(let);
char tmp[8];
char tmp[2];
sprintf(tmp, "%c", let);
updateText(tmp);
}
@ -94,51 +42,28 @@ namespace ui
updateText(tmp);
}
unsigned key::getX()
{
return x;
}
unsigned key::getY()
{
return y;
}
unsigned key::getW()
{
return w;
}
unsigned key::getH()
{
return h;
}
keyboard::keyboard()
{
int x = 160, y = 256;
for(unsigned i = 0; i < 40; i++, x += 96)
{
char tmp[2];
sprintf(tmp, "%c", qwerty[i]);
key newKey(tmp, qwerty[i], 64, x, y, 80, 80);
keys.push_back(newKey);
char ch = qwerty[i];
if(ch == '0' || ch == 'p' || ch == '_')
for(int y = 256, i = 0; i < 40; y += 96)
{
int endRow = i + 10;
for(int x = 160; i < endRow; x += 96, i++)
{
x = 64;
y += 96;
char tmp[2];
sprintf(tmp, "%c", qwerty[i]);
key newKey(tmp, qwerty[i], x, y, 80, 80);
keys.push_back(newKey);
}
}
//spc key
key shift("Shift", ' ', 64, 16, 544, 128, 80);
key shift("Shift", ' ', 16, 544, 128, 80);
//Space bar needs to be trimmed back so we don't try to draw off buffer
key space(" ", ' ', 64, 240, 640, 800, 72);
key bckSpc("Back", ' ', 64, 1120, 256, 128, 80);
key enter("Entr", ' ', 64, 1120, 352, 128, 80);
key cancel("Cancl", ' ', 64, 1120, 448, 128, 80);
key space(" ", ' ', 240, 640, 800, 72);
key bckSpc("Back", ' ', 1120, 256, 128, 80);
key enter("Entr", ' ', 1120, 352, 128, 80);
key cancel("Cancl", ' ', 1120, 448, 128, 80);
keys.push_back(space);
keys.push_back(shift);
@ -227,14 +152,18 @@ namespace ui
//Stndrd key
for(unsigned i = 0; i < 41; i++)
{
if(keys[i].released(p))
keys[i].update(p);
if(keys[i].getEvent() == BUTTON_RELEASED)
{
str += keys[i].getLet();
}
}
for(unsigned i = 41; i < 44; i++)
keys[i].update(p);
//shift
if(keys[41].released(p) || down & KEY_LSTICK)
if(keys[41].getEvent() == BUTTON_RELEASED || down & KEY_LSTICK)
{
if(keys[10].getLet() == 'q')
{
@ -248,16 +177,16 @@ namespace ui
}
}
//bckspace
else if(keys[42].released(p) || down & KEY_Y)
else if(keys[42].getEvent() == BUTTON_RELEASED || down & KEY_Y)
{
if(!str.empty())
str.erase(str.end() - 1, str.end());
}
//enter
else if(keys[43].released(p) || down & KEY_PLUS)
else if(keys[43].getEvent() == BUTTON_RELEASED || down & KEY_PLUS)
break;
//cancel
else if(keys[44].released(p) || down & KEY_B)
else if(keys[44].getEvent() == BUTTON_RELEASED || down & KEY_B)
{
str.erase(str.begin(), str.end());
break;

View File

@ -1,4 +1,5 @@
#include <string>
#include <cstring>
#include <vector>
#include <fstream>
#include <switch.h>
@ -8,6 +9,7 @@
#include "gfx.h"
#include "data.h"
#include "ui.h"
#include "file.h"
extern "C"
{
@ -36,8 +38,10 @@ extern "C"
int main(int argc, const char *argv[])
{
gfx::init();
ui::init();
data::loadDataInfo();
ui::init();
appletSetScreenShotPermission(0);
bool run = true;
while(appletMainLoop() && run)

View File

@ -3,9 +3,25 @@
#include "gfx.h"
#include "menu.h"
#include "miscui.h"
namespace ui
{
void menu::setParams(const unsigned& _x, const unsigned& _y, const unsigned& _rW)
{
x = _x;
y = _y;
rW = _rW;
rY = _y;
for(unsigned i = 0; i < 15; i++)
{
//Init + push invisible options buttons
ui::button newOptButton("", x, y + i * 36, rW, 36);
optButtons.push_back(newOptButton);
}
}
void menu::addOpt(const std::string& add)
{
opt.push_back(add);
@ -16,7 +32,7 @@ namespace ui
opt.clear();
}
void menu::handleInput(const uint64_t& down, const uint64_t& held)
void menu::handleInput(const uint64_t& down, const uint64_t& held, const touchPosition& p)
{
if( (held & KEY_UP) || (held & KEY_DOWN))
fc++;
@ -66,14 +82,42 @@ namespace ui
if(selected < start)
start = selected;
}
//New touch shit
for(int i = 0; i < 15; i++)
{
optButtons[i].update(p);
if(selected == i && optButtons[i - start].getEvent() == BUTTON_RELEASED)
{
retEvent = MENU_DOUBLE_REL;
break;
}
else if(optButtons[i].getEvent() == BUTTON_RELEASED && i + start < (int)opt.size())
{
selected = i + start;
retEvent = MENU_NOTHING;
}
else
retEvent = MENU_NOTHING;
}
track.update(p);
switch(track.getEvent())
{
case TRACK_SWIPE_UP:
if(start + 15 < (int)opt.size())
start++, selected++;
break;
case TRACK_SWIPE_DOWN:
if(start - 1 >= 0)
start--, selected--;
break;
}
}
int menu::getSelected()
{
return selected;
}
void menu::print(const unsigned& x, const unsigned& y, const uint32_t& textClr, const uint32_t& rectWidth)
void menu::draw(const uint32_t& textClr)
{
if(clrAdd)
{
@ -99,7 +143,7 @@ namespace ui
for(int i = start; i < length; i++)
{
if(i == selected)
gfx::drawRectangle(x, y + ((i - start) * 36), rectWidth, 32, rectClr);
gfx::drawRectangle(x, y + ((i - start) * 36), rW, 32, rectClr);
gfx::drawText(opt[i], x, y + ((i - start) * 36), 38, textClr);
}

View File

@ -48,56 +48,98 @@ namespace ui
ty = y + (h / 2) - (th / 2);
}
void button::update(const touchPosition& p)
{
prev = cur;
cur = p;
//If button was first thing pressed
if(isOver() && prev.px == 0 && prev.py == 0)
{
first = true;
pressed = true;
retEvent = BUTTON_PRESSED;
}
else if(retEvent == BUTTON_PRESSED && hidTouchCount() == 0 && wasOver())
{
first = false;
pressed = false;
retEvent = BUTTON_RELEASED;
}
else if(retEvent != BUTTON_NOTHING && hidTouchCount() == 0)
{
first = false;
pressed = false;
retEvent = BUTTON_NOTHING;
}
}
bool button::isOver()
{
return (cur.px > x && cur.px < x + w && cur.py > y && cur.py < y + h);
}
bool button::wasOver()
{
return (prev.px > x && prev.px < x + w && prev.py > y && prev.py < y + h);
}
void button::draw()
{
if(pressed)
gfx::drawRectangle(x, y, w, h, 0xFFD0D0D0);
else
{
ui::drawTextbox(x, y, w, h);
}
gfx::drawText(text, tx, ty, 48, txtClr);
}
unsigned button::getX()
void touchTrack::update(const touchPosition& p)
{
return x;
}
unsigned button::getY()
{
return y;
}
bool button::isOver(const touchPosition& p)
{
return (p.px > x && p.px < x + w) && (p.py > y && p.py < y + h);
}
bool button::released(const touchPosition& p)
{
prev = p;
if(isOver(p))
pressed = true;
else
if(hidTouchCount() > 0)
{
uint32_t touchCount = hidTouchCount();
if(pressed && touchCount == 0)
pos[curPos++] = p;
if(curPos == 5)
{
pressed = false;
return true;
curPos = 0;
for(unsigned i = 1; i < 5; i++)
{
touchPosition c = pos[i], p = pos[i - 1];
avX += c.px - p.px;
avY += c.py - p.py;
}
avX /= 5;
avY /= 5;
if(avY <= -8)
retTrack = TRACK_SWIPE_UP;
else if(avY >= 8)
retTrack = TRACK_SWIPE_DOWN;
else if(retTrack <= -8)
retTrack = TRACK_SWIPE_LEFT;
else if(retTrack >= 8)
retTrack = TRACK_SWIPE_RIGHT;
else
retTrack = TRACK_NOTHING;
std::memset(pos, 0, sizeof(touchPosition) * 5);
}
else
pressed = false;
retTrack = TRACK_NOTHING;
}
else
{
retTrack = TRACK_NOTHING;
curPos = 0;
}
return false;
}
void showMessage(const std::string& mess)
{
button ok("OK (A)", 256, 496, 768, 96);
button ok("OK", 256, 496, 768, 96);
std::string wrapMess = util::getWrappedString(mess, 48, 752);
while(true)
{
@ -107,12 +149,15 @@ namespace ui
touchPosition p;
hidTouchRead(&p, 0);
if(down & KEY_A || down & KEY_B || ok.released(p))
ok.update(p);
if(down & KEY_A || down & KEY_B || ok.getEvent() == BUTTON_RELEASED)
break;
ui::drawTextbox(256, 128, 768, 464);
gfx::drawText(wrapMess, 272, 144, 48, txtClr);
ok.draw();
ui::buttonA.drawInvert(ok.getTx() + 48, ok.getTy());
gfx::handleBuffs();
}
@ -133,7 +178,9 @@ namespace ui
touchPosition p;
hidTouchRead(&p, 0);
if(down & KEY_A || down & KEY_B || ok.released(p))
ok.update(p);
if(down & KEY_A || down & KEY_B || ok.getEvent() == BUTTON_RELEASED)
break;
ui::drawTextbox(256, 128, 768, 464);
@ -148,8 +195,8 @@ namespace ui
{
bool ret = false;
button yes("Yes (A)", 256, 496, 384, 96);
button no("No (B)", 640, 496, 384, 96);
button yes("Yes ", 256, 496, 384, 96);
button no("No ", 640, 496, 384, 96);
std::string wrapMess = util::getWrappedString(mess, 48, 752);
@ -161,12 +208,15 @@ namespace ui
touchPosition p;
hidTouchRead(&p, 0);
if(down & KEY_A || yes.released(p))
yes.update(p);
no.update(p);
if(down & KEY_A || yes.getEvent() == BUTTON_RELEASED)
{
ret = true;
break;
}
else if(down & KEY_B || no.released(p))
else if(down & KEY_B || no.getEvent() == BUTTON_RELEASED)
{
ret = false;
break;
@ -175,7 +225,9 @@ namespace ui
ui::drawTextbox(256, 128, 768, 464);
gfx::drawText(wrapMess, 272, 144, 48, txtClr);
yes.draw();
ui::buttonA.drawInvert(yes.getTx() + 56, yes.getTy());
no.draw();
ui::buttonB.drawInvert(no.getTx() + 48, no.getTy());
gfx::handleBuffs();
}
@ -197,30 +249,6 @@ namespace ui
return confirm(confMess);
}
void debShowTex(gfx::tex tx)
{
unsigned tbX = 256, tbY = 128;
unsigned tbW = 768, tbH = 464;
unsigned texX = tbX + ((tbW / 2) - (tx.getWidth() / 2));
unsigned texY = tbY + ((tbH / 2) - (tx.getHeight() / 2));
while(true)
{
hidScanInput();
uint64_t down = hidKeysDown(CONTROLLER_P1_AUTO);
if(down & KEY_A)
break;
ui::drawTextbox(tbX, tbY, tbW, tbH);
tx.drawNoBlend(texX, texY);
gfx::handleBuffs();
}
}
void drawTextbox(unsigned x, unsigned y, unsigned w, unsigned h)
{
//Top

View File

@ -2,9 +2,11 @@
#include <vector>
#include <fstream>
#include <cstdio>
#include <cstring>
#include <switch.h>
#include "ui.h"
#include "clsui.h"
#include "gfx.h"
#include "util.h"
#include "file.h"
@ -14,25 +16,31 @@ enum menuState
USR_SEL,
TTL_SEL,
FLD_SEL,
ADV_MDE
ADV_MDE,
CLS_USR,
CLS_TTL
};
#define TITLE_TEXT "JKSV - 07/01/2018"
#define TITLE_TEXT "JKSV - 07/08/2018"
//Menu currently up
int mstate = USR_SEL;
//Button controlled menus
static ui::menu folderMenu, devMenu, saveMenu, sdMenu, copyMenu;
static ui::menu folderMenu, saveMenu, sdMenu, copyMenu;
//Bar at top
static gfx::tex buttonA, buttonB, buttonX, buttonY;
//Shhhh
static gfx::tex background;
//Shown if someone tries to write to system saves
static const std::string sysSaveMess = "No system saves until we get public NAND restore.";
//Advanced mode paths
static std::string savePath, sdPath, saveWrap, sdWrap, folderMenuInfo;
static std::string savePath, sdPath, saveWrap, sdWrap;
//This needs to be edited by clsui, so not static
std::string folderMenuInfo;
//Advanced mode directory listings
static fs::dirList saveList(""), sdList("");
//Current menu and previous menu for advanced mode.
@ -42,12 +50,17 @@ static std::vector<ui::button> selButtons;
namespace ui
{
bool clsMode = false;
uint32_t clearClr = 0xFFFFFFFF, mnuTxt = 0xFF000000, txtClr = 0xFF000000, \
rectLt = 0xFFC0C0C0, rectSh = 0, tboxClr = 0xFFC0C0C0;
//textbox pieces
//I was going to flip them when I draw them, but then laziness kicked in.
gfx::tex cornerTopLeft, cornerTopRight, cornerBottomLeft, cornerBottomRight, horEdgeTop, horEdgeBot, vertEdgeLeft, vertEdgeRight;
gfx::tex cornerTopLeft, cornerTopRight, cornerBottomLeft, cornerBottomRight, \
horEdgeTop, horEdgeBot, vertEdgeLeft, vertEdgeRight;
gfx::tex buttonA, buttonB, buttonX, buttonY, buttonMin;
void init()
{
@ -58,16 +71,23 @@ namespace ui
{
case ColorSetId_Light:
//Dark corners
cornerTopLeft.loadFromFile("romfs:/img/tbox/tboxCornerTopLeft_drk.png");
cornerTopRight.loadFromFile("romfs:/img/tbox/tboxCornerTopRight_drk.png");
cornerBottomLeft.loadFromFile("romfs:/img/tbox/tboxCornerBotLeft_drk.png");
cornerBottomRight.loadFromFile("romfs:/img/tbox/tboxCornerBotRight_drk.png");
cornerTopLeft.loadPNGFile("romfs:/img/tbox/tboxCornerTopLeft_drk.png");
cornerTopRight.loadPNGFile("romfs:/img/tbox/tboxCornerTopRight_drk.png");
cornerBottomLeft.loadPNGFile("romfs:/img/tbox/tboxCornerBotLeft_drk.png");
cornerBottomRight.loadPNGFile("romfs:/img/tbox/tboxCornerBotRight_drk.png");
//Dark edges
horEdgeTop.loadFromFile("romfs:/img/tbox/tboxHorEdgeTop_drk.png");
horEdgeBot.loadFromFile("romfs:/img/tbox/tboxHorEdgeBot_drk.png");
vertEdgeLeft.loadFromFile("romfs:/img/tbox/tboxVertEdgeLeft_drk.png");
vertEdgeRight.loadFromFile("romfs:/img/tbox/tboxVertEdgeRight_drk.png");
horEdgeTop.loadPNGFile("romfs:/img/tbox/tboxHorEdgeTop_drk.png");
horEdgeBot.loadPNGFile("romfs:/img/tbox/tboxHorEdgeBot_drk.png");
vertEdgeLeft.loadPNGFile("romfs:/img/tbox/tboxVertEdgeLeft_drk.png");
vertEdgeRight.loadPNGFile("romfs:/img/tbox/tboxVertEdgeRight_drk.png");
//Dark buttons
buttonA.loadPNGFile("romfs:/img/button/buttonA_drk.png");
buttonB.loadPNGFile("romfs:/img/button/buttonB_drk.png");
buttonX.loadPNGFile("romfs:/img/button/buttonX_drk.png");
buttonY.loadPNGFile("romfs:/img/button/buttonY_drk.png");
buttonMin.loadPNGFile("romfs:/img/button/buttonMin_drk.png");
clearClr = 0xFFEBEBEB;
mnuTxt = 0xFF000000;
@ -80,16 +100,23 @@ namespace ui
default:
case ColorSetId_Dark:
//Light corners
cornerTopLeft.loadFromFile("romfs:/img/tbox/tboxCornerTopLeft_lght.png");
cornerTopRight.loadFromFile("romfs:/img/tbox/tboxCornerTopRight_lght.png");
cornerBottomLeft.loadFromFile("romfs:/img/tbox/tboxCornerBotLeft_lght.png");
cornerBottomRight.loadFromFile("romfs:/img/tbox/tboxCornerBotRight_lght.png");
cornerTopLeft.loadPNGFile("romfs:/img/tbox/tboxCornerTopLeft_lght.png");
cornerTopRight.loadPNGFile("romfs:/img/tbox/tboxCornerTopRight_lght.png");
cornerBottomLeft.loadPNGFile("romfs:/img/tbox/tboxCornerBotLeft_lght.png");
cornerBottomRight.loadPNGFile("romfs:/img/tbox/tboxCornerBotRight_lght.png");
//light edges
horEdgeTop.loadFromFile("romfs:/img/tbox/tboxHorEdgeTop_lght.png");
horEdgeBot.loadFromFile("romfs:/img/tbox/tboxHorEdgeBot_lght.png");
vertEdgeLeft.loadFromFile("romfs:/img/tbox/tboxVertEdgeLeft_lght.png");
vertEdgeRight.loadFromFile("romfs:/img/tbox/tboxVertEdgeRight_lght.png");
horEdgeTop.loadPNGFile("romfs:/img/tbox/tboxHorEdgeTop_lght.png");
horEdgeBot.loadPNGFile("romfs:/img/tbox/tboxHorEdgeBot_lght.png");
vertEdgeLeft.loadPNGFile("romfs:/img/tbox/tboxVertEdgeLeft_lght.png");
vertEdgeRight.loadPNGFile("romfs:/img/tbox/tboxVertEdgeRight_lght.png");
//Light buttons
buttonA.loadPNGFile("romfs:/img/button/buttonA_lght.png");
buttonB.loadPNGFile("romfs:/img/button/buttonB_lght.png");
buttonX.loadPNGFile("romfs:/img/button/buttonX_lght.png");
buttonY.loadPNGFile("romfs:/img/button/buttonY_lght.png");
buttonMin.loadPNGFile("romfs:/img/button/buttonMin_lght.png");
clearClr = 0xFF2D2D2D;
mnuTxt = 0xFFFFFFFF;
@ -100,13 +127,23 @@ namespace ui
break;
}
buttonA.loadFromFile("romfs:/img/buttonA.png");
buttonB.loadFromFile("romfs:/img/buttonB.png");
buttonX.loadFromFile("romfs:/img/buttonX.png");
buttonY.loadFromFile("romfs:/img/buttonY.png");
setupSelButtons();
folderMenu.setParams(308, 88, 956);
saveMenu.setParams(16, 88, 616);
sdMenu.setParams(648, 88, 616);
copyMenu.setParams(472, 278, 304);
if(fs::fileExists("back.jpg"))
background.loadJpegFile("back.jpg");
if(fs::fileExists("cls.txt"))
{
clsUserPrep();
clsMode = true;
mstate = CLS_USR;
}
copyMenu.addOpt("Copy From");
copyMenu.addOpt("Delete");
copyMenu.addOpt("Rename");
@ -131,6 +168,8 @@ namespace ui
buttonB.deleteData();
buttonX.deleteData();
buttonY.deleteData();
background.deleteData();
}
void setupSelButtons()
@ -163,7 +202,11 @@ namespace ui
void drawUI()
{
gfx::clearBufferColor(clearClr);
if(background.getDataPointer() == NULL)
gfx::clearBufferColor(clearClr);
else
background.drawNoBlend(0, 0);
gfx::drawText(TITLE_TEXT, 16, 16, 64, mnuTxt);
switch(mstate)
@ -189,9 +232,24 @@ namespace ui
break;
case ADV_MDE:
gfx::drawRectangle(16, 64, 1248, 1, rectLt);
gfx::drawRectangle(16, 65, 1248, 2, rectSh);
gfx::drawRectangle(640, 64, 1, 592, rectLt);
gfx::drawRectangle(641, 64, 2, 592, rectSh);
gfx::drawRectangle(16, 656, 1248, 1, rectLt);
gfx::drawRectangle(16, 657, 1248, 2, rectSh);
break;
case CLS_TTL:
case CLS_USR:
gfx::drawRectangle(16, 64, 1248, 1, rectLt);
gfx::drawRectangle(16, 65, 1248, 2, rectSh);
gfx::drawRectangle(448, 64, 1, 592, rectLt);
gfx::drawRectangle(449, 64, 2, 592, rectSh);
gfx::drawRectangle(16, 656, 1248, 1, rectLt);
gfx::drawRectangle(16, 657, 1248, 2, rectSh);
break;
@ -200,17 +258,21 @@ namespace ui
switch(mstate)
{
case USR_SEL:
case CLS_USR:
{
//Input guide
unsigned startX = 1010;
unsigned startX = 848;
buttonA.draw(startX, 672);
gfx::drawText("Select", startX += 38, 668, 32, mnuTxt);
buttonY.draw(startX += 72, 672);
gfx::drawText("Dump All", startX += 38, 668, 32, mnuTxt);
buttonX.draw(startX += 96, 672);
gfx::drawText("Classic Mode", startX += 38, 668, 32, mnuTxt);
}
break;
case TTL_SEL:
case CLS_TTL:
{
unsigned startX = 914;
buttonA.draw(startX, 672);
@ -224,11 +286,12 @@ namespace ui
case FLD_SEL:
{
folderMenu.print(308, 88, mnuTxt, 956);
folderMenu.draw(mnuTxt);
//Input guide
unsigned startX = 726;
gfx::drawText("- Adv. Mode", startX, 668, 32, mnuTxt);
buttonA.draw(startX += 110, 672);
unsigned startX = 690;
buttonMin.draw(startX, 672);
gfx::drawText("Adv. Mode", startX += 38, 668, 32, mnuTxt);
buttonA.draw(startX += 100, 672);
gfx::drawText("Backup", startX += 38, 668, 32, mnuTxt);
buttonY.draw(startX += 72, 672);
gfx::drawText("Restore", startX += 38, 668, 32, mnuTxt);
@ -240,8 +303,8 @@ namespace ui
break;
case ADV_MDE:
saveMenu.print(16, 88, mnuTxt, 616);
sdMenu.print(648, 88, mnuTxt, 616);
saveMenu.draw(mnuTxt);
sdMenu.draw(mnuTxt);
gfx::drawText(saveWrap, 16, 652, 32, mnuTxt);
gfx::drawText(sdWrap, 656, 652, 32, mnuTxt);
@ -251,6 +314,7 @@ namespace ui
void updateUserMenu(const uint64_t& down, const uint64_t& held, const touchPosition& p)
{
//Static so they don't get reset every loop
static int start = 0, selected = 0;
static uint8_t clrShft = 0;
@ -319,7 +383,7 @@ namespace ui
drawTextbox(userRectX, y - 50, userRectWidth, 38);
gfx::drawText(username, userRectX + 16, y - 50, 32, txtClr);
}
data::users[i].icn.drawNoBlendSkip(tX, y);
data::users[i].icn.drawNoBlendSkipSmooth(tX, y);
}
}
@ -327,18 +391,22 @@ namespace ui
//Update invisible buttons
for(int i = 0; i < 32; i++)
{
if(selected == i && selButtons[i].released(p))
selButtons[i].update(p);
if(selected == i && selButtons[i].getEvent() == BUTTON_RELEASED)
{
data::curUser = data::users[selected];
mstate = TTL_SEL;
}
else if(selButtons[i].released(p))
else if(selButtons[i].getEvent() == BUTTON_RELEASED)
{
if(start + i < (int)data::users.size())
selected = start + i;
}
}
//Update touch tracking
track.update(p);
if(down & KEY_RIGHT)
{
if(selected < (int)data::users.size() - 1)
@ -387,6 +455,16 @@ namespace ui
for(unsigned i = 0; i < data::users.size(); i++)
fs::dumpAllUserSaves(data::users[i]);
}
else if(down & KEY_X)
{
//Just create file so user doesn't have to constantly enable
std::fstream cls("cls.txt", std::ios::out);
cls.close();
clsUserPrep();
mstate = CLS_USR;
clsMode = true;
}
}
void updateTitleMenu(const uint64_t& down, const uint64_t& held, const touchPosition& p)
@ -403,6 +481,8 @@ namespace ui
//Selected rectangle X and Y.
static unsigned selRectX = 64, selRectY = 74;
static ui::touchTrack track;
if(clrAdd)
{
clrShft += 4;
@ -472,7 +552,8 @@ namespace ui
//Buttons
for(int i = 0; i < 32; i++)
{
if(i == selected && selButtons[i].released(p))
selButtons[i].update(p);
if(i == selected - start && selButtons[i].getEvent() == BUTTON_RELEASED)
{
//Correct rectangle if it can't catch up. Buttons use same x, y as icons
selRectX = selButtons[i].getX() - 6;
@ -483,16 +564,46 @@ namespace ui
{
util::makeTitleDir(data::curUser, data::curData);
folderMenuPrepare(data::curUser, data::curData);
folderMenuInfo = util::getWrappedString(util::getInfoString(data::curUser, data::curData), 38, 256);
mstate = FLD_SEL;
}
}
else if(selButtons[i].released(p))
else if(selButtons[i].getEvent() == BUTTON_RELEASED)
{
if(start + i < (int)data::curUser.titles.size())
selected = start + i;
}
}
//Update touchtracking
track.update(p);
switch(track.getEvent())
{
case TRACK_SWIPE_UP:
{
if(start + 32 < (int)data::curUser.titles.size())
{
start += 8;
selected += 8;
if(selected > (int)data::curUser.titles.size() - 1)
selected = data::curUser.titles.size() - 1;
}
}
break;
case TRACK_SWIPE_DOWN:
{
if(start - 8 >= 0)
{
start -= 8;
selected -= 8;
}
}
break;
}
if(down & KEY_RIGHT)
{
if(selected < (int)data::curUser.titles.size() - 1)
@ -534,12 +645,7 @@ namespace ui
{
util::makeTitleDir(data::curUser, data::curData);
folderMenuPrepare(data::curUser, data::curData);
char tmp[18];
sprintf(tmp, " %016lX", data::curData.getID());
folderMenuInfo = data::curData.getTitle() + tmp + util::retTypeString(data::curData);
folderMenuInfo = util::getWrappedString(folderMenuInfo, 38, 256);
folderMenuInfo = util::getWrappedString(util::getInfoString(data::curUser, data::curData), 38, 256);
mstate = FLD_SEL;
}
@ -559,14 +665,14 @@ namespace ui
}
}
void updateFolderMenu(const uint64_t& down, const uint64_t& held)
void updateFolderMenu(const uint64_t& down, const uint64_t& held, const touchPosition& p)
{
folderMenu.handleInput(down, held);
folderMenu.handleInput(down, held, p);
data::curData.icon.draw(16, 88);
gfx::drawText(folderMenuInfo, 16, 344, 38, mnuTxt);
if(down & KEY_A)
if(down & KEY_A || folderMenu.getTouchEvent() == MENU_DOUBLE_REL)
{
if(folderMenu.getSelected() == 0)
{
@ -662,7 +768,10 @@ namespace ui
else if(down & KEY_B)
{
fsdevUnmountDevice("sv");
mstate = TTL_SEL;
if(clsMode)
mstate = CLS_TTL;
else
mstate = TTL_SEL;
}
}
@ -955,21 +1064,21 @@ namespace ui
util::copyDirListToMenu(saveList, saveMenu);
}
void updateAdvMode(const uint64_t& down, const uint64_t& held)
void updateAdvMode(const uint64_t& down, const uint64_t& held, const touchPosition& p)
{
//0 = save; 1 = sd; 2 = cpy
switch(advMenuCtrl)
{
case 0:
saveMenu.handleInput(down, held);
saveMenu.handleInput(down, held, p);
break;
case 1:
sdMenu.handleInput(down, held);
sdMenu.handleInput(down, held, p);
break;
case 2:
copyMenu.handleInput(down, held);
copyMenu.handleInput(down, held, p);
break;
}
@ -1094,7 +1203,7 @@ namespace ui
break;
}
copyMenu.print(472, 278, txtClr, 304);
copyMenu.draw(txtClr);
}
}
@ -1114,11 +1223,19 @@ namespace ui
break;
case FLD_SEL:
updateFolderMenu(down, held);
updateFolderMenu(down, held, p);
break;
case ADV_MDE:
updateAdvMode(down, held);
updateAdvMode(down, held, p);
break;
case CLS_USR:
classicUserMenuUpdate(down, held, p);
break;
case CLS_TTL:
classicTitleMenuUpdate(down, held, p);
break;
}
}

View File

@ -122,26 +122,30 @@ namespace util
return ret;
}
std::string retTypeString(data::titledata& d)
std::string getInfoString(data::user& u, data::titledata& d)
{
std::string ret = "???";
std::string ret = d.getTitle();
char id[18];
sprintf(id, " %016lX", d.getID());
ret += id;
switch(d.getType())
{
case FsSaveDataType_SystemSaveData:
ret = " System Save";
ret += " System Save";
break;
case FsSaveDataType_SaveData:
ret = " Save Data";
ret += " Save Data";
break;
case FsSaveDataType_BcatDeliveryCacheStorage:
ret = " Bcat Delivery Cache";
ret += " Bcat Delivery Cache";
break;
case FsSaveDataType_DeviceSaveData:
ret = " Device Save";
ret += " Device Save";
break;
case FsSaveDataType_TemporaryStorage:
@ -149,10 +153,12 @@ namespace util
break;
case FsSaveDataType_CacheStorage:
ret = " Cache Storage";
ret+= " Cache Storage";
break;
}
ret += "\n" + u.getUsername();
return ret;
}
}