2016-02-25 16:57:01 +01:00
# include "godmode.h"
# include "draw.h"
# include "hid.h"
# include "fs.h"
2016-02-27 19:58:41 +01:00
# define COLOR_TOP_BAR COLOR_WHITE
2016-02-28 13:11:07 +01:00
# define COLOR_SIDE_BAR COLOR_DARKGREY
2016-02-27 19:58:41 +01:00
# define COLOR_MARKED COLOR_TINTEDYELLOW
# define COLOR_FILE COLOR_TINTEDGREEN
# define COLOR_DIR COLOR_TINTEDBLUE
# define COLOR_ROOT COLOR_GREY
2016-02-29 22:27:04 +01:00
void DrawUserInterface ( const char * curr_path , DirEntry * curr_entry , DirStruct * clipboard ) {
2016-02-27 19:58:41 +01:00
const u32 info_start = 16 ;
char bytestr0 [ 32 ] ;
char bytestr1 [ 32 ] ;
char tempstr [ 64 ] ;
// top bar - current path & free/total storage
DrawRectangleF ( true , 0 , 0 , SCREEN_WIDTH_TOP , 12 , COLOR_TOP_BAR ) ;
if ( strncmp ( curr_path , " " , 256 ) ! = 0 ) {
TruncateString ( tempstr , curr_path , 30 , 8 ) ;
DrawStringF ( true , 2 , 2 , COLOR_STD_BG , COLOR_TOP_BAR , tempstr ) ;
DrawStringF ( true , 30 * 8 + 4 , 2 , COLOR_STD_BG , COLOR_TOP_BAR , " %19.19s " , " LOADING... " ) ;
FormatBytes ( bytestr0 , GetFreeSpace ( curr_path ) ) ;
FormatBytes ( bytestr1 , GetTotalSpace ( curr_path ) ) ;
snprintf ( tempstr , 64 , " %s/%s " , bytestr0 , bytestr1 ) ;
DrawStringF ( true , 30 * 8 + 4 , 2 , COLOR_STD_BG , COLOR_TOP_BAR , " %19.19s " , tempstr ) ;
} else {
DrawStringF ( true , 2 , 2 , COLOR_STD_BG , COLOR_TOP_BAR , " [root] " ) ;
DrawStringF ( true , 30 * 8 + 6 , 2 , COLOR_STD_BG , COLOR_TOP_BAR , " %19.19s " , " GodMode9 " ) ;
}
// left top - current file info
2016-02-28 13:11:07 +01:00
DrawStringF ( true , 2 , info_start , COLOR_STD_FONT , COLOR_STD_BG , " [CURRENT] " ) ;
2016-02-27 19:58:41 +01:00
ResizeString ( tempstr , curr_entry - > name , 20 , 8 , false ) ;
2016-02-29 22:27:04 +01:00
u32 color_current = ( curr_entry - > marked ) ? COLOR_MARKED : ( curr_entry - > type = = T_FAT_ROOT ) ? COLOR_ROOT : ( curr_entry - > type = = T_FAT_DIR ) ? COLOR_DIR : COLOR_FILE ;
DrawStringF ( true , 4 , info_start + 12 , color_current , COLOR_STD_BG , " %s " , tempstr ) ;
2016-02-27 19:58:41 +01:00
if ( curr_entry - > type = = T_FAT_DIR ) {
ResizeString ( tempstr , " (dir) " , 20 , 8 , false ) ;
} else {
FormatBytes ( bytestr0 , curr_entry - > size ) ;
ResizeString ( tempstr , bytestr0 , 20 , 8 , false ) ;
}
2016-02-29 22:27:04 +01:00
DrawStringF ( true , 4 , info_start + 12 + 10 , color_current , COLOR_STD_BG , tempstr ) ;
// right top - clipboard
DrawStringF ( true , SCREEN_WIDTH_TOP - ( 20 * 8 ) , info_start , COLOR_STD_FONT , COLOR_STD_BG , " %20s " , ( clipboard - > n_entries ) ? " [CLIPBOARD] " : " " ) ;
for ( u32 c = 0 ; c < 10 ; c + + ) {
ResizeString ( tempstr , ( clipboard - > n_entries > c ) ? clipboard - > entry [ c ] . name : " " , 20 , 8 , true ) ;
DrawStringF ( true , SCREEN_WIDTH_TOP - ( 20 * 8 ) - 4 , info_start + 12 + ( c * 10 ) , ( clipboard - > entry [ c ] . type = = T_FAT_FILE ) ? COLOR_FILE : COLOR_DIR , COLOR_STD_BG , tempstr ) ;
}
* tempstr = ' \0 ' ;
if ( clipboard - > n_entries > 10 ) snprintf ( tempstr , 60 , " + %lu more " , clipboard - > n_entries - 10 ) ;
DrawStringF ( true , SCREEN_WIDTH_TOP - ( 20 * 8 ) - 4 , info_start + 12 + ( 10 * 10 ) , COLOR_GREY , COLOR_STD_BG , " %20s " , tempstr ) ;
2016-02-27 19:58:41 +01:00
// bottom: inctruction block
2016-02-29 22:51:20 +01:00
char * instr = " GodMode 9 v0.0.3 \n <A>/<B>/< \x18 \x19 \x1A \x1B > - Navigation \n <L>(+< \x18 \x19 \x1A \x1B > - Mark entries(s) \n <X> - Make a Screenshot \n <START/+ \x1B > - Reboot/Poweroff " ;
2016-02-27 19:58:41 +01:00
DrawStringF ( true , ( SCREEN_WIDTH_TOP - GetDrawStringWidth ( instr ) ) / 2 , SCREEN_HEIGHT - 2 - GetDrawStringHeight ( instr ) , COLOR_STD_FONT , COLOR_STD_BG , instr ) ;
}
void DrawDirContents ( DirStruct * contents , u32 cursor ) {
static u32 offset_disp = 0 ;
2016-02-28 13:11:07 +01:00
const int str_width = 39 ;
2016-02-27 19:58:41 +01:00
const u32 start_y = 2 ;
2016-02-26 17:03:25 +01:00
const u32 stp_y = 12 ;
const u32 pos_x = 0 ;
2016-02-27 19:58:41 +01:00
const u32 lines = ( SCREEN_HEIGHT - start_y + stp_y - 1 ) / stp_y ;
u32 pos_y = start_y ;
if ( offset_disp > cursor ) offset_disp = cursor ;
else if ( offset_disp + lines < = cursor ) offset_disp = cursor - lines + 1 ;
2016-02-25 16:57:01 +01:00
for ( u32 i = 0 ; pos_y < SCREEN_HEIGHT ; i + + ) {
char tempstr [ str_width + 1 ] ;
2016-02-27 19:58:41 +01:00
u32 offset_i = offset_disp + i ;
2016-02-25 16:57:01 +01:00
u32 color_font ;
if ( offset_i < contents - > n_entries ) {
2016-02-26 17:03:25 +01:00
if ( cursor ! = offset_i ) {
2016-02-27 19:58:41 +01:00
color_font = ( contents - > entry [ offset_i ] . marked ) ? COLOR_MARKED : ( contents - > entry [ offset_i ] . type = = T_FAT_DIR ) ? COLOR_DIR : ( contents - > entry [ offset_i ] . type = = T_FAT_FILE ) ? COLOR_FILE : COLOR_ROOT ;
2016-02-26 17:03:25 +01:00
} else {
2016-02-27 19:58:41 +01:00
color_font = COLOR_STD_FONT ;
2016-02-26 17:03:25 +01:00
}
2016-02-28 13:11:07 +01:00
ResizeString ( tempstr , contents - > entry [ offset_i ] . name , str_width , str_width - 10 , false ) ;
2016-02-25 16:57:01 +01:00
} else {
2016-02-26 17:03:25 +01:00
color_font = COLOR_WHITE ;
2016-02-25 16:57:01 +01:00
snprintf ( tempstr , str_width + 1 , " %-*.*s " , str_width , str_width , " " ) ;
}
2016-02-28 13:11:07 +01:00
DrawStringF ( false , pos_x , pos_y , color_font , COLOR_STD_BG , tempstr ) ;
2016-02-25 16:57:01 +01:00
pos_y + = stp_y ;
}
2016-02-28 13:11:07 +01:00
if ( contents - > n_entries > lines ) { // draw position bar at the right
const u32 bar_height_min = 32 ;
const u32 bar_width = 2 ;
u32 bar_height = ( lines * SCREEN_HEIGHT ) / contents - > n_entries ;
if ( bar_height < bar_height_min ) bar_height = bar_height_min ;
2016-02-29 16:23:33 +01:00
u32 bar_pos = ( ( u64 ) offset_disp * ( SCREEN_HEIGHT - bar_height ) ) / ( contents - > n_entries - lines ) ;
2016-02-28 13:11:07 +01:00
DrawRectangleF ( false , SCREEN_WIDTH_BOT - bar_width , 0 , bar_width , bar_pos , COLOR_STD_BG ) ;
DrawRectangleF ( false , SCREEN_WIDTH_BOT - bar_width , bar_pos + bar_height , bar_width , SCREEN_WIDTH_BOT - ( bar_pos + bar_height ) , COLOR_STD_BG ) ;
DrawRectangleF ( false , SCREEN_WIDTH_BOT - bar_width , bar_pos , bar_width , bar_height , COLOR_SIDE_BAR ) ;
}
2016-02-25 16:57:01 +01:00
}
u32 GodMode ( ) {
2016-02-27 19:58:41 +01:00
static const u32 quick_stp = 20 ;
2016-02-25 16:57:01 +01:00
u32 exit_mode = GODMODE_EXIT_REBOOT ;
2016-02-29 16:14:39 +01:00
// reserve 512kB for each, just to be safe
static DirStruct * current_dir = ( DirStruct * ) 0x21000000 ;
static DirStruct * clipboard = ( DirStruct * ) 0x21080000 ;
2016-02-26 18:52:30 +01:00
char current_path [ 256 ] = { 0x00 } ;
2016-02-29 16:14:39 +01:00
2016-02-29 16:47:38 +01:00
int mark_setting = - 1 ;
2016-02-26 18:52:30 +01:00
u32 cursor = 0 ;
2016-02-25 16:57:01 +01:00
2016-02-27 19:58:41 +01:00
ClearScreenF ( true , true , COLOR_BLACK ) ;
if ( ! InitFS ( ) ) return exit_mode ;
2016-02-25 16:57:01 +01:00
2016-02-29 16:14:39 +01:00
GetDirContents ( current_dir , " " ) ;
clipboard - > n_entries = 0 ;
2016-02-26 18:52:30 +01:00
while ( true ) { // this is the main loop
2016-02-29 22:27:04 +01:00
DrawUserInterface ( current_path , & ( current_dir - > entry [ cursor ] ) , clipboard ) ; // no need to fully do this everytime!
2016-02-29 16:14:39 +01:00
DrawDirContents ( current_dir , cursor ) ;
2016-02-26 18:52:30 +01:00
u32 pad_state = InputWait ( ) ;
2016-02-29 16:47:38 +01:00
if ( pad_state & BUTTON_DOWN ) { // cursor up
2016-02-26 18:52:30 +01:00
cursor + + ;
2016-02-29 16:14:39 +01:00
if ( cursor > = current_dir - > n_entries )
cursor = current_dir - > n_entries - 1 ;
2016-02-29 16:47:38 +01:00
} else if ( ( pad_state & BUTTON_UP ) & & cursor ) { // cursor down
2016-02-26 18:52:30 +01:00
cursor - - ;
2016-02-29 16:47:38 +01:00
} else if ( ( pad_state & BUTTON_RIGHT ) & & ( mark_setting < 0 ) ) { // cursor down (quick)
2016-02-27 19:58:41 +01:00
cursor + = quick_stp ;
2016-02-29 16:14:39 +01:00
if ( cursor > = current_dir - > n_entries )
cursor = current_dir - > n_entries - 1 ;
2016-02-29 16:47:38 +01:00
} else if ( ( pad_state & BUTTON_LEFT ) & & ( mark_setting < 0 ) ) { // curor up (quick)
2016-02-27 19:58:41 +01:00
cursor = ( cursor > = quick_stp ) ? cursor - quick_stp : 0 ;
2016-02-29 16:47:38 +01:00
} else if ( pad_state & BUTTON_RIGHT ) { // mark all entries
for ( u32 c = 0 ; c < current_dir - > n_entries ; c + + ) current_dir - > entry [ c ] . marked = 1 ;
} else if ( pad_state & BUTTON_LEFT ) { // unmark all entries
for ( u32 c = 0 ; c < current_dir - > n_entries ; c + + ) current_dir - > entry [ c ] . marked = 0 ;
} else if ( ( pad_state & BUTTON_L1 ) & & * current_path ) { // switch marking for single entry
if ( mark_setting > = 0 ) {
current_dir - > entry [ cursor ] . marked = mark_setting ;
} else {
current_dir - > entry [ cursor ] . marked ^ = 0x1 ;
mark_setting = current_dir - > entry [ cursor ] . marked ;
}
} else if ( ( pad_state & BUTTON_A ) & & ( current_dir - > entry [ cursor ] . type ! = T_FAT_FILE ) ) { // one level up
2016-02-29 16:14:39 +01:00
strncpy ( current_path , current_dir - > entry [ cursor ] . path , 256 ) ;
GetDirContents ( current_dir , current_path ) ;
2016-02-27 19:58:41 +01:00
cursor = 0 ;
2016-02-29 15:47:45 +01:00
ClearScreenF ( true , true , COLOR_STD_BG ) ; // not really required
2016-02-29 16:47:38 +01:00
} else if ( pad_state & BUTTON_B ) { // one level down
2016-02-26 18:52:30 +01:00
char * last_slash = strrchr ( current_path , ' / ' ) ;
if ( last_slash ) * last_slash = ' \0 ' ;
else * current_path = ' \0 ' ;
2016-02-29 16:14:39 +01:00
GetDirContents ( current_dir , current_path ) ;
2016-02-27 19:58:41 +01:00
cursor = 0 ;
2016-02-29 15:47:45 +01:00
ClearScreenF ( true , true , COLOR_STD_BG ) ; // not really required
2016-02-29 16:47:38 +01:00
} else if ( pad_state & BUTTON_X ) { // create a screenshot
2016-02-29 15:47:45 +01:00
CreateScreenshot ( ) ;
2016-02-29 22:27:04 +01:00
} else if ( ( pad_state & BUTTON_Y ) & & ( clipboard - > n_entries = = 0 ) ) { // fill clipboard
for ( u32 c = 0 ; c < current_dir - > n_entries ; c + + ) {
if ( current_dir - > entry [ c ] . marked ) {
DirEntryCpy ( & ( clipboard - > entry [ clipboard - > n_entries ] ) , & ( current_dir - > entry [ c ] ) ) ;
current_dir - > entry [ c ] . marked = 0 ;
clipboard - > n_entries + + ;
}
}
if ( clipboard - > n_entries = = 0 ) {
DirEntryCpy ( & ( clipboard - > entry [ 0 ] ) , & ( current_dir - > entry [ cursor ] ) ) ;
clipboard - > n_entries = 1 ;
}
} else if ( ( pad_state & BUTTON_SELECT ) & & ( clipboard - > n_entries > 0 ) ) { // clear clipboard
clipboard - > n_entries = 0 ;
2016-02-26 18:52:30 +01:00
}
2016-02-29 22:27:04 +01:00
2016-02-29 16:47:38 +01:00
if ( ! ( pad_state & BUTTON_L1 ) ) {
mark_setting = - 1 ;
}
2016-02-26 18:52:30 +01:00
if ( pad_state & BUTTON_START ) {
exit_mode = ( pad_state & BUTTON_LEFT ) ? GODMODE_EXIT_POWEROFF : GODMODE_EXIT_REBOOT ;
break ;
}
}
2016-02-25 16:57:01 +01:00
DeinitFS ( ) ;
return exit_mode ;
}