InstalledList.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. #include <cmath>
  2. #include <TweenEngine/Tween.h>
  3. #include <cpp3ds/System/Lock.hpp>
  4. #include "InstalledList.hpp"
  5. #include "AppList.hpp"
  6. #include "TitleKeys.hpp"
  7. namespace FreeShop {
  8. InstalledList::InstalledList()
  9. : m_scrollPos(0.f)
  10. , m_size(320.f, 0.f)
  11. , m_expandedItem(nullptr)
  12. {
  13. // Make install options initially transparent for fade in
  14. TweenEngine::Tween::set(m_options, InstalledOptions::ALPHA)
  15. .target(0.f).start(m_tweenManager);
  16. }
  17. InstalledList &InstalledList::getInstance()
  18. {
  19. static InstalledList installedList;
  20. return installedList;
  21. }
  22. void InstalledList::refresh()
  23. {
  24. cpp3ds::Lock lock(m_mutexRefresh);
  25. cpp3ds::Uint64 relatedTitleId;
  26. std::vector<cpp3ds::Uint64> titleIds;
  27. m_installedTitleIds.clear();
  28. m_installedItems.clear();
  29. m_expandedItem = nullptr;
  30. TweenEngine::Tween::set(m_options, InstalledOptions::ALPHA).target(0.f).start(m_tweenManager);
  31. #ifdef EMULATION
  32. // some hardcoded title IDs for testing
  33. titleIds.push_back(0x00040000000edf00); // [US] Super Smash Bros.
  34. titleIds.push_back(0x0004000000030100); // [US] Kid Icarus: Uprising
  35. titleIds.push_back(0x0004000000030800); // [US] Mario Kart 7
  36. titleIds.push_back(0x0004000000041700); // [US] Kirby's Dream Land
  37. titleIds.push_back(0x0004008000008f00);
  38. #else
  39. u32 titleCount;
  40. AM_GetTitleCount(MEDIATYPE_SD, &titleCount);
  41. titleIds.resize(titleCount);
  42. AM_GetTitleList(nullptr, MEDIATYPE_SD, titleCount, &titleIds[0]);
  43. AM_GetTitleCount(MEDIATYPE_NAND, &titleCount);
  44. titleIds.resize(titleCount + titleIds.size());
  45. AM_GetTitleList(nullptr, MEDIATYPE_NAND, titleCount, &titleIds[titleIds.size() - titleCount]);
  46. #endif
  47. for (auto& titleId : titleIds)
  48. {
  49. size_t titleType = titleId >> 32;
  50. cpp3ds::Uint32 titleLower = (titleId & 0xFFFFFFFF) >> 8;
  51. relatedTitleId = 0;
  52. if (titleType == TitleKeys::Game || titleType == TitleKeys::Update ||
  53. titleType == TitleKeys::DLC || titleType == TitleKeys::Demo || titleType == TitleKeys::DSiWare)
  54. m_installedTitleIds.push_back(titleId);
  55. if (titleType == TitleKeys::DLC || titleType == TitleKeys::Update)
  56. {
  57. relatedTitleId = (static_cast<cpp3ds::Uint64>(titleType) << 32) | (titleLower << 8);
  58. }
  59. for (auto& appItemGUI : AppList::getInstance().getList())
  60. {
  61. auto appItem = appItemGUI->getAppItem();
  62. if (appItem->getTitleId() == (relatedTitleId ? relatedTitleId : titleId))
  63. {
  64. appItem->setInstalled(true);
  65. }
  66. }
  67. }
  68. // Add all primary game titles first
  69. for (auto& titleId : titleIds)
  70. {
  71. TitleKeys::TitleType titleType = static_cast<TitleKeys::TitleType>(titleId >> 32);
  72. if (titleType == TitleKeys::Game || titleType == TitleKeys::DSiWare)
  73. try
  74. {
  75. std::unique_ptr<InstalledItem> item(new InstalledItem(titleId));
  76. m_installedItems.emplace_back(std::move(item));
  77. }
  78. catch (int e)
  79. {
  80. //
  81. }
  82. }
  83. // Sort alphabetically
  84. std::sort(m_installedItems.begin(), m_installedItems.end(), [=](const std::unique_ptr<InstalledItem>& a, const std::unique_ptr<InstalledItem>& b)
  85. {
  86. return a->getAppItem()->getNormalizedTitle() < b->getAppItem()->getNormalizedTitle();
  87. });
  88. repositionItems();
  89. // Add updates that have not yet been installed for which we have a titlekey
  90. for (auto& titleKey : TitleKeys::getList())
  91. {
  92. size_t titleType = titleKey.first >> 32;
  93. if (titleType == TitleKeys::Update || titleType == TitleKeys::DLC)
  94. {
  95. size_t titleLower = (titleKey.first & 0xFFFFFFFF) >> 8;
  96. for (auto& installedItem : m_installedItems)
  97. {
  98. if (titleLower == (installedItem->getTitleId() & 0xFFFFFFFF) >> 8)
  99. {
  100. if (titleType == TitleKeys::Update)
  101. installedItem->setUpdateStatus(titleKey.first, false);
  102. else
  103. installedItem->setDLCStatus(titleKey.first, false);
  104. }
  105. }
  106. }
  107. }
  108. // Add all installed updates/DLC to the above titles added.
  109. // If not found, attempt to fetch parent title info from system.
  110. for (auto& titleId : titleIds)
  111. {
  112. TitleKeys::TitleType titleType = static_cast<TitleKeys::TitleType>(titleId >> 32);
  113. if (titleType == TitleKeys::Update || titleType == TitleKeys::DLC)
  114. {
  115. bool found = false;
  116. cpp3ds::Uint32 titleLower = (titleId & 0xFFFFFFFF) >> 8;
  117. for (auto& installedItem : m_installedItems)
  118. {
  119. if (titleLower == (installedItem->getTitleId() & 0xFFFFFFFF) >> 8)
  120. {
  121. found = true;
  122. if (titleType == TitleKeys::Update)
  123. installedItem->setUpdateStatus(titleId, true);
  124. else
  125. installedItem->setDLCStatus(titleId, true);
  126. break;
  127. }
  128. }
  129. }
  130. }
  131. }
  132. void InstalledList::draw(cpp3ds::RenderTarget &target, cpp3ds::RenderStates states) const
  133. {
  134. states.transform *= getTransform();
  135. states.scissor = cpp3ds::UintRect(0, 30, 320, 210);
  136. for (auto& item : m_installedItems)
  137. {
  138. float posY = item->getPosition().y;
  139. if (posY > -10.f && posY < 240.f)
  140. target.draw(*item, states);
  141. }
  142. if (m_expandedItem)
  143. target.draw(m_options, states);
  144. }
  145. void InstalledList::update(float delta)
  146. {
  147. m_tweenManager.update(delta);
  148. }
  149. bool InstalledList::processEvent(const cpp3ds::Event &event)
  150. {
  151. if (m_tweenManager.getRunningTweensCount() > 0)
  152. return false;
  153. if (event.type == cpp3ds::Event::TouchEnded)
  154. {
  155. if (event.touch.y < 30)
  156. return false;
  157. for (auto &item : m_installedItems)
  158. {
  159. float posY = getPosition().y + item->getPosition().y;
  160. if (event.touch.y > posY && event.touch.y < posY + item->getHeight())
  161. {
  162. if (item.get() == m_expandedItem)
  163. {
  164. if (event.touch.y < posY + 16.f)
  165. expandItem(nullptr);
  166. else
  167. m_options.processTouchEvent(event);
  168. }
  169. else
  170. expandItem(item.get());
  171. break;
  172. }
  173. }
  174. }
  175. return false;
  176. }
  177. void InstalledList::setScroll(float position)
  178. {
  179. m_scrollPos = std::round(position);
  180. repositionItems();
  181. }
  182. float InstalledList::getScroll()
  183. {
  184. return m_scrollPos;
  185. }
  186. void InstalledList::repositionItems()
  187. {
  188. float posY = 30.f + m_scrollPos;
  189. for (auto& item : m_installedItems)
  190. {
  191. if (item.get() == m_expandedItem)
  192. m_options.setPosition(0.f, posY + 20.f);
  193. item->setPosition(0.f, posY);
  194. posY += item->getHeight();
  195. }
  196. m_size.y = posY - 6.f - m_scrollPos;
  197. if (m_expandedItem)
  198. m_size.y -= 24.f;
  199. updateScrollSize();
  200. }
  201. const cpp3ds::Vector2f &InstalledList::getScrollSize()
  202. {
  203. return m_size;
  204. }
  205. void InstalledList::expandItem(InstalledItem *item)
  206. {
  207. if (item == m_expandedItem)
  208. return;
  209. const float optionsFadeDelay = 0.15f;
  210. const float expandDuration = 0.2f;
  211. // Expand animation
  212. if (m_expandedItem)
  213. {
  214. TweenEngine::Tween::to(*m_expandedItem, InstalledItem::HEIGHT, expandDuration)
  215. .target(16.f)
  216. .setCallback(TweenEngine::TweenCallback::COMPLETE, [=](TweenEngine::BaseTween* source) {
  217. m_expandedItem = item;
  218. repositionItems();
  219. })
  220. .delay(optionsFadeDelay)
  221. .start(m_tweenManager);
  222. TweenEngine::Tween::to(m_options, InstalledOptions::ALPHA, optionsFadeDelay + 0.05f)
  223. .target(0.f)
  224. .start(m_tweenManager);
  225. }
  226. if (item)
  227. {
  228. TweenEngine::Tween::to(*item, InstalledItem::HEIGHT, expandDuration)
  229. .target(40.f)
  230. .setCallback(TweenEngine::TweenCallback::COMPLETE, [=](TweenEngine::BaseTween* source) {
  231. m_expandedItem = item;
  232. m_options.setInstalledItem(item);
  233. repositionItems();
  234. })
  235. .delay(m_expandedItem ? optionsFadeDelay : 0.f)
  236. .start(m_tweenManager);
  237. TweenEngine::Tween::to(m_options, InstalledOptions::ALPHA, expandDuration)
  238. .target(255.f)
  239. .delay(m_expandedItem ? expandDuration + optionsFadeDelay : optionsFadeDelay)
  240. .start(m_tweenManager);
  241. }
  242. // Move animation for items in between expanded items
  243. bool foundItem = false;
  244. bool foundExpanded = false;
  245. for (auto &itemToMove : m_installedItems)
  246. {
  247. if (foundItem && !foundExpanded)
  248. {
  249. TweenEngine::Tween::to(*itemToMove, InstalledItem::POSITION_Y, expandDuration)
  250. .targetRelative(24.f)
  251. .delay(m_expandedItem ? optionsFadeDelay : 0.f)
  252. .start(m_tweenManager);
  253. }
  254. else if (foundExpanded && !foundItem)
  255. {
  256. TweenEngine::Tween::to(*itemToMove, InstalledItem::POSITION_Y, expandDuration)
  257. .targetRelative(-24.f)
  258. .delay(m_expandedItem ? optionsFadeDelay : 0.f)
  259. .start(m_tweenManager);
  260. }
  261. if (itemToMove.get() == m_expandedItem)
  262. foundExpanded = true;
  263. else if (itemToMove.get() == item)
  264. {
  265. foundItem = true;
  266. }
  267. if (foundExpanded && foundItem)
  268. break;
  269. }
  270. }
  271. bool InstalledList::isInstalled(cpp3ds::Uint64 titleId)
  272. {
  273. auto &v = getInstance().m_installedTitleIds;
  274. return std::find(v.begin(), v.end(), titleId) != v.end();
  275. }
  276. } // namespace FreeShop