mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-22 14:15:38 +00:00
Added a virtual keyboard.
This commit is contained in:
parent
bbaf2739d4
commit
c4e6d3cac1
|
@ -14,6 +14,7 @@
|
||||||
#include "components/SwitchComponent.h"
|
#include "components/SwitchComponent.h"
|
||||||
#include "guis/GuiMsgBox.h"
|
#include "guis/GuiMsgBox.h"
|
||||||
#include "guis/GuiSettings.h"
|
#include "guis/GuiSettings.h"
|
||||||
|
#include "guis/GuiTextEditKeyboardPopup.h"
|
||||||
#include "guis/GuiTextEditPopup.h"
|
#include "guis/GuiTextEditPopup.h"
|
||||||
#include "utils/StringUtil.h"
|
#include "utils/StringUtil.h"
|
||||||
#include "views/ViewController.h"
|
#include "views/ViewController.h"
|
||||||
|
@ -208,10 +209,21 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(Window* window, std::st
|
||||||
window->removeGui(topGui);
|
window->removeGui(topGui);
|
||||||
createCustomCollection(name);
|
createCustomCollection(name);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (Settings::getInstance()->getBool("VirtualKeyboard")) {
|
||||||
row.makeAcceptInputHandler([this, createCollectionCall] {
|
row.makeAcceptInputHandler([this, createCollectionCall] {
|
||||||
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), "New Collection Name", "",
|
mWindow->pushGui(new GuiTextEditKeyboardPopup(
|
||||||
createCollectionCall, false, "SAVE"));
|
mWindow, getHelpStyle(), "New Collection Name", "", createCollectionCall, false,
|
||||||
|
"CREATE", "CREATE COLLECTION?"));
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
row.makeAcceptInputHandler([this, createCollectionCall] {
|
||||||
|
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), "New Collection Name",
|
||||||
|
"", createCollectionCall, false, "CREATE",
|
||||||
|
"CREATE COLLECTION?"));
|
||||||
|
});
|
||||||
|
}
|
||||||
addRow(row);
|
addRow(row);
|
||||||
|
|
||||||
// Delete custom collection.
|
// Delete custom collection.
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include "SystemData.h"
|
#include "SystemData.h"
|
||||||
#include "components/OptionListComponent.h"
|
#include "components/OptionListComponent.h"
|
||||||
|
#include "guis/GuiTextEditKeyboardPopup.h"
|
||||||
#include "guis/GuiTextEditPopup.h"
|
#include "guis/GuiTextEditPopup.h"
|
||||||
#include "views/UIModeController.h"
|
#include "views/UIModeController.h"
|
||||||
#include "views/ViewController.h"
|
#include "views/ViewController.h"
|
||||||
|
@ -118,11 +119,20 @@ void GuiGamelistFilter::addFiltersToMenu()
|
||||||
mFilterIndex->setTextFilter(Utils::String::toUpper(newVal));
|
mFilterIndex->setTextFilter(Utils::String::toUpper(newVal));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (Settings::getInstance()->getBool("VirtualKeyboard")) {
|
||||||
row.makeAcceptInputHandler([this, updateVal] {
|
row.makeAcceptInputHandler([this, updateVal] {
|
||||||
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), "TEXT FILTER (GAME NAME)",
|
mWindow->pushGui(new GuiTextEditKeyboardPopup(
|
||||||
mTextFilterField->getValue(), updateVal, false, "OK",
|
mWindow, getHelpStyle(), "TEXT FILTER (GAME NAME)", mTextFilterField->getValue(),
|
||||||
"APPLY CHANGES?"));
|
updateVal, false, "OK", "APPLY CHANGES?"));
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
row.makeAcceptInputHandler([this, updateVal] {
|
||||||
|
mWindow->pushGui(new GuiTextEditPopup(
|
||||||
|
mWindow, getHelpStyle(), "TEXT FILTER (GAME NAME)", mTextFilterField->getValue(),
|
||||||
|
updateVal, false, "OK", "APPLY CHANGES?"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
mMenu.addRow(row);
|
mMenu.addRow(row);
|
||||||
|
|
||||||
|
|
|
@ -22,12 +22,13 @@
|
||||||
#include "components/SwitchComponent.h"
|
#include "components/SwitchComponent.h"
|
||||||
#include "guis/GuiAlternativeEmulators.h"
|
#include "guis/GuiAlternativeEmulators.h"
|
||||||
#include "guis/GuiCollectionSystemsOptions.h"
|
#include "guis/GuiCollectionSystemsOptions.h"
|
||||||
#include "guis/GuiComplexTextEditPopup.h"
|
|
||||||
#include "guis/GuiDetectDevice.h"
|
#include "guis/GuiDetectDevice.h"
|
||||||
#include "guis/GuiMediaViewerOptions.h"
|
#include "guis/GuiMediaViewerOptions.h"
|
||||||
#include "guis/GuiMsgBox.h"
|
#include "guis/GuiMsgBox.h"
|
||||||
#include "guis/GuiScraperMenu.h"
|
#include "guis/GuiScraperMenu.h"
|
||||||
#include "guis/GuiScreensaverOptions.h"
|
#include "guis/GuiScreensaverOptions.h"
|
||||||
|
#include "guis/GuiTextEditKeyboardPopup.h"
|
||||||
|
#include "guis/GuiTextEditPopup.h"
|
||||||
#include "views/UIModeController.h"
|
#include "views/UIModeController.h"
|
||||||
#include "views/ViewController.h"
|
#include "views/ViewController.h"
|
||||||
#include "views/gamelist/IGameListView.h"
|
#include "views/gamelist/IGameListView.h"
|
||||||
|
@ -509,6 +510,18 @@ void GuiMenu::openUIOptions()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Enable virtual (on-screen) keyboard.
|
||||||
|
auto virtual_keyboard = std::make_shared<SwitchComponent>(mWindow);
|
||||||
|
virtual_keyboard->setState(Settings::getInstance()->getBool("VirtualKeyboard"));
|
||||||
|
s->addWithLabel("ENABLE VIRTUAL KEYBOARD", virtual_keyboard);
|
||||||
|
s->addSaveFunc([virtual_keyboard, s] {
|
||||||
|
if (virtual_keyboard->getState() != Settings::getInstance()->getBool("VirtualKeyboard")) {
|
||||||
|
Settings::getInstance()->setBool("VirtualKeyboard", virtual_keyboard->getState());
|
||||||
|
s->setNeedsSaving();
|
||||||
|
s->setInvalidateCachedBackground();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Enable the 'Y' button for tagging games as favorites.
|
// Enable the 'Y' button for tagging games as favorites.
|
||||||
auto favorites_add_button = std::make_shared<SwitchComponent>(mWindow);
|
auto favorites_add_button = std::make_shared<SwitchComponent>(mWindow);
|
||||||
favorites_add_button->setState(Settings::getInstance()->getBool("FavoritesAddButton"));
|
favorites_add_button->setState(Settings::getInstance()->getBool("FavoritesAddButton"));
|
||||||
|
@ -809,10 +822,20 @@ void GuiMenu::openOtherOptions()
|
||||||
rowMediaDir.makeAcceptInputHandler([this, titleMediaDir, mediaDirectoryStaticText,
|
rowMediaDir.makeAcceptInputHandler([this, titleMediaDir, mediaDirectoryStaticText,
|
||||||
defaultDirectoryText, initValueMediaDir, updateValMediaDir,
|
defaultDirectoryText, initValueMediaDir, updateValMediaDir,
|
||||||
multiLineMediaDir] {
|
multiLineMediaDir] {
|
||||||
mWindow->pushGui(new GuiComplexTextEditPopup(
|
if (Settings::getInstance()->getBool("VirtualKeyboard")) {
|
||||||
mWindow, getHelpStyle(), titleMediaDir, mediaDirectoryStaticText, defaultDirectoryText,
|
mWindow->pushGui(new GuiTextEditKeyboardPopup(
|
||||||
|
mWindow, getHelpStyle(), titleMediaDir,
|
||||||
Settings::getInstance()->getString("MediaDirectory"), updateValMediaDir,
|
Settings::getInstance()->getString("MediaDirectory"), updateValMediaDir,
|
||||||
multiLineMediaDir, "SAVE", "SAVE CHANGES?"));
|
multiLineMediaDir, "SAVE", "SAVE CHANGES?", mediaDirectoryStaticText,
|
||||||
|
defaultDirectoryText, "load default directory"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mWindow->pushGui(new GuiTextEditPopup(
|
||||||
|
mWindow, getHelpStyle(), titleMediaDir,
|
||||||
|
Settings::getInstance()->getString("MediaDirectory"), updateValMediaDir,
|
||||||
|
multiLineMediaDir, "SAVE", "SAVE CHANGES?", mediaDirectoryStaticText,
|
||||||
|
defaultDirectoryText, "load default directory"));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
s->addRow(rowMediaDir);
|
s->addRow(rowMediaDir);
|
||||||
|
|
||||||
|
|
|
@ -23,9 +23,9 @@
|
||||||
#include "components/RatingComponent.h"
|
#include "components/RatingComponent.h"
|
||||||
#include "components/SwitchComponent.h"
|
#include "components/SwitchComponent.h"
|
||||||
#include "components/TextComponent.h"
|
#include "components/TextComponent.h"
|
||||||
#include "guis/GuiComplexTextEditPopup.h"
|
|
||||||
#include "guis/GuiGameScraper.h"
|
#include "guis/GuiGameScraper.h"
|
||||||
#include "guis/GuiMsgBox.h"
|
#include "guis/GuiMsgBox.h"
|
||||||
|
#include "guis/GuiTextEditKeyboardPopup.h"
|
||||||
#include "guis/GuiTextEditPopup.h"
|
#include "guis/GuiTextEditPopup.h"
|
||||||
#include "resources/Font.h"
|
#include "resources/Font.h"
|
||||||
#include "utils/StringUtil.h"
|
#include "utils/StringUtil.h"
|
||||||
|
@ -364,11 +364,20 @@ GuiMetaDataEd::GuiMetaDataEd(Window* window,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (Settings::getInstance()->getBool("VirtualKeyboard")) {
|
||||||
|
row.makeAcceptInputHandler([this, title, ed, updateVal, multiLine] {
|
||||||
|
mWindow->pushGui(new GuiTextEditKeyboardPopup(
|
||||||
|
mWindow, getHelpStyle(), title, ed->getValue(), updateVal, multiLine,
|
||||||
|
"apply", "APPLY CHANGES?", "", ""));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
row.makeAcceptInputHandler([this, title, ed, updateVal, multiLine] {
|
row.makeAcceptInputHandler([this, title, ed, updateVal, multiLine] {
|
||||||
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), title,
|
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), title,
|
||||||
ed->getValue(), updateVal, multiLine,
|
ed->getValue(), updateVal, multiLine,
|
||||||
"APPLY", "APPLY CHANGES?"));
|
"APPLY", "APPLY CHANGES?"));
|
||||||
});
|
});
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "components/ScrollableContainer.h"
|
#include "components/ScrollableContainer.h"
|
||||||
#include "components/TextComponent.h"
|
#include "components/TextComponent.h"
|
||||||
#include "guis/GuiMsgBox.h"
|
#include "guis/GuiMsgBox.h"
|
||||||
|
#include "guis/GuiTextEditKeyboardPopup.h"
|
||||||
#include "guis/GuiTextEditPopup.h"
|
#include "guis/GuiTextEditPopup.h"
|
||||||
#include "resources/Font.h"
|
#include "resources/Font.h"
|
||||||
#include "utils/StringUtil.h"
|
#include "utils/StringUtil.h"
|
||||||
|
@ -808,8 +809,16 @@ void GuiScraperSearch::openInputScreen(ScraperSearchParams& params)
|
||||||
searchString = params.nameOverride;
|
searchString = params.nameOverride;
|
||||||
}
|
}
|
||||||
|
|
||||||
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), "REFINE SEARCH", searchString,
|
if (Settings::getInstance()->getBool("VirtualKeyboard")) {
|
||||||
searchForFunc, false, "SEARCH", "APPLY CHANGES?"));
|
mWindow->pushGui(new GuiTextEditKeyboardPopup(mWindow, getHelpStyle(), "REFINE SEARCH",
|
||||||
|
searchString, searchForFunc, false, "SEARCH",
|
||||||
|
"SEARCH USING REFINED NAME?"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), "REFINE SEARCH",
|
||||||
|
searchString, searchForFunc, false, "SEARCH",
|
||||||
|
"SEARCH USING REFINED NAME?"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GuiScraperSearch::saveMetadata(const ScraperSearchResult& result,
|
bool GuiScraperSearch::saveMetadata(const ScraperSearchResult& result,
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "SystemData.h"
|
#include "SystemData.h"
|
||||||
#include "Window.h"
|
#include "Window.h"
|
||||||
#include "components/HelpComponent.h"
|
#include "components/HelpComponent.h"
|
||||||
|
#include "guis/GuiTextEditKeyboardPopup.h"
|
||||||
#include "guis/GuiTextEditPopup.h"
|
#include "guis/GuiTextEditPopup.h"
|
||||||
#include "views/ViewController.h"
|
#include "views/ViewController.h"
|
||||||
#include "views/gamelist/IGameListView.h"
|
#include "views/gamelist/IGameListView.h"
|
||||||
|
@ -193,15 +194,30 @@ void GuiSettings::addEditableTextComponent(const std::string label,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (Settings::getInstance()->getBool("VirtualKeyboard")) {
|
||||||
row.makeAcceptInputHandler([this, label, ed, updateVal, isPassword] {
|
row.makeAcceptInputHandler([this, label, ed, updateVal, isPassword] {
|
||||||
// Never display the value if it's a password, instead set it to blank.
|
// Never display the value if it's a password, instead set it to blank.
|
||||||
if (isPassword)
|
if (isPassword)
|
||||||
mWindow->pushGui(
|
mWindow->pushGui(new GuiTextEditKeyboardPopup(
|
||||||
new GuiTextEditPopup(mWindow, getHelpStyle(), label, "", updateVal, false));
|
mWindow, getHelpStyle(), label, "", updateVal, false, "SAVE", "SAVE CHANGES?"));
|
||||||
else
|
else
|
||||||
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), label, ed->getValue(),
|
mWindow->pushGui(new GuiTextEditKeyboardPopup(mWindow, getHelpStyle(), label,
|
||||||
updateVal, false));
|
ed->getValue(), updateVal, false,
|
||||||
|
"SAVE", "SAVE CHANGES?"));
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
row.makeAcceptInputHandler([this, label, ed, updateVal, isPassword] {
|
||||||
|
if (isPassword)
|
||||||
|
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), label, "", updateVal,
|
||||||
|
false, "SAVE", "SAVE CHANGES?"));
|
||||||
|
else
|
||||||
|
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), label,
|
||||||
|
ed->getValue(), updateVal, false, "SAVE",
|
||||||
|
"SAVE CHANGES?"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
assert(ed);
|
assert(ed);
|
||||||
addRow(row);
|
addRow(row);
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
#include "animations/MoveCameraAnimation.h"
|
#include "animations/MoveCameraAnimation.h"
|
||||||
#include "guis/GuiInfoPopup.h"
|
#include "guis/GuiInfoPopup.h"
|
||||||
#include "guis/GuiMenu.h"
|
#include "guis/GuiMenu.h"
|
||||||
|
#include "guis/GuiTextEditKeyboardPopup.h"
|
||||||
|
#include "guis/GuiTextEditPopup.h"
|
||||||
#include "views/SystemView.h"
|
#include "views/SystemView.h"
|
||||||
#include "views/UIModeController.h"
|
#include "views/UIModeController.h"
|
||||||
#include "views/gamelist/DetailedGameListView.h"
|
#include "views/gamelist/DetailedGameListView.h"
|
||||||
|
@ -135,15 +137,15 @@ void ViewController::noGamesDialog()
|
||||||
#else
|
#else
|
||||||
currentROMDirectory = FileData::getROMDirectory();
|
currentROMDirectory = FileData::getROMDirectory();
|
||||||
#endif
|
#endif
|
||||||
|
if (Settings::getInstance()->getBool("VirtualKeyboard")) {
|
||||||
mWindow->pushGui(new GuiComplexTextEditPopup(
|
mWindow->pushGui(new GuiTextEditKeyboardPopup(
|
||||||
mWindow, HelpStyle(), "ENTER ROM DIRECTORY PATH",
|
mWindow, HelpStyle(), "ENTER ROM DIRECTORY PATH", currentROMDirectory,
|
||||||
"Currently configured path:", currentROMDirectory, currentROMDirectory,
|
|
||||||
[this](const std::string& newROMDirectory) {
|
[this](const std::string& newROMDirectory) {
|
||||||
Settings::getInstance()->setString("ROMDirectory", newROMDirectory);
|
Settings::getInstance()->setString("ROMDirectory", newROMDirectory);
|
||||||
Settings::getInstance()->saveFile();
|
Settings::getInstance()->saveFile();
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
mRomDirectory = Utils::String::replace(FileData::getROMDirectory(), "/", "\\");
|
mRomDirectory =
|
||||||
|
Utils::String::replace(FileData::getROMDirectory(), "/", "\\");
|
||||||
#else
|
#else
|
||||||
mRomDirectory = FileData::getROMDirectory();
|
mRomDirectory = FileData::getROMDirectory();
|
||||||
#endif
|
#endif
|
||||||
|
@ -151,10 +153,36 @@ void ViewController::noGamesDialog()
|
||||||
mWindow->pushGui(new GuiMsgBox(mWindow, HelpStyle(),
|
mWindow->pushGui(new GuiMsgBox(mWindow, HelpStyle(),
|
||||||
"ROM DIRECTORY SETTING SAVED, RESTART\n"
|
"ROM DIRECTORY SETTING SAVED, RESTART\n"
|
||||||
"THE APPLICATION TO RESCAN THE SYSTEMS",
|
"THE APPLICATION TO RESCAN THE SYSTEMS",
|
||||||
"OK", nullptr, "", nullptr, "", nullptr, true));
|
"OK", nullptr, "", nullptr, "", nullptr,
|
||||||
|
true));
|
||||||
},
|
},
|
||||||
false, "SAVE", "SAVE CHANGES?", "LOAD CURRENT", "LOAD CURRENTLY CONFIGURED VALUE",
|
false, "SAVE", "SAVE CHANGES?", "Currently configured path:",
|
||||||
"CLEAR", "CLEAR (LEAVE BLANK TO RESET TO DEFAULT DIRECTORY)", false));
|
currentROMDirectory, "LOAD CURRENTLY CONFIGURED PATH",
|
||||||
|
"CLEAR (LEAVE BLANK TO RESET TO DEFAULT PATH)"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mWindow->pushGui(new GuiTextEditPopup(
|
||||||
|
mWindow, HelpStyle(), "ENTER ROM DIRECTORY PATH", currentROMDirectory,
|
||||||
|
[this](const std::string& newROMDirectory) {
|
||||||
|
Settings::getInstance()->setString("ROMDirectory", newROMDirectory);
|
||||||
|
Settings::getInstance()->saveFile();
|
||||||
|
#if defined(_WIN64)
|
||||||
|
mRomDirectory =
|
||||||
|
Utils::String::replace(FileData::getROMDirectory(), "/", "\\");
|
||||||
|
#else
|
||||||
|
mRomDirectory = FileData::getROMDirectory();
|
||||||
|
#endif
|
||||||
|
mNoGamesMessageBox->changeText(mNoGamesErrorMessage + mRomDirectory);
|
||||||
|
mWindow->pushGui(new GuiMsgBox(mWindow, HelpStyle(),
|
||||||
|
"ROM DIRECTORY SETTING SAVED, RESTART\n"
|
||||||
|
"THE APPLICATION TO RESCAN THE SYSTEMS",
|
||||||
|
"OK", nullptr, "", nullptr, "", nullptr,
|
||||||
|
true));
|
||||||
|
},
|
||||||
|
false, "SAVE", "SAVE CHANGES?", "Currently configured path:",
|
||||||
|
currentROMDirectory, "LOAD CURRENTLY CONFIGURED PATH",
|
||||||
|
"CLEAR (LEAVE BLANK TO RESET TO DEFAULT PATH)"));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"CREATE DIRECTORIES",
|
"CREATE DIRECTORIES",
|
||||||
[this] {
|
[this] {
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
|
|
||||||
#include "FileData.h"
|
#include "FileData.h"
|
||||||
#include "GuiComponent.h"
|
#include "GuiComponent.h"
|
||||||
#include "guis/GuiComplexTextEditPopup.h"
|
|
||||||
#include "guis/GuiMsgBox.h"
|
#include "guis/GuiMsgBox.h"
|
||||||
#include "renderers/Renderer.h"
|
#include "renderers/Renderer.h"
|
||||||
|
|
||||||
|
|
|
@ -60,10 +60,10 @@ set(CORE_HEADERS
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/VideoVlcComponent.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/VideoVlcComponent.h
|
||||||
|
|
||||||
# GUIs
|
# GUIs
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiComplexTextEditPopup.h
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiDetectDevice.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiDetectDevice.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiInputConfig.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiInputConfig.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiMsgBox.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiMsgBox.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiTextEditKeyboardPopup.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiTextEditPopup.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiTextEditPopup.h
|
||||||
|
|
||||||
# Renderers
|
# Renderers
|
||||||
|
@ -130,10 +130,10 @@ set(CORE_SOURCES
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/VideoVlcComponent.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/VideoVlcComponent.cpp
|
||||||
|
|
||||||
# GUIs
|
# GUIs
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiComplexTextEditPopup.cpp
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiDetectDevice.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiDetectDevice.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiInputConfig.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiInputConfig.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiMsgBox.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiMsgBox.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiTextEditKeyboardPopup.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiTextEditPopup.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiTextEditPopup.cpp
|
||||||
|
|
||||||
# Renderer
|
# Renderer
|
||||||
|
|
|
@ -180,6 +180,7 @@ void Settings::setDefaults()
|
||||||
mBoolMap["FavoritesStar"] = {true, true};
|
mBoolMap["FavoritesStar"] = {true, true};
|
||||||
mBoolMap["SpecialCharsASCII"] = {false, false};
|
mBoolMap["SpecialCharsASCII"] = {false, false};
|
||||||
mBoolMap["ListScrollOverlay"] = {false, false};
|
mBoolMap["ListScrollOverlay"] = {false, false};
|
||||||
|
mBoolMap["VirtualKeyboard"] = {true, true};
|
||||||
mBoolMap["FavoritesAddButton"] = {true, true};
|
mBoolMap["FavoritesAddButton"] = {true, true};
|
||||||
mBoolMap["RandomAddButton"] = {false, false};
|
mBoolMap["RandomAddButton"] = {false, false};
|
||||||
mBoolMap["GamelistFilters"] = {true, true};
|
mBoolMap["GamelistFilters"] = {true, true};
|
||||||
|
|
|
@ -1,155 +0,0 @@
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
//
|
|
||||||
// EmulationStation Desktop Edition
|
|
||||||
// GuiComplexTextEditPopup.cpp
|
|
||||||
//
|
|
||||||
// Text edit popup with a title, two text strings, a text input box and buttons
|
|
||||||
// to load the second text string and to clear the input field.
|
|
||||||
// Intended for updating settings for configuration files and similar.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "guis/GuiComplexTextEditPopup.h"
|
|
||||||
|
|
||||||
#include "Window.h"
|
|
||||||
#include "components/ButtonComponent.h"
|
|
||||||
#include "components/MenuComponent.h"
|
|
||||||
#include "components/TextEditComponent.h"
|
|
||||||
#include "guis/GuiMsgBox.h"
|
|
||||||
|
|
||||||
GuiComplexTextEditPopup::GuiComplexTextEditPopup(
|
|
||||||
Window* window,
|
|
||||||
const HelpStyle& helpstyle,
|
|
||||||
const std::string& title,
|
|
||||||
const std::string& infoString1,
|
|
||||||
const std::string& infoString2,
|
|
||||||
const std::string& initValue,
|
|
||||||
const std::function<void(const std::string&)>& okCallback,
|
|
||||||
bool multiLine,
|
|
||||||
const std::string& acceptBtnText,
|
|
||||||
const std::string& saveConfirmationText,
|
|
||||||
const std::string& loadBtnText,
|
|
||||||
const std::string& loadBtnHelpText,
|
|
||||||
const std::string& clearBtnText,
|
|
||||||
const std::string& clearBtnHelpText,
|
|
||||||
bool hideCancelButton)
|
|
||||||
: GuiComponent(window)
|
|
||||||
, mHelpStyle(helpstyle)
|
|
||||||
, mBackground(window, ":/graphics/frame.svg")
|
|
||||||
, mGrid(window, glm::ivec2{1, 5})
|
|
||||||
, mMultiLine(multiLine)
|
|
||||||
, mInitValue(initValue)
|
|
||||||
, mOkCallback(okCallback)
|
|
||||||
, mSaveConfirmationText(saveConfirmationText)
|
|
||||||
, mHideCancelButton(hideCancelButton)
|
|
||||||
{
|
|
||||||
addChild(&mBackground);
|
|
||||||
addChild(&mGrid);
|
|
||||||
|
|
||||||
mTitle = std::make_shared<TextComponent>(mWindow, Utils::String::toUpper(title),
|
|
||||||
Font::get(FONT_SIZE_MEDIUM), 0x555555FF, ALIGN_CENTER);
|
|
||||||
mInfoString1 = std::make_shared<TextComponent>(mWindow, infoString1, Font::get(FONT_SIZE_SMALL),
|
|
||||||
0x555555FF, ALIGN_CENTER);
|
|
||||||
mInfoString2 = std::make_shared<TextComponent>(mWindow, infoString2, Font::get(FONT_SIZE_SMALL),
|
|
||||||
0x555555FF, ALIGN_CENTER);
|
|
||||||
|
|
||||||
mText = std::make_shared<TextEditComponent>(mWindow);
|
|
||||||
mText->setValue(initValue);
|
|
||||||
|
|
||||||
std::vector<std::shared_ptr<ButtonComponent>> buttons;
|
|
||||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, acceptBtnText, acceptBtnText,
|
|
||||||
[this, okCallback] {
|
|
||||||
okCallback(mText->getValue());
|
|
||||||
delete this;
|
|
||||||
}));
|
|
||||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, loadBtnText, loadBtnHelpText,
|
|
||||||
[this, infoString2] {
|
|
||||||
mText->setValue(infoString2);
|
|
||||||
mText->setCursor(0);
|
|
||||||
mText->setCursor(infoString2.size());
|
|
||||||
}));
|
|
||||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, clearBtnText, clearBtnHelpText,
|
|
||||||
[this] { mText->setValue(""); }));
|
|
||||||
if (!mHideCancelButton)
|
|
||||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "CANCEL", "discard changes",
|
|
||||||
[this] { delete this; }));
|
|
||||||
|
|
||||||
mButtonGrid = makeButtonGrid(mWindow, buttons);
|
|
||||||
|
|
||||||
mGrid.setEntry(mTitle, glm::ivec2{0, 0}, false, true);
|
|
||||||
mGrid.setEntry(mInfoString1, glm::ivec2{0, 1}, false, true);
|
|
||||||
mGrid.setEntry(mInfoString2, glm::ivec2{0, 2}, false, false);
|
|
||||||
mGrid.setEntry(mText, glm::ivec2{0, 3}, true, false, glm::ivec2{1, 1},
|
|
||||||
GridFlags::BORDER_TOP | GridFlags::BORDER_BOTTOM);
|
|
||||||
mGrid.setEntry(mButtonGrid, glm::ivec2{0, 4}, true, false);
|
|
||||||
mGrid.setRowHeightPerc(1, 0.15f, true);
|
|
||||||
|
|
||||||
float textHeight = mText->getFont()->getHeight();
|
|
||||||
|
|
||||||
if (multiLine)
|
|
||||||
textHeight *= 6.0f;
|
|
||||||
|
|
||||||
// Adjust the width relative to the aspect ratio of the screen to make the GUI look coherent
|
|
||||||
// regardless of screen type. The 1.778 aspect ratio value is the 16:9 reference.
|
|
||||||
float aspectValue = 1.778f / Renderer::getScreenAspectRatio();
|
|
||||||
float infoWidth = glm::clamp(0.70f * aspectValue, 0.60f, 0.85f) * Renderer::getScreenWidth();
|
|
||||||
float windowWidth = glm::clamp(0.75f * aspectValue, 0.65f, 0.90f) * Renderer::getScreenWidth();
|
|
||||||
|
|
||||||
mText->setSize(0, textHeight);
|
|
||||||
mInfoString2->setSize(infoWidth, mInfoString2->getFont()->getHeight());
|
|
||||||
|
|
||||||
setSize(windowWidth, mTitle->getFont()->getHeight() + textHeight + mButtonGrid->getSize().y +
|
|
||||||
mButtonGrid->getSize().y * 1.85f);
|
|
||||||
setPosition((Renderer::getScreenWidth() - mSize.x) / 2.0f,
|
|
||||||
(Renderer::getScreenHeight() - mSize.y) / 2.0f);
|
|
||||||
mText->startEditing();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GuiComplexTextEditPopup::onSizeChanged()
|
|
||||||
{
|
|
||||||
mBackground.fitTo(mSize, glm::vec3{}, glm::vec2{-32.0f, -32.0f});
|
|
||||||
mText->setSize(mSize.x - 40.0f, mText->getSize().y);
|
|
||||||
|
|
||||||
// Update grid.
|
|
||||||
mGrid.setRowHeightPerc(0, mTitle->getFont()->getHeight() / mSize.y);
|
|
||||||
mGrid.setRowHeightPerc(2, mButtonGrid->getSize().y / mSize.y);
|
|
||||||
mGrid.setSize(mSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GuiComplexTextEditPopup::input(InputConfig* config, Input input)
|
|
||||||
{
|
|
||||||
if (GuiComponent::input(config, input))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (!mHideCancelButton) {
|
|
||||||
// Pressing back when not text editing closes us.
|
|
||||||
if (config->isMappedTo("b", input) && input.value) {
|
|
||||||
if (mText->getValue() != mInitValue) {
|
|
||||||
// Changes were made, ask if the user wants to save them.
|
|
||||||
mWindow->pushGui(new GuiMsgBox(
|
|
||||||
mWindow, mHelpStyle, mSaveConfirmationText, "YES",
|
|
||||||
[this] {
|
|
||||||
this->mOkCallback(mText->getValue());
|
|
||||||
delete this;
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
"NO",
|
|
||||||
[this] {
|
|
||||||
delete this;
|
|
||||||
return false;
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
delete this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<HelpPrompt> GuiComplexTextEditPopup::getHelpPrompts()
|
|
||||||
{
|
|
||||||
std::vector<HelpPrompt> prompts = mGrid.getHelpPrompts();
|
|
||||||
if (!mHideCancelButton)
|
|
||||||
prompts.push_back(HelpPrompt("b", "back"));
|
|
||||||
return prompts;
|
|
||||||
}
|
|
|
@ -1,64 +0,0 @@
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
//
|
|
||||||
// EmulationStation Desktop Edition
|
|
||||||
// GuiComplexTextEditPopup.h
|
|
||||||
//
|
|
||||||
// Text edit popup with a title, two text strings, a text input box and buttons
|
|
||||||
// to load the second text string and to clear the input field.
|
|
||||||
// Intended for updating settings for configuration files and similar.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ES_CORE_GUIS_GUI_COMPLEX_TEXT_EDIT_POPUP_H
|
|
||||||
#define ES_CORE_GUIS_GUI_COMPLEX_TEXT_EDIT_POPUP_H
|
|
||||||
|
|
||||||
#include "GuiComponent.h"
|
|
||||||
#include "components/ComponentGrid.h"
|
|
||||||
#include "components/NinePatchComponent.h"
|
|
||||||
|
|
||||||
class TextComponent;
|
|
||||||
class TextEditComponent;
|
|
||||||
|
|
||||||
class GuiComplexTextEditPopup : public GuiComponent
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
GuiComplexTextEditPopup(Window* window,
|
|
||||||
const HelpStyle& helpstyle,
|
|
||||||
const std::string& title,
|
|
||||||
const std::string& infoString1,
|
|
||||||
const std::string& infoString2,
|
|
||||||
const std::string& initValue,
|
|
||||||
const std::function<void(const std::string&)>& okCallback,
|
|
||||||
bool multiLine,
|
|
||||||
const std::string& acceptBtnText = "OK",
|
|
||||||
const std::string& saveConfirmationText = "SAVE CHANGES?",
|
|
||||||
const std::string& loadBtnText = "LOAD",
|
|
||||||
const std::string& loadBtnHelpText = "load default",
|
|
||||||
const std::string& clearBtnText = "CLEAR",
|
|
||||||
const std::string& clearBtnHelpText = "clear",
|
|
||||||
bool hideCancelButton = false);
|
|
||||||
|
|
||||||
bool input(InputConfig* config, Input input) override;
|
|
||||||
void onSizeChanged() override;
|
|
||||||
|
|
||||||
std::vector<HelpPrompt> getHelpPrompts() override;
|
|
||||||
HelpStyle getHelpStyle() override { return mHelpStyle; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
NinePatchComponent mBackground;
|
|
||||||
ComponentGrid mGrid;
|
|
||||||
|
|
||||||
std::shared_ptr<TextComponent> mTitle;
|
|
||||||
std::shared_ptr<TextComponent> mInfoString1;
|
|
||||||
std::shared_ptr<TextComponent> mInfoString2;
|
|
||||||
std::shared_ptr<TextEditComponent> mText;
|
|
||||||
std::shared_ptr<ComponentGrid> mButtonGrid;
|
|
||||||
|
|
||||||
HelpStyle mHelpStyle;
|
|
||||||
bool mMultiLine;
|
|
||||||
bool mHideCancelButton;
|
|
||||||
std::string mInitValue;
|
|
||||||
std::function<void(const std::string&)> mOkCallback;
|
|
||||||
std::string mSaveConfirmationText;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // ES_CORE_GUIS_GUI_COMPLEX_TEXT_EDIT_POPUP_H
|
|
697
es-core/src/guis/GuiTextEditKeyboardPopup.cpp
Normal file
697
es-core/src/guis/GuiTextEditKeyboardPopup.cpp
Normal file
|
@ -0,0 +1,697 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
// EmulationStation Desktop Edition
|
||||||
|
// GuiTextEditKeyboardPopup.cpp
|
||||||
|
//
|
||||||
|
// Text edit popup with a virtual keyboard.
|
||||||
|
// Has a default mode and a complex mode, both with various options passed as arguments.
|
||||||
|
//
|
||||||
|
|
||||||
|
#define KEYBOARD_WIDTH Renderer::getScreenWidth() * 0.78f
|
||||||
|
#define KEYBOARD_HEIGHT Renderer::getScreenHeight() * 0.60f
|
||||||
|
|
||||||
|
#define KEYBOARD_PADDINGX (Renderer::getScreenWidth() * 0.02f)
|
||||||
|
#define KEYBOARD_PADDINGY (Renderer::getScreenWidth() * 0.01f)
|
||||||
|
|
||||||
|
#define BUTTON_GRID_HORIZ_PADDING (10.0f * Renderer::getScreenHeightModifier())
|
||||||
|
|
||||||
|
#define NAVIGATION_REPEAT_START_DELAY 400
|
||||||
|
#define NAVIGATION_REPEAT_SPEED 70 // Lower is faster.
|
||||||
|
|
||||||
|
#define DELETE_REPEAT_START_DELAY 600
|
||||||
|
#define DELETE_REPEAT_SPEED 90 // Lower is faster.
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) // MSVC compiler.
|
||||||
|
#define DELETE_SYMBOL Utils::String::wideStringToString(L"\uf177")
|
||||||
|
#define OK_SYMBOL Utils::String::wideStringToString(L"\uf058")
|
||||||
|
#define SHIFT_SYMBOL Utils::String::wideStringToString(L"\uf176")
|
||||||
|
#define ALT_SYMBOL Utils::String::wideStringToString(L"\uf141")
|
||||||
|
#else
|
||||||
|
#define DELETE_SYMBOL "\uf177"
|
||||||
|
#define OK_SYMBOL "\uf058"
|
||||||
|
#define SHIFT_SYMBOL "\uf176"
|
||||||
|
#define ALT_SYMBOL "\uf141"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "guis/GuiTextEditKeyboardPopup.h"
|
||||||
|
|
||||||
|
#include "components/MenuComponent.h"
|
||||||
|
#include "guis/GuiMsgBox.h"
|
||||||
|
#include "utils/StringUtil.h"
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
std::vector<std::vector<const char*>> kbBaseUS{
|
||||||
|
{"1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "=", "DEL"},
|
||||||
|
{"!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "+", "DEL"},
|
||||||
|
{"¡", "²", "³", "¤", "€", "¼", "½", "¾", "‘", "’", "¥", "×", "DEL"},
|
||||||
|
{"¹", "", "", "£", "", "", "", "", "", "", "", "÷", "DEL"},
|
||||||
|
|
||||||
|
{"q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "[", "]", "OK"},
|
||||||
|
{"Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "{", "}", "OK"},
|
||||||
|
{"ä", "å", "é", "®", "þ", "ü", "ú", "í", "ó", "ö", "«", "»", "OK"},
|
||||||
|
{"Ä", "Å", "É", "", "Þ", "Ü", "Ú", "Í", "Ó", "Ö", "", "", "OK"},
|
||||||
|
|
||||||
|
{"a", "s", "d", "f", "g", "h", "j", "k", "l", ";", "'", "\\", "-rowspan-"},
|
||||||
|
{"A", "S", "D", "F", "G", "H", "J", "K", "L", ":", "\"", "|", "-rowspan-"},
|
||||||
|
{"á", "ß", "ð", "", "", "", "", "", "ø", "¶", "´", "¬", "-rowspan-"},
|
||||||
|
{"Á", "§", "Ð", "", "", "", "", "", "Ø", "°", "¨", "¦", "-rowspan-"},
|
||||||
|
|
||||||
|
{"`", "z", "x", "c", "v", "b", "n", "m", ",", ".", "/", "ALT", "-colspan-"},
|
||||||
|
{"~", "Z", "X", "C", "V", "B", "N", "M", "<", ">", "?", "ALT", "-colspan-"},
|
||||||
|
{"", "æ", "", "©", "", "", "ñ", "µ", "ç", "", "¿", "ALT", "-colspan-"},
|
||||||
|
{"", "Æ", "", "¢", "", "", "Ñ", "Μ", "Ç", "", "", "ALT", "-colspan-"}};
|
||||||
|
|
||||||
|
std::vector<std::vector<const char*>> kbLastRowNormal{
|
||||||
|
{"SHIFT", "-colspan-", "SPACE", "-colspan-", "-colspan-", "-colspan-", "-colspan-", "-colspan-", "-colspan-", "CLEAR", "-colspan-", "CANCEL", "-colspan-"},
|
||||||
|
{"SHIFT", "-colspan-", "SPACE", "-colspan-", "-colspan-", "-colspan-", "-colspan-", "-colspan-", "-colspan-", "CLEAR", "-colspan-", "CANCEL", "-colspan-"},
|
||||||
|
{"SHIFT", "-colspan-", "SPACE", "-colspan-", "-colspan-", "-colspan-", "-colspan-", "-colspan-", "-colspan-", "CLEAR", "-colspan-", "CANCEL", "-colspan-"},
|
||||||
|
{"SHIFT", "-colspan-", "SPACE", "-colspan-", "-colspan-", "-colspan-", "-colspan-", "-colspan-", "-colspan-", "CLEAR", "-colspan-", "CANCEL", "-colspan-"}};
|
||||||
|
|
||||||
|
std::vector<std::vector<const char*>> kbLastRowLoad{
|
||||||
|
{"SHIFT", "-colspan-", "SPACE", "-colspan-", "-colspan-", "-colspan-", "-colspan-", "LOAD", "-colspan-", "CLEAR", "-colspan-", "CANCEL", "-colspan-"},
|
||||||
|
{"SHIFT", "-colspan-", "SPACE", "-colspan-", "-colspan-", "-colspan-", "-colspan-", "LOAD", "-colspan-", "CLEAR", "-colspan-", "CANCEL", "-colspan-"},
|
||||||
|
{"SHIFT", "-colspan-", "SPACE", "-colspan-", "-colspan-", "-colspan-", "-colspan-", "LOAD", "-colspan-", "CLEAR", "-colspan-", "CANCEL", "-colspan-"},
|
||||||
|
{"SHIFT", "-colspan-", "SPACE", "-colspan-", "-colspan-", "-colspan-", "-colspan-", "LOAD", "-colspan-", "CLEAR", "-colspan-", "CANCEL", "-colspan-"}};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
GuiTextEditKeyboardPopup::GuiTextEditKeyboardPopup(
|
||||||
|
Window* window,
|
||||||
|
const HelpStyle& helpstyle,
|
||||||
|
const std::string& title,
|
||||||
|
const std::string& initValue,
|
||||||
|
const std::function<void(const std::string&)>& okCallback,
|
||||||
|
bool multiLine,
|
||||||
|
const std::string& acceptBtnHelpText,
|
||||||
|
const std::string& saveConfirmationText,
|
||||||
|
const std::string& infoString,
|
||||||
|
const std::string& defaultValue,
|
||||||
|
const std::string& loadBtnHelpText,
|
||||||
|
const std::string& clearBtnHelpText,
|
||||||
|
const std::string& cancelBtnHelpText)
|
||||||
|
: GuiComponent{window}
|
||||||
|
, mHelpStyle{helpstyle}
|
||||||
|
, mInitValue{initValue}
|
||||||
|
, mOkCallback{okCallback}
|
||||||
|
, mMultiLine{multiLine}
|
||||||
|
, mAcceptBtnHelpText{acceptBtnHelpText}
|
||||||
|
, mSaveConfirmationText{saveConfirmationText}
|
||||||
|
, mLoadBtnHelpText{loadBtnHelpText}
|
||||||
|
, mClearBtnHelpText{clearBtnHelpText}
|
||||||
|
, mCancelBtnHelpText{cancelBtnHelpText}
|
||||||
|
, mBackground{window, ":/graphics/frame.svg"}
|
||||||
|
, mGrid{window, glm::ivec2{1, (infoString != "" && defaultValue != "" ? 8 : 6)}}
|
||||||
|
, mComplexMode{(infoString != "" && defaultValue != "")}
|
||||||
|
, mDeleteRepeat{false}
|
||||||
|
, mShift{false}
|
||||||
|
, mAlt{false}
|
||||||
|
, mAltShift{false}
|
||||||
|
, mDeleteRepeatTimer{0}
|
||||||
|
, mNavigationRepeatTimer{0}
|
||||||
|
, mNavigationRepeatDirX{0}
|
||||||
|
, mNavigationRepeatDirY{0}
|
||||||
|
{
|
||||||
|
addChild(&mBackground);
|
||||||
|
addChild(&mGrid);
|
||||||
|
|
||||||
|
mTitle = std::make_shared<TextComponent>(mWindow, Utils::String::toUpper(title),
|
||||||
|
Font::get(FONT_SIZE_LARGE), 0x555555FF, ALIGN_CENTER);
|
||||||
|
|
||||||
|
std::vector<std::vector<const char*>> kbLayout;
|
||||||
|
|
||||||
|
// At the moment there is only the US keyboard layout available.
|
||||||
|
kbLayout.insert(kbLayout.cend(), kbBaseUS.cbegin(), kbBaseUS.cend());
|
||||||
|
|
||||||
|
// In complex mode, the last row of the keyboard contains an additional "LOAD" button.
|
||||||
|
if (mComplexMode)
|
||||||
|
kbLayout.insert(kbLayout.cend(), kbLastRowLoad.cbegin(), kbLastRowLoad.cend());
|
||||||
|
else
|
||||||
|
kbLayout.insert(kbLayout.cend(), kbLastRowNormal.cbegin(), kbLastRowNormal.cend());
|
||||||
|
|
||||||
|
mHorizontalKeyCount = static_cast<int>(kbLayout[0].size());
|
||||||
|
|
||||||
|
mKeyboardGrid = std::make_shared<ComponentGrid>(
|
||||||
|
mWindow, glm::ivec2(mHorizontalKeyCount, static_cast<int>(kbLayout.size()) / 3));
|
||||||
|
|
||||||
|
mText = std::make_shared<TextEditComponent>(mWindow);
|
||||||
|
mText->setValue(initValue);
|
||||||
|
|
||||||
|
if (!multiLine)
|
||||||
|
mText->setCursor(initValue.size());
|
||||||
|
|
||||||
|
// Header.
|
||||||
|
mGrid.setEntry(mTitle, glm::ivec2{0, 0}, false, true);
|
||||||
|
|
||||||
|
int yPos = 1;
|
||||||
|
|
||||||
|
if (mComplexMode) {
|
||||||
|
mInfoString = std::make_shared<TextComponent>(
|
||||||
|
mWindow, infoString, Font::get(FONT_SIZE_MEDIUM), 0x555555FF, ALIGN_CENTER);
|
||||||
|
mGrid.setEntry(mInfoString, glm::ivec2{0, yPos}, false, true);
|
||||||
|
|
||||||
|
mDefaultValue = std::make_shared<TextComponent>(
|
||||||
|
mWindow, defaultValue, Font::get(FONT_SIZE_SMALL), 0x555555FF, ALIGN_CENTER);
|
||||||
|
mGrid.setEntry(mDefaultValue, glm::ivec2{0, yPos + 1}, false, true);
|
||||||
|
yPos += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Text edit field.
|
||||||
|
mGrid.setEntry(mText, glm::ivec2{0, yPos}, true, false, glm::ivec2{1, 1},
|
||||||
|
GridFlags::BORDER_TOP);
|
||||||
|
|
||||||
|
std::vector<std::vector<std::shared_ptr<ButtonComponent>>> buttonList;
|
||||||
|
|
||||||
|
// Create keyboard.
|
||||||
|
for (int i = 0; i < static_cast<int>(kbLayout.size()) / 4; i++) {
|
||||||
|
std::vector<std::shared_ptr<ButtonComponent>> buttons;
|
||||||
|
|
||||||
|
for (int j = 0; j < static_cast<int>(kbLayout[i].size()); j++) {
|
||||||
|
std::string lower = kbLayout[4 * i][j];
|
||||||
|
if (lower.empty() || lower == "-rowspan-" || lower == "-colspan-")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::string upper = kbLayout[4 * i + 1][j];
|
||||||
|
std::string alted = kbLayout[4 * i + 2][j];
|
||||||
|
std::string altshifted = kbLayout[4 * i + 3][j];
|
||||||
|
|
||||||
|
std::shared_ptr<ButtonComponent> button = nullptr;
|
||||||
|
|
||||||
|
if (lower == "DEL") {
|
||||||
|
lower = DELETE_SYMBOL;
|
||||||
|
upper = DELETE_SYMBOL;
|
||||||
|
alted = DELETE_SYMBOL;
|
||||||
|
altshifted = DELETE_SYMBOL;
|
||||||
|
}
|
||||||
|
else if (lower == "OK") {
|
||||||
|
lower = OK_SYMBOL;
|
||||||
|
upper = OK_SYMBOL;
|
||||||
|
alted = OK_SYMBOL;
|
||||||
|
altshifted = OK_SYMBOL;
|
||||||
|
}
|
||||||
|
else if (lower == "SPACE") {
|
||||||
|
lower = " ";
|
||||||
|
upper = " ";
|
||||||
|
alted = " ";
|
||||||
|
altshifted = " ";
|
||||||
|
}
|
||||||
|
else if (lower != "SHIFT" && lower.length() > 1) {
|
||||||
|
lower = (lower.c_str());
|
||||||
|
upper = (upper.c_str());
|
||||||
|
alted = (alted.c_str());
|
||||||
|
altshifted = (altshifted.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lower == "SHIFT") {
|
||||||
|
mShiftButton = std::make_shared<ButtonComponent>(
|
||||||
|
mWindow, (SHIFT_SYMBOL), ("SHIFT"), [this] { shiftKeys(); }, false, true);
|
||||||
|
button = mShiftButton;
|
||||||
|
}
|
||||||
|
else if (lower == "ALT") {
|
||||||
|
mAltButton = std::make_shared<ButtonComponent>(
|
||||||
|
mWindow, (ALT_SYMBOL), ("ALT"), [this] { altKeys(); }, false, true);
|
||||||
|
button = mAltButton;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
button = makeButton(lower, upper, alted, altshifted);
|
||||||
|
}
|
||||||
|
|
||||||
|
button->setPadding(
|
||||||
|
glm::vec4(BUTTON_GRID_HORIZ_PADDING / 4.0f, BUTTON_GRID_HORIZ_PADDING / 4.0f,
|
||||||
|
BUTTON_GRID_HORIZ_PADDING / 4.0f, BUTTON_GRID_HORIZ_PADDING / 4.0f));
|
||||||
|
buttons.push_back(button);
|
||||||
|
|
||||||
|
int colSpan = 1;
|
||||||
|
for (int cs = j + 1; cs < static_cast<int>(kbLayout[i].size()); cs++) {
|
||||||
|
if (std::string(kbLayout[4 * i][cs]) == "-colspan-")
|
||||||
|
colSpan++;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rowSpan = 1;
|
||||||
|
for (int cs = (4 * i) + 4; cs < static_cast<int>(kbLayout.size()); cs += 4) {
|
||||||
|
if (std::string(kbLayout[cs][j]) == "-rowspan-")
|
||||||
|
rowSpan++;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mKeyboardGrid->setEntry(button, glm::ivec2{j, i}, true, true,
|
||||||
|
glm::ivec2{colSpan, rowSpan});
|
||||||
|
|
||||||
|
buttonList.push_back(buttons);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mGrid.setEntry(mKeyboardGrid, glm::ivec2{0, yPos + 1}, true, true, glm::ivec2{2, 4});
|
||||||
|
|
||||||
|
float textHeight = mText->getFont()->getHeight();
|
||||||
|
// If the multiLine option has been set, then include three lines of text on screen.
|
||||||
|
if (multiLine) {
|
||||||
|
textHeight *= 3.0f;
|
||||||
|
textHeight += 2.0f * Renderer::getScreenHeightModifier();
|
||||||
|
}
|
||||||
|
|
||||||
|
mText->setSize(0.0f, textHeight);
|
||||||
|
|
||||||
|
// If attempting to navigate beyond the edge of the keyboard grid, then wrap around.
|
||||||
|
mGrid.setPastBoundaryCallback([this, kbLayout](InputConfig* config, Input input) -> bool {
|
||||||
|
if (config->isMappedLike("left", input)) {
|
||||||
|
if (mGrid.getSelectedComponent() == mKeyboardGrid) {
|
||||||
|
mKeyboardGrid->moveCursorTo(mHorizontalKeyCount - 1, -1, true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (config->isMappedLike("right", input)) {
|
||||||
|
if (mGrid.getSelectedComponent() == mKeyboardGrid) {
|
||||||
|
mKeyboardGrid->moveCursorTo(0, -1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Adapt width to the geometry of the display. The 1.778 aspect ratio is the 16:9 reference.
|
||||||
|
float aspectValue = 1.778f / Renderer::getScreenAspectRatio();
|
||||||
|
float width = glm::clamp(0.78f * aspectValue, 0.35f, 0.90f) * Renderer::getScreenWidth();
|
||||||
|
|
||||||
|
// The combination of multiLine and complex mode is not supported as there is currently
|
||||||
|
// no need for that.
|
||||||
|
if (mMultiLine) {
|
||||||
|
setSize(width, KEYBOARD_HEIGHT + textHeight - mText->getFont()->getHeight());
|
||||||
|
|
||||||
|
setPosition((static_cast<float>(Renderer::getScreenWidth()) - mSize.x) / 2.0f,
|
||||||
|
(static_cast<float>(Renderer::getScreenHeight()) - mSize.y) / 2.0f);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (mComplexMode)
|
||||||
|
setSize(width, KEYBOARD_HEIGHT + mDefaultValue->getSize().y * 3.0f);
|
||||||
|
else
|
||||||
|
setSize(width, KEYBOARD_HEIGHT);
|
||||||
|
|
||||||
|
setPosition((static_cast<float>(Renderer::getScreenWidth()) - mSize.x) / 2.0f,
|
||||||
|
(static_cast<float>(Renderer::getScreenHeight()) - mSize.y) / 2.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiTextEditKeyboardPopup::onSizeChanged()
|
||||||
|
{
|
||||||
|
mBackground.fitTo(mSize, glm::vec3{}, glm::vec2{-32.0f, -32.0f});
|
||||||
|
mText->setSize(mSize.x - KEYBOARD_PADDINGX - KEYBOARD_PADDINGX, mText->getSize().y);
|
||||||
|
|
||||||
|
// Update grid.
|
||||||
|
mGrid.setRowHeightPerc(0, mTitle->getFont()->getHeight() / mSize.y);
|
||||||
|
|
||||||
|
if (mInfoString && mDefaultValue) {
|
||||||
|
mGrid.setRowHeightPerc(1, (mInfoString->getSize().y * 0.6f) / mSize.y);
|
||||||
|
mGrid.setRowHeightPerc(2, (mDefaultValue->getSize().y * 1.6f) / mSize.y);
|
||||||
|
mGrid.setRowHeightPerc(1, (mText->getSize().y * 1.0f) / mSize.y);
|
||||||
|
}
|
||||||
|
else if (mMultiLine) {
|
||||||
|
mGrid.setRowHeightPerc(1, (mText->getSize().y * 1.15f) / mSize.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
mGrid.setSize(mSize);
|
||||||
|
|
||||||
|
auto pos = mKeyboardGrid->getPosition();
|
||||||
|
auto sz = mKeyboardGrid->getSize();
|
||||||
|
|
||||||
|
// Add a small margin between buttons.
|
||||||
|
mKeyboardGrid->setSize(mSize.x - KEYBOARD_PADDINGX - KEYBOARD_PADDINGX,
|
||||||
|
sz.y - KEYBOARD_PADDINGY + 70.0f * Renderer::getScreenHeightModifier());
|
||||||
|
mKeyboardGrid->setPosition(KEYBOARD_PADDINGX, pos.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GuiTextEditKeyboardPopup::input(InputConfig* config, Input input)
|
||||||
|
{
|
||||||
|
// Enter/return key or numpad enter key accepts the changes.
|
||||||
|
if (config->getDeviceId() == DEVICE_KEYBOARD && mText->isEditing() && !mMultiLine &&
|
||||||
|
input.value && (input.id == SDLK_RETURN || input.id == SDLK_KP_ENTER)) {
|
||||||
|
this->mOkCallback(mText->getValue());
|
||||||
|
delete this;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Dito for the A button if using a controller.
|
||||||
|
else if (config->getDeviceId() != DEVICE_KEYBOARD && mText->isEditing() &&
|
||||||
|
config->isMappedTo("a", input) && input.value) {
|
||||||
|
this->mOkCallback(mText->getValue());
|
||||||
|
delete this;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the keyboard has been configured with backspace as the back button (which is the default
|
||||||
|
// configuration) then ignore this key if we're currently editing or otherwise it would be
|
||||||
|
// impossible to erase characters using this key.
|
||||||
|
bool keyboardBackspace = (config->getDeviceId() == DEVICE_KEYBOARD && mText->isEditing() &&
|
||||||
|
input.id == SDLK_BACKSPACE);
|
||||||
|
|
||||||
|
// Pressing back (or the escape key if using keyboard input) closes us.
|
||||||
|
if ((config->getDeviceId() == DEVICE_KEYBOARD && input.value && input.id == SDLK_ESCAPE) ||
|
||||||
|
(!keyboardBackspace && config->isMappedTo("b", input)) && input.value) {
|
||||||
|
if (mText->getValue() != mInitValue) {
|
||||||
|
// Changes were made, ask if the user wants to save them.
|
||||||
|
mWindow->pushGui(new GuiMsgBox(
|
||||||
|
mWindow, mHelpStyle, mSaveConfirmationText, "YES",
|
||||||
|
[this] {
|
||||||
|
this->mOkCallback(mText->getValue());
|
||||||
|
delete this;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
"NO",
|
||||||
|
[this] {
|
||||||
|
delete this;
|
||||||
|
return false;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mText->isEditing() && config->isMappedLike("down", input) && input.value) {
|
||||||
|
mText->stopEditing();
|
||||||
|
mGrid.setCursorTo(mGrid.getSelectedComponent());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Left trigger button outside text editing field toggles Shift key.
|
||||||
|
if (!mText->isEditing() && config->isMappedLike("lefttrigger", input) && input.value)
|
||||||
|
shiftKeys();
|
||||||
|
|
||||||
|
// Right trigger button outside text editing field toggles Alt key.
|
||||||
|
if (!mText->isEditing() && config->isMappedLike("righttrigger", input) && input.value)
|
||||||
|
altKeys();
|
||||||
|
|
||||||
|
// Left shoulder button deletes a character (backspace).
|
||||||
|
if (config->isMappedTo("leftshoulder", input)) {
|
||||||
|
if (input.value) {
|
||||||
|
mDeleteRepeat = true;
|
||||||
|
mDeleteRepeatTimer = -(DELETE_REPEAT_START_DELAY - DELETE_REPEAT_SPEED);
|
||||||
|
|
||||||
|
bool editing = mText->isEditing();
|
||||||
|
if (!editing)
|
||||||
|
mText->startEditing();
|
||||||
|
|
||||||
|
mText->textInput("\b");
|
||||||
|
|
||||||
|
if (!editing)
|
||||||
|
mText->stopEditing();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mDeleteRepeat = false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Right shoulder button inserts a blank space.
|
||||||
|
if (config->isMappedTo("rightshoulder", input) && input.value) {
|
||||||
|
bool editing = mText->isEditing();
|
||||||
|
if (!editing)
|
||||||
|
mText->startEditing();
|
||||||
|
|
||||||
|
mText->textInput(" ");
|
||||||
|
|
||||||
|
if (!editing)
|
||||||
|
mText->stopEditing();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actual navigation of the keyboard grid is done in ComponentGrid, this code only handles
|
||||||
|
// key repeat while holding the left/right/up/down buttons.
|
||||||
|
if (!mText->isEditing() && config->isMappedLike("left", input)) {
|
||||||
|
if (input.value) {
|
||||||
|
mNavigationRepeatDirX = -1;
|
||||||
|
mNavigationRepeatTimer = -(NAVIGATION_REPEAT_START_DELAY - NAVIGATION_REPEAT_SPEED);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mNavigationRepeatDirX = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mText->isEditing() && config->isMappedLike("right", input)) {
|
||||||
|
if (input.value) {
|
||||||
|
mNavigationRepeatDirX = 1;
|
||||||
|
mNavigationRepeatTimer = -(NAVIGATION_REPEAT_START_DELAY - NAVIGATION_REPEAT_SPEED);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mNavigationRepeatDirX = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mText->isEditing() && config->isMappedLike("up", input)) {
|
||||||
|
if (input.value) {
|
||||||
|
mNavigationRepeatDirY = -1;
|
||||||
|
mNavigationRepeatTimer = -(NAVIGATION_REPEAT_START_DELAY - NAVIGATION_REPEAT_SPEED);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mNavigationRepeatDirY = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mText->isEditing() && config->isMappedLike("down", input)) {
|
||||||
|
if (input.value) {
|
||||||
|
mNavigationRepeatDirY = 1;
|
||||||
|
mNavigationRepeatTimer = -(NAVIGATION_REPEAT_START_DELAY - NAVIGATION_REPEAT_SPEED);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mNavigationRepeatDirY = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GuiComponent::input(config, input))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiTextEditKeyboardPopup::update(int deltaTime)
|
||||||
|
{
|
||||||
|
updateNavigationRepeat(deltaTime);
|
||||||
|
updateDeleteRepeat(deltaTime);
|
||||||
|
GuiComponent::update(deltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<HelpPrompt> GuiTextEditKeyboardPopup::getHelpPrompts()
|
||||||
|
{
|
||||||
|
std::vector<HelpPrompt> prompts = mGrid.getHelpPrompts();
|
||||||
|
|
||||||
|
if (!mText->isEditing()) {
|
||||||
|
prompts.push_back(HelpPrompt("lt", "shift"));
|
||||||
|
prompts.push_back(HelpPrompt("rt", "alt"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
prompts.push_back(HelpPrompt("a", mAcceptBtnHelpText));
|
||||||
|
}
|
||||||
|
|
||||||
|
prompts.push_back(HelpPrompt("l", "backspace"));
|
||||||
|
prompts.push_back(HelpPrompt("r", "space"));
|
||||||
|
prompts.push_back(HelpPrompt("b", "back"));
|
||||||
|
|
||||||
|
if (prompts.size() > 0 && prompts.front().second == OK_SYMBOL)
|
||||||
|
prompts.front().second = mAcceptBtnHelpText;
|
||||||
|
|
||||||
|
if (prompts.size() > 0 && prompts.front().second == " ")
|
||||||
|
prompts.front().second = "SPACE";
|
||||||
|
|
||||||
|
if (prompts.size() > 0 && prompts.front().second == "CLEAR")
|
||||||
|
prompts.front().second = mClearBtnHelpText;
|
||||||
|
|
||||||
|
if (prompts.size() > 0 && prompts.front().second == "LOAD")
|
||||||
|
prompts.front().second = mLoadBtnHelpText;
|
||||||
|
|
||||||
|
if (prompts.size() > 0 && prompts.front().second == "CANCEL")
|
||||||
|
prompts.front().second = mCancelBtnHelpText;
|
||||||
|
|
||||||
|
// If a prompt has no value set, then remove it.
|
||||||
|
if (prompts.size() > 0 && prompts.front().second == "")
|
||||||
|
prompts.erase(prompts.begin(), prompts.begin() + 1);
|
||||||
|
|
||||||
|
return prompts;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiTextEditKeyboardPopup::updateDeleteRepeat(int deltaTime)
|
||||||
|
{
|
||||||
|
if (!mDeleteRepeat)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mDeleteRepeatTimer += deltaTime;
|
||||||
|
|
||||||
|
while (mDeleteRepeatTimer >= DELETE_REPEAT_SPEED) {
|
||||||
|
bool editing = mText->isEditing();
|
||||||
|
if (!editing)
|
||||||
|
mText->startEditing();
|
||||||
|
|
||||||
|
mText->textInput("\b");
|
||||||
|
|
||||||
|
if (!editing)
|
||||||
|
mText->stopEditing();
|
||||||
|
|
||||||
|
mDeleteRepeatTimer -= DELETE_REPEAT_SPEED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiTextEditKeyboardPopup::updateNavigationRepeat(int deltaTime)
|
||||||
|
{
|
||||||
|
if (mNavigationRepeatDirX == 0 && mNavigationRepeatDirY == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mNavigationRepeatTimer += deltaTime;
|
||||||
|
|
||||||
|
while (mNavigationRepeatTimer >= NAVIGATION_REPEAT_SPEED) {
|
||||||
|
|
||||||
|
if (mNavigationRepeatDirX != 0) {
|
||||||
|
mKeyboardGrid.get()->moveCursor({mNavigationRepeatDirX, 0});
|
||||||
|
// If replacing the line above with this code, the keyboard will wrap around the
|
||||||
|
// edges also when key repeat is active.
|
||||||
|
// if (!mKeyboardGrid.get()->moveCursor({mNavigationRepeatDirX, 0})) {
|
||||||
|
// if (mNavigationRepeatDirX < 0)
|
||||||
|
// mKeyboardGrid->moveCursorTo(mHorizontalKeyCount - 1, -1);
|
||||||
|
// else
|
||||||
|
// mKeyboardGrid->moveCursorTo(0, -1);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mNavigationRepeatDirY != 0)
|
||||||
|
mKeyboardGrid.get()->moveCursor({0, mNavigationRepeatDirY});
|
||||||
|
|
||||||
|
mNavigationRepeatTimer -= NAVIGATION_REPEAT_SPEED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiTextEditKeyboardPopup::shiftKeys()
|
||||||
|
{
|
||||||
|
mShift = !mShift;
|
||||||
|
|
||||||
|
if (mShift) {
|
||||||
|
mShiftButton->setFlatColorFocused(0xFF2222FF);
|
||||||
|
mShiftButton->setFlatColorUnfocused(0xFF2222FF);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mShiftButton->setFlatColorFocused(0x878787FF);
|
||||||
|
mShiftButton->setFlatColorUnfocused(0x60606025);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mAlt && mShift) {
|
||||||
|
altShiftKeys();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This only happens when Alt was deselected while both Shift and Alt were active.
|
||||||
|
if (mAlt) {
|
||||||
|
altKeys();
|
||||||
|
altKeys();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (auto& kb : mKeyboardButtons) {
|
||||||
|
const std::string& text = mShift ? kb.shiftedKey : kb.key;
|
||||||
|
auto sz = kb.button->getSize();
|
||||||
|
kb.button->setText(text, text, false);
|
||||||
|
kb.button->setSize(sz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiTextEditKeyboardPopup::altKeys()
|
||||||
|
{
|
||||||
|
mAlt = !mAlt;
|
||||||
|
|
||||||
|
if (mAlt) {
|
||||||
|
mAltButton->setFlatColorFocused(0xFF2222FF);
|
||||||
|
mAltButton->setFlatColorUnfocused(0xFF2222FF);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mAltButton->setFlatColorFocused(0x878787FF);
|
||||||
|
mAltButton->setFlatColorUnfocused(0x60606025);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mShift && mAlt) {
|
||||||
|
altShiftKeys();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This only happens when Shift was deselected while both Shift and Alt were active.
|
||||||
|
if (mShift) {
|
||||||
|
shiftKeys();
|
||||||
|
shiftKeys();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (auto& kb : mKeyboardButtons) {
|
||||||
|
const std::string& text = mAlt ? kb.altedKey : kb.key;
|
||||||
|
auto sz = kb.button->getSize();
|
||||||
|
kb.button->setText(text, text, false);
|
||||||
|
kb.button->setSize(sz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiTextEditKeyboardPopup::altShiftKeys()
|
||||||
|
{
|
||||||
|
for (auto& kb : mKeyboardButtons) {
|
||||||
|
const std::string& text = kb.altshiftedKey;
|
||||||
|
auto sz = kb.button->getSize();
|
||||||
|
kb.button->setText(text, text, false);
|
||||||
|
kb.button->setSize(sz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<ButtonComponent> GuiTextEditKeyboardPopup::makeButton(
|
||||||
|
const std::string& key,
|
||||||
|
const std::string& shiftedKey,
|
||||||
|
const std::string& altedKey,
|
||||||
|
const std::string& altshiftedKey)
|
||||||
|
{
|
||||||
|
std::shared_ptr<ButtonComponent> button = std::make_shared<ButtonComponent>(
|
||||||
|
mWindow, key, key,
|
||||||
|
[this, key, shiftedKey, altedKey, altshiftedKey] {
|
||||||
|
if (key == (OK_SYMBOL) || key.find("OK") != std::string::npos) {
|
||||||
|
mOkCallback(mText->getValue());
|
||||||
|
delete this;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (key == (DELETE_SYMBOL) || key == "DEL") {
|
||||||
|
mText->startEditing();
|
||||||
|
mText->textInput("\b");
|
||||||
|
mText->stopEditing();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (key == "SPACE" || key == " ") {
|
||||||
|
mText->startEditing();
|
||||||
|
mText->textInput(" ");
|
||||||
|
mText->stopEditing();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (key == "LOAD") {
|
||||||
|
mText->setValue(mDefaultValue->getValue());
|
||||||
|
mText->setCursor(mDefaultValue->getValue().size());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (key == "CLEAR") {
|
||||||
|
mText->setValue("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (key == "CANCEL") {
|
||||||
|
delete this;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mAlt && altedKey.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
mText->startEditing();
|
||||||
|
|
||||||
|
if (mShift && mAlt)
|
||||||
|
mText->textInput(altshiftedKey.c_str());
|
||||||
|
else if (mAlt)
|
||||||
|
mText->textInput(altedKey.c_str());
|
||||||
|
else if (mShift)
|
||||||
|
mText->textInput(shiftedKey.c_str());
|
||||||
|
else
|
||||||
|
mText->textInput(key.c_str());
|
||||||
|
|
||||||
|
mText->stopEditing();
|
||||||
|
},
|
||||||
|
false, true);
|
||||||
|
|
||||||
|
KeyboardButton kb(button, key, shiftedKey, altedKey, altshiftedKey);
|
||||||
|
mKeyboardButtons.push_back(kb);
|
||||||
|
return button;
|
||||||
|
}
|
112
es-core/src/guis/GuiTextEditKeyboardPopup.h
Normal file
112
es-core/src/guis/GuiTextEditKeyboardPopup.h
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
// EmulationStation Desktop Edition
|
||||||
|
// GuiTextEditKeyboardPopup.h
|
||||||
|
//
|
||||||
|
// Text edit popup with a virtual keyboard.
|
||||||
|
// Has a default mode and a complex mode, both with various options passed as arguments.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef ES_CORE_GUIS_GUI_TEXT_EDIT_KEYBOARD_POPUP_H
|
||||||
|
#define ES_CORE_GUIS_GUI_TEXT_EDIT_KEYBOARD_POPUP_H
|
||||||
|
|
||||||
|
#include "GuiComponent.h"
|
||||||
|
#include "components/ButtonComponent.h"
|
||||||
|
#include "components/ComponentGrid.h"
|
||||||
|
#include "components/TextEditComponent.h"
|
||||||
|
|
||||||
|
class GuiTextEditKeyboardPopup : public GuiComponent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GuiTextEditKeyboardPopup(Window* window,
|
||||||
|
const HelpStyle& helpstyle,
|
||||||
|
const std::string& title,
|
||||||
|
const std::string& initValue,
|
||||||
|
const std::function<void(const std::string&)>& okCallback,
|
||||||
|
bool multiLine,
|
||||||
|
const std::string& acceptBtnHelpText = "OK",
|
||||||
|
const std::string& saveConfirmationText = "SAVE CHANGES?",
|
||||||
|
const std::string& infoString = "",
|
||||||
|
const std::string& defaultValue = "",
|
||||||
|
const std::string& loadBtnHelpText = "LOAD DEFAULT",
|
||||||
|
const std::string& clearBtnHelpText = "CLEAR",
|
||||||
|
const std::string& cancelBtnHelpText = "DISCARD CHANGES");
|
||||||
|
|
||||||
|
void onSizeChanged();
|
||||||
|
bool input(InputConfig* config, Input input);
|
||||||
|
void update(int deltaTime) override;
|
||||||
|
|
||||||
|
std::vector<HelpPrompt> getHelpPrompts() override;
|
||||||
|
HelpStyle getHelpStyle() override { return mHelpStyle; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
class KeyboardButton
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::shared_ptr<ButtonComponent> button;
|
||||||
|
const std::string key;
|
||||||
|
const std::string shiftedKey;
|
||||||
|
const std::string altedKey;
|
||||||
|
const std::string altshiftedKey;
|
||||||
|
KeyboardButton(const std::shared_ptr<ButtonComponent> b,
|
||||||
|
const std::string& k,
|
||||||
|
const std::string& sk,
|
||||||
|
const std::string& ak,
|
||||||
|
const std::string& ask)
|
||||||
|
: button{b}
|
||||||
|
, key{k}
|
||||||
|
, shiftedKey{sk}
|
||||||
|
, altedKey{ak}
|
||||||
|
, altshiftedKey{ask} {};
|
||||||
|
};
|
||||||
|
|
||||||
|
void updateDeleteRepeat(int deltaTime);
|
||||||
|
void updateNavigationRepeat(int deltaTime);
|
||||||
|
|
||||||
|
void shiftKeys();
|
||||||
|
void altKeys();
|
||||||
|
void altShiftKeys();
|
||||||
|
|
||||||
|
std::shared_ptr<ButtonComponent> makeButton(const std::string& key,
|
||||||
|
const std::string& shiftedKey,
|
||||||
|
const std::string& altedKey,
|
||||||
|
const std::string& altshiftedKey);
|
||||||
|
std::vector<KeyboardButton> mKeyboardButtons;
|
||||||
|
|
||||||
|
std::shared_ptr<ButtonComponent> mShiftButton;
|
||||||
|
std::shared_ptr<ButtonComponent> mAltButton;
|
||||||
|
|
||||||
|
NinePatchComponent mBackground;
|
||||||
|
ComponentGrid mGrid;
|
||||||
|
HelpStyle mHelpStyle;
|
||||||
|
|
||||||
|
std::shared_ptr<TextComponent> mTitle;
|
||||||
|
std::shared_ptr<TextComponent> mInfoString;
|
||||||
|
std::shared_ptr<TextComponent> mDefaultValue;
|
||||||
|
std::shared_ptr<TextEditComponent> mText;
|
||||||
|
std::shared_ptr<ComponentGrid> mKeyboardGrid;
|
||||||
|
|
||||||
|
std::string mInitValue;
|
||||||
|
std::string mAcceptBtnHelpText;
|
||||||
|
std::string mSaveConfirmationText;
|
||||||
|
std::string mLoadBtnHelpText;
|
||||||
|
std::string mClearBtnHelpText;
|
||||||
|
std::string mCancelBtnHelpText;
|
||||||
|
|
||||||
|
std::function<void(const std::string&)> mOkCallback;
|
||||||
|
|
||||||
|
bool mMultiLine;
|
||||||
|
bool mComplexMode;
|
||||||
|
bool mDeleteRepeat;
|
||||||
|
bool mShift;
|
||||||
|
bool mAlt;
|
||||||
|
bool mAltShift;
|
||||||
|
|
||||||
|
int mHorizontalKeyCount;
|
||||||
|
int mDeleteRepeatTimer;
|
||||||
|
int mNavigationRepeatTimer;
|
||||||
|
int mNavigationRepeatDirX;
|
||||||
|
int mNavigationRepeatDirY;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ES_CORE_GUIS_GUI_TEXT_EDIT_KEYBOARD_POPUP_H
|
|
@ -3,15 +3,16 @@
|
||||||
// EmulationStation Desktop Edition
|
// EmulationStation Desktop Edition
|
||||||
// GuiTextEditPopup.cpp
|
// GuiTextEditPopup.cpp
|
||||||
//
|
//
|
||||||
// Simple text edit popup with a title, a text input box and OK and Cancel buttons.
|
// Text edit popup.
|
||||||
|
// Has a default mode and a complex mode, both with various options passed as arguments.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#define DELETE_REPEAT_START_DELAY 600
|
||||||
|
#define DELETE_REPEAT_SPEED 90 // Lower is faster.
|
||||||
|
|
||||||
#include "guis/GuiTextEditPopup.h"
|
#include "guis/GuiTextEditPopup.h"
|
||||||
|
|
||||||
#include "Window.h"
|
|
||||||
#include "components/ButtonComponent.h"
|
|
||||||
#include "components/MenuComponent.h"
|
#include "components/MenuComponent.h"
|
||||||
#include "components/TextEditComponent.h"
|
|
||||||
#include "guis/GuiMsgBox.h"
|
#include "guis/GuiMsgBox.h"
|
||||||
|
|
||||||
GuiTextEditPopup::GuiTextEditPopup(Window* window,
|
GuiTextEditPopup::GuiTextEditPopup(Window* window,
|
||||||
|
@ -21,15 +22,27 @@ GuiTextEditPopup::GuiTextEditPopup(Window* window,
|
||||||
const std::function<void(const std::string&)>& okCallback,
|
const std::function<void(const std::string&)>& okCallback,
|
||||||
bool multiLine,
|
bool multiLine,
|
||||||
const std::string& acceptBtnText,
|
const std::string& acceptBtnText,
|
||||||
const std::string& saveConfirmationText)
|
const std::string& saveConfirmationText,
|
||||||
: GuiComponent(window)
|
const std::string& infoString,
|
||||||
, mHelpStyle(helpstyle)
|
const std::string& defaultValue,
|
||||||
, mBackground(window, ":/graphics/frame.svg")
|
const std::string& loadBtnHelpText,
|
||||||
, mGrid(window, glm::ivec2{1, 3})
|
const std::string& clearBtnHelpText,
|
||||||
, mMultiLine(multiLine)
|
const std::string& cancelBtnHelpText)
|
||||||
, mInitValue(initValue)
|
: GuiComponent{window}
|
||||||
, mOkCallback(okCallback)
|
, mHelpStyle{helpstyle}
|
||||||
, mSaveConfirmationText(saveConfirmationText)
|
, mInitValue{initValue}
|
||||||
|
, mOkCallback{okCallback}
|
||||||
|
, mMultiLine{multiLine}
|
||||||
|
, mAcceptBtnText{acceptBtnText}
|
||||||
|
, mSaveConfirmationText{saveConfirmationText}
|
||||||
|
, mLoadBtnHelpText{loadBtnHelpText}
|
||||||
|
, mClearBtnHelpText{clearBtnHelpText}
|
||||||
|
, mCancelBtnHelpText{cancelBtnHelpText}
|
||||||
|
, mBackground{window, ":/graphics/frame.svg"}
|
||||||
|
, mGrid{window, glm::ivec2{1, (infoString != "" && defaultValue != "" ? 5 : 3)}}
|
||||||
|
, mComplexMode{(infoString != "" && defaultValue != "")}
|
||||||
|
, mDeleteRepeat{false}
|
||||||
|
, mDeleteRepeatTimer{0}
|
||||||
{
|
{
|
||||||
addChild(&mBackground);
|
addChild(&mBackground);
|
||||||
addChild(&mGrid);
|
addChild(&mGrid);
|
||||||
|
@ -37,6 +50,13 @@ GuiTextEditPopup::GuiTextEditPopup(Window* window,
|
||||||
mTitle = std::make_shared<TextComponent>(mWindow, Utils::String::toUpper(title),
|
mTitle = std::make_shared<TextComponent>(mWindow, Utils::String::toUpper(title),
|
||||||
Font::get(FONT_SIZE_MEDIUM), 0x555555FF, ALIGN_CENTER);
|
Font::get(FONT_SIZE_MEDIUM), 0x555555FF, ALIGN_CENTER);
|
||||||
|
|
||||||
|
if (mComplexMode) {
|
||||||
|
mInfoString = std::make_shared<TextComponent>(
|
||||||
|
mWindow, infoString, Font::get(FONT_SIZE_SMALL), 0x555555FF, ALIGN_CENTER);
|
||||||
|
mDefaultValue = std::make_shared<TextComponent>(
|
||||||
|
mWindow, defaultValue, Font::get(FONT_SIZE_SMALL), 0x555555FF, ALIGN_CENTER);
|
||||||
|
}
|
||||||
|
|
||||||
mText = std::make_shared<TextEditComponent>(mWindow);
|
mText = std::make_shared<TextEditComponent>(mWindow);
|
||||||
mText->setValue(initValue);
|
mText->setValue(initValue);
|
||||||
|
|
||||||
|
@ -46,55 +66,116 @@ GuiTextEditPopup::GuiTextEditPopup(Window* window,
|
||||||
okCallback(mText->getValue());
|
okCallback(mText->getValue());
|
||||||
delete this;
|
delete this;
|
||||||
}));
|
}));
|
||||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "CLEAR", "clear",
|
if (mComplexMode) {
|
||||||
|
buttons.push_back(std::make_shared<ButtonComponent>(
|
||||||
|
mWindow, "load", loadBtnHelpText, [this, defaultValue] {
|
||||||
|
mText->setValue(defaultValue);
|
||||||
|
mText->setCursor(0);
|
||||||
|
mText->setCursor(defaultValue.size());
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "clear", clearBtnHelpText,
|
||||||
[this] { mText->setValue(""); }));
|
[this] { mText->setValue(""); }));
|
||||||
|
|
||||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "CANCEL", "discard changes",
|
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "CANCEL", "discard changes",
|
||||||
[this] { delete this; }));
|
[this] { delete this; }));
|
||||||
|
|
||||||
mButtonGrid = makeButtonGrid(mWindow, buttons);
|
mButtonGrid = makeButtonGrid(mWindow, buttons);
|
||||||
|
|
||||||
mGrid.setEntry(mTitle, glm::ivec2{0, 0}, false, true);
|
mGrid.setEntry(mTitle, glm::ivec2{0, 0}, false, true);
|
||||||
mGrid.setEntry(mText, glm::ivec2{0, 1}, true, false, glm::ivec2{1, 1},
|
|
||||||
|
int yPos = 1;
|
||||||
|
|
||||||
|
if (mComplexMode) {
|
||||||
|
mGrid.setEntry(mInfoString, glm::ivec2{0, yPos}, false, true);
|
||||||
|
mGrid.setEntry(mDefaultValue, glm::ivec2{0, yPos + 1}, false, false);
|
||||||
|
yPos += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
mGrid.setEntry(mText, glm::ivec2{0, yPos}, true, false, glm::ivec2{1, 1},
|
||||||
GridFlags::BORDER_TOP | GridFlags::BORDER_BOTTOM);
|
GridFlags::BORDER_TOP | GridFlags::BORDER_BOTTOM);
|
||||||
mGrid.setEntry(mButtonGrid, glm::ivec2{0, 2}, true, false);
|
mGrid.setEntry(mButtonGrid, glm::ivec2{0, yPos + 1}, true, false);
|
||||||
|
|
||||||
float textHeight = mText->getFont()->getHeight();
|
float textHeight = mText->getFont()->getHeight();
|
||||||
|
|
||||||
if (multiLine)
|
if (multiLine)
|
||||||
textHeight *= 6.0f;
|
textHeight *= 6.0f;
|
||||||
|
|
||||||
mText->setSize(0, textHeight);
|
mText->setSize(0, textHeight);
|
||||||
|
|
||||||
// Adjust the width relative to the aspect ratio of the screen to make the GUI look coherent
|
// Adapt width to the geometry of the display. The 1.778 aspect ratio is the 16:9 reference.
|
||||||
// regardless of screen type. The 1.778 aspect ratio value is the 16:9 reference.
|
|
||||||
float aspectValue = 1.778f / Renderer::getScreenAspectRatio();
|
float aspectValue = 1.778f / Renderer::getScreenAspectRatio();
|
||||||
float width = glm::clamp(0.50f * aspectValue, 0.40f, 0.70f) * Renderer::getScreenWidth();
|
|
||||||
|
if (mComplexMode) {
|
||||||
|
float infoWidth =
|
||||||
|
glm::clamp(0.70f * aspectValue, 0.34f, 0.85f) * Renderer::getScreenWidth();
|
||||||
|
float windowWidth =
|
||||||
|
glm::clamp(0.75f * aspectValue, 0.40f, 0.90f) * Renderer::getScreenWidth();
|
||||||
|
|
||||||
|
mDefaultValue->setSize(infoWidth, mDefaultValue->getFont()->getHeight());
|
||||||
|
|
||||||
|
setSize(windowWidth, mTitle->getFont()->getHeight() + textHeight +
|
||||||
|
mButtonGrid->getSize().y + mButtonGrid->getSize().y * 1.85f);
|
||||||
|
setPosition((Renderer::getScreenWidth() - mSize.x) / 2.0f,
|
||||||
|
(Renderer::getScreenHeight() - mSize.y) / 2.0f);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
float width = glm::clamp(0.54f * aspectValue, 0.20f, 0.70f) * Renderer::getScreenWidth();
|
||||||
|
|
||||||
setSize(width, mTitle->getFont()->getHeight() + textHeight + mButtonGrid->getSize().y +
|
setSize(width, mTitle->getFont()->getHeight() + textHeight + mButtonGrid->getSize().y +
|
||||||
mButtonGrid->getSize().y / 2.0f);
|
mButtonGrid->getSize().y / 2.0f);
|
||||||
setPosition((Renderer::getScreenWidth() - mSize.x) / 2.0f,
|
setPosition((Renderer::getScreenWidth() - mSize.x) / 2.0f,
|
||||||
(Renderer::getScreenHeight() - mSize.y) / 2.0f);
|
(Renderer::getScreenHeight() - mSize.y) / 2.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!multiLine)
|
||||||
|
mText->setCursor(initValue.size());
|
||||||
|
|
||||||
mText->startEditing();
|
mText->startEditing();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiTextEditPopup::onSizeChanged()
|
void GuiTextEditPopup::onSizeChanged()
|
||||||
{
|
{
|
||||||
mBackground.fitTo(mSize, glm::vec3{}, glm::vec2{-32.0f, -32.0f});
|
mBackground.fitTo(mSize, glm::vec3{}, glm::vec2{-32.0f, -32.0f});
|
||||||
|
mText->setSize(mSize.x - 40.0f * Renderer::getScreenHeightModifier(), mText->getSize().y);
|
||||||
mText->setSize(mSize.x - 40.0f, mText->getSize().y);
|
|
||||||
|
|
||||||
// Update grid.
|
// Update grid.
|
||||||
mGrid.setRowHeightPerc(0, mTitle->getFont()->getHeight() / mSize.y);
|
mGrid.setRowHeightPerc(0, mTitle->getFont()->getHeight() / mSize.y);
|
||||||
|
|
||||||
|
if (mComplexMode)
|
||||||
|
mGrid.setRowHeightPerc(1, 0.15f);
|
||||||
|
|
||||||
mGrid.setRowHeightPerc(2, mButtonGrid->getSize().y / mSize.y);
|
mGrid.setRowHeightPerc(2, mButtonGrid->getSize().y / mSize.y);
|
||||||
mGrid.setSize(mSize);
|
mGrid.setSize(mSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GuiTextEditPopup::input(InputConfig* config, Input input)
|
bool GuiTextEditPopup::input(InputConfig* config, Input input)
|
||||||
{
|
{
|
||||||
if (GuiComponent::input(config, input))
|
// Enter key (main key or via numpad) accepts the changes.
|
||||||
|
if (config->getDeviceId() == DEVICE_KEYBOARD && mText->isEditing() && !mMultiLine &&
|
||||||
|
input.value && (input.id == SDLK_RETURN || input.id == SDLK_KP_ENTER)) {
|
||||||
|
this->mOkCallback(mText->getValue());
|
||||||
|
delete this;
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
// Dito for the A button if using a controller.
|
||||||
|
else if (config->getDeviceId() != DEVICE_KEYBOARD && mText->isEditing() &&
|
||||||
|
config->isMappedTo("a", input) && input.value) {
|
||||||
|
this->mOkCallback(mText->getValue());
|
||||||
|
delete this;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Pressing back when not text editing closes us.
|
// If the keyboard has been configured with backspace as the back button (which is the default
|
||||||
if (config->isMappedTo("b", input) && input.value) {
|
// configuration) then ignore this key if we're currently editing or otherwise it would be
|
||||||
|
// impossible to erase characters using this key.
|
||||||
|
bool keyboardBackspace = (config->getDeviceId() == DEVICE_KEYBOARD && mText->isEditing() &&
|
||||||
|
input.id == SDLK_BACKSPACE);
|
||||||
|
|
||||||
|
// Pressing back (or the escape key if using keyboard input) closes us.
|
||||||
|
if ((config->getDeviceId() == DEVICE_KEYBOARD && input.value && input.id == SDLK_ESCAPE) ||
|
||||||
|
(!keyboardBackspace && config->isMappedTo("b", input)) && input.value) {
|
||||||
if (mText->getValue() != mInitValue) {
|
if (mText->getValue() != mInitValue) {
|
||||||
// Changes were made, ask if the user wants to save them.
|
// Changes were made, ask if the user wants to save them.
|
||||||
mWindow->pushGui(new GuiMsgBox(
|
mWindow->pushGui(new GuiMsgBox(
|
||||||
|
@ -114,12 +195,89 @@ bool GuiTextEditPopup::input(InputConfig* config, Input input)
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mText->isEditing() && config->isMappedLike("down", input) && input.value) {
|
||||||
|
mText->stopEditing();
|
||||||
|
mGrid.setCursorTo(mGrid.getSelectedComponent());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Left shoulder button deletes a character (backspace).
|
||||||
|
if (config->isMappedTo("leftshoulder", input)) {
|
||||||
|
if (input.value) {
|
||||||
|
mDeleteRepeat = true;
|
||||||
|
mDeleteRepeatTimer = -(DELETE_REPEAT_START_DELAY - DELETE_REPEAT_SPEED);
|
||||||
|
|
||||||
|
bool editing = mText->isEditing();
|
||||||
|
if (!editing)
|
||||||
|
mText->startEditing();
|
||||||
|
|
||||||
|
mText->textInput("\b");
|
||||||
|
|
||||||
|
if (!editing)
|
||||||
|
mText->stopEditing();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mDeleteRepeat = false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Right shoulder button inserts a blank space.
|
||||||
|
if (config->isMappedTo("rightshoulder", input) && input.value) {
|
||||||
|
bool editing = mText->isEditing();
|
||||||
|
if (!editing)
|
||||||
|
mText->startEditing();
|
||||||
|
|
||||||
|
mText->textInput(" ");
|
||||||
|
|
||||||
|
if (!editing)
|
||||||
|
mText->stopEditing();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GuiComponent::input(config, input))
|
||||||
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GuiTextEditPopup::update(int deltaTime)
|
||||||
|
{
|
||||||
|
updateDeleteRepeat(deltaTime);
|
||||||
|
GuiComponent::update(deltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<HelpPrompt> GuiTextEditPopup::getHelpPrompts()
|
std::vector<HelpPrompt> GuiTextEditPopup::getHelpPrompts()
|
||||||
{
|
{
|
||||||
std::vector<HelpPrompt> prompts = mGrid.getHelpPrompts();
|
std::vector<HelpPrompt> prompts = mGrid.getHelpPrompts();
|
||||||
|
|
||||||
|
if (mText->isEditing())
|
||||||
|
prompts.push_back(HelpPrompt("a", mAcceptBtnText));
|
||||||
|
|
||||||
|
prompts.push_back(HelpPrompt("l", "backspace"));
|
||||||
|
prompts.push_back(HelpPrompt("r", "space"));
|
||||||
prompts.push_back(HelpPrompt("b", "back"));
|
prompts.push_back(HelpPrompt("b", "back"));
|
||||||
return prompts;
|
return prompts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GuiTextEditPopup::updateDeleteRepeat(int deltaTime)
|
||||||
|
{
|
||||||
|
if (!mDeleteRepeat)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mDeleteRepeatTimer += deltaTime;
|
||||||
|
|
||||||
|
while (mDeleteRepeatTimer >= DELETE_REPEAT_SPEED) {
|
||||||
|
bool editing = mText->isEditing();
|
||||||
|
if (!editing)
|
||||||
|
mText->startEditing();
|
||||||
|
|
||||||
|
mText->textInput("\b");
|
||||||
|
|
||||||
|
if (!editing)
|
||||||
|
mText->stopEditing();
|
||||||
|
|
||||||
|
mDeleteRepeatTimer -= DELETE_REPEAT_SPEED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -3,18 +3,17 @@
|
||||||
// EmulationStation Desktop Edition
|
// EmulationStation Desktop Edition
|
||||||
// GuiTextEditPopup.h
|
// GuiTextEditPopup.h
|
||||||
//
|
//
|
||||||
// Simple text edit popup with a title, a text input box and OK and Cancel buttons.
|
// Text edit popup.
|
||||||
|
// Has a default mode and a complex mode, both with various options passed as arguments.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef ES_CORE_GUIS_GUI_TEXT_EDIT_POPUP_H
|
#ifndef ES_CORE_GUIS_GUI_TEXT_EDIT_POPUP_H
|
||||||
#define ES_CORE_GUIS_GUI_TEXT_EDIT_POPUP_H
|
#define ES_CORE_GUIS_GUI_TEXT_EDIT_POPUP_H
|
||||||
|
|
||||||
#include "GuiComponent.h"
|
#include "GuiComponent.h"
|
||||||
|
#include "components/ButtonComponent.h"
|
||||||
#include "components/ComponentGrid.h"
|
#include "components/ComponentGrid.h"
|
||||||
#include "components/NinePatchComponent.h"
|
#include "components/TextEditComponent.h"
|
||||||
|
|
||||||
class TextComponent;
|
|
||||||
class TextEditComponent;
|
|
||||||
|
|
||||||
class GuiTextEditPopup : public GuiComponent
|
class GuiTextEditPopup : public GuiComponent
|
||||||
{
|
{
|
||||||
|
@ -26,27 +25,47 @@ public:
|
||||||
const std::function<void(const std::string&)>& okCallback,
|
const std::function<void(const std::string&)>& okCallback,
|
||||||
bool multiLine,
|
bool multiLine,
|
||||||
const std::string& acceptBtnText = "OK",
|
const std::string& acceptBtnText = "OK",
|
||||||
const std::string& saveConfirmationText = "SAVE CHANGES?");
|
const std::string& saveConfirmationText = "SAVE CHANGES?",
|
||||||
|
const std::string& infoString = "",
|
||||||
|
const std::string& defaultValue = "",
|
||||||
|
const std::string& loadBtnHelpText = "LOAD DEFAULT",
|
||||||
|
const std::string& clearBtnHelpText = "CLEAR",
|
||||||
|
const std::string& cancelBtnHelpText = "DISCARD CHANGES");
|
||||||
|
|
||||||
bool input(InputConfig* config, Input input) override;
|
|
||||||
void onSizeChanged() override;
|
void onSizeChanged() override;
|
||||||
|
bool input(InputConfig* config, Input input) override;
|
||||||
|
void update(int deltaTime) override;
|
||||||
|
|
||||||
std::vector<HelpPrompt> getHelpPrompts() override;
|
std::vector<HelpPrompt> getHelpPrompts() override;
|
||||||
HelpStyle getHelpStyle() override { return mHelpStyle; }
|
HelpStyle getHelpStyle() override { return mHelpStyle; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void updateDeleteRepeat(int deltaTime);
|
||||||
|
|
||||||
NinePatchComponent mBackground;
|
NinePatchComponent mBackground;
|
||||||
ComponentGrid mGrid;
|
ComponentGrid mGrid;
|
||||||
|
HelpStyle mHelpStyle;
|
||||||
|
|
||||||
std::shared_ptr<TextComponent> mTitle;
|
std::shared_ptr<TextComponent> mTitle;
|
||||||
|
std::shared_ptr<TextComponent> mInfoString;
|
||||||
|
std::shared_ptr<TextComponent> mDefaultValue;
|
||||||
std::shared_ptr<TextEditComponent> mText;
|
std::shared_ptr<TextEditComponent> mText;
|
||||||
std::shared_ptr<ComponentGrid> mButtonGrid;
|
std::shared_ptr<ComponentGrid> mButtonGrid;
|
||||||
|
|
||||||
HelpStyle mHelpStyle;
|
|
||||||
bool mMultiLine;
|
|
||||||
std::string mInitValue;
|
std::string mInitValue;
|
||||||
std::function<void(const std::string&)> mOkCallback;
|
std::string mAcceptBtnText;
|
||||||
std::string mSaveConfirmationText;
|
std::string mSaveConfirmationText;
|
||||||
|
std::string mLoadBtnHelpText;
|
||||||
|
std::string mClearBtnHelpText;
|
||||||
|
std::string mCancelBtnHelpText;
|
||||||
|
|
||||||
|
std::function<void(const std::string&)> mOkCallback;
|
||||||
|
|
||||||
|
bool mMultiLine;
|
||||||
|
bool mComplexMode;
|
||||||
|
bool mDeleteRepeat;
|
||||||
|
|
||||||
|
int mDeleteRepeatTimer;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ES_CORE_GUIS_GUI_TEXT_EDIT_POPUP_H
|
#endif // ES_CORE_GUIS_GUI_TEXT_EDIT_POPUP_H
|
||||||
|
|
Loading…
Reference in a new issue