diff --git a/.gitignore b/.gitignore
index 349553ac..48679ecb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,8 +15,6 @@
*.d
*.opk
*.klf
-*.raw
-*.wav
*.iso
*.gdi
*.cdi
diff --git a/Makefile b/Makefile
index 63cb0af2..a7ab126a 100644
--- a/Makefile
+++ b/Makefile
@@ -11,10 +11,14 @@
#
TARGET = DS
-TARGET_NAME = DreamShell_v4.0.0_Release
+TARGET_NAME = DreamShell_v4.0.1_Release
TARGET_BIN = $(TARGET)_CORE.BIN
TARGET_BIN_CD = 1$(TARGET_BIN)
-TRAGET_VERSION = -DVER_MAJOR=4 -DVER_MINOR=0 -DVER_MICRO=0 -DVER_BUILD=0x30
+# Build types: 0x0N - Alpha, 0x1N - Beta, 0x2N - RC, 0x3N - Release
+TRAGET_VERSION = -DVER_MAJOR=4 \
+ -DVER_MINOR=0 \
+ -DVER_MICRO=1 \
+ -DVER_BUILD=0x30
# TARGET_DEBUG = 1 # or 2 for GDB
# TARGET_EMU = 1
# TARGET_PROF = 1
@@ -30,9 +34,12 @@ SRC_DIR = $(DS_BASE)/src
LIB_DIR = $(DS_BASE)/lib
KOS_LDFLAGS += -L$(LIB_DIR)
-KOS_CFLAGS += -I$(INC_DIR) -I$(INC_DIR)/SDL -I$(INC_DIR)/fatfs \
+KOS_CFLAGS += -I$(INC_DIR) -I$(INC_DIR)/img -I$(INC_DIR)/SDL -I$(INC_DIR)/fatfs \
+ -I$(INC_DIR)/tsunami \
-DHAVE_SDLIMAGE $(TRAGET_VERSION)
+KOS_CPPFLAGS += -Wno-template-id-cdtor
+
ifdef TARGET_DEBUG
KOS_CFLAGS += -g -DDS_DEBUG=$(TARGET_DEBUG)
endif
@@ -46,21 +53,26 @@ SDL_IMAGE_VER = 1.2.12
SDL_TTF_VER = 2.0.11
SDL_RTF_VER = 0.1.1
LUA_VER = 5.1.4-2
+TSUNAMI_VER = 2.0.0
+PARALLAX_VER = 2.0.0
+FREETYPE_VER = 2.4.4
-EXTRA_LIBS = -lcfg -lmxml -lparallax
+EXTRA_LIBS = -lcfg -lmxml
SDL_LIBS = -lSDL_$(SDL_VER) \
-lSDL_image_$(SDL_IMAGE_VER) \
-lSDL_ttf_$(SDL_TTF_VER) \
-lSDL_rtf_$(SDL_RTF_VER) \
-lSDL_gfx_$(SDL_GFX_VER) \
- -lfreetype
-
+ -lfreetype_$(FREETYPE_VER)
+
IMAGE_LIBS = -lkmg -ljpeg -lpng -lz
LUA_LIBS = -llua_$(LUA_VER)
KLIBS = -lkosext2fs -lkosutils -lstdc++ -lm
+GRAPHICS_LIBS = -ltsunami_$(TSUNAMI_VER) \
+ -lparallax_$(PARALLAX_VER)
-CORE_LIBS = $(EXTRA_LIBS) $(SDL_LIBS) $(IMAGE_LIBS) $(LUA_LIBS) $(KLIBS)
+CORE_LIBS = $(EXTRA_LIBS) $(SDL_LIBS) $(GRAPHICS_LIBS) $(IMAGE_LIBS) $(LUA_LIBS) $(KLIBS)
SDL_GUI = $(LIB_DIR)/SDL_gui
SDL_CONSOLE = $(LIB_DIR)/SDL_Console/src
@@ -99,7 +111,10 @@ OBJS = $(SRC_DIR)/main.o $(SRC_DIR)/video.o $(SRC_DIR)/console.o \
$(SRC_DIR)/module.o $(SRC_DIR)/events.o $(SRC_DIR)/fs/fs.o \
$(SRC_DIR)/lua/lua.o $(SRC_DIR)/lua/lua_ds.o $(SRC_DIR)/lua/packlib.o \
$(SRC_DIR)/app/app.o $(SRC_DIR)/app/load.o $(SRC_DIR)/list.o \
- $(SRC_DIR)/img/pvr.o $(SRC_DIR)/cmd_elf.o $(SRC_DIR)/vmu/vmu.o \
+ $(SRC_DIR)/img/SegaPVRImage.o $(SRC_DIR)/img/stb_image.o \
+ $(SRC_DIR)/img/load.o $(SRC_DIR)/img/utils.o \
+ $(SRC_DIR)/img/decode.o $(SRC_DIR)/img/convert.o $(SRC_DIR)/img/copy.o \
+ $(SRC_DIR)/cmd_elf.o $(SRC_DIR)/vmu/vmu.o \
$(SRC_DIR)/irq/exceptions.o $(SRC_DIR)/irq/setjmp.o \
$(SRC_DIR)/settings.o $(SRC_DIR)/sfx.o \
$(DRIVERS_OBJ) $(GUI_OBJS) $(CONSOLE_OBJ) \
@@ -165,9 +180,9 @@ $(LIB_DIR)/libSDL_$(SDL_VER).a:
build: $(TARGET)
@echo Building modules, commands, applications and firmwares...
- cd $(DS_BASE)/modules && make && make install
- cd $(DS_BASE)/commands && make && make install
- cd $(DS_BASE)/applications && make && make install
+ cd $(DS_BASE)/modules && make
+ cd $(DS_BASE)/commands && make
+ cd $(DS_BASE)/applications && make
cd $(DS_BASE)/firmware/isoldr && make && make install
cd $(DS_BASE)/firmware/bootloader && make && make install
# cd $(DS_BASE)/firmware/aica && make && make install
@@ -176,6 +191,7 @@ clean-all: clean
@-rm -rf $(DS_BUILD)/.* 2> /dev/null
@-rm -rf $(DS_BASE)/release
@-rm -rf $(DS_BASE)/build
+ @-rm -rf $(DS_SDK)/lib/*.a
cd $(DS_BASE)/lib && make clean
cd $(DS_BASE)/modules && make clean
cd $(DS_BASE)/commands && make clean
@@ -198,6 +214,32 @@ release: build cdi
@echo
@echo "\033[42m Complete $(DS_BASE)/release \033[0m"
+update:
+ @echo Fetching DreamShell from GitHub...
+ @git fetch && git checkout origin/master
+ @echo Fetching KallistiOS from GitHub...
+ @cd $(KOS_BASE) && git fetch && git checkout `cat $(DS_BASE)/sdk/doc/KallistiOS.txt`
+ @echo Fetching kos-ports from GitHub...
+ @cd $(KOS_BASE)/../kos-ports && git fetch && git checkout origin/master
+
+update-build:
+ @echo Fetching DreamShell from GitHub...
+ @git fetch && git checkout origin/master
+ @echo Fetching and build KallistiOS from GitHub...
+ @cd $(KOS_BASE) && git fetch && git checkout `cat $(DS_BASE)/sdk/doc/KallistiOS.txt` && make clean && make
+ @echo Fetching and build kos-ports from GitHub...
+ @mv include include_
+ @cd $(KOS_BASE)/../kos-ports && git fetch && git checkout origin/master && ./utils/build-all.sh
+ @mv include_ include
+ @echo Building DreamShell...
+ @make clean-all && make build
+
+toolchain:
+ @cp $(DS_SDK)/toolchain/environ.sh $(KOS_BASE)/environ.sh
+ @cp $(DS_SDK)/toolchain/patches/*.diff $(KOS_BASE)/utils/dc-chain/patches
+ @source $(KOS_BASE)/environ.sh
+ @cd $(KOS_BASE)/utils/dc-chain && cp Makefile.default.cfg Makefile.cfg && make
+
$(TARGET): libs $(TARGET_BIN) make-build
$(TARGET).elf: $(OBJS)
@@ -273,7 +315,7 @@ lxdgdb: $(TARGET).cdi
$(KOS_CC_BASE)/bin/$(KOS_CC_PREFIX)-gdb $(TARGET)-DBG.elf --eval-command "target remote localhost:2000"
flycast: $(TARGET).cdi
- Flycast -config config:Debug.SerialConsoleEnabled=yes
+ Flycast -config config:Debug.SerialConsoleEnabled=yes ./$(TARGET).cdi
gprof:
@sh-elf-gprof $(TARGET)-DBG.elf $(DS_BUILD)/kernel_gmon.out > gprof.out
diff --git a/README.md b/README.md
index d6c8f78d..2153a8e0 100644
--- a/README.md
+++ b/README.md
@@ -12,10 +12,16 @@ There are also large subproject is the ISO Loader, which contains emulation of B
### Setup environment
##### Packages
```console
-sudo apt-get install -y genisoimage squashfs-tools
-sudo apt-get install -y libpng-dev libjpeg-dev liblzo2-dev liblua5.2-dev
-cd /tmp && git clone https://github.com/LuaDist/tolua.git && cd tolua
-mkdir build && cd ./build
+sudo apt update
+sudo apt install -y gawk patch bzip2 tar make cmake pkg-config
+sudo apt install -y gettext wget bison flex sed meson ninja-build
+sudo apt install -y build-essential diffutils curl python3 rake
+sudo apt install -y genisoimage squashfs-tools texinfo git
+sudo apt install -y libgmp-dev libmpfr-dev libmpc-dev libelf-dev libisofs-dev
+sudo apt install -y libpng-dev libjpeg-dev liblzo2-dev liblua5.2-dev
+cd /tmp
+git clone https://github.com/LuaDist/tolua.git
+cd /tmp/tolua && mkdir build && cd ./build
cmake ../ && make && sudo make install
```
##### Code
@@ -24,7 +30,8 @@ sudo mkdir -p /usr/local/dc/kos
sudo chown -R $(id -u):$(id -g) /usr/local/dc
cd /usr/local/dc/kos
git clone https://github.com/KallistiOS/kos-ports.git
-git clone https://github.com/KallistiOS/KallistiOS.git kos && cd kos
+git clone https://github.com/KallistiOS/KallistiOS.git kos
+cd /usr/local/dc/kos/kos
git clone https://github.com/DC-SWAT/DreamShell.git ds
git checkout `cat ds/sdk/doc/KallistiOS.txt`
cp ds/sdk/toolchain/environ.sh environ.sh
@@ -35,20 +42,16 @@ cp ds/sdk/toolchain/patches/*.diff utils/dc-chain/patches
sudo mkdir -p /opt/toolchains/dc
sudo chown -R $(id -u):$(id -g) /opt/toolchains/dc
cd /usr/local/dc/kos/kos/utils/dc-chain
-cp config/config.mk.stable.sample config.mk
-make && cd ../../
+cp Makefile.default.cfg Makefile.cfg
+make
```
##### SDK
```console
cd /usr/local/dc/kos/kos
source ./environ.sh
-make && cd ../kos-ports && ./utils/build-all.sh && cd ./lib
-mv libfreetype.a libfreetype-kos.a
-mv liboggvorbisplay.a liboggvorbisplay-kos.a
-mv libogg.a libogg-kos.a
-mv libvorbis.a libvorbis-kos.a
-mv libwav.a libwav-kos.a
-cd ../../kos/ds/sdk/bin/src && make && make install && cd ../../../
+make && cd ../kos-ports && ./utils/build-all.sh
+cd ${KOS_BASE}/ds/sdk/bin/src && make && make install
+cd ${KOS_BASE}/ds
ln -nsf `which tolua` sdk/bin/tolua
ln -nsf `which mkisofs` sdk/bin/mkisofs
ln -nsf `which mksquashfs` sdk/bin/mksquashfs
@@ -61,28 +64,44 @@ cd /usr/local/dc/kos/kos/ds && source ../environ.sh
```
### Build code
-##### Core and libraries
+##### Full build
```console
-make
+make build
```
-##### Modules, applications and commands
+##### Full clean
```console
-cd ./modules && make && make install && cd ../
-cd ./commands && make && make install && cd ../
-cd ./applications && make && make install && cd ../
+make clean-all
```
-##### Firmwares
+##### Make release package
```console
-cd ./firmware/bootloader && make && make release && cd ../../
-cd ./firmware/isoldr && make && make install && cd ../../../
+make release
```
-##### Full build (modules, apps etc)
+##### Update code from GitHub
```console
-make build
+make update
```
-##### Make release package
+##### Update code from GitHub and re-build
```console
-make release
+make update-build
+```
+##### Re-build toochain (if updated)
+```console
+make toolchain
+```
+##### Core and libraries only
+```console
+make
+```
+##### Modules, applications and commands only
+```console
+cd ${KOS_BASE}/ds/modules && make
+cd ${KOS_BASE}/ds/commands && make
+cd ${KOS_BASE}/ds/applications && make
+```
+##### Firmwares only
+```console
+cd ${KOS_BASE}/ds/firmware/bootloader && make && make release
+cd ${KOS_BASE}/ds/firmware/isoldr && make && make install
```
### Running
@@ -90,6 +109,7 @@ make release
- dc-tool-serial: `make run-serial`
- lxdream emulator: `make lxdream`
- nulldc emulator: `make nulldc`
+- flycast emulator: `make flycast`
- make cdi image: `make cdi`
## Links
diff --git a/applications/Makefile b/applications/Makefile
index 6f72c730..c38792d0 100644
--- a/applications/Makefile
+++ b/applications/Makefile
@@ -6,13 +6,12 @@
_SUBDIRS = main filemanager region_changer iso_loader \
bios_flasher gd_ripper speedtest vmu_manager \
- settings gdplay dreameye network
-
+ settings gdplay dreameye network games_menu
all: $(patsubst %, _dir_%, $(_SUBDIRS))
$(patsubst %, _dir_%, $(_SUBDIRS)):
- $(MAKE) -C $(patsubst _dir_%, %, $@)
+ $(MAKE) -C $(patsubst _dir_%, %, $@) all install
clean: $(patsubst %, _clean_dir_%, $(_SUBDIRS))
diff --git a/applications/bios_flasher/app.xml b/applications/bios_flasher/app.xml
index 6e227fef..7812d1ed 100644
--- a/applications/bios_flasher/app.xml
+++ b/applications/bios_flasher/app.xml
@@ -18,7 +18,7 @@
-
+
@@ -31,14 +31,14 @@
-
+
-
+
diff --git a/applications/filemanager/lua/main.lua b/applications/filemanager/lua/main.lua
index 8643dbde..fdf63e80 100644
--- a/applications/filemanager/lua/main.lua
+++ b/applications/filemanager/lua/main.lua
@@ -25,7 +25,7 @@ FileManager = {
audio = {
ext = {
".mp1", ".mp2", ".mp3", ".ogg", ".adx", ".s3m", ".wav",
- ".raw"
+ ".raw", ".pcm", "dpcm"
}
},
@@ -570,8 +570,8 @@ function FileManager:openFile()
local mod = string.sub(ext, -3);
- if mod == "raw" then
- mod = "wav"
+ if mod == "raw" or mod == "wav" or mod == "pcm" then
+ mod = "wave"
elseif mod == "ogg" then
mod = "oggvorbis"
elseif mod == "mp1" or mod == "mp2" or mod == "mp3" then
diff --git a/applications/games_menu/Makefile b/applications/games_menu/Makefile
new file mode 100644
index 00000000..fe42b88c
--- /dev/null
+++ b/applications/games_menu/Makefile
@@ -0,0 +1,39 @@
+#
+# GAMES Loader App for DreamShell
+# Copyright (C) 2024 MANIAC VERA
+# http://www.dc-swat.ru
+#
+
+SUBDIRS = modules
+
+include ../../sdk/Makefile.cfg
+
+APP_NAME = games_menu
+APP_DIR = $(DS_BUILD)/apps/$(APP_NAME)
+DEPS = modules/app_$(APP_NAME).klf
+
+KOS_CFLAGS += -I./
+
+all: install
+
+$(DEPS): modules/module.c
+ cd modules && make
+
+clean:
+ cd modules && make clean && cd ../
+
+install: app.xml $(DEPS)
+ -mkdir -p $(APP_DIR)
+ -mkdir -p $(APP_DIR)/modules
+ -mkdir -p $(APP_DIR)/images
+ -mkdir -p $(APP_DIR)/covers
+ -mkdir -p $(APP_DIR)/fonts
+ -mkdir -p $(APP_DIR)/music
+ -mkdir -p $(APP_DIR)/presets
+ -mkdir -p $(APP_DIR)/resources
+ cp modules/app_$(APP_NAME).klf $(APP_DIR)/modules/app_$(APP_NAME).klf
+ cp app.xml $(APP_DIR)/app.xml
+ cp -R images $(APP_DIR)
+ cp -R fonts $(APP_DIR)
+ cp -R resources $(APP_DIR)
+
\ No newline at end of file
diff --git a/applications/games_menu/app.xml b/applications/games_menu/app.xml
new file mode 100644
index 00000000..5c873be8
--- /dev/null
+++ b/applications/games_menu/app.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/applications/games_menu/fonts/arial.txf b/applications/games_menu/fonts/arial.txf
new file mode 100644
index 00000000..756018e7
Binary files /dev/null and b/applications/games_menu/fonts/arial.txf differ
diff --git a/applications/games_menu/fonts/axaxax.txf b/applications/games_menu/fonts/axaxax.txf
new file mode 100644
index 00000000..20496e20
Binary files /dev/null and b/applications/games_menu/fonts/axaxax.txf differ
diff --git a/applications/games_menu/fonts/default.txf b/applications/games_menu/fonts/default.txf
new file mode 100644
index 00000000..5affe94a
Binary files /dev/null and b/applications/games_menu/fonts/default.txf differ
diff --git a/applications/games_menu/fonts/helvetica.txf b/applications/games_menu/fonts/helvetica.txf
new file mode 100644
index 00000000..61ad84ff
Binary files /dev/null and b/applications/games_menu/fonts/helvetica.txf differ
diff --git a/applications/games_menu/fonts/m23.txf b/applications/games_menu/fonts/m23.txf
new file mode 100644
index 00000000..0e5ddb50
Binary files /dev/null and b/applications/games_menu/fonts/m23.txf differ
diff --git a/applications/games_menu/fonts/message.txf b/applications/games_menu/fonts/message.txf
new file mode 100644
index 00000000..5affe94a
Binary files /dev/null and b/applications/games_menu/fonts/message.txf differ
diff --git a/applications/games_menu/fonts/msjh.txf b/applications/games_menu/fonts/msjh.txf
new file mode 100644
index 00000000..32312f5b
Binary files /dev/null and b/applications/games_menu/fonts/msjh.txf differ
diff --git a/applications/games_menu/fonts/no_continue.txf b/applications/games_menu/fonts/no_continue.txf
new file mode 100644
index 00000000..ab113109
Binary files /dev/null and b/applications/games_menu/fonts/no_continue.txf differ
diff --git a/applications/games_menu/fonts/serpent_font.txf b/applications/games_menu/fonts/serpent_font.txf
new file mode 100644
index 00000000..9f90485a
Binary files /dev/null and b/applications/games_menu/fonts/serpent_font.txf differ
diff --git a/applications/games_menu/fonts/typewriter.txf b/applications/games_menu/fonts/typewriter.txf
new file mode 100644
index 00000000..a3abc092
Binary files /dev/null and b/applications/games_menu/fonts/typewriter.txf differ
diff --git a/applications/games_menu/images/btn_a.png b/applications/games_menu/images/btn_a.png
new file mode 100644
index 00000000..abad0f08
Binary files /dev/null and b/applications/games_menu/images/btn_a.png differ
diff --git a/applications/games_menu/images/btn_b.png b/applications/games_menu/images/btn_b.png
new file mode 100644
index 00000000..cfcc2db3
Binary files /dev/null and b/applications/games_menu/images/btn_b.png differ
diff --git a/applications/games_menu/images/btn_lt.png b/applications/games_menu/images/btn_lt.png
new file mode 100644
index 00000000..631ac3ba
Binary files /dev/null and b/applications/games_menu/images/btn_lt.png differ
diff --git a/applications/games_menu/images/btn_rt.png b/applications/games_menu/images/btn_rt.png
new file mode 100644
index 00000000..2f3fdcfe
Binary files /dev/null and b/applications/games_menu/images/btn_rt.png differ
diff --git a/applications/games_menu/images/btn_start.png b/applications/games_menu/images/btn_start.png
new file mode 100644
index 00000000..898a45b2
Binary files /dev/null and b/applications/games_menu/images/btn_start.png differ
diff --git a/applications/games_menu/images/btn_x.png b/applications/games_menu/images/btn_x.png
new file mode 100644
index 00000000..e930f9c4
Binary files /dev/null and b/applications/games_menu/images/btn_x.png differ
diff --git a/applications/games_menu/images/btn_y.png b/applications/games_menu/images/btn_y.png
new file mode 100644
index 00000000..4f1cd348
Binary files /dev/null and b/applications/games_menu/images/btn_y.png differ
diff --git a/applications/games_menu/images/cover.png b/applications/games_menu/images/cover.png
new file mode 100644
index 00000000..bc6e4fa6
Binary files /dev/null and b/applications/games_menu/images/cover.png differ
diff --git a/applications/games_menu/images/gd.jpg b/applications/games_menu/images/gd.jpg
new file mode 100644
index 00000000..f4b8be07
Binary files /dev/null and b/applications/games_menu/images/gd.jpg differ
diff --git a/applications/games_menu/images/gd.png b/applications/games_menu/images/gd.png
new file mode 100644
index 00000000..f5d1d026
Binary files /dev/null and b/applications/games_menu/images/gd.png differ
diff --git a/applications/games_menu/images/icon.png b/applications/games_menu/images/icon.png
new file mode 100644
index 00000000..59eee9b9
Binary files /dev/null and b/applications/games_menu/images/icon.png differ
diff --git a/applications/games_menu/images/label_no_cover.png b/applications/games_menu/images/label_no_cover.png
new file mode 100644
index 00000000..8625612d
Binary files /dev/null and b/applications/games_menu/images/label_no_cover.png differ
diff --git a/applications/games_menu/images/no_cover.png b/applications/games_menu/images/no_cover.png
new file mode 100644
index 00000000..7da0b943
Binary files /dev/null and b/applications/games_menu/images/no_cover.png differ
diff --git a/applications/games_menu/images/save.png b/applications/games_menu/images/save.png
new file mode 100644
index 00000000..c4100528
Binary files /dev/null and b/applications/games_menu/images/save.png differ
diff --git a/applications/games_menu/modules/Makefile b/applications/games_menu/modules/Makefile
new file mode 100644
index 00000000..50f6bf5f
--- /dev/null
+++ b/applications/games_menu/modules/Makefile
@@ -0,0 +1,27 @@
+#
+# GAMES app module for DreamShell
+# Copyright (C) 2024 Maniac Vera
+# http://www.dc-swat.ru
+#
+
+APP_NAME = games_menu
+TARGET_NAME = app_$(APP_NAME)
+OBJS = module.o utils.o menu.o system_menu.o preset.o
+DBG_LIBS = -lds -lisofs -lisoldr -lwave
+EXPORTS_FILE = exports.txt
+
+VER_MAJOR = 0
+VER_MINOR = 1
+VER_MICRO = 0
+
+all: rm-elf
+
+include ../../../sdk/Makefile.loadable
+
+rm-elf:
+ -rm -f $(TARGET)
+
+install: $(TARGET)
+ -rm $(DS_BUILD)/apps/$(APP_NAME)/modules/$(TARGET)
+ cp $(TARGET) $(DS_BUILD)/apps/$(APP_NAME)/modules/$(TARGET)
+
diff --git a/applications/games_menu/modules/app_definition.h b/applications/games_menu/modules/app_definition.h
new file mode 100644
index 00000000..8b353a01
--- /dev/null
+++ b/applications/games_menu/modules/app_definition.h
@@ -0,0 +1,246 @@
+/*
+ Tsunami for KallistiOS ##version##
+
+ menudefinition.h
+
+ Copyright (C) 2024 Maniac Vera
+
+*/
+
+#ifndef __APP_DEFINITION_H
+#define __APP_DEFINITION_H
+
+#define MAX_SIZE_ITEMS 12
+#define MAX_BUTTONS 7
+#define MAX_SCAN_COUNT 2
+#define MAX_MENU 3
+#define FIRMWARE_SIZE 8
+#define MAX_VMU 999
+#define DEFAULT_VMU_NUMBER "001"
+#define SCREENSHOT_HOTKEY (CONT_START | CONT_A | CONT_B)
+#define ALT_BOOT_FILE "2ND_READ.BIN"
+
+#include
+
+enum PresetControlEnum
+{
+ SAVE_CONTROL_ID = 1,
+ DMA_CONTROL_ID,
+ ASYNC_CONTROL_ID,
+ BYPASS_CONTROL_ID,
+ IRQ_CONTROL_ID,
+ OS_CONTROL_ID,
+ LOADER_CONTROL_ID,
+ BOOT_CONTROL_ID,
+ FASTBOOT_CONTROL_ID,
+ LOWLEVEL_CONTROL_ID,
+ MEMORY_CONTROL_ID,
+ CUSTOM_MEMORY_CONTROL_ID,
+ HEAP_CONTROL_ID,
+
+ CDDA_CONTROL_ID,
+ CDDA_SOURCE_CONTROL_ID,
+ CDDA_DESTINATION_CONTROL_ID,
+ CDDA_POSITION_CONTROL_ID,
+ CDDA_CHANNEL_CONTROL_ID,
+
+ PATCH_ADDRESS1_CONTROL_ID,
+ PATCH_VALUE1_CONTROL_ID,
+ PATCH_ADDRESS2_CONTROL_ID,
+ PATCH_VALUE2_CONTROL_ID,
+
+ ALTERBOOT_CONTROL_ID,
+ SCREENSHOT_CONTROL_ID,
+ BUTTON_START_CONTROL_ID,
+ BUTTON_X_CONTROL_ID,
+ BUTTON_Y_CONTROL_ID,
+ BUTTON_Z_CONTROL_ID,
+ BUTTON_LT_CONTROL_ID,
+ BUTTON_A_CONTROL_ID,
+ BUTTON_B_CONTROL_ID,
+ BUTTON_C_CONTROL_ID,
+ BUTTON_RT_CONTROL_ID,
+
+ VMU_CONTROL_ID,
+ VMUSELECTOR_CONTROL_ID,
+
+ SHORTCUT_SIZE_CONTROL_ID,
+ SHORTCUT_ROTATE_CONTROL_ID,
+ SHORTCUT_NAME_CONTROL_ID,
+ SHORTCUT_DONTSHOWNAME_CONTROL_ID,
+ SHORTCUT_CREATE_CONTROL_ID,
+ SHORTCUT_COVER_CONTROL_ID,
+};
+
+enum StateAppEnum
+{
+ SA_NONE = 0,
+ SA_GAMES_MENU,
+ SA_SYSTEM_MENU,
+ SA_PRESET_MENU,
+ SA_SCAN_COVER,
+ SA_OPTIMIZE_COVER,
+ SA_CONTROL
+};
+
+enum DirectionMenuDisplacementEnum
+{
+ DMD_NONE = 0,
+ DMD_LEFT = 1,
+ DMD_RIGHT = 2,
+ DMD_UP = 3,
+ DMD_DOWN = 4
+};
+
+enum SearchCoverEnum
+{
+ SC_WITHOUT_SEARCHING = -1,
+ SC_NOT_EXIST = 0,
+ SC_EXISTS = 1,
+ SC_DEFAULT = 2
+};
+
+enum CoverStatusEnum
+{
+ CSE_EXISTS = 1,
+ CSE_PROCESSING = 2,
+ CSE_COMPLETED = 3
+};
+
+enum CheckCDDAGameEnum
+{
+ CCGE_NOT_CHECKED = -1,
+ CCGE_CDDA = 1,
+ CCGE_CDDA_BIG_SIZE = 2,
+ CCGE_NOT_CDDA = 3,
+ CCGE_CANDIDATE = 4
+};
+
+typedef struct FirmwareStructure
+{
+ char file[FIRMWARE_SIZE+1];
+} FirmwareStruct;
+
+typedef struct PresetStructure
+{
+ int game_index;
+ int use_dma;
+ int emu_async;
+ int use_irq;
+ int alt_read;
+ int fastboot;
+ int low;
+ int scr_hotkey;
+ int boot_mode;
+ int bin_type;
+ int alt_boot;
+ int screenshot;
+ int cdda;
+ int rotate_image;
+ int dont_show_name;
+ int icon_size;
+ int vmu_mode;
+
+ uint32 emu_vmu;
+ uint32 emu_cdda;
+ uint32 heap;
+ uint32 pa[2];
+ uint32 pv[2];
+
+ char title[32];
+ char device[FIRMWARE_SIZE+1];
+ char memory[12];
+ char custom_memory[12];
+ char heap_memory[12];
+ char bin_file[12];
+ char patch_a[2][10];
+ char patch_v[2][10];
+ char vmu_file[32];
+ char shortcut_name[33];
+ char preset_file_name[100];
+} PresetStruct;
+
+typedef struct SectorDataStructure
+{
+ int image_type;
+ int sector_size;
+ uint8 md5[16];
+ uint8 boot_sector[2048];
+ uint32 *addr;
+} SectorDataStruct;
+
+typedef struct MenuOptionStructure
+{
+ int max_page_size;
+ int max_columns;
+ int size_items_column;
+ int init_position_x;
+ int init_position_y;
+ int padding_x;
+ int padding_y;
+ float image_size;
+} MenuOptionStruct;
+
+typedef struct GameItemStructure
+{
+ uint8 device;
+ char *game;
+ char *folder;
+ char *folder_name;
+ bool is_folder_name;
+ int16 exists_cover[MAX_MENU];
+ uint64 cover_type;
+ bool check_pvr;
+ bool is_pvr_cover;
+ bool check_optimized;
+ bool is_gdi_optimized;
+ int16 is_cdda;
+
+} GameItemStruct;
+
+typedef struct CoverStructure
+{
+ char *cover;
+ uint8 device;
+ uint8 menu_type;
+ uint8 image_type[MAX_MENU];
+
+} CoverStruct;
+
+typedef struct ImageDimensionStructure
+{
+ unsigned int width;
+ unsigned int height;
+} ImageDimensionStruct;
+
+#pragma pack(push, 4)
+typedef struct CoverScannedStructure
+{
+ char last_game_scanned[NAME_MAX];
+ uint32 last_game_index;
+ uint32 last_game_status;
+ uint32 games_count;
+ uint32 scan_count;
+} CoverScannedStruct;
+#pragma pack(pop)
+
+#pragma pack(push, 4)
+typedef struct AppConfigStructure
+{
+ int initial_view;
+ int save_preset;
+ int cover_background;
+ int change_page_with_pad;
+} AppConfigStruct;
+#pragma pack(pop)
+
+typedef struct isoldr_conf_structure
+{
+ const char *name;
+ int conf_type;
+ void *pointer;
+} isoldr_conf;
+
+typedef isoldr_conf GenericConfigStruct;
+
+#endif //__APP_DEFINITION_H
diff --git a/applications/games_menu/modules/app_menu.h b/applications/games_menu/modules/app_menu.h
new file mode 100644
index 00000000..72050f78
--- /dev/null
+++ b/applications/games_menu/modules/app_menu.h
@@ -0,0 +1,128 @@
+#ifndef __APP_MENU_H
+#define __APP_MENU_H
+
+#include
+#include
+#include "app_utils.h"
+#include "app_definition.h"
+#include "tsunami/tsudefinition.h"
+
+#define MOTOSHORT(p) ((*(p)) << 8) + *(p + 1)
+#define IN_CACHE_GAMES
+#define MAX_SIZE_CDDA 0
+#define MAX_TRIGGER_VALUE 255
+#define PLANE_TEXT_MENU_FOLDER ""
+#define IMAGE_TEXT_64_5X2_MENU_FOLDER "/64"
+#define IMAGE_128_4X3_FOLDER "/128"
+#define IMAGE_TYPE_SUPPORTED (IT_PNG | IT_JPG | IT_PVR)
+
+typedef void SendMessageCallBack(const char *fmt, const char *message);
+typedef void PostPVRCoverCallBack(bool new_cover);
+typedef void PostOptimizerCoverCallBack();
+
+struct menu_structure
+{
+ bool save_preset;
+ bool cover_background;
+ bool change_page_with_pad;
+ bool ide;
+ bool sd;
+ bool cd;
+ bool rescan_covers;
+ bool convert_pvr_to_png;
+ volatile bool finish_menu;
+ volatile bool finished_menu;
+ volatile bool cdda_game_changed;
+ volatile bool stop_load_pvr_cover;
+ volatile bool stop_optimize_game_cover;
+ int default_cover_type;
+ int state_app;
+ int menu_type;
+ int games_array_count;
+ int covers_array_count;
+ int firmware_array_count;
+ int current_dev;
+ int vmu_mode;
+
+ char default_dir[20];
+ char games_path[NAME_MAX];
+ char covers_path[50];
+
+ char default_dir_sd[20];
+ char games_path_sd[NAME_MAX];
+ char covers_path_sd[50];
+
+ PresetStruct *preset;
+
+ AppConfigStruct app_config;
+ CoverScannedStruct cover_scanned_app;
+ MenuOptionStruct menu_option;
+ GameItemStruct *games_array;
+ CoverStruct *covers_array;
+ FirmwareStruct *firmware_array;
+
+ SendMessageCallBack *send_message_scan;
+ SendMessageCallBack *send_message_optimizer;
+ PostPVRCoverCallBack *post_pvr_cover;
+ PostOptimizerCoverCallBack *post_optimizer_cover;
+
+ kthread_t *play_cdda_thread;
+ kthread_t *load_pvr_cover_thread;
+ kthread_t *optimize_game_cover_thread;
+};
+
+const char* GetDefaultDir(uint8 device);
+const char* GetGamesPath(uint8 device);
+const char* GetCoversPath(uint8 device);
+void CreateMenuData(SendMessageCallBack *send_message_scan, SendMessageCallBack *send_message_optimizer
+ , PostPVRCoverCallBack *post_pvr_cover, PostOptimizerCoverCallBack *post_optimizer_cover);
+void DestroyMenuData();
+bool CheckGdiOptimized();
+const char *GetFullGamePathByIndex(int game_index);
+void StopCDDA();
+bool CheckCDDA(int game_index);
+void* PlayCDDAThread(void *params);
+void PlayCDDA(int game_index);
+ImageDimensionStruct *GetImageDimension(const char *image_file);
+bool IsValidImage(const char *image_file);
+bool ExistsCoverFile(const char *cover_file, int menu_type);
+bool CheckCoverImageType(int game_index, int menu_type, uint16 image_type);
+int16 CheckCover(int game_index, int menu_type);
+bool GetCoverName(int game_index, char **cover_name);
+const char* GetCoverFolder(int menu_type);
+bool GetGameCoverPath(int game_index, char **game_cover_path, int menu_type);
+void SetMenuType(int menu_type);
+void FreeGames();
+void FreeGamesForce();
+int GenerateVMUFile(const char* full_path_game, int vmu_mode, uint32 vmu_number);
+bool LoadFirmwareFiles();
+void LoadDefaultMenuConfig();
+bool LoadMenuConfig();
+void PatchParseText(PresetStruct *preset);
+PresetStruct* GetDefaultPresetGame(const char* full_path_game, SectorDataStruct *sector_data);
+PresetStruct* LoadPresetGame(int game_index);
+bool SavePresetGame(PresetStruct *preset);
+isoldr_info_t* ParsePresetToIsoldr(int game_index, PresetStruct *preset);
+void ParseMenuConfigToPresentation();
+void ParsePresentationToMenuConfig();
+bool SaveMenuConfig();
+bool SaveScannedCover();
+bool LoadScannedCover();
+bool HasAnyCover();
+void CleanIncompleteCover();
+void OptimizeGameCovers();
+void OptimizeCover(int game_index, const char *game_name, kos_img_t *img, bool is_alpha);
+bool ExtractPVRCover(int game_index);
+void* LoadPVRCoverThread(void *params);
+void* OptimizeCoverThread(void *param);
+bool IsUniqueFileGame(const char *full_path_folder);
+void RetrieveCovers(uint8 device, int menu_type);
+void RetrieveGamesRecursive(const char *full_path_folder, const char *folder, int level);
+bool RetrieveGames();
+uint16 GetCoverType(int game_index, int menu_type);
+const char* GetCoverExtensionFromType(uint16 image_type);
+void CleanCoverType(int game_index, int menu_type);
+void SetCoverType(int game_index, int menu_type, uint16 dw_image_type);
+bool ContainsCoverType(int game_index, int menu_type, uint16 dw_image_type);
+
+#endif // __APP_MENU_H
diff --git a/applications/games_menu/modules/app_module.h b/applications/games_menu/modules/app_module.h
new file mode 100644
index 00000000..0ff1e3bd
--- /dev/null
+++ b/applications/games_menu/modules/app_module.h
@@ -0,0 +1,16 @@
+/* DreamShell ##version##
+
+ app_module.h - Games app module header
+ Copyright (C) 2024 Maniac Vera
+
+*/
+
+#include
+
+void GamesApp_Init(App_t *app);
+
+void GamesApp_Shutdown(App_t *app);
+
+void GamesApp_Open(App_t *app);
+
+void GamesApp_Exit(GUI_Widget *widget);
\ No newline at end of file
diff --git a/applications/games_menu/modules/app_preset.h b/applications/games_menu/modules/app_preset.h
new file mode 100644
index 00000000..3a7e6d82
--- /dev/null
+++ b/applications/games_menu/modules/app_preset.h
@@ -0,0 +1,130 @@
+/* DreamShell ##version##
+
+ app_system_menu.h
+ Copyright (C) 2024 Maniac Vera
+
+*/
+
+#ifndef __APP_PRESET_H
+#define __APP_PRESET_H
+
+#include
+#include "tsunami/tsudefinition.h"
+#include "tsunami/drawable.h"
+#include "tsunami/dsapp.h"
+#include "tsunami/drawables/scene.h"
+#include "tsunami/drawables/form.h"
+#include "tsunami/texture.h"
+
+#include "app_utils.h"
+#include "app_definition.h"
+
+void CreatePresetMenu(DSApp *dsapp_ptr, Scene *scene_ptr, Font *menu_font, Font *message_font);
+void DestroyPresetMenu();
+void PresetMenuRemoveAll();
+void OnViewIndexChangedEvent(Drawable *drawable, int view_index);
+void CreateGeneralView(Form *form_ptr);
+void CreateCDDAView(Form *form_ptr);
+void CreatePatchView(Form *form_ptr);
+void CreateExtensionsView(Form *form_ptr);
+void CreateShortcutView(Form *form_ptr);
+
+void PresetMenuInputEvent(int type, int key);
+int StatePresetMenu();
+void ShowPresetMenu(int game_index);
+void HidePresetMenu();
+void PresetMenuSelectedEvent(Drawable *drawable, uint bottom_index, uint column, uint row);
+
+void ExitPresetMenuClick(Drawable *drawable);
+void SavePresetOptionClick(Drawable *drawable);
+void DMAOptionClick(Drawable *drawable);
+void AsyncOptionClick(Drawable *drawable);
+void ByPassOptionClick(Drawable *drawable);
+void CDDAOptionClick(Drawable *drawable);
+void IRQOptionClick(Drawable *drawable);
+void OSOptionClick(Drawable *drawable);
+
+void LoaderOptionClick(Drawable *drawable);
+void BootOptionClick(Drawable *drawable);
+void FastOptionClick(Drawable *drawable);
+void LowLevelOptionClick(Drawable *drawable);
+void MemoryOptionClick(Drawable *drawable);
+void CustomMemoryOptionClick(Drawable *drawable);
+void HeapOptionClick(Drawable *drawable);
+
+void CDDASourceOptionClick(Drawable *drawable);
+void CDDADestinationOptionClick(Drawable *drawable);
+void CDDAPositionOptionClick(Drawable *drawable);
+void CDDAChannelOptionClick(Drawable *drawable);
+
+void PatchAddress1OptionClick(Drawable *drawable);
+void PatchValue1OptionClick(Drawable *drawable);
+void PatchAddress2OptionClick(Drawable *drawable);
+void PatchValue2OptionClick(Drawable *drawable);
+
+void AlterBootOptionClick(Drawable *drawable);
+void SetModeScreenshot();
+int GetModeScreenshot();
+bool AllButtonsDisabled();
+void CheckScreenshot();
+void ScreenshotOptionClick(Drawable *drawable);
+void ButtonStartOptionClick(Drawable *drawable);
+void ButtonXOptionClick(Drawable *drawable);
+void ButtonYOptionClick(Drawable *drawable);
+void ButtonZOptionClick(Drawable *drawable);
+void ButtonLTOptionClick(Drawable *drawable);
+void ButtonAOptionClick(Drawable *drawable);
+void ButtonBOptionClick(Drawable *drawable);
+void ButtonCOptionClick(Drawable *drawable);
+void ButtonRTOptionClick(Drawable *drawable);
+void VMUOptionClick(Drawable *drawable);
+void VMUSelectorOptionClick(Drawable *drawable);
+
+void ShortcutSizeOptionClick(Drawable *drawable);
+void ShortcutRotateOptionClick(Drawable *drawable);
+void ShortcutNameOptionClick(Drawable *drawable);
+void ShortcutDontShowNameOptionClick(Drawable *drawable);
+void ShortcutCreateOptionClick(Drawable *drawable);
+
+void SavePresetInputEvent(int type, int key);
+void DMAInputEvent(int type, int key);
+void AsyncInputEvent(int type, int key);
+void ByPassInputEvent(int type, int key);
+void CDDAInputEvent(int type, int key);
+void IRQInputEvent(int type, int key);
+void OSInputEvent(int type, int key);
+
+void LoaderInputEvent(int type, int key);
+void BootInputEvent(int type, int key);
+void FastInputEvent(int type, int key);
+void LowLevelInputEvent(int type, int key);
+void MemoryInputEvent(int type, int key);
+void CustomMemoryInputEvent(int type, int key);
+void HeapInputEvent(int type, int key);
+
+void CDDASourceInputEvent(int type, int key);
+void CDDADestinationInputEvent(int type, int key);
+void CDDAPositionInputEvent(int type, int key);
+void CDDAChannelInputEvent(int type, int key);
+
+void SetPatchByType(TextBox *patch_textbox, int control_type, char *patch_text_variable_ptr, uint32 *patch_variable_ptr);
+void PatchAddress1InputEvent(int type, int key);
+void PatchValue1InputEvent(int type, int key);
+void PatchAddress2InputEvent(int type, int key);
+void PatchValue2InputEvent(int type, int key);
+
+void AlterBootInputEvent(int type, int key);
+void ScreenshotInputEvent(int type, int key);
+void VMUInputEvent(int type, int key);
+void VMUSelectorInputEvent(int type, int key);
+void ShortcutSizeInputEvent(int type, int key);
+void ShortcutRotateInputEvent(int type, int key);
+void ShortcutNameInputEvent(int type, int key);
+void ShortcutDontShowNameInputEvent(int type, int key);
+void ShortcutCreateInputEvent(int type, int key);
+void ShortcutLoadTextureCover();
+void ShortcutChangeCoverSize();
+
+void CheckIfShorcutExits();
+
+#endif // __APP_PRESET_H
diff --git a/applications/games_menu/modules/app_system_menu.h b/applications/games_menu/modules/app_system_menu.h
new file mode 100644
index 00000000..35d2759e
--- /dev/null
+++ b/applications/games_menu/modules/app_system_menu.h
@@ -0,0 +1,49 @@
+/* DreamShell ##version##
+
+ app_system_menu.h
+ Copyright (C) 2024 Maniac Vera
+
+*/
+
+#ifndef __APP_SYSTEM_MENU_H
+#define __APP_SYSTEM_MENU_H
+
+#include
+#include "tsunami/tsudefinition.h"
+#include "tsunami/drawable.h"
+#include "tsunami/dsapp.h"
+#include "tsunami/drawables/scene.h"
+#include "tsunami/drawables/form.h"
+
+#include "app_utils.h"
+#include "app_definition.h"
+
+void CreateSystemMenu(DSApp *dsapp_ptr, Scene *scene_ptr, Font *menu_font, Font *message_font);
+void CreateSystemMenuView(Form *form_ptr);
+void OnSystemViewIndexChangedEvent(Drawable *drawable, int view_index);
+void DestroySystemMenu();
+void SystemMenuRemoveAll();
+
+void SystemMenuInputEvent(int type, int key);
+int StateSystemMenu();
+void ShowSystemMenu();
+void HideSystemMenu();
+void SystemMenuSelectedEvent(Drawable *drawable, uint bottom_index, uint column, uint row);
+void OptimizeCoversClick(Drawable *drawable);
+void ExitSystemMenuClick(Drawable *drawable);
+void ScanMissingCoversClick(Drawable *drawable);
+void DefaultSavePresetOptionClick(Drawable *drawable);
+void CoverBackgroundOptionClick(Drawable *drawable);
+void ChangePageWithPadOptionClick(Drawable *drawable);
+
+void ShowOptimizeCoverPopup();
+void HideOptimizeCoverPopup();
+void SetMessageOptimizer(const char *fmt, const char *message);
+int StopOptimizeCovers();
+
+void ShowCoverScan();
+void HideCoverScan();
+void SetMessageScan(const char *fmt, const char *message);
+int StopScanCovers();
+
+#endif // __APP_SYSTEM_MENU_H
diff --git a/applications/games_menu/modules/app_utils.h b/applications/games_menu/modules/app_utils.h
new file mode 100644
index 00000000..69b117ad
--- /dev/null
+++ b/applications/games_menu/modules/app_utils.h
@@ -0,0 +1,49 @@
+/* DreamShell ##version##
+
+ utils.h - ISO Loader app utils
+ Copyright (C) 2024 Maniac Vera
+
+*/
+
+#ifndef __APP_UTILS_H
+#define __APP_UTILS_H
+
+#include "app_definition.h"
+
+/* Indexes of devices */
+enum {
+ APP_DEVICE_CD = 0,
+ APP_DEVICE_SD = 1,
+ APP_DEVICE_IDE,
+ APP_DEVICE_PC,
+ APP_DEVICE_COUNT
+};
+
+enum {
+ CONF_END = 0,
+ CONF_INT = 1,
+ CONF_STR,
+ CONF_ULONG,
+};
+
+
+
+char *Trim(char *string);
+void TrimSpaces(char *input, char *output, int size);
+char *TrimSpaces2(char *txt);
+char *FixSpaces(char *str);
+bool MakeShortcut(PresetStruct *preset, const char* device_dir, const char* full_path_game, bool show_name, const char* game_cover_path, int width, int height, bool yflip);
+int ConfigParse(isoldr_conf *cfg, const char *filename);
+bool IsGdiOptimized(const char *full_path_game);
+const char* GetLastPart(const char *source, const char separator, int option_path);
+bool ContainsOnlyNumbers(const char *string);
+int GetDeviceType(const char *dir);
+int CanUseTrueAsyncDMA(int sector_size, int current_dev, int image_type);
+void GetMD5HashISO(const char *file_mount_point, SectorDataStruct *sector_data);
+char* MakePresetFilename(const char *default_dir, const char *device_dir, uint8 *md5, const char *app_name);
+const char *GetFolderPathFromFile(const char *full_path_file);
+size_t GetCDDATrackFilename(int num, const char *full_path_game, char **result);
+void PlayCDDATrack(const char *file, int loop);
+void StopCDDATrack();
+
+#endif // __APP_UTILS_H
diff --git a/applications/games_menu/modules/exports.txt b/applications/games_menu/modules/exports.txt
new file mode 100644
index 00000000..60563d0d
--- /dev/null
+++ b/applications/games_menu/modules/exports.txt
@@ -0,0 +1,7 @@
+include kos/exports.h
+include app_module.h
+
+# GAMES Loader exports
+GamesApp_Init
+GamesApp_Shutdown
+GamesApp_Open
\ No newline at end of file
diff --git a/applications/games_menu/modules/menu.c b/applications/games_menu/modules/menu.c
new file mode 100644
index 00000000..e3662c12
--- /dev/null
+++ b/applications/games_menu/modules/menu.c
@@ -0,0 +1,2485 @@
+#include "app_menu.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+struct menu_structure menu_data;
+
+void CreateMenuData(SendMessageCallBack *send_message_scan, SendMessageCallBack *send_message_optimizer
+ , PostPVRCoverCallBack *post_pvr_cover, PostOptimizerCoverCallBack *post_optimizer_cover)
+{
+ menu_data.save_preset = true;
+ menu_data.cover_background = true;
+ menu_data.games_array_count = 0;
+ menu_data.firmware_array_count = 0;
+ menu_data.default_cover_type = -1;
+ menu_data.play_cdda_thread = NULL;
+ menu_data.load_pvr_cover_thread = NULL;
+ menu_data.finished_menu = false;
+ menu_data.cdda_game_changed = false;
+ menu_data.stop_load_pvr_cover = false;
+ menu_data.firmware_array = NULL;
+ menu_data.vmu_mode = 0;
+ menu_data.preset = NULL;
+
+ menu_data.send_message_scan = send_message_scan;
+ menu_data.send_message_optimizer = send_message_optimizer;
+ menu_data.post_pvr_cover = post_pvr_cover;
+ menu_data.post_optimizer_cover = post_optimizer_cover;
+
+ menu_data.games_array = NULL;
+ memset(&menu_data.menu_option, 0, sizeof(menu_data.menu_option));
+
+ memset(menu_data.default_dir, 0, sizeof(menu_data.default_dir));
+ memset(menu_data.covers_path, 0, sizeof(menu_data.covers_path));
+ memset(menu_data.games_path, 0, sizeof(menu_data.games_path));
+
+ memset(menu_data.default_dir_sd, 0, sizeof(menu_data.default_dir_sd));
+ memset(menu_data.covers_path_sd, 0, sizeof(menu_data.covers_path_sd));
+ memset(menu_data.games_path_sd, 0, sizeof(menu_data.games_path_sd));
+
+ menu_data.ide = (DirExists("/ide/games") == 1);
+ menu_data.sd = (DirExists("/sd/games") == 1);
+ menu_data.cd = (!is_custom_bios());
+
+ if (menu_data.ide)
+ {
+ strcpy(menu_data.default_dir, "/ide/DS");
+ strcpy(menu_data.games_path, "/ide/games");
+ strcpy(menu_data.covers_path, "/ide/DS/apps/games_menu/covers");
+ }
+
+ if (menu_data.sd)
+ {
+ if (menu_data.ide)
+ {
+ strcpy(menu_data.default_dir_sd, "/sd/DS");
+ strcpy(menu_data.games_path_sd, "/sd/games");
+ strcpy(menu_data.covers_path_sd, "/sd/DS/apps/games_menu/covers");
+ }
+ else
+ {
+ strcpy(menu_data.default_dir, "/sd/DS");
+ strcpy(menu_data.games_path, "/sd/games");
+ strcpy(menu_data.covers_path, "/sd/DS/apps/games_menu/covers");
+ }
+ }
+
+ if ((!menu_data.ide && !menu_data.sd) && menu_data.cd)
+ {
+ strcpy(menu_data.default_dir, "/cd");
+ strcpy(menu_data.games_path, "/cd/games");
+ strcpy(menu_data.covers_path, "/cd/apps/games_menu/covers");
+ }
+
+ menu_data.current_dev = GetDeviceType(menu_data.default_dir);
+ menu_data.convert_pvr_to_png = (menu_data.current_dev == APP_DEVICE_IDE);
+
+ char game_cover_path[NAME_MAX];
+ memset(game_cover_path, 0, NAME_MAX);
+ snprintf(game_cover_path, NAME_MAX, "%s/%s", GetDefaultDir(menu_data.current_dev), "apps/games_menu/images/gd.jpg");
+ menu_data.default_cover_type = (FileExists(game_cover_path) ? IT_JPG : IT_PNG);
+
+ LoadMenuConfig();
+ LoadFirmwareFiles();
+}
+
+void DestroyMenuData()
+{
+ if(menu_data.load_pvr_cover_thread != NULL)
+ {
+ menu_data.stop_load_pvr_cover = true;
+ thd_join(menu_data.load_pvr_cover_thread, NULL);
+ menu_data.load_pvr_cover_thread = NULL;
+ }
+
+ if(menu_data.play_cdda_thread != NULL)
+ {
+ menu_data.cdda_game_changed = true;
+ thd_join(menu_data.play_cdda_thread, NULL);
+ menu_data.play_cdda_thread = NULL;
+ }
+
+ if (menu_data.firmware_array != NULL)
+ {
+ free(menu_data.firmware_array);
+ menu_data.firmware_array_count = 0;
+ }
+
+ FreeGamesForce();
+}
+
+const char* GetDefaultDir(uint8 device)
+{
+ switch (device)
+ {
+ case APP_DEVICE_CD:
+ return menu_data.default_dir;
+
+ case APP_DEVICE_SD:
+ {
+ if (menu_data.ide)
+ {
+ return menu_data.default_dir_sd;
+ }
+ else
+ {
+ return menu_data.default_dir;
+ }
+ }
+ break;
+
+ case APP_DEVICE_IDE:
+ return menu_data.default_dir;
+
+ case APP_DEVICE_PC:
+ return menu_data.default_dir;
+
+ default:
+ return menu_data.default_dir;
+ }
+}
+
+const char* GetGamesPath(uint8 device)
+{
+ switch (device)
+ {
+ case APP_DEVICE_CD:
+ return menu_data.games_path;
+
+ case APP_DEVICE_SD:
+ {
+ if (menu_data.ide)
+ {
+ return menu_data.games_path_sd;
+ }
+ else
+ {
+ return menu_data.games_path;
+ }
+ }
+ break;
+
+ case APP_DEVICE_IDE:
+ return menu_data.games_path;
+
+ case APP_DEVICE_PC:
+ return menu_data.games_path;
+
+ default:
+ return menu_data.games_path;
+ }
+
+ return NULL;
+}
+
+const char* GetCoversPath(uint8 device)
+{
+ switch (device)
+ {
+ case APP_DEVICE_CD:
+ return menu_data.covers_path;
+
+ case APP_DEVICE_SD:
+ {
+ if (menu_data.ide)
+ {
+ return menu_data.covers_path_sd;
+ }
+ else
+ {
+ return menu_data.covers_path;
+ }
+ }
+ break;
+
+ case APP_DEVICE_IDE:
+ return menu_data.covers_path;
+
+ case APP_DEVICE_PC:
+ return menu_data.covers_path;
+
+ default:
+ return menu_data.covers_path;
+ }
+}
+
+const char* GetFullGamePathByIndex(int game_index)
+{
+ static char full_path_game[NAME_MAX];
+ memset(full_path_game, 0, sizeof(full_path_game));
+ if (game_index >= 0)
+ {
+ if (menu_data.games_array[game_index].folder)
+ {
+ snprintf(full_path_game, NAME_MAX, "%s/%s/%s", GetGamesPath(menu_data.games_array[game_index].device), menu_data.games_array[game_index].folder, menu_data.games_array[game_index].game);
+ }
+ else
+ {
+ snprintf(full_path_game, NAME_MAX, "%s/%s", GetGamesPath(menu_data.games_array[game_index].device), menu_data.games_array[game_index].game);
+ }
+ }
+
+ return full_path_game;
+}
+
+void* PlayCDDAThread(void *params)
+{
+ int game_index = (int)params;
+ if (game_index >= 0)
+ {
+ const char *full_path_game = GetFullGamePathByIndex(game_index);
+ const uint max_time = 2000;
+ uint time_elapsed = 0;
+
+ while (!menu_data.cdda_game_changed && time_elapsed < max_time)
+ {
+ thd_sleep(50);
+ time_elapsed += 50;
+ }
+
+ if (!menu_data.cdda_game_changed)
+ {
+ if (CheckCDDA(game_index))
+ {
+ if (!menu_data.cdda_game_changed)
+ {
+ size_t track_size = 0;
+ char *track_file_path = (char *)malloc(NAME_MAX);
+ srand(time(NULL));
+
+ do
+ {
+ track_size = GetCDDATrackFilename((random() % 15) + 4, full_path_game, &track_file_path);
+ } while (track_size == 0);
+
+ PlayCDDATrack(track_file_path, 3);
+ free(track_file_path);
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+bool CheckCDDA(int game_index)
+{
+ bool isCDDA = false;
+ if (game_index >= 0)
+ {
+ if (menu_data.games_array[game_index].is_cdda == CCGE_CDDA)
+ {
+ isCDDA = true;
+ }
+ else
+ {
+ if (menu_data.games_array[game_index].is_cdda == CCGE_NOT_CHECKED)
+ {
+ const char *full_path_game = GetFullGamePathByIndex(game_index);
+ size_t track_size = 0;
+
+ char *track_file_path = (char *)malloc(NAME_MAX);
+ track_size = GetCDDATrackFilename(4, full_path_game, &track_file_path);
+
+ if (track_size > 0 && track_size < 30 * 1024 * 1024)
+ {
+ track_size = GetCDDATrackFilename(6, full_path_game, &track_file_path);
+ }
+
+ if (track_size > 0 && (MAX_SIZE_CDDA == 0 || track_size <= MAX_SIZE_CDDA))
+ {
+ isCDDA = true;
+ menu_data.games_array[game_index].is_cdda = CCGE_CDDA;
+ }
+ else
+ {
+ isCDDA = false;
+ menu_data.games_array[game_index].is_cdda = CCGE_NOT_CDDA;
+ }
+
+ free(track_file_path);
+ }
+ }
+ }
+
+ return isCDDA;
+}
+
+void StopCDDA()
+{
+ StopCDDATrack();
+ if (menu_data.play_cdda_thread != NULL)
+ {
+ menu_data.cdda_game_changed = true;
+ thd_join(menu_data.play_cdda_thread, NULL);
+ menu_data.play_cdda_thread = NULL;
+ menu_data.cdda_game_changed = false;
+ }
+}
+
+void PlayCDDA(int game_index)
+{
+ StopCDDA();
+
+ if ((menu_data.games_array[game_index].is_cdda == CCGE_NOT_CHECKED || menu_data.games_array[game_index].is_cdda == CCGE_CDDA)
+ && menu_data.current_dev == APP_DEVICE_IDE)
+ {
+ menu_data.play_cdda_thread = thd_create(0, PlayCDDAThread, (void *)game_index);
+ }
+}
+
+ImageDimensionStruct *GetImageDimension(const char *image_file)
+{
+ ImageDimensionStruct *image = NULL;
+ char *image_type = strrchr(image_file, '.');
+
+ if (strcasecmp(image_type, ".kmg") == 0)
+ {
+ /* Open the file */
+ file_t image_handle = fs_open(image_file, O_RDONLY);
+ if (image_handle == FILEHND_INVALID) {
+ return NULL;
+ }
+
+ kmg_header_t hdr;
+ /* Read the header */
+ if (fs_read(image_handle, &hdr, sizeof(hdr)) != sizeof(hdr)) {
+ fs_close(image_handle);
+ return NULL;
+ }
+
+ /* Verify a few things */
+ if (hdr.magic != KMG_MAGIC || hdr.version != KMG_VERSION ||
+ hdr.platform != KMG_PLAT_DC)
+ {
+ fs_close(image_handle);
+ return NULL;
+ }
+ fs_close(image_handle);
+
+ image = (ImageDimensionStruct *)malloc(sizeof(ImageDimensionStruct));
+ memset(image, 0, sizeof(ImageDimensionStruct));
+ image->width = hdr.width;
+ image->height = hdr.height;
+ }
+ else if (strcasecmp(image_type, ".pvr") == 0)
+ {
+ file_t image_handle = fs_open(image_file, O_RDONLY);
+
+ if (image_handle == FILEHND_INVALID)
+ return NULL;
+
+ size_t fsize = 512;
+ uint8 *data = (uint8 *)memalign(32, fsize);
+ if (data == NULL)
+ {
+ fs_close(image_handle);
+ return NULL;
+ }
+
+ if (fs_read(image_handle, data, fsize) == -1)
+ {
+ fs_close(image_handle);
+ return NULL;
+ }
+ fs_close(image_handle);
+
+ struct PVRTHeader pvrtHeader;
+ unsigned int offset = ReadPVRHeader(data, &pvrtHeader);
+ if (offset == 0)
+ {
+ free(data);
+ return NULL;
+ }
+ free(data);
+
+ enum TextureFormatMasks srcFormat = (enum TextureFormatMasks)(pvrtHeader.textureAttributes & 0xFF);
+ if (srcFormat != TFM_ARGB1555 && srcFormat != TFM_RGB565 && srcFormat != TFM_ARGB4444)
+ {
+ return NULL;
+ }
+
+ image = (ImageDimensionStruct *)malloc(sizeof(ImageDimensionStruct));
+ memset(image, 0, sizeof(ImageDimensionStruct));
+ image->width = pvrtHeader.width;
+ image->height = pvrtHeader.height;
+ }
+ else if (strcasecmp(image_type, ".jpg") == 0)
+ {
+ file_t image_handle = fs_open(image_file, O_RDONLY);
+
+ if (image_handle == FILEHND_INVALID)
+ return NULL;
+
+ image = (ImageDimensionStruct *)malloc(sizeof(ImageDimensionStruct));
+ memset(image, 0, sizeof(ImageDimensionStruct));
+
+ size_t file_size = fs_total(image_handle);
+ unsigned char buffer[32];
+ int i, j, marker;
+
+ fs_seek(image_handle, 0, SEEK_SET);
+ fs_read(image_handle, buffer, 32);
+ i = j = 2; // Start at offset of first marker
+ marker = 0; // Search for SOF (start of frame) marker
+
+ while (i < 32 && marker != 0xffc0 && j < file_size)
+ {
+ marker = (MOTOSHORT(&buffer[i])) & 0xfffc;
+ if (marker < 0xff00) // invalid marker
+ {
+ i += 2;
+ continue;
+ }
+ if (marker == 0xffc0)
+ break;
+
+ j += 2 + MOTOSHORT(&buffer[i + 2]); // Skip to next marker
+ if (j < file_size) // need to read more
+ {
+ fs_seek(image_handle, j, SEEK_SET); // read some more
+ fs_read(image_handle, buffer, 32);
+ i = 0;
+ }
+ else
+ break;
+ }
+
+ if (marker == 0xffc0)
+ {
+ image->height = MOTOSHORT(&buffer[i + 5]);
+ image->width = MOTOSHORT(&buffer[i + 7]);
+ }
+
+ fs_close(image_handle);
+ }
+ else if (strcasecmp(image_type, ".png") == 0 || strcasecmp(image_type, ".bpm") == 0)
+ {
+ file_t image_handle = fs_open(image_file, O_RDONLY);
+
+ if (image_handle == FILEHND_INVALID)
+ return NULL;
+
+ image = (ImageDimensionStruct *)malloc(sizeof(ImageDimensionStruct));
+ memset(image, 0, sizeof(ImageDimensionStruct));
+
+ if (strcasecmp(image_type, ".png") == 0)
+ {
+ fs_seek(image_handle, 16, SEEK_SET);
+ fs_read(image_handle, (char *)&image->width, sizeof(uint32));
+
+ fs_seek(image_handle, 20, SEEK_SET);
+ fs_read(image_handle, (char *)&image->height, sizeof(uint32));
+ }
+ else if (strcasecmp(image_type, ".bmp") == 0)
+ {
+ fs_seek(image_handle, 18, SEEK_SET);
+ fs_read(image_handle, (char *)&image->width, sizeof(uint32));
+
+ fs_seek(image_handle, 22, SEEK_SET);
+ fs_read(image_handle, (char *)&image->height, sizeof(uint32));
+ }
+
+ image->width = ntohl(image->width);
+ image->height = ntohl(image->height);
+
+ fs_close(image_handle);
+ }
+
+ image_type = NULL;
+ return image;
+}
+
+bool IsValidImage(const char *image_file)
+{
+ bool isValid = false;
+
+ ImageDimensionStruct *image = GetImageDimension(image_file);
+ if (image != NULL)
+ {
+ isValid = (image->height == 64 && image->width == 64)
+ || (image->height == 128 && image->width == 128)
+ || (image->height == 256 && image->width == 256);
+
+ free(image);
+ }
+
+ return isValid;
+}
+
+bool ExistsCoverFile(const char *cover_file, int menu_type)
+{
+ bool exists = false;
+
+ if (menu_data.covers_array_count > 0)
+ {
+ char first_char_left = (cover_file[0] == 'a' ? 'A' : toupper(cover_file[0]));
+ char first_char_rigth = '\0';
+ bool char_match = false;
+
+ for (int i = 0; i < menu_data.covers_array_count; i++)
+ {
+ first_char_rigth = (menu_data.covers_array[i].cover[0] == 'a' ? 'A' : toupper(menu_data.covers_array[i].cover[0]));
+
+ if (char_match && first_char_left != first_char_rigth)
+ {
+ break;
+ }
+
+ if (((menu_data.covers_array[i].menu_type & (1<<(menu_type-1))))
+ && first_char_left == first_char_rigth)
+ {
+ char_match = true;
+ if (strcasecmp(cover_file, menu_data.covers_array[i].cover) == 0)
+ {
+ exists = true;
+ break;
+ }
+ }
+ }
+ }
+
+ return exists;
+}
+
+bool ContainsCoverType(int game_index, int menu_type, uint16 dw_image_type)
+{
+ bool result = false;
+
+ if (game_index >= 0 && dw_image_type > 0)
+ {
+ result = ((GetCoverType(game_index, menu_type) & (dw_image_type)) == dw_image_type);
+ }
+
+ return result;
+}
+
+uint16 GetCoverType(int game_index, int menu_type)
+{
+ uint16 dw_image_type = 0;
+
+ if (game_index >= 0)
+ {
+ if (menu_data.games_array[game_index].cover_type <= 0)
+ {
+ menu_data.games_array[game_index].cover_type = 0;
+ }
+
+ dw_image_type = ((menu_data.games_array[game_index].cover_type>>((menu_type-1)*16)) & IMAGE_TYPE_MASK);
+ }
+
+ return dw_image_type;
+}
+
+void CleanCoverType(int game_index, int menu_type)
+{
+ if (game_index >= 0)
+ {
+ if (menu_data.games_array[game_index].cover_type <= 0)
+ {
+ menu_data.games_array[game_index].cover_type = 0;
+ return;
+ }
+
+ switch (menu_type)
+ {
+ case MT_PLANE_TEXT:
+ menu_data.games_array[game_index].cover_type &= 0xFFFFFFFF0000;
+ break;
+
+ case MT_IMAGE_TEXT_64_5X2:
+ menu_data.games_array[game_index].cover_type &= 0xFFFF0000FFFF;
+ break;
+
+ case MT_IMAGE_128_4X3:
+ menu_data.games_array[game_index].cover_type &= 0x0000FFFFFFFF;
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+void SetCoverType(int game_index, int menu_type, uint16 dw_image_type)
+{
+ if (game_index >= 0)
+ {
+ if (menu_data.games_array[game_index].cover_type <= 0)
+ {
+ menu_data.games_array[game_index].cover_type = 0;
+ }
+
+ menu_data.games_array[game_index].cover_type |= (uint64)dw_image_type<<((menu_type-1)*16);
+ }
+}
+
+const char* GetCoverExtensionFromType(uint16 image_type)
+{
+ switch (image_type)
+ {
+ case IT_PNG:
+ return ".png";
+
+ case IT_JPG:
+ return ".jpg";
+
+ case IT_BPM:
+ return ".bpm";
+
+ case IT_PVR:
+ return ".pvr";
+
+ case IT_KMG:
+ return ".kmg";
+
+ default:
+ return ".jpg";
+ }
+}
+
+bool CheckCoverImageType(int game_index, int menu_type, uint16 image_type)
+{
+ bool exists_cover = false;
+
+ char *game_without_extension = NULL;
+ if (GetCoverName(game_index, &game_without_extension))
+ {
+ char cover_file[NAME_MAX];
+ memset(cover_file, 0, NAME_MAX);
+ snprintf(cover_file, NAME_MAX, "%s%s", game_without_extension, GetCoverExtensionFromType(image_type));
+
+ if (ExistsCoverFile(cover_file, menu_type))
+ {
+ char *game_cover_path = (char *)malloc(NAME_MAX);
+ memset(game_cover_path, 0, NAME_MAX);
+ snprintf(game_cover_path, NAME_MAX, "%s%s/%s%s", GetCoversPath(menu_data.current_dev), GetCoverFolder(menu_type), game_without_extension, GetCoverExtensionFromType(image_type));
+
+ if (IsValidImage(game_cover_path))
+ {
+ menu_data.games_array[game_index].exists_cover[menu_type-1] = SC_EXISTS;
+ SetCoverType(game_index, menu_type, image_type);
+ exists_cover = true;
+ }
+ else
+ {
+ fs_unlink(game_cover_path);
+ // ds_printf("INVALID IMAGE: %s\n", cover_file);
+ }
+
+ free(game_cover_path);
+ }
+
+ free(game_without_extension);
+ }
+
+ return exists_cover;
+}
+
+int16 CheckCover(int game_index, int menu_type)
+{
+ int16 exists_cover = SC_WITHOUT_SEARCHING;
+
+ if (menu_data.games_array[game_index].exists_cover[menu_type-1] == SC_WITHOUT_SEARCHING)
+ {
+ uint16 image_count = 1;
+ while (image_count < IMAGE_TYPE_SUPPORTED)
+ {
+ if (IMAGE_TYPE_SUPPORTED & image_count)
+ {
+ if (CheckCoverImageType(game_index, menu_type, image_count))
+ {
+ exists_cover = menu_data.games_array[game_index].exists_cover[menu_type-1];
+ break;
+ }
+ }
+ image_count = image_count<<1;
+ }
+
+ if (menu_data.games_array[game_index].exists_cover[menu_type-1] == SC_WITHOUT_SEARCHING)
+ {
+ SetCoverType(game_index, menu_type, menu_data.default_cover_type);
+ exists_cover = menu_data.games_array[game_index].exists_cover[menu_type-1] = SC_DEFAULT;
+ menu_data.games_array[game_index].check_pvr = true;
+ }
+ }
+ else
+ {
+ exists_cover = menu_data.games_array[game_index].exists_cover[menu_type-1];
+ }
+
+ return exists_cover;
+}
+
+bool GetCoverName(int game_index, char **cover_name)
+{
+ if (*cover_name != NULL)
+ {
+ free(*cover_name);
+ }
+
+ *cover_name = NULL;
+ if (game_index >= 0)
+ {
+ *cover_name = (char *)malloc(NAME_MAX);
+ memset(*cover_name, 0, NAME_MAX);
+
+ if (menu_data.games_array[game_index].is_folder_name)
+ {
+ strncpy(*cover_name, menu_data.games_array[game_index].folder_name, strlen(menu_data.games_array[game_index].folder_name));
+ }
+ else
+ {
+ strncpy(*cover_name, menu_data.games_array[game_index].game, strlen(menu_data.games_array[game_index].game) - 4);
+ }
+ }
+
+ return *cover_name != NULL;
+}
+
+const char* GetCoverFolder(int menu_type)
+{
+ switch (menu_type)
+ {
+ case MT_PLANE_TEXT:
+ return PLANE_TEXT_MENU_FOLDER;
+
+ case MT_IMAGE_TEXT_64_5X2:
+ return IMAGE_TEXT_64_5X2_MENU_FOLDER;
+
+ case MT_IMAGE_128_4X3:
+ return IMAGE_128_4X3_FOLDER;
+
+ default:
+ return PLANE_TEXT_MENU_FOLDER;
+ }
+}
+
+bool GetGameCoverPath(int game_index, char **game_cover_path, int menu_type)
+{
+ if (*game_cover_path != NULL)
+ {
+ free(*game_cover_path);
+ }
+
+ *game_cover_path = NULL;
+ if (game_index >= 0)
+ {
+ *game_cover_path = (char *)malloc(NAME_MAX);
+ memset(*game_cover_path, 0, NAME_MAX);
+
+ if (menu_data.games_array[game_index].exists_cover[menu_type-1] == SC_EXISTS)
+ {
+ char *game = NULL;
+ const char *cover_folder = GetCoverFolder(menu_type);
+ GetCoverName(game_index, &game);
+
+ uint16 image_count = 1;
+ while (image_count < IMAGE_TYPE_SUPPORTED)
+ {
+ if (IMAGE_TYPE_SUPPORTED & image_count)
+ {
+ if (ContainsCoverType(game_index, menu_type, image_count))
+ {
+ snprintf(*game_cover_path, NAME_MAX, "%s%s/%s%s", GetCoversPath(menu_data.current_dev), cover_folder, game, GetCoverExtensionFromType(image_count));
+ break;
+ }
+ }
+ image_count = image_count<<1;
+ }
+
+ if (game != NULL)
+ {
+ free(game);
+ }
+ }
+ else
+ {
+ if (menu_data.games_array[game_index].exists_cover[menu_type-1] == SC_DEFAULT)
+ {
+ if (ContainsCoverType(game_index, menu_type, IT_JPG))
+ {
+ snprintf(*game_cover_path, NAME_MAX, "%s/%s", GetDefaultDir(menu_data.current_dev), "apps/games_menu/images/gd.jpg");
+ }
+ else
+ {
+ snprintf(*game_cover_path, NAME_MAX, "%s/%s", GetDefaultDir(menu_data.current_dev), "apps/games_menu/images/gd.png");
+ }
+ }
+ }
+ }
+
+ return *game_cover_path != NULL;
+}
+
+void SetMenuType(int menu_type)
+{
+ menu_data.menu_type = menu_type;
+
+ switch (menu_type)
+ {
+ case MT_IMAGE_TEXT_64_5X2:
+ {
+ menu_data.menu_option.max_page_size = 10;
+ menu_data.menu_option.max_columns = 2;
+ menu_data.menu_option.size_items_column = menu_data.menu_option.max_page_size / menu_data.menu_option.max_columns;
+ menu_data.menu_option.init_position_x = 20;
+ menu_data.menu_option.init_position_y = -22;
+ menu_data.menu_option.padding_x = 320;
+ menu_data.menu_option.padding_y = 22;
+ menu_data.menu_option.image_size = 64.0f;
+ }
+ break;
+
+ case MT_IMAGE_128_4X3:
+ {
+ menu_data.menu_option.max_page_size = 12;
+ menu_data.menu_option.max_columns = 4;
+ menu_data.menu_option.size_items_column = menu_data.menu_option.max_page_size / menu_data.menu_option.max_columns;
+ menu_data.menu_option.init_position_x = 55;
+ menu_data.menu_option.init_position_y = -45;
+ menu_data.menu_option.padding_x = 163;
+ menu_data.menu_option.padding_y = 12;
+ menu_data.menu_option.image_size = 128.0f;
+ }
+ break;
+
+ case MT_IMAGE_256_3X2:
+ {
+ menu_data.menu_option.max_page_size = 6;
+ menu_data.menu_option.max_columns = 3;
+ menu_data.menu_option.size_items_column = menu_data.menu_option.max_page_size / menu_data.menu_option.max_columns;
+ menu_data.menu_option.init_position_x = 90;
+ menu_data.menu_option.init_position_y = -82;
+ menu_data.menu_option.padding_x = 212.0f;
+ menu_data.menu_option.padding_y = 12;
+ menu_data.menu_option.image_size = 200.0f;
+ }
+ break;
+
+ case MT_PLANE_TEXT:
+ {
+ menu_data.menu_option.max_page_size = 12;
+ menu_data.menu_option.max_columns = 1;
+ menu_data.menu_option.size_items_column = menu_data.menu_option.max_page_size / menu_data.menu_option.max_columns;
+ menu_data.menu_option.init_position_x = 2;
+ menu_data.menu_option.init_position_y = 25;
+ menu_data.menu_option.padding_x = 2;
+ menu_data.menu_option.padding_y = 34;
+ menu_data.menu_option.image_size = 0.0f;
+ }
+ break;
+
+ default:
+ {
+ menu_data.menu_option.max_page_size = 10;
+ menu_data.menu_option.max_columns = 2;
+ menu_data.menu_option.size_items_column = menu_data.menu_option.max_page_size / menu_data.menu_option.max_columns;
+ menu_data.menu_option.init_position_x = 20;
+ menu_data.menu_option.init_position_y = 5;
+ menu_data.menu_option.padding_x = 320;
+ menu_data.menu_option.padding_y = 12;
+ menu_data.menu_option.image_size = 64.0f;
+ }
+ break;
+ }
+}
+
+void FreeGames()
+{
+#ifndef IN_CACHE_GAMES
+ FreeGamesForce();
+#endif
+}
+
+void FreeGamesForce()
+{
+ if (menu_data.covers_array_count > 0)
+ {
+ for (int icount = 0; icount < menu_data.covers_array_count; icount++)
+ {
+ if (menu_data.covers_array[icount].cover)
+ {
+ free(menu_data.covers_array[icount].cover);
+ }
+
+ menu_data.covers_array[icount].cover = NULL;
+ }
+ menu_data.covers_array_count = 0;
+ }
+
+ if (menu_data.games_array_count > 0)
+ {
+ for (int icount = 0; icount < menu_data.games_array_count; icount++)
+ {
+ if (menu_data.games_array[icount].game)
+ {
+ free(menu_data.games_array[icount].game);
+ }
+
+ if (menu_data.games_array[icount].folder)
+ {
+ free(menu_data.games_array[icount].folder);
+ }
+
+ if (menu_data.games_array[icount].folder_name)
+ {
+ free(menu_data.games_array[icount].folder_name);
+ }
+
+ menu_data.games_array[icount].game = NULL;
+ menu_data.games_array[icount].folder = NULL;
+ menu_data.games_array[icount].folder_name = NULL;
+ }
+
+ free(menu_data.games_array);
+ menu_data.games_array = NULL;
+ menu_data.games_array_count = 0;
+ }
+}
+
+int GenerateVMUFile(const char* full_path_game, int vmu_mode, uint32 vmu_number)
+{
+ if (full_path_game != NULL && vmu_mode > 0)
+ {
+ char vmu_file_path[NAME_MAX];
+ memset(vmu_file_path, 0, NAME_MAX);
+
+ char private_path[NAME_MAX];
+ snprintf(private_path, NAME_MAX, "%s/vmu%03ld.vmd", GetFolderPathFromFile(full_path_game), vmu_number);
+
+ int private_size = FileSize(private_path);
+ if (vmu_mode == 1) // SHARED
+ {
+ if (private_size > 0)
+ {
+ fs_unlink(private_path);
+ }
+
+ return 0;
+ }
+
+ switch(vmu_mode)
+ {
+ case 2: // 200 BLOCKS
+ {
+ snprintf(vmu_file_path, sizeof(vmu_file_path),
+ "%s/apps/%s/resources/empty_vmu_128kb.vmd",
+ GetDefaultDir(menu_data.current_dev), "games_menu");
+ }
+ break;
+
+ case 3: // 1800 BLOCKS
+ {
+ snprintf(vmu_file_path, sizeof(vmu_file_path),
+ "%s/apps/%s/resources/empty_vmu_1024kb.vmd",
+ GetDefaultDir(menu_data.current_dev), "games_menu");
+ }
+ break;
+ }
+
+ int source_size = FileSize(vmu_file_path);
+ if (source_size > 0 && private_size != source_size)
+ {
+ if (private_size > 0)
+ {
+ fs_unlink(private_path);
+ }
+
+ CopyFile(vmu_file_path, private_path, 0);
+ return 0;
+ }
+ else {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int AppCompareFirmwares(const void *a, const void *b)
+{
+ const FirmwareStruct *left = (const FirmwareStruct *)a;
+ const FirmwareStruct *right = (const FirmwareStruct *)b;
+
+ if (ContainsOnlyNumbers(left->file) && ContainsOnlyNumbers(right->file))
+ {
+ return atoi(left->file) - atoi(right->file);
+ }
+ else if (ContainsOnlyNumbers(left->file))
+ {
+ return -1;
+ }
+ else if (ContainsOnlyNumbers(right->file))
+ {
+ return 1;
+ }
+
+ return strcmp(left->file, right->file);
+}
+
+bool LoadFirmwareFiles()
+{
+ char fw_dir[128];
+ memset(fw_dir, 0, sizeof(fw_dir));
+ sprintf(fw_dir, "%s/firmware/isoldr", GetDefaultDir(menu_data.current_dev));
+
+ if (menu_data.firmware_array != NULL)
+ {
+ free(menu_data.firmware_array);
+ menu_data.firmware_array = NULL;
+ menu_data.firmware_array_count = 0;
+ }
+
+ file_t fd = fs_open(fw_dir, O_RDONLY | O_DIR);
+ if (fd == FILEHND_INVALID)
+ return false;
+
+ dirent_t *ent = NULL;
+ char *file_type = NULL;
+
+ while ((ent = fs_readdir(fd)) != NULL)
+ {
+ if (ent->name[0] == '.')
+ continue;
+
+ file_type = strrchr(ent->name, '.');
+
+ if (strcasecmp(file_type, ".bin") == 0 && (strlen(ent->name) - 4) <= FIRMWARE_SIZE)
+ {
+ menu_data.firmware_array_count++;
+
+ if (menu_data.firmware_array == NULL)
+ {
+ menu_data.firmware_array = (FirmwareStruct *)malloc(sizeof(FirmwareStruct));
+ }
+ else
+ {
+ menu_data.firmware_array = (FirmwareStruct *)realloc(menu_data.firmware_array, menu_data.firmware_array_count * sizeof(FirmwareStruct));
+ }
+
+ memset(&menu_data.firmware_array[menu_data.firmware_array_count-1], 0, sizeof(FirmwareStruct));
+ memset(menu_data.firmware_array[menu_data.firmware_array_count-1].file, 0, FIRMWARE_SIZE+1);
+ strncpy(menu_data.firmware_array[menu_data.firmware_array_count-1].file, ent->name, strlen(ent->name) - 4);
+ }
+ }
+ fs_close(fd);
+
+ if (menu_data.firmware_array_count > 0)
+ {
+ qsort(menu_data.firmware_array, menu_data.firmware_array_count, sizeof(FirmwareStruct), AppCompareFirmwares);
+ }
+
+ return true;
+}
+
+PresetStruct* GetDefaultPresetGame(const char* full_path_game, SectorDataStruct *sector_data)
+{
+ PresetStruct *preset = NULL;
+
+ if (full_path_game)
+ {
+ preset = (PresetStruct *)malloc(sizeof(PresetStruct));
+ memset(preset, 0, sizeof(PresetStruct));
+
+ bool free_sector_data = false;
+ if (sector_data == NULL)
+ {
+ if (fs_iso_mount("/iso_game", full_path_game) == 0)
+ {
+ sector_data = (SectorDataStruct *)malloc(sizeof(SectorDataStruct));
+ memset(sector_data, 0, sizeof(SectorDataStruct));
+ GetMD5HashISO("/iso_game", sector_data);
+ fs_iso_unmount("/iso_game");
+ free_sector_data = true;
+ }
+ }
+
+ if (CanUseTrueAsyncDMA(sector_data->sector_size, GetDeviceType(full_path_game), sector_data->image_type))
+ {
+ preset->use_dma = 1;
+ preset->emu_async = 0;
+ sprintf(preset->memory, "0x%08lx", (unsigned long)ISOLDR_DEFAULT_ADDR_MIN_GINSU);
+
+ }
+ else
+ {
+ preset->use_dma = 0;
+ preset->emu_async = 8;
+ sprintf(preset->memory, "0x%08lx", (unsigned long)ISOLDR_DEFAULT_ADDR_LOW);
+ }
+
+ char title[32];
+ memset(title, 0, sizeof(title));
+
+ ipbin_meta_t *ipbin = (ipbin_meta_t *)sector_data->boot_sector;
+ TrimSpaces(ipbin->title, title, sizeof(ipbin->title));
+
+ if (free_sector_data)
+ {
+ free(sector_data);
+ }
+
+ preset->alt_read = 0;
+ strcpy(preset->device, "auto");
+ preset->emu_cdda = CDDA_MODE_DISABLED;
+ preset->use_irq = 0;
+ preset->emu_vmu = 0;
+ preset->scr_hotkey = 0;
+ preset->boot_mode = BOOT_MODE_DIRECT;
+ strcpy(preset->title, title);
+
+ // Enable CDDA if present
+ if (full_path_game[0] != '\0')
+ {
+ char *track_file_path = NULL;
+ size_t track_size = GetCDDATrackFilename(4, full_path_game, &track_file_path);
+
+ if (track_size && track_size < 30 * 1024 * 1024)
+ {
+ track_size = GetCDDATrackFilename(6, full_path_game, &track_file_path);
+ }
+
+ if (track_size > 0)
+ {
+ preset->use_irq = 1;
+ preset->emu_cdda = 1;
+ }
+
+ if (track_file_path)
+ {
+ free(track_file_path);
+ }
+ }
+
+ preset->heap = strtoul(preset->heap_memory, NULL, 16);
+ PatchParseText(preset);
+ }
+
+ return preset;
+}
+
+PresetStruct* LoadPresetGame(int game_index)
+{
+ PresetStruct *preset = NULL;
+
+ if (game_index >= 0)
+ {
+ preset = (PresetStruct *)malloc(sizeof(PresetStruct));
+ memset(preset, 0, sizeof(PresetStruct));
+
+ preset->game_index = game_index;
+ const char *full_path_game = GetFullGamePathByIndex(game_index);
+
+ char *full_preset_file_name = NULL;
+ SectorDataStruct sector_data;
+ memset(§or_data, 0, sizeof(SectorDataStruct));
+
+ if (fs_iso_mount("/iso_game", full_path_game) == 0)
+ {
+ GetMD5HashISO("/iso_game", §or_data);
+ fs_iso_unmount("/iso_game");
+
+ int app_name_count = 0;
+ const char *app_name_array[3] = { "games_menu", "iso_loader", NULL };
+ while (app_name_array[app_name_count] != NULL)
+ {
+ if (GetDeviceType(full_path_game) == APP_DEVICE_SD)
+ {
+ full_preset_file_name = MakePresetFilename(GetDefaultDir(APP_DEVICE_SD), GetDefaultDir(APP_DEVICE_SD), sector_data.md5, app_name_array[app_name_count]);
+ if (!FileExists(full_preset_file_name) && menu_data.ide)
+ {
+ full_preset_file_name = MakePresetFilename(GetDefaultDir(APP_DEVICE_IDE), GetDefaultDir(APP_DEVICE_SD), sector_data.md5, app_name_array[app_name_count]);
+ }
+ }
+ else if (GetDeviceType(full_path_game) == APP_DEVICE_IDE)
+ {
+ full_preset_file_name = MakePresetFilename(GetDefaultDir(APP_DEVICE_IDE), GetDefaultDir(APP_DEVICE_IDE), sector_data.md5, app_name_array[app_name_count]);
+ }
+ else
+ {
+ full_preset_file_name = MakePresetFilename(getenv("PATH"), GetDefaultDir(menu_data.current_dev), sector_data.md5, app_name_array[app_name_count]);
+ }
+
+ if (FileSize(full_preset_file_name) >= 5)
+ {
+ break;
+ }
+
+ ++app_name_count;
+ }
+
+ // ds_printf("PresetFileName: %s\n", full_preset_file_name);
+ }
+
+ if (full_preset_file_name != NULL)
+ {
+ memset(preset->preset_file_name, 0, sizeof(preset->preset_file_name));
+ strcpy(preset->preset_file_name, strrchr(full_preset_file_name, '/') + 1);
+ }
+
+ if (FileSize(full_preset_file_name) < 5)
+ {
+ full_preset_file_name = NULL;
+ }
+
+ preset->emu_async = 16;
+ preset->boot_mode = BOOT_MODE_DIRECT;
+ preset->bin_type = BIN_TYPE_AUTO;
+ preset->cdda = CDDA_MODE_DISABLED;
+ strcpy(preset->title, "");
+ strcpy(preset->device, "");
+ sprintf(preset->memory, "0x%08lx", (unsigned long)ISOLDR_DEFAULT_ADDR_MIN);
+
+ strcpy(preset->heap_memory, "");
+ strcpy(preset->bin_file, "");
+
+ memset(preset->patch_a, 0, 2 * 10);
+ memset(preset->patch_v, 0, 2 * 10);
+ memset(preset->pa, 0, 2 * sizeof(uint32));
+ memset(preset->pv, 0, 2 * sizeof(uint32));
+
+ char scr_hotkey[4];
+ memset(scr_hotkey, 0, sizeof(scr_hotkey));
+
+ isoldr_conf options[] = {
+ {"dma", CONF_INT, (void *)&preset->use_dma},
+ {"altread", CONF_INT, (void *)&preset->alt_read},
+ {"cdda", CONF_ULONG, (void *)&preset->emu_cdda},
+ {"irq", CONF_INT, (void *)&preset->use_irq},
+ {"low", CONF_INT, (void *)&preset->low},
+ {"vmu", CONF_INT, (void *)&preset->emu_vmu},
+ {"scrhotkey", CONF_STR, (void *)scr_hotkey},
+ {"heap", CONF_STR, (void *)&preset->heap_memory},
+ {"memory", CONF_STR, (void *)preset->memory},
+ {"async", CONF_INT, (void *)&preset->emu_async},
+ {"mode", CONF_INT, (void *)&preset->boot_mode},
+ {"type", CONF_INT, (void *)&preset->bin_type},
+ {"file", CONF_STR, (void *)preset->bin_file},
+ {"title", CONF_STR, (void *)preset->title},
+ {"device", CONF_STR, (void *)preset->device},
+ {"fastboot", CONF_INT, (void *)&preset->fastboot},
+ {"pa1", CONF_STR, (void *)preset->patch_a[0]},
+ {"pv1", CONF_STR, (void *)preset->patch_v[0]},
+ {"pa2", CONF_STR, (void *)preset->patch_a[1]},
+ {"pv2", CONF_STR, (void *)preset->patch_v[1]},
+ {NULL, CONF_END, NULL}};
+
+ char preset_file_name[100];
+ memset(preset_file_name, 0, sizeof(preset_file_name));
+ strcpy(preset_file_name, preset->preset_file_name);
+
+ if (full_preset_file_name != NULL)
+ {
+ if (ConfigParse(options, full_preset_file_name) == 0)
+ {
+ preset->heap = strtoul(preset->heap_memory, NULL, 16);
+ PatchParseText(preset);
+
+ if (scr_hotkey[0] != '\0' && scr_hotkey[0] != ' ')
+ {
+ preset->scr_hotkey = strtol(scr_hotkey, NULL, 16);
+ }
+ }
+ else
+ {
+ free(preset);
+ preset = GetDefaultPresetGame(full_path_game, §or_data);
+ preset->game_index = game_index;
+ strcpy(preset->preset_file_name, preset_file_name);
+ }
+
+ if (preset->scr_hotkey)
+ {
+ preset->screenshot = 1;
+ preset->use_irq = 1;
+ }
+
+ if (preset->emu_vmu)
+ {
+ preset->use_irq = 1;
+ snprintf(preset->vmu_file, sizeof(preset->vmu_file), "vmu%03ld.vmd", preset->emu_vmu);
+
+ char dst_path[NAME_MAX];
+ snprintf(dst_path, NAME_MAX, "%s/%s", GetFolderPathFromFile(full_path_game), preset->vmu_file);
+
+ int dst_size = FileSize(dst_path);
+
+ menu_data.vmu_mode = 0;
+ if (dst_size <= 0)
+ {
+ preset->vmu_mode = 1;
+ }
+ else if(dst_size < 256 << 10)
+ {
+ preset->vmu_mode = 2;
+ }
+ else
+ {
+ preset->vmu_mode = 3;
+ }
+ menu_data.vmu_mode = preset->vmu_mode;
+ }
+ else
+ {
+ preset->vmu_mode = 0;
+ }
+
+ if (preset->device[0] == '\0')
+ {
+ strcpy(preset->device, "auto");
+ }
+ }
+ else
+ {
+ free(preset);
+ preset = GetDefaultPresetGame(full_path_game, §or_data);
+ preset->game_index = game_index;
+ strcpy(preset->preset_file_name, preset_file_name);
+ }
+
+ if (preset->emu_cdda)
+ {
+ preset->cdda = 1;
+ }
+ }
+
+ return preset;
+}
+
+void PatchParseText(PresetStruct *preset)
+{
+ if (preset)
+ {
+ for(int i = 0; i < 2; ++i)
+ {
+ if (preset->patch_a[i][1] != '0' && strlen(preset->patch_a[i]) == 8 && strlen(preset->patch_v[i]))
+ {
+ preset->pa[i] = strtoul(preset->patch_a[i], NULL, 16);
+ preset->pv[i] = strtoul(preset->patch_v[i], NULL, 16);
+ }
+ else
+ {
+ preset->pa[i] = 0;
+ preset->pv[i] = 0;
+ }
+ }
+ }
+}
+
+isoldr_info_t* ParsePresetToIsoldr(int game_index, PresetStruct *preset)
+{
+ isoldr_info_t *isoldr = NULL;
+ if (game_index >= 0 && preset != NULL && preset->game_index >= 0)
+ {
+ const char *full_path_game = GetFullGamePathByIndex(game_index);
+
+ if ((isoldr = isoldr_get_info(full_path_game, 0)) == NULL)
+ {
+ return NULL;
+ }
+
+ isoldr->use_dma = preset->use_dma;
+ isoldr->alt_read = preset->alt_read;
+ isoldr->emu_async = preset->emu_async;
+ isoldr->emu_cdda = preset->emu_cdda;
+ isoldr->use_irq = preset->use_irq;
+ isoldr->scr_hotkey = preset->scr_hotkey;
+ isoldr->heap = preset->heap;
+ isoldr->boot_mode = preset->boot_mode;
+ isoldr->fast_boot = preset->fastboot;
+ isoldr->emu_vmu = preset->emu_vmu;
+
+ if (preset->low)
+ {
+ isoldr->syscalls = 1;
+ }
+
+ if (preset->bin_type != BIN_TYPE_AUTO)
+ {
+ isoldr->exec.type = preset->bin_type;
+ }
+
+ if (strlen(preset->device) > 0)
+ {
+ if (strncmp(preset->device, "auto", 4) != 0)
+ {
+ strcpy(isoldr->fs_dev, preset->device);
+ }
+ else
+ {
+ strcpy(isoldr->fs_dev, "auto");
+ }
+ }
+ else
+ {
+ strcpy(isoldr->fs_dev, "auto");
+ }
+
+ for(int i = 0; i < sizeof(isoldr->patch_addr) >> 2; ++i)
+ {
+ if(preset->pa[i] & 0xffffff)
+ {
+ isoldr->patch_addr[i] = preset->pa[i];
+ isoldr->patch_value[i] = preset->pa[i];
+ }
+ }
+
+ if(preset->alt_boot && menu_data.games_array[game_index].folder)
+ {
+ char game_path[NAME_MAX];
+ memset(game_path, 0, NAME_MAX);
+ snprintf(game_path, NAME_MAX, "%s/%s", GetGamesPath(menu_data.games_array[game_index].device), menu_data.games_array[game_index].folder);
+ isoldr_set_boot_file(isoldr, game_path, ALT_BOOT_FILE);
+ }
+ }
+
+ return isoldr;
+}
+
+bool SavePresetGame(PresetStruct *preset)
+{
+ bool saved = false;
+
+ if (menu_data.current_dev != APP_DEVICE_SD && menu_data.current_dev != APP_DEVICE_IDE)
+ {
+ return false;
+ }
+
+ if (preset != NULL && preset->game_index >= 0)
+ {
+ file_t fd;
+ char result[1024];
+ char memory[24];
+ int async = 0, type = 0, mode = 0;
+ uint32 heap = HEAP_MODE_AUTO;
+ uint32 cdda_mode = CDDA_MODE_DISABLED;
+
+ char preset_file_name[NAME_MAX];
+ memset(preset_file_name, 0, NAME_MAX);
+
+ snprintf(preset_file_name, sizeof(preset_file_name),
+ "%s/apps/%s/presets/%s",
+ GetDefaultDir(menu_data.current_dev), "games_menu", preset->preset_file_name);
+
+ fd = fs_open(preset_file_name, O_CREAT | O_TRUNC | O_WRONLY);
+
+ if(fd == FILEHND_INVALID)
+ {
+ return false;
+ }
+
+ memset(result, 0, sizeof(result));
+ memset(memory, 0, sizeof(memory));
+
+ async = preset->emu_async;
+ type = preset->bin_type;
+ mode = preset->boot_mode;
+
+ if (preset->cdda)
+ {
+ cdda_mode = preset->emu_cdda;
+ }
+
+ if (strcasecmp(preset->memory, "0x8c") == 0)
+ {
+ snprintf(memory, sizeof(memory), "%s%s", preset->memory, preset->custom_memory);
+ }
+ else
+ {
+ strcpy(memory, preset->memory);
+ }
+
+ heap = preset->heap;
+
+ if (preset->device[0] == '\0' || preset->device[0] == ' ')
+ {
+ strcpy(preset->device, "auto");
+ }
+
+ if (preset->emu_vmu > 0 || preset->scr_hotkey)
+ {
+ preset->use_irq = 1;
+ }
+
+ snprintf(result, sizeof(result),
+ "title = %s\ndevice = %s\ndma = %d\nasync = %d\ncdda = %08lx\n"
+ "irq = %d\nlow = %d\nheap = %08lx\nfastboot = %d\ntype = %d\nmode = %d\nmemory = %s\n"
+ "vmu = %d\nscrhotkey = %lx\naltread = %d\n"
+ "pa1 = %08lx\npv1 = %08lx\npa2 = %08lx\npv2 = %08lx\n",
+ preset->title, preset->device, preset->use_dma, async,
+ cdda_mode, preset->use_irq, preset->low, heap,
+ preset->fastboot, type, mode, memory,
+ (int)preset->emu_vmu, (uint32)preset->scr_hotkey,
+ preset->alt_read,
+ preset->pa[0], preset->pv[0], preset->pa[1], preset->pv[1]);
+
+ if (preset->alt_boot)
+ {
+ strcat(result, "file = " ALT_BOOT_FILE "\n");
+ }
+
+ fs_write(fd, result, strlen(result));
+ fs_close(fd);
+
+ char isoldr_preset_file_name[NAME_MAX];
+ memset(isoldr_preset_file_name, 0, NAME_MAX);
+
+ snprintf(isoldr_preset_file_name, sizeof(isoldr_preset_file_name),
+ "%s/apps/%s/presets/%s",
+ GetDefaultDir(menu_data.current_dev), "iso_loader", preset->preset_file_name);
+
+ // COPY TO ISO LOADER FOLDER
+ CopyFile(preset_file_name, isoldr_preset_file_name, 0);
+ saved = true;
+ }
+
+ return saved;
+}
+
+void LoadDefaultMenuConfig()
+{
+ menu_data.app_config.initial_view = menu_data.menu_type = MT_PLANE_TEXT;
+ menu_data.app_config.save_preset = 1;
+ menu_data.app_config.cover_background = 1;
+ menu_data.app_config.change_page_with_pad = 0;
+}
+
+bool LoadMenuConfig()
+{
+ char file_name[100];
+ snprintf(file_name, sizeof(file_name), "%s/%s/%s", GetDefaultDir(menu_data.current_dev), "apps/games_menu", "menu_games.cfg");
+
+ GenericConfigStruct options[] =
+ {
+ { "initial_view", CONF_INT, (void *)&menu_data.app_config.initial_view },
+ { "save_preset", CONF_INT, (void *)&menu_data.app_config.save_preset },
+ { "cover_background", CONF_INT, (void *)&menu_data.app_config.cover_background },
+ { "change_page_with_pad", CONF_INT, (void *)&menu_data.app_config.change_page_with_pad }
+ };
+
+ if (ConfigParse(options, file_name) == -1)
+ {
+ LoadDefaultMenuConfig();
+ ParseMenuConfigToPresentation();
+
+ return false;
+ }
+
+ ParseMenuConfigToPresentation();
+ return true;
+}
+
+void ParseMenuConfigToPresentation()
+{
+ if (menu_data.app_config.initial_view > 0)
+ {
+ menu_data.menu_type = menu_data.app_config.initial_view;
+ }
+ else
+ {
+ menu_data.app_config.initial_view = menu_data.menu_type = MT_PLANE_TEXT;
+ }
+
+ menu_data.save_preset = (menu_data.app_config.save_preset == 1);
+ menu_data.cover_background = (menu_data.app_config.cover_background == 1);
+ menu_data.change_page_with_pad = (menu_data.app_config.change_page_with_pad == 1);
+}
+
+void ParsePresentationToMenuConfig()
+{
+ menu_data.app_config.initial_view = menu_data.menu_type;
+ menu_data.app_config.save_preset = (menu_data.save_preset ? 1 : 0);
+ menu_data.app_config.cover_background = (menu_data.cover_background ? 1 : 0);
+ menu_data.app_config.change_page_with_pad = (menu_data.change_page_with_pad ? 1 : 0);
+}
+
+bool SaveMenuConfig()
+{
+ if (menu_data.current_dev != APP_DEVICE_SD && menu_data.current_dev != APP_DEVICE_IDE)
+ {
+ return false;
+ }
+
+ file_t fd;
+ char file_name[100];
+ char result[1024];
+
+ ParsePresentationToMenuConfig();
+
+ snprintf(file_name, sizeof(file_name), "%s/%s/%s", GetDefaultDir(menu_data.current_dev), "apps/games_menu", "menu_games.cfg");
+ fd = fs_open(file_name, O_CREAT | O_TRUNC | O_WRONLY);
+
+ if(fd == FILEHND_INVALID) {
+ return false;
+ }
+
+ snprintf(result, sizeof(result),
+ "initial_view = %d\nsave_preset = %d\ncover_background = %d\nchange_page_with_pad = %d",
+ menu_data.app_config.initial_view, menu_data.app_config.save_preset, menu_data.app_config.cover_background,
+ menu_data.app_config.change_page_with_pad);
+
+ fs_write(fd, result, strlen(result));
+ fs_close(fd);
+
+ return true;
+}
+
+bool SaveScannedCover()
+{
+ if (menu_data.current_dev != APP_DEVICE_SD && menu_data.current_dev != APP_DEVICE_IDE)
+ {
+ return false;
+ }
+
+ char file_name[100];
+ snprintf(file_name, sizeof(file_name), "%s/%s/%s", GetDefaultDir(menu_data.current_dev), "apps/games_menu", "scanned_cover.log");
+
+ file_t fd = fs_open(file_name, O_WRONLY | O_CREAT | O_TRUNC);
+ if (fd == FILEHND_INVALID)
+ {
+ return false;
+ }
+
+ fs_write(fd, &menu_data.cover_scanned_app, sizeof(CoverScannedStruct));
+ fs_close(fd);
+
+ return true;
+}
+
+bool LoadScannedCover()
+{
+ char file_name[100];
+ snprintf(file_name, sizeof(file_name), "%s/%s/%s", GetDefaultDir(menu_data.current_dev), "apps/games_menu", "scanned_cover.log");
+
+ file_t fd = fs_open(file_name, O_RDONLY);
+ if (fd == FILEHND_INVALID)
+ {
+ return false;
+ }
+
+ memset(&menu_data.cover_scanned_app, 0, sizeof(CoverScannedStruct));
+
+ size_t file_size = fs_total(fd);
+ if (file_size > 0)
+ {
+ unsigned char *buffer = (unsigned char *)malloc(sizeof(CoverScannedStruct));
+ fs_read(fd, buffer, sizeof(CoverScannedStruct));
+ memcpy(&menu_data.cover_scanned_app, buffer, sizeof(CoverScannedStruct));
+ free(buffer);
+ }
+ fs_close(fd);
+
+ if (file_size <= 0)
+ {
+ memset(&menu_data.cover_scanned_app, 0, sizeof(CoverScannedStruct));
+ fs_unlink(file_name);
+ }
+
+ if (!HasAnyCover())
+ {
+ memset(&menu_data.cover_scanned_app, 0, sizeof(CoverScannedStruct));
+ fs_unlink(file_name);
+ }
+
+ return true;
+}
+
+void CleanIncompleteCover()
+{
+ if (menu_data.cover_scanned_app.last_game_status == CSE_PROCESSING)
+ {
+ char game_cover_path[NAME_MAX];
+ uint16 image_count = 1;
+
+ while (image_count < IMAGE_TYPE_SUPPORTED)
+ {
+ if (IMAGE_TYPE_SUPPORTED & image_count)
+ {
+ memset(game_cover_path, 0, sizeof(game_cover_path));
+ snprintf(game_cover_path, sizeof(game_cover_path), "%s/%s%s", GetCoversPath(menu_data.current_dev), menu_data.cover_scanned_app.last_game_scanned, GetCoverExtensionFromType(image_count));
+ if (FileExists(game_cover_path))
+ {
+ fs_unlink(game_cover_path);
+ }
+
+ strcat(game_cover_path, ".tmp");
+ if (FileExists(game_cover_path))
+ {
+ fs_unlink(game_cover_path);
+ }
+ }
+
+ image_count = image_count<<1;
+ }
+ }
+}
+
+void OptimizeGameCovers()
+{
+ char *game_cover_path = NULL;
+ char *image_type = NULL;
+ char *game_without_extension = NULL;
+ kos_img_t kimg;
+
+ for (int icount = 0; icount < menu_data.games_array_count; icount++)
+ {
+ if (menu_data.stop_optimize_game_cover || menu_data.finished_menu) break;
+
+ if (CheckCover(icount, MT_PLANE_TEXT) == SC_EXISTS)
+ {
+ GetCoverName(icount, &game_without_extension);
+ menu_data.send_message_optimizer("Check COVER: %s", game_without_extension);
+
+ if (CheckCover(icount, MT_IMAGE_TEXT_64_5X2) != SC_EXISTS || CheckCover(icount, MT_IMAGE_128_4X3) != SC_EXISTS)
+ {
+ if (GetGameCoverPath(icount, &game_cover_path, MT_PLANE_TEXT))
+ {
+ image_type = strrchr(game_cover_path, '.');
+
+ if ((strcasecmp(image_type, ".png") == 0 && png_decode(game_cover_path, &kimg) == 0)
+ || (strcasecmp(image_type, ".jpg") == 0 && jpg_decode(game_cover_path, &kimg) == 0))
+ {
+ menu_data.send_message_optimizer ("Optimizing cover: %s", game_without_extension);
+ OptimizeCover(icount, game_without_extension, &kimg, strcasecmp(image_type, ".png") == 0 ? true : false);
+ kos_img_free(&kimg, 0);
+ }
+
+ free(game_cover_path);
+ game_cover_path = NULL;
+ }
+ }
+
+ menu_data.send_message_optimizer("%s", "");
+ if (game_without_extension != NULL)
+ {
+ free(game_without_extension);
+ game_without_extension = NULL;
+ }
+ }
+ }
+
+ image_type = NULL;
+}
+
+void OptimizeCover(int game_index, const char *game_name, kos_img_t *img, bool is_alpha)
+{
+ if (img != NULL && img->data)
+ {
+ bool optimize_to_128 = img->w > 128;
+ bool optimize_to_64 = img->w > 64;
+ char new_cover_path[NAME_MAX];
+ char cover_folder[NAME_MAX];
+ int image_size = 0;
+
+ for (int16 imenu = 2; imenu <= MAX_MENU; imenu++)
+ {
+ if ((optimize_to_64 && imenu == MT_IMAGE_TEXT_64_5X2) || (optimize_to_128 && imenu == MT_IMAGE_128_4X3))
+ {
+ memset(cover_folder, 0, NAME_MAX);
+ memset(new_cover_path, 0, NAME_MAX);
+
+ image_size = (imenu == MT_IMAGE_TEXT_64_5X2 ? 64 : 128);
+
+ snprintf(cover_folder, NAME_MAX, "%s%s", GetCoversPath(menu_data.current_dev), GetCoverFolder(imenu));
+ if (DirExists(cover_folder) == 0)
+ {
+ fs_mkdir(cover_folder);
+ }
+
+ snprintf(new_cover_path, NAME_MAX, "%s/%s%s", cover_folder, game_name, is_alpha ? GetCoverExtensionFromType(IT_PNG) : GetCoverExtensionFromType(IT_JPG));
+ if (copy_image_memory_to_file(img, new_cover_path, true, image_size, image_size))
+ {
+ CleanCoverType(game_index, imenu);
+ SetCoverType(game_index, imenu, is_alpha ? IT_PNG : IT_JPG);
+ menu_data.games_array[game_index].exists_cover[imenu - 1] = SC_EXISTS;
+ }
+ }
+ }
+ }
+}
+
+bool ExtractPVRCover(int game_index)
+{
+ bool extracted_cover = false;
+ if (game_index >= 0 && (menu_data.current_dev == APP_DEVICE_SD || menu_data.current_dev == APP_DEVICE_IDE))
+ {
+ if (!menu_data.games_array[game_index].check_pvr || menu_data.games_array[game_index].exists_cover[MT_PLANE_TEXT-1] != SC_DEFAULT)
+ {
+ return false;
+ }
+
+ char *game_without_extension = NULL;
+ const char *full_game_path = GetFullGamePathByIndex(game_index);
+ menu_data.games_array[game_index].check_pvr = false;
+
+ GetCoverName(game_index, &game_without_extension);
+ menu_data.send_message_scan("Mounting GAME: %s", game_without_extension);
+
+ if(fs_iso_mount("/iso_cover", full_game_path) == 0)
+ {
+ char pvr_path[30];
+ memset(pvr_path, 0, 30);
+ strcpy(pvr_path, "/iso_cover/0GDTEX.PVR");
+
+ menu_data.send_message_scan("Extracting PVR: %s", game_without_extension);
+ menu_data.cover_scanned_app.last_game_status = CSE_PROCESSING;
+ SaveScannedCover();
+
+ kos_img_t kimg;
+ if(pvr_decode(pvr_path, &kimg) == 0)
+ {
+ uint16 image_type = 0;
+ if (kimg.fmt != TFM_RGB565 && menu_data.convert_pvr_to_png)
+ {
+ image_type = IT_PNG;
+ }
+ else
+ {
+ image_type = IT_JPG;
+ }
+
+ if (image_type > 0)
+ {
+ char game_cover_path[NAME_MAX];
+ memset(game_cover_path, 0, NAME_MAX);
+ snprintf(game_cover_path, NAME_MAX, "%s/%s%s", GetCoversPath(menu_data.current_dev), game_without_extension, GetCoverExtensionFromType(image_type));
+
+ if ( (image_type == IT_PNG && img_to_png(&kimg, game_cover_path, 0, 0))
+ || (image_type == IT_JPG && img_to_jpg(&kimg, game_cover_path, 0, 0, 100)) )
+ {
+ menu_data.games_array[game_index].exists_cover[MT_PLANE_TEXT-1] = SC_EXISTS;
+ SetCoverType(game_index, MT_PLANE_TEXT, image_type);
+
+ menu_data.send_message_scan("Optimizing cover: %s", game_without_extension);
+ OptimizeCover(game_index, game_without_extension, &kimg, (image_type == IT_PNG));
+
+ menu_data.games_array[game_index].is_pvr_cover = true;
+ extracted_cover = true;
+ }
+ }
+
+ kos_img_free(&kimg, 0);
+ menu_data.cover_scanned_app.last_game_status = CSE_COMPLETED;
+ }
+
+ fs_iso_unmount("/iso_cover");
+ }
+
+ if (game_without_extension)
+ {
+ free(game_without_extension);
+ game_without_extension = NULL;
+ }
+ }
+
+ return extracted_cover;
+}
+
+void* OptimizeCoverThread(void *param)
+{
+ OptimizeGameCovers();
+ menu_data.post_optimizer_cover();
+
+ return NULL;
+}
+
+void* LoadPVRCoverThread(void *params)
+{
+ menu_data.cover_scanned_app.scan_count++;
+
+ bool new_cover = false;
+ if (menu_data.rescan_covers)
+ {
+ menu_data.rescan_covers = false;
+ menu_data.cover_scanned_app.last_game_index = 1;
+ }
+
+ if (menu_data.cover_scanned_app.last_game_index == 0)
+ {
+ menu_data.cover_scanned_app.last_game_index = 1;
+ }
+
+ char *game_without_extension = NULL;
+ for (int icount = menu_data.cover_scanned_app.last_game_index-1; icount < menu_data.games_array_count; icount++)
+ {
+ if (menu_data.stop_load_pvr_cover || menu_data.finished_menu) break;
+
+ GetCoverName(icount, &game_without_extension);
+
+ memset(menu_data.cover_scanned_app.last_game_scanned, 0, sizeof(menu_data.cover_scanned_app.last_game_scanned));
+ strncpy(menu_data.cover_scanned_app.last_game_scanned, game_without_extension, strlen(game_without_extension));
+
+ menu_data.send_message_scan("Check game: %s", game_without_extension);
+
+ if (CheckCover(icount, MT_PLANE_TEXT) == SC_DEFAULT)
+ {
+ // CHECK AGAIN TO SEE IF IT WAS NOT DOWNLOADED IN PVR
+ menu_data.games_array[icount].exists_cover[MT_PLANE_TEXT-1] = SC_WITHOUT_SEARCHING;
+ if (CheckCover(icount, MT_PLANE_TEXT) == SC_DEFAULT)
+ {
+ ExtractPVRCover(icount);
+ new_cover = true;
+ }
+ else
+ {
+ menu_data.games_array[icount].is_pvr_cover = true;
+ menu_data.cover_scanned_app.last_game_status = CSE_EXISTS;
+ }
+ }
+ else
+ {
+ menu_data.cover_scanned_app.last_game_status = CSE_EXISTS;
+ }
+
+ menu_data.cover_scanned_app.last_game_index = (uint32)icount + 1;
+ SaveScannedCover();
+ }
+
+ if (game_without_extension != NULL)
+ {
+ free(game_without_extension);
+ game_without_extension = NULL;
+ }
+
+ menu_data.post_pvr_cover(new_cover);
+
+ return NULL;
+}
+
+static int AppCompareGames(const void *a, const void *b)
+{
+ const GameItemStruct *left = (const GameItemStruct *)a;
+ const GameItemStruct *right = (const GameItemStruct *)b;
+ int cmp = 0;
+
+ char *left_compare = malloc(NAME_MAX);
+ char *right_compare = malloc(NAME_MAX);
+
+ memset(left_compare, 0, NAME_MAX);
+ memset(right_compare, 0, NAME_MAX);
+
+ if (left->is_folder_name && right->is_folder_name)
+ {
+ cmp = strcmp(left->folder_name, right->folder_name);
+ }
+ else if (left->is_folder_name)
+ {
+ strncpy(right_compare, right->game, strlen(right->game) - 4);
+ cmp = strcmp(left->folder_name, right_compare);
+ }
+ else if (right->is_folder_name)
+ {
+ strncpy(left_compare, left->game, strlen(left->game) - 4);
+ cmp = strcmp(left_compare, right->folder_name);
+ }
+ else
+ {
+ strncpy(left_compare, left->game, strlen(left->game) - 4);
+ strncpy(right_compare, right->game, strlen(right->game) - 4);
+
+ cmp = strcmp(left_compare, right_compare);
+ }
+
+ if (cmp == 0)
+ {
+ int left_device = (left->device == APP_DEVICE_IDE ? 1 : 2);
+ int right_device = (right->device == APP_DEVICE_IDE ? 1 : 2);
+ cmp = left_device - right_device;
+ }
+
+ free(left_compare);
+ free(right_compare);
+
+ return cmp;
+}
+
+bool CheckGdiOptimized(int game_index)
+{
+ bool optimized = false;
+
+ if (game_index >= 0)
+ {
+ if (!menu_data.games_array[game_index].check_optimized)
+ {
+ menu_data.games_array[game_index].check_optimized = true;
+ optimized = menu_data.games_array[game_index].is_gdi_optimized = IsGdiOptimized(GetFullGamePathByIndex(game_index));
+ }
+ else
+ {
+ optimized = menu_data.games_array[game_index].is_gdi_optimized;
+ }
+ }
+
+ return optimized;
+}
+
+bool IsUniqueFileGame(const char *full_path_folder)
+{
+ file_t fd = fs_open(full_path_folder, O_RDONLY | O_DIR);
+ if (fd == FILEHND_INVALID)
+ return false;
+
+ int file_count = 0;
+ char *file_type = NULL;
+ dirent_t *ent = NULL;
+
+ while ((ent = fs_readdir(fd)) != NULL)
+ {
+ if (ent->name[0] == '.')
+ continue;
+
+ file_type = strrchr(ent->name, '.');
+ if (strcasecmp(file_type, ".gdi") == 0
+ || strcasecmp(file_type, ".cdi") == 0
+ || (strcasecmp(file_type, ".iso") == 0 && !(strncasecmp(ent->name, "track", strlen("track")) == 0))
+ || strcasecmp(file_type, ".cso") == 0)
+ {
+ file_count++;
+
+ if (file_count > 1)
+ {
+ break;
+ }
+ }
+ }
+ ent = NULL;
+ fs_close(fd);
+
+ return !(file_count > 1);
+}
+
+bool HasAnyCover()
+{
+ bool any_cover = false;
+ file_t fd = fs_open(GetCoversPath(menu_data.current_dev), O_RDONLY | O_DIR);
+ if (fd == FILEHND_INVALID)
+ return false;
+
+ char *file_type = NULL;
+ dirent_t *ent = NULL;
+
+ while ((ent = fs_readdir(fd)) != NULL)
+ {
+ if (ent->name[0] == '.')
+ continue;
+
+ file_type = strrchr(ent->name, '.');
+ if (strcasecmp(file_type, ".jpg") == 0
+ || strcasecmp(file_type, ".png") == 0
+ || strcasecmp(file_type, ".pvr") == 0)
+ {
+ any_cover = true;
+ break;
+ }
+ }
+ ent = NULL;
+ fs_close(fd);
+
+ return any_cover;
+}
+
+static int AppCompareCovers(const void *a, const void *b)
+{
+ const CoverStruct *left = (const CoverStruct *)a;
+ const CoverStruct *right = (const CoverStruct *)b;
+ return strcasecmp(left->cover, right->cover);
+}
+
+void RetrieveCovers(uint8 device, int menu_type)
+{
+ if (menu_type > 0)
+ {
+ char game_cover_path[NAME_MAX];
+ snprintf(game_cover_path, NAME_MAX, "%s%s", GetCoversPath(device), GetCoverFolder(menu_type));
+ file_t fd = fs_open(game_cover_path, O_RDONLY | O_DIR);
+ if (fd == FILEHND_INVALID)
+ return;
+
+ dirent_t *ent = NULL;
+ char cover[NAME_MAX];
+ char *file_type = NULL;
+ uint8 dw_image_type = 0;
+ CoverStruct cover_key;
+ CoverStruct *cover_found = NULL;
+ CoverStruct *covers_array = NULL;
+
+ int covers_array_count = 0;
+ cover_key.cover = (char *)malloc(NAME_MAX);
+
+ while ((ent = fs_readdir(fd)) != NULL)
+ {
+ if (ent->name[0] == '.')
+ continue;
+
+ cover_found = NULL;
+ dw_image_type = 0;
+ memset(cover, 0, NAME_MAX);
+ file_type = strrchr(ent->name, '.');
+
+ if (strcasecmp(file_type, ".png") == 0)
+ {
+ dw_image_type = IT_PNG;
+ }
+ else if (strcasecmp(file_type, ".jpg") == 0)
+ {
+ dw_image_type = IT_JPG;
+ }
+ else if (strcasecmp(file_type, ".bpm") == 0)
+ {
+ dw_image_type = IT_BPM;
+ }
+ else if (strcasecmp(file_type, ".pvr") == 0)
+ {
+ dw_image_type = IT_PVR;
+ }
+ else if (strcasecmp(file_type, ".kmg") == 0)
+ {
+ dw_image_type = IT_KMG;
+ }
+ else
+ {
+ continue;
+ }
+
+ strncpy(cover, ent->name, strlen(ent->name));
+
+ if (menu_data.covers_array_count > 0)
+ {
+ memset(cover_key.cover, 0, NAME_MAX);
+ strcpy(cover_key.cover, cover);
+
+ cover_found = (CoverStruct *)bsearch(&cover_key, menu_data.covers_array, menu_data.covers_array_count, sizeof(CoverStruct), AppCompareCovers);
+ }
+
+ if (cover_found != NULL)
+ {
+ cover_found->menu_type |= (1<<(menu_type-1));
+ cover_found->image_type[menu_type-1] |= dw_image_type;
+ cover_found->device |= (1<<(device-1));
+ continue;
+ }
+ else
+ {
+ covers_array_count++;
+ if (covers_array == NULL)
+ {
+ covers_array = (CoverStruct *)malloc(sizeof(CoverStruct));
+ }
+ else
+ {
+ covers_array = (CoverStruct *)realloc(covers_array, covers_array_count * sizeof(CoverStruct));
+ }
+
+ memset(&covers_array[covers_array_count - 1], 0, sizeof(CoverStruct));
+
+ covers_array[covers_array_count-1].cover = (char *)malloc(strlen(cover)+1);
+ memset(covers_array[covers_array_count-1].cover, 0, strlen(cover)+1);
+ strncpy(covers_array[covers_array_count-1].cover, cover, strlen(cover));
+
+ covers_array[covers_array_count-1].menu_type = 0;
+ covers_array[covers_array_count-1].menu_type |= (1<<(menu_type-1));
+
+ // THIS VALUE IS TO AVOID SAVING EVERY GAME THAT CONTAINS MULTIPLE EXTENSIONS, NOT USED YET.
+ covers_array[covers_array_count-1].image_type[menu_type-1] = 0;
+ covers_array[covers_array_count-1].image_type[menu_type-1] |= dw_image_type;
+
+ covers_array[covers_array_count-1].device = 0;
+ covers_array[covers_array_count-1].device |= (1<<(device-1));
+ }
+ }
+
+ if (covers_array_count > 0)
+ {
+ int current_pos = menu_data.covers_array_count;
+ menu_data.covers_array_count += covers_array_count;
+
+ if (menu_data.covers_array == NULL)
+ {
+ menu_data.covers_array = (CoverStruct *)malloc(menu_data.covers_array_count * sizeof(CoverStruct));
+ }
+ else
+ {
+ menu_data.covers_array = (CoverStruct *)realloc(menu_data.covers_array, menu_data.covers_array_count * sizeof(CoverStruct));
+ }
+
+ memcpy(&menu_data.covers_array[current_pos], covers_array, covers_array_count * sizeof(CoverStruct));
+ free(covers_array);
+
+ qsort(menu_data.covers_array, menu_data.covers_array_count, sizeof(CoverStruct), AppCompareCovers);
+ }
+
+ free(cover_key.cover);
+ fs_close(fd);
+ }
+}
+
+void RetrieveGamesRecursive(const char *full_path_folder, const char *folder, int level)
+{
+ file_t fd = fs_open(full_path_folder, O_RDONLY | O_DIR);
+ if (fd == FILEHND_INVALID)
+ return;
+
+ dirent_t *ent = NULL;
+ char game[NAME_MAX];
+ char new_folder[NAME_MAX];
+ char *file_type = NULL;
+ bool is_folder_name = false;
+ int unique_file = -1;
+ int gdi_index = -1;
+ bool gdi_optimized = false;
+ int gdi_cdda = CCGE_NOT_CHECKED;
+
+ while ((ent = fs_readdir(fd)) != NULL)
+ {
+ if (ent->name[0] == '.')
+ continue;
+
+ // SKIP FULL NAMES WITH A LENGTH LONGER THAN NAMEMAX
+ if ((full_path_folder && (strlen(full_path_folder) + strlen(ent->name)) > NAME_MAX)
+ || strlen(ent->name) > NAME_MAX)
+ continue;
+
+ is_folder_name = false;
+ file_type = strrchr(ent->name, '.');
+ memset(game, '\0', sizeof(game));
+
+ if (strcasecmp(file_type, ".gdi") == 0)
+ {
+ strcpy(game, ent->name);
+ is_folder_name = level > 0;
+ }
+ else if (strcasecmp(file_type, ".cdi") == 0)
+ {
+ strcpy(game, ent->name);
+
+ if (unique_file == -1)
+ {
+ unique_file = level > 0 ? IsUniqueFileGame(full_path_folder) : false;
+ }
+ is_folder_name = (unique_file == 1);
+ }
+ else if (strcasecmp(file_type, ".iso") == 0 && !(strncasecmp(ent->name, "track", strlen("track")) == 0))
+ {
+ strcpy(game, ent->name);
+
+ if (unique_file == -1)
+ {
+ unique_file = level > 0 ? IsUniqueFileGame(full_path_folder) : false;
+ }
+ is_folder_name = (unique_file == 1);
+ }
+ else if (strcasecmp(file_type, ".cso") == 0)
+ {
+ strcpy(game, ent->name);
+ if (unique_file == -1)
+ {
+ unique_file = level > 0 ? IsUniqueFileGame(full_path_folder) : false;
+ }
+ is_folder_name = (unique_file == 1);
+ }
+ else if (strncasecmp(ent->name, "track", strlen("track")) == 0)
+ {
+ if (strncasecmp(ent->name, "track03.iso", strlen("track03.iso")) == 0)
+ {
+ gdi_optimized = true;
+ }
+
+ if (gdi_cdda != CCGE_CDDA)
+ {
+ if (strncasecmp(ent->name, "track06.wav", strlen("track06.wav")) == 0
+ || strncasecmp(ent->name, "track06.raw", strlen("track06.raw")) == 0)
+ {
+ gdi_cdda = CCGE_CDDA;
+ }
+ else if (strncasecmp(ent->name, "track04.wav", strlen("track04.wav")) == 0
+ || strncasecmp(ent->name, "track04.raw", strlen("track04.raw")) == 0)
+ {
+ gdi_cdda = CCGE_CANDIDATE;
+ }
+ }
+ }
+ else
+ {
+ if (ent->attr != O_DIR)
+ continue;
+
+ memset(new_folder, 0, NAME_MAX);
+ snprintf(new_folder, NAME_MAX, "%s/%s", full_path_folder, ent->name);
+ RetrieveGamesRecursive(new_folder, ent->name, level+1);
+ }
+
+ if (game[0] != '\0')
+ {
+ for (char *c = game; (*c = toupper(*c)); ++c)
+ {
+ if (*c == 'a')
+ *c = 'A'; // Maniac Vera: BUG toupper in the letter a, it does not convert it
+ }
+
+ menu_data.games_array_count++;
+ if (menu_data.games_array == NULL)
+ {
+ menu_data.games_array = (GameItemStruct *)malloc(sizeof(GameItemStruct));
+ }
+ else
+ {
+ menu_data.games_array = (GameItemStruct *)realloc(menu_data.games_array, menu_data.games_array_count * sizeof(GameItemStruct));
+ }
+
+ memset(&menu_data.games_array[menu_data.games_array_count - 1], 0, sizeof(GameItemStruct));
+
+ menu_data.games_array[menu_data.games_array_count - 1].game = (char *)malloc(strlen(game) + 1);
+ memset(menu_data.games_array[menu_data.games_array_count - 1].game, 0, strlen(game) + 1);
+ strncpy(menu_data.games_array[menu_data.games_array_count - 1].game, game, strlen(game));
+
+ if (folder)
+ {
+ char *folder_game = malloc(NAME_MAX);
+ memset(folder_game, 0, NAME_MAX);
+ strcpy(folder_game, full_path_folder + strlen(GetGamesPath(GetDeviceType(full_path_folder))) + 1);
+
+ for (char *c = folder_game; (*c = toupper(*c)); ++c)
+ {
+ if (*c == 'a')
+ *c = 'A'; // Maniac Vera: BUG toupper in the letter a, it does not convert it
+ }
+
+ menu_data.games_array[menu_data.games_array_count - 1].folder = (char *)malloc(strlen(folder_game) + 1);
+ memset(menu_data.games_array[menu_data.games_array_count - 1].folder, 0, strlen(folder_game) + 1);
+ strcpy(menu_data.games_array[menu_data.games_array_count - 1].folder, folder_game);
+
+ if (is_folder_name)
+ {
+ menu_data.games_array[menu_data.games_array_count - 1].folder_name = (char *)malloc(strlen(GetLastPart(folder_game, '/', 0)) + 1);
+ memset(menu_data.games_array[menu_data.games_array_count - 1].folder_name, 0, strlen(GetLastPart(folder_game, '/', 0)) + 1);
+ strcpy(menu_data.games_array[menu_data.games_array_count - 1].folder_name, GetLastPart(folder_game, '/', 0));
+ }
+
+ free(folder_game);
+ }
+
+ menu_data.games_array[menu_data.games_array_count - 1].is_folder_name = is_folder_name;
+ menu_data.games_array[menu_data.games_array_count - 1].exists_cover[MT_PLANE_TEXT-1] = SC_WITHOUT_SEARCHING;
+ menu_data.games_array[menu_data.games_array_count - 1].exists_cover[MT_IMAGE_TEXT_64_5X2-1] = SC_WITHOUT_SEARCHING;
+ menu_data.games_array[menu_data.games_array_count - 1].exists_cover[MT_IMAGE_128_4X3-1] = SC_WITHOUT_SEARCHING;
+ menu_data.games_array[menu_data.games_array_count - 1].check_optimized = false;
+ menu_data.games_array[menu_data.games_array_count - 1].is_cdda = CCGE_NOT_CHECKED;
+ menu_data.games_array[menu_data.games_array_count - 1].device = GetDeviceType(full_path_folder);
+
+ if (strcasecmp(file_type, ".gdi") == 0)
+ {
+ gdi_index = menu_data.games_array_count - 1;
+ }
+ else
+ {
+ menu_data.games_array[menu_data.games_array_count - 1].is_cdda = CCGE_NOT_CDDA;
+ }
+ }
+ }
+
+ if (gdi_index >= 0)
+ {
+ menu_data.games_array[gdi_index].check_optimized = menu_data.games_array[gdi_index].is_gdi_optimized = gdi_optimized;
+
+ if (gdi_cdda == CCGE_CANDIDATE || gdi_cdda == CCGE_CDDA)
+ {
+ if (gdi_cdda == CCGE_CANDIDATE)
+ {
+ size_t track_size = 0;
+ char *track_file_path = (char *)malloc(NAME_MAX);
+ const char *full_path_game = GetFullGamePathByIndex(gdi_index);
+ track_size = GetCDDATrackFilename(4, full_path_game, &track_file_path);
+ free(track_file_path);
+
+ if (track_size > 0)
+ {
+ if (track_size < 30 * 1024 * 1024)
+ {
+ gdi_cdda = CCGE_NOT_CDDA;
+ }
+ else
+ {
+ gdi_cdda = CCGE_CDDA;
+ }
+ }
+ else
+ {
+ gdi_cdda = CCGE_NOT_CDDA;
+ }
+ }
+
+ menu_data.games_array[gdi_index].is_cdda = gdi_cdda;
+ }
+ else
+ {
+ menu_data.games_array[gdi_index].is_cdda = CCGE_NOT_CDDA;
+ }
+ }
+
+ ent = NULL;
+ file_type = NULL;
+ fs_close(fd);
+}
+
+bool RetrieveGames()
+{
+#ifdef IN_CACHE_GAMES
+ if (menu_data.games_array_count > 0)
+ {
+ return true;
+ }
+#endif
+
+ FreeGames();
+ RetrieveGamesRecursive(GetGamesPath(menu_data.current_dev), NULL, 0);
+
+ if (menu_data.ide && menu_data.sd)
+ {
+ RetrieveGamesRecursive(GetGamesPath(APP_DEVICE_SD), NULL, 0);
+ }
+
+ if (menu_data.games_array_count > 0)
+ {
+ qsort(menu_data.games_array, menu_data.games_array_count, sizeof(GameItemStruct), AppCompareGames);
+
+ menu_data.rescan_covers = false;
+ if (menu_data.cover_scanned_app.games_count != menu_data.games_array_count)
+ {
+ menu_data.cover_scanned_app.games_count = menu_data.games_array_count;
+ menu_data.rescan_covers = true;
+ }
+ else if (menu_data.cover_scanned_app.games_count > 0
+ && menu_data.cover_scanned_app.last_game_index > 0
+ && menu_data.cover_scanned_app.last_game_index <= menu_data.games_array_count)
+ {
+ char *name = NULL;
+ if (GetCoverName(menu_data.cover_scanned_app.last_game_index-1, &name))
+ {
+ if (strcasecmp(menu_data.cover_scanned_app.last_game_scanned, name) != 0)
+ {
+ menu_data.rescan_covers = true;
+ }
+
+ if (name != NULL)
+ {
+ free(name);
+ }
+ }
+ }
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/applications/games_menu/modules/module.c b/applications/games_menu/modules/module.c
new file mode 100644
index 00000000..1c103413
--- /dev/null
+++ b/applications/games_menu/modules/module.c
@@ -0,0 +1,2317 @@
+/* DreamShell ##version##
+
+ module.h - Games app module
+ Copyright (C) 2024 Maniac Vera
+
+*/
+
+#include
+#include "app_menu.h"
+#include "app_system_menu.h"
+#include "app_preset.h"
+#include "app_utils.h"
+#include "app_module.h"
+#include "app_definition.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+DEFAULT_MODULE_EXPORTS(app_games_menu);
+
+extern struct menu_structure menu_data;
+static Event_t *do_menu_control_event;
+static Event_t *do_menu_video_event;
+static void* MenuExitHelper(void *params);
+static mutex_t change_page_mutex = MUTEX_INITIALIZER;
+
+static struct
+{
+ App_t *app;
+ DSApp *dsapp_ptr;
+ Scene *scene_ptr;
+
+ bool have_args;
+ int image_type;
+ int sector_size;
+ uint8 md5[16];
+ uint8 boot_sector[2048];
+ uint32 addr;
+ isoldr_info_t *isoldr;
+
+ bool exit_app, wait_to_exit_app;
+ bool first_menu_load;
+ volatile bool game_changed;
+ volatile bool show_cover_game;
+ uint32 scan_covers_start_time;
+ uint32 scan_covers_end_time;
+ int pages;
+ int current_page;
+ int previous_page;
+ int game_count;
+ int menu_cursel;
+ int scan_count;
+ uint8 device_selected;
+
+ int game_index_selected;
+ char item_value_selected[NAME_MAX];
+
+ LogXYMover *item_selector_animation;
+ Rectangle *item_selector;
+ Font *menu_font;
+ Font *message_font;
+ Death *exit_trigger_list[MAX_SIZE_ITEMS];
+ LogXYMover *run_animation;
+ ExpXYMover *exit_animation_list[MAX_SIZE_ITEMS];
+ LogXYMover *item_game_animation[MAX_SIZE_ITEMS];
+ ItemMenu *item_game[MAX_SIZE_ITEMS];
+ ItemMenu *item_button[MAX_BUTTONS];
+ Banner *img_cover_game_background;
+ Banner *img_cover_game;
+ FadeTo *animation_cover_game;
+ FadeOut *fadeout_cover_animation;
+ Texture *texture_cover_game_background;
+ Texture *texture_cover_game;
+ Label *title, *title_back;
+ Label *title_type;
+ LogXYMover *title_animation;
+ LogXYMover *title_back_animation;
+ LogXYMover *title_type_animation;
+ Box *main_box;
+ Rectangle *title_rectangle;
+ Rectangle *title_type_rectangle;
+ Rectangle *game_list_rectangle;
+ Rectangle *img_cover_game_rectangle;
+
+ kthread_t *show_cover_thread;
+} self;
+
+
+static void* ShowCoverThread(void *params)
+{
+ int game_index = (int)params;
+ if (game_index >= 0)
+ {
+ srand(time(NULL));
+ uint time_elapsed = 0;
+ if (self.img_cover_game != NULL)
+ {
+ self.show_cover_game = false;
+ if (self.animation_cover_game != NULL)
+ {
+ TSU_AnimationComplete((Animation *)self.animation_cover_game, (Drawable *)self.img_cover_game);
+ thd_pass();
+ TSU_FadeToDestroy(&self.animation_cover_game);
+ }
+
+ if (self.fadeout_cover_animation == NULL)
+ {
+ self.fadeout_cover_animation = TSU_FadeOutCreate(10.0f);
+ TSU_DrawableAnimAdd((Drawable *)self.img_cover_game, (Animation *)self.fadeout_cover_animation);
+ }
+
+ const uint max_time = 200;
+ while (!self.game_changed && menu_data.menu_type == MT_PLANE_TEXT && time_elapsed < max_time)
+ {
+ thd_sleep(50);
+ time_elapsed += 50;
+ }
+
+ if (self.game_changed || menu_data.menu_type != MT_PLANE_TEXT)
+ return NULL;
+
+ TSU_AnimationComplete((Animation *)self.fadeout_cover_animation, (Drawable *)self.img_cover_game);
+ thd_pass();
+ TSU_FadeOutDestroy(&self.fadeout_cover_animation);
+
+ TSU_DrawableSetFinished((Drawable *)self.img_cover_game);
+ TSU_AppSubRemoveBanner(self.dsapp_ptr, self.img_cover_game);
+
+ thd_pass();
+ TSU_BannerDestroy(&self.img_cover_game);
+ TSU_TextureDestroy(&self.texture_cover_game);
+ }
+
+ const uint max_time = 400;
+ while (!self.game_changed && menu_data.menu_type == MT_PLANE_TEXT && time_elapsed < max_time)
+ {
+ thd_sleep(50);
+ time_elapsed += 50;
+ }
+
+ if (self.game_changed || menu_data.menu_type != MT_PLANE_TEXT)
+ return NULL;
+
+ uint16 checked_cover = CheckCover(game_index, MT_PLANE_TEXT);
+ if (checked_cover == SC_EXISTS || checked_cover == SC_DEFAULT)
+ {
+ self.show_cover_game = true;
+
+ Vector vector_position = {490, 180, ML_ITEM + 2, 1};
+ char *game_cover_path = NULL;
+ uint16 cover_type = GetCoverType(game_index, MT_PLANE_TEXT);
+
+ if (checked_cover == SC_EXISTS)
+ {
+ GetGameCoverPath(game_index, &game_cover_path, MT_PLANE_TEXT);
+ }
+ else
+ {
+ game_cover_path = (char *)malloc(NAME_MAX);
+ snprintf(game_cover_path, NAME_MAX, "%s/%s", GetDefaultDir(menu_data.current_dev), "apps/games_menu/images/no_cover.png");
+ cover_type = IT_PNG;
+ }
+
+ self.texture_cover_game = TSU_TextureCreateFromFile(game_cover_path, cover_type != IT_JPG, false, 0);
+ self.img_cover_game = TSU_BannerCreate(cover_type == IT_JPG ? PVR_LIST_OP_POLY : PVR_LIST_TR_POLY, self.texture_cover_game);
+ free(game_cover_path);
+
+ TSU_DrawableTranslate((Drawable *)self.img_cover_game, &vector_position);
+ TSU_BannerSetSize(self.img_cover_game, 256, 256);
+
+ vector_position.x = 0.0f;
+ vector_position.y = 0.0f;
+ TSU_DrawableSetScale((Drawable *)self.img_cover_game, &vector_position);
+
+ TSU_AppSubAddBanner(self.dsapp_ptr, self.img_cover_game);
+ self.animation_cover_game = TSU_FadeToCreate(0.0f, 1.0f, 7.5f);
+ TSU_DrawableAnimAdd((Drawable *)self.img_cover_game, (Animation *)self.animation_cover_game);
+
+ self.show_cover_game = false;
+ }
+ }
+
+ return NULL;
+}
+
+static bool StopShowCover()
+{
+ if (self.show_cover_thread != NULL)
+ {
+ thd_join(self.show_cover_thread, NULL);
+ self.show_cover_thread = NULL;
+ }
+
+ return (self.show_cover_thread == NULL);
+}
+
+static void ShowCover(int game_index)
+{
+ if (menu_data.menu_type == MT_PLANE_TEXT && game_index >= 0)
+ {
+ if (StopShowCover())
+ {
+ self.show_cover_thread = thd_create(0, ShowCoverThread, (void *)game_index);
+ thd_set_prio(self.show_cover_thread, PRIO_DEFAULT - 2);
+ }
+ }
+}
+
+static bool LoadCover(ItemMenu *item_menu, int game_count)
+{
+ bool loaded_cover = false;
+
+ if (item_menu != NULL)
+ {
+ int game_index = TSU_ItemMenuGetItemIndex(item_menu);
+
+ if (menu_data.menu_type == MT_PLANE_TEXT)
+ {
+ if (self.menu_cursel == game_count)
+ {
+ ShowCover(game_index);
+ loaded_cover = true;
+ }
+ }
+ else
+ {
+ char *game_cover_path = NULL;
+ if (GetGameCoverPath(game_index, &game_cover_path, menu_data.menu_type))
+ {
+ TSU_ItemMenuSetImage(item_menu, game_cover_path, ContainsCoverType(game_index, menu_data.menu_type, IT_JPG) ? PVR_LIST_OP_POLY : PVR_LIST_TR_POLY);
+ loaded_cover = true;
+ free(game_cover_path);
+ }
+ }
+ }
+
+ return loaded_cover;
+}
+
+static void SetTitle(int game_index, const char *text)
+{
+ char titleText[101];
+ memset(titleText, 0, sizeof(titleText));
+
+ if (menu_data.ide && menu_data.sd && game_index >= 0)
+ {
+ switch (menu_data.games_array[game_index].device)
+ {
+ case APP_DEVICE_IDE:
+ strncpy(titleText, "IDE: ", sizeof("IDE: "));
+ break;
+
+ case APP_DEVICE_SD:
+ strncpy(titleText, "SD: ", sizeof("SD: "));
+ break;
+ }
+ }
+
+ if (strlen(text) > sizeof(titleText) - 6)
+ {
+ strncpy(&titleText[strlen(titleText)], text, sizeof(titleText) - 6);
+ }
+ else
+ {
+ strcpy(&titleText[strlen(titleText)], text);
+ }
+
+ static Vector vectorInit = {-50, 32, ML_ITEM, 1};
+ static Vector vector = {10, 32, ML_ITEM, 1};
+ vectorInit.z = ML_ITEM + 1;
+ vector.z = ML_ITEM + 1;
+
+ if(vid_check_cable() != CT_VGA)
+ {
+ vectorInit.y = 40;
+
+ vector.x = 14;
+ vector.y = 40;
+ }
+
+ if (self.title != NULL)
+ {
+ TSU_LabelSetText(self.title_back, titleText);
+ TSU_LabelSetText(self.title, titleText);
+ }
+ else
+ {
+ int font_size = 20;
+ Color color = {1, 1.0f, 1.0f, 1.0f};
+
+ self.title = TSU_LabelCreate(self.menu_font, titleText, font_size, false, false);
+ TSU_LabelSetTint(self.title, &color);
+ TSU_AppSubAddLabel(self.dsapp_ptr, self.title);
+
+ Color color_back = {1, 0.0f, 0.0f, 0.0f};
+ self.title_back = TSU_LabelCreate(self.menu_font, titleText, font_size, false, false);
+ TSU_LabelSetTint(self.title_back, &color_back);
+ TSU_AppSubAddLabel(self.dsapp_ptr, self.title_back);
+ }
+
+ if (self.title_animation != NULL)
+ {
+ TSU_AnimationComplete((Animation *)self.title_animation, (Drawable *)self.title);
+ TSU_LogXYMoverDestroy(&self.title_animation);
+
+ TSU_AnimationComplete((Animation *)self.title_back_animation, (Drawable *)self.title_back);
+ TSU_LogXYMoverDestroy(&self.title_back_animation);
+ }
+
+ TSU_LabelSetTranslate(self.title, &vectorInit);
+ self.title_animation = TSU_LogXYMoverCreate(vector.x, vector.y);
+ TSU_DrawableAnimAdd((Drawable *)self.title, (Animation *)self.title_animation);
+
+ vectorInit.z = ML_ITEM;
+ TSU_LabelSetTranslate(self.title_back, &vectorInit);
+ self.title_back_animation = TSU_LogXYMoverCreate(vector.x, vector.y);
+ TSU_DrawableAnimAdd((Drawable *)self.title_back, (Animation *)self.title_back_animation);
+}
+
+static void SetTitleType(const char *full_path_game, bool is_gdi_optimized)
+{
+ if (full_path_game != NULL)
+ {
+ Color title_type_color = {1, 1.0f, 0.95f, 0.0f};
+ char *file_type = strrchr(full_path_game, '.');
+
+ char title_text[4];
+ memset(title_text, 0, sizeof(title_text));
+
+ if (is_gdi_optimized)
+ {
+ strncpy(title_text, "GDI", 3);
+ }
+ else if (strcasecmp(file_type, ".cdi") == 0)
+ {
+ strncpy(title_text, "CDI", 3);
+ }
+ else if (strcasecmp(file_type, ".iso") == 0)
+ {
+ strncpy(title_text, "ISO", 3);
+ }
+ else if (strcasecmp(file_type, ".cso") == 0)
+ {
+ strncpy(title_text, "CSO", 3);
+ }
+ else if (strcasecmp(file_type, ".gdi") == 0)
+ {
+ strncpy(title_text, "GDI", 3);
+
+ title_type_color.r = 1.0f;
+ title_type_color.g = 0.54f;
+ title_type_color.b = 0.0f;
+ }
+
+ TSU_DrawableSetTint((Drawable *)self.title_type_rectangle, &title_type_color);
+
+ static Vector vectorInit = {700, 32, ML_ITEM + 6, 1};
+ static Vector vector = {592, 32, ML_ITEM + 6, 1};
+
+ vectorInit.z = ML_ITEM + 6;
+
+ if(vid_check_cable() != CT_VGA)
+ {
+ vectorInit.y = 40;
+
+ vector.x = 592;
+ vector.y = 40;
+ }
+
+ if (self.title_type != NULL)
+ {
+ TSU_LabelSetText(self.title_type, title_text);
+ }
+ else
+ {
+ int font_size = 20;
+
+ static Color color = {1, 1.0f, 1.0f, 1.0f};
+ self.title_type = TSU_LabelCreate(self.menu_font, title_text, font_size, false, true);
+ TSU_LabelSetTint(self.title_type, &color);
+ TSU_AppSubAddLabel(self.dsapp_ptr, self.title_type);
+ }
+
+ if (self.title_type_animation != NULL)
+ {
+ TSU_AnimationComplete((Animation *)self.title_type_animation, (Drawable *)self.title_type);
+ TSU_LogXYMoverDestroy(&self.title_type_animation);
+ }
+
+ TSU_LabelSetTranslate(self.title_type, &vectorInit);
+ self.title_type_animation = TSU_LogXYMoverCreate(vector.x, vector.y);
+ TSU_DrawableAnimAdd((Drawable *)self.title_type, (Animation *)self.title_type_animation);
+ }
+}
+
+static void SetCursor()
+{
+ static Vector selector_translate = {0, 0, ML_CURSOR, 1};
+
+ if (self.item_selector_animation != NULL)
+ {
+ TSU_AnimationComplete((Animation *)self.item_selector_animation, (Drawable *)self.item_selector);
+ TSU_LogXYMoverDestroy(&self.item_selector_animation);
+ }
+
+ if (self.item_selector != NULL)
+ {
+ TSU_AppSubRemoveRectangle(self.dsapp_ptr, self.item_selector);
+ TSU_RectangleDestroy(&self.item_selector);
+ }
+
+ if (self.item_selector == NULL)
+ {
+ if (menu_data.menu_type == MT_IMAGE_TEXT_64_5X2)
+ {
+ Color color = {0, 0.0f, 0.0f, 0.0f};
+ Color border_color = {1, 1.0f, 1.0f, 0.1f};
+
+ self.item_selector = TSU_RectangleCreateWithBorder(PVR_LIST_TR_POLY, 0, 0, 0, 0, &color, ML_CURSOR, 3, &border_color, 0);
+ TSU_DrawableSetTint((Drawable *)self.item_selector, &color);
+ }
+ else if (menu_data.menu_type == MT_IMAGE_128_4X3)
+ {
+ Color color = {0, 0.0f, 0.0f, 0.0f};
+ Color border_color = {1, 1.0f, 1.0f, 0.1f};
+
+ self.item_selector = TSU_RectangleCreateWithBorder(PVR_LIST_TR_POLY, 0, 0, 0, 0, &color, ML_CURSOR, 6, &border_color, 0);
+ TSU_DrawableSetTint((Drawable *)self.item_selector, &color);
+ }
+ else if (menu_data.menu_type == MT_PLANE_TEXT)
+ {
+ Color color = {0.8f, 0.0f, 0.0f, 0.0f};
+ Color border_color = {1, 1.0f, 1.0f, 0.1f};
+
+ self.item_selector = TSU_RectangleCreateWithBorder(PVR_LIST_TR_POLY, 0, 0, 0, 0, &color, ML_CURSOR, 2, &border_color, 0);
+ TSU_DrawableSetTint((Drawable *)self.item_selector, &color);
+ }
+ else
+ {
+ Color color = {0, 0.0f, 0.0f, 0.0f};
+ Color border_color = {1, 1.0f, 1.0f, 0.1f};
+
+ self.item_selector = TSU_RectangleCreateWithBorder(PVR_LIST_TR_POLY, 0, 0, 0, 0, &color, ML_CURSOR, 4, &border_color, 0);
+ TSU_DrawableSetTint((Drawable *)self.item_selector, &color);
+ }
+
+ if (selector_translate.x > 0 && selector_translate.y > 0)
+ {
+ TSU_DrawableSetTranslate((Drawable *)self.item_selector, &selector_translate);
+ }
+
+ TSU_AppSubAddRectangle(self.dsapp_ptr, self.item_selector);
+ }
+
+ static int init_position_x;
+ static int init_position_y;
+
+ if (menu_data.menu_type == MT_IMAGE_TEXT_64_5X2)
+ {
+ TSU_RectangleSetSize(self.item_selector, 310, menu_data.menu_option.image_size + 8);
+ init_position_x = 5;
+ init_position_y = 34;
+ selector_translate.z = ML_CURSOR;
+ }
+ else if (menu_data.menu_type == MT_IMAGE_128_4X3)
+ {
+ TSU_RectangleSetSize(self.item_selector, menu_data.menu_option.image_size + 4, menu_data.menu_option.image_size + 4);
+ init_position_x = 9;
+ init_position_y = 41;
+ selector_translate.z = ML_CURSOR;
+ }
+ else if (menu_data.menu_type == MT_PLANE_TEXT)
+ {
+ TSU_RectangleSetSize(self.item_selector, 329, 30);
+ init_position_x = 18;
+ init_position_y = 52;
+ selector_translate.z = ML_SELECTED - 1;
+ }
+ else
+ {
+ TSU_RectangleSetSize(self.item_selector, menu_data.menu_option.image_size + 4, menu_data.menu_option.image_size + 4);
+ init_position_x = 8;
+ init_position_y = 40;
+ selector_translate.z = ML_CURSOR;
+ }
+
+ TSU_DrawableSetTranslate((Drawable *)self.item_selector, &selector_translate);
+ selector_translate.x = self.menu_cursel / menu_data.menu_option.size_items_column * menu_data.menu_option.padding_x + init_position_x;
+ selector_translate.y = ((self.menu_cursel + 1) - menu_data.menu_option.size_items_column * (self.menu_cursel / menu_data.menu_option.size_items_column)) * (menu_data.menu_option.padding_y + menu_data.menu_option.image_size) + init_position_y;
+
+ self.item_selector_animation = TSU_LogXYMoverCreate(selector_translate.x, selector_translate.y);
+ TSU_DrawableAnimAdd((Drawable *)self.item_selector, (Animation *)self.item_selector_animation);
+}
+
+static void RemoveViewTextPlane()
+{
+ self.show_cover_game = false;
+
+ if (self.img_cover_game_background != NULL)
+ {
+ TSU_DrawableSetFinished((Drawable *)self.img_cover_game_background);
+ }
+
+ if (self.img_cover_game_rectangle != NULL)
+ {
+ TSU_DrawableSetFinished((Drawable *)self.img_cover_game_rectangle);
+ }
+
+ for (int i = 0; i < MAX_BUTTONS; i++)
+ {
+ if (self.item_button[i] != NULL)
+ {
+ TSU_DrawableSetFinished((Drawable *)self.item_button[i]);
+ }
+ }
+
+ if (self.img_cover_game != NULL)
+ {
+ if (self.animation_cover_game != NULL)
+ {
+ TSU_AnimationComplete((Animation *)self.animation_cover_game, (Drawable *)self.img_cover_game);
+ }
+
+ if (self.fadeout_cover_animation != NULL)
+ {
+ TSU_AnimationComplete((Animation *)self.fadeout_cover_animation, (Drawable *)self.img_cover_game);
+ }
+
+ TSU_DrawableSetFinished((Drawable *)self.img_cover_game);
+ }
+
+ if (self.game_list_rectangle != NULL)
+ {
+ TSU_DrawableSetFinished((Drawable *)self.game_list_rectangle);
+ }
+
+ TSU_DrawableSubRemoveFinished((Drawable *)self.scene_ptr);
+ thd_pass();
+
+ if (self.img_cover_game_background != NULL)
+ {
+ TSU_BannerDestroy(&self.img_cover_game_background);
+ TSU_TextureDestroy(&self.texture_cover_game_background);
+ }
+
+ if (self.img_cover_game_rectangle != NULL)
+ {
+ TSU_RectangleDestroy(&self.img_cover_game_rectangle);
+ }
+
+ for (int i = 0; i < MAX_BUTTONS; i++)
+ {
+ if (self.item_button[i] != NULL)
+ {
+ TSU_ItemMenuDestroy(&self.item_button[i]);
+ }
+ }
+
+ if (self.img_cover_game != NULL)
+ {
+ if (self.animation_cover_game != NULL)
+ {
+ TSU_FadeToDestroy(&self.animation_cover_game);
+ }
+
+ if (self.fadeout_cover_animation != NULL)
+ {
+ TSU_FadeOutDestroy(&self.fadeout_cover_animation);
+ }
+
+ TSU_BannerDestroy(&self.img_cover_game);
+ TSU_TextureDestroy(&self.texture_cover_game);
+ }
+
+ if (self.game_list_rectangle != NULL)
+ {
+ TSU_RectangleDestroy(&self.game_list_rectangle);
+ }
+}
+
+static void CreateInfoButton(uint8 button_index, const char *button_file, const char *text, float x, float y)
+{
+ if(self.item_button[button_index] == NULL)
+ {
+ char *image_path = (char *)malloc(NAME_MAX);
+ snprintf(image_path, NAME_MAX, "%s/%s/%s", GetDefaultDir(menu_data.current_dev), "apps/games_menu/images", button_file);
+
+ if (FileExists(image_path))
+ {
+ Vector vector_translate = { x, y, ML_ITEM + 3, 1};
+ self.item_button[button_index] = TSU_ItemMenuCreate(image_path, 32, 32, PVR_LIST_TR_POLY, text, self.menu_font, 14, false, 0);
+ TSU_ItemMenuSetTranslate(self.item_button[button_index], &vector_translate);
+ }
+
+ free(image_path);
+ }
+}
+
+static void AddInfoButtons()
+{
+ for (int i = 0; i < MAX_BUTTONS; i++)
+ {
+ if (self.item_button[i] != NULL)
+ {
+ TSU_AppSubAddItemMenu(self.dsapp_ptr, self.item_button[i]);
+ }
+ }
+}
+
+static void CreateViewTextPlane()
+{
+ CreateInfoButton(0, "btn_x.png", "CHANGE VIEW", 359, 315);
+ CreateInfoButton(1, "btn_y.png", "SETTINGS", 512, 315);
+ CreateInfoButton(2, "btn_a.png", "PLAY", 359, 315 + (32 * 1) + (5 * 1));
+ CreateInfoButton(3, "btn_b.png", "EXIT", 512, 315 + (32 * 1) + (5 * 1));
+ CreateInfoButton(4, "btn_lt.png", "PREVIOUS", 359, 315 + (32 * 2) + (5 * 2));
+ CreateInfoButton(5, "btn_rt.png", "NEXT", 512, 315 + (32 * 2) + (5 * 2));
+ CreateInfoButton(6, "btn_start.png", "SYSTEM MENU", 359, 315 + (32 * 3) + (5 * 3));
+ AddInfoButtons();
+
+ if (self.game_list_rectangle == NULL)
+ {
+ Color border_color = {1, 1.0f, 1.0f, 1.0f};
+ Color background_color = {1, 0.22f, 0.06f, 0.25f};
+ self.game_list_rectangle = TSU_RectangleCreateWithBorder(PVR_LIST_OP_POLY, 15, 460, 335, 405, &background_color, ML_ITEM, 3, &border_color, 0);
+
+ TSU_AppSubAddRectangle(self.dsapp_ptr, self.game_list_rectangle);
+ }
+
+ if (self.img_cover_game_background == NULL && menu_data.cover_background)
+ {
+ char *game_cover_path = (char *)malloc(NAME_MAX);
+ snprintf(game_cover_path, NAME_MAX, "%s/%s", GetDefaultDir(menu_data.current_dev), "apps/games_menu/images/cover.png");
+
+ if (FileExists(game_cover_path))
+ {
+ self.texture_cover_game_background = TSU_TextureCreateFromFile(game_cover_path, true, false, 0);
+ self.img_cover_game_background = TSU_BannerCreate(PVR_LIST_TR_POLY, self.texture_cover_game_background);
+
+ Vector vector_position = {490, 180, ML_ITEM + 3, 1};
+ TSU_DrawableTranslate((Drawable *)self.img_cover_game_background, &vector_position);
+ TSU_BannerSetSize(self.img_cover_game_background, 256, 256);
+ TSU_AppSubAddBanner(self.dsapp_ptr, self.img_cover_game_background);
+
+ Color background_color = {1, 0.88f, 0.88f, 0.88f};
+ self.img_cover_game_rectangle = TSU_RectangleCreate(PVR_LIST_OP_POLY, vector_position.x - 128, vector_position.y + 128, 256, 256, &background_color, ML_ITEM + 1, 0);
+ TSU_AppSubAddRectangle(self.dsapp_ptr, self.img_cover_game_rectangle);
+ }
+
+ free(game_cover_path);
+ }
+}
+
+static bool LoadPage(bool change_view, uint8 direction)
+{
+ const int LENGTH_NAME_TEXT_PLANE = 26;
+ const int LENGTH_NAME_TEXT_64_5X2 = 19;
+ bool loaded = false;
+ char name_truncated[LENGTH_NAME_TEXT_PLANE];
+ char game_cover_path[NAME_MAX];
+ char name[NAME_MAX];
+ char *game_cover_path_tmp = NULL;
+
+ if (self.pages == -1)
+ {
+ for (int imenu = 1; imenu <= MAX_MENU; imenu++)
+ {
+ RetrieveCovers(menu_data.current_dev, imenu);
+ }
+
+ if (RetrieveGames())
+ {
+ timer_ms_gettime(&self.scan_covers_start_time, NULL);
+ self.pages = (menu_data.games_array_count > 0 ? ceil((float)menu_data.games_array_count / (float)menu_data.menu_option.max_page_size) : 0);
+ }
+ }
+ else
+ {
+ if (change_view)
+ {
+ self.pages = (menu_data.games_array_count > 0 ? ceil((float)menu_data.games_array_count / (float)menu_data.menu_option.max_page_size) : 0);
+ }
+ }
+
+ if (self.pages > 0)
+ {
+ if (self.current_page < 1)
+ {
+ self.current_page = self.pages;
+ }
+ else if (self.current_page > self.pages)
+ {
+ self.current_page = 1;
+ }
+
+ if (self.current_page != self.previous_page || change_view)
+ {
+ self.previous_page = self.current_page;
+
+ for (int i = 0; i < MAX_SIZE_ITEMS; i++)
+ {
+ if (self.item_game_animation[i] != NULL)
+ {
+ TSU_AnimationComplete((Animation *)self.item_game_animation[i], (Drawable *)self.item_game[i]);
+ }
+
+ if (self.item_game[i] != NULL)
+ {
+ TSU_DrawableSetFinished((Drawable *)self.item_game[i]);
+ }
+ }
+
+ TSU_DrawableSubRemoveFinished((Drawable *)self.scene_ptr);
+ thd_pass();
+
+ for (int i = 0; i < MAX_SIZE_ITEMS; i++)
+ {
+ if (self.item_game_animation[i] != NULL)
+ {
+ TSU_LogXYMoverDestroy(&self.item_game_animation[i]);
+ }
+
+ if (self.item_game[i] != NULL)
+ {
+ TSU_ItemMenuDestroy(&self.item_game[i]);
+ }
+ }
+
+ if (change_view || self.first_menu_load)
+ {
+ if (menu_data.menu_type == MT_PLANE_TEXT)
+ {
+ CreateViewTextPlane();
+ }
+ else
+ {
+ RemoveViewTextPlane();
+ }
+ }
+
+ int cover_menu_type = 0;
+ int column = 0;
+ int page = 0;
+ self.game_count = 0;
+ Vector vectorTranslate = {0, 480, ML_ITEM, 1};
+
+ for (int icount = ((self.current_page - 1) * menu_data.menu_option.max_page_size); icount < menu_data.games_array_count; icount++)
+ {
+ page = ceil((float)(icount + 1) / (float)menu_data.menu_option.max_page_size);
+
+ if (page < self.current_page)
+ continue;
+ else if (page > self.current_page)
+ break;
+
+ self.game_count++;
+
+ column = floor((float)(self.game_count - 1) / (float)menu_data.menu_option.size_items_column);
+
+ if (menu_data.menu_type != MT_PLANE_TEXT)
+ {
+ game_cover_path_tmp = NULL;
+ if (CheckCover(icount, menu_data.menu_type) == SC_EXISTS)
+ {
+ cover_menu_type = menu_data.menu_type;
+ }
+ else
+ {
+ CheckCover(icount, MT_PLANE_TEXT);
+ cover_menu_type = MT_PLANE_TEXT;
+ }
+
+ if (GetGameCoverPath(icount, &game_cover_path_tmp, cover_menu_type))
+ {
+ strcpy(game_cover_path, game_cover_path_tmp);
+ free(game_cover_path_tmp);
+ }
+ }
+
+ memset(name, 0, sizeof(name));
+ if (menu_data.games_array[icount].is_folder_name)
+ {
+ strcpy(name, menu_data.games_array[icount].folder_name);
+ }
+ else
+ {
+ strncpy(name, menu_data.games_array[icount].game, strlen(menu_data.games_array[icount].game) - 4);
+ }
+
+ if (menu_data.menu_type == MT_IMAGE_TEXT_64_5X2)
+ {
+ memset(name_truncated, 0, LENGTH_NAME_TEXT_PLANE);
+ if (strlen(name) > LENGTH_NAME_TEXT_64_5X2 - 1)
+ {
+ strncpy(name_truncated, name, LENGTH_NAME_TEXT_64_5X2 - 1);
+ }
+ else
+ {
+ strcpy(name_truncated, name);
+ }
+
+ self.item_game[self.game_count - 1] = TSU_ItemMenuCreate(game_cover_path, menu_data.menu_option.image_size, menu_data.menu_option.image_size
+ , ContainsCoverType(icount, cover_menu_type, IT_JPG) ? PVR_LIST_OP_POLY : PVR_LIST_TR_POLY
+ , name_truncated, self.menu_font, 18, false, 0);
+
+ }
+ else if (menu_data.menu_type == MT_PLANE_TEXT)
+ {
+ memset(name_truncated, 0, LENGTH_NAME_TEXT_PLANE);
+ if (strlen(name) > LENGTH_NAME_TEXT_PLANE - 1)
+ {
+ strncpy(name_truncated, name, LENGTH_NAME_TEXT_PLANE - 1);
+ }
+ else
+ {
+ strcpy(name_truncated, name);
+ }
+
+ self.item_game[self.game_count - 1] = TSU_ItemMenuCreateLabel(name_truncated, self.menu_font, 18);
+ Color color_unselected = { 1, 0.95f, 0.95f, 0.95f };
+ TSU_ItemMenuSetColorUnselected(self.item_game[self.game_count - 1], &color_unselected);
+ }
+ else
+ {
+ self.item_game[self.game_count - 1] = TSU_ItemMenuCreateImage(game_cover_path
+ , menu_data.menu_option.image_size
+ , menu_data.menu_option.image_size
+ , ContainsCoverType(icount, cover_menu_type, IT_JPG) ? PVR_LIST_OP_POLY : PVR_LIST_TR_POLY
+ , false
+ , PVR_TXRLOAD_SQ);
+ }
+
+ ItemMenu *item_menu = self.item_game[self.game_count - 1];
+
+ TSU_ItemMenuSetItemIndex(item_menu, icount);
+ TSU_ItemMenuSetItemValue(item_menu, name);
+
+ if (menu_data.menu_type == MT_PLANE_TEXT)
+ {
+ switch (direction)
+ {
+ case DMD_UP:
+ case DMD_LEFT:
+ vectorTranslate.x = 50;
+ vectorTranslate.y = (menu_data.menu_option.image_size + menu_data.menu_option.padding_y) * (self.game_count - menu_data.menu_option.size_items_column * column) + menu_data.menu_option.init_position_y;
+ break;
+
+ case DMD_DOWN:
+ case DMD_RIGHT:
+ vectorTranslate.x = -50;
+ vectorTranslate.y = (menu_data.menu_option.image_size + menu_data.menu_option.padding_y) * (self.game_count - menu_data.menu_option.size_items_column * column) + menu_data.menu_option.init_position_y;
+ break;
+
+ default:
+ vectorTranslate.x = 50;
+ break;
+ }
+
+ TSU_ItemMenuSetTranslate(item_menu, &vectorTranslate);
+ }
+ else
+ {
+ TSU_ItemMenuSetTranslate(item_menu, &vectorTranslate);
+ }
+
+ self.item_game_animation[self.game_count - 1] = TSU_LogXYMoverCreate(menu_data.menu_option.init_position_x + (column * menu_data.menu_option.padding_x),
+ (menu_data.menu_option.image_size + menu_data.menu_option.padding_y) * (self.game_count - menu_data.menu_option.size_items_column * column) + menu_data.menu_option.init_position_y);
+
+ if (menu_data.menu_type != MT_PLANE_TEXT)
+ {
+ if (menu_data.menu_type == MT_IMAGE_TEXT_64_5X2)
+ {
+ TSU_LogXYMoverSetFactor(self.item_game_animation[self.game_count - 1], 6.5f);
+ }
+ else
+ {
+ TSU_LogXYMoverSetFactor(self.item_game_animation[self.game_count - 1], 6.0f);
+ }
+ }
+
+ TSU_ItemMenuAnimAdd(item_menu, (Animation *)self.item_game_animation[self.game_count - 1]);
+
+ if (self.first_menu_load)
+ {
+ if (self.game_count == 1)
+ {
+ TSU_ItemMenuSetSelected(item_menu, true, false);
+ SetTitle(TSU_ItemMenuGetItemIndex(item_menu), name);
+ SetTitleType(GetFullGamePathByIndex(TSU_ItemMenuGetItemIndex(item_menu))
+ , CheckGdiOptimized(TSU_ItemMenuGetItemIndex(item_menu)));
+
+ SetCursor();
+ ShowCover(TSU_ItemMenuGetItemIndex(item_menu));
+ PlayCDDA(TSU_ItemMenuGetItemIndex(item_menu));
+ }
+ else
+ {
+ TSU_ItemMenuSetSelected(item_menu, false, false);
+ }
+ }
+
+ TSU_AppSubAddItemMenu(self.dsapp_ptr, item_menu);
+ }
+
+ loaded = true;
+ self.first_menu_load = false;
+ FreeGames();
+ }
+ }
+ else
+ {
+ static bool draw_message = true;
+ if (draw_message)
+ {
+ draw_message = false;
+ memset(game_cover_path, 0, sizeof(game_cover_path));
+
+ char font_path[NAME_MAX];
+ memset(font_path, 0, sizeof(font_path));
+ snprintf(font_path, sizeof(font_path), "%s/%s", GetDefaultDir(menu_data.current_dev), "apps/games_menu/fonts/message.txf");
+
+ TSU_LabelDestroy(&self.title);
+ TSU_FontDestroy(&self.menu_font);
+ self.menu_font = TSU_FontCreate(font_path, PVR_LIST_TR_POLY);
+
+ snprintf(game_cover_path, sizeof(game_cover_path), "You need put the games here:\n\n%s\n\n\n\nand images here:\n\n%s", GetGamesPath(menu_data.current_dev), GetCoversPath(menu_data.current_dev));
+ ds_printf(game_cover_path);
+ SetTitle(-1, game_cover_path);
+ }
+ }
+
+ return loaded;
+}
+
+static void InitMenu()
+{
+ menu_data.state_app = SA_GAMES_MENU;
+ self.scene_ptr = TSU_AppGetScene(self.dsapp_ptr);
+
+ char font_path[NAME_MAX];
+ memset(font_path, 0, sizeof(font_path));
+ snprintf(font_path, sizeof(font_path), "%s/%s", GetDefaultDir(menu_data.current_dev), "apps/games_menu/fonts/default.txf");
+ self.menu_font = TSU_FontCreate(font_path, PVR_LIST_TR_POLY);
+
+ memset(font_path, 0, sizeof(font_path));
+ snprintf(font_path, sizeof(font_path), "%s/%s", GetDefaultDir(menu_data.current_dev), "apps/games_menu/fonts/message.txf");
+ self.message_font = TSU_FontCreate(font_path, PVR_LIST_TR_POLY);
+
+ SetMenuType(menu_data.menu_type);
+ self.exit_app = false;
+ self.title = NULL;
+ self.title_type = NULL;
+ self.title_back = NULL;
+ self.game_index_selected = -1;
+
+ Vector vector = {0, 0, 10, 1};
+ TSU_AppSetTranslate(self.dsapp_ptr, &vector);
+
+ if (LoadScannedCover())
+ {
+ CleanIncompleteCover();
+ }
+ else
+ {
+ memset(&menu_data.cover_scanned_app, 0, sizeof(CoverScannedStruct));
+ }
+
+ self.current_page = 1;
+ LoadPage(false, DMD_NONE);
+
+ self.menu_cursel = 0;
+}
+
+static void RemoveAll()
+{
+ TSU_AnimationComplete((Animation *)self.title_animation, (Drawable *)self.title);
+ TSU_AnimationComplete((Animation *)self.title_back_animation, (Drawable *)self.title_back);
+ TSU_AnimationComplete((Animation *)self.title_type_animation, (Drawable *)self.title_type);
+ TSU_AnimationComplete((Animation *)self.item_selector_animation, (Drawable *)self.item_selector);
+
+ if (self.animation_cover_game != NULL && self.img_cover_game != NULL)
+ {
+ TSU_AnimationComplete((Animation *)self.animation_cover_game, (Drawable *)self.img_cover_game);
+ }
+
+
+ TSU_DrawableSetFinished((Drawable *)self.main_box);
+ TSU_DrawableSetFinished((Drawable *)self.title_rectangle);
+ TSU_DrawableSetFinished((Drawable *)self.title_type_rectangle);
+ TSU_DrawableSetFinished((Drawable *)self.game_list_rectangle);
+ TSU_DrawableSetFinished((Drawable *)self.item_selector);
+ TSU_DrawableSetFinished((Drawable *)self.title);
+ TSU_DrawableSetFinished((Drawable *)self.title_type);
+ TSU_DrawableSetFinished((Drawable *)self.title_back);
+
+ if (self.img_cover_game != NULL)
+ {
+ TSU_DrawableSetFinished((Drawable *)self.img_cover_game);
+ }
+
+ if (self.img_cover_game_background != NULL)
+ {
+ TSU_DrawableSetFinished((Drawable *)self.img_cover_game_background);
+ }
+
+ if (self.img_cover_game_rectangle != NULL)
+ {
+ TSU_DrawableSetFinished((Drawable *)self.img_cover_game_rectangle);
+ }
+
+ for (int i = 0; i < MAX_BUTTONS; i++)
+ {
+ if (self.item_button[i] != NULL)
+ {
+ TSU_DrawableSetFinished((Drawable *)self.item_button[i]);
+ }
+ }
+
+ for (int i = 0; i < MAX_SIZE_ITEMS; i++)
+ {
+ if (self.item_game_animation[i] != NULL)
+ {
+ TSU_AnimationComplete((Animation *)self.item_game_animation[i], (Drawable *)self.item_game[i]);
+ }
+ }
+
+ SystemMenuRemoveAll();
+ TSU_DrawableSubRemoveFinished((Drawable *)self.scene_ptr);
+ thd_pass();
+}
+
+static void StartExit()
+{
+ StopCDDA();
+ StopShowCover();
+ RemoveAll();
+
+ float y = 1.0f;
+ self.game_index_selected = -1;
+
+ for (int i = 0; i < MAX_SIZE_ITEMS; i++)
+ {
+ if (self.item_game[i] != NULL)
+ {
+ if (!self.exit_app && TSU_ItemMenuIsSelected(self.item_game[i]))
+ {
+ self.game_index_selected = TSU_ItemMenuGetItemIndex(self.item_game[i]);
+ strcpy(self.item_value_selected, GetFullGamePathByIndex(self.game_index_selected));
+ self.device_selected = menu_data.games_array[TSU_ItemMenuGetItemIndex(self.item_game[i])].device;
+
+ if (menu_data.menu_type == MT_PLANE_TEXT)
+ {
+ float w, h;
+ char *label_text = (char *)malloc(NAME_MAX);
+ memset(label_text, 0, NAME_MAX);
+
+ strcpy(label_text, TSU_ItemMenuGetLabelText(self.item_game[i]));
+ label_text = Trim(label_text);
+
+ TSU_FontSetSize(self.menu_font, 18);
+ TSU_FontGetTextSize(self.menu_font, label_text, &w, &h);
+ self.run_animation = TSU_LogXYMoverCreate((640/2 - w/2), (480 - 84) / 2);
+
+ free(label_text);
+ }
+ else if (TSU_ItemMenuHasTextAndImage(self.item_game[i]))
+ {
+ self.run_animation = TSU_LogXYMoverCreate((640 - (84 + 64)) / 2, (480 - 84) / 2);
+ }
+ else
+ {
+ self.run_animation = TSU_LogXYMoverCreate((640 - 84) / 2, (480 - 84) / 2);
+ }
+
+ self.exit_trigger_list[i] = TSU_DeathCreate(NULL);
+ TSU_TriggerAdd((Animation *)self.run_animation, (Trigger *)self.exit_trigger_list[i]);
+ TSU_DrawableAnimAdd((Drawable *)self.item_game[i], (Animation *)self.run_animation);
+ }
+ else
+ {
+ self.exit_animation_list[i] = TSU_ExpXYMoverCreate(0, y + .10, 0, 500);
+ self.exit_trigger_list[i] = TSU_DeathCreate(NULL);
+
+ TSU_TriggerAdd((Animation *)self.exit_animation_list[i], (Trigger *)self.exit_trigger_list[i]);
+ TSU_DrawableAnimAdd((Drawable *)self.item_game[i], (Animation *)self.exit_animation_list[i]);
+ }
+ }
+ }
+ TSU_AppStartExit(self.dsapp_ptr);
+
+ self.wait_to_exit_app = true;
+ while (!menu_data.finished_menu) { thd_pass(); }
+
+ RemoveEvent(do_menu_video_event);
+ RemoveEvent(do_menu_control_event);
+
+ MenuExitHelper(NULL);
+}
+
+static void GamesApp_SystemMenuInputEvent(int type, int key)
+{
+ if (type != EvtKeypress)
+ return;
+
+ mutex_lock(&change_page_mutex);
+
+ switch (key)
+ {
+ case KeyStart:
+ {
+ if (StateSystemMenu())
+ {
+ menu_data.state_app = SA_GAMES_MENU;
+ HideSystemMenu();
+ }
+ }
+ break;
+
+ default:
+ {
+ if (StateSystemMenu())
+ {
+ SystemMenuInputEvent(type, key);
+ }
+ }
+ break;
+ }
+
+ mutex_unlock(&change_page_mutex);
+}
+
+static void GamesApp_PresetMenuInputEvent(int type, int key)
+{
+ if (type != EvtKeypress)
+ return;
+
+ mutex_lock(&change_page_mutex);
+
+ switch (key)
+ {
+ case KeyStart:
+ case KeyMiscY:
+ {
+ if (StatePresetMenu())
+ {
+ HidePresetMenu();
+ menu_data.state_app = SA_GAMES_MENU;
+ }
+ }
+ break;
+
+ default:
+ {
+ if (StatePresetMenu())
+ {
+ PresetMenuInputEvent(type, key);
+ }
+ }
+ break;
+ }
+
+ mutex_unlock(&change_page_mutex);
+}
+
+static void GamesApp_ScanCoverInputEvent(int type, int key)
+{
+ if (type != EvtKeypress)
+ return;
+
+ mutex_lock(&change_page_mutex);
+
+ StopScanCovers();
+ HideCoverScan();
+ menu_data.state_app = SA_GAMES_MENU;
+ timer_ms_gettime(&self.scan_covers_start_time, NULL);
+
+ mutex_unlock(&change_page_mutex);
+}
+
+static void GamesApp_OptimizeCoverInputEvent(int type, int key)
+{
+ if (type != EvtKeypress)
+ return;
+
+ mutex_lock(&change_page_mutex);
+
+ StopOptimizeCovers();
+ HideOptimizeCoverPopup();
+ menu_data.state_app = SA_GAMES_MENU;
+ timer_ms_gettime(&self.scan_covers_start_time, NULL);
+
+ mutex_unlock(&change_page_mutex);
+}
+
+static void GamesApp_ControlInputEvent(int type, int key, int state_app)
+{
+ if (type != EvtKeypress)
+ return;
+
+ switch (state_app)
+ {
+ case SA_CONTROL + ASYNC_CONTROL_ID: //ASYNC
+ {
+ AsyncInputEvent(type, key);
+ break;
+ }
+
+ case SA_CONTROL + OS_CONTROL_ID: //OS
+ {
+ OSInputEvent(type, key);
+ break;
+ }
+
+ case SA_CONTROL + LOADER_CONTROL_ID: //LOADER
+ {
+ LoaderInputEvent(type, key);
+ break;
+ }
+
+ case SA_CONTROL + BOOT_CONTROL_ID: //BOOT
+ {
+ BootInputEvent(type, key);
+ break;
+ }
+
+ case SA_CONTROL + MEMORY_CONTROL_ID: //MEMORY
+ {
+ MemoryInputEvent(type, key);
+ break;
+ }
+
+ case SA_CONTROL + CUSTOM_MEMORY_CONTROL_ID: //CUSTOM MEMORY
+ {
+ CustomMemoryInputEvent(type, key);
+ break;
+ }
+
+ case SA_CONTROL + HEAP_CONTROL_ID: //HEAP
+ {
+ HeapInputEvent(type, key);
+ break;
+ }
+
+ case SA_CONTROL + CDDA_SOURCE_CONTROL_ID: //CDDA SOURCE
+ {
+ CDDASourceInputEvent(type, key);
+ break;
+ }
+
+ case SA_CONTROL + CDDA_DESTINATION_CONTROL_ID: //CDDA DESTINATION
+ {
+ CDDADestinationInputEvent(type, key);
+ break;
+ }
+
+ case SA_CONTROL + CDDA_POSITION_CONTROL_ID: //CDDA POSITION
+ {
+ CDDAPositionInputEvent(type, key);
+ break;
+ }
+
+ case SA_CONTROL + CDDA_CHANNEL_CONTROL_ID: //CDDA CHANNEL
+ {
+ CDDAChannelInputEvent(type, key);
+ break;
+ }
+
+ case SA_CONTROL + PATCH_ADDRESS1_CONTROL_ID: //PATCH ADDRESS 1
+ {
+ PatchAddress1InputEvent(type, key);
+ break;
+ }
+
+ case SA_CONTROL + PATCH_VALUE1_CONTROL_ID: //PATCH VALUE 1
+ {
+ PatchValue1InputEvent(type, key);
+ break;
+ }
+
+ case SA_CONTROL + PATCH_ADDRESS2_CONTROL_ID: //PATCH ADDRESS 2
+ {
+ PatchAddress2InputEvent(type, key);
+ break;
+ }
+
+ case SA_CONTROL + PATCH_VALUE2_CONTROL_ID: //PATCH VALUE 2
+ {
+ PatchValue2InputEvent(type, key);
+ break;
+ }
+
+ case SA_CONTROL + ALTERBOOT_CONTROL_ID: //ALTER BOOT
+ {
+ AlterBootInputEvent(type, key);
+ break;
+ }
+
+ case SA_CONTROL + SCREENSHOT_CONTROL_ID: //SCREENSHOT
+ {
+ ScreenshotInputEvent(type, key);
+ break;
+ }
+
+ case SA_CONTROL + VMU_CONTROL_ID: //VMU
+ {
+ VMUInputEvent(type, key);
+ break;
+ }
+
+ case SA_CONTROL + VMUSELECTOR_CONTROL_ID: //VMU OPTION
+ {
+ VMUSelectorInputEvent(type, key);
+ break;
+ }
+
+ case SA_CONTROL + SHORTCUT_SIZE_CONTROL_ID: //SHORTCUT SIZE
+ {
+ ShortcutSizeInputEvent(type, key);
+ break;
+ }
+
+ case SA_CONTROL + SHORTCUT_ROTATE_CONTROL_ID: //SHORTCUT ROTATE
+ {
+ ShortcutRotateInputEvent(type, key);
+ break;
+ }
+
+ case SA_CONTROL + SHORTCUT_NAME_CONTROL_ID: //SHORTCUT NAME
+ {
+ ShortcutNameInputEvent(type, key);
+ break;
+ }
+
+ case SA_CONTROL + SHORTCUT_DONTSHOWNAME_CONTROL_ID: //SHORTCUT DONT SHOW NAME
+ {
+ ShortcutDontShowNameInputEvent(type, key);
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+static void GamesApp_InputEvent(int type, int key)
+{
+ if (type != EvtKeypress)
+ return;
+
+ mutex_lock(&change_page_mutex);
+
+ bool skip_cursor = false;
+ bool fast_cursor = false;
+ timer_ms_gettime(&self.scan_covers_start_time, NULL);
+
+ switch (key)
+ {
+ case KeyStart:
+ {
+ menu_data.state_app = SA_SYSTEM_MENU;
+ ShowSystemMenu();
+ skip_cursor = true;
+ }
+ break;
+
+ case KeyMiscY:
+ {
+ if (menu_data.games_array_count > 0)
+ {
+ menu_data.state_app = SA_PRESET_MENU;
+ ShowPresetMenu(TSU_ItemMenuGetItemIndex(self.item_game[self.menu_cursel]));
+ }
+ skip_cursor = true;
+ }
+ break;
+
+ // X: CHANGE VISUALIZATION
+ case KeyMiscX:
+ {
+ StopShowCover();
+
+ int real_cursel = (self.current_page - 1) * menu_data.menu_option.max_page_size + self.menu_cursel + 1;
+ SetMenuType(menu_data.menu_type >= MT_IMAGE_128_4X3 ? MT_PLANE_TEXT : menu_data.menu_type + 1);
+ self.current_page = ceil((float)real_cursel / (float)menu_data.menu_option.max_page_size);
+ self.menu_cursel = real_cursel - (self.current_page - 1) * menu_data.menu_option.max_page_size - 1;
+
+ if (LoadPage(true, DMD_NONE))
+ {
+ }
+ }
+ break;
+
+ case KeyCancel:
+ {
+ self.exit_app = true;
+ skip_cursor = true;
+ StartExit();
+ }
+ break;
+
+ // LEFT TRIGGER
+ case KeyPgup:
+ {
+ if (menu_data.menu_type == MT_PLANE_TEXT)
+ {
+ fast_cursor = true;
+ }
+
+ self.current_page--;
+ self.menu_cursel = 0;
+ if (LoadPage(false, DMD_RIGHT))
+ {
+ }
+ }
+ break;
+
+ // RIGHT TRIGGER
+ case KeyPgdn:
+ {
+ if (menu_data.menu_type == MT_PLANE_TEXT)
+ {
+ fast_cursor = true;
+ }
+
+ self.current_page++;
+ self.menu_cursel = 0;
+ if (LoadPage(false, DMD_LEFT))
+ {
+ }
+ }
+ break;
+
+ case KeyUp:
+ {
+ self.menu_cursel--;
+
+ if (menu_data.menu_type == MT_IMAGE_TEXT_64_5X2)
+ {
+ if (self.menu_cursel < 0)
+ {
+ self.menu_cursel += self.game_count;
+ }
+ }
+ else if (menu_data.menu_type == MT_PLANE_TEXT)
+ {
+ if (self.menu_cursel < 0)
+ {
+ fast_cursor = true;
+ self.current_page--;
+ LoadPage(false, DMD_DOWN);
+ self.menu_cursel = self.game_count - 1;
+ }
+ }
+ else
+ {
+ if ((self.menu_cursel + 1) % menu_data.menu_option.size_items_column == 0)
+ {
+ self.menu_cursel += menu_data.menu_option.size_items_column;
+ }
+
+ if (self.menu_cursel < 0)
+ {
+ self.menu_cursel = 0;
+ }
+ else if (self.menu_cursel >= self.game_count)
+ {
+ self.menu_cursel = self.game_count - 1;
+ }
+ }
+ }
+
+ break;
+
+ case KeyDown:
+ {
+ self.menu_cursel++;
+
+ if (menu_data.menu_type == MT_IMAGE_TEXT_64_5X2)
+ {
+ if (self.menu_cursel >= self.game_count)
+ {
+ self.menu_cursel -= self.game_count;
+ }
+ }
+ else if (menu_data.menu_type == MT_PLANE_TEXT)
+ {
+ if (self.menu_cursel >= self.game_count)
+ {
+ fast_cursor = true;
+ self.current_page++;
+ self.menu_cursel = 0;
+ LoadPage(false, DMD_UP);
+ }
+ }
+ else
+ {
+ if (self.menu_cursel % menu_data.menu_option.size_items_column == 0)
+ {
+ self.menu_cursel -= menu_data.menu_option.size_items_column;
+ }
+
+ if (self.menu_cursel >= self.game_count)
+ {
+ self.menu_cursel = self.game_count - 1;
+ }
+ }
+ }
+
+ break;
+
+ case KeyLeft:
+
+ if (menu_data.menu_type == MT_PLANE_TEXT)
+ {
+ fast_cursor = true;
+ self.current_page--;
+ self.menu_cursel = 0;
+ if (LoadPage(false, DMD_RIGHT))
+ {
+ }
+ }
+ else
+ {
+ if (self.game_count <= menu_data.menu_option.size_items_column)
+ {
+ self.menu_cursel = 0;
+
+ if (menu_data.app_config.change_page_with_pad)
+ {
+ self.current_page--;
+ self.menu_cursel = 0;
+ if (LoadPage(false, DMD_RIGHT))
+ {
+ }
+ }
+ }
+ else
+ {
+ self.menu_cursel -= menu_data.menu_option.size_items_column;
+
+ if (self.menu_cursel < 0)
+ {
+ if (menu_data.app_config.change_page_with_pad)
+ {
+ self.current_page--;
+ self.menu_cursel = 0;
+ if (LoadPage(false, DMD_RIGHT))
+ {
+ }
+ }
+ else
+ {
+ self.menu_cursel += self.game_count;
+ }
+ }
+ }
+ }
+
+ break;
+
+ case KeyRight:
+ if (menu_data.menu_type == MT_PLANE_TEXT)
+ {
+ fast_cursor = true;
+ self.current_page++;
+ self.menu_cursel = 0;
+ if (LoadPage(false, DMD_LEFT))
+ {
+ }
+ }
+ else
+ {
+ if (self.game_count <= menu_data.menu_option.size_items_column)
+ {
+ self.menu_cursel = self.game_count - 1;
+
+ if (menu_data.app_config.change_page_with_pad)
+ {
+ self.current_page++;
+ self.menu_cursel = 0;
+ if (LoadPage(false, DMD_LEFT))
+ {
+ }
+ }
+ }
+ else
+ {
+ self.menu_cursel += menu_data.menu_option.size_items_column;
+
+ if (self.menu_cursel >= self.game_count)
+ {
+ if (menu_data.app_config.change_page_with_pad)
+ {
+ self.current_page++;
+ self.menu_cursel = 0;
+ if (LoadPage(false, DMD_LEFT))
+ {
+ }
+ }
+ else
+ {
+ self.menu_cursel -= self.game_count;
+ }
+ }
+ }
+ }
+
+ break;
+
+ case KeySelect:
+ {
+ StartExit();
+ skip_cursor = true;
+ }
+ break;
+
+ default:
+ {
+ }
+ break;
+ }
+
+ if (!skip_cursor)
+ {
+ if (key != KeyMiscX)
+ StopCDDA();
+
+ self.game_changed = true;
+ for (int i = 0; i < self.game_count; i++)
+ {
+ if (self.item_game[i] != NULL)
+ {
+ if (i == self.menu_cursel)
+ {
+ TSU_ItemMenuSetSelected(self.item_game[i], true, false);
+ SetTitle(TSU_ItemMenuGetItemIndex(self.item_game[i]), TSU_ItemMenuGetItemValue(self.item_game[i]));
+
+ SetTitleType(GetFullGamePathByIndex(TSU_ItemMenuGetItemIndex(self.item_game[i]))
+ , CheckGdiOptimized(TSU_ItemMenuGetItemIndex(self.item_game[i])));
+
+ SetCursor();
+
+ if (fast_cursor)
+ {
+ TSU_LogXYMoverSetFactor(self.item_selector_animation, 5.5f);
+ }
+ else
+ {
+ TSU_LogXYMoverSetFactor(self.item_selector_animation, 7.0f);
+ }
+
+ ShowCover(TSU_ItemMenuGetItemIndex(self.item_game[i]));
+
+ if (key != KeyMiscX)
+ PlayCDDA(TSU_ItemMenuGetItemIndex(self.item_game[i]));
+ }
+ else
+ {
+ TSU_ItemMenuSetSelected(self.item_game[i], false, false);
+ }
+ }
+ }
+ self.game_changed = false;
+ }
+
+ mutex_unlock(&change_page_mutex);
+}
+
+static int LoadPreset()
+{
+ if (menu_data.preset == NULL || menu_data.preset->game_index != self.game_index_selected)
+ {
+ if (menu_data.preset != NULL)
+ {
+ free(menu_data.preset);
+ }
+
+ menu_data.preset = LoadPresetGame(self.game_index_selected);
+ }
+
+ if ((self.isoldr = ParsePresetToIsoldr(self.game_index_selected, menu_data.preset)) == NULL)
+ {
+ return 0;
+ }
+
+ char memory[12];
+ memset(memory, 0, sizeof(memory));
+
+ if (strcasecmp(menu_data.preset->memory, "0x8c") == 0)
+ {
+ snprintf(memory, sizeof(memory), "%s%s", menu_data.preset->memory, menu_data.preset->custom_memory);
+ }
+ else
+ {
+ strcpy(memory, menu_data.preset->memory);
+ }
+
+ self.addr = strtoul(memory, NULL, 16);
+
+ if (menu_data.preset->emu_vmu)
+ {
+ GenerateVMUFile(self.item_value_selected, menu_data.preset->vmu_mode, menu_data.preset->emu_vmu);
+ }
+
+ if (strncmp(self.isoldr->fs_dev, "auto", 4) == 0)
+ {
+ if (self.device_selected == APP_DEVICE_SD)
+ {
+ strcpy(self.isoldr->fs_dev, "sd");
+ }
+ else
+ {
+ if (!strncasecmp(GetDefaultDir(menu_data.current_dev), "/cd", 3))
+ {
+ strcpy(self.isoldr->fs_dev, "cd");
+ }
+ else if (!strncasecmp(GetDefaultDir(menu_data.current_dev), "/sd", 3))
+ {
+ strcpy(self.isoldr->fs_dev, "sd");
+ }
+ else if (!strncasecmp(GetDefaultDir(menu_data.current_dev), "/ide", 4))
+ {
+ strcpy(self.isoldr->fs_dev, "ide");
+ }
+ }
+ }
+
+ return 1;
+}
+
+static void FreeAppData()
+{
+ mutex_destroy(&change_page_mutex);
+
+ for (int i = 0; i < MAX_SIZE_ITEMS; i++)
+ {
+ if (self.item_game[i] != NULL)
+ {
+ if (!self.exit_app && TSU_ItemMenuIsSelected(self.item_game[i]) && self.run_animation != NULL)
+ {
+ TSU_AnimationComplete((Animation *)self.run_animation, (Drawable *)self.item_game[i]);
+ }
+ else if (self.exit_animation_list[i] != NULL)
+ {
+ TSU_AnimationComplete((Animation *)self.exit_animation_list[i], (Drawable *)self.item_game[i]);
+ }
+
+ TSU_DrawableSetFinished((Drawable *)self.item_game[i]);
+ }
+ }
+
+ TSU_DrawableSubRemoveFinished((Drawable *)self.scene_ptr);
+ thd_pass();
+
+ for (int i = 0; i < MAX_SIZE_ITEMS; i++)
+ {
+ if (self.item_game[i] != NULL)
+ {
+ if (TSU_ItemMenuIsSelected(self.item_game[i]) && self.run_animation != NULL)
+ {
+ TSU_LogXYMoverDestroy(&self.run_animation);
+ }
+ else if (self.exit_animation_list[i] != NULL)
+ {
+ TSU_ExpXYMoverDestroy(&self.exit_animation_list[i]);
+ }
+
+ if (self.item_game_animation[i] != NULL)
+ {
+ TSU_LogXYMoverDestroy(&self.item_game_animation[i]);
+ }
+
+ if (self.exit_trigger_list[i] != NULL)
+ {
+ TSU_DeathDestroy(&self.exit_trigger_list[i]);
+ }
+
+ if (self.item_game[i] != NULL)
+ {
+ TSU_ItemMenuDestroy(&self.item_game[i]);
+ }
+ }
+ }
+
+ if (self.main_box != NULL)
+ {
+ TSU_BoxDestroy(&self.main_box);
+ }
+
+ if (self.title_rectangle != NULL)
+ {
+ TSU_RectangleDestroy(&self.title_rectangle);
+ }
+
+ if (self.title_type_rectangle != NULL)
+ {
+ TSU_RectangleDestroy(&self.title_type_rectangle);
+ }
+
+ if (self.game_list_rectangle != NULL)
+ {
+ TSU_RectangleDestroy(&self.game_list_rectangle);
+ }
+
+ if (self.item_selector != NULL)
+ {
+ TSU_RectangleDestroy(&self.item_selector);
+ }
+
+ if (self.title != NULL)
+ {
+ TSU_LabelDestroy(&self.title);
+ }
+
+ if (self.title_back != NULL)
+ {
+ TSU_LabelDestroy(&self.title_back);
+ }
+
+ if (self.title_animation != NULL)
+ {
+ TSU_LogXYMoverDestroy(&self.title_animation);
+ }
+
+ if (self.title_back_animation != NULL)
+ {
+ TSU_LogXYMoverDestroy(&self.title_back_animation);
+ }
+
+ if (self.title_type != NULL)
+ {
+ TSU_LabelDestroy(&self.title_type);
+ }
+
+ if (self.title_type_animation != NULL)
+ {
+ TSU_LogXYMoverDestroy(&self.title_type_animation);
+ }
+
+ if (self.item_selector_animation != NULL)
+ {
+ TSU_LogXYMoverDestroy(&self.item_selector_animation);
+ }
+
+ if (self.animation_cover_game != NULL)
+ {
+ TSU_FadeToDestroy(&self.animation_cover_game);
+ }
+
+ if (self.fadeout_cover_animation != NULL)
+ {
+ TSU_FadeOutDestroy(&self.fadeout_cover_animation);
+ }
+
+ if (self.img_cover_game != NULL)
+ {
+ TSU_BannerDestroy(&self.img_cover_game);
+ TSU_TextureDestroy(&self.texture_cover_game);
+ }
+
+ if (self.img_cover_game_background != NULL)
+ {
+ TSU_BannerDestroy(&self.img_cover_game_background);
+ TSU_TextureDestroy(&self.texture_cover_game_background);
+ }
+
+ for (int i = 0; i < MAX_BUTTONS; i++)
+ {
+ if (self.item_button[i] != NULL)
+ {
+ TSU_ItemMenuDestroy(&self.item_button[i]);
+ }
+ }
+
+ if (self.img_cover_game_rectangle != NULL)
+ {
+ TSU_RectangleDestroy(&self.img_cover_game_rectangle);
+ }
+
+ DestroySystemMenu();
+ DestroyPresetMenu();
+
+ TSU_FontDestroy(&self.menu_font);
+ TSU_FontDestroy(&self.message_font);
+ TSU_AppDestroy(&self.dsapp_ptr);
+ self.scene_ptr = NULL;
+
+ DestroyMenuData();
+}
+
+static bool PlayGame()
+{
+ bool is_running = false;
+
+ if (self.item_value_selected[0] != '\0')
+ {
+ ds_printf("DS_GAMES: Run: %s", self.item_value_selected);
+
+ if (LoadPreset() == 1)
+ {
+ ds_printf("LoadPresset: %s", "OK");
+ SaveMenuConfig();
+ FreeAppData();
+
+ isoldr_exec(self.isoldr, self.addr);
+ is_running = true;
+ }
+ }
+
+ return is_running;
+}
+
+static void PostOptimizer()
+{
+ HideOptimizeCoverPopup();
+ menu_data.state_app = SA_GAMES_MENU;
+ menu_data.optimize_game_cover_thread = NULL;
+}
+
+static void PostLoadPVRCover(bool new_cover)
+{
+ if (new_cover)
+ {
+ int game_index = 0;
+ for (int i = 0; i < self.game_count; i++)
+ {
+ if (menu_data.finished_menu) break;
+
+ if (self.item_game[i] != NULL)
+ {
+ game_index = TSU_ItemMenuGetItemIndex(self.item_game[i]);
+
+ // ONLY PVR AT THIS TIME
+ if (menu_data.games_array[game_index].is_pvr_cover)
+ {
+ if (menu_data.finished_menu) break;
+
+ thd_pass();
+ LoadCover(self.item_game[i], i);
+ }
+ }
+ }
+ }
+
+ HideCoverScan();
+ menu_data.state_app = SA_GAMES_MENU;
+ menu_data.load_pvr_cover_thread = NULL;
+}
+
+static void StateAppInpuEvent(int state_app, int type, int key)
+{
+ switch (state_app)
+ {
+ case SA_GAMES_MENU:
+ GamesApp_InputEvent(type, key);
+ break;
+
+ case SA_SYSTEM_MENU:
+ GamesApp_SystemMenuInputEvent(type, key);
+ break;
+
+ case SA_PRESET_MENU:
+ GamesApp_PresetMenuInputEvent(type, key);
+ break;
+
+ case SA_SCAN_COVER:
+ GamesApp_ScanCoverInputEvent(type, key);
+ break;
+
+ case SA_OPTIMIZE_COVER:
+ GamesApp_OptimizeCoverInputEvent(type, key);
+ break;
+
+ default:
+ if (state_app >= SA_CONTROL) {
+ GamesApp_ControlInputEvent(type, key, state_app);
+ }
+ break;
+ }
+}
+
+static void DoMenuControlHandler(void *ds_event, void *param, int action)
+{
+ if (self.show_cover_game) thd_pass();
+
+ SDL_Event *event = (SDL_Event *) param;
+
+ switch(event->type) {
+ case SDL_JOYBUTTONDOWN: {
+ switch(event->jbutton.button) {
+ case 1: // B
+ StateAppInpuEvent(menu_data.state_app, EvtKeypress, KeyCancel);
+ break;
+
+ case 2: // A
+ StateAppInpuEvent(menu_data.state_app, EvtKeypress, KeySelect);
+ break;
+
+ case 5: // Y
+ StateAppInpuEvent(menu_data.state_app, EvtKeypress, KeyMiscY);
+ break;
+
+ case 6: // X
+ StateAppInpuEvent(menu_data.state_app, EvtKeypress, KeyMiscX);
+ break;
+
+ case 4: // Z
+ StateAppInpuEvent(menu_data.state_app, EvtKeypress, KeyPgup);
+ break;
+
+ case 0: // C
+ StateAppInpuEvent(menu_data.state_app, EvtKeypress, KeyPgdn);
+ break;
+
+ case 3: // START
+ StateAppInpuEvent(menu_data.state_app, EvtKeypress, KeyStart);
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ case SDL_JOYAXISMOTION: {
+ switch(event->jaxis.axis) {
+ case 2: // RIGHT TRIGGER
+ {
+ static bool right_trigger_down = false;
+ if (!right_trigger_down && (event->jaxis.value >= MAX_TRIGGER_VALUE/3)) {
+ right_trigger_down = true;
+ StateAppInpuEvent(menu_data.state_app, EvtKeypress, KeyPgdn);
+ }
+ else if (event->jaxis.value < MAX_TRIGGER_VALUE/3) {
+ right_trigger_down = false;
+ }
+ }
+ break;
+
+ case 3: // LEFT TRIGGER
+ {
+ static bool left_trigger_down = false;
+ if (!left_trigger_down && (event->jaxis.value >= MAX_TRIGGER_VALUE/3)) {
+ left_trigger_down = true;
+ StateAppInpuEvent(menu_data.state_app, EvtKeypress, KeyPgup);
+ }
+ else if (event->jaxis.value < MAX_TRIGGER_VALUE/3) {
+ left_trigger_down = false;
+ }
+ }
+ break;
+ }
+ }
+
+ case SDL_JOYHATMOTION: {
+ switch(event->jhat.value) {
+ case 0x0E: // KEY UP
+ StateAppInpuEvent(menu_data.state_app, EvtKeypress, KeyUp);
+ break;
+
+ case 0x0B: // KEY DOWN
+ StateAppInpuEvent(menu_data.state_app, EvtKeypress, KeyDown);
+ break;
+
+ case 0x07: // KEY LEFT
+ StateAppInpuEvent(menu_data.state_app, EvtKeypress, KeyLeft);
+ break;
+
+ case 0x0D: // KEY RIGHT
+ StateAppInpuEvent(menu_data.state_app, EvtKeypress, KeyRight);
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void DoMenuVideoHandler(void *ds_event, void *param, int action)
+{
+ if (!self.wait_to_exit_app)
+ {
+ if (self.show_cover_game) thd_pass();
+
+ if ((menu_data.current_dev == APP_DEVICE_SD || menu_data.current_dev == APP_DEVICE_IDE)
+ && menu_data.state_app == SA_GAMES_MENU)
+ {
+ if (menu_data.cover_scanned_app.scan_count < MAX_SCAN_COUNT
+ && (self.scan_count < MAX_SCAN_COUNT)
+ && menu_data.cover_scanned_app.last_game_index < menu_data.games_array_count
+ && menu_data.load_pvr_cover_thread == NULL
+ && menu_data.optimize_game_cover_thread == NULL)
+ {
+ timer_ms_gettime(&self.scan_covers_end_time, NULL);
+ if ((self.scan_covers_end_time - self.scan_covers_start_time) >= 5)
+ {
+ self.scan_covers_start_time = self.scan_covers_end_time;
+ menu_data.stop_load_pvr_cover = false;
+ menu_data.load_pvr_cover_thread = thd_create(0, LoadPVRCoverThread, NULL);
+ StopCDDA();
+ ShowCoverScan();
+ }
+ }
+ }
+ }
+
+ switch(action)
+ {
+ case EVENT_ACTION_RENDER:
+ {
+ if (!self.wait_to_exit_app)
+ {
+ TSU_AppDoFrame(self.dsapp_ptr);
+ }
+ else
+ {
+ if (!menu_data.finished_menu && TSU_AppEnd(self.dsapp_ptr))
+ {
+ menu_data.finished_menu = true;
+ }
+ }
+ }
+ break;
+ case EVENT_ACTION_RENDER_POST:
+ break;
+ case EVENT_ACTION_UPDATE:
+ break;
+ default:
+ break;
+ }
+}
+
+static void* MenuExitHelper(void *params)
+{
+ if (self.dsapp_ptr != NULL)
+ {
+ if (!self.exit_app)
+ {
+ if (PlayGame())
+ {
+ SDL_DC_EmulateMouse(SDL_TRUE);
+ EnableScreen();
+ GUI_Enable();
+ ShutdownDS();
+ }
+ else
+ {
+ FreeAppData();
+ SDL_DC_EmulateMouse(SDL_TRUE);
+ EnableScreen();
+ GUI_Enable();
+
+ GamesApp_Exit(NULL);
+ }
+ }
+ else
+ {
+ FreeAppData();
+ SDL_DC_EmulateMouse(SDL_TRUE);
+ EnableScreen();
+ GUI_Enable();
+
+ GamesApp_Exit(NULL);
+ }
+ }
+
+ return NULL;
+}
+
+void GamesApp_Init(App_t *app)
+{
+ srand(time(NULL));
+ mutex_init((mutex_t *)&change_page_mutex, MUTEX_TYPE_NORMAL);
+
+ memset(&self, 0, sizeof(self));
+
+ if (app->args != NULL)
+ {
+ self.have_args = true;
+ }
+ else
+ {
+ self.have_args = false;
+ }
+
+ self.app = app;
+ self.app->thd = NULL;
+ self.sector_size = 2048;
+ self.pages = -1;
+ self.first_menu_load = true;
+
+ memset(self.item_value_selected, 0, sizeof(self.item_value_selected));
+
+ for (int i = 0; i < MAX_BUTTONS; i++)
+ {
+ self.item_button[i] = NULL;
+ }
+
+ self.run_animation = NULL;
+ for (int i = 0; i < MAX_SIZE_ITEMS; i++)
+ {
+ self.item_game[i] = NULL;
+ self.item_game_animation[i] = NULL;
+ self.exit_animation_list[i] = NULL;
+ self.exit_trigger_list[i] = NULL;
+ }
+
+ if ((self.dsapp_ptr = TSU_AppCreate(GamesApp_InputEvent)) != NULL)
+ {
+ Color main_color = {1, 0.22f, 0.06f, 0.25f};
+ self.main_box = TSU_BoxCreate(PVR_LIST_OP_POLY, 3, 480 - 12, 640 - 6, 480 - 9, 12, &main_color, ML_BACKGROUND, 0);
+
+ Color title_color = {1, 0.22f, 0.06f, 0.25f};
+ Color title_type_color = {1, 1.0f, 1.0f, 0.1f};
+
+ if(vid_check_cable() == CT_VGA)
+ {
+ self.title_rectangle = TSU_RectangleCreate(PVR_LIST_OP_POLY, 0, 40, 640, 40, &title_color, ML_BACKGROUND, 0);
+ self.title_type_rectangle = TSU_RectangleCreateWithBorder(PVR_LIST_OP_POLY, 584, 37, 60, 34, &title_type_color, ML_ITEM + 2, 3, &title_color, 0);
+ }
+ else
+ {
+ self.title_rectangle = TSU_RectangleCreate(PVR_LIST_OP_POLY, 0, 46, 640, 46, &title_color, ML_BACKGROUND, 0);
+ self.title_type_rectangle = TSU_RectangleCreateWithBorder(PVR_LIST_OP_POLY, 584, 43, 60, 40, &title_type_color, ML_ITEM + 2, 3, &title_color, 0);
+ }
+
+ TSU_AppSubAddBox(self.dsapp_ptr, self.main_box);
+ TSU_AppSubAddRectangle(self.dsapp_ptr, self.title_rectangle);
+ TSU_AppSubAddRectangle(self.dsapp_ptr, self.title_type_rectangle);
+
+ CreateMenuData(&SetMessageScan, &SetMessageOptimizer, &PostLoadPVRCover, &PostOptimizer);
+ InitMenu();
+
+ CreateSystemMenu(self.dsapp_ptr, self.scene_ptr, self.menu_font, self.message_font);
+ CreatePresetMenu(self.dsapp_ptr, self.scene_ptr, self.menu_font, self.message_font);
+ }
+}
+
+void GamesApp_Open(App_t *app)
+{
+ (void)app;
+
+ if (self.dsapp_ptr != NULL)
+ {
+ int mx = 0;
+ int my = 0;
+ SDL_GetMouseState(&mx, &my);
+ SDL_DC_EmulateMouse(SDL_FALSE);
+ SDL_DC_EmulateKeyboard(SDL_FALSE);
+
+ DisableScreen();
+ GUI_Disable();
+
+ TSU_AppBegin(self.dsapp_ptr);
+
+ do_menu_control_event = AddEvent
+ (
+ "GamesControl_Event",
+ EVENT_TYPE_INPUT,
+ EVENT_PRIO_DEFAULT,
+ DoMenuControlHandler,
+ NULL
+ );
+
+ do_menu_video_event = AddEvent
+ (
+ "GamesVideo_Event",
+ EVENT_TYPE_VIDEO,
+ EVENT_PRIO_DEFAULT,
+ DoMenuVideoHandler,
+ NULL
+ );
+ }
+}
+
+void GamesApp_Shutdown(App_t *app)
+{
+ (void)app;
+
+ if (self.isoldr)
+ {
+ free(self.isoldr);
+ }
+}
+
+void GamesApp_Exit(GUI_Widget *widget)
+{
+ (void)widget;
+ App_t *app = GetAppByName("Main");
+ OpenApp(app, NULL);
+}
\ No newline at end of file
diff --git a/applications/games_menu/modules/preset.c b/applications/games_menu/modules/preset.c
new file mode 100644
index 00000000..3110df71
--- /dev/null
+++ b/applications/games_menu/modules/preset.c
@@ -0,0 +1,2301 @@
+/* DreamShell ##version##
+
+ preset.h
+ Copyright (C) 2024 Maniac Vera
+
+*/
+
+#include "app_preset.h"
+#include "app_definition.h"
+#include "app_menu.h"
+#include "app_utils.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+extern struct menu_structure menu_data;
+
+enum PatchEnum
+{
+ PATCH_ADDRESS_TYPE = 1,
+ PATCH_VALUE_TYPE = 2
+};
+
+enum ViewEnum
+{
+ GENERAL_VIEW = 0,
+ CDDA_VIEW,
+ PATCH_VIEW,
+ EXTENSIONS_VIEW,
+ SHORTCUT_VIEW
+};
+
+static struct
+{
+ DSApp *dsapp_ptr;
+ Scene *scene_ptr;
+ Form *preset_menu_form;
+
+ bool save;
+ int body_letter_size;
+ int game_index;
+ uint body_height_size;
+ char full_path_game[NAME_MAX];
+ char *game_cover_path;
+ int changed_yflip;
+ bool button_start;
+ bool button_x;
+ bool button_y;
+ bool button_z;
+ bool button_lt;
+ bool button_a;
+ bool button_b;
+ bool button_c;
+ bool button_rt;
+
+ LogXYMover *menu_init_animation;
+ ExpXYMover *menu_end_animation;
+
+ Font *message_font;
+ Font *menu_font;
+ Font *textbox_font;
+
+ CheckBox *save_preset_option;
+ CheckBox *dma_option;
+ OptionGroup *async_option;
+ CheckBox *bypass_option;
+ CheckBox *cdda_option;
+ CheckBox *irq_option;
+ OptionGroup *os_option;
+ OptionGroup *loader_option;
+ OptionGroup *boot_option;
+ CheckBox *fast_option;
+ CheckBox *lowlevel_option;
+ OptionGroup *memory_option;
+ TextBox *custom_memory_option;
+ OptionGroup *heap_option;
+
+ OptionGroup *cdda_source_option;
+ OptionGroup *cdda_destination_option;
+ OptionGroup *cdda_position_option;
+ OptionGroup *cdda_channel_option;
+
+ TextBox *patch_address1_option;
+ TextBox *patch_value1_option;
+ TextBox *patch_address2_option;
+ TextBox *patchvalue2_option;
+
+ CheckBox *altboot_option;
+ CheckBox *screenshot_option;
+ CheckBox *button_start_option;
+ CheckBox *button_x_option;
+ CheckBox *button_y_option;
+ CheckBox *button_z_option;
+ CheckBox *button_rt_option;
+ CheckBox *button_a_option;
+ CheckBox *button_b_option;
+ CheckBox *button_c_option;
+ CheckBox *button_lt_option;
+ TextBox *vmu_option;
+ OptionGroup *vmu_selector_option;
+
+ OptionGroup *shortcut_size_option;
+ CheckBox *shortcut_rotate_option;
+ TextBox *shortcut_name_option;
+ CheckBox *shortcut_dontshowname_option;
+ ItemMenu *shortcut_create_option;
+
+ Texture *cover_texture;
+ Banner *cover_banner;
+} self;
+
+
+void CreatePresetMenu(DSApp *dsapp_ptr, Scene *scene_ptr, Font *menu_font, Font *message_font)
+{
+ self.dsapp_ptr = dsapp_ptr;
+ self.scene_ptr = scene_ptr;
+ self.message_font = message_font;
+ self.menu_font = menu_font;
+ self.preset_menu_form = NULL;
+ self.menu_init_animation = NULL;
+ self.menu_end_animation = NULL;
+ self.body_letter_size = 16;
+ self.body_height_size = 22;
+
+ char font_path[NAME_MAX];
+ memset(font_path, 0, sizeof(font_path));
+ snprintf(font_path, sizeof(font_path), "%s/%s", GetDefaultDir(menu_data.current_dev), "apps/games_menu/fonts/default.txf");
+
+ self.textbox_font = TSU_FontCreate(font_path, PVR_LIST_TR_POLY);
+
+ memset(self.full_path_game, 0, NAME_MAX);
+ self.cover_texture = NULL;
+ self.cover_banner = NULL;
+ self.game_cover_path = NULL;
+ self.changed_yflip = -1;
+}
+
+void DestroyPresetMenu()
+{
+ HidePresetMenu();
+
+ self.dsapp_ptr = NULL;
+ self.scene_ptr = NULL;
+ self.message_font = NULL;
+ self.menu_font = NULL;
+
+ TSU_FontDestroy(&self.textbox_font);
+
+ if (menu_data.preset != NULL)
+ {
+ free(menu_data.preset);
+ menu_data.preset = NULL;
+ }
+
+ self.cover_texture = NULL;
+}
+
+void PresetMenuRemoveAll()
+{
+}
+
+void PresetMenuInputEvent(int type, int key)
+{
+ TSU_FormInputEvent(self.preset_menu_form, type, key);
+}
+
+int StatePresetMenu()
+{
+ return (self.preset_menu_form != NULL ? 1 : 0);
+}
+
+void OnViewIndexChangedEvent(Drawable *drawable, int view_index)
+{
+ switch (view_index)
+ {
+ case GENERAL_VIEW:
+ CreateGeneralView((Form *)drawable);
+ break;
+
+ case CDDA_VIEW:
+ CreateCDDAView((Form *)drawable);
+ break;
+
+ case PATCH_VIEW:
+ CreatePatchView((Form *)drawable);
+ break;
+
+ case EXTENSIONS_VIEW:
+ CreateExtensionsView((Form *)drawable);
+ break;
+
+ case SHORTCUT_VIEW:
+ CreateShortcutView((Form *)drawable);
+ break;
+ }
+}
+
+void OnGetObjectsCurrentViewEvent(uint loop_index, int id, Drawable *drawable, uint type, uint row, uint column, int view_index)
+{
+ if (loop_index == 0 && view_index == CDDA_VIEW)
+ {
+ menu_data.preset->emu_cdda = CDDA_MODE_DISABLED;
+ }
+
+ switch (id)
+ {
+ case SAVE_CONTROL_ID:
+ {
+ self.save = TSU_CheckBoxGetValue((CheckBox *)drawable);
+ }
+ break;
+
+ case DMA_CONTROL_ID:
+ {
+ menu_data.preset->use_dma = TSU_CheckBoxGetValue((CheckBox *)drawable);
+ }
+ break;
+
+ case ASYNC_CONTROL_ID:
+ {
+ menu_data.preset->emu_async = TSU_OptionGroupGetKeySelected((OptionGroup *)drawable);
+ }
+ break;
+
+ case BYPASS_CONTROL_ID:
+ {
+ menu_data.preset->alt_read = TSU_CheckBoxGetValue((CheckBox *)drawable);
+ }
+ break;
+
+ case IRQ_CONTROL_ID:
+ {
+ menu_data.preset->use_irq = TSU_CheckBoxGetValue((CheckBox *)drawable);
+ }
+ break;
+
+ case OS_CONTROL_ID:
+ {
+ menu_data.preset->bin_type = TSU_OptionGroupGetKeySelected((OptionGroup *)drawable);
+ }
+ break;
+
+ case LOADER_CONTROL_ID:
+ {
+ memset(menu_data.preset->device, 0, FIRMWARE_SIZE);
+ strcpy(menu_data.preset->device, TSU_OptionGroupGetTextSelected((OptionGroup *)drawable));
+ }
+ break;
+
+ case BOOT_CONTROL_ID:
+ {
+ menu_data.preset->boot_mode = TSU_OptionGroupGetKeySelected((OptionGroup *)drawable);
+ }
+ break;
+
+ case FASTBOOT_CONTROL_ID:
+ {
+ menu_data.preset->fastboot = TSU_CheckBoxGetValue((CheckBox *)drawable);
+ }
+ break;
+
+ case LOWLEVEL_CONTROL_ID:
+ {
+ menu_data.preset->low = TSU_CheckBoxGetValue((CheckBox *)drawable);
+ }
+ break;
+
+ case MEMORY_CONTROL_ID:
+ {
+ memset(menu_data.preset->memory, 0, sizeof(menu_data.preset->memory));
+ strcpy(menu_data.preset->memory, TSU_OptionGroupGetTextSelected((OptionGroup *)drawable));
+ }
+ break;
+
+ case CUSTOM_MEMORY_CONTROL_ID:
+ {
+
+ }
+ break;
+
+ case HEAP_CONTROL_ID:
+ {
+ memset(menu_data.preset->heap_memory, 0, sizeof(menu_data.preset->heap_memory));
+ strcpy(menu_data.preset->heap_memory, TSU_OptionGroupGetTextSelected((OptionGroup *)drawable));
+ menu_data.preset->heap = TSU_OptionGroupGetKeySelected((OptionGroup *)drawable);
+ }
+ break;
+
+ case CDDA_CONTROL_ID:
+ {
+ menu_data.preset->cdda = TSU_CheckBoxGetValue((CheckBox *)drawable);
+ }
+ break;
+
+ case CDDA_SOURCE_CONTROL_ID:
+ {
+ menu_data.preset->emu_cdda |= TSU_OptionGroupGetKeySelected((OptionGroup *)drawable);
+ }
+ break;
+
+ case CDDA_DESTINATION_CONTROL_ID:
+ {
+ menu_data.preset->emu_cdda |= TSU_OptionGroupGetKeySelected((OptionGroup *)drawable);
+ }
+ break;
+
+ case CDDA_POSITION_CONTROL_ID:
+ {
+ menu_data.preset->emu_cdda |= TSU_OptionGroupGetKeySelected((OptionGroup *)drawable);
+ }
+ break;
+
+ case CDDA_CHANNEL_CONTROL_ID:
+ {
+ menu_data.preset->emu_cdda |= TSU_OptionGroupGetKeySelected((OptionGroup *)drawable);
+ }
+ break;
+
+ case PATCH_ADDRESS1_CONTROL_ID:
+ {
+ }
+ break;
+
+ case PATCH_VALUE1_CONTROL_ID:
+ {
+ }
+ break;
+
+ case PATCH_ADDRESS2_CONTROL_ID:
+ {
+ }
+ break;
+
+ case PATCH_VALUE2_CONTROL_ID:
+ {
+ }
+ break;
+
+ case ALTERBOOT_CONTROL_ID:
+ {
+ menu_data.preset->alt_boot = TSU_CheckBoxGetValue((CheckBox *)drawable);
+ }
+ break;
+
+ case SCREENSHOT_CONTROL_ID:
+ {
+ menu_data.preset->screenshot = TSU_CheckBoxGetValue((CheckBox *)drawable);
+ }
+ break;
+
+ case VMU_CONTROL_ID:
+ {
+ }
+ break;
+
+ case VMUSELECTOR_CONTROL_ID:
+ {
+ menu_data.preset->vmu_mode = TSU_OptionGroupGetKeySelected((OptionGroup *)drawable);
+ }
+ break;
+
+ case SHORTCUT_SIZE_CONTROL_ID:
+ {
+ menu_data.preset->icon_size = TSU_OptionGroupGetKeySelected((OptionGroup *)drawable);
+ }
+ break;
+
+ case SHORTCUT_ROTATE_CONTROL_ID:
+ {
+ menu_data.preset->rotate_image = TSU_CheckBoxGetValue((CheckBox *)drawable);
+ }
+ break;
+
+ case SHORTCUT_NAME_CONTROL_ID:
+ {
+ }
+ break;
+
+ case SHORTCUT_DONTSHOWNAME_CONTROL_ID:
+ {
+ menu_data.preset->dont_show_name = TSU_CheckBoxGetValue((CheckBox *)drawable);
+ }
+ break;
+
+ case SHORTCUT_CREATE_CONTROL_ID:
+ {
+ }
+ break;
+ }
+}
+
+void CreateGeneralView(Form *form_ptr)
+{
+ TSU_FormtSetAttributes(form_ptr, 4, 9, 100, 34);
+
+ Font* form_font = TSU_FormGetTitleFont(form_ptr);
+ TSU_FormSetColumnSize(form_ptr, 1, 120);
+ TSU_FormSetColumnSize(form_ptr, 2, 170);
+ TSU_FormSetColumnSize(form_ptr, 3, 140);
+ TSU_FormSetColumnSize(form_ptr, 4, 170);
+ TSU_FormSetRowSize(form_ptr, 7, 34);
+ TSU_FormSetTitle(form_ptr, "SETTINGS - PRESET");
+
+ int body_letter_size = self.body_letter_size - 2;
+ uint body_height_size = self.body_height_size - 4;
+
+ {
+ // SAVE
+ Label *save_label = TSU_LabelCreate(form_font, "SAVE AS PRESET:", body_letter_size, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)save_label, true);
+ TSU_FormAddBodyLabel(form_ptr, save_label, 1, 1);
+
+ self.save_preset_option = TSU_CheckBoxCreate(form_font, (uint)body_letter_size, 50, body_height_size);
+ TSU_DrawableSetId((Drawable *)self.save_preset_option, SAVE_CONTROL_ID);
+
+ TSU_FormAddBodyCheckBox(form_ptr, self.save_preset_option, 2, 1);
+ TSU_DrawableEventSetClick((Drawable *)self.save_preset_option, &SavePresetOptionClick);
+
+ if (self.save)
+ {
+ TSU_CheckBoxSetOn(self.save_preset_option);
+ }
+
+ Vector save_vector = TSU_DrawableGetPosition((Drawable *)self.save_preset_option);
+ save_vector.x += 80;
+ TSU_DrawableSetTranslate((Drawable *)self.save_preset_option, &save_vector);
+ TSU_FormSetCursor(form_ptr, (Drawable *)self.save_preset_option);
+
+ save_label = NULL;
+ }
+
+ {
+ // DMA
+ Label *dma_label = TSU_LabelCreate(form_font, "DMA:", body_letter_size, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)dma_label, true);
+ TSU_FormAddBodyLabel(form_ptr, dma_label, 1, 2);
+
+ self.dma_option = TSU_CheckBoxCreate(form_font, (uint)body_letter_size, 50, body_height_size);
+ TSU_DrawableSetId((Drawable *)self.dma_option, DMA_CONTROL_ID);
+
+ TSU_FormAddBodyCheckBox(form_ptr, self.dma_option, 2, 2);
+ TSU_DrawableEventSetClick((Drawable *)self.dma_option, &DMAOptionClick);
+
+ if (menu_data.preset->use_dma)
+ {
+ TSU_CheckBoxSetOn(self.dma_option);
+ }
+
+ dma_label = NULL;
+ }
+
+ {
+ // ASYNC
+ Label *async_label = TSU_LabelCreate(form_font, "ASYNC:", body_letter_size, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)async_label, true);
+ TSU_FormAddBodyLabel(form_ptr, async_label, 1, 3);
+
+ self.async_option = TSU_OptionGroupCreate(form_font, (uint)body_letter_size, 80, body_height_size);
+ TSU_DrawableSetId((Drawable *)self.async_option, ASYNC_CONTROL_ID);
+
+ if (TSU_CheckBoxGetValue(self.dma_option))
+ {
+ TSU_OptionGroupAdd(self.async_option, 0, "TRUE");
+ }
+ else
+ {
+ TSU_OptionGroupAdd(self.async_option, 0, "NONE");
+ }
+
+ TSU_OptionGroupAdd(self.async_option, 1, "1");
+ TSU_OptionGroupAdd(self.async_option, 2, "2");
+ TSU_OptionGroupAdd(self.async_option, 3, "3");
+ TSU_OptionGroupAdd(self.async_option, 4, "4");
+ TSU_OptionGroupAdd(self.async_option, 5, "5");
+ TSU_OptionGroupAdd(self.async_option, 6, "6");
+ TSU_OptionGroupAdd(self.async_option, 7, "7");
+ TSU_OptionGroupAdd(self.async_option, 8, "8");
+ TSU_OptionGroupAdd(self.async_option, 16, "16");
+ TSU_OptionGroupSetStates(self.async_option, SA_CONTROL + ASYNC_CONTROL_ID, SA_PRESET_MENU, &menu_data.state_app);
+ TSU_FormAddBodyOptionGroup(form_ptr, self.async_option, 2, 3);
+ TSU_DrawableEventSetClick((Drawable *)self.async_option, &AsyncOptionClick);
+
+ if (menu_data.preset->emu_async)
+ {
+ TSU_OptionGroupSelectOptionByKey(self.async_option, menu_data.preset->emu_async);
+ }
+
+ async_label = NULL;
+ }
+
+ {
+ // BY PASS
+ Label *bypass_label = TSU_LabelCreate(form_font, "BY PASS:", body_letter_size, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)bypass_label, true);
+ TSU_FormAddBodyLabel(form_ptr, bypass_label, 1, 4);
+
+ self.bypass_option = TSU_CheckBoxCreate(form_font, (uint)body_letter_size, 50, body_height_size);
+ TSU_DrawableSetId((Drawable *)self.bypass_option, BYPASS_CONTROL_ID);
+
+ TSU_FormAddBodyCheckBox(form_ptr, self.bypass_option, 2, 4);
+ TSU_DrawableEventSetClick((Drawable *)self.bypass_option, &ByPassOptionClick);
+
+ if (menu_data.preset->alt_read)
+ {
+ TSU_CheckBoxSetOn(self.bypass_option);
+ }
+
+ bypass_label = NULL;
+ }
+
+ {
+ // IRQ
+ Label *irq_label = TSU_LabelCreate(form_font, "IRQ:", body_letter_size, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)irq_label, true);
+ TSU_FormAddBodyLabel(form_ptr, irq_label, 1, 5);
+
+ self.irq_option = TSU_CheckBoxCreate(form_font, (uint)body_letter_size, 50, body_height_size);
+ TSU_DrawableSetId((Drawable *)self.irq_option, IRQ_CONTROL_ID);
+
+ TSU_FormAddBodyCheckBox(form_ptr, self.irq_option, 2, 5);
+ TSU_DrawableEventSetClick((Drawable *)self.irq_option, &IRQOptionClick);
+
+ if (menu_data.preset->use_irq)
+ {
+ TSU_CheckBoxSetOn(self.irq_option);
+ }
+
+ irq_label = NULL;
+ }
+
+ {
+ // LOADER
+ Label *loader_label = TSU_LabelCreate(form_font, "LOADER FW:", body_letter_size, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)loader_label, true);
+ TSU_FormAddBodyLabel(form_ptr, loader_label, 1, 6);
+
+ self.loader_option = TSU_OptionGroupCreate(form_font, (uint)body_letter_size, 130, body_height_size);
+ TSU_DrawableSetId((Drawable *)self.loader_option, LOADER_CONTROL_ID);
+
+ TSU_OptionGroupSetStates(self.loader_option, SA_CONTROL + LOADER_CONTROL_ID, SA_PRESET_MENU, &menu_data.state_app);
+ TSU_OptionGroupAdd(self.loader_option, 0, "auto");
+
+ for (int i = 0; i < menu_data.firmware_array_count; i++)
+ {
+ TSU_OptionGroupAdd(self.loader_option, i+1, menu_data.firmware_array[i].file);
+ }
+
+ TSU_FormAddBodyOptionGroup(form_ptr, self.loader_option, 2, 6);
+ TSU_DrawableEventSetClick((Drawable *)self.loader_option, &LoaderOptionClick);
+
+ if (menu_data.preset->device[0] != '\0')
+ {
+ TSU_OptionGroupSelectOptionByText(self.loader_option, menu_data.preset->device);
+ }
+
+ loader_label = NULL;
+ }
+
+ {
+ // OS
+ Label *os_label = TSU_LabelCreate(form_font, "OS:", body_letter_size, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)os_label, true);
+ TSU_FormAddBodyLabel(form_ptr, os_label, 3, 2);
+
+ self.os_option = TSU_OptionGroupCreate(form_font, (uint)body_letter_size, 130, body_height_size);
+ TSU_DrawableSetId((Drawable *)self.os_option, OS_CONTROL_ID);
+
+ TSU_OptionGroupAdd(self.os_option, 0, "AUTO");
+ TSU_OptionGroupAdd(self.os_option, 1, "KATANA");
+ TSU_OptionGroupAdd(self.os_option, 2, "HOMEBREW");
+ TSU_OptionGroupAdd(self.os_option, 3, "WinCE");
+ TSU_OptionGroupSetStates(self.os_option, SA_CONTROL + OS_CONTROL_ID, SA_PRESET_MENU, &menu_data.state_app);
+ TSU_FormAddBodyOptionGroup(form_ptr, self.os_option, 4, 2);
+ TSU_DrawableEventSetClick((Drawable *)self.os_option, &OSOptionClick);
+
+ if (menu_data.preset->bin_type)
+ {
+ TSU_OptionGroupSelectOptionByKey(self.os_option, menu_data.preset->bin_type);
+ }
+
+ os_label = NULL;
+ }
+
+ {
+ // BOOT MODE
+ Label *boot_label = TSU_LabelCreate(form_font, "BOOT MODE:", body_letter_size, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)boot_label, true);
+ TSU_FormAddBodyLabel(form_ptr, boot_label, 3, 3);
+
+ self.boot_option = TSU_OptionGroupCreate(form_font, (uint)body_letter_size, 120, body_height_size);
+ TSU_DrawableSetId((Drawable *)self.boot_option, BOOT_CONTROL_ID);
+
+ TSU_OptionGroupAdd(self.boot_option, BOOT_MODE_DIRECT, "DIRECT");
+ TSU_OptionGroupAdd(self.boot_option, BOOT_MODE_IPBIN, "IP.BIN");
+ TSU_OptionGroupAdd(self.boot_option, BOOT_MODE_IPBIN_TRUNC, "IP.BIN CUT");
+ TSU_OptionGroupSetStates(self.boot_option, SA_CONTROL + BOOT_CONTROL_ID, SA_PRESET_MENU, &menu_data.state_app);
+ TSU_FormAddBodyOptionGroup(form_ptr, self.boot_option, 4, 3);
+ TSU_DrawableEventSetClick((Drawable *)self.boot_option, &BootOptionClick);
+
+ if (menu_data.preset->boot_mode)
+ {
+ TSU_OptionGroupSelectOptionByKey(self.boot_option, menu_data.preset->boot_mode);
+ }
+
+ boot_label = NULL;
+ }
+
+ {
+ // FAST BOOT
+ Label *fast_label = TSU_LabelCreate(form_font, "FAST BOOT:", body_letter_size, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)fast_label, true);
+ TSU_FormAddBodyLabel(form_ptr, fast_label, 3, 4);
+
+ self.fast_option = TSU_CheckBoxCreate(form_font, (uint)body_letter_size, 50, body_height_size);
+ TSU_DrawableSetId((Drawable *)self.fast_option, FASTBOOT_CONTROL_ID);
+
+ TSU_FormAddBodyCheckBox(form_ptr, self.fast_option, 4, 4);
+ TSU_DrawableEventSetClick((Drawable *)self.fast_option, &FastOptionClick);
+
+ if (menu_data.preset->fastboot)
+ {
+ TSU_CheckBoxSetOn(self.fast_option);
+ }
+
+ fast_label = NULL;
+ }
+
+ {
+ // LOW LEVEL
+ Label *lowlevel_label = TSU_LabelCreate(form_font, "LOW LEVEL:", body_letter_size, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)lowlevel_label, true);
+ TSU_FormAddBodyLabel(form_ptr, lowlevel_label, 3, 5);
+
+ self.lowlevel_option = TSU_CheckBoxCreate(form_font, (uint)body_letter_size, 50, body_height_size);
+ TSU_DrawableSetId((Drawable *)self.lowlevel_option, LOWLEVEL_CONTROL_ID);
+
+ TSU_FormAddBodyCheckBox(form_ptr, self.lowlevel_option, 4, 5);
+ TSU_DrawableEventSetClick((Drawable *)self.lowlevel_option, &LowLevelOptionClick);
+
+ if (menu_data.preset->low)
+ {
+ TSU_CheckBoxSetOn(self.lowlevel_option);
+ }
+
+ lowlevel_label = NULL;
+ }
+
+ {
+ // MEMORY
+ Label *memory_label = TSU_LabelCreate(form_font, "LOADER :\n\nMEMORY", body_letter_size, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)memory_label, true);
+ TSU_FormAddBodyLabel(form_ptr, memory_label, 1, 7);
+
+ self.memory_option = TSU_OptionGroupCreate(form_font, (uint)body_letter_size, 130, body_height_size);
+ TSU_DrawableSetId((Drawable *)self.memory_option, MEMORY_CONTROL_ID);
+
+ TSU_OptionGroupAdd(self.memory_option, 1, "0x8c000100");
+ TSU_OptionGroupAdd(self.memory_option, 2, "0x8c001100");
+ TSU_OptionGroupAdd(self.memory_option, 3, "0x8c004000");
+ TSU_OptionGroupAdd(self.memory_option, 4, "0x8c004800");
+ TSU_OptionGroupAdd(self.memory_option, 5, "0x8c008000");
+ TSU_OptionGroupAdd(self.memory_option, 6, "0x8ce00000");
+ TSU_OptionGroupAdd(self.memory_option, 7, "0x8cef8000");
+ TSU_OptionGroupAdd(self.memory_option, 8, "0x8cf80000");
+ TSU_OptionGroupAdd(self.memory_option, 9, "0x8cfc0000");
+ TSU_OptionGroupAdd(self.memory_option, 10, "0x8cfd0000");
+ TSU_OptionGroupAdd(self.memory_option, 11, "0x8cfe0000");
+ TSU_OptionGroupAdd(self.memory_option, 12, "0x8cfe8000");
+ TSU_OptionGroupAdd(self.memory_option, 13, "0x8cff0000");
+ TSU_OptionGroupAdd(self.memory_option, 14, "0x8cff4800");
+ TSU_OptionGroupAdd(self.memory_option, 15, "0x8d000000");
+ TSU_OptionGroupAdd(self.memory_option, 16, "0x8c");
+ TSU_OptionGroupSetStates(self.memory_option, SA_CONTROL + MEMORY_CONTROL_ID, SA_PRESET_MENU, &menu_data.state_app);
+ TSU_FormAddBodyOptionGroup(form_ptr, self.memory_option, 2, 7);
+ TSU_DrawableEventSetClick((Drawable *)self.memory_option, &MemoryOptionClick);
+
+ if (menu_data.preset->memory[0] != 0)
+ {
+ if (TSU_OptionGroupGetOptionByText(self.memory_option, menu_data.preset->memory) != NULL)
+ {
+ TSU_OptionGroupSelectOptionByText(self.memory_option, menu_data.preset->memory);
+ }
+ else
+ {
+ TSU_OptionGroupSelectOptionByText(self.memory_option, "0x8c");
+ memset(menu_data.preset->custom_memory, 0, sizeof(menu_data.preset->custom_memory));
+
+ if (strlen(menu_data.preset->memory) == 10)
+ {
+ strcpy(menu_data.preset->custom_memory, &menu_data.preset->memory[4]);
+ memset(menu_data.preset->memory, 0, sizeof(menu_data.preset->memory));
+ strcpy(menu_data.preset->memory, "0x8c");
+ }
+ else
+ {
+ TSU_OptionGroupSelectOptionByText(self.memory_option, "0x8c000100");
+ }
+ }
+ }
+
+ memory_label = NULL;
+ }
+
+ {
+ // CUSTOM MEMORY
+ self.custom_memory_option = TSU_TextBoxCreate(self.textbox_font, (uint)body_letter_size, false, 130, body_height_size, true, false, true, false);
+ TSU_DrawableSetId((Drawable *)self.custom_memory_option, CUSTOM_MEMORY_CONTROL_ID);
+
+ TSU_TextBoxSetStates(self.custom_memory_option, SA_CONTROL + CUSTOM_MEMORY_CONTROL_ID, SA_PRESET_MENU, &menu_data.state_app);
+ TSU_FormAddBodyTextBox(form_ptr, self.custom_memory_option, 3, 7);
+ TSU_DrawableEventSetClick((Drawable *)self.custom_memory_option, &CustomMemoryOptionClick);
+
+ TSU_TextBoxSetText(self.custom_memory_option, menu_data.preset->custom_memory);
+ }
+
+ {
+ // HEAP
+ Label *heap_label = TSU_LabelCreate(form_font, "HEAP :\n\nMEMORY", body_letter_size, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)heap_label, true);
+ TSU_FormAddBodyLabel(form_ptr, heap_label, 1, 9);
+
+ self.heap_option = TSU_OptionGroupCreate(form_font, (uint)body_letter_size, 320, body_height_size);
+ TSU_DrawableSetId((Drawable *)self.heap_option, HEAP_CONTROL_ID);
+
+ TSU_OptionGroupAdd(self.heap_option, HEAP_MODE_AUTO, "AUTO");
+ TSU_OptionGroupAdd(self.heap_option, HEAP_MODE_BEHIND, "BEHIND THE LOADER");
+ TSU_OptionGroupAdd(self.heap_option, HEAP_MODE_INGAME, "INGAME HEAP (KATANA ONLY)");
+ TSU_OptionGroupAdd(self.heap_option, HEAP_MODE_MAPLE, "MAPPLE DMA BUFFER");
+ TSU_OptionGroupAdd(self.heap_option, (int32)0x8c000100, "0x8c000100");
+ TSU_OptionGroupAdd(self.heap_option, (int32)0x8c001100, "0x8c001100");
+ TSU_OptionGroupAdd(self.heap_option, (int32)0x8c004000, "0x8c004000");
+ TSU_OptionGroupAdd(self.heap_option, (int32)0x8c004800, "0x8c004800");
+ TSU_OptionGroupAdd(self.heap_option, (int32)0x8c008000, "0x8c008000");
+ TSU_OptionGroupAdd(self.heap_option, (int32)0x8ce00000, "0x8ce00000");
+ TSU_OptionGroupAdd(self.heap_option, (int32)0x8cef8000, "0x8cef8000");
+ TSU_OptionGroupAdd(self.heap_option, (int32)0x8cf80000, "0x8cf80000");
+ TSU_OptionGroupAdd(self.heap_option, (int32)0x8cfc0000, "0x8cfc0000");
+ TSU_OptionGroupAdd(self.heap_option, (int32)0x8cfd0000, "0x8cfd0000");
+ TSU_OptionGroupAdd(self.heap_option, (int32)0x8cfe0000, "0x8cfe0000");
+ TSU_OptionGroupAdd(self.heap_option, (int32)0x8cfe8000, "0x8cfe8000");
+ TSU_OptionGroupAdd(self.heap_option, (int32)0x8cff0000, "0x8cff0000");
+ TSU_OptionGroupAdd(self.heap_option, (int32)0x8cff4800, "0x8cff4800");
+ TSU_OptionGroupAdd(self.heap_option, (int32)0x8d000000, "0x8d000000");
+ TSU_OptionGroupSetStates(self.heap_option, SA_CONTROL + HEAP_CONTROL_ID, SA_PRESET_MENU, &menu_data.state_app);
+ TSU_FormAddBodyOptionGroup(form_ptr, self.heap_option, 2, 9);
+ TSU_DrawableEventSetClick((Drawable *)self.heap_option, &HeapOptionClick);
+
+ if (menu_data.preset->heap)
+ {
+ TSU_OptionGroupSelectOptionByKey(self.heap_option, (int32)menu_data.preset->heap);
+ }
+
+ heap_label = NULL;
+ }
+}
+
+void CreateCDDAView(Form *form_ptr)
+{
+ TSU_FormtSetAttributes(form_ptr, 4, 3, 100, 42);
+
+ Font* form_font = TSU_FormGetTitleFont(form_ptr);
+ TSU_FormSetColumnSize(form_ptr, 1, 110);
+ TSU_FormSetColumnSize(form_ptr, 2, 165);
+ TSU_FormSetColumnSize(form_ptr, 3, 150);
+ TSU_FormSetColumnSize(form_ptr, 4, 165);
+ TSU_FormSetTitle(form_ptr, "SETTINGS - PRESET");
+
+ {
+ // CDDA
+ Label *cdda_label = TSU_LabelCreate(form_font, "CDDA:", self.body_letter_size, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)cdda_label, true);
+ TSU_FormAddBodyLabel(form_ptr, cdda_label, 1, 1);
+
+ self.cdda_option = TSU_CheckBoxCreate(form_font, (uint)self.body_letter_size, 50, self.body_height_size);
+ TSU_DrawableSetId((Drawable *)self.cdda_option, CDDA_CONTROL_ID);
+
+ TSU_FormAddBodyCheckBox(form_ptr, self.cdda_option, 2, 1);
+ TSU_DrawableEventSetClick((Drawable *)self.cdda_option, &CDDAOptionClick);
+
+ if (menu_data.preset->cdda)
+ {
+ TSU_CheckBoxSetOn(self.cdda_option);
+ }
+
+ cdda_label = NULL;
+ }
+
+ {
+ // CDDA SOURCE
+ Label *cdda_source_label = TSU_LabelCreate(form_font, "Source:", self.body_letter_size, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)cdda_source_label, true);
+ TSU_FormAddBodyLabel(form_ptr, cdda_source_label, 1, 2);
+
+ self.cdda_source_option = TSU_OptionGroupCreate(form_font, (uint)self.body_letter_size, 120, self.body_height_size);
+ TSU_DrawableSetId((Drawable *)self.cdda_source_option, CDDA_SOURCE_CONTROL_ID);
+
+ TSU_OptionGroupAdd(self.cdda_source_option, CDDA_MODE_SRC_PIO, "PIO");
+ TSU_OptionGroupAdd(self.cdda_source_option, CDDA_MODE_SRC_DMA, "DMA");
+ TSU_OptionGroupSetStates(self.cdda_source_option, SA_CONTROL + CDDA_SOURCE_CONTROL_ID, SA_PRESET_MENU, &menu_data.state_app);
+ TSU_FormAddBodyOptionGroup(form_ptr, self.cdda_source_option, 2, 2);
+ TSU_DrawableEventSetClick((Drawable *)self.cdda_source_option, &CDDASourceOptionClick);
+
+ if (menu_data.preset->emu_cdda == CDDA_MODE_DISABLED)
+ {
+ TSU_OptionGroupSelectOptionByKey(self.cdda_source_option, (int32)CDDA_MODE_SRC_PIO);
+ }
+ else if (menu_data.preset->emu_cdda & CDDA_MODE_SRC_PIO)
+ {
+ TSU_OptionGroupSelectOptionByKey(self.cdda_source_option, (int32)CDDA_MODE_SRC_PIO);
+ }
+ else
+ {
+ TSU_OptionGroupSelectOptionByKey(self.cdda_source_option, (int32)CDDA_MODE_SRC_DMA);
+ }
+
+ cdda_source_label = NULL;
+ }
+
+ {
+ // CDDA DESTINATION
+ Label *cdda_destination_label = TSU_LabelCreate(form_font, "Destination:", self.body_letter_size, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)cdda_destination_label, true);
+ TSU_FormAddBodyLabel(form_ptr, cdda_destination_label, 3, 2);
+
+ self.cdda_destination_option = TSU_OptionGroupCreate(form_font, (uint)self.body_letter_size, 120, self.body_height_size);
+ TSU_DrawableSetId((Drawable *)self.cdda_destination_option, CDDA_DESTINATION_CONTROL_ID);
+
+ TSU_OptionGroupAdd(self.cdda_destination_option, 1, "PIO");
+ TSU_OptionGroupAdd(self.cdda_destination_option, CDDA_MODE_DST_SQ, "SQ");
+ TSU_OptionGroupAdd(self.cdda_destination_option, CDDA_MODE_DST_DMA, "DMA");
+ TSU_OptionGroupSetStates(self.cdda_destination_option, SA_CONTROL + CDDA_DESTINATION_CONTROL_ID, SA_PRESET_MENU, &menu_data.state_app);
+ TSU_FormAddBodyOptionGroup(form_ptr, self.cdda_destination_option, 4, 2);
+ TSU_DrawableEventSetClick((Drawable *)self.cdda_destination_option, &CDDADestinationOptionClick);
+
+ if (menu_data.preset->emu_cdda == CDDA_MODE_DISABLED)
+ {
+ TSU_OptionGroupSelectOptionByKey(self.cdda_destination_option, (int32)CDDA_MODE_DST_SQ);
+ }
+ else if (menu_data.preset->emu_cdda & CDDA_MODE_DST_SQ)
+ {
+ TSU_OptionGroupSelectOptionByKey(self.cdda_destination_option, (int32)CDDA_MODE_DST_SQ);
+ }
+ else
+ {
+ TSU_OptionGroupSelectOptionByKey(self.cdda_destination_option, (int32)CDDA_MODE_DST_DMA);
+ }
+
+ cdda_destination_label = NULL;
+ }
+
+ {
+ // CDDA POSITION
+ Label *cdda_position_label = TSU_LabelCreate(form_font, "Position:", self.body_letter_size, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)cdda_position_label, true);
+ TSU_FormAddBodyLabel(form_ptr, cdda_position_label, 1, 3);
+
+ self.cdda_position_option = TSU_OptionGroupCreate(form_font, (uint)self.body_letter_size, 120, self.body_height_size);
+ TSU_DrawableSetId((Drawable *)self.cdda_position_option, CDDA_POSITION_CONTROL_ID);
+
+ TSU_OptionGroupAdd(self.cdda_position_option, CDDA_MODE_POS_TMU1, "TMU1");
+ TSU_OptionGroupAdd(self.cdda_position_option, CDDA_MODE_POS_TMU2, "TMU2");
+ TSU_OptionGroupSetStates(self.cdda_position_option, SA_CONTROL + CDDA_POSITION_CONTROL_ID, SA_PRESET_MENU, &menu_data.state_app);
+ TSU_FormAddBodyOptionGroup(form_ptr, self.cdda_position_option, 2, 3);
+ TSU_DrawableEventSetClick((Drawable *)self.cdda_position_option, &CDDAPositionOptionClick);
+
+ if (menu_data.preset->emu_cdda == CDDA_MODE_DISABLED)
+ {
+ TSU_OptionGroupSelectOptionByKey(self.cdda_position_option, (int32)CDDA_MODE_POS_TMU1);
+ }
+ else if (menu_data.preset->emu_cdda & CDDA_MODE_POS_TMU1)
+ {
+ TSU_OptionGroupSelectOptionByKey(self.cdda_position_option, (int32)CDDA_MODE_POS_TMU1);
+ }
+ else
+ {
+ TSU_OptionGroupSelectOptionByKey(self.cdda_position_option, (int32)CDDA_MODE_POS_TMU2);
+ }
+
+ cdda_position_label = NULL;
+ }
+
+ {
+ // CDDA CHANNEL
+ Label *cdda_channel_label = TSU_LabelCreate(form_font, "Channel:", self.body_letter_size, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)cdda_channel_label, true);
+ TSU_FormAddBodyLabel(form_ptr, cdda_channel_label, 3, 3);
+
+ self.cdda_channel_option = TSU_OptionGroupCreate(form_font, (uint)self.body_letter_size, 120, self.body_height_size);
+ TSU_DrawableSetId((Drawable *)self.cdda_channel_option, CDDA_CHANNEL_CONTROL_ID);
+
+ TSU_OptionGroupAdd(self.cdda_channel_option, CDDA_MODE_CH_ADAPT, "Fixed");
+ TSU_OptionGroupAdd(self.cdda_channel_option, CDDA_MODE_CH_FIXED, "Adaptive");
+ TSU_OptionGroupSetStates(self.cdda_channel_option, SA_CONTROL + CDDA_CHANNEL_CONTROL_ID, SA_PRESET_MENU, &menu_data.state_app);
+ TSU_FormAddBodyOptionGroup(form_ptr, self.cdda_channel_option, 4, 3);
+ TSU_DrawableEventSetClick((Drawable *)self.cdda_channel_option, &CDDAChannelOptionClick);
+
+ if (menu_data.preset->emu_cdda == CDDA_MODE_DISABLED)
+ {
+ TSU_OptionGroupSelectOptionByKey(self.cdda_channel_option, (int32)CDDA_MODE_CH_ADAPT);
+ }
+ else if (menu_data.preset->emu_cdda & CDDA_MODE_CH_ADAPT)
+ {
+ TSU_OptionGroupSelectOptionByKey(self.cdda_channel_option, (int32)CDDA_MODE_CH_ADAPT);
+ }
+ else
+ {
+ TSU_OptionGroupSelectOptionByKey(self.cdda_channel_option, (int32)CDDA_MODE_CH_FIXED);
+ }
+
+ cdda_channel_label = NULL;
+ }
+}
+
+void CreatePatchView(Form *form_ptr)
+{
+ TSU_FormtSetAttributes(form_ptr, 2, 4, 100, 42);
+
+ Font* form_font = TSU_FormGetTitleFont(form_ptr);
+ TSU_FormSetColumnSize(form_ptr, 1, 220);
+ TSU_FormSetColumnSize(form_ptr, 2, 170);
+ TSU_FormSetTitle(form_ptr, "SETTINGS - PRESET");
+
+ {
+ // PATCH ADDRESS 1
+ Label *patch_addres1_label = TSU_LabelCreate(form_font, "PATCH ADDRESS 1:", self.body_letter_size, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)patch_addres1_label, true);
+ TSU_FormAddBodyLabel(form_ptr, patch_addres1_label, 1, 1);
+
+ self.patch_address1_option = TSU_TextBoxCreate(self.textbox_font, (uint)self.body_letter_size, false, 155, self.body_height_size, true, false, true, true);
+ TSU_DrawableSetId((Drawable *)self.patch_address1_option, PATCH_ADDRESS1_CONTROL_ID);
+
+ TSU_TextBoxSetStates(self.patch_address1_option, SA_CONTROL + PATCH_ADDRESS1_CONTROL_ID, SA_PRESET_MENU, &menu_data.state_app);
+ TSU_FormAddBodyTextBox(form_ptr, self.patch_address1_option, 2, 1);
+ TSU_DrawableEventSetClick((Drawable *)self.patch_address1_option, &PatchAddress1OptionClick);
+
+ if (menu_data.preset->pa[0] == 0) {
+ TSU_TextBoxSetText(self.patch_address1_option, "0c000000");
+ }
+ else {
+ TSU_TextBoxSetText(self.patch_address1_option, menu_data.preset->patch_a[0]);
+ }
+
+ patch_addres1_label = NULL;
+ }
+
+ {
+ // PATCH VALUE 1
+ Label *patch_value1_label = TSU_LabelCreate(form_font, "PATCH VALUE 1:", self.body_letter_size, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)patch_value1_label, true);
+ TSU_FormAddBodyLabel(form_ptr, patch_value1_label, 1, 2);
+
+ self.patch_value1_option = TSU_TextBoxCreate(self.textbox_font, (uint)self.body_letter_size, false, 155, self.body_height_size, true, false, true, true);
+ TSU_DrawableSetId((Drawable *)self.patch_value1_option, PATCH_VALUE1_CONTROL_ID);
+
+ TSU_TextBoxSetStates(self.patch_value1_option, SA_CONTROL + PATCH_VALUE1_CONTROL_ID, SA_PRESET_MENU, &menu_data.state_app);
+ TSU_FormAddBodyTextBox(form_ptr, self.patch_value1_option, 2, 2);
+ TSU_DrawableEventSetClick((Drawable *)self.patch_value1_option, &PatchValue1OptionClick);
+
+ if (menu_data.preset->pv[0] == 0) {
+ TSU_TextBoxSetText(self.patch_value1_option, "00000000");
+ }
+ else {
+ TSU_TextBoxSetText(self.patch_value1_option, menu_data.preset->patch_v[0]);
+ }
+
+ patch_value1_label = NULL;
+ }
+
+ {
+ // PATCH ADDRESS 2
+ Label *patch_addres2_label = TSU_LabelCreate(form_font, "PATCH ADDRESS 2:", self.body_letter_size, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)patch_addres2_label, true);
+ TSU_FormAddBodyLabel(form_ptr, patch_addres2_label, 1, 3);
+
+ self.patch_address2_option = TSU_TextBoxCreate(self.textbox_font, (uint)self.body_letter_size, false, 155, self.body_height_size, true, false, true, true);
+ TSU_DrawableSetId((Drawable *)self.patch_address2_option, PATCH_ADDRESS2_CONTROL_ID);
+
+ TSU_TextBoxSetStates(self.patch_address2_option, SA_CONTROL + PATCH_ADDRESS2_CONTROL_ID, SA_PRESET_MENU, &menu_data.state_app);
+ TSU_FormAddBodyTextBox(form_ptr, self.patch_address2_option, 2, 3);
+ TSU_DrawableEventSetClick((Drawable *)self.patch_address2_option, &PatchAddress2OptionClick);
+
+ if (menu_data.preset->pa[1] == 0) {
+ TSU_TextBoxSetText(self.patch_address2_option, "0c000000");
+ }
+ else {
+ TSU_TextBoxSetText(self.patch_address2_option, menu_data.preset->patch_a[1]);
+ }
+
+ patch_addres2_label = NULL;
+ }
+
+ {
+ // PATCH VALUE 2
+ Label *patch_value2_label = TSU_LabelCreate(form_font, "PATCH VALUE 2:", self.body_letter_size, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)patch_value2_label, true);
+ TSU_FormAddBodyLabel(form_ptr, patch_value2_label, 1, 4);
+
+ self.patchvalue2_option = TSU_TextBoxCreate(self.textbox_font, (uint)self.body_letter_size, false, 155, self.body_height_size, true, false, true, true);
+ TSU_DrawableSetId((Drawable *)self.patchvalue2_option, PATCH_VALUE2_CONTROL_ID);
+
+ TSU_TextBoxSetStates(self.patchvalue2_option, SA_CONTROL + PATCH_VALUE2_CONTROL_ID, SA_PRESET_MENU, &menu_data.state_app);
+ TSU_FormAddBodyTextBox(form_ptr, self.patchvalue2_option, 2, 4);
+ TSU_DrawableEventSetClick((Drawable *)self.patchvalue2_option, &PatchValue2OptionClick);
+
+ if (menu_data.preset->pv[1] == 0) {
+ TSU_TextBoxSetText(self.patchvalue2_option, "00000000");
+ }
+ else {
+ TSU_TextBoxSetText(self.patchvalue2_option, menu_data.preset->patch_v[1]);
+ }
+
+ patch_value2_label = NULL;
+ }
+}
+
+void CreateExtensionsView(Form *form_ptr)
+{
+ TSU_FormtSetAttributes(form_ptr, 5, 6, 100, 42);
+
+ Font* form_font = TSU_FormGetTitleFont(form_ptr);
+ TSU_FormSetColumnSize(form_ptr, 1, 250);
+ TSU_FormSetColumnSize(form_ptr, 2, 320);
+ TSU_FormSetRowSize(form_ptr, 3, 34);
+ TSU_FormSetRowSize(form_ptr, 4, 34);
+ TSU_FormSetTitle(form_ptr, "SETTINGS - EXTENSIONS");
+
+ {
+ // ALTER BOOT
+ Label *alterboot_label = TSU_LabelCreate(form_font, "Boot from 2ND_READ.BIN:", self.body_letter_size - 2, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)alterboot_label, true);
+ TSU_FormAddBodyLabel(form_ptr, alterboot_label, 1, 1);
+
+ self.altboot_option = TSU_CheckBoxCreate(form_font, (uint)self.body_letter_size - 2, 50, self.body_height_size);
+ TSU_DrawableSetId((Drawable *)self.altboot_option, ALTERBOOT_CONTROL_ID);
+
+ TSU_FormAddBodyCheckBox(form_ptr, self.altboot_option, 2, 1);
+ TSU_DrawableEventSetClick((Drawable *)self.altboot_option, &AlterBootOptionClick);
+
+ Vector altboot_vector = TSU_DrawableGetPosition((Drawable *)self.altboot_option);
+ altboot_vector.x += 50;
+ TSU_DrawableSetTranslate((Drawable *)self.altboot_option, &altboot_vector);
+
+ if (menu_data.preset->alt_boot)
+ {
+ TSU_CheckBoxSetOn(self.altboot_option);
+ }
+
+ alterboot_label = NULL;
+ }
+
+ {
+ // SCREENSHOT
+ Label *screenshot_label = TSU_LabelCreate(form_font, "Enable screenshots:", self.body_letter_size - 2, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)screenshot_label, true);
+ TSU_FormAddBodyLabel(form_ptr, screenshot_label, 1, 2);
+
+ self.screenshot_option = TSU_CheckBoxCreate(form_font, (uint)self.body_letter_size - 2, 50, self.body_height_size);
+ TSU_DrawableSetId((Drawable *)self.screenshot_option, SCREENSHOT_CONTROL_ID);
+
+ TSU_FormAddBodyCheckBox(form_ptr, self.screenshot_option, 2, 2);
+ TSU_DrawableEventSetClick((Drawable *)self.screenshot_option, &ScreenshotOptionClick);
+
+ Vector screenshot_vector = TSU_DrawableGetPosition((Drawable *)self.screenshot_option);
+ screenshot_vector.x += 50;
+ TSU_DrawableSetTranslate((Drawable *)self.screenshot_option, &screenshot_vector);
+
+ if (menu_data.preset->screenshot)
+ {
+ TSU_CheckBoxSetOn(self.screenshot_option);
+ }
+
+ screenshot_label = NULL;
+ }
+
+ Vector init_button_position, start_button_vector, a_button_vector;
+ {
+ self.button_start_option = TSU_CheckBoxCreateWithCustomText(form_font, (uint)self.body_letter_size - 3, 52, self.body_height_size - 6, "START", "START");
+ TSU_DrawableSetId((Drawable *)self.button_start_option, BUTTON_START_CONTROL_ID);
+
+ TSU_FormAddBodyCheckBox(form_ptr, self.button_start_option, 1, 3);
+ TSU_DrawableEventSetClick((Drawable *)self.button_start_option, &ButtonStartOptionClick);
+
+ init_button_position = start_button_vector = TSU_DrawableGetPosition((Drawable *)self.button_start_option);
+ start_button_vector.x += 40;
+ TSU_DrawableSetTranslate((Drawable *)self.button_start_option, &start_button_vector);
+
+ if (self.button_start)
+ {
+ TSU_CheckBoxSetOn(self.button_start_option);
+ }
+ }
+
+ {
+ self.button_x_option = TSU_CheckBoxCreateWithCustomText(form_font, (uint)self.body_letter_size - 2, 36, self.body_height_size - 6, "x", "x");
+ TSU_DrawableSetId((Drawable *)self.button_x_option, BUTTON_X_CONTROL_ID);
+
+ TSU_FormAddBodyCheckBox(form_ptr, self.button_x_option, 2, 3);
+ TSU_DrawableEventSetClick((Drawable *)self.button_x_option, &ButtonXOptionClick);
+
+ start_button_vector.x += 120;
+ TSU_DrawableSetTranslate((Drawable *)self.button_x_option, &start_button_vector);
+
+ if (self.button_x)
+ {
+ TSU_CheckBoxSetOn(self.button_x_option);
+ }
+ }
+
+ {
+ self.button_y_option = TSU_CheckBoxCreateWithCustomText(form_font, (uint)self.body_letter_size - 2, 36, self.body_height_size - 6, "y", "y");
+ TSU_DrawableSetId((Drawable *)self.button_y_option, BUTTON_Y_CONTROL_ID);
+
+ TSU_FormAddBodyCheckBox(form_ptr, self.button_y_option, 3, 3);
+ TSU_DrawableEventSetClick((Drawable *)self.button_y_option, &ButtonYOptionClick);
+
+ start_button_vector.x += 100;
+ TSU_DrawableSetTranslate((Drawable *)self.button_y_option, &start_button_vector);
+
+ if (self.button_y)
+ {
+ TSU_CheckBoxSetOn(self.button_y_option);
+ }
+ }
+
+ {
+ self.button_z_option = TSU_CheckBoxCreateWithCustomText(form_font, (uint)self.body_letter_size - 2, 36, self.body_height_size - 6, "z", "z");
+ TSU_DrawableSetId((Drawable *)self.button_z_option, BUTTON_Z_CONTROL_ID);
+
+ TSU_FormAddBodyCheckBox(form_ptr, self.button_z_option, 4, 3);
+ TSU_DrawableEventSetClick((Drawable *)self.button_z_option, &ButtonZOptionClick);
+
+ start_button_vector.x += 100;
+ TSU_DrawableSetTranslate((Drawable *)self.button_z_option, &start_button_vector);
+
+ if (self.button_z)
+ {
+ TSU_CheckBoxSetOn(self.button_z_option);
+ }
+ }
+
+ if (1 != 1) // DISABLED
+ {
+ self.button_lt_option = TSU_CheckBoxCreateWithCustomText(form_font, (uint)self.body_letter_size - 2, 36, self.body_height_size - 6, "lt", "lt");
+ TSU_DrawableSetId((Drawable *)self.button_lt_option, BUTTON_LT_CONTROL_ID);
+
+ TSU_FormAddBodyCheckBox(form_ptr, self.button_lt_option, 5, 3);
+ TSU_DrawableEventSetClick((Drawable *)self.button_lt_option, &ButtonLTOptionClick);
+
+ start_button_vector.x += 100;
+ TSU_DrawableSetTranslate((Drawable *)self.button_lt_option, &start_button_vector);
+
+ if (self.button_lt)
+ {
+ TSU_CheckBoxSetOn(self.button_lt_option);
+ }
+ }
+
+ init_button_position.x += 160;
+ {
+ self.button_a_option = TSU_CheckBoxCreateWithCustomText(form_font, (uint)self.body_letter_size - 2, 36, self.body_height_size - 6, "a", "a");
+ TSU_DrawableSetId((Drawable *)self.button_a_option, BUTTON_A_CONTROL_ID);
+
+ TSU_FormAddBodyCheckBox(form_ptr, self.button_a_option, 2, 4);
+ TSU_DrawableEventSetClick((Drawable *)self.button_a_option, &ButtonAOptionClick);
+
+ a_button_vector = TSU_DrawableGetPosition((Drawable *)self.button_a_option);
+ a_button_vector.x = init_button_position.x;
+ TSU_DrawableSetTranslate((Drawable *)self.button_a_option, &a_button_vector);
+
+ if (self.button_a)
+ {
+ TSU_CheckBoxSetOn(self.button_a_option);
+ }
+ }
+
+ {
+ self.button_b_option = TSU_CheckBoxCreateWithCustomText(form_font, (uint)self.body_letter_size - 2, 36, self.body_height_size - 6, "b", "b");
+ TSU_DrawableSetId((Drawable *)self.button_b_option, BUTTON_B_CONTROL_ID);
+
+ TSU_FormAddBodyCheckBox(form_ptr, self.button_b_option, 3, 4);
+ TSU_DrawableEventSetClick((Drawable *)self.button_b_option, &ButtonBOptionClick);
+
+ a_button_vector.x += 100;
+ TSU_DrawableSetTranslate((Drawable *)self.button_b_option, &a_button_vector);
+
+ if (self.button_b)
+ {
+ TSU_CheckBoxSetOn(self.button_b_option);
+ }
+ }
+
+ {
+ self.button_c_option = TSU_CheckBoxCreateWithCustomText(form_font, (uint)self.body_letter_size - 2, 36, self.body_height_size - 6, "c", "c");
+ TSU_DrawableSetId((Drawable *)self.button_c_option, BUTTON_C_CONTROL_ID);
+
+ TSU_FormAddBodyCheckBox(form_ptr, self.button_c_option, 4, 4);
+ TSU_DrawableEventSetClick((Drawable *)self.button_c_option, &ButtonCOptionClick);
+
+ a_button_vector.x += 100;
+ TSU_DrawableSetTranslate((Drawable *)self.button_c_option, &a_button_vector);
+
+ if (self.button_c)
+ {
+ TSU_CheckBoxSetOn(self.button_c_option);
+ }
+ }
+
+ if (1 != 1) // DISABLED
+ {
+ self.button_rt_option = TSU_CheckBoxCreateWithCustomText(form_font, (uint)self.body_letter_size - 2, 36, self.body_height_size - 6, "rt", "rt");
+ TSU_DrawableSetId((Drawable *)self.button_rt_option, BUTTON_RT_CONTROL_ID);
+
+ TSU_FormAddBodyCheckBox(form_ptr, self.button_rt_option, 5, 4);
+ TSU_DrawableEventSetClick((Drawable *)self.button_rt_option, &ButtonRTOptionClick);
+
+ a_button_vector.x += 100;
+ TSU_DrawableSetTranslate((Drawable *)self.button_rt_option, &a_button_vector);
+
+ if (self.button_rt)
+ {
+ TSU_CheckBoxSetOn(self.button_rt_option);
+ }
+ }
+
+ {
+ // VMU EMULATION
+ Label *vmu_label = TSU_LabelCreate(form_font, "VMU EMULATION:", self.body_letter_size - 2, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)vmu_label, true);
+ TSU_FormAddBodyLabel(form_ptr, vmu_label, 1, 5);
+
+ self.vmu_option = TSU_TextBoxCreate(self.textbox_font, (uint)self.body_letter_size - 2, false, 130, self.body_height_size, false, false, true, false);
+ TSU_DrawableSetId((Drawable *)self.vmu_option, VMU_CONTROL_ID);
+
+ TSU_TextBoxSetStates(self.vmu_option, SA_CONTROL + VMU_CONTROL_ID, SA_PRESET_MENU, &menu_data.state_app);
+ TSU_FormAddBodyTextBox(form_ptr, self.vmu_option, 2, 5);
+ TSU_DrawableEventSetClick((Drawable *)self.vmu_option, &VMUOptionClick);
+
+ memset(menu_data.preset->vmu_file, 0, sizeof(menu_data.preset->vmu_file));
+ if (menu_data.preset->emu_vmu)
+ {
+ snprintf(menu_data.preset->vmu_file, sizeof(menu_data.preset->vmu_file), "%03ld", menu_data.preset->emu_vmu);
+ TSU_TextBoxSetText(self.vmu_option, menu_data.preset->vmu_file);
+ }
+ else
+ {
+ menu_data.preset->emu_vmu = atoi(DEFAULT_VMU_NUMBER);
+ strcpy(menu_data.preset->vmu_file, DEFAULT_VMU_NUMBER);
+ TSU_TextBoxSetText(self.vmu_option, menu_data.preset->vmu_file);
+ }
+
+ vmu_label = NULL;
+ }
+
+ {
+ // VMU SELECTOR MODE
+ self.vmu_selector_option = TSU_OptionGroupCreate(form_font, (uint)self.body_letter_size - 2, 320, self.body_height_size);
+ TSU_DrawableSetId((Drawable *)self.vmu_selector_option, VMUSELECTOR_CONTROL_ID);
+
+ TSU_OptionGroupAdd(self.vmu_selector_option, 0, "Disable");
+ TSU_OptionGroupAdd(self.vmu_selector_option, 1, "Shared dump from root");
+ TSU_OptionGroupAdd(self.vmu_selector_option, 2, "Private dump 200 blocks (128 KB)");
+ TSU_OptionGroupAdd(self.vmu_selector_option, 3, "Private dump 1800 blocks (1024 KB)");
+ TSU_OptionGroupSetStates(self.vmu_selector_option, SA_CONTROL + VMUSELECTOR_CONTROL_ID, SA_PRESET_MENU, &menu_data.state_app);
+ TSU_FormAddBodyOptionGroup(form_ptr, self.vmu_selector_option, 2, 6);
+ TSU_DrawableEventSetClick((Drawable *)self.vmu_selector_option, &VMUSelectorOptionClick);
+
+ if (menu_data.preset->vmu_mode)
+ {
+ TSU_OptionGroupSelectOptionByKey(self.vmu_selector_option, menu_data.preset->vmu_mode);
+ }
+ else
+ {
+ menu_data.preset->vmu_mode = 0;
+ TSU_OptionGroupSelectOptionByKey(self.vmu_selector_option, 0);
+ }
+ }
+}
+
+void CreateShortcutView(Form *form_ptr)
+{
+ TSU_FormtSetAttributes(form_ptr, 3, 6, 100, 42);
+
+ Font* form_font = TSU_FormGetTitleFont(form_ptr);
+ TSU_FormSetColumnSize(form_ptr, 1, 170);
+ TSU_FormSetColumnSize(form_ptr, 2, 170);
+ TSU_FormSetColumnSize(form_ptr, 3, 260);
+ TSU_FormSetRowSize(form_ptr, 6, 60);
+ TSU_FormSetTitle(form_ptr, "SETTINGS - SHORTCUT");
+
+ {
+ // SHORTCUT ICON SIZE
+ Label *shortcut_size_label = TSU_LabelCreate(form_font, "Icon size:", self.body_letter_size - 2, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)shortcut_size_label, true);
+ TSU_FormAddBodyLabel(form_ptr, shortcut_size_label, 1, 1);
+
+ self.shortcut_size_option = TSU_OptionGroupCreate(form_font, (uint)self.body_letter_size - 2, 170, self.body_height_size);
+ TSU_DrawableSetId((Drawable *)self.shortcut_size_option, SHORTCUT_SIZE_CONTROL_ID);
+
+ TSU_OptionGroupAdd(self.shortcut_size_option, 1, "48x48");
+ TSU_OptionGroupAdd(self.shortcut_size_option, 2, "64x64 (as apps)");
+ TSU_OptionGroupAdd(self.shortcut_size_option, 3, "96x96");
+ TSU_OptionGroupAdd(self.shortcut_size_option, 4, "128x128 (Default)");
+ TSU_OptionGroupAdd(self.shortcut_size_option, 5, "256x256");
+ TSU_OptionGroupSetStates(self.shortcut_size_option, SA_CONTROL + SHORTCUT_SIZE_CONTROL_ID, SA_PRESET_MENU, &menu_data.state_app);
+ TSU_FormAddBodyOptionGroup(form_ptr, self.shortcut_size_option, 2, 1);
+ TSU_DrawableEventSetClick((Drawable *)self.shortcut_size_option, &ShortcutSizeOptionClick);
+
+ if (menu_data.preset->icon_size)
+ {
+ TSU_OptionGroupSelectOptionByKey(self.shortcut_size_option, menu_data.preset->icon_size);
+ }
+ else
+ {
+ menu_data.preset->icon_size = 0;
+ TSU_OptionGroupSelectOptionByKey(self.shortcut_size_option, 4);
+ }
+
+ shortcut_size_label = NULL;
+ }
+
+ {
+ // SHORTCUT ROTATE IMAGE
+ Label *screenshot_rotateimage_label = TSU_LabelCreate(form_font, "Rotate image 180:", self.body_letter_size - 2, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)screenshot_rotateimage_label, true);
+ TSU_FormAddBodyLabel(form_ptr, screenshot_rotateimage_label, 1, 2);
+
+ self.shortcut_rotate_option = TSU_CheckBoxCreate(form_font, (uint)self.body_letter_size - 2, 50, self.body_height_size);
+ TSU_DrawableSetId((Drawable *)self.shortcut_rotate_option, SHORTCUT_ROTATE_CONTROL_ID);
+
+ TSU_FormAddBodyCheckBox(form_ptr, self.shortcut_rotate_option, 2, 2);
+ TSU_DrawableEventSetClick((Drawable *)self.shortcut_rotate_option, &ShortcutRotateOptionClick);
+
+ if (menu_data.preset->rotate_image)
+ {
+ TSU_CheckBoxSetOn(self.shortcut_rotate_option);
+ }
+
+ screenshot_rotateimage_label = NULL;
+ }
+
+ Vector name_label_vector;
+ {
+ // SHORTCUT NAME
+ Label *shortcut_name_label = TSU_LabelCreate(form_font, "Icon name:", self.body_letter_size - 2, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)shortcut_name_label, true);
+ TSU_FormAddBodyLabel(form_ptr, shortcut_name_label, 1, 3);
+ name_label_vector = TSU_DrawableGetPosition((Drawable *)shortcut_name_label);
+
+ self.shortcut_name_option = TSU_TextBoxCreate(self.textbox_font, (uint)self.body_letter_size - 2, false, 300, self.body_height_size, true, false, true, false);
+ TSU_DrawableSetId((Drawable *)self.shortcut_name_option, SHORTCUT_NAME_CONTROL_ID);
+
+ TSU_TextBoxSetStates(self.shortcut_name_option, SA_CONTROL + SHORTCUT_NAME_CONTROL_ID, SA_PRESET_MENU, &menu_data.state_app);
+ TSU_FormAddBodyTextBox(form_ptr, self.shortcut_name_option, 2, 4);
+ TSU_DrawableEventSetClick((Drawable *)self.shortcut_name_option, &ShortcutNameOptionClick);
+
+ Vector shortcut_name_vector = TSU_DrawableGetPosition((Drawable *)self.shortcut_name_option);
+ shortcut_name_vector.y -= 18;
+ shortcut_name_vector.x = name_label_vector.x;
+ TSU_DrawableSetTranslate((Drawable *)self.shortcut_name_option, &shortcut_name_vector);
+
+ if (menu_data.preset->shortcut_name[0] == '\0' || menu_data.preset->shortcut_name[0] == ' ')
+ {
+ char *game_without_extension = NULL;
+ GetCoverName(self.game_index, &game_without_extension);
+
+ memset(menu_data.preset->shortcut_name, 0, sizeof(menu_data.preset->shortcut_name));
+ strncpy(menu_data.preset->shortcut_name, game_without_extension, sizeof(menu_data.preset->shortcut_name) - 4);
+ free(game_without_extension);
+ }
+
+ TSU_TextBoxSetText(self.shortcut_name_option, menu_data.preset->shortcut_name);
+ shortcut_name_label = NULL;
+ }
+
+ {
+ // SHORTCUT DONT SHOW NAME
+ Label *shortcut_dontshowname_label = TSU_LabelCreate(form_font, "Don't show name:", self.body_letter_size - 2, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)shortcut_dontshowname_label, true);
+ TSU_FormAddBodyLabel(form_ptr, shortcut_dontshowname_label, 1, 5);
+
+ self.shortcut_dontshowname_option = TSU_CheckBoxCreate(form_font, (uint)self.body_letter_size - 2, 50, self.body_height_size);
+ TSU_DrawableSetId((Drawable *)self.shortcut_dontshowname_option, SHORTCUT_DONTSHOWNAME_CONTROL_ID);
+
+ TSU_FormAddBodyCheckBox(form_ptr, self.shortcut_dontshowname_option, 2, 5);
+ TSU_DrawableEventSetClick((Drawable *)self.shortcut_dontshowname_option, &ShortcutDontShowNameOptionClick);
+
+ if (menu_data.preset->dont_show_name)
+ {
+ TSU_CheckBoxSetOn(self.shortcut_dontshowname_option);
+ }
+
+ shortcut_dontshowname_label = NULL;
+ }
+
+ {
+ // CREATE SHORTCUT
+ char *image_path = (char *)malloc(NAME_MAX);
+ snprintf(image_path, NAME_MAX, "%s/%s", GetDefaultDir(menu_data.current_dev), "apps/games_menu/images/save.png");
+ self.shortcut_create_option = TSU_ItemMenuCreate(image_path, 32, 32, PVR_LIST_TR_POLY, "Create shortcut", self.menu_font, (uint)self.body_letter_size - 2, false, 0);
+ free(image_path);
+
+ TSU_DrawableSetId((Drawable *)self.shortcut_create_option, SHORTCUT_CREATE_CONTROL_ID);
+ TSU_FormAddBodyItemMenu(form_ptr, self.shortcut_create_option, 2, 6);
+ TSU_DrawableEventSetClick((Drawable *)self.shortcut_create_option, &ShortcutCreateOptionClick);
+
+ Vector shortcut_vector = TSU_DrawableGetPosition((Drawable *)self.shortcut_create_option);
+ shortcut_vector.y -= 22;
+ shortcut_vector.x = name_label_vector.x;
+ TSU_DrawableSetTranslate((Drawable *)self.shortcut_create_option, &shortcut_vector);
+ }
+
+ {
+ // COVER BANNER
+ ShortcutLoadTextureCover();
+ if (self.cover_texture != NULL)
+ {
+ uint16 cover_type = GetCoverType(self.game_index, MT_PLANE_TEXT);
+ self.cover_banner = TSU_BannerCreate(cover_type == IT_JPG ? PVR_LIST_OP_POLY : PVR_LIST_TR_POLY, self.cover_texture);
+ TSU_DrawableSetReadOnly((Drawable*)self.cover_banner, true);
+ TSU_BannerSetSize(self.cover_banner, 128, 128);
+ TSU_DrawableSetId((Drawable *)self.cover_banner, SHORTCUT_COVER_CONTROL_ID);
+ TSU_FormAddBodyBanner(form_ptr, self.cover_banner, 3, 5);
+
+ Vector banner_vector = TSU_DrawableGetPosition((Drawable *)self.cover_banner);
+ banner_vector.x += 256/2;
+ TSU_DrawableSetTranslate((Drawable *)self.cover_banner, &banner_vector);
+ }
+ }
+
+ CheckIfShorcutExits();
+}
+
+void ShortcutLoadTextureCover()
+{
+ if (TSU_CheckBoxGetValue(self.shortcut_rotate_option) != self.changed_yflip)
+ {
+ self.changed_yflip = TSU_CheckBoxGetValue(self.shortcut_rotate_option);
+ uint16 cover_type = GetCoverType(self.game_index, MT_PLANE_TEXT);
+
+ if (self.game_cover_path != NULL)
+ {
+ Texture *texture_tmp = TSU_TextureCreateFromFile(self.game_cover_path, cover_type != IT_JPG, self.changed_yflip, 0);
+ if (texture_tmp != NULL)
+ {
+ if (self.cover_banner != NULL)
+ {
+ TSU_BannerSetTexture(self.cover_banner, texture_tmp);
+ }
+
+ if (self.cover_texture != NULL)
+ {
+ TSU_TextureDestroy(&self.cover_texture);
+ }
+
+ self.cover_texture = texture_tmp;
+ texture_tmp = NULL;
+ }
+ }
+ else
+ {
+ // READ PVR
+ }
+ }
+}
+
+void ShowPresetMenu(int game_index)
+{
+ if (game_index >= 0)
+ {
+ self.changed_yflip = -1;
+ self.game_index = game_index;
+ memset(self.full_path_game, 0, sizeof(NAME_MAX));
+ strcpy(self.full_path_game, GetFullGamePathByIndex(self.game_index));
+
+ HidePresetMenu();
+
+ CheckCover(self.game_index, MT_PLANE_TEXT);
+ GetGameCoverPath(self.game_index, &self.game_cover_path, MT_PLANE_TEXT);
+
+ if (self.preset_menu_form == NULL)
+ {
+ self.save = menu_data.save_preset;
+ if (menu_data.preset == NULL || menu_data.preset->game_index != self.game_index)
+ {
+ if (menu_data.preset != NULL)
+ {
+ free(menu_data.preset);
+ }
+
+ menu_data.preset = LoadPresetGame(self.game_index);
+ }
+
+ SetModeScreenshot();
+
+ char font_path[NAME_MAX];
+ memset(font_path, 0, sizeof(font_path));
+ snprintf(font_path, sizeof(font_path), "%s/%s", GetDefaultDir(menu_data.current_dev), "apps/games_menu/fonts/default.txf");
+
+ Font *form_font = TSU_FontCreate(font_path, PVR_LIST_TR_POLY);
+
+ self.preset_menu_form = TSU_FormCreate(640/2 - 618/2, 480/2 + 450/2, 618, 455, true, 3, true, true, form_font, &OnViewIndexChangedEvent);
+ TSU_FormGetObjectsCurrentViewEvent(self.preset_menu_form, &OnGetObjectsCurrentViewEvent);
+
+ {
+ Label *general_label = TSU_LabelCreate(form_font, "GENERAL", 12, false, false);
+ TSU_FormAddBottomLabel(self.preset_menu_form, general_label);
+ general_label = NULL;
+ }
+
+ {
+ Label *cdda_label = TSU_LabelCreate(form_font, "CDDA", 12, false, false);
+ TSU_FormAddBottomLabel(self.preset_menu_form, cdda_label);
+ cdda_label = NULL;
+ }
+
+ {
+ Label *patch_label = TSU_LabelCreate(form_font, "PATCH", 12, false, false);
+ TSU_FormAddBottomLabel(self.preset_menu_form, patch_label);
+ patch_label = NULL;
+ }
+
+ {
+ Label *extensions_label = TSU_LabelCreate(form_font, "EXTS.", 12, false, false);
+ TSU_FormAddBottomLabel(self.preset_menu_form, extensions_label);
+ extensions_label = NULL;
+ }
+
+ {
+ Label *shortcut_label = TSU_LabelCreate(form_font, "SHORTCUT", 11, false, false);
+ TSU_FormAddBottomLabel(self.preset_menu_form, shortcut_label);
+ shortcut_label = NULL;
+ }
+
+ TSU_DrawableSubAdd((Drawable *)self.scene_ptr, (Drawable *)self.preset_menu_form);
+
+ Vector menu_position = TSU_DrawableGetPosition((Drawable *)self.preset_menu_form);
+ menu_position.y -= 200;
+ TSU_DrawableSetTranslate((Drawable *)self.preset_menu_form, &menu_position);
+
+ self.menu_init_animation = TSU_LogXYMoverCreate(0, 0);
+ TSU_DrawableAnimAdd((Drawable *)self.preset_menu_form, (Animation *)self.menu_init_animation);
+
+ form_font = NULL;
+ }
+ }
+}
+
+void HidePresetMenu()
+{
+ if (self.preset_menu_form != NULL)
+ {
+ TSU_FormOnGetObjectsCurrentView(self.preset_menu_form);
+
+ if (menu_data.preset->vmu_mode == 0)
+ {
+ menu_data.preset->emu_vmu = 0;
+ }
+
+ if (menu_data.preset->cdda == 0)
+ {
+ menu_data.preset->emu_cdda = CDDA_MODE_DISABLED;
+ }
+
+ if (menu_data.preset->vmu_mode || menu_data.preset->screenshot)
+ {
+ menu_data.preset->use_irq = 1;
+ }
+
+ if (strlen(menu_data.preset->memory) == 10)
+ {
+ memset(menu_data.preset->custom_memory, 0, sizeof(menu_data.preset->custom_memory));
+ }
+
+ if (self.save)
+ {
+ SavePresetGame(menu_data.preset);
+ }
+
+ if (self.menu_init_animation != NULL)
+ {
+ TSU_AnimationComplete((Animation *)self.menu_init_animation, (Drawable *)self.preset_menu_form);
+ TSU_LogXYMoverDestroy(&self.menu_init_animation);
+ }
+
+ TSU_FormDestroy(&self.preset_menu_form);
+ self.cover_banner = NULL;
+
+ if (self.cover_texture != NULL)
+ {
+ TSU_TextureDestroy(&self.cover_texture);
+ }
+
+ if (self.game_cover_path != NULL)
+ {
+ free(self.game_cover_path);
+ self.game_cover_path = NULL;
+ }
+ }
+}
+
+void SavePresetOptionClick(Drawable *drawable)
+{
+ SavePresetInputEvent(0, KeySelect);
+}
+
+void DMAOptionClick(Drawable *drawable)
+{
+ DMAInputEvent(0, KeySelect);
+
+ if (TSU_CheckBoxGetValue(self.dma_option))
+ {
+ TSU_OptionGroupSetOptionByKey(self.async_option, 0, "TRUE");
+ TSU_OptionGroupSelectOptionByIndex(self.async_option, 0);
+ }
+ else
+ {
+ TSU_OptionGroupSetOptionByKey(self.async_option, 0, "NONE");
+
+ if (TSU_OptionGroupGetKeySelected(self.async_option) == 0)
+ {
+ TSU_OptionGroupSelectOptionByIndex(self.async_option, 8);
+ }
+ }
+}
+
+void AsyncOptionClick(Drawable *drawable)
+{
+ TSU_OptionGroupSetFocus(self.async_option, true);
+}
+
+void ByPassOptionClick(Drawable *drawable)
+{
+ ByPassInputEvent(0, KeySelect);
+}
+
+void CDDAOptionClick(Drawable *drawable)
+{
+ CDDAInputEvent(0, KeySelect);
+}
+
+void IRQOptionClick(Drawable *drawable)
+{
+ IRQInputEvent(0, KeySelect);
+}
+
+void OSOptionClick(Drawable *drawable)
+{
+ TSU_OptionGroupSetFocus(self.os_option, true);
+}
+
+void LoaderOptionClick(Drawable *drawable)
+{
+ TSU_OptionGroupSetFocus(self.loader_option, true);
+}
+
+void BootOptionClick(Drawable *drawable)
+{
+ TSU_OptionGroupSetFocus(self.boot_option, true);
+}
+
+void FastOptionClick(Drawable *drawable)
+{
+ FastInputEvent(0, KeySelect);
+}
+
+void LowLevelOptionClick(Drawable *drawable)
+{
+ LowLevelInputEvent(0, KeySelect);
+}
+
+void MemoryOptionClick(Drawable *drawable)
+{
+ TSU_OptionGroupSetFocus(self.memory_option, true);
+}
+
+void CustomMemoryOptionClick(Drawable *drawable)
+{
+ TSU_TextBoxSetFocus(self.custom_memory_option, true);
+}
+
+void HeapOptionClick(Drawable *drawable)
+{
+ TSU_OptionGroupSetFocus(self.heap_option, true);
+}
+
+void CDDASourceOptionClick(Drawable *drawable)
+{
+ TSU_OptionGroupSetFocus(self.cdda_source_option, true);
+}
+
+void CDDADestinationOptionClick(Drawable *drawable)
+{
+ TSU_OptionGroupSetFocus(self.cdda_destination_option, true);
+}
+
+void CDDAPositionOptionClick(Drawable *drawable)
+{
+ TSU_OptionGroupSetFocus(self.cdda_position_option, true);
+}
+
+void CDDAChannelOptionClick(Drawable *drawable)
+{
+ TSU_OptionGroupSetFocus(self.cdda_channel_option, true);
+}
+
+void PatchAddress1OptionClick(Drawable *drawable)
+{
+ TSU_TextBoxSetFocus(self.patch_address1_option, true);
+}
+
+void PatchValue1OptionClick(Drawable *drawable)
+{
+ TSU_TextBoxSetFocus(self.patch_value1_option, true);
+}
+
+void PatchAddress2OptionClick(Drawable *drawable)
+{
+ TSU_TextBoxSetFocus(self.patch_address2_option, true);
+}
+
+void PatchValue2OptionClick(Drawable *drawable)
+{
+ TSU_TextBoxSetFocus(self.patchvalue2_option, true);
+}
+
+void AlterBootOptionClick(Drawable *drawable)
+{
+ AlterBootInputEvent(0, KeySelect);
+}
+
+bool AllButtonsDisabled()
+{
+ return (!self.button_x && !self.button_y && !self.button_z && !self.button_rt
+ && !self.button_a && !self.button_b && !self.button_c && !self.button_lt
+ && !self.button_start);
+}
+
+void ScreenshotOptionClick(Drawable *drawable)
+{
+ ScreenshotInputEvent(0, KeySelect);
+
+ if (TSU_CheckBoxGetValue(self.screenshot_option))
+ {
+ if (AllButtonsDisabled())
+ {
+ TSU_CheckBoxSetOn(self.button_start_option);
+ TSU_CheckBoxSetOn(self.button_a_option);
+ TSU_CheckBoxSetOn(self.button_b_option);
+
+ self.button_a = self.button_b = self.button_start = true;
+ menu_data.preset->scr_hotkey = GetModeScreenshot();
+ }
+ }
+ else
+ {
+ TSU_CheckBoxSetOff(self.button_start_option);
+ TSU_CheckBoxSetOff(self.button_x_option);
+ TSU_CheckBoxSetOff(self.button_y_option);
+ TSU_CheckBoxSetOff(self.button_z_option);
+ TSU_CheckBoxSetOff(self.button_lt_option);
+ TSU_CheckBoxSetOff(self.button_a_option);
+ TSU_CheckBoxSetOff(self.button_b_option);
+ TSU_CheckBoxSetOff(self.button_c_option);
+ TSU_CheckBoxSetOff(self.button_rt_option);
+
+ self.button_x = self.button_y = self.button_z = self.button_rt = self.button_a = self.button_b = self.button_c = self.button_lt = self.button_start = false;
+ menu_data.preset->scr_hotkey = GetModeScreenshot();
+ }
+}
+
+void SetModeScreenshot()
+{
+ self.button_x = (menu_data.preset->scr_hotkey & CONT_X);
+ self.button_y = (menu_data.preset->scr_hotkey & CONT_Y);
+ self.button_z = (menu_data.preset->scr_hotkey & CONT_Z);
+ self.button_lt = false;
+ self.button_a = (menu_data.preset->scr_hotkey & CONT_A);
+ self.button_b = (menu_data.preset->scr_hotkey & CONT_B);
+ self.button_c = (menu_data.preset->scr_hotkey & CONT_C);
+ self.button_start = (menu_data.preset->scr_hotkey & CONT_START);
+ self.button_rt = false;
+}
+
+int GetModeScreenshot()
+{
+ int screenshot_mode = 0;
+
+ if (self.button_x)
+ {
+ screenshot_mode |= CONT_X;
+ }
+
+ if (self.button_y)
+ {
+ screenshot_mode |= CONT_Y;
+ }
+
+ if (self.button_z)
+ {
+ screenshot_mode |= CONT_Z;
+ }
+
+ if (self.button_rt)
+ {
+ }
+
+ if (self.button_a)
+ {
+ screenshot_mode |= CONT_A;
+ }
+
+ if (self.button_b)
+ {
+ screenshot_mode |= CONT_B;
+ }
+
+ if (self.button_c)
+ {
+ screenshot_mode |= CONT_C;
+ }
+
+ if (self.button_lt)
+ {
+ }
+
+ if (self.button_start)
+ {
+ screenshot_mode |= CONT_START;
+ }
+
+ return screenshot_mode;
+}
+
+void CheckScreenshot()
+{
+ if (AllButtonsDisabled())
+ {
+ TSU_CheckBoxSetOff(self.screenshot_option);
+ menu_data.preset->scr_hotkey = menu_data.preset->screenshot = 0;
+ }
+ else
+ {
+ TSU_CheckBoxSetOn(self.screenshot_option);
+ menu_data.preset->screenshot = 1;
+ menu_data.preset->scr_hotkey = GetModeScreenshot();
+ }
+}
+
+void ButtonStartOptionClick(Drawable *drawable)
+{
+ TSU_CheckBoxInputEvent(self.button_start_option, 0, KeySelect);
+ self.button_start = TSU_CheckBoxGetValue(self.button_start_option);
+ CheckScreenshot();
+}
+
+void ButtonXOptionClick(Drawable *drawable)
+{
+ TSU_CheckBoxInputEvent(self.button_x_option, 0, KeySelect);
+ self.button_x = TSU_CheckBoxGetValue(self.button_x_option);
+ CheckScreenshot();
+}
+
+void ButtonYOptionClick(Drawable *drawable)
+{
+ TSU_CheckBoxInputEvent(self.button_y_option, 0, KeySelect);
+ self.button_y = TSU_CheckBoxGetValue(self.button_y_option);
+ CheckScreenshot();
+}
+
+void ButtonZOptionClick(Drawable *drawable)
+{
+ TSU_CheckBoxInputEvent(self.button_z_option, 0, KeySelect);
+ self.button_z = TSU_CheckBoxGetValue(self.button_z_option);
+ CheckScreenshot();
+}
+
+void ButtonLTOptionClick(Drawable *drawable)
+{
+ TSU_CheckBoxInputEvent(self.button_lt_option, 0, KeySelect);
+ self.button_lt = TSU_CheckBoxGetValue(self.button_lt_option);
+ CheckScreenshot();
+}
+
+void ButtonAOptionClick(Drawable *drawable)
+{
+ TSU_CheckBoxInputEvent(self.button_a_option, 0, KeySelect);
+ self.button_a = TSU_CheckBoxGetValue(self.button_a_option);
+ CheckScreenshot();
+}
+
+void ButtonBOptionClick(Drawable *drawable)
+{
+ TSU_CheckBoxInputEvent(self.button_b_option, 0, KeySelect);
+ self.button_b = TSU_CheckBoxGetValue(self.button_b_option);
+ CheckScreenshot();
+}
+
+void ButtonCOptionClick(Drawable *drawable)
+{
+ TSU_CheckBoxInputEvent(self.button_c_option, 0, KeySelect);
+ self.button_c = TSU_CheckBoxGetValue(self.button_c_option);
+ CheckScreenshot();
+}
+
+void ButtonRTOptionClick(Drawable *drawable)
+{
+ TSU_CheckBoxInputEvent(self.button_rt_option, 0, KeySelect);
+ self.button_rt = TSU_CheckBoxGetValue(self.button_rt_option);
+ CheckScreenshot();
+}
+
+void VMUOptionClick(Drawable *drawable)
+{
+ TSU_TextBoxSetFocus(self.vmu_option, true);
+}
+
+void VMUSelectorOptionClick(Drawable *drawable)
+{
+ TSU_OptionGroupSetFocus(self.vmu_selector_option, true);
+}
+
+void ShortcutSizeOptionClick(Drawable *drawable)
+{
+ TSU_OptionGroupSetFocus(self.shortcut_size_option, true);
+}
+
+void ShortcutRotateOptionClick(Drawable *drawable)
+{
+ ShortcutRotateInputEvent(0, KeySelect);
+}
+
+void ShortcutNameOptionClick(Drawable *drawable)
+{
+ TSU_TextBoxSetFocus(self.shortcut_name_option, true);
+}
+
+void ShortcutDontShowNameOptionClick(Drawable *drawable)
+{
+ ShortcutDontShowNameInputEvent(0, KeySelect);
+}
+
+void ShortcutCreateOptionClick(Drawable *drawable)
+{
+ Color press_color = {1, 1.0f, 1.0f, 0.1f};
+ Color drop_color = {1, 1.0f, 1.0f, 1.0f};
+
+ TSU_ItemMenuSetTint(self.shortcut_create_option, press_color, press_color);
+ TSU_ItemMenuSetLabelText(self.shortcut_create_option, "Creating...");
+
+ int width = 0;
+ int height = 0;
+ if (self.cover_banner != NULL)
+ {
+ switch (TSU_OptionGroupGetKeySelected(self.shortcut_size_option))
+ {
+ case 1:
+ width = height = 48;
+ break;
+
+ case 2:
+ width = height = 64;
+ break;
+
+ case 3:
+ width = height = 96;
+ break;
+
+ case 5:
+ width = height = 256;
+ break;
+
+ default:
+ width = height = 128;
+ break;
+ }
+ }
+
+ MakeShortcut(menu_data.preset, GetDefaultDir(menu_data.current_dev), self.full_path_game
+ , TSU_CheckBoxGetValue(self.shortcut_dontshowname_option) ? false : true, self.game_cover_path
+ , width, height, TSU_CheckBoxGetValue(self.shortcut_rotate_option) ? true : false);
+
+ TSU_ItemMenuSetTint(self.shortcut_create_option, drop_color, drop_color);
+ TSU_ItemMenuSetLabelText(self.shortcut_create_option, "Rewrite shortcut");
+}
+
+void ExitPresetMenuClick(Drawable *drawable)
+{
+ HidePresetMenu();
+ menu_data.state_app = SA_GAMES_MENU;
+}
+
+void SavePresetInputEvent(int type, int key)
+{
+ TSU_CheckBoxInputEvent(self.save_preset_option, type, key);
+}
+
+void DMAInputEvent(int type, int key)
+{
+ TSU_CheckBoxInputEvent(self.dma_option, type, key);
+}
+
+void AsyncInputEvent(int type, int key)
+{
+ TSU_OptionGroupInputEvent(self.async_option, type, key);
+}
+
+void ByPassInputEvent(int type, int key)
+{
+ TSU_CheckBoxInputEvent(self.bypass_option, type, key);
+}
+
+void CDDAInputEvent(int type, int key)
+{
+ TSU_CheckBoxInputEvent(self.cdda_option, type, key);
+}
+
+void IRQInputEvent(int type, int key)
+{
+ TSU_CheckBoxInputEvent(self.irq_option, type, key);
+}
+
+void OSInputEvent(int type, int key)
+{
+ TSU_OptionGroupInputEvent(self.os_option, type, key);
+}
+
+void LoaderInputEvent(int type, int key)
+{
+ TSU_OptionGroupInputEvent(self.loader_option, type, key);
+}
+
+void BootInputEvent(int type, int key)
+{
+ TSU_OptionGroupInputEvent(self.boot_option, type, key);
+}
+
+void FastInputEvent(int type, int key)
+{
+ TSU_CheckBoxInputEvent(self.fast_option, type, key);
+}
+
+void LowLevelInputEvent(int type, int key)
+{
+ TSU_CheckBoxInputEvent(self.lowlevel_option, type, key);
+}
+
+void MemoryInputEvent(int type, int key)
+{
+ TSU_OptionGroupInputEvent(self.memory_option, type, key);
+}
+
+void CustomMemoryInputEvent(int type, int key)
+{
+ if (key == KeyCancel)
+ {
+ memset(menu_data.preset->custom_memory, 0, sizeof(menu_data.preset->custom_memory));
+ strcpy(menu_data.preset->custom_memory, TSU_TextBoxGetText(self.custom_memory_option));
+
+ if (strlen(menu_data.preset->custom_memory) != 6)
+ {
+ memset(menu_data.preset->custom_memory, 0, sizeof(menu_data.preset->custom_memory));
+ TSU_TextBoxSetText(self.custom_memory_option, menu_data.preset->custom_memory);
+ }
+ }
+
+ TSU_TextBoxInputEvent(self.custom_memory_option, type, key);
+}
+
+void HeapInputEvent(int type, int key)
+{
+ TSU_OptionGroupInputEvent(self.heap_option, type, key);
+}
+
+void CDDASourceInputEvent(int type, int key)
+{
+ TSU_OptionGroupInputEvent(self.cdda_source_option, type, key);
+}
+
+void CDDADestinationInputEvent(int type, int key)
+{
+ TSU_OptionGroupInputEvent(self.cdda_destination_option, type, key);
+}
+
+void CDDAPositionInputEvent(int type, int key)
+{
+ TSU_OptionGroupInputEvent(self.cdda_position_option, type, key);
+}
+
+void CDDAChannelInputEvent(int type, int key)
+{
+ TSU_OptionGroupInputEvent(self.cdda_channel_option, type, key);
+}
+
+void SetPatchByType(TextBox *patch_textbox, int control_type, char *patch_text_variable_ptr, uint32 *patch_variable_ptr)
+{
+ char text[10];
+ memset(text, 0, sizeof(text));
+ strcpy(text, TSU_TextBoxGetText(patch_textbox));
+ uint32_t text_value = strtoul(text, NULL, 16);
+
+ if( (strlen(text) != 8) || (control_type == PATCH_ADDRESS_TYPE && (!(text_value & 0xffffff)
+ || (
+ (text_value >> 24 != 0x0c)
+ && (text_value >> 24 != 0x8c)
+ && (text_value >> 24 != 0xac)
+ )
+ ))
+ || (control_type == PATCH_VALUE_TYPE && !text_value))
+ {
+ TSU_TextBoxSetText(patch_textbox, (control_type == PATCH_ADDRESS_TYPE ? "0c000000" : "00000000"));
+
+ memset(patch_text_variable_ptr, 0, 10);
+ strcpy(patch_text_variable_ptr, (control_type == PATCH_ADDRESS_TYPE ? "0c000000" : "00000000"));
+ *patch_variable_ptr = 0;
+ }
+ else
+ {
+ memset(patch_text_variable_ptr, 0, 10);
+ strcpy(patch_text_variable_ptr, text);
+ *patch_variable_ptr = strtoul(text, NULL, 16);
+ }
+}
+
+void PatchAddress1InputEvent(int type, int key)
+{
+ if (key == KeyCancel)
+ {
+ SetPatchByType(self.patch_address1_option, PATCH_ADDRESS_TYPE, menu_data.preset->patch_a[0], &menu_data.preset->pa[0]);
+ }
+
+ TSU_TextBoxInputEvent(self.patch_address1_option , type, key);
+}
+
+void PatchValue1InputEvent(int type, int key)
+{
+ if (key == KeyCancel)
+ {
+ SetPatchByType(self.patch_value1_option, PATCH_VALUE_TYPE, menu_data.preset->patch_v[0], &menu_data.preset->pv[0]);
+ }
+
+ TSU_TextBoxInputEvent(self.patch_value1_option, type, key);
+}
+
+void PatchAddress2InputEvent(int type, int key)
+{
+ if (key == KeyCancel)
+ {
+ SetPatchByType(self.patch_address2_option, PATCH_ADDRESS_TYPE, menu_data.preset->patch_a[1], &menu_data.preset->pa[1]);
+ }
+
+ TSU_TextBoxInputEvent(self.patch_address2_option, type, key);
+}
+
+void PatchValue2InputEvent(int type, int key)
+{
+ if (key == KeyCancel)
+ {
+ SetPatchByType(self.patchvalue2_option, PATCH_VALUE_TYPE, menu_data.preset->patch_v[1], &menu_data.preset->pv[1]);
+ }
+
+ TSU_TextBoxInputEvent(self.patchvalue2_option, type, key);
+}
+
+void AlterBootInputEvent(int type, int key)
+{
+ TSU_CheckBoxInputEvent(self.altboot_option, type, key);
+}
+
+void ScreenshotInputEvent(int type, int key)
+{
+ TSU_CheckBoxInputEvent(self.screenshot_option, type, key);
+}
+
+void VMUInputEvent(int type, int key)
+{
+ if (key == KeyCancel)
+ {
+ memset(menu_data.preset->vmu_file, 0, sizeof(menu_data.preset->vmu_file));
+ strcpy(menu_data.preset->vmu_file, TSU_TextBoxGetText(self.vmu_option));
+
+ if (menu_data.preset->vmu_file[0] != '\0' && ContainsOnlyNumbers(menu_data.preset->vmu_file))
+ {
+ menu_data.preset->emu_vmu = atoi(menu_data.preset->vmu_file);
+ if (menu_data.preset->emu_vmu > MAX_VMU)
+ {
+ memset(menu_data.preset->vmu_file, 0, sizeof(menu_data.preset->vmu_file));
+ snprintf(menu_data.preset->vmu_file, sizeof(menu_data.preset->vmu_file), "%d", MAX_VMU);
+ menu_data.preset->emu_vmu = MAX_VMU;
+ }
+ }
+ else
+ {
+ strcpy(menu_data.preset->vmu_file, DEFAULT_VMU_NUMBER);
+ menu_data.preset->emu_vmu = 1;
+ }
+
+ TSU_TextBoxSetText(self.vmu_option, menu_data.preset->vmu_file);
+ }
+
+ TSU_TextBoxInputEvent(self.vmu_option, type, key);
+}
+
+void VMUSelectorInputEvent(int type, int key)
+{
+ TSU_OptionGroupInputEvent(self.vmu_selector_option, type, key);
+}
+
+void ShortcutChangeCoverSize()
+{
+ if (self.cover_banner != NULL)
+ {
+ switch (TSU_OptionGroupGetKeySelected(self.shortcut_size_option))
+ {
+ case 1:
+ TSU_BannerSetSize(self.cover_banner, 48, 48);
+ break;
+
+ case 2:
+ TSU_BannerSetSize(self.cover_banner, 64, 64);
+ break;
+
+ case 3:
+ TSU_BannerSetSize(self.cover_banner, 96, 96);
+ break;
+
+ case 5:
+ TSU_BannerSetSize(self.cover_banner, 256, 256);
+ break;
+
+ default:
+ TSU_BannerSetSize(self.cover_banner, 128, 128);
+ break;
+ }
+ }
+}
+
+void ShortcutSizeInputEvent(int type, int key)
+{
+ TSU_OptionGroupInputEvent(self.shortcut_size_option, type, key);
+ ShortcutChangeCoverSize();
+}
+
+void ShortcutRotateInputEvent(int type, int key)
+{
+ TSU_CheckBoxInputEvent(self.shortcut_rotate_option, type, key);
+ ShortcutLoadTextureCover();
+ ShortcutChangeCoverSize();
+}
+
+void ShortcutNameInputEvent(int type, int key)
+{
+ TSU_TextBoxInputEvent(self.shortcut_name_option, type, key);
+
+ if (key == KeyCancel)
+ {
+ memset(menu_data.preset->shortcut_name, 0, sizeof(menu_data.preset->shortcut_name));
+ strncpy(menu_data.preset->shortcut_name, TSU_TextBoxGetText(self.shortcut_name_option), sizeof(menu_data.preset->shortcut_name) - 4);
+
+ CheckIfShorcutExits();
+ }
+}
+
+void ShortcutDontShowNameInputEvent(int type, int key)
+{
+ TSU_CheckBoxInputEvent(self.shortcut_dontshowname_option, type, key);
+ CheckIfShorcutExits();
+}
+
+void ShortcutCreateInputEvent(int type, int key)
+{
+}
+
+void CheckIfShorcutExits()
+{
+ char shortcut_file[NAME_MAX];
+
+ if (TSU_CheckBoxGetValue(self.shortcut_dontshowname_option) == 0)
+ {
+ snprintf(shortcut_file, NAME_MAX, "%s/apps/main/scripts/%s.dsc", GetDefaultDir(menu_data.current_dev), menu_data.preset->shortcut_name);
+ }
+ else
+ {
+ snprintf(shortcut_file, NAME_MAX, "%s/apps/main/scripts/_%s.dsc", GetDefaultDir(menu_data.current_dev), menu_data.preset->shortcut_name);
+ }
+
+ if (FileExists(shortcut_file))
+ {
+ TSU_ItemMenuSetLabelText(self.shortcut_create_option, "Rewrite shortcut");
+ }
+ else
+ {
+ TSU_ItemMenuSetLabelText(self.shortcut_create_option, "Create shortcut");
+ }
+}
\ No newline at end of file
diff --git a/applications/games_menu/modules/system_menu.c b/applications/games_menu/modules/system_menu.c
new file mode 100644
index 00000000..7a1727de
--- /dev/null
+++ b/applications/games_menu/modules/system_menu.c
@@ -0,0 +1,501 @@
+/* DreamShell ##version##
+
+ app_system_menu.h - ISO Loader app utils
+ Copyright (C) 2024 Maniac Vera
+
+*/
+
+#include "app_system_menu.h"
+#include "app_definition.h"
+#include "app_menu.h"
+#include "app_utils.h"
+#include
+#include
+#include
+#include
+#include
+
+extern struct menu_structure menu_data;
+
+enum ViewEnum
+{
+ SYSTEM_MENU_VIEW = 0
+};
+
+static struct
+{
+ bool first_scan_cover;
+ DSApp *dsapp_ptr;
+ Scene *scene_ptr;
+ Form *system_menu_form;
+ Form *optimize_cover_popup;
+
+ Label *optimize_covers_label;
+ Label *title_cover_scan;
+ Label *note_cover_scan;
+ Label *message_cover_scan;
+ Rectangle *modal_cover_scan;
+
+ CheckBox *save_preset_option;
+ CheckBox *cover_background_option;
+ CheckBox *change_page_with_page_option;
+
+ Font *message_font;
+ Font *menu_font;
+} self;
+
+void CreateSystemMenu(DSApp *dsapp_ptr, Scene *scene_ptr, Font *menu_font, Font *message_font)
+{
+ self.dsapp_ptr = dsapp_ptr;
+ self.scene_ptr = scene_ptr;
+ self.message_font = message_font;
+ self.menu_font = menu_font;
+ self.system_menu_form = NULL;
+ self.optimize_cover_popup = NULL;
+ self.optimize_covers_label = NULL;
+ self.first_scan_cover = false;
+}
+
+void DestroySystemMenu()
+{
+ HideSystemMenu();
+ HideOptimizeCoverPopup();
+ HideCoverScan();
+
+ self.dsapp_ptr = NULL;
+ self.scene_ptr = NULL;
+ self.message_font = NULL;
+ self.menu_font = NULL;
+}
+
+void SystemMenuRemoveAll()
+{
+}
+
+void SystemMenuInputEvent(int type, int key)
+{
+ TSU_FormInputEvent(self.system_menu_form, type, key);
+}
+
+int StateSystemMenu()
+{
+ return (self.system_menu_form != NULL ? 1 : 0);
+}
+
+void ShowSystemMenu()
+{
+ HideSystemMenu();
+
+ if (self.system_menu_form == NULL)
+ {
+ char font_path[NAME_MAX];
+ memset(font_path, 0, sizeof(font_path));
+ snprintf(font_path, sizeof(font_path), "%s/%s", GetDefaultDir(menu_data.current_dev), "apps/games_menu/fonts/default.txf");
+
+ Font *form_font = TSU_FontCreate(font_path, PVR_LIST_TR_POLY);
+
+ uint width = 300;
+ uint height = 390;
+ self.system_menu_form = TSU_FormCreate(640 / 2 - 150, 480 / 2 + (height - 10) / 2, width, height, true, 3, true, false, form_font, &OnSystemViewIndexChangedEvent);
+ TSU_DrawableSubAdd((Drawable *)self.scene_ptr, (Drawable *)self.system_menu_form);
+ TSU_FormSelectedEvent(self.system_menu_form, &SystemMenuSelectedEvent);
+ }
+}
+
+void OnSystemViewIndexChangedEvent(Drawable *drawable, int view_index)
+{
+ switch (view_index)
+ {
+ case SYSTEM_MENU_VIEW:
+ CreateSystemMenuView((Form *)drawable);
+ break;
+ }
+}
+
+void CreateSystemMenuView(Form *form_ptr)
+{
+ Font* form_font = TSU_FormGetTitleFont(form_ptr);
+ TSU_FormtSetAttributes(form_ptr, 1, 10, 296, 38);
+ TSU_FormSetRowSize(form_ptr, 4, 30);
+ TSU_FormSetRowSize(form_ptr, 6, 30);
+ TSU_FormSetRowSize(form_ptr, 8, 30);
+ TSU_FormSetRowSize(form_ptr, 9, 20);
+ TSU_FormSetTitle(form_ptr, "SYSTEM MENU");
+
+ int font_size = 17;
+
+ // THE ALIGN SHOULD BE IN FORM CLASS
+ {
+ // SCAN MISSING COVERS
+ Label *missing_covers_label = TSU_LabelCreate(form_font, "Scan missing covers", font_size, false, false);
+ TSU_FormAddBodyLabel(form_ptr, missing_covers_label, 1, 1);
+ TSU_DrawableEventSetClick((Drawable *)missing_covers_label, &ScanMissingCoversClick);
+
+ Vector option_vector = TSU_DrawableGetPosition((Drawable *)missing_covers_label);
+ option_vector.x += 24;
+ TSU_DrawableSetTranslate((Drawable *)missing_covers_label, &option_vector);
+ TSU_FormSetCursor(form_ptr, (Drawable *)missing_covers_label);
+
+ missing_covers_label = NULL;
+ }
+
+ {
+ // OPTIMIZE COVERS
+ Label *optimize_covers_label = TSU_LabelCreate(form_font, "Optimize covers", font_size, false, false);
+ TSU_FormAddBodyLabel(form_ptr, optimize_covers_label, 1, 2);
+ TSU_DrawableEventSetClick((Drawable *)optimize_covers_label, &OptimizeCoversClick);
+
+ Vector option_vector = TSU_DrawableGetPosition((Drawable *)optimize_covers_label);
+ option_vector.x += 48;
+ TSU_DrawableSetTranslate((Drawable *)optimize_covers_label, &option_vector);
+
+ optimize_covers_label = NULL;
+ }
+
+ {
+ // DEFAULT SAVE PRESET
+ Label *save_preset_label = TSU_LabelCreate(form_font, "Default save preset:", font_size, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)save_preset_label, true);
+ TSU_FormAddBodyLabel(form_ptr, save_preset_label, 1, 3);
+
+ self.save_preset_option = TSU_CheckBoxCreate(form_font, font_size, 50, 22);
+ TSU_FormAddBodyCheckBox(form_ptr, self.save_preset_option, 1, 4);
+
+ Vector option_vector = TSU_DrawableGetPosition((Drawable *)self.save_preset_option);
+ option_vector.y -= 5;
+ TSU_DrawableSetTranslate((Drawable *)self.save_preset_option, &option_vector);
+
+ TSU_DrawableEventSetClick((Drawable *)self.save_preset_option, &DefaultSavePresetOptionClick);
+
+ if (menu_data.app_config.save_preset)
+ {
+ TSU_CheckBoxSetOn(self.save_preset_option);
+ }
+
+ save_preset_label = NULL;
+ }
+
+ {
+ // COVER BACKGROUND
+ Label *cover_background_label = TSU_LabelCreate(form_font, "Cover background:", font_size, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)cover_background_label, true);
+ TSU_FormAddBodyLabel(form_ptr, cover_background_label, 1, 5);
+
+ self.cover_background_option = TSU_CheckBoxCreate(form_font, font_size, 50, 22);
+ TSU_FormAddBodyCheckBox(form_ptr, self.cover_background_option, 1, 6);
+
+ Vector option_vector = TSU_DrawableGetPosition((Drawable *)self.cover_background_option);
+ option_vector.y -= 5;
+ TSU_DrawableSetTranslate((Drawable *)self.cover_background_option, &option_vector);
+
+ TSU_DrawableEventSetClick((Drawable *)self.cover_background_option, &CoverBackgroundOptionClick);
+
+ if (menu_data.app_config.cover_background)
+ {
+ TSU_CheckBoxSetOn(self.cover_background_option);
+ }
+
+ cover_background_label = NULL;
+ }
+
+ {
+ // CHANGE PAGE WITH PAD
+ Label *change_page_with_page_label = TSU_LabelCreate(form_font, "Change page with pad:", font_size, false, false);
+ TSU_DrawableSetReadOnly((Drawable*)change_page_with_page_label, true);
+ TSU_FormAddBodyLabel(form_ptr, change_page_with_page_label, 1, 7);
+
+ self.change_page_with_page_option = TSU_CheckBoxCreate(form_font, font_size, 50, 22);
+ TSU_FormAddBodyCheckBox(form_ptr, self.change_page_with_page_option, 1, 8);
+
+ Vector option_vector = TSU_DrawableGetPosition((Drawable *)self.change_page_with_page_option);
+ option_vector.y -= 5;
+ TSU_DrawableSetTranslate((Drawable *)self.change_page_with_page_option, &option_vector);
+
+ TSU_DrawableEventSetClick((Drawable *)self.change_page_with_page_option, &ChangePageWithPadOptionClick);
+
+ if (menu_data.app_config.change_page_with_pad)
+ {
+ TSU_CheckBoxSetOn(self.change_page_with_page_option);
+ }
+
+ change_page_with_page_label = NULL;
+ }
+
+ {
+ // EXIT TO MAIN MENU
+ Label *exit_covers_label = TSU_LabelCreate(form_font, "Return", font_size, false, false);
+ TSU_FormAddBodyLabel(form_ptr, exit_covers_label, 1, 10);
+ TSU_DrawableEventSetClick((Drawable *)exit_covers_label, &ExitSystemMenuClick);
+
+ Vector option_vector = TSU_DrawableGetPosition((Drawable *)exit_covers_label);
+ option_vector.x += 110;
+ TSU_DrawableSetTranslate((Drawable *)exit_covers_label, &option_vector);
+
+ exit_covers_label = NULL;
+ }
+
+ form_font = NULL;
+}
+
+void HideSystemMenu()
+{
+ if (self.system_menu_form != NULL)
+ {
+ TSU_FormDestroy(&self.system_menu_form);
+ }
+}
+
+void SystemMenuSelectedEvent(Drawable *drawable, uint bottom_index, uint column, uint row)
+{
+}
+
+void ScanMissingCoversClick(Drawable *drawable)
+{
+ HideSystemMenu();
+
+ if (menu_data.current_dev == APP_DEVICE_SD || menu_data.current_dev == APP_DEVICE_IDE)
+ {
+ if (menu_data.load_pvr_cover_thread == NULL && menu_data.optimize_game_cover_thread == NULL)
+ {
+ menu_data.stop_load_pvr_cover = false;
+
+ if (!self.first_scan_cover)
+ {
+ menu_data.rescan_covers = true;
+ }
+
+ self.first_scan_cover = true;
+ menu_data.load_pvr_cover_thread = thd_create(0, LoadPVRCoverThread, NULL);
+ ShowCoverScan();
+ }
+ }
+ else
+ {
+ menu_data.state_app = SA_GAMES_MENU;
+ }
+}
+
+void OptimizeCoversClick(Drawable *drawable)
+{
+ HideSystemMenu();
+
+ if (menu_data.current_dev == APP_DEVICE_SD || menu_data.current_dev == APP_DEVICE_IDE)
+ {
+ if (menu_data.load_pvr_cover_thread == NULL && menu_data.optimize_game_cover_thread == NULL)
+ {
+ menu_data.stop_optimize_game_cover = false;
+ menu_data.optimize_game_cover_thread = thd_create(0, OptimizeCoverThread, NULL);
+ ShowOptimizeCoverPopup();
+ menu_data.state_app = SA_OPTIMIZE_COVER;
+ }
+ }
+ else
+ {
+ menu_data.state_app = SA_GAMES_MENU;
+ }
+}
+
+void DefaultSavePresetOptionClick(Drawable *drawable)
+{
+ TSU_CheckBoxInputEvent(self.save_preset_option, 0, KeySelect);
+ menu_data.save_preset = (TSU_CheckBoxGetValue(self.save_preset_option) ? 1 : 0);
+}
+
+void CoverBackgroundOptionClick(Drawable *drawable)
+{
+ TSU_CheckBoxInputEvent(self.cover_background_option, 0, KeySelect);
+ menu_data.cover_background = (TSU_CheckBoxGetValue(self.cover_background_option) ? 1 : 0);
+}
+
+void ChangePageWithPadOptionClick(Drawable *drawable)
+{
+ TSU_CheckBoxInputEvent(self.change_page_with_page_option, 0, KeySelect);
+ menu_data.change_page_with_pad = (TSU_CheckBoxGetValue(self.change_page_with_page_option) ? 1 : 0);
+}
+
+void ExitSystemMenuClick(Drawable *drawable)
+{
+ HideSystemMenu();
+
+ int menu_type = menu_data.menu_type;
+ menu_data.menu_type = menu_data.app_config.initial_view;
+ SaveMenuConfig();
+ menu_data.menu_type = menu_type;
+
+ menu_data.state_app = SA_GAMES_MENU;
+}
+
+void ShowOptimizeCoverPopup()
+{
+ StopCDDA();
+ HideOptimizeCoverPopup();
+
+ if (self.optimize_cover_popup == NULL)
+ {
+ char font_path[NAME_MAX];
+ memset(font_path, 0, sizeof(font_path));
+ snprintf(font_path, sizeof(font_path), "%s/%s", GetDefaultDir(menu_data.current_dev), "apps/games_menu/fonts/default.txf");
+
+ Font *form_font = TSU_FontCreate(font_path, PVR_LIST_TR_POLY);
+
+ self.optimize_cover_popup = TSU_FormCreate(640 / 2 - 500 / 2, 480 / 2 + 230 / 2 - 30, 500, 230, true, 3, true, false, form_font, NULL);
+ TSU_FormtSetAttributes(self.optimize_cover_popup, 1, 2, 500, 32);
+
+ self.optimize_covers_label = TSU_LabelCreate(form_font, "", 16, false, false);
+ Label *exit_covers_label = TSU_LabelCreate(form_font, " Press any key to exit", 16, false, false);
+
+ TSU_DrawableSetReadOnly((Drawable *)self.optimize_covers_label, true);
+ TSU_DrawableSetReadOnly((Drawable *)exit_covers_label, true);
+
+ TSU_FormSetRowSize(self.optimize_cover_popup, 1, 50);
+ TSU_FormSetRowSize(self.optimize_cover_popup, 2, 100);
+ TSU_FormSetTitle(self.optimize_cover_popup, "OPTIMIZING COVERS");
+
+ TSU_FormAddBodyLabel(self.optimize_cover_popup, self.optimize_covers_label, 1, 1);
+ TSU_FormAddBodyLabel(self.optimize_cover_popup, exit_covers_label, 1, 2);
+
+ TSU_DrawableSubAdd((Drawable *)self.scene_ptr, (Drawable *)self.optimize_cover_popup);
+
+ form_font = NULL;
+ exit_covers_label = NULL;
+ }
+}
+
+void HideOptimizeCoverPopup()
+{
+ if (self.optimize_cover_popup != NULL)
+ {
+ TSU_FormDestroy(&self.optimize_cover_popup);
+ self.optimize_covers_label = NULL;
+ }
+}
+
+void SetMessageOptimizer(const char *fmt, const char *message)
+{
+ char message_optimizer[NAME_MAX];
+ memset(message_optimizer, 0, sizeof(message_optimizer));
+ snprintf(message_optimizer, sizeof(message_optimizer), fmt, message);
+ message_optimizer[44] = '\0';
+
+ if (self.optimize_covers_label != NULL)
+ {
+ TSU_LabelSetText(self.optimize_covers_label, message_optimizer);
+ }
+}
+
+int StopOptimizeCovers()
+{
+ if (menu_data.optimize_game_cover_thread != NULL)
+ {
+ bool skip_return = self.optimize_cover_popup == NULL;
+ menu_data.stop_optimize_game_cover = true;
+ thd_join(menu_data.optimize_game_cover_thread, NULL);
+ menu_data.optimize_game_cover_thread = NULL;
+ HideOptimizeCoverPopup();
+
+ if (!skip_return)
+ return 1;
+ }
+
+ return (menu_data.optimize_game_cover_thread == NULL ? 0 : -1);
+}
+
+void ShowCoverScan()
+{
+ menu_data.state_app = SA_SCAN_COVER;
+
+ StopCDDA();
+ HideCoverScan();
+
+ Vector vector_init_title = {640 / 2, 400 / 2 - 50, ML_CURSOR + 6, 1};
+ Color modal_color = {1, 0.0f, 0.0f, 0.0f};
+ Color modal_border_color = {1, 1.0f, 1.0f, 1.0f};
+
+ self.modal_cover_scan = TSU_RectangleCreateWithBorder(PVR_LIST_OP_POLY, 40, 350, 560, 230, &modal_color, ML_CURSOR + 5, 3, &modal_border_color, 0);
+ TSU_AppSubAddRectangle(self.dsapp_ptr, self.modal_cover_scan);
+
+ static Color color = {1, 1.0f, 1.0f, 1.0f};
+ self.title_cover_scan = TSU_LabelCreate(self.menu_font, "SCANNING MISSING COVER", 26, true, true);
+ TSU_LabelSetTint(self.title_cover_scan, &color);
+ TSU_AppSubAddLabel(self.dsapp_ptr, self.title_cover_scan);
+ TSU_LabelSetTranslate(self.title_cover_scan, &vector_init_title);
+
+ vector_init_title.x = 640 / 2;
+ vector_init_title.y = 400 / 2 + 100;
+ self.note_cover_scan = TSU_LabelCreate(self.menu_font, "\n\nPress any key to exit", 14, true, true);
+ TSU_LabelSetTint(self.note_cover_scan, &color);
+ TSU_AppSubAddLabel(self.dsapp_ptr, self.note_cover_scan);
+ TSU_LabelSetTranslate(self.note_cover_scan, &vector_init_title);
+}
+
+void HideCoverScan()
+{
+ if (self.modal_cover_scan != NULL)
+ {
+ TSU_AppSubRemoveRectangle(self.dsapp_ptr, self.modal_cover_scan);
+ thd_pass();
+ TSU_RectangleDestroy(&self.modal_cover_scan);
+ }
+
+ if (self.title_cover_scan != NULL)
+ {
+ TSU_AppSubRemoveLabel(self.dsapp_ptr, self.title_cover_scan);
+ thd_pass();
+ TSU_LabelDestroy(&self.title_cover_scan);
+ }
+
+ if (self.note_cover_scan != NULL)
+ {
+ TSU_AppSubRemoveLabel(self.dsapp_ptr, self.note_cover_scan);
+ thd_pass();
+ TSU_LabelDestroy(&self.note_cover_scan);
+ }
+
+ if (self.message_cover_scan != NULL)
+ {
+ TSU_AppSubRemoveLabel(self.dsapp_ptr, self.message_cover_scan);
+ thd_pass();
+ TSU_LabelDestroy(&self.message_cover_scan);
+ }
+}
+
+void SetMessageScan(const char *fmt, const char *message)
+{
+ char message_scan[NAME_MAX];
+ memset(message_scan, 0, sizeof(message_scan));
+ snprintf(message_scan, sizeof(message_scan), fmt, message);
+ message_scan[49] = '\0';
+
+ if (self.message_cover_scan != NULL)
+ {
+ TSU_LabelSetText(self.message_cover_scan, message_scan);
+ }
+ else
+ {
+ Color color = {1, 1.0f, 1.0f, 1.0f};
+ Vector vector_init_title = {640/2, 400/2, ML_CURSOR + 6, 1};
+ vector_init_title.x = 50;
+ vector_init_title.y += 40;
+
+ self.message_cover_scan = TSU_LabelCreate(self.message_font, message_scan, 16, false, true);
+ TSU_LabelSetTint(self.message_cover_scan, &color);
+ TSU_AppSubAddLabel(self.dsapp_ptr, self.message_cover_scan);
+ TSU_LabelSetTranslate(self.message_cover_scan, &vector_init_title);
+ }
+}
+
+int StopScanCovers()
+{
+ if (menu_data.load_pvr_cover_thread != NULL)
+ {
+ bool skip_return = self.modal_cover_scan == NULL;
+ menu_data.stop_load_pvr_cover = true;
+ thd_join(menu_data.load_pvr_cover_thread, NULL);
+ menu_data.load_pvr_cover_thread = NULL;
+
+ if (!skip_return)
+ return 1;
+ }
+
+ return (menu_data.load_pvr_cover_thread == NULL ? 0 : -1);
+}
\ No newline at end of file
diff --git a/applications/games_menu/modules/utils.c b/applications/games_menu/modules/utils.c
new file mode 100644
index 00000000..d3d68d43
--- /dev/null
+++ b/applications/games_menu/modules/utils.c
@@ -0,0 +1,612 @@
+/* DreamShell ##version##
+
+ utils.c - ISO Loader app utils
+ Copyright (C) 2022-2024 SWAT
+ Copyright (C) 2024 Maniac Vera
+
+*/
+
+#include "ds.h"
+#include
+#include
+#include
+#include "app_utils.h"
+#include "audio/wav.h"
+
+/* Trim begin/end spaces and copy into output buffer */
+void TrimSpaces(char *input, char *output, int size)
+{
+ char *p;
+ char *o;
+ int s = 0;
+ size--;
+
+ p = input;
+ o = output;
+
+ if (*p == '\0')
+ {
+ *o = '\0';
+ return;
+ }
+
+ while (*p == ' ' && size > 0)
+ {
+ p++;
+ size--;
+ }
+
+ if (!size)
+ {
+ *o = '\0';
+ return;
+ }
+
+ while (size--)
+ {
+ *o++ = *p++;
+ s++;
+ }
+
+ *o = '\0';
+ o--;
+
+ while (*o == ' ' && s > 0)
+ {
+ *o = '\0';
+ o--;
+ s--;
+ }
+}
+
+char *Trim(char *string)
+{
+ // trim prefix
+ while ((*string) == ' ' ) {
+ string ++;
+ }
+
+ // find end of original string
+ char *c = string;
+ while (*c) {
+ c ++;
+ }
+ c--;
+
+ // trim suffix
+ while ((*c) == ' ' ) {
+ *c = '\0';
+ c--;
+ }
+ return string;
+}
+
+char *TrimSpaces2(char *txt)
+{
+ int32_t i;
+
+ while (txt[0] == ' ')
+ {
+ txt++;
+ }
+
+ int32_t len = strlen(txt);
+
+ for (i = len; i; i--)
+ {
+ if (txt[i] > ' ')
+ break;
+ txt[i] = '\0';
+ }
+
+ return txt;
+}
+
+char *FixSpaces(char *str)
+{
+ if (!str)
+ return NULL;
+
+ int i, len = (int)strlen(str);
+
+ for (i = 0; i < len; i++)
+ {
+ if (str[i] == ' ')
+ str[i] = '\\';
+ }
+
+ return str;
+}
+
+int ConfigParse(isoldr_conf *cfg, const char *filename)
+{
+ file_t fd;
+ int i;
+
+ fd = fs_open(filename, O_RDONLY);
+
+ if (fd == FILEHND_INVALID)
+ {
+ ds_printf("DS_ERROR: Can't open %s\n", filename);
+ return -1;
+ }
+
+ size_t size = fs_total(fd);
+
+ char buf[512];
+ char *optname = NULL, *value = NULL;
+
+ if (fs_read(fd, buf, size) != size)
+ {
+ fs_close(fd);
+ ds_printf("DS_ERROR: Can't read %s\n", filename);
+ return -1;
+ }
+
+ fs_close(fd);
+
+ while (1)
+ {
+ if (optname == NULL)
+ optname = strtok(buf, "=");
+ else
+ optname = strtok('\0', "=");
+
+ value = strtok('\0', "\n");
+
+ if (optname == NULL || value == NULL)
+ break;
+
+ for (i = 0; cfg[i].conf_type; i++)
+ {
+ if (strncasecmp(cfg[i].name, TrimSpaces2(optname), 32))
+ continue;
+
+ switch (cfg[i].conf_type)
+ {
+ case CONF_INT:
+ *(int *)cfg[i].pointer = atoi(value);
+ break;
+
+ case CONF_STR:
+ strcpy((char *)cfg[i].pointer, TrimSpaces2(value));
+ break;
+
+ case CONF_ULONG:
+ *(uint32 *)cfg[i].pointer = strtoul(value, NULL, 16);
+ }
+ break;
+ }
+ }
+
+ return 0;
+}
+
+bool IsGdiOptimized(const char *full_path_game)
+{
+ bool is_optimized = false;
+ if (full_path_game)
+ {
+ char result[NAME_MAX];
+ char path[NAME_MAX];
+
+ char game[NAME_MAX];
+ memset(game, 0, NAME_MAX);
+ strcpy(game, GetLastPart(full_path_game, '/', 0));
+
+ memset(result, 0, NAME_MAX);
+ memset(path, 0, NAME_MAX);
+
+ strncpy(path, full_path_game, strlen(full_path_game) - (strlen(game) + 1));
+ snprintf(result, NAME_MAX, "%s/track03.iso", path);
+
+ is_optimized = (FileExists(result) == 1);
+ }
+ return is_optimized;
+}
+
+const char* GetLastPart(const char *source, const char separator, int option_path)
+{
+ static char path[NAME_MAX];
+ memset(path, 0, NAME_MAX);
+
+ char *last_folder = strrchr(source, separator);
+ if (last_folder != NULL)
+ {
+ strcpy(path, last_folder + 1);
+ }
+ else
+ {
+ strcpy(path, source);
+ }
+
+ if (option_path == 2)
+ {
+ for (char *c = path; (*c = toupper(*c)); ++c)
+ {
+ if (*c == 'a')
+ *c = 'A'; // Maniac Vera: BUG toupper in the letter a, it does not convert it
+ }
+ }
+ else if (option_path == 1)
+ {
+ for (char *c = path; (*c = tolower(*c)); ++c)
+ {
+ if (*c == 'A')
+ *c = 'a'; // Maniac Vera: BUG toupper in the letter a, it does not convert it
+ }
+ }
+
+ return path;
+}
+
+bool ContainsOnlyNumbers(const char *string)
+{
+ volatile char c;
+
+ if (string == NULL)
+ return false;
+
+ if (*string == 0)
+ return false;
+
+ while ((c=*(string++))!=0)
+ {
+ if (c<'0' || c>'9')
+ return false;
+ }
+
+ return true;
+}
+
+int GetDeviceType(const char *dir)
+{
+ if (!strncasecmp(dir, "/cd", 3))
+ {
+ return APP_DEVICE_CD;
+ }
+ else if (!strncasecmp(dir, "/sd", 3))
+ {
+ return APP_DEVICE_SD;
+ }
+ else if (!strncasecmp(dir, "/ide", 4))
+ {
+ return APP_DEVICE_IDE;
+ }
+ else if (!strncasecmp(dir, "/pc", 3))
+ {
+ return APP_DEVICE_PC;
+ // } else if(!strncasecmp(dir, "/???", 5)) {
+ // return APP_DEVICE_NET;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+int CanUseTrueAsyncDMA(int sector_size, int current_dev, int image_type)
+{
+ return (sector_size == 2048 &&
+ (current_dev == APP_DEVICE_IDE || current_dev == APP_DEVICE_CD) &&
+ (image_type == ISOFS_IMAGE_TYPE_ISO || image_type == ISOFS_IMAGE_TYPE_GDI));
+}
+
+void GetMD5HashISO(const char *file_mount_point, SectorDataStruct *sector_data)
+{
+ file_t fd;
+ fd = fs_iso_first_file(file_mount_point);
+
+ if (fd != FILEHND_INVALID)
+ {
+ if (fs_ioctl(fd, ISOFS_IOCTL_GET_BOOT_SECTOR_DATA, (int)sector_data->boot_sector) < 0)
+ {
+ memset(sector_data->md5, 0, sizeof(sector_data->md5));
+ memset(sector_data->boot_sector, 0, sizeof(sector_data->boot_sector));
+ }
+ else
+ {
+ kos_md5(sector_data->boot_sector, sizeof(sector_data->boot_sector), sector_data->md5);
+ }
+
+ // Also get image type and sector size
+ if (fs_ioctl(fd, ISOFS_IOCTL_GET_IMAGE_TYPE, (int)§or_data->image_type) < 0)
+ {
+ ds_printf("Can't get image type\n");
+ }
+
+ if (fs_ioctl(fd, ISOFS_IOCTL_GET_DATA_TRACK_SECTOR_SIZE, (int)§or_data->sector_size) < 0)
+ {
+ ds_printf("Can't get sector size\n");
+ }
+
+ fs_close(fd);
+ }
+}
+
+bool MakeShortcut(PresetStruct *preset, const char* device_dir, const char* full_path_game, bool show_name, const char* game_cover_path, int width, int height, bool yflip)
+{
+ FILE *fd;
+ char save_file[NAME_MAX];
+ char cmd[NAME_MAX * 2];
+ int i;
+
+ if (show_name)
+ {
+ snprintf(save_file, NAME_MAX, "%s/apps/main/scripts/%s.dsc", device_dir, preset->shortcut_name);
+ }
+ else
+ {
+ snprintf(save_file, NAME_MAX, "%s/apps/main/scripts/_%s.dsc", device_dir, preset->shortcut_name);
+ }
+
+ fd = fopen(save_file, "w");
+
+ if(!fd)
+ {
+ ds_printf("DS_ERROR: Can't save shortcut\n");
+ return false;
+ }
+
+ fprintf(fd, "module -o -f %s/modules/minilzo.klf\n", device_dir);
+ fprintf(fd, "module -o -f %s/modules/isofs.klf\n", device_dir);
+ fprintf(fd, "module -o -f %s/modules/isoldr.klf\n", device_dir);
+
+ strcpy(cmd, "isoldr");
+ strcat(cmd, preset->fastboot ? " -s" : " -i" );
+
+ if (preset->use_dma)
+ {
+ strcat(cmd, " -a");
+ }
+
+ if (preset->alt_read)
+ {
+ strcat(cmd, " -y");
+ }
+
+ if (preset->use_irq)
+ {
+ strcat(cmd, " -q");
+ }
+
+ if (preset->low)
+ {
+ strcat(cmd, " -l");
+ }
+
+ if (preset->emu_async)
+ {
+ char async[8];
+ snprintf(async, sizeof(async), " -e %d", preset->emu_async);
+ strcat(cmd, async);
+ }
+
+ if(strncmp(preset->device, "auto", 4) != 0)
+ {
+ strcat(cmd, " -d ");
+ strcat(cmd, preset->device);
+ }
+
+ const char *memory_tmp;
+
+ if(strlen(preset->memory) < 8)
+ {
+ char text[24];
+ memset(text, 0, sizeof(text));
+ strncpy(text, preset->memory, 10);
+ memory_tmp = strncat(text, preset->custom_memory, 10);
+
+ strcat(cmd, " -x ");
+ strcat(cmd, memory_tmp);
+ }
+ else
+ {
+ strcat(cmd, " -x ");
+ strcat(cmd, preset->memory);
+ }
+
+ char game[NAME_MAX];
+ memset(game, 0, NAME_MAX);
+ strcpy(game, full_path_game);
+
+ strcat(cmd, " -f ");
+ strcat(cmd, FixSpaces(game));
+
+ char boot_mode[8];
+ sprintf(boot_mode, "%d", preset->boot_mode);
+ strcat(cmd, " -j ");
+ strcat(cmd, boot_mode);
+
+ char os[8];
+ sprintf(os, "%d", preset->bin_type);
+ strcat(cmd, " -o ");
+ strcat(cmd, os);
+
+ char patchstr[24];
+ for(i = 0; i < 2 ; ++i)
+ {
+ if(preset->pa[i] & 0xffffff) {
+ sprintf(patchstr," --pa%d 0x%s", i + 1, preset->patch_a[i]);
+ strcat(cmd, patchstr);
+ sprintf(patchstr," --pv%d 0x%s", i + 1, preset->patch_v[i]);
+ strcat(cmd, patchstr);
+ }
+ }
+
+ if (preset->emu_cdda)
+ {
+ char cdda_mode[12];
+ sprintf(cdda_mode, "0x%08lx", preset->emu_cdda);
+ strcat(cmd, " -g ");
+ strcat(cmd, cdda_mode);
+ }
+
+ if (preset->heap <= HEAP_MODE_MAPLE)
+ {
+ char mode[24];
+ sprintf(mode, " -h %d", i);
+ strcat(cmd, mode);
+ }
+ else
+ {
+ char *addr = preset->heap_memory;
+ strcat(cmd, " -h ");
+ strcat(cmd, addr);
+ }
+
+ if (preset->vmu_mode > 0)
+ {
+ char number[12];
+ sprintf(number, " -v %d", atoi(preset->vmu_file));
+ strcat(cmd, number);
+ }
+
+ if (preset->screenshot)
+ {
+ char hotkey[24];
+ sprintf(hotkey, " -k 0x%lx", (uint32)SCREENSHOT_HOTKEY);
+ strcat(cmd, hotkey);
+ }
+
+ if(preset->alt_boot)
+ {
+ char boot_file[24];
+ sprintf(boot_file, " -b %s", ALT_BOOT_FILE);
+ strcat(cmd, boot_file);
+ }
+
+ fprintf(fd, "%s\n", cmd);
+ fprintf(fd, "console --show\n");
+ fclose(fd);
+
+ if (show_name)
+ {
+ snprintf(save_file, NAME_MAX, "%s/apps/main/images/%s.png", device_dir, preset->shortcut_name);
+ }
+ else
+ {
+ snprintf(save_file, NAME_MAX, "%s/apps/main/images/_%s.png", device_dir, preset->shortcut_name);
+ }
+
+ if(FileExists(save_file))
+ {
+ fs_unlink(save_file);
+ }
+
+ if (game_cover_path != NULL)
+ {
+ copy_image(game_cover_path, save_file, strcasecmp(strrchr(game_cover_path, '.'), ".png") == 0 ? true : false, true, 256, 256, width, height, yflip);
+ }
+
+ return true;
+}
+
+char* MakePresetFilename(const char *default_dir, const char *device_dir, uint8 *md5, const char *app_name)
+{
+ char dev[8];
+ static char filename[NAME_MAX];
+
+ memset(filename, 0, sizeof(filename));
+ strncpy(dev, &device_dir[1], 3);
+
+ if (dev[2] == '/')
+ {
+ dev[2] = '\0';
+ }
+ else
+ {
+ dev[3] = '\0';
+ }
+
+ snprintf(filename, sizeof(filename),
+ "%s/apps/%s/presets/%s_%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x.cfg",
+ default_dir, app_name, dev, md5[0],
+ md5[1], md5[2], md5[3], md5[4], md5[5],
+ md5[6], md5[7], md5[8], md5[9], md5[10],
+ md5[11], md5[12], md5[13], md5[14], md5[15]);
+
+ return filename;
+}
+
+const char *GetFolderPathFromFile(const char *full_path_file)
+{
+ static char path[NAME_MAX];
+
+ char *filename = (char *)malloc(NAME_MAX);
+ memset(filename, 0, NAME_MAX);
+ strcpy(filename, GetLastPart(full_path_file, '/', 0));
+
+ memset(path, 0, NAME_MAX);
+
+ strncpy(path, full_path_file, strlen(full_path_file) - (strlen(filename) + 1));
+ free(filename);
+
+ return path;
+}
+
+size_t GetCDDATrackFilename(int num, const char *full_path_game, char **result)
+{
+ char *path = (char *)malloc(NAME_MAX);
+ int size = 0;
+
+ char *game = (char *)malloc(NAME_MAX);
+ memset(game, 0, NAME_MAX);
+ strcpy(game, GetLastPart(full_path_game, '/', 0));
+
+ if (*result == NULL)
+ {
+ *result = (char *)malloc(NAME_MAX);
+ }
+
+ memset(*result, 0, NAME_MAX);
+ memset(path, 0, NAME_MAX);
+
+ strncpy(path, full_path_game, strlen(full_path_game) - (strlen(game) + 1));
+ snprintf(*result, NAME_MAX, "%s/track%02d.raw", path, num);
+ free(game);
+ free(path);
+ size = FileSize(*result);
+
+ if (size > 0)
+ {
+ return size;
+ }
+
+ int len = strlen(*result);
+ (*result)[len - 3] = 'w';
+ (*result)[len - 1] = 'v';
+
+ return FileSize(*result);
+}
+
+static wav_stream_hnd_t wav_hnd = SND_STREAM_INVALID;
+static int wav_inited = 0;
+
+void StopCDDATrack()
+{
+ if (wav_inited)
+ {
+ wav_inited = 0;
+ wav_shutdown();
+ }
+}
+
+void PlayCDDATrack(const char *file, int loop)
+{
+ StopCDDATrack();
+ wav_inited = wav_init();
+
+ if (wav_inited)
+ {
+ wav_hnd = wav_create(file, loop);
+
+ if (wav_hnd == SND_STREAM_INVALID)
+ {
+ ds_printf("DS_ERROR: Can't play file: %s\n", file);
+ return;
+ }
+ ds_printf("DS_OK: Start playing: %s\n", file);
+ wav_play(wav_hnd);
+ }
+}
diff --git a/applications/games_menu/resources/empty_vmu_1024kb.vmd b/applications/games_menu/resources/empty_vmu_1024kb.vmd
new file mode 100644
index 00000000..f7a72c9c
Binary files /dev/null and b/applications/games_menu/resources/empty_vmu_1024kb.vmd differ
diff --git a/applications/games_menu/resources/empty_vmu_128kb.vmd b/applications/games_menu/resources/empty_vmu_128kb.vmd
new file mode 100755
index 00000000..90f4f872
Binary files /dev/null and b/applications/games_menu/resources/empty_vmu_128kb.vmd differ
diff --git a/applications/iso_loader/app.xml b/applications/iso_loader/app.xml
index 8920e888..1622ca63 100644
--- a/applications/iso_loader/app.xml
+++ b/applications/iso_loader/app.xml
@@ -1,10 +1,10 @@
-
+
-
+
@@ -15,19 +15,19 @@
-
+
-
+
-
+
@@ -42,15 +42,15 @@
-
+
-
+
-
+
@@ -78,6 +78,13 @@
+
+
+
+
+
+
+
@@ -149,6 +156,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -255,12 +279,12 @@
-
+
-
+
@@ -294,6 +318,9 @@
+
+
+
@@ -302,7 +329,7 @@
-
+
@@ -317,14 +344,9 @@
-
-
-
-
-
-
+
@@ -339,16 +361,19 @@
+
+
+
-
+
-
-
+
+
-
-
+
+
@@ -366,7 +391,7 @@
-
+
@@ -382,12 +407,12 @@
+
+
+
-
-
-
@@ -476,42 +501,45 @@
-
+
-
-
-
+
+
+
-
-
+
+
-
-
-
+
+
+
-
-
+
+
+
+
+
-
+
-
+
-
-
+
+
-
+
-
+
-
-
+
+
@@ -539,6 +567,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/applications/iso_loader/modules/Makefile b/applications/iso_loader/modules/Makefile
index 7c232920..287400fa 100644
--- a/applications/iso_loader/modules/Makefile
+++ b/applications/iso_loader/modules/Makefile
@@ -7,7 +7,7 @@
APP_NAME = iso_loader
TARGET_NAME = app_$(APP_NAME)
OBJS = module.o utils.o
-DBG_LIBS = -lds -lisofs -lisoldr -lwav
+DBG_LIBS = -lds -lisofs -lisoldr -lwave
EXPORTS_FILE = exports.txt
VER_MAJOR = 0
diff --git a/applications/iso_loader/modules/app_module.h b/applications/iso_loader/modules/app_module.h
index 2d60a636..e73b00ba 100644
--- a/applications/iso_loader/modules/app_module.h
+++ b/applications/iso_loader/modules/app_module.h
@@ -91,4 +91,7 @@ void isoLoader_Shutdown(App_t *app);
void isoLoader_Exit(GUI_Widget *widget);
uint32 getModeCDDA();
+
void setModeCDDA(uint32 mode);
+
+void isoLoader_FwItemClick(dirent_fm_t *fm_ent);
diff --git a/applications/iso_loader/modules/exports.txt b/applications/iso_loader/modules/exports.txt
index 17e20bc2..89fe5a00 100644
--- a/applications/iso_loader/modules/exports.txt
+++ b/applications/iso_loader/modules/exports.txt
@@ -36,3 +36,4 @@ isoLoader_toggleLinkName
isoLoader_Rotate_Image
isoLoader_toggleExtension
isoLoader_toggleVMU
+isoLoader_FwItemClick
diff --git a/applications/iso_loader/modules/module.c b/applications/iso_loader/modules/module.c
index 5a5288ff..b95ca8f6 100644
--- a/applications/iso_loader/modules/module.c
+++ b/applications/iso_loader/modules/module.c
@@ -56,7 +56,7 @@ static struct {
GUI_Widget *cdda;
GUI_Widget *cdda_mode[6];
GUI_Widget *cdda_mode_src[2];
- GUI_Widget *cdda_mode_dst[2];
+ GUI_Widget *cdda_mode_dst[3];
GUI_Widget *cdda_mode_pos[2];
GUI_Widget *cdda_mode_ch[2];
GUI_Widget *irq;
@@ -73,11 +73,13 @@ static struct {
GUI_Widget *vmu_priv_1mb;
GUI_Widget *screenshot;
GUI_Widget *alt_boot;
+ GUI_Widget *alt_read;
GUI_Widget *device;
+ GUI_Widget *fw_browser;
GUI_Widget *os_chk[4];
- GUI_Widget *options_switch[4];
+ GUI_Widget *options_switch[5];
GUI_Widget *boot_mode_chk[3];
GUI_Widget *memory_chk[16];
GUI_Widget *memory_text;
@@ -305,6 +307,8 @@ static void setTitle(const char *text) {
}
GUI_LabelSetText(self.title, lines[0]);
GUI_LabelSetText(self.title2, lines[1]);
+
+ vmu_draw_string(text);
}
/* Try to get cover image from ISO */
@@ -317,6 +321,7 @@ static void showCover() {
ipbin_meta_t *ipbin;
int use_cover = 0;
+ setTitle("Loading...");
snprintf(path, NAME_MAX, "%s/%s", GUI_FileManagerGetPath(self.filebrowser), self.filename);
if(fs_iso_mount("/isocover", path)) {
@@ -372,8 +377,6 @@ static void showCover() {
GUI_PanelSetBackground(self.cover_widget, self.default_cover);
self.current_cover = self.default_cover;
}
-
- vmu_draw_string(noext);
}
void isoLoader_MakeShortcut(GUI_Widget *widget) {
@@ -405,11 +408,12 @@ void isoLoader_MakeShortcut(GUI_Widget *widget) {
if(GUI_WidgetGetState(self.dma)) {
strcat(cmd, " -a");
}
-
+ if(GUI_WidgetGetState(self.alt_read)) {
+ strcat(cmd, " -y");
+ }
if(GUI_WidgetGetState(self.irq)) {
strcat(cmd, " -q");
}
-
if(GUI_WidgetGetState(self.low)) {
strcat(cmd, " -l");
}
@@ -836,9 +840,11 @@ uint32 getModeCDDA() {
index = getActiveWidgetIndex(self.cdda_mode_dst, sizeof(self.cdda_mode_dst) >> 2);
if (index == 0) {
- mode |= CDDA_MODE_DST_SQ;
- } else {
+ mode |= CDDA_MODE_DST_PIO;
+ } else if(index == 1) {
mode |= CDDA_MODE_DST_DMA;
+ } else {
+ mode |= CDDA_MODE_DST_SQ;
}
index = getActiveWidgetIndex(self.cdda_mode_pos, sizeof(self.cdda_mode_pos) >> 2);
@@ -887,13 +893,13 @@ void setModeCDDA(uint32 mode) {
break;
case CDDA_MODE_SQ_TMU2:
isoLoader_toggleCDDA_Source(self.cdda_mode_src[0]);
- isoLoader_toggleCDDA_Dest(self.cdda_mode_dst[0]);
+ isoLoader_toggleCDDA_Dest(self.cdda_mode_dst[2]);
isoLoader_toggleCDDA_Pos(self.cdda_mode_pos[1]);
isoLoader_toggleCDDA_Chan(self.cdda_mode_ch[1]);
break;
case CDDA_MODE_SQ_TMU1:
isoLoader_toggleCDDA_Source(self.cdda_mode_src[0]);
- isoLoader_toggleCDDA_Dest(self.cdda_mode_dst[0]);
+ isoLoader_toggleCDDA_Dest(self.cdda_mode_dst[2]);
isoLoader_toggleCDDA_Pos(self.cdda_mode_pos[0]);
isoLoader_toggleCDDA_Chan(self.cdda_mode_ch[1]);
break;
@@ -909,10 +915,12 @@ void setModeCDDA(uint32 mode) {
isoLoader_toggleCDDA_Source(self.cdda_mode_src[1]);
}
- if (mode & CDDA_MODE_DST_SQ) {
+ if (mode & CDDA_MODE_DST_PIO) {
isoLoader_toggleCDDA_Dest(self.cdda_mode_dst[0]);
- } else {
+ } else if (mode & CDDA_MODE_DST_DMA) {
isoLoader_toggleCDDA_Dest(self.cdda_mode_dst[1]);
+ } else {
+ isoLoader_toggleCDDA_Dest(self.cdda_mode_dst[2]);
}
if (mode & CDDA_MODE_POS_TMU1) {
@@ -1011,6 +1019,24 @@ void isoLoader_toggleVMU(GUI_Widget *widget) {
}
}
+void isoLoader_FwItemClick(dirent_fm_t *fm_ent) {
+ if (!fm_ent) {
+ return;
+ }
+ dirent_t *ent = &fm_ent->ent;
+
+ if (ent->attr != O_DIR) {
+ char noext[128];
+ size_t len = strlen(ent->name) - 4;
+ memset(noext, 0, sizeof(noext));
+ strncpy(noext, ent->name, len);
+ GUI_TextEntrySetText(self.device, noext);
+ }
+ else if(ent->name[0] == '.' && ent->name[1] == '.') {
+ GUI_TextEntrySetText(self.device, "auto");
+ }
+}
+
void isoLoader_Run(GUI_Widget *widget) {
char filepath[NAME_MAX];
@@ -1054,11 +1080,9 @@ void isoLoader_Run(GUI_Widget *widget) {
if(GUI_WidgetGetState(self.irq)) {
self.isoldr->use_irq = 1;
}
-
if(GUI_WidgetGetState(self.low)) {
self.isoldr->syscalls = 1;
}
-
if(GUI_WidgetGetState(self.cdda)) {
self.isoldr->emu_cdda = getModeCDDA();
}
@@ -1086,7 +1110,9 @@ void isoLoader_Run(GUI_Widget *widget) {
if(GUI_WidgetGetState(self.dma)) {
self.isoldr->use_dma = 1;
}
-
+ if(GUI_WidgetGetState(self.alt_read)) {
+ self.isoldr->alt_read = 1;
+ }
if(GUI_WidgetGetState(self.fastboot)) {
self.isoldr->fast_boot = 1;
}
@@ -1160,23 +1186,25 @@ void isoLoader_Run(GUI_Widget *widget) {
}
} else {
+ char vmupath[NAME_MAX];
+ memset(vmupath, 0, NAME_MAX);
if(GUI_WidgetGetState(self.vmu_priv_1mb)) {
- snprintf(filepath, sizeof(filepath),
+ snprintf(vmupath, sizeof(vmupath),
"%s/apps/%s/resources/empty_vmu_1024kb.vmd",
getenv("PATH"), lib_get_name() + 4);
} else {
- snprintf(filepath, sizeof(filepath),
+ snprintf(vmupath, sizeof(vmupath),
"%s/apps/%s/resources/empty_vmu_128kb.vmd",
getenv("PATH"), lib_get_name() + 4);
}
- int src_size = FileSize(filepath);
+ int src_size = FileSize(vmupath);
if (src_size > 0 && priv_size != src_size) {
if (priv_size > 0) {
fs_unlink(priv_path);
}
- CopyFile(filepath, priv_path, 0);
+ CopyFile(vmupath, priv_path, 0);
}
}
}
@@ -1348,6 +1376,7 @@ void isoLoader_DefaultPreset() {
setModeCDDA(CDDA_MODE_DISABLED);
+ GUI_WidgetSetState(self.alt_read, 0);
GUI_WidgetSetState(self.irq, 0);
GUI_WidgetSetState(self.low, 0);
isoLoader_toggleVMU(self.vmu_disabled);
@@ -1386,20 +1415,22 @@ void isoLoader_DefaultPreset() {
int isoLoader_SavePreset() {
- if (!GUI_WidgetGetState(self.preset)) {
+ if(!GUI_WidgetGetState(self.preset)) {
return 0;
}
- char *filename, *memory = NULL;
+ char *filename;
file_t fd;
ipbin_meta_t *ipbin = (ipbin_meta_t *)self.boot_sector;
char result[1024];
- char text[24];
+ char memory[24];
+ char title[32];
int async = 0, type = 0, mode = 0;
uint32 heap = HEAP_MODE_AUTO;
uint32 cdda_mode = CDDA_MODE_DISABLED;
+ int vmu_num = 0;
- if (!self.filename[0]) {
+ if(!self.filename[0]) {
return 0;
}
@@ -1412,6 +1443,10 @@ int isoLoader_SavePreset() {
return -1;
}
+ memset(result, 0, sizeof(result));
+ memset(title, 0, sizeof(title));
+ memset(memory, 0, sizeof(memory));
+
for(int i = 1; i < sizeof(self.async) >> 2; i++) {
if(GUI_WidgetGetState(self.async[i])) {
async = atoi(GUI_LabelGetText(GUI_ButtonGetCaption(self.async[i])));
@@ -1438,15 +1473,14 @@ int isoLoader_SavePreset() {
if (i <= HEAP_MODE_MAPLE) {
heap = i;
} else {
- char *tmpval = (char* )GUI_ObjectGetName((GUI_Object *)self.heap[i]);
+ char *tmpval = (char *)GUI_ObjectGetName((GUI_Object *)self.heap[i]);
if(strlen(tmpval) < 8) {
- memset(text, 0, sizeof(text));
- strncpy(text, tmpval, 10);
- tmpval = strncat(text, GUI_TextEntryGetText(self.heap_memory_text), 10);
+ strncpy(memory, tmpval, 10);
+ tmpval = strncat(memory, GUI_TextEntryGetText(self.heap_memory_text), 10);
}
-
heap = strtoul(tmpval, NULL, 16);
+ memset(memory, 0, sizeof(memory));
}
break;
}
@@ -1460,35 +1494,32 @@ int isoLoader_SavePreset() {
if(GUI_WidgetGetState(self.memory_chk[i])) {
- memory = (char* )GUI_ObjectGetName((GUI_Object *)self.memory_chk[i]);
+ char *tmpval = (char *)GUI_ObjectGetName((GUI_Object *)self.memory_chk[i]);
+ strncpy(memory, tmpval, 10);
- if(strlen(memory) < 8) {
- memset(text, 0, sizeof(text));
- strncpy(text, memory, 10);
- memory = strncat(text, GUI_TextEntryGetText(self.memory_text), 10);
+ if(strlen(tmpval) < 8) {
+ strncat(memory, GUI_TextEntryGetText(self.memory_text), 10);
}
break;
}
}
- trim_spaces(ipbin->title, text, sizeof(ipbin->title));
- memset(result, 0, sizeof(result));
-
- int vmu_num = 0;
+ trim_spaces(ipbin->title, title, sizeof(ipbin->title));
- if (GUI_WidgetGetState(self.vmu_disabled) == 0) {
+ if(GUI_WidgetGetState(self.vmu_disabled) == 0) {
vmu_num = atoi(GUI_TextEntryGetText(self.vmu_number));
}
snprintf(result, sizeof(result),
"title = %s\ndevice = %s\ndma = %d\nasync = %d\ncdda = %08lx\n"
"irq = %d\nlow = %d\nheap = %08lx\nfastboot = %d\ntype = %d\nmode = %d\nmemory = %s\n"
- "vmu = %d\nscrhotkey = %lx\n"
+ "vmu = %d\nscrhotkey = %lx\naltread = %d\n"
"pa1 = %08lx\npv1 = %08lx\npa2 = %08lx\npv2 = %08lx\n",
- text, GUI_TextEntryGetText(self.device), GUI_WidgetGetState(self.dma), async,
+ title, GUI_TextEntryGetText(self.device), GUI_WidgetGetState(self.dma), async,
cdda_mode, GUI_WidgetGetState(self.irq), GUI_WidgetGetState(self.low), heap,
GUI_WidgetGetState(self.fastboot), type, mode, memory,
vmu_num, (uint32)(GUI_WidgetGetState(self.screenshot) ? SCREENSHOT_HOTKEY : 0),
+ GUI_WidgetGetState(self.alt_read),
self.pa[0], self.pv[0], self.pa[1], self.pv[1]);
if(GUI_WidgetGetState(self.alt_boot)) {
@@ -1515,7 +1546,7 @@ int isoLoader_LoadPreset() {
return -1;
}
- int use_dma = 0, emu_async = 16, use_irq = 0;
+ int use_dma = 0, emu_async = 16, use_irq = 0, alt_read = 0;
int fastboot = 0, low = 0, emu_vmu = 0, scr_hotkey = 0;
int boot_mode = BOOT_MODE_DIRECT;
int bin_type = BIN_TYPE_AUTO;
@@ -1534,6 +1565,7 @@ int isoLoader_LoadPreset() {
isoldr_conf options[] = {
{ "dma", CONF_INT, (void *) &use_dma },
+ { "altread", CONF_INT, (void *) &alt_read },
{ "cdda", CONF_ULONG, (void *) &emu_cdda },
{ "irq", CONF_INT, (void *) &use_irq },
{ "low", CONF_INT, (void *) &low },
@@ -1563,6 +1595,7 @@ int isoLoader_LoadPreset() {
GUI_WidgetSetState(self.dma, use_dma);
isoLoader_toggleDMA(self.dma);
+ GUI_WidgetSetState(self.alt_read, alt_read);
if (emu_async == 0) {
GUI_WidgetSetState(self.async[0], 1);
@@ -1642,7 +1675,6 @@ int isoLoader_LoadPreset() {
if (strlen(title) > 0) {
setTitle(title);
- vmu_draw_string(title);
}
if (strlen(device) > 0) {
@@ -1690,9 +1722,11 @@ void isoLoader_Init(App_t *app) {
char *default_dir = NULL;
if(app != NULL) {
-
+ (void)random();
+ (void)random();
+
memset(&self, 0, sizeof(self));
-
+
self.app = app;
self.current_dev = -1;
self.current_item = -1;
@@ -1737,6 +1771,7 @@ void isoLoader_Init(App_t *app) {
self.preset = APP_GET_WIDGET("preset-checkbox");
self.dma = APP_GET_WIDGET("dma-checkbox");
+ self.alt_read = APP_GET_WIDGET("alt-read-checkbox");
self.cdda = APP_GET_WIDGET("cdda-checkbox");
self.irq = APP_GET_WIDGET("irq-checkbox");
self.low = APP_GET_WIDGET("low-checkbox");
@@ -1786,6 +1821,11 @@ void isoLoader_Init(App_t *app) {
self.async_label = APP_GET_WIDGET("async-label");
self.device = APP_GET_WIDGET("device");
+ self.fw_browser = APP_GET_WIDGET("fw_browser");
+
+ char fw_dir[128];
+ sprintf(fw_dir, "%s/firmware/isoldr", getenv("PATH"));
+ GUI_FileManagerChangeDir(self.fw_browser, fw_dir, 0);
w = APP_GET_WIDGET("switch-panel");
diff --git a/applications/iso_loader/modules/utils.c b/applications/iso_loader/modules/utils.c
index e0c4c46d..4a238d34 100644
--- a/applications/iso_loader/modules/utils.c
+++ b/applications/iso_loader/modules/utils.c
@@ -15,6 +15,7 @@ void trim_spaces(char *input, char *output, int size) {
char *p;
char *o;
int s = 0;
+ size--;
p = input;
o = output;
@@ -24,7 +25,7 @@ void trim_spaces(char *input, char *output, int size) {
return;
}
- while(*p == ' ' && s > 0) {
+ while(*p == ' ' && size > 0) {
p++;
size--;
}
diff --git a/applications/main/images/icon.png b/applications/main/images/icon.png
index 690b8abf..e62dfbd2 100755
Binary files a/applications/main/images/icon.png and b/applications/main/images/icon.png differ
diff --git a/applications/main/images/left.png b/applications/main/images/left.png
index 97f3fb00..b7da35bb 100644
Binary files a/applications/main/images/left.png and b/applications/main/images/left.png differ
diff --git a/applications/main/images/left_hover.png b/applications/main/images/left_hover.png
index d6401870..8b4440eb 100644
Binary files a/applications/main/images/left_hover.png and b/applications/main/images/left_hover.png differ
diff --git a/applications/main/images/logo.png b/applications/main/images/logo.png
index 819afeb5..f23589eb 100644
Binary files a/applications/main/images/logo.png and b/applications/main/images/logo.png differ
diff --git a/applications/main/images/right.png b/applications/main/images/right.png
index 1c1e507b..410b4fed 100644
Binary files a/applications/main/images/right.png and b/applications/main/images/right.png differ
diff --git a/applications/main/images/right_hover.png b/applications/main/images/right_hover.png
index ff895ec0..2cfb56fc 100644
Binary files a/applications/main/images/right_hover.png and b/applications/main/images/right_hover.png differ
diff --git a/applications/main/modules/module.c b/applications/main/modules/module.c
index 356fb509..12b71017 100644
--- a/applications/main/modules/module.c
+++ b/applications/main/modules/module.c
@@ -114,10 +114,10 @@ static void AddToList(const char *name, const char *icon,
else {
ts.w = 0;
pad_x -= 10;
+ }
- if(h >= 96) {
- pad_y -= 5;
- }
+ if(h >= 96) {
+ pad_y -= 5;
}
int w = ts.w + GUI_SurfaceGetWidth(s);
diff --git a/applications/settings/modules/module.c b/applications/settings/modules/module.c
index 042e503a..31c68ba9 100644
--- a/applications/settings/modules/module.c
+++ b/applications/settings/modules/module.c
@@ -397,25 +397,30 @@ static void SetupBootSettings() {
static void update_rtc_ui() {
char buf[5];
- struct tm time;
-
- rtc_gettimeutc(&time);
-
- sprintf(buf,"%04d",time.tm_year + 1900);
- GUI_TextEntrySetText(self.sysdate[0], buf);
- sprintf(buf,"%02d",time.tm_mon + 1);
- GUI_TextEntrySetText(self.sysdate[1], buf);
- sprintf(buf,"%02d",time.tm_mday);
- GUI_TextEntrySetText(self.sysdate[2], buf);
- sprintf(buf,"%02d",time.tm_hour);
- GUI_TextEntrySetText(self.sysdate[3], buf);
- sprintf(buf,"%02d",time.tm_min);
- GUI_TextEntrySetText(self.sysdate[4], buf);
+ struct tm *time;
+ time_t unix_time;
+
+ unix_time = rtc_unix_secs();
+ time = gmtime(&unix_time);
+
+ if (time != NULL) {
+ sprintf(buf, "%04d", time->tm_year + 1900);
+ GUI_TextEntrySetText(self.sysdate[0], buf);
+ sprintf(buf, "%02d", time->tm_mon + 1);
+ GUI_TextEntrySetText(self.sysdate[1], buf);
+ sprintf(buf, "%02d", time->tm_mday);
+ GUI_TextEntrySetText(self.sysdate[2], buf);
+ sprintf(buf, "%02d", time->tm_hour);
+ GUI_TextEntrySetText(self.sysdate[3], buf);
+ sprintf(buf, "%02d", time->tm_min);
+ GUI_TextEntrySetText(self.sysdate[4], buf);
+ }
}
void SettingsApp_TimeChange(GUI_Widget *widget)
{
struct tm time;
+ time_t unix_time;
if(strcmp(GUI_ObjectGetName(widget), "get-time") == 0)
{
@@ -429,7 +434,11 @@ void SettingsApp_TimeChange(GUI_Widget *widget)
time.tm_mday = atoi(GUI_TextEntryGetText(self.sysdate[2]));
time.tm_mon = atoi(GUI_TextEntryGetText(self.sysdate[1])) - 1;
time.tm_year = atoi(GUI_TextEntryGetText(self.sysdate[0])) - 1900;
- rtc_settimeutc(&time);
+
+ unix_time = mktime(&time);
+ if(unix_time != -1) {
+ rtc_set_unix_secs(unix_time);
+ }
}
else if(strcmp(GUI_ObjectGetName(widget), "sync-time") == 0)
{
diff --git a/applications/speedtest/app.xml b/applications/speedtest/app.xml
index 9dd1aa4b..ab8bf4c6 100644
--- a/applications/speedtest/app.xml
+++ b/applications/speedtest/app.xml
@@ -1,5 +1,5 @@
-
+
@@ -79,13 +79,13 @@
-
+
-
+
-
+