1
0
mirror of synced 2024-11-28 09:30:51 +01:00

impr: Various code cleanup

This commit is contained in:
WerWolv 2023-08-26 12:54:52 +02:00
parent bfc835fc54
commit ba66005585
9 changed files with 267 additions and 16 deletions

View File

@ -20,68 +20,127 @@ namespace hex {
public:
explicit Achievement(std::string unlocalizedCategory, std::string unlocalizedName) : m_unlocalizedCategory(std::move(unlocalizedCategory)), m_unlocalizedName(std::move(unlocalizedName)) { }
/**
* @brief Returns the unlocalized name of the achievement
* @return Unlocalized name of the achievement
*/
[[nodiscard]] const std::string &getUnlocalizedName() const {
return this->m_unlocalizedName;
}
/**
* @brief Returns the unlocalized category of the achievement
* @return Unlocalized category of the achievement
*/
[[nodiscard]] const std::string &getUnlocalizedCategory() const {
return this->m_unlocalizedCategory;
}
/**
* @brief Returns whether the achievement is unlocked
* @return Whether the achievement is unlocked
*/
[[nodiscard]] bool isUnlocked() const {
return this->m_progress == this->m_maxProgress;
}
/**
* @brief Sets the description of the achievement
* @param description Description of the achievement
* @return Reference to the achievement
*/
Achievement& setDescription(std::string description) {
this->m_unlocalizedDescription = std::move(description);
return *this;
}
/**
* @brief Adds a requirement to the achievement. The achievement will only be unlockable if all requirements are unlocked.
* @param requirement Unlocalized name of the requirement
* @return Reference to the achievement
*/
Achievement& addRequirement(std::string requirement) {
this->m_requirements.emplace_back(std::move(requirement));
return *this;
}
/**
* @brief Adds a visibility requirement to the achievement. The achievement will only be visible if all requirements are unlocked.
* @param requirement Unlocalized name of the requirement
* @return Reference to the achievement
*/
Achievement& addVisibilityRequirement(std::string requirement) {
this->m_visibilityRequirements.emplace_back(std::move(requirement));
return *this;
}
/**
* @brief Marks the achievement as blacked. Blacked achievements are visible but their name and description are hidden.
* @return Reference to the achievement
*/
Achievement& setBlacked() {
this->m_blacked = true;
return *this;
}
/**
* @brief Marks the achievement as invisible. Invisible achievements are not visible at all.
* @return Reference to the achievement
*/
Achievement& setInvisible() {
this->m_invisible = true;
return *this;
}
/**
* @brief Returns whether the achievement is blacked
* @return Whether the achievement is blacked
*/
[[nodiscard]] bool isBlacked() const {
return this->m_blacked;
}
/**
* @brief Returns whether the achievement is invisible
* @return Whether the achievement is invisible
*/
[[nodiscard]] bool isInvisible() const {
return this->m_invisible;
}
/**
* @brief Returns the list of requirements of the achievement
* @return List of requirements of the achievement
*/
[[nodiscard]] const std::vector<std::string> &getRequirements() const {
return this->m_requirements;
}
/**
* @brief Returns the list of visibility requirements of the achievement
* @return List of visibility requirements of the achievement
*/
[[nodiscard]] const std::vector<std::string> &getVisibilityRequirements() const {
return this->m_visibilityRequirements;
}
/**
* @brief Returns the unlocalized description of the achievement
* @return Unlocalized description of the achievement
*/
[[nodiscard]] const std::string &getUnlocalizedDescription() const {
return this->m_unlocalizedDescription;
}
/**
* @brief Returns the icon of the achievement
* @return Icon of the achievement
*/
[[nodiscard]] const ImGui::Texture &getIcon() const {
if (this->m_iconData.empty())
return this->m_icon;
@ -94,6 +153,11 @@ namespace hex {
return this->m_icon;
}
/**
* @brief Sets the icon of the achievement
* @param data Icon data
* @return Reference to the achievement
*/
Achievement& setIcon(std::span<const std::byte> data) {
this->m_iconData.reserve(data.size());
for (auto &byte : data)
@ -102,19 +166,34 @@ namespace hex {
return *this;
}
/**
* @brief Sets the icon of the achievement
* @param data Icon data
* @return Reference to the achievement
*/
Achievement& setIcon(std::span<const u8> data) {
this->m_iconData.assign(data.begin(), data.end());
return *this;
}
/**
* @brief Sets the icon of the achievement
* @param data Icon data
* @return Reference to the achievement
*/
Achievement& setIcon(std::vector<u8> data) {
this->m_iconData = std::move(data);
return *this;
}
Achievement& setIcon(std::vector<std::byte> data) {
/**
* @brief Sets the icon of the achievement
* @param data Icon data
* @return Reference to the achievement
*/
Achievement& setIcon(const std::vector<std::byte> &data) {
this->m_iconData.reserve(data.size());
for (auto &byte : data)
this->m_iconData.emplace_back(static_cast<u8>(byte));
@ -122,32 +201,61 @@ namespace hex {
return *this;
}
/**
* @brief Specifies the required progress to unlock the achievement. This is the number of times this achievement has to be triggered to unlock it. The default is 1.
* @param progress Required progress
* @return Reference to the achievement
*/
Achievement& setRequiredProgress(u32 progress) {
this->m_maxProgress = progress;
return *this;
}
/**
* @brief Returns the required progress to unlock the achievement
* @return Required progress to unlock the achievement
*/
[[nodiscard]] u32 getRequiredProgress() const {
return this->m_maxProgress;
}
/**
* @brief Returns the current progress of the achievement
* @return Current progress of the achievement
*/
[[nodiscard]] u32 getProgress() const {
return this->m_progress;
}
/**
* @brief Sets the callback to call when the achievement is clicked
* @param callback Callback to call when the achievement is clicked
*/
void setClickCallback(const std::function<void(Achievement &)> &callback) {
this->m_clickCallback = callback;
}
/**
* @brief Returns the callback to call when the achievement is clicked
* @return Callback to call when the achievement is clicked
*/
[[nodiscard]] const std::function<void(Achievement &)> &getClickCallback() const {
return this->m_clickCallback;
}
/**
* @brief Returns whether the achievement is temporary. Temporary achievements have been added by challenge projects for example and will be removed when the project is closed.
* @return Whether the achievement is temporary
*/
[[nodiscard]] bool isTemporary() const {
return this->m_temporary;
}
/**
* @brief Sets whether the achievement is unlocked
* @param unlocked Whether the achievement is unlocked
*/
void setUnlocked(bool unlocked) {
if (unlocked) {
if (this->m_progress < this->m_maxProgress)
@ -210,6 +318,12 @@ namespace hex {
}
};
/**
* @brief Adds a new achievement
* @tparam T Type of the achievement
* @param args Arguments to pass to the constructor of the achievement
* @return Reference to the achievement
*/
template<std::derived_from<Achievement> T = Achievement>
static Achievement& addAchievement(auto && ... args) {
auto newAchievement = std::make_unique<T>(std::forward<decltype(args)>(args)...);
@ -228,6 +342,12 @@ namespace hex {
return *achievement;
}
/**
* @brief Adds a new temporary achievement
* @tparam T Type of the achievement
* @param args Arguments to pass to the constructor of the achievement
* @return Reference to the achievement
*/
template<std::derived_from<Achievement> T = Achievement>
static Achievement& addTemporaryAchievement(auto && ... args) {
auto &achievement = addAchievement(std::forward<decltype(args)>(args)...);
@ -237,17 +357,52 @@ namespace hex {
return achievement;
}
/**
* @brief Unlocks an achievement
* @param unlocalizedCategory Unlocalized category of the achievement
* @param unlocalizedName Unlocalized name of the achievement
*/
static void unlockAchievement(const std::string &unlocalizedCategory, const std::string &unlocalizedName);
/**
* @brief Returns all registered achievements
* @return All achievements
*/
static std::unordered_map<std::string, std::unordered_map<std::string, std::unique_ptr<Achievement>>>& getAchievements();
/**
* @brief Returns all achievement start nodes
* @note Start nodes are all nodes that don't have any parents
* @param rebuild Whether to rebuild the list of start nodes
* @return All achievement start nodes
*/
static std::unordered_map<std::string, std::vector<AchievementNode*>>& getAchievementStartNodes(bool rebuild = true);
/**
* @brief Returns all achievement nodes
* @param rebuild Whether to rebuild the list of nodes
* @return All achievement nodes
*/
static std::unordered_map<std::string, std::list<AchievementNode>>& getAchievementNodes(bool rebuild = true);
/**
* @brief Loads the progress of all achievements from the achievements save file
*/
static void loadProgress();
/**
* @brief Stores the progress of all achievements to the achievements save file
*/
static void storeProgress();
/**
* @brief Removes all registered achievements from the tree
*/
static void clear();
/**
* @brief Removes all temporary achievements from the tree
*/
static void clearTemporary();
private:

View File

@ -43,7 +43,9 @@ namespace hex {
}
}
constexpr bool operator==(const EventId &rhs) const = default;
constexpr bool operator==(const EventId &other) const {
return this->m_hash == other.m_hash;
}
private:
u32 m_hash;
@ -67,6 +69,9 @@ namespace hex {
Callback m_func;
};
template<typename T>
concept EventType = std::derived_from<T, EventBase>;
}
@ -84,7 +89,7 @@ namespace hex {
* @param function Function to call when the event is posted
* @return Token to unsubscribe from the event
*/
template<typename E>
template<impl::EventType E>
static EventList::iterator subscribe(typename E::Callback function) {
auto &events = getEvents();
return events.insert(events.end(), std::make_pair(E::Id, std::make_unique<E>(function)));
@ -96,7 +101,7 @@ namespace hex {
* @param token Unique token to register the event to. Later required to unsubscribe again
* @param function Function to call when the event is posted
*/
template<typename E>
template<impl::EventType E>
static void subscribe(void *token, typename E::Callback function) {
getTokenStore().insert(std::make_pair(token, subscribe<E>(function)));
}
@ -114,7 +119,7 @@ namespace hex {
* @tparam E Event
* @param token Token passed to subscribe
*/
template<typename E>
template<impl::EventType E>
static void unsubscribe(void *token) noexcept {
auto &tokenStore = getTokenStore();
auto iter = std::find_if(tokenStore.begin(), tokenStore.end(), [&](auto &item) {
@ -133,7 +138,7 @@ namespace hex {
* @tparam E Event
* @param args Arguments to pass to the event
*/
template<typename E>
template<impl::EventType E>
static void post(auto &&...args) noexcept {
for (const auto &[id, event] : getEvents()) {
if (id == E::Id) {

View File

@ -18,14 +18,44 @@ namespace hex {
std::fs::path path;
};
/**
* @brief Save the current layout
* @param name Name of the layout
*/
static void save(const std::string &name);
/**
* @brief Load a layout from a file
* @param path Path to the layout file
*/
static void load(const std::fs::path &path);
/**
* @brief Load a layout from a string
* @param content Layout string
*/
static void loadString(const std::string &content);
/**
* @brief Get a list of all layouts
* @return List of all added layouts
*/
static std::vector<Layout> getLayouts();
/**
* @brief Handles loading of layouts if needed
* @note This function should only be called by ImHex
*/
static void process();
/**
* @brief Reload all layouts
*/
static void reload();
/**
* @brief Reset the layout manager
*/
static void reset();
private:

View File

@ -115,6 +115,11 @@ namespace hex {
std::weak_ptr<Task> m_task;
};
struct Timer {
std::chrono::time_point<std::chrono::steady_clock> elapseTime;
std::function<void()> callback;
};
/**
* @brief The Task Manager is responsible for running and managing asynchronous tasks
*/
@ -144,7 +149,6 @@ namespace hex {
*/
static TaskHolder createBackgroundTask(std::string name, std::function<void(Task &)> function);
/**
* @brief Creates a new synchronous task that will execute the given function at the start of the next frame
* @param function Function to be executed
@ -157,6 +161,12 @@ namespace hex {
*/
static void runWhenTasksFinished(const std::function<void()> &function);
/**
* @brief Creates a callback that will be executed after the given time
* @param duration Time to wait
* @param function Function to be executed
*/
static void doAfter(std::chrono::duration<i64> duration, const std::function<void()> &function);
static void collectGarbage();
@ -164,6 +174,7 @@ namespace hex {
static size_t getRunningBackgroundTaskCount();
static std::list<std::shared_ptr<Task>> &getRunningTasks();
static std::list<Timer> &getTimers();
static void runDeferredCalls();
private:

View File

@ -48,6 +48,7 @@ namespace ImGui {
public:
Texture() = default;
Texture(const ImU8 *buffer, int size, int width = 0, int height = 0);
Texture(std::span<const std::byte> bytes, int width = 0, int height = 0);
explicit Texture(const char *path);
Texture(unsigned int texture, int width, int height);
Texture(const Texture&) = delete;

View File

@ -19,6 +19,7 @@ namespace hex {
std::mutex s_deferredCallsMutex, s_tasksFinishedMutex;
std::list<std::shared_ptr<Task>> s_tasks, s_taskQueue;
std::list<Timer> s_timers;
std::list<std::function<void()>> s_deferredCalls;
std::list<std::function<void()>> s_tasksFinishedCallbacks;
@ -300,12 +301,17 @@ namespace hex {
call();
s_tasksFinishedCallbacks.clear();
}
}
std::list<std::shared_ptr<Task>> &TaskManager::getRunningTasks() {
return s_tasks;
}
std::list<Timer> &TaskManager::getTimers() {
return s_timers;
}
size_t TaskManager::getRunningTaskCount() {
std::unique_lock lock(s_queueMutex);
@ -336,6 +342,12 @@ namespace hex {
call();
s_deferredCalls.clear();
for (const auto &timer : s_timers) {
if (timer.elapseTime >= std::chrono::steady_clock::now()) {
timer.callback();
}
}
}
void TaskManager::runWhenTasksFinished(const std::function<void()> &function) {
@ -344,4 +356,8 @@ namespace hex {
s_tasksFinishedCallbacks.push_back(function);
}
void TaskManager::doAfter(std::chrono::duration<i64> duration, const std::function<void()> &function) {
s_timers.push_back({ std::chrono::steady_clock::now() + duration, function });
}
}

View File

@ -48,6 +48,8 @@ namespace ImGui {
this->m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
}
Texture::Texture(std::span<const std::byte> bytes, int width, int height) : Texture(reinterpret_cast<const ImU8*>(bytes.data()), bytes.size(), width, height) { }
Texture::Texture(const char *path) {
unsigned char *imageData = stbi_load(path, &this->m_width, &this->m_height, nullptr, 4);
if (imageData == nullptr)

View File

@ -15,6 +15,7 @@ namespace hex::plugin::builtin {
ViewAbout::ViewAbout() : View("hex.builtin.view.help.about.name") {
// Add "About" menu item to the help menu
ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.help", "hex.builtin.view.help.about.name" }, 1000, Shortcut::None, [this] {
TaskManager::doLater([] { ImGui::OpenPopup(View::toWindowName("hex.builtin.view.help.about.name").c_str()); });
this->m_aboutWindowOpen = true;
@ -23,6 +24,7 @@ namespace hex::plugin::builtin {
ContentRegistry::Interface::addMenuItemSeparator({ "hex.builtin.menu.help" }, 2000);
// Add documentation links to the help menu
ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.help", "hex.builtin.view.help.documentation" }, 3000, Shortcut::None, [] {
hex::openWebpage("https://docs.werwolv.net/imhex");
AchievementManager::unlockAchievement("hex.builtin.achievement.starting_out", "hex.builtin.achievement.starting_out.docs.name");
@ -31,18 +33,23 @@ namespace hex::plugin::builtin {
ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.help", "hex.builtin.menu.help.ask_for_help" }, 4000, CTRLCMD + SHIFT + Keys::D, [] {
PopupDocsQuestion::open();
});
this->m_logoTexture = ImGui::Texture(romfs::get("assets/common/logo.png").span());
}
static void link(const std::string &name, const std::string &author, const std::string &url) {
// Draw the hyperlink and open the URL if clicked
if (ImGui::BulletHyperlink(name.c_str()))
hex::openWebpage(url);
// Show the URL as a tooltip
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::TextFormatted("{}", url);
ImGui::EndTooltip();
}
// Show the author if there is one
if (!author.empty()) {
ImGui::SameLine(0, 0);
ImGui::TextFormatted("by {}", author);
@ -50,28 +57,33 @@ namespace hex::plugin::builtin {
}
void ViewAbout::drawAboutMainPage() {
// Draw main about table
if (ImGui::BeginTable("about_table", 2, ImGuiTableFlags_SizingFixedFit)) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
if (!this->m_logoTexture.isValid()) {
auto logo = romfs::get("assets/common/logo.png");
this->m_logoTexture = ImGui::Texture(reinterpret_cast<const ImU8 *>(logo.data()), logo.size());
}
// Draw the ImHex icon
ImGui::Image(this->m_logoTexture, scaled({ 64, 64 }));
ImGui::TableNextColumn();
// Draw basic information about ImHex and its version
ImGui::TextFormatted("ImHex Hex Editor v{} by WerWolv - " ICON_FA_CODE_BRANCH, ImHexApi::System::getImHexVersion());
ImGui::SameLine();
// Draw clickable link to the current commit
if (ImGui::Hyperlink(hex::format("{0}@{1}", ImHexApi::System::getCommitBranch(), ImHexApi::System::getCommitHash()).c_str()))
hex::openWebpage("https://github.com/WerWolv/ImHex/commit/" + ImHexApi::System::getCommitHash(true));
// Draw the author of the current translation
ImGui::TextUnformatted("hex.builtin.view.help.about.translator"_lang);
// Draw information about the open-source nature of ImHex
ImGui::TextUnformatted("hex.builtin.view.help.about.source"_lang);
ImGui::SameLine();
//Draw clickable link to the GitHub repository
if (ImGui::Hyperlink("WerWolv/ImHex"))
hex::openWebpage("https://github.com/WerWolv/ImHex");
@ -80,6 +92,7 @@ namespace hex::plugin::builtin {
ImGui::NewLine();
// Draw donation links
ImGui::TextUnformatted("hex.builtin.view.help.about.donations"_lang);
ImGui::Separator();
@ -99,6 +112,13 @@ namespace hex::plugin::builtin {
ImGui::TextFormattedWrapped("These amazing people have contributed to ImHex in the past. If you'd like to become part of them, please submit a PR to the GitHub Repository!");
ImGui::NewLine();
// Draw main ImHex contributors
link("iTrooz for a huge amount of help maintaining ImHex and the CI", "", "https://github.com/iTrooz");
link("jumanji144 for a ton of help with the Pattern Language, API and usage stats", "", "https://github.com/Nowilltolife");
ImGui::NewLine();
// Draw additional contributors
link("Mary for porting ImHex to MacOS", "", "https://github.com/Thog");
link("Roblabla for adding the MSI Windows installer", "", "https://github.com/roblabla");
link("jam1garner for adding support for Rust plugins", "", "https://github.com/jam1garner");
@ -111,6 +131,7 @@ namespace hex::plugin::builtin {
void ViewAbout::drawLibraryCreditsPage() {
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.2F, 0.2F, 0.2F, 0.3F));
// Draw ImGui dependencies
link("ImGui", "ocornut", "https://github.com/ocornut/imgui/");
link("imgui_club", "ocornut", "https://github.com/ocornut/imgui_club/");
link("imnodes", "Nelarius", "https://github.com/Nelarius/imnodes/");
@ -119,6 +140,7 @@ namespace hex::plugin::builtin {
ImGui::NewLine();
// Draw dependencies maintained by individual people
link("capstone", "aquynh", "https://github.com/aquynh/capstone/");
link("JSON for Modern C++", "nlohmann", "https://github.com/nlohmann/json/");
link("YARA", "VirusTotal", "https://github.com/VirusTotal/yara/");
@ -127,12 +149,13 @@ namespace hex::plugin::builtin {
link("microtar", "rxi", "https://github.com/rxi/microtar/");
link("xdgpp", "danyspin97", "https://sr.ht/~danyspin97/xdgpp/");
link("FreeType", "David Turner", "https://gitlab.freedesktop.org/freetype/freetype/");
link("Mbed TLS", "ARM", "https://github.com/ARMmbed/mbedtls/");
link("mbedTLS", "ARM", "https://github.com/ARMmbed/mbedtls/");
link("libcurl", "Daniel Stenberg", "https://curl.se/");
link("libfmt", "vitaut", "https://fmt.dev/");
ImGui::NewLine();
// Draw dependencies maintained by groups
link("GNU libmagic", "", "https://www.darwinsys.com/file/");
link("GLFW3", "", "https://github.com/glfw/glfw/");
link("LLVM", "", "https://github.com/llvm/llvm-project/");
@ -148,7 +171,8 @@ namespace hex::plugin::builtin {
ImGui::TableSetupColumn("Type");
ImGui::TableSetupColumn("Paths");
constexpr static std::array<std::pair<const char *, fs::ImHexPath>, u32(fs::ImHexPath::END)-1> PathTypes = {
// Specify the types of paths to display
constexpr static std::array<std::pair<const char *, fs::ImHexPath>, size_t(fs::ImHexPath::END) - 1U> PathTypes = {
{
{ "Patterns", fs::ImHexPath::Patterns },
{ "Patterns Includes", fs::ImHexPath::PatternsInclude },
@ -169,6 +193,7 @@ namespace hex::plugin::builtin {
}
};
// Draw the table
ImGui::TableHeadersRow();
for (const auto &[name, type] : PathTypes) {
ImGui::TableNextRow();
@ -177,6 +202,7 @@ namespace hex::plugin::builtin {
ImGui::TableNextColumn();
for (auto &path : fs::getDefaultPaths(type, true)){
// Draw hyperlink to paths that exist or red text if they don't
if (wolv::io::fs::isDirectory(path)){
if (ImGui::Hyperlink(wolv::util::toUTF8String(path).c_str())) {
fs::openFolderExternal(path);
@ -198,11 +224,13 @@ namespace hex::plugin::builtin {
void ViewAbout::drawAboutPopup() {
if (ImGui::BeginPopupModal(View::toWindowName("hex.builtin.view.help.about.name").c_str(), &this->m_aboutWindowOpen)) {
// Allow window to be closed by pressing ESC
if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_Escape)))
ImGui::CloseCurrentPopup();
if (ImGui::BeginTabBar("about_tab_bar")) {
// Draw main ImHex tab
if (ImGui::BeginTabItem("ImHex")) {
if (ImGui::BeginChild(1)) {
this->drawAboutMainPage();
@ -211,6 +239,7 @@ namespace hex::plugin::builtin {
ImGui::EndTabItem();
}
// Draw contributors tab
if (ImGui::BeginTabItem("hex.builtin.view.help.about.contributor"_lang)) {
ImGui::NewLine();
if (ImGui::BeginChild(1)) {
@ -220,6 +249,7 @@ namespace hex::plugin::builtin {
ImGui::EndTabItem();
}
// Draw libraries tab
if (ImGui::BeginTabItem("hex.builtin.view.help.about.libs"_lang)) {
ImGui::NewLine();
if (ImGui::BeginChild(1)) {
@ -229,6 +259,7 @@ namespace hex::plugin::builtin {
ImGui::EndTabItem();
}
// Draw paths tab
if (ImGui::BeginTabItem("hex.builtin.view.help.about.paths"_lang)) {
ImGui::NewLine();
if (ImGui::BeginChild(1)) {
@ -238,6 +269,7 @@ namespace hex::plugin::builtin {
ImGui::EndTabItem();
}
// Draw license tab
if (ImGui::BeginTabItem("hex.builtin.view.help.about.license"_lang)) {
ImGui::NewLine();
if (ImGui::BeginChild(1)) {

View File

@ -1,8 +1,7 @@
#include "content/views/view_achievements.hpp"
#include <hex/api/content_registry.hpp>
#include <wolv/utils/guards.hpp>
#include <hex/api/task.hpp>
#include <cmath>