diff options
author | Garrett Brown <themagnificentmrb@gmail.com> | 2018-09-11 13:56:05 -0700 |
---|---|---|
committer | Garrett Brown <themagnificentmrb@gmail.com> | 2018-09-20 16:53:26 +0200 |
commit | 655373fcba24c00e25e038025e53af34b5186766 (patch) | |
tree | 32dc80b8978b7612e90167e10f734c5f3dc42374 | |
parent | c945a6a7b96abdb8467a6807bea1bd1f767c40f2 (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.
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; + }; +} +} |