2020-12-22 18:10:01 +01:00
|
|
|
#pragma once
|
|
|
|
|
2021-01-11 21:11:03 +01:00
|
|
|
#include <hex.hpp>
|
|
|
|
|
2021-03-27 11:36:36 +01:00
|
|
|
#include <list>
|
|
|
|
#include <map>
|
|
|
|
#include <string_view>
|
2020-12-22 18:10:01 +01:00
|
|
|
#include <functional>
|
|
|
|
|
2021-03-27 11:36:36 +01:00
|
|
|
#include <hex/api/imhex_api.hpp>
|
2022-03-04 11:36:37 +01:00
|
|
|
#include <hex/helpers/fs.hpp>
|
2023-05-02 20:35:30 +02:00
|
|
|
#include <hex/helpers/logger.hpp>
|
2020-12-22 18:10:01 +01:00
|
|
|
|
2023-05-02 20:35:30 +02:00
|
|
|
#include <wolv/types/type_name.hpp>
|
|
|
|
|
2023-06-10 15:08:56 +02:00
|
|
|
#define EVENT_DEF_IMPL(event_name, event_name_string, should_log, ...) \
|
|
|
|
struct event_name final : public hex::impl::Event<__VA_ARGS__> { \
|
|
|
|
constexpr static auto Id = [] { return hex::impl::EventId(event_name_string); }(); \
|
|
|
|
constexpr static auto ShouldLog = (should_log); \
|
|
|
|
explicit event_name(Callback func) noexcept : Event(std::move(func)) { } \
|
2021-09-08 15:18:24 +02:00
|
|
|
}
|
2020-12-22 18:10:01 +01:00
|
|
|
|
2023-06-10 15:08:56 +02:00
|
|
|
#define EVENT_DEF(event_name, ...) EVENT_DEF_IMPL(event_name, #event_name, true, __VA_ARGS__)
|
|
|
|
#define EVENT_DEF_NO_LOG(event_name, ...) EVENT_DEF_IMPL(event_name, #event_name, false, __VA_ARGS__)
|
2023-05-02 20:35:30 +02:00
|
|
|
|
2023-08-06 21:33:15 +02:00
|
|
|
|
|
|
|
/* Forward declarations */
|
2022-03-27 00:01:28 +01:00
|
|
|
struct GLFWwindow;
|
2023-08-06 21:33:15 +02:00
|
|
|
namespace hex { class Achievement; }
|
|
|
|
|
2020-12-22 18:10:01 +01:00
|
|
|
|
2021-03-27 11:36:36 +01:00
|
|
|
namespace hex {
|
2020-12-22 18:10:01 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
namespace impl {
|
|
|
|
|
|
|
|
class EventId {
|
|
|
|
public:
|
2023-06-10 15:08:56 +02:00
|
|
|
explicit constexpr EventId(const char *eventName) {
|
|
|
|
this->m_hash = 0x811C'9DC5;
|
|
|
|
for (auto c : std::string_view(eventName)) {
|
2023-03-21 15:33:43 +01:00
|
|
|
this->m_hash = (this->m_hash >> 5) | (this->m_hash << 27);
|
|
|
|
this->m_hash ^= c;
|
|
|
|
}
|
2021-03-27 11:36:36 +01:00
|
|
|
}
|
2021-01-11 20:31:40 +01:00
|
|
|
|
2023-08-26 12:54:52 +02:00
|
|
|
constexpr bool operator==(const EventId &other) const {
|
|
|
|
return this->m_hash == other.m_hash;
|
|
|
|
}
|
2021-01-11 21:11:03 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
private:
|
|
|
|
u32 m_hash;
|
|
|
|
};
|
2021-01-11 21:11:03 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
struct EventBase {
|
|
|
|
EventBase() noexcept = default;
|
|
|
|
};
|
2020-12-22 18:10:01 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
template<typename... Params>
|
|
|
|
struct Event : public EventBase {
|
|
|
|
using Callback = std::function<void(Params...)>;
|
2021-03-27 11:36:36 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
explicit Event(Callback func) noexcept : m_func(std::move(func)) { }
|
2021-03-27 11:36:36 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
void operator()(Params... params) const noexcept {
|
|
|
|
this->m_func(params...);
|
|
|
|
}
|
2021-03-27 11:36:36 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
private:
|
|
|
|
Callback m_func;
|
|
|
|
};
|
2020-12-22 18:10:01 +01:00
|
|
|
|
2023-08-26 12:54:52 +02:00
|
|
|
template<typename T>
|
|
|
|
concept EventType = std::derived_from<T, EventBase>;
|
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief The EventManager allows subscribing to and posting events to different parts of the program.
|
|
|
|
* To create a new event, use the EVENT_DEF macro. This will create a new event type with the given name and parameters
|
|
|
|
*/
|
2020-12-22 18:10:01 +01:00
|
|
|
class EventManager {
|
|
|
|
public:
|
2023-06-11 10:47:17 +02:00
|
|
|
using EventList = std::list<std::pair<impl::EventId, std::unique_ptr<impl::EventBase>>>;
|
2023-03-21 15:33:43 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Subscribes to an event
|
|
|
|
* @tparam E Event
|
|
|
|
* @param function Function to call when the event is posted
|
|
|
|
* @return Token to unsubscribe from the event
|
|
|
|
*/
|
2023-08-26 12:54:52 +02:00
|
|
|
template<impl::EventType E>
|
2022-02-08 18:38:54 +01:00
|
|
|
static EventList::iterator subscribe(typename E::Callback function) {
|
2023-07-26 13:50:51 +02:00
|
|
|
auto &events = getEvents();
|
|
|
|
return events.insert(events.end(), std::make_pair(E::Id, std::make_unique<E>(function)));
|
2021-03-27 11:36:36 +01:00
|
|
|
}
|
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
/**
|
|
|
|
* @brief Subscribes to an event
|
|
|
|
* @tparam E Event
|
|
|
|
* @param token Unique token to register the event to. Later required to unsubscribe again
|
|
|
|
* @param function Function to call when the event is posted
|
|
|
|
*/
|
2023-08-26 12:54:52 +02:00
|
|
|
template<impl::EventType E>
|
2021-03-27 11:36:36 +01:00
|
|
|
static void subscribe(void *token, typename E::Callback function) {
|
2023-07-26 13:50:51 +02:00
|
|
|
getTokenStore().insert(std::make_pair(token, subscribe<E>(function)));
|
2021-03-27 11:36:36 +01:00
|
|
|
}
|
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
/**
|
|
|
|
* @brief Unsubscribes from an event
|
|
|
|
* @param token Token returned by subscribe
|
|
|
|
*/
|
|
|
|
static void unsubscribe(const EventList::iterator &token) noexcept {
|
2023-07-26 13:50:51 +02:00
|
|
|
getEvents().erase(token);
|
2021-03-27 11:36:36 +01:00
|
|
|
}
|
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
/**
|
|
|
|
* @brief Unsubscribes from an event
|
|
|
|
* @tparam E Event
|
|
|
|
* @param token Token passed to subscribe
|
|
|
|
*/
|
2023-08-26 12:54:52 +02:00
|
|
|
template<impl::EventType E>
|
2021-03-27 11:36:36 +01:00
|
|
|
static void unsubscribe(void *token) noexcept {
|
2023-07-26 13:50:51 +02:00
|
|
|
auto &tokenStore = getTokenStore();
|
|
|
|
auto iter = std::find_if(tokenStore.begin(), tokenStore.end(), [&](auto &item) {
|
2023-05-02 20:35:30 +02:00
|
|
|
return item.first == token && item.second->first == E::Id;
|
2021-03-27 11:36:36 +01:00
|
|
|
});
|
|
|
|
|
2023-07-26 13:50:51 +02:00
|
|
|
if (iter != tokenStore.end()) {
|
|
|
|
getEvents().remove(*iter->second);
|
|
|
|
tokenStore.erase(iter);
|
2021-03-27 11:36:36 +01:00
|
|
|
}
|
2023-01-01 01:01:24 +01:00
|
|
|
|
2021-03-27 11:36:36 +01:00
|
|
|
}
|
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
/**
|
|
|
|
* @brief Posts an event to all subscribers of it
|
|
|
|
* @tparam E Event
|
|
|
|
* @param args Arguments to pass to the event
|
|
|
|
*/
|
2023-08-26 12:54:52 +02:00
|
|
|
template<impl::EventType E>
|
2022-01-24 20:53:17 +01:00
|
|
|
static void post(auto &&...args) noexcept {
|
2023-07-26 13:50:51 +02:00
|
|
|
for (const auto &[id, event] : getEvents()) {
|
2023-05-02 20:35:30 +02:00
|
|
|
if (id == E::Id) {
|
2023-06-11 10:47:17 +02:00
|
|
|
(*static_cast<E *const>(event.get()))(std::forward<decltype(args)>(args)...);
|
2023-05-02 20:35:30 +02:00
|
|
|
}
|
2021-03-27 11:36:36 +01:00
|
|
|
}
|
2023-05-02 20:35:30 +02:00
|
|
|
|
|
|
|
#if defined (DEBUG)
|
|
|
|
if (E::ShouldLog)
|
|
|
|
log::debug("Event posted: '{}'", wolv::type::getTypeName<E>());
|
|
|
|
#endif
|
2021-03-27 11:36:36 +01:00
|
|
|
}
|
2022-01-24 20:53:17 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
/**
|
|
|
|
* @brief Unsubscribe all subscribers from all events
|
|
|
|
*/
|
2022-08-03 10:45:50 +02:00
|
|
|
static void clear() noexcept {
|
2023-07-26 13:50:51 +02:00
|
|
|
getEvents().clear();
|
|
|
|
getTokenStore().clear();
|
2022-08-03 10:45:50 +02:00
|
|
|
}
|
|
|
|
|
2021-03-27 11:36:36 +01:00
|
|
|
private:
|
2023-07-26 13:50:51 +02:00
|
|
|
static std::map<void *, EventList::iterator>& getTokenStore();
|
|
|
|
static EventList& getEvents();
|
2020-12-22 18:10:01 +01:00
|
|
|
};
|
|
|
|
|
2021-03-27 11:36:36 +01:00
|
|
|
/* Default Events */
|
2023-06-01 18:35:41 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Called when Imhex finished startup, and will enter the main window rendering loop
|
|
|
|
*/
|
|
|
|
EVENT_DEF(EventImHexStartupFinished);
|
|
|
|
|
2022-03-04 11:36:37 +01:00
|
|
|
EVENT_DEF(EventFileLoaded, std::fs::path);
|
2021-03-27 11:36:36 +01:00
|
|
|
EVENT_DEF(EventDataChanged);
|
2022-02-04 00:29:47 +01:00
|
|
|
EVENT_DEF(EventHighlightingChanged);
|
2022-01-24 20:53:17 +01:00
|
|
|
EVENT_DEF(EventWindowClosing, GLFWwindow *);
|
2022-11-08 21:43:22 +01:00
|
|
|
EVENT_DEF(EventRegionSelected, ImHexApi::HexEditor::ProviderRegion);
|
2021-03-27 11:36:36 +01:00
|
|
|
EVENT_DEF(EventSettingsChanged);
|
2021-08-17 13:41:44 +02:00
|
|
|
EVENT_DEF(EventAbnormalTermination, int);
|
2023-05-22 12:00:35 +02:00
|
|
|
EVENT_DEF(EventThemeChanged);
|
2021-09-16 22:23:51 +02:00
|
|
|
EVENT_DEF(EventOSThemeChanged);
|
2023-05-05 22:02:18 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Called when the provider is created.
|
|
|
|
* This event is responsible for (optionally) initializing the provider and calling EventProviderOpened
|
|
|
|
* (although the event can also be called manually without problem)
|
|
|
|
*/
|
2022-01-24 20:53:17 +01:00
|
|
|
EVENT_DEF(EventProviderCreated, prv::Provider *);
|
2022-02-01 18:09:40 +01:00
|
|
|
EVENT_DEF(EventProviderChanged, prv::Provider *, prv::Provider *);
|
2023-05-05 22:02:18 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Called as a continuation of EventProviderCreated
|
|
|
|
* this event is normally called immediately after EventProviderCreated successfully initialized the provider.
|
|
|
|
* If no initialization (Provider::skipLoadInterface() has been set), this event should be called manually
|
|
|
|
* If skipLoadInterface failed, this event is not called
|
|
|
|
*
|
|
|
|
* @note this is not related to Provider::open()
|
|
|
|
*/
|
2022-08-08 21:23:52 +02:00
|
|
|
EVENT_DEF(EventProviderOpened, prv::Provider *);
|
|
|
|
EVENT_DEF(EventProviderClosing, prv::Provider *, bool *);
|
|
|
|
EVENT_DEF(EventProviderClosed, prv::Provider *);
|
2022-07-30 22:01:49 +02:00
|
|
|
EVENT_DEF(EventProviderDeleted, prv::Provider *);
|
2023-04-06 17:36:28 +02:00
|
|
|
EVENT_DEF(EventProviderSaved, prv::Provider *);
|
2022-02-15 22:50:04 +01:00
|
|
|
EVENT_DEF(EventWindowInitialized);
|
2023-04-06 17:36:28 +02:00
|
|
|
EVENT_DEF(EventBookmarkCreated, ImHexApi::Bookmarks::Entry&);
|
|
|
|
EVENT_DEF(EventPatchCreated, u64, u8, u8);
|
|
|
|
EVENT_DEF(EventPatternExecuted, const std::string&);
|
|
|
|
EVENT_DEF(EventPatternEditorChanged, const std::string&);
|
|
|
|
EVENT_DEF(EventStoreContentDownloaded, const std::fs::path&);
|
|
|
|
EVENT_DEF(EventStoreContentRemoved, const std::fs::path&);
|
2023-04-17 16:18:48 +02:00
|
|
|
EVENT_DEF(EventImHexClosing);
|
2023-08-06 21:33:15 +02:00
|
|
|
EVENT_DEF(EventAchievementUnlocked, const Achievement&);
|
2021-03-27 11:36:36 +01:00
|
|
|
|
2023-05-27 16:59:30 +02:00
|
|
|
/**
|
|
|
|
* @brief Called when a project has been loaded
|
|
|
|
*/
|
|
|
|
EVENT_DEF(EventProjectOpened);
|
|
|
|
|
2023-05-02 20:35:30 +02:00
|
|
|
EVENT_DEF_NO_LOG(EventFrameBegin);
|
|
|
|
EVENT_DEF_NO_LOG(EventFrameEnd);
|
|
|
|
EVENT_DEF_NO_LOG(EventSetTaskBarIconState, u32, u32, u32);
|
|
|
|
|
2021-03-27 11:36:36 +01:00
|
|
|
EVENT_DEF(RequestOpenWindow, std::string);
|
|
|
|
EVENT_DEF(RequestSelectionChange, Region);
|
2022-02-01 18:09:40 +01:00
|
|
|
EVENT_DEF(RequestAddBookmark, Region, std::string, std::string, color_t);
|
2021-09-26 21:18:25 +02:00
|
|
|
EVENT_DEF(RequestSetPatternLanguageCode, std::string);
|
2023-04-01 11:18:52 +02:00
|
|
|
EVENT_DEF(RequestLoadPatternLanguageFile, std::fs::path);
|
|
|
|
EVENT_DEF(RequestSavePatternLanguageFile, std::fs::path);
|
2023-01-07 17:31:22 +01:00
|
|
|
EVENT_DEF(RequestUpdateWindowTitle);
|
2021-08-21 13:53:50 +02:00
|
|
|
EVENT_DEF(RequestCloseImHex, bool);
|
2022-08-16 11:48:37 +02:00
|
|
|
EVENT_DEF(RequestRestartImHex);
|
2022-03-04 11:36:37 +01:00
|
|
|
EVENT_DEF(RequestOpenFile, std::fs::path);
|
2022-12-29 19:26:00 +01:00
|
|
|
EVENT_DEF(RequestChangeTheme, std::string);
|
2021-09-26 21:18:25 +02:00
|
|
|
EVENT_DEF(RequestOpenPopup, std::string);
|
2023-05-05 22:02:18 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Creates a provider from it's unlocalized name, and add it to the provider list
|
|
|
|
*/
|
2023-06-08 17:02:16 +02:00
|
|
|
EVENT_DEF(RequestCreateProvider, std::string, bool, bool, hex::prv::Provider **);
|
2023-02-16 18:06:40 +01:00
|
|
|
EVENT_DEF(RequestInitThemeHandlers);
|
2021-08-21 13:53:50 +02:00
|
|
|
|
2023-04-08 00:58:53 +02:00
|
|
|
EVENT_DEF(RequestOpenInfoPopup, const std::string);
|
|
|
|
EVENT_DEF(RequestOpenErrorPopup, const std::string);
|
|
|
|
EVENT_DEF(RequestOpenFatalPopup, const std::string);
|
2023-07-13 14:08:23 +02:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Send an event to the main Imhex instance
|
|
|
|
*/
|
|
|
|
EVENT_DEF(SendMessageToMainInstance, const std::string, const std::vector<u8>&);
|
2023-08-26 01:47:44 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Move the data from all PerProvider instances from one provider to another.
|
|
|
|
* The 'from' provider should not have any per provider data after this, and should be immediately deleted
|
|
|
|
*/
|
|
|
|
EVENT_DEF(MovePerProviderData, prv::Provider *, prv::Provider *);
|
2020-12-22 18:10:01 +01:00
|
|
|
}
|