/*
mainlist.cpp
Copyright (C) 2007 Acekard, www.acekard.com
Copyright (C) 2007-2009 somebody
Copyright (C) 2009 yellow wood goblin
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
//�
#include
#include
#include "mainlist.h"
#include "dbgtool.h"
#include "startmenu.h"
#include "systemfilenames.h"
#include "romloader.h"
#include "windowmanager.h"
#include "timetool.h"
#include "../../share/memtool.h"
#include "inifile.h"
#include "unknown_banner_bin.h"
#include "nds_save_banner_bin.h"
#include "nand_banner_bin.h"
#include "microsd_banner_bin.h"
#include "gba_banner_bin.h"
#include "folder_banner_bin.h"
#include "progresswnd.h"
#include "language.h"
#include "unicode.h"
using namespace akui;
cMainList::cMainList( s32 x, s32 y, u32 w, u32 h, cWindow * parent, const std::string & text )
: cListView( x, y, w, h, parent, text ),_showAllFiles(false),
_topCount(3),_topuSD(0),_topSlot2(1),_topFavorites(2)
{
_viewMode = VM_LIST;
_activeIconScale = 1;
_activeIcon.hide();
_activeIcon.update();
animationManager().addAnimation( &_activeIcon );
dbg_printf("_activeIcon.init\n");
fifoSendValue32(FIFO_USER_01,MENU_MSG_SYSTEM);
while(!fifoCheckValue32(FIFO_USER_02));
u32 system=fifoGetValue32(FIFO_USER_02);
if(2==system) //dsi
{
_topCount=2;
_topSlot2=2;
_topFavorites=1;
}
}
cMainList::~cMainList()
{}
int cMainList::init()
{
CIniFile ini(SFN_UI_SETTINGS);
_textColor=ini.GetInt("main list","textColor",RGB15(7,7,7));
_textColorHilight=ini.GetInt("main list","textColorHilight",RGB15(31,0,31));
_selectionBarColor1=ini.GetInt("main list","selectionBarColor1",RGB15(16,20,24));
_selectionBarColor2=ini.GetInt("main list","selectionBarColor2",RGB15(20,25,0));
_selectionBarOpacity=ini.GetInt("main list","selectionBarOpacity",100);
//selectedRowClicked.connect(this,&cMainList::executeSelected);
insertColumn(ICON_COLUMN,"icon",0);
insertColumn(SHOWNAME_COLUMN,"showName",0);
insertColumn(INTERNALNAME_COLUMN,"internalName",0);
insertColumn(REALNAME_COLUMN,"realName",0); // hidden column for contain real filename
insertColumn(SAVETYPE_COLUMN,"saveType",0);
insertColumn(FILESIZE_COLUMN,"fileSize",0);
setViewMode((cMainList::VIEW_MODE)gs().viewMode);
_activeIcon.hide();
return 1;
}
static bool itemSortComp( const cListView::itemVector & item1, const cListView::itemVector & item2 ) {
const std::string & fn1 = item1[cMainList::SHOWNAME_COLUMN].text();
const std::string & fn2 = item2[cMainList::SHOWNAME_COLUMN].text();
if( "../" == fn1 )
return true;
if( "../" == fn2 )
return false;
if( '/' == fn1[fn1.size()-1] && '/' == fn2[fn2.size()-1] )
return fn1 < fn2;
if( '/' == fn1[fn1.size()-1] )
return true;
if( '/' == fn2[fn2.size()-1] )
return false;
return fn1 < fn2;
}
static bool extnameFilter( const std::vector & extNames, std::string extName )
{
if( 0 == extNames.size() )
return true;
for( size_t i = 0; i < extName.size(); ++i )
extName[i] = tolower( extName[i] );
for( size_t i = 0; i < extNames.size(); ++i ) {
if( extName == extNames[i] ) {
return true;
}
}
return false;
}
bool cMainList::enterDir( const std::string & dirName )
{
_saves.clear();
if( "..." == dirName ) // select RPG or SD card
{
removeAllRows();
_romInfoList.clear();
for( size_t i = 0; i < _topCount; ++i ) {
std::vector< std::string > a_row;
a_row.push_back( "" ); // make a space for icon
DSRomInfo rominfo;
if( _topuSD == i ) {
a_row.push_back( LANG("mainlist","microsd card") );
a_row.push_back( "" );
a_row.push_back( SD_ROOT );
rominfo.setBanner("usd",microsd_banner_bin);
} else if( _topSlot2 == i ) {
a_row.push_back( LANG("mainlist","slot2 card") );
a_row.push_back( "" );
a_row.push_back( "slot2:/" );
rominfo.setBanner("slot2",gba_banner_bin);
} else if( _topFavorites == i ) {
a_row.push_back( LANG("mainlist","favorites") );
a_row.push_back( "" );
a_row.push_back( "favorites:/" );
rominfo.setBanner("folder",folder_banner_bin);
}
insertRow( i, a_row );
_romInfoList.push_back( rominfo );
}
_currentDir = "";
directoryChanged();
return true;
}
if( "slot2:/" == dirName ) {
_currentDir = "";
directoryChanged();
return true;
}
bool favorites=("favorites:/"==dirName);
DIR* dir=NULL;
struct dirent *entry;
if(!favorites)
{
dir = opendir( dirName.c_str() );
if (dir == NULL) {
if( SD_ROOT == dirName ) {
std::string title = LANG( "sd card error", "title" );
std::string sdError = LANG( "sd card error", "text" );
messageBox( NULL, title, sdError, MB_OK );
}
dbg_printf ("Unable to open directory<%s>.\n", dirName.c_str() );
return false;
}
}
removeAllRows();
_romInfoList.clear();
std::vector< std::string > extNames;
extNames.push_back( ".nds" );
extNames.push_back( ".ids" );
if( gs().showGbaRoms > 0 )
extNames.push_back( ".gba" );
if( gs().fileListType > 0 )
extNames.push_back( ".sav" );
if( _showAllFiles || gs().fileListType > 1 )
extNames.clear();
std::vector< std::string > savNames;
savNames.push_back( ".sav" );
// insert 一堆文件, 两列,一列作为显示,一列作为真实文件名
std::string extName;
// list dir
{
cwl();
if(favorites)
{
CIniFile ini(SFN_FAVORITES);
std::vector items;
ini.GetStringVector("main","list",items,'|');
for(size_t ii=0;ii a_row;
a_row.push_back(""); // make a space for icon
size_t pos=items[ii].rfind('/',items[ii].length()-2);
if(pos==items[ii].npos)
{
a_row.push_back(items[ii]); //show name
}
else
{
a_row.push_back(items[ii].substr(pos+1,items[ii].npos)); //show name
}
a_row.push_back(""); // make a space for internal name
a_row.push_back(items[ii]); //real name
size_t insertPos(row_count);
insertRow(insertPos,a_row);
DSRomInfo rominfo;
_romInfoList.push_back(rominfo);
}
}
else if(dir)
{
while((entry=readdir(dir))!=NULL)
{
std::string lfn( entry->d_name );
// entry->d_type == DT_DIR indicates a directory
size_t lastDotPos = lfn.find_last_of( '.' );
if( lfn.npos != lastDotPos )
extName = lfn.substr( lastDotPos );
else
extName = "";
dbg_printf( "%s: %s %s\n", (entry->d_type == DT_DIR ? " DIR" : "FILE"), entry->d_name, extName.c_str() );
bool showThis=(entry->d_type == DT_DIR)?(strcmp(entry->d_name,".")&&strcmp(entry->d_name,"..")):extnameFilter( extNames, extName );
showThis=showThis&&(_showAllFiles||gs().showHiddenFiles||!(FAT_getAttr(entry->d_name) & ATTR_HIDDEN));
// 如果有后缀名,或者是个目录,就push进去
if(showThis) {
u32 row_count = getRowCount();
std::vector< std::string > a_row;
a_row.push_back( "" ); // make a space for icon
a_row.push_back(lfn); //show name
a_row.push_back( "" ); // make a space for internal name
a_row.push_back(dirName+lfn); //real name
if( entry->d_type == DT_DIR ) {
a_row[SHOWNAME_COLUMN] += "/";
a_row[REALNAME_COLUMN] += "/";
}
size_t insertPos( row_count );
insertRow( insertPos, a_row );
DSRomInfo rominfo;
_romInfoList.push_back( rominfo );
}
if(extnameFilter(savNames,extName))
{
_saves.push_back(dirName+lfn);
}
}
closedir( dir );
}
std::sort( _rows.begin(), _rows.end(), itemSortComp );
std::sort(_saves.begin(),_saves.end(),stringComp);
for( size_t ii = 0; ii < _rows.size(); ++ii )
{
////_romInfoList.push_back( rominfo );
// 这段代码会引起拷贝文件完成后的图标显示不正确,因为图标的内容还没有被读入,就去更新了active icon的内容
//u8 percent = ii * 100 / _rows.size();
//if( !(percent & 0x07) )
// progressWnd().setPercent( percent );
DSRomInfo & rominfo = _romInfoList[ii];
std::string filename = _rows[ii][REALNAME_COLUMN].text();
size_t lastDotPos = filename.find_last_of( '.' );
if( filename.npos != lastDotPos )
extName = filename.substr( lastDotPos );
else
extName = "";
for( size_t jj = 0; jj < extName.size(); ++jj )
extName[jj] = tolower( extName[jj] );
if( '/' == filename[filename.size()-1] )
{
rominfo.setBanner("folder",folder_banner_bin);
}
else
{
bool allowExt=true,allowUnknown=false;
if( ".sav" == extName ) {
memcpy( &rominfo.banner(), nds_save_banner_bin, sizeof(tNDSBanner) );
} else if( ".gba" == extName ) {
rominfo.MayBeGbaRom(filename);
} else if( ".nds" != extName && ".ids" != extName ) {
memcpy( &rominfo.banner(), unknown_banner_bin, sizeof(tNDSBanner) );
allowUnknown=true;
} else {
rominfo.MayBeDSRom(filename);
allowExt=false;
}
rominfo.setExtIcon(_rows[ii][SHOWNAME_COLUMN].text());
if(allowExt&&extName.length()&&!rominfo.isExtIcon()) rominfo.setExtIcon(extName.substr(1));
if(allowUnknown&&!rominfo.isExtIcon()) rominfo.setExtIcon("unknown");
}
}
_currentDir = dirName;
}
directoryChanged();
return true;
}
void cMainList::onSelectChanged( u32 index )
{
dbg_printf( "%s\n", _rows[index][3].text().c_str() );
}
void cMainList::onSelectedRowClicked( u32 index )
{
const INPUT & input = getInput();
//dbg_printf("%d %d", input.touchPt.px, _position.x );
if( input.touchPt.px > _position.x && input.touchPt.px < _position.x + 32 )
selectedRowHeadClicked( index );
}
void cMainList::onScrolled( u32 index )
{
_activeIconScale = 1;
//updateActiveIcon( CONTENT );
}
void cMainList::backParentDir()
{
if( "..." == _currentDir )
return;
bool fat1=(SD_ROOT==_currentDir),favorites=("favorites:/"==_currentDir);
if( "fat:/" == _currentDir || fat1 || favorites || "/" == _currentDir ) {
enterDir( "..." );
if(fat1) selectRow(_topuSD);
if(favorites) selectRow(_topFavorites);
return;
}
size_t pos = _currentDir.rfind( "/", _currentDir.size() - 2 );
std::string parentDir = _currentDir.substr( 0, pos + 1 );
dbg_printf( "%s->%s\n", _currentDir.c_str(), parentDir.c_str() );
std::string oldCurrentDir = _currentDir;
if( enterDir( parentDir ) ) { // select last entered director
for( size_t i = 0; i < _rows.size(); ++i ){
if( parentDir + _rows[i][SHOWNAME_COLUMN].text() == oldCurrentDir ) {
selectRow( i );
}
}
}
}
std::string cMainList::getSelectedFullPath()
{
if( !_rows.size() )
return std::string("");
return _rows[_selectedRowId][REALNAME_COLUMN].text();
}
std::string cMainList::getSelectedShowName()
{
if( !_rows.size() )
return std::string("");
return _rows[_selectedRowId][SHOWNAME_COLUMN].text();
}
bool cMainList::getRomInfo( u32 rowIndex, DSRomInfo & info ) const
{
if( rowIndex < _romInfoList.size() ) {
info = _romInfoList[rowIndex];
return true;
}
else {
return false;
}
}
void cMainList::setRomInfo( u32 rowIndex, const DSRomInfo & info )
{
if( !_romInfoList[rowIndex].isDSRom() )
return;
if( rowIndex < _romInfoList.size() ) {
_romInfoList[rowIndex] = info;
}
}
void cMainList::draw()
{
updateInternalNames();
cListView::draw();
updateActiveIcon( POSITION );
drawIcons();
}
void cMainList::drawIcons() // 直接画家算法画 icons
{
if( VM_LIST != _viewMode ) {
size_t total = _visibleRowCount;
if( total > _rows.size() - _firstVisibleRowId )
total = _rows.size() - _firstVisibleRowId;
for( size_t i = 0; i < total; ++i ) {
// 这里图像呈现比真正的 MAIN buffer 翻转要早,所以会闪一下
// 解决方法是在 gdi().present 里边统一呈现翻转
if( _firstVisibleRowId + i == _selectedRowId ) {
if( _activeIcon.visible() ) {
continue;
}
}
s32 itemX = _position.x + 1;
s32 itemY = _position.y + i * _rowHeight + ((_rowHeight-32)>>1) - 1;
_romInfoList[_firstVisibleRowId+i].drawDSRomIcon( itemX, itemY, _engine );
}
}
}
void cMainList::setViewMode(VIEW_MODE mode)
{
if(!_columns.size()) return;
_viewMode=mode;
switch(_viewMode)
{
case VM_LIST:
_columns[ICON_COLUMN].width=0;
_columns[SHOWNAME_COLUMN].width=250;
_columns[INTERNALNAME_COLUMN].width=0;
arangeColumnsSize();
setRowHeight(15);
break;
case VM_ICON:
_columns[ICON_COLUMN].width=36;
_columns[SHOWNAME_COLUMN].width=214;
_columns[INTERNALNAME_COLUMN].width=0;
arangeColumnsSize();
setRowHeight(38);
break;
case VM_INTERNAL:
_columns[ICON_COLUMN].width=36;
_columns[SHOWNAME_COLUMN].width=0;
_columns[INTERNALNAME_COLUMN].width=214;
arangeColumnsSize();
setRowHeight(38);
break;
}
scrollTo(_selectedRowId-_visibleRowCount+1);
}
void cMainList::updateActiveIcon( bool updateContent )
{
const INPUT & temp = getInput();
bool allowAnimation = true;
animateIcons(allowAnimation);
//do not show active icon when hold key to list files. Otherwise the icon will not show correctly.
if( getInputIdleMs() > 1000 && VM_LIST != _viewMode && allowAnimation && _romInfoList.size() && 0 == temp.keysHeld && gs().Animation)
{
if( !_activeIcon.visible() ) {
u8 backBuffer[32*32*2];
zeroMemory( backBuffer, 32 * 32 * 2 );
_romInfoList[_selectedRowId].drawDSRomIconMem( backBuffer );
memcpy( _activeIcon.buffer(), backBuffer, 32 * 32 * 2 );
_activeIcon.setBufferChanged();
s32 itemX = _position.x;
s32 itemY = _position.y + (_selectedRowId - _firstVisibleRowId) * _rowHeight + ((_rowHeight-32)>>1) - 1;
_activeIcon.setPosition( itemX, itemY );
_activeIcon.show();
dbg_printf("sel %d ac ico x %d y %d\n", _selectedRowId, itemX, itemY );
for( u8 i = 0; i < 8; ++i )
dbg_printf("%02x", backBuffer[i] );
dbg_printf("\n");
}
} else {
if( _activeIcon.visible() ) {
_activeIcon.hide();
cwl();
}
}
}
std::string cMainList::getCurrentDir()
{
return _currentDir;
}
void cMainList::updateInternalNames(void)
{
if(_viewMode==VM_INTERNAL)
{
size_t total=_visibleRowCount;
if(total>_rows.size()-_firstVisibleRowId) total=_rows.size()-_firstVisibleRowId;
for(size_t ii=0;ii* cMainList::Saves(void)
{
return IsFavorites()?NULL:&_saves;
}
void cMainList::SwitchShowAllFiles(void)
{
_showAllFiles=!_showAllFiles;
enterDir(getCurrentDir());
}