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_int32(keyboard_mode);
|
||||
|
||||
DEFINE_bool(fullscreen, false, "Whether to launch the emulator in fullscreen.",
|
||||
"Display");
|
||||
|
||||
|
@ -576,6 +578,7 @@ bool EmulatorWindow::Initialize() {
|
|||
// FIXME: This code is really messy.
|
||||
auto main_menu = MenuItem::Create(MenuItem::Type::kNormal);
|
||||
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 zar_menu = MenuItem::Create(MenuItem::Type::kPopup, "&Zar Package");
|
||||
FillRecentlyLaunchedTitlesMenu(recent_menu.get());
|
||||
|
@ -612,6 +615,17 @@ bool EmulatorWindow::Initialize() {
|
|||
}
|
||||
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
|
||||
auto profile_menu = MenuItem::Create(MenuItem::Type::kPopup, "&Profile");
|
||||
{
|
||||
|
@ -727,6 +741,14 @@ bool EmulatorWindow::Initialize() {
|
|||
}
|
||||
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_->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) {
|
||||
if (!emulator_initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!window_->GetMainMenuEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (e.virtual_key()) {
|
||||
case ui::VirtualKey::kO: {
|
||||
if (!e.is_ctrl_pressed()) {
|
||||
|
|
|
@ -207,6 +207,8 @@ class EmulatorWindow {
|
|||
GetGuestOutputPaintConfigForCvars();
|
||||
void ApplyDisplayConfigForCvars();
|
||||
|
||||
void ToggleToolBar();
|
||||
|
||||
void OnKeyDown(ui::KeyEvent& e);
|
||||
void OnMouseDown(const ui::MouseEvent& e);
|
||||
void ToggleFullscreenOnDoubleClick();
|
||||
|
|
|
@ -29,6 +29,8 @@ MenuItem::MenuItem(Type type, const std::string& text,
|
|||
const std::string& hotkey, std::function<void()> callback)
|
||||
: type_(type),
|
||||
parent_item_(nullptr),
|
||||
previous_item_(nullptr),
|
||||
next_item_(nullptr),
|
||||
text_(text),
|
||||
hotkey_(hotkey),
|
||||
callback_(std::move(callback)) {}
|
||||
|
@ -46,6 +48,14 @@ void MenuItem::AddChild(std::unique_ptr<MenuItem> child_item) {
|
|||
|
||||
void MenuItem::AddChild(MenuItemPtr child_item) {
|
||||
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));
|
||||
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() {
|
||||
if (type() == Type::kChecked) {
|
||||
ResetChecked();
|
||||
SetChecked(true);
|
||||
}
|
||||
|
||||
if (callback_) {
|
||||
callback_();
|
||||
// Note that this MenuItem might have been destroyed by the callback.
|
||||
|
|
|
@ -27,10 +27,11 @@ class MenuItem {
|
|||
typedef std::unique_ptr<MenuItem, void (*)(MenuItem*)> MenuItemPtr;
|
||||
|
||||
enum class Type {
|
||||
kPopup, // Popup menu (submenu)
|
||||
kSeparator,
|
||||
kNormal, // Root menu
|
||||
kString, // Menu is just a string
|
||||
kPopup, // Popup menu (submenu)
|
||||
kSeparator, // Seperator between elements
|
||||
kNormal, // Root menu
|
||||
kString, // Menu is just a string
|
||||
kChecked // Menu is child of submenu with checkmarks
|
||||
};
|
||||
|
||||
static std::unique_ptr<MenuItem> Create(Type type);
|
||||
|
@ -43,8 +44,11 @@ class MenuItem {
|
|||
|
||||
virtual ~MenuItem();
|
||||
|
||||
MenuItem* parent_item() const { return parent_item_; }
|
||||
Type type() { return type_; }
|
||||
MenuItem* GetParentItem() const { return parent_item_; }
|
||||
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& hotkey() { return hotkey_; }
|
||||
|
||||
|
@ -57,9 +61,17 @@ class MenuItem {
|
|||
void AddChild(std::unique_ptr<MenuItem> child_item);
|
||||
void AddChild(MenuItemPtr 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(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:
|
||||
MenuItem(Type type, const std::string& text, const std::string& hotkey,
|
||||
|
@ -74,6 +86,8 @@ class MenuItem {
|
|||
|
||||
Type type_;
|
||||
MenuItem* parent_item_;
|
||||
MenuItem* previous_item_;
|
||||
MenuItem* next_item_;
|
||||
std::vector<MenuItemPtr> children_;
|
||||
std::string text_;
|
||||
std::string hotkey_;
|
||||
|
|
|
@ -317,7 +317,8 @@ void Window::SetMainMenuEnabled(bool enabled) {
|
|||
// pressing) that may execute callbacks potentially destroying the Window via
|
||||
// the outer architecture.
|
||||
WindowDestructionReceiver destruction_receiver(this);
|
||||
main_menu_->SetEnabled(enabled);
|
||||
main_menu_->SetEnabledCascade(enabled);
|
||||
main_menu_enabled_ = enabled;
|
||||
if (destruction_receiver.IsWindowDestroyed()) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -349,6 +349,10 @@ class Window {
|
|||
}
|
||||
}
|
||||
|
||||
MenuItem* GetMainMenu() const { return main_menu_.get(); }
|
||||
|
||||
bool GetMainMenuEnabled() const { return main_menu_enabled_; }
|
||||
|
||||
protected:
|
||||
// The receiver, which must never be instantiated in the Window object itself
|
||||
// (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.
|
||||
virtual void LoadAndApplyIcon(const void* buffer, size_t size,
|
||||
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.
|
||||
virtual void ApplyNewMainMenu(MenuItem* old_main_menu) {}
|
||||
// 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 main_menu_enabled_ = false;
|
||||
|
||||
Presenter* presenter_ = nullptr;
|
||||
std::unique_ptr<Surface> presenter_surface_;
|
||||
// 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
|
||||
// the assignment here to handle the case of a failure after WM_NCCREATE, for
|
||||
// instance.
|
||||
hwnd_ = CreateWindowExW(
|
||||
window_ex_style, L"XeniaWindowClass",
|
||||
reinterpret_cast<LPCWSTR>(xe::to_utf16(GetTitle()).c_str()), window_style,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
window_size_rect.right - window_size_rect.left,
|
||||
window_size_rect.bottom - window_size_rect.top, nullptr, nullptr,
|
||||
hinstance, this);
|
||||
const auto window_title = xe::to_utf16(GetTitle());
|
||||
|
||||
hwnd_ = CreateWindowExW(window_ex_style, L"XeniaWindowClass",
|
||||
reinterpret_cast<LPCWSTR>(window_title.c_str()),
|
||||
window_style, CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
window_size_rect.right - window_size_rect.left,
|
||||
window_size_rect.bottom - window_size_rect.top,
|
||||
nullptr, nullptr, hinstance, this);
|
||||
if (!hwnd_) {
|
||||
XELOGE("CreateWindowExW failed");
|
||||
return false;
|
||||
|
@ -1202,16 +1203,16 @@ LRESULT Win32Window::WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
|||
TABLET_ENABLE_MULTITOUCHDATA;
|
||||
|
||||
case WM_MENUCOMMAND: {
|
||||
MENUINFO menu_info = {0};
|
||||
MENUINFO menu_info = {};
|
||||
menu_info.cbSize = sizeof(menu_info);
|
||||
menu_info.fMask = MIM_MENUDATA;
|
||||
GetMenuInfo(HMENU(lParam), &menu_info);
|
||||
auto parent_item = reinterpret_cast<Win32MenuItem*>(menu_info.dwMenuData);
|
||||
auto child_item =
|
||||
reinterpret_cast<Win32MenuItem*>(parent_item->child(wParam));
|
||||
assert_not_null(child_item);
|
||||
auto next_item = reinterpret_cast<Win32MenuItem*>(
|
||||
parent_item->GetItem(static_cast<uint32_t>(wParam)));
|
||||
assert_not_null(next_item);
|
||||
WindowDestructionReceiver destruction_receiver(this);
|
||||
child_item->OnSelected();
|
||||
next_item->OnSelected();
|
||||
if (destruction_receiver.IsWindowDestroyed()) {
|
||||
break;
|
||||
}
|
||||
|
@ -1286,19 +1287,25 @@ Win32MenuItem::Win32MenuItem(Type type, const std::string& text,
|
|||
switch (type) {
|
||||
case MenuItem::Type::kNormal:
|
||||
handle_ = CreateMenu();
|
||||
identifier_ = -1;
|
||||
break;
|
||||
case MenuItem::Type::kPopup:
|
||||
handle_ = CreatePopupMenu();
|
||||
identifier_ = -1;
|
||||
break;
|
||||
case MenuItem::Type::kSeparator:
|
||||
identifier_ = -1;
|
||||
break;
|
||||
default:
|
||||
// May just be a placeholder.
|
||||
break;
|
||||
}
|
||||
|
||||
if (handle_) {
|
||||
MENUINFO menu_info = {0};
|
||||
MENUINFO menu_info = {};
|
||||
menu_info.cbSize = sizeof(menu_info);
|
||||
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;
|
||||
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) {
|
||||
SetEnabled(position(), enabled);
|
||||
}
|
||||
|
||||
void Win32MenuItem::SetEnabled(uint32_t position, bool enabled) {
|
||||
UINT enable_flags = MF_BYPOSITION | (enabled ? MF_ENABLED : MF_GRAYED);
|
||||
UINT i = 0;
|
||||
for (auto iter = children_.begin(); iter != children_.end(); ++iter, ++i) {
|
||||
EnableMenuItem(handle_, i, enable_flags);
|
||||
|
||||
const auto parent_item = static_cast<Win32MenuItem*>(GetParentItem());
|
||||
|
||||
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) {
|
||||
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()) {
|
||||
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()));
|
||||
break;
|
||||
case MenuItem::Type::kSeparator:
|
||||
AppendMenuW(handle_, MF_SEPARATOR, UINT_PTR(child_item->handle_), 0);
|
||||
AppendMenuW(handle_, MF_SEPARATOR, 0, nullptr);
|
||||
break;
|
||||
case MenuItem::Type::kChecked:
|
||||
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()) {
|
||||
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()));
|
||||
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 xe
|
||||
|
|
|
@ -159,8 +159,30 @@ class Win32MenuItem : public MenuItem {
|
|||
~Win32MenuItem() override;
|
||||
|
||||
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(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;
|
||||
|
||||
|
@ -170,6 +192,8 @@ class Win32MenuItem : public MenuItem {
|
|||
|
||||
private:
|
||||
HMENU handle_ = nullptr;
|
||||
uint32_t identifier_ = 0;
|
||||
uint32_t position_ = 0;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
|
|
Loading…
Reference in New Issue