prerender all text + get IME working flawlessly

This commit is contained in:
Soph :3 2025-11-17 12:12:44 +02:00
parent d245a92811
commit c4f12cfb65
2 changed files with 100 additions and 37 deletions

View file

@ -22,6 +22,7 @@
#include <psp2/libime.h> #include <psp2/libime.h>
#include <psp2/ime_dialog.h> #include <psp2/ime_dialog.h>
#include <psp2/io/stat.h> #include <psp2/io/stat.h>
#include <psp2/sysmodule.h>
#define SCREEN_W 960 #define SCREEN_W 960
#define SCREEN_H 544 #define SCREEN_H 544
@ -38,6 +39,9 @@ struct Item {
std::string coverId; // <-- NEW: Subsonic coverArt ID std::string coverId; // <-- NEW: Subsonic coverArt ID
bool isTrack = false; bool isTrack = false;
int trackNum = 0; int trackNum = 0;
SDL_Texture* titleTex = nullptr;
SDL_Texture* artistTex = nullptr;
}; };
struct ArtRequest { struct ArtRequest {
std::string id; std::string id;
@ -55,10 +59,13 @@ struct AudioQueueEntry {
struct InputBox { struct InputBox {
int x, y, w, h; int x, y, w, h;
std::string text; std::string text;
std::string title;
bool focused = false; bool focused = false;
int caretPos = 0; // caret index int caretPos = 0; // caret index
Uint32 lastBlink = 0; // for caret blinking Uint32 lastBlink = 0; // for caret blinking
bool caretVisible = true; bool caretVisible = true;
bool openedKeyboard = false;
}; };
std::queue<ArtRequest> gArtRequestQ; std::queue<ArtRequest> gArtRequestQ;
@ -249,17 +256,15 @@ void renderLeftList(
SDL_RenderCopy(rd, artTex, NULL, &art); SDL_RenderCopy(rd, artTex, NULL, &art);
// TEXTURES // TEXTURES
SDL_Texture* t1 = text(rd, fontSmall, items[i].title, {255,255,255}); SDL_Texture* t1 = items[i].titleTex;
int tw1,th1; SDL_QueryTexture(t1,NULL,NULL,&tw1,&th1); int tw1,th1; SDL_QueryTexture(t1,NULL,NULL,&tw1,&th1);
SDL_Rect td1 = { rt1.x, rt1.y, tw1, th1 }; SDL_Rect td1 = { rt1.x, rt1.y, tw1, th1 };
SDL_RenderCopy(rd, t1, NULL, &td1); SDL_RenderCopy(rd, items[i].titleTex, NULL, &td1);
SDL_DestroyTexture(t1);
SDL_Texture* t2 = text(rd, fontSmall, items[i].artist, {180,180,180}); SDL_Texture* t2 = items[i].artistTex;
int tw2,th2; SDL_QueryTexture(t2,NULL,NULL,&tw2,&th2); int tw2,th2; SDL_QueryTexture(t2,NULL,NULL,&tw2,&th1);
SDL_Rect td2 = { rt2.x, rt2.y, tw2, th2 }; SDL_Rect td2 = { rt2.x, rt2.y, tw2, th2 };
SDL_RenderCopy(rd, t2, NULL, &td2); SDL_RenderCopy(rd, items[i].artistTex, NULL, &td2);
SDL_DestroyTexture(t2);
} }
SDL_SetRenderTarget(rd, NULL); SDL_SetRenderTarget(rd, NULL);
@ -429,8 +434,8 @@ static bool PollIME(char* utf8Out, int maxlen)
return true; return true;
} }
void handleInputBoxEvent(InputBox& box, const SDL_Event& e) void handleInputBoxEvent(InputBox& box, const SDL_Event& e) {
{
// Click = focus + open IME keyboard // Click = focus + open IME keyboard
if (e.type == SDL_FINGERDOWN) { if (e.type == SDL_FINGERDOWN) {
int mx = e.tfinger.x * SCREEN_W; int mx = e.tfinger.x * SCREEN_W;
@ -441,21 +446,8 @@ void handleInputBoxEvent(InputBox& box, const SDL_Event& e)
if (inside) { if (inside) {
box.focused = true; box.focused = true;
ShowIME("testing.. testing..", box.text.c_str()); ShowIME(box.title.c_str(), box.text.c_str());
char* result; box.openedKeyboard = true;
while(true) {
if(PollIME(result, 256)) {
// Replace the entire input content
box.text = result;
box.caretPos = box.text.size();
box.lastBlink = SDL_GetTicks();
box.caretVisible = true;
box.focused = false;
break;
}
}
} else { } else {
box.focused = false; box.focused = false;
} }
@ -465,6 +457,23 @@ void handleInputBoxEvent(InputBox& box, const SDL_Event& e)
return; return;
} }
void HandleKeyboardInputBox(InputBox& box) {
if(box.openedKeyboard) {
char result[256];
if(PollIME(result, 256)) {
// Replace the entire input content
box.text = result;
box.caretPos = box.text.size();
box.lastBlink = SDL_GetTicks();
box.caretVisible = true;
box.openedKeyboard = false;
box.focused = false;
}
}
}
void renderRightPanel( void renderRightPanel(
SDL_Renderer* rd, SDL_Renderer* rd,
TTF_Font* fontBig, TTF_Font* fontMed, TTF_Font* fontBig, TTF_Font* fontMed,
@ -545,6 +554,8 @@ void loadTracks(
std::vector<Item>& items, std::vector<Item>& items,
const SubsonicClient& ss, const SubsonicClient& ss,
const std::string& albumId, const std::string& albumId,
SDL_Renderer* rd,
TTF_Font* font,
SDL_Window* win) SDL_Window* win)
{ {
std::string err; std::string err;
@ -552,6 +563,10 @@ void loadTracks(
if (!err.empty()) if (!err.empty())
log(win, "getAlbum error: %s", err.c_str()); log(win, "getAlbum error: %s", err.c_str());
for (auto& it : items) {
if (it.titleTex) SDL_DestroyTexture(it.titleTex);
if (it.artistTex) SDL_DestroyTexture(it.artistTex);
}
items.clear(); items.clear();
items.reserve(tracks.size()); items.reserve(tracks.size());
@ -577,6 +592,10 @@ void loadTracks(
it.titleRect = { 20 + artSize + 15, y + 10, 240, 24 }; it.titleRect = { 20 + artSize + 15, y + 10, 240, 24 };
it.artistRect = { 20 + artSize + 15, y + 36, 240, 22 }; it.artistRect = { 20 + artSize + 15, y + 36, 240, 22 };
it.titleTex = text(rd, font, it.title, {255,255,255});
it.artistTex = text(rd, font, it.artist, {180,180,180});
items.push_back(it); items.push_back(it);
} }
@ -587,13 +606,18 @@ void loadTracks(
void loadArtists( void loadArtists(
std::vector<Item>& items, std::vector<Item>& items,
const SubsonicClient& ss const SubsonicClient& ss,
SDL_Renderer* rd,
TTF_Font* font
) { ) {
std::string err; std::string err;
auto allArtists = ss.getArtists(&err); auto allArtists = ss.getArtists(&err);
if (!err.empty()) if (!err.empty())
SDL_Log("getArtists error: %s", err.c_str()); SDL_Log("getArtists error: %s", err.c_str());
for (auto& it : items) {
if (it.titleTex) SDL_DestroyTexture(it.titleTex);
if (it.artistTex) SDL_DestroyTexture(it.artistTex);
}
items.clear(); items.clear();
items.reserve(allArtists.size()); items.reserve(allArtists.size());
@ -617,6 +641,9 @@ void loadArtists(
it.titleRect = {20 + artSize + 15, y + 10, 200, 20}; it.titleRect = {20 + artSize + 15, y + 10, 200, 20};
it.artistRect = {20 + artSize + 15, y + 35, 200, 20}; it.artistRect = {20 + artSize + 15, y + 35, 200, 20};
it.titleTex = text(rd, font, it.title, {255,255,255});
it.artistTex = text(rd, font, it.artist, {180,180,180});
items.push_back(it); items.push_back(it);
} }
@ -627,13 +654,18 @@ void loadArtists(
void loadAlbums( void loadAlbums(
std::vector<Item>& items, std::vector<Item>& items,
const SubsonicClient& ss, const SubsonicClient& ss,
SDL_Renderer* rd,
TTF_Font* font,
std::string artist = "" std::string artist = ""
) { ) {
std::string err; std::string err;
auto allAlbums = ss.getAllAlbums(&err); auto allAlbums = ss.getAllAlbums(&err);
if (!err.empty()) if (!err.empty())
SDL_Log("getAlbum error: %s", err.c_str()); SDL_Log("getAlbum error: %s", err.c_str());
for (auto& it : items) {
if (it.titleTex) SDL_DestroyTexture(it.titleTex);
if (it.artistTex) SDL_DestroyTexture(it.artistTex);
}
items.clear(); items.clear();
const int artSize = 80; const int artSize = 80;
@ -664,6 +696,10 @@ void loadAlbums(
it.titleRect = {20 + artSize + 15, y + 10, 200, 20}; it.titleRect = {20 + artSize + 15, y + 10, 200, 20};
it.artistRect = {20 + artSize + 15, y + 35, 200, 20}; it.artistRect = {20 + artSize + 15, y + 35, 200, 20};
it.titleTex = text(rd, font, it.title, {255,255,255});
it.artistTex = text(rd, font, it.artist, {180,180,180});
items.push_back(it); items.push_back(it);
k2=k2+1; k2=k2+1;
@ -690,6 +726,8 @@ int main()
SDL_setenv("VITA_DISABLE_TOUCH_BACK", "1", 1); SDL_setenv("VITA_DISABLE_TOUCH_BACK", "1", 1);
sceSysmoduleLoadModule(SCE_SYSMODULE_IME);
Audio_Init(); Audio_Init();
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER); SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
IMG_Init(IMG_INIT_PNG); IMG_Init(IMG_INIT_PNG);
@ -729,7 +767,7 @@ int main()
}; };
std::vector<Item> items; std::vector<Item> items;
loadAlbums(items, ss); loadAlbums(items, ss, rd, fontSmall);
int artSize = 80; int artSize = 80;
int rowHeight = 100; int rowHeight = 100;
int startY = 70; int startY = 70;
@ -755,16 +793,19 @@ int main()
InputBox serverUrl { InputBox serverUrl {
10,10+50+10,350,30, 10,10+50+10,350,30,
settings.server settings.server,
"Server URL"
}; };
InputBox password { InputBox password {
10,10+50+10+30+10,350,30, 10,10+50+10+30+10,350,30,
settings.user settings.pass,
"Password"
}; };
InputBox username { InputBox username {
10,10+50+10+30+10+30+10,350,30, 10,10+50+10+30+10+30+10,350,30,
settings.pass settings.user,
"Username"
}; };
Button btnSettingsSave = { Button btnSettingsSave = {
@ -821,6 +862,10 @@ int main()
} }
} }
HandleKeyboardInputBox(username);
HandleKeyboardInputBox(password);
HandleKeyboardInputBox(serverUrl);
if (touch) if (touch)
{ {
if(settingsOpened) { if(settingsOpened) {
@ -832,11 +877,19 @@ int main()
} }
if(hit(tx,ty,rS)) { if(hit(tx,ty,rS)) {
settings.pass = password.text;
settings.server = serverUrl.text; settings.server = serverUrl.text;
settings.user = username.text; settings.user = username.text;
settings.pass = password.text;
settings.save(); settings.save();
ss = SubsonicClient(
settings.server,
settings.user,
settings.pass,
"vita-player",
"1.16.1"
);
} }
} else { } else {
// Tabs // Tabs
@ -848,10 +901,10 @@ int main()
for(int j=0;j<3;j++) tabs[j].active=false; for(int j=0;j<3;j++) tabs[j].active=false;
tabs[i].active=true; tabs[i].active=true;
if (strcmp(tabs[i].label, "albums") == 0) { if (strcmp(tabs[i].label, "albums") == 0) {
loadAlbums(items, ss); loadAlbums(items, ss, rd, fontSmall);
} }
if (strcmp(tabs[i].label, "artists") == 0) { if (strcmp(tabs[i].label, "artists") == 0) {
loadArtists(items, ss); loadArtists(items, ss, rd, fontSmall);
} }
} }
} }
@ -861,13 +914,13 @@ int main()
r.y -= scrollOffset; r.y -= scrollOffset;
if (hit(tx, ty, {LEFT_X + r.x, r.y, r.w, r.h})) { if (hit(tx, ty, {LEFT_X + r.x, r.y, r.w, r.h})) {
if (tabs[0].active) { if (tabs[0].active) {
loadTracks(items, ss, items[i].id, win); loadTracks(items, ss, items[i].id, rd, fontSmall, win);
// switch to Tracks tab // switch to Tracks tab
for (int j = 0; j < 3; j++) tabs[j].active = false; for (int j = 0; j < 3; j++) tabs[j].active = false;
tabs[2].active = true; tabs[2].active = true;
} else if(tabs[1].active) { } else if(tabs[1].active) {
loadAlbums(items, ss, items[i].id); loadAlbums(items, ss, rd, fontSmall, items[i].id);
for (int j = 0; j < 3; j++) tabs[j].active = false; for (int j = 0; j < 3; j++) tabs[j].active = false;
tabs[0].active = true; tabs[0].active = true;

View file

@ -6,6 +6,7 @@
#include <curl/curl.h> #include <curl/curl.h>
#include <jsoncpp/json/json.h> #include <jsoncpp/json/json.h>
#include <SDL2/SDL.h>
struct ArtistInfo { struct ArtistInfo {
std::string id; std::string id;
@ -141,6 +142,9 @@ public:
curl_easy_setopt(c, CURLOPT_CONNECTTIMEOUT, 10L); curl_easy_setopt(c, CURLOPT_CONNECTTIMEOUT, 10L);
curl_easy_setopt(c, CURLOPT_TIMEOUT, 30L); curl_easy_setopt(c, CURLOPT_TIMEOUT, 30L);
curl_easy_setopt(c, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(c, CURLOPT_SSL_VERIFYHOST, 0L);
CURLcode res = curl_easy_perform(c); CURLcode res = curl_easy_perform(c);
char* ctype = NULL; char* ctype = NULL;
@ -288,7 +292,10 @@ public:
const Json::Value& albumList = sub["albumList2"]; const Json::Value& albumList = sub["albumList2"];
if (!albumList.isObject()) { if (!albumList.isObject()) {
if (outError) *outError = "Missing 'albumList2'"; if (outError) {
SDL_Log("full json: %s", body.c_str());
*outError = "Missing 'albumList2'";
}
return {}; return {};
} }
@ -584,6 +591,9 @@ private:
curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, &curlWriteCallback); curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, &curlWriteCallback);
curl_easy_setopt(c, CURLOPT_WRITEDATA, &outBody); curl_easy_setopt(c, CURLOPT_WRITEDATA, &outBody);
curl_easy_setopt(c, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(c, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(c, CURLOPT_USE_SSL, CURLUSESSL_TRY);
// Reasonable defaults; tweak if Vita/curl complains // Reasonable defaults; tweak if Vita/curl complains
curl_easy_setopt(c, CURLOPT_CONNECTTIMEOUT, 10L); curl_easy_setopt(c, CURLOPT_CONNECTTIMEOUT, 10L);