|
|
|
@ -1,499 +1,241 @@
|
|
|
|
|
#include <SFML/Graphics.hpp>
|
|
|
|
|
#include <xlnt/xlnt.hpp>
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <vector>
|
|
|
|
|
#include <locale>
|
|
|
|
|
#include <codecvt>
|
|
|
|
|
#include <chrono>
|
|
|
|
|
#include <thread>
|
|
|
|
|
#include <map>
|
|
|
|
|
|
|
|
|
|
int font_size = 15;
|
|
|
|
|
float width = 800.f;
|
|
|
|
|
float height = 600.f;
|
|
|
|
|
|
|
|
|
|
const int border_size = 50;
|
|
|
|
|
|
|
|
|
|
std::wstring intToWString(int value)
|
|
|
|
|
{
|
|
|
|
|
std::wostringstream woss;
|
|
|
|
|
woss << value;
|
|
|
|
|
return woss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::wstring stringToWString(const std::string &str)
|
|
|
|
|
{
|
|
|
|
|
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
|
|
|
|
|
return converter.from_bytes(str);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string wstringToString(const std::wstring &wstr)
|
|
|
|
|
{
|
|
|
|
|
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
|
|
|
|
|
return converter.to_bytes(wstr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct QueryResult
|
|
|
|
|
{
|
|
|
|
|
std::wstring keyword;
|
|
|
|
|
std::wstring content;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
bool containsIgnoreCase(const std::wstring &haystack, const std::wstring &needle)
|
|
|
|
|
{
|
|
|
|
|
std::wstring lowercaseHaystack = haystack;
|
|
|
|
|
std::transform(lowercaseHaystack.begin(), lowercaseHaystack.end(), lowercaseHaystack.begin(), ::tolower);
|
|
|
|
|
std::wstring lowercaseNeedle = needle;
|
|
|
|
|
std::transform(lowercaseNeedle.begin(), lowercaseNeedle.end(), lowercaseNeedle.begin(), ::tolower);
|
|
|
|
|
return lowercaseHaystack.find(lowercaseNeedle) != std::wstring::npos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<QueryResult> queryData(const std::wstring &keyword, const std::vector<QueryResult> &data)
|
|
|
|
|
{
|
|
|
|
|
std::vector<QueryResult> results;
|
|
|
|
|
for (const auto &entry : data)
|
|
|
|
|
{
|
|
|
|
|
if (containsIgnoreCase(entry.keyword, keyword))
|
|
|
|
|
{
|
|
|
|
|
results.push_back(entry);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return results;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sf::Text textWithWrap(
|
|
|
|
|
const std::wstring &content,
|
|
|
|
|
const sf::Font &font,
|
|
|
|
|
unsigned int characterSize,
|
|
|
|
|
float maxWidth,
|
|
|
|
|
bool firstLineCut = false)
|
|
|
|
|
{
|
|
|
|
|
sf::Text text;
|
|
|
|
|
int line_counter = 1;
|
|
|
|
|
text.setString(L"");
|
|
|
|
|
std::wstring line;
|
|
|
|
|
float lineWidth = 0.f;
|
|
|
|
|
float lineHeight = static_cast<float>(font.getLineSpacing(characterSize));
|
|
|
|
|
bool skippingFirstLine = false;
|
|
|
|
|
for (auto &ch : content)
|
|
|
|
|
{
|
|
|
|
|
if (skippingFirstLine)
|
|
|
|
|
{
|
|
|
|
|
if (ch == L'\n')
|
|
|
|
|
skippingFirstLine = false;
|
|
|
|
|
else
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
sf::Glyph glyph = font.getGlyph(ch, characterSize, false);
|
|
|
|
|
if (ch == L'\n')
|
|
|
|
|
{
|
|
|
|
|
line_counter++;
|
|
|
|
|
text.setString(text.getString() + line + L"\n");
|
|
|
|
|
// text.setString(text.getString() + line + L"\n" + intToWString(line_counter) + L">>");
|
|
|
|
|
line.clear();
|
|
|
|
|
lineWidth = 0.f;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
lineWidth += glyph.advance;
|
|
|
|
|
if (lineWidth + characterSize > maxWidth)
|
|
|
|
|
{
|
|
|
|
|
if (firstLineCut && line_counter == 1)
|
|
|
|
|
{
|
|
|
|
|
skippingFirstLine = true;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
line_counter++;
|
|
|
|
|
text.setString(text.getString() + line + L"\n");
|
|
|
|
|
// text.setString(text.getString() + line + L"\n" + intToWString(line_counter) + L">>");
|
|
|
|
|
// line_counter++;
|
|
|
|
|
line.clear();
|
|
|
|
|
lineWidth = glyph.advance;
|
|
|
|
|
}
|
|
|
|
|
line += ch;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
text.setString(text.getString() + line);
|
|
|
|
|
return text;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<sf::VertexArray> genX(double x, double y)
|
|
|
|
|
{
|
|
|
|
|
std::vector<sf::VertexArray> res;
|
|
|
|
|
sf::VertexArray line(sf::Lines, 2);
|
|
|
|
|
line[0].position.x = x - 6;
|
|
|
|
|
line[0].position.y = y - 6;
|
|
|
|
|
line[1].position.x = x + 6;
|
|
|
|
|
line[1].position.y = y + 6;
|
|
|
|
|
line[0].color = sf::Color::White;
|
|
|
|
|
line[1].color = sf::Color::White;
|
|
|
|
|
res.push_back(line);
|
|
|
|
|
auto line_ = line;
|
|
|
|
|
line_[0].position.x = x + 6;
|
|
|
|
|
line_[1].position.x = x - 6;
|
|
|
|
|
res.push_back(line_);
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sf::VertexArray genCursor(double x, double y, double h)
|
|
|
|
|
{
|
|
|
|
|
sf::VertexArray line(sf::Lines, 2);
|
|
|
|
|
line[0].position.x = x;
|
|
|
|
|
line[0].position.y = y + 2;
|
|
|
|
|
line[1].position.x = x;
|
|
|
|
|
line[1].position.y = y + h - 2;
|
|
|
|
|
line[0].color = sf::Color::Black;
|
|
|
|
|
line[1].color = sf::Color::Black;
|
|
|
|
|
return line;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main()
|
|
|
|
|
{
|
|
|
|
|
std::map<std::wstring, std::wstring> results;
|
|
|
|
|
std::wstring content;
|
|
|
|
|
float scroll = 0.f;
|
|
|
|
|
int offset = 0;
|
|
|
|
|
int shadowIndex = -1;
|
|
|
|
|
std::shared_ptr<bool> running(new bool(true));
|
|
|
|
|
std::shared_ptr<bool> cursor_on(new bool(false));
|
|
|
|
|
|
|
|
|
|
std::jthread worker([running, cursor_on]()
|
|
|
|
|
{
|
|
|
|
|
while(*running){
|
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
|
|
|
|
*cursor_on = !*cursor_on;
|
|
|
|
|
} });
|
|
|
|
|
|
|
|
|
|
// ¶ÁÈ¡ExcelÎļþ
|
|
|
|
|
xlnt::workbook wb;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
wb.load("data.xlsx");
|
|
|
|
|
}
|
|
|
|
|
catch (const std::exception &e)
|
|
|
|
|
{
|
|
|
|
|
std::cerr << "Error loading Excel file: " << e.what() << std::endl;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
xlnt::worksheet ws = wb.active_sheet();
|
|
|
|
|
std::vector<QueryResult> data;
|
|
|
|
|
for (auto row : ws.rows(false))
|
|
|
|
|
{
|
|
|
|
|
QueryResult entry;
|
|
|
|
|
entry.keyword = stringToWString(row[0].to_string());
|
|
|
|
|
entry.content = stringToWString(row[1].to_string());
|
|
|
|
|
data.push_back(entry);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sf::RenderWindow window(sf::VideoMode(width, height), L"查询");
|
|
|
|
|
|
|
|
|
|
sf::Font font;
|
|
|
|
|
if (!font.loadFromFile("msyh.ttc"))
|
|
|
|
|
{ // ʹÓÃÖ§³ÖÖÐÎĵÄ×ÖÌåÎļþ
|
|
|
|
|
std::cerr << "Error loading font\n";
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Input box
|
|
|
|
|
sf::RectangleShape inputBox(sf::Vector2f(400, 30));
|
|
|
|
|
inputBox.setPosition(border_size, border_size);
|
|
|
|
|
inputBox.setSize(sf::Vector2f(width - border_size * 2 - 120, 30));
|
|
|
|
|
inputBox.setFillColor(sf::Color::White);
|
|
|
|
|
inputBox.setOutlineColor(sf::Color::Black);
|
|
|
|
|
inputBox.setOutlineThickness(2);
|
|
|
|
|
|
|
|
|
|
std::wstring inputText;
|
|
|
|
|
sf::Text inputTextBox;
|
|
|
|
|
inputTextBox.setFont(font);
|
|
|
|
|
inputTextBox.setCharacterSize(20);
|
|
|
|
|
inputTextBox.setFillColor(sf::Color::Black);
|
|
|
|
|
inputTextBox.setPosition(border_size + 5, border_size + 5);
|
|
|
|
|
|
|
|
|
|
// query Button
|
|
|
|
|
sf::RectangleShape button(sf::Vector2f(100, 30));
|
|
|
|
|
button.setPosition(width - border_size - button.getSize().x, 50);
|
|
|
|
|
button.setFillColor(sf::Color(0x33, 0xff, 0x33));
|
|
|
|
|
button.setOutlineColor(sf::Color::Black);
|
|
|
|
|
button.setOutlineThickness(2);
|
|
|
|
|
|
|
|
|
|
sf::Text buttonText;
|
|
|
|
|
buttonText.setFont(font);
|
|
|
|
|
buttonText.setString(L"查询");
|
|
|
|
|
buttonText.setCharacterSize(20);
|
|
|
|
|
buttonText.setFillColor(sf::Color::Black);
|
|
|
|
|
buttonText.setPosition(
|
|
|
|
|
button.getPosition().x + button.getSize().x / 2 - //
|
|
|
|
|
buttonText.getCharacterSize() * buttonText.getString().getSize() / 2,
|
|
|
|
|
52);
|
|
|
|
|
|
|
|
|
|
// delete Button
|
|
|
|
|
sf::CircleShape deleteButton(12, 32);
|
|
|
|
|
deleteButton.setPosition(
|
|
|
|
|
sf::Vector2f(
|
|
|
|
|
border_size + inputBox.getSize().x - 27,
|
|
|
|
|
border_size + inputBox.getSize().y / 2 - deleteButton.getRadius()));
|
|
|
|
|
deleteButton.setFillColor(sf::Color(0x80, 0x80, 0x80));
|
|
|
|
|
|
|
|
|
|
// Query result area
|
|
|
|
|
sf::RectangleShape resultBox(sf::Vector2f(width - border_size * 2 - 4 - 260, height - 100.f - border_size - 4));
|
|
|
|
|
resultBox.setPosition(262, 2);
|
|
|
|
|
resultBox.setFillColor(sf::Color::White);
|
|
|
|
|
resultBox.setOutlineColor(sf::Color::Black);
|
|
|
|
|
resultBox.setOutlineThickness(2);
|
|
|
|
|
|
|
|
|
|
sf::RectangleShape resultList(sf::Vector2f(258, height - 100.f - border_size - 4));
|
|
|
|
|
resultList.setPosition(2, 2);
|
|
|
|
|
resultList.setFillColor(sf::Color::White);
|
|
|
|
|
resultList.setOutlineColor(sf::Color::Black);
|
|
|
|
|
resultList.setOutlineThickness(2);
|
|
|
|
|
|
|
|
|
|
sf::RectangleShape resultTitle(sf::Vector2f(width - border_size * 2 - 4 - 260, 20));
|
|
|
|
|
resultTitle.setPosition(262, 2);
|
|
|
|
|
resultTitle.setFillColor(sf::Color::Yellow);
|
|
|
|
|
|
|
|
|
|
sf::RectangleShape shadow(sf::Vector2f(258, 20));
|
|
|
|
|
shadow.setFillColor(sf::Color(0xbb, 0xbb, 0xbb));
|
|
|
|
|
|
|
|
|
|
sf::View resultView(sf::FloatRect(0.f, 0.f, width - border_size * 2, height - 100.f - border_size));
|
|
|
|
|
resultView.setViewport(
|
|
|
|
|
sf::FloatRect(
|
|
|
|
|
border_size / width, 100.f / height,
|
|
|
|
|
(width - border_size * 2) / width,
|
|
|
|
|
(height - 100.f - border_size) / height));
|
|
|
|
|
|
|
|
|
|
sf::View reslistView(sf::FloatRect(0.f, 0.f, 260, height - 100.f - border_size));
|
|
|
|
|
reslistView.setViewport(
|
|
|
|
|
sf::FloatRect(
|
|
|
|
|
border_size / width, 100.f / height,
|
|
|
|
|
260 / width, (height - 100.f - border_size) / height));
|
|
|
|
|
|
|
|
|
|
sf::View showView(sf::FloatRect(0.f, 0.f, width - border_size * 2 - 262, height - 100.f - border_size));
|
|
|
|
|
showView.setViewport(
|
|
|
|
|
sf::FloatRect(
|
|
|
|
|
(border_size + 262) / width, 100.f / height,
|
|
|
|
|
(width - border_size * 2 - 262) / width,
|
|
|
|
|
(height - 100.f - border_size) / height));
|
|
|
|
|
|
|
|
|
|
while (window.isOpen())
|
|
|
|
|
{
|
|
|
|
|
sf::Event event;
|
|
|
|
|
while (window.pollEvent(event))
|
|
|
|
|
{
|
|
|
|
|
if (event.type == sf::Event::Closed)
|
|
|
|
|
{
|
|
|
|
|
*running = false;
|
|
|
|
|
window.close();
|
|
|
|
|
}
|
|
|
|
|
if (event.type == sf::Event::TextEntered)
|
|
|
|
|
{
|
|
|
|
|
if (event.text.unicode == 8)
|
|
|
|
|
{ // Backspace¼üµÄUnicodeÖµÊÇ8
|
|
|
|
|
if (!inputText.empty())
|
|
|
|
|
{
|
|
|
|
|
inputText.pop_back();
|
|
|
|
|
inputTextBox.setString(inputText);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
inputText += static_cast<wchar_t>(event.text.unicode);
|
|
|
|
|
inputTextBox.setString(inputText);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (event.type == sf::Event::MouseButtonPressed)
|
|
|
|
|
{
|
|
|
|
|
if (event.mouseButton.button == sf::Mouse::Left)
|
|
|
|
|
{
|
|
|
|
|
sf::Vector2i mousePos = sf::Mouse::getPosition(window);
|
|
|
|
|
if (button.getGlobalBounds().contains(mousePos.x, mousePos.y))
|
|
|
|
|
{
|
|
|
|
|
// Perform query
|
|
|
|
|
std::vector<QueryResult> qresults = queryData(inputText, data);
|
|
|
|
|
results.clear();
|
|
|
|
|
for (const auto &result : qresults)
|
|
|
|
|
{
|
|
|
|
|
if (result.keyword.empty())
|
|
|
|
|
continue;
|
|
|
|
|
results.insert(std::pair(result.keyword, result.content));
|
|
|
|
|
}
|
|
|
|
|
button.setFillColor(sf::Color(0xaa, 0xff, 0xaa));
|
|
|
|
|
reslistView.reset(sf::FloatRect(0.f, 0.f, 260, height - 100.f - border_size));
|
|
|
|
|
offset = 0;
|
|
|
|
|
}
|
|
|
|
|
else if (deleteButton.getGlobalBounds().contains(mousePos.x, mousePos.y))
|
|
|
|
|
{
|
|
|
|
|
deleteButton.setFillColor(sf::Color::Red);
|
|
|
|
|
content.clear();
|
|
|
|
|
shadowIndex = -1;
|
|
|
|
|
results.clear();
|
|
|
|
|
inputText.clear();
|
|
|
|
|
inputTextBox.setString(inputText);
|
|
|
|
|
}
|
|
|
|
|
else if (inputBox.getGlobalBounds().contains(mousePos.x, mousePos.y))
|
|
|
|
|
{
|
|
|
|
|
inputBox.setOutlineColor(sf::Color(0xaa, 0xaa, 0xaa));
|
|
|
|
|
}
|
|
|
|
|
sf::Vector2f vp(
|
|
|
|
|
mousePos.x - reslistView.getViewport().left * width,
|
|
|
|
|
mousePos.y - reslistView.getViewport().top * height);
|
|
|
|
|
if (resultList.getGlobalBounds().contains(vp.x, vp.y) && shadowIndex != -1)
|
|
|
|
|
{
|
|
|
|
|
auto i = shadowIndex + offset;
|
|
|
|
|
auto it = results.begin();
|
|
|
|
|
for (; i && it != results.end(); i--, it++)
|
|
|
|
|
;
|
|
|
|
|
if (it != results.end())
|
|
|
|
|
{
|
|
|
|
|
content = it->first + L"\n" + it->second;
|
|
|
|
|
std::wcout << content << std::endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (event.type == sf::Event::MouseButtonReleased)
|
|
|
|
|
{
|
|
|
|
|
if (event.mouseButton.button == sf::Mouse::Left)
|
|
|
|
|
{
|
|
|
|
|
sf::Vector2i mousePos = sf::Mouse::getPosition(window);
|
|
|
|
|
if (button.getGlobalBounds().contains(mousePos.x, mousePos.y))
|
|
|
|
|
{
|
|
|
|
|
button.setFillColor(sf::Color(0x33, 0xff, 0x33));
|
|
|
|
|
}
|
|
|
|
|
else if (deleteButton.getGlobalBounds().contains(mousePos.x, mousePos.y))
|
|
|
|
|
{
|
|
|
|
|
deleteButton.setFillColor(sf::Color(0x80, 0x80, 0x80));
|
|
|
|
|
}
|
|
|
|
|
else if (inputBox.getGlobalBounds().contains(mousePos.x, mousePos.y))
|
|
|
|
|
{
|
|
|
|
|
inputBox.setOutlineColor(sf::Color::Black);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (event.type == sf::Event::MouseMoved)
|
|
|
|
|
{
|
|
|
|
|
sf::Vector2i mousePos = sf::Mouse::getPosition(window);
|
|
|
|
|
sf::Vector2f vp(
|
|
|
|
|
mousePos.x - reslistView.getViewport().left * width,
|
|
|
|
|
mousePos.y - reslistView.getViewport().top * height);
|
|
|
|
|
if (resultList.getGlobalBounds().contains(vp.x, vp.y))
|
|
|
|
|
{
|
|
|
|
|
shadowIndex = (int)vp.y / 20;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (event.type == sf::Event::MouseWheelScrolled)
|
|
|
|
|
{
|
|
|
|
|
if (event.mouseWheelScroll.wheel == sf::Mouse::VerticalWheel)
|
|
|
|
|
{
|
|
|
|
|
sf::Vector2i mousePos = sf::Mouse::getPosition(window);
|
|
|
|
|
sf::Vector2f vp(reslistView.getViewport().left * width, reslistView.getViewport().top * height);
|
|
|
|
|
if (resultList.getGlobalBounds().contains(mousePos.x - vp.x, mousePos.y - vp.y))
|
|
|
|
|
{
|
|
|
|
|
offset -= event.mouseWheelScroll.delta;
|
|
|
|
|
if (offset < 0)
|
|
|
|
|
offset = 0;
|
|
|
|
|
else if (offset > results.size())
|
|
|
|
|
offset = results.size();
|
|
|
|
|
else
|
|
|
|
|
scroll -= event.mouseWheelScroll.delta * 20.f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// catch the resize events
|
|
|
|
|
if (event.type == sf::Event::Resized)
|
|
|
|
|
{
|
|
|
|
|
width = event.size.width;
|
|
|
|
|
height = event.size.height;
|
|
|
|
|
inputBox.setSize(sf::Vector2f(width - border_size * 2 - 120, 30));
|
|
|
|
|
deleteButton.setPosition(
|
|
|
|
|
sf::Vector2f(
|
|
|
|
|
border_size + inputBox.getSize().x - 27,
|
|
|
|
|
border_size + inputBox.getSize().y / 2 - deleteButton.getRadius()));
|
|
|
|
|
button.setPosition(width - border_size - button.getSize().x, 50);
|
|
|
|
|
buttonText.setPosition(
|
|
|
|
|
button.getPosition().x + button.getSize().x / 2 -
|
|
|
|
|
buttonText.getCharacterSize() * buttonText.getString().getSize() / 2,
|
|
|
|
|
52);
|
|
|
|
|
|
|
|
|
|
resultList.setSize(sf::Vector2f(258, height - 100.f - border_size - 4));
|
|
|
|
|
resultBox.setSize(sf::Vector2f(width - border_size * 2 - 4 - 260, height - 100.f - border_size - 4));
|
|
|
|
|
resultTitle.setSize(sf::Vector2f(width - border_size * 2 - 4 - 260, 20));
|
|
|
|
|
|
|
|
|
|
resultView.reset(sf::FloatRect(0.f, 0.f, width - border_size * 2, height - 100.f - border_size));
|
|
|
|
|
resultView.setViewport(
|
|
|
|
|
sf::FloatRect(
|
|
|
|
|
border_size / width, 100.f / height,
|
|
|
|
|
(width - border_size * 2) / width,
|
|
|
|
|
(height - 100.f - border_size) / height));
|
|
|
|
|
|
|
|
|
|
reslistView.reset(sf::FloatRect(0.f, 0.f, 260, height - 100.f - border_size));
|
|
|
|
|
reslistView.setViewport(
|
|
|
|
|
sf::FloatRect(
|
|
|
|
|
border_size / width, 100.f / height,
|
|
|
|
|
260 / width, (height - 100.f - border_size - 2) / height));
|
|
|
|
|
reslistView.move(sf::Vector2f(0, offset * 20));
|
|
|
|
|
|
|
|
|
|
showView.reset(sf::FloatRect(0.f, 0.f, width - border_size * 2 - 260, height - 100.f - border_size));
|
|
|
|
|
showView.setViewport(sf::FloatRect(
|
|
|
|
|
(border_size + 262) / width, 100.f / height,
|
|
|
|
|
(width - border_size * 2 - 260) / width,
|
|
|
|
|
(height - 100.f - border_size) / height));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
window.setView(sf::View(sf::FloatRect(0.f, 0.f, width, height)));
|
|
|
|
|
window.clear(sf::Color(0x40, 0x80, 0x40));
|
|
|
|
|
window.draw(inputBox);
|
|
|
|
|
window.draw(inputTextBox);
|
|
|
|
|
if (*cursor_on)
|
|
|
|
|
{
|
|
|
|
|
auto b = inputTextBox.getGlobalBounds();
|
|
|
|
|
auto c = genCursor(b.getSize().x + b.getPosition().x, inputBox.getPosition().y, inputBox.getSize().y);
|
|
|
|
|
window.draw(c);
|
|
|
|
|
}
|
|
|
|
|
window.draw(deleteButton);
|
|
|
|
|
auto x = genX(deleteButton.getPosition().x + 12, deleteButton.getPosition().y + 12);
|
|
|
|
|
window.draw(x[0]);
|
|
|
|
|
window.draw(x[1]);
|
|
|
|
|
window.draw(button);
|
|
|
|
|
window.draw(buttonText);
|
|
|
|
|
|
|
|
|
|
window.setView(resultView);
|
|
|
|
|
window.draw(resultList);
|
|
|
|
|
window.draw(resultBox);
|
|
|
|
|
window.draw(resultTitle);
|
|
|
|
|
|
|
|
|
|
window.setView(reslistView);
|
|
|
|
|
reslistView.move(sf::Vector2f(0, scroll));
|
|
|
|
|
scroll = 0;
|
|
|
|
|
auto i = 0;
|
|
|
|
|
for (auto it = results.begin(); it != results.end(); it++)
|
|
|
|
|
{
|
|
|
|
|
if (i == shadowIndex)
|
|
|
|
|
{
|
|
|
|
|
shadow.setPosition(2, 2 + offset * 20 + i * 20);
|
|
|
|
|
window.draw(shadow);
|
|
|
|
|
}
|
|
|
|
|
auto text = textWithWrap(it->first, font, font_size, reslistView.getSize().x);
|
|
|
|
|
text.setFont(font);
|
|
|
|
|
text.setCharacterSize(font_size);
|
|
|
|
|
text.setFillColor(sf::Color::Black);
|
|
|
|
|
text.setPosition(7, 2 + i * 20);
|
|
|
|
|
window.draw(text);
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
window.setView(showView);
|
|
|
|
|
auto contentText = textWithWrap(content, font, font_size, showView.getSize().x, true);
|
|
|
|
|
contentText.setFont(font);
|
|
|
|
|
contentText.setCharacterSize(font_size);
|
|
|
|
|
contentText.setFillColor(sf::Color::Black);
|
|
|
|
|
contentText.setPosition(7, 4);
|
|
|
|
|
window.draw(contentText);
|
|
|
|
|
|
|
|
|
|
window.display();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
#include <SFML/Graphics.hpp>
|
|
|
|
|
#include <xlnt/xlnt.hpp>
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <vector>
|
|
|
|
|
#include <locale>
|
|
|
|
|
#include <codecvt>
|
|
|
|
|
|
|
|
|
|
int font_size = 15;
|
|
|
|
|
float width = 800.f;
|
|
|
|
|
float height = 600.f;
|
|
|
|
|
|
|
|
|
|
std::wstring intToWString(int value) {
|
|
|
|
|
std::wostringstream woss;
|
|
|
|
|
woss << value;
|
|
|
|
|
return woss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::wstring stringToWString(const std::string& str) {
|
|
|
|
|
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
|
|
|
|
|
return converter.from_bytes(str);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string wstringToString(const std::wstring& wstr) {
|
|
|
|
|
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
|
|
|
|
|
return converter.to_bytes(wstr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct QueryResult {
|
|
|
|
|
std::wstring keyword;
|
|
|
|
|
std::wstring content;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
bool containsIgnoreCase(const std::wstring& haystack, const std::wstring& needle) {
|
|
|
|
|
std::wstring lowercaseHaystack = haystack;
|
|
|
|
|
std::transform(lowercaseHaystack.begin(), lowercaseHaystack.end(), lowercaseHaystack.begin(), ::tolower);
|
|
|
|
|
std::wstring lowercaseNeedle = needle;
|
|
|
|
|
std::transform(lowercaseNeedle.begin(), lowercaseNeedle.end(), lowercaseNeedle.begin(), ::tolower);
|
|
|
|
|
return lowercaseHaystack.find(lowercaseNeedle) != std::wstring::npos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<QueryResult> queryData(const std::wstring& keyword, const std::vector<QueryResult>& data) {
|
|
|
|
|
std::vector<QueryResult> results;
|
|
|
|
|
for (const auto& entry : data) {
|
|
|
|
|
if (containsIgnoreCase(entry.keyword, keyword)) {
|
|
|
|
|
results.push_back(entry);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return results;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int line_counter = 1;
|
|
|
|
|
//static int extra_line_counter = 0;
|
|
|
|
|
void setTextWithWrap(sf::Text& text, const std::wstring& content, const sf::Font& font, unsigned int characterSize, float maxWidth) {
|
|
|
|
|
line_counter = 1;
|
|
|
|
|
text.setString(L"");
|
|
|
|
|
std::wstring line;
|
|
|
|
|
float lineWidth = 0.f;
|
|
|
|
|
float lineHeight = static_cast<float>(font.getLineSpacing(characterSize));
|
|
|
|
|
for (auto& ch : content) {
|
|
|
|
|
sf::Glyph glyph = font.getGlyph(ch, characterSize, false);
|
|
|
|
|
if (ch == L'\n') {
|
|
|
|
|
line_counter++;
|
|
|
|
|
text.setString(text.getString() + line + L"\n");
|
|
|
|
|
//text.setString(text.getString() + line + L"\n" + intToWString(line_counter) + L">>");
|
|
|
|
|
line.clear();
|
|
|
|
|
lineWidth = 0.f;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
lineWidth += glyph.advance;
|
|
|
|
|
if (lineWidth > maxWidth) {
|
|
|
|
|
line_counter++;
|
|
|
|
|
text.setString(text.getString() + line + L"\n");
|
|
|
|
|
//text.setString(text.getString() + line + L"\n" + intToWString(line_counter) + L">>");
|
|
|
|
|
//line_counter++;
|
|
|
|
|
line.clear();
|
|
|
|
|
lineWidth = glyph.advance;
|
|
|
|
|
}
|
|
|
|
|
line += ch;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
text.setString(text.getString() + line);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main() {
|
|
|
|
|
std::wstring resultStr;
|
|
|
|
|
float offset = 0.f;
|
|
|
|
|
|
|
|
|
|
// 读取Excel文件
|
|
|
|
|
xlnt::workbook wb;
|
|
|
|
|
try {
|
|
|
|
|
wb.load("data.xlsx");
|
|
|
|
|
}
|
|
|
|
|
catch (const std::exception& e) {
|
|
|
|
|
std::cerr << "Error loading Excel file: " << e.what() << std::endl;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
xlnt::worksheet ws = wb.active_sheet();
|
|
|
|
|
std::vector<QueryResult> data;
|
|
|
|
|
for (auto row : ws.rows(false)) {
|
|
|
|
|
QueryResult entry;
|
|
|
|
|
entry.keyword = stringToWString(row[0].to_string());
|
|
|
|
|
entry.content = stringToWString(row[1].to_string());
|
|
|
|
|
data.push_back(entry);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sf::RenderWindow window(sf::VideoMode(width, height), L"查询工具");
|
|
|
|
|
|
|
|
|
|
sf::Font font;
|
|
|
|
|
if (!font.loadFromFile("msyh.ttc")) { //使用支持中文的字体文件
|
|
|
|
|
std::cerr << "Error loading font\n";
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Input box
|
|
|
|
|
sf::RectangleShape inputBox(sf::Vector2f(400, 30));
|
|
|
|
|
inputBox.setPosition(50, 50);
|
|
|
|
|
inputBox.setFillColor(sf::Color::White);
|
|
|
|
|
inputBox.setOutlineColor(sf::Color::Black);
|
|
|
|
|
inputBox.setOutlineThickness(2);
|
|
|
|
|
|
|
|
|
|
std::wstring inputText;
|
|
|
|
|
sf::Text inputTextBox;
|
|
|
|
|
inputTextBox.setFont(font);
|
|
|
|
|
inputTextBox.setCharacterSize(20);
|
|
|
|
|
inputTextBox.setFillColor(sf::Color::Black);
|
|
|
|
|
inputTextBox.setPosition(55, 55);
|
|
|
|
|
|
|
|
|
|
// Button
|
|
|
|
|
sf::RectangleShape button(sf::Vector2f(100, 30));
|
|
|
|
|
button.setPosition(500, 50);
|
|
|
|
|
button.setFillColor(sf::Color::Green);
|
|
|
|
|
button.setOutlineColor(sf::Color::Black);
|
|
|
|
|
button.setOutlineThickness(2);
|
|
|
|
|
|
|
|
|
|
sf::Text buttonText;
|
|
|
|
|
buttonText.setFont(font);
|
|
|
|
|
buttonText.setString(L"查询");
|
|
|
|
|
buttonText.setCharacterSize(20);
|
|
|
|
|
buttonText.setFillColor(sf::Color::Black);
|
|
|
|
|
buttonText.setPosition(529, 52);
|
|
|
|
|
|
|
|
|
|
// Query result area
|
|
|
|
|
sf::RectangleShape resultBox(sf::Vector2f(width * 7.f/8 - 4, height * 5.f/6));
|
|
|
|
|
resultBox.setPosition(2, 100);
|
|
|
|
|
resultBox.setFillColor(sf::Color::White);
|
|
|
|
|
resultBox.setOutlineColor(sf::Color::Black);
|
|
|
|
|
resultBox.setOutlineThickness(2);
|
|
|
|
|
|
|
|
|
|
sf::Text resultText;
|
|
|
|
|
resultText.setFont(font);
|
|
|
|
|
resultText.setCharacterSize(font_size);
|
|
|
|
|
resultText.setFillColor(sf::Color::Black);
|
|
|
|
|
resultText.setPosition(7, 105);
|
|
|
|
|
|
|
|
|
|
sf::View resultView(sf::FloatRect(0.f, 0.f, width * 7.f/8, height * 5.f/6));
|
|
|
|
|
resultView.setViewport(sf::FloatRect(0.05f, 0.0f, 0.9f, 1.0f));
|
|
|
|
|
|
|
|
|
|
while (window.isOpen()) {
|
|
|
|
|
sf::Event event;
|
|
|
|
|
while (window.pollEvent(event)) {
|
|
|
|
|
if (event.type == sf::Event::Closed)
|
|
|
|
|
window.close();
|
|
|
|
|
if (event.type == sf::Event::TextEntered) {
|
|
|
|
|
if (event.text.unicode == 8) { //Backspace键的Unicode值是8
|
|
|
|
|
if (!inputText.empty()) {
|
|
|
|
|
inputText.pop_back();
|
|
|
|
|
inputTextBox.setString(inputText);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
inputText += static_cast<wchar_t>(event.text.unicode);
|
|
|
|
|
inputTextBox.setString(inputText);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (event.type == sf::Event::MouseButtonPressed) {
|
|
|
|
|
if (event.mouseButton.button == sf::Mouse::Left) {
|
|
|
|
|
sf::Vector2i mousePos = sf::Mouse::getPosition(window);
|
|
|
|
|
if (button.getGlobalBounds().contains(mousePos.x, mousePos.y)) {
|
|
|
|
|
// Perform query
|
|
|
|
|
std::vector<QueryResult> results = queryData(inputText, data);
|
|
|
|
|
resultStr.clear();
|
|
|
|
|
//extra_line_counter = 0;
|
|
|
|
|
for (const auto& result : results) {
|
|
|
|
|
resultStr += result.keyword + L"\n" + result.content + L"\n\n";
|
|
|
|
|
//line_counter += 3;
|
|
|
|
|
//extra_line_counter += 3;
|
|
|
|
|
}
|
|
|
|
|
//setTextWithWrap(resultText, resultStr, font, font_size, width * 7.f/8); // 设置换行
|
|
|
|
|
//resultView.reset(sf::FloatRect(0.f, 0.f, 800.f, 600.f));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (event.type == sf::Event::MouseWheelScrolled) {
|
|
|
|
|
if (event.mouseWheelScroll.wheel == sf::Mouse::VerticalWheel) {
|
|
|
|
|
//resultView.move(0.f, -event.mouseWheelScroll.delta * 20.f);
|
|
|
|
|
offset -= event.mouseWheelScroll.delta * 20.f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// catch the resize events
|
|
|
|
|
if (event.type == sf::Event::Resized)
|
|
|
|
|
{
|
|
|
|
|
// update the view to the new size of the window
|
|
|
|
|
//visibleArea = sf::FloatRect(0.f, 0.f, event.size.width, event.size.height);
|
|
|
|
|
width = event.size.width;
|
|
|
|
|
height = event.size.height;
|
|
|
|
|
//setTextWithWrap(resultText, resultStr, font, font_size, width * 7.f / 8);
|
|
|
|
|
//window.setView(sf::View(visibleArea));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//inputBox.setSize(sf::Vector2f());
|
|
|
|
|
//inputTextBox;
|
|
|
|
|
//button;
|
|
|
|
|
//buttonText;
|
|
|
|
|
//resultView.setSize(sf::Vector2f(width * 7.f / 8, height * 5.f / 6));
|
|
|
|
|
setTextWithWrap(resultText, resultStr, font, font_size, width * 7.f / 8 - 14);
|
|
|
|
|
resultView.reset(sf::FloatRect(0.f, 0.f, width * 7.f / 8, height * 5.f / 6));
|
|
|
|
|
|
|
|
|
|
resultView.move(0.f, offset);
|
|
|
|
|
resultBox.setSize(sf::Vector2f(width * 7.f / 8 - 4, (line_counter) * 20 + 10));
|
|
|
|
|
//resultText;
|
|
|
|
|
//window.setView(sf::View(visibleArea));
|
|
|
|
|
window.setView(sf::View(sf::FloatRect(0.f, 0.f, width, height)));
|
|
|
|
|
window.clear(sf::Color::Cyan);
|
|
|
|
|
window.draw(inputBox);
|
|
|
|
|
window.draw(inputTextBox);
|
|
|
|
|
window.draw(button);
|
|
|
|
|
window.draw(buttonText);
|
|
|
|
|
|
|
|
|
|
window.setView(resultView);
|
|
|
|
|
window.draw(resultBox);
|
|
|
|
|
window.draw(resultText);
|
|
|
|
|
//window.setView(window.getDefaultView());
|
|
|
|
|
|
|
|
|
|
window.display();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|