From 6ea0db2ccd53cdf677d71050f6c6514e4b97e510 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sat, 22 Aug 2015 23:20:21 -0700 Subject: [PATCH] GUI: Upstream cross-platform GUI code --- CMakeLists.txt | 1 + res/font.png | Bin 0 -> 5383 bytes src/util/gui.h | 35 ++++++++++ src/util/gui/file-select.c | 128 +++++++++++++++++++++++++++++++++++++ src/util/gui/file-select.h | 13 ++++ src/util/gui/font.h | 25 ++++++++ 6 files changed, 202 insertions(+) create mode 100644 res/font.png create mode 100644 src/util/gui.h create mode 100644 src/util/gui/file-select.c create mode 100644 src/util/gui/file-select.h create mode 100644 src/util/gui/font.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f97de096..9197ebc7a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,7 @@ file(GLOB GBA_SRC ${CMAKE_SOURCE_DIR}/src/gba/*.c) file(GLOB GBA_CHEATS_SRC ${CMAKE_SOURCE_DIR}/src/gba/cheats/*.c) file(GLOB GBA_RR_SRC ${CMAKE_SOURCE_DIR}/src/gba/rr/*.c) file(GLOB GBA_SV_SRC ${CMAKE_SOURCE_DIR}/src/gba/supervisor/*.c) +file(GLOB GUI_SRC ${CMAKE_SOURCE_DIR}/src/gui/*.c) file(GLOB UTIL_SRC ${CMAKE_SOURCE_DIR}/src/util/*.[cSs]) file(GLOB RENDERER_SRC ${CMAKE_SOURCE_DIR}/src/gba/renderers/*.c) file(GLOB SIO_SRC ${CMAKE_SOURCE_DIR}/src/gba/sio/lockstep.c) diff --git a/res/font.png b/res/font.png new file mode 100644 index 0000000000000000000000000000000000000000..73b9893c564395a0318693a381cdc5ee3dba44a5 GIT binary patch literal 5383 zcmeHJQC;7 z&{M|R+HR0t*F^aLmfYM-;cy5_(EE`w!dAG5cDn*kiZ31R}ERVSxah%x$>d`BtE0tXR+ z)9RD_M2i4H4JZU8C=~$;YB-48Ol~6}9}ln@u(w+S^aTJLo{-H60Fir{6^H|vr?S!D z5IXL`)h%A6w?bt;2=y4Ur7T=vxSv9g~PASz;a{>V`u!)HvGw-k_?PF>QTU^_0 z1;KXzEIN@;G4kb;K>)~4rn#H;kSeT6%;GKEmzh6W0NrvlVgv>x($Y8ghjnK>qfe$%*HGwNWidLeI`_tgp{J?NlMC1#5jMDo@U0mb0&sUfDu^{;+ap3CC1~^#TBn8$8;6@e+U#&fzN~zPE?aYxR6C0O6?l-U|S%R5%4;{k6~@0sv6S59Rx+ z$Z*>BkiQk5vF+Y`8}XHmM1&G&XS))G647%6qqohYiZCVKsG+Y+d^V6@3QS_H2F_6_ zo@9dU#y`pAJjwss66CexeJsb~we`ed12KqTxcs!?4yHMGV+?ia}qWps%oeT3R4;?d_m z!r6%r@^ePLzthXbOB8I4mOGQrCCV%J2(|ux2o~*pDJ0n4q4ezuKVgdfz&G{^lJai) zug@w#4KZi-Bj0@Ss6tg+2_^7+l~`?=6*b`6aNQY=5>`e|G0HhYNkUMBK|2q7N{QBY z?t02Uoe%9qgrnga{2WtMiT5ECfk@>}NlvO5Wf2~960YXA&#-Z-akX)GLym3!(i|}j zdXAL7x#zAmV5wAo*2le(>$&S4>!Rxn>uks7M7eefUY{?GR(TEkUp%GTpx6-Gz<03eg%7rv$ z-HcI_@qumi-xJUS>#zB z#&A9q-&>mGexkIeY20ZHd=OY^Sy9z zhGyTs;cLjeW@?C&D=RIKQWkwGYEo->lIjQruVs2&e(=#H+~O_HI0=qjq&|GK`iP-O zOdBoiVBuPpo{n~#vPhAefQx>CjQ*_Jorkpyy9-;bBrFC>)H)ilL zRVX)9kgby)ty5iBRmVX}Q%X>M(7S6nFlqEGSviv#Q}CjAU-}mK8Ao6c#YIkCXj7f|kXOu1Y zn01de_;do^?Lwy5-6S0TJ~_!tsf3e z=RF?UAFS=iBuRca{CK-h)lRkY9`z+k%S3<)zS&gqLaIjA%O69uMsx3R)HD1F*`Ki} zKDSA|@_mzxs^BK>03Fv*tG52IwjVgIyTrys8<9b~^V9p5dT@y8(hu9eQMnBAG%>MN z)EL?fnvfaZdA|*YXpjDutohXMrRAOI=Od2ej@z4y0(s_S>17$48D#FHvvc1`m!5s! zKRZ{&Kr)7SF%97;WprVS?9WDr;=bV_87S;C>=gDFCUG#n@WXcc(tYfJA+YgWY;O`{ z-gt2>-`9*W#xd5Jbewd+YGP|Ipj9zt+n4EBH_J+0H?RF3&^YKC%t3~lM*o^*8kd6^ zCQd!xRVV9VX}-xl^c5hLAT@sXp?j6XQ^kLM`+{)kf|*o$?oE7P#R_3AeQH!U|PSn$uh z4dxRnaLayp=>@sRVLgS<%DC!n+?GtE%&^7rPoLu&%*K6_pC;MW($;P}K0C5EDHD1< z4Idh^tI!s%=!1Z!AAyb++YEViR5t20TAwQHE6yq}L{CD^Z{}wX=R;n!`sSaE&8uJFM~08wB%dXcE8k1ZN*stH zjoQt7A}=Mi3iZC;zA9E8c|O9OM|<<>W}u4p0VMcxa(8-oEOV?N<2WOw#qI5v>z&qJ zx@t^!dpC1)pP#6()#)?rew**SFVkV+61m>`ThW<7NM`~7t;c)oE;RrE0s7i7RT)Lq z+kbJ_{6G9pf&Xs`Olb_)-OUX0G1N7>y#=QGNfiMAOslD)2=klUvzQ*=eL{eruymVj z3$b92RnV=e&9Rp~p*5}P=TQ)2Aj}Jr3%Vv%0F44-!2gNBwK4 z3GX$?_!Yha#V|#E2$N{$X*&T>^8}9rK>!>ZP$}Sd*Mih2k_!VCJA~*ho0w9%uGN?R z)I~0fb5I3^XOZJBQ`7wT>~d(ErDB5XO!VgiXn5Q0v5ZnhF%p}|W-rCS5r(j8!33d| zTR%tgyBeHi=`Z$QLmTMv@);jDZq^MT)+krQJ9LZWb{uS6>zgbQesT#tkWd=J^ocE$ zLbJgkK{bsi0nswoz3t4SN4*JD&3c`mraAOqbH|Yg6#|-d8mDxgdq|9MlI;W%3WuWE zvG!?(eciP*21xSFiP>pA6|G~BbxcIXOs-NLnfUtKfu6r!VN0We8t3*dPtFK_bAdGh zO1Xl;M7cnIeAs2B=!%}u<3XuqP6tM21vDpaFWKY%dyxJJlWw*ivr-hkfl;YVLWb4& zlZU~oZC4|1IKhFQdoPdh^KqP`k+gPuaZ^?o4i4AgIhi)IAWm3i>WLvllGK^|d!6FG zU+GS_Y~5K^lL6@%?`Kqy@gdgf*8!e6a}#;NvHQp7ze`pl&D17^(X#>5&7)nGfn(Bb z4A;eT#f3t4lNmc93_h%?vsc^o&ve9v2EX1Hs*-xoq%|wD#LAX*{Zax%N}II{)UAdXf6m^$qBR$Pf9=+PJo_hf@!@PMUz*c*(|bU?)N0Z3 zES7fYN4DEEitKs#vAZ11(JE?qBQmAc1Nb;RAY5j)4%|Jue{gdlw>$!v3mUzUIr%T1 zeZKl>Cm}Wyx;dozNnTGr+#e}8xGmtpim*^<%`igUsp%&1_cV= zM3gnX1NkN1>z`j>Evi1+mWamCzXa$J=V0m^;5@+Cc}d1Ke%1T5aTrRlRmj3K1xlKr z^6&K!`j*NS(yA|;kWt#?zPo?qGH~Oc6S8aTuFTsq#6rmUl^5L)%hWd zh?77$w!OIlA~K)|udVkp?PeJ2sKK{^S#LddZh-B-_j=CuBsuSgDPAbfa(b;#48UiW z+N-Nr6!rofHtl9M<>kIRxQ!J1KQ%Opvk|fK*E|sBl+aeL^%L!~QutbM$V#18@Ah(U zzH5BW<3uPvMC!@qy zQ2Q2Ec2u{LBzyyWW7OW%|704(g;RDke_z77wP+|(Iy|=}VyzCEU)grI!G4X<<*Fv@ zE^K9xM}H5raZWxHz_R}_k{^JK#*SJBw!~hTV;57$y2oSBx%nv>v4YZWlei!CY{c65 zPkN|!hZ!Vey zmR=h%Kxoa*LtrVA+vhk5$jm@^_g}dS+M^VXh}=>~>nwC_FyG6LY}`&QoskHM;Fj!; zH4S=1khkBIIr=t%@amNKRVL9#eae=W!%;<3j1!zRpcaCzB5j}IB( za_a7?WXXM-;L+z-`>%Wmaw$uMlo!EUABPO68vQ0a~x> zu8C=ILt_F)SoE=YyT{e*VE*j25U*f`!M0qM(Qf^JpF`q5;47$J4FGv*J2CI=~>WKOpmeS6s7I=*aTDmp*Sa;RRtD~!B>YTAa}k% zALaWM&9}b22>)P2`LwJKu97!oyCWD{{XA=OmmI&i;?K=TlKMV)%at5}m4i};u|eC< uJg_GpImDJ&BJzI{cwj+u^lvZEMgR}IEL%*Z`JKZA08Le0l`18hu>S!2ey`yG literal 0 HcmV?d00001 diff --git a/src/util/gui.h b/src/util/gui.h new file mode 100644 index 000000000..d8b2bb058 --- /dev/null +++ b/src/util/gui.h @@ -0,0 +1,35 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GUI_H +#define GUI_H + +#include "util/common.h" + +struct GUIFont; + +enum GUIInput { + GUI_INPUT_NONE = -1, + GUI_INPUT_SELECT = 0, + GUI_INPUT_BACK, + GUI_INPUT_CANCEL, + + GUI_INPUT_UP, + GUI_INPUT_DOWN, + GUI_INPUT_LEFT, + GUI_INPUT_RIGHT, +}; + +struct GUIParams { + int width; + int height; + const struct GUIFont* font; + + void (*drawStart)(void); + void (*drawEnd)(void); + int (*pollInput)(void); +}; + +#endif diff --git a/src/util/gui/file-select.c b/src/util/gui/file-select.c new file mode 100644 index 000000000..05a0fbb67 --- /dev/null +++ b/src/util/gui/file-select.c @@ -0,0 +1,128 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "file-select.h" + +#include "util/gui/font.h" +#include "util/vector.h" +#include "util/vfs.h" + +DECLARE_VECTOR(FileList, char*); +DEFINE_VECTOR(FileList, char*); + +void _cleanFiles(struct FileList* currentFiles) { + size_t size = FileListSize(currentFiles); + size_t i; + for (i = 0; i < size; ++i) { + free(*FileListGetPointer(currentFiles, i)); + } + FileListClear(currentFiles); +} + +void _upDirectory(char* currentPath) { + char* end = strrchr(currentPath, '/'); + if (!end) { + return; + } + end[0] = '\0'; + if (end[1]) { + return; + } + // TODO: What if there was a trailing slash? +} + +bool _refreshDirectory(const char* currentPath, struct FileList* currentFiles) { + _cleanFiles(currentFiles); + + struct VDir* dir = VDirOpen(currentPath); + if (!dir) { + return false; + } + struct VDirEntry* de; + while ((de = dir->listNext(dir))) { + if (de->name(de)[0] == '.') { + continue; + } + *FileListAppend(currentFiles) = strdup(de->name(de)); + } + dir->close(dir); + return true; +} + +bool selectFile(const struct GUIParams* params, const char* basePath, char* outPath, size_t outLen, const char* suffix) { + char currentPath[256]; + strncpy(currentPath, basePath, sizeof(currentPath)); + int oldInput = -1; + size_t fileIndex = 0; + size_t start = 0; + + struct FileList currentFiles; + FileListInit(¤tFiles, 0); + _refreshDirectory(currentPath, ¤tFiles); + + while (true) { + int input = params->pollInput(); + int newInput = input & (oldInput ^ input); + oldInput = input; + + if (newInput & (1 << GUI_INPUT_UP) && fileIndex > 0) { + --fileIndex; + } + if (newInput & (1 << GUI_INPUT_DOWN) && fileIndex < FileListSize(¤tFiles) - 1) { + ++fileIndex; + } + if (fileIndex < start) { + start = fileIndex; + } + while ((fileIndex - start + 4) * GUIFontHeight(params->font) > params->height) { + ++start; + } + if (newInput & (1 << GUI_INPUT_CANCEL)) { + _cleanFiles(¤tFiles); + FileListDeinit(¤tFiles); + return false; + } + if (newInput & (1 << GUI_INPUT_SELECT)) { + snprintf(currentPath, sizeof(currentPath), "%s%c%s", currentPath, '/', *FileListGetPointer(¤tFiles, fileIndex)); + if (!_refreshDirectory(currentPath, ¤tFiles)) { + strncpy(outPath, currentPath, outLen); + return true; + } + fileIndex = 0; + } + if (newInput & (1 << GUI_INPUT_BACK)) { + if (strncmp(currentPath, basePath, sizeof(currentPath)) == 0) { + _cleanFiles(¤tFiles); + FileListDeinit(¤tFiles); + return false; + } + _upDirectory(currentPath); + _refreshDirectory(currentPath, ¤tFiles); + fileIndex = 0; + } + + params->drawStart(); + int y = GUIFontHeight(params->font); + GUIFontPrintf(params->font, 0, y, GUI_TEXT_LEFT, 0xFFFFFFFF, "Current directory: %s", currentPath); + y += 2 * GUIFontHeight(params->font); + size_t i; + for (i = start; i < FileListSize(¤tFiles); ++i) { + int color = 0xE0A0A0A0; + char bullet = ' '; + if (i == fileIndex) { + color = 0xFFFFFFFF; + bullet = '>'; + } + GUIFontPrintf(params->font, 0, y, GUI_TEXT_LEFT, color, "%c %s", bullet, *FileListGetPointer(¤tFiles, i)); + y += GUIFontHeight(params->font); + if (y + GUIFontHeight(params->font) > params->height) { + break; + } + } + y += GUIFontHeight(params->font) * 2; + + params->drawEnd(); + } +} diff --git a/src/util/gui/file-select.h b/src/util/gui/file-select.h new file mode 100644 index 000000000..c96f821c0 --- /dev/null +++ b/src/util/gui/file-select.h @@ -0,0 +1,13 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GUI_FILE_CHOOSER_H +#define GUI_FILE_CHOOSER_H + +#include "util/gui.h" + +bool selectFile(const struct GUIParams*, const char* basePath, char* outPath, size_t outLen, const char* suffix); + +#endif diff --git a/src/util/gui/font.h b/src/util/gui/font.h new file mode 100644 index 000000000..4120814c2 --- /dev/null +++ b/src/util/gui/font.h @@ -0,0 +1,25 @@ +/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GUI_FONT_H +#define GUI_FONT_H + +#include "util/common.h" + +struct GUIFont; +struct GUIFont* GUIFontCreate(void); +void GUIFontDestroy(struct GUIFont*); + +enum GUITextAlignment { + GUI_TEXT_LEFT = 0, + GUI_TEXT_CENTER, + GUI_TEXT_RIGHT +}; + +int GUIFontHeight(const struct GUIFont*); + +void GUIFontPrintf(const struct GUIFont*, int x, int y, enum GUITextAlignment, uint32_t color, const char* text, ...); + +#endif