diff --git a/src/guiengine/skin.cpp b/src/guiengine/skin.cpp index c00cc4da2..bca14b495 100644 --- a/src/guiengine/skin.cpp +++ b/src/guiengine/skin.cpp @@ -672,13 +672,11 @@ void Skin::drawRibbonChild(const core::rect< s32 > &rect, Widget* widget, const if (mark_selected) { // selected tab should be slighlty bigger than others - if(vertical_flip) - rect2.UpperLeftCorner.Y -= 10; - else - rect2.LowerRightCorner.Y += 10; + if (vertical_flip) rect2.UpperLeftCorner.Y -= 10; + else rect2.LowerRightCorner.Y += 10; } - drawBoxFromStretchableTexture(widget, rect2, *params); + drawBoxFromStretchableTexture(widget, rect2, *params, parentRibbon->m_deactivated); } diff --git a/src/guiengine/widgets/dynamic_ribbon_widget.cpp b/src/guiengine/widgets/dynamic_ribbon_widget.cpp index f5a4caf2f..c76b06050 100644 --- a/src/guiengine/widgets/dynamic_ribbon_widget.cpp +++ b/src/guiengine/widgets/dynamic_ribbon_widget.cpp @@ -417,6 +417,8 @@ void DynamicRibbonWidget::registerHoverListener(DynamicRibbonHoverListener* list // ----------------------------------------------------------------------------- EventPropagation DynamicRibbonWidget::rightPressed(const int playerID) { + if (m_deactivated) return EVENT_LET; + RibbonWidget* w = getSelectedRibbon(playerID); if (w != NULL) { @@ -443,6 +445,8 @@ EventPropagation DynamicRibbonWidget::rightPressed(const int playerID) // ----------------------------------------------------------------------------- EventPropagation DynamicRibbonWidget::leftPressed(const int playerID) { + if (m_deactivated) return EVENT_LET; + RibbonWidget* w = getSelectedRibbon(playerID); if (w != NULL) { @@ -465,6 +469,8 @@ EventPropagation DynamicRibbonWidget::leftPressed(const int playerID) // ----------------------------------------------------------------------------- EventPropagation DynamicRibbonWidget::transmitEvent(Widget* w, std::string& originator, const int playerID) { + if (m_deactivated) return EVENT_LET; + if (originator=="left") { scroll(-1); @@ -492,6 +498,7 @@ EventPropagation DynamicRibbonWidget::transmitEvent(Widget* w, std::string& orig // ----------------------------------------------------------------------------- EventPropagation DynamicRibbonWidget::mouseHovered(Widget* child, const int playerID) { + if (m_deactivated) return EVENT_LET; //std::cout << "DynamicRibbonWidget::mouseHovered " << playerID << std::endl; updateLabel(); @@ -536,6 +543,8 @@ void DynamicRibbonWidget::onRibbonWidgetScroll(const int delta_x) void DynamicRibbonWidget::onRibbonWidgetFocus(RibbonWidget* emitter, const int playerID) { + if (m_deactivated) return; + if (emitter->m_selection[playerID] >= emitter->m_children.size()) { emitter->m_selection[playerID] = emitter->m_children.size()-1; diff --git a/src/guiengine/widgets/ribbon_widget.cpp b/src/guiengine/widgets/ribbon_widget.cpp index a336b7fb0..3948d9f94 100644 --- a/src/guiengine/widgets/ribbon_widget.cpp +++ b/src/guiengine/widgets/ribbon_widget.cpp @@ -252,6 +252,8 @@ void RibbonWidget::select(std::string item, const int mousePlayerID) // ----------------------------------------------------------------------------- EventPropagation RibbonWidget::rightPressed(const int playerID) { + if (m_deactivated) return EVENT_LET; + m_selection[playerID]++; if (m_selection[playerID] >= m_children.size()) { @@ -285,6 +287,8 @@ EventPropagation RibbonWidget::rightPressed(const int playerID) // ----------------------------------------------------------------------------- EventPropagation RibbonWidget::leftPressed(const int playerID) { + if (m_deactivated) return EVENT_LET; + m_selection[playerID]--; if (m_selection[playerID] < 0) { @@ -340,6 +344,8 @@ EventPropagation RibbonWidget::focused(const int playerID) // ----------------------------------------------------------------------------- EventPropagation RibbonWidget::mouseHovered(Widget* child, const int mousePlayerID) { + if (m_deactivated) return EVENT_LET; + //std::cout << "RibbonWidget::mouseHovered " << mousePlayerID << std::endl; const int subbuttons_amount = m_children.size(); @@ -417,19 +423,22 @@ void RibbonWidget::updateSelection() // ----------------------------------------------------------------------------- EventPropagation RibbonWidget::transmitEvent(Widget* w, std::string& originator, const int playerID) { - const int subbuttons_amount = m_children.size(); - - for (int i=0; isetFocusForPlayer( playerID ); diff --git a/src/states_screens/kart_selection.cpp b/src/states_screens/kart_selection.cpp index 42881e474..755593d3f 100644 --- a/src/states_screens/kart_selection.cpp +++ b/src/states_screens/kart_selection.cpp @@ -601,6 +601,14 @@ public: } }; +/** Small utility function that returns whether the two given players chose the same kart. + * The advantage of this function is that it can handle "random kart" selection. */ +bool sameKart(const PlayerKartWidget& player1, const PlayerKartWidget& player2) +{ + return player1.getKartInternalName() == player2.getKartInternalName() && + player1.getKartInternalName() != RANDOM_KART_ID; +} + #if 0 #pragma mark - #pragma mark KartHoverListener @@ -690,6 +698,7 @@ KartHoverListener* karthoverListener = NULL; KartSelectionScreen::KartSelectionScreen() : Screen("karts.stkgui") { g_dispatcher = new FocusDispatcher(this); + m_player_confirmed = false; // Dynamically add tabs // FIXME: it's not very well documented that RibbonWidgets can have dynamically generated contents @@ -715,15 +724,118 @@ KartSelectionScreen::KartSelectionScreen() : Screen("karts.stkgui") item->m_properties[PROP_ID] = ALL_KART_GROUPS_ID; tabs->m_children.push_back(item); } + +// ----------------------------------------------------------------------------- + +void KartSelectionScreen::init() +{ + m_player_confirmed = false; + + RibbonWidget* tabs = this->getWidget("kartgroups"); + assert( tabs != NULL ); + tabs->m_deactivated = false; + + // FIXME: Reload previous kart selection screen state + m_kart_widgets.clearAndDeleteAll(); + StateManager::get()->resetActivePlayers(); + input_manager->getDeviceList()->setAssignMode(DETECT_NEW); + + DynamicRibbonWidget* w = this->getWidget("karts"); + assert( w != NULL ); + + if (karthoverListener == NULL) + { + karthoverListener = new KartHoverListener(this); + w->registerHoverListener(karthoverListener); + } + + // Build kart list + // (it is built everytikme, to account for .g. locking) + w->clearItems(); + std::vector group = kart_properties_manager->getKartsInGroup("standard"); + const int kart_amount = group.size(); + + // add Tux (or whatever default kart) first + std::string& default_kart = UserConfigParams::m_default_kart; + for(int n=0; ngetKartById(group[n]); + if (prop->getIdent() == default_kart) + { + std::string icon_path = "/karts/" + prop->getIdent() + "/" + prop->getIconFile(); + const bool locked = unlock_manager->isLocked(prop->getIdent()); + w->addItem(prop->getName(), prop->getIdent().c_str(), icon_path.c_str(), locked); + //std::cout << "Add item : " << prop->getIdent().c_str() << std::endl; + break; + } + } + + // add others + for(int n=0; ngetKartById(group[n]); + if (prop->getIdent() != default_kart) + { + std::string icon_path = "/karts/" + prop->getIdent() + "/" + prop->getIconFile(); + const bool locked = unlock_manager->isLocked(prop->getIdent()); + w->addItem(prop->getName(), prop->getIdent().c_str(), icon_path.c_str(), locked); + //std::cout << "Add item : " << prop->getIdent().c_str() << std::endl; + } + } + + // add random + w->addItem(_("Random Kart"), RANDOM_KART_ID, "/gui/random_kart.png"); + + /* + + TODO: Ultimately, it'd be nice to *not* delete g_player_karts so that + when players return to the kart selection screen, it will appear as + it did when they left (at least when returning from the track menu). + Rebuilding the screen is a little tricky. + + */ + + if (m_kart_widgets.size() > 0) + { + // FIXME: trying to rebuild the screen + for (int n = 0; n < m_kart_widgets.size(); n++) + { + PlayerKartWidget *pkw; + pkw = m_kart_widgets.get(n); + this->manualAddWidget(pkw); + pkw->add(); + } + + } + else // For now this is what will happen + { + playerJoin( input_manager->getDeviceList()->getLatestUsedDevice(), true ); + w->updateItemDisplay(); + } + + // Player 0 select first kart (Tux) + w->setSelection(0, 0, true); +} + // ----------------------------------------------------------------------------- + +void KartSelectionScreen::tearDown() +{ + //g_player_karts.clearWithoutDeleting(); + m_kart_widgets.clearAndDeleteAll(); +} + +// ----------------------------------------------------------------------------- + void KartSelectionScreen::forgetWhatWasLoaded() { Screen::forgetWhatWasLoaded(); - // these pointers is no more valid (have been deleted along other widgets) + // these pointers are no more valid (have been deleted along other widgets) g_dispatcher = NULL; karthoverListener = NULL; } + // ----------------------------------------------------------------------------- // Return true if event was handled successfully bool KartSelectionScreen::playerJoin(InputDevice* device, bool firstPlayer) @@ -904,311 +1016,13 @@ void KartSelectionScreen::onUpdate(float delta, irr::video::IVideoDriver*) } } -// ----------------------------------------------------------------------------- -void KartSelectionScreen::tearDown() -{ - //g_player_karts.clearWithoutDeleting(); - m_kart_widgets.clearAndDeleteAll(); -} - -// ----------------------------------------------------------------------------- -void KartSelectionScreen::init() -{ - // FIXME: Reload previous kart selection screen state - m_kart_widgets.clearAndDeleteAll(); - StateManager::get()->resetActivePlayers(); - input_manager->getDeviceList()->setAssignMode(DETECT_NEW); - - DynamicRibbonWidget* w = this->getWidget("karts"); - assert( w != NULL ); - - if (karthoverListener == NULL) - { - karthoverListener = new KartHoverListener(this); - w->registerHoverListener(karthoverListener); - } - - // Build kart list - // (it is built everytikme, to account for .g. locking) - w->clearItems(); - std::vector group = kart_properties_manager->getKartsInGroup("standard"); - const int kart_amount = group.size(); - - // add Tux (or whatever default kart) first - std::string& default_kart = UserConfigParams::m_default_kart; - for(int n=0; ngetKartById(group[n]); - if (prop->getIdent() == default_kart) - { - std::string icon_path = "/karts/" + prop->getIdent() + "/" + prop->getIconFile(); - const bool locked = unlock_manager->isLocked(prop->getIdent()); - w->addItem(prop->getName(), prop->getIdent().c_str(), icon_path.c_str(), locked); - //std::cout << "Add item : " << prop->getIdent().c_str() << std::endl; - break; - } - } - - // add others - for(int n=0; ngetKartById(group[n]); - if (prop->getIdent() != default_kart) - { - std::string icon_path = "/karts/" + prop->getIdent() + "/" + prop->getIconFile(); - const bool locked = unlock_manager->isLocked(prop->getIdent()); - w->addItem(prop->getName(), prop->getIdent().c_str(), icon_path.c_str(), locked); - //std::cout << "Add item : " << prop->getIdent().c_str() << std::endl; - } - } - - // add random - w->addItem(_("Random Kart"), RANDOM_KART_ID, "/gui/random_kart.png"); - - /* - - TODO: Ultimately, it'd be nice to *not* delete g_player_karts so that - when players return to the kart selection screen, it will appear as - it did when they left (at least when returning from the track menu). - Rebuilding the screen is a little tricky. - - */ - - if (m_kart_widgets.size() > 0) - { - // FIXME: trying to rebuild the screen - for (int n = 0; n < m_kart_widgets.size(); n++) - { - PlayerKartWidget *pkw; - pkw = m_kart_widgets.get(n); - this->manualAddWidget(pkw); - pkw->add(); - } - - } - else // For now this is what will happen - { - playerJoin( input_manager->getDeviceList()->getLatestUsedDevice(), true ); - w->updateItemDisplay(); - } - - // Player 0 select first kart (Tux) - w->setSelection(0, 0, true); -} - -// ----------------------------------------------------------------------------- -void KartSelectionScreen::allPlayersDone() -{ - input_manager->setMasterPlayerOnly(true); - - DynamicRibbonWidget* w = this->getWidget("karts"); - assert( w != NULL ); - - const ptr_vector< StateManager::ActivePlayer, HOLD >& players = StateManager::get()->getActivePlayers(); - - // ---- Print selection (for debugging purposes) - std::cout << "==========\n" << players.size() << " players :\n"; - for (int n=0; ngetName() - << " on " << players[n].getDevice()->m_name << std::endl; - } - std::cout << "==========\n"; - - // ---- Give player info to race manager - race_manager->setNumPlayers( players.size() ); - race_manager->setNumLocalPlayers( players.size() ); - - // ---- Manage 'random kart' selection(s) - RandomGenerator random; - - //g_player_karts.clearAndDeleteAll(); - //race_manager->setLocalKartInfo(0, w->getSelectionIDString()); - - std::vector items = w->getItems(); - - // remove the 'random' item itself - const int item_count = items.size(); - for (int n=0; ngetProfile()->getName() << std::endl; - std::cout << " Player " << m << " chose " << m_kart_widgets[m].getAssociatedPlayer()->getProfile()->getName() << std::endl; - - // two players took the same name. check if one is ready - if (!m_kart_widgets[n].isReady() && m_kart_widgets[m].isReady()) - { - // player m is ready, so player n should not choose this name - m_kart_widgets[n].playerName->markAsIncorrect(); - } - else if (m_kart_widgets[n].isReady() && !m_kart_widgets[m].isReady()) - { - // player n is ready, so player m should not choose this name - m_kart_widgets[m].playerName->markAsIncorrect(); - } - else if (m_kart_widgets[n].isReady() && m_kart_widgets[m].isReady()) - { - // it should be impossible for two players to confirm they're ready with the same name - assert(false); - } - - ok = false; - } - } // end for - } - - return ok; -} - -// ----------------------------------------------------------------------------- - -/** Small utility that returns whether the two given players chose the same kart. - * The advantage of this function is that it can handle "random kart" selection. */ -bool sameKart(const PlayerKartWidget& player1, const PlayerKartWidget& player2) -{ - return player1.getKartInternalName() == player2.getKartInternalName() && - player1.getKartInternalName() != RANDOM_KART_ID; -} - -bool KartSelectionScreen::validateKartChoices() -{ - bool ok = true; - - const int amount = m_kart_widgets.size(); - - // reset all marks, we'll re-add them next if errors are still there - for (int n=0; nunsetBadge(BAD_BADGE); - } - - for (int n=0; n Setting red badge on player " << n << std::endl; - // player m is ready, so player n should not choose this name - m_kart_widgets[n].modelView->setBadge(BAD_BADGE); - } - else if (m_kart_widgets[n].isReady() && !m_kart_widgets[m].isReady()) - { - std::cout << "--> Setting red badge on player " << m << std::endl; - // player n is ready, so player m should not choose this name - m_kart_widgets[m].modelView->setBadge(BAD_BADGE); - } - else if (m_kart_widgets[n].isReady() && m_kart_widgets[m].isReady()) - { - // it should be impossible for two players to confirm they're ready with the same kart - assert(false); - } - - // we know it's not ok (but don't stop right now, all bad ones need red badges) - ok = false; - } - } // end for - } - - return ok; - -} - // ----------------------------------------------------------------------------- /** * Callback handling events from the kart selection menu */ void KartSelectionScreen::eventCallback(Widget* widget, const std::string& name, const int playerID) { - if (name == "kartgroups") + if (name == "kartgroups" && !m_player_confirmed) // don't allow changing group after someone confirmed { RibbonWidget* tabs = this->getWidget("kartgroups"); assert(tabs != NULL); @@ -1314,6 +1128,11 @@ void KartSelectionScreen::eventCallback(Widget* widget, const std::string& name, // Mark this player as ready to start m_kart_widgets[playerID].markAsReady(); + m_player_confirmed = true; + + RibbonWidget* tabs = this->getWidget("kartgroups"); + assert( tabs != NULL ); + tabs->m_deactivated = true; // validate choices to notify player of duplicates const bool names_ok = validateIdentChoices(); @@ -1349,6 +1168,211 @@ void KartSelectionScreen::eventCallback(Widget* widget, const std::string& name, } } +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- + +#if 0 +#pragma mark - +#pragma mark KartSelectionScreen (private) +#endif + +void KartSelectionScreen::allPlayersDone() +{ + input_manager->setMasterPlayerOnly(true); + + DynamicRibbonWidget* w = this->getWidget("karts"); + assert( w != NULL ); + + const ptr_vector< StateManager::ActivePlayer, HOLD >& players = StateManager::get()->getActivePlayers(); + + // ---- Print selection (for debugging purposes) + std::cout << "==========\n" << players.size() << " players :\n"; + for (int n=0; ngetName() + << " on " << players[n].getDevice()->m_name << std::endl; + } + std::cout << "==========\n"; + + // ---- Give player info to race manager + race_manager->setNumPlayers( players.size() ); + race_manager->setNumLocalPlayers( players.size() ); + + // ---- Manage 'random kart' selection(s) + RandomGenerator random; + + //g_player_karts.clearAndDeleteAll(); + //race_manager->setLocalKartInfo(0, w->getSelectionIDString()); + + std::vector items = w->getItems(); + + // remove the 'random' item itself + const int item_count = items.size(); + for (int n=0; ngetProfile()->getName() << std::endl; + std::cout << " Player " << m << " chose " << m_kart_widgets[m].getAssociatedPlayer()->getProfile()->getName() << std::endl; + + // two players took the same name. check if one is ready + if (!m_kart_widgets[n].isReady() && m_kart_widgets[m].isReady()) + { + // player m is ready, so player n should not choose this name + m_kart_widgets[n].playerName->markAsIncorrect(); + } + else if (m_kart_widgets[n].isReady() && !m_kart_widgets[m].isReady()) + { + // player n is ready, so player m should not choose this name + m_kart_widgets[m].playerName->markAsIncorrect(); + } + else if (m_kart_widgets[n].isReady() && m_kart_widgets[m].isReady()) + { + // it should be impossible for two players to confirm they're ready with the same name + assert(false); + } + + ok = false; + } + } // end for + } + + return ok; +} + +// ----------------------------------------------------------------------------- + +bool KartSelectionScreen::validateKartChoices() +{ + bool ok = true; + + const int amount = m_kart_widgets.size(); + + // reset all marks, we'll re-add them next if errors are still there + for (int n=0; nunsetBadge(BAD_BADGE); + } + + for (int n=0; n Setting red badge on player " << n << std::endl; + // player m is ready, so player n should not choose this name + m_kart_widgets[n].modelView->setBadge(BAD_BADGE); + } + else if (m_kart_widgets[n].isReady() && !m_kart_widgets[m].isReady()) + { + std::cout << "--> Setting red badge on player " << m << std::endl; + // player n is ready, so player m should not choose this name + m_kart_widgets[m].modelView->setBadge(BAD_BADGE); + } + else if (m_kart_widgets[n].isReady() && m_kart_widgets[m].isReady()) + { + // it should be impossible for two players to confirm they're ready with the same kart + assert(false); + } + + // we know it's not ok (but don't stop right now, all bad ones need red badges) + ok = false; + } + } // end for + } + + return ok; + +} + // ----------------------------------------------------------------------------- void KartSelectionScreen::renumberKarts() diff --git a/src/states_screens/kart_selection.hpp b/src/states_screens/kart_selection.hpp index bcc95163b..26d489508 100644 --- a/src/states_screens/kart_selection.hpp +++ b/src/states_screens/kart_selection.hpp @@ -35,12 +35,19 @@ class KartSelectionScreen : public GUIEngine::Screen, public GUIEngine::ScreenSi friend class PlayerNameSpinner; friend class FocusDispatcher; - // ref only since we're adding them to a Screen, and the Screen will take ownership of these widgets + /** Contains the custom widget shown for every player. (ref only since we're adding them to a + * Screen, and the Screen will take ownership of these widgets) + */ ptr_vector m_kart_widgets; friend class GUIEngine::ScreenSingleton; KartSelectionScreen(); + /** Stores whether any player confirmed their choice; then, some things are "frozen", for instance + * the selected kart group tab + */ + bool m_player_confirmed; + /** Called when all players selected their kart */ void allPlayersDone(); @@ -48,11 +55,13 @@ class KartSelectionScreen : public GUIEngine::Screen, public GUIEngine::ScreenSi void renumberKarts(); /** Checks identities chosen by players, making sure no duplicates are used. - \return Whether all choices are ok */ + * \return Whether all choices are ok + */ bool validateIdentChoices(); /** Checks karts chosen by players, making sure no duplicates are used. - \return Whether all choices are ok */ + * \return Whether all choices are ok + */ bool validateKartChoices(); public: