feat: Allow toolbar icons to be modified (#1509)
This commit is contained in:
parent
a13b5bf8c0
commit
d005b5d2d9
@ -103,8 +103,8 @@ if (NOT IMHEX_EXTERNAL_PLUGIN_BUILD)
|
||||
target_link_libraries(libimhex PUBLIC ${FOUNDATION})
|
||||
endif ()
|
||||
|
||||
target_link_libraries(libimhex PRIVATE microtar libpl plcli libpl-gen libwolv ${NFD_LIBRARIES} magic dl ${NLOHMANN_JSON_LIBRARIES} ${MBEDTLS_LIBRARIES} ${LIBBACKTRACE_LIBRARIES} ${JTHREAD_LIBRARIES})
|
||||
target_link_libraries(libimhex PUBLIC ${IMGUI_LIBRARIES})
|
||||
target_link_libraries(libimhex PRIVATE microtar libwolv ${NFD_LIBRARIES} magic dl ${NLOHMANN_JSON_LIBRARIES} ${MBEDTLS_LIBRARIES} ${JTHREAD_LIBRARIES})
|
||||
target_link_libraries(libimhex PUBLIC libpl ${IMGUI_LIBRARIES})
|
||||
endif()
|
||||
|
||||
target_link_libraries(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${NLOHMANN_JSON_LIBRARIES} imgui_all_includes ${FMT_LIBRARIES})
|
||||
|
@ -18,6 +18,7 @@
|
||||
using ImGuiDataType = int;
|
||||
using ImGuiInputTextFlags = int;
|
||||
struct ImColor;
|
||||
enum ImGuiCustomCol : int;
|
||||
|
||||
namespace hex {
|
||||
|
||||
@ -656,6 +657,13 @@ namespace hex {
|
||||
/* Interface Registry. Allows adding new items to various interfaces */
|
||||
namespace Interface {
|
||||
|
||||
struct Icon {
|
||||
Icon(const char *glyph, ImGuiCustomCol color = ImGuiCustomCol(0x00)) : glyph(glyph), color(color) {}
|
||||
|
||||
std::string glyph;
|
||||
ImGuiCustomCol color;
|
||||
};
|
||||
|
||||
namespace impl {
|
||||
|
||||
using DrawCallback = std::function<void()>;
|
||||
@ -670,12 +678,13 @@ namespace hex {
|
||||
|
||||
struct MenuItem {
|
||||
std::vector<UnlocalizedString> unlocalizedNames;
|
||||
const char *icon;
|
||||
Icon icon;
|
||||
std::unique_ptr<Shortcut> shortcut;
|
||||
View *view;
|
||||
MenuCallback callback;
|
||||
EnabledCallback enabledCallback;
|
||||
SelectedCallback selectedCallback;
|
||||
i32 toolbarIndex;
|
||||
};
|
||||
|
||||
struct SidebarItem {
|
||||
@ -723,7 +732,7 @@ namespace hex {
|
||||
*/
|
||||
void addMenuItem(
|
||||
const std::vector<UnlocalizedString> &unlocalizedMainMenuNames,
|
||||
const char *icon,
|
||||
const Icon &icon,
|
||||
u32 priority,
|
||||
const Shortcut &shortcut,
|
||||
const impl::MenuCallback &function,
|
||||
@ -743,7 +752,7 @@ namespace hex {
|
||||
*/
|
||||
void addMenuItem(
|
||||
const std::vector<UnlocalizedString> &unlocalizedMainMenuNames,
|
||||
const char *icon,
|
||||
const Icon &icon,
|
||||
u32 priority,
|
||||
const Shortcut &shortcut,
|
||||
const impl::MenuCallback &function,
|
||||
@ -829,6 +838,13 @@ namespace hex {
|
||||
*/
|
||||
void addToolbarItem(const impl::DrawCallback &function);
|
||||
|
||||
/**
|
||||
* @brief Adds a menu item to the toolbar
|
||||
* @param unlocalizedName Unlocalized name of the menu item
|
||||
* @param color Color of the toolbar icon
|
||||
*/
|
||||
void addMenuItemToToolbar(const UnlocalizedString &unlocalizedName, ImGuiCustomCol color);
|
||||
|
||||
/**
|
||||
* @brief Adds a new sidebar item
|
||||
* @param icon The icon to use for the item
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
#include <wolv/utils/string.hpp>
|
||||
|
||||
enum ImGuiCustomCol {
|
||||
enum ImGuiCustomCol : int {
|
||||
ImGuiCustomCol_DescButton,
|
||||
ImGuiCustomCol_DescButtonHovered,
|
||||
ImGuiCustomCol_DescButtonActive,
|
||||
|
@ -148,8 +148,6 @@ namespace hex {
|
||||
const auto entry = insertOrGetEntry(subCategory->entries, unlocalizedName);
|
||||
|
||||
entry->widget = std::move(widget);
|
||||
entry->widget->load(getSetting(unlocalizedCategory, unlocalizedName, entry->widget->store()));
|
||||
entry->widget->onChanged();
|
||||
|
||||
return entry->widget.get();
|
||||
}
|
||||
@ -723,22 +721,26 @@ namespace hex {
|
||||
}
|
||||
|
||||
void addMenuItem(const std::vector<UnlocalizedString> &unlocalizedMainMenuNames, u32 priority, const Shortcut &shortcut, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback, const impl::SelectedCallback &selectedCallback, View *view) {
|
||||
addMenuItem(unlocalizedMainMenuNames, nullptr, priority, shortcut, function, enabledCallback, selectedCallback, view);
|
||||
addMenuItem(unlocalizedMainMenuNames, "", priority, shortcut, function, enabledCallback, selectedCallback, view);
|
||||
}
|
||||
|
||||
void addMenuItem(const std::vector<UnlocalizedString> &unlocalizedMainMenuNames, const char *icon, u32 priority, const Shortcut &shortcut, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback, View *view) {
|
||||
void addMenuItem(const std::vector<UnlocalizedString> &unlocalizedMainMenuNames, const Icon &icon, u32 priority, const Shortcut &shortcut, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback, View *view) {
|
||||
addMenuItem(unlocalizedMainMenuNames, icon, priority, shortcut, function, enabledCallback, []{ return false; }, view);
|
||||
}
|
||||
|
||||
void addMenuItem(const std::vector<UnlocalizedString> &unlocalizedMainMenuNames, u32 priority, const Shortcut &shortcut, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback, View *view) {
|
||||
addMenuItem(unlocalizedMainMenuNames, nullptr, priority, shortcut, function, enabledCallback, []{ return false; }, view);
|
||||
addMenuItem(unlocalizedMainMenuNames, "", priority, shortcut, function, enabledCallback, []{ return false; }, view);
|
||||
}
|
||||
|
||||
void addMenuItem(const std::vector<UnlocalizedString> &unlocalizedMainMenuNames, const char *icon, u32 priority, const Shortcut &shortcut, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback, const impl::SelectedCallback &selectedCallback, View *view) {
|
||||
void addMenuItem(const std::vector<UnlocalizedString> &unlocalizedMainMenuNames, const Icon &icon, u32 priority, const Shortcut &shortcut, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback, const impl::SelectedCallback &selectedCallback, View *view) {
|
||||
log::debug("Added new menu item to menu {} with priority {}", unlocalizedMainMenuNames[0].get(), priority);
|
||||
|
||||
Icon coloredIcon = icon;
|
||||
if (coloredIcon.color == 0x00)
|
||||
coloredIcon.color = ImGuiCustomCol_ToolbarGray;
|
||||
|
||||
impl::getMenuItems().insert({
|
||||
priority, impl::MenuItem { unlocalizedMainMenuNames, icon, std::make_unique<Shortcut>(shortcut), view, function, enabledCallback, selectedCallback }
|
||||
priority, impl::MenuItem { unlocalizedMainMenuNames, coloredIcon, std::make_unique<Shortcut>(shortcut), view, function, enabledCallback, selectedCallback, -1 }
|
||||
});
|
||||
|
||||
if (shortcut != Shortcut::None) {
|
||||
@ -750,7 +752,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
void addMenuItemSubMenu(std::vector<UnlocalizedString> unlocalizedMainMenuNames, u32 priority, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback) {
|
||||
addMenuItemSubMenu(std::move(unlocalizedMainMenuNames), nullptr, priority, function, enabledCallback);
|
||||
addMenuItemSubMenu(std::move(unlocalizedMainMenuNames), "", priority, function, enabledCallback);
|
||||
}
|
||||
|
||||
void addMenuItemSubMenu(std::vector<UnlocalizedString> unlocalizedMainMenuNames, const char *icon, u32 priority, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback) {
|
||||
@ -758,14 +760,14 @@ namespace hex {
|
||||
|
||||
unlocalizedMainMenuNames.emplace_back(impl::SubMenuValue);
|
||||
impl::getMenuItems().insert({
|
||||
priority, impl::MenuItem { unlocalizedMainMenuNames, icon, std::make_unique<Shortcut>(), nullptr, function, enabledCallback, []{ return false; } }
|
||||
priority, impl::MenuItem { unlocalizedMainMenuNames, icon, std::make_unique<Shortcut>(), nullptr, function, enabledCallback, []{ return false; }, -1 }
|
||||
});
|
||||
}
|
||||
|
||||
void addMenuItemSeparator(std::vector<UnlocalizedString> unlocalizedMainMenuNames, u32 priority) {
|
||||
unlocalizedMainMenuNames.emplace_back(impl::SeparatorValue);
|
||||
impl::getMenuItems().insert({
|
||||
priority, impl::MenuItem { unlocalizedMainMenuNames, "", std::make_unique<Shortcut>(), nullptr, []{}, []{ return true; }, []{ return false; } }
|
||||
priority, impl::MenuItem { unlocalizedMainMenuNames, "", std::make_unique<Shortcut>(), nullptr, []{}, []{ return true; }, []{ return false; }, -1 }
|
||||
});
|
||||
}
|
||||
|
||||
@ -781,6 +783,21 @@ namespace hex {
|
||||
impl::getToolbarItems().push_back(function);
|
||||
}
|
||||
|
||||
void addMenuItemToToolbar(const UnlocalizedString& unlocalizedName, ImGuiCustomCol color) {
|
||||
auto maxIndex = std::ranges::max_element(impl::getMenuItems(), [](const auto &a, const auto &b) {
|
||||
return a.second.toolbarIndex < b.second.toolbarIndex;
|
||||
})->second.toolbarIndex;
|
||||
|
||||
for (auto &[priority, menuItem] : impl::getMenuItems()) {
|
||||
if (menuItem.unlocalizedNames.back() == unlocalizedName) {
|
||||
menuItem.toolbarIndex = maxIndex + 1;
|
||||
menuItem.icon.color = color;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void addSidebarItem(const std::string &icon, const impl::DrawCallback &function, const impl::EnabledCallback &enabledCallback) {
|
||||
impl::getSidebarItems().push_back({ icon, function, enabledCallback });
|
||||
}
|
||||
|
@ -79,6 +79,7 @@ namespace hex {
|
||||
Lang::Lang(const UnlocalizedString &unlocalizedString) : m_unlocalizedString(unlocalizedString.get()) { }
|
||||
Lang::Lang(std::string_view unlocalizedString) : m_unlocalizedString(unlocalizedString) { }
|
||||
|
||||
|
||||
Lang::operator std::string() const {
|
||||
return get();
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ set_target_properties(main PROPERTIES
|
||||
|
||||
target_compile_definitions(main PRIVATE IMHEX_PROJECT_NAME="${PROJECT_NAME}")
|
||||
|
||||
target_link_libraries(main PRIVATE libromfs-imhex libimhex libwolv libpl plcli libpl-gen ${FMT_LIBRARIES} LLVMDemangle ${LIBBACKTRACE_LIBRARIES})
|
||||
target_link_libraries(main PRIVATE libromfs-imhex libimhex libwolv ${LIBBACKTRACE_LIBRARIES} LLVMDemangle)
|
||||
if (WIN32)
|
||||
target_link_libraries(main PRIVATE usp10 wsock32 ws2_32 Dwmapi.lib)
|
||||
else ()
|
||||
|
@ -519,9 +519,9 @@ namespace hex {
|
||||
}
|
||||
|
||||
for (auto &[priority, menuItem] : ContentRegistry::Interface::impl::getMenuItems()) {
|
||||
const auto &[unlocalizedNames, icon, shortcut, view, callback, enabledCallback, selectedCallack] = menuItem;
|
||||
const auto &[unlocalizedNames, icon, shortcut, view, callback, enabledCallback, selectedCallack, toolbarIndex] = menuItem;
|
||||
|
||||
createNestedMenu(unlocalizedNames, icon, *shortcut, callback, enabledCallback, selectedCallack);
|
||||
createNestedMenu(unlocalizedNames, icon.glyph.c_str(), *shortcut, callback, enabledCallback, selectedCallack);
|
||||
}
|
||||
};
|
||||
|
||||
@ -792,10 +792,10 @@ namespace hex {
|
||||
|
||||
// Draw main menu popups
|
||||
for (auto &[priority, menuItem] : ContentRegistry::Interface::impl::getMenuItems()) {
|
||||
const auto &[unlocalizedNames, icon, shortcut, view, callback, enabledCallback, selectedCallback] = menuItem;
|
||||
const auto &[unlocalizedNames, icon, shortcut, view, callback, enabledCallback, selectedCallback, toolbarIndex] = menuItem;
|
||||
|
||||
if (ImGui::BeginPopup(unlocalizedNames.front().get().c_str())) {
|
||||
createNestedMenu({ unlocalizedNames.begin() + 1, unlocalizedNames.end() }, icon, *shortcut, callback, enabledCallback, selectedCallback);
|
||||
createNestedMenu({ unlocalizedNames.begin() + 1, unlocalizedNames.end() }, icon.glyph.c_str(), *shortcut, callback, enabledCallback, selectedCallback);
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
project(updater)
|
||||
project(updater)
|
||||
|
||||
add_executable(updater
|
||||
source/main.cpp
|
||||
)
|
||||
|
||||
target_compile_definitions(updater PRIVATE IMHEX_PROJECT_NAME="${PROJECT_NAME}")
|
||||
target_link_libraries(updater PRIVATE libimhex wolv::io ${FMT_LIBRARIES})
|
||||
target_link_libraries(updater PRIVATE libimhex ${FMT_LIBRARIES})
|
||||
add_dependencies(main updater)
|
||||
|
||||
if (APPLE)
|
||||
|
@ -483,6 +483,9 @@
|
||||
"hex.builtin.setting.proxy.url.tooltip": "http(s):// or socks5:// (e.g., http://127.0.0.1:1080)",
|
||||
"hex.builtin.setting.shortcuts": "Shortcuts",
|
||||
"hex.builtin.setting.shortcuts.global": "Global Shortcuts",
|
||||
"hex.builtin.setting.toolbar": "Toolbar",
|
||||
"hex.builtin.setting.toolbar.description": "Add or remove menu options to the toolbar.",
|
||||
"hex.builtin.setting.toolbar.icons": "Toolbar Icons",
|
||||
"hex.builtin.shortcut.next_provider": "Select next provider",
|
||||
"hex.builtin.shortcut.prev_provider": "Select previous provider",
|
||||
"hex.builtin.title_bar_button.debug_build": "Debug build",
|
||||
|
@ -351,7 +351,7 @@ namespace hex::plugin::builtin {
|
||||
}, noRunningTasks);
|
||||
|
||||
/* Open File */
|
||||
ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.menu.file.open_file" }, ICON_VS_OPEN_PREVIEW, 1100, CTRLCMD + Keys::O, [] {
|
||||
ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.menu.file.open_file" }, ICON_VS_FOLDER_OPENED, 1100, CTRLCMD + Keys::O, [] {
|
||||
RequestOpenWindow::post("Open File");
|
||||
}, noRunningTasks);
|
||||
|
||||
|
@ -360,6 +360,247 @@ namespace hex::plugin::builtin {
|
||||
bool m_hasDuplicate = false;
|
||||
};
|
||||
|
||||
class ToolbarIconsWidget : public ContentRegistry::Settings::Widgets::Widget {
|
||||
private:
|
||||
struct MenuItemSorter {
|
||||
bool operator()(const auto *a, const auto *b) const {
|
||||
return a->toolbarIndex < b->toolbarIndex;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
bool draw(const std::string &) override {
|
||||
bool changed = false;
|
||||
|
||||
// Top level layout table
|
||||
if (ImGui::BeginTable("##top_level", 2, ImGuiTableFlags_None, ImGui::GetContentRegionAvail())) {
|
||||
ImGui::TableSetupColumn("##left", ImGuiTableColumnFlags_WidthStretch, 0.3F);
|
||||
ImGui::TableSetupColumn("##right", ImGuiTableColumnFlags_WidthStretch, 0.7F);
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
// Draw list of menu items that can be added to the toolbar
|
||||
if (ImGui::BeginTable("##all_icons", 1, ImGuiTableFlags_BordersOuter | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY, ImVec2(0, 280_scaled))) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
// Loop over all available menu items
|
||||
for (auto &[priority, menuItem] : ContentRegistry::Interface::impl::getMenuItems()) {
|
||||
// Filter out items without icon, separators, submenus and items that are already in the toolbar
|
||||
|
||||
if (menuItem.icon.glyph.empty())
|
||||
continue;
|
||||
|
||||
const auto &unlocalizedName = menuItem.unlocalizedNames.back();
|
||||
if (menuItem.unlocalizedNames.size() > 2)
|
||||
continue;
|
||||
if (unlocalizedName.get() == ContentRegistry::Interface::impl::SeparatorValue)
|
||||
continue;
|
||||
if (unlocalizedName.get() == ContentRegistry::Interface::impl::SubMenuValue)
|
||||
continue;
|
||||
if (menuItem.toolbarIndex != -1)
|
||||
continue;
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
// Draw the menu item
|
||||
ImGui::Selectable(hex::format("{} {}", menuItem.icon.glyph, Lang(unlocalizedName)).c_str(), false, ImGuiSelectableFlags_SpanAllColumns);
|
||||
|
||||
// Handle draggin the menu item to the toolbar box
|
||||
if (ImGui::BeginDragDropSource()) {
|
||||
auto ptr = &menuItem;
|
||||
ImGui::SetDragDropPayload("MENU_ITEM_PAYLOAD", &ptr, sizeof(void*));
|
||||
|
||||
ImGuiExt::TextFormatted("{} {}", menuItem.icon.glyph, Lang(unlocalizedName));
|
||||
|
||||
ImGui::EndDragDropSource();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
// Handle dropping menu items from the toolbar box
|
||||
if (ImGui::BeginDragDropTarget()) {
|
||||
if (auto payload = ImGui::AcceptDragDropPayload("TOOLBAR_ITEM_PAYLOAD"); payload != nullptr) {
|
||||
auto &menuItem = *static_cast<ContentRegistry::Interface::impl::MenuItem **>(payload->Data);
|
||||
|
||||
menuItem->toolbarIndex = -1;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
// Draw toolbar icon box
|
||||
ImGuiExt::BeginSubWindow("hex.builtin.setting.toolbar.icons"_lang, ImGui::GetContentRegionAvail());
|
||||
{
|
||||
if (ImGui::BeginTable("##icons", 6, ImGuiTableFlags_SizingStretchSame, ImGui::GetContentRegionAvail())) {
|
||||
ImGui::TableNextRow();
|
||||
|
||||
// Find all menu items that are in the toolbar and sort them by their toolbar index
|
||||
std::set<ContentRegistry::Interface::impl::MenuItem*, MenuItemSorter> toolbarItems;
|
||||
for (auto &[priority, menuItem] : ContentRegistry::Interface::impl::getMenuItems()) {
|
||||
if (menuItem.toolbarIndex == -1)
|
||||
continue;
|
||||
|
||||
toolbarItems.emplace(&menuItem);
|
||||
}
|
||||
|
||||
// Loop over all toolbar items
|
||||
for (auto &menuItem : toolbarItems) {
|
||||
// Filter out items without icon, separators, submenus and items that are not in the toolbar
|
||||
if (menuItem->icon.glyph.empty())
|
||||
continue;
|
||||
|
||||
const auto &unlocalizedName = menuItem->unlocalizedNames.back();
|
||||
if (menuItem->unlocalizedNames.size() > 2)
|
||||
continue;
|
||||
if (unlocalizedName.get() == ContentRegistry::Interface::impl::SubMenuValue)
|
||||
continue;
|
||||
if (menuItem->toolbarIndex == -1)
|
||||
continue;
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
// Draw the toolbar item
|
||||
ImGui::InvisibleButton(unlocalizedName.get().c_str(), ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().x));
|
||||
|
||||
// Handle dragging the toolbar item around
|
||||
if (ImGui::BeginDragDropSource()) {
|
||||
ImGui::SetDragDropPayload("TOOLBAR_ITEM_PAYLOAD", &menuItem, sizeof(void*));
|
||||
|
||||
ImGuiExt::TextFormatted("{} {}", menuItem->icon.glyph, Lang(unlocalizedName));
|
||||
|
||||
ImGui::EndDragDropSource();
|
||||
}
|
||||
|
||||
// Handle dropping toolbar items onto each other to reorder them
|
||||
if (ImGui::BeginDragDropTarget()) {
|
||||
if (auto payload = ImGui::AcceptDragDropPayload("TOOLBAR_ITEM_PAYLOAD"); payload != nullptr) {
|
||||
auto &otherMenuItem = *static_cast<ContentRegistry::Interface::impl::MenuItem **>(payload->Data);
|
||||
|
||||
std::swap(menuItem->toolbarIndex, otherMenuItem->toolbarIndex);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
|
||||
// Handle right clicking toolbar items to open the color selection popup
|
||||
if (ImGui::IsItemClicked(ImGuiMouseButton_Right))
|
||||
ImGui::OpenPopup(unlocalizedName.get().c_str());
|
||||
|
||||
// Draw the color selection popup
|
||||
if (ImGui::BeginPopup(unlocalizedName.get().c_str())) {
|
||||
constexpr static std::array Colors = {
|
||||
ImGuiCustomCol_ToolbarGray,
|
||||
ImGuiCustomCol_ToolbarRed,
|
||||
ImGuiCustomCol_ToolbarYellow,
|
||||
ImGuiCustomCol_ToolbarGreen,
|
||||
ImGuiCustomCol_ToolbarBlue,
|
||||
ImGuiCustomCol_ToolbarPurple,
|
||||
ImGuiCustomCol_ToolbarBrown
|
||||
};
|
||||
|
||||
// Draw all the color buttons
|
||||
for (auto color : Colors) {
|
||||
ImGui::PushID(&color);
|
||||
if (ImGui::ColorButton(hex::format("##color{}", u32(color)).c_str(), ImGuiExt::GetCustomColorVec4(color), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker, ImVec2(20, 20))) {
|
||||
menuItem->icon.color = color;
|
||||
ImGui::CloseCurrentPopup();
|
||||
changed = true;
|
||||
}
|
||||
ImGui::PopID();
|
||||
ImGui::SameLine();
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
auto min = ImGui::GetItemRectMin();
|
||||
auto max = ImGui::GetItemRectMax();
|
||||
auto iconSize = ImGui::CalcTextSize(menuItem->icon.glyph.c_str());
|
||||
|
||||
auto text = Lang(unlocalizedName).get();
|
||||
if (text.ends_with("..."))
|
||||
text = text.substr(0, text.size() - 3);
|
||||
|
||||
auto textSize = ImGui::CalcTextSize(text.c_str());
|
||||
|
||||
// Draw icon and text of the toolbar item
|
||||
auto drawList = ImGui::GetWindowDrawList();
|
||||
drawList->AddText((min + ((max - min) - iconSize) / 2) - ImVec2(0, 10_scaled), ImGuiExt::GetCustomColorU32(ImGuiCustomCol(menuItem->icon.color)), menuItem->icon.glyph.c_str());
|
||||
drawList->AddText((min + ((max - min)) / 2) + ImVec2(-textSize.x / 2, 5_scaled), ImGui::GetColorU32(ImGuiCol_Text), text.c_str());
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
ImGuiExt::EndSubWindow();
|
||||
|
||||
// Handle dropping menu items onto the toolbar box
|
||||
if (ImGui::BeginDragDropTarget()) {
|
||||
if (auto payload = ImGui::AcceptDragDropPayload("MENU_ITEM_PAYLOAD"); payload != nullptr) {
|
||||
auto &menuItem = *static_cast<ContentRegistry::Interface::impl::MenuItem **>(payload->Data);
|
||||
|
||||
menuItem->toolbarIndex = m_currIndex;
|
||||
m_currIndex += 1;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
nlohmann::json store() override {
|
||||
std::map<i32, std::pair<std::string, u32>> items;
|
||||
|
||||
for (const auto &[priority, menuItem] : ContentRegistry::Interface::impl::getMenuItems()) {
|
||||
if (menuItem.toolbarIndex != -1)
|
||||
items.emplace(menuItem.toolbarIndex, std::make_pair(menuItem.unlocalizedNames.back().get(), menuItem.icon.color));
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
void load(const nlohmann::json &data) override {
|
||||
if (data.is_null())
|
||||
return;
|
||||
|
||||
auto toolbarItems = data.get<std::map<i32, std::pair<std::string, u32>>>();
|
||||
if (toolbarItems.empty())
|
||||
return;
|
||||
|
||||
for (auto &[priority, menuItem] : ContentRegistry::Interface::impl::getMenuItems())
|
||||
menuItem.toolbarIndex = -1;
|
||||
|
||||
for (auto &[priority, menuItem] : ContentRegistry::Interface::impl::getMenuItems()) {
|
||||
for (const auto &[index, value] : toolbarItems) {
|
||||
const auto &[name, color] = value;
|
||||
if (menuItem.unlocalizedNames.back().get() == name) {
|
||||
menuItem.toolbarIndex = index;
|
||||
menuItem.icon.color = ImGuiCustomCol(color);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_currIndex = toolbarItems.size();
|
||||
}
|
||||
|
||||
private:
|
||||
i32 m_currIndex = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void registerSettings() {
|
||||
@ -536,6 +777,11 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
});
|
||||
|
||||
/* Toolbar icons */
|
||||
ContentRegistry::Settings::setCategoryDescription("hex.builtin.setting.toolbar", "hex.builtin.setting.toolbar.description");
|
||||
|
||||
ContentRegistry::Settings::add<ToolbarIconsWidget>("hex.builtin.setting.toolbar", "", "hex.builtin.setting.toolbar.icons");
|
||||
|
||||
}
|
||||
|
||||
static void loadLayoutSettings() {
|
||||
|
@ -233,6 +233,12 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
}
|
||||
|
||||
struct MenuItemSorter {
|
||||
bool operator()(const auto *a, const auto *b) const {
|
||||
return a->toolbarIndex < b->toolbarIndex;
|
||||
}
|
||||
};
|
||||
|
||||
void addToolbarItems() {
|
||||
ShortcutManager::addGlobalShortcut(AllowWhileTyping + ALT + CTRLCMD + Keys::Left, "hex.builtin.shortcut.prev_provider", []{
|
||||
auto currIndex = ImHexApi::Provider::getCurrentProviderIndex();
|
||||
@ -274,87 +280,39 @@ namespace hex::plugin::builtin {
|
||||
});
|
||||
|
||||
ContentRegistry::Interface::addToolbarItem([] {
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
bool providerValid = provider != nullptr;
|
||||
bool tasksRunning = TaskManager::getRunningTaskCount() > 0;
|
||||
std::set<const ContentRegistry::Interface::impl::MenuItem*, MenuItemSorter> menuItems;
|
||||
|
||||
// Undo
|
||||
ImGui::BeginDisabled(!providerValid || !provider->canUndo());
|
||||
{
|
||||
if (ImGuiExt::ToolBarButton(ICON_VS_DISCARD, ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_ToolbarBlue)))
|
||||
provider->undo();
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
// Redo
|
||||
ImGui::BeginDisabled(!providerValid || !provider->canRedo());
|
||||
{
|
||||
if (ImGuiExt::ToolBarButton(ICON_VS_REDO, ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_ToolbarBlue)))
|
||||
provider->redo();
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||
|
||||
ImGui::BeginDisabled(tasksRunning);
|
||||
{
|
||||
// Create new file
|
||||
if (ImGuiExt::ToolBarButton(ICON_VS_FILE, ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_ToolbarGray))) {
|
||||
auto newProvider = hex::ImHexApi::Provider::createProvider("hex.builtin.provider.mem_file", true);
|
||||
if (newProvider != nullptr && !newProvider->open())
|
||||
hex::ImHexApi::Provider::remove(newProvider);
|
||||
else
|
||||
EventProviderOpened::post(newProvider);
|
||||
}
|
||||
|
||||
// Open file
|
||||
if (ImGuiExt::ToolBarButton(ICON_VS_FOLDER_OPENED, ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_ToolbarBrown)))
|
||||
RequestOpenWindow::post("Open File");
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||
|
||||
// Save file
|
||||
ImGui::BeginDisabled(!providerValid || !provider->isWritable() || !provider->isSavable());
|
||||
{
|
||||
if (ImGuiExt::ToolBarButton(ICON_VS_SAVE, ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_ToolbarBlue)))
|
||||
provider->save();
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
// Save file as
|
||||
ImGui::BeginDisabled(!providerValid || !provider->isSavable());
|
||||
{
|
||||
if (ImGuiExt::ToolBarButton(ICON_VS_SAVE_AS, ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_ToolbarBlue)))
|
||||
fs::openFileBrowser(fs::DialogMode::Save, {}, [&provider](auto path) {
|
||||
provider->saveAs(path);
|
||||
});
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
|
||||
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||
|
||||
|
||||
// Create bookmark
|
||||
ImGui::BeginDisabled(!providerValid || !provider->isReadable() || !ImHexApi::HexEditor::isSelectionValid());
|
||||
{
|
||||
if (ImGuiExt::ToolBarButton(ICON_VS_BOOKMARK, ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_ToolbarGreen))) {
|
||||
auto region = ImHexApi::HexEditor::getSelection();
|
||||
|
||||
if (region.has_value())
|
||||
ImHexApi::Bookmarks::add(region->getStartAddress(), region->getSize(), {}, {});
|
||||
for (const auto &[priority, menuItem] : ContentRegistry::Interface::impl::getMenuItems()) {
|
||||
if (menuItem.toolbarIndex != -1) {
|
||||
menuItems.insert(&menuItem);
|
||||
}
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
for (const auto &menuItem : menuItems) {
|
||||
if (menuItem->unlocalizedNames.back().get() == ContentRegistry::Interface::impl::SeparatorValue) {
|
||||
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||
continue;
|
||||
}
|
||||
|
||||
ImGui::BeginDisabled(!menuItem->enabledCallback());
|
||||
if (ImGuiExt::ToolBarButton(menuItem->icon.glyph.c_str(), ImGuiExt::GetCustomColorVec4(ImGuiCustomCol(menuItem->icon.color)))) {
|
||||
menuItem->callback();
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
});
|
||||
|
||||
// Provider switcher
|
||||
ContentRegistry::Interface::addToolbarItem([] {
|
||||
const auto provider = ImHexApi::Provider::get();
|
||||
const bool providerValid = provider != nullptr;
|
||||
const bool tasksRunning = TaskManager::getRunningTaskCount() > 0;
|
||||
|
||||
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||
ImGui::Spacing();
|
||||
ImGui::Spacing();
|
||||
ImGui::Spacing();
|
||||
|
||||
// Provider switcher
|
||||
ImGui::BeginDisabled(!providerValid || tasksRunning);
|
||||
{
|
||||
auto &providers = ImHexApi::Provider::getProviders();
|
||||
@ -446,6 +404,14 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
});
|
||||
|
||||
ContentRegistry::Interface::addMenuItemToToolbar("hex.builtin.menu.edit.undo", ImGuiCustomCol_ToolbarBlue);
|
||||
ContentRegistry::Interface::addMenuItemToToolbar("hex.builtin.menu.edit.redo", ImGuiCustomCol_ToolbarBlue);
|
||||
ContentRegistry::Interface::addMenuItemToToolbar("hex.builtin.menu.file.create_file", ImGuiCustomCol_ToolbarGray);
|
||||
ContentRegistry::Interface::addMenuItemToToolbar("hex.builtin.menu.file.open_file", ImGuiCustomCol_ToolbarBrown);
|
||||
ContentRegistry::Interface::addMenuItemToToolbar("hex.builtin.view.hex_editor.menu.file.save", ImGuiCustomCol_ToolbarBlue);
|
||||
ContentRegistry::Interface::addMenuItemToToolbar("hex.builtin.view.hex_editor.menu.file.save_as", ImGuiCustomCol_ToolbarBlue);
|
||||
ContentRegistry::Interface::addMenuItemToToolbar("hex.builtin.menu.edit.bookmark.create", ImGuiCustomCol_ToolbarGreen);
|
||||
}
|
||||
|
||||
void handleBorderlessWindowMode() {
|
||||
|
@ -24,10 +24,26 @@ namespace hex::plugin::builtin {
|
||||
ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.extras", "hex.builtin.view.settings.name" }, ICON_VS_SETTINGS_GEAR, 4000, Shortcut::None, [&, this] {
|
||||
this->getWindowOpenState() = true;
|
||||
});
|
||||
|
||||
EventImHexStartupFinished::subscribe(this, [] {
|
||||
for (const auto &[unlocalizedCategory, unlocalizedDescription, subCategories] : ContentRegistry::Settings::impl::getSettings()) {
|
||||
for (const auto &[unlocalizedSubCategory, entries] : subCategories) {
|
||||
for (const auto &[unlocalizedName, widget] : entries) {
|
||||
try {
|
||||
widget->load(ContentRegistry::Settings::impl::getSetting(unlocalizedCategory, unlocalizedName, widget->store()));
|
||||
widget->onChanged();
|
||||
} catch (const std::exception &e) {
|
||||
log::error("Failed to load setting [{} / {}]: {}", unlocalizedCategory.get(), unlocalizedName.get(), e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ViewSettings::~ViewSettings() {
|
||||
RequestOpenWindow::unsubscribe(this);
|
||||
EventImHexStartupFinished::unsubscribe(this);
|
||||
}
|
||||
|
||||
void ViewSettings::drawContent() {
|
||||
|
@ -81,6 +81,8 @@ IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") {
|
||||
loadFonts();
|
||||
extractBundledFiles();
|
||||
|
||||
registerMainMenuEntries();
|
||||
|
||||
registerEventHandlers();
|
||||
registerDataVisualizers();
|
||||
registerDataInspectorEntries();
|
||||
@ -114,7 +116,5 @@ IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") {
|
||||
addToolbarItems();
|
||||
addGlobalUIItems();
|
||||
|
||||
registerMainMenuEntries();
|
||||
|
||||
handleBorderlessWindowMode();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user