Improve file selection search behaviour

This commit is contained in:
Vas Crabb 2018-09-27 18:27:44 +10:00
parent 73a25da76f
commit f5504bba24
2 changed files with 105 additions and 82 deletions

View File

@ -283,6 +283,105 @@ void menu_file_selector::append_entry_menu_item(const file_selector_entry *entry
}
//-------------------------------------------------
// select_item
//-------------------------------------------------
void menu_file_selector::select_item(const file_selector_entry &entry)
{
switch (entry.type)
{
case SELECTOR_ENTRY_TYPE_EMPTY:
// empty slot - unload
m_result = result::EMPTY;
stack_pop();
break;
case SELECTOR_ENTRY_TYPE_CREATE:
// create
m_result = result::CREATE;
stack_pop();
break;
case SELECTOR_ENTRY_TYPE_SOFTWARE_LIST:
m_result = result::SOFTLIST;
stack_pop();
break;
case SELECTOR_ENTRY_TYPE_DRIVE:
case SELECTOR_ENTRY_TYPE_DIRECTORY:
// drive/directory - first check the path
{
util::zippath_directory::ptr dir;
osd_file::error const err = util::zippath_directory::open(entry.fullpath, dir);
if (err != osd_file::error::NONE)
{
// this path is problematic; present the user with an error and bail
ui().popup_time(1, _("Error accessing %s"), entry.fullpath);
break;
}
}
m_current_directory.assign(entry.fullpath);
reset(reset_options::SELECT_FIRST);
break;
case SELECTOR_ENTRY_TYPE_FILE:
// file
m_current_file.assign(entry.fullpath);
m_result = result::FILE;
stack_pop();
break;
}
}
//-------------------------------------------------
// type_search_char
//-------------------------------------------------
void menu_file_selector::type_search_char(char32_t ch)
{
std::string const current(m_filename);
if (input_character(m_filename, ch, uchar_is_printable))
{
ui().popup_time(ERROR_MESSAGE_TIME, "%s", m_filename.c_str());
file_selector_entry const *const cur_selected(reinterpret_cast<file_selector_entry const *>(get_selection_ref()));
// if it's a perfect match for the current selection, don't move it
if (!cur_selected || core_strnicmp(cur_selected->basename.c_str(), m_filename.c_str(), m_filename.size()))
{
std::string::size_type bestmatch(0);
file_selector_entry const *selected_entry(cur_selected);
for (auto &entry : m_entrylist)
{
// TODO: more efficient "common prefix" code
std::string::size_type match(0);
for (std::string::size_type i = 1; m_filename.size() >= i; ++i)
{
if (!core_strnicmp(entry.basename.c_str(), m_filename.c_str(), i))
match = i;
else
break;
}
if (match > bestmatch)
{
bestmatch = match;
selected_entry = &entry;
}
}
if (selected_entry && (selected_entry != cur_selected))
{
set_selection((void *)selected_entry);
centre_selection();
}
}
}
}
//-------------------------------------------------
// populate
//-------------------------------------------------
@ -375,61 +474,14 @@ void menu_file_selector::populate(float &customtop, float &custombottom)
void menu_file_selector::handle()
{
osd_file::error err;
const file_selector_entry *selected_entry = nullptr;
int bestmatch = 0;
// process the menu
const event *event = process(0);
if (event != nullptr && event->itemref != nullptr)
event const *const event = process(0);
if (event && event->itemref)
{
// handle selections
if (event->iptkey == IPT_UI_SELECT)
{
auto entry = (const file_selector_entry *) event->itemref;
switch (entry->type)
{
case SELECTOR_ENTRY_TYPE_EMPTY:
// empty slot - unload
m_result = result::EMPTY;
stack_pop();
break;
case SELECTOR_ENTRY_TYPE_CREATE:
// create
m_result = result::CREATE;
stack_pop();
break;
case SELECTOR_ENTRY_TYPE_SOFTWARE_LIST:
m_result = result::SOFTLIST;
stack_pop();
break;
case SELECTOR_ENTRY_TYPE_DRIVE:
case SELECTOR_ENTRY_TYPE_DIRECTORY:
// drive/directory - first check the path
{
util::zippath_directory::ptr dir;
err = util::zippath_directory::open(entry->fullpath, dir);
}
if (err != osd_file::error::NONE)
{
// this path is problematic; present the user with an error and bail
ui().popup_time(1, _("Error accessing %s"), entry->fullpath);
break;
}
m_current_directory.assign(entry->fullpath);
reset(reset_options::SELECT_FIRST);
break;
case SELECTOR_ENTRY_TYPE_FILE:
// file
m_current_file.assign(entry->fullpath);
m_result = result::FILE;
stack_pop();
break;
}
select_item(*reinterpret_cast<file_selector_entry const *>(event->itemref));
// reset the char buffer when pressing IPT_UI_SELECT
m_filename.clear();
@ -437,38 +489,7 @@ void menu_file_selector::handle()
else if (event->iptkey == IPT_SPECIAL)
{
// if it's any other key and we're not maxed out, update
if (input_character(m_filename, event->unichar, uchar_is_printable))
{
ui().popup_time(ERROR_MESSAGE_TIME, "%s", m_filename.c_str());
file_selector_entry const *const cur_selected(reinterpret_cast<file_selector_entry const *>(get_selection_ref()));
// check for entries which matches our m_filename_buffer:
for (auto &entry : m_entrylist)
{
if (cur_selected != &entry)
{
int match = 0;
for (int i = 0; i < m_filename.size() + 1; i++)
{
if (core_strnicmp(entry.basename.c_str(), m_filename.c_str(), i) == 0)
match = i;
}
if (match > bestmatch)
{
bestmatch = match;
selected_entry = &entry;
}
}
}
if (selected_entry != nullptr && selected_entry != cur_selected)
{
set_selection((void *)selected_entry);
centre_selection();
}
}
type_search_char(event->unichar);
}
else if (event->iptkey == IPT_UI_CANCEL)
{

View File

@ -89,6 +89,8 @@ private:
file_selector_entry &append_entry(file_selector_entry_type entry_type, std::string &&entry_basename, std::string &&entry_fullpath);
file_selector_entry *append_dirent_entry(const osd::directory::entry *dirent);
void append_entry_menu_item(const file_selector_entry *entry);
void select_item(const file_selector_entry &entry);
void type_search_char(char32_t ch);
};