From 118859e85ffba358fb8bf8b0695ef9b15481f415 Mon Sep 17 00:00:00 2001 From: Hamood-bot Date: Sat, 1 Nov 2025 04:34:20 +0200 Subject: [PATCH 1/2] feat(observer): show compact cash, rank and XP in observer UI; refresh list and info view; formatting fixes --- .../Include/GameClient/ControlBar.h | 1 + .../GameClient/GUI/ControlBar/ControlBar.cpp | 2 +- .../GUI/ControlBar/ControlBarObserver.cpp | 196 +++++++++++++++++- .../Include/GameClient/ControlBar.h | 1 + .../GameClient/GUI/ControlBar/ControlBar.cpp | 2 +- .../GUI/ControlBar/ControlBarObserver.cpp | 195 ++++++++++++++++- 6 files changed, 386 insertions(+), 11 deletions(-) diff --git a/Generals/Code/GameEngine/Include/GameClient/ControlBar.h b/Generals/Code/GameEngine/Include/GameClient/ControlBar.h index c8b686550b..6a3cd7771f 100644 --- a/Generals/Code/GameEngine/Include/GameClient/ControlBar.h +++ b/Generals/Code/GameEngine/Include/GameClient/ControlBar.h @@ -722,6 +722,7 @@ class ControlBar : public SubsystemInterface void initObserverControls( void ); void populateObserverInfoWindow ( void ); void populateObserverList( void ); + void refreshObserverUI(); Bool isObserverControlBarOn( void ) { return m_isObserverCommandBar;} void setObserverLookAtPlayer (Player *player); ///< Sets the looked at player. Used to present information about the player. diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/ControlBar/ControlBar.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/ControlBar/ControlBar.cpp index 068ef53773..a26baf2ef5 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/ControlBar/ControlBar.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/ControlBar/ControlBar.cpp @@ -1432,7 +1432,7 @@ void ControlBar::update( void ) if( m_isObserverCommandBar) { if((TheGameLogic->getFrame() % (LOGICFRAMES_PER_SECOND/2)) == 0) - populateObserverInfoWindow(); + refreshObserverUI(); Drawable *drawToEvaluateFor = NULL; if( TheInGameUI->getSelectCount() > 1 ) diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/ControlBar/ControlBarObserver.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/ControlBar/ControlBarObserver.cpp index f9060a8639..9f93ca58bf 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/ControlBar/ControlBarObserver.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/ControlBar/ControlBarObserver.cpp @@ -100,6 +100,155 @@ static GameWindow *staticTextPlayerName = NULL; static NameKeyType s_replayObserverNameKey = NAMEKEY_INVALID; +static AsciiString formatCompactCash(UnsignedInt cash) +{ + AsciiString cashText; + + if (cash >= 1000000) + { + if ((cash % 1000000) == 0) + { + cashText.format("$%uM", cash / 1000000); + } + else + { + const float millions = static_cast(cash) / 1000000.0f; + cashText.format("$%.1fM", millions); + } + } + else if (cash >= 1000) + { + if ((cash % 1000) == 0) + { + cashText.format("$%uK", cash / 1000); + } + else + { + const float thousands = static_cast(cash) / 1000.0f; + cashText.format("$%.1fK", thousands); + } + } + else + { + cashText.format("$%u", cash); + } + + return cashText; +} + +// TheSuperHackers @feature GitHubCopilot 01/11/2025 Surface cash/rank/xp summary for observer overlays. +static UnicodeString formatObserverPlayerSummary(const Player *player) +{ + UnicodeString summary; + + if (!player) + { + return summary; + } + + UnsignedInt cash = 0; + if (player->getMoney()) + { + cash = player->getMoney()->countMoney(); + } + + const Int rankLevel = player->getRankLevel(); + const Int totalSkillPoints = player->getSkillPoints(); + const Int levelFloor = player->getSkillPointsLevelDown(); + const Int levelCeiling = player->getSkillPointsLevelUp(); + + Int xpProgress = totalSkillPoints - levelFloor; + if (xpProgress < 0) + { + xpProgress = 0; + } + + Int xpSpan = levelCeiling - levelFloor; + if (xpSpan < 0) + { + xpSpan = 0; + } + + Int xpPercent = 100; + if (xpSpan > 0) + { + xpPercent = (xpProgress * 100) / xpSpan; + if (xpPercent > 100) + { + xpPercent = 100; + } + } + + AsciiString asciiSummary = formatCompactCash(cash); + + AsciiString rankToken; + rankToken.format(" R%d", rankLevel); + asciiSummary.concat(rankToken); + + AsciiString xpToken; + if (xpSpan > 0) + { + xpToken.format(" XP %d%%", xpPercent); + } + else + { + xpToken.format(" XP %d", totalSkillPoints); + } + asciiSummary.concat(xpToken); + + summary.translate(asciiSummary); + return summary; +} + +static void appendSummaryToSecondLine(UnicodeString &text, const UnicodeString &summary) +{ + if (summary.isEmpty()) + { + return; + } + + UnicodeString firstLine; + UnicodeString secondLine; + Bool onSecondLine = FALSE; + + const Int length = text.getLength(); + for (Int index = 0; index < length; ++index) + { + const WideChar ch = text.getCharAt(index); + if (!onSecondLine) + { + firstLine.concat(ch); + if (ch == L'\n') + { + onSecondLine = TRUE; + } + } + else + { + secondLine.concat(ch); + } + } + + if (onSecondLine) + { + if (!secondLine.isEmpty()) + { + secondLine.concat(L" "); + } + secondLine.concat(summary); + text = firstLine; + text.concat(secondLine); + } + else + { + if (!text.isEmpty()) + { + text.concat(L"\n"); + } + text.concat(summary); + } +} + //----------------------------------------------------------------------------- // PUBLIC FUNCTIONS /////////////////////////////////////////////////////////// //----------------------------------------------------------------------------- @@ -270,7 +419,14 @@ void ControlBar::populateObserverList( void ) //GadgetButtonSetHiliteImage( buttonPlayer[currentButton], p->getPlayerTemplate()->getHiliteImage() ); //GadgetButtonSetHiliteSelectedImage( buttonPlayer[currentButton], p->getPlayerTemplate()->getPushedImage() ); //GadgetButtonSetDisabledImage( buttonPlayer[currentButton], p->getPlayerTemplate()->getDisabledImage() ); - buttonPlayer[currentButton]->winSetTooltip(p->getPlayerDisplayName()); + const UnicodeString summary = formatObserverPlayerSummary(p); + UnicodeString tooltip = p->getPlayerDisplayName(); + if (!summary.isEmpty()) + { + tooltip.concat(L"\n"); + tooltip.concat(summary); + } + buttonPlayer[currentButton]->winSetTooltip(tooltip); buttonPlayer[currentButton]->winHide(FALSE); buttonPlayer[currentButton]->winSetStatus( WIN_STATUS_USE_OVERLAY_STATES ); @@ -283,10 +439,10 @@ void ControlBar::populateObserverList( void ) teamStr.format("Team:%d", slot->getTeamNumber() + 1); if (slot->isAI() && slot->getTeamNumber() == -1) teamStr = "Team:AI"; - UnicodeString text; text.format(TheGameText->fetch("CONTROLBAR:ObsPlayerLabel"), p->getPlayerDisplayName().str(), TheGameText->fetch(teamStr).str()); + appendSummaryToSecondLine(text, summary); GadgetStaticTextSetText(staticTextPlayer[currentButton], text ); @@ -312,7 +468,14 @@ void ControlBar::populateObserverList( void ) //GadgetButtonSetHiliteImage( buttonPlayer[currentButton], p->getPlayerTemplate()->getHiliteImage() ); //GadgetButtonSetHiliteSelectedImage( buttonPlayer[currentButton], p->getPlayerTemplate()->getPushedImage() ); //GadgetButtonSetDisabledImage( buttonPlayer[currentButton], p->getPlayerTemplate()->getDisabledImage() ); - buttonPlayer[currentButton]->winSetTooltip(p->getPlayerDisplayName()); + const UnicodeString summary = formatObserverPlayerSummary(p); + UnicodeString tooltip = p->getPlayerDisplayName(); + if (!summary.isEmpty()) + { + tooltip.concat(L"\n"); + tooltip.concat(summary); + } + buttonPlayer[currentButton]->winSetTooltip(tooltip); buttonPlayer[currentButton]->winHide(FALSE); buttonPlayer[currentButton]->winSetStatus( WIN_STATUS_USE_OVERLAY_STATES ); @@ -320,7 +483,9 @@ void ControlBar::populateObserverList( void ) Color backColor = GameMakeColor(0, 0, 0, 255); staticTextPlayer[currentButton]->winSetEnabledTextColors( playerColor, backColor ); staticTextPlayer[currentButton]->winHide(FALSE); - GadgetStaticTextSetText(staticTextPlayer[currentButton], p->getPlayerDisplayName()); + UnicodeString text = p->getPlayerDisplayName(); + appendSummaryToSecondLine(text, summary); + GadgetStaticTextSetText(staticTextPlayer[currentButton], text); ++currentButton; break; @@ -376,10 +541,31 @@ void ControlBar::populateObserverInfoWindow ( void ) GadgetStaticTextSetText(staticTextNumberOfUnitsKilled, uString); uString.format(L"%d",m_observerLookAtPlayer->getScoreKeeper()->getTotalUnitsLost()); GadgetStaticTextSetText(staticTextNumberOfUnitsLost, uString); - GadgetStaticTextSetText(staticTextPlayerName, m_observerLookAtPlayer->getPlayerDisplayName()); + UnicodeString playerName = m_observerLookAtPlayer->getPlayerDisplayName(); + const UnicodeString infoSummary = formatObserverPlayerSummary(m_observerLookAtPlayer); + appendSummaryToSecondLine(playerName, infoSummary); + GadgetStaticTextSetText(staticTextPlayerName, playerName); Color color = m_observerLookAtPlayer->getPlayerColor(); staticTextPlayerName->winSetEnabledTextColors(color, GameMakeColor(0,0,0,255)); winFlag->winSetEnabledImage(0, m_observerLookAtPlayer->getPlayerTemplate()->getFlagWaterMarkImage()); winGeneralPortrait->winHide(FALSE); buttonIdleWorker->winHide(FALSE); } + +void ControlBar::refreshObserverUI() +{ + if (!m_isObserverCommandBar) + { + return; + } + + if (ObserverPlayerInfoWindow && !ObserverPlayerInfoWindow->winIsHidden()) + { + populateObserverInfoWindow(); + } + + if (ObserverPlayerListWindow && !ObserverPlayerListWindow->winIsHidden()) + { + populateObserverList(); + } +} diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/ControlBar.h b/GeneralsMD/Code/GameEngine/Include/GameClient/ControlBar.h index e15b68975c..3d933caaa7 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/ControlBar.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/ControlBar.h @@ -736,6 +736,7 @@ class ControlBar : public SubsystemInterface void initObserverControls( void ); void populateObserverInfoWindow ( void ); void populateObserverList( void ); + void refreshObserverUI(); Bool isObserverControlBarOn( void ) { return m_isObserverCommandBar;} void setObserverLookAtPlayer (Player *player); ///< Sets the looked at player. Used to present information about the player. diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/ControlBar/ControlBar.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/ControlBar/ControlBar.cpp index efce005ebd..729727e502 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/ControlBar/ControlBar.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/ControlBar/ControlBar.cpp @@ -1455,7 +1455,7 @@ void ControlBar::update( void ) if( m_isObserverCommandBar) { if((TheGameLogic->getFrame() % (LOGICFRAMES_PER_SECOND/2)) == 0) - populateObserverInfoWindow(); + refreshObserverUI(); Drawable *drawToEvaluateFor = NULL; if( TheInGameUI->getSelectCount() > 1 ) diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/ControlBar/ControlBarObserver.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/ControlBar/ControlBarObserver.cpp index 1c8c9dd67f..ad866beada 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/ControlBar/ControlBarObserver.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/ControlBar/ControlBarObserver.cpp @@ -100,6 +100,155 @@ static GameWindow *staticTextPlayerName = NULL; static NameKeyType s_replayObserverNameKey = NAMEKEY_INVALID; +static AsciiString formatCompactCash(UnsignedInt cash) +{ + AsciiString cashText; + + if (cash >= 1000000) + { + if ((cash % 1000000) == 0) + { + cashText.format("$%uM", cash / 1000000); + } + else + { + const float millions = static_cast(cash) / 1000000.0f; + cashText.format("$%.1fM", millions); + } + } + else if (cash >= 1000) + { + if ((cash % 1000) == 0) + { + cashText.format("$%uK", cash / 1000); + } + else + { + const float thousands = static_cast(cash) / 1000.0f; + cashText.format("$%.1fK", thousands); + } + } + else + { + cashText.format("$%u", cash); + } + + return cashText; +} + +// TheSuperHackers @feature GitHubCopilot 01/11/2025 Surface cash/rank/xp summary for observer overlays. +static UnicodeString formatObserverPlayerSummary(const Player *player) +{ + UnicodeString summary; + + if (!player) + { + return summary; + } + + UnsignedInt cash = 0; + if (player->getMoney()) + { + cash = player->getMoney()->countMoney(); + } + + const Int rankLevel = player->getRankLevel(); + const Int totalSkillPoints = player->getSkillPoints(); + const Int levelFloor = player->getSkillPointsLevelDown(); + const Int levelCeiling = player->getSkillPointsLevelUp(); + + Int xpProgress = totalSkillPoints - levelFloor; + if (xpProgress < 0) + { + xpProgress = 0; + } + + Int xpSpan = levelCeiling - levelFloor; + if (xpSpan < 0) + { + xpSpan = 0; + } + + Int xpPercent = 100; + if (xpSpan > 0) + { + xpPercent = (xpProgress * 100) / xpSpan; + if (xpPercent > 100) + { + xpPercent = 100; + } + } + + AsciiString asciiSummary = formatCompactCash(cash); + + AsciiString rankToken; + rankToken.format(" R%d", rankLevel); + asciiSummary.concat(rankToken); + + AsciiString xpToken; + if (xpSpan > 0) + { + xpToken.format(" XP %d%%", xpPercent); + } + else + { + xpToken.format(" XP %d", totalSkillPoints); + } + asciiSummary.concat(xpToken); + + summary.translate(asciiSummary); + return summary; +} + +static void appendSummaryToSecondLine(UnicodeString &text, const UnicodeString &summary) +{ + if (summary.isEmpty()) + { + return; + } + + UnicodeString firstLine; + UnicodeString secondLine; + Bool onSecondLine = FALSE; + + const Int length = text.getLength(); + for (Int index = 0; index < length; ++index) + { + const WideChar ch = text.getCharAt(index); + if (!onSecondLine) + { + firstLine.concat(ch); + if (ch == L'\n') + { + onSecondLine = TRUE; + } + } + else + { + secondLine.concat(ch); + } + } + + if (onSecondLine) + { + if (!secondLine.isEmpty()) + { + secondLine.concat(L" "); + } + secondLine.concat(summary); + text = firstLine; + text.concat(secondLine); + } + else + { + if (!text.isEmpty()) + { + text.concat(L"\n"); + } + text.concat(summary); + } +} + //----------------------------------------------------------------------------- // PUBLIC FUNCTIONS /////////////////////////////////////////////////////////// //----------------------------------------------------------------------------- @@ -270,7 +419,14 @@ void ControlBar::populateObserverList( void ) //GadgetButtonSetHiliteImage( buttonPlayer[currentButton], p->getPlayerTemplate()->getHiliteImage() ); //GadgetButtonSetHiliteSelectedImage( buttonPlayer[currentButton], p->getPlayerTemplate()->getPushedImage() ); //GadgetButtonSetDisabledImage( buttonPlayer[currentButton], p->getPlayerTemplate()->getDisabledImage() ); - buttonPlayer[currentButton]->winSetTooltip(p->getPlayerDisplayName()); + const UnicodeString summary = formatObserverPlayerSummary(p); + UnicodeString tooltip = p->getPlayerDisplayName(); + if (!summary.isEmpty()) + { + tooltip.concat(L"\n"); + tooltip.concat(summary); + } + buttonPlayer[currentButton]->winSetTooltip(tooltip); buttonPlayer[currentButton]->winHide(FALSE); buttonPlayer[currentButton]->winSetStatus( WIN_STATUS_USE_OVERLAY_STATES ); @@ -287,6 +443,7 @@ void ControlBar::populateObserverList( void ) UnicodeString text; text.format(TheGameText->fetch("CONTROLBAR:ObsPlayerLabel"), p->getPlayerDisplayName().str(), TheGameText->fetch(teamStr).str()); + appendSummaryToSecondLine(text, summary); GadgetStaticTextSetText(staticTextPlayer[currentButton], text ); @@ -312,7 +469,14 @@ void ControlBar::populateObserverList( void ) //GadgetButtonSetHiliteImage( buttonPlayer[currentButton], p->getPlayerTemplate()->getHiliteImage() ); //GadgetButtonSetHiliteSelectedImage( buttonPlayer[currentButton], p->getPlayerTemplate()->getPushedImage() ); //GadgetButtonSetDisabledImage( buttonPlayer[currentButton], p->getPlayerTemplate()->getDisabledImage() ); - buttonPlayer[currentButton]->winSetTooltip(p->getPlayerDisplayName()); + const UnicodeString summary = formatObserverPlayerSummary(p); + UnicodeString tooltip = p->getPlayerDisplayName(); + if (!summary.isEmpty()) + { + tooltip.concat(L"\n"); + tooltip.concat(summary); + } + buttonPlayer[currentButton]->winSetTooltip(tooltip); buttonPlayer[currentButton]->winHide(FALSE); buttonPlayer[currentButton]->winSetStatus( WIN_STATUS_USE_OVERLAY_STATES ); @@ -320,7 +484,9 @@ void ControlBar::populateObserverList( void ) Color backColor = GameMakeColor(0, 0, 0, 255); staticTextPlayer[currentButton]->winSetEnabledTextColors( playerColor, backColor ); staticTextPlayer[currentButton]->winHide(FALSE); - GadgetStaticTextSetText(staticTextPlayer[currentButton], p->getPlayerDisplayName()); + UnicodeString text = p->getPlayerDisplayName(); + appendSummaryToSecondLine(text, summary); + GadgetStaticTextSetText(staticTextPlayer[currentButton], text); ++currentButton; break; @@ -376,10 +542,31 @@ void ControlBar::populateObserverInfoWindow ( void ) GadgetStaticTextSetText(staticTextNumberOfUnitsKilled, uString); uString.format(L"%d",m_observerLookAtPlayer->getScoreKeeper()->getTotalUnitsLost()); GadgetStaticTextSetText(staticTextNumberOfUnitsLost, uString); - GadgetStaticTextSetText(staticTextPlayerName, m_observerLookAtPlayer->getPlayerDisplayName()); + UnicodeString nameLine = m_observerLookAtPlayer->getPlayerDisplayName(); + const UnicodeString summary = formatObserverPlayerSummary(m_observerLookAtPlayer); + appendSummaryToSecondLine(nameLine, summary); + GadgetStaticTextSetText(staticTextPlayerName, nameLine); Color color = m_observerLookAtPlayer->getPlayerColor(); staticTextPlayerName->winSetEnabledTextColors(color, GameMakeColor(0,0,0,255)); winFlag->winSetEnabledImage(0, m_observerLookAtPlayer->getPlayerTemplate()->getFlagWaterMarkImage()); winGeneralPortrait->winHide(FALSE); buttonIdleWorker->winHide(FALSE); } + +void ControlBar::refreshObserverUI() +{ + if (!m_isObserverCommandBar) + { + return; + } + + if (ObserverPlayerInfoWindow && !ObserverPlayerInfoWindow->winIsHidden()) + { + populateObserverInfoWindow(); + } + + if (ObserverPlayerListWindow && !ObserverPlayerListWindow->winIsHidden()) + { + populateObserverList(); + } +} From e78c2035646c002b913796e348baff2ff1ef55b6 Mon Sep 17 00:00:00 2001 From: Hamood-bot Date: Sat, 1 Nov 2025 05:05:11 +0200 Subject: [PATCH 2/2] Adjust player name label height in observer UI Introduces logic to capture and set the original size of the player name label, ensuring its height is adjusted appropriately when displaying player information in the observer control bar. This improves UI consistency and prevents layout issues when the label content changes. --- .../GUI/ControlBar/ControlBarObserver.cpp | 40 ++++++++++++++++++- .../GUI/ControlBar/ControlBarObserver.cpp | 40 ++++++++++++++++++- 2 files changed, 76 insertions(+), 4 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/ControlBar/ControlBarObserver.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/ControlBar/ControlBarObserver.cpp index 9f93ca58bf..d03d336a62 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/ControlBar/ControlBarObserver.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/ControlBar/ControlBarObserver.cpp @@ -99,6 +99,38 @@ static GameWindow *staticTextNumberOfUnitsLost = NULL; static GameWindow *staticTextPlayerName = NULL; static NameKeyType s_replayObserverNameKey = NAMEKEY_INVALID; +static Int s_playerNameOriginalWidth = 0; +static Int s_playerNameOriginalHeight = 0; +static Bool s_playerNameSizeCaptured = FALSE; + +static void ensurePlayerNameLabelHeight(Bool needsTwoLines) +{ + if (!staticTextPlayerName) + { + return; + } + + if (!s_playerNameSizeCaptured) + { + staticTextPlayerName->winGetSize(&s_playerNameOriginalWidth, &s_playerNameOriginalHeight); + s_playerNameSizeCaptured = TRUE; + } + + if (s_playerNameOriginalHeight <= 0) + { + return; + } + + Int currentWidth = 0; + Int currentHeight = 0; + staticTextPlayerName->winGetSize(¤tWidth, ¤tHeight); + + const Int targetHeight = needsTwoLines ? s_playerNameOriginalHeight * 2 : s_playerNameOriginalHeight; + if (currentHeight != targetHeight) + { + staticTextPlayerName->winSetSize(currentWidth, targetHeight); + } +} static AsciiString formatCompactCash(UnsignedInt cash) { @@ -275,6 +307,11 @@ void ControlBar::initObserverControls( void ) staticTextNumberOfUnitsKilled = TheWindowManager->winGetWindowFromId(NULL, TheNameKeyGenerator->nameToKey("ControlBar.wnd:StaticTextNumberOfUnitsKilled")); staticTextNumberOfUnitsLost = TheWindowManager->winGetWindowFromId(NULL, TheNameKeyGenerator->nameToKey("ControlBar.wnd:StaticTextNumberOfUnitsLost")); staticTextPlayerName = TheWindowManager->winGetWindowFromId(NULL, TheNameKeyGenerator->nameToKey("ControlBar.wnd:StaticTextPlayerName")); + if (staticTextPlayerName) + { + staticTextPlayerName->winGetSize(&s_playerNameOriginalWidth, &s_playerNameOriginalHeight); + s_playerNameSizeCaptured = TRUE; + } winFlag = TheWindowManager->winGetWindowFromId(NULL, TheNameKeyGenerator->nameToKey("ControlBar.wnd:WinFlag")); winGeneralPortrait = TheWindowManager->winGetWindowFromId(NULL, TheNameKeyGenerator->nameToKey("ControlBar.wnd:WinGeneralPortrait")); buttonIdleWorker = TheWindowManager->winGetWindowFromId(NULL, TheNameKeyGenerator->nameToKey("ControlBar.wnd:ButtonIdleWorker")); @@ -542,9 +579,8 @@ void ControlBar::populateObserverInfoWindow ( void ) uString.format(L"%d",m_observerLookAtPlayer->getScoreKeeper()->getTotalUnitsLost()); GadgetStaticTextSetText(staticTextNumberOfUnitsLost, uString); UnicodeString playerName = m_observerLookAtPlayer->getPlayerDisplayName(); - const UnicodeString infoSummary = formatObserverPlayerSummary(m_observerLookAtPlayer); - appendSummaryToSecondLine(playerName, infoSummary); GadgetStaticTextSetText(staticTextPlayerName, playerName); + ensurePlayerNameLabelHeight(FALSE); Color color = m_observerLookAtPlayer->getPlayerColor(); staticTextPlayerName->winSetEnabledTextColors(color, GameMakeColor(0,0,0,255)); winFlag->winSetEnabledImage(0, m_observerLookAtPlayer->getPlayerTemplate()->getFlagWaterMarkImage()); diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/ControlBar/ControlBarObserver.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/ControlBar/ControlBarObserver.cpp index ad866beada..64cc45c78b 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/ControlBar/ControlBarObserver.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/ControlBar/ControlBarObserver.cpp @@ -99,6 +99,38 @@ static GameWindow *staticTextNumberOfUnitsLost = NULL; static GameWindow *staticTextPlayerName = NULL; static NameKeyType s_replayObserverNameKey = NAMEKEY_INVALID; +static Int s_playerNameOriginalWidth = 0; +static Int s_playerNameOriginalHeight = 0; +static Bool s_playerNameSizeCaptured = FALSE; + +static void ensurePlayerNameLabelHeight(Bool needsTwoLines) +{ + if (!staticTextPlayerName) + { + return; + } + + if (!s_playerNameSizeCaptured) + { + staticTextPlayerName->winGetSize(&s_playerNameOriginalWidth, &s_playerNameOriginalHeight); + s_playerNameSizeCaptured = TRUE; + } + + if (s_playerNameOriginalHeight <= 0) + { + return; + } + + Int currentWidth = 0; + Int currentHeight = 0; + staticTextPlayerName->winGetSize(¤tWidth, ¤tHeight); + + const Int targetHeight = needsTwoLines ? s_playerNameOriginalHeight * 2 : s_playerNameOriginalHeight; + if (currentHeight != targetHeight) + { + staticTextPlayerName->winSetSize(currentWidth, targetHeight); + } +} static AsciiString formatCompactCash(UnsignedInt cash) { @@ -275,6 +307,11 @@ void ControlBar::initObserverControls( void ) staticTextNumberOfUnitsKilled = TheWindowManager->winGetWindowFromId(NULL, TheNameKeyGenerator->nameToKey("ControlBar.wnd:StaticTextNumberOfUnitsKilled")); staticTextNumberOfUnitsLost = TheWindowManager->winGetWindowFromId(NULL, TheNameKeyGenerator->nameToKey("ControlBar.wnd:StaticTextNumberOfUnitsLost")); staticTextPlayerName = TheWindowManager->winGetWindowFromId(NULL, TheNameKeyGenerator->nameToKey("ControlBar.wnd:StaticTextPlayerName")); + if (staticTextPlayerName) + { + staticTextPlayerName->winGetSize(&s_playerNameOriginalWidth, &s_playerNameOriginalHeight); + s_playerNameSizeCaptured = TRUE; + } winFlag = TheWindowManager->winGetWindowFromId(NULL, TheNameKeyGenerator->nameToKey("ControlBar.wnd:WinFlag")); winGeneralPortrait = TheWindowManager->winGetWindowFromId(NULL, TheNameKeyGenerator->nameToKey("ControlBar.wnd:WinGeneralPortrait")); buttonIdleWorker = TheWindowManager->winGetWindowFromId(NULL, TheNameKeyGenerator->nameToKey("ControlBar.wnd:ButtonIdleWorker")); @@ -543,9 +580,8 @@ void ControlBar::populateObserverInfoWindow ( void ) uString.format(L"%d",m_observerLookAtPlayer->getScoreKeeper()->getTotalUnitsLost()); GadgetStaticTextSetText(staticTextNumberOfUnitsLost, uString); UnicodeString nameLine = m_observerLookAtPlayer->getPlayerDisplayName(); - const UnicodeString summary = formatObserverPlayerSummary(m_observerLookAtPlayer); - appendSummaryToSecondLine(nameLine, summary); GadgetStaticTextSetText(staticTextPlayerName, nameLine); + ensurePlayerNameLabelHeight(FALSE); Color color = m_observerLookAtPlayer->getPlayerColor(); staticTextPlayerName->winSetEnabledTextColors(color, GameMakeColor(0,0,0,255)); winFlag->winSetEnabledImage(0, m_observerLookAtPlayer->getPlayerTemplate()->getFlagWaterMarkImage());