This commit is contained in:
pointer-to-bios 2024-07-23 17:04:47 +08:00
commit 1251d2f72b
8 changed files with 507 additions and 0 deletions

39
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,39 @@
name: CI
on: [push, pull_request]
defaults:
run:
shell: bash
jobs:
build:
name: ${{ matrix.platform.name }} ${{ matrix.config.name }}
runs-on: ${{ matrix.platform.os }}
strategy:
fail-fast: false
matrix:
platform:
- { name: Windows VS2019, os: windows-2019 }
- { name: Windows VS2022, os: windows-2022 }
- { name: Linux GCC, os: ubuntu-latest }
- { name: Linux Clang, os: ubuntu-latest, flags: -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ }
- { name: macOS, os: macos-latest }
config:
- { name: Shared, flags: -DBUILD_SHARED_LIBS=TRUE }
- { name: Static, flags: -DBUILD_SHARED_LIBS=FALSE }
steps:
- name: Install Linux Dependencies
if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install libxrandr-dev libxcursor-dev libudev-dev libopenal-dev libflac-dev libvorbis-dev libgl1-mesa-dev libegl1-mesa-dev
- name: Checkout
uses: actions/checkout@v4
- name: Configure
run: cmake -B build ${{matrix.platform.flags}} ${{matrix.config.flags}}
- name: Build
run: cmake --build build --config Release

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
build
out
.cache
.idea
.vs
.vscode

31
CMakeLists.txt Normal file
View File

@ -0,0 +1,31 @@
cmake_minimum_required(VERSION 3.16)
project(CMakeSFMLProject LANGUAGES CXX)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
include(FetchContent)
FetchContent_Declare(SFML
GIT_REPOSITORY https://github.com/SFML/SFML.git
GIT_TAG 2.6.x)
FetchContent_MakeAvailable(SFML)
FetchContent_Declare(
xlnt
GIT_REPOSITORY https://github.com/pointertobios/xlnt.git
GIT_TAG master)
FetchContent_MakeAvailable(xlnt)
add_executable(main src/main.cpp)
target_link_libraries(main PRIVATE sfml-graphics xlnt)
target_compile_features(main PRIVATE cxx_std_17)
target_include_directories(main PRIVATE include)
if(WIN32)
add_custom_command(
TARGET main
COMMENT "Copy OpenAL DLL"
PRE_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${SFML_SOURCE_DIR}/extlibs/bin/$<IF:$<EQUAL:${CMAKE_SIZEOF_VOID_P},8>,x64,x86>/openal32.dll $<TARGET_FILE_DIR:main>
VERBATIM)
endif()

50
LICENSE.md Normal file
View File

@ -0,0 +1,50 @@
# CMake SFML Project Licenses
*This software is available under 2 licenses -- choose whichever you prefer.*
## Public Domain
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
## MIT License
Copyright (c) 2022 Lukas Dürrenberger
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

105
README.md Normal file
View File

@ -0,0 +1,105 @@
# CMake SFML Project Template
This repository template should allow for a fast and hassle-free kick start of your next SFML project using CMake.
Thanks to [GitHub's nature of templates](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-repository-from-a-template), you can fork this repository without inheriting its Git history.
The template starts out very basic, but might receive additional features over time:
- Basic CMake script to build your project and link SFML on any operating system
- Basic [GitHub Actions](https://github.com/features/actions) script for all major platforms
## How to Use
1. Install Git and CMake. Use your system's package manager if available.
1. Follow the above instructions about how to use GitHub's project template feature to create your own project.
1. Clone your new GitHub repo and open the repo in your text editor of choice.
1. Open [CMakeLists.txt](CMakeLists.txt). Rename the project and the executable to whatever name you want.
1. If you want to add or remove any .cpp files, change the source files listed in the [`add_executable`](CMakeLists.txt#L10) call in CMakeLists.txt to match the source files your project requires. If you plan on keeping the default main.cpp file then no changes are required.
1. If you use Linux, install SFML's dependencies using your system package manager. On Ubuntu and other Debian-based distributions you can use the following commands:
```
sudo apt update
sudo apt install \
libxrandr-dev \
libxcursor-dev \
libudev-dev \
libfreetype-dev \
libopenal-dev \
libflac-dev \
libvorbis-dev \
libgl1-mesa-dev \
libegl1-mesa-dev
```
1. Configure and build your project. Most popular IDEs support CMake projects with very little effort on your part.
- [VS Code](https://code.visualstudio.com) via the [CMake extension](https://code.visualstudio.com/docs/cpp/cmake-linux)
- [Visual Studio](https://docs.microsoft.com/en-us/cpp/build/cmake-projects-in-visual-studio?view=msvc-170)
- [CLion](https://www.jetbrains.com/clion/features/cmake-support.html)
- [Qt Creator](https://doc.qt.io/qtcreator/creator-project-cmake.html)
Using CMake from the command line is straightforward as well.
For a single-configuration generator (typically the case on Linux and macOS):
```
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
```
For a multi-configuration generator (typically the case on Windows):
```
cmake -S . -B build
cmake --build build --config Release
```
1. Enjoy!
## Upgrading SFML
SFML is found via CMake's [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html) module.
FetchContent automatically downloads SFML from GitHub and builds it alongside your own code.
Beyond the convenience of not having to install SFML yourself, this ensures ABI compatability and simplifies things like specifying static versus shared libraries.
Modifying what version of SFML you want is as easy as changing the [`GIT_TAG`](CMakeLists.txt#L7) argument.
Currently it uses the latest in-development version of SFML 2 via the `2.6.x` tag.
If you're feeling adventurous and want to give SFML 3 a try, use the `master` tag.
Beware, this requires changing your code to suit the modified API!
The nice folks in the [SFML community](https://github.com/SFML/SFML#community) can help you with that transition and the bugs you may encounter along the way.
## But I want to...
Modify CMake options by adding them as configuration parameters (with a `-D` flag) or by modifying the contents of CMakeCache.txt and rebuilding.
### Use Static Libraries
By default SFML builds shared libraries and this default is inherited by your project.
CMake's [`BUILD_SHARED_LIBS`](https://cmake.org/cmake/help/latest/variable/BUILD_SHARED_LIBS.html) option lets you pick static or shared libraries for the entire project.
### Change Compilers
See the variety of [`CMAKE_<LANG>_COMPILER`](https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_COMPILER.html) options.
In particular you'll want to modify `CMAKE_CXX_COMPILER` to point to the C++ compiler you wish to use.
### Change Compiler Optimizations
CMake abstracts away specific optimizer flags through the [`CMAKE_BUILD_TYPE`](https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html) option.
By default this project recommends `Release` builds which enable optimizations.
Other build types include `Debug` builds which enable debug symbols but disable optimizations.
If you're using a multi-configuration generator (as is often the case on Windows), you can modify the [`CMAKE_CONFIGURATION_TYPES`](https://cmake.org/cmake/help/latest/variable/CMAKE_CONFIGURATION_TYPES.html#variable:CMAKE_CONFIGURATION_TYPES) option.
### Change Generators
While CMake will attempt to pick a suitable default generator, some systems offer a number of generators to choose from.
Ubuntu, for example, offers Makefiles and Ninja as two potential options.
For a list of generators, click [here](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html).
To modify the generator you're using you must reconfigure your project providing a `-G` flag with a value corresponding to the generator you want.
You can't simply modify an entry in the CMakeCache.txt file unlike the above options.
Then you may rebuild your project with this new generator.
## More Reading
Here are some useful resources if you want to learn more about CMake:
- [How to Use CMake Without the Agonizing Pain - Part 1](https://alexreinking.com/blog/how-to-use-cmake-without-the-agonizing-pain-part-1.html)
- [How to Use CMake Without the Agonizing Pain - Part 2](https://alexreinking.com/blog/how-to-use-cmake-without-the-agonizing-pain-part-2.html)
- [Better CMake YouTube series by Jefferon Amstutz](https://www.youtube.com/playlist?list=PL8i3OhJb4FNV10aIZ8oF0AA46HgA2ed8g)
## License
The source code is dual licensed under Public Domain and MIT -- choose whichever you prefer.

8
include/query.hpp Normal file
View File

@ -0,0 +1,8 @@
#ifndef QUERY_HPP
#define QUERY_HPP
class Query {
};
#endif

267
src/main.cpp Normal file
View File

@ -0,0 +1,267 @@
#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;
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;
}
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(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(55, 55);
// Button
sf::RectangleShape button(sf::Vector2f(100, 30));
button.setPosition(width - border_size - button.getSize().x, 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(
button.getPosition().x + button.getSize().x / 2 - //
buttonText.getCharacterSize() * buttonText.getString().getSize() / 2,
52);
// Query result area
sf::RectangleShape resultBox(sf::Vector2f(width * 7.f / 8 - 4, height * 5.f / 6));
resultBox.setPosition(2, 2);
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, 0);
sf::View resultView(sf::FloatRect(0.f, 0.f, width * 7.f / 8 - 2, height * 5.f / 6 - 100));
resultView.setViewport(sf::FloatRect(1.f / 16, 100.f / height, 7.f / 8, 1.f));
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();
for (const auto &result : results)
{
resultStr += result.keyword + L"\n" + result.content + L"\n\n";
}
}
}
}
if (event.type == sf::Event::MouseWheelScrolled)
{
if (event.mouseWheelScroll.wheel == sf::Mouse::VerticalWheel)
{
offset -= 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));
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);
resultBox.setSize(sf::Vector2f(width - border_size * 2 - 4, height - 100.f - border_size - 4));
resultView.setViewport(sf::FloatRect(border_size / width, 100.f / height, (width - border_size * 2) / width, (height - 100.f - border_size) / height));
}
}
setTextWithWrap(resultText, resultStr, font, font_size, width * 7.f / 8 - 14);
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);
window.draw(button);
window.draw(buttonText);
resultView.reset(sf::FloatRect(0.f, 0.f, width - border_size * 2, height - 100.f - border_size));
window.setView(resultView);
window.draw(resultBox);
resultView.move(sf::Vector2f(0, offset));
window.setView(resultView);
window.draw(resultText);
window.display();
}
return 0;
}

1
src/query.cpp Normal file
View File

@ -0,0 +1 @@
#include <query.hpp>