Adding menus.
This commit is contained in:
parent
b9c39d1b33
commit
9441808b40
|
@ -34,6 +34,7 @@
|
|||
<ClCompile Include="src\xenia\base\mapped_memory_win.cc" />
|
||||
<ClCompile Include="src\xenia\base\math.cc" />
|
||||
<ClCompile Include="src\xenia\base\memory_generic.cc" />
|
||||
<ClCompile Include="src\xenia\base\platform_win.cc" />
|
||||
<ClCompile Include="src\xenia\base\ring_buffer.cc" />
|
||||
<ClCompile Include="src\xenia\base\string.cc" />
|
||||
<ClCompile Include="src\xenia\base\string_buffer.cc" />
|
||||
|
|
|
@ -712,9 +712,6 @@
|
|||
<ClCompile Include="src\xenia\cpu\backend\x64\x64_code_cache.cc">
|
||||
<Filter>src\xenia\cpu\backend\x64</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\xenia\apu\audio_decoder.cc">
|
||||
<Filter>src\xenia\apu</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\xenia\base\clock.cc">
|
||||
<Filter>src\xenia\base</Filter>
|
||||
</ClCompile>
|
||||
|
@ -778,6 +775,9 @@
|
|||
<ClCompile Include="src\xenia\apu\xma_context.cc">
|
||||
<Filter>src\xenia\apu</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\xenia\base\platform_win.cc">
|
||||
<Filter>src\xenia\base</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src\xenia\emulator.h">
|
||||
|
|
|
@ -71,6 +71,8 @@ const char path_separator = '/';
|
|||
const size_t max_path = 1024; // PATH_MAX
|
||||
#endif // XE_PLATFORM_WIN32
|
||||
|
||||
void LaunchBrowser(const char* url);
|
||||
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_BASE_PLATFORM_H_
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/base/platform.h"
|
||||
|
||||
#include <shellapi.h>
|
||||
|
||||
namespace xe {
|
||||
|
||||
void LaunchBrowser(const char* url) {
|
||||
ShellExecuteA(NULL, "open", url, NULL, NULL, SW_SHOWNORMAL);
|
||||
}
|
||||
|
||||
} // namespace xe
|
|
@ -129,6 +129,10 @@ void Profiler::OnMouseWheel(int x, int y, int dy) {
|
|||
MicroProfileMousePosition(x, y, dy);
|
||||
}
|
||||
|
||||
void Profiler::ToggleDisplay() { MicroProfileToggleDisplayMode(); }
|
||||
|
||||
void Profiler::TogglePause() { MicroProfileTogglePause(); }
|
||||
|
||||
#else
|
||||
|
||||
void Profiler::OnMouseDown(bool left_button, bool right_button) {}
|
||||
|
@ -139,6 +143,10 @@ void Profiler::OnMouseMove(int x, int y) {}
|
|||
|
||||
void Profiler::OnMouseWheel(int x, int y, int dy) {}
|
||||
|
||||
void Profiler::ToggleDisplay() {}
|
||||
|
||||
void Profiler::TogglePause() {}
|
||||
|
||||
#endif // XE_OPTION_PROFILING_UI
|
||||
|
||||
void Profiler::set_display(std::unique_ptr<ProfilerDisplay> display) {
|
||||
|
|
|
@ -176,6 +176,8 @@ class Profiler {
|
|||
static void OnMouseUp();
|
||||
static void OnMouseMove(int x, int y);
|
||||
static void OnMouseWheel(int x, int y, int dy);
|
||||
static void ToggleDisplay();
|
||||
static void TogglePause();
|
||||
|
||||
// Gets the current display, if any.
|
||||
static ProfilerDisplay* display() { return display_.get(); }
|
||||
|
@ -184,8 +186,6 @@ class Profiler {
|
|||
// Presents the profiler to the bound display, if any.
|
||||
static void Present();
|
||||
|
||||
// TODO(benvanik): display mode/pause/etc?
|
||||
|
||||
private:
|
||||
static std::unique_ptr<ProfilerDisplay> display_;
|
||||
};
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "xenia/base/clock.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/platform.h"
|
||||
#include "xenia/base/threading.h"
|
||||
#include "xenia/gpu/graphics_system.h"
|
||||
#include "xenia/emulator.h"
|
||||
|
@ -19,6 +20,25 @@
|
|||
namespace xe {
|
||||
namespace ui {
|
||||
|
||||
enum Commands {
|
||||
IDC_FILE_EXIT,
|
||||
|
||||
IDC_CPU_TIME_SCALAR_RESET,
|
||||
IDC_CPU_TIME_SCALAR_HALF,
|
||||
IDC_CPU_TIME_SCALAR_DOUBLE,
|
||||
|
||||
IDC_CPU_PROFILER_TOGGLE_DISPLAY,
|
||||
IDC_CPU_PROFILER_TOGGLE_PAUSE,
|
||||
|
||||
IDC_GPU_TRACE_FRAME,
|
||||
IDC_GPU_CLEAR_CACHES,
|
||||
|
||||
IDC_WINDOW_FULLSCREEN,
|
||||
|
||||
IDC_HELP_WEBSITE,
|
||||
IDC_HELP_ABOUT,
|
||||
};
|
||||
|
||||
const std::wstring kBaseTitle = L"xenia";
|
||||
|
||||
MainWindow::MainWindow(Emulator* emulator)
|
||||
|
@ -56,63 +76,116 @@ bool MainWindow::Initialize() {
|
|||
on_key_down.AddListener([this](KeyEvent& e) {
|
||||
bool handled = true;
|
||||
switch (e.key_code()) {
|
||||
case 0x0D: { // numpad enter
|
||||
OnCommand(Commands::IDC_CPU_TIME_SCALAR_RESET);
|
||||
} break;
|
||||
case 0x6D: { // numpad minus
|
||||
OnCommand(Commands::IDC_CPU_TIME_SCALAR_HALF);
|
||||
} break;
|
||||
case 0x6B: { // numpad plus
|
||||
OnCommand(Commands::IDC_CPU_TIME_SCALAR_DOUBLE);
|
||||
} break;
|
||||
|
||||
case 0x73: { // VK_F4
|
||||
emulator()->graphics_system()->RequestFrameTrace();
|
||||
break;
|
||||
}
|
||||
OnCommand(Commands::IDC_GPU_TRACE_FRAME);
|
||||
} break;
|
||||
case 0x74: { // VK_F5
|
||||
emulator()->graphics_system()->ClearCaches();
|
||||
break;
|
||||
}
|
||||
OnCommand(Commands::IDC_GPU_CLEAR_CACHES);
|
||||
} break;
|
||||
|
||||
case 0x7A: { // VK_F11
|
||||
ToggleFullscreen();
|
||||
break;
|
||||
}
|
||||
OnCommand(Commands::IDC_WINDOW_FULLSCREEN);
|
||||
} break;
|
||||
case 0x1B: { // VK_ESCAPE
|
||||
// Allow users to escape fullscreen (but not enter it)
|
||||
// Allow users to escape fullscreen (but not enter it).
|
||||
if (fullscreen_) {
|
||||
ToggleFullscreen();
|
||||
}
|
||||
}
|
||||
case 0x6D: { // numpad minus
|
||||
Clock::set_guest_time_scalar(Clock::guest_time_scalar() / 2.0);
|
||||
UpdateTitle();
|
||||
break;
|
||||
}
|
||||
case 0x6B: { // numpad plus
|
||||
Clock::set_guest_time_scalar(Clock::guest_time_scalar() * 2.0);
|
||||
UpdateTitle();
|
||||
break;
|
||||
}
|
||||
case 0x0D: { // numpad enter
|
||||
Clock::set_guest_time_scalar(1.0);
|
||||
UpdateTitle();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
handled = false;
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
case 0x70: { // VK_F1
|
||||
OnCommand(Commands::IDC_HELP_WEBSITE);
|
||||
} break;
|
||||
|
||||
default: { handled = false; } break;
|
||||
}
|
||||
e.set_handled(handled);
|
||||
});
|
||||
|
||||
// Main menu
|
||||
// Main menu.
|
||||
// FIXME: This code is really messy.
|
||||
auto file = std::make_unique<PlatformMenu>(MenuItem::Type::kPopup, L"&File");
|
||||
file->AddChild(std::make_unique<PlatformMenu>(
|
||||
MenuItem::Type::kString, Commands::IDC_FILE_OPEN, L"&Open"));
|
||||
auto file_menu =
|
||||
std::make_unique<PlatformMenu>(MenuItem::Type::kPopup, L"&File");
|
||||
{
|
||||
file_menu->AddChild(std::make_unique<PlatformMenu>(
|
||||
MenuItem::Type::kString, Commands::IDC_FILE_EXIT, L"E&xit", L"Alt+F4"));
|
||||
}
|
||||
main_menu_.AddChild(std::move(file_menu));
|
||||
|
||||
main_menu_.AddChild(std::move(file));
|
||||
// CPU menu.
|
||||
auto cpu_menu =
|
||||
std::make_unique<PlatformMenu>(MenuItem::Type::kPopup, L"&CPU");
|
||||
{
|
||||
cpu_menu->AddChild(std::make_unique<PlatformMenu>(
|
||||
MenuItem::Type::kString, Commands::IDC_CPU_TIME_SCALAR_RESET,
|
||||
L"&Reset Time Scalar", L"Numpad Enter"));
|
||||
cpu_menu->AddChild(std::make_unique<PlatformMenu>(
|
||||
MenuItem::Type::kString, Commands::IDC_CPU_TIME_SCALAR_HALF,
|
||||
L"Time Scalar /= 2", L"Numpad -"));
|
||||
cpu_menu->AddChild(std::make_unique<PlatformMenu>(
|
||||
MenuItem::Type::kString, Commands::IDC_CPU_TIME_SCALAR_DOUBLE,
|
||||
L"Time Scalar *= 2", L"Numpad +"));
|
||||
}
|
||||
cpu_menu->AddChild(
|
||||
std::make_unique<PlatformMenu>(MenuItem::Type::kSeparator));
|
||||
{
|
||||
cpu_menu->AddChild(std::make_unique<PlatformMenu>(
|
||||
MenuItem::Type::kString, Commands::IDC_CPU_PROFILER_TOGGLE_DISPLAY,
|
||||
L"Toggle Profiler &Display", L"Tab"));
|
||||
cpu_menu->AddChild(std::make_unique<PlatformMenu>(
|
||||
MenuItem::Type::kString, Commands::IDC_CPU_PROFILER_TOGGLE_PAUSE,
|
||||
L"&Pause/Resume Profiler", L"`"));
|
||||
}
|
||||
main_menu_.AddChild(std::move(cpu_menu));
|
||||
|
||||
// Window submenu
|
||||
auto window =
|
||||
// GPU menu.
|
||||
auto gpu_menu =
|
||||
std::make_unique<PlatformMenu>(MenuItem::Type::kPopup, L"&GPU");
|
||||
{
|
||||
gpu_menu->AddChild(std::make_unique<PlatformMenu>(
|
||||
MenuItem::Type::kString, Commands::IDC_GPU_TRACE_FRAME, L"&Trace Frame",
|
||||
L"F4"));
|
||||
}
|
||||
gpu_menu->AddChild(
|
||||
std::make_unique<PlatformMenu>(MenuItem::Type::kSeparator));
|
||||
{
|
||||
gpu_menu->AddChild(std::make_unique<PlatformMenu>(
|
||||
MenuItem::Type::kString, Commands::IDC_GPU_CLEAR_CACHES,
|
||||
L"&Clear Caches", L"F5"));
|
||||
}
|
||||
main_menu_.AddChild(std::move(gpu_menu));
|
||||
|
||||
// Window menu.
|
||||
auto window_menu =
|
||||
std::make_unique<PlatformMenu>(MenuItem::Type::kPopup, L"&Window");
|
||||
window->AddChild(std::make_unique<PlatformMenu>(
|
||||
MenuItem::Type::kString, Commands::IDC_WINDOW_FULLSCREEN,
|
||||
L"Fullscreen\tF11"));
|
||||
{
|
||||
window_menu->AddChild(std::make_unique<PlatformMenu>(
|
||||
MenuItem::Type::kString, Commands::IDC_WINDOW_FULLSCREEN,
|
||||
L"&Fullscreen", L"F11"));
|
||||
}
|
||||
main_menu_.AddChild(std::move(window_menu));
|
||||
|
||||
main_menu_.AddChild(std::move(window));
|
||||
// Help menu.
|
||||
auto help_menu =
|
||||
std::make_unique<PlatformMenu>(MenuItem::Type::kPopup, L"&Help");
|
||||
{
|
||||
help_menu->AddChild(std::make_unique<PlatformMenu>(
|
||||
MenuItem::Type::kString, Commands::IDC_HELP_WEBSITE, L"&Website...",
|
||||
L"F1"));
|
||||
help_menu->AddChild(std::make_unique<PlatformMenu>(
|
||||
MenuItem::Type::kString, Commands::IDC_HELP_ABOUT, L"&About..."));
|
||||
}
|
||||
main_menu_.AddChild(std::move(help_menu));
|
||||
|
||||
SetMenu(&main_menu_);
|
||||
|
||||
|
@ -146,11 +219,46 @@ void MainWindow::OnClose() {
|
|||
|
||||
void MainWindow::OnCommand(int id) {
|
||||
switch (id) {
|
||||
// TODO: Setup delegates to MenuItems so we don't have to do this
|
||||
case IDC_FILE_EXIT: {
|
||||
Close();
|
||||
} break;
|
||||
|
||||
case IDC_CPU_TIME_SCALAR_RESET: {
|
||||
Clock::set_guest_time_scalar(1.0);
|
||||
UpdateTitle();
|
||||
} break;
|
||||
case IDC_CPU_TIME_SCALAR_HALF: {
|
||||
Clock::set_guest_time_scalar(Clock::guest_time_scalar() / 2.0);
|
||||
UpdateTitle();
|
||||
} break;
|
||||
case IDC_CPU_TIME_SCALAR_DOUBLE: {
|
||||
Clock::set_guest_time_scalar(Clock::guest_time_scalar() * 2.0);
|
||||
UpdateTitle();
|
||||
} break;
|
||||
case IDC_CPU_PROFILER_TOGGLE_DISPLAY: {
|
||||
Profiler::ToggleDisplay();
|
||||
} break;
|
||||
case IDC_CPU_PROFILER_TOGGLE_PAUSE: {
|
||||
Profiler::TogglePause();
|
||||
} break;
|
||||
|
||||
case IDC_GPU_TRACE_FRAME: {
|
||||
emulator()->graphics_system()->RequestFrameTrace();
|
||||
} break;
|
||||
case IDC_GPU_CLEAR_CACHES: {
|
||||
emulator()->graphics_system()->ClearCaches();
|
||||
} break;
|
||||
|
||||
case IDC_WINDOW_FULLSCREEN: {
|
||||
ToggleFullscreen();
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
case IDC_HELP_WEBSITE: {
|
||||
LaunchBrowser("http://xenia.jp");
|
||||
} break;
|
||||
case IDC_HELP_ABOUT: {
|
||||
LaunchBrowser("http://xenia.jp/about/");
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -50,12 +50,6 @@ class MainWindow : public PlatformWindow {
|
|||
void OnClose() override;
|
||||
void OnCommand(int id) override;
|
||||
|
||||
enum Commands {
|
||||
IDC_FILE_OPEN,
|
||||
|
||||
IDC_WINDOW_FULLSCREEN,
|
||||
};
|
||||
|
||||
Emulator* emulator_;
|
||||
PlatformLoop loop_;
|
||||
PlatformMenu main_menu_;
|
||||
|
|
|
@ -14,8 +14,9 @@ namespace ui {
|
|||
|
||||
MenuItem::MenuItem(Type type) : type_(type), parent_item_(nullptr) {}
|
||||
|
||||
MenuItem::MenuItem(Type type, const std::wstring& text)
|
||||
: type_(type), parent_item_(nullptr), text_(text) {}
|
||||
MenuItem::MenuItem(Type type, const std::wstring& text,
|
||||
const std::wstring& hotkey)
|
||||
: type_(type), parent_item_(nullptr), text_(text), hotkey_(hotkey) {}
|
||||
|
||||
MenuItem::~MenuItem() = default;
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ class MenuItem {
|
|||
MenuItem* parent_item() const { return parent_item_; }
|
||||
Type type() { return type_; }
|
||||
const std::wstring& text() { return text_; }
|
||||
const std::wstring& hotkey() { return hotkey_; }
|
||||
|
||||
void AddChild(MenuItem* child_item);
|
||||
void AddChild(std::unique_ptr<MenuItem> child_item);
|
||||
|
@ -45,7 +46,7 @@ class MenuItem {
|
|||
|
||||
protected:
|
||||
MenuItem(Type type);
|
||||
MenuItem(Type type, const std::wstring& text);
|
||||
MenuItem(Type type, const std::wstring& text, const std::wstring& hotkey);
|
||||
|
||||
virtual void OnChildAdded(MenuItem* child_item) {}
|
||||
virtual void OnChildRemoved(MenuItem* child_item) {}
|
||||
|
@ -55,7 +56,8 @@ class MenuItem {
|
|||
Type type_;
|
||||
MenuItem* parent_item_;
|
||||
std::vector<MenuItemPtr> children_;
|
||||
std::wstring text_; // Text associated with this item (typically the title)
|
||||
std::wstring text_;
|
||||
std::wstring hotkey_;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
|
|
|
@ -15,8 +15,9 @@ namespace xe {
|
|||
namespace ui {
|
||||
namespace win32 {
|
||||
|
||||
Win32MenuItem::Win32MenuItem(Type type, int id, const std::wstring& text)
|
||||
: id_(id), MenuItem(type, text) {
|
||||
Win32MenuItem::Win32MenuItem(Type type, int id, const std::wstring& text,
|
||||
const std::wstring& hotkey)
|
||||
: id_(id), MenuItem(type, text, hotkey) {
|
||||
switch (type) {
|
||||
case MenuItem::Type::kNormal:
|
||||
handle_ = CreateMenu();
|
||||
|
@ -29,8 +30,9 @@ Win32MenuItem::Win32MenuItem(Type type, int id, const std::wstring& text)
|
|||
|
||||
Win32MenuItem::Win32MenuItem(Type type) : Win32MenuItem(type, 0, L"") {}
|
||||
|
||||
Win32MenuItem::Win32MenuItem(Type type, const std::wstring& text)
|
||||
: Win32MenuItem(type, 0, text) {}
|
||||
Win32MenuItem::Win32MenuItem(Type type, const std::wstring& text,
|
||||
const std::wstring& hotkey)
|
||||
: Win32MenuItem(type, 0, text, hotkey) {}
|
||||
|
||||
Win32MenuItem::~Win32MenuItem() {
|
||||
if (handle_) {
|
||||
|
@ -51,8 +53,11 @@ void Win32MenuItem::OnChildAdded(MenuItem* generic_child_item) {
|
|||
AppendMenuW(handle_, MF_SEPARATOR, child_item->id(), 0);
|
||||
break;
|
||||
case MenuItem::Type::kString:
|
||||
AppendMenuW(handle_, MF_STRING, child_item->id(),
|
||||
child_item->text().c_str());
|
||||
auto full_name = child_item->text();
|
||||
if (!child_item->hotkey().empty()) {
|
||||
full_name += L"\t" + child_item->hotkey();
|
||||
}
|
||||
AppendMenuW(handle_, MF_STRING, child_item->id(), full_name.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,8 +22,10 @@ namespace win32 {
|
|||
class Win32MenuItem : public MenuItem {
|
||||
public:
|
||||
Win32MenuItem(Type type);
|
||||
Win32MenuItem(Type type, const std::wstring& text);
|
||||
Win32MenuItem(Type type, int id, const std::wstring& text);
|
||||
Win32MenuItem(Type type, const std::wstring& text,
|
||||
const std::wstring& hotkey = L"");
|
||||
Win32MenuItem(Type type, int id, const std::wstring& text,
|
||||
const std::wstring& hotkey = L"");
|
||||
~Win32MenuItem() override;
|
||||
|
||||
HMENU handle() { return handle_; }
|
||||
|
|
Loading…
Reference in New Issue