mirror of
https://github.com/OpenMW/openmw.git
synced 2025-11-10 16:56:40 +00:00
Merge branch '7214-add-searching-to-ingame-console' into 'master'
Searching in the in-game console Closes #7214 See merge request OpenMW/openmw!2759
This commit is contained in:
commit
8651ea4412
5 changed files with 164 additions and 4 deletions
|
|
@ -202,6 +202,7 @@ Programmers
|
||||||
Sergey Shambir (sergey-shambir)
|
Sergey Shambir (sergey-shambir)
|
||||||
sergoz
|
sergoz
|
||||||
ShadowRadiance
|
ShadowRadiance
|
||||||
|
Shihan42
|
||||||
Siimacore
|
Siimacore
|
||||||
Simon Meulenbeek (simonmb)
|
Simon Meulenbeek (simonmb)
|
||||||
sir_herrbatka
|
sir_herrbatka
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@
|
||||||
Feature #7130: Ability to set MyGUI logging verbosity
|
Feature #7130: Ability to set MyGUI logging verbosity
|
||||||
Feature #7148: Optimize string literal lookup in mwscript
|
Feature #7148: Optimize string literal lookup in mwscript
|
||||||
Feature #7194: Ori to show texture paths
|
Feature #7194: Ori to show texture paths
|
||||||
|
Feature #7214: Searching in the in-game console
|
||||||
Task #7117: Replace boost::scoped_array with std::vector
|
Task #7117: Replace boost::scoped_array with std::vector
|
||||||
Task #7151: Do not use std::strerror to get errno error message
|
Task #7151: Do not use std::strerror to get errno error message
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
#include "console.hpp"
|
#include "console.hpp"
|
||||||
|
|
||||||
|
#include <MyGUI_Button.h>
|
||||||
#include <MyGUI_EditBox.h>
|
#include <MyGUI_EditBox.h>
|
||||||
#include <MyGUI_InputManager.h>
|
#include <MyGUI_InputManager.h>
|
||||||
#include <MyGUI_LayerManager.h>
|
#include <MyGUI_LayerManager.h>
|
||||||
|
|
@ -13,6 +14,7 @@
|
||||||
#include <components/compiler/locals.hpp>
|
#include <components/compiler/locals.hpp>
|
||||||
#include <components/compiler/scanner.hpp>
|
#include <components/compiler/scanner.hpp>
|
||||||
#include <components/interpreter/interpreter.hpp>
|
#include <components/interpreter/interpreter.hpp>
|
||||||
|
#include "components/misc/utf8stream.hpp"
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
#include "../mwscript/extensions.hpp"
|
#include "../mwscript/extensions.hpp"
|
||||||
|
|
@ -144,11 +146,19 @@ namespace MWGui
|
||||||
|
|
||||||
getWidget(mCommandLine, "edit_Command");
|
getWidget(mCommandLine, "edit_Command");
|
||||||
getWidget(mHistory, "list_History");
|
getWidget(mHistory, "list_History");
|
||||||
|
getWidget(mSearchTerm, "edit_SearchTerm");
|
||||||
|
getWidget(mNextButton, "button_Next");
|
||||||
|
getWidget(mPreviousButton, "button_Previous");
|
||||||
|
|
||||||
// Set up the command line box
|
// Set up the command line box
|
||||||
mCommandLine->eventEditSelectAccept += newDelegate(this, &Console::acceptCommand);
|
mCommandLine->eventEditSelectAccept += newDelegate(this, &Console::acceptCommand);
|
||||||
mCommandLine->eventKeyButtonPressed += newDelegate(this, &Console::keyPress);
|
mCommandLine->eventKeyButtonPressed += newDelegate(this, &Console::commandBoxKeyPress);
|
||||||
|
|
||||||
|
// Set up the search term box
|
||||||
|
mSearchTerm->eventEditSelectAccept += newDelegate(this, &Console::acceptSearchTerm);
|
||||||
|
mNextButton->eventMouseButtonClick += newDelegate(this, &Console::findNextOccurrence);
|
||||||
|
mPreviousButton->eventMouseButtonClick += newDelegate(this, &Console::findPreviousOccurence);
|
||||||
|
|
||||||
// Set up the log window
|
// Set up the log window
|
||||||
mHistory->setOverflowToTheLeft(true);
|
mHistory->setOverflowToTheLeft(true);
|
||||||
|
|
||||||
|
|
@ -254,7 +264,7 @@ namespace MWGui
|
||||||
return c == ' ' || c == '\t';
|
return c == ' ' || c == '\t';
|
||||||
}
|
}
|
||||||
|
|
||||||
void Console::keyPress(MyGUI::Widget* _sender, MyGUI::KeyCode key, MyGUI::Char _char)
|
void Console::commandBoxKeyPress(MyGUI::Widget* _sender, MyGUI::KeyCode key, MyGUI::Char _char)
|
||||||
{
|
{
|
||||||
if (MyGUI::InputManager::getInstance().isControlPressed())
|
if (MyGUI::InputManager::getInstance().isControlPressed())
|
||||||
{
|
{
|
||||||
|
|
@ -370,6 +380,130 @@ namespace MWGui
|
||||||
execute(cm);
|
execute(cm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Console::acceptSearchTerm(MyGUI::EditBox* _sender)
|
||||||
|
{
|
||||||
|
const std::string& searchTerm = mSearchTerm->getOnlyText();
|
||||||
|
|
||||||
|
if (searchTerm.empty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mCurrentSearchTerm = Utf8Stream::lowerCaseUtf8(searchTerm);
|
||||||
|
mCurrentOccurrence = std::string::npos;
|
||||||
|
|
||||||
|
findNextOccurrence(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Console::findNextOccurrence(MyGUI::Widget* _sender)
|
||||||
|
{
|
||||||
|
if (mCurrentSearchTerm.empty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto historyText = Utf8Stream::lowerCaseUtf8(mHistory->getOnlyText().asUTF8());
|
||||||
|
|
||||||
|
// Search starts at the beginning
|
||||||
|
size_t startIndex = 0;
|
||||||
|
|
||||||
|
// If this is not the first search, we start right AFTER the last occurrence.
|
||||||
|
if (mCurrentOccurrence != std::string::npos && historyText.length() - mCurrentOccurrence > 1)
|
||||||
|
{
|
||||||
|
startIndex = mCurrentOccurrence + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mCurrentOccurrence = historyText.find(mCurrentSearchTerm, startIndex);
|
||||||
|
|
||||||
|
// If the last search did not find anything AND we didn't start at
|
||||||
|
// the beginning, we repeat the search one time for wrapping around the text.
|
||||||
|
if (mCurrentOccurrence == std::string::npos && startIndex != 0)
|
||||||
|
{
|
||||||
|
mCurrentOccurrence = historyText.find(mCurrentSearchTerm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only scroll & select if we actually found something
|
||||||
|
if (mCurrentOccurrence != std::string::npos)
|
||||||
|
{
|
||||||
|
markOccurrence(mCurrentOccurrence, mCurrentSearchTerm.length());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
markOccurrence(0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Console::findPreviousOccurence(MyGUI::Widget* _sender)
|
||||||
|
{
|
||||||
|
if (mCurrentSearchTerm.empty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto historyText = Utf8Stream::lowerCaseUtf8(mHistory->getOnlyText().asUTF8());
|
||||||
|
|
||||||
|
// Search starts at the end
|
||||||
|
size_t startIndex = historyText.length();
|
||||||
|
|
||||||
|
// If this is not the first search, we start right BEFORE the last occurrence.
|
||||||
|
if (mCurrentOccurrence != std::string::npos && mCurrentOccurrence > 1)
|
||||||
|
{
|
||||||
|
startIndex = mCurrentOccurrence - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mCurrentOccurrence = historyText.rfind(mCurrentSearchTerm, startIndex);
|
||||||
|
|
||||||
|
// If the last search did not find anything AND we didn't start at
|
||||||
|
// the end, we repeat the search one time for wrapping around the text.
|
||||||
|
if (mCurrentOccurrence == std::string::npos && startIndex != historyText.length())
|
||||||
|
{
|
||||||
|
mCurrentOccurrence = historyText.rfind(mCurrentSearchTerm, historyText.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only scroll & select if we actually found something
|
||||||
|
if (mCurrentOccurrence != std::string::npos)
|
||||||
|
{
|
||||||
|
markOccurrence(mCurrentOccurrence, mCurrentSearchTerm.length());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
markOccurrence(0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Console::markOccurrence(const size_t textPosition, const size_t length)
|
||||||
|
{
|
||||||
|
if (textPosition == 0 && length == 0)
|
||||||
|
{
|
||||||
|
mHistory->setTextSelection(0, 0);
|
||||||
|
mHistory->setVScrollPosition(mHistory->getVScrollRange());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto historyText = mHistory->getOnlyText();
|
||||||
|
const size_t upperLimit = std::min(historyText.length(), textPosition);
|
||||||
|
|
||||||
|
// Since MyGUI::EditBox.setVScrollPosition() works on pixels instead of text positions
|
||||||
|
// we need to calculate the actual pixel position by counting lines.
|
||||||
|
size_t lineNumber = 0;
|
||||||
|
for (size_t i = 0; i < upperLimit; i++)
|
||||||
|
{
|
||||||
|
if (historyText[i] == '\n')
|
||||||
|
{
|
||||||
|
lineNumber++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make some space before the actual result
|
||||||
|
if (lineNumber >= 2)
|
||||||
|
{
|
||||||
|
lineNumber -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
mHistory->setTextSelection(textPosition, textPosition + length);
|
||||||
|
mHistory->setVScrollPosition(mHistory->getFontHeight() * lineNumber);
|
||||||
|
}
|
||||||
|
|
||||||
std::string Console::complete(std::string input, std::vector<std::string>& matches)
|
std::string Console::complete(std::string input, std::vector<std::string>& matches)
|
||||||
{
|
{
|
||||||
std::string output = input;
|
std::string output = input;
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,9 @@ namespace MWGui
|
||||||
|
|
||||||
MyGUI::EditBox* mCommandLine;
|
MyGUI::EditBox* mCommandLine;
|
||||||
MyGUI::EditBox* mHistory;
|
MyGUI::EditBox* mHistory;
|
||||||
|
MyGUI::EditBox* mSearchTerm;
|
||||||
|
MyGUI::Button* mNextButton;
|
||||||
|
MyGUI::Button* mPreviousButton;
|
||||||
|
|
||||||
typedef std::list<std::string> StringList;
|
typedef std::list<std::string> StringList;
|
||||||
|
|
||||||
|
|
@ -77,10 +80,16 @@ namespace MWGui
|
||||||
|
|
||||||
void updateConsoleTitle();
|
void updateConsoleTitle();
|
||||||
|
|
||||||
void keyPress(MyGUI::Widget* _sender, MyGUI::KeyCode key, MyGUI::Char _char);
|
void commandBoxKeyPress(MyGUI::Widget* _sender, MyGUI::KeyCode key, MyGUI::Char _char);
|
||||||
|
|
||||||
void acceptCommand(MyGUI::EditBox* _sender);
|
void acceptCommand(MyGUI::EditBox* _sender);
|
||||||
|
|
||||||
|
void acceptSearchTerm(MyGUI::EditBox* _sender);
|
||||||
|
void findNextOccurrence(MyGUI::Widget* _sender);
|
||||||
|
void findPreviousOccurence(MyGUI::Widget* _sender);
|
||||||
|
void markOccurrence(size_t textPosition, size_t length);
|
||||||
|
size_t mCurrentOccurrence = std::string::npos;
|
||||||
|
std::string mCurrentSearchTerm;
|
||||||
|
|
||||||
std::string complete(std::string input, std::vector<std::string>& matches);
|
std::string complete(std::string input, std::vector<std::string>& matches);
|
||||||
|
|
||||||
Compiler::Extensions mExtensions;
|
Compiler::Extensions mExtensions;
|
||||||
|
|
|
||||||
|
|
@ -23,5 +23,20 @@
|
||||||
<UserString key="AcceptTab" value="true"/>
|
<UserString key="AcceptTab" value="true"/>
|
||||||
</Widget>
|
</Widget>
|
||||||
|
|
||||||
|
<!-- Search box -->
|
||||||
|
<Widget type="EditBox" skin="MW_ConsoleCommand" position="250 1 115 28" align="Top Right" name="edit_SearchTerm">
|
||||||
|
<Property key="InvertSelected" value="false"/>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<!-- "Next" button -->
|
||||||
|
<Widget type="Button" skin="MW_Button" position="220 0 28 28" name="button_Next" align="Top Right">
|
||||||
|
<Property key="Caption" value=">"/>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<!-- "Previous" button -->
|
||||||
|
<Widget type="Button" skin="MW_Button" position="190 0 28 28" name="button_Previous" align="Top Right">
|
||||||
|
<Property key="Caption" value="<"/>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
</Widget>
|
</Widget>
|
||||||
</MyGUI>
|
</MyGUI>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue