4545#include " GameClient/GameWindowManager.h"
4646#include " GameClient/MessageBox.h"
4747#include " GameClient/MapUtil.h"
48+ #include " GameClient/Mouse.h"
4849#include " GameClient/GameText.h"
4950#include " GameClient/GameWindowTransitions.h"
5051
52+ typedef UnicodeString ReplayName;
53+ typedef UnicodeString TooltipString;
54+ typedef std::map<ReplayName, TooltipString> ReplayTooltipMap;
55+
56+ static ReplayTooltipMap replayTooltipCache;
5157
5258// window ids -------------------------------------------------------------------------------------
5359static NameKeyType parentReplayMenuID = NAMEKEY_INVALID;
@@ -166,11 +172,70 @@ static UnicodeString createMapName(const AsciiString& filename, const ReplayGame
166172 return mapName;
167173}
168174
175+ // -------------------------------------------------------------------------------------------------
176+ // TheSuperHackers @feature Stubbjax 21/10/2025 Show extra info tooltip when hovering over a replay.
177+
178+ static void showReplayTooltip (GameWindow* window, WinInstanceData* instData, UnsignedInt mouse)
179+ {
180+ Int x, y, row, col;
181+ x = LOLONGTOSHORT (mouse);
182+ y = HILONGTOSHORT (mouse);
183+
184+ GadgetListBoxGetEntryBasedOnXY (window, x, y, row, col);
185+
186+ if (row == -1 || col == -1 )
187+ {
188+ TheMouse->setCursorTooltip (UnicodeString::TheEmptyString);
189+ return ;
190+ }
191+
192+ UnicodeString replayFileName = GetReplayFilenameFromListbox (window, row);
193+
194+ ReplayTooltipMap::const_iterator it = replayTooltipCache.find (replayFileName);
195+ if (it != replayTooltipCache.end ())
196+ TheMouse->setCursorTooltip (it->second , -1 , NULL , 1 .5f );
197+ else
198+ TheMouse->setCursorTooltip (UnicodeString::TheEmptyString);
199+ }
200+
201+ static UnicodeString buildReplayTooltip (RecorderClass::ReplayHeader header, ReplayGameInfo info)
202+ {
203+ UnicodeString tooltipStr;
204+
205+ if (header.endTime < header.startTime )
206+ header.startTime = header.endTime ;
207+
208+ time_t totalSeconds = header.endTime - header.startTime ;
209+ UnsignedInt hours = totalSeconds / 3600 ;
210+ UnsignedInt mins = (totalSeconds % 3600 ) / 60 ;
211+ UnsignedInt secs = totalSeconds % 60 ;
212+ Real fps = totalSeconds > 0 ? header.frameCount / totalSeconds : 0 ;
213+ tooltipStr.format (L" %02u:%02u:%02u (%g fps)" , hours, mins, secs, fps);
214+
215+ if (header.localPlayerIndex >= 0 )
216+ {
217+ // MP game
218+ for (Int i = 0 ; i < MAX_SLOTS; ++i)
219+ {
220+ const GameSlot* slot = info.getConstSlot (i);
221+ if (slot && slot->isHuman ())
222+ {
223+ tooltipStr.concat (L" \n " );
224+ tooltipStr.concat (info.getConstSlot (i)->getName ());
225+ }
226+ }
227+ }
228+
229+ return tooltipStr;
230+ }
231+
169232// -------------------------------------------------------------------------------------------------
170233/* * Populate the listbox with the names of the available replay files */
171234// -------------------------------------------------------------------------------------------------
172235void PopulateReplayFileListbox (GameWindow *listbox)
173236{
237+ replayTooltipCache.clear ();
238+
174239 if (!TheMapCache)
175240 return ;
176241
@@ -234,39 +299,12 @@ void PopulateReplayFileListbox(GameWindow *listbox)
234299 // map
235300 UnicodeString mapStr = createMapName (asciistr, info, mapData);
236301
237- // // extra
238- // UnicodeString extraStr;
239- // if (header.localPlayerIndex >= 0)
240- // {
241- // // MP game
242- // time_t totalSeconds = header.endTime - header.startTime;
243- // Int mins = totalSeconds/60;
244- // Int secs = totalSeconds%60;
245- // Real fps = header.frameCount/totalSeconds;
246- // extraStr.format(L"%d:%d (%g fps) %hs", mins, secs, fps, header.desyncGame?"OOS ":"");
247- //
248- // for (Int i=0; i<MAX_SLOTS; ++i)
249- // {
250- // const GameSlot *slot = info.getConstSlot(i);
251- // if (slot && slot->isHuman())
252- // {
253- // if (i)
254- // extraStr.concat(L", ");
255- // if (header.playerDiscons[i])
256- // extraStr.concat(L'*');
257- // extraStr.concat(info.getConstSlot(i)->getName());
258- // }
259- // }
260- // }
261- // else
262- // {
263- // // solo game
264- // time_t totalSeconds = header.endTime - header.startTime;
265- // Int mins = totalSeconds/60;
266- // Int secs = totalSeconds%60;
267- // Real fps = header.frameCount/totalSeconds;
268- // extraStr.format(L"%d:%d (%g fps)", mins, secs, fps);
269- // }
302+ // tooltip
303+ UnicodeString tooltipStr = buildReplayTooltip (header, info);
304+
305+ UnicodeString key;
306+ key.translate (asciistr);
307+ replayTooltipCache[key] = tooltipStr;
270308
271309 // pick a color
272310 Color color;
@@ -321,7 +359,6 @@ void PopulateReplayFileListbox(GameWindow *listbox)
321359 GadgetListBoxAddEntryText (listbox, displayTimeBuffer, color, insertionIndex, 1 );
322360 GadgetListBoxAddEntryText (listbox, header.versionString , color, insertionIndex, 2 );
323361 GadgetListBoxAddEntryText (listbox, mapStr, mapColor, insertionIndex, 3 );
324- // GadgetListBoxAddEntryText(listbox, extraStr, color, insertionIndex, 4);
325362 }
326363 }
327364 GadgetListBoxSetSelected (listbox, 0 );
@@ -346,6 +383,7 @@ void ReplayMenuInit( WindowLayout *layout, void *userData )
346383 buttonLoad = TheWindowManager->winGetWindowFromId ( parentReplayMenu, buttonLoadID );
347384 buttonBack = TheWindowManager->winGetWindowFromId ( parentReplayMenu, buttonBackID );
348385 listboxReplayFiles = TheWindowManager->winGetWindowFromId ( parentReplayMenu, listboxReplayFilesID );
386+ listboxReplayFiles->winSetTooltipFunc (showReplayTooltip);
349387 buttonDelete = TheWindowManager->winGetWindowFromId ( parentReplayMenu, buttonDeleteID );
350388 buttonCopy = TheWindowManager->winGetWindowFromId ( parentReplayMenu, buttonCopyID );
351389
0 commit comments