diff options
author | tamland <thomas.amland@gmail.com> | 2016-07-17 10:22:23 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-07-17 10:22:23 +0200 |
commit | d071db22e1a68567b79d43093c3f7c67283fb707 (patch) | |
tree | fbcd9c55d06fd7c9faaf1780d852df89d6f6aa53 | |
parent | 0dd39fccd851def055034c4f99cac6d6c116a208 (diff) | |
parent | 0a0b8065aed03f8c839c14d8e56e18174f3efb2b (diff) |
Merge pull request #10060 from tamland/addon_screenshots
[addons] screeshot support
36 files changed, 348 insertions, 211 deletions
diff --git a/addons/skin.estouchy/addon.xml b/addons/skin.estouchy/addon.xml index de49fa667d..f227eb9ed5 100644 --- a/addons/skin.estouchy/addon.xml +++ b/addons/skin.estouchy/addon.xml @@ -74,5 +74,21 @@ <website></website> <email></email> <source>https://github.com/xbmc/skin.estouchy/</source> + <assets> + <icon>resources/icon.png</icon> + <fanart>resources/fanart.jpg</fanart> + <screenshot>resources/screenshot-01.jpg</screenshot> + <screenshot>resources/screenshot-02.jpg</screenshot> + <screenshot>resources/screenshot-03.jpg</screenshot> + <screenshot>resources/screenshot-04.jpg</screenshot> + <screenshot>resources/screenshot-05.jpg</screenshot> + <screenshot>resources/screenshot-06.jpg</screenshot> + <screenshot>resources/screenshot-07.jpg</screenshot> + <screenshot>resources/screenshot-08.jpg</screenshot> + <screenshot>resources/screenshot-09.jpg</screenshot> + <screenshot>resources/screenshot-10.jpg</screenshot> + <screenshot>resources/screenshot-11.jpg</screenshot> + <screenshot>resources/screenshot-12.jpg</screenshot> + </assets> </extension> </addon> diff --git a/addons/skin.estouchy/fanart.jpg b/addons/skin.estouchy/resources/fanart.jpg Binary files differindex 1f4d5d934f..1f4d5d934f 100644 --- a/addons/skin.estouchy/fanart.jpg +++ b/addons/skin.estouchy/resources/fanart.jpg diff --git a/addons/skin.estouchy/icon.png b/addons/skin.estouchy/resources/icon.png Binary files differindex 7714c72d65..7714c72d65 100644 --- a/addons/skin.estouchy/icon.png +++ b/addons/skin.estouchy/resources/icon.png diff --git a/addons/skin.estouchy/resources/screenshot-01.jpg b/addons/skin.estouchy/resources/screenshot-01.jpg Binary files differnew file mode 100644 index 0000000000..91ad9b5234 --- /dev/null +++ b/addons/skin.estouchy/resources/screenshot-01.jpg diff --git a/addons/skin.estouchy/resources/screenshot-02.jpg b/addons/skin.estouchy/resources/screenshot-02.jpg Binary files differnew file mode 100644 index 0000000000..e184527f50 --- /dev/null +++ b/addons/skin.estouchy/resources/screenshot-02.jpg diff --git a/addons/skin.estouchy/resources/screenshot-03.jpg b/addons/skin.estouchy/resources/screenshot-03.jpg Binary files differnew file mode 100644 index 0000000000..7b464acb45 --- /dev/null +++ b/addons/skin.estouchy/resources/screenshot-03.jpg diff --git a/addons/skin.estouchy/resources/screenshot-04.jpg b/addons/skin.estouchy/resources/screenshot-04.jpg Binary files differnew file mode 100644 index 0000000000..8075153def --- /dev/null +++ b/addons/skin.estouchy/resources/screenshot-04.jpg diff --git a/addons/skin.estouchy/resources/screenshot-05.jpg b/addons/skin.estouchy/resources/screenshot-05.jpg Binary files differnew file mode 100644 index 0000000000..3fcfd51ad0 --- /dev/null +++ b/addons/skin.estouchy/resources/screenshot-05.jpg diff --git a/addons/skin.estouchy/resources/screenshot-06.jpg b/addons/skin.estouchy/resources/screenshot-06.jpg Binary files differnew file mode 100644 index 0000000000..614653db06 --- /dev/null +++ b/addons/skin.estouchy/resources/screenshot-06.jpg diff --git a/addons/skin.estouchy/resources/screenshot-07.jpg b/addons/skin.estouchy/resources/screenshot-07.jpg Binary files differnew file mode 100644 index 0000000000..05c5c87aa5 --- /dev/null +++ b/addons/skin.estouchy/resources/screenshot-07.jpg diff --git a/addons/skin.estouchy/resources/screenshot-08.jpg b/addons/skin.estouchy/resources/screenshot-08.jpg Binary files differnew file mode 100644 index 0000000000..e0ed056218 --- /dev/null +++ b/addons/skin.estouchy/resources/screenshot-08.jpg diff --git a/addons/skin.estouchy/resources/screenshot-09.jpg b/addons/skin.estouchy/resources/screenshot-09.jpg Binary files differnew file mode 100644 index 0000000000..245e995450 --- /dev/null +++ b/addons/skin.estouchy/resources/screenshot-09.jpg diff --git a/addons/skin.estouchy/resources/screenshot-10.jpg b/addons/skin.estouchy/resources/screenshot-10.jpg Binary files differnew file mode 100644 index 0000000000..113a857504 --- /dev/null +++ b/addons/skin.estouchy/resources/screenshot-10.jpg diff --git a/addons/skin.estouchy/resources/screenshot-11.jpg b/addons/skin.estouchy/resources/screenshot-11.jpg Binary files differnew file mode 100644 index 0000000000..a2c09d832e --- /dev/null +++ b/addons/skin.estouchy/resources/screenshot-11.jpg diff --git a/addons/skin.estouchy/resources/screenshot-12.jpg b/addons/skin.estouchy/resources/screenshot-12.jpg Binary files differnew file mode 100644 index 0000000000..1dd782f040 --- /dev/null +++ b/addons/skin.estouchy/resources/screenshot-12.jpg diff --git a/addons/skin.estuary/1080i/DialogAddonInfo.xml b/addons/skin.estuary/1080i/DialogAddonInfo.xml index 8c15bbd80d..e236493cdd 100644 --- a/addons/skin.estuary/1080i/DialogAddonInfo.xml +++ b/addons/skin.estuary/1080i/DialogAddonInfo.xml @@ -8,37 +8,93 @@ <control type="group"> <include>OpenClose_Right</include> <control type="button"> - <left>770</left> - <top>162</top> - <width>1040</width> - <height>559</height> + <left>605</left> + <top>400</top> + <width>1235</width> + <height>375</height> <label>-</label> </control> <control type="textbox"> - <left>840</left> - <top>200</top> - <width>900</width> - <height>380</height> + <left>670</left> + <top>435</top> + <width>1050</width> + <height>300</height> <font>font_textbox</font> <label>$INFO[ListItem.AddonSummary,[B],[/B][CR]][COLOR=white]$INFO[ListItem.AddonDescription][/COLOR][COLOR=white][CR][/COLOR]</label> <textcolor>button_focus</textcolor> </control> - <control type="textbox"> - <left>840</left> - <top>610</top> - <width>900</width> - <height>70</height> - <font>font_textbox</font> - <label fallback="31008">$INFO[ListItem.AddonDisclaimer,$LOCALIZE[24052]: ]</label> - <textcolor>button_focus</textcolor> + <control type="group"> + <left>625</left> + <top>176</top> + <visible>Integer.IsEqual(Container(50).NumItems,0)</visible> + <control type="image"> + <width>385</width> + <height>220</height> + <texture border="2" background="true">DefaultNoPreview.png</texture> + <aspectratio>scale</aspectratio> + <bordertexture colordiffuse="border_alpha">colors/black.png</bordertexture> + <bordersize>4</bordersize> + </control> + <control type="image"> + <left>405</left> + <width>385</width> + <height>220</height> + <texture border="2" background="true">DefaultNoPreview.png</texture> + <aspectratio>scale</aspectratio> + <bordertexture colordiffuse="border_alpha">colors/black.png</bordertexture> + <bordersize>4</bordersize> + </control> + <control type="image"> + <left>810</left> + <width>385</width> + <height>220</height> + <texture border="2" background="true">DefaultNoPreview.png</texture> + <aspectratio>scale</aspectratio> + <bordertexture colordiffuse="border_alpha">colors/black.png</bordertexture> + <bordersize>4</bordersize> + </control> </control> - <control type="image"> - <left>790</left> - <top>600</top> - <width>1000</width> - <height>3</height> - <texture colordiffuse="button_focus" border="2">dialogs/separator-grey.png</texture> + <control type="panel" id="50"> + <left>625</left> + <top>176</top> + <width>1215</width> + <height>233</height> + <ondown>9000</ondown> + <onup>9000</onup> + <orientation>horizontal</orientation> + <itemlayout height="225" width="405"> + <control type="image"> + <width>385</width> + <height>220</height> + <texture border="2" fallback="DefaultAddonNone.png" background="true">$INFO[ListItem.Icon]</texture> + <aspectratio>scale</aspectratio> + <bordertexture colordiffuse="border_alpha">colors/black.png</bordertexture> + <bordersize>4</bordersize> + </control> + </itemlayout> + <focusedlayout height="225" width="405"> + <control type="image"> + <width>385</width> + <height>220</height> + <texture border="2" fallback="DefaultAddonNone.png" background="true">$INFO[ListItem.Icon]</texture> + <aspectratio>scale</aspectratio> + <bordertexture colordiffuse="border_alpha">colors/black.png</bordertexture> + <bordersize>4</bordersize> + </control> + <control type="image"> + <width>385</width> + <height>220</height> + <texture border="8" colordiffuse="button_focus">buttons/thumbnail_focused.png</texture> + </control> + </focusedlayout> </control> + <include content="LeftRightArrows"> + <param name="list_id" value="50" /> + <param name="left_posx" value="580" /> + <param name="right_posx" value="1840" /> + <param name="posy" value="280" /> + <param name="visible" value="true" /> + </include> <control type="grouplist" id="9000"> <left>90</left> <top>820</top> @@ -46,7 +102,7 @@ <height>300</height> <onleft>9000</onleft> <onright>9000</onright> - <onup>9000</onup> + <onup>50</onup> <ondown>9000</ondown> <align>center</align> <itemgap>-18</itemgap> @@ -97,11 +153,11 @@ </control> <control type="group"> <include>OpenClose_Left</include> - <left>120</left> + <top>158</top> + <left>80</left> <control type="image"> - <top>162</top> - <width>559</width> - <height>559</height> + <width>505</width> + <height>505</height> <aspectratio>scale</aspectratio> <texture colordiffuse="border_alpha">colors/black.png</texture> <bordertexture border="20">overlays/shadow.png</bordertexture> @@ -109,13 +165,30 @@ </control> <control type="image"> <left>24</left> - <top>186</top> - <width>511</width> - <height>511</height> + <top>24</top> + <width>457</width> + <height>457</height> <aspectratio aligny="top">scale</aspectratio> <fadetime>300</fadetime> <texture background="true" fallback="DefaultFolderSquare.png">$INFO[ListItem.Art(thumb)]</texture> </control> + <control type="button"> + <left>-3</left> + <top>490</top> + <width>511</width> + <height>128</height> + <label>-</label> + </control> + <control type="textbox"> + <left>42</left> + <top>515</top> + <width>446</width> + <height>80</height> + <font>font_textbox</font> + <label fallback="31008">$INFO[ListItem.AddonDisclaimer,$LOCALIZE[24052]: ]</label> + <textcolor>button_focus</textcolor> + <autoscroll time="2000" delay="3000" repeat="5000">true</autoscroll> + </control> <control type="group"> <visible>!String.IsEmpty(ListItem.AddonBroken)</visible> <include>OpenClose_Fade</include> diff --git a/addons/skin.estuary/1080i/SlideShow.xml b/addons/skin.estuary/1080i/SlideShow.xml index 50b6429383..bfe6d61c65 100644 --- a/addons/skin.estuary/1080i/SlideShow.xml +++ b/addons/skin.estuary/1080i/SlideShow.xml @@ -1,5 +1,3 @@ <?xml version="1.0" encoding="UTF-8"?> <window> - <defaultcontrol>2</defaultcontrol> - <controls /> </window> diff --git a/addons/skin.estuary/media/DefaultNoPreview.png b/addons/skin.estuary/media/DefaultNoPreview.png Binary files differnew file mode 100644 index 0000000000..99ccbb5dba --- /dev/null +++ b/addons/skin.estuary/media/DefaultNoPreview.png diff --git a/tools/darwin/Support/CopyRootFiles-ios.command b/tools/darwin/Support/CopyRootFiles-ios.command index 23f78bc1e5..971cac7d10 100755 --- a/tools/darwin/Support/CopyRootFiles-ios.command +++ b/tools/darwin/Support/CopyRootFiles-ios.command @@ -44,8 +44,7 @@ SYNCSKIN_A="${SKINSYNC} --exclude *.png --exclude *.jpg" fi ${SYNCSKIN_A} "$SRCROOT/addons/skin.estouchy" "$TARGET_BUILD_DIR/$TARGET_NAME/AppData/AppHome/addons" ${SYNC} "$SRCROOT/addons/skin.estouchy/background" "$TARGET_BUILD_DIR/$TARGET_NAME/AppData/AppHome/addons/skin.estouchy" -${SYNC} "$SRCROOT/addons/skin.estouchy/icon.png" "$TARGET_BUILD_DIR/$TARGET_NAME/AppData/AppHome/addons/skin.estouchy" -${SYNC} "$SRCROOT/addons/skin.estouchy/fanart.jpg" "$TARGET_BUILD_DIR/$TARGET_NAME/AppData/AppHome/addons/skin.estouchy" +${SYNC} "$SRCROOT/addons/skin.estouchy/resources" "$TARGET_BUILD_DIR/$TARGET_NAME/AppData/AppHome/addons/skin.estouchy" # sync skin.estuary SYNCSKIN_B=${SKINSYNC} diff --git a/tools/darwin/Support/CopyRootFiles-osx.command b/tools/darwin/Support/CopyRootFiles-osx.command index a4831eb3c0..2fb62b0582 100755 --- a/tools/darwin/Support/CopyRootFiles-osx.command +++ b/tools/darwin/Support/CopyRootFiles-osx.command @@ -39,8 +39,7 @@ ${SYNC} "$SRCROOT/addons/skin.estuary/icon.png" "$TARGET_BUILD_DIR/$TARGET_NAME ${SYNC} "$SRCROOT/addons/skin.estuary/fanart.jpg" "$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/$APP_NAME/addons/skin.estuary" ${SYNCSKIN} "$SRCROOT/addons/skin.estouchy" "$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/$APP_NAME/addons" ${SYNC} "$SRCROOT/addons/skin.estouchy/background" "$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/$APP_NAME/addons/skin.estouchy" -${SYNC} "$SRCROOT/addons/skin.estouchy/icon.png" "$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/$APP_NAME/addons/skin.estouchy" -${SYNC} "$SRCROOT/addons/skin.estouchy/fanart.jpg" "$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/$APP_NAME/addons/skin.estouchy" +${SYNC} "$SRCROOT/addons/skin.estouchy/resources" "$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/$APP_NAME/addons/skin.estouchy" ${SYNC} "$SRCROOT/system" "$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/$APP_NAME" ${SYNC} "$SRCROOT/userdata" "$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/$APP_NAME" diff --git a/xbmc/FileItem.cpp b/xbmc/FileItem.cpp index 21a09f5b4a..eda5cc10dd 100644 --- a/xbmc/FileItem.cpp +++ b/xbmc/FileItem.cpp @@ -1808,15 +1808,21 @@ void CFileItemList::ClearItems() m_map.clear(); } -void CFileItemList::Add(const CFileItemPtr &pItem) +void CFileItemList::Add(CFileItemPtr pItem) { CSingleLock lock(m_lock); - - m_items.push_back(pItem); if (m_fastLookup) - { m_map.insert(MAPFILEITEMSPAIR(m_ignoreURLOptions ? CURL(pItem->GetPath()).GetWithoutOptions() : pItem->GetPath(), pItem)); - } + m_items.emplace_back(std::move(pItem)); +} + +void CFileItemList::Add(CFileItem&& item) +{ + CSingleLock lock(m_lock); + auto ptr = std::make_shared<CFileItem>(std::move(item)); + if (m_fastLookup) + m_map.insert(MAPFILEITEMSPAIR(m_ignoreURLOptions ? CURL(ptr->GetPath()).GetWithoutOptions() : ptr->GetPath(), ptr)); + m_items.emplace_back(std::move(ptr)); } void CFileItemList::AddFront(const CFileItemPtr &pItem, int itemPosition) diff --git a/xbmc/FileItem.h b/xbmc/FileItem.h index 252f6c3d0b..1630072709 100644 --- a/xbmc/FileItem.h +++ b/xbmc/FileItem.h @@ -605,7 +605,8 @@ public: const CFileItemPtr operator[] (const std::string& strPath) const; void Clear(); void ClearItems(); - void Add(const CFileItemPtr &pItem); + void Add(CFileItemPtr item); + void Add(CFileItem&& item); void AddFront(const CFileItemPtr &pItem, int itemPosition); void Remove(CFileItem* pItem); void Remove(int iItem); diff --git a/xbmc/addons/Addon.h b/xbmc/addons/Addon.h index fc2b14fd4a..515afe1283 100644 --- a/xbmc/addons/Addon.h +++ b/xbmc/addons/Addon.h @@ -74,6 +74,7 @@ public: std::string icon; std::string changelog; std::string fanart; + std::vector<std::string> screenshots; std::string disclaimer; ADDONDEPS dependencies; std::string broken; @@ -109,6 +110,7 @@ public: std::string ChangeLog() const override { return m_props.changelog; } std::string FanArt() const override { return m_props.fanart; } std::string Icon() const override { return m_props.icon; }; + std::vector<std::string> Screenshots() const override { return m_props.screenshots; }; std::string Disclaimer() const override { return m_props.disclaimer; } std::string Broken() const override { return m_props.broken; } CDateTime InstallDate() const override { return m_props.installDate; } diff --git a/xbmc/addons/AddonBuilder.h b/xbmc/addons/AddonBuilder.h index 074f7ebe69..29663642d6 100644 --- a/xbmc/addons/AddonBuilder.h +++ b/xbmc/addons/AddonBuilder.h @@ -40,6 +40,7 @@ public: void SetSource(std::string source) { m_props.source = std::move(source); } void SetIcon(std::string icon) { m_props.icon = std::move(icon); } void SetFanart(std::string fanart) { m_props.fanart = std::move(fanart); } + void SetScreenshots(std::vector<std::string> screenshots) { m_props.screenshots = std::move(screenshots); } void SetChangelog(std::string changelog) { m_props.changelog = std::move(changelog); } void SetBroken(std::string broken) { m_props.broken = std::move(broken); } void SetPath(std::string path) { m_props.path = std::move(path); } diff --git a/xbmc/addons/AddonDatabase.cpp b/xbmc/addons/AddonDatabase.cpp index 6f49f14c28..0898f9b58d 100644 --- a/xbmc/addons/AddonDatabase.cpp +++ b/xbmc/addons/AddonDatabase.cpp @@ -50,6 +50,10 @@ static std::string SerializeMetadata(const IAddon& addon) variant["fanart"] = addon.FanArt(); variant["icon"] = addon.Icon(); + variant["screenshots"] = CVariant(CVariant::VariantTypeArray); + for (const auto& item : addon.Screenshots()) + variant["screenshots"].push_back(item); + variant["extensions"] = CVariant(CVariant::VariantTypeArray); variant["extensions"].push_back(ADDON::TranslateType(addon.Type(), false)); @@ -88,6 +92,11 @@ static void DeserializeMetadata(const std::string& document, CAddonBuilder& buil builder.SetFanart(variant["fanart"].asString()); builder.SetIcon(variant["icon"].asString()); + std::vector<std::string> screenshots; + for (auto it = variant["screenshots"].begin_array(); it != variant["screenshots"].end_array(); ++it) + screenshots.push_back(it->asString()); + builder.SetScreenshots(std::move(screenshots)); + builder.SetType(TranslateType(variant["extensions"][0].asString())); ADDONDEPS deps; diff --git a/xbmc/addons/AddonManager.cpp b/xbmc/addons/AddonManager.cpp index 01984c3d03..67d845f20f 100644 --- a/xbmc/addons/AddonManager.cpp +++ b/xbmc/addons/AddonManager.cpp @@ -142,13 +142,6 @@ void CAddonMgr::FillCpluffMetadata(const cp_plugin_info_t* plugin, CAddonBuilder if (plugin->provider_name) builder.SetAuthor(plugin->provider_name); - if (plugin->plugin_path && strcmp(plugin->plugin_path, "") != 0) - { - builder.SetPath(plugin->plugin_path); - builder.SetIcon(URIUtils::AddFileToFolder(plugin->plugin_path, "icon.png")); - builder.SetFanart(URIUtils::AddFileToFolder(plugin->plugin_path, "fanart.jpg")); - } - { ADDONDEPS dependencies; for (unsigned int i = 0; i < plugin->num_imports; ++i) @@ -185,10 +178,44 @@ void CAddonMgr::FillCpluffMetadata(const cp_plugin_info_t* plugin, CAddonBuilder builder.SetBroken(CAddonMgr::GetInstance().GetExtValue(metadata->configuration, "broken")); - if (CAddonMgr::GetInstance().GetExtValue(metadata->configuration, "nofanart") == "true") - builder.SetFanart(""); - if (CAddonMgr::GetInstance().GetExtValue(metadata->configuration, "noicon") == "true") - builder.SetIcon(""); + if (plugin->plugin_path && strcmp(plugin->plugin_path, "") != 0) + { + builder.SetPath(plugin->plugin_path); + + auto assets = CAddonMgr::GetInstance().GetExtElement(metadata->configuration, "assets"); + if (assets) + { + std::string icon = CAddonMgr::GetInstance().GetExtValue(assets, "icon"); + std::string fanart = CAddonMgr::GetInstance().GetExtValue(assets, "fanart"); + + if (!icon.empty()) + builder.SetIcon(URIUtils::AddFileToFolder(plugin->plugin_path, icon)); + if (!fanart.empty()) + builder.SetFanart(URIUtils::AddFileToFolder(plugin->plugin_path, fanart)); + + std::vector<std::string> screenshots; + ELEMENTS elements; + if (CAddonMgr::GetInstance().GetExtElements(assets, "screenshot", elements)) + { + for (const auto& elem : elements) + { + if (elem->value && strcmp(elem->value, "") != 0) + screenshots.emplace_back(URIUtils::AddFileToFolder(plugin->plugin_path, elem->value)); + } + } + builder.SetScreenshots(std::move(screenshots)); + } + else + { + //backwards compatibility + std::string icon = CAddonMgr::GetInstance().GetExtValue(metadata->configuration, "noicon") == "true" ? "" : "icon.png"; + std::string fanart = CAddonMgr::GetInstance().GetExtValue(metadata->configuration, "nofanart") == "true" ? "" : "fanart.jpg"; + if (!icon.empty()) + builder.SetIcon(URIUtils::AddFileToFolder(plugin->plugin_path, icon)); + if (!fanart.empty()) + builder.SetFanart(URIUtils::AddFileToFolder(plugin->plugin_path, fanart)); + } + } } } diff --git a/xbmc/addons/GUIDialogAddonInfo.cpp b/xbmc/addons/GUIDialogAddonInfo.cpp index ae5756a2de..e6c23b080e 100644 --- a/xbmc/addons/GUIDialogAddonInfo.cpp +++ b/xbmc/addons/GUIDialogAddonInfo.cpp @@ -36,6 +36,7 @@ #include "GUIUserMessages.h" #include "guilib/GUIWindowManager.h" #include "input/Key.h" +#include "pictures/GUIWindowSlideShow.h" #include "settings/Settings.h" #include "utils/JobManager.h" #include "utils/FileOperationJob.h" @@ -55,6 +56,7 @@ #define CONTROL_BTN_SETTINGS 9 #define CONTROL_BTN_SELECT 12 #define CONTROL_BTN_AUTOUPDATE 13 +#define CONTROL_LIST_SCREENSHOTS 50 using namespace ADDON; using namespace XFILE; @@ -135,6 +137,17 @@ bool CGUIDialogAddonInfo::OnMessage(CGUIMessage& message) OnToggleAutoUpdates(); return true; } + else if (iControl == CONTROL_LIST_SCREENSHOTS) + { + if (message.GetParam1() == ACTION_SELECT_ITEM || message.GetParam1() == ACTION_MOUSE_LEFT_CLICK) + { + CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), iControl); + OnMessage(msg); + int start = msg.GetParam1(); + if (start >= 0 && start < m_item->GetAddonInfo()->Screenshots().size()) + CGUIWindowSlideShow::RunSlideShow(m_item->GetAddonInfo()->Screenshots(), start); + } + } } break; default: @@ -198,6 +211,16 @@ void CGUIDialogAddonInfo::UpdateControls() SET_CONTROL_LABEL(CONTROL_BTN_SELECT, CanUse() ? 21480 : (CanOpen() ? 21478 : 21479)); CONTROL_ENABLE_ON_CONDITION(CONTROL_BTN_SETTINGS, isInstalled && m_localAddon->HasSettings()); + + CFileItemList items; + for (const auto& screenshot : m_item->GetAddonInfo()->Screenshots()) + { + auto item = std::make_shared<CFileItem>(""); + item->SetArt("thumb", screenshot); + items.Add(std::move(item)); + } + CGUIMessage msg(GUI_MSG_LABEL_BIND, GetID(), CONTROL_LIST_SCREENSHOTS, 0, 0, &items); + OnMessage(msg); } static const std::string LOCAL_CACHE = "\\0_local_cache"; // \0 to give it the lowest priority when sorting diff --git a/xbmc/addons/IAddon.h b/xbmc/addons/IAddon.h index 0cb5bbc4b1..1b1dfb3f76 100644 --- a/xbmc/addons/IAddon.h +++ b/xbmc/addons/IAddon.h @@ -26,6 +26,7 @@ #include <set> #include <string> #include <utility> +#include <vector> #include "XBDateTime.h" class TiXmlElement; @@ -106,6 +107,7 @@ namespace ADDON virtual std::string LibPath() const =0; virtual std::string ChangeLog() const =0; virtual std::string FanArt() const =0; + virtual std::vector<std::string> Screenshots() const =0; virtual std::string Author() const =0; virtual std::string Icon() const =0; virtual std::string Disclaimer() const =0; diff --git a/xbmc/addons/Repository.cpp b/xbmc/addons/Repository.cpp index 2f571646c7..86df11ba34 100644 --- a/xbmc/addons/Repository.cpp +++ b/xbmc/addons/Repository.cpp @@ -191,12 +191,14 @@ bool CRepositoryUpdateJob::DoWork() AddonPtr oldAddon; if (database.GetAddon(addon->ID(), oldAddon) && addon->Version() > oldAddon->Version()) { - if (!addon->Icon().empty() || !addon->FanArt().empty()) + if (!oldAddon->Icon().empty() || !oldAddon->FanArt().empty() || !oldAddon->Screenshots().empty()) CLog::Log(LOGDEBUG, "CRepository: invalidating cached art for '%s'", addon->ID().c_str()); - if (!addon->Icon().empty()) - textureDB.InvalidateCachedTexture(addon->Icon()); - if (!addon->FanArt().empty()) - textureDB.InvalidateCachedTexture(addon->Icon()); + if (!oldAddon->Icon().empty()) + textureDB.InvalidateCachedTexture(oldAddon->Icon()); + if (!oldAddon->FanArt().empty()) + textureDB.InvalidateCachedTexture(oldAddon->Icon()); + for (const auto& path : oldAddon->Screenshots()) + textureDB.InvalidateCachedTexture(path); } } textureDB.CommitMultipleExecute(); diff --git a/xbmc/guilib/GUIWindow.cpp b/xbmc/guilib/GUIWindow.cpp index 2f15256479..70f7063f62 100644 --- a/xbmc/guilib/GUIWindow.cpp +++ b/xbmc/guilib/GUIWindow.cpp @@ -55,7 +55,6 @@ CGUIWindow::CGUIWindow(int id, const std::string &xmlFile) SetID(id); SetProperty("xmlfile", xmlFile); m_lastControlID = 0; - m_isDialog = false; m_needsScaling = true; m_windowLoaded = false; m_loadType = LOAD_EVERY_TIME; @@ -187,14 +186,7 @@ bool CGUIWindow::Load(TiXmlElement* pRootElement) while (pChild) { std::string strValue = pChild->Value(); - if (strValue == "type" && pChild->FirstChild()) - { - // if we have are a window type (ie not a dialog), and we have <type>dialog</type> - // then make this window act like a dialog - if (!IsDialog() && strcmpi(pChild->FirstChild()->Value(), "dialog") == 0) - m_isDialog = true; - } - else if (strValue == "previouswindow" && pChild->FirstChild()) + if (strValue == "previouswindow" && pChild->FirstChild()) { m_previousWindow = CButtonTranslator::TranslateWindow(pChild->FirstChild()->Value()); } diff --git a/xbmc/guilib/GUIWindow.h b/xbmc/guilib/GUIWindow.h index 19d800a38b..0b64939c11 100644 --- a/xbmc/guilib/GUIWindow.h +++ b/xbmc/guilib/GUIWindow.h @@ -244,7 +244,6 @@ protected: bool m_needsScaling; bool m_windowLoaded; // true if the window's xml file has been loaded LOAD_TYPE m_loadType; - bool m_isDialog; // true if we have a dialog, false otherwise. bool m_dynamicResourceAlloc; bool m_closing; bool m_active; // true if window is active or dialog is running diff --git a/xbmc/interfaces/AnnouncementManager.cpp b/xbmc/interfaces/AnnouncementManager.cpp index 7e693aac91..9508cac002 100644 --- a/xbmc/interfaces/AnnouncementManager.cpp +++ b/xbmc/interfaces/AnnouncementManager.cpp @@ -100,13 +100,13 @@ void CAnnouncementManager::Announce(AnnouncementFlag flag, const char *sender, c Announce(flag, sender, message, CFileItemPtr(), data); } -void CAnnouncementManager::Announce(AnnouncementFlag flag, const char *sender, const char *message, CFileItemPtr item) +void CAnnouncementManager::Announce(AnnouncementFlag flag, const char *sender, const char *message, const std::shared_ptr<const CFileItem>& item) { CVariant data; Announce(flag, sender, message, item, data); } -void CAnnouncementManager::Announce(AnnouncementFlag flag, const char *sender, const char *message, CFileItemPtr item, const CVariant &data) +void CAnnouncementManager::Announce(AnnouncementFlag flag, const char *sender, const char *message, const std::shared_ptr<const CFileItem>& item, const CVariant &data) { CAnnounceData announcement; announcement.flag = flag; diff --git a/xbmc/interfaces/AnnouncementManager.h b/xbmc/interfaces/AnnouncementManager.h index 978512487c..0ab56acbcc 100644 --- a/xbmc/interfaces/AnnouncementManager.h +++ b/xbmc/interfaces/AnnouncementManager.h @@ -47,8 +47,10 @@ namespace ANNOUNCEMENT void Announce(AnnouncementFlag flag, const char *sender, const char *message); void Announce(AnnouncementFlag flag, const char *sender, const char *message, const CVariant &data); - void Announce(AnnouncementFlag flag, const char *sender, const char *message, CFileItemPtr item); - void Announce(AnnouncementFlag flag, const char *sender, const char *message, CFileItemPtr item, const CVariant &data); + void Announce(AnnouncementFlag flag, const char *sender, const char *message, + const std::shared_ptr<const CFileItem>& item); + void Announce(AnnouncementFlag flag, const char *sender, const char *message, + const std::shared_ptr<const CFileItem>& item, const CVariant &data); protected: void Process(); diff --git a/xbmc/pictures/GUIWindowSlideShow.cpp b/xbmc/pictures/GUIWindowSlideShow.cpp index e62255d619..2890113e6d 100644 --- a/xbmc/pictures/GUIWindowSlideShow.cpp +++ b/xbmc/pictures/GUIWindowSlideShow.cpp @@ -39,6 +39,7 @@ #include "guilib/Texture.h" #include "windowing/WindowingFactory.h" #include "guilib/LocalizeStrings.h" +#include "TextureDatabase.h" #include "threads/SingleLock.h" #include "utils/log.h" #include "utils/Variant.h" @@ -56,7 +57,7 @@ using namespace KODI::MESSAGING; #define MAX_ZOOM_FACTOR 10 #define MAX_PICTURE_SIZE 2048*2048 -#define IMMEDIATE_TRANSISTION_TIME 20 +#define IMMEDIATE_TRANSITION_TIME 1 #define PICTURE_MOVE_AMOUNT 0.02f #define PICTURE_MOVE_AMOUNT_ANALOG 0.01f @@ -66,12 +67,8 @@ using namespace KODI::MESSAGING; #define ROTATION_SNAP_RANGE 10.0f -#define FPS 25 - -#define BAR_IMAGE 1 #define LABEL_ROW1 10 #define LABEL_ROW2 11 -#define LABEL_ROW2_EXTRA 12 #define CONTROL_PAUSE 13 static float zoomamount[10] = { 1.0f, 1.2f, 1.5f, 2.0f, 2.8f, 4.0f, 6.0f, 9.0f, 13.5f, 20.0f }; @@ -151,22 +148,15 @@ void CBackgroundPicLoader::LoadPic(int iPic, int iSlideNumber, const std::string } CGUIWindowSlideShow::CGUIWindowSlideShow(void) - : CGUIWindow(WINDOW_SLIDESHOW, "SlideShow.xml") + : CGUIDialog(WINDOW_SLIDESHOW, "SlideShow.xml") { m_pBackgroundLoader = NULL; - m_slides = new CFileItemList; m_Resolution = RES_INVALID; m_loadType = KEEP_IN_MEMORY; m_bLoadNextPic = false; Reset(); } -CGUIWindowSlideShow::~CGUIWindowSlideShow(void) -{ - Reset(); - delete m_slides; -} - void CGUIWindowSlideShow::AnnouncePlayerPlay(const CFileItemPtr& item) { CVariant param; @@ -191,14 +181,6 @@ void CGUIWindowSlideShow::AnnouncePlayerStop(const CFileItemPtr& item) ANNOUNCEMENT::CAnnouncementManager::GetInstance().Announce(ANNOUNCEMENT::Player, "xbmc", "OnStop", item, param); } -void CGUIWindowSlideShow::AnnouncePlaylistRemove(int pos) -{ - CVariant data; - data["playlistid"] = PLAYLIST_PICTURE; - data["position"] = pos; - ANNOUNCEMENT::CAnnouncementManager::GetInstance().Announce(ANNOUNCEMENT::Playlist, "xbmc", "OnRemove", data); -} - void CGUIWindowSlideShow::AnnouncePlaylistClear() { CVariant data; @@ -252,8 +234,7 @@ void CGUIWindowSlideShow::Reset() m_iCurrentPic = 0; m_iDirection = 1; m_iLastFailedNextSlide = -1; - CSingleLock lock(m_slideSection); - m_slides->Clear(); + m_slides.clear(); AnnouncePlaylistClear(); m_Resolution = g_graphicsContext.GetVideoResolution(); } @@ -287,7 +268,7 @@ void CGUIWindowSlideShow::OnDeinitWindow(int nextWindowID) } g_infoManager.ResetCurrentSlide(); - CGUIWindow::OnDeinitWindow(nextWindowID); + CGUIDialog::OnDeinitWindow(nextWindowID); } void CGUIWindowSlideShow::Add(const CFileItem *picture) @@ -302,14 +283,14 @@ void CGUIWindowSlideShow::Add(const CFileItem *picture) // then it is a picture and force tag generation item->GetPictureInfoTag(); } - AnnouncePlaylistAdd(item, m_slides->Size()); + AnnouncePlaylistAdd(item, m_slides.size()); - m_slides->Add(item); + m_slides.emplace_back(std::move(item)); } void CGUIWindowSlideShow::ShowNext() { - if (m_slides->Size() == 1) + if (m_slides.size() == 1) return; m_iDirection = 1; @@ -322,7 +303,7 @@ void CGUIWindowSlideShow::ShowNext() void CGUIWindowSlideShow::ShowPrevious() { - if (m_slides->Size() == 1) + if (m_slides.size() == 1) return; m_iDirection = -1; @@ -336,9 +317,9 @@ void CGUIWindowSlideShow::ShowPrevious() void CGUIWindowSlideShow::Select(const std::string& strPicture) { - for (int i = 0; i < m_slides->Size(); ++i) + for (int i = 0; i < m_slides.size(); ++i) { - const CFileItemPtr item = m_slides->Get(i); + const CFileItemPtr item = m_slides.at(i); if (item->GetPath() == strPicture) { m_iDirection = 1; @@ -358,21 +339,16 @@ void CGUIWindowSlideShow::Select(const std::string& strPicture) } } -const CFileItemList &CGUIWindowSlideShow::GetSlideShowContents() -{ - return *m_slides; -} - void CGUIWindowSlideShow::GetSlideShowContents(CFileItemList &list) { - for (int index = 0; index < m_slides->Size(); index++) - list.Add(CFileItemPtr(new CFileItem(*m_slides->Get(index)))); + for (int index = 0; index < m_slides.size(); index++) + list.Add(CFileItemPtr(new CFileItem(*m_slides.at(index)))); } -const CFileItemPtr CGUIWindowSlideShow::GetCurrentSlide() +std::shared_ptr<const CFileItem> CGUIWindowSlideShow::GetCurrentSlide() { - if (m_iCurrentSlide >= 0 && m_iCurrentSlide < m_slides->Size()) - return m_slides->Get(m_iCurrentSlide); + if (m_iCurrentSlide >= 0 && m_iCurrentSlide < m_slides.size()) + return m_slides.at(m_iCurrentSlide); return CFileItemPtr(); } @@ -385,8 +361,8 @@ void CGUIWindowSlideShow::StartSlideShow() { m_bSlideShow = true; m_iDirection = 1; - if (m_slides->Size()) - AnnouncePlayerPlay(m_slides->Get(m_iCurrentSlide)); + if (m_slides.size()) + AnnouncePlayerPlay(m_slides.at(m_iCurrentSlide)); } void CGUIWindowSlideShow::SetDirection(int direction) @@ -407,16 +383,16 @@ void CGUIWindowSlideShow::Process(unsigned int currentTime, CDirtyRegionList &re // (unless we are the screensaver!) if (m_bSlideShow && !m_bPause && !g_application.IsInScreenSaver()) g_application.ResetScreenSaver(); - int iSlides = m_slides->Size(); + int iSlides = m_slides.size(); if (!iSlides) return ; // if we haven't processed yet, we should mark the whole screen if (!HasProcessed()) regions.push_back(CRect(0.0f, 0.0f, (float)g_graphicsContext.GetWidth(), (float)g_graphicsContext.GetHeight())); - if (m_iCurrentSlide < 0 || m_iCurrentSlide >= m_slides->Size()) + if (m_iCurrentSlide < 0 || m_iCurrentSlide >= m_slides.size()) m_iCurrentSlide = 0; - if (m_iNextSlide < 0 || m_iNextSlide >= m_slides->Size()) + if (m_iNextSlide < 0 || m_iNextSlide >= m_slides.size()) m_iNextSlide = GetNextSlide(); // Create our background loader if necessary @@ -432,7 +408,7 @@ void CGUIWindowSlideShow::Process(unsigned int currentTime, CDirtyRegionList &re } bool bSlideShow = m_bSlideShow && !m_bPause && !m_bPlayingVideo; - if (bSlideShow && m_slides->Get(m_iCurrentSlide)->HasProperty("unplayable")) + if (bSlideShow && m_slides.at(m_iCurrentSlide)->HasProperty("unplayable")) { m_iNextSlide = GetNextSlide(); if (m_iCurrentSlide == m_iNextSlide) @@ -454,14 +430,14 @@ void CGUIWindowSlideShow::Process(unsigned int currentTime, CDirtyRegionList &re } else { - CLog::Log(LOGERROR, "Error loading the current image %d: %s", m_iCurrentSlide, m_slides->Get(m_iCurrentSlide)->GetPath().c_str()); - if (!m_slides->Get(m_iCurrentPic)->IsVideo()) + CLog::Log(LOGERROR, "Error loading the current image %d: %s", m_iCurrentSlide, m_slides.at(m_iCurrentSlide)->GetPath().c_str()); + if (!m_slides.at(m_iCurrentPic)->IsVideo()) { // try next if we are in slideshow - CLog::Log(LOGINFO, "set image %s unplayable", m_slides->Get(m_iCurrentSlide)->GetPath().c_str()); - m_slides->Get(m_iCurrentSlide)->SetProperty("unplayable", true); + CLog::Log(LOGINFO, "set image %s unplayable", m_slides.at(m_iCurrentSlide)->GetPath().c_str()); + m_slides.at(m_iCurrentSlide)->SetProperty("unplayable", true); } - if (m_bLoadNextPic || (bSlideShow && !m_bPause && !m_slides->Get(m_iCurrentPic)->IsVideo())) + if (m_bLoadNextPic || (bSlideShow && !m_bPause && !m_slides.at(m_iCurrentPic)->IsVideo())) { // change to next item, wait loading. m_iCurrentSlide = m_iNextSlide; @@ -473,12 +449,12 @@ void CGUIWindowSlideShow::Process(unsigned int currentTime, CDirtyRegionList &re } else if (m_iNextSlide == m_pBackgroundLoader->SlideNumber()) { - CLog::Log(LOGERROR, "Error loading the next image %d: %s", m_iNextSlide, m_slides->Get(m_iNextSlide)->GetPath().c_str()); + CLog::Log(LOGERROR, "Error loading the next image %d: %s", m_iNextSlide, m_slides.at(m_iNextSlide)->GetPath().c_str()); // load next image failed, then skip to load next of next if next is not video. - if (!m_slides->Get(m_iNextSlide)->IsVideo()) + if (!m_slides.at(m_iNextSlide)->IsVideo()) { - CLog::Log(LOGINFO, "set image %s unplayable", m_slides->Get(m_iNextSlide)->GetPath().c_str()); - m_slides->Get(m_iNextSlide)->SetProperty("unplayable", true); + CLog::Log(LOGINFO, "set image %s unplayable", m_slides.at(m_iNextSlide)->GetPath().c_str()); + m_slides.at(m_iNextSlide)->SetProperty("unplayable", true); // change to next item, wait loading. m_iNextSlide = GetNextSlide(); } @@ -490,7 +466,7 @@ void CGUIWindowSlideShow::Process(unsigned int currentTime, CDirtyRegionList &re } else { // Non-current and non-next slide, just ignore error. - CLog::Log(LOGERROR, "Error loading the non-current non-next image %d/%d: %s", m_iNextSlide, m_pBackgroundLoader->SlideNumber(), m_slides->Get(m_iNextSlide)->GetPath().c_str()); + CLog::Log(LOGERROR, "Error loading the non-current non-next image %d/%d: %s", m_iNextSlide, m_pBackgroundLoader->SlideNumber(), m_slides.at(m_iNextSlide)->GetPath().c_str()); m_bErrorMessage = false; } } @@ -501,11 +477,9 @@ void CGUIWindowSlideShow::Process(unsigned int currentTime, CDirtyRegionList &re return; } - CSingleLock lock(m_slideSection); - if (!m_Image[m_iCurrentPic].IsLoaded() && !m_pBackgroundLoader->IsLoading()) { // load first image - CFileItemPtr item = m_slides->Get(m_iCurrentSlide); + CFileItemPtr item = m_slides.at(m_iCurrentSlide); std::string picturePath = GetPicturePath(item.get()); if (!picturePath.empty()) { @@ -533,7 +507,7 @@ void CGUIWindowSlideShow::Process(unsigned int currentTime, CDirtyRegionList &re if (m_iNextSlide != m_iCurrentSlide && m_Image[m_iCurrentPic].IsLoaded() && !m_Image[1 - m_iCurrentPic].IsLoaded() && !m_pBackgroundLoader->IsLoading() && m_iLastFailedNextSlide != m_iNextSlide) { // load the next image m_iLastFailedNextSlide = -1; - CFileItemPtr item = m_slides->Get(m_iNextSlide); + CFileItemPtr item = m_slides.at(m_iNextSlide); std::string picturePath = GetPicturePath(item.get()); if (!picturePath.empty() && (!item->IsVideo() || !m_bSlideShow || m_bPause)) { @@ -550,7 +524,7 @@ void CGUIWindowSlideShow::Process(unsigned int currentTime, CDirtyRegionList &re } } - if (m_slides->Get(m_iCurrentSlide)->IsVideo() && bSlideShow) + if (m_slides.at(m_iCurrentSlide)->IsVideo() && bSlideShow) { if (!PlayVideo()) return; @@ -568,10 +542,10 @@ void CGUIWindowSlideShow::Process(unsigned int currentTime, CDirtyRegionList &re // Check if we should be transistioning immediately if (m_bLoadNextPic && m_Image[m_iCurrentPic].IsLoaded()) { - CLog::Log(LOGDEBUG, "Starting immediate transistion due to user wanting slide %s", m_slides->Get(m_iNextSlide)->GetPath().c_str()); + CLog::Log(LOGDEBUG, "Starting immediate transistion due to user wanting slide %s", m_slides.at(m_iNextSlide)->GetPath().c_str()); if (m_Image[m_iCurrentPic].StartTransistion()) { - m_Image[m_iCurrentPic].SetTransistionTime(1, IMMEDIATE_TRANSISTION_TIME); // only 20 frames for the transistion + m_Image[m_iCurrentPic].SetTransistionTime(1, IMMEDIATE_TRANSITION_TIME); m_bLoadNextPic = false; } } @@ -579,7 +553,7 @@ void CGUIWindowSlideShow::Process(unsigned int currentTime, CDirtyRegionList &re // render the next image if (m_Image[m_iCurrentPic].DrawNextImage()) { - if (m_bSlideShow && !m_bPause && m_slides->Get(m_iNextSlide)->IsVideo()) + if (m_bSlideShow && !m_bPause && m_slides.at(m_iNextSlide)->IsVideo()) { // do not show thumb of video when playing slideshow } @@ -594,7 +568,7 @@ void CGUIWindowSlideShow::Process(unsigned int currentTime, CDirtyRegionList &re } // set the appropriate transistion time m_Image[1 - m_iCurrentPic].SetTransistionTime(0, m_Image[m_iCurrentPic].GetTransistionTime(1)); - m_Image[1 - m_iCurrentPic].Pause(!m_bSlideShow || m_bPause || m_slides->Get(m_iNextSlide)->IsVideo()); + m_Image[1 - m_iCurrentPic].Pause(!m_bSlideShow || m_bPause || m_slides.at(m_iNextSlide)->IsVideo()); m_Image[1 - m_iCurrentPic].Process(currentTime, regions); } else // next pic isn't loaded. We should hang around if it is in progress @@ -612,10 +586,10 @@ void CGUIWindowSlideShow::Process(unsigned int currentTime, CDirtyRegionList &re { m_bLoadNextPic = false; if (m_Image[m_iCurrentPic].IsFinished()) - CLog::Log(LOGDEBUG, "Image %s is finished rendering, switching to %s", m_slides->Get(m_iCurrentSlide)->GetPath().c_str(), m_slides->Get(m_iNextSlide)->GetPath().c_str()); + CLog::Log(LOGDEBUG, "Image %s is finished rendering, switching to %s", m_slides.at(m_iCurrentSlide)->GetPath().c_str(), m_slides.at(m_iNextSlide)->GetPath().c_str()); else // what if it's bg loading? - CLog::Log(LOGDEBUG, "Image %s is not loaded, switching to %s", m_slides->Get(m_iCurrentSlide)->GetPath().c_str(), m_slides->Get(m_iNextSlide)->GetPath().c_str()); + CLog::Log(LOGDEBUG, "Image %s is not loaded, switching to %s", m_slides.at(m_iCurrentSlide)->GetPath().c_str(), m_slides.at(m_iNextSlide)->GetPath().c_str()); if (m_Image[m_iCurrentPic].IsFinished() && m_iCurrentSlide == m_iNextSlide && m_Image[m_iCurrentPic].SlideNumber() == m_iNextSlide) m_Image[m_iCurrentPic].Reset(GetDisplayEffect(m_iCurrentSlide)); @@ -639,7 +613,7 @@ void CGUIWindowSlideShow::Process(unsigned int currentTime, CDirtyRegionList &re m_iCurrentSlide = m_iNextSlide; m_iNextSlide = GetNextSlide(); } - AnnouncePlayerPlay(m_slides->Get(m_iCurrentSlide)); + AnnouncePlayerPlay(m_slides.at(m_iCurrentSlide)); m_iZoomFactor = 1; m_fZoom = 1.0f; @@ -647,14 +621,17 @@ void CGUIWindowSlideShow::Process(unsigned int currentTime, CDirtyRegionList &re } if (m_Image[m_iCurrentPic].IsLoaded()) - g_infoManager.SetCurrentSlide(*m_slides->Get(m_iCurrentSlide)); + g_infoManager.SetCurrentSlide(*m_slides.at(m_iCurrentSlide)); RenderPause(); CGUIWindow::Process(currentTime, regions); + m_renderRegion.SetRect(0, 0, (float)g_graphicsContext.GetWidth(), (float)g_graphicsContext.GetHeight()); } void CGUIWindowSlideShow::Render() { + g_graphicsContext.Clear(0xff000000); + if (m_Image[m_iCurrentPic].IsLoaded()) m_Image[m_iCurrentPic].Render(); @@ -667,15 +644,15 @@ void CGUIWindowSlideShow::Render() int CGUIWindowSlideShow::GetNextSlide() { - if (m_slides->Size() <= 1) + if (m_slides.size() <= 1) return m_iCurrentSlide; int step = m_iDirection >= 0 ? 1 : -1; - int nextSlide = (m_iCurrentSlide + step + m_slides->Size()) % m_slides->Size(); + int nextSlide = (m_iCurrentSlide + step + m_slides.size()) % m_slides.size(); while (nextSlide != m_iCurrentSlide) { - if (!m_slides->Get(nextSlide)->HasProperty("unplayable")) + if (!m_slides.at(nextSlide)->HasProperty("unplayable")) return nextSlide; - nextSlide = (nextSlide + step + m_slides->Size()) % m_slides->Size(); + nextSlide = (nextSlide + step + m_slides.size()) % m_slides.size(); } return m_iCurrentSlide; } @@ -770,13 +747,10 @@ bool CGUIWindowSlideShow::OnAction(const CAction &action) } } break; - - case ACTION_PREVIOUS_MENU: - case ACTION_NAV_BACK: case ACTION_STOP: - if (m_slides->Size()) - AnnouncePlayerStop(m_slides->Get(m_iCurrentSlide)); - g_windowManager.PreviousWindow(); + if (m_slides.size()) + AnnouncePlayerStop(m_slides.at(m_iCurrentSlide)); + Close(); break; case ACTION_NEXT_PICTURE: @@ -811,9 +785,9 @@ bool CGUIWindowSlideShow::OnAction(const CAction &action) case ACTION_PAUSE: case ACTION_PLAYER_PLAY: - if (m_slides->Size() == 0) + if (m_slides.size() == 0) break; - if (m_slides->Get(m_iCurrentSlide)->IsVideo()) + if (m_slides.at(m_iCurrentSlide)->IsVideo()) { if (!m_bPlayingVideo) { @@ -836,12 +810,12 @@ bool CGUIWindowSlideShow::OnAction(const CAction &action) if (m_Image[m_iCurrentPic].DisplayEffectNeedChange(effect)) m_Image[m_iCurrentPic].Reset(effect); } - AnnouncePlayerPlay(m_slides->Get(m_iCurrentSlide)); + AnnouncePlayerPlay(m_slides.at(m_iCurrentSlide)); } else if (action.GetID() == ACTION_PAUSE) { m_bPause = true; - AnnouncePlayerPause(m_slides->Get(m_iCurrentSlide)); + AnnouncePlayerPause(m_slides.at(m_iCurrentSlide)); } break; @@ -900,7 +874,7 @@ bool CGUIWindowSlideShow::OnAction(const CAction &action) break; default: - return CGUIWindow::OnAction(action); + return CGUIDialog::OnAction(action); } return true; } @@ -934,10 +908,10 @@ bool CGUIWindowSlideShow::OnMessage(CGUIMessage& message) else m_Resolution = g_graphicsContext.GetVideoResolution(); - CGUIWindow::OnMessage(message); + CGUIDialog::OnMessage(message); // turn off slideshow if we only have 1 image - if (m_slides->Size() <= 1) + if (m_slides.size() <= 1) m_bSlideShow = false; return true; @@ -1016,7 +990,7 @@ bool CGUIWindowSlideShow::OnMessage(CGUIMessage& message) m_iCurrentPic = 1 - m_iCurrentPic; m_iCurrentSlide = m_iNextSlide; m_iNextSlide = GetNextSlide(); - AnnouncePlayerPlay(m_slides->Get(m_iCurrentSlide)); + AnnouncePlayerPlay(m_slides.at(m_iCurrentSlide)); m_iZoomFactor = 1; m_fZoom = 1.0f; m_fRotate = 0.0f; @@ -1025,7 +999,7 @@ bool CGUIWindowSlideShow::OnMessage(CGUIMessage& message) } break; } - return CGUIWindow::OnMessage(message); + return CGUIDialog::OnMessage(message); } void CGUIWindowSlideShow::RenderPause() @@ -1038,16 +1012,6 @@ void CGUIWindowSlideShow::RenderPause() { SET_CONTROL_HIDDEN(CONTROL_PAUSE); } - /* - static DWORD dwCounter=0; - dwCounter++; - if (dwCounter > 25) - { - dwCounter=0; - } - if (!m_bPause) return; - if (dwCounter <13) return;*/ - } void CGUIWindowSlideShow::Rotate(float fAngle, bool immediate /* = false */) @@ -1108,7 +1072,7 @@ void CGUIWindowSlideShow::Move(float fX, float fY) bool CGUIWindowSlideShow::PlayVideo() { - CFileItemPtr item = m_slides->Get(m_iCurrentSlide); + CFileItemPtr item = m_slides.at(m_iCurrentSlide); if (!item || !item->IsVideo()) return false; CLog::Log(LOGDEBUG, "Playing current video slide %s", item->GetPath().c_str()); @@ -1129,7 +1093,7 @@ bool CGUIWindowSlideShow::PlayVideo() CSlideShowPic::DISPLAY_EFFECT CGUIWindowSlideShow::GetDisplayEffect(int iSlideNumber) const { - if (m_bSlideShow && !m_bPause && !m_slides->Get(iSlideNumber)->IsVideo()) + if (m_bSlideShow && !m_bPause && !m_slides.at(iSlideNumber)->IsVideo()) return CSettings::GetInstance().GetBool(CSettings::SETTING_SLIDESHOW_DISPLAYEFFECTS) ? CSlideShowPic::EFFECT_RANDOM : CSlideShowPic::EFFECT_NONE; else return CSlideShowPic::EFFECT_NO_TIMEOUT; @@ -1140,20 +1104,19 @@ void CGUIWindowSlideShow::OnLoadPic(int iPic, int iSlideNumber, const std::strin if (pTexture) { // set the pic's texture + size etc. - CSingleLock lock(m_slideSection); - if (iSlideNumber >= m_slides->Size() || GetPicturePath(m_slides->Get(iSlideNumber).get()) != strFileName) + if (iSlideNumber >= m_slides.size() || GetPicturePath(m_slides.at(iSlideNumber).get()) != strFileName) { // throw this away - we must have cleared the slideshow while we were still loading delete pTexture; return; } - CLog::Log(LOGDEBUG, "Finished background loading slot %d, %d: %s", iPic, iSlideNumber, m_slides->Get(iSlideNumber)->GetPath().c_str()); + CLog::Log(LOGDEBUG, "Finished background loading slot %d, %d: %s", iPic, iSlideNumber, m_slides.at(iSlideNumber)->GetPath().c_str()); m_Image[iPic].SetTexture(iSlideNumber, pTexture, GetDisplayEffect(iSlideNumber)); m_Image[iPic].SetOriginalSize(pTexture->GetOriginalWidth(), pTexture->GetOriginalHeight(), bFullSize); m_Image[iPic].m_bIsComic = false; - if (URIUtils::IsInRAR(m_slides->Get(m_iCurrentSlide)->GetPath()) || URIUtils::IsInZIP(m_slides->Get(m_iCurrentSlide)->GetPath())) // move to top for cbr/cbz + if (URIUtils::IsInRAR(m_slides.at(m_iCurrentSlide)->GetPath()) || URIUtils::IsInZIP(m_slides.at(m_iCurrentSlide)->GetPath())) // move to top for cbr/cbz { - CURL url(m_slides->Get(m_iCurrentSlide)->GetPath()); + CURL url(m_slides.at(m_iCurrentSlide)->GetPath()); std::string strHostName = url.GetHostName(); if (URIUtils::HasExtension(strHostName, ".cbr|.cbz")) { @@ -1162,9 +1125,9 @@ void CGUIWindowSlideShow::OnLoadPic(int iPic, int iSlideNumber, const std::strin } } } - else if (iSlideNumber >= m_slides->Size() || GetPicturePath(m_slides->Get(iSlideNumber).get()) != strFileName) + else if (iSlideNumber >= m_slides.size() || GetPicturePath(m_slides.at(iSlideNumber).get()) != strFileName) { // Failed to load image. and not match values calling LoadPic, then something is changed, ignore. - CLog::Log(LOGDEBUG, "CGUIWindowSlideShow::OnLoadPic(%d, %d, %s) on failure not match current state (cur %d, next %d, curpic %d, pic[0, 1].slidenumber=%d, %d, %s)", iPic, iSlideNumber, strFileName.c_str(), m_iCurrentSlide, m_iNextSlide, m_iCurrentPic, m_Image[0].SlideNumber(), m_Image[1].SlideNumber(), iSlideNumber >= m_slides->Size() ? "" : m_slides->Get(iSlideNumber)->GetPath().c_str()); + CLog::Log(LOGDEBUG, "CGUIWindowSlideShow::OnLoadPic(%d, %d, %s) on failure not match current state (cur %d, next %d, curpic %d, pic[0, 1].slidenumber=%d, %d, %s)", iPic, iSlideNumber, strFileName.c_str(), m_iCurrentSlide, m_iNextSlide, m_iCurrentPic, m_Image[0].SlideNumber(), m_Image[1].SlideNumber(), iSlideNumber >= m_slides.size() ? "" : m_slides.at(iSlideNumber)->GetPath().c_str()); } else { // Failed to load image. What should be done?? @@ -1176,7 +1139,7 @@ void CGUIWindowSlideShow::OnLoadPic(int iPic, int iSlideNumber, const std::strin void CGUIWindowSlideShow::Shuffle() { - m_slides->Randomize(); + std::random_shuffle(m_slides.begin(), m_slides.end()); m_iCurrentSlide = 0; m_iNextSlide = GetNextSlide(); m_bShuffled = true; @@ -1186,7 +1149,7 @@ void CGUIWindowSlideShow::Shuffle() int CGUIWindowSlideShow::NumSlides() const { - return m_slides->Size(); + return m_slides.size(); } int CGUIWindowSlideShow::CurrentSlide() const @@ -1203,7 +1166,6 @@ void CGUIWindowSlideShow::AddFromPath(const std::string &strPath, { // reset the slideshow Reset(); - m_strExtensions = strExtensions; if (bRecursive) { path_set recursivePaths; @@ -1316,3 +1278,23 @@ std::string CGUIWindowSlideShow::GetPicturePath(CFileItem *item) return picturePath; } + +void CGUIWindowSlideShow::RunSlideShow(std::vector<std::string> paths, int start /* = 0*/) +{ + auto dialog = static_cast<CGUIWindowSlideShow*>(g_windowManager.GetWindow(WINDOW_SLIDESHOW)); + if (dialog) + { + std::vector<CFileItemPtr> items; + for (const auto& path : paths) + items.push_back(std::make_shared<CFileItem>(CTextureUtils::GetWrappedImageURL(path), false)); + + dialog->Reset(); + dialog->m_bPause = true; + dialog->m_bSlideShow = false; + dialog->m_iDirection = 1; + dialog->m_iCurrentSlide = start; + dialog->m_iNextSlide = (start + 1) % items.size(); + dialog->m_slides = std::move(items); + dialog->Open(); + } +} diff --git a/xbmc/pictures/GUIWindowSlideShow.h b/xbmc/pictures/GUIWindowSlideShow.h index 8c00b2745e..4559124f28 100644 --- a/xbmc/pictures/GUIWindowSlideShow.h +++ b/xbmc/pictures/GUIWindowSlideShow.h @@ -21,7 +21,7 @@ */ #include <set> -#include "guilib/GUIWindow.h" +#include "guilib/GUIDialog.h" #include "threads/Thread.h" #include "threads/CriticalSection.h" #include "threads/Event.h" @@ -59,21 +59,25 @@ private: CGUIWindowSlideShow *m_pCallback; }; -class CGUIWindowSlideShow : public CGUIWindow +class CGUIWindowSlideShow : public CGUIDialog { public: CGUIWindowSlideShow(void); - virtual ~CGUIWindowSlideShow(void); + virtual ~CGUIWindowSlideShow() {}; + + bool OnMessage(CGUIMessage& message) override; + EVENT_RESULT OnMouseEvent(const CPoint &point, const CMouseEvent &event) override; + bool OnAction(const CAction &action) override; + void Render() override; + void Process(unsigned int currentTime, CDirtyRegionList ®ions) override; + void OnDeinitWindow(int nextWindowID) override; void Reset(); void Add(const CFileItem *picture); bool IsPlaying() const; - void ShowNext(); - void ShowPrevious(); void Select(const std::string& strPicture); - const CFileItemList &GetSlideShowContents(); void GetSlideShowContents(CFileItemList &list); - const CFileItemPtr GetCurrentSlide(); + std::shared_ptr<const CFileItem> GetCurrentSlide(); void RunSlideShow(const std::string &strPath, bool bRecursive = false, bool bRandom = false, bool bNotRandom = false, const std::string &beginSlidePath="", bool startSlideShow = true, @@ -88,12 +92,6 @@ public: const std::string &strExtensions=""); void StartSlideShow(); bool InSlideShow() const; - virtual bool OnMessage(CGUIMessage& message); - virtual EVENT_RESULT OnMouseEvent(const CPoint &point, const CMouseEvent &event); - virtual bool OnAction(const CAction &action); - virtual void Render(); - virtual void Process(unsigned int currentTime, CDirtyRegionList ®ions); - virtual void OnDeinitWindow(int nextWindowID); void OnLoadPic(int iPic, int iSlideNumber, const std::string &strFileName, CBaseTexture* pTexture, bool bFullSize); int NumSlides() const; int CurrentSlide() const; @@ -101,8 +99,14 @@ public: bool IsPaused() const { return m_bPause; } bool IsShuffled() const { return m_bShuffled; } int GetDirection() const { return m_iDirection; } - void SetDirection(int direction); // -1: rewind, 1: forward + + static void RunSlideShow(std::vector<std::string> paths, int start=0); + private: + void ShowNext(); + void ShowPrevious(); + void SetDirection(int direction); // -1: rewind, 1: forward + typedef std::set<std::string> path_set; // set to track which paths we're adding void AddItems(const std::string &strPath, path_set *recursivePaths, SortBy method = SortByLabel, @@ -123,7 +127,6 @@ private: void AnnouncePlayerPlay(const CFileItemPtr& item); void AnnouncePlayerPause(const CFileItemPtr& item); void AnnouncePlayerStop(const CFileItemPtr& item); - void AnnouncePlaylistRemove(int pos); void AnnouncePlaylistClear(); void AnnouncePlaylistAdd(const CFileItemPtr& item, int pos); void AnnouncePropertyChanged(const std::string &strProperty, const CVariant &value); @@ -143,7 +146,7 @@ private: bool m_bPlayingVideo; bool m_bErrorMessage; - CFileItemList* m_slides; + std::vector<CFileItemPtr> m_slides; CSlideShowPic m_Image[2]; @@ -153,7 +156,5 @@ private: int m_iLastFailedNextSlide; bool m_bLoadNextPic; RESOLUTION m_Resolution; - CCriticalSection m_slideSection; - std::string m_strExtensions; CPoint m_firstGesturePoint; }; diff --git a/xbmc/pictures/SlideShowPicture.cpp b/xbmc/pictures/SlideShowPicture.cpp index 7d77391014..f571d0472d 100644 --- a/xbmc/pictures/SlideShowPicture.cpp +++ b/xbmc/pictures/SlideShowPicture.cpp @@ -42,7 +42,7 @@ static float zoomamount[10] = { 1.0f, 1.2f, 1.5f, 2.0f, 2.8f, 4.0f, 6.0f, 9.0f, 13.5f, 20.0f }; -CSlideShowPic::CSlideShowPic() +CSlideShowPic::CSlideShowPic() : m_alpha(0) { m_pImage = NULL; m_bIsLoaded = false; @@ -75,6 +75,7 @@ void CSlideShowPic::Close() m_bDrawNextImage = false; m_bTransistionImmediately = false; m_bIsDirty = true; + m_alpha = 0; #ifdef HAS_DX SAFE_RELEASE(m_vb); #endif @@ -122,6 +123,18 @@ void CSlideShowPic::SetTexture_Internal(int iSlideNumber, CBaseTexture* pTexture // initialize our transistion effect m_transistionStart.type = transEffect; m_transistionStart.start = 0; + + // initialize our display effect + if (dispEffect == EFFECT_RANDOM) + { + if (((m_fWidth / m_fHeight) > 1.9) || ((m_fHeight / m_fWidth) > 1.9)) + m_displayEffect = EFFECT_PANORAMA; + else + m_displayEffect = (DISPLAY_EFFECT)((rand() % (EFFECT_RANDOM - 1)) + 1); + } + else + m_displayEffect = dispEffect; + // the +1's make sure it actually occurs float fadeTime = 0.2f; if (m_displayEffect != EFFECT_NO_TIMEOUT) @@ -148,16 +161,6 @@ void CSlideShowPic::SetTexture_Internal(int iSlideNumber, CBaseTexture* pTexture m_fZoomAmount = 1; m_fZoomLeft = 0; m_fZoomTop = 0; - // initialize our display effect - if (dispEffect == EFFECT_RANDOM) - { - if (((m_fWidth / m_fHeight) > 1.9) || ((m_fHeight / m_fWidth) > 1.9)) - m_displayEffect = EFFECT_PANORAMA; - else - m_displayEffect = (DISPLAY_EFFECT)((rand() % (EFFECT_RANDOM - 1)) + 1); - } - else - m_displayEffect = dispEffect; m_fPosX = m_fPosY = 0.0f; m_fPosZ = 1.0f; m_fVelocityX = m_fVelocityY = m_fVelocityZ = 0.0f; |