feat: Let ImHex use the native menu bar on macOS (#2048)
This commit is contained in:
parent
24979d7fbd
commit
6009b5013b
@ -2,137 +2,25 @@
|
|||||||
|
|
||||||
#include <hex.hpp>
|
#include <hex.hpp>
|
||||||
#include <hex/api/localization_manager.hpp>
|
#include <hex/api/localization_manager.hpp>
|
||||||
|
#include <hex/helpers/keys.hpp>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <GLFW/glfw3.h>
|
|
||||||
|
|
||||||
struct ImGuiWindow;
|
struct ImGuiWindow;
|
||||||
|
|
||||||
|
struct KeyEquivalent {
|
||||||
|
bool valid;
|
||||||
|
bool ctrl, opt, cmd, shift;
|
||||||
|
int key;
|
||||||
|
};
|
||||||
|
|
||||||
namespace hex {
|
namespace hex {
|
||||||
|
|
||||||
class View;
|
class View;
|
||||||
|
|
||||||
enum class Keys : u32 {
|
|
||||||
Space = GLFW_KEY_SPACE,
|
|
||||||
Apostrophe = GLFW_KEY_APOSTROPHE,
|
|
||||||
Comma = GLFW_KEY_COMMA,
|
|
||||||
Minus = GLFW_KEY_MINUS,
|
|
||||||
Period = GLFW_KEY_PERIOD,
|
|
||||||
Slash = GLFW_KEY_SLASH,
|
|
||||||
Num0 = GLFW_KEY_0,
|
|
||||||
Num1 = GLFW_KEY_1,
|
|
||||||
Num2 = GLFW_KEY_2,
|
|
||||||
Num3 = GLFW_KEY_3,
|
|
||||||
Num4 = GLFW_KEY_4,
|
|
||||||
Num5 = GLFW_KEY_5,
|
|
||||||
Num6 = GLFW_KEY_6,
|
|
||||||
Num7 = GLFW_KEY_7,
|
|
||||||
Num8 = GLFW_KEY_8,
|
|
||||||
Num9 = GLFW_KEY_9,
|
|
||||||
Semicolon = GLFW_KEY_SEMICOLON,
|
|
||||||
Equals = GLFW_KEY_EQUAL,
|
|
||||||
A = GLFW_KEY_A,
|
|
||||||
B = GLFW_KEY_B,
|
|
||||||
C = GLFW_KEY_C,
|
|
||||||
D = GLFW_KEY_D,
|
|
||||||
E = GLFW_KEY_E,
|
|
||||||
F = GLFW_KEY_F,
|
|
||||||
G = GLFW_KEY_G,
|
|
||||||
H = GLFW_KEY_H,
|
|
||||||
I = GLFW_KEY_I,
|
|
||||||
J = GLFW_KEY_J,
|
|
||||||
K = GLFW_KEY_K,
|
|
||||||
L = GLFW_KEY_L,
|
|
||||||
M = GLFW_KEY_M,
|
|
||||||
N = GLFW_KEY_N,
|
|
||||||
O = GLFW_KEY_O,
|
|
||||||
P = GLFW_KEY_P,
|
|
||||||
Q = GLFW_KEY_Q,
|
|
||||||
R = GLFW_KEY_R,
|
|
||||||
S = GLFW_KEY_S,
|
|
||||||
T = GLFW_KEY_T,
|
|
||||||
U = GLFW_KEY_U,
|
|
||||||
V = GLFW_KEY_V,
|
|
||||||
W = GLFW_KEY_W,
|
|
||||||
X = GLFW_KEY_X,
|
|
||||||
Y = GLFW_KEY_Y,
|
|
||||||
Z = GLFW_KEY_Z,
|
|
||||||
LeftBracket = GLFW_KEY_LEFT_BRACKET,
|
|
||||||
Backslash = GLFW_KEY_BACKSLASH,
|
|
||||||
RightBracket = GLFW_KEY_RIGHT_BRACKET,
|
|
||||||
GraveAccent = GLFW_KEY_GRAVE_ACCENT,
|
|
||||||
World1 = GLFW_KEY_WORLD_1,
|
|
||||||
World2 = GLFW_KEY_WORLD_2,
|
|
||||||
Escape = GLFW_KEY_ESCAPE,
|
|
||||||
Enter = GLFW_KEY_ENTER,
|
|
||||||
Tab = GLFW_KEY_TAB,
|
|
||||||
Backspace = GLFW_KEY_BACKSPACE,
|
|
||||||
Insert = GLFW_KEY_INSERT,
|
|
||||||
Delete = GLFW_KEY_DELETE,
|
|
||||||
Right = GLFW_KEY_RIGHT,
|
|
||||||
Left = GLFW_KEY_LEFT,
|
|
||||||
Down = GLFW_KEY_DOWN,
|
|
||||||
Up = GLFW_KEY_UP,
|
|
||||||
PageUp = GLFW_KEY_PAGE_UP,
|
|
||||||
PageDown = GLFW_KEY_PAGE_DOWN,
|
|
||||||
Home = GLFW_KEY_HOME,
|
|
||||||
End = GLFW_KEY_END,
|
|
||||||
CapsLock = GLFW_KEY_CAPS_LOCK,
|
|
||||||
ScrollLock = GLFW_KEY_SCROLL_LOCK,
|
|
||||||
NumLock = GLFW_KEY_NUM_LOCK,
|
|
||||||
PrintScreen = GLFW_KEY_PRINT_SCREEN,
|
|
||||||
Pause = GLFW_KEY_PAUSE,
|
|
||||||
F1 = GLFW_KEY_F1,
|
|
||||||
F2 = GLFW_KEY_F2,
|
|
||||||
F3 = GLFW_KEY_F3,
|
|
||||||
F4 = GLFW_KEY_F4,
|
|
||||||
F5 = GLFW_KEY_F5,
|
|
||||||
F6 = GLFW_KEY_F6,
|
|
||||||
F7 = GLFW_KEY_F7,
|
|
||||||
F8 = GLFW_KEY_F8,
|
|
||||||
F9 = GLFW_KEY_F9,
|
|
||||||
F10 = GLFW_KEY_F10,
|
|
||||||
F11 = GLFW_KEY_F11,
|
|
||||||
F12 = GLFW_KEY_F12,
|
|
||||||
F13 = GLFW_KEY_F13,
|
|
||||||
F14 = GLFW_KEY_F14,
|
|
||||||
F15 = GLFW_KEY_F15,
|
|
||||||
F16 = GLFW_KEY_F16,
|
|
||||||
F17 = GLFW_KEY_F17,
|
|
||||||
F18 = GLFW_KEY_F18,
|
|
||||||
F19 = GLFW_KEY_F19,
|
|
||||||
F20 = GLFW_KEY_F20,
|
|
||||||
F21 = GLFW_KEY_F21,
|
|
||||||
F22 = GLFW_KEY_F22,
|
|
||||||
F23 = GLFW_KEY_F23,
|
|
||||||
F24 = GLFW_KEY_F24,
|
|
||||||
F25 = GLFW_KEY_F25,
|
|
||||||
KeyPad0 = GLFW_KEY_KP_0,
|
|
||||||
KeyPad1 = GLFW_KEY_KP_1,
|
|
||||||
KeyPad2 = GLFW_KEY_KP_2,
|
|
||||||
KeyPad3 = GLFW_KEY_KP_3,
|
|
||||||
KeyPad4 = GLFW_KEY_KP_4,
|
|
||||||
KeyPad5 = GLFW_KEY_KP_5,
|
|
||||||
KeyPad6 = GLFW_KEY_KP_6,
|
|
||||||
KeyPad7 = GLFW_KEY_KP_7,
|
|
||||||
KeyPad8 = GLFW_KEY_KP_8,
|
|
||||||
KeyPad9 = GLFW_KEY_KP_9,
|
|
||||||
KeyPadDecimal = GLFW_KEY_KP_DECIMAL,
|
|
||||||
KeyPadDivide = GLFW_KEY_KP_DIVIDE,
|
|
||||||
KeyPadMultiply = GLFW_KEY_KP_MULTIPLY,
|
|
||||||
KeyPadSubtract = GLFW_KEY_KP_SUBTRACT,
|
|
||||||
KeyPadAdd = GLFW_KEY_KP_ADD,
|
|
||||||
KeyPadEnter = GLFW_KEY_KP_ENTER,
|
|
||||||
KeyPadEqual = GLFW_KEY_KP_EQUAL,
|
|
||||||
Menu = GLFW_KEY_MENU,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Key {
|
class Key {
|
||||||
public:
|
public:
|
||||||
constexpr Key() = default;
|
constexpr Key() = default;
|
||||||
@ -175,6 +63,7 @@ namespace hex {
|
|||||||
|
|
||||||
bool isLocal() const;
|
bool isLocal() const;
|
||||||
std::string toString() const;
|
std::string toString() const;
|
||||||
|
KeyEquivalent toKeyEquivalent() const;
|
||||||
const std::set<Key>& getKeys() const;
|
const std::set<Key>& getKeys() const;
|
||||||
bool has(Key key) const;
|
bool has(Key key) const;
|
||||||
bool matches(const Shortcut &other) const;
|
bool matches(const Shortcut &other) const;
|
||||||
|
122
lib/libimhex/include/hex/helpers/keys.hpp
Normal file
122
lib/libimhex/include/hex/helpers/keys.hpp
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
enum class Keys {
|
||||||
|
#else
|
||||||
|
enum Keys {
|
||||||
|
#endif
|
||||||
|
Space = GLFW_KEY_SPACE,
|
||||||
|
Apostrophe = GLFW_KEY_APOSTROPHE,
|
||||||
|
Comma = GLFW_KEY_COMMA,
|
||||||
|
Minus = GLFW_KEY_MINUS,
|
||||||
|
Period = GLFW_KEY_PERIOD,
|
||||||
|
Slash = GLFW_KEY_SLASH,
|
||||||
|
Num0 = GLFW_KEY_0,
|
||||||
|
Num1 = GLFW_KEY_1,
|
||||||
|
Num2 = GLFW_KEY_2,
|
||||||
|
Num3 = GLFW_KEY_3,
|
||||||
|
Num4 = GLFW_KEY_4,
|
||||||
|
Num5 = GLFW_KEY_5,
|
||||||
|
Num6 = GLFW_KEY_6,
|
||||||
|
Num7 = GLFW_KEY_7,
|
||||||
|
Num8 = GLFW_KEY_8,
|
||||||
|
Num9 = GLFW_KEY_9,
|
||||||
|
Semicolon = GLFW_KEY_SEMICOLON,
|
||||||
|
Equals = GLFW_KEY_EQUAL,
|
||||||
|
A = GLFW_KEY_A,
|
||||||
|
B = GLFW_KEY_B,
|
||||||
|
C = GLFW_KEY_C,
|
||||||
|
D = GLFW_KEY_D,
|
||||||
|
E = GLFW_KEY_E,
|
||||||
|
F = GLFW_KEY_F,
|
||||||
|
G = GLFW_KEY_G,
|
||||||
|
H = GLFW_KEY_H,
|
||||||
|
I = GLFW_KEY_I,
|
||||||
|
J = GLFW_KEY_J,
|
||||||
|
K = GLFW_KEY_K,
|
||||||
|
L = GLFW_KEY_L,
|
||||||
|
M = GLFW_KEY_M,
|
||||||
|
N = GLFW_KEY_N,
|
||||||
|
O = GLFW_KEY_O,
|
||||||
|
P = GLFW_KEY_P,
|
||||||
|
Q = GLFW_KEY_Q,
|
||||||
|
R = GLFW_KEY_R,
|
||||||
|
S = GLFW_KEY_S,
|
||||||
|
T = GLFW_KEY_T,
|
||||||
|
U = GLFW_KEY_U,
|
||||||
|
V = GLFW_KEY_V,
|
||||||
|
W = GLFW_KEY_W,
|
||||||
|
X = GLFW_KEY_X,
|
||||||
|
Y = GLFW_KEY_Y,
|
||||||
|
Z = GLFW_KEY_Z,
|
||||||
|
LeftBracket = GLFW_KEY_LEFT_BRACKET,
|
||||||
|
Backslash = GLFW_KEY_BACKSLASH,
|
||||||
|
RightBracket = GLFW_KEY_RIGHT_BRACKET,
|
||||||
|
GraveAccent = GLFW_KEY_GRAVE_ACCENT,
|
||||||
|
World1 = GLFW_KEY_WORLD_1,
|
||||||
|
World2 = GLFW_KEY_WORLD_2,
|
||||||
|
Escape = GLFW_KEY_ESCAPE,
|
||||||
|
Enter = GLFW_KEY_ENTER,
|
||||||
|
Tab = GLFW_KEY_TAB,
|
||||||
|
Backspace = GLFW_KEY_BACKSPACE,
|
||||||
|
Insert = GLFW_KEY_INSERT,
|
||||||
|
Delete = GLFW_KEY_DELETE,
|
||||||
|
Right = GLFW_KEY_RIGHT,
|
||||||
|
Left = GLFW_KEY_LEFT,
|
||||||
|
Down = GLFW_KEY_DOWN,
|
||||||
|
Up = GLFW_KEY_UP,
|
||||||
|
PageUp = GLFW_KEY_PAGE_UP,
|
||||||
|
PageDown = GLFW_KEY_PAGE_DOWN,
|
||||||
|
Home = GLFW_KEY_HOME,
|
||||||
|
End = GLFW_KEY_END,
|
||||||
|
CapsLock = GLFW_KEY_CAPS_LOCK,
|
||||||
|
ScrollLock = GLFW_KEY_SCROLL_LOCK,
|
||||||
|
NumLock = GLFW_KEY_NUM_LOCK,
|
||||||
|
PrintScreen = GLFW_KEY_PRINT_SCREEN,
|
||||||
|
Pause = GLFW_KEY_PAUSE,
|
||||||
|
F1 = GLFW_KEY_F1,
|
||||||
|
F2 = GLFW_KEY_F2,
|
||||||
|
F3 = GLFW_KEY_F3,
|
||||||
|
F4 = GLFW_KEY_F4,
|
||||||
|
F5 = GLFW_KEY_F5,
|
||||||
|
F6 = GLFW_KEY_F6,
|
||||||
|
F7 = GLFW_KEY_F7,
|
||||||
|
F8 = GLFW_KEY_F8,
|
||||||
|
F9 = GLFW_KEY_F9,
|
||||||
|
F10 = GLFW_KEY_F10,
|
||||||
|
F11 = GLFW_KEY_F11,
|
||||||
|
F12 = GLFW_KEY_F12,
|
||||||
|
F13 = GLFW_KEY_F13,
|
||||||
|
F14 = GLFW_KEY_F14,
|
||||||
|
F15 = GLFW_KEY_F15,
|
||||||
|
F16 = GLFW_KEY_F16,
|
||||||
|
F17 = GLFW_KEY_F17,
|
||||||
|
F18 = GLFW_KEY_F18,
|
||||||
|
F19 = GLFW_KEY_F19,
|
||||||
|
F20 = GLFW_KEY_F20,
|
||||||
|
F21 = GLFW_KEY_F21,
|
||||||
|
F22 = GLFW_KEY_F22,
|
||||||
|
F23 = GLFW_KEY_F23,
|
||||||
|
F24 = GLFW_KEY_F24,
|
||||||
|
F25 = GLFW_KEY_F25,
|
||||||
|
KeyPad0 = GLFW_KEY_KP_0,
|
||||||
|
KeyPad1 = GLFW_KEY_KP_1,
|
||||||
|
KeyPad2 = GLFW_KEY_KP_2,
|
||||||
|
KeyPad3 = GLFW_KEY_KP_3,
|
||||||
|
KeyPad4 = GLFW_KEY_KP_4,
|
||||||
|
KeyPad5 = GLFW_KEY_KP_5,
|
||||||
|
KeyPad6 = GLFW_KEY_KP_6,
|
||||||
|
KeyPad7 = GLFW_KEY_KP_7,
|
||||||
|
KeyPad8 = GLFW_KEY_KP_8,
|
||||||
|
KeyPad9 = GLFW_KEY_KP_9,
|
||||||
|
KeyPadDecimal = GLFW_KEY_KP_DECIMAL,
|
||||||
|
KeyPadDivide = GLFW_KEY_KP_DIVIDE,
|
||||||
|
KeyPadMultiply = GLFW_KEY_KP_MULTIPLY,
|
||||||
|
KeyPadSubtract = GLFW_KEY_KP_SUBTRACT,
|
||||||
|
KeyPadAdd = GLFW_KEY_KP_ADD,
|
||||||
|
KeyPadEnter = GLFW_KEY_KP_ENTER,
|
||||||
|
KeyPadEqual = GLFW_KEY_KP_EQUAL,
|
||||||
|
Menu = GLFW_KEY_MENU,
|
||||||
|
};
|
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <hex/helpers/keys.hpp>
|
||||||
|
|
||||||
#if defined(OS_MACOS)
|
#if defined(OS_MACOS)
|
||||||
|
|
||||||
struct GLFWwindow;
|
struct GLFWwindow;
|
||||||
@ -20,6 +22,8 @@
|
|||||||
void macosSetWindowMovable(GLFWwindow *window, bool movable);
|
void macosSetWindowMovable(GLFWwindow *window, bool movable);
|
||||||
bool macosIsWindowBeingResizedByUser(GLFWwindow *window);
|
bool macosIsWindowBeingResizedByUser(GLFWwindow *window);
|
||||||
void macosMarkContentEdited(GLFWwindow *window, bool edited = true);
|
void macosMarkContentEdited(GLFWwindow *window, bool edited = true);
|
||||||
|
|
||||||
|
void macosGetKey(Keys key, int *output);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -233,6 +233,44 @@ namespace hex {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyEquivalent Shortcut::toKeyEquivalent() const {
|
||||||
|
#if defined(OS_MACOS)
|
||||||
|
if (*this == None)
|
||||||
|
return { };
|
||||||
|
|
||||||
|
KeyEquivalent result = {};
|
||||||
|
result.valid = true;
|
||||||
|
|
||||||
|
for (const auto &key : m_keys) {
|
||||||
|
switch (key.getKeyCode()) {
|
||||||
|
case CTRL.getKeyCode():
|
||||||
|
result.ctrl = true;
|
||||||
|
break;
|
||||||
|
case SHIFT.getKeyCode():
|
||||||
|
result.shift = true;
|
||||||
|
break;
|
||||||
|
case ALT.getKeyCode():
|
||||||
|
result.opt = true;
|
||||||
|
break;
|
||||||
|
case SUPER.getKeyCode():
|
||||||
|
case CTRLCMD.getKeyCode():
|
||||||
|
result.cmd = true;
|
||||||
|
break;
|
||||||
|
case CurrentView.getKeyCode(): break;
|
||||||
|
case AllowWhileTyping.getKeyCode(): break;
|
||||||
|
default:
|
||||||
|
macosGetKey(Keys(key.getKeyCode()), &result.key);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
#else
|
||||||
|
return { };
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void ShortcutManager::addGlobalShortcut(const Shortcut &shortcut, const std::vector<UnlocalizedString> &unlocalizedName, const std::function<void()> &callback, const EnabledCallback &enabledCallback) {
|
void ShortcutManager::addGlobalShortcut(const Shortcut &shortcut, const std::vector<UnlocalizedString> &unlocalizedName, const std::function<void()> &callback, const EnabledCallback &enabledCallback) {
|
||||||
log::debug("Adding global shortcut {} for {}", shortcut.toString(), unlocalizedName.back().get());
|
log::debug("Adding global shortcut {} for {}", shortcut.toString(), unlocalizedName.back().get());
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#include <hex/helpers/keys.hpp>
|
||||||
|
|
||||||
void errorMessageMacos(const char *cMessage) {
|
void errorMessageMacos(const char *cMessage) {
|
||||||
CFStringRef strMessage = CFStringCreateWithCString(NULL, cMessage, kCFStringEncodingUTF8);
|
CFStringRef strMessage = CFStringCreateWithCString(NULL, cMessage, kCFStringEncodingUTF8);
|
||||||
CFUserNotificationDisplayAlert(0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL, strMessage, NULL, NULL, NULL, NULL, NULL);
|
CFUserNotificationDisplayAlert(0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL, strMessage, NULL, NULL, NULL, NULL, NULL);
|
||||||
@ -151,4 +153,123 @@
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
void macosGetKey(enum Keys key, int *output) {
|
||||||
|
*output = 0x00;
|
||||||
|
switch (key) {
|
||||||
|
case Space: *output = ' '; break;
|
||||||
|
case Apostrophe: *output = '\''; break;
|
||||||
|
case Comma: *output = ','; break;
|
||||||
|
case Minus: *output = '-'; break;
|
||||||
|
case Period: *output = '.'; break;
|
||||||
|
case Slash: *output = '/'; break;
|
||||||
|
case Num0: *output = '0'; break;
|
||||||
|
case Num1: *output = '1'; break;
|
||||||
|
case Num2: *output = '2'; break;
|
||||||
|
case Num3: *output = '3'; break;
|
||||||
|
case Num4: *output = '4'; break;
|
||||||
|
case Num5: *output = '5'; break;
|
||||||
|
case Num6: *output = '6'; break;
|
||||||
|
case Num7: *output = '7'; break;
|
||||||
|
case Num8: *output = '8'; break;
|
||||||
|
case Num9: *output = '9'; break;
|
||||||
|
case Semicolon: *output = ';'; break;
|
||||||
|
case Equals: *output = '='; break;
|
||||||
|
case A: *output = 'a'; break;
|
||||||
|
case B: *output = 'b'; break;
|
||||||
|
case C: *output = 'c'; break;
|
||||||
|
case D: *output = 'd'; break;
|
||||||
|
case E: *output = 'e'; break;
|
||||||
|
case F: *output = 'f'; break;
|
||||||
|
case G: *output = 'g'; break;
|
||||||
|
case H: *output = 'h'; break;
|
||||||
|
case I: *output = 'i'; break;
|
||||||
|
case J: *output = 'j'; break;
|
||||||
|
case K: *output = 'k'; break;
|
||||||
|
case L: *output = 'l'; break;
|
||||||
|
case M: *output = 'm'; break;
|
||||||
|
case N: *output = 'n'; break;
|
||||||
|
case O: *output = 'o'; break;
|
||||||
|
case P: *output = 'p'; break;
|
||||||
|
case Q: *output = 'q'; break;
|
||||||
|
case R: *output = 'r'; break;
|
||||||
|
case S: *output = 's'; break;
|
||||||
|
case T: *output = 't'; break;
|
||||||
|
case U: *output = 'u'; break;
|
||||||
|
case V: *output = 'v'; break;
|
||||||
|
case W: *output = 'w'; break;
|
||||||
|
case X: *output = 'x'; break;
|
||||||
|
case Y: *output = 'y'; break;
|
||||||
|
case Z: *output = 'z'; break;
|
||||||
|
case LeftBracket: *output = '/'; break;
|
||||||
|
case Backslash: *output = '\\'; break;
|
||||||
|
case RightBracket: *output = ']'; break;
|
||||||
|
case GraveAccent: *output = '`'; break;
|
||||||
|
case World1: break;
|
||||||
|
case World2: break;
|
||||||
|
case Escape: break;
|
||||||
|
case Enter: *output = NSEnterCharacter; break;
|
||||||
|
case Tab: *output = NSTabCharacter; break;
|
||||||
|
case Backspace: *output = NSBackspaceCharacter; break;
|
||||||
|
case Insert: *output = NSInsertFunctionKey; break;
|
||||||
|
case Delete: *output = NSDeleteCharacter; break;
|
||||||
|
case Right: *output = NSRightArrowFunctionKey; break;
|
||||||
|
case Left: *output = NSLeftArrowFunctionKey; break;
|
||||||
|
case Down: *output = NSDownArrowFunctionKey; break;
|
||||||
|
case Up: *output = NSUpArrowFunctionKey; break;
|
||||||
|
case PageUp: *output = NSPageUpFunctionKey; break;
|
||||||
|
case PageDown: *output = NSPageDownFunctionKey; break;
|
||||||
|
case Home: *output = NSHomeFunctionKey; break;
|
||||||
|
case End: *output = NSEndFunctionKey; break;
|
||||||
|
case CapsLock: break;
|
||||||
|
case ScrollLock: *output = NSScrollLockFunctionKey; break;
|
||||||
|
case NumLock: break;
|
||||||
|
case PrintScreen: *output = NSPrintScreenFunctionKey; break;
|
||||||
|
case Pause: *output = NSPauseFunctionKey; break;
|
||||||
|
case F1: *output = NSF1FunctionKey; break;
|
||||||
|
case F2: *output = NSF2FunctionKey; break;
|
||||||
|
case F3: *output = NSF3FunctionKey; break;
|
||||||
|
case F4: *output = NSF4FunctionKey; break;
|
||||||
|
case F5: *output = NSF5FunctionKey; break;
|
||||||
|
case F6: *output = NSF6FunctionKey; break;
|
||||||
|
case F7: *output = NSF7FunctionKey; break;
|
||||||
|
case F8: *output = NSF8FunctionKey; break;
|
||||||
|
case F9: *output = NSF9FunctionKey; break;
|
||||||
|
case F10: *output = NSF10FunctionKey; break;
|
||||||
|
case F11: *output = NSF11FunctionKey; break;
|
||||||
|
case F12: *output = NSF12FunctionKey; break;
|
||||||
|
case F13: *output = NSF13FunctionKey; break;
|
||||||
|
case F14: *output = NSF14FunctionKey; break;
|
||||||
|
case F15: *output = NSF15FunctionKey; break;
|
||||||
|
case F16: *output = NSF16FunctionKey; break;
|
||||||
|
case F17: *output = NSF17FunctionKey; break;
|
||||||
|
case F18: *output = NSF18FunctionKey; break;
|
||||||
|
case F19: *output = NSF19FunctionKey; break;
|
||||||
|
case F20: *output = NSF20FunctionKey; break;
|
||||||
|
case F21: *output = NSF21FunctionKey; break;
|
||||||
|
case F22: *output = NSF22FunctionKey; break;
|
||||||
|
case F23: *output = NSF23FunctionKey; break;
|
||||||
|
case F24: *output = NSF24FunctionKey; break;
|
||||||
|
case F25: *output = NSF25FunctionKey; break;
|
||||||
|
case KeyPad0: *output = '0'; break;
|
||||||
|
case KeyPad1: *output = '1'; break;
|
||||||
|
case KeyPad2: *output = '2'; break;
|
||||||
|
case KeyPad3: *output = '3'; break;
|
||||||
|
case KeyPad4: *output = '4'; break;
|
||||||
|
case KeyPad5: *output = '5'; break;
|
||||||
|
case KeyPad6: *output = '6'; break;
|
||||||
|
case KeyPad7: *output = '7'; break;
|
||||||
|
case KeyPad8: *output = '8'; break;
|
||||||
|
case KeyPad9: *output = '9'; break;
|
||||||
|
case KeyPadDecimal: *output = '.'; break;
|
||||||
|
case KeyPadDivide: *output = '/'; break;
|
||||||
|
case KeyPadMultiply: *output = '*'; break;
|
||||||
|
case KeyPadSubtract: *output = '-'; break;
|
||||||
|
case KeyPadAdd: *output = '+'; break;
|
||||||
|
case KeyPadEnter: *output = NSEnterCharacter; break;
|
||||||
|
case KeyPadEqual: *output = '='; break;
|
||||||
|
case Menu: *output = NSMenuFunctionKey; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -514,6 +514,7 @@
|
|||||||
"hex.builtin.setting.interface.scaling.fractional_warning": "The default font does not support fractional scaling. For better results, select a custom font in the 'Font' tab.",
|
"hex.builtin.setting.interface.scaling.fractional_warning": "The default font does not support fractional scaling. For better results, select a custom font in the 'Font' tab.",
|
||||||
"hex.builtin.setting.interface.show_header_command_palette": "Show Command Palette in Window Header",
|
"hex.builtin.setting.interface.show_header_command_palette": "Show Command Palette in Window Header",
|
||||||
"hex.builtin.setting.interface.style": "Styling",
|
"hex.builtin.setting.interface.style": "Styling",
|
||||||
|
"hex.builtin.setting.interface.use_native_menu_bar": "Use native menu bar",
|
||||||
"hex.builtin.setting.interface.window": "Window",
|
"hex.builtin.setting.interface.window": "Window",
|
||||||
"hex.builtin.setting.interface.pattern_data_row_bg": "Enable colored pattern background",
|
"hex.builtin.setting.interface.pattern_data_row_bg": "Enable colored pattern background",
|
||||||
"hex.builtin.setting.interface.wiki_explain_language": "Wikipedia Language",
|
"hex.builtin.setting.interface.wiki_explain_language": "Wikipedia Language",
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include <wolv/literals.hpp>
|
#include <wolv/literals.hpp>
|
||||||
|
|
||||||
#include <romfs/romfs.hpp>
|
#include <romfs/romfs.hpp>
|
||||||
|
#include <ui/menu_items.hpp>
|
||||||
|
|
||||||
using namespace std::literals::string_literals;
|
using namespace std::literals::string_literals;
|
||||||
using namespace wolv::literals;
|
using namespace wolv::literals;
|
||||||
@ -212,7 +213,7 @@ namespace hex::plugin::builtin {
|
|||||||
|
|
||||||
void drawExportLanguageMenu() {
|
void drawExportLanguageMenu() {
|
||||||
for (const auto &formatter : ContentRegistry::DataFormatter::impl::getExportMenuEntries()) {
|
for (const auto &formatter : ContentRegistry::DataFormatter::impl::getExportMenuEntries()) {
|
||||||
if (ImGui::MenuItem(Lang(formatter.unlocalizedName), nullptr, false, ImHexApi::Provider::get()->getActualSize() > 0)) {
|
if (menu::menuItem(Lang(formatter.unlocalizedName), Shortcut::None, false, ImHexApi::Provider::isValid() && ImHexApi::Provider::get()->getActualSize() > 0)) {
|
||||||
fs::openFileBrowser(fs::DialogMode::Save, {}, [&formatter](const auto &path) {
|
fs::openFileBrowser(fs::DialogMode::Save, {}, [&formatter](const auto &path) {
|
||||||
TaskManager::createTask("hex.builtin.task.exporting_data"_lang, TaskManager::NoProgress, [&formatter, path](auto&){
|
TaskManager::createTask("hex.builtin.task.exporting_data"_lang, TaskManager::NoProgress, [&formatter, path](auto&){
|
||||||
auto provider = ImHexApi::Provider::get();
|
auto provider = ImHexApi::Provider::get();
|
||||||
@ -379,7 +380,7 @@ namespace hex::plugin::builtin {
|
|||||||
/* Open Other */
|
/* Open Other */
|
||||||
ContentRegistry::Interface::addMenuItemSubMenu({ "hex.builtin.menu.file", "hex.builtin.menu.file.open_other"}, ICON_VS_TELESCOPE, 1150, [] {
|
ContentRegistry::Interface::addMenuItemSubMenu({ "hex.builtin.menu.file", "hex.builtin.menu.file.open_other"}, ICON_VS_TELESCOPE, 1150, [] {
|
||||||
for (const auto &unlocalizedProviderName : ContentRegistry::Provider::impl::getEntries()) {
|
for (const auto &unlocalizedProviderName : ContentRegistry::Provider::impl::getEntries()) {
|
||||||
if (ImGui::MenuItem(Lang(unlocalizedProviderName)))
|
if (menu::menuItem(Lang(unlocalizedProviderName)))
|
||||||
ImHexApi::Provider::createProvider(unlocalizedProviderName);
|
ImHexApi::Provider::createProvider(unlocalizedProviderName);
|
||||||
}
|
}
|
||||||
}, noRunningTasks);
|
}, noRunningTasks);
|
||||||
@ -556,7 +557,7 @@ namespace hex::plugin::builtin {
|
|||||||
if (view->hasViewMenuItemEntry()) {
|
if (view->hasViewMenuItemEntry()) {
|
||||||
auto &state = view->getWindowOpenState();
|
auto &state = view->getWindowOpenState();
|
||||||
|
|
||||||
if (ImGui::MenuItemEx(Lang(view->getUnlocalizedName()), view->getIcon(), "", state, ImHexApi::Provider::isValid() && !LayoutManager::isLayoutLocked()))
|
if (menu::menuItemEx(Lang(view->getUnlocalizedName()), view->getIcon(), Shortcut::None, state, ImHexApi::Provider::isValid() && !LayoutManager::isLayoutLocked()))
|
||||||
state = !state;
|
state = !state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -577,7 +578,7 @@ namespace hex::plugin::builtin {
|
|||||||
|
|
||||||
ContentRegistry::Interface::addMenuItemSubMenu({ "hex.builtin.menu.workspace", "hex.builtin.menu.workspace.layout" }, ICON_VS_LAYOUT, 1150, [] {
|
ContentRegistry::Interface::addMenuItemSubMenu({ "hex.builtin.menu.workspace", "hex.builtin.menu.workspace.layout" }, ICON_VS_LAYOUT, 1150, [] {
|
||||||
bool locked = LayoutManager::isLayoutLocked();
|
bool locked = LayoutManager::isLayoutLocked();
|
||||||
if (ImGui::MenuItemEx("hex.builtin.menu.workspace.layout.lock"_lang, ICON_VS_LOCK, nullptr, locked, ImHexApi::Provider::isValid())) {
|
if (menu::menuItemEx("hex.builtin.menu.workspace.layout.lock"_lang, ICON_VS_LOCK, Shortcut::None, locked, ImHexApi::Provider::isValid())) {
|
||||||
LayoutManager::lockLayout(!locked);
|
LayoutManager::lockLayout(!locked);
|
||||||
ContentRegistry::Settings::write<bool>("hex.builtin.setting.interface", "hex.builtin.setting.interface.layout_locked", !locked);
|
ContentRegistry::Settings::write<bool>("hex.builtin.setting.interface", "hex.builtin.setting.interface.layout_locked", !locked);
|
||||||
}
|
}
|
||||||
@ -587,14 +588,14 @@ namespace hex::plugin::builtin {
|
|||||||
|
|
||||||
ContentRegistry::Interface::addMenuItemSubMenu({ "hex.builtin.menu.workspace", "hex.builtin.menu.workspace.layout" }, 2000, [] {
|
ContentRegistry::Interface::addMenuItemSubMenu({ "hex.builtin.menu.workspace", "hex.builtin.menu.workspace.layout" }, 2000, [] {
|
||||||
for (const auto &path : romfs::list("layouts")) {
|
for (const auto &path : romfs::list("layouts")) {
|
||||||
if (ImGui::MenuItem(wolv::util::capitalizeString(path.stem().string()).c_str(), "", false, ImHexApi::Provider::isValid())) {
|
if (menu::menuItem(wolv::util::capitalizeString(path.stem().string()).c_str(), Shortcut::None, false, ImHexApi::Provider::isValid())) {
|
||||||
LayoutManager::loadFromString(std::string(romfs::get(path).string()));
|
LayoutManager::loadFromString(std::string(romfs::get(path).string()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool shiftPressed = ImGui::GetIO().KeyShift;
|
bool shiftPressed = ImGui::GetIO().KeyShift;
|
||||||
for (auto &[name, path] : LayoutManager::getLayouts()) {
|
for (auto &[name, path] : LayoutManager::getLayouts()) {
|
||||||
if (ImGui::MenuItem(hex::format("{}{}", name, shiftPressed ? " " ICON_VS_X : "").c_str(), "", false, ImHexApi::Provider::isValid())) {
|
if (menu::menuItem(hex::format("{}{}", name, shiftPressed ? " " ICON_VS_X : "").c_str(), Shortcut::None, false, ImHexApi::Provider::isValid())) {
|
||||||
if (shiftPressed) {
|
if (shiftPressed) {
|
||||||
LayoutManager::removeLayout(name);
|
LayoutManager::removeLayout(name);
|
||||||
break;
|
break;
|
||||||
@ -627,7 +628,7 @@ namespace hex::plugin::builtin {
|
|||||||
const auto &[name, workspace] = *it;
|
const auto &[name, workspace] = *it;
|
||||||
|
|
||||||
bool canRemove = shiftPressed && !workspace.builtin;
|
bool canRemove = shiftPressed && !workspace.builtin;
|
||||||
if (ImGui::MenuItem(hex::format("{}{}", name, canRemove ? " " ICON_VS_X : "").c_str(), "", it == WorkspaceManager::getCurrentWorkspace(), ImHexApi::Provider::isValid())) {
|
if (menu::menuItem(hex::format("{}{}", name, canRemove ? " " ICON_VS_X : "").c_str(), Shortcut::None, it == WorkspaceManager::getCurrentWorkspace(), ImHexApi::Provider::isValid())) {
|
||||||
if (canRemove) {
|
if (canRemove) {
|
||||||
WorkspaceManager::removeWorkspace(name);
|
WorkspaceManager::removeWorkspace(name);
|
||||||
break;
|
break;
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
#include <ui/menu_items.hpp>
|
||||||
|
|
||||||
namespace hex::plugin::builtin::recent {
|
namespace hex::plugin::builtin::recent {
|
||||||
|
|
||||||
@ -352,17 +353,17 @@ namespace hex::plugin::builtin::recent {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
ContentRegistry::Interface::addMenuItemSubMenu({ "hex.builtin.menu.file" }, 1200, [] {
|
ContentRegistry::Interface::addMenuItemSubMenu({ "hex.builtin.menu.file" }, 1200, [] {
|
||||||
if (ImGui::BeginMenuEx("hex.builtin.menu.file.open_recent"_lang, ICON_VS_ARCHIVE, !recent::s_recentEntriesUpdating && !s_recentEntries.empty())) {
|
if (menu::beginMenuEx("hex.builtin.menu.file.open_recent"_lang, ICON_VS_ARCHIVE, !recent::s_recentEntriesUpdating && !s_recentEntries.empty())) {
|
||||||
// Copy to avoid changing list while iteration
|
// Copy to avoid changing list while iteration
|
||||||
auto recentEntries = s_recentEntries;
|
auto recentEntries = s_recentEntries;
|
||||||
for (auto &recentEntry : recentEntries) {
|
for (auto &recentEntry : recentEntries) {
|
||||||
if (ImGui::MenuItem(recentEntry.displayName.c_str())) {
|
if (menu::menuItem(recentEntry.displayName.c_str())) {
|
||||||
loadRecentEntry(recentEntry);
|
loadRecentEntry(recentEntry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Separator();
|
menu::menuSeparator();
|
||||||
if (ImGui::MenuItem("hex.builtin.menu.file.clear_recent"_lang)) {
|
if (menu::menuItem("hex.builtin.menu.file.clear_recent"_lang)) {
|
||||||
s_recentEntries.clear();
|
s_recentEntries.clear();
|
||||||
|
|
||||||
// Remove all recent files
|
// Remove all recent files
|
||||||
@ -372,7 +373,7 @@ namespace hex::plugin::builtin::recent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndMenu();
|
menu::endMenu();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -833,6 +833,10 @@ namespace hex::plugin::builtin {
|
|||||||
ContentRegistry::Settings::add<Widgets::Checkbox>("hex.builtin.setting.interface", "hex.builtin.setting.interface.window", "hex.builtin.setting.interface.native_window_decorations", !getDefaultBorderlessWindowMode()).requiresRestart();
|
ContentRegistry::Settings::add<Widgets::Checkbox>("hex.builtin.setting.interface", "hex.builtin.setting.interface.window", "hex.builtin.setting.interface.native_window_decorations", !getDefaultBorderlessWindowMode()).requiresRestart();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined (OS_MACOS)
|
||||||
|
ContentRegistry::Settings::add<Widgets::Checkbox>("hex.builtin.setting.interface", "hex.builtin.setting.interface.window", "hex.builtin.setting.interface.use_native_menu_bar", true);
|
||||||
|
#endif
|
||||||
|
|
||||||
ContentRegistry::Settings::add<Widgets::Checkbox>("hex.builtin.setting.interface", "hex.builtin.setting.interface.window", "hex.builtin.setting.interface.restore_window_pos", false);
|
ContentRegistry::Settings::add<Widgets::Checkbox>("hex.builtin.setting.interface", "hex.builtin.setting.interface.window", "hex.builtin.setting.interface.restore_window_pos", false);
|
||||||
|
|
||||||
ContentRegistry::Settings::add<Widgets::ColorPicker>("hex.builtin.setting.hex_editor", "", "hex.builtin.setting.hex_editor.highlight_color", ImColor(0x80, 0x80, 0xC0, 0x60));
|
ContentRegistry::Settings::add<Widgets::ColorPicker>("hex.builtin.setting.hex_editor", "", "hex.builtin.setting.hex_editor.highlight_color", ImColor(0x80, 0x80, 0xC0, 0x60));
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include <wolv/utils/string.hpp>
|
#include <wolv/utils/string.hpp>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <ui/menu_items.hpp>
|
||||||
|
|
||||||
namespace hex::plugin::builtin {
|
namespace hex::plugin::builtin {
|
||||||
|
|
||||||
@ -86,6 +87,9 @@ namespace hex::plugin::builtin {
|
|||||||
ContentRegistry::Interface::addMenuItemSeparator({ "hex.builtin.menu.help" }, 2000);
|
ContentRegistry::Interface::addMenuItemSeparator({ "hex.builtin.menu.help" }, 2000);
|
||||||
|
|
||||||
ContentRegistry::Interface::addMenuItemSubMenu({ "hex.builtin.menu.help" }, 3000, [] {
|
ContentRegistry::Interface::addMenuItemSubMenu({ "hex.builtin.menu.help" }, 3000, [] {
|
||||||
|
if (menu::isNativeMenuBarUsed())
|
||||||
|
return;
|
||||||
|
|
||||||
static std::string content;
|
static std::string content;
|
||||||
if (ImGui::InputTextWithHint("##search", "hex.builtin.view.help.documentation_search"_lang, content, ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_EscapeClearsAll | ImGuiInputTextFlags_EnterReturnsTrue)) {
|
if (ImGui::InputTextWithHint("##search", "hex.builtin.view.help.documentation_search"_lang, content, ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_EscapeClearsAll | ImGuiInputTextFlags_EnterReturnsTrue)) {
|
||||||
PopupDocsQuestion::open(content);
|
PopupDocsQuestion::open(content);
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include <content/popups/popup_blocking_task.hpp>
|
#include <content/popups/popup_blocking_task.hpp>
|
||||||
#include <content/popups/hex_editor/popup_hex_editor_find.hpp>
|
#include <content/popups/hex_editor/popup_hex_editor_find.hpp>
|
||||||
#include <pl/patterns/pattern.hpp>
|
#include <pl/patterns/pattern.hpp>
|
||||||
|
#include <ui/menu_items.hpp>
|
||||||
#include <wolv/literals.hpp>
|
#include <wolv/literals.hpp>
|
||||||
|
|
||||||
using namespace std::literals::string_literals;
|
using namespace std::literals::string_literals;
|
||||||
@ -1278,7 +1279,7 @@ namespace hex::plugin::builtin {
|
|||||||
|
|
||||||
bool enabled = ImHexApi::HexEditor::isSelectionValid();
|
bool enabled = ImHexApi::HexEditor::isSelectionValid();
|
||||||
for (const auto &[unlocalizedName, callback] : ContentRegistry::DataFormatter::impl::getExportMenuEntries()) {
|
for (const auto &[unlocalizedName, callback] : ContentRegistry::DataFormatter::impl::getExportMenuEntries()) {
|
||||||
if (ImGui::MenuItem(Lang(unlocalizedName), nullptr, false, enabled)) {
|
if (menu::menuItem(Lang(unlocalizedName), Shortcut::None, false, enabled)) {
|
||||||
ImGui::SetClipboardText(
|
ImGui::SetClipboardText(
|
||||||
callback(
|
callback(
|
||||||
provider,
|
provider,
|
||||||
@ -1425,7 +1426,13 @@ namespace hex::plugin::builtin {
|
|||||||
ContentRegistry::Interface::addMenuItemSubMenu({ "hex.builtin.menu.edit", "hex.builtin.view.hex_editor.menu.edit.jump_to" }, ICON_VS_DEBUG_STEP_OUT, 1850,
|
ContentRegistry::Interface::addMenuItemSubMenu({ "hex.builtin.menu.edit", "hex.builtin.view.hex_editor.menu.edit.jump_to" }, ICON_VS_DEBUG_STEP_OUT, 1850,
|
||||||
[] {
|
[] {
|
||||||
auto provider = ImHexApi::Provider::get();
|
auto provider = ImHexApi::Provider::get();
|
||||||
auto selection = ImHexApi::HexEditor::getSelection();
|
if (provider == nullptr)
|
||||||
|
return;
|
||||||
|
const auto selection = ImHexApi::HexEditor::getSelection();
|
||||||
|
if (!selection.has_value())
|
||||||
|
return;
|
||||||
|
if (selection->getSize() > sizeof(u64))
|
||||||
|
return;
|
||||||
|
|
||||||
u64 value = 0;
|
u64 value = 0;
|
||||||
provider->read(selection->getStartAddress(), &value, selection->getSize());
|
provider->read(selection->getStartAddress(), &value, selection->getSize());
|
||||||
@ -1438,18 +1445,18 @@ namespace hex::plugin::builtin {
|
|||||||
};
|
};
|
||||||
|
|
||||||
ImGui::PushID(1);
|
ImGui::PushID(1);
|
||||||
if (ImGui::MenuItem(hex::format("0x{:08X}", littleEndianValue).c_str(), "hex.ui.common.little_endian"_lang, false, canJumpTo(littleEndianValue))) {
|
if (menu::menuItem(hex::format("{} | 0x{:08X}", "hex.ui.common.little_endian"_lang, littleEndianValue).c_str(), Shortcut::None, false, canJumpTo(littleEndianValue))) {
|
||||||
ImHexApi::HexEditor::setSelection(littleEndianValue, 1);
|
ImHexApi::HexEditor::setSelection(littleEndianValue, 1);
|
||||||
}
|
}
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
|
|
||||||
ImGui::PushID(2);
|
ImGui::PushID(2);
|
||||||
if (ImGui::MenuItem(hex::format("0x{:08X}", bigEndianValue).c_str(), "hex.ui.common.big_endian"_lang, false, canJumpTo(bigEndianValue))) {
|
if (menu::menuItem(hex::format("{} | 0x{:08X}", "hex.ui.common.big_endian"_lang, bigEndianValue).c_str(), Shortcut::None, false, canJumpTo(bigEndianValue))) {
|
||||||
ImHexApi::HexEditor::setSelection(bigEndianValue, 1);
|
ImHexApi::HexEditor::setSelection(bigEndianValue, 1);
|
||||||
}
|
}
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
|
|
||||||
if (ImGui::MenuItem("hex.builtin.view.hex_editor.menu.edit.jump_to.curr_pattern"_lang, "", false, selection.has_value() && ContentRegistry::PatternLanguage::getRuntime().getCreatedPatternCount() > 0)) {
|
if (menu::menuItem("hex.builtin.view.hex_editor.menu.edit.jump_to.curr_pattern"_lang, Shortcut::None, false, selection.has_value() && ContentRegistry::PatternLanguage::getRuntime().getCreatedPatternCount() > 0)) {
|
||||||
auto patterns = ContentRegistry::PatternLanguage::getRuntime().getPatternsAtAddress(selection->getStartAddress());
|
auto patterns = ContentRegistry::PatternLanguage::getRuntime().getPatternsAtAddress(selection->getStartAddress());
|
||||||
|
|
||||||
if (!patterns.empty())
|
if (!patterns.empty())
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include <wolv/utils/lock.hpp>
|
#include <wolv/utils/lock.hpp>
|
||||||
|
|
||||||
#include <content/global_actions.hpp>
|
#include <content/global_actions.hpp>
|
||||||
|
#include <ui/menu_items.hpp>
|
||||||
|
|
||||||
namespace hex::plugin::builtin {
|
namespace hex::plugin::builtin {
|
||||||
|
|
||||||
@ -2074,12 +2075,12 @@ namespace hex::plugin::builtin {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (menus.size() == 1) {
|
if (menus.size() == 1) {
|
||||||
if (ImGui::MenuItem(menus.front().c_str()))
|
if (menu::menuItem(menus.front().c_str()))
|
||||||
function();
|
function();
|
||||||
} else {
|
} else {
|
||||||
if (ImGui::BeginMenu(menus.front().c_str())) {
|
if (menu::beginMenu(menus.front().c_str())) {
|
||||||
createNestedMenu({ menus.begin() + 1, menus.end() }, function);
|
createNestedMenu({ menus.begin() + 1, menus.end() }, function);
|
||||||
ImGui::EndMenu();
|
menu::endMenu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2135,30 +2136,30 @@ namespace hex::plugin::builtin {
|
|||||||
/* Place pattern... */
|
/* Place pattern... */
|
||||||
ContentRegistry::Interface::addMenuItemSubMenu({ "hex.builtin.menu.edit", "hex.builtin.view.pattern_editor.menu.edit.place_pattern" }, ICON_VS_LIBRARY, 3000,
|
ContentRegistry::Interface::addMenuItemSubMenu({ "hex.builtin.menu.edit", "hex.builtin.view.pattern_editor.menu.edit.place_pattern" }, ICON_VS_LIBRARY, 3000,
|
||||||
[&, this] {
|
[&, this] {
|
||||||
if (ImGui::BeginMenu("hex.builtin.view.pattern_editor.menu.edit.place_pattern.builtin"_lang)) {
|
if (menu::beginMenu("hex.builtin.view.pattern_editor.menu.edit.place_pattern.builtin"_lang)) {
|
||||||
if (ImGui::BeginMenu("hex.builtin.view.pattern_editor.menu.edit.place_pattern.builtin.single"_lang)) {
|
if (menu::beginMenu("hex.builtin.view.pattern_editor.menu.edit.place_pattern.builtin.single"_lang)) {
|
||||||
for (const auto &[type, size] : Types) {
|
for (const auto &[type, size] : Types) {
|
||||||
if (ImGui::MenuItem(type))
|
if (menu::menuItem(type))
|
||||||
appendVariable(type);
|
appendVariable(type);
|
||||||
}
|
}
|
||||||
ImGui::EndMenu();
|
menu::endMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::BeginMenu("hex.builtin.view.pattern_editor.menu.edit.place_pattern.builtin.array"_lang)) {
|
if (menu::beginMenu("hex.builtin.view.pattern_editor.menu.edit.place_pattern.builtin.array"_lang)) {
|
||||||
for (const auto &[type, size] : Types) {
|
for (const auto &[type, size] : Types) {
|
||||||
if (ImGui::MenuItem(type))
|
if (menu::menuItem(type))
|
||||||
appendArray(type, size);
|
appendArray(type, size);
|
||||||
}
|
}
|
||||||
ImGui::EndMenu();
|
menu::endMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndMenu();
|
menu::endMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &types = m_editorRuntime->getInternals().parser->getTypes();
|
const auto &types = m_editorRuntime->getInternals().parser->getTypes();
|
||||||
const bool hasPlaceableTypes = std::ranges::any_of(types, [](const auto &type) { return !type.second->isTemplateType(); });
|
const bool hasPlaceableTypes = std::ranges::any_of(types, [](const auto &type) { return !type.second->isTemplateType(); });
|
||||||
|
|
||||||
if (ImGui::BeginMenu("hex.builtin.view.pattern_editor.menu.edit.place_pattern.custom"_lang, hasPlaceableTypes)) {
|
if (menu::beginMenu("hex.builtin.view.pattern_editor.menu.edit.place_pattern.custom"_lang, hasPlaceableTypes)) {
|
||||||
const auto &selection = ImHexApi::HexEditor::getSelection();
|
const auto &selection = ImHexApi::HexEditor::getSelection();
|
||||||
|
|
||||||
for (const auto &[typeName, type] : types) {
|
for (const auto &[typeName, type] : types) {
|
||||||
@ -2175,7 +2176,7 @@ namespace hex::plugin::builtin {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndMenu();
|
menu::endMenu();
|
||||||
}
|
}
|
||||||
}, [this] {
|
}, [this] {
|
||||||
return ImHexApi::Provider::isValid() && ImHexApi::HexEditor::isSelectionValid() && m_runningParsers == 0;
|
return ImHexApi::Provider::isValid() && ImHexApi::HexEditor::isSelectionValid() && m_runningParsers == 0;
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <imgui_internal.h>
|
#include <imgui_internal.h>
|
||||||
#include <hex/ui/imgui_imhex_extensions.h>
|
#include <hex/ui/imgui_imhex_extensions.h>
|
||||||
|
#include <ui/menu_items.hpp>
|
||||||
|
|
||||||
#include <fonts/vscode_icons.hpp>
|
#include <fonts/vscode_icons.hpp>
|
||||||
#include <romfs/romfs.hpp>
|
#include <romfs/romfs.hpp>
|
||||||
@ -32,21 +33,23 @@ namespace hex::plugin::builtin {
|
|||||||
const auto &name = menuItems.front();
|
const auto &name = menuItems.front();
|
||||||
|
|
||||||
if (name.get() == ContentRegistry::Interface::impl::SeparatorValue) {
|
if (name.get() == ContentRegistry::Interface::impl::SeparatorValue) {
|
||||||
ImGui::Separator();
|
menu::menuSeparator();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name.get() == ContentRegistry::Interface::impl::SubMenuValue) {
|
if (name.get() == ContentRegistry::Interface::impl::SubMenuValue) {
|
||||||
|
if (enabledCallback()) {
|
||||||
callback();
|
callback();
|
||||||
|
}
|
||||||
} else if (menuItems.size() == 1) {
|
} else if (menuItems.size() == 1) {
|
||||||
if (ImGui::MenuItemEx(Lang(name), icon, shortcut.toString().c_str(), selectedCallback(), enabledCallback()))
|
if (menu::menuItemEx(Lang(name), icon, shortcut, selectedCallback(), enabledCallback()))
|
||||||
callback();
|
callback();
|
||||||
} else {
|
} else {
|
||||||
bool isSubmenu = (menuItems.begin() + 1)->get() == ContentRegistry::Interface::impl::SubMenuValue;
|
bool isSubmenu = (menuItems.begin() + 1)->get() == ContentRegistry::Interface::impl::SubMenuValue;
|
||||||
|
|
||||||
if (ImGui::BeginMenuEx(Lang(name), std::next(menuItems.begin())->get() == ContentRegistry::Interface::impl::SubMenuValue ? icon : nullptr, isSubmenu ? enabledCallback() : true)) {
|
if (menu::beginMenuEx(Lang(name), std::next(menuItems.begin())->get() == ContentRegistry::Interface::impl::SubMenuValue ? icon : nullptr, isSubmenu ? enabledCallback() : true)) {
|
||||||
createNestedMenu({ std::next(menuItems.begin()), menuItems.end() }, icon, shortcut, callback, enabledCallback, selectedCallback);
|
createNestedMenu({ std::next(menuItems.begin()), menuItems.end() }, icon, shortcut, callback, enabledCallback, selectedCallback);
|
||||||
ImGui::EndMenu();
|
menu::endMenu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -285,9 +288,9 @@ namespace hex::plugin::builtin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void defineMenu(const UnlocalizedString &menuName) {
|
void defineMenu(const UnlocalizedString &menuName) {
|
||||||
if (ImGui::BeginMenu(Lang(menuName))) {
|
if (menu::beginMenu(Lang(menuName))) {
|
||||||
populateMenu(menuName);
|
populateMenu(menuName);
|
||||||
ImGui::EndMenu();
|
menu::endMenu();
|
||||||
} else {
|
} else {
|
||||||
if (s_displayShortcutHighlights) {
|
if (s_displayShortcutHighlights) {
|
||||||
if (const auto lastShortcutMenu = ShortcutManager::getLastActivatedMenu(); lastShortcutMenu.has_value()) {
|
if (const auto lastShortcutMenu = ShortcutManager::getLastActivatedMenu(); lastShortcutMenu.has_value()) {
|
||||||
@ -301,10 +304,16 @@ namespace hex::plugin::builtin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void drawMenu() {
|
void drawMenu() {
|
||||||
|
const auto &menuItems = ContentRegistry::Interface::impl::getMainMenuItems();
|
||||||
|
|
||||||
|
if (menu::isNativeMenuBarUsed()) {
|
||||||
|
for (const auto &[priority, menuItem] : menuItems) {
|
||||||
|
defineMenu(menuItem.unlocalizedName);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
auto cursorPos = ImGui::GetCursorPosX();
|
auto cursorPos = ImGui::GetCursorPosX();
|
||||||
u32 fittingItems = 0;
|
u32 fittingItems = 0;
|
||||||
|
|
||||||
const auto &menuItems = ContentRegistry::Interface::impl::getMainMenuItems();
|
|
||||||
for (const auto &[priority, menuItem] : menuItems) {
|
for (const auto &[priority, menuItem] : menuItems) {
|
||||||
auto menuName = Lang(menuItem.unlocalizedName);
|
auto menuName = Lang(menuItem.unlocalizedName);
|
||||||
|
|
||||||
@ -355,6 +364,7 @@ namespace hex::plugin::builtin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void drawMainMenu([[maybe_unused]] float menuBarHeight) {
|
void drawMainMenu([[maybe_unused]] float menuBarHeight) {
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0F);
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0F);
|
||||||
@ -366,13 +376,8 @@ namespace hex::plugin::builtin {
|
|||||||
ON_SCOPE_EXIT { ImGui::PopStyleVar(); };
|
ON_SCOPE_EXIT { ImGui::PopStyleVar(); };
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (ImGui::BeginMainMenuBar()) {
|
|
||||||
ImGui::Dummy({});
|
|
||||||
|
|
||||||
auto window = ImHexApi::System::getMainWindowHandle();
|
auto window = ImHexApi::System::getMainWindowHandle();
|
||||||
|
if (menu::beginMainMenuBar()) {
|
||||||
ImGui::PopStyleVar(2);
|
|
||||||
|
|
||||||
if (ImHexApi::System::isBorderlessWindowModeEnabled()) {
|
if (ImHexApi::System::isBorderlessWindowModeEnabled()) {
|
||||||
#if defined(OS_WINDOWS)
|
#if defined(OS_WINDOWS)
|
||||||
ImGui::SetCursorPosX(5_scaled);
|
ImGui::SetCursorPosX(5_scaled);
|
||||||
@ -406,8 +411,14 @@ namespace hex::plugin::builtin {
|
|||||||
|
|
||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
drawMenu();
|
drawMenu();
|
||||||
|
menu::endMainMenuBar();
|
||||||
|
}
|
||||||
|
if (ImGui::BeginMainMenuBar()) {
|
||||||
|
ImGui::Dummy({});
|
||||||
|
|
||||||
|
ImGui::PopStyleVar(2);
|
||||||
|
|
||||||
drawTitleBar();
|
drawTitleBar();
|
||||||
|
|
||||||
#if defined(OS_MACOS)
|
#if defined(OS_MACOS)
|
||||||
@ -611,6 +622,10 @@ namespace hex::plugin::builtin {
|
|||||||
ContentRegistry::Settings::onChange("hex.builtin.setting.interface", "hex.builtin.setting.interface.display_shortcut_highlights", [](const ContentRegistry::Settings::SettingsValue &value) {
|
ContentRegistry::Settings::onChange("hex.builtin.setting.interface", "hex.builtin.setting.interface.display_shortcut_highlights", [](const ContentRegistry::Settings::SettingsValue &value) {
|
||||||
s_displayShortcutHighlights = value.get<bool>(true);
|
s_displayShortcutHighlights = value.get<bool>(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ContentRegistry::Settings::onChange("hex.builtin.setting.interface", "hex.builtin.setting.interface.use_native_menu_bar", [](const ContentRegistry::Settings::SettingsValue &value) {
|
||||||
|
menu::enableNativeMenuBar(value.get<bool>(true));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ add_imhex_plugin(
|
|||||||
source/ui/hex_editor.cpp
|
source/ui/hex_editor.cpp
|
||||||
source/ui/pattern_drawer.cpp
|
source/ui/pattern_drawer.cpp
|
||||||
source/ui/visualizer_drawer.cpp
|
source/ui/visualizer_drawer.cpp
|
||||||
|
source/ui/menu_items.cpp
|
||||||
INCLUDES
|
INCLUDES
|
||||||
include
|
include
|
||||||
LIBRARIES
|
LIBRARIES
|
||||||
@ -18,3 +19,10 @@ add_imhex_plugin(
|
|||||||
fonts
|
fonts
|
||||||
LIBRARY_PLUGIN
|
LIBRARY_PLUGIN
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (APPLE)
|
||||||
|
target_sources(ui PRIVATE source/ui/macos_menu.m)
|
||||||
|
find_library(FOUNDATION NAMES Foundation REQUIRED)
|
||||||
|
find_library(COCOA NAMES Cocoa REQUIRED)
|
||||||
|
target_link_libraries(ui PUBLIC ${FOUNDATION} ${COCOA})
|
||||||
|
endif()
|
25
plugins/ui/include/ui/menu_items.hpp
Normal file
25
plugins/ui/include/ui/menu_items.hpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <hex/api/shortcut_manager.hpp>
|
||||||
|
|
||||||
|
namespace hex::menu {
|
||||||
|
|
||||||
|
void enableNativeMenuBar(bool enabled);
|
||||||
|
bool isNativeMenuBarUsed();
|
||||||
|
|
||||||
|
bool beginMainMenuBar();
|
||||||
|
void endMainMenuBar();
|
||||||
|
|
||||||
|
bool beginMenu(const char *label, bool enabled = true);
|
||||||
|
void endMenu();
|
||||||
|
|
||||||
|
bool beginMenuEx(const char* label, const char* icon, bool enabled = true);
|
||||||
|
|
||||||
|
bool menuItem(const char *label, const Shortcut &shortcut = Shortcut::None, bool selected = false, bool enabled = true);
|
||||||
|
bool menuItem(const char *label, const Shortcut &shortcut, bool *selected, bool enabled = true);
|
||||||
|
|
||||||
|
bool menuItemEx(const char *label, const char *icon, const Shortcut &shortcut = Shortcut::None, bool selected = false, bool enabled = true);
|
||||||
|
bool menuItemEx(const char *label, const char *icon, const Shortcut &shortcut, bool *selected, bool enabled = true);
|
||||||
|
|
||||||
|
void menuSeparator();
|
||||||
|
|
||||||
|
}
|
181
plugins/ui/source/ui/macos_menu.m
Normal file
181
plugins/ui/source/ui/macos_menu.m
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
struct KeyEquivalent {
|
||||||
|
bool valid;
|
||||||
|
bool ctrl, opt, cmd, shift;
|
||||||
|
int key;
|
||||||
|
};
|
||||||
|
|
||||||
|
const static int MenuBegin = 1;
|
||||||
|
static NSInteger s_currTag = MenuBegin;
|
||||||
|
static NSInteger s_selectedTag = -1;
|
||||||
|
|
||||||
|
@interface MenuItemHandler : NSObject
|
||||||
|
-(void) OnClick: (id) sender;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MenuItemHandler
|
||||||
|
-(void) OnClick: (id) sender {
|
||||||
|
NSMenuItem* menu_item = sender;
|
||||||
|
s_selectedTag = menu_item.tag;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
static NSMenu* s_menuStack[1024];
|
||||||
|
static int s_menuStackSize = 0;
|
||||||
|
|
||||||
|
static MenuItemHandler* s_menuItemHandler;
|
||||||
|
|
||||||
|
static bool s_constructingMenu = false;
|
||||||
|
static bool s_resetNeeded = true;
|
||||||
|
|
||||||
|
void macosMenuBarInit(void) {
|
||||||
|
s_menuStack[0] = NSApp.mainMenu;
|
||||||
|
s_menuStackSize += 1;
|
||||||
|
|
||||||
|
s_menuItemHandler = [[MenuItemHandler alloc] init];
|
||||||
|
}
|
||||||
|
|
||||||
|
void macosClearMenu(void) {
|
||||||
|
// Remove all items except the Application menu
|
||||||
|
while (s_menuStack[0].itemArray.count > 2) {
|
||||||
|
[s_menuStack[0] removeItemAtIndex:1];
|
||||||
|
}
|
||||||
|
|
||||||
|
s_currTag = MenuBegin;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool macosBeginMainMenuBar(void) {
|
||||||
|
if (s_resetNeeded) {
|
||||||
|
macosClearMenu();
|
||||||
|
s_resetNeeded = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void macosEndMainMenuBar(void) {
|
||||||
|
s_constructingMenu = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool macosBeginMenu(const char* label, bool enabled) {
|
||||||
|
NSString* title = [NSString stringWithUTF8String:label];
|
||||||
|
|
||||||
|
// Search for menu item with the given name
|
||||||
|
NSInteger menuIndex = [s_menuStack[s_menuStackSize - 1] indexOfItemWithTitle:title];
|
||||||
|
if (menuIndex == -1) {
|
||||||
|
// Construct the content of the menu if it doesn't exist yet
|
||||||
|
|
||||||
|
s_constructingMenu = true;
|
||||||
|
|
||||||
|
NSMenu* newMenu = [[NSMenu alloc] init];
|
||||||
|
newMenu.autoenablesItems = false;
|
||||||
|
newMenu.title = title;
|
||||||
|
|
||||||
|
NSMenuItem* menuItem = [[NSMenuItem alloc] init];
|
||||||
|
menuItem.title = title;
|
||||||
|
[menuItem setSubmenu:newMenu];
|
||||||
|
|
||||||
|
// Add the new menu to the end of the list
|
||||||
|
menuIndex = [s_menuStack[s_menuStackSize - 1] numberOfItems];
|
||||||
|
|
||||||
|
if (s_menuStackSize == 1)
|
||||||
|
menuIndex -= 1;
|
||||||
|
|
||||||
|
[s_menuStack[s_menuStackSize - 1] insertItem:menuItem atIndex:menuIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSMenuItem* menuItem = [s_menuStack[s_menuStackSize - 1] itemAtIndex:menuIndex];
|
||||||
|
if (menuItem != NULL) {
|
||||||
|
menuItem.enabled = enabled;
|
||||||
|
|
||||||
|
s_menuStack[s_menuStackSize] = menuItem.submenu;
|
||||||
|
s_menuStackSize += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void macosEndMenu(void) {
|
||||||
|
s_menuStack[s_menuStackSize - 1] = NULL;
|
||||||
|
s_menuStackSize -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool macosMenuItem(const char* label, struct KeyEquivalent keyEquivalent, bool selected, bool enabled) {
|
||||||
|
NSString* title = [NSString stringWithUTF8String:label];
|
||||||
|
|
||||||
|
if (s_constructingMenu) {
|
||||||
|
NSMenuItem* menuItem = [[NSMenuItem alloc] init];
|
||||||
|
menuItem.title = title;
|
||||||
|
menuItem.action = @selector(OnClick:);
|
||||||
|
menuItem.target = s_menuItemHandler;
|
||||||
|
|
||||||
|
[menuItem setTag:s_currTag];
|
||||||
|
s_currTag += 1;
|
||||||
|
|
||||||
|
// Setup the key equivalent, aka the shortcut
|
||||||
|
if (keyEquivalent.valid) {
|
||||||
|
NSInteger flags = 0x00;
|
||||||
|
|
||||||
|
if (keyEquivalent.ctrl)
|
||||||
|
flags |= NSEventModifierFlagControl;
|
||||||
|
if (keyEquivalent.shift)
|
||||||
|
flags |= NSEventModifierFlagShift;
|
||||||
|
if (keyEquivalent.cmd)
|
||||||
|
flags |= NSEventModifierFlagCommand;
|
||||||
|
if (keyEquivalent.opt)
|
||||||
|
flags |= NSEventModifierFlagOption;
|
||||||
|
|
||||||
|
[menuItem setKeyEquivalentModifierMask:flags];
|
||||||
|
menuItem.keyEquivalent = [[NSString alloc] initWithCharacters:(const unichar *)&keyEquivalent.key length:1];
|
||||||
|
}
|
||||||
|
|
||||||
|
[s_menuStack[s_menuStackSize - 1] addItem:menuItem];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSInteger menuIndex = [s_menuStack[s_menuStackSize - 1] indexOfItemWithTitle:title];
|
||||||
|
NSMenuItem* menuItem = NULL;
|
||||||
|
if (menuIndex >= 0 && menuIndex < [s_menuStack[s_menuStackSize - 1] numberOfItems]) {
|
||||||
|
menuItem = [s_menuStack[s_menuStackSize - 1] itemAtIndex:menuIndex];
|
||||||
|
if (menuItem != NULL) {
|
||||||
|
if (s_constructingMenu == false) {
|
||||||
|
if (![title isEqualToString:menuItem.title]) {
|
||||||
|
s_resetNeeded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
menuItem.enabled = enabled;
|
||||||
|
menuItem.state = selected ? NSControlStateValueOn : NSControlStateValueOff;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enabled && menuItem != NULL) {
|
||||||
|
if ([menuItem tag] == s_selectedTag) {
|
||||||
|
s_selectedTag = -1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s_resetNeeded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool macosMenuItemSelect(const char* label, struct KeyEquivalent keyEquivalent, bool* selected, bool enabled) {
|
||||||
|
if (macosMenuItem(label, keyEquivalent, selected != NULL ? *selected : false, enabled)) {
|
||||||
|
if (selected != NULL)
|
||||||
|
*selected = !(*selected);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void macosSeparator(void) {
|
||||||
|
if (s_constructingMenu) {
|
||||||
|
NSMenuItem* separator = [NSMenuItem separatorItem];
|
||||||
|
[s_menuStack[s_menuStackSize - 1] addItem:separator];
|
||||||
|
}
|
||||||
|
}
|
156
plugins/ui/source/ui/menu_items.cpp
Normal file
156
plugins/ui/source/ui/menu_items.cpp
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
#include <ui/menu_items.hpp>
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <imgui_internal.h>
|
||||||
|
#include <hex/api/shortcut_manager.hpp>
|
||||||
|
|
||||||
|
#if defined(OS_MACOS)
|
||||||
|
extern "C" {
|
||||||
|
void macosMenuBarInit(void);
|
||||||
|
|
||||||
|
bool macosBeginMainMenuBar(void);
|
||||||
|
void macosEndMainMenuBar(void);
|
||||||
|
void macosClearMenu(void);
|
||||||
|
|
||||||
|
bool macosBeginMenu(const char* label, bool enabled);
|
||||||
|
void macosEndMenu(void);
|
||||||
|
|
||||||
|
bool macosMenuItem(const char* label, KeyEquivalent keyEquivalent, bool selected, bool enabled);
|
||||||
|
bool macosMenuItemSelect(const char* label, KeyEquivalent keyEquivalent, bool* p_selected, bool enabled);
|
||||||
|
|
||||||
|
void macosSeparator(void);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace hex::menu {
|
||||||
|
|
||||||
|
static bool s_useNativeMenuBar = false;
|
||||||
|
void enableNativeMenuBar(bool enabled) {
|
||||||
|
#if !defined (OS_MACOS)
|
||||||
|
std::ignore = enabled;
|
||||||
|
#else
|
||||||
|
if (!enabled) {
|
||||||
|
macosClearMenu();
|
||||||
|
}
|
||||||
|
s_useNativeMenuBar = enabled;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isNativeMenuBarUsed() {
|
||||||
|
return s_useNativeMenuBar;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool s_initialized = false;
|
||||||
|
bool beginMainMenuBar() {
|
||||||
|
#if defined(OS_MACOS)
|
||||||
|
if (s_useNativeMenuBar) {
|
||||||
|
if (!s_initialized) {
|
||||||
|
macosMenuBarInit();
|
||||||
|
s_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return macosBeginMainMenuBar();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
std::ignore = s_initialized;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ImGui::BeginMainMenuBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
void endMainMenuBar() {
|
||||||
|
#if defined(OS_MACOS)
|
||||||
|
if (s_useNativeMenuBar) {
|
||||||
|
macosEndMainMenuBar();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ImGui::EndMainMenuBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool beginMenu(const char *label, bool enabled) {
|
||||||
|
#if defined(OS_MACOS)
|
||||||
|
if (s_useNativeMenuBar)
|
||||||
|
return macosBeginMenu(label, enabled);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ImGui::BeginMenu(label, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool beginMenuEx(const char *label, const char *icon, bool enabled) {
|
||||||
|
#if defined(OS_MACOS)
|
||||||
|
if (s_useNativeMenuBar)
|
||||||
|
return macosBeginMenu(label, enabled);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ImGui::BeginMenuEx(label, icon, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
void endMenu() {
|
||||||
|
#if defined(OS_MACOS)
|
||||||
|
if (s_useNativeMenuBar) {
|
||||||
|
macosEndMenu();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool menuItem(const char *label, const Shortcut &shortcut, bool selected, bool enabled) {
|
||||||
|
#if defined(OS_MACOS)
|
||||||
|
if (s_useNativeMenuBar)
|
||||||
|
return macosMenuItem(label, shortcut.toKeyEquivalent(), selected, enabled);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ImGui::MenuItem(label, shortcut.toString().c_str(), selected, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool menuItem(const char *label, const Shortcut &shortcut, bool *selected, bool enabled) {
|
||||||
|
#if defined(OS_MACOS)
|
||||||
|
if (s_useNativeMenuBar)
|
||||||
|
return macosMenuItemSelect(label, shortcut.toKeyEquivalent(), selected, enabled);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ImGui::MenuItem(label, shortcut.toString().c_str(), selected, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool menuItemEx(const char *label, const char *icon, const Shortcut &shortcut, bool selected, bool enabled) {
|
||||||
|
#if defined(OS_MACOS)
|
||||||
|
if (s_useNativeMenuBar)
|
||||||
|
return macosMenuItem(label, shortcut.toKeyEquivalent(), selected, enabled);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ImGui::MenuItemEx(label, icon, shortcut.toString().c_str(), selected, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool menuItemEx(const char *label, const char *icon, const Shortcut &shortcut, bool *selected, bool enabled) {
|
||||||
|
#if defined(OS_MACOS)
|
||||||
|
if (s_useNativeMenuBar)
|
||||||
|
return macosMenuItemSelect(label, shortcut.toKeyEquivalent(), selected, enabled);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (ImGui::MenuItemEx(label, icon, shortcut.toString().c_str(), selected != nullptr ? *selected : false, enabled)) {
|
||||||
|
if (selected != nullptr)
|
||||||
|
*selected = !*selected;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void menuSeparator() {
|
||||||
|
#if defined(OS_MACOS)
|
||||||
|
if (s_useNativeMenuBar) {
|
||||||
|
macosSeparator();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user