Skip to content

Commit 50ffe07

Browse files
committed
feat: Display additional replay information as a tooltip
1 parent bf56c29 commit 50ffe07

File tree

2 files changed

+158
-70
lines changed
  • GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus
  • Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus

2 files changed

+158
-70
lines changed

Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/ReplayMenu.cpp

Lines changed: 79 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,18 @@
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+
struct ReplayInfoCacheEntry
53+
{
54+
RecorderClass::ReplayHeader header;
55+
ReplayGameInfo info;
56+
UnicodeString extraStr;
57+
};
58+
59+
static std::map<AsciiString, ReplayInfoCacheEntry> replayInfoCache;
5160

5261
// window ids -------------------------------------------------------------------------------------
5362
static NameKeyType parentReplayMenuID = NAMEKEY_INVALID;
@@ -166,11 +175,40 @@ static UnicodeString createMapName(const AsciiString& filename, const ReplayGame
166175
return mapName;
167176
}
168177

178+
//-------------------------------------------------------------------------------------------------
179+
180+
static void replayTooltip(GameWindow* window, WinInstanceData* instData, UnsignedInt mouse)
181+
{
182+
Int x, y, row, col;
183+
x = LOLONGTOSHORT(mouse);
184+
y = HILONGTOSHORT(mouse);
185+
186+
GadgetListBoxGetEntryBasedOnXY(window, x, y, row, col);
187+
188+
if (row == -1 || col == -1)
189+
{
190+
TheMouse->setCursorTooltip(UnicodeString::TheEmptyString);
191+
return;
192+
}
193+
194+
UnicodeString replayFileName = GetReplayFilenameFromListbox(window, row);
195+
AsciiString replayFileNameAscii;
196+
replayFileNameAscii.translate(replayFileName);
197+
198+
std::map<AsciiString, ReplayInfoCacheEntry>::const_iterator it = replayInfoCache.find(replayFileNameAscii);
199+
if (it != replayInfoCache.end())
200+
TheMouse->setCursorTooltip(it->second.extraStr, -1, NULL, 1.5f);
201+
else
202+
TheMouse->setCursorTooltip(UnicodeString::TheEmptyString);
203+
}
204+
169205
//-------------------------------------------------------------------------------------------------
170206
/** Populate the listbox with the names of the available replay files */
171207
//-------------------------------------------------------------------------------------------------
172208
void PopulateReplayFileListbox(GameWindow *listbox)
173209
{
210+
replayInfoCache.clear();
211+
174212
if (!TheMapCache)
175213
return;
176214

@@ -234,41 +272,46 @@ void PopulateReplayFileListbox(GameWindow *listbox)
234272
// map
235273
UnicodeString mapStr = createMapName(asciistr, info, mapData);
236274

237-
// // extra
238-
// UnicodeString extraStr;
239-
// if (header.localPlayerIndex >= 0)
240-
// {
241-
// // MP game
242-
// time_t totalSeconds = header.endTime - header.startTime;
243-
// Int hours = totalSeconds / 3600;
244-
// Int mins = (totalSeconds % 3600) / 60;
245-
// Int secs = totalSeconds % 60;
246-
// Real fps = header.frameCount / totalSeconds;
247-
// extraStr.format(L"%02d:%02d:%02d (%g fps) %hs", hours, mins, secs, fps, header.desyncGame ? "OOS " : "");
248-
//
249-
// for (Int i=0; i<MAX_SLOTS; ++i)
250-
// {
251-
// const GameSlot *slot = info.getConstSlot(i);
252-
// if (slot && slot->isHuman())
253-
// {
254-
// if (i)
255-
// extraStr.concat(L", ");
256-
// if (header.playerDiscons[i])
257-
// extraStr.concat(L'*');
258-
// extraStr.concat(info.getConstSlot(i)->getName());
259-
// }
260-
// }
261-
// }
262-
// else
263-
// {
264-
// // solo game
265-
// time_t totalSeconds = header.endTime - header.startTime;
266-
// Int hours = totalSeconds / 3600;
267-
// Int mins = (totalSeconds % 3600) / 60;
268-
// Int secs = totalSeconds % 60;
269-
// Real fps = header.frameCount / totalSeconds;
270-
// extraStr.format(L"%02d:%02d:%02d (%g fps)", hours, mins, secs, fps);
271-
// }
275+
// extra
276+
UnicodeString extraStr;
277+
if (header.localPlayerIndex >= 0)
278+
{
279+
// MP game
280+
time_t totalSeconds = header.endTime - header.startTime;
281+
Int hours = totalSeconds / 3600;
282+
Int mins = (totalSeconds % 3600) / 60;
283+
Int secs = totalSeconds % 60;
284+
Real fps = header.frameCount / totalSeconds;
285+
extraStr.format(L"%02d:%02d:%02d (%g fps) %hs", hours, mins, secs, fps, header.desyncGame ? "OOS " : "");
286+
287+
for (Int i=0; i<MAX_SLOTS; ++i)
288+
{
289+
const GameSlot *slot = info.getConstSlot(i);
290+
if (slot && slot->isHuman())
291+
{
292+
extraStr.concat(L"\n");
293+
if (header.playerDiscons[i])
294+
extraStr.concat(L'*');
295+
extraStr.concat(info.getConstSlot(i)->getName());
296+
}
297+
}
298+
}
299+
else
300+
{
301+
// solo game
302+
time_t totalSeconds = header.endTime - header.startTime;
303+
Int hours = totalSeconds / 3600;
304+
Int mins = (totalSeconds % 3600) / 60;
305+
Int secs = totalSeconds % 60;
306+
Real fps = header.frameCount / totalSeconds;
307+
extraStr.format(L"%02d:%02d:%02d (%g fps)", hours, mins, secs, fps);
308+
}
309+
310+
ReplayInfoCacheEntry entry;
311+
entry.header = header;
312+
entry.info = info;
313+
entry.extraStr = extraStr;
314+
replayInfoCache[asciistr] = entry;
272315

273316
// pick a color
274317
Color color;
@@ -348,6 +391,7 @@ void ReplayMenuInit( WindowLayout *layout, void *userData )
348391
buttonLoad = TheWindowManager->winGetWindowFromId( parentReplayMenu, buttonLoadID );
349392
buttonBack = TheWindowManager->winGetWindowFromId( parentReplayMenu, buttonBackID );
350393
listboxReplayFiles = TheWindowManager->winGetWindowFromId( parentReplayMenu, listboxReplayFilesID );
394+
listboxReplayFiles->winSetTooltipFunc(replayTooltip);
351395
buttonDelete = TheWindowManager->winGetWindowFromId( parentReplayMenu, buttonDeleteID );
352396
buttonCopy = TheWindowManager->winGetWindowFromId( parentReplayMenu, buttonCopyID );
353397

GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/ReplayMenu.cpp

Lines changed: 79 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,18 @@
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+
struct ReplayInfoCacheEntry
53+
{
54+
RecorderClass::ReplayHeader header;
55+
ReplayGameInfo info;
56+
UnicodeString extraStr;
57+
};
58+
59+
static std::map<AsciiString, ReplayInfoCacheEntry> replayInfoCache;
5160

5261
// window ids -------------------------------------------------------------------------------------
5362
static NameKeyType parentReplayMenuID = NAMEKEY_INVALID;
@@ -166,11 +175,40 @@ static UnicodeString createMapName(const AsciiString& filename, const ReplayGame
166175
return mapName;
167176
}
168177

178+
//-------------------------------------------------------------------------------------------------
179+
180+
static void replayTooltip(GameWindow* window, WinInstanceData* instData, UnsignedInt mouse)
181+
{
182+
Int x, y, row, col;
183+
x = LOLONGTOSHORT(mouse);
184+
y = HILONGTOSHORT(mouse);
185+
186+
GadgetListBoxGetEntryBasedOnXY(window, x, y, row, col);
187+
188+
if (row == -1 || col == -1)
189+
{
190+
TheMouse->setCursorTooltip(UnicodeString::TheEmptyString);
191+
return;
192+
}
193+
194+
UnicodeString replayFileName = GetReplayFilenameFromListbox(window, row);
195+
AsciiString replayFileNameAscii;
196+
replayFileNameAscii.translate(replayFileName);
197+
198+
std::map<AsciiString, ReplayInfoCacheEntry>::const_iterator it = replayInfoCache.find(replayFileNameAscii);
199+
if (it != replayInfoCache.end())
200+
TheMouse->setCursorTooltip(it->second.extraStr, -1, NULL, 1.5f);
201+
else
202+
TheMouse->setCursorTooltip(UnicodeString::TheEmptyString);
203+
}
204+
169205
//-------------------------------------------------------------------------------------------------
170206
/** Populate the listbox with the names of the available replay files */
171207
//-------------------------------------------------------------------------------------------------
172208
void PopulateReplayFileListbox(GameWindow *listbox)
173209
{
210+
replayInfoCache.clear();
211+
174212
if (!TheMapCache)
175213
return;
176214

@@ -234,41 +272,46 @@ void PopulateReplayFileListbox(GameWindow *listbox)
234272
// map
235273
UnicodeString mapStr = createMapName(asciistr, info, mapData);
236274

237-
// // extra
238-
// UnicodeString extraStr;
239-
// if (header.localPlayerIndex >= 0)
240-
// {
241-
// // MP game
242-
// time_t totalSeconds = header.endTime - header.startTime;
243-
// Int hours = totalSeconds / 3600;
244-
// Int mins = (totalSeconds % 3600) / 60;
245-
// Int secs = totalSeconds % 60;
246-
// Real fps = header.frameCount / totalSeconds;
247-
// extraStr.format(L"%02d:%02d:%02d (%g fps) %hs", hours, mins, secs, fps, header.desyncGame ? "OOS " : "");
248-
//
249-
// for (Int i=0; i<MAX_SLOTS; ++i)
250-
// {
251-
// const GameSlot *slot = info.getConstSlot(i);
252-
// if (slot && slot->isHuman())
253-
// {
254-
// if (i)
255-
// extraStr.concat(L", ");
256-
// if (header.playerDiscons[i])
257-
// extraStr.concat(L'*');
258-
// extraStr.concat(info.getConstSlot(i)->getName());
259-
// }
260-
// }
261-
// }
262-
// else
263-
// {
264-
// // solo game
265-
// time_t totalSeconds = header.endTime - header.startTime;
266-
// Int hours = totalSeconds / 3600;
267-
// Int mins = (totalSeconds % 3600) / 60;
268-
// Int secs = totalSeconds % 60;
269-
// Real fps = header.frameCount / totalSeconds;
270-
// extraStr.format(L"%02d:%02d:%02d (%g fps)", hours, mins, secs, fps);
271-
// }
275+
// extra
276+
UnicodeString extraStr;
277+
if (header.localPlayerIndex >= 0)
278+
{
279+
// MP game
280+
time_t totalSeconds = header.endTime - header.startTime;
281+
Int hours = totalSeconds / 3600;
282+
Int mins = (totalSeconds % 3600) / 60;
283+
Int secs = totalSeconds % 60;
284+
Real fps = header.frameCount / totalSeconds;
285+
extraStr.format(L"%02d:%02d:%02d (%g fps) %hs", hours, mins, secs, fps, header.desyncGame ? "OOS " : "");
286+
287+
for (Int i=0; i<MAX_SLOTS; ++i)
288+
{
289+
const GameSlot *slot = info.getConstSlot(i);
290+
if (slot && slot->isHuman())
291+
{
292+
extraStr.concat(L"\n");
293+
if (header.playerDiscons[i])
294+
extraStr.concat(L'*');
295+
extraStr.concat(info.getConstSlot(i)->getName());
296+
}
297+
}
298+
}
299+
else
300+
{
301+
// solo game
302+
time_t totalSeconds = header.endTime - header.startTime;
303+
Int hours = totalSeconds / 3600;
304+
Int mins = (totalSeconds % 3600) / 60;
305+
Int secs = totalSeconds % 60;
306+
Real fps = header.frameCount / totalSeconds;
307+
extraStr.format(L"%02d:%02d:%02d (%g fps)", hours, mins, secs, fps);
308+
}
309+
310+
ReplayInfoCacheEntry entry;
311+
entry.header = header;
312+
entry.info = info;
313+
entry.extraStr = extraStr;
314+
replayInfoCache[asciistr] = entry;
272315

273316
// pick a color
274317
Color color;
@@ -348,6 +391,7 @@ void ReplayMenuInit( WindowLayout *layout, void *userData )
348391
buttonLoad = TheWindowManager->winGetWindowFromId( parentReplayMenu, buttonLoadID );
349392
buttonBack = TheWindowManager->winGetWindowFromId( parentReplayMenu, buttonBackID );
350393
listboxReplayFiles = TheWindowManager->winGetWindowFromId( parentReplayMenu, listboxReplayFilesID );
394+
listboxReplayFiles->winSetTooltipFunc(replayTooltip);
351395
buttonDelete = TheWindowManager->winGetWindowFromId( parentReplayMenu, buttonDeleteID );
352396
buttonCopy = TheWindowManager->winGetWindowFromId( parentReplayMenu, buttonCopyID );
353397

0 commit comments

Comments
 (0)