aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarrett Brown <themagnificentmrb@gmail.com>2018-09-11 13:56:05 -0700
committerGarrett Brown <themagnificentmrb@gmail.com>2018-09-20 16:53:26 +0200
commit655373fcba24c00e25e038025e53af34b5186766 (patch)
tree32dc80b8978b7612e90167e10f734c5f3dc42374
parentc945a6a7b96abdb8467a6807bea1bd1f767c40f2 (diff)
Game OSD: Show help dialog on first view
This adds a help dialog to the game OSD and encapsulates the GUI playback control mechanisms. The volume dialog has been modified to play the game in the background for audible feedback.
-rw-r--r--addons/resource.language.en_gb/resources/strings.po8
-rw-r--r--addons/skin.estuary/xml/GameOSD.xml390
-rw-r--r--cmake/treedata/common/retroplayer.txt1
-rw-r--r--system/keymaps/joystick.xml2
-rwxr-xr-xsystem/settings/settings.xml6
-rw-r--r--xbmc/cores/RetroPlayer/RetroPlayer.cpp136
-rw-r--r--xbmc/cores/RetroPlayer/RetroPlayer.h26
-rw-r--r--xbmc/cores/RetroPlayer/RetroPlayerInput.cpp5
-rw-r--r--xbmc/cores/RetroPlayer/RetroPlayerInput.h5
-rw-r--r--xbmc/cores/RetroPlayer/guiplayback/CMakeLists.txt7
-rw-r--r--xbmc/cores/RetroPlayer/guiplayback/GUIPlaybackControl.cpp153
-rw-r--r--xbmc/cores/RetroPlayer/guiplayback/GUIPlaybackControl.h52
-rw-r--r--xbmc/cores/RetroPlayer/guiwindows/GameWindowFullScreen.cpp7
-rw-r--r--xbmc/cores/RetroPlayer/playback/CMakeLists.txt13
-rw-r--r--xbmc/cores/RetroPlayer/playback/IPlaybackControl.h52
-rw-r--r--xbmc/cores/RetroPlayer/rendering/RPRenderManager.cpp3
-rw-r--r--xbmc/games/GameSettings.cpp17
-rw-r--r--xbmc/games/GameSettings.h2
-rw-r--r--xbmc/games/addons/GameClient.cpp2
-rw-r--r--xbmc/games/addons/GameClientCallbacks.h15
-rw-r--r--xbmc/games/addons/input/GameClientInput.cpp15
-rw-r--r--xbmc/games/addons/input/GameClientInput.h4
-rw-r--r--xbmc/games/dialogs/osd/CMakeLists.txt2
-rw-r--r--xbmc/games/dialogs/osd/DialogGameOSD.cpp63
-rw-r--r--xbmc/games/dialogs/osd/DialogGameOSD.h29
-rw-r--r--xbmc/games/dialogs/osd/DialogGameOSDHelp.cpp71
-rw-r--r--xbmc/games/dialogs/osd/DialogGameOSDHelp.h40
27 files changed, 861 insertions, 265 deletions
diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po
index 5925ef794a..a01645e3bf 100644
--- a/addons/resource.language.en_gb/resources/strings.po
+++ b/addons/resource.language.en_gb/resources/strings.po
@@ -17460,7 +17460,13 @@ msgctxt "#35234"
msgid "Controls"
msgstr ""
-#empty strings from id 35235 to 35249
+#. Help text shown when the user first plays a game. {0:s} - Button combo to open the in-game menu
+#: addons/skin.estuary/xml/GameOSD.xml
+msgctxt "#35235"
+msgid "Press {0:s} to open the in-game menu."
+msgstr ""
+
+#empty strings from id 35236 to 35249
#: xbmc/windows/GUIMediaWindow.cpp
msgctxt "#35250"
diff --git a/addons/skin.estuary/xml/GameOSD.xml b/addons/skin.estuary/xml/GameOSD.xml
index ad0e0863c1..c44464ac46 100644
--- a/addons/skin.estuary/xml/GameOSD.xml
+++ b/addons/skin.estuary/xml/GameOSD.xml
@@ -1,184 +1,232 @@
<?xml version="1.0" encoding="utf-8"?>
<window>
- <defaultcontrol always="true">100</defaultcontrol>
+ <defaultcontrol always="true">1103</defaultcontrol>
<include>Animation_DialogPopupOpenClose</include>
+ <depth>DepthOSD</depth>
<controls>
- <control type="group">
- <centerleft>50%</centerleft>
- <height>400</height>
- <centertop>50%</centertop>
- <width>700</width>
+ <control type="group" id="1">
<visible>!Window.IsActive(1101) + !Window.IsActive(GameVideoFilter) + !Window.IsActive(GameViewMode) + !Window.IsActive(GameControllers) + !Window.IsActive(GameVideoRotation)</visible>
- <animation effect="fade" time="200">VisibleChange</animation>
- <include content="DialogBackgroundCommons">
- <param name="width" value="700" />
- <param name="height" value="400" />
- <param name="header_label" value="$LOCALIZE[35221]" />
- <param name="header_id" value="1" />
- </include>
- <control type="group">
- <top>80</top>
- <control type="list" id="100">
- <defaultcontrol always="true">101</defaultcontrol>
- <height>320</height>
- <orientation>vertical</orientation>
- <itemlayout condition="!Control.IsVisible(200)" width="700" height="80">
- <control type="image">
- <left>8</left>
- <top>8</top>
- <width>64</width>
- <height>64</height>
- <info>ListItem.Icon</info>
- </control>
- <control type="label">
- <left>80</left>
- <width>600</width>
- <height>80</height>
- <info>ListItem.Label</info>
- <font>font13</font>
- <align>left</align>
- <aligny>center</aligny>
- </control>
- <control type="label">
- <right>20</right>
- <width>600</width>
- <height>80</height>
- <info>ListItem.Label2</info>
- <font>font13</font>
- <align>right</align>
- <aligny>center</aligny>
- <textcolor>grey</textcolor>
- </control>
- </itemlayout>
- <itemlayout condition="Control.IsVisible(200)" width="688" height="80">
- <control type="image">
- <left>8</left>
- <top>8</top>
- <width>64</width>
- <height>64</height>
- <info>ListItem.Icon</info>
- </control>
- <control type="label">
- <left>80</left>
- <width>600</width>
- <height>80</height>
- <info>ListItem.Label</info>
- <font>font13</font>
- <align>left</align>
- <aligny>center</aligny>
- </control>
- <control type="label">
- <right>20</right>
- <width>600</width>
- <height>80</height>
- <info>ListItem.Label2</info>
+ <control type="group" id="10">
+ <visible>System.GetBool(gamesgeneral.showosdhelp)</visible>
+ <defaultcontrol always="true">1103</defaultcontrol>
+ <centerleft>50%</centerleft>
+ <height>910</height>
+ <centertop>50%</centertop>
+ <width>700</width>
+ <animation effect="fade" time="200">VisibleChange</animation>
+ <include content="DialogBackgroundCommons">
+ <param name="width" value="700" />
+ <param name="height" value="910" />
+ <param name="header_label" value="$LOCALIZE[35221]" />
+ <param name="header_id" value="2" />
+ </include>
+ <control type="group" id="1000">
+ <top>80</top>
+ <control type="group" id="1100">
+ <control type="textbox" id="1101">
+ <description>Help text</description>
+ <top>30</top>
+ <left>30</left>
+ <right>30</right>
+ <height>130</height>
<font>font13</font>
- <align>right</align>
- <aligny>center</aligny>
- <textcolor>grey</textcolor>
</control>
- </itemlayout>
- <focusedlayout condition="!Control.IsVisible(200)" width="700" height="80">
- <control type="image">
- <texture colordiffuse="button_focus">lists/focus.png</texture>
- <visible>Control.HasFocus(100)</visible>
+ <control type="gamecontroller" id="1102">
+ <top>160</top>
+ <left>30</left>
+ <width>640</width>
+ <height>640</height>
</control>
- <control type="image">
- <left>8</left>
- <top>8</top>
- <width>64</width>
- <height>64</height>
- <info>ListItem.Icon</info>
- </control>
- <control type="label">
- <left>80</left>
- <width>600</width>
- <height>80</height>
- <info>ListItem.Label</info>
- <font>font13</font>
- <align>left</align>
- <aligny>center</aligny>
+ <control type="button">
+ <description>Button to close the dialog</description>
+ <top>0</top>
+ <bottom>0</bottom>
+ <left>0</left>
+ <right>0</right>
+ <texturefocus />
+ <texturenofocus />
+ <onclick>Action(close)</onclick>
</control>
- <control type="label">
- <right>20</right>
- <width>600</width>
- <height>80</height>
- <info>ListItem.Label2</info>
- <font>font13</font>
- <align>right</align>
- <aligny>center</aligny>
- <textcolor>grey</textcolor>
- </control>
- </focusedlayout>
- <focusedlayout condition="Control.IsVisible(200)" width="688" height="80">
- <control type="image">
- <texture colordiffuse="button_focus">lists/focus.png</texture>
- <visible>Control.HasFocus(100)</visible>
- </control>
- <control type="image">
- <left>8</left>
- <top>8</top>
- <width>64</width>
- <height>64</height>
- <info>ListItem.Icon</info>
- </control>
- <control type="label">
- <left>80</left>
- <width>600</width>
- <height>80</height>
- <info>ListItem.Label</info>
- <font>font13</font>
- <align>left</align>
- <aligny>center</aligny>
- </control>
- <control type="label">
- <right>20</right>
- <width>600</width>
- <height>80</height>
- <info>ListItem.Label2</info>
- <font>font13</font>
- <align>right</align>
- <aligny>center</aligny>
- <textcolor>grey</textcolor>
- </control>
- </focusedlayout>
- <content>
- <item id="101">
- <description>Pause / Resume button</description>
- <label>$LOCALIZE[35224]</label>
- <label2>Select + X</label2>
- <icon>osd/fullscreen/buttons/play.png</icon>
- <onclick>Play</onclick>
- </item>
- <item id="102">
- <description>Reset button</description>
- <label>$LOCALIZE[13007]</label>
- <icon>osd/fullscreen/buttons/reset.png</icon>
- <onclick>PlayerControl(Reset)</onclick>
- </item>
- <item id="103">
- <description>Stop button</description>
- <label>$LOCALIZE[35222]</label>
- <label2>Select + Start</label2>
- <icon>osd/fullscreen/buttons/stop.png</icon>
- <onclick>Stop</onclick>
- </item>
- <item id="108">
- <description>Settings button</description>
- <label>$LOCALIZE[5]</label>
- <icon>osd/fullscreen/buttons/settings.png</icon>
- <onclick>SetProperty(settingslist_content,games,home)</onclick>
- <onclick>SetProperty(settingslist_header,$LOCALIZE[5],home)</onclick>
- <onclick>ActivateWindow(1101)</onclick>
- </item>
- </content>
- <pagecontrol>200</pagecontrol>
+ </control>
</control>
- <control type="scrollbar" id="200">
- <top>-10</top>
- <right>0</right>
- <width>12</width>
- <orientation>vertical</orientation>
+ </control>
+ <control type="group" id="20">
+ <visible>!System.GetBool(gamesgeneral.showosdhelp)</visible>
+ <centerleft>50%</centerleft>
+ <height>400</height>
+ <centertop>50%</centertop>
+ <width>700</width>
+ <animation effect="fade" time="200">VisibleChange</animation>
+ <include content="DialogBackgroundCommons">
+ <param name="width" value="700" />
+ <param name="height" value="400" />
+ <param name="header_label" value="$LOCALIZE[35221]" />
+ <param name="header_id" value="3" />
+ </include>
+ <control type="group" id="2000">
+ <top>80</top>
+ <control type="list" id="1103">
+ <defaultcontrol always="true">2101</defaultcontrol>
+ <height max="400">auto</height>
+ <orientation>vertical</orientation>
+ <itemlayout condition="!Control.IsVisible(2200)" width="700" height="80">
+ <control type="image">
+ <left>8</left>
+ <top>8</top>
+ <width>64</width>
+ <height>64</height>
+ <info>ListItem.Icon</info>
+ </control>
+ <control type="label">
+ <left>80</left>
+ <width>600</width>
+ <height>80</height>
+ <info>ListItem.Label</info>
+ <font>font13</font>
+ <align>left</align>
+ <aligny>center</aligny>
+ </control>
+ <control type="label">
+ <right>20</right>
+ <width>600</width>
+ <height>80</height>
+ <info>ListItem.Label2</info>
+ <font>font13</font>
+ <align>right</align>
+ <aligny>center</aligny>
+ <textcolor>grey</textcolor>
+ </control>
+ </itemlayout>
+ <itemlayout condition="Control.IsVisible(2200)" width="688" height="80">
+ <control type="image">
+ <left>8</left>
+ <top>8</top>
+ <width>64</width>
+ <height>64</height>
+ <info>ListItem.Icon</info>
+ </control>
+ <control type="label">
+ <left>80</left>
+ <width>600</width>
+ <height>80</height>
+ <info>ListItem.Label</info>
+ <font>font13</font>
+ <align>left</align>
+ <aligny>center</aligny>
+ </control>
+ <control type="label">
+ <right>20</right>
+ <width>600</width>
+ <height>80</height>
+ <info>ListItem.Label2</info>
+ <font>font13</font>
+ <align>right</align>
+ <aligny>center</aligny>
+ <textcolor>grey</textcolor>
+ </control>
+ </itemlayout>
+ <focusedlayout condition="!Control.IsVisible(2200)" width="700" height="80">
+ <control type="image">
+ <texture colordiffuse="button_focus">lists/focus.png</texture>
+ <visible>Control.HasFocus(1103)</visible>
+ </control>
+ <control type="image">
+ <left>8</left>
+ <top>8</top>
+ <width>64</width>
+ <height>64</height>
+ <info>ListItem.Icon</info>
+ </control>
+ <control type="label">
+ <left>80</left>
+ <width>600</width>
+ <height>80</height>
+ <info>ListItem.Label</info>
+ <font>font13</font>
+ <align>left</align>
+ <aligny>center</aligny>
+ </control>
+ <control type="label">
+ <right>20</right>
+ <width>600</width>
+ <height>80</height>
+ <info>ListItem.Label2</info>
+ <font>font13</font>
+ <align>right</align>
+ <aligny>center</aligny>
+ <textcolor>grey</textcolor>
+ </control>
+ </focusedlayout>
+ <focusedlayout condition="Control.IsVisible(2200)" width="688" height="80">
+ <control type="image">
+ <texture colordiffuse="button_focus">lists/focus.png</texture>
+ <visible>Control.HasFocus(1103)</visible>
+ </control>
+ <control type="image">
+ <left>8</left>
+ <top>8</top>
+ <width>64</width>
+ <height>64</height>
+ <info>ListItem.Icon</info>
+ </control>
+ <control type="label">
+ <left>80</left>
+ <width>600</width>
+ <height>80</height>
+ <info>ListItem.Label</info>
+ <font>font13</font>
+ <align>left</align>
+ <aligny>center</aligny>
+ </control>
+ <control type="label">
+ <right>20</right>
+ <width>600</width>
+ <height>80</height>
+ <info>ListItem.Label2</info>
+ <font>font13</font>
+ <align>right</align>
+ <aligny>center</aligny>
+ <textcolor>grey</textcolor>
+ </control>
+ </focusedlayout>
+ <content>
+ <item id="2101">
+ <description>Pause / Resume button</description>
+ <label>$LOCALIZE[35224]</label>
+ <label2>Select + X</label2>
+ <icon>osd/fullscreen/buttons/play.png</icon>
+ <onclick>Play</onclick>
+ </item>
+ <item id="2102">
+ <description>Reset button</description>
+ <label>$LOCALIZE[13007]</label>
+ <icon>osd/fullscreen/buttons/reset.png</icon>
+ <onclick>PlayerControl(Reset)</onclick>
+ </item>
+ <item id="2103">
+ <description>Stop button</description>
+ <label>$LOCALIZE[35222]</label>
+ <label2>Select + Start</label2>
+ <icon>osd/fullscreen/buttons/stop.png</icon>
+ <onclick>Stop</onclick>
+ </item>
+ <item id="2108">
+ <description>Settings button</description>
+ <label>$LOCALIZE[5]</label>
+ <icon>osd/fullscreen/buttons/settings.png</icon>
+ <onclick>SetProperty(settingslist_content,games,home)</onclick>
+ <onclick>SetProperty(settingslist_header,$LOCALIZE[5],home)</onclick>
+ <onclick>ActivateWindow(1101)</onclick>
+ </item>
+ </content>
+ <pagecontrol>2200</pagecontrol>
+ </control>
+ <control type="scrollbar" id="2200">
+ <top>-10</top>
+ <right>0</right>
+ <width>12</width>
+ <orientation>vertical</orientation>
+ </control>
</control>
</control>
</control>
diff --git a/cmake/treedata/common/retroplayer.txt b/cmake/treedata/common/retroplayer.txt
index cf9c9c5f52..97fc849a02 100644
--- a/cmake/treedata/common/retroplayer.txt
+++ b/cmake/treedata/common/retroplayer.txt
@@ -4,6 +4,7 @@ xbmc/cores/RetroPlayer/buffers cores/RetroPlaye
xbmc/cores/RetroPlayer/buffers/video cores/RetroPlayer/buffers/video
xbmc/cores/RetroPlayer/guibridge cores/RetroPlayer/guibridge
xbmc/cores/RetroPlayer/guicontrols cores/RetroPlayer/guicontrols
+xbmc/cores/RetroPlayer/guiplayback cores/RetroPlayer/guiplayback
xbmc/cores/RetroPlayer/guiwindows cores/RetroPlayer/guiwindows
xbmc/cores/RetroPlayer/playback cores/RetroPlayer/playback
xbmc/cores/RetroPlayer/process cores/RetroPlayer/process
diff --git a/system/keymaps/joystick.xml b/system/keymaps/joystick.xml
index c9dace69cf..63d10002d4 100644
--- a/system/keymaps/joystick.xml
+++ b/system/keymaps/joystick.xml
@@ -153,7 +153,7 @@
<!-- Reset is disabled until player can undo a reset -->
<!--<b hotkey="back">PlayerControl(Reset)</b> -->
<x hotkey="back">OSD</x>
- <y hotkey="back">FullScreen</y>
+ <y hotkey="back">OSD</y>
<start hotkey="back">Stop</start>
<!--
<rightbumper hotkey="back">Save</rightbumper>
diff --git a/system/settings/settings.xml b/system/settings/settings.xml
index 2dccdb212c..395d5816c2 100755
--- a/system/settings/settings.xml
+++ b/system/settings/settings.xml
@@ -2023,6 +2023,12 @@
<default>true</default>
<control type="toggle" />
</setting>
+ <setting id="gamesgeneral.showosdhelp" type="boolean">
+ <visible>false</visible>
+ <level>0</level>
+ <default>true</default>
+ <control type="toggle" />
+ </setting>
<setting id="gamesgeneral.enableautosave" type="boolean" label="35253" help="35254">
<level>0</level>
<default>true</default>
diff --git a/xbmc/cores/RetroPlayer/RetroPlayer.cpp b/xbmc/cores/RetroPlayer/RetroPlayer.cpp
index 87b8f047d4..207414cfad 100644
--- a/xbmc/cores/RetroPlayer/RetroPlayer.cpp
+++ b/xbmc/cores/RetroPlayer/RetroPlayer.cpp
@@ -13,6 +13,7 @@
#include "cores/DataCacheCore.h"
#include "cores/IPlayerCallback.h"
#include "cores/RetroPlayer/guibridge/GUIGameRenderManager.h"
+#include "cores/RetroPlayer/guiplayback/GUIPlaybackControl.h"
#include "cores/RetroPlayer/playback/IPlayback.h"
#include "cores/RetroPlayer/playback/RealtimePlayback.h"
#include "cores/RetroPlayer/playback/ReversiblePlayback.h"
@@ -37,6 +38,7 @@
#include "guilib/WindowIDs.h"
#include "input/Action.h"
#include "input/ActionIDs.h"
+#include "messaging/ApplicationMessenger.h"
#include "settings/MediaSettings.h"
#include "threads/SingleLock.h"
#include "utils/JobManager.h"
@@ -169,13 +171,19 @@ bool CRetroPlayer::OpenFile(const CFileItem& file, const CPlayerOptions& options
if (bSuccess)
{
+ // Switch to fullscreen
+ MESSAGING::CApplicationMessenger::GetInstance().PostMsg(TMSG_SWITCHTOFULLSCREEN);
+
+ // Initialize gameplay
CreatePlayback(m_gameServices.GameSettings().AutosaveEnabled());
RegisterWindowCallbacks();
- SetSpeedInternal(1.0);
+ m_playbackControl.reset(new CGUIPlaybackControl(*this));
m_callback.OnPlayBackStarted(fileCopy);
m_callback.OnAVStarted(fileCopy);
if (!bStandalone)
m_autoSave.reset(new CRetroPlayerAutoSave(*this, m_gameServices.GameSettings()));
+
+ // Set video framerate
m_processInfo->SetVideoFps(static_cast<float>(m_gameClient->GetFrameRate()));
}
else
@@ -198,6 +206,8 @@ bool CRetroPlayer::CloseFile(bool reopen /* = false */)
UnregisterWindowCallbacks();
+ m_playbackControl.reset();
+
CSingleLock lock(m_mutex);
if (m_gameClient && m_gameServices.GameSettings().AutosaveEnabled())
@@ -329,7 +339,6 @@ void CRetroPlayer::SeekTime(int64_t iTime /* = 0 */)
return;
m_playback->SeekTimeMs(static_cast<unsigned int>(iTime));
- OnSpeedChange(m_playback->GetSpeed());
}
bool CRetroPlayer::SeekTimeRelative(int64_t iTime)
@@ -360,9 +369,24 @@ void CRetroPlayer::SetSpeed(float speed)
m_callback.OnPlayBackResumed();
else if (speed == 0.0f)
m_callback.OnPlayBackPaused();
- }
- SetSpeedInternal(static_cast<double>(speed));
+ SetSpeedInternal(static_cast<double>(speed));
+
+ if (speed == 0.0f)
+ {
+ const int dialogId = CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindowOrDialog();
+ if (dialogId == WINDOW_FULLSCREEN_GAME)
+ {
+ CLog::Log(LOGDEBUG, "RetroPlayer[PLAYER]: Opening OSD via speed change (%f)", speed);
+ OpenOSD();
+ }
+ }
+ else
+ {
+ CLog::Log(LOGDEBUG, "RetroPlayer[PLAYER]: Closing OSD via speed change (%f)", speed);
+ CloseOSD();
+ }
+ }
}
bool CRetroPlayer::OnAction(const CAction &action)
@@ -392,7 +416,7 @@ bool CRetroPlayer::OnAction(const CAction &action)
}
case ACTION_SHOW_OSD:
{
- if (m_gameClient && m_playback->GetSpeed() == 0.0)
+ if (m_gameClient)
{
CLog::Log(LOGDEBUG, "RetroPlayer[PLAYER]: Closing OSD via ACTION_SHOW_OSD");
CloseOSD();
@@ -432,63 +456,11 @@ void CRetroPlayer::FrameMove()
if (m_renderManager)
m_renderManager->FrameMove();
- if (m_gameClient)
- {
- const int activeId = CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindowOrDialog();
- const bool bFullscreen = (activeId == WINDOW_FULLSCREEN_GAME);
-
- switch (m_state)
- {
- case State::STARTING:
- {
- if (bFullscreen)
- m_state = State::FULLSCREEN;
- break;
- }
- case State::FULLSCREEN:
- {
- if (!bFullscreen)
- {
- m_priorSpeed = m_playback->GetSpeed();
-
- if (m_priorSpeed != 0.0)
- {
- IPlayerCallback *callback = &m_callback;
- CJobManager::GetInstance().Submit([callback]()
- {
- callback->OnPlayBackPaused();
- }, CJob::PRIORITY_NORMAL);
- }
-
- SetSpeedInternal(0.0);
-
- m_state = State::BACKGROUND;
- }
- break;
- }
- case State::BACKGROUND:
- {
- if (bFullscreen)
- {
- if (m_playback->GetSpeed() == 0.0 && m_priorSpeed != 0.0)
- {
- IPlayerCallback *callback = &m_callback;
- CJobManager::GetInstance().Submit([callback]()
- {
- callback->OnPlayBackResumed();
- }, CJob::PRIORITY_NORMAL);
-
- SetSpeedInternal(m_priorSpeed);
- }
-
- m_state = State::FULLSCREEN;
- }
- break;
- }
- }
+ if (m_playbackControl)
+ m_playbackControl->FrameMove();
+ if (m_processInfo)
m_processInfo->SetPlayTimes(0, GetTime(), 0, GetTotalTime());
- }
}
void CRetroPlayer::Render(bool clear, uint32_t alpha /* = 255 */, bool gui /* = true */)
@@ -509,6 +481,40 @@ std::string CRetroPlayer::GameClientID() const
return "";
}
+void CRetroPlayer::SetPlaybackSpeed(double speed)
+{
+ if (m_playback)
+ {
+ if (m_playback->GetSpeed() != speed)
+ {
+ if (speed == 1.0)
+ {
+ IPlayerCallback *callback = &m_callback;
+ CJobManager::GetInstance().Submit([callback]()
+ {
+ callback->OnPlayBackResumed();
+ }, CJob::PRIORITY_NORMAL);
+ }
+ else if (speed == 0.0)
+ {
+ IPlayerCallback *callback = &m_callback;
+ CJobManager::GetInstance().Submit([callback]()
+ {
+ callback->OnPlayBackPaused();
+ }, CJob::PRIORITY_NORMAL);
+ }
+ }
+ }
+
+ SetSpeedInternal(speed);
+}
+
+void CRetroPlayer::EnableInput(bool bEnable)
+{
+ if (m_input)
+ m_input->EnableInput(bEnable);
+}
+
bool CRetroPlayer::IsAutoSaveEnabled() const
{
return m_playback->GetSpeed() > 0.0;
@@ -535,11 +541,6 @@ void CRetroPlayer::OnSpeedChange(double newSpeed)
m_input->SetSpeed(newSpeed);
m_renderManager->SetSpeed(newSpeed);
m_processInfo->SetSpeed(static_cast<float>(newSpeed));
- if (newSpeed != 0.0)
- {
- CLog::Log(LOGDEBUG, "RetroPlayer[PLAYER]: Closing OSD via speed change (%f)", newSpeed);
- CloseOSD();
- }
}
void CRetroPlayer::CreatePlayback(bool bRestoreState)
@@ -576,6 +577,11 @@ void CRetroPlayer::ResetPlayback()
m_playback.reset(new CRealtimePlayback);
}
+void CRetroPlayer::OpenOSD()
+{
+ CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(WINDOW_DIALOG_GAME_OSD);
+}
+
void CRetroPlayer::CloseOSD()
{
CServiceBroker::GetGUI()->GetWindowManager().CloseDialogs(true);
diff --git a/xbmc/cores/RetroPlayer/RetroPlayer.h b/xbmc/cores/RetroPlayer/RetroPlayer.h
index 3355c37931..e905b05dac 100644
--- a/xbmc/cores/RetroPlayer/RetroPlayer.h
+++ b/xbmc/cores/RetroPlayer/RetroPlayer.h
@@ -10,6 +10,7 @@
#include "RetroPlayerAutoSave.h"
#include "cores/RetroPlayer/guibridge/IGameCallback.h"
+#include "cores/RetroPlayer/playback/IPlaybackControl.h"
#include "cores/IPlayer.h"
#include "games/GameTypes.h"
#include "guilib/DispResource.h"
@@ -35,6 +36,7 @@ namespace RETRO
class CRetroPlayer : public IPlayer,
public IRenderLoop,
public IGameCallback,
+ public IPlaybackCallback,
public IAutoSaveCallback
{
public:
@@ -68,6 +70,10 @@ namespace RETRO
// Implementation of IGameCallback
std::string GameClientID() const override;
+ // Implementation of IPlaybackCallback
+ void SetPlaybackSpeed(double speed) override;
+ void EnableInput(bool bEnable) override;
+
// Implementation of IAutoSaveCallback
bool IsAutoSaveEnabled() const override;
std::string CreateSavestate() override;
@@ -86,6 +92,11 @@ namespace RETRO
void ResetPlayback();
/*!
+ * \brief Opens the OSD
+ */
+ void OpenOSD();
+
+ /*!
* \brief Closes the OSD and shows the FullscreenGame window
*/
void CloseOSD();
@@ -104,22 +115,19 @@ namespace RETRO
// Construction parameters
GAME::CGameServices &m_gameServices;
- enum class State
- {
- STARTING,
- FULLSCREEN,
- BACKGROUND,
- };
-
- State m_state = State::STARTING;
- double m_priorSpeed = 0.0f; // Speed of gameplay before entering OSD
+ // Subsystems
std::unique_ptr<CRPProcessInfo> m_processInfo;
std::unique_ptr<CRPRenderManager> m_renderManager;
std::unique_ptr<CRPStreamManager> m_streamManager;
std::unique_ptr<CRetroPlayerInput> m_input;
std::unique_ptr<IPlayback> m_playback;
+ std::unique_ptr<IPlaybackControl> m_playbackControl;
std::unique_ptr<CRetroPlayerAutoSave> m_autoSave;
+
+ // Game parameters
GAME::GameClientPtr m_gameClient;
+
+ // Synchronization parameters
CCriticalSection m_mutex;
};
}
diff --git a/xbmc/cores/RetroPlayer/RetroPlayerInput.cpp b/xbmc/cores/RetroPlayer/RetroPlayerInput.cpp
index b048f4b182..49153aa5e6 100644
--- a/xbmc/cores/RetroPlayer/RetroPlayerInput.cpp
+++ b/xbmc/cores/RetroPlayer/RetroPlayerInput.cpp
@@ -37,6 +37,11 @@ void CRetroPlayerInput::SetSpeed(double speed)
m_inputPollHandle->Deactivate();
}
+void CRetroPlayerInput::EnableInput(bool bEnabled)
+{
+ m_bEnabled = bEnabled;
+}
+
void CRetroPlayerInput::PollInput()
{
m_inputPollHandle->HandleEvents(true);
diff --git a/xbmc/cores/RetroPlayer/RetroPlayerInput.h b/xbmc/cores/RetroPlayer/RetroPlayerInput.h
index a3d960447d..98066e2220 100644
--- a/xbmc/cores/RetroPlayer/RetroPlayerInput.h
+++ b/xbmc/cores/RetroPlayer/RetroPlayerInput.h
@@ -27,8 +27,10 @@ namespace RETRO
~CRetroPlayerInput() override;
void SetSpeed(double speed);
+ void EnableInput(bool bEnabled);
- // implementation of IGameAudioCallback
+ // implementation of IGameInputCallback
+ bool AcceptsInput() const override { return m_bEnabled; }
void PollInput() override;
private:
@@ -37,6 +39,7 @@ namespace RETRO
// Input variables
PERIPHERALS::EventPollHandlePtr m_inputPollHandle;
+ bool m_bEnabled = false;
};
}
}
diff --git a/xbmc/cores/RetroPlayer/guiplayback/CMakeLists.txt b/xbmc/cores/RetroPlayer/guiplayback/CMakeLists.txt
new file mode 100644
index 0000000000..47501115cc
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/guiplayback/CMakeLists.txt
@@ -0,0 +1,7 @@
+set(SOURCES GUIPlaybackControl.cpp
+)
+
+set(HEADERS GUIPlaybackControl.h
+)
+
+core_add_library(retroplayer_guiplayback)
diff --git a/xbmc/cores/RetroPlayer/guiplayback/GUIPlaybackControl.cpp b/xbmc/cores/RetroPlayer/guiplayback/GUIPlaybackControl.cpp
new file mode 100644
index 0000000000..6458312793
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/guiplayback/GUIPlaybackControl.cpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "GUIPlaybackControl.h"
+#include "games/dialogs/osd/DialogGameOSD.h"
+#include "guilib/GUIComponent.h"
+#include "guilib/GUIWindowManager.h"
+#include "ServiceBroker.h"
+
+using namespace KODI;
+using namespace RETRO;
+
+CGUIPlaybackControl::CGUIPlaybackControl(IPlaybackCallback &callback) :
+ m_callback(callback)
+{
+}
+
+CGUIPlaybackControl::~CGUIPlaybackControl() = default;
+
+void CGUIPlaybackControl::FrameMove()
+{
+ CGUIComponent *gui = CServiceBroker::GetGUI();
+ if (gui == nullptr)
+ return;
+
+ const int windowId = gui->GetWindowManager().GetActiveWindow();
+ const int dialogId = gui->GetWindowManager().GetActiveWindowOrDialog();
+
+ // Check if game has entered fullscreen yet
+ const bool bFullscreen = (windowId == WINDOW_FULLSCREEN_GAME);
+
+ // Check if game is in the OSD dialog
+ const bool bInMenu = (dialogId != WINDOW_FULLSCREEN_GAME);
+
+ // Check if game should play in the background of dialog
+ const bool bInBackground = GAME::CDialogGameOSD::PlayInBackground(dialogId);
+
+ GuiState nextState = NextState(bFullscreen, bInMenu, bInBackground);
+ if (nextState != m_state)
+ {
+ m_state = nextState;
+
+ double targetSpeed = GetTargetSpeed(m_state);
+ if (m_previousSpeed != targetSpeed)
+ {
+ m_previousSpeed = targetSpeed;
+ m_callback.SetPlaybackSpeed(targetSpeed);
+ }
+
+ m_callback.EnableInput(AcceptsInput(m_state));
+ }
+}
+
+CGUIPlaybackControl::GuiState CGUIPlaybackControl::NextState(bool bFullscreen, bool bInMenu, bool bInBackground)
+{
+ GuiState newState = m_state;
+
+ switch (m_state)
+ {
+ case GuiState::UNKNOWN:
+ {
+ // Wait for game to enter fullscreen
+ if (bFullscreen)
+ newState = GuiState::FULLSCREEN;
+ break;
+ }
+ case GuiState::FULLSCREEN:
+ {
+ if (bInMenu)
+ {
+ if (bInBackground)
+ newState = GuiState::MENU_PLAYING;
+ else
+ newState = GuiState::MENU_PAUSED;
+ }
+ break;
+ }
+ case GuiState::MENU_PAUSED:
+ {
+ if (!bInMenu)
+ newState = GuiState::FULLSCREEN;
+ else if (bInBackground)
+ newState = GuiState::MENU_PLAYING;
+ break;
+ }
+ case GuiState::MENU_PLAYING:
+ {
+ if (!bInBackground)
+ {
+ if (!bInMenu)
+ newState = GuiState::FULLSCREEN;
+ else
+ newState = GuiState::MENU_PAUSED;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return newState;
+}
+
+double CGUIPlaybackControl::GetTargetSpeed(GuiState state)
+{
+ double targetSpeed = 0.0;
+
+ switch (state)
+ {
+ case GuiState::FULLSCREEN:
+ {
+ targetSpeed = 1.0;
+ break;
+ }
+ case GuiState::MENU_PAUSED:
+ {
+ targetSpeed = 0.0;
+ break;
+ }
+ case GuiState::MENU_PLAYING:
+ {
+ targetSpeed = 1.0;
+ break;
+ }
+ default:
+ break;
+ }
+
+ return targetSpeed;
+}
+
+bool CGUIPlaybackControl::AcceptsInput(GuiState state)
+{
+ bool bEnableInput = false;
+
+ switch (state)
+ {
+ case GuiState::FULLSCREEN:
+ {
+ bEnableInput = true;
+ break;
+ }
+ default:
+ break;
+ }
+
+ return bEnableInput;
+}
diff --git a/xbmc/cores/RetroPlayer/guiplayback/GUIPlaybackControl.h b/xbmc/cores/RetroPlayer/guiplayback/GUIPlaybackControl.h
new file mode 100644
index 0000000000..496a58ece2
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/guiplayback/GUIPlaybackControl.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "cores/RetroPlayer/playback/IPlaybackControl.h"
+
+namespace KODI
+{
+namespace RETRO
+{
+ /*!
+ * \brief Class to control playback by monitoring OSD status
+ */
+ class CGUIPlaybackControl : public IPlaybackControl
+ {
+ public:
+ CGUIPlaybackControl(IPlaybackCallback &callback);
+
+ ~CGUIPlaybackControl() override;
+
+ // Implementation of IPlaybackControl
+ void FrameMove() override;
+
+ private:
+ enum class GuiState
+ {
+ UNKNOWN,
+ FULLSCREEN,
+ MENU_PAUSED,
+ MENU_PLAYING,
+ };
+
+ // Helper functions
+ GuiState NextState(bool bFullscreen, bool bInMenu, bool bInBackground);
+ static double GetTargetSpeed(GuiState state);
+ static bool AcceptsInput(GuiState state);
+
+ // Construction parameters
+ IPlaybackCallback &m_callback;
+
+ // State parameters
+ GuiState m_state = GuiState::UNKNOWN;
+ double m_previousSpeed = 0.0;
+ };
+}
+}
diff --git a/xbmc/cores/RetroPlayer/guiwindows/GameWindowFullScreen.cpp b/xbmc/cores/RetroPlayer/guiwindows/GameWindowFullScreen.cpp
index 33e7d79b3b..fb575526d0 100644
--- a/xbmc/cores/RetroPlayer/guiwindows/GameWindowFullScreen.cpp
+++ b/xbmc/cores/RetroPlayer/guiwindows/GameWindowFullScreen.cpp
@@ -11,6 +11,8 @@
#include "cores/RetroPlayer/guibridge/GUIGameRenderManager.h"
#include "cores/RetroPlayer/guibridge/GUIRenderHandle.h"
#include "windowing/GraphicContext.h" //! @todo Remove me
+#include "games/GameServices.h"
+#include "games/GameSettings.h"
#include "guilib/GUIDialog.h"
#include "guilib/GUIControl.h"
#include "guilib/GUIComponent.h"
@@ -177,6 +179,11 @@ void CGameWindowFullScreen::OnInitWindow()
CServiceBroker::GetWinSystem()->GetGfxContext().SetFullScreenVideo(true); //! @todo
CGUIWindow::OnInitWindow();
+
+ // Show OSD help
+ GAME::CGameSettings &gameSettings = CServiceBroker::GetGameServices().GameSettings();
+ if (gameSettings.ShowOSDHelp())
+ TriggerOSD();
}
void CGameWindowFullScreen::OnDeinitWindow(int nextWindowID)
diff --git a/xbmc/cores/RetroPlayer/playback/CMakeLists.txt b/xbmc/cores/RetroPlayer/playback/CMakeLists.txt
index 4f834939eb..058522f36e 100644
--- a/xbmc/cores/RetroPlayer/playback/CMakeLists.txt
+++ b/xbmc/cores/RetroPlayer/playback/CMakeLists.txt
@@ -1,9 +1,10 @@
-set(SOURCES ReversiblePlayback.cpp
- GameLoop.cpp)
+set(SOURCES GameLoop.cpp
+ ReversiblePlayback.cpp)
-set(HEADERS RealtimePlayback.h
- ReversiblePlayback.h
- GameLoop.h
- IPlayback.h)
+set(HEADERS GameLoop.h
+ IPlayback.h
+ IPlaybackControl.h
+ RealtimePlayback.h
+ ReversiblePlayback.h)
core_add_library(retroplayer_playback)
diff --git a/xbmc/cores/RetroPlayer/playback/IPlaybackControl.h b/xbmc/cores/RetroPlayer/playback/IPlaybackControl.h
new file mode 100644
index 0000000000..598dea9a79
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/playback/IPlaybackControl.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+namespace KODI
+{
+namespace RETRO
+{
+ /*!
+ * \brief The playback client being controlled
+ */
+ class IPlaybackCallback
+ {
+ public:
+ virtual ~IPlaybackCallback() = default;
+
+ /*!
+ * \brief Set the playback speed
+ *
+ * \param speed The new speed
+ */
+ virtual void SetPlaybackSpeed(double speed) = 0;
+
+ /*!
+ * \brief Enable/disable game input
+ *
+ * \param bEnable True to enable input, false to disable input
+ */
+ virtual void EnableInput(bool bEnable) = 0;
+ };
+
+ /*!
+ * \brief Class that can control playback and input
+ */
+ class IPlaybackControl
+ {
+ public:
+ virtual ~IPlaybackControl() = default;
+
+ /*!
+ * \brief Called every frame
+ */
+ virtual void FrameMove() = 0;
+ };
+}
+}
diff --git a/xbmc/cores/RetroPlayer/rendering/RPRenderManager.cpp b/xbmc/cores/RetroPlayer/rendering/RPRenderManager.cpp
index 6bb82f80a6..ac2887cd84 100644
--- a/xbmc/cores/RetroPlayer/rendering/RPRenderManager.cpp
+++ b/xbmc/cores/RetroPlayer/rendering/RPRenderManager.cpp
@@ -19,7 +19,6 @@
#include "cores/RetroPlayer/process/RPProcessInfo.h"
#include "cores/RetroPlayer/rendering/VideoRenderers/RPBaseRenderer.h"
#include "utils/TransformMatrix.h"
-#include "messaging/ApplicationMessenger.h"
#include "threads/SingleLock.h"
#include "utils/Color.h"
#include "utils/log.h"
@@ -232,8 +231,6 @@ void CRPRenderManager::FrameMove()
{
m_processInfo.ConfigureRenderSystem(m_format);
- MESSAGING::CApplicationMessenger::GetInstance().PostMsg(TMSG_SWITCHTOFULLSCREEN);
-
m_state = RENDER_STATE::CONFIGURED;
CLog::Log(LOGINFO, "RetroPlayer[RENDER]: Renderer configured on first frame");
diff --git a/xbmc/games/GameSettings.cpp b/xbmc/games/GameSettings.cpp
index 8fa53417d7..6684ffc07f 100644
--- a/xbmc/games/GameSettings.cpp
+++ b/xbmc/games/GameSettings.cpp
@@ -19,6 +19,7 @@ using namespace GAME;
namespace
{
const std::string SETTING_GAMES_ENABLE = "gamesgeneral.enable";
+ const std::string SETTING_GAMES_SHOW_OSD_HELP = "gamesgeneral.showosdhelp";
const std::string SETTING_GAMES_ENABLEAUTOSAVE = "gamesgeneral.enableautosave";
const std::string SETTING_GAMES_ENABLEREWIND = "gamesgeneral.enablerewind";
const std::string SETTING_GAMES_REWINDTIME = "gamesgeneral.rewindtime";
@@ -44,6 +45,22 @@ bool CGameSettings::GamesEnabled()
return m_settings->GetBool(SETTING_GAMES_ENABLE);
}
+bool CGameSettings::ShowOSDHelp()
+{
+ return m_settings->GetBool(SETTING_GAMES_SHOW_OSD_HELP);
+}
+
+void CGameSettings::SetShowOSDHelp(bool bShow)
+{
+ if (m_settings->GetBool(SETTING_GAMES_SHOW_OSD_HELP) != bShow)
+ {
+ m_settings->SetBool(SETTING_GAMES_SHOW_OSD_HELP, bShow);
+
+ //! @todo Asynchronous save
+ m_settings->Save();
+ }
+}
+
void CGameSettings::ToggleGames()
{
m_settings->ToggleBool(SETTING_GAMES_ENABLE);
diff --git a/xbmc/games/GameSettings.h b/xbmc/games/GameSettings.h
index dd746eec47..795824ced1 100644
--- a/xbmc/games/GameSettings.h
+++ b/xbmc/games/GameSettings.h
@@ -28,6 +28,8 @@ public:
// General settings
bool GamesEnabled();
+ bool ShowOSDHelp();
+ void SetShowOSDHelp(bool bShow);
void ToggleGames();
bool AutosaveEnabled();
bool RewindEnabled();
diff --git a/xbmc/games/addons/GameClient.cpp b/xbmc/games/addons/GameClient.cpp
index e8af4e8f09..0ac2828385 100644
--- a/xbmc/games/addons/GameClient.cpp
+++ b/xbmc/games/addons/GameClient.cpp
@@ -313,7 +313,7 @@ bool CGameClient::InitializeGameplay(const std::string& gamePath, RETRO::IStream
{
if (LoadGameInfo())
{
- Input().Start();
+ Input().Start(input);
m_bIsPlaying = true;
m_gamePath = gamePath;
diff --git a/xbmc/games/addons/GameClientCallbacks.h b/xbmc/games/addons/GameClientCallbacks.h
index 169597e2c0..5a93f9b63c 100644
--- a/xbmc/games/addons/GameClientCallbacks.h
+++ b/xbmc/games/addons/GameClientCallbacks.h
@@ -12,11 +12,26 @@ namespace KODI
{
namespace GAME
{
+ /*!
+ * \brief Input callbacks
+ *
+ * @todo Remove this file when Game API is updated for input polling
+ */
class IGameInputCallback
{
public:
virtual ~IGameInputCallback() = default;
+ /*!
+ * \brief Return true if the input source accepts input
+ *
+ * \return True if input should be processed, false otherwise
+ */
+ virtual bool AcceptsInput() const = 0;
+
+ /*!
+ * \brief Poll the input source for input
+ */
virtual void PollInput() = 0;
};
}
diff --git a/xbmc/games/addons/input/GameClientInput.cpp b/xbmc/games/addons/input/GameClientInput.cpp
index a8e0389ca5..3fcdf190af 100644
--- a/xbmc/games/addons/input/GameClientInput.cpp
+++ b/xbmc/games/addons/input/GameClientInput.cpp
@@ -15,12 +15,10 @@
#include "GameClientTopology.h"
#include "addons/kodi-addon-dev-kit/include/kodi/kodi_game_types.h"
#include "games/addons/GameClient.h"
+#include "games/addons/GameClientCallbacks.h"
#include "games/controllers/Controller.h"
#include "games/controllers/ControllerTopology.h"
#include "games/GameServices.h"
-#include "guilib/GUIComponent.h"
-#include "guilib/GUIWindowManager.h"
-#include "guilib/WindowIDs.h"
#include "input/joysticks/JoystickTypes.h"
#include "peripherals/EventLockHandle.h"
#include "peripherals/Peripherals.h"
@@ -50,8 +48,10 @@ void CGameClientInput::Initialize()
LoadTopology();
}
-void CGameClientInput::Start()
+void CGameClientInput::Start(IGameInputCallback *input)
{
+ m_inputCallback = input;
+
// Open keyboard
//! @todo Move to player manager
if (SupportsKeyboard())
@@ -113,11 +113,16 @@ void CGameClientInput::Stop()
CloseMouse();
CloseKeyboard();
+
+ m_inputCallback = nullptr;
}
bool CGameClientInput::AcceptsInput() const
{
- return CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindowOrDialog() == WINDOW_FULLSCREEN_GAME;
+ if (m_inputCallback != nullptr)
+ return m_inputCallback->AcceptsInput();
+
+ return false;
}
void CGameClientInput::LoadTopology()
diff --git a/xbmc/games/addons/input/GameClientInput.h b/xbmc/games/addons/input/GameClientInput.h
index 45de53141d..b35836e147 100644
--- a/xbmc/games/addons/input/GameClientInput.h
+++ b/xbmc/games/addons/input/GameClientInput.h
@@ -35,6 +35,7 @@ namespace GAME
class CGameClientJoystick;
class CGameClientKeyboard;
class CGameClientMouse;
+ class IGameInputCallback;
class CGameClientInput : protected CGameClientSubsystem,
public Observer
@@ -48,7 +49,7 @@ namespace GAME
void Initialize();
void Deinitialize();
- void Start();
+ void Start(IGameInputCallback *input);
void Stop();
// Input functions
@@ -98,6 +99,7 @@ namespace GAME
static ControllerVector GetControllers(const CGameClient &gameClient);
// Input properties
+ IGameInputCallback *m_inputCallback = nullptr;
CControllerTree m_controllers;
JoystickMap m_joysticks;
PortMap m_portMap;
diff --git a/xbmc/games/dialogs/osd/CMakeLists.txt b/xbmc/games/dialogs/osd/CMakeLists.txt
index c0bf01c323..5fd669130f 100644
--- a/xbmc/games/dialogs/osd/CMakeLists.txt
+++ b/xbmc/games/dialogs/osd/CMakeLists.txt
@@ -1,5 +1,6 @@
set(SOURCES DialogGameAdvancedSettings.cpp
DialogGameOSD.cpp
+ DialogGameOSDHelp.cpp
DialogGameStretchMode.cpp
DialogGameVideoFilter.cpp
DialogGameVideoRotation.cpp
@@ -9,6 +10,7 @@ set(SOURCES DialogGameAdvancedSettings.cpp
set(HEADERS DialogGameAdvancedSettings.h
DialogGameOSD.h
+ DialogGameOSDHelp.h
DialogGameStretchMode.h
DialogGameVideoFilter.h
DialogGameVideoRotation.h
diff --git a/xbmc/games/dialogs/osd/DialogGameOSD.cpp b/xbmc/games/dialogs/osd/DialogGameOSD.cpp
index d684a6ac1e..2aaaf0bc52 100644
--- a/xbmc/games/dialogs/osd/DialogGameOSD.cpp
+++ b/xbmc/games/dialogs/osd/DialogGameOSD.cpp
@@ -7,14 +7,75 @@
*/
#include "DialogGameOSD.h"
+#include "DialogGameOSDHelp.h"
+#include "games/GameServices.h"
+#include "games/GameSettings.h"
#include "guilib/WindowIDs.h"
+#include "input/Action.h"
+#include "input/ActionIDs.h"
+#include "ServiceBroker.h"
using namespace KODI;
using namespace GAME;
CDialogGameOSD::CDialogGameOSD() :
- CGUIDialog(WINDOW_DIALOG_GAME_OSD, "GameOSD.xml")
+ CGUIDialog(WINDOW_DIALOG_GAME_OSD, "GameOSD.xml"),
+ m_helpDialog(new CDialogGameOSDHelp(*this))
{
// Initialize CGUIWindow
m_loadType = KEEP_IN_MEMORY;
}
+
+bool CDialogGameOSD::OnAction(const CAction &action)
+{
+ switch (action.GetID())
+ {
+ case ACTION_PARENT_DIR:
+ case ACTION_PREVIOUS_MENU:
+ case ACTION_NAV_BACK:
+ case ACTION_SHOW_OSD:
+ case ACTION_PLAYER_PLAY:
+ {
+ // Disable OSD help if visible
+ if (m_helpDialog->IsVisible() && CServiceBroker::IsServiceManagerUp())
+ {
+ GAME::CGameSettings &gameSettings = CServiceBroker::GetGameServices().GameSettings();
+ if (gameSettings.ShowOSDHelp())
+ {
+ gameSettings.SetShowOSDHelp(false);
+ return true;
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return CGUIDialog::OnAction(action);
+}
+
+void CDialogGameOSD::OnInitWindow()
+{
+ // Init parent class
+ CGUIDialog::OnInitWindow();
+
+ // Init help dialog
+ m_helpDialog->OnInitWindow();
+}
+
+void CDialogGameOSD::OnDeinitWindow(int nextWindowID)
+{
+ CGUIDialog::OnDeinitWindow(nextWindowID);
+
+ if (CServiceBroker::IsServiceManagerUp())
+ {
+ GAME::CGameSettings &gameSettings = CServiceBroker::GetGameServices().GameSettings();
+ gameSettings.SetShowOSDHelp(false);
+ }
+}
+
+bool CDialogGameOSD::PlayInBackground(int dialogId)
+{
+ return dialogId == WINDOW_DIALOG_GAME_VOLUME;
+}
diff --git a/xbmc/games/dialogs/osd/DialogGameOSD.h b/xbmc/games/dialogs/osd/DialogGameOSD.h
index f567b2e48d..7a4cc77dfd 100644
--- a/xbmc/games/dialogs/osd/DialogGameOSD.h
+++ b/xbmc/games/dialogs/osd/DialogGameOSD.h
@@ -10,16 +10,45 @@
#include "guilib/GUIDialog.h"
+#include <memory>
+
namespace KODI
{
namespace GAME
{
+ class CDialogGameOSDHelp;
+
class CDialogGameOSD : public CGUIDialog
{
public:
CDialogGameOSD();
~CDialogGameOSD() override = default;
+
+ // Implementation of CGUIControl via CGUIDialog
+ bool OnAction(const CAction &action) override;
+
+ // Implementation of CGUIWindow via CGUIDialog
+ void OnDeinitWindow(int nextWindowID) override;
+
+ /*!
+ * \brief Decide if the game should play behind the given dialog
+ *
+ * If true, the game should be played at regular speed.
+ *
+ * \param dialog The current dialog
+ *
+ * \return True if the game should be played at regular speed behind the
+ * dialog, false otherwise
+ */
+ static bool PlayInBackground(int dialogId);
+
+ protected:
+ // Implementation of CGUIWindow via CGUIDialog
+ void OnInitWindow() override;
+
+ private:
+ std::unique_ptr<CDialogGameOSDHelp> m_helpDialog;
};
}
}
diff --git a/xbmc/games/dialogs/osd/DialogGameOSDHelp.cpp b/xbmc/games/dialogs/osd/DialogGameOSDHelp.cpp
new file mode 100644
index 0000000000..79c23fe9da
--- /dev/null
+++ b/xbmc/games/dialogs/osd/DialogGameOSDHelp.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "DialogGameOSDHelp.h"
+#include "DialogGameOSD.h"
+#include "games/controllers/guicontrols/GUIGameController.h"
+#include "games/GameServices.h"
+#include "guilib/GUIMessage.h"
+#include "guilib/LocalizeStrings.h"
+#include "guilib/WindowIDs.h"
+#include "utils/StringUtils.h"
+#include "ServiceBroker.h"
+
+using namespace KODI;
+using namespace GAME;
+
+const int CDialogGameOSDHelp::CONTROL_ID_HELP_TEXT = 1101;
+const int CDialogGameOSDHelp::CONTROL_ID_GAME_CONTROLLER = 1102;
+
+CDialogGameOSDHelp::CDialogGameOSDHelp(CDialogGameOSD &dialog) :
+ m_dialog(dialog)
+{
+}
+
+void CDialogGameOSDHelp::OnInitWindow()
+{
+ // Set help text
+ //! @todo Define Select + X combo elsewhere
+ // "Press {0:s} to open the menu."
+ std::string helpText = StringUtils::Format(g_localizeStrings.Get(35235), "Select + X");
+
+ CGUIMessage msg(GUI_MSG_LABEL_SET, WINDOW_DIALOG_GAME_OSD, CONTROL_ID_HELP_TEXT);
+ msg.SetLabel(helpText);
+ m_dialog.OnMessage(msg);
+
+ // Set controller
+ if (CServiceBroker::IsServiceManagerUp())
+ {
+ CGameServices& gameServices = CServiceBroker::GetGameServices();
+
+ //! @todo Define SNES controller elsewhere
+ ControllerPtr controller = gameServices.GetController("game.controller.snes");
+ if (controller)
+ {
+ //! @todo Activate controller for all game controller controls
+ CGUIGameController* guiController = dynamic_cast<CGUIGameController*>(m_dialog.GetControl(CONTROL_ID_GAME_CONTROLLER));
+ if (guiController != nullptr)
+ guiController->ActivateController(controller);
+ }
+ }
+}
+
+bool CDialogGameOSDHelp::IsVisible()
+{
+ return IsVisible(CONTROL_ID_HELP_TEXT) ||
+ IsVisible(CONTROL_ID_GAME_CONTROLLER);
+}
+
+bool CDialogGameOSDHelp::IsVisible(int windowId)
+{
+ CGUIControl *control = m_dialog.GetControl(windowId);
+ if (control != nullptr)
+ return control->IsVisible();
+
+ return false;
+}
diff --git a/xbmc/games/dialogs/osd/DialogGameOSDHelp.h b/xbmc/games/dialogs/osd/DialogGameOSDHelp.h
new file mode 100644
index 0000000000..3e8d37b4ac
--- /dev/null
+++ b/xbmc/games/dialogs/osd/DialogGameOSDHelp.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+namespace KODI
+{
+namespace GAME
+{
+ class CDialogGameOSD;
+
+ class CDialogGameOSDHelp
+ {
+ public:
+ CDialogGameOSDHelp(CDialogGameOSD &dialog);
+
+ // Initialize help controls
+ void OnInitWindow();
+
+ // Check if any help controls are visible
+ bool IsVisible();
+
+ private:
+ // Utility functions
+ bool IsVisible(int windowId);
+
+ // Construction parameters
+ CDialogGameOSD &m_dialog;
+
+ // Help control IDs
+ static const int CONTROL_ID_HELP_TEXT;
+ static const int CONTROL_ID_GAME_CONTROLLER;
+ };
+}
+}