Files
Xenia-Canary/src/xenia/ui/main_window.cc
2015-07-01 08:02:22 -07:00

265 lines
7.3 KiB
C++

/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/ui/main_window.h"
#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"
#include "xenia/profiling.h"
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)
: PlatformWindow(&loop_, kBaseTitle),
emulator_(emulator),
main_menu_(MenuItem::Type::kNormal) {}
MainWindow::~MainWindow() = default;
std::unique_ptr<PlatformWindow> MainWindow::Create(Emulator* emulator) {
std::unique_ptr<MainWindow> main_window(new MainWindow(emulator));
xe::threading::Fence fence;
main_window->loop()->Post([&main_window, &fence]() {
xe::threading::set_name("Win32 Loop");
xe::Profiler::ThreadEnter("Win32 Loop");
if (!main_window->Initialize()) {
XEFATAL("Failed to initialize main window");
exit(1);
}
fence.Signal();
});
fence.Wait();
return std::unique_ptr<PlatformWindow>(main_window.release());
}
bool MainWindow::Initialize() {
if (!PlatformWindow::Initialize()) {
return false;
}
UpdateTitle();
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
OnCommand(Commands::IDC_GPU_TRACE_FRAME);
} break;
case 0x74: { // VK_F5
OnCommand(Commands::IDC_GPU_CLEAR_CACHES);
} break;
case 0x7A: { // VK_F11
OnCommand(Commands::IDC_WINDOW_FULLSCREEN);
} break;
case 0x1B: { // VK_ESCAPE
// Allow users to escape fullscreen (but not enter it).
if (is_fullscreen()) {
ToggleFullscreen(false);
}
} break;
case 0x70: { // VK_F1
OnCommand(Commands::IDC_HELP_WEBSITE);
} break;
default: { handled = false; } break;
}
e.set_handled(handled);
});
// Main menu.
// FIXME: This code is really messy.
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));
// 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));
// 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_menu->AddChild(std::make_unique<PlatformMenu>(
MenuItem::Type::kString, Commands::IDC_WINDOW_FULLSCREEN,
L"&Fullscreen", L"F11"));
}
main_menu_.AddChild(std::move(window_menu));
// 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));
set_menu(&main_menu_);
Resize(1280, 720);
return true;
}
void MainWindow::UpdateTitle() {
std::wstring title(kBaseTitle);
if (Clock::guest_time_scalar() != 1.0) {
title += L" (@";
title += xe::to_wstring(std::to_string(Clock::guest_time_scalar()));
title += L"x)";
}
set_title(title);
}
void MainWindow::OnClose() {
loop_.Quit();
// TODO(benvanik): proper exit.
XELOGI("User-initiated death!");
exit(1);
}
void MainWindow::OnCommand(int id) {
switch (id) {
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(!is_fullscreen());
} break;
case IDC_HELP_WEBSITE: {
LaunchBrowser("http://xenia.jp");
} break;
case IDC_HELP_ABOUT: {
LaunchBrowser("http://xenia.jp/about/");
} break;
}
}
} // namespace ui
} // namespace xe