diff --git a/Source/Core/DolphinQt/CMakeLists.txt b/Source/Core/DolphinQt/CMakeLists.txt index 96db4ebcca..48fd1cfa06 100644 --- a/Source/Core/DolphinQt/CMakeLists.txt +++ b/Source/Core/DolphinQt/CMakeLists.txt @@ -14,7 +14,7 @@ set(SRCS SystemInfo.cpp Utils/Resources.cpp Utils/Utils.cpp - VideoInterface/VideoInterface.cpp + VideoInterface/RenderWidget.cpp ) set(UIS diff --git a/Source/Core/DolphinQt/DolphinQt.vcxproj b/Source/Core/DolphinQt/DolphinQt.vcxproj index 08b4484179..bc5482a1b4 100644 --- a/Source/Core/DolphinQt/DolphinQt.vcxproj +++ b/Source/Core/DolphinQt/DolphinQt.vcxproj @@ -48,6 +48,9 @@ $(ExternalsDir)OpenAL\$(PlatformName);%(AdditionalLibraryDirectories) iphlpapi.lib;winmm.lib;setupapi.lib;vfw32.lib;opengl32.lib;glu32.lib;rpcrt4.lib;comctl32.lib;%(AdditionalDependencies) + + $(ProjectDir)\VideoInterface;%(AdditionalIncludeDirectories) + @@ -62,16 +65,18 @@ + - + + - + @@ -152,6 +157,7 @@ + diff --git a/Source/Core/DolphinQt/DolphinQt.vcxproj.filters b/Source/Core/DolphinQt/DolphinQt.vcxproj.filters index e81be15e09..e415c300a5 100644 --- a/Source/Core/DolphinQt/DolphinQt.vcxproj.filters +++ b/Source/Core/DolphinQt/DolphinQt.vcxproj.filters @@ -5,9 +5,6 @@ - - VideoInterface - Utils @@ -15,11 +12,27 @@ Utils + + VideoInterface + + + Generated Files + + + Generated Files + + + Generated Files + + + Generated Files + + @@ -34,6 +47,9 @@ {730f2ae7-a686-4bc8-bb49-b4f8bd240329} + + {c18a1fb3-64ff-4249-b808-d73a56ea3a2d} + @@ -42,5 +58,8 @@ Utils + + VideoInterface + \ No newline at end of file diff --git a/Source/Core/DolphinQt/Host.cpp b/Source/Core/DolphinQt/Host.cpp index ced35df0ab..af10de63c9 100644 --- a/Source/Core/DolphinQt/Host.cpp +++ b/Source/Core/DolphinQt/Host.cpp @@ -5,9 +5,14 @@ #include #include +#include +#include + #include "Common/MsgHandler.h" #include "Core/Host.h" +#include "DolphinQt/MainWindow.h" + void Host_SysMessage(const char *fmt, ...) { va_list list; @@ -27,9 +32,48 @@ void Host_Message(int id) // TODO } +void Host_UpdateMainFrame() +{ + // TODO +} + +void Host_UpdateTitle(const std::string& title) +{ + // TODO +} + void* Host_GetRenderHandle() { - return nullptr; + return (void*)(g_main_window->GetRenderWidget()->winId()); +} + +void Host_GetRenderWindowSize(int& x, int& y, int& w, int& h) +{ + // TODO: Make it more clear what this is supposed to return.. i.e. WX always sets x=y=0 + g_main_window->RenderWidgetSize(x, y, w, h); + x = 0; + y = 0; +} + +void Host_RequestRenderWindowSize(int w, int h) +{ + DRenderWidget* render_widget = g_main_window->GetRenderWidget(); + qApp->postEvent(render_widget, new QResizeEvent(QSize(w, h), render_widget->size())); +} + +bool Host_RendererHasFocus() +{ + return g_main_window->RenderWidgetHasFocus(); +} + +bool Host_UIHasFocus() +{ + return g_main_window->isActiveWindow(); +} + +void Host_RequestFullscreen(bool enable) +{ + // TODO } void Host_NotifyMapLoaded() @@ -42,31 +86,6 @@ void Host_UpdateDisasmDialog() // TODO } -void Host_UpdateMainFrame() -{ - // TODO -} - -void Host_UpdateTitle(const std::string& title) -{ - // TODO -} - -void Host_GetRenderWindowSize(int& x, int& y, int& width, int& height) -{ - // TODO -} - -void Host_RequestRenderWindowSize(int width, int height) -{ - // TODO -} - -void Host_RequestFullscreen(bool enable_fullscreen) -{ - // TODO -} - void Host_SetStartupDebuggingParameters() { // TODO @@ -77,18 +96,6 @@ void Host_SetWiiMoteConnectionState(int state) // TODO } -bool Host_UIHasFocus() -{ - // TODO - return false; -} - -bool Host_RendererHasFocus() -{ - // TODO - return false; -} - void Host_ConnectWiimote(int wm_idx, bool connect) { // TODO diff --git a/Source/Core/DolphinQt/Main.cpp b/Source/Core/DolphinQt/Main.cpp index 93d853ad62..29279e812e 100644 --- a/Source/Core/DolphinQt/Main.cpp +++ b/Source/Core/DolphinQt/Main.cpp @@ -54,10 +54,11 @@ int main(int argc, char* argv[]) return 1; } - DMainWindow w; - w.show(); + g_main_window = new DMainWindow(); + g_main_window->show(); int retcode = app.exec(); + delete g_main_window; UICommon::Shutdown(); return retcode; } diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index 62382e10c5..0a1d7fa469 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -3,36 +3,247 @@ // Refer to the license.txt file included. #include +#include +#include #include #include "ui_MainWindow.h" #include "Common/StdMakeUnique.h" +#include "Core/BootManager.h" +#include "Core/ConfigManager.h" + #include "DolphinQt/AboutDialog.h" #include "DolphinQt/MainWindow.h" #include "DolphinQt/SystemInfo.h" #include "DolphinQt/Utils/Resources.h" #include "DolphinQt/Utils/Utils.h" +// The "g_main_window" object as defined in MainWindow.h +DMainWindow* g_main_window = nullptr; + DMainWindow::DMainWindow(QWidget* parent_widget) : QMainWindow(parent_widget) { m_ui = std::make_unique(); m_ui->setupUi(this); - - Resources::Init(); - m_ui->actOpen->setIcon(Resources::GetIcon(Resources::TOOLBAR_OPEN)); - #ifdef Q_OS_MACX m_ui->toolbar->setMovable(false); #endif + + Resources::Init(); + + UpdateIcons(); + setWindowIcon(Resources::GetIcon(Resources::DOLPHIN_LOGO)); + + connect(this, SIGNAL(CoreStateChanged(Core::EState)), this, SLOT(OnCoreStateChanged(Core::EState))); + emit CoreStateChanged(Core::CORE_UNINITIALIZED); // update GUI items } DMainWindow::~DMainWindow() { } +// Emulation + +void DMainWindow::StartGame(const QString filename) +{ + m_render_widget = std::make_unique(); + m_render_widget->setWindowTitle(tr("Dolphin")); // TODO + m_render_widget->setWindowIcon(windowIcon()); + + // TODO: When rendering to main, this won't resize the parent window.. + if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bRenderToMain) + { + connect(m_render_widget.get(), SIGNAL(Closed()), this, SLOT(on_actStop_triggered())); + m_render_widget->move(SConfig::GetInstance().m_LocalCoreStartupParameter.iRenderWindowXPos, + SConfig::GetInstance().m_LocalCoreStartupParameter.iRenderWindowYPos); + m_render_widget->resize(SConfig::GetInstance().m_LocalCoreStartupParameter.iRenderWindowWidth, // TODO: Make sure these are client sizes! + SConfig::GetInstance().m_LocalCoreStartupParameter.iRenderWindowHeight); + m_render_widget->show(); + } + else + { + m_ui->centralWidget->addWidget(m_render_widget.get()); + m_ui->centralWidget->setCurrentWidget(m_render_widget.get()); + } + + if (!BootManager::BootCore(filename.toStdString())) + { + QMessageBox::critical(this, tr("Fatal error"), tr("Failed to init Core"), QMessageBox::Ok); + if (SConfig::GetInstance().m_LocalCoreStartupParameter.bRenderToMain) + m_ui->centralWidget->removeWidget(m_render_widget.get()); + else + m_render_widget->close(); + m_render_widget.reset(); + } + else + { + // TODO: Disable screensaver! + + // TODO: Fullscreen + //DoFullscreen(SConfig::GetInstance().m_LocalCoreStartupParameter.bFullscreen); + + m_render_widget->focusWidget(); + emit CoreStateChanged(Core::CORE_RUN); + } +} + +QString DMainWindow::RequestBootFilename() +{ + // If a game is already selected, just return the filename + // ... TODO + + return ShowFileDialog(); +} + +QString DMainWindow::ShowFileDialog() +{ + return QFileDialog::getOpenFileName(this, tr("Open File"), QString(), + tr("All supported ROMs (%1);;All files (*)") + .arg(SL("*.gcm *.iso *.ciso *.gcz *.wbfs *.elf *.dol *.dff *.tmd *.wad"))); +} + +void DMainWindow::DoStartPause() +{ + if (Core::GetState() == Core::CORE_RUN) + { + Core::SetState(Core::CORE_PAUSE); + emit CoreStateChanged(Core::CORE_PAUSE); + } + else + { + Core::SetState(Core::CORE_RUN); + emit CoreStateChanged(Core::CORE_RUN); + } + if (SConfig::GetInstance().m_LocalCoreStartupParameter.bHideCursor) + m_render_widget->setCursor(Qt::BlankCursor); +} + +void DMainWindow::on_actOpen_triggered() +{ + StartGame(ShowFileDialog()); +} + +void DMainWindow::on_actPlay_triggered() +{ + if (Core::GetState() != Core::CORE_UNINITIALIZED) + { + DoStartPause(); + } + else + { + // initialize Core and boot the game + QString filename = RequestBootFilename(); + if (!filename.isNull()) + StartGame(filename); + } +} + +void DMainWindow::on_actStop_triggered() +{ + if (Core::GetState() != Core::CORE_UNINITIALIZED && !m_isStopping) + { + m_isStopping = true; + // Ask for confirmation in case the user accidentally clicked Stop / Escape + if (SConfig::GetInstance().m_LocalCoreStartupParameter.bConfirmStop) + { + int ret = QMessageBox::question(m_render_widget.get(), tr("Please confirm..."), + tr("Do you want to stop the current emulation?"), + QMessageBox::Yes | QMessageBox::No, QMessageBox::No); + + if (ret == QMessageBox::No) + return; + } + + // TODO: Movie stuff + // TODO: Show the author/description dialog here + + // TODO: Show busy cursor + BootManager::Stop(); + // TODO: Hide busy cursor again + + // TODO: Allow screensaver again + // TODO: Restore original window title + + // TODO: Return from fullscreen if necessary (DoFullscreen in the wx code) + + // TODO: + // If batch mode was specified on the command-line, exit now. + //if (m_bBatchMode) + // Close(true); + + if (SConfig::GetInstance().m_LocalCoreStartupParameter.bRenderToMain) + m_ui->centralWidget->removeWidget(m_render_widget.get()); + else + m_render_widget->close(); + m_render_widget.reset(); + + emit CoreStateChanged(Core::CORE_UNINITIALIZED); + } + m_isStopping = false; +} + +void DMainWindow::OnCoreStateChanged(Core::EState state) +{ + bool is_not_initialized = (state == Core::CORE_UNINITIALIZED); + bool is_running = (state == Core::CORE_RUN); + bool is_paused = (state == Core::CORE_PAUSE); + + // Update the toolbar + m_ui->actPlay->setEnabled(is_not_initialized || is_running || is_paused); + if (is_running) + { + m_ui->actPlay->setIcon(Resources::GetIcon(Resources::TOOLBAR_PAUSE)); + m_ui->actPlay->setText(tr("Pause")); + } + else if (is_paused || is_not_initialized) + { + m_ui->actPlay->setIcon(Resources::GetIcon(Resources::TOOLBAR_PLAY)); + m_ui->actPlay->setText(tr("Play")); + } + + m_ui->actStop->setEnabled(!is_not_initialized); + m_ui->actOpen->setEnabled(is_not_initialized); +} + +// DRenderWidget +void DMainWindow::RenderWidgetSize(int& x_pos, int& y_pos, int& w, int& h) +{ + if (SConfig::GetInstance().m_LocalCoreStartupParameter.bRenderToMain) + { + x_pos = x(); + y_pos = y(); + } + else + { + x_pos = m_render_widget->x(); + y_pos = m_render_widget->y(); + } + w = m_render_widget->width(); + h = m_render_widget->height(); +} + +bool DMainWindow::RenderWidgetHasFocus() +{ + if (SConfig::GetInstance().m_LocalCoreStartupParameter.bRenderToMain) + return isActiveWindow(); + else if (m_render_widget != nullptr) + return m_render_widget->isActiveWindow(); + else + return false; +} + +// Update all the icons used in DMainWindow with fresh ones from +// "Resources". Call this function after changing the icon theme. +void DMainWindow::UpdateIcons() +{ + m_ui->actOpen->setIcon(Resources::GetIcon(Resources::TOOLBAR_OPEN)); + m_ui->actStop->setIcon(Resources::GetIcon(Resources::TOOLBAR_STOP)); +} + +// Help menu void DMainWindow::on_actWebsite_triggered() { QDesktopServices::openUrl(QUrl(SL("https://dolphin-emu.org/"))); diff --git a/Source/Core/DolphinQt/MainWindow.h b/Source/Core/DolphinQt/MainWindow.h index a1ffa1c6ed..d01279ae6f 100644 --- a/Source/Core/DolphinQt/MainWindow.h +++ b/Source/Core/DolphinQt/MainWindow.h @@ -7,6 +7,10 @@ #include #include +#include "Core/Core.h" + +#include "DolphinQt/VideoInterface/RenderWidget.h" + // Predefinitions namespace Ui { @@ -21,7 +25,23 @@ public: explicit DMainWindow(QWidget* parent_widget = nullptr); ~DMainWindow(); + // DRenderWidget + void RenderWidgetSize(int& x_pos, int& y_pos, int& w, int& h); + bool RenderWidgetHasFocus(); + DRenderWidget* GetRenderWidget() { return m_render_widget.get(); } + +signals: + void CoreStateChanged(Core::EState state); + private slots: + // Emulation + void StartGame(const QString filename); + void OnCoreStateChanged(Core::EState state); + + // Main toolbar + void on_actOpen_triggered(); + void on_actPlay_triggered(); + void on_actStop_triggered(); // Help menu void on_actWebsite_triggered(); @@ -30,6 +50,20 @@ private slots: void on_actSystemInfo_triggered(); void on_actAbout_triggered(); + // Misc. + void UpdateIcons(); + private: std::unique_ptr m_ui; + + // Emulation + QString RequestBootFilename(); + QString ShowFileDialog(); + void DoStartPause(); + + std::unique_ptr m_render_widget; + bool m_isStopping = false; }; + +// Pointer to the only instance of DMainWindow, used by Host_* +extern DMainWindow* g_main_window; diff --git a/Source/Core/DolphinQt/MainWindow.ui b/Source/Core/DolphinQt/MainWindow.ui index c63d5610c0..884dad3714 100644 --- a/Source/Core/DolphinQt/MainWindow.ui +++ b/Source/Core/DolphinQt/MainWindow.ui @@ -25,14 +25,14 @@ true - + 0 0 992 - 24 + 21 @@ -97,6 +97,9 @@ false + + + @@ -134,6 +137,16 @@ &System Information + + + Play + + + + + Stop + + diff --git a/Source/Core/DolphinQt/VideoInterface/RenderWidget.cpp b/Source/Core/DolphinQt/VideoInterface/RenderWidget.cpp new file mode 100644 index 0000000000..4fbcd3cd29 --- /dev/null +++ b/Source/Core/DolphinQt/VideoInterface/RenderWidget.cpp @@ -0,0 +1,24 @@ +// Copyright 2014 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include + +#include "DolphinQt/VideoInterface/RenderWidget.h" + +DRenderWidget::DRenderWidget(QWidget* parent_widget) + : QWidget(parent_widget) +{ + setAttribute(Qt::WA_NativeWindow, true); + setAttribute(Qt::WA_OpaquePaintEvent, true); + setAttribute(Qt::WA_NoSystemBackground, true); +} + +void DRenderWidget::closeEvent(QCloseEvent* e) +{ + // TODO: update render window positions in config + + // TODO: Do this differently... + emit Closed(); + QWidget::closeEvent(e); +} diff --git a/Source/Core/DolphinQt/VideoInterface/RenderWidget.h b/Source/Core/DolphinQt/VideoInterface/RenderWidget.h new file mode 100644 index 0000000000..81ad82374e --- /dev/null +++ b/Source/Core/DolphinQt/VideoInterface/RenderWidget.h @@ -0,0 +1,28 @@ +// Copyright 2014 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include + +class DRenderWidget : public QWidget +{ + Q_OBJECT + +public: + DRenderWidget(QWidget* parent_widget = nullptr); + +protected: + // Some window managers start window dragging if an "empty" window area was clicked. + // Prevent this by intercepting the mouse press event. + void mousePressEvent(QMouseEvent*) override {} + void paintEvent(QPaintEvent*) override {} + +private slots: + void closeEvent(QCloseEvent* e) override; + +signals: + void Closed(); +}; + diff --git a/Source/Core/DolphinQt/VideoInterface/VideoInterface.cpp b/Source/Core/DolphinQt/VideoInterface/VideoInterface.cpp deleted file mode 100644 index 4424175f16..0000000000 --- a/Source/Core/DolphinQt/VideoInterface/VideoInterface.cpp +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2014 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include "VideoBackends/OGL/GLInterfaceBase.h" - -cInterfaceBase* HostGL_CreateGLInterface() -{ - // TODO - return nullptr; -}