Merge fb8b61f12e
into 55bbb28a80
This commit is contained in:
commit
f7c9d3f7e0
|
@ -60,6 +60,8 @@ DECLARE_bool(clear_memory_page_state);
|
||||||
|
|
||||||
DECLARE_bool(d3d12_readback_resolve);
|
DECLARE_bool(d3d12_readback_resolve);
|
||||||
|
|
||||||
|
DECLARE_int32(keyboard_mode);
|
||||||
|
|
||||||
DEFINE_bool(fullscreen, false, "Whether to launch the emulator in fullscreen.",
|
DEFINE_bool(fullscreen, false, "Whether to launch the emulator in fullscreen.",
|
||||||
"Display");
|
"Display");
|
||||||
|
|
||||||
|
@ -576,6 +578,7 @@ bool EmulatorWindow::Initialize() {
|
||||||
// FIXME: This code is really messy.
|
// FIXME: This code is really messy.
|
||||||
auto main_menu = MenuItem::Create(MenuItem::Type::kNormal);
|
auto main_menu = MenuItem::Create(MenuItem::Type::kNormal);
|
||||||
auto file_menu = MenuItem::Create(MenuItem::Type::kPopup, "&File");
|
auto file_menu = MenuItem::Create(MenuItem::Type::kPopup, "&File");
|
||||||
|
auto testing_menu = MenuItem::Create(MenuItem::Type::kPopup, "&Testing");
|
||||||
auto recent_menu = MenuItem::Create(MenuItem::Type::kPopup, "&Open Recent");
|
auto recent_menu = MenuItem::Create(MenuItem::Type::kPopup, "&Open Recent");
|
||||||
auto zar_menu = MenuItem::Create(MenuItem::Type::kPopup, "&Zar Package");
|
auto zar_menu = MenuItem::Create(MenuItem::Type::kPopup, "&Zar Package");
|
||||||
FillRecentlyLaunchedTitlesMenu(recent_menu.get());
|
FillRecentlyLaunchedTitlesMenu(recent_menu.get());
|
||||||
|
@ -612,6 +615,17 @@ bool EmulatorWindow::Initialize() {
|
||||||
}
|
}
|
||||||
main_menu->AddChild(std::move(file_menu));
|
main_menu->AddChild(std::move(file_menu));
|
||||||
|
|
||||||
|
testing_menu->AddChild(
|
||||||
|
std::move(MenuItem::Create(MenuItem::Type::kChecked, "&SubMenu 1")));
|
||||||
|
testing_menu->AddChild(
|
||||||
|
std::move(MenuItem::Create(MenuItem::Type::kChecked, "&SubMenu 2")));
|
||||||
|
testing_menu->AddChild(
|
||||||
|
std::move(MenuItem::Create(MenuItem::Type::kChecked, "&SubMenu 3")));
|
||||||
|
testing_menu->AddChild(MenuItem::Create(MenuItem::Type::kSeparator));
|
||||||
|
testing_menu->AddChild(
|
||||||
|
std::move(MenuItem::Create(MenuItem::Type::kChecked, "&SubMenu 4")));
|
||||||
|
main_menu->AddChild(std::move(testing_menu));
|
||||||
|
|
||||||
// Profile Menu
|
// Profile Menu
|
||||||
auto profile_menu = MenuItem::Create(MenuItem::Type::kPopup, "&Profile");
|
auto profile_menu = MenuItem::Create(MenuItem::Type::kPopup, "&Profile");
|
||||||
{
|
{
|
||||||
|
@ -727,6 +741,14 @@ bool EmulatorWindow::Initialize() {
|
||||||
}
|
}
|
||||||
main_menu->AddChild(std::move(help_menu));
|
main_menu->AddChild(std::move(help_menu));
|
||||||
|
|
||||||
|
// if (cvars::keyboard_mode == 2) {
|
||||||
|
auto toggle_menu =
|
||||||
|
MenuItem::Create(MenuItem::Type::kString, "&Disable Toolbar",
|
||||||
|
std::bind(&EmulatorWindow::ToggleToolBar, this));
|
||||||
|
|
||||||
|
main_menu->AddChild(std::move(toggle_menu));
|
||||||
|
//}
|
||||||
|
|
||||||
window_->SetMainMenu(std::move(main_menu));
|
window_->SetMainMenu(std::move(main_menu));
|
||||||
|
|
||||||
window_->SetMainMenuEnabled(false);
|
window_->SetMainMenuEnabled(false);
|
||||||
|
@ -830,11 +852,30 @@ void EmulatorWindow::ApplyDisplayConfigForCvars() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmulatorWindow::ToggleToolBar() {
|
||||||
|
const uint32_t toolbar_pos = 8;
|
||||||
|
|
||||||
|
auto toolbar_item = window_->GetMainMenu()->GetItem(toolbar_pos);
|
||||||
|
|
||||||
|
window_->SetMainMenuEnabled(!window_->GetMainMenuEnabled());
|
||||||
|
toolbar_item->SetEnabled(true);
|
||||||
|
|
||||||
|
if (window_->GetMainMenuEnabled()) {
|
||||||
|
toolbar_item->ModifyString("Disable Toolbar");
|
||||||
|
} else {
|
||||||
|
toolbar_item->ModifyString("Enable Toolbar");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EmulatorWindow::OnKeyDown(ui::KeyEvent& e) {
|
void EmulatorWindow::OnKeyDown(ui::KeyEvent& e) {
|
||||||
if (!emulator_initialized_) {
|
if (!emulator_initialized_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!window_->GetMainMenuEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (e.virtual_key()) {
|
switch (e.virtual_key()) {
|
||||||
case ui::VirtualKey::kO: {
|
case ui::VirtualKey::kO: {
|
||||||
if (!e.is_ctrl_pressed()) {
|
if (!e.is_ctrl_pressed()) {
|
||||||
|
|
|
@ -207,6 +207,8 @@ class EmulatorWindow {
|
||||||
GetGuestOutputPaintConfigForCvars();
|
GetGuestOutputPaintConfigForCvars();
|
||||||
void ApplyDisplayConfigForCvars();
|
void ApplyDisplayConfigForCvars();
|
||||||
|
|
||||||
|
void ToggleToolBar();
|
||||||
|
|
||||||
void OnKeyDown(ui::KeyEvent& e);
|
void OnKeyDown(ui::KeyEvent& e);
|
||||||
void OnMouseDown(const ui::MouseEvent& e);
|
void OnMouseDown(const ui::MouseEvent& e);
|
||||||
void ToggleFullscreenOnDoubleClick();
|
void ToggleFullscreenOnDoubleClick();
|
||||||
|
|
|
@ -29,6 +29,8 @@ MenuItem::MenuItem(Type type, const std::string& text,
|
||||||
const std::string& hotkey, std::function<void()> callback)
|
const std::string& hotkey, std::function<void()> callback)
|
||||||
: type_(type),
|
: type_(type),
|
||||||
parent_item_(nullptr),
|
parent_item_(nullptr),
|
||||||
|
previous_item_(nullptr),
|
||||||
|
next_item_(nullptr),
|
||||||
text_(text),
|
text_(text),
|
||||||
hotkey_(hotkey),
|
hotkey_(hotkey),
|
||||||
callback_(std::move(callback)) {}
|
callback_(std::move(callback)) {}
|
||||||
|
@ -46,6 +48,14 @@ void MenuItem::AddChild(std::unique_ptr<MenuItem> child_item) {
|
||||||
|
|
||||||
void MenuItem::AddChild(MenuItemPtr child_item) {
|
void MenuItem::AddChild(MenuItemPtr child_item) {
|
||||||
auto child_item_ptr = child_item.get();
|
auto child_item_ptr = child_item.get();
|
||||||
|
child_item_ptr->parent_item_ = this;
|
||||||
|
|
||||||
|
// Doubly Linked List
|
||||||
|
if (children_.size()) {
|
||||||
|
child_item_ptr->previous_item_ = children_.back().get();
|
||||||
|
child_item_ptr->previous_item_->next_item_ = child_item_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
children_.emplace_back(std::move(child_item));
|
children_.emplace_back(std::move(child_item));
|
||||||
OnChildAdded(child_item_ptr);
|
OnChildAdded(child_item_ptr);
|
||||||
}
|
}
|
||||||
|
@ -60,9 +70,20 @@ void MenuItem::RemoveChild(MenuItem* child_item) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuItem* MenuItem::child(size_t index) { return children_[index].get(); }
|
MenuItem* MenuItem::GetItem(uint32_t index) { return children_[index].get(); }
|
||||||
|
|
||||||
|
void MenuItem::SetPreviousItem(MenuItem* previous_item) {
|
||||||
|
previous_item_ = previous_item;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MenuItem::SetNextItem(MenuItem* next_item) { next_item_ = next_item; }
|
||||||
|
|
||||||
void MenuItem::OnSelected() {
|
void MenuItem::OnSelected() {
|
||||||
|
if (type() == Type::kChecked) {
|
||||||
|
ResetChecked();
|
||||||
|
SetChecked(true);
|
||||||
|
}
|
||||||
|
|
||||||
if (callback_) {
|
if (callback_) {
|
||||||
callback_();
|
callback_();
|
||||||
// Note that this MenuItem might have been destroyed by the callback.
|
// Note that this MenuItem might have been destroyed by the callback.
|
||||||
|
|
|
@ -28,9 +28,10 @@ class MenuItem {
|
||||||
|
|
||||||
enum class Type {
|
enum class Type {
|
||||||
kPopup, // Popup menu (submenu)
|
kPopup, // Popup menu (submenu)
|
||||||
kSeparator,
|
kSeparator, // Seperator between elements
|
||||||
kNormal, // Root menu
|
kNormal, // Root menu
|
||||||
kString, // Menu is just a string
|
kString, // Menu is just a string
|
||||||
|
kChecked // Menu is child of submenu with checkmarks
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::unique_ptr<MenuItem> Create(Type type);
|
static std::unique_ptr<MenuItem> Create(Type type);
|
||||||
|
@ -43,8 +44,11 @@ class MenuItem {
|
||||||
|
|
||||||
virtual ~MenuItem();
|
virtual ~MenuItem();
|
||||||
|
|
||||||
MenuItem* parent_item() const { return parent_item_; }
|
MenuItem* GetParentItem() const { return parent_item_; }
|
||||||
Type type() { return type_; }
|
MenuItem* GetPreviousItem() const { return previous_item_; }
|
||||||
|
MenuItem* GetNextItem() const { return next_item_; }
|
||||||
|
|
||||||
|
Type type() const { return type_; }
|
||||||
const std::string& text() { return text_; }
|
const std::string& text() { return text_; }
|
||||||
const std::string& hotkey() { return hotkey_; }
|
const std::string& hotkey() { return hotkey_; }
|
||||||
|
|
||||||
|
@ -57,9 +61,17 @@ class MenuItem {
|
||||||
void AddChild(std::unique_ptr<MenuItem> child_item);
|
void AddChild(std::unique_ptr<MenuItem> child_item);
|
||||||
void AddChild(MenuItemPtr child_item);
|
void AddChild(MenuItemPtr child_item);
|
||||||
void RemoveChild(MenuItem* child_item);
|
void RemoveChild(MenuItem* child_item);
|
||||||
MenuItem* child(size_t index);
|
void SetPreviousItem(MenuItem* previous_item);
|
||||||
|
void SetNextItem(MenuItem* next_item);
|
||||||
|
MenuItem* GetItem(uint32_t index);
|
||||||
|
|
||||||
|
virtual void SetEnabledCascade(bool enabled) {}
|
||||||
virtual void SetEnabled(bool enabled) {}
|
virtual void SetEnabled(bool enabled) {}
|
||||||
|
virtual void SetEnabled(uint32_t position, bool enabled) {}
|
||||||
|
virtual void SetChecked(bool checked) {}
|
||||||
|
virtual void SetChecked(uint32_t identifier, bool checked) {}
|
||||||
|
virtual void ResetChecked() {};
|
||||||
|
virtual void ModifyString(std::string modify_str) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
MenuItem(Type type, const std::string& text, const std::string& hotkey,
|
MenuItem(Type type, const std::string& text, const std::string& hotkey,
|
||||||
|
@ -74,6 +86,8 @@ class MenuItem {
|
||||||
|
|
||||||
Type type_;
|
Type type_;
|
||||||
MenuItem* parent_item_;
|
MenuItem* parent_item_;
|
||||||
|
MenuItem* previous_item_;
|
||||||
|
MenuItem* next_item_;
|
||||||
std::vector<MenuItemPtr> children_;
|
std::vector<MenuItemPtr> children_;
|
||||||
std::string text_;
|
std::string text_;
|
||||||
std::string hotkey_;
|
std::string hotkey_;
|
||||||
|
|
|
@ -317,7 +317,8 @@ void Window::SetMainMenuEnabled(bool enabled) {
|
||||||
// pressing) that may execute callbacks potentially destroying the Window via
|
// pressing) that may execute callbacks potentially destroying the Window via
|
||||||
// the outer architecture.
|
// the outer architecture.
|
||||||
WindowDestructionReceiver destruction_receiver(this);
|
WindowDestructionReceiver destruction_receiver(this);
|
||||||
main_menu_->SetEnabled(enabled);
|
main_menu_->SetEnabledCascade(enabled);
|
||||||
|
main_menu_enabled_ = enabled;
|
||||||
if (destruction_receiver.IsWindowDestroyed()) {
|
if (destruction_receiver.IsWindowDestroyed()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -349,6 +349,10 @@ class Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MenuItem* GetMainMenu() const { return main_menu_.get(); }
|
||||||
|
|
||||||
|
bool GetMainMenuEnabled() const { return main_menu_enabled_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// The receiver, which must never be instantiated in the Window object itself
|
// The receiver, which must never be instantiated in the Window object itself
|
||||||
// (rather, usually it should be created as a local variable, because only
|
// (rather, usually it should be created as a local variable, because only
|
||||||
|
@ -509,7 +513,6 @@ class Window {
|
||||||
// default one. Returns whether the icon has been updated successfully.
|
// default one. Returns whether the icon has been updated successfully.
|
||||||
virtual void LoadAndApplyIcon(const void* buffer, size_t size,
|
virtual void LoadAndApplyIcon(const void* buffer, size_t size,
|
||||||
bool can_apply_state_in_current_phase) {}
|
bool can_apply_state_in_current_phase) {}
|
||||||
MenuItem* GetMainMenu() const { return main_menu_.get(); }
|
|
||||||
// May be called to add, replace or remove the main menu.
|
// May be called to add, replace or remove the main menu.
|
||||||
virtual void ApplyNewMainMenu(MenuItem* old_main_menu) {}
|
virtual void ApplyNewMainMenu(MenuItem* old_main_menu) {}
|
||||||
// If there's main menu, and state can be applied, will be called to make the
|
// If there's main menu, and state can be applied, will be called to make the
|
||||||
|
@ -711,6 +714,8 @@ class Window {
|
||||||
|
|
||||||
bool has_focus_ = false;
|
bool has_focus_ = false;
|
||||||
|
|
||||||
|
bool main_menu_enabled_ = false;
|
||||||
|
|
||||||
Presenter* presenter_ = nullptr;
|
Presenter* presenter_ = nullptr;
|
||||||
std::unique_ptr<Surface> presenter_surface_;
|
std::unique_ptr<Surface> presenter_surface_;
|
||||||
// Whether currently in InPaint to prevent recursive painting in case it's
|
// Whether currently in InPaint to prevent recursive painting in case it's
|
||||||
|
|
|
@ -128,13 +128,14 @@ bool Win32Window::OpenImpl() {
|
||||||
// Create the window. Though WM_NCCREATE will assign to `hwnd_` too, still do
|
// Create the window. Though WM_NCCREATE will assign to `hwnd_` too, still do
|
||||||
// the assignment here to handle the case of a failure after WM_NCCREATE, for
|
// the assignment here to handle the case of a failure after WM_NCCREATE, for
|
||||||
// instance.
|
// instance.
|
||||||
hwnd_ = CreateWindowExW(
|
const auto window_title = xe::to_utf16(GetTitle());
|
||||||
window_ex_style, L"XeniaWindowClass",
|
|
||||||
reinterpret_cast<LPCWSTR>(xe::to_utf16(GetTitle()).c_str()), window_style,
|
hwnd_ = CreateWindowExW(window_ex_style, L"XeniaWindowClass",
|
||||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
reinterpret_cast<LPCWSTR>(window_title.c_str()),
|
||||||
|
window_style, CW_USEDEFAULT, CW_USEDEFAULT,
|
||||||
window_size_rect.right - window_size_rect.left,
|
window_size_rect.right - window_size_rect.left,
|
||||||
window_size_rect.bottom - window_size_rect.top, nullptr, nullptr,
|
window_size_rect.bottom - window_size_rect.top,
|
||||||
hinstance, this);
|
nullptr, nullptr, hinstance, this);
|
||||||
if (!hwnd_) {
|
if (!hwnd_) {
|
||||||
XELOGE("CreateWindowExW failed");
|
XELOGE("CreateWindowExW failed");
|
||||||
return false;
|
return false;
|
||||||
|
@ -1202,16 +1203,16 @@ LRESULT Win32Window::WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||||
TABLET_ENABLE_MULTITOUCHDATA;
|
TABLET_ENABLE_MULTITOUCHDATA;
|
||||||
|
|
||||||
case WM_MENUCOMMAND: {
|
case WM_MENUCOMMAND: {
|
||||||
MENUINFO menu_info = {0};
|
MENUINFO menu_info = {};
|
||||||
menu_info.cbSize = sizeof(menu_info);
|
menu_info.cbSize = sizeof(menu_info);
|
||||||
menu_info.fMask = MIM_MENUDATA;
|
menu_info.fMask = MIM_MENUDATA;
|
||||||
GetMenuInfo(HMENU(lParam), &menu_info);
|
GetMenuInfo(HMENU(lParam), &menu_info);
|
||||||
auto parent_item = reinterpret_cast<Win32MenuItem*>(menu_info.dwMenuData);
|
auto parent_item = reinterpret_cast<Win32MenuItem*>(menu_info.dwMenuData);
|
||||||
auto child_item =
|
auto next_item = reinterpret_cast<Win32MenuItem*>(
|
||||||
reinterpret_cast<Win32MenuItem*>(parent_item->child(wParam));
|
parent_item->GetItem(static_cast<uint32_t>(wParam)));
|
||||||
assert_not_null(child_item);
|
assert_not_null(next_item);
|
||||||
WindowDestructionReceiver destruction_receiver(this);
|
WindowDestructionReceiver destruction_receiver(this);
|
||||||
child_item->OnSelected();
|
next_item->OnSelected();
|
||||||
if (destruction_receiver.IsWindowDestroyed()) {
|
if (destruction_receiver.IsWindowDestroyed()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1286,19 +1287,25 @@ Win32MenuItem::Win32MenuItem(Type type, const std::string& text,
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case MenuItem::Type::kNormal:
|
case MenuItem::Type::kNormal:
|
||||||
handle_ = CreateMenu();
|
handle_ = CreateMenu();
|
||||||
|
identifier_ = -1;
|
||||||
break;
|
break;
|
||||||
case MenuItem::Type::kPopup:
|
case MenuItem::Type::kPopup:
|
||||||
handle_ = CreatePopupMenu();
|
handle_ = CreatePopupMenu();
|
||||||
|
identifier_ = -1;
|
||||||
|
break;
|
||||||
|
case MenuItem::Type::kSeparator:
|
||||||
|
identifier_ = -1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// May just be a placeholder.
|
// May just be a placeholder.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handle_) {
|
if (handle_) {
|
||||||
MENUINFO menu_info = {0};
|
MENUINFO menu_info = {};
|
||||||
menu_info.cbSize = sizeof(menu_info);
|
menu_info.cbSize = sizeof(menu_info);
|
||||||
menu_info.fMask = MIM_MENUDATA | MIM_STYLE;
|
menu_info.fMask = MIM_MENUDATA | MIM_STYLE;
|
||||||
menu_info.dwMenuData = ULONG_PTR(this);
|
menu_info.dwMenuData = reinterpret_cast<ULONG_PTR>(this);
|
||||||
menu_info.dwStyle = MNS_NOTIFYBYPOS;
|
menu_info.dwStyle = MNS_NOTIFYBYPOS;
|
||||||
SetMenuInfo(handle_, &menu_info);
|
SetMenuInfo(handle_, &menu_info);
|
||||||
}
|
}
|
||||||
|
@ -1310,16 +1317,87 @@ Win32MenuItem::~Win32MenuItem() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Win32MenuItem::SetEnabledCascade(bool enabled) {
|
||||||
|
for (const auto& item : children_) {
|
||||||
|
item->SetEnabled(enabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Win32MenuItem::SetEnabled(bool enabled) {
|
void Win32MenuItem::SetEnabled(bool enabled) {
|
||||||
|
SetEnabled(position(), enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32MenuItem::SetEnabled(uint32_t position, bool enabled) {
|
||||||
UINT enable_flags = MF_BYPOSITION | (enabled ? MF_ENABLED : MF_GRAYED);
|
UINT enable_flags = MF_BYPOSITION | (enabled ? MF_ENABLED : MF_GRAYED);
|
||||||
UINT i = 0;
|
|
||||||
for (auto iter = children_.begin(); iter != children_.end(); ++iter, ++i) {
|
const auto parent_item = static_cast<Win32MenuItem*>(GetParentItem());
|
||||||
EnableMenuItem(handle_, i, enable_flags);
|
|
||||||
|
if (parent_item) {
|
||||||
|
EnableMenuItem(parent_item->handle(), position, enable_flags);
|
||||||
|
} else if (handle_) {
|
||||||
|
EnableMenuItem(handle_, position, enable_flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32MenuItem::SetChecked(bool checked) {
|
||||||
|
SetChecked(identifier(), checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32MenuItem::SetChecked(uint32_t identifier, bool checked) {
|
||||||
|
MENUITEMINFOW MII = {};
|
||||||
|
MII.cbSize = sizeof(MENUITEMINFO);
|
||||||
|
MII.fMask = MIIM_STATE;
|
||||||
|
MII.fState = checked ? MFS_CHECKED : MFS_UNCHECKED;
|
||||||
|
|
||||||
|
// assert_true(handle_ != 0);
|
||||||
|
|
||||||
|
if (type() == Type::kChecked) {
|
||||||
|
const auto parent_item = static_cast<Win32MenuItem*>(GetParentItem());
|
||||||
|
|
||||||
|
if (parent_item) {
|
||||||
|
SetMenuItemInfoW(parent_item->handle(), identifier, false, &MII);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32MenuItem::ResetChecked() {
|
||||||
|
if (type() == Type::kChecked) {
|
||||||
|
const auto parent = static_cast<Win32MenuItem*>(GetParentItem());
|
||||||
|
|
||||||
|
if (parent) {
|
||||||
|
for (const auto& item : parent->children_) {
|
||||||
|
item->SetChecked(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32MenuItem::ModifyString(std::string modify_str) {
|
||||||
|
MENUITEMINFOW MII = {};
|
||||||
|
MII.cbSize = sizeof(MENUITEMINFO);
|
||||||
|
MII.fMask = MIIM_STRING;
|
||||||
|
|
||||||
|
const auto updated_string = xe::to_utf16(modify_str);
|
||||||
|
const auto updated_text = reinterpret_cast<LPCWSTR>(updated_string.c_str());
|
||||||
|
MII.dwTypeData = const_cast<LPWSTR>(updated_text);
|
||||||
|
|
||||||
|
// assert_true(handle_ != 0);
|
||||||
|
|
||||||
|
if (type() == Type::kString) {
|
||||||
|
const auto parent_item = static_cast<Win32MenuItem*>(GetParentItem());
|
||||||
|
|
||||||
|
if (parent_item) {
|
||||||
|
SetMenuItemInfoW(parent_item->handle(), position(), true, &MII);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Win32MenuItem::OnChildAdded(MenuItem* generic_child_item) {
|
void Win32MenuItem::OnChildAdded(MenuItem* generic_child_item) {
|
||||||
auto child_item = static_cast<Win32MenuItem*>(generic_child_item);
|
auto child_item = static_cast<Win32MenuItem*>(generic_child_item);
|
||||||
|
auto parent_item = static_cast<Win32MenuItem*>(child_item->GetParentItem());
|
||||||
|
|
||||||
|
child_item->position_ =
|
||||||
|
static_cast<uint32_t>(parent_item->children_.size()) - 1;
|
||||||
|
|
||||||
switch (child_item->type()) {
|
switch (child_item->type()) {
|
||||||
case MenuItem::Type::kNormal:
|
case MenuItem::Type::kNormal:
|
||||||
|
@ -1331,20 +1409,55 @@ void Win32MenuItem::OnChildAdded(MenuItem* generic_child_item) {
|
||||||
reinterpret_cast<LPCWSTR>(xe::to_utf16(child_item->text()).c_str()));
|
reinterpret_cast<LPCWSTR>(xe::to_utf16(child_item->text()).c_str()));
|
||||||
break;
|
break;
|
||||||
case MenuItem::Type::kSeparator:
|
case MenuItem::Type::kSeparator:
|
||||||
AppendMenuW(handle_, MF_SEPARATOR, UINT_PTR(child_item->handle_), 0);
|
AppendMenuW(handle_, MF_SEPARATOR, 0, nullptr);
|
||||||
break;
|
break;
|
||||||
|
case MenuItem::Type::kChecked:
|
||||||
case MenuItem::Type::kString:
|
case MenuItem::Type::kString:
|
||||||
auto full_name = child_item->text();
|
child_item->identifier_ = parent_item->next_identifier();
|
||||||
|
|
||||||
|
std::string full_name = child_item->text();
|
||||||
|
|
||||||
if (!child_item->hotkey().empty()) {
|
if (!child_item->hotkey().empty()) {
|
||||||
full_name += "\t" + child_item->hotkey();
|
full_name = fmt::format("{}\t{}", full_name, child_item->hotkey());
|
||||||
}
|
}
|
||||||
AppendMenuW(handle_, MF_STRING, UINT_PTR(child_item->handle_),
|
|
||||||
|
AppendMenuW(handle_, MF_STRING, child_item->identifier(),
|
||||||
reinterpret_cast<LPCWSTR>(xe::to_utf16(full_name).c_str()));
|
reinterpret_cast<LPCWSTR>(xe::to_utf16(full_name).c_str()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Win32MenuItem::OnChildRemoved(MenuItem* generic_child_item) {}
|
void Win32MenuItem::OnChildRemoved(MenuItem* generic_child_item) {
|
||||||
|
auto child_item = static_cast<Win32MenuItem*>(generic_child_item);
|
||||||
|
auto previous_item =
|
||||||
|
static_cast<Win32MenuItem*>(child_item->GetPreviousItem());
|
||||||
|
auto next_item = static_cast<Win32MenuItem*>(child_item->GetNextItem());
|
||||||
|
auto parent_item = static_cast<Win32MenuItem*>(child_item->GetParentItem());
|
||||||
|
|
||||||
|
UINT flags = MF_BYPOSITION;
|
||||||
|
const uint32_t position = child_item->position();
|
||||||
|
|
||||||
|
bool deleted_item = false;
|
||||||
|
|
||||||
|
if (parent_item) {
|
||||||
|
deleted_item = DeleteMenu(parent_item->handle(), position, flags);
|
||||||
|
} else if (handle_) {
|
||||||
|
deleted_item = DeleteMenu(handle_, position, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Reindex linked list positions
|
||||||
|
|
||||||
|
// Update Linked List
|
||||||
|
if (deleted_item) {
|
||||||
|
if (previous_item) {
|
||||||
|
previous_item->SetNextItem(child_item->GetNextItem());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next_item) {
|
||||||
|
next_item->SetPreviousItem(child_item->GetPreviousItem());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ui
|
} // namespace ui
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -159,8 +159,30 @@ class Win32MenuItem : public MenuItem {
|
||||||
~Win32MenuItem() override;
|
~Win32MenuItem() override;
|
||||||
|
|
||||||
HMENU handle() const { return handle_; }
|
HMENU handle() const { return handle_; }
|
||||||
|
uint32_t identifier() const { return identifier_; }
|
||||||
|
uint32_t position() const { return position_; }
|
||||||
|
uint32_t next_identifier() const {
|
||||||
|
if (children_.size() > 1) {
|
||||||
|
auto item = static_cast<Win32MenuItem*>(
|
||||||
|
children_.back().get()->GetPreviousItem());
|
||||||
|
|
||||||
|
while (item != nullptr && item->identifier() == -1) {
|
||||||
|
item = static_cast<Win32MenuItem*>(item->GetPreviousItem());
|
||||||
|
}
|
||||||
|
|
||||||
|
return item == nullptr ? 0 : item->identifier() + 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetEnabledCascade(bool enabled) override;
|
||||||
void SetEnabled(bool enabled) override;
|
void SetEnabled(bool enabled) override;
|
||||||
|
void SetEnabled(uint32_t position, bool enabled) override;
|
||||||
|
void SetChecked(bool checked) override;
|
||||||
|
void SetChecked(uint32_t identifier, bool checked) override;
|
||||||
|
void ResetChecked() override;
|
||||||
|
void ModifyString(std::string modify_str) override;
|
||||||
|
|
||||||
using MenuItem::OnSelected;
|
using MenuItem::OnSelected;
|
||||||
|
|
||||||
|
@ -170,6 +192,8 @@ class Win32MenuItem : public MenuItem {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HMENU handle_ = nullptr;
|
HMENU handle_ = nullptr;
|
||||||
|
uint32_t identifier_ = 0;
|
||||||
|
uint32_t position_ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ui
|
} // namespace ui
|
||||||
|
|
Loading…
Reference in New Issue