mirror of
https://github.com/spicyjpeg/573in1.git
synced 2025-01-22 19:52:05 +01:00
Add RTC time adjustment menu
This commit is contained in:
parent
3f259377ce
commit
88528c1e72
@ -94,6 +94,7 @@ addExecutable(
|
|||||||
src/main/main.cpp
|
src/main/main.cpp
|
||||||
src/main/uibase.cpp
|
src/main/uibase.cpp
|
||||||
src/main/uicommon.cpp
|
src/main/uicommon.cpp
|
||||||
|
src/main/uimodals.cpp
|
||||||
src/main/zs01.cpp
|
src/main/zs01.cpp
|
||||||
src/main/app/app.cpp
|
src/main/app/app.cpp
|
||||||
src/main/app/cartactions.cpp
|
src/main/app/cartactions.cpp
|
||||||
|
@ -323,6 +323,15 @@
|
|||||||
"name": "View IDE device and filesystem information",
|
"name": "View IDE device and filesystem information",
|
||||||
"prompt": "Display information about the connected IDE/ATAPI devices and mounted FAT filesystem (if any)."
|
"prompt": "Display information about the connected IDE/ATAPI devices and mounted FAT filesystem (if any)."
|
||||||
},
|
},
|
||||||
|
"runExecutable": {
|
||||||
|
"name": "Run executable from hard drive",
|
||||||
|
"prompt": "Load and launch a System 573 executable file from the IDE hard drive or CF card connected as secondary drive (if any).",
|
||||||
|
"filePrompt": "Note that PlayStation executables built without proper System 573 support will not run unless the watchdog is manually disabled."
|
||||||
|
},
|
||||||
|
"setRTCTime": {
|
||||||
|
"name": "Set RTC date and time",
|
||||||
|
"prompt": "Adjust the current date and time. Note that the time will not persist after a power cycle if the RTC's internal battery is empty."
|
||||||
|
},
|
||||||
"setResolution": {
|
"setResolution": {
|
||||||
"name": "Change screen resolution",
|
"name": "Change screen resolution",
|
||||||
"prompt": "Switch to a different screen resolution and aspect ratio. Some monitors and upscalers may not support all resolutions."
|
"prompt": "Switch to a different screen resolution and aspect ratio. Some monitors and upscalers may not support all resolutions."
|
||||||
@ -331,11 +340,6 @@
|
|||||||
"name": "About this tool",
|
"name": "About this tool",
|
||||||
"prompt": "View information about this tool, including open source licenses."
|
"prompt": "View information about this tool, including open source licenses."
|
||||||
},
|
},
|
||||||
"runExecutable": {
|
|
||||||
"name": "Run executable from hard drive",
|
|
||||||
"prompt": "Load and launch a System 573 executable file from the IDE hard drive or CF card connected as secondary drive (if any).",
|
|
||||||
"filePrompt": "Note that PlayStation executables built without proper System 573 support will not run unless the watchdog is manually disabled."
|
|
||||||
},
|
|
||||||
"ejectCD": {
|
"ejectCD": {
|
||||||
"name": "Eject CD-ROM",
|
"name": "Eject CD-ROM",
|
||||||
"prompt": "Open the CD-ROM drive's tray. You may use this option if the drive's eject button is not easily accessible on your 573."
|
"prompt": "Open the CD-ROM drive's tray. You may use this option if the drive's eject button is not easily accessible on your 573."
|
||||||
@ -383,6 +387,13 @@
|
|||||||
"640x480i": "640x480 (4:3), interlaced"
|
"640x480i": "640x480 (4:3), interlaced"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"RTCTimeScreen": {
|
||||||
|
"title": "Set RTC date and time",
|
||||||
|
"body": "Enter the current date and time. Note that System 573 games only accept years in 1970-2069 range.\n\nUse {LEFT_BUTTON}{RIGHT_BUTTON} to move the cursor, hold {START_BUTTON} and use {LEFT_BUTTON}{RIGHT_BUTTON} to edit the highlighted field.",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"ok": "Confirm"
|
||||||
|
},
|
||||||
|
|
||||||
"StorageActionsScreen": {
|
"StorageActionsScreen": {
|
||||||
"title": "{CART_ICON} Storage device options",
|
"title": "{CART_ICON} Storage device options",
|
||||||
"itemPrompt": "{RIGHT_ARROW} Press {START_BUTTON} to select, hold {LEFT_BUTTON}{RIGHT_BUTTON} + {START_BUTTON} to go back",
|
"itemPrompt": "{RIGHT_ARROW} Press {START_BUTTON} to select, hold {LEFT_BUTTON}{RIGHT_BUTTON} + {START_BUTTON} to go back",
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "common/ide.hpp"
|
#include "common/ide.hpp"
|
||||||
#include "common/io.hpp"
|
#include "common/io.hpp"
|
||||||
|
#include "common/util.hpp"
|
||||||
#include "vendor/diskio.h"
|
#include "vendor/diskio.h"
|
||||||
|
|
||||||
/* FatFs library API glue */
|
/* FatFs library API glue */
|
||||||
@ -87,5 +88,8 @@ extern "C" DRESULT disk_ioctl(uint8_t drive, uint8_t cmd, void *data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" uint32_t get_fattime(void) {
|
extern "C" uint32_t get_fattime(void) {
|
||||||
return io::getRTCTime();
|
util::Date date;
|
||||||
|
|
||||||
|
io::getRTCTime(date);
|
||||||
|
return date.toDOSTime();
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "common/io.hpp"
|
#include "common/io.hpp"
|
||||||
|
#include "common/util.hpp"
|
||||||
#include "ps1/registers.h"
|
#include "ps1/registers.h"
|
||||||
#include "ps1/registers573.h"
|
#include "ps1/registers573.h"
|
||||||
#include "ps1/system.h"
|
#include "ps1/system.h"
|
||||||
@ -63,32 +64,53 @@ uint32_t getJAMMAInputs(void) {
|
|||||||
return inputs ^ 0x1fffffff;
|
return inputs ^ 0x1fffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t getRTCTime(void) {
|
void getRTCTime(util::Date &output) {
|
||||||
SYS573_RTC_CTRL |= SYS573_RTC_CTRL_READ;
|
SYS573_RTC_CTRL |= SYS573_RTC_CTRL_READ;
|
||||||
|
|
||||||
int year = SYS573_RTC_YEAR, month = SYS573_RTC_MONTH, day = SYS573_RTC_DAY;
|
auto second = SYS573_RTC_SECOND, minute = SYS573_RTC_MINUTE;
|
||||||
int hour = SYS573_RTC_HOUR, min = SYS573_RTC_MINUTE, sec = SYS573_RTC_SECOND;
|
auto hour = SYS573_RTC_HOUR, day = SYS573_RTC_DAY;
|
||||||
|
auto month = SYS573_RTC_MONTH, year = SYS573_RTC_YEAR;
|
||||||
|
|
||||||
SYS573_RTC_CTRL &= ~SYS573_RTC_CTRL_READ;
|
SYS573_RTC_CTRL &= ~SYS573_RTC_CTRL_READ;
|
||||||
|
|
||||||
year = (year & 15) + 10 * ((year >> 4) & 15); // 0-99
|
output.year = (year & 15) + 10 * ((year >> 4) & 15); // 0-99
|
||||||
month = (month & 15) + 10 * ((month >> 4) & 1); // 1-12
|
output.month = (month & 15) + 10 * ((month >> 4) & 1); // 1-12
|
||||||
day = (day & 15) + 10 * ((day >> 4) & 3); // 1-31
|
output.day = (day & 15) + 10 * ((day >> 4) & 3); // 1-31
|
||||||
hour = (hour & 15) + 10 * ((hour >> 4) & 3); // 0-23
|
output.hour = (hour & 15) + 10 * ((hour >> 4) & 3); // 0-23
|
||||||
min = (min & 15) + 10 * ((min >> 4) & 7); // 0-59
|
output.minute = (minute & 15) + 10 * ((minute >> 4) & 7); // 0-59
|
||||||
sec = (sec & 15) + 10 * ((sec >> 4) & 7); // 0-59
|
output.second = (second & 15) + 10 * ((second >> 4) & 7); // 0-59
|
||||||
|
|
||||||
// Return all values packed into a FAT/MS-DOS-style bitfield. Assume the
|
output.year += (output.year < 70) ? 2000 : 1900;
|
||||||
// year is always in 1995-2094 range.
|
}
|
||||||
int _year = (year >= 95) ? (year + 1900 - 1980) : (year + 2000 - 1980);
|
|
||||||
|
|
||||||
return 0
|
void setRTCTime(const util::Date &value, bool stop) {
|
||||||
| (_year << 25)
|
//assert((value.year >= 1970) && (value.year <= 2069));
|
||||||
| (month << 21)
|
|
||||||
| (day << 16)
|
int _year = value.year % 100;
|
||||||
| (hour << 11)
|
int weekday = value.getDayOfWeek();
|
||||||
| (min << 5)
|
|
||||||
| (sec >> 1);
|
int year = (_year % 10) | (((_year / 10) & 15) << 4);
|
||||||
|
int month = (value.month % 10) | (((value.month / 10) & 1) << 4);
|
||||||
|
int day = (value.day % 10) | (((value.day / 10) & 3) << 4);
|
||||||
|
int hour = (value.hour % 10) | (((value.hour / 10) & 3) << 4);
|
||||||
|
int minute = (value.minute % 10) | (((value.minute / 10) & 7) << 4);
|
||||||
|
int second = (value.second % 10) | (((value.second / 10) & 7) << 4);
|
||||||
|
|
||||||
|
SYS573_RTC_CTRL |= SYS573_RTC_CTRL_WRITE;
|
||||||
|
|
||||||
|
SYS573_RTC_SECOND = second
|
||||||
|
| (stop ? SYS573_RTC_SECOND_STOP : 0);
|
||||||
|
SYS573_RTC_MINUTE = minute;
|
||||||
|
SYS573_RTC_HOUR = hour;
|
||||||
|
SYS573_RTC_WEEKDAY = weekday
|
||||||
|
| SYS573_RTC_WEEKDAY_CENTURY
|
||||||
|
| SYS573_RTC_WEEKDAY_CENTURY_ENABLE;
|
||||||
|
SYS573_RTC_DAY = day
|
||||||
|
| SYS573_RTC_DAY_BATTERY_MONITOR;
|
||||||
|
SYS573_RTC_MONTH = month;
|
||||||
|
SYS573_RTC_YEAR = year;
|
||||||
|
|
||||||
|
SYS573_RTC_CTRL &= ~SYS573_RTC_CTRL_WRITE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isRTCBatteryLow(void) {
|
bool isRTCBatteryLow(void) {
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "common/util.hpp"
|
||||||
#include "ps1/registers.h"
|
#include "ps1/registers.h"
|
||||||
#include "ps1/registers573.h"
|
#include "ps1/registers573.h"
|
||||||
|
|
||||||
@ -159,7 +161,8 @@ static inline void setDIO1Wire(bool value) {
|
|||||||
|
|
||||||
void init(void);
|
void init(void);
|
||||||
uint32_t getJAMMAInputs(void);
|
uint32_t getJAMMAInputs(void);
|
||||||
uint32_t getRTCTime(void);
|
void getRTCTime(util::Date &output);
|
||||||
|
void setRTCTime(const util::Date &value, bool stop = false);
|
||||||
bool isRTCBatteryLow(void);
|
bool isRTCBatteryLow(void);
|
||||||
|
|
||||||
bool loadBitstream(const uint8_t *data, size_t length);
|
bool loadBitstream(const uint8_t *data, size_t length);
|
||||||
|
@ -31,6 +31,69 @@ Hash hash(const uint8_t *data, size_t length) {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Date and time class */
|
||||||
|
|
||||||
|
int Date::getDayOfWeek(void) const {
|
||||||
|
// See https://datatracker.ietf.org/doc/html/rfc3339#appendix-B
|
||||||
|
int _year = year, _month = month - 2;
|
||||||
|
|
||||||
|
if (_month <= 0) {
|
||||||
|
_month += 12;
|
||||||
|
_year--;
|
||||||
|
}
|
||||||
|
|
||||||
|
int century = _year / 100;
|
||||||
|
_year %= 100;
|
||||||
|
|
||||||
|
int weekday = 0
|
||||||
|
+ day
|
||||||
|
+ (_month * 26 - 2) / 10
|
||||||
|
+ _year
|
||||||
|
+ _year / 4
|
||||||
|
+ century / 4
|
||||||
|
+ century * 5;
|
||||||
|
|
||||||
|
return weekday % 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Date::getMonthDayCount(void) const {
|
||||||
|
switch (month) {
|
||||||
|
case 2:
|
||||||
|
return isLeapYear() ? 29 : 28;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
case 6:
|
||||||
|
case 9:
|
||||||
|
case 11:
|
||||||
|
return 30;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 31;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Date::toDOSTime(void) const {
|
||||||
|
int _year = year + 2000 - 1980;
|
||||||
|
|
||||||
|
if ((_year < 0) || (_year > 127))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 0
|
||||||
|
| (_year << 25)
|
||||||
|
| (month << 21)
|
||||||
|
| (day << 16)
|
||||||
|
| (hour << 11)
|
||||||
|
| (minute << 5)
|
||||||
|
| (second >> 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Date::toString(char *output) const {
|
||||||
|
return sprintf(
|
||||||
|
output, "%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute,
|
||||||
|
second
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/* Tween/animation classes */
|
/* Tween/animation classes */
|
||||||
|
|
||||||
template<typename T, typename E> void Tween<T, E>::setValue(
|
template<typename T, typename E> void Tween<T, E>::setValue(
|
||||||
|
@ -158,6 +158,29 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Date and time class */
|
||||||
|
|
||||||
|
class Date {
|
||||||
|
public:
|
||||||
|
uint16_t year;
|
||||||
|
uint8_t month, day;
|
||||||
|
uint8_t hour, minute, second;
|
||||||
|
|
||||||
|
inline bool isLeapYear(void) const {
|
||||||
|
if (year % 4)
|
||||||
|
return false;
|
||||||
|
if (!(year % 100) && (year % 400))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getDayOfWeek(void) const;
|
||||||
|
int getMonthDayCount(void) const;
|
||||||
|
uint32_t toDOSTime(void) const;
|
||||||
|
size_t toString(char *output) const;
|
||||||
|
};
|
||||||
|
|
||||||
/* Tween/animation classes */
|
/* Tween/animation classes */
|
||||||
|
|
||||||
static constexpr int TWEEN_UNIT = 1 << 12;
|
static constexpr int TWEEN_UNIT = 1 << 12;
|
||||||
|
@ -187,14 +187,23 @@ void App::_interruptHandler(void) {
|
|||||||
_setupInterrupts();
|
_setupInterrupts();
|
||||||
_loadResources();
|
_loadResources();
|
||||||
|
|
||||||
_backgroundLayer.text = "v" VERSION_STRING;
|
char dateString[24];
|
||||||
_ctx.background = &_backgroundLayer;
|
|
||||||
|
_backgroundLayer.leftText = dateString;
|
||||||
|
_backgroundLayer.rightText = "v" VERSION_STRING;
|
||||||
|
|
||||||
|
_ctx.background = &_backgroundLayer;
|
||||||
#ifdef ENABLE_LOG_BUFFER
|
#ifdef ENABLE_LOG_BUFFER
|
||||||
_ctx.overlay = &_overlayLayer;
|
_ctx.overlay = &_overlayLayer;
|
||||||
#endif
|
#endif
|
||||||
_ctx.show(_workerStatusScreen);
|
_ctx.show(_workerStatusScreen);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
util::Date date;
|
||||||
|
|
||||||
|
io::getRTCTime(date);
|
||||||
|
date.toString(dateString);
|
||||||
|
|
||||||
_ctx.update();
|
_ctx.update();
|
||||||
_ctx.draw();
|
_ctx.draw();
|
||||||
|
|
||||||
|
@ -60,6 +60,7 @@ class App {
|
|||||||
friend class StorageInfoScreen;
|
friend class StorageInfoScreen;
|
||||||
friend class StorageActionsScreen;
|
friend class StorageActionsScreen;
|
||||||
friend class IDEInfoScreen;
|
friend class IDEInfoScreen;
|
||||||
|
friend class RTCTimeScreen;
|
||||||
friend class ResolutionScreen;
|
friend class ResolutionScreen;
|
||||||
friend class AboutScreen;
|
friend class AboutScreen;
|
||||||
friend class CartInfoScreen;
|
friend class CartInfoScreen;
|
||||||
@ -84,6 +85,7 @@ private:
|
|||||||
StorageInfoScreen _storageInfoScreen;
|
StorageInfoScreen _storageInfoScreen;
|
||||||
StorageActionsScreen _storageActionsScreen;
|
StorageActionsScreen _storageActionsScreen;
|
||||||
IDEInfoScreen _ideInfoScreen;
|
IDEInfoScreen _ideInfoScreen;
|
||||||
|
RTCTimeScreen _rtcTimeScreen;
|
||||||
ResolutionScreen _resolutionScreen;
|
ResolutionScreen _resolutionScreen;
|
||||||
AboutScreen _aboutScreen;
|
AboutScreen _aboutScreen;
|
||||||
CartInfoScreen _cartInfoScreen;
|
CartInfoScreen _cartInfoScreen;
|
||||||
|
@ -305,9 +305,7 @@ void SystemIDEntryScreen::show(ui::Context &ctx, bool goBack) {
|
|||||||
_buttons[0] = STR("SystemIDEntryScreen.cancel");
|
_buttons[0] = STR("SystemIDEntryScreen.cancel");
|
||||||
_buttons[1] = STR("SystemIDEntryScreen.ok");
|
_buttons[1] = STR("SystemIDEntryScreen.ok");
|
||||||
|
|
||||||
_numButtons = 2;
|
_numButtons = 2;
|
||||||
_locked = false;
|
|
||||||
|
|
||||||
_bufferLength = 8;
|
_bufferLength = 8;
|
||||||
_separator = '-';
|
_separator = '-';
|
||||||
|
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include "common/gpu.hpp"
|
#include "common/gpu.hpp"
|
||||||
#include "common/util.hpp"
|
|
||||||
#include "main/cartdata.hpp"
|
#include "main/cartdata.hpp"
|
||||||
#include "main/uibase.hpp"
|
#include "main/uibase.hpp"
|
||||||
#include "main/uicommon.hpp"
|
#include "main/uicommon.hpp"
|
||||||
|
#include "main/uimodals.hpp"
|
||||||
|
|
||||||
/* Unlocked cartridge screens */
|
/* Unlocked cartridge screens */
|
||||||
|
|
||||||
|
@ -342,9 +342,7 @@ void KeyEntryScreen::show(ui::Context &ctx, bool goBack) {
|
|||||||
_buttons[0] = STR("KeyEntryScreen.cancel");
|
_buttons[0] = STR("KeyEntryScreen.cancel");
|
||||||
_buttons[1] = STR("KeyEntryScreen.ok");
|
_buttons[1] = STR("KeyEntryScreen.ok");
|
||||||
|
|
||||||
_numButtons = 2;
|
_numButtons = 2;
|
||||||
_locked = false;
|
|
||||||
|
|
||||||
_bufferLength = 8;
|
_bufferLength = 8;
|
||||||
_separator = '-';
|
_separator = '-';
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "main/uibase.hpp"
|
#include "main/uibase.hpp"
|
||||||
#include "main/uicommon.hpp"
|
#include "main/uicommon.hpp"
|
||||||
|
#include "main/uimodals.hpp"
|
||||||
|
|
||||||
/* Pre-unlock cartridge screens */
|
/* Pre-unlock cartridge screens */
|
||||||
|
|
||||||
|
@ -99,6 +99,14 @@ static const MenuEntry _MENU_ENTRIES[]{
|
|||||||
.name = "MainMenuScreen.ideInfo.name"_h,
|
.name = "MainMenuScreen.ideInfo.name"_h,
|
||||||
.prompt = "MainMenuScreen.ideInfo.prompt"_h,
|
.prompt = "MainMenuScreen.ideInfo.prompt"_h,
|
||||||
.target = &MainMenuScreen::ideInfo
|
.target = &MainMenuScreen::ideInfo
|
||||||
|
}, {
|
||||||
|
.name = "MainMenuScreen.runExecutable.name"_h,
|
||||||
|
.prompt = "MainMenuScreen.runExecutable.prompt"_h,
|
||||||
|
.target = &MainMenuScreen::runExecutable
|
||||||
|
}, {
|
||||||
|
.name = "MainMenuScreen.setRTCTime.name"_h,
|
||||||
|
.prompt = "MainMenuScreen.setRTCTime.prompt"_h,
|
||||||
|
.target = &MainMenuScreen::setRTCTime
|
||||||
}, {
|
}, {
|
||||||
.name = "MainMenuScreen.setResolution.name"_h,
|
.name = "MainMenuScreen.setResolution.name"_h,
|
||||||
.prompt = "MainMenuScreen.setResolution.prompt"_h,
|
.prompt = "MainMenuScreen.setResolution.prompt"_h,
|
||||||
@ -107,10 +115,6 @@ static const MenuEntry _MENU_ENTRIES[]{
|
|||||||
.name = "MainMenuScreen.about.name"_h,
|
.name = "MainMenuScreen.about.name"_h,
|
||||||
.prompt = "MainMenuScreen.about.prompt"_h,
|
.prompt = "MainMenuScreen.about.prompt"_h,
|
||||||
.target = &MainMenuScreen::about
|
.target = &MainMenuScreen::about
|
||||||
}, {
|
|
||||||
.name = "MainMenuScreen.runExecutable.name"_h,
|
|
||||||
.prompt = "MainMenuScreen.runExecutable.prompt"_h,
|
|
||||||
.target = &MainMenuScreen::runExecutable
|
|
||||||
}, {
|
}, {
|
||||||
.name = "MainMenuScreen.ejectCD.name"_h,
|
.name = "MainMenuScreen.ejectCD.name"_h,
|
||||||
.prompt = "MainMenuScreen.ejectCD.prompt"_h,
|
.prompt = "MainMenuScreen.ejectCD.prompt"_h,
|
||||||
@ -143,14 +147,6 @@ void MainMenuScreen::ideInfo(ui::Context &ctx) {
|
|||||||
ctx.show(APP->_ideInfoScreen, false, true);
|
ctx.show(APP->_ideInfoScreen, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainMenuScreen::setResolution(ui::Context &ctx) {
|
|
||||||
ctx.show(APP->_resolutionScreen, false, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainMenuScreen::about(ui::Context &ctx) {
|
|
||||||
ctx.show(APP->_aboutScreen, false, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainMenuScreen::runExecutable(ui::Context &ctx) {
|
void MainMenuScreen::runExecutable(ui::Context &ctx) {
|
||||||
APP->_filePickerScreen.setMessage(
|
APP->_filePickerScreen.setMessage(
|
||||||
*this,
|
*this,
|
||||||
@ -164,6 +160,18 @@ void MainMenuScreen::runExecutable(ui::Context &ctx) {
|
|||||||
APP->_filePickerScreen.loadRootAndShow(ctx);
|
APP->_filePickerScreen.loadRootAndShow(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainMenuScreen::setRTCTime(ui::Context &ctx) {
|
||||||
|
ctx.show(APP->_rtcTimeScreen, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainMenuScreen::setResolution(ui::Context &ctx) {
|
||||||
|
ctx.show(APP->_resolutionScreen, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainMenuScreen::about(ui::Context &ctx) {
|
||||||
|
ctx.show(APP->_aboutScreen, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
void MainMenuScreen::ejectCD(ui::Context &ctx) {
|
void MainMenuScreen::ejectCD(ui::Context &ctx) {
|
||||||
APP->_setupWorker(&App::_atapiEjectWorker);
|
APP->_setupWorker(&App::_atapiEjectWorker);
|
||||||
ctx.show(APP->_workerStatusScreen, false, true);
|
ctx.show(APP->_workerStatusScreen, false, true);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "main/uibase.hpp"
|
#include "main/uibase.hpp"
|
||||||
#include "main/uicommon.hpp"
|
#include "main/uicommon.hpp"
|
||||||
|
#include "main/uimodals.hpp"
|
||||||
|
|
||||||
/* Main menu screens */
|
/* Main menu screens */
|
||||||
|
|
||||||
@ -33,9 +34,10 @@ public:
|
|||||||
void cartInfo(ui::Context &ctx);
|
void cartInfo(ui::Context &ctx);
|
||||||
void storageInfo(ui::Context &ctx);
|
void storageInfo(ui::Context &ctx);
|
||||||
void ideInfo(ui::Context &ctx);
|
void ideInfo(ui::Context &ctx);
|
||||||
|
void runExecutable(ui::Context &ctx);
|
||||||
|
void setRTCTime(ui::Context &ctx);
|
||||||
void setResolution(ui::Context &ctx);
|
void setResolution(ui::Context &ctx);
|
||||||
void about(ui::Context &ctx);
|
void about(ui::Context &ctx);
|
||||||
void runExecutable(ui::Context &ctx);
|
|
||||||
void ejectCD(ui::Context &ctx);
|
void ejectCD(ui::Context &ctx);
|
||||||
void reboot(ui::Context &ctx);
|
void reboot(ui::Context &ctx);
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "common/file.hpp"
|
#include "common/file.hpp"
|
||||||
#include "common/ide.hpp"
|
#include "common/ide.hpp"
|
||||||
|
#include "common/io.hpp"
|
||||||
#include "common/spu.hpp"
|
#include "common/spu.hpp"
|
||||||
#include "common/util.hpp"
|
#include "common/util.hpp"
|
||||||
#include "main/app/app.hpp"
|
#include "main/app/app.hpp"
|
||||||
@ -107,6 +108,32 @@ void IDEInfoScreen::update(ui::Context &ctx) {
|
|||||||
|
|
||||||
/* Misc. screens */
|
/* Misc. screens */
|
||||||
|
|
||||||
|
void RTCTimeScreen::show(ui::Context &ctx, bool goBack) {
|
||||||
|
_title = STR("RTCTimeScreen.title");
|
||||||
|
_body = STR("RTCTimeScreen.body");
|
||||||
|
_buttons[0] = STR("RTCTimeScreen.cancel");
|
||||||
|
_buttons[1] = STR("RTCTimeScreen.ok");
|
||||||
|
|
||||||
|
_numButtons = 2;
|
||||||
|
io::getRTCTime(_date);
|
||||||
|
|
||||||
|
DateEntryScreen::show(ctx, goBack);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RTCTimeScreen::update(ui::Context &ctx) {
|
||||||
|
DateEntryScreen::update(ctx);
|
||||||
|
|
||||||
|
if (
|
||||||
|
ctx.buttons.pressed(ui::BTN_START) &&
|
||||||
|
(_activeButton >= _buttonIndexOffset)
|
||||||
|
) {
|
||||||
|
if (_activeButton == (_buttonIndexOffset + 1))
|
||||||
|
io::setRTCTime(_date);
|
||||||
|
|
||||||
|
ctx.show(APP->_mainMenuScreen, true, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct Resolution {
|
struct Resolution {
|
||||||
public:
|
public:
|
||||||
util::Hash name;
|
util::Hash name;
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "common/util.hpp"
|
#include "common/util.hpp"
|
||||||
#include "main/uibase.hpp"
|
#include "main/uibase.hpp"
|
||||||
#include "main/uicommon.hpp"
|
#include "main/uicommon.hpp"
|
||||||
|
#include "main/uimodals.hpp"
|
||||||
|
|
||||||
/* System information screens */
|
/* System information screens */
|
||||||
|
|
||||||
@ -20,6 +21,12 @@ public:
|
|||||||
|
|
||||||
/* Misc. screens */
|
/* Misc. screens */
|
||||||
|
|
||||||
|
class RTCTimeScreen : public ui::DateEntryScreen {
|
||||||
|
public:
|
||||||
|
void show(ui::Context &ctx, bool goBack = false);
|
||||||
|
void update(ui::Context &ctx);
|
||||||
|
};
|
||||||
|
|
||||||
class ResolutionScreen : public ui::ListScreen {
|
class ResolutionScreen : public ui::ListScreen {
|
||||||
protected:
|
protected:
|
||||||
const char *_getItemName(ui::Context &ctx, int index) const;
|
const char *_getItemName(ui::Context &ctx, int index) const;
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "common/util.hpp"
|
#include "common/util.hpp"
|
||||||
#include "main/uibase.hpp"
|
#include "main/uibase.hpp"
|
||||||
#include "main/uicommon.hpp"
|
#include "main/uicommon.hpp"
|
||||||
|
#include "main/uimodals.hpp"
|
||||||
|
|
||||||
/* Modal screens */
|
/* Modal screens */
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "common/rom.hpp"
|
#include "common/rom.hpp"
|
||||||
#include "main/uibase.hpp"
|
#include "main/uibase.hpp"
|
||||||
#include "main/uicommon.hpp"
|
#include "main/uicommon.hpp"
|
||||||
|
#include "main/uimodals.hpp"
|
||||||
|
|
||||||
/* Storage device submenu */
|
/* Storage device submenu */
|
||||||
|
|
||||||
|
@ -216,17 +216,23 @@ void TiledBackground::draw(Context &ctx, bool active) const {
|
|||||||
tile.draw(ctx.gpuCtx, x, y);
|
tile.draw(ctx.gpuCtx, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!text)
|
|
||||||
return;
|
|
||||||
|
|
||||||
gpu::RectWH rect;
|
gpu::RectWH rect;
|
||||||
|
|
||||||
int width = ctx.font.getStringWidth(text);
|
rect.y = ctx.gpuCtx.height - (8 + ctx.font.metrics.lineHeight);
|
||||||
rect.x = ctx.gpuCtx.width - (8 + width);
|
rect.h = ctx.font.metrics.lineHeight;
|
||||||
rect.y = ctx.gpuCtx.height - (8 + ctx.font.metrics.lineHeight);
|
|
||||||
rect.w = width;
|
if (leftText) {
|
||||||
rect.h = ctx.font.metrics.lineHeight;
|
rect.x = 8;
|
||||||
ctx.font.draw(ctx.gpuCtx, text, rect, ctx.colors[COLOR_TEXT2]);
|
rect.w = ctx.gpuCtx.width - 16;
|
||||||
|
ctx.font.draw(ctx.gpuCtx, leftText, rect, ctx.colors[COLOR_TEXT2]);
|
||||||
|
}
|
||||||
|
if (rightText) {
|
||||||
|
int width = ctx.font.getStringWidth(rightText);
|
||||||
|
|
||||||
|
rect.x = ctx.gpuCtx.width - (8 + width);
|
||||||
|
rect.w = width;
|
||||||
|
ctx.font.draw(ctx.gpuCtx, rightText, rect, ctx.colors[COLOR_TEXT2]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LogOverlay::LogOverlay(util::LogBuffer &buffer)
|
LogOverlay::LogOverlay(util::LogBuffer &buffer)
|
||||||
|
@ -186,10 +186,10 @@ public:
|
|||||||
class TiledBackground : public Layer {
|
class TiledBackground : public Layer {
|
||||||
public:
|
public:
|
||||||
gpu::Image tile;
|
gpu::Image tile;
|
||||||
const char *text;
|
const char *leftText, *rightText;
|
||||||
|
|
||||||
inline TiledBackground(void)
|
inline TiledBackground(void)
|
||||||
: text(nullptr) {}
|
: leftText(nullptr), rightText(nullptr) {}
|
||||||
|
|
||||||
void draw(Context &ctx, bool active = true) const;
|
void draw(Context &ctx, bool active = true) const;
|
||||||
};
|
};
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
|
|
||||||
#include "common/defs.hpp"
|
#include "common/defs.hpp"
|
||||||
#include "common/gpu.hpp"
|
#include "common/gpu.hpp"
|
||||||
#include "common/gpufont.hpp"
|
|
||||||
#include "main/uibase.hpp"
|
#include "main/uibase.hpp"
|
||||||
#include "main/uicommon.hpp"
|
#include "main/uicommon.hpp"
|
||||||
#include "ps1/gpucmd.h"
|
#include "ps1/gpucmd.h"
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
/* Common higher-level screens */
|
/* Common screens */
|
||||||
|
|
||||||
void PlaceholderScreen::draw(Context &ctx, bool active) const {
|
void PlaceholderScreen::draw(Context &ctx, bool active) const {
|
||||||
_newLayer(ctx, 0, 0, ctx.gpuCtx.width, ctx.gpuCtx.height);
|
_newLayer(ctx, 0, 0, ctx.gpuCtx.width, ctx.gpuCtx.height);
|
||||||
@ -17,268 +16,6 @@ void PlaceholderScreen::draw(Context &ctx, bool active) const {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageBoxScreen::MessageBoxScreen(void)
|
|
||||||
: ModalScreen(MODAL_WIDTH, MODAL_HEIGHT_FULL), _numButtons(0),
|
|
||||||
_buttonIndexOffset(0), _locked(false) {}
|
|
||||||
|
|
||||||
void MessageBoxScreen::show(Context &ctx, bool goBack) {
|
|
||||||
ModalScreen::show(ctx, goBack);
|
|
||||||
|
|
||||||
_activeButton = 0;
|
|
||||||
_buttonAnim.setValue(_getButtonWidth());
|
|
||||||
}
|
|
||||||
|
|
||||||
void MessageBoxScreen::draw(Context &ctx, bool active) const {
|
|
||||||
ModalScreen::draw(ctx, active);
|
|
||||||
|
|
||||||
if (!active || !_numButtons)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int activeButton = _activeButton - _buttonIndexOffset;
|
|
||||||
|
|
||||||
int buttonX = _width / 8;
|
|
||||||
int buttonY = TITLE_BAR_HEIGHT + _height - (BUTTON_HEIGHT + MODAL_PADDING);
|
|
||||||
gpu::RectWH rect;
|
|
||||||
|
|
||||||
rect.y = buttonY + BUTTON_PADDING;
|
|
||||||
rect.w = _getButtonWidth();
|
|
||||||
rect.h = rect.y + ctx.font.metrics.lineHeight;
|
|
||||||
//rect.h = BUTTON_HEIGHT - BUTTON_PADDING * 2;
|
|
||||||
|
|
||||||
for (int i = 0; i < _numButtons; i++) {
|
|
||||||
rect.x = buttonX +
|
|
||||||
(rect.w - ctx.font.getStringWidth(_buttons[i])) / 2;
|
|
||||||
|
|
||||||
if (_locked) {
|
|
||||||
ctx.gpuCtx.drawRect(
|
|
||||||
buttonX, buttonY, rect.w, BUTTON_HEIGHT,
|
|
||||||
ctx.colors[COLOR_SHADOW], true
|
|
||||||
);
|
|
||||||
|
|
||||||
ctx.font.draw(
|
|
||||||
ctx.gpuCtx, _buttons[i], rect, ctx.colors[COLOR_TEXT2]
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
if (i == activeButton) {
|
|
||||||
ctx.gpuCtx.drawRect(
|
|
||||||
buttonX, buttonY, rect.w, BUTTON_HEIGHT,
|
|
||||||
ctx.colors[COLOR_HIGHLIGHT2]
|
|
||||||
);
|
|
||||||
ctx.gpuCtx.drawRect(
|
|
||||||
buttonX, buttonY, _buttonAnim.getValue(ctx.time),
|
|
||||||
BUTTON_HEIGHT, ctx.colors[COLOR_HIGHLIGHT1]
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
ctx.gpuCtx.drawRect(
|
|
||||||
buttonX, buttonY, rect.w, BUTTON_HEIGHT,
|
|
||||||
ctx.colors[COLOR_WINDOW3]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.font.draw(
|
|
||||||
ctx.gpuCtx, _buttons[i], rect, ctx.colors[COLOR_TITLE]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
buttonX += rect.w + BUTTON_SPACING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MessageBoxScreen::update(Context &ctx) {
|
|
||||||
if (_locked)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int numButtons = _buttonIndexOffset + _numButtons;
|
|
||||||
|
|
||||||
if (
|
|
||||||
ctx.buttons.pressed(ui::BTN_LEFT) ||
|
|
||||||
(ctx.buttons.repeating(ui::BTN_LEFT) && (_activeButton > 0))
|
|
||||||
) {
|
|
||||||
_activeButton--;
|
|
||||||
if (_activeButton < 0) {
|
|
||||||
_activeButton += numButtons;
|
|
||||||
ctx.sounds[SOUND_CLICK].play();
|
|
||||||
} else {
|
|
||||||
ctx.sounds[SOUND_MOVE].play();
|
|
||||||
}
|
|
||||||
|
|
||||||
_buttonAnim.setValue(ctx.time, 0, _getButtonWidth(), SPEED_FASTEST);
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
ctx.buttons.pressed(ui::BTN_RIGHT) ||
|
|
||||||
(ctx.buttons.repeating(ui::BTN_RIGHT) && (_activeButton < (numButtons - 1)))
|
|
||||||
) {
|
|
||||||
_activeButton++;
|
|
||||||
if (_activeButton >= numButtons) {
|
|
||||||
_activeButton -= numButtons;
|
|
||||||
ctx.sounds[SOUND_CLICK].play();
|
|
||||||
} else {
|
|
||||||
ctx.sounds[SOUND_MOVE].play();
|
|
||||||
}
|
|
||||||
|
|
||||||
_buttonAnim.setValue(ctx.time, 0, _getButtonWidth(), SPEED_FASTEST);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HexEntryScreen::HexEntryScreen(void)
|
|
||||||
: _bufferLength(0) {
|
|
||||||
__builtin_memset(_buffer, 0, sizeof(_buffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
void HexEntryScreen::show(Context &ctx, bool goBack) {
|
|
||||||
MessageBoxScreen::show(ctx, goBack);
|
|
||||||
|
|
||||||
_buttonIndexOffset = _bufferLength * 2;
|
|
||||||
//__builtin_memset(_buffer, 0, _bufferLength);
|
|
||||||
|
|
||||||
_charIndex = 0;
|
|
||||||
_cursorAnim.setValue(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HexEntryScreen::draw(Context &ctx, bool active) const {
|
|
||||||
MessageBoxScreen::draw(ctx, active);
|
|
||||||
|
|
||||||
if (!active)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int boxY = TITLE_BAR_HEIGHT + _height -
|
|
||||||
(BUTTON_HEIGHT + MODAL_PADDING) * 2;
|
|
||||||
int boxWidth = _width - MODAL_PADDING * 2;
|
|
||||||
|
|
||||||
// Text box
|
|
||||||
ctx.gpuCtx.drawRect(
|
|
||||||
MODAL_PADDING, boxY, boxWidth, BUTTON_HEIGHT, ctx.colors[COLOR_BOX1]
|
|
||||||
);
|
|
||||||
|
|
||||||
char text[128];
|
|
||||||
gpu::Rect rect;
|
|
||||||
|
|
||||||
util::hexToString(text, _buffer, _bufferLength, _separator);
|
|
||||||
|
|
||||||
int digitWidth = ctx.font.getCharacterWidth('0');
|
|
||||||
int textOffset = MODAL_PADDING +
|
|
||||||
(boxWidth - ctx.font.getStringWidth(text)) / 2;
|
|
||||||
|
|
||||||
// Cursor
|
|
||||||
if (_activeButton < _buttonIndexOffset)
|
|
||||||
ctx.gpuCtx.drawGradientRectV(
|
|
||||||
textOffset + _cursorAnim.getValue(ctx.time),
|
|
||||||
boxY + BUTTON_HEIGHT / 2, digitWidth, BUTTON_HEIGHT / 2,
|
|
||||||
ctx.colors[COLOR_BOX1], ctx.colors[COLOR_HIGHLIGHT1]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Text
|
|
||||||
rect.x1 = textOffset;
|
|
||||||
rect.y1 = boxY + BUTTON_PADDING;
|
|
||||||
rect.x2 = _width - MODAL_PADDING;
|
|
||||||
rect.y2 = boxY + BUTTON_PADDING + ctx.font.metrics.lineHeight;
|
|
||||||
ctx.font.draw(ctx.gpuCtx, text, rect, ctx.colors[COLOR_TITLE]);
|
|
||||||
|
|
||||||
// Highlighted digit
|
|
||||||
if (_activeButton < _buttonIndexOffset) {
|
|
||||||
text[0] = text[_charIndex];
|
|
||||||
text[1] = 0;
|
|
||||||
|
|
||||||
rect.x1 = textOffset + _cursorAnim.getTargetValue();
|
|
||||||
ctx.font.draw(ctx.gpuCtx, text, rect, ctx.colors[COLOR_SUBTITLE]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HexEntryScreen::update(Context &ctx) {
|
|
||||||
if (
|
|
||||||
ctx.buttons.held(ui::BTN_START) && (_activeButton < _buttonIndexOffset)
|
|
||||||
) {
|
|
||||||
uint8_t *ptr = &_buffer[_activeButton / 2];
|
|
||||||
int digit = (_activeButton % 2) ? (*ptr & 0x0f) : (*ptr >> 4);
|
|
||||||
|
|
||||||
if (
|
|
||||||
ctx.buttons.pressed(ui::BTN_LEFT) ||
|
|
||||||
(ctx.buttons.repeating(ui::BTN_LEFT) && (digit > 0))
|
|
||||||
) {
|
|
||||||
digit--;
|
|
||||||
if (digit < 0) {
|
|
||||||
digit = 0xf;
|
|
||||||
ctx.sounds[SOUND_CLICK].play();
|
|
||||||
} else {
|
|
||||||
ctx.sounds[SOUND_MOVE].play();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
ctx.buttons.pressed(ui::BTN_RIGHT) ||
|
|
||||||
(ctx.buttons.repeating(ui::BTN_RIGHT) && (digit < 0xf))
|
|
||||||
) {
|
|
||||||
digit++;
|
|
||||||
if (digit > 0xf) {
|
|
||||||
digit = 0;
|
|
||||||
ctx.sounds[SOUND_CLICK].play();
|
|
||||||
} else {
|
|
||||||
ctx.sounds[SOUND_MOVE].play();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_activeButton % 2)
|
|
||||||
*ptr = (*ptr & 0xf0) | digit;
|
|
||||||
else
|
|
||||||
*ptr = (*ptr & 0x0f) | (digit << 4);
|
|
||||||
} else {
|
|
||||||
int oldActive = _activeButton;
|
|
||||||
|
|
||||||
MessageBoxScreen::update(ctx);
|
|
||||||
|
|
||||||
// Update the cursor's position if necessary.
|
|
||||||
if (oldActive != _activeButton) {
|
|
||||||
int digitWidth = ctx.font.getCharacterWidth('0');
|
|
||||||
int sepWidth = ctx.font.getCharacterWidth(_separator);
|
|
||||||
|
|
||||||
int offset = _activeButton, cursorX = 0;
|
|
||||||
_charIndex = 0;
|
|
||||||
|
|
||||||
for (; offset >= 2; offset -= 2) {
|
|
||||||
cursorX += digitWidth * 2 + sepWidth;
|
|
||||||
_charIndex += 3;
|
|
||||||
}
|
|
||||||
for (; offset; offset--) {
|
|
||||||
cursorX += digitWidth;
|
|
||||||
_charIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
_cursorAnim.setValue(ctx.time, cursorX, SPEED_FASTEST);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ProgressScreen::ProgressScreen(void)
|
|
||||||
: ModalScreen(MODAL_WIDTH, MODAL_HEIGHT_REDUCED) {}
|
|
||||||
|
|
||||||
void ProgressScreen::show(Context &ctx, bool goBack) {
|
|
||||||
ModalScreen::show(ctx, goBack);
|
|
||||||
|
|
||||||
_progressBarAnim.setValue(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProgressScreen::draw(Context &ctx, bool active) const {
|
|
||||||
ModalScreen::draw(ctx, active);
|
|
||||||
|
|
||||||
if (!active)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int fullBarWidth = _width - MODAL_PADDING * 2;
|
|
||||||
|
|
||||||
int barX = (_width - fullBarWidth) / 2;
|
|
||||||
int barY = TITLE_BAR_HEIGHT + _height -
|
|
||||||
(PROGRESS_BAR_HEIGHT + MODAL_PADDING);
|
|
||||||
|
|
||||||
_setBlendMode(ctx, GP0_BLEND_SEMITRANS, true);
|
|
||||||
|
|
||||||
ctx.gpuCtx.drawRect(
|
|
||||||
barX, barY, fullBarWidth, PROGRESS_BAR_HEIGHT, ctx.colors[COLOR_WINDOW3]
|
|
||||||
);
|
|
||||||
ctx.gpuCtx.drawGradientRectH(
|
|
||||||
barX, barY, _progressBarAnim.getValue(ctx.time), PROGRESS_BAR_HEIGHT,
|
|
||||||
ctx.colors[COLOR_PROGRESS2], ctx.colors[COLOR_PROGRESS1]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
TextScreen::TextScreen(void)
|
TextScreen::TextScreen(void)
|
||||||
: _title(nullptr), _body(nullptr), _prompt(nullptr) {}
|
: _title(nullptr), _body(nullptr), _prompt(nullptr) {}
|
||||||
|
|
||||||
@ -555,7 +292,7 @@ void ListScreen::update(Context &ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_itemAnim.setValue(ctx.time, 0, _getItemWidth(ctx), SPEED_FAST);
|
_itemAnim.setValue(ctx.time, 0, _getItemWidth(ctx), SPEED_FAST);
|
||||||
|
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
ctx.buttons.pressed(ui::BTN_RIGHT) ||
|
ctx.buttons.pressed(ui::BTN_RIGHT) ||
|
||||||
|
@ -2,81 +2,19 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "common/gpufont.hpp"
|
#include "common/gpu.hpp"
|
||||||
#include "common/util.hpp"
|
#include "common/util.hpp"
|
||||||
#include "main/uibase.hpp"
|
#include "main/uibase.hpp"
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
/* Common higher-level screens */
|
/* Common screens */
|
||||||
|
|
||||||
class PlaceholderScreen : public AnimatedScreen {
|
class PlaceholderScreen : public AnimatedScreen {
|
||||||
public:
|
public:
|
||||||
void draw(Context &ctx, bool active) const;
|
void draw(Context &ctx, bool active) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MessageBoxScreen : public ModalScreen {
|
|
||||||
private:
|
|
||||||
util::Tween<int, util::QuadOutEasing> _buttonAnim;
|
|
||||||
|
|
||||||
inline int _getButtonWidth(void) const {
|
|
||||||
return ((_width / 5) * 4) / _numButtons - BUTTON_SPACING;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
int _numButtons, _activeButton, _buttonIndexOffset;
|
|
||||||
bool _locked;
|
|
||||||
|
|
||||||
const char *_buttons[4];
|
|
||||||
|
|
||||||
public:
|
|
||||||
MessageBoxScreen(void);
|
|
||||||
virtual void show(Context &ctx, bool goBack = false);
|
|
||||||
virtual void draw(Context &ctx, bool active = true) const;
|
|
||||||
virtual void update(Context &ctx);
|
|
||||||
};
|
|
||||||
|
|
||||||
class HexEntryScreen : public MessageBoxScreen {
|
|
||||||
private:
|
|
||||||
int _charIndex;
|
|
||||||
|
|
||||||
util::Tween<int, util::QuadOutEasing> _cursorAnim;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
uint8_t _buffer[32];
|
|
||||||
char _separator;
|
|
||||||
|
|
||||||
int _bufferLength;
|
|
||||||
|
|
||||||
public:
|
|
||||||
HexEntryScreen(void);
|
|
||||||
virtual void show(Context &ctx, bool goBack = false);
|
|
||||||
virtual void draw(Context &ctx, bool active = true) const;
|
|
||||||
virtual void update(Context &ctx);
|
|
||||||
};
|
|
||||||
|
|
||||||
class ProgressScreen : public ModalScreen {
|
|
||||||
private:
|
|
||||||
util::Tween<int, util::QuadOutEasing> _progressBarAnim;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
inline void _setProgress(Context &ctx, int part, int total) {
|
|
||||||
if (!total)
|
|
||||||
total = 1;
|
|
||||||
|
|
||||||
int totalWidth = _width - MODAL_PADDING * 2;
|
|
||||||
int partWidth = (totalWidth * part) / total;
|
|
||||||
|
|
||||||
if (_progressBarAnim.getTargetValue() != partWidth)
|
|
||||||
_progressBarAnim.setValue(ctx.time, partWidth, SPEED_FASTEST);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
ProgressScreen(void);
|
|
||||||
virtual void show(Context &ctx, bool goBack = false);
|
|
||||||
virtual void draw(Context &ctx, bool active = true) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
class TextScreen : public AnimatedScreen {
|
class TextScreen : public AnimatedScreen {
|
||||||
private:
|
private:
|
||||||
util::Tween<int, util::QuadOutEasing> _scrollAnim;
|
util::Tween<int, util::QuadOutEasing> _scrollAnim;
|
||||||
|
446
src/main/uimodals.cpp
Normal file
446
src/main/uimodals.cpp
Normal file
@ -0,0 +1,446 @@
|
|||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "common/gpu.hpp"
|
||||||
|
#include "main/uibase.hpp"
|
||||||
|
#include "main/uimodals.hpp"
|
||||||
|
|
||||||
|
namespace ui {
|
||||||
|
|
||||||
|
MessageBoxScreen::MessageBoxScreen(void)
|
||||||
|
: ModalScreen(MODAL_WIDTH, MODAL_HEIGHT_FULL), _numButtons(0),
|
||||||
|
_buttonIndexOffset(0), _locked(false) {}
|
||||||
|
|
||||||
|
void MessageBoxScreen::show(Context &ctx, bool goBack) {
|
||||||
|
ModalScreen::show(ctx, goBack);
|
||||||
|
|
||||||
|
_activeButton = 0;
|
||||||
|
_buttonAnim.setValue(_getButtonWidth());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageBoxScreen::draw(Context &ctx, bool active) const {
|
||||||
|
ModalScreen::draw(ctx, active);
|
||||||
|
|
||||||
|
if (!active || !_numButtons)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int activeButton = _activeButton - _buttonIndexOffset;
|
||||||
|
|
||||||
|
int buttonX = _width / 8;
|
||||||
|
int buttonY = TITLE_BAR_HEIGHT + _height - (BUTTON_HEIGHT + MODAL_PADDING);
|
||||||
|
gpu::RectWH rect;
|
||||||
|
|
||||||
|
rect.y = buttonY + BUTTON_PADDING;
|
||||||
|
rect.w = _getButtonWidth();
|
||||||
|
rect.h = rect.y + ctx.font.metrics.lineHeight;
|
||||||
|
//rect.h = BUTTON_HEIGHT - BUTTON_PADDING * 2;
|
||||||
|
|
||||||
|
for (int i = 0; i < _numButtons; i++) {
|
||||||
|
rect.x = buttonX +
|
||||||
|
(rect.w - ctx.font.getStringWidth(_buttons[i])) / 2;
|
||||||
|
|
||||||
|
if (_locked) {
|
||||||
|
ctx.gpuCtx.drawRect(
|
||||||
|
buttonX, buttonY, rect.w, BUTTON_HEIGHT,
|
||||||
|
ctx.colors[COLOR_SHADOW], true
|
||||||
|
);
|
||||||
|
|
||||||
|
ctx.font.draw(
|
||||||
|
ctx.gpuCtx, _buttons[i], rect, ctx.colors[COLOR_TEXT2]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if (i == activeButton) {
|
||||||
|
ctx.gpuCtx.drawRect(
|
||||||
|
buttonX, buttonY, rect.w, BUTTON_HEIGHT,
|
||||||
|
ctx.colors[COLOR_HIGHLIGHT2]
|
||||||
|
);
|
||||||
|
ctx.gpuCtx.drawRect(
|
||||||
|
buttonX, buttonY, _buttonAnim.getValue(ctx.time),
|
||||||
|
BUTTON_HEIGHT, ctx.colors[COLOR_HIGHLIGHT1]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
ctx.gpuCtx.drawRect(
|
||||||
|
buttonX, buttonY, rect.w, BUTTON_HEIGHT,
|
||||||
|
ctx.colors[COLOR_WINDOW3]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.font.draw(
|
||||||
|
ctx.gpuCtx, _buttons[i], rect, ctx.colors[COLOR_TITLE]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
buttonX += rect.w + BUTTON_SPACING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageBoxScreen::update(Context &ctx) {
|
||||||
|
if (_locked)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int numButtons = _buttonIndexOffset + _numButtons;
|
||||||
|
|
||||||
|
if (
|
||||||
|
ctx.buttons.pressed(ui::BTN_LEFT) ||
|
||||||
|
(ctx.buttons.repeating(ui::BTN_LEFT) && (_activeButton > 0))
|
||||||
|
) {
|
||||||
|
_activeButton--;
|
||||||
|
if (_activeButton < 0) {
|
||||||
|
_activeButton += numButtons;
|
||||||
|
ctx.sounds[SOUND_CLICK].play();
|
||||||
|
} else {
|
||||||
|
ctx.sounds[SOUND_MOVE].play();
|
||||||
|
}
|
||||||
|
|
||||||
|
_buttonAnim.setValue(ctx.time, 0, _getButtonWidth(), SPEED_FASTEST);
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
ctx.buttons.pressed(ui::BTN_RIGHT) ||
|
||||||
|
(ctx.buttons.repeating(ui::BTN_RIGHT) && (_activeButton < (numButtons - 1)))
|
||||||
|
) {
|
||||||
|
_activeButton++;
|
||||||
|
if (_activeButton >= numButtons) {
|
||||||
|
_activeButton -= numButtons;
|
||||||
|
ctx.sounds[SOUND_CLICK].play();
|
||||||
|
} else {
|
||||||
|
ctx.sounds[SOUND_MOVE].play();
|
||||||
|
}
|
||||||
|
|
||||||
|
_buttonAnim.setValue(ctx.time, 0, _getButtonWidth(), SPEED_FASTEST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HexEntryScreen::HexEntryScreen(void)
|
||||||
|
: _bufferLength(0) {
|
||||||
|
__builtin_memset(_buffer, 0, sizeof(_buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
void HexEntryScreen::show(Context &ctx, bool goBack) {
|
||||||
|
MessageBoxScreen::show(ctx, goBack);
|
||||||
|
|
||||||
|
//__builtin_memset(_buffer, 0, _bufferLength);
|
||||||
|
|
||||||
|
_buttonIndexOffset = _bufferLength * 2;
|
||||||
|
_charWidth = ctx.font.getCharacterWidth('0');
|
||||||
|
_separatorWidth = ctx.font.getCharacterWidth(_separator);
|
||||||
|
_stringWidth = 0
|
||||||
|
+ _charWidth * (_bufferLength * 2)
|
||||||
|
+ _separatorWidth * (_bufferLength - 1);
|
||||||
|
|
||||||
|
_cursorAnim.setValue(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HexEntryScreen::draw(Context &ctx, bool active) const {
|
||||||
|
MessageBoxScreen::draw(ctx, active);
|
||||||
|
|
||||||
|
if (!active)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int boxY = TITLE_BAR_HEIGHT + _height -
|
||||||
|
(BUTTON_HEIGHT + MODAL_PADDING) * 2;
|
||||||
|
int boxWidth = _width - MODAL_PADDING * 2;
|
||||||
|
|
||||||
|
// Text box
|
||||||
|
ctx.gpuCtx.drawRect(
|
||||||
|
MODAL_PADDING, boxY, boxWidth, BUTTON_HEIGHT, ctx.colors[COLOR_BOX1]
|
||||||
|
);
|
||||||
|
|
||||||
|
char string[128];
|
||||||
|
gpu::Rect rect;
|
||||||
|
|
||||||
|
util::hexToString(string, _buffer, _bufferLength, _separator);
|
||||||
|
|
||||||
|
int stringOffset = MODAL_PADDING + (boxWidth - _stringWidth) / 2;
|
||||||
|
int charIndex = _activeButton + _activeButton / 2;
|
||||||
|
|
||||||
|
// Cursor
|
||||||
|
if (_activeButton < _buttonIndexOffset)
|
||||||
|
ctx.gpuCtx.drawGradientRectV(
|
||||||
|
stringOffset + _cursorAnim.getValue(ctx.time),
|
||||||
|
boxY + BUTTON_HEIGHT / 2, _charWidth, BUTTON_HEIGHT / 2,
|
||||||
|
ctx.colors[COLOR_BOX1], ctx.colors[COLOR_HIGHLIGHT1]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Current string
|
||||||
|
rect.x1 = stringOffset;
|
||||||
|
rect.y1 = boxY + BUTTON_PADDING;
|
||||||
|
rect.x2 = _width - MODAL_PADDING;
|
||||||
|
rect.y2 = boxY + BUTTON_PADDING + ctx.font.metrics.lineHeight;
|
||||||
|
ctx.font.draw(ctx.gpuCtx, string, rect, ctx.colors[COLOR_TITLE]);
|
||||||
|
|
||||||
|
// Highlighted field
|
||||||
|
if (_activeButton < _buttonIndexOffset) {
|
||||||
|
auto ptr = &string[charIndex];
|
||||||
|
ptr[1] = 0;
|
||||||
|
|
||||||
|
rect.x1 = stringOffset + _cursorAnim.getTargetValue();
|
||||||
|
ctx.font.draw(ctx.gpuCtx, ptr, rect, ctx.colors[COLOR_SUBTITLE]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HexEntryScreen::update(Context &ctx) {
|
||||||
|
if (
|
||||||
|
ctx.buttons.held(ui::BTN_START) && (_activeButton < _buttonIndexOffset)
|
||||||
|
) {
|
||||||
|
auto ptr = &_buffer[_activeButton / 2];
|
||||||
|
int value = (_activeButton % 2) ? (*ptr & 0x0f) : (*ptr >> 4);
|
||||||
|
|
||||||
|
if (
|
||||||
|
ctx.buttons.pressed(ui::BTN_LEFT) ||
|
||||||
|
(ctx.buttons.repeating(ui::BTN_LEFT) && (value > 0))
|
||||||
|
) {
|
||||||
|
if (--value < 0) {
|
||||||
|
value = 0xf;
|
||||||
|
ctx.sounds[SOUND_CLICK].play();
|
||||||
|
} else {
|
||||||
|
ctx.sounds[SOUND_MOVE].play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
ctx.buttons.pressed(ui::BTN_RIGHT) ||
|
||||||
|
(ctx.buttons.repeating(ui::BTN_RIGHT) && (value < 0xf))
|
||||||
|
) {
|
||||||
|
if (++value > 0xf) {
|
||||||
|
value = 0;
|
||||||
|
ctx.sounds[SOUND_CLICK].play();
|
||||||
|
} else {
|
||||||
|
ctx.sounds[SOUND_MOVE].play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_activeButton % 2)
|
||||||
|
*ptr = (*ptr & 0xf0) | value;
|
||||||
|
else
|
||||||
|
*ptr = (*ptr & 0x0f) | (value << 4);
|
||||||
|
} else {
|
||||||
|
int oldActive = _activeButton;
|
||||||
|
|
||||||
|
MessageBoxScreen::update(ctx);
|
||||||
|
|
||||||
|
// Update the cursor's position if necessary.
|
||||||
|
if (oldActive != _activeButton) {
|
||||||
|
int cursorX = 0
|
||||||
|
+ _charWidth * _activeButton
|
||||||
|
+ _separatorWidth * (_activeButton / 2);
|
||||||
|
|
||||||
|
_cursorAnim.setValue(ctx.time, cursorX, SPEED_FASTEST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DateField {
|
||||||
|
public:
|
||||||
|
size_t offset;
|
||||||
|
uint16_t minValue, maxValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const DateField _DATE_FIELDS[]{
|
||||||
|
{
|
||||||
|
.offset = offsetof(util::Date, year),
|
||||||
|
.minValue = 1970,
|
||||||
|
.maxValue = 2069
|
||||||
|
}, {
|
||||||
|
.offset = offsetof(util::Date, month),
|
||||||
|
.minValue = 1,
|
||||||
|
.maxValue = 12
|
||||||
|
}, {
|
||||||
|
.offset = offsetof(util::Date, day),
|
||||||
|
.minValue = 1,
|
||||||
|
.maxValue = 31
|
||||||
|
}, {
|
||||||
|
.offset = offsetof(util::Date, hour),
|
||||||
|
.minValue = 0,
|
||||||
|
.maxValue = 23
|
||||||
|
}, {
|
||||||
|
.offset = offsetof(util::Date, minute),
|
||||||
|
.minValue = 0,
|
||||||
|
.maxValue = 59
|
||||||
|
}, {
|
||||||
|
.offset = offsetof(util::Date, second),
|
||||||
|
.minValue = 0,
|
||||||
|
.maxValue = 59
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
DateEntryScreen::DateEntryScreen(void) {
|
||||||
|
_date.year = 2000;
|
||||||
|
_date.month = 1;
|
||||||
|
_date.day = 1;
|
||||||
|
_date.hour = 0;
|
||||||
|
_date.minute = 0;
|
||||||
|
_date.second = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DateEntryScreen::show(Context &ctx, bool goBack) {
|
||||||
|
MessageBoxScreen::show(ctx, goBack);
|
||||||
|
|
||||||
|
_buttonIndexOffset = 6;
|
||||||
|
_charWidth = ctx.font.getCharacterWidth('0');
|
||||||
|
|
||||||
|
int dateSepWidth = ctx.font.getCharacterWidth('-');
|
||||||
|
int spaceWidth = ctx.font.metrics.spaceWidth;
|
||||||
|
int timeSepWidth = ctx.font.getCharacterWidth(':');
|
||||||
|
|
||||||
|
_fieldOffsets[0] = 0;
|
||||||
|
_fieldOffsets[1] = _fieldOffsets[0] + _charWidth * 4 + dateSepWidth;
|
||||||
|
_fieldOffsets[2] = _fieldOffsets[1] + _charWidth * 2 + dateSepWidth;
|
||||||
|
_fieldOffsets[3] = _fieldOffsets[2] + _charWidth * 2 + spaceWidth;
|
||||||
|
_fieldOffsets[4] = _fieldOffsets[3] + _charWidth * 2 + timeSepWidth;
|
||||||
|
_fieldOffsets[5] = _fieldOffsets[4] + _charWidth * 2 + timeSepWidth;
|
||||||
|
_stringWidth = _fieldOffsets[5] + _charWidth * 2;
|
||||||
|
|
||||||
|
_cursorAnim.setValue(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DateEntryScreen::draw(Context &ctx, bool active) const {
|
||||||
|
MessageBoxScreen::draw(ctx, active);
|
||||||
|
|
||||||
|
if (!active)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int boxY = TITLE_BAR_HEIGHT + _height -
|
||||||
|
(BUTTON_HEIGHT + MODAL_PADDING) * 2;
|
||||||
|
int boxWidth = _width - MODAL_PADDING * 2;
|
||||||
|
|
||||||
|
// Text box
|
||||||
|
ctx.gpuCtx.drawRect(
|
||||||
|
MODAL_PADDING, boxY, boxWidth, BUTTON_HEIGHT, ctx.colors[COLOR_BOX1]
|
||||||
|
);
|
||||||
|
|
||||||
|
char string[24];
|
||||||
|
gpu::Rect rect;
|
||||||
|
|
||||||
|
_date.toString(string);
|
||||||
|
|
||||||
|
int stringOffset = MODAL_PADDING + (boxWidth - _stringWidth) / 2;
|
||||||
|
int charIndex = _activeButton * 3;
|
||||||
|
int fieldLength = 2;
|
||||||
|
|
||||||
|
// The first field (year) has 4 digits, while all others have 2.
|
||||||
|
if (_activeButton)
|
||||||
|
charIndex += 2;
|
||||||
|
else
|
||||||
|
fieldLength += 2;
|
||||||
|
|
||||||
|
// Cursor
|
||||||
|
if (_activeButton < _buttonIndexOffset)
|
||||||
|
ctx.gpuCtx.drawGradientRectV(
|
||||||
|
stringOffset + _cursorAnim.getValue(ctx.time),
|
||||||
|
boxY + BUTTON_HEIGHT / 2, _charWidth * fieldLength,
|
||||||
|
BUTTON_HEIGHT / 2,ctx.colors[COLOR_BOX1],
|
||||||
|
ctx.colors[COLOR_HIGHLIGHT1]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Current string
|
||||||
|
rect.x1 = stringOffset;
|
||||||
|
rect.y1 = boxY + BUTTON_PADDING;
|
||||||
|
rect.x2 = _width - MODAL_PADDING;
|
||||||
|
rect.y2 = boxY + BUTTON_PADDING + ctx.font.metrics.lineHeight;
|
||||||
|
ctx.font.draw(ctx.gpuCtx, string, rect, ctx.colors[COLOR_TITLE]);
|
||||||
|
|
||||||
|
// Highlighted field
|
||||||
|
if (_activeButton < _buttonIndexOffset) {
|
||||||
|
auto ptr = &string[charIndex];
|
||||||
|
ptr[fieldLength] = 0;
|
||||||
|
|
||||||
|
rect.x1 = stringOffset + _cursorAnim.getTargetValue();
|
||||||
|
ctx.font.draw(ctx.gpuCtx, ptr, rect, ctx.colors[COLOR_SUBTITLE]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DateEntryScreen::update(Context &ctx) {
|
||||||
|
if (
|
||||||
|
ctx.buttons.held(ui::BTN_START) && (_activeButton < _buttonIndexOffset)
|
||||||
|
) {
|
||||||
|
auto &field = _DATE_FIELDS[_activeButton];
|
||||||
|
int value;
|
||||||
|
|
||||||
|
// The year is the only 16-bit field.
|
||||||
|
if (!_activeButton)
|
||||||
|
value = _date.year;
|
||||||
|
else
|
||||||
|
value = *reinterpret_cast<uint8_t *>(
|
||||||
|
reinterpret_cast<uintptr_t>(&_date) + field.offset
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
ctx.buttons.pressed(ui::BTN_LEFT) ||
|
||||||
|
(ctx.buttons.repeating(ui::BTN_LEFT) && (value > field.minValue))
|
||||||
|
) {
|
||||||
|
if (--value < field.minValue) {
|
||||||
|
value = field.maxValue;
|
||||||
|
ctx.sounds[SOUND_CLICK].play();
|
||||||
|
} else {
|
||||||
|
ctx.sounds[SOUND_MOVE].play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
ctx.buttons.pressed(ui::BTN_RIGHT) ||
|
||||||
|
(ctx.buttons.repeating(ui::BTN_RIGHT) && (value < field.maxValue))
|
||||||
|
) {
|
||||||
|
if (++value > field.maxValue) {
|
||||||
|
value = field.minValue;
|
||||||
|
ctx.sounds[SOUND_CLICK].play();
|
||||||
|
} else {
|
||||||
|
ctx.sounds[SOUND_MOVE].play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_activeButton)
|
||||||
|
_date.year = value;
|
||||||
|
else
|
||||||
|
*reinterpret_cast<uint8_t *>(
|
||||||
|
reinterpret_cast<uintptr_t>(&_date) + field.offset
|
||||||
|
) = value;
|
||||||
|
|
||||||
|
// The day field must be fixed up after any date change.
|
||||||
|
int maxDayValue = _date.getMonthDayCount();
|
||||||
|
|
||||||
|
if (_date.day > maxDayValue)
|
||||||
|
_date.day = maxDayValue;
|
||||||
|
} else {
|
||||||
|
int oldActive = _activeButton;
|
||||||
|
|
||||||
|
MessageBoxScreen::update(ctx);
|
||||||
|
|
||||||
|
// Update the cursor's position if necessary.
|
||||||
|
if (oldActive != _activeButton)
|
||||||
|
_cursorAnim.setValue(
|
||||||
|
ctx.time, _fieldOffsets[_activeButton], SPEED_FASTEST
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ProgressScreen::ProgressScreen(void)
|
||||||
|
: ModalScreen(MODAL_WIDTH, MODAL_HEIGHT_REDUCED) {}
|
||||||
|
|
||||||
|
void ProgressScreen::show(Context &ctx, bool goBack) {
|
||||||
|
ModalScreen::show(ctx, goBack);
|
||||||
|
|
||||||
|
_progressBarAnim.setValue(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProgressScreen::draw(Context &ctx, bool active) const {
|
||||||
|
ModalScreen::draw(ctx, active);
|
||||||
|
|
||||||
|
if (!active)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int fullBarWidth = _width - MODAL_PADDING * 2;
|
||||||
|
|
||||||
|
int barX = (_width - fullBarWidth) / 2;
|
||||||
|
int barY = TITLE_BAR_HEIGHT + _height -
|
||||||
|
(PROGRESS_BAR_HEIGHT + MODAL_PADDING);
|
||||||
|
|
||||||
|
_setBlendMode(ctx, GP0_BLEND_SEMITRANS, true);
|
||||||
|
|
||||||
|
ctx.gpuCtx.drawRect(
|
||||||
|
barX, barY, fullBarWidth, PROGRESS_BAR_HEIGHT, ctx.colors[COLOR_WINDOW3]
|
||||||
|
);
|
||||||
|
ctx.gpuCtx.drawGradientRectH(
|
||||||
|
barX, barY, _progressBarAnim.getValue(ctx.time), PROGRESS_BAR_HEIGHT,
|
||||||
|
ctx.colors[COLOR_PROGRESS2], ctx.colors[COLOR_PROGRESS1]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
90
src/main/uimodals.hpp
Normal file
90
src/main/uimodals.hpp
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "common/util.hpp"
|
||||||
|
#include "main/uibase.hpp"
|
||||||
|
|
||||||
|
namespace ui {
|
||||||
|
|
||||||
|
/* Common modal screens */
|
||||||
|
|
||||||
|
class MessageBoxScreen : public ModalScreen {
|
||||||
|
private:
|
||||||
|
util::Tween<int, util::QuadOutEasing> _buttonAnim;
|
||||||
|
|
||||||
|
inline int _getButtonWidth(void) const {
|
||||||
|
return ((_width / 5) * 4) / _numButtons - BUTTON_SPACING;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int _numButtons, _activeButton, _buttonIndexOffset;
|
||||||
|
bool _locked;
|
||||||
|
|
||||||
|
const char *_buttons[4];
|
||||||
|
|
||||||
|
public:
|
||||||
|
MessageBoxScreen(void);
|
||||||
|
virtual void show(Context &ctx, bool goBack = false);
|
||||||
|
virtual void draw(Context &ctx, bool active = true) const;
|
||||||
|
virtual void update(Context &ctx);
|
||||||
|
};
|
||||||
|
|
||||||
|
class HexEntryScreen : public MessageBoxScreen {
|
||||||
|
private:
|
||||||
|
uint8_t _charWidth, _separatorWidth, _stringWidth;
|
||||||
|
|
||||||
|
util::Tween<int, util::QuadOutEasing> _cursorAnim;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint8_t _buffer[32];
|
||||||
|
char _separator;
|
||||||
|
|
||||||
|
int _bufferLength;
|
||||||
|
|
||||||
|
public:
|
||||||
|
HexEntryScreen(void);
|
||||||
|
virtual void show(Context &ctx, bool goBack = false);
|
||||||
|
virtual void draw(Context &ctx, bool active = true) const;
|
||||||
|
virtual void update(Context &ctx);
|
||||||
|
};
|
||||||
|
|
||||||
|
class DateEntryScreen : public MessageBoxScreen {
|
||||||
|
private:
|
||||||
|
uint8_t _charWidth, _stringWidth, _fieldOffsets[6];
|
||||||
|
|
||||||
|
util::Tween<int, util::QuadOutEasing> _cursorAnim;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
util::Date _date;
|
||||||
|
|
||||||
|
public:
|
||||||
|
DateEntryScreen(void);
|
||||||
|
virtual void show(Context &ctx, bool goBack = false);
|
||||||
|
virtual void draw(Context &ctx, bool active = true) const;
|
||||||
|
virtual void update(Context &ctx);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ProgressScreen : public ModalScreen {
|
||||||
|
private:
|
||||||
|
util::Tween<int, util::QuadOutEasing> _progressBarAnim;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
inline void _setProgress(Context &ctx, int part, int total) {
|
||||||
|
if (!total)
|
||||||
|
total = 1;
|
||||||
|
|
||||||
|
int totalWidth = _width - MODAL_PADDING * 2;
|
||||||
|
int partWidth = (totalWidth * part) / total;
|
||||||
|
|
||||||
|
if (_progressBarAnim.getTargetValue() != partWidth)
|
||||||
|
_progressBarAnim.setValue(ctx.time, partWidth, SPEED_FASTEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
ProgressScreen(void);
|
||||||
|
virtual void show(Context &ctx, bool goBack = false);
|
||||||
|
virtual void draw(Context &ctx, bool active = true) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -91,6 +91,13 @@ typedef enum {
|
|||||||
SYS573_RTC_SECOND_STOP = 1 << 7
|
SYS573_RTC_SECOND_STOP = 1 << 7
|
||||||
} Sys573RTCSecondFlag;
|
} Sys573RTCSecondFlag;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SYS573_RTC_WEEKDAY_UNITS_BITMASK = 7 << 0,
|
||||||
|
SYS573_RTC_WEEKDAY_CENTURY = 1 << 4,
|
||||||
|
SYS573_RTC_WEEKDAY_CENTURY_ENABLE = 1 << 5,
|
||||||
|
SYS573_RTC_WEEKDAY_FREQUENCY_TEST = 1 << 6
|
||||||
|
} Sys573RTCWeekdayFlag;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SYS573_RTC_DAY_UNITS_BITMASK = 15 << 0,
|
SYS573_RTC_DAY_UNITS_BITMASK = 15 << 0,
|
||||||
SYS573_RTC_DAY_TENS_BITMASK = 3 << 4,
|
SYS573_RTC_DAY_TENS_BITMASK = 3 << 4,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user