Searchengine changed: now find games, that hath the search string in it.

e.G. "SPOR" find "ea SPORts", "mario SPORts mix", "SPORe heros" and so on.
This commit is contained in:
ardi@ist-einmalig.de 2011-11-11 20:15:29 +00:00
parent baff754740
commit 164889c917
8 changed files with 94 additions and 70 deletions

View File

@ -2,8 +2,8 @@
<app version="1"> <app version="1">
<name> USB Loader GX</name> <name> USB Loader GX</name>
<coder>USB Loader GX Team</coder> <coder>USB Loader GX Team</coder>
<version>2.3 r1126</version> <version>2.3 r1127</version>
<release_date>201111081925</release_date> <release_date>201111111858</release_date>
<!-- // remove this line to enable arguments <!-- // remove this line to enable arguments
<arguments> <arguments>
<arg>--ios=250</arg> <arg>--ios=250</arg>

View File

@ -29,7 +29,7 @@ class cSearchButton
}; };
GuiSearchBar::GuiSearchBar(const wchar_t *SearchChars) : GuiSearchBar::GuiSearchBar(const std::set<wchar_t> &SearchChars) :
inSide(0), text((char *) NULL, 22, ( GXColor ) inSide(0), text((char *) NULL, 22, ( GXColor )
{ 0, 0, 0, 255}), buttons(0), { 0, 0, 0, 255}), buttons(0),
keyImageData(Resources::GetFile("keyboard_key.png"), Resources::GetFileSize("keyboard_key.png")), keyImageData(Resources::GetFile("keyboard_key.png"), Resources::GetFileSize("keyboard_key.png")),
@ -39,24 +39,24 @@ GuiSearchBar::GuiSearchBar(const wchar_t *SearchChars) :
trigB.SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B); trigB.SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B);
SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE); SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE);
cnt = wcslen(SearchChars); cnt = SearchChars.size();
buttons = new cSearchButton*[cnt]; buttons = new cSearchButton*[cnt];
wchar_t charstr[2] = { 0, 0 }; wchar_t charstr[2] = { 0, 0 };
int lines = (cnt + 9) / 10; int lines = (cnt + 9) / 10;
int buttonsPerLine = (cnt + lines - 1) / lines; int buttonsPerLine = (cnt + lines - 1) / lines;
width = 10 + buttonsPerLine * 42 + 10; width = 10 + buttonsPerLine * 42 + 10;
int x_start = 10, x = 0, y_start = 10 + 42, y = 0; int i = 0, x_start = 10, x = 0, y_start = 10 + 42, y = 0;
if (width < 200) if (width < 320)
{ {
x_start += (200 - width) >> 1; x_start += (320 - width) >> 1;
width = 200; width = 320;
} }
for (int i = 0; i < cnt; i++, x++) for (std::set<wchar_t>::iterator it=SearchChars.begin() ; it != SearchChars.end(); it++, i++, x++)
{ {
if (x >= buttonsPerLine) x = 0; if (x >= buttonsPerLine) x = 0;
if (x == 0) y++; if (x == 0) y++;
charstr[0] = SearchChars[i]; charstr[0] = *it;
buttons[i] = new cSearchButton(charstr, &keyImageData, &keyOverImageData, x_start + x * 42, y_start - 42 + y buttons[i] = new cSearchButton(charstr, &keyImageData, &keyOverImageData, x_start + x * 42, y_start - 42 + y
* 42, &trig, btnSoundOver, btnSoundClick); * 42, &trig, btnSoundOver, btnSoundClick);
this->Append(&(buttons[i]->button)); this->Append(&(buttons[i]->button));

View File

@ -1,13 +1,14 @@
#ifndef GUI_SEARCHBAR_H_ #ifndef GUI_SEARCHBAR_H_
#define GUI_SEARCHBAR_H_ #define GUI_SEARCHBAR_H_
#include "gui.h" #include "gui.h"
#include <set>
class cSearchButton; class cSearchButton;
class GuiSearchBar: public GuiWindow class GuiSearchBar: public GuiWindow
{ {
public: public:
GuiSearchBar(const wchar_t *SearchChars); GuiSearchBar(const std::set<wchar_t> &SearchChars);
virtual ~GuiSearchBar(); virtual ~GuiSearchBar();
void Draw(); void Draw();
void Update(GuiTrigger * t); void Update(GuiTrigger * t);

View File

@ -908,13 +908,39 @@ int GameBrowseMenu::MainLoop()
{ {
if (searchChar > 27) //! Character clicked if (searchChar > 27) //! Character clicked
{ {
int len = gameList.GetCurrentFilter() ? wcslen(gameList.GetCurrentFilter()) : 0; for(;;)
{
int len = wcslen(gameList.GetCurrentFilter());
wchar_t newFilter[len + 2]; wchar_t newFilter[len + 2];
if (gameList.GetCurrentFilter()) wcscpy(newFilter, gameList.GetCurrentFilter()); wcscpy(newFilter, gameList.GetCurrentFilter());
newFilter[len] = searchChar; newFilter[len] = searchChar;
newFilter[len + 1] = 0; newFilter[len + 1] = 0;
gameList.FilterList(newFilter); gameList.FilterList(newFilter);
if(gameList.GetAvailableSearchChars().size() != 1)
break;
searchChar = *gameList.GetAvailableSearchChars().begin();
}
bool autoClose = false;
switch(Settings.gameDisplay)
{
case LIST_MODE:
autoClose = gameList.size()<=9;
break;
case CAROUSEL_MODE:
autoClose = gameList.size()<=5;
break;
case GRID_MODE:
autoClose = gameList.size()<=3;
default:
break;
}
if(autoClose) // Close Searchwindow when less than 5 Games found
{
show_searchwindow = false;
searchBtn->StopEffect();
}
} }
else if (searchChar == 27) //! Close else if (searchChar == 27) //! Close
{ {
@ -930,11 +956,16 @@ int GameBrowseMenu::MainLoop()
{ {
int len = wcslen(gameList.GetCurrentFilter()); int len = wcslen(gameList.GetCurrentFilter());
wchar_t newFilter[len + 1]; wchar_t newFilter[len + 1];
if (gameList.GetCurrentFilter()) wcscpy(newFilter, gameList.GetCurrentFilter()); wcscpy(newFilter, gameList.GetCurrentFilter());
newFilter[len > 0 ? len - 1 : 0] = 0; int old_game_count = gameList.size();
gameList.FilterList(newFilter); for(; len > 0; len--)
{
newFilter[len - 1] = 0; // remove last char
if(len == 1) if(len == 1)
Settings.gridRows = GridRowsPreSearch; //! restore old rows amount so we don't stay on one row Settings.gridRows = GridRowsPreSearch; //! restore old rows amount so we don't stay on one row
if(gameList.FilterList(newFilter) != old_game_count)
break;
}
} }
ReloadBrowser(); ReloadBrowser();
return MENU_NONE; return MENU_NONE;

View File

@ -181,14 +181,6 @@ int GameList::ReadGameList()
return LoadUnfiltered(); return LoadUnfiltered();
} }
static bool WCharSortCallback(const wchar_t char1, const wchar_t char2)
{
if (char2 == 0) return true;
if (char1 == 0) return false;
return char2 > char1;
}
int GameList::FilterList(const wchar_t * gameFilter) int GameList::FilterList(const wchar_t * gameFilter)
{ {
if (FullGameList.size() == 0) ReadGameList(); if (FullGameList.size() == 0) ReadGameList();
@ -251,22 +243,30 @@ int GameList::FilterList(const wchar_t * gameFilter)
if(n == Settings.EnabledCategories.size()) continue; if(n == Settings.EnabledCategories.size()) continue;
wchar_t *gameName = charToWideChar(GameTitles.GetTitle(header)); wchar_t *gameName = charToWideChar(GameTitles.GetTitle(header));
if (gameName && *GameFilter.c_str()) if (gameName)
{ {
if (wcsnicmp(gameName, GameFilter.c_str(), GameFilter.size()) != 0) if ( GameFilter.size() ) // has Filter
{
bool found = false;
wchar_t *s1 = gameName, *s2;
while( (s2 = wcscasestr(s1, GameFilter.c_str())) ) // search filter in gameName
{
found = true;
wchar_t ch = towupper(s2[GameFilter.size()]);
if(ch) AvailableSearchChars.insert(ch);
s1++; // try search filter in gameName more times
}
if(!found)
{ {
delete [] gameName; delete [] gameName;
continue; continue;
} }
} }
else // no Filter -> makes all chars as aviable
if (gameName)
{ {
if (wcslen(gameName) > GameFilter.size() && for(wchar_t *ch = gameName; *ch; ch++)
AvailableSearchChars.find(towupper(gameName[GameFilter.size()])) == std::string::npos && if(*ch >= '@') // limit chars by empty filter
AvailableSearchChars.find(towlower(gameName[GameFilter.size()])) == std::string::npos) AvailableSearchChars.insert(towupper(*ch));
{
AvailableSearchChars.push_back(gameName[GameFilter.size()]);
} }
delete [] gameName; delete [] gameName;
@ -277,7 +277,7 @@ int GameList::FilterList(const wchar_t * gameFilter)
NewTitles::Instance()->Save(); NewTitles::Instance()->Save();
AvailableSearchChars.push_back(L'\0'); if (FilteredList.size() < 2)
if (FilteredList.size() < 2) if (FilteredList.size() < 2)
AvailableSearchChars.clear(); AvailableSearchChars.clear();
@ -305,12 +305,9 @@ int GameList::LoadUnfiltered()
wchar_t *gameName = charToWideChar(GameTitles.GetTitle(header)); wchar_t *gameName = charToWideChar(GameTitles.GetTitle(header));
if (gameName) if (gameName)
{ {
if (wcslen(gameName) > GameFilter.size() && for(wchar_t *ch = gameName; *ch; ch++)
AvailableSearchChars.find(towupper(gameName[GameFilter.size()])) == std::string::npos && if(*ch >= '@') // limit chars by unfiltered list
AvailableSearchChars.find(towlower(gameName[GameFilter.size()])) == std::string::npos) AvailableSearchChars.insert(towupper(*ch));
{
AvailableSearchChars.push_back(gameName[GameFilter.size()]);
}
delete [] gameName; delete [] gameName;
} }
@ -320,8 +317,6 @@ int GameList::LoadUnfiltered()
NewTitles::Instance()->Save(); NewTitles::Instance()->Save();
AvailableSearchChars.push_back(L'\0');
if (FilteredList.size() < 2) if (FilteredList.size() < 2)
AvailableSearchChars.clear(); AvailableSearchChars.clear();
@ -350,10 +345,6 @@ void GameList::SortList()
{ {
std::sort(FilteredList.begin(), FilteredList.end(), NameSortCallback); std::sort(FilteredList.begin(), FilteredList.end(), NameSortCallback);
} }
if (AvailableSearchChars.size() > 1)
std::sort(AvailableSearchChars.begin(), AvailableSearchChars.end(), WCharSortCallback);
} }
bool GameList::NameSortCallback(const struct discHdr *a, const struct discHdr *b) bool GameList::NameSortCallback(const struct discHdr *a, const struct discHdr *b)

View File

@ -2,6 +2,7 @@
#define GAME_LIST_H_ #define GAME_LIST_H_
#include <vector> #include <vector>
#include <set>
#include "Controls/DeviceHandler.hpp" #include "Controls/DeviceHandler.hpp"
#include "wstring.hpp" #include "wstring.hpp"
#include "usbloader/disc.h" #include "usbloader/disc.h"
@ -19,7 +20,7 @@ class GameList
struct discHdr * operator[](int i) const { if (i < 0 || i >= (int) FilteredList.size()) return NULL; return FilteredList[i]; } struct discHdr * operator[](int i) const { if (i < 0 || i >= (int) FilteredList.size()) return NULL; return FilteredList[i]; }
struct discHdr * GetDiscHeader(const char * gameID) const; struct discHdr * GetDiscHeader(const char * gameID) const;
const wchar_t * GetCurrentFilter() const { return GameFilter.c_str(); } const wchar_t * GetCurrentFilter() const { return GameFilter.c_str(); }
const wchar_t * GetAvailableSearchChars() const { return AvailableSearchChars.c_str(); } const std::set<wchar_t> &GetAvailableSearchChars() const { return AvailableSearchChars; }
void SortList(); void SortList();
void clear(); void clear();
bool operator!() const { return (FullGameList.size() == 0); } bool operator!() const { return (FullGameList.size() == 0); }
@ -41,7 +42,7 @@ class GameList
static bool RankingSortCallback(const struct discHdr *a, const struct discHdr *b); static bool RankingSortCallback(const struct discHdr *a, const struct discHdr *b);
static bool PlayersSortCallback(const struct discHdr *a, const struct discHdr *b); static bool PlayersSortCallback(const struct discHdr *a, const struct discHdr *b);
wString AvailableSearchChars; std::set<wchar_t> AvailableSearchChars;
wString GameFilter; wString GameFilter;
int selectedGame; int selectedGame;
std::vector<struct discHdr *> FilteredList; std::vector<struct discHdr *> FilteredList;

View File

@ -147,16 +147,15 @@ size_t utf8Len(const char *s)
return len; return len;
} }
int wcsnicmp(const wchar_t *s1, const wchar_t *s2, int len) wchar_t *wcscasestr(const wchar_t *s1, const wchar_t *s2)
{ {
if (len <= 0) return (0); if(*s2==0) return (wchar_t *)s1;
int s1_len = wcslen(s1);
do int s2_len = wcslen(s2);
{ if(s1_len < s2_len) return 0;
int r = towupper(*s1) - towupper(*s2++); const wchar_t *end = &s1[s1_len-s2_len];
if (r) return r; for(wchar_t *s=(wchar_t *)s1; s<=end; s++)
if (*s1++ == 0) break; if(wcsncasecmp(s, s2, s2_len)==0)
} while (--len != 0); return s;
return 0;
return (0);
} }

View File

@ -22,6 +22,7 @@ class wString: public std::basic_string<wchar_t, std::char_traits<wchar_t>, std:
}; };
size_t utf8Len(const char *s); size_t utf8Len(const char *s);
int wcsnicmp(const wchar_t *s1, const wchar_t *s2, int len);
wchar_t *wcscasestr(const wchar_t *s1, const wchar_t *s2);
#endif // !defined(__WSTRING_HPP) #endif // !defined(__WSTRING_HPP)