From 7ec159152cca8a9a4b7d9b97bda28a5f26b42cee Mon Sep 17 00:00:00 2001 From: Maschell Date: Fri, 21 Feb 2020 20:17:24 +0100 Subject: [PATCH] - Added support for multiple pages - Added support for non touch controls --- data/sounds/button_click.mp3 | Bin 0 -> 5433 bytes src/gui/GuiIconGrid.cpp | 217 ++++++++++++++++++++++++++++++++--- src/gui/GuiIconGrid.h | 12 +- 3 files changed, 206 insertions(+), 23 deletions(-) create mode 100644 data/sounds/button_click.mp3 diff --git a/data/sounds/button_click.mp3 b/data/sounds/button_click.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..ec4aad7d9b8d4b67da17d0481c333c41d30063a7 GIT binary patch literal 5433 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 + + rightButton.setTrigger(&rightTrigger); + rightButton.clicked.connect(this, &GuiIconGrid::OnRightClick); + this->append(&rightButton); + + downButton.setTrigger(&downTrigger); + downButton.clicked.connect(this, &GuiIconGrid::OnDownClick); + this->append(&downButton); + + upButton.setTrigger(&upTrigger); + upButton.clicked.connect(this, &GuiIconGrid::OnUpClick); + this->append(&upButton); + + launchButton.setTrigger(&buttonATrigger); + launchButton.setSoundClick(buttonClickSound); + launchButton.clicked.connect(this, &GuiIconGrid::OnLaunchClick); + this->append(&launchButton); + arrowLeftButton.setImage(&arrowLeftImage); arrowLeftButton.setEffectGrow(); arrowLeftButton.setPosition(40, 0); @@ -67,6 +89,7 @@ GuiIconGrid::GuiIconGrid(int32_t w, int32_t h, uint64_t GameIndex,bool sortByNam arrowLeftButton.setTrigger(&buttonLTrigger); arrowLeftButton.setSoundClick(buttonClickSound); arrowLeftButton.clicked.connect(this, &GuiIconGrid::OnLeftArrowClick); + append(&arrowLeftButton); arrowRightButton.setImage(&arrowRightImage); arrowRightButton.setEffectGrow(); @@ -77,7 +100,9 @@ GuiIconGrid::GuiIconGrid(int32_t w, int32_t h, uint64_t GameIndex,bool sortByNam arrowRightButton.setTrigger(&buttonRTrigger); arrowRightButton.setSoundClick(buttonClickSound); arrowRightButton.clicked.connect(this, &GuiIconGrid::OnRightArrowClick); + append(&arrowRightButton); + // at most we are rendering 2 screens at the same time for(int i = 0; i< MAX_COLS * MAX_ROWS *2; i++) { GameIcon * image = new GameIcon(&emptyIcon); emptyIcons.push_back(image); @@ -100,6 +125,17 @@ GuiIconGrid::~GuiIconGrid() { emptyIcons.clear(); } +int32_t GuiIconGrid::offsetForTitleId(uint64_t titleId) { + int32_t offset = -1; + for(uint32_t i = 0; i < position.size(); i++) { + if(position.at(i) == titleId) { + offset = i; + break; + } + } + return offset; +} + void GuiIconGrid::setSelectedGame(uint64_t idx) { this->selectedGame = idx; @@ -108,16 +144,22 @@ void GuiIconGrid::setSelectedGame(uint64_t idx) { GameInfoContainer * container = NULL; for (auto const& x : gameInfoContainers) { container = x.second; - - if(x.first == idx) { container->image->setSelected(true); } else { container->image->setSelected(false); } } - containerMutex.unlock(); + + int32_t offset = offsetForTitleId(getSelectedGame()); + if(offset > 0) { + uint32_t newPage = offset / (MAX_COLS * MAX_ROWS); + if(newPage != (uint32_t) curPage) { + curPage = newPage; + bUpdatePositions = true; + } + } } uint64_t GuiIconGrid::getSelectedGame(void) { @@ -168,37 +210,107 @@ void GuiIconGrid::OnGameTitleListUpdated(GameList * gameList) { containerMutex.unlock(); gameList->unlock(); + setSelectedGame(0); + curPage = 0; + currentLeftPosition = 0; bUpdatePositions = true; } void GuiIconGrid::OnLeftArrowClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { - + curPage--; + setSelectedGame(0); + bUpdatePositions = true; } void GuiIconGrid::OnRightArrowClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { - + curPage++; + setSelectedGame(0); + bUpdatePositions = true; } void GuiIconGrid::OnLeftClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { + int32_t offset = offsetForTitleId(getSelectedGame()); + if(offset < 0){ + return; + } + if((offset % MAX_COLS) == 0) { + offset -= ((MAX_COLS * MAX_ROWS) - MAX_COLS) + 1; + } else { + offset--; + } + if(offset < 0 || position.empty()) { + return; + } + uint64_t newTitleId = position.at(offset); + if(newTitleId > 0) { + setSelectedGame(newTitleId); + } } void GuiIconGrid::OnRightClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { - + int32_t offset = offsetForTitleId(getSelectedGame()); + if(offset < 0){ + return; + } + if((offset % MAX_COLS) == MAX_COLS - 1) { + offset += ((MAX_COLS * MAX_ROWS) - MAX_COLS) + 1; + } else { + offset++; + } + if((uint32_t) offset >= position.size()) { + return; + } + uint64_t newTitleId = position.at(offset); + if(newTitleId > 0) { + setSelectedGame(newTitleId); + } } void GuiIconGrid::OnDownClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { + int32_t offset = offsetForTitleId(getSelectedGame()); + if(offset < 0){ + return; + } + if(offset % (MAX_COLS * MAX_ROWS) < (MAX_COLS * MAX_ROWS) - MAX_COLS) { + offset = offset + MAX_COLS; + } else { + return; + } + if((uint32_t) offset >= position.size()) { + return; + } + uint64_t newTitleId = position.at(offset); + if(newTitleId > 0) { + setSelectedGame(newTitleId); + } } void GuiIconGrid::OnUpClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { + int32_t offset = offsetForTitleId(getSelectedGame()); + if(offset < 0){ + return; + } + if(offset % (MAX_COLS * MAX_ROWS) >= MAX_COLS) { + offset = offset - MAX_COLS; + } else { + return; + } + if(offset < 0) { + return; + } + uint64_t newTitleId = position.at(offset); + if(newTitleId > 0) { + setSelectedGame(newTitleId); + } } void GuiIconGrid::OnLaunchClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) { //! do not auto launch when wiimote is pointing to screen and presses A - //if((trigger == &buttonATrigger) && (controller->chan & (GuiTrigger::CHANNEL_2 | GuiTrigger::CHANNEL_3 | GuiTrigger::CHANNEL_4 | GuiTrigger::CHANNEL_5)) && controller->data.validPointer) { - // return; - //} + if((trigger == &buttonATrigger) && (controller->chan & (GuiTrigger::CHANNEL_2 | GuiTrigger::CHANNEL_3 | GuiTrigger::CHANNEL_4 | GuiTrigger::CHANNEL_5)) && controller->data.validPointer) { + return; + } DEBUG_FUNCTION_LINE("Tried to launch %s (%016llX)\n", gameInfoContainers[getSelectedGame()]->info->name.c_str(),getSelectedGame()); gameLaunchClicked(this, getSelectedGame()); } @@ -302,9 +414,13 @@ void GuiIconGrid::update(GuiController * c) { } void GuiIconGrid::updateButtonPositions() { + arrowRightButton.setState(GuiElement::STATE_DISABLED); + arrowRightButton.setVisible(false); + arrowLeftButton.setState(GuiElement::STATE_DISABLED); + arrowLeftButton.setVisible(false); + int32_t col = 0, row = 0, listOff = 0; - int i = 0; // create an empty vector of pairs std::vector> vec; @@ -315,6 +431,14 @@ void GuiIconGrid::updateButtonPositions() { containerMutex.unlock(); + for (auto const& x : vec) { + remove(x.second->button); + } + + for (auto const& x : emptyIcons) { + remove(x); + } + if(sortByName) { std::sort(vec.begin(), vec.end(), [](const std::pair& l, const std::pair& r) { @@ -326,27 +450,82 @@ void GuiIconGrid::updateButtonPositions() { } - for (auto const& x : vec) { - listOff = i / (MAX_COLS * MAX_ROWS); + // TODO somehow be able to adjust the positions. + position.clear(); + for(auto const & x: vec) { + position.push_back(x.first); + } + uint32_t elementSize = position.size(); + uint32_t pages = (elementSize / (MAX_COLS * MAX_ROWS)) +1; + + uint32_t emptyIconUse = 0; + + if(curPage < 0) { + curPage = 0; + } + if((uint32_t) curPage > pages) { + curPage = 0; + } + + targetLeftPosition = -curPage * getWidth(); + + if((uint32_t) curPage < (pages - 1)) { + arrowRightButton.clearState(GuiElement::STATE_DISABLED); + arrowRightButton.setVisible(true); + bringToFront(&arrowRightButton); + } + if(curPage > 0) { + arrowLeftButton.clearState(GuiElement::STATE_DISABLED); + arrowLeftButton.setVisible(true); + bringToFront(&arrowLeftButton); + } + + uint32_t startPage = -(currentLeftPosition / getWidth()); + uint32_t endPage = startPage; + + if(targetLeftPosition != currentLeftPosition) { + endPage++; + if(endPage > pages) { + endPage = pages; + } + } + + for(uint32_t i = startPage * (MAX_COLS * MAX_ROWS); i < (endPage + 1) * (MAX_COLS * MAX_ROWS); i++) { + listOff = i / (MAX_COLS * MAX_ROWS); + GuiElement * element = NULL; float posX = currentLeftPosition + listOff * width + ( col * (noIcon.getWidth() + noIcon.getWidth() * 0.5f) - (MAX_COLS * 0.5f - 0.5f) * (noIcon.getWidth() + noIcon.getWidth() * 0.5f) ); float posY = -row * (noIcon.getHeight() + noIcon.getHeight() * 0.5f) + (MAX_ROWS * 0.5f - 0.5f) * (noIcon.getHeight() + noIcon.getHeight() * 0.5f) + 30.0f; - if(x.second->button != NULL) { - x.second->button->setPosition(posX, posY); + if(i < position.size()) { + uint64_t titleID = position.at(i); + if(titleID > 0) { + GameInfoContainer * container = gameInfoContainers[titleID]; + if(container != NULL) { + element = container->button; + } + } } + if(element == NULL) { + if(emptyIcons.size() <= emptyIconUse) { + break; + } + element = emptyIcons.at(emptyIconUse); + emptyIconUse++; + } + element->setPosition(posX, posY); + append(element); + col++; if(col >= MAX_COLS) { col = 0; row++; } - if(row >= MAX_ROWS) + if(row >= MAX_ROWS) { row = 0; - - i++; + } } - } void GuiIconGrid::draw(CVideo *pVideo) { diff --git a/src/gui/GuiIconGrid.h b/src/gui/GuiIconGrid.h index 92df7d2..3e7102f 100644 --- a/src/gui/GuiIconGrid.h +++ b/src/gui/GuiIconGrid.h @@ -43,12 +43,12 @@ private: static const int32_t MAX_ROWS = 3; static const int32_t MAX_COLS = 5; - GuiSound *buttonClickSound; - bool sortByName = false; GuiParticleImage particleBgImage; + GuiSound *buttonClickSound; + GuiTrigger touchTrigger; GuiTrigger wpadTouchTrigger; GuiTrigger leftTrigger; @@ -86,6 +86,9 @@ private: void OnGameButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger); void updateButtonPositions(); + int32_t offsetForTitleId(uint64_t titleId); + + int32_t curPage = 0; int32_t listOffset; uint64_t selectedGame; int32_t currentLeftPosition; @@ -95,7 +98,7 @@ private: class GameInfoContainer { public: - GameInfoContainer(GuiButton* button, GuiImage * image, gameInfo * info) { + GameInfoContainer(GuiButton* button, GameIcon * image, gameInfo * info) { this->image = image; this->info = info; this->button = button; @@ -116,13 +119,14 @@ private: } } - GuiImage * image; + GameIcon * image; gameInfo * info; GuiButton * button; }; std::recursive_mutex containerMutex; std::map gameInfoContainers; + std::vector position; std::vector emptyIcons;