mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-27 23:37:05 -05:00
feat: Added banners, replace some modals with them
This commit is contained in:
@@ -50,6 +50,7 @@ set(LIBIMHEX_SOURCES
|
||||
source/ui/view.cpp
|
||||
source/ui/popup.cpp
|
||||
source/ui/toast.cpp
|
||||
source/ui/banner.cpp
|
||||
|
||||
source/subcommands/subcommands.cpp
|
||||
)
|
||||
|
||||
57
lib/libimhex/include/hex/ui/banner.hpp
Normal file
57
lib/libimhex/include/hex/ui/banner.hpp
Normal file
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
#include <imgui.h>
|
||||
#include <imgui_internal.h>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include "hex/api/localization_manager.hpp"
|
||||
|
||||
namespace hex {
|
||||
|
||||
namespace impl {
|
||||
|
||||
class BannerBase {
|
||||
public:
|
||||
BannerBase(ImColor color) : m_color(color) {}
|
||||
virtual ~BannerBase() = default;
|
||||
|
||||
virtual void draw() { drawContent(); }
|
||||
virtual void drawContent() = 0;
|
||||
|
||||
[[nodiscard]] static std::list<std::unique_ptr<BannerBase>> &getOpenBanners();
|
||||
|
||||
[[nodiscard]] const ImColor& getColor() const {
|
||||
return m_color;
|
||||
}
|
||||
|
||||
void close() { m_shouldClose = true; }
|
||||
[[nodiscard]] bool shouldClose() const { return m_shouldClose; }
|
||||
|
||||
protected:
|
||||
static std::mutex& getMutex();
|
||||
|
||||
bool m_shouldClose = false;
|
||||
ImColor m_color;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class Banner : public impl::BannerBase {
|
||||
public:
|
||||
using impl::BannerBase::BannerBase;
|
||||
|
||||
template<typename ...Args>
|
||||
static void open(Args && ... args) {
|
||||
std::lock_guard lock(getMutex());
|
||||
|
||||
auto toast = std::make_unique<T>(std::forward<Args>(args)...);
|
||||
getOpenBanners().emplace_back(std::move(toast));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -686,7 +686,7 @@ namespace hex {
|
||||
return string;
|
||||
|
||||
// If the string is longer than the max length, find the last space before the max length
|
||||
auto it = string.begin() + maxLength;
|
||||
auto it = string.begin() + maxLength / 2;
|
||||
while (it != string.begin() && !std::isspace(*it)) --it;
|
||||
|
||||
// If there's no space before the max length, just cut the string
|
||||
|
||||
18
lib/libimhex/source/ui/banner.cpp
Normal file
18
lib/libimhex/source/ui/banner.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#include <hex/ui/banner.hpp>
|
||||
#include <hex/helpers/auto_reset.hpp>
|
||||
|
||||
namespace hex::impl {
|
||||
|
||||
[[nodiscard]] std::list<std::unique_ptr<BannerBase>> &BannerBase::getOpenBanners() {
|
||||
static AutoReset<std::list<std::unique_ptr<BannerBase>>> openBanners;
|
||||
|
||||
return openBanners;
|
||||
}
|
||||
|
||||
std::mutex& BannerBase::getMutex() {
|
||||
static std::mutex mutex;
|
||||
|
||||
return mutex;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,6 +25,8 @@ namespace hex::init {
|
||||
int main(int argc, char **argv) {
|
||||
using namespace hex;
|
||||
|
||||
std::setlocale(LC_ALL, "en_US.utf8");
|
||||
|
||||
// Set the main thread's name to "Main"
|
||||
TaskManager::setCurrentThreadName("Main");
|
||||
|
||||
@@ -43,9 +45,10 @@ int main(int argc, char **argv) {
|
||||
log::info("Welcome to ImHex {}!", ImHexApi::System::getImHexVersion().get());
|
||||
log::info("Compiled using commit {}@{}", ImHexApi::System::getCommitBranch(), ImHexApi::System::getCommitHash());
|
||||
log::info("Running on {} {} ({})", ImHexApi::System::getOSName(), ImHexApi::System::getOSVersion(), ImHexApi::System::getArchitecture());
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
auto distro = ImHexApi::System::getLinuxDistro().value();
|
||||
log::info("Linux distribution: {}. Version: {}", distro.name, distro.version == "" ? "None" : distro.version);
|
||||
auto distro = ImHexApi::System::getLinuxDistro().value();
|
||||
log::info("Linux distribution: {}. Version: {}", distro.name, distro.version == "" ? "None" : distro.version);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "window.hpp"
|
||||
#include "hex/ui/banner.hpp"
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
@@ -553,6 +554,44 @@ namespace hex {
|
||||
});
|
||||
}
|
||||
|
||||
// Draw Banners
|
||||
{
|
||||
const bool onWelcomeScreen = !ImHexApi::Provider::isValid();
|
||||
|
||||
float startY = (ImGui::GetTextLineHeight() + ImGui::GetStyle().FramePadding.y * 2.0F) * (onWelcomeScreen ? 2 : 3);
|
||||
const auto height = 30_scaled;
|
||||
|
||||
for (const auto &banner : impl::BannerBase::getOpenBanners() | std::views::take(5)) {
|
||||
ImGui::PushID(banner.get());
|
||||
{
|
||||
ImGui::SetNextWindowPos(ImVec2(1_scaled, startY));
|
||||
ImGui::SetNextWindowSize(ImVec2(ImHexApi::System::getMainWindowSize().x - 2_scaled, height));
|
||||
ImGui::PushStyleColor(ImGuiCol_WindowBg, banner->getColor().Value);
|
||||
if (ImGui::Begin("##Banner", nullptr, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing)) {
|
||||
if (ImGui::BeginChild("##Content", ImGui::GetContentRegionAvail() - ImVec2(20_scaled, 0))) {
|
||||
banner->draw();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::CloseButton(ImGui::GetID("BannerCloseButton"), ImGui::GetCursorScreenPos())) {
|
||||
banner->close();
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
ImGui::PopID();
|
||||
|
||||
startY += height;
|
||||
}
|
||||
|
||||
std::erase_if(impl::BannerBase::getOpenBanners(), [](const auto &banner) {
|
||||
return banner->shouldClose();
|
||||
});
|
||||
}
|
||||
|
||||
// Run all deferred calls
|
||||
TaskManager::runDeferredCalls();
|
||||
}
|
||||
|
||||
@@ -422,8 +422,10 @@
|
||||
"hex.builtin.provider.file.size": "Size",
|
||||
"hex.builtin.provider.file.menu.open_file": "Open file externally",
|
||||
"hex.builtin.provider.file.menu.open_folder": "Open containing folder",
|
||||
"hex.builtin.provider.file.too_large": "This file is too large to be loaded into memory. Opening it anyways will result in modifications to be written directly to the file. Would you like to open it as Read-Only instead?",
|
||||
"hex.builtin.provider.file.reload_changes": "The file has been modified by an external source. Do you want to reload it?",
|
||||
"hex.builtin.provider.file.too_large": "File is larger than limit set limit, changes will be written directly to the file. Allow write access anyways?",
|
||||
"hex.builtin.provider.file.too_large.allow_write": "Allow write access",
|
||||
"hex.builtin.provider.file.reload_changes": "File has been modified by an external source. Do you want to reload it?",
|
||||
"hex.builtin.provider.file.reload_changes.reload": "Reload",
|
||||
"hex.builtin.provider.gdb": "GDB Server Data",
|
||||
"hex.builtin.provider.gdb.ip": "IP Address",
|
||||
"hex.builtin.provider.gdb.name": "GDB Server <{0}:{1}>",
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <hex/api/project_file_manager.hpp>
|
||||
#include <hex/api/task_manager.hpp>
|
||||
|
||||
#include <popups/popup_question.hpp>
|
||||
#include <banners/banner_button.hpp>
|
||||
#include <toasts/toast_notification.hpp>
|
||||
|
||||
#include <hex/helpers/utils.hpp>
|
||||
@@ -216,11 +216,7 @@ namespace hex::plugin::builtin {
|
||||
if (result && directAccess) {
|
||||
m_writable = false;
|
||||
|
||||
ui::PopupQuestion::open("hex.builtin.provider.file.too_large"_lang,
|
||||
[this] {
|
||||
m_writable = false;
|
||||
},
|
||||
[this] {
|
||||
ui::BannerButton::open(ICON_VS_WARNING, "hex.builtin.provider.file.too_large", ImColor(135, 116, 66), "hex.builtin.provider.file.too_large.allow_write", [this]{
|
||||
m_writable = true;
|
||||
RequestUpdateWindowTitle::post();
|
||||
});
|
||||
@@ -281,6 +277,8 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
}
|
||||
|
||||
m_changeEventAcknowledgementPending = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -368,15 +366,12 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
m_changeEventAcknowledgementPending = true;
|
||||
|
||||
ui::PopupQuestion::open("hex.builtin.provider.file.reload_changes"_lang, [this] {
|
||||
ui::BannerButton::open(ICON_VS_INFO, "hex.builtin.provider.file.reload_changes"_lang, ImColor(66, 104, 135), "hex.builtin.provider.file.reload_changes.reload", [this] {
|
||||
this->close();
|
||||
(void)this->open(!m_loadedIntoMemory);
|
||||
|
||||
getUndoStack().reapply();
|
||||
m_changeEventAcknowledgementPending = false;
|
||||
},
|
||||
[this]{
|
||||
m_changeEventAcknowledgementPending = false;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
51
plugins/ui/include/banners/banner_button.hpp
Normal file
51
plugins/ui/include/banners/banner_button.hpp
Normal file
@@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/ui/banner.hpp>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <hex/ui/imgui_imhex_extensions.h>
|
||||
|
||||
namespace hex::ui {
|
||||
|
||||
class BannerButton : public Banner<BannerButton> {
|
||||
public:
|
||||
BannerButton(const char *icon, UnlocalizedString message, ImColor color, UnlocalizedString buttonText, std::function<void()> buttonCallback)
|
||||
: Banner(color), m_icon(icon), m_message(std::move(message)), m_buttonText(std::move(buttonText)), m_buttonCallback(std::move(buttonCallback)) { }
|
||||
|
||||
void drawContent() override {
|
||||
const std::string buttonText = Lang(m_buttonText);
|
||||
const auto buttonSize = ImGui::CalcTextSize(buttonText.c_str());
|
||||
|
||||
ImGui::TextUnformatted(m_icon);
|
||||
ImGui::SameLine(0, 10_scaled);
|
||||
|
||||
const std::string message = Lang(m_message);
|
||||
const auto messageSize = ImGui::CalcTextSize(message.c_str());
|
||||
ImGuiExt::TextFormatted("{}", limitStringLength(message, message.size() * ((ImGui::GetContentRegionAvail().x - buttonSize.x - 40_scaled) / messageSize.x)));
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetNextWindowSize(ImVec2(400_scaled, 0));
|
||||
if (ImGui::BeginTooltip()) {
|
||||
ImGuiExt::TextFormattedWrapped("{}", message);
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - buttonSize.x - 20_scaled);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 2_scaled);
|
||||
if (ImGui::SmallButton(buttonText.c_str())) {
|
||||
m_buttonCallback();
|
||||
this->close();
|
||||
}
|
||||
ImGui::PopStyleVar(1);
|
||||
}
|
||||
|
||||
private:
|
||||
const char *m_icon;
|
||||
UnlocalizedString m_message;
|
||||
UnlocalizedString m_buttonText;
|
||||
std::function<void()> m_buttonCallback;
|
||||
};
|
||||
|
||||
}
|
||||
24
plugins/ui/include/banners/banner_icon.hpp
Normal file
24
plugins/ui/include/banners/banner_icon.hpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/ui/banner.hpp>
|
||||
#include <imgui.h>
|
||||
|
||||
namespace hex::ui {
|
||||
|
||||
class BannerIcon : public Banner<BannerIcon> {
|
||||
public:
|
||||
BannerIcon(const char *icon, UnlocalizedString message, ImColor color)
|
||||
: Banner(color), m_icon(icon), m_message(std::move(message)) { }
|
||||
|
||||
void drawContent() override {
|
||||
ImGui::TextUnformatted(m_icon);
|
||||
ImGui::SameLine(0, 10_scaled);
|
||||
ImGui::TextUnformatted(Lang(m_message));
|
||||
}
|
||||
|
||||
private:
|
||||
const char *m_icon;
|
||||
UnlocalizedString m_message;
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user