From 63e414fc8a7ec04a0710a05ac9ce610fbb15f1e5 Mon Sep 17 00:00:00 2001 From: Ethan Yonker Date: Fri, 6 Feb 2015 15:44:39 -0600 Subject: [PATCH] Scale the GUI to fit the screen With this patch set, if needed, we scale the images during early boot. TTF support is needed to properly scale the font. No font scaling is done on the old style fixed width font used in the console. Special thanks to _that for figuring out the scaling and blending function calls to make this possible. Change-Id: If2f79bef16d6db2e1298bfc3d00c9bcca2bee37a --- gui/Android.mk | 3 + gui/devices/1024x600/res/ui.xml | 10 +- gui/devices/1024x768/res/ui.xml | 10 +- gui/devices/1080x1920/res/ui.xml | 10 +- gui/devices/1200x1920/res/ui.xml | 10 +- gui/devices/1280x800/res/ui.xml | 10 +- gui/devices/1440x2560/res/ui.xml | 10 +- gui/devices/1600x2560/res/ui.xml | 10 +- gui/devices/1920x1200/res/ui.xml | 10 +- gui/devices/240x240/res/images/cursor.png | Bin 0 -> 1452 bytes gui/devices/240x240/res/ui.xml | 10 +- gui/devices/2560x1600/res/ui.xml | 10 +- gui/devices/280x280/res/images/cursor.png | Bin 0 -> 1452 bytes gui/devices/280x280/res/ui.xml | 10 +- gui/devices/320x320/res/images/cursor.png | Bin 0 -> 1452 bytes gui/devices/320x320/res/ui.xml | 10 +- gui/devices/320x480/res/ui.xml | 10 +- gui/devices/480x800/res/ui.xml | 10 +- gui/devices/480x854/res/ui.xml | 10 +- gui/devices/540x960/res/ui.xml | 10 +- gui/devices/720x1280/res/ui.xml | 10 +- gui/devices/800x1280/res/ui.xml | 10 +- gui/devices/800x480/res/ui.xml | 10 +- gui/gui.cpp | 64 +++++++++++- gui/gui.h | 8 ++ gui/input.cpp | 2 +- gui/keyboard.cpp | 7 +- gui/pages.cpp | 56 +++++++++++ gui/resources.cpp | 113 +++++++++++++++------- gui/resources.hpp | 6 +- gui/scrolllist.cpp | 14 +-- gui/slidervalue.cpp | 8 +- minuitwrp/minui.h | 2 + minuitwrp/resources.c | 76 ++++++++++++++- 34 files changed, 399 insertions(+), 150 deletions(-) create mode 100644 gui/devices/240x240/res/images/cursor.png create mode 100644 gui/devices/280x280/res/images/cursor.png create mode 100644 gui/devices/320x320/res/images/cursor.png diff --git a/gui/Android.mk b/gui/Android.mk index 93913f55..0b5afe1d 100644 --- a/gui/Android.mk +++ b/gui/Android.mk @@ -63,6 +63,9 @@ endif ifneq ($(TW_Y_OFFSET),) LOCAL_CFLAGS += -DTW_Y_OFFSET=$(TW_Y_OFFSET) endif +ifeq ($(TW_ROUND_SCREEN), true) + LOCAL_CFLAGS += -DTW_ROUND_SCREEN +endif ifeq ($(DEVICE_RESOLUTION),) $(warning ********************************************************************************) diff --git a/gui/devices/1024x600/res/ui.xml b/gui/devices/1024x600/res/ui.xml index 1669d458..e76cc950 100644 --- a/gui/devices/1024x600/res/ui.xml +++ b/gui/devices/1024x600/res/ui.xml @@ -22,10 +22,10 @@ - - - - + + + + @@ -42,7 +42,7 @@ - + diff --git a/gui/devices/1024x768/res/ui.xml b/gui/devices/1024x768/res/ui.xml index 253ae07e..cfaf48e0 100644 --- a/gui/devices/1024x768/res/ui.xml +++ b/gui/devices/1024x768/res/ui.xml @@ -22,10 +22,10 @@ - - - - + + + + @@ -42,7 +42,7 @@ - + diff --git a/gui/devices/1080x1920/res/ui.xml b/gui/devices/1080x1920/res/ui.xml index ddab4f31..f38462c4 100644 --- a/gui/devices/1080x1920/res/ui.xml +++ b/gui/devices/1080x1920/res/ui.xml @@ -25,10 +25,10 @@ - - - - + + + + @@ -43,7 +43,7 @@ - + diff --git a/gui/devices/1200x1920/res/ui.xml b/gui/devices/1200x1920/res/ui.xml index c02032fb..782f0bd4 100644 --- a/gui/devices/1200x1920/res/ui.xml +++ b/gui/devices/1200x1920/res/ui.xml @@ -25,10 +25,10 @@ - - - - + + + + @@ -43,7 +43,7 @@ - + diff --git a/gui/devices/1280x800/res/ui.xml b/gui/devices/1280x800/res/ui.xml index 94d0bf98..0c7ecf0b 100644 --- a/gui/devices/1280x800/res/ui.xml +++ b/gui/devices/1280x800/res/ui.xml @@ -22,10 +22,10 @@ - - - - + + + + @@ -42,7 +42,7 @@ - + diff --git a/gui/devices/1440x2560/res/ui.xml b/gui/devices/1440x2560/res/ui.xml index 52bf2077..35bd4c62 100644 --- a/gui/devices/1440x2560/res/ui.xml +++ b/gui/devices/1440x2560/res/ui.xml @@ -25,10 +25,10 @@ - - - - + + + + @@ -43,7 +43,7 @@ - + diff --git a/gui/devices/1600x2560/res/ui.xml b/gui/devices/1600x2560/res/ui.xml index b85803bb..8c35ef8a 100644 --- a/gui/devices/1600x2560/res/ui.xml +++ b/gui/devices/1600x2560/res/ui.xml @@ -25,10 +25,10 @@ - - - - + + + + @@ -43,7 +43,7 @@ - + diff --git a/gui/devices/1920x1200/res/ui.xml b/gui/devices/1920x1200/res/ui.xml index 4bd85a27..05a3ee62 100644 --- a/gui/devices/1920x1200/res/ui.xml +++ b/gui/devices/1920x1200/res/ui.xml @@ -22,10 +22,10 @@ - - - - + + + + @@ -42,7 +42,7 @@ - + diff --git a/gui/devices/240x240/res/images/cursor.png b/gui/devices/240x240/res/images/cursor.png new file mode 100644 index 0000000000000000000000000000000000000000..32c8ae1ca70901b21c7b3a8df9e28369e4667677 GIT binary patch literal 1452 zcmV;d1ylNoP)5bQIb$YLS15LH*u5g{!M0%4?TCCO|xy0X0i*t zaGBZJ`MKXc=iKvi0eXOSz*?XT2v9;T2%G{O;CH>|0#Zs4qWuG)9=HQ2FC|GB09PR% zE;R^Q0`Wf30IV++n-D;b964ej9N-;Qr;>mWKtx1(dwUIp4ZH>j@WHNb` z6huTanT)izw;PBU@G@|JF+m6*i9}*qDTs)qQYmR`YcmitKsylDATU@I0Q2+nl1wHg zo6TM&1rd=%A|b7PeiF$z2l+`C#3 z0?4IHmu^@JA|lafR2mu@48(816Tm%wL*zc>y6#n7q;O&u4u=^U8ltwg7T{6fbM@Bi zHJ7k_2N03Gqv?fOU0od~PoAWvrUu|~;8R^*EB%5fC;>0bwc5sw8yOrNq`JBqU<>ex zF0Z~oT>CPxc(Y43WlJUC z9q>|^P$HKBq;qi~8H~%?6GgJI40y+Zi4n&ixk-hw19-GLJn5 zOsXS02mAv3tjBY}uj;8Uuf*)&n>Jm{^u&suz2K7R{ThfxA5YPIYXdl{91lWNd6q&YwRolarHj=+Gf=vC9VJ^y$-* z$z*adQb$LJ`M+P+e-o9K>tIa}s-#ye@yP*#RB(ZK8{O;{Y@57qncfxm%i zjeRnH*?>`xpl1~-6th@*ZzXWIs#Hh^n$WW2te)HWw9^?_;x*+uA2tvnRjD-!kWtB{ zJy9us0sNnp%ksoH#`!s{!X9(rCO%hEo8!0It#+#wN&6R%ar5++a#gti0000
+ masteroftime TWRP x201 tDPI Smartwatch Theme @@ -25,10 +26,10 @@ - - - - + + + + @@ -43,6 +44,7 @@ + diff --git a/gui/devices/2560x1600/res/ui.xml b/gui/devices/2560x1600/res/ui.xml index 6da373e5..57945cb7 100644 --- a/gui/devices/2560x1600/res/ui.xml +++ b/gui/devices/2560x1600/res/ui.xml @@ -22,10 +22,10 @@ - - - - + + + + @@ -42,7 +42,7 @@ - + diff --git a/gui/devices/280x280/res/images/cursor.png b/gui/devices/280x280/res/images/cursor.png new file mode 100644 index 0000000000000000000000000000000000000000..32c8ae1ca70901b21c7b3a8df9e28369e4667677 GIT binary patch literal 1452 zcmV;d1ylNoP)5bQIb$YLS15LH*u5g{!M0%4?TCCO|xy0X0i*t zaGBZJ`MKXc=iKvi0eXOSz*?XT2v9;T2%G{O;CH>|0#Zs4qWuG)9=HQ2FC|GB09PR% zE;R^Q0`Wf30IV++n-D;b964ej9N-;Qr;>mWKtx1(dwUIp4ZH>j@WHNb` z6huTanT)izw;PBU@G@|JF+m6*i9}*qDTs)qQYmR`YcmitKsylDATU@I0Q2+nl1wHg zo6TM&1rd=%A|b7PeiF$z2l+`C#3 z0?4IHmu^@JA|lafR2mu@48(816Tm%wL*zc>y6#n7q;O&u4u=^U8ltwg7T{6fbM@Bi zHJ7k_2N03Gqv?fOU0od~PoAWvrUu|~;8R^*EB%5fC;>0bwc5sw8yOrNq`JBqU<>ex zF0Z~oT>CPxc(Y43WlJUC z9q>|^P$HKBq;qi~8H~%?6GgJI40y+Zi4n&ixk-hw19-GLJn5 zOsXS02mAv3tjBY}uj;8Uuf*)&n>Jm{^u&suz2K7R{ThfxA5YPIYXdl{91lWNd6q&YwRolarHj=+Gf=vC9VJ^y$-* z$z*adQb$LJ`M+P+e-o9K>tIa}s-#ye@yP*#RB(ZK8{O;{Y@57qncfxm%i zjeRnH*?>`xpl1~-6th@*ZzXWIs#Hh^n$WW2te)HWw9^?_;x*+uA2tvnRjD-!kWtB{ zJy9us0sNnp%ksoH#`!s{!X9(rCO%hEo8!0It#+#wN&6R%ar5++a#gti0000
+ TeamWin Backup Naowz Default basic theme @@ -25,10 +26,10 @@ - - - - + + + + @@ -43,6 +44,7 @@ + diff --git a/gui/devices/320x320/res/images/cursor.png b/gui/devices/320x320/res/images/cursor.png new file mode 100644 index 0000000000000000000000000000000000000000..32c8ae1ca70901b21c7b3a8df9e28369e4667677 GIT binary patch literal 1452 zcmV;d1ylNoP)5bQIb$YLS15LH*u5g{!M0%4?TCCO|xy0X0i*t zaGBZJ`MKXc=iKvi0eXOSz*?XT2v9;T2%G{O;CH>|0#Zs4qWuG)9=HQ2FC|GB09PR% zE;R^Q0`Wf30IV++n-D;b964ej9N-;Qr;>mWKtx1(dwUIp4ZH>j@WHNb` z6huTanT)izw;PBU@G@|JF+m6*i9}*qDTs)qQYmR`YcmitKsylDATU@I0Q2+nl1wHg zo6TM&1rd=%A|b7PeiF$z2l+`C#3 z0?4IHmu^@JA|lafR2mu@48(816Tm%wL*zc>y6#n7q;O&u4u=^U8ltwg7T{6fbM@Bi zHJ7k_2N03Gqv?fOU0od~PoAWvrUu|~;8R^*EB%5fC;>0bwc5sw8yOrNq`JBqU<>ex zF0Z~oT>CPxc(Y43WlJUC z9q>|^P$HKBq;qi~8H~%?6GgJI40y+Zi4n&ixk-hw19-GLJn5 zOsXS02mAv3tjBY}uj;8Uuf*)&n>Jm{^u&suz2K7R{ThfxA5YPIYXdl{91lWNd6q&YwRolarHj=+Gf=vC9VJ^y$-* z$z*adQb$LJ`M+P+e-o9K>tIa}s-#ye@yP*#RB(ZK8{O;{Y@57qncfxm%i zjeRnH*?>`xpl1~-6th@*ZzXWIs#Hh^n$WW2te)HWw9^?_;x*+uA2tvnRjD-!kWtB{ zJy9us0sNnp%ksoH#`!s{!X9(rCO%hEo8!0It#+#wN&6R%ar5++a#gti0000
+ TeamWin Backup Naowz Default basic theme @@ -25,10 +26,10 @@ - - - - + + + + @@ -43,6 +44,7 @@ + diff --git a/gui/devices/320x480/res/ui.xml b/gui/devices/320x480/res/ui.xml index 70d33e60..d91df420 100644 --- a/gui/devices/320x480/res/ui.xml +++ b/gui/devices/320x480/res/ui.xml @@ -25,10 +25,10 @@ - - - - + + + + @@ -43,7 +43,7 @@ - + diff --git a/gui/devices/480x800/res/ui.xml b/gui/devices/480x800/res/ui.xml index 895cfaa4..b1880bad 100644 --- a/gui/devices/480x800/res/ui.xml +++ b/gui/devices/480x800/res/ui.xml @@ -25,10 +25,10 @@ - - - - + + + + @@ -43,7 +43,7 @@ - + diff --git a/gui/devices/480x854/res/ui.xml b/gui/devices/480x854/res/ui.xml index c4ce65f3..52a9f4b1 100644 --- a/gui/devices/480x854/res/ui.xml +++ b/gui/devices/480x854/res/ui.xml @@ -25,10 +25,10 @@ - - - - + + + + @@ -43,7 +43,7 @@ - + diff --git a/gui/devices/540x960/res/ui.xml b/gui/devices/540x960/res/ui.xml index eb6d671b..5abe640e 100644 --- a/gui/devices/540x960/res/ui.xml +++ b/gui/devices/540x960/res/ui.xml @@ -25,10 +25,10 @@ - - - - + + + + @@ -43,7 +43,7 @@ - + diff --git a/gui/devices/720x1280/res/ui.xml b/gui/devices/720x1280/res/ui.xml index 3020daa4..714ca4c6 100644 --- a/gui/devices/720x1280/res/ui.xml +++ b/gui/devices/720x1280/res/ui.xml @@ -25,10 +25,10 @@ - - - - + + + + @@ -43,7 +43,7 @@ - + diff --git a/gui/devices/800x1280/res/ui.xml b/gui/devices/800x1280/res/ui.xml index 6f49bf7f..e4d8b299 100644 --- a/gui/devices/800x1280/res/ui.xml +++ b/gui/devices/800x1280/res/ui.xml @@ -25,10 +25,10 @@ - - - - + + + + @@ -43,7 +43,7 @@ - + diff --git a/gui/devices/800x480/res/ui.xml b/gui/devices/800x480/res/ui.xml index b80ed3be..faa0878b 100644 --- a/gui/devices/800x480/res/ui.xml +++ b/gui/devices/800x480/res/ui.xml @@ -22,10 +22,10 @@ - - - - + + + + @@ -42,7 +42,7 @@ - + diff --git a/gui/gui.cpp b/gui/gui.cpp index 8bdd4251..35b33b10 100644 --- a/gui/gui.cpp +++ b/gui/gui.cpp @@ -75,6 +75,8 @@ static TWAtomicInt gForceRender; const int gNoAnimation = 1; blanktimer blankTimer; int ors_read_fd = -1; +static float scale_theme_w = 1; +static float scale_theme_h = 1; // Needed by pages.cpp too int gGuiRunning = 0; @@ -767,13 +769,26 @@ extern "C" int gui_init(void) { gr_init(); std::string curtain_path = TWRES "images/curtain.jpg"; + gr_surface source_Surface = NULL; - if (res_create_surface(curtain_path.c_str(), &gCurtain)) + if (res_create_surface(curtain_path.c_str(), &source_Surface)) { - printf - ("Unable to locate '%s'\nDid you set a DEVICE_RESOLUTION in your config files?\n", curtain_path.c_str()); + printf("Unable to locate '%s'\nDid you set a DEVICE_RESOLUTION in your config files?\n", curtain_path.c_str()); return -1; } + if (gr_get_width(source_Surface) != gr_fb_width() || gr_get_height(source_Surface) != gr_fb_height()) { + // We need to scale the curtain to fit the screen + float scale_w = (float)gr_fb_width() / (float)gr_get_width(source_Surface); + float scale_h = (float)gr_fb_height() / (float)gr_get_height(source_Surface); + if (res_scale_surface(source_Surface, &gCurtain, scale_w, scale_h)) { + LOGINFO("Failed to scale curtain\n"); + gCurtain = source_Surface; + } else { + LOGINFO("Scaling the curtain width %fx and height %fx\n", scale_w, scale_h); + } + } else { + gCurtain = source_Surface; + } curtainSet(); @@ -965,3 +980,46 @@ extern "C" int gui_console_only(void) return 0; } + +extern "C" void set_scale_values(float w, float h) +{ + scale_theme_w = w; + scale_theme_h = h; +} + +extern "C" int scale_theme_x(int initial_x) +{ + if (scale_theme_w != 1) { + return (int) ((float)initial_x * scale_theme_w); + } + return initial_x; +} + +extern "C" int scale_theme_y(int initial_y) +{ + if (scale_theme_h != 1) { + return (int) ((float)initial_y * scale_theme_h); + } + return initial_y; +} + +extern "C" int scale_theme_min(int initial_value) +{ + if (scale_theme_w != 1 || scale_theme_h != 1) { + if (scale_theme_w < scale_theme_h) + return scale_theme_x(initial_value); + else + return scale_theme_y(initial_value); + } + return initial_value; +} + +extern "C" float get_scale_w() +{ + return scale_theme_w; +} + +extern "C" float get_scale_h() +{ + return scale_theme_h; +} diff --git a/gui/gui.h b/gui/gui.h index 5b2cdec1..37d20540 100644 --- a/gui/gui.h +++ b/gui/gui.h @@ -31,5 +31,13 @@ void gui_print(const char *fmt, ...); void gui_print_color(const char *color, const char *fmt, ...); void gui_set_FILE(FILE* f); +void set_scale_values(float w, float h); +int scale_theme_x(int initial_x); +int scale_theme_y(int initial_y); +int scale_theme_min(int initial_value); +float get_scale_w(); +float get_scale_h(); +float get_scale_h(); + #endif // _GUI_HEADER diff --git a/gui/input.cpp b/gui/input.cpp index 21b1f0b8..e8933357 100644 --- a/gui/input.cpp +++ b/gui/input.cpp @@ -127,7 +127,7 @@ GUIInput::GUIInput(xml_node<>* node) if (attr) { std::string cwidth = gui_parse_text(attr->value()); - CursorWidth = atoi(cwidth.c_str()); + CursorWidth = scale_theme_x(atoi(cwidth.c_str())); } } DrawCursor = HasInputFocus; diff --git a/gui/keyboard.cpp b/gui/keyboard.cpp index bbc6ed2d..db968aee 100644 --- a/gui/keyboard.cpp +++ b/gui/keyboard.cpp @@ -37,6 +37,7 @@ extern "C" { #include "../twcommon.h" #include "../minuitwrp/minui.h" +#include "gui.h" } #include "rapidxml.hpp" @@ -131,12 +132,12 @@ GUIKeyboard::GUIKeyboard(xml_node<>* node) if (child) { attr = child->first_attribute("height"); if (attr) - keyHeight = atoi(attr->value()); + keyHeight = scale_theme_y(atoi(attr->value())); else keyHeight = 0; attr = child->first_attribute("width"); if (attr) - keyWidth = atoi(attr->value()); + keyWidth = scale_theme_x(atoi(attr->value())); else keyWidth = 0; attr = child->first_attribute("capslock"); @@ -234,7 +235,7 @@ int GUIKeyboard::ParseKey(const char* keyinfo, keyboard_key_class& key, int& Xin keychar = keyinfo[0]; } else { // This key has extra data: {keywidth}:{what_the_key_does} - keyWidth = atoi(keyinfo); + keyWidth = scale_theme_x(atoi(keyinfo)); const char* ptr = keyinfo; while (*ptr > 32 && *ptr != ':') diff --git a/gui/pages.cpp b/gui/pages.cpp index 8fef7b4c..47e2edde 100644 --- a/gui/pages.cpp +++ b/gui/pages.cpp @@ -41,6 +41,7 @@ extern "C" { #include "../minuitwrp/minui.h" #include "../minzip/SysUtil.h" #include "../minzip/Zip.h" +#include "gui.h" } #include "rapidxml.hpp" @@ -113,6 +114,7 @@ bool LoadPlacement(xml_node<>* node, int* x, int* y, int* w /* = NULL */, int* h value = node->first_attribute("x")->value(); DataManager::GetValue(value, value); *x = atol(value.c_str()); + *x = scale_theme_x(*x); *x += tw_x_offset; } @@ -121,6 +123,7 @@ bool LoadPlacement(xml_node<>* node, int* x, int* y, int* w /* = NULL */, int* h value = node->first_attribute("y")->value(); DataManager::GetValue(value, value); *y = atol(value.c_str()); + *y = scale_theme_y(*y); *y += tw_y_offset; } @@ -129,6 +132,7 @@ bool LoadPlacement(xml_node<>* node, int* x, int* y, int* w /* = NULL */, int* h value = node->first_attribute("w")->value(); DataManager::GetValue(value, value); *w = atol(value.c_str()); + *w = scale_theme_x(*w); } if (h && node->first_attribute("h")) @@ -136,6 +140,7 @@ bool LoadPlacement(xml_node<>* node, int* x, int* y, int* w /* = NULL */, int* h value = node->first_attribute("h")->value(); DataManager::GetValue(value, value); *h = atol(value.c_str()); + *h = scale_theme_y(*h); } if (placement && node->first_attribute("placement")) @@ -581,7 +586,58 @@ int PageSet::Load(ZipArchive* package) if (!parent) parent = mDoc.first_node("install"); + set_scale_values(1, 1); // Reset any previous scaling values + // Now, let's parse the XML + LOGINFO("Checking resolution...\n"); + child = parent->first_node("details"); + if (child) { + xml_node<>* resolution = child->first_node("resolution"); + if (resolution) { + xml_attribute<>* width_attr = resolution->first_attribute("width"); + xml_attribute<>* height_attr = resolution->first_attribute("height"); + xml_attribute<>* noscale_attr = resolution->first_attribute("noscaling"); + if (width_attr && height_attr && !noscale_attr) { + int width = atoi(width_attr->value()); + int height = atoi(height_attr->value()); + int offx = 0, offy = 0; +#ifdef TW_ROUND_SCREEN + xml_node<>* roundscreen = child->first_node("roundscreen"); + if (roundscreen) { + LOGINFO("TW_ROUND_SCREEN := true, using round screen XML settings.\n"); + xml_attribute<>* offx_attr = roundscreen->first_attribute("offset_x"); + xml_attribute<>* offy_attr = roundscreen->first_attribute("offset_y"); + if (offx_attr) { + offx = atoi(offx_attr->value()); + } + if (offy_attr) { + offy = atoi(offy_attr->value()); + } + } +#endif + if (width != 0 && height != 0) { + float scale_w = ((float)gr_fb_width() - ((float)offx * 2.0)) / (float)width; + float scale_h = ((float)gr_fb_height() - ((float)offy * 2.0)) / (float)height; +#ifdef TW_ROUND_SCREEN + float scale_off_w = (float)gr_fb_width() / (float)width; + float scale_off_h = (float)gr_fb_height() / (float)height; + tw_x_offset = offx * scale_off_w; + tw_y_offset = offy * scale_off_h; +#endif + if (scale_w != 1 || scale_h != 1) { + LOGINFO("Scaling theme width %fx and height %fx, offsets x: %i y: %i\n", scale_w, scale_h, tw_x_offset, tw_y_offset); + set_scale_values(scale_w, scale_h); + } + } + } else { + LOGINFO("XML does not contain width and height, no scaling will be applied\n"); + } + } else { + LOGINFO("XML contains no resolution tag, no scaling will be applied.\n"); + } + } else { + LOGINFO("XML contains no details tag, no scaling will be applied.\n"); + } LOGINFO("Loading resources...\n"); child = parent->first_node("resources"); if (child) diff --git a/gui/resources.cpp b/gui/resources.cpp index d769c17e..d9f2741d 100644 --- a/gui/resources.cpp +++ b/gui/resources.cpp @@ -23,6 +23,7 @@ extern "C" { #include "../twcommon.h" #include "../minuitwrp/minui.h" +#include "gui.h" } #include "rapidxml.hpp" @@ -61,6 +62,49 @@ int Resource::ExtractResource(ZipArchive* pZip, std::string folderName, std::str return ret; } +void Resource::LoadImage(ZipArchive* pZip, std::string file, gr_surface* source) +{ + if (ExtractResource(pZip, "images", file, ".png", TMP_RESOURCE_NAME) == 0) + { + res_create_surface(TMP_RESOURCE_NAME, source); + unlink(TMP_RESOURCE_NAME); + } + else if (ExtractResource(pZip, "images", file, "", TMP_RESOURCE_NAME) == 0) + { + // JPG includes the .jpg extension in the filename so extension should be blank + res_create_surface(TMP_RESOURCE_NAME, source); + unlink(TMP_RESOURCE_NAME); + } + else if (!pZip) + { + // File name in xml may have included .png so try without adding .png + res_create_surface(file.c_str(), source); + } +} + +void Resource::CheckAndScaleImage(gr_surface source, gr_surface* destination, int retain_aspect) +{ + if (!source) { + *destination = NULL; + return; + } + if (get_scale_w() != 0 && get_scale_h() != 0) { + float scale_w = get_scale_w(), scale_h = get_scale_h(); + if (retain_aspect) { + if (scale_w < scale_h) + scale_h = scale_w; + else + scale_w = scale_h; + } + if (res_scale_surface(source, destination, scale_w, scale_h)) { + LOGINFO("Error scaling image, using regular size.\n"); + *destination = source; + } + } else { + *destination = source; + } +} + FontResource::FontResource(xml_node<>* node, ZipArchive* pZip) : Resource(node, pZip) { @@ -86,7 +130,7 @@ FontResource::FontResource(xml_node<>* node, ZipArchive* pZip) if(!attr) return; - int size = atoi(attr->value()); + int size = scale_theme_min(atoi(attr->value())); int dpi = 300; attr = node->first_attribute("dpi"); @@ -143,10 +187,11 @@ FontResource::~FontResource() } } -ImageResource::ImageResource(xml_node<>* node, ZipArchive* pZip) +ImageResource::ImageResource(xml_node<>* node, ZipArchive* pZip, int retain_aspect) : Resource(node, pZip) { std::string file; + gr_surface temp_surface = NULL; mSurface = NULL; if (!node) { @@ -156,20 +201,13 @@ ImageResource::ImageResource(xml_node<>* node, ZipArchive* pZip) if (node->first_attribute("filename")) file = node->first_attribute("filename")->value(); + else { + LOGERR("No filename specified for image resource.\n"); + return; + } - if (ExtractResource(pZip, "images", file, ".png", TMP_RESOURCE_NAME) == 0) - { - res_create_surface(TMP_RESOURCE_NAME, &mSurface); - unlink(TMP_RESOURCE_NAME); - } - else if (ExtractResource(pZip, "images", file, "", TMP_RESOURCE_NAME) == 0) - { - // JPG includes the .jpg extension in the filename so extension should be blank - res_create_surface(TMP_RESOURCE_NAME, &mSurface); - unlink(TMP_RESOURCE_NAME); - } - else - res_create_surface(file.c_str(), &mSurface); + LoadImage(pZip, file, &temp_surface); + CheckAndScaleImage(temp_surface, &mSurface, retain_aspect); } ImageResource::~ImageResource() @@ -178,7 +216,7 @@ ImageResource::~ImageResource() res_free_surface(mSurface); } -AnimationResource::AnimationResource(xml_node<>* node, ZipArchive* pZip) +AnimationResource::AnimationResource(xml_node<>* node, ZipArchive* pZip, int retain_aspect) : Resource(node, pZip) { std::string file; @@ -189,30 +227,24 @@ AnimationResource::AnimationResource(xml_node<>* node, ZipArchive* pZip) if (node->first_attribute("filename")) file = node->first_attribute("filename")->value(); + else { + LOGERR("No filename specified for image resource.\n"); + return; + } for (;;) { std::ostringstream fileName; fileName << file << std::setfill ('0') << std::setw (3) << fileNum; - gr_surface surface; - if (pZip) - { - if (ExtractResource(pZip, "images", fileName.str(), ".png", TMP_RESOURCE_NAME) != 0) - break; - - if (res_create_surface(TMP_RESOURCE_NAME, &surface)) - break; - - unlink(TMP_RESOURCE_NAME); - } - else - { - if (res_create_surface(fileName.str().c_str(), &surface)) - break; - } - mSurfaces.push_back(surface); - fileNum++; + gr_surface surface, temp_surface = NULL; + LoadImage(pZip, fileName.str(), &temp_surface); + CheckAndScaleImage(temp_surface, &surface, retain_aspect); + if (surface) { + mSurfaces.push_back(surface); + fileNum++; + } else + break; // Done loading animation images } } @@ -264,17 +296,24 @@ void ResourceManager::LoadResources(xml_node<>* resList, ZipArchive* pZip) } else if (type == "image") { - res = new ImageResource(child, pZip); + int retain = 0; + xml_attribute<>* retain_aspect_ratio = child->first_attribute("retainaspect"); + if (retain_aspect_ratio) + retain = 1; // the value does not matter, if retainaspect is present, we assume that we want to retain it + res = new ImageResource(child, pZip, retain); } else if (type == "animation") { - res = new AnimationResource(child, pZip); + int retain = 0; + xml_attribute<>* retain_aspect_ratio = child->first_attribute("retainaspect"); + if (retain_aspect_ratio) + retain = 1; // the value does not matter, if retainaspect is present, we assume that we want to retain it + res = new AnimationResource(child, pZip, retain); } else { LOGERR("Resource type (%s) not supported.\n", type.c_str()); } - if (res == NULL || res->GetResource() == NULL) { std::string res_name; diff --git a/gui/resources.hpp b/gui/resources.hpp index 603b1c95..cc5e7b6f 100644 --- a/gui/resources.hpp +++ b/gui/resources.hpp @@ -25,6 +25,8 @@ private: protected: static int ExtractResource(ZipArchive* pZip, std::string folderName, std::string fileName, std::string fileExtn, std::string destFile); + static void LoadImage(ZipArchive* pZip, std::string file, gr_surface* source); + static void CheckAndScaleImage(gr_surface source, gr_surface* destination, int retain_aspect); }; class FontResource : public Resource @@ -52,7 +54,7 @@ protected: class ImageResource : public Resource { public: - ImageResource(xml_node<>* node, ZipArchive* pZip); + ImageResource(xml_node<>* node, ZipArchive* pZip, int retain_aspect); virtual ~ImageResource(); public: @@ -65,7 +67,7 @@ protected: class AnimationResource : public Resource { public: - AnimationResource(xml_node<>* node, ZipArchive* pZip); + AnimationResource(xml_node<>* node, ZipArchive* pZip, int retain_aspect); virtual ~AnimationResource(); public: diff --git a/gui/scrolllist.cpp b/gui/scrolllist.cpp index 3010d3a7..eb66de8e 100644 --- a/gui/scrolllist.cpp +++ b/gui/scrolllist.cpp @@ -91,7 +91,7 @@ GUIScrollList::GUIScrollList(xml_node<>* node) : GUIObject(node) attr = child->first_attribute("separatorheight"); if (attr) { string parsevalue = gui_parse_text(attr->value()); - mHeaderSeparatorH = atoi(parsevalue.c_str()); + mHeaderSeparatorH = scale_theme_y(atoi(parsevalue.c_str())); header_separator_height_specified = -1; } } @@ -156,7 +156,7 @@ GUIScrollList::GUIScrollList(xml_node<>* node) : GUIObject(node) attr = child->first_attribute("spacing"); if (attr) { string parsevalue = gui_parse_text(attr->value()); - mItemSpacing = atoi(parsevalue.c_str()); + mItemSpacing = scale_theme_y(atoi(parsevalue.c_str())); } attr = child->first_attribute("highlightcolor"); @@ -185,7 +185,7 @@ GUIScrollList::GUIScrollList(xml_node<>* node) : GUIObject(node) attr = child->first_attribute("height"); if (attr) { string parsevalue = gui_parse_text(attr->value()); - mSeparatorH = atoi(parsevalue.c_str()); + mSeparatorH = scale_theme_y(atoi(parsevalue.c_str())); if (!header_separator_height_specified) mHeaderSeparatorH = mSeparatorH; } @@ -206,25 +206,25 @@ GUIScrollList::GUIScrollList(xml_node<>* node) : GUIObject(node) attr = child->first_attribute("w"); if (attr) { string parsevalue = gui_parse_text(attr->value()); - mFastScrollW = atoi(parsevalue.c_str()); + mFastScrollW = scale_theme_x(atoi(parsevalue.c_str())); } attr = child->first_attribute("linew"); if (attr) { string parsevalue = gui_parse_text(attr->value()); - mFastScrollLineW = atoi(parsevalue.c_str()); + mFastScrollLineW = scale_theme_x(atoi(parsevalue.c_str())); } attr = child->first_attribute("rectw"); if (attr) { string parsevalue = gui_parse_text(attr->value()); - mFastScrollRectW = atoi(parsevalue.c_str()); + mFastScrollRectW = scale_theme_x(atoi(parsevalue.c_str())); } attr = child->first_attribute("recth"); if (attr) { string parsevalue = gui_parse_text(attr->value()); - mFastScrollRectH = atoi(parsevalue.c_str()); + mFastScrollRectH = scale_theme_y(atoi(parsevalue.c_str())); } } diff --git a/gui/slidervalue.cpp b/gui/slidervalue.cpp index 3ae6b985..7c38e329 100644 --- a/gui/slidervalue.cpp +++ b/gui/slidervalue.cpp @@ -173,14 +173,14 @@ GUISliderValue::GUISliderValue(xml_node<>* node) : GUIObject(node) if (attr) { string parsevalue = gui_parse_text(attr->value()); - mLineH = atoi(parsevalue.c_str()); + mLineH = scale_theme_y(atoi(parsevalue.c_str())); } attr = child->first_attribute("linepadding"); if (attr) { string parsevalue = gui_parse_text(attr->value()); - mPadding = atoi(parsevalue.c_str()); + mPadding = scale_theme_x(atoi(parsevalue.c_str())); mLinePadding = mPadding; } @@ -188,14 +188,14 @@ GUISliderValue::GUISliderValue(xml_node<>* node) : GUIObject(node) if (attr) { string parsevalue = gui_parse_text(attr->value()); - mSliderW = atoi(parsevalue.c_str()); + mSliderW = scale_theme_x(atoi(parsevalue.c_str())); } attr = child->first_attribute("sliderh"); if (attr) { string parsevalue = gui_parse_text(attr->value()); - mSliderH = atoi(parsevalue.c_str()); + mSliderH = scale_theme_y(atoi(parsevalue.c_str())); } } diff --git a/minuitwrp/minui.h b/minuitwrp/minui.h index 3aa48651..fff7ddb9 100644 --- a/minuitwrp/minui.h +++ b/minuitwrp/minui.h @@ -67,6 +67,7 @@ unsigned int gr_get_height(gr_surface surface); int gr_get_surface(gr_surface* surface); int gr_free_surface(gr_surface surface); +// Functions in graphics_utils.c int gr_save_screenshot(const char *dest); // input event structure, include for the definition. @@ -83,6 +84,7 @@ int ev_has_mouse(void); // Returns 0 if no error, else negative. int res_create_surface(const char* name, gr_surface* pSurface); void res_free_surface(gr_surface surface); +int res_scale_surface(gr_surface source, gr_surface* destination, float scale_w, float scale_h); // Needed for AOSP: int ev_wait(int timeout); diff --git a/minuitwrp/resources.c b/minuitwrp/resources.c index 2e58311a..eef5713a 100644 --- a/minuitwrp/resources.c +++ b/minuitwrp/resources.c @@ -347,7 +347,7 @@ int res_create_surface(const char* name, gr_surface* pSurface) { if (!name) return -1; if (strlen(name) > 4 && strcmp(name + strlen(name) - 4, ".jpg") == 0) - return res_create_surface_jpg(name,pSurface); + return res_create_surface_jpg(name,pSurface); ret = res_create_surface_png(name,pSurface); if (ret < 0) @@ -362,3 +362,77 @@ void res_free_surface(gr_surface surface) { free(pSurface); } } + +// Scale image function +int res_scale_surface(gr_surface source, gr_surface* destination, float scale_w, float scale_h) { + GGLContext *sc_context = 0; + gglInit(&sc_context); + GGLContext *gl = sc_context; + GGLSurface* sc_mem_surface = NULL; + *destination = NULL; + GGLSurface *surface = (GGLSurface*)source; + int w = gr_get_width(source), h = gr_get_height(source); + int sx = 0, sy = 0, dx = 0, dy = 0; + float dw = (float)w * scale_w; + float dh = (float)h * scale_h; + + // Create a new surface that is the appropriate size + sc_mem_surface = init_display_surface((int)dw, (int)dh); + if (!sc_mem_surface) { + printf("gr_scale_surface failed to init_display_surface\n"); + return -1; + } + sc_mem_surface->format = surface->format; + + // Finish initializing the context + gl->colorBuffer(gl, sc_mem_surface); + gl->activeTexture(gl, 0); + + // Enable or disable blending based on source surface format + if (surface->format == GGL_PIXEL_FORMAT_RGBX_8888) { + gl->disable(gl, GGL_BLEND); + } else { + gl->enable(gl, GGL_BLEND); + gl->blendFunc(gl, GGL_ONE, GGL_ZERO); + } + + // Bind our source surface to the context + gl->bindTexture(gl, surface); + + // Deal with the scaling + gl->texParameteri(gl, GGL_TEXTURE_2D, GGL_TEXTURE_MIN_FILTER, GGL_LINEAR); + gl->texParameteri(gl, GGL_TEXTURE_2D, GGL_TEXTURE_MAG_FILTER, GGL_LINEAR); + gl->texParameteri(gl, GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_S, GGL_CLAMP); + gl->texParameteri(gl, GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_T, GGL_CLAMP); + gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE); + gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_AUTOMATIC); + gl->texGeni(gl, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_AUTOMATIC); + gl->enable(gl, GGL_TEXTURE_2D); + + int32_t grad[8]; + memset(grad, 0, sizeof(grad)); + // s, dsdx, dsdy, scale, t, dtdx, dtdy, tscale <- this is wrong! + // This api uses block floating-point for S and T texture coordinates. + // All values are given in 16.16, scaled by 'scale'. In other words, + // set scale to 0, for 16.16 values. + + // s, dsdx, dsdy, t, dtdx, dtdy, sscale, tscale + float dsdx = (float)w / dw; + float dtdy = (float)h / dh; + grad[0] = ((float)sx - (dsdx * dx)) * 65536; + grad[1] = dsdx * 65536; + grad[3] = ((float)sy - (dtdy * dy)) * 65536; + grad[5] = dtdy * 65536; +// printf("blit: w=%d h=%d dx=%d dy=%d dw=%f dh=%f dsdx=%f dtdy=%f s0=%x dsdx=%x t0=%x dtdy=%x\n", +// w, h, dx, dy, dw, dh, dsdx, dtdy, grad[0], grad[1], grad[3], grad[5]); + gl->texCoordGradScale8xv(gl, 0 /*tmu*/, grad); + + // draw / scale the source surface to our target context + gl->recti(gl, dx, dy, dx + dw, dy + dh); + // put the scaled surface in our destination + *destination = (gr_surface*) sc_mem_surface; + // free memory used in the source + res_free_surface(source); + source = NULL; + return 0; +}